Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .codex/skills/navop-shell-extension/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ bash scripts/install-local-composite-extensions.sh # 构建并装到 ~/.config
- operations 的 `requires` 填 provider method URI 清单(capabilities 按它校验);新增有能力的操作就把 method 填进去。
- 一个 page 只允许一个 stack 原语(多原语安装期被拒);table 只有行级 actions,没有页面级 toolbar。
- `shellViews[].modules` 决定可用宿主模块:`workbench` 仅工作台挂载会话可用(独立打开必报错,且这类视图不进工具箱)。
- 文案跟随界面语言用 `navop.i18n`(`modules: ["i18n"]`),组件库那套主题名(`list_active`/`table_hover`)用 `navop.theme`(`modules: ["theme"]`)。两个都**不碰资源**:不需要 `backends`,嵌入式工作台页面也能用 —— 纯界面页可以只声明这两个。⚠️ 切语言时宿主重建的是 `render()`、**不重跑 `init()`**,所以 `locale()` 必须在 `render()` 里读;细节见 `references/script-api.md` §6.2/§6.3。
- 改动 languages/i18n key 时同步 locales(守卫测试 1338/1414 行那组)。

## 参考
Expand Down
8 changes: 7 additions & 1 deletion .codex/skills/navop-shell-extension/references/manifest.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,14 @@
| `log` | `navop.log` | `debug/info/warn/error(message)` —— 进扩展结构化日志(`navop.log` 用法见 dev-tools workbench.js) |
| `runtime` | `navop.runtime` | `info(backend)` → `{ backend, runtimeId, generation }` |
| `dev` | `navop.dev` | `list/open/reload/watch/remove/logs/pickDirectory/pickResult/openView` —— dev-tools 专用 |
| `i18n` | `navop.i18n` | `locale()` → 宿主当前界面语言(`"en"` \| `"zh-CN"` \| `"zh-HK"`)、`available()` → 宿主可能处在的语言、`revision()` → 每次切语言 +1。**只给语言事实,没有词条表** —— 扩展自己的文案自己带(见 [脚本 API §6.3](script-api.md)) |
| `theme` | `navop.theme` | `appearance()` → `"light"` \| `"dark"`、`names()` → 组件主题名清单、`colors()` → `{ 名字: "#rrggbbaa" }`、`color(name)` → `string` \| `null`、`revision()` → 主题变了 +1。**组件库那些面(`list_active`、`table_hover`、`sidebar_*`)只在这里**:`cx.theme()` 仍然是 gpui-base 的 18 个语义色(见 [脚本 API §6.2](script-api.md)) |

`ShellHostModule` 枚举源:`../navop/crates/extension-runtime/src/extension/manifest/contributes/shell.rs`;模块实现:`../navop/crates/universal-plugins/src/shell_plugin_host/{context,workbench,resource,job,event,blob,log,runtime,dev}.rs`(declarations 即 TS 签名,以它为准)。
`i18n` 与 `theme` **不碰资源**(既不需要 `backends`,嵌入式工作台页面也可用),所以纯界面页可以只声明这两个。

`ShellHostModule` 枚举源:`../navop/crates/extension-runtime/src/extension/manifest/contributes/shell.rs`(`module_specifier()` 是「声明面拼写 ↔ 脚本 import 名字」的唯一来源);模块实现:`../navop/crates/universal-plugins/src/shell_plugin_host/{context,workbench,resource,job,event,blob,log,runtime,dev,i18n,theme}.rs`(declarations 即 TS 签名,以它为准)。

上表的覆盖范围由宿主侧的守卫盯着:`cargo test -p universal-plugins --features shell-plugins -- the_skill_document_lists_every_declared_host_module`(相邻仓缺席时跳过)。

## 8. 构建 / 安装 / 发布

Expand Down
53 changes: 52 additions & 1 deletion .codex/skills/navop-shell-extension/references/script-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { dispatch, current } from "navop.workbench";
import { current as ctx } from "navop.context"; // 注意与 workbench.current 的内容不同
import { info, error as logError } from "navop.log";
import * as dev from "navop.dev"; // dev-tools 专用
import { locale, available } from "navop.i18n"; // 宿主当前界面语言(词条表自己带,见 §6.3)
import * as theme from "navop.theme"; // 组件库那套主题名(§6.2)
```

- **输入状态优先用 `gpui-base.InputState.new()` / `TextareaState.new()`**;styled `Input` / `Textarea` 从 `gpui-component` 导入。此规则只针对已验证的输入桥接,不表示所有 state 都在 base,也不表示 component catalog 的 retained state 都是空壳。
Expand Down Expand Up @@ -122,7 +124,9 @@ new Spinner().size("medium")
| 交互 div | 需要 hover/click 状态的加 `.id("唯一id")`;行可点加 `.cursor_pointer()` |
| 主题色 | 只用 `cx.theme().colors.<token>` 或 `#hex`;等宽文本 `.font_family("monospace")` |

## 6. 主题 token 闭集(18 个,多一个都不认)
## 6. 主题与语言

### 6.1 `cx.theme()`:18 个语义色闭集(多一个都不认)

```
background foreground surface surface_foreground
Expand All @@ -135,6 +139,53 @@ ring selection
- `cx.theme().colors` 是 gpui-base 的语义色闭集(`../gpui-component/crates/shell/src/theme_tokens.rs`);组件库自家主题名(`list_active`、`table_hover`)读出来是 `undefined` ⇒ 整页渲染失败("This view could not be rendered" / `expected a string, got nil`)。
- 静态守卫:`tests/scripts.test.mjs` 里两条测试 —— ①扩展 UI 不得出现裸 token 名颜色(颜色要么主题 token 要么 #rgb/#rrggbb/#rrggbbaa);②`cx.theme().colors.<name>` 的 name 必须在 18 名单内(名单是契约,故意与 gpui-component 重复)。

### 6.2 `navop.theme`:组件库那套主题名(100 多个)

6.1 那 18 个只是 gpui-base 的语义面。宿主界面自己画的东西主要在组件库的**另一套**主题里(`background`、`popover`、`list_active`、`table_hover`、`sidebar_*`、`chart_*` …),它们读不到 `cx.theme()`,要从 `navop.theme` 取:

```js
import * as theme from "navop.theme";
import { div } from "gpui";

const danger = theme.color("danger"); // "#rrggbbaa" 或 null
```

| 函数 | 返回 |
|---|---|
| `appearance()` | `"light"` \| `"dark"` |
| `names()` | 全部可用名字 |
| `colors()` | `{ 名字: "#rrggbbaa" }` |
| `color(name)` | `"#rrggbbaa"` \| `null` |
| `revision()` | 主题每次变化 +1 |

- 颜色统一是 `#rrggbbaa`(`gpui::Hsla` 的序列化形式),可以直接喂给 `bg()` / `text_color()` / `Badge.color` / `Icon.color`。
- ⚠️ **取不到的名字返回 `null`,不是让整页挂掉** —— 与 6.1「名字错 ⇒ 整页白屏」的失败方式**不一样**,所以别指望静态守卫救你:自己兜底,`theme.color("x") ?? "#00000000"`。
- manifest 里要声明 `modules: ["theme"]`。

### 6.3 `navop.i18n`:宿主语言 + 扩展自带词条表

**词条表由扩展自己带**,宿主只回答"现在是什么语言":

```js
import { locale } from "navop.i18n";

const TABLES = { en: { connect: "Connect" }, "zh-CN": { connect: "连接" }, "zh-HK": { connect: "連接" } };
const t = (key) => (TABLES[locale()] ?? TABLES.en)[key] ?? key;

render(_cx) { return div().child(t("connect")); } // ← 必须在 render 里读
```

| 函数 | 返回 |
|---|---|
| `locale()` | 宿主当前界面语言:`"en"` \| `"zh-CN"` \| `"zh-HK"` |
| `available()` | 宿主可能处在的语言(顺序无含义) |
| `revision()` | 每次宿主切语言 +1 |

- 宿主**没有** `t(key)` 给扩展用:扩展的文案不在宿主自己的 `locales/` 里,宿主替扩展解析会把两边的键空间搅在一起(宿主的 `common.connect` 与扩展的同名键撞上时谁都说不清谁赢)。分工是「宿主给事实、扩展带词条」——与驱动扩展的 `locales/*.yml` 是同一套思路。
- ⚠️ **切语言时宿主重建的是页面的 `render()`,`init()` 不会再跑一遍**(`ScriptView::refresh` → `rebuild` → 已有实例的 `render`)。所以**别在 `init` 里把词条表选好存起来**:那样切语言后页面仍显示旧语言,而且不报任何错。要么每次 `render` 读 `locale()`,要么在 `render` 里比对 `revision()` 再重选表。
- `shellViews[].title` / 工具箱卡片文案写在 manifest 里,是**单语言**的:页面内文案能跟随语言,标题不行(除非按语言发不同扩展)。
- manifest 里要声明 `modules: ["i18n"]`;它不碰资源,**纯界面页可以只声明这一个**(不需要 `backends`,嵌入式工作台页面也可用)。`navop.theme` 同理。

## 7. 实时数据:轮询(嵌入式页面唯一选择)

```js
Expand Down
2 changes: 1 addition & 1 deletion extensions/acp-agent/claude-acp/acp_agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "claude-acp",
"name": "Claude Code",
"description": "通过 Claude Agent ACP 将 Anthropic Claude Code 接入 Navop 的 Shell ACP 智能体扩展,可在工作区中进行代码分析、编辑和任务协作;需要 Node.js/npm 及适配器支持的 Claude Code 登录方式。 Shell ACP agent extension that connects Anthropic Claude Code to Navop through Claude Agent ACP for code analysis, editing, and task collaboration; requires Node.js/npm and a supported Claude Code authentication method.",
"version": "0.1.0",
"version": "0.1.1",
"agents": [
{
"id": "claude-acp",
Expand Down
2 changes: 1 addition & 1 deletion extensions/acp-agent/codex-acp/acp_agent.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "codex-acp",
"name": "Codex",
"description": "将 OpenAI Codex 接入 Navop 的 Shell ACP 智能体扩展,可在工作区中进行代码分析、修改、命令执行和开发任务协作;需要 Node.js/npm 及 Codex ACP 适配器支持的认证方式。 Shell ACP agent extension that connects OpenAI Codex to Navop for code analysis, editing, command execution, and development workflows; requires Node.js/npm and an authentication method supported by the Codex ACP adapter.",
"version": "0.1.0",
"version": "0.1.1",
"agents": [
{
"id": "codex-acp",
Expand Down
63 changes: 63 additions & 0 deletions extensions/ipc/iotdb/driver.json
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,69 @@
"submenu_of": null,
"toolbar_scope": "CurrentNode"
},
{
"id": "DumpSqlStructure",
"label_i18n_key": "ImportExport.export_structure",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "DumpSqlData",
"label_i18n_key": "ImportExport.export_data",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "DumpSqlStructureAndData",
"label_i18n_key": "ImportExport.export_structure_and_data",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "ImportData",
"label_i18n_key": "ImportExport.import_data",
Expand Down
63 changes: 63 additions & 0 deletions extensions/ipc/tdengine/driver.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,69 @@
"submenu_of": null,
"toolbar_scope": "CurrentNode"
},
{
"id": "DumpSqlStructure",
"label_i18n_key": "ImportExport.export_structure",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "DumpSqlData",
"label_i18n_key": "ImportExport.export_data",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "DumpSqlStructureAndData",
"label_i18n_key": "ImportExport.export_structure_and_data",
"icon": null,
"targets": [
{
"node_type": "Database"
},
{
"node_type": "Schema"
},
{
"node_type": "Table"
}
],
"placement": "ContextMenu",
"requires_active_connection": true,
"group": null,
"submenu_of": null,
"toolbar_scope": null
},
{
"id": "ImportData",
"label_i18n_key": "ImportExport.import_data",
Expand Down
6 changes: 1 addition & 5 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@
"release_tag": "gemini-acp-v0.1.0",
"description": "将 Google Gemini CLI 接入 Navop 的 Shell ACP 智能体扩展,使用 Gemini CLI 的原生 --experimental-acp 模式,可在工作区中进行代码理解、编辑和自动化开发任务;需要本机已安装并完成 Google 账号或 API Key 登录的 Gemini CLI。 Shell ACP agent extension that connects the Google Gemini CLI to Navop via its native --experimental-acp mode for code understanding, editing, and automated development tasks; requires a locally installed and authenticated Gemini CLI.",
"file_extensions": [],
"engines": {
"onetcli": ""
},
"manifest": "gemini-acp/manifest.json",
"artifacts": {}
"manifest": "gemini-acp/manifest.json"
},
{
"id": "opencode-acp",
Expand Down
3 changes: 2 additions & 1 deletion tests/scripts.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1215,7 +1215,7 @@ test("Windows x86 backfill matrix resolves every supported published extension",
);
const matrix = JSON.parse(output);

assert.equal(matrix.include.length, 18);
assert.equal(matrix.include.length, 19);
assert.deepEqual(
matrix.include.map((entry) => entry.extension),
[
Expand All @@ -1224,6 +1224,7 @@ test("Windows x86 backfill matrix resolves every supported published extension",
"dm",
"docker",
"duckdb",
"gemini-acp",
"iotdb",
"kingbase",
"mongodb-legacy",
Expand Down
Loading