@ai-zen/cli 1.0.0-alpha.20 → 1.0.0-alpha.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/README.md +43 -17
  3. package/README.zh.md +43 -17
  4. package/dist/agent-creator.d.ts.map +1 -1
  5. package/dist/agent-creator.js +32 -10
  6. package/dist/agent-creator.js.map +1 -1
  7. package/dist/agent-switch.d.ts +61 -0
  8. package/dist/agent-switch.d.ts.map +1 -0
  9. package/dist/agent-switch.js +83 -0
  10. package/dist/agent-switch.js.map +1 -0
  11. package/dist/agents-store.d.ts +6 -1
  12. package/dist/agents-store.d.ts.map +1 -1
  13. package/dist/agents-store.js +6 -1
  14. package/dist/agents-store.js.map +1 -1
  15. package/dist/auto-migrate-confirm.d.ts.map +1 -1
  16. package/dist/auto-migrate-confirm.js +2 -1
  17. package/dist/auto-migrate-confirm.js.map +1 -1
  18. package/dist/config-editor.d.ts +9 -1
  19. package/dist/config-editor.d.ts.map +1 -1
  20. package/dist/config-editor.js +30 -19
  21. package/dist/config-editor.js.map +1 -1
  22. package/dist/config.d.ts +1 -1
  23. package/dist/config.d.ts.map +1 -1
  24. package/dist/config.js +29 -13
  25. package/dist/config.js.map +1 -1
  26. package/dist/conversation-commands/registry.d.ts +123 -4
  27. package/dist/conversation-commands/registry.d.ts.map +1 -1
  28. package/dist/conversation-commands/registry.js +92 -17
  29. package/dist/conversation-commands/registry.js.map +1 -1
  30. package/dist/conversation-persist-plugin.d.ts.map +1 -1
  31. package/dist/conversation-persist-plugin.js +6 -14
  32. package/dist/conversation-persist-plugin.js.map +1 -1
  33. package/dist/conversation-repository.d.ts +68 -14
  34. package/dist/conversation-repository.d.ts.map +1 -1
  35. package/dist/conversation-repository.js +81 -23
  36. package/dist/conversation-repository.js.map +1 -1
  37. package/dist/cwd-tracker-plugin.d.ts.map +1 -1
  38. package/dist/cwd-tracker-plugin.js +6 -2
  39. package/dist/cwd-tracker-plugin.js.map +1 -1
  40. package/dist/format-time.d.ts +17 -6
  41. package/dist/format-time.d.ts.map +1 -1
  42. package/dist/format-time.js +32 -14
  43. package/dist/format-time.js.map +1 -1
  44. package/dist/handoff-service.d.ts.map +1 -1
  45. package/dist/handoff-service.js +22 -19
  46. package/dist/handoff-service.js.map +1 -1
  47. package/dist/hook.d.ts.map +1 -1
  48. package/dist/hook.js +69 -15
  49. package/dist/hook.js.map +1 -1
  50. package/dist/i18n/en-wizard.d.ts +8 -0
  51. package/dist/i18n/en-wizard.d.ts.map +1 -0
  52. package/dist/i18n/en-wizard.js +290 -0
  53. package/dist/i18n/en-wizard.js.map +1 -0
  54. package/dist/i18n/en.d.ts +7 -0
  55. package/dist/i18n/en.d.ts.map +1 -0
  56. package/dist/i18n/en.js +224 -0
  57. package/dist/i18n/en.js.map +1 -0
  58. package/dist/i18n/index.d.ts +57 -0
  59. package/dist/i18n/index.d.ts.map +1 -0
  60. package/dist/i18n/index.js +109 -0
  61. package/dist/i18n/index.js.map +1 -0
  62. package/dist/i18n/preferences.d.ts +34 -0
  63. package/dist/i18n/preferences.d.ts.map +1 -0
  64. package/dist/i18n/preferences.js +69 -0
  65. package/dist/i18n/preferences.js.map +1 -0
  66. package/dist/i18n/zh-wizard.d.ts +11 -0
  67. package/dist/i18n/zh-wizard.d.ts.map +1 -0
  68. package/dist/i18n/zh-wizard.js +293 -0
  69. package/dist/i18n/zh-wizard.js.map +1 -0
  70. package/dist/i18n/zh.d.ts +10 -0
  71. package/dist/i18n/zh.d.ts.map +1 -0
  72. package/dist/i18n/zh.js +228 -0
  73. package/dist/i18n/zh.js.map +1 -0
  74. package/dist/index.js +41 -23
  75. package/dist/index.js.map +1 -1
  76. package/dist/mcp-command.d.ts +32 -0
  77. package/dist/mcp-command.d.ts.map +1 -0
  78. package/dist/mcp-command.js +37 -0
  79. package/dist/mcp-command.js.map +1 -0
  80. package/dist/mode.d.ts +31 -4
  81. package/dist/mode.d.ts.map +1 -1
  82. package/dist/mode.js +42 -7
  83. package/dist/mode.js.map +1 -1
  84. package/dist/model-switch.d.ts.map +1 -1
  85. package/dist/model-switch.js +5 -4
  86. package/dist/model-switch.js.map +1 -1
  87. package/dist/reasoning-effort.d.ts +23 -4
  88. package/dist/reasoning-effort.d.ts.map +1 -1
  89. package/dist/reasoning-effort.js +51 -24
  90. package/dist/reasoning-effort.js.map +1 -1
  91. package/dist/sdk-log.d.ts +23 -16
  92. package/dist/sdk-log.d.ts.map +1 -1
  93. package/dist/sdk-log.js +43 -19
  94. package/dist/sdk-log.js.map +1 -1
  95. package/dist/stdio-runner.d.ts.map +1 -1
  96. package/dist/stdio-runner.js +19 -19
  97. package/dist/stdio-runner.js.map +1 -1
  98. package/dist/tui/chat-session.d.ts +27 -0
  99. package/dist/tui/chat-session.d.ts.map +1 -1
  100. package/dist/tui/chat-session.js +120 -28
  101. package/dist/tui/chat-session.js.map +1 -1
  102. package/dist/tui/components.d.ts +43 -2
  103. package/dist/tui/components.d.ts.map +1 -1
  104. package/dist/tui/components.js +97 -4
  105. package/dist/tui/components.js.map +1 -1
  106. package/dist/tui/config-wizard/detail.d.ts +12 -6
  107. package/dist/tui/config-wizard/detail.d.ts.map +1 -1
  108. package/dist/tui/config-wizard/detail.js +33 -32
  109. package/dist/tui/config-wizard/detail.js.map +1 -1
  110. package/dist/tui/config-wizard/engine.d.ts.map +1 -1
  111. package/dist/tui/config-wizard/engine.js +26 -20
  112. package/dist/tui/config-wizard/engine.js.map +1 -1
  113. package/dist/tui/config-wizard/fields.d.ts.map +1 -1
  114. package/dist/tui/config-wizard/fields.js +176 -164
  115. package/dist/tui/config-wizard/fields.js.map +1 -1
  116. package/dist/tui/config-wizard/kv-editor.d.ts.map +1 -1
  117. package/dist/tui/config-wizard/kv-editor.js +9 -5
  118. package/dist/tui/config-wizard/kv-editor.js.map +1 -1
  119. package/dist/tui/config-wizard/list.d.ts.map +1 -1
  120. package/dist/tui/config-wizard/list.js +2 -1
  121. package/dist/tui/config-wizard/list.js.map +1 -1
  122. package/dist/tui/config-wizard/mcp-helpers.d.ts.map +1 -1
  123. package/dist/tui/config-wizard/mcp-helpers.js +4 -3
  124. package/dist/tui/config-wizard/mcp-helpers.js.map +1 -1
  125. package/dist/tui/config-wizard/menu.d.ts.map +1 -1
  126. package/dist/tui/config-wizard/menu.js +32 -19
  127. package/dist/tui/config-wizard/menu.js.map +1 -1
  128. package/dist/tui/config-wizard/prompt-editor.d.ts.map +1 -1
  129. package/dist/tui/config-wizard/prompt-editor.js +4 -3
  130. package/dist/tui/config-wizard/prompt-editor.js.map +1 -1
  131. package/dist/tui/config-wizard/prompt.d.ts.map +1 -1
  132. package/dist/tui/config-wizard/prompt.js +8 -7
  133. package/dist/tui/config-wizard/prompt.js.map +1 -1
  134. package/dist/tui/config-wizard/step-agents.d.ts.map +1 -1
  135. package/dist/tui/config-wizard/step-agents.js +29 -20
  136. package/dist/tui/config-wizard/step-agents.js.map +1 -1
  137. package/dist/tui/config-wizard/step-defaults.d.ts.map +1 -1
  138. package/dist/tui/config-wizard/step-defaults.js +21 -17
  139. package/dist/tui/config-wizard/step-defaults.js.map +1 -1
  140. package/dist/tui/config-wizard/step-endpoints.d.ts.map +1 -1
  141. package/dist/tui/config-wizard/step-endpoints.js +16 -6
  142. package/dist/tui/config-wizard/step-endpoints.js.map +1 -1
  143. package/dist/tui/config-wizard/step-mcp.d.ts.map +1 -1
  144. package/dist/tui/config-wizard/step-mcp.js +17 -19
  145. package/dist/tui/config-wizard/step-mcp.js.map +1 -1
  146. package/dist/tui/config-wizard/step-models.d.ts.map +1 -1
  147. package/dist/tui/config-wizard/step-models.js +41 -26
  148. package/dist/tui/config-wizard/step-models.js.map +1 -1
  149. package/dist/tui/config-wizard/step-new-endpoint.d.ts.map +1 -1
  150. package/dist/tui/config-wizard/step-new-endpoint.js +16 -12
  151. package/dist/tui/config-wizard/step-new-endpoint.js.map +1 -1
  152. package/dist/tui/config-wizard/step-simple.d.ts.map +1 -1
  153. package/dist/tui/config-wizard/step-simple.js +18 -17
  154. package/dist/tui/config-wizard/step-simple.js.map +1 -1
  155. package/dist/tui/index.d.ts +17 -1
  156. package/dist/tui/index.d.ts.map +1 -1
  157. package/dist/tui/index.js +25 -14
  158. package/dist/tui/index.js.map +1 -1
  159. package/dist/tui/input-editing.d.ts +4 -1
  160. package/dist/tui/input-editing.d.ts.map +1 -1
  161. package/dist/tui/input-editing.js +7 -3
  162. package/dist/tui/input-editing.js.map +1 -1
  163. package/dist/tui/phase.d.ts +64 -0
  164. package/dist/tui/phase.d.ts.map +1 -0
  165. package/dist/tui/phase.js +112 -0
  166. package/dist/tui/phase.js.map +1 -0
  167. package/dist/tui/screens/chat-commands.d.ts +54 -3
  168. package/dist/tui/screens/chat-commands.d.ts.map +1 -1
  169. package/dist/tui/screens/chat-commands.js +469 -330
  170. package/dist/tui/screens/chat-commands.js.map +1 -1
  171. package/dist/tui/screens/chat.d.ts +8 -0
  172. package/dist/tui/screens/chat.d.ts.map +1 -1
  173. package/dist/tui/screens/chat.js +206 -405
  174. package/dist/tui/screens/chat.js.map +1 -1
  175. package/dist/tui/screens/common-keys.d.ts +36 -0
  176. package/dist/tui/screens/common-keys.d.ts.map +1 -0
  177. package/dist/tui/screens/common-keys.js +67 -0
  178. package/dist/tui/screens/common-keys.js.map +1 -0
  179. package/dist/tui/screens/handoff-choice.d.ts.map +1 -1
  180. package/dist/tui/screens/handoff-choice.js +4 -3
  181. package/dist/tui/screens/handoff-choice.js.map +1 -1
  182. package/dist/tui/screens/index.d.ts +1 -1
  183. package/dist/tui/screens/index.d.ts.map +1 -1
  184. package/dist/tui/screens/index.js +1 -1
  185. package/dist/tui/screens/index.js.map +1 -1
  186. package/dist/tui/screens/input-row.d.ts +64 -0
  187. package/dist/tui/screens/input-row.d.ts.map +1 -0
  188. package/dist/tui/screens/input-row.js +67 -0
  189. package/dist/tui/screens/input-row.js.map +1 -0
  190. package/dist/tui/screens/input.d.ts +11 -1
  191. package/dist/tui/screens/input.d.ts.map +1 -1
  192. package/dist/tui/screens/input.js +21 -12
  193. package/dist/tui/screens/input.js.map +1 -1
  194. package/dist/tui/screens/layout.d.ts +8 -0
  195. package/dist/tui/screens/layout.d.ts.map +1 -1
  196. package/dist/tui/screens/layout.js +6 -2
  197. package/dist/tui/screens/layout.js.map +1 -1
  198. package/dist/tui/screens/lines.d.ts.map +1 -1
  199. package/dist/tui/screens/lines.js +6 -6
  200. package/dist/tui/screens/lines.js.map +1 -1
  201. package/dist/tui/screens/messages-view.d.ts.map +1 -1
  202. package/dist/tui/screens/messages-view.js +5 -4
  203. package/dist/tui/screens/messages-view.js.map +1 -1
  204. package/dist/tui/screens/notice-bar.d.ts +5 -0
  205. package/dist/tui/screens/notice-bar.d.ts.map +1 -0
  206. package/dist/tui/screens/notice-bar.js +15 -0
  207. package/dist/tui/screens/notice-bar.js.map +1 -0
  208. package/dist/tui/screens/notice.d.ts +40 -8
  209. package/dist/tui/screens/notice.d.ts.map +1 -1
  210. package/dist/tui/screens/notice.js +75 -15
  211. package/dist/tui/screens/notice.js.map +1 -1
  212. package/dist/tui/screens/overlays.d.ts.map +1 -1
  213. package/dist/tui/screens/overlays.js +3 -2
  214. package/dist/tui/screens/overlays.js.map +1 -1
  215. package/dist/tui/screens/splash.d.ts +1 -1
  216. package/dist/tui/screens/splash.d.ts.map +1 -1
  217. package/dist/tui/screens/splash.js +5 -2
  218. package/dist/tui/screens/splash.js.map +1 -1
  219. package/dist/tui/screens/use-chat-viewport.d.ts +22 -0
  220. package/dist/tui/screens/use-chat-viewport.d.ts.map +1 -0
  221. package/dist/tui/screens/use-chat-viewport.js +50 -0
  222. package/dist/tui/screens/use-chat-viewport.js.map +1 -0
  223. package/dist/tui/screens/use-input-editing.d.ts +44 -0
  224. package/dist/tui/screens/use-input-editing.d.ts.map +1 -0
  225. package/dist/tui/screens/use-input-editing.js +192 -0
  226. package/dist/tui/screens/use-input-editing.js.map +1 -0
  227. package/dist/tui/screens/use-overlays.d.ts +25 -0
  228. package/dist/tui/screens/use-overlays.d.ts.map +1 -0
  229. package/dist/tui/screens/use-overlays.js +32 -0
  230. package/dist/tui/screens/use-overlays.js.map +1 -0
  231. package/dist/tui/screens/use-wizard-host.d.ts +35 -0
  232. package/dist/tui/screens/use-wizard-host.d.ts.map +1 -0
  233. package/dist/tui/screens/use-wizard-host.js +103 -0
  234. package/dist/tui/screens/use-wizard-host.js.map +1 -0
  235. package/dist/tui/status-segments.d.ts +37 -0
  236. package/dist/tui/status-segments.d.ts.map +1 -0
  237. package/dist/tui/status-segments.js +166 -0
  238. package/dist/tui/status-segments.js.map +1 -0
  239. package/dist/tui/text.d.ts +8 -5
  240. package/dist/tui/text.d.ts.map +1 -1
  241. package/dist/tui/text.js +95 -35
  242. package/dist/tui/text.js.map +1 -1
  243. package/dist/tui/token-rate.d.ts +83 -0
  244. package/dist/tui/token-rate.d.ts.map +1 -0
  245. package/dist/tui/token-rate.js +195 -0
  246. package/dist/tui/token-rate.js.map +1 -0
  247. package/dist/types.d.ts +0 -3
  248. package/dist/types.d.ts.map +1 -1
  249. package/package.json +4 -3
@@ -1,38 +1,78 @@
1
1
  import { agentKindLabel, agentList } from "../../agents-store.js";
2
- import { findEndpoint, findModel, formatAgentPermission, formatArgs, getAgentPrompt, kvSummary, maskApiKey, mcpServerIdTaken, parseArgs, parsePermission, PERMISSION_DIMENSIONS, renameMcpServer, setAgentPermission, summarizePermissions, updateAgentDefinition, updateAgentFunction, updateEndpoint, updateImageModel, updateMcpServer, updateModel } from "../../config-editor.js";
2
+ import { findEndpoint, findModel, formatAgentPermission, formatArgs, getAgentPrompt, kvSummary, maskApiKey, mcpServerIdTaken, mergeTokenThresholds, parseArgs, parsePermission, PERMISSION_DIMENSIONS, renameMcpServer, setAgentPermission, summarizePermissions, updateAgentDefinition, updateAgentFunction, updateEndpoint, updateImageModel, updateMcpServer, updateModel } from "../../config-editor.js";
3
+ import { t } from "../../i18n/index.js";
3
4
  import { scopeLabel } from "./mcp-helpers.js";
5
+ /**
6
+ * 权限四维的显示名。
7
+ *
8
+ * 维度名(`tools` / `skills` / …)是配置里的键,直接上屏等于把内部标识暴露给用户;
9
+ * 这里映射到词条,`Record<PermissionDimension, …>` 保证四个维度都有对应文案。
10
+ */
11
+ const PERMISSION_DIMENSION_LABEL_KEY = {
12
+ tools: "perm.tools",
13
+ skills: "perm.skills",
14
+ mcps: "perm.mcps",
15
+ subagents: "perm.subagents",
16
+ };
4
17
  // 由 src/tui/config-wizard.tsx 拆分而来 —— 详情屏字段构造器(工厂)
5
18
  /** 多行文本在详情屏的**单行摘要**(避免换行撑破吸底布局);内容一律走外部编辑器编辑 */
6
19
  function summarizeMultiline(text) {
7
20
  const body = text.replace(/\r\n/g, "\n").trim();
8
21
  if (!body)
9
- return "(空)· Enter 打开编辑器";
22
+ return t("common.emptyWithEditor");
10
23
  const lines = body.split("\n");
11
- return lines.length > 1 ? `${lines.length} 行 · Enter 打开编辑器` : `${body} · Enter 打开编辑器`;
24
+ return lines.length > 1
25
+ ? t("common.linesWithEditor", { n: lines.length })
26
+ : t("common.bodyWithEditor", { text: body });
12
27
  }
13
28
  export function createFieldBuilders(context) {
14
29
  const { config, mcp, store, reasoningPresets, persist, persistMcp, saveAgent, removeAgentQuiet, go } = context;
15
- // ---------- 字段构造器 ----------
30
+ // ---------- 共享字段 ----------
31
+ /**
32
+ * 「名称」字段:端点 / 模型 / 图片模型三处的形状逐字相同,只有写回目标不同。
33
+ * 空名称一律拦下 —— 名称会进提示语与列表,写空等于把这一条「弄丢」。
34
+ */
35
+ const nameField = (current, save) => ({
36
+ key: "name",
37
+ label: t("field.name"),
38
+ kind: "text",
39
+ value: current.name || current.id,
40
+ initial: current.name,
41
+ commit: (raw) => (raw.trim() ? save({ name: raw.trim() }, t("field.name")) : t("err.nameRequired")),
42
+ });
43
+ /** 「绑定端点」字段:模型 / 图片模型共用,选项是全局端点表 */
44
+ const endpointIdField = (currentEndpointId, save) => ({
45
+ key: "endpointId",
46
+ label: t("field.endpoint"),
47
+ kind: "enum",
48
+ value: findEndpoint(config, currentEndpointId)?.name ?? currentEndpointId,
49
+ options: config.endpoints.map((endpoint) => ({ label: endpoint.name || endpoint.id, value: endpoint.id })),
50
+ // 选回原端点不算改动:否则会白白写盘一次
51
+ commit: (raw) => (raw === currentEndpointId ? null : save({ endpointId: raw }, t("field.endpoint"))),
52
+ });
53
+ /**
54
+ * 出厂托管条目的改动标记。
55
+ *
56
+ * 托管条目由 SDK 同步维护,**任何本地改动都必须打成 `custom: true`**,否则下次
57
+ * 同步会把改动覆盖掉。提示语后缀同步告知用户这一后果。
58
+ */
59
+ const customPatch = (entity, patch) => entity.custom ? patch : { ...patch, custom: true };
60
+ /** 同上,用于「整份定义」写回(如 Agent 定义):返回完整对象 */
61
+ const markCustom = (entity) => entity.custom ? entity : { ...entity, custom: true };
62
+ const customNote = (managed) => (managed ? t("common.customOnlyNote") : "");
16
63
  /** 端点详情字段(editable:名称 / Base URL / API Key / 描述) */
17
64
  const endpointFields = (endpoint) => {
18
65
  const name = endpoint.name || endpoint.id;
19
- const save = (patch, label) => persist(updateEndpoint(config, endpoint.id, patch), `端点 ${name} 的 ${label} 已更新`, [endpoint.id]);
66
+ const save = (patch, label) => persist(updateEndpoint(config, endpoint.id, patch), t("wiz.endpointUpdated", { name, label }), [endpoint.id]);
20
67
  return [
21
- {
22
- key: "name",
23
- label: "名称",
24
- kind: "text",
25
- value: name,
26
- initial: endpoint.name,
27
- commit: (raw) => (raw.trim() ? save({ name: raw.trim() }, "名称") : Promise.resolve("名称不能为空")),
28
- },
68
+ nameField(endpoint, save),
29
69
  {
30
70
  key: "baseUrl",
31
71
  label: "Base URL",
32
72
  kind: "text",
33
73
  value: endpoint.baseUrl,
34
74
  initial: endpoint.baseUrl,
35
- commit: (raw) => /^https?:\/\//i.test(raw) ? save({ baseUrl: raw }, "Base URL") : Promise.resolve("Base URL 需以 http:// 或 https:// 开头"),
75
+ commit: (raw) => /^https?:\/\//i.test(raw) ? save({ baseUrl: raw }, "Base URL") : t("err.baseUrlScheme"),
36
76
  },
37
77
  {
38
78
  key: "apiKey",
@@ -40,217 +80,189 @@ export function createFieldBuilders(context) {
40
80
  kind: "secret",
41
81
  value: maskApiKey(endpoint.apiKey),
42
82
  initial: endpoint.apiKey ?? "",
43
- commit: (raw) => (raw ? save({ apiKey: raw }, "API Key") : Promise.resolve("API Key 不能为空")),
83
+ commit: (raw) => (raw ? save({ apiKey: raw }, "API Key") : t("err.apiKeyRequired")),
44
84
  },
45
85
  {
46
86
  key: "description",
47
- label: "描述",
87
+ label: t("field.description"),
48
88
  kind: "text",
49
- value: endpoint.description ?? "(空)",
89
+ value: endpoint.description ?? t("common.empty"),
50
90
  initial: endpoint.description ?? "",
51
- commit: (raw) => save({ description: raw || undefined }, "描述"),
91
+ commit: (raw) => save({ description: raw || undefined }, t("field.description")),
52
92
  },
53
93
  ];
54
94
  };
55
95
  /** 模型详情页「思考策略」的展示文案:附上该策略的档位,免得用户还得去翻 JSON */
56
96
  const describePreset = (name) => {
57
97
  if (!name)
58
- return "(不调档)";
98
+ return t("common.notAdjustable");
59
99
  const preset = Object.prototype.hasOwnProperty.call(reasoningPresets, name)
60
100
  ? reasoningPresets[name]
61
101
  : undefined;
62
102
  const levels = Object.keys(preset?.levels ?? {});
63
- return levels.length ? `${name}(${levels.join(" / ")})` : `${name}(策略不存在)`;
103
+ return levels.length
104
+ ? t("wiz.presetLevels", { name, levels: levels.join(" / ") })
105
+ : t("wiz.presetMissingName", { name });
64
106
  };
65
107
  /** 模型详情字段;编辑「出厂托管」模型时自动标记 `custom: true`(否则改动会被 SDK 同步覆盖) */
66
108
  const modelFields = (model) => {
67
109
  const managed = !model.custom;
68
- const save = (patch, label) => {
69
- const next = updateModel(config, model.id, managed ? { ...patch, custom: true } : patch);
70
- const suffix = managed ? "(已标记为自定义,改动才会保留)" : "";
71
- return persist(next, `模型 ${model.name || model.id} 的 ${label} 已更新${suffix}`, [model.endpointId]);
72
- };
110
+ const save = (patch, label) => persist(updateModel(config, model.id, customPatch(model, patch)), t("wiz.modelUpdated", { name: model.name || model.id, label, suffix: customNote(managed) }), [model.endpointId]);
73
111
  return [
74
- {
75
- key: "name",
76
- label: "名称",
77
- kind: "text",
78
- value: model.name || model.id,
79
- initial: model.name,
80
- commit: (raw) => (raw.trim() ? save({ name: raw.trim() }, "名称") : Promise.resolve("名称不能为空")),
81
- },
82
- {
83
- key: "endpointId",
84
- label: "端点",
85
- kind: "enum",
86
- value: findEndpoint(config, model.endpointId)?.name ?? model.endpointId,
87
- options: config.endpoints.map((endpoint) => ({ label: endpoint.name || endpoint.id, value: endpoint.id })),
88
- commit: (raw) => (raw === model.endpointId ? Promise.resolve(null) : save({ endpointId: raw }, "端点")),
89
- },
112
+ nameField(model, save),
113
+ endpointIdField(model.endpointId, save),
90
114
  {
91
115
  key: "modelName",
92
- label: "模型名",
116
+ label: t("field.modelName"),
93
117
  kind: "text",
94
- value: model.modelName ?? "(同 id)",
118
+ value: model.modelName ?? t("common.sameAsId"),
95
119
  initial: model.modelName ?? "",
96
- commit: (raw) => save({ modelName: raw || undefined }, "模型名"),
120
+ commit: (raw) => save({ modelName: raw || undefined }, t("field.modelName")),
97
121
  },
98
122
  {
99
123
  key: "reasoningPreset",
100
- label: "思考策略",
124
+ label: t("field.reasoningPreset"),
101
125
  kind: "text",
102
126
  value: describePreset(model.reasoningPreset),
103
127
  initial: model.reasoningPreset ?? "",
104
128
  commit: (raw) => {
105
129
  const name = raw.trim();
106
130
  if (!name)
107
- return save({ reasoningPreset: undefined }, "思考策略");
131
+ return save({ reasoningPreset: undefined }, t("field.reasoningPreset"));
108
132
  // 名字写错等于静默失去调档能力,当场拦住
109
133
  if (!Object.prototype.hasOwnProperty.call(reasoningPresets, name)) {
110
134
  const available = Object.keys(reasoningPresets);
111
- return Promise.resolve(available.length
112
- ? `策略 "${name}" 不存在(可选:${available.join(" / ")})`
113
- : `策略 "${name}" 不存在(策略表为空,见 reasoning-presets.json)`);
135
+ return available.length
136
+ ? t("err.presetNotFound", { name, options: available.join(" / ") })
137
+ : t("err.presetTableEmpty", { name });
114
138
  }
115
- return save({ reasoningPreset: name }, "思考策略");
139
+ return save({ reasoningPreset: name }, t("field.reasoningPreset"));
116
140
  },
117
141
  },
118
142
  {
119
143
  key: "handoffTokens",
120
- label: "交接阈值",
144
+ label: t("field.handoffThreshold"),
121
145
  kind: "number",
122
146
  value: String(model.tokenThresholds?.handoff ?? 0),
123
147
  initial: String(model.tokenThresholds?.handoff ?? 0),
124
148
  commit: (raw) => {
125
149
  const n = Number(raw.trim());
126
150
  if (!Number.isFinite(n) || n <= 0)
127
- return Promise.resolve("交接阈值需为正整数");
151
+ return t("err.handoffPositive");
128
152
  const guard = model.tokenThresholds?.guard ?? 0;
129
153
  // 软线不得越过硬线,否则一启动就被阻断
130
154
  if (guard > 0 && Math.floor(n) >= guard)
131
- return Promise.resolve("交接阈值需小于阻断阈值");
132
- return save({ tokenThresholds: { handoff: Math.floor(n), guard } }, "交接阈值");
155
+ return t("err.handoffLessThanGuard");
156
+ return save({ tokenThresholds: mergeTokenThresholds(model.tokenThresholds, { handoff: Math.floor(n) }) }, t("field.handoffThreshold"));
133
157
  },
134
158
  },
135
159
  {
136
160
  key: "guardTokens",
137
- label: "阻断阈值",
161
+ label: t("field.guardThreshold"),
138
162
  kind: "number",
139
163
  value: String(model.tokenThresholds?.guard ?? 0),
140
164
  initial: String(model.tokenThresholds?.guard ?? 0),
141
165
  commit: (raw) => {
142
166
  const n = Number(raw.trim());
143
167
  if (!Number.isFinite(n) || n <= 0)
144
- return Promise.resolve("阻断阈值需为正整数");
168
+ return t("err.guardPositive");
145
169
  const handoff = model.tokenThresholds?.handoff ?? 0;
146
170
  if (Math.floor(n) <= handoff)
147
- return Promise.resolve("阻断阈值需大于交接阈值");
148
- return save({ tokenThresholds: { handoff, guard: Math.floor(n) } }, "阻断阈值");
171
+ return t("err.guardGreaterThanHandoff");
172
+ return save({ tokenThresholds: mergeTokenThresholds(model.tokenThresholds, { guard: Math.floor(n) }) }, t("field.guardThreshold"));
149
173
  },
150
174
  },
151
175
  {
152
176
  key: "vision",
153
- label: "视觉",
177
+ label: t("field.vision"),
154
178
  kind: "bool",
155
- value: model.vision ? "是" : "否",
156
- toggle: () => save({ vision: !model.vision }, "视觉"),
179
+ value: model.vision ? t("common.yes") : t("common.no"),
180
+ toggle: () => save({ vision: !model.vision }, t("field.vision")),
157
181
  },
158
182
  {
159
183
  key: "description",
160
- label: "描述",
184
+ label: t("field.description"),
161
185
  kind: "text",
162
- value: model.description ?? "(空)",
186
+ value: model.description ?? t("common.empty"),
163
187
  initial: model.description ?? "",
164
- commit: (raw) => save({ description: raw || undefined }, "描述"),
188
+ commit: (raw) => save({ description: raw || undefined }, t("field.description")),
165
189
  },
166
190
  {
167
191
  key: "custom",
168
- label: "自定义",
192
+ label: t("field.custom"),
169
193
  kind: "bool",
170
- value: model.custom ? "是" : "否(出厂托管)",
171
- toggle: () => persist(updateModel(config, model.id, { custom: !model.custom }), `模型 ${model.name || model.id} 的「自定义」已设为 ${!model.custom ? "是" : "否"}`, [model.endpointId]),
194
+ value: model.custom ? t("common.yes") : t("common.factoryManaged"),
195
+ toggle: () => persist(updateModel(config, model.id, { custom: !model.custom }), t("wiz.modelCustomSet", {
196
+ name: model.name || model.id,
197
+ value: !model.custom ? t("common.yes") : t("common.no"),
198
+ }), [model.endpointId]),
172
199
  },
173
200
  ];
174
201
  };
175
202
  /** 图片模型详情字段(同样对托管条目自动标记 `custom: true`) */
176
203
  const imageModelFields = (model) => {
177
204
  const managed = !model.custom;
178
- const save = (patch, label) => {
179
- const next = updateImageModel(config, model.id, managed ? { ...patch, custom: true } : patch);
180
- const suffix = managed ? "(已标记为自定义,改动才会保留)" : "";
181
- return persist(next, `图片模型 ${model.name || model.id} 的 ${label} 已更新${suffix}`, [model.endpointId]);
182
- };
205
+ const save = (patch, label) => persist(updateImageModel(config, model.id, customPatch(model, patch)), t("wiz.imageModelUpdated", { name: model.name || model.id, label, suffix: customNote(managed) }), [model.endpointId]);
183
206
  return [
184
- {
185
- key: "name",
186
- label: "名称",
187
- kind: "text",
188
- value: model.name || model.id,
189
- initial: model.name,
190
- commit: (raw) => (raw.trim() ? save({ name: raw.trim() }, "名称") : Promise.resolve("名称不能为空")),
191
- },
192
- {
193
- key: "endpointId",
194
- label: "端点",
195
- kind: "enum",
196
- value: findEndpoint(config, model.endpointId)?.name ?? model.endpointId,
197
- options: config.endpoints.map((endpoint) => ({ label: endpoint.name || endpoint.id, value: endpoint.id })),
198
- commit: (raw) => (raw === model.endpointId ? Promise.resolve(null) : save({ endpointId: raw }, "端点")),
199
- },
207
+ nameField(model, save),
208
+ endpointIdField(model.endpointId, save),
200
209
  {
201
210
  key: "modelName",
202
- label: "模型名",
211
+ label: t("field.modelName"),
203
212
  kind: "text",
204
213
  value: model.modelName,
205
214
  initial: model.modelName,
206
- commit: (raw) => (raw.trim() ? save({ modelName: raw.trim() }, "模型名") : Promise.resolve("模型名不能为空")),
215
+ commit: (raw) => (raw.trim() ? save({ modelName: raw.trim() }, t("field.modelName")) : t("err.modelNameRequired")),
207
216
  },
208
217
  {
209
218
  key: "defaultSize",
210
- label: "尺寸",
219
+ label: t("field.size"),
211
220
  kind: "text",
212
- value: model.defaultSize ?? "(默认)",
221
+ value: model.defaultSize ?? t("common.defaultInParens"),
213
222
  initial: model.defaultSize ?? "",
214
- commit: (raw) => save({ defaultSize: raw || undefined }, "尺寸"),
223
+ commit: (raw) => save({ defaultSize: raw || undefined }, t("field.size")),
215
224
  },
216
225
  {
217
226
  key: "defaultQuality",
218
- label: "质量",
227
+ label: t("field.quality"),
219
228
  kind: "text",
220
- value: model.defaultQuality ?? "(默认)",
229
+ value: model.defaultQuality ?? t("common.defaultInParens"),
221
230
  initial: model.defaultQuality ?? "",
222
- commit: (raw) => save({ defaultQuality: raw || undefined }, "质量"),
231
+ commit: (raw) => save({ defaultQuality: raw || undefined }, t("field.quality")),
223
232
  },
224
233
  {
225
234
  key: "custom",
226
- label: "自定义",
235
+ label: t("field.custom"),
227
236
  kind: "bool",
228
- value: model.custom ? "是" : "否(出厂托管)",
229
- toggle: () => persist(updateImageModel(config, model.id, { custom: !model.custom }), `图片模型 ${model.name || model.id} 的「自定义」已设为 ${!model.custom ? "是" : "否"}`, [model.endpointId]),
237
+ value: model.custom ? t("common.yes") : t("common.factoryManaged"),
238
+ toggle: () => persist(updateImageModel(config, model.id, { custom: !model.custom }), t("wiz.imageModelCustomSet", {
239
+ name: model.name || model.id,
240
+ value: !model.custom ? t("common.yes") : t("common.no"),
241
+ }), [model.endpointId]),
230
242
  },
231
243
  ];
232
244
  };
233
245
  /** MCP 服务器详情字段(依 transport 呈现 stdio 或 http/sse 字段) */
234
246
  const mcpServerFields = (scope, id, entry) => {
235
247
  const scopeName = scopeLabel(scope);
236
- const save = (patch, label) => persistMcp(scope, updateMcpServer(mcp[scope], id, patch), `MCP ${id} 的${label}已更新(${scopeName})`);
248
+ const save = (patch, label) => persistMcp(scope, updateMcpServer(mcp[scope], id, patch), t("wiz.mcpFieldUpdated", { id, label, scope: scopeName }));
237
249
  const type = entry.type ?? "stdio";
238
250
  const fields = [
239
251
  {
240
252
  key: "id",
241
- label: "名称",
253
+ label: t("field.name"),
242
254
  kind: "text",
243
255
  value: id,
244
256
  initial: id,
245
257
  commit: (raw) => {
246
258
  const name = raw.trim();
247
259
  if (!name)
248
- return Promise.resolve("名称不能为空");
260
+ return t("err.nameRequired");
249
261
  if (name === id)
250
- return Promise.resolve(null);
262
+ return null;
251
263
  if (mcpServerIdTaken(mcp[scope], name, id))
252
- return Promise.resolve(`已存在名为 ${name} 的服务器`);
253
- return persistMcp(scope, renameMcpServer(mcp[scope], id, name), `MCP ${id} 已重命名为 ${name}(${scopeName})`).then((failure) => {
264
+ return t("err.mcpNameTaken", { name });
265
+ return persistMcp(scope, renameMcpServer(mcp[scope], id, name), t("wiz.mcpRenamed", { id, name, scope: scopeName })).then((failure) => {
254
266
  if (!failure)
255
267
  go({ kind: "mcp-server", scope, serverId: name });
256
268
  return failure;
@@ -259,54 +271,54 @@ export function createFieldBuilders(context) {
259
271
  },
260
272
  {
261
273
  key: "type",
262
- label: "传输",
274
+ label: t("field.transport"),
263
275
  kind: "enum",
264
276
  value: type,
265
277
  options: [
266
- { label: "stdio(本地子进程)", value: "stdio" },
267
- { label: "http(Streamable HTTP)", value: "http" },
268
- { label: "sse(Server-Sent Events)", value: "sse" },
278
+ { label: t("common.transportStdio"), value: "stdio" },
279
+ { label: t("common.transportHttp"), value: "http" },
280
+ { label: t("common.transportSse"), value: "sse" },
269
281
  ],
270
- commit: (raw) => raw === type ? Promise.resolve(null) : save({ type: raw }, "传输方式"),
282
+ commit: (raw) => raw === type ? null : save({ type: raw }, t("common.transportMode")),
271
283
  },
272
284
  {
273
285
  key: "enabled",
274
- label: "启用",
286
+ label: t("field.enabled"),
275
287
  kind: "bool",
276
- value: entry.disabled === true ? "否(已禁用)" : "是",
277
- toggle: () => save({ disabled: entry.disabled === true ? undefined : true }, "启用状态"),
288
+ value: entry.disabled === true ? t("common.disabledInParens") : t("common.yes"),
289
+ toggle: () => save({ disabled: entry.disabled === true ? undefined : true }, t("common.enabledState")),
278
290
  },
279
291
  {
280
292
  key: "description",
281
- label: "描述",
293
+ label: t("field.description"),
282
294
  kind: "text",
283
- value: entry.description ?? "(空)",
295
+ value: entry.description ?? t("common.empty"),
284
296
  initial: entry.description ?? "",
285
- commit: (raw) => save({ description: raw.trim() || undefined }, "描述"),
297
+ commit: (raw) => save({ description: raw.trim() || undefined }, t("field.description")),
286
298
  },
287
299
  ];
288
300
  if (type === "stdio") {
289
301
  fields.push({
290
302
  key: "command",
291
- label: "命令",
303
+ label: t("field.command"),
292
304
  kind: "text",
293
- value: entry.command ?? "(空)",
305
+ value: entry.command ?? t("common.empty"),
294
306
  initial: entry.command ?? "",
295
- commit: (raw) => save({ command: raw.trim() || undefined }, "命令"),
307
+ commit: (raw) => save({ command: raw.trim() || undefined }, t("field.command")),
296
308
  }, {
297
309
  key: "args",
298
- label: "参数",
310
+ label: t("field.args"),
299
311
  kind: "text",
300
- value: formatArgs(entry.args) || "(空)",
312
+ value: formatArgs(entry.args) || t("common.empty"),
301
313
  initial: formatArgs(entry.args),
302
314
  commit: (raw) => {
303
315
  const args = parseArgs(raw.trim());
304
- return save({ args: args.length ? args : undefined }, "参数");
316
+ return save({ args: args.length ? args : undefined }, t("field.args"));
305
317
  },
306
318
  }, {
307
319
  key: "env",
308
- label: "环境变量",
309
- kind: "map",
320
+ label: t("field.env"),
321
+ kind: "open",
310
322
  value: kvSummary(entry.env),
311
323
  open: () => go({ kind: "mcp-kv", scope, serverId: id, field: "env" }),
312
324
  });
@@ -316,13 +328,13 @@ export function createFieldBuilders(context) {
316
328
  key: "url",
317
329
  label: "URL",
318
330
  kind: "text",
319
- value: entry.url ?? "(空)",
331
+ value: entry.url ?? t("common.empty"),
320
332
  initial: entry.url ?? "",
321
333
  commit: (raw) => save({ url: raw.trim() || undefined }, "URL"),
322
334
  }, {
323
335
  key: "headers",
324
- label: "请求头",
325
- kind: "map",
336
+ label: t("field.headers"),
337
+ kind: "open",
326
338
  value: kvSummary(entry.headers),
327
339
  open: () => go({ kind: "mcp-kv", scope, serverId: id, field: "headers" }),
328
340
  });
@@ -334,37 +346,37 @@ export function createFieldBuilders(context) {
334
346
  const kindName = agentKindLabel(kind);
335
347
  const managed = kind === "agent" && !def.custom;
336
348
  const save = (nextDef, label) => {
337
- const marked = managed ? { ...nextDef, custom: true } : nextDef;
338
- const suffix = managed ? "(已标记为自定义,改动才会保留)" : "";
339
- return saveAgent(kind, marked, `${kindName} ${def.id} 的 ${label} 已更新${suffix}`);
349
+ const marked = markCustom(nextDef);
350
+ const suffix = customNote(managed);
351
+ return saveAgent(kind, marked, t("wiz.agentFieldUpdated", { kind: kindName, id: def.id, label, suffix }));
340
352
  };
341
353
  const fields = [
342
354
  {
343
355
  key: "name",
344
- label: "名称",
356
+ label: t("field.name"),
345
357
  kind: "text",
346
358
  value: def.name || def.id,
347
359
  initial: def.name,
348
360
  commit: (raw) => raw.trim()
349
- ? save(updateAgentDefinition(def, { name: raw.trim() }), "名称")
350
- : Promise.resolve("名称不能为空"),
361
+ ? save(updateAgentDefinition(def, { name: raw.trim() }), t("field.name"))
362
+ : t("err.nameRequired"),
351
363
  },
352
364
  {
353
365
  key: "id",
354
- label: "标识",
366
+ label: t("field.id"),
355
367
  kind: "text",
356
368
  value: def.id,
357
369
  initial: def.id,
358
370
  commit: (raw) => {
359
371
  const name = raw.trim();
360
372
  if (!name)
361
- return Promise.resolve("标识不能为空");
373
+ return t("err.idRequired");
362
374
  if (name === def.id)
363
- return Promise.resolve(null);
375
+ return null;
364
376
  if (agentList(store, kind).some((item) => item.id === name))
365
- return Promise.resolve(`已存在标识 ${name} 的定义`);
377
+ return t("err.agentIdTaken", { name });
366
378
  return (async () => {
367
- const failure = await saveAgent(kind, { ...def, id: name }, `${kindName} ${def.id} 已重命名为 ${name}`);
379
+ const failure = await saveAgent(kind, { ...def, id: name }, t("wiz.agentRenamed", { kind: kindName, id: def.id, name }));
368
380
  if (failure)
369
381
  return failure;
370
382
  await removeAgentQuiet(kind, def.id);
@@ -375,34 +387,34 @@ export function createFieldBuilders(context) {
375
387
  },
376
388
  {
377
389
  key: "description",
378
- label: "描述",
390
+ label: t("field.description"),
379
391
  kind: "text",
380
- value: def.description ?? "(空)",
392
+ value: def.description ?? t("common.empty"),
381
393
  initial: def.description ?? "",
382
- commit: (raw) => save(updateAgentDefinition(def, { description: raw.trim() || undefined }), "描述"),
394
+ commit: (raw) => save(updateAgentDefinition(def, { description: raw.trim() || undefined }), t("field.description")),
383
395
  },
384
396
  {
385
397
  key: "modelId",
386
- label: "模型",
398
+ label: t("field.model"),
387
399
  kind: "enum",
388
- value: findModel(config, def.modelId)?.name ?? def.modelId ?? "(未设置)",
400
+ value: findModel(config, def.modelId)?.name ?? def.modelId ?? t("common.unset"),
389
401
  options: [
390
402
  ...config.models.map((model) => ({ label: model.name || model.id, value: model.id })),
391
- { label: "(未设置)", value: "" },
403
+ { label: t("common.unset"), value: "" },
392
404
  ],
393
- commit: (raw) => save(updateAgentDefinition(def, { modelId: raw || undefined }), "模型"),
405
+ commit: (raw) => save(updateAgentDefinition(def, { modelId: raw || undefined }), t("field.model")),
394
406
  },
395
407
  {
396
408
  key: "prompt",
397
- label: "提示词",
398
- kind: "map",
409
+ label: t("field.prompt"),
410
+ kind: "open",
399
411
  value: summarizeMultiline(getAgentPrompt(def)),
400
412
  open: () => go({ kind: "agent-text", agentKind: kind, agentId: def.id, field: "prompt" }),
401
413
  },
402
414
  {
403
415
  key: "permissions",
404
- label: "权限",
405
- kind: "map",
416
+ label: t("field.permissions"),
417
+ kind: "open",
406
418
  value: summarizePermissions(def.permissions),
407
419
  open: () => go({ kind: "agent-perms", agentKind: kind, agentId: def.id }),
408
420
  },
@@ -410,32 +422,32 @@ export function createFieldBuilders(context) {
410
422
  if (kind === "agent") {
411
423
  fields.push({
412
424
  key: "custom",
413
- label: "自定义",
425
+ label: t("field.custom"),
414
426
  kind: "bool",
415
- value: def.custom ? "是" : "否(出厂托管)",
416
- toggle: () => save(updateAgentDefinition(def, { custom: !def.custom }), "「自定义」"),
427
+ value: def.custom ? t("common.yes") : t("common.factoryManaged"),
428
+ toggle: () => save(updateAgentDefinition(def, { custom: !def.custom }), t("common.customQuoted")),
417
429
  });
418
430
  }
419
431
  else {
420
432
  fields.push({
421
433
  key: "fnName",
422
- label: "函数名",
434
+ label: t("field.functionName"),
423
435
  kind: "text",
424
- value: def.function?.name ?? "(空)",
436
+ value: def.function?.name ?? t("common.empty"),
425
437
  initial: def.function?.name ?? "",
426
438
  commit: (raw) => raw.trim()
427
- ? save(updateAgentFunction(def, { name: raw.trim() }), "函数名")
428
- : Promise.resolve("函数名不能为空"),
439
+ ? save(updateAgentFunction(def, { name: raw.trim() }), t("field.functionName"))
440
+ : t("err.functionNameRequired"),
429
441
  }, {
430
442
  key: "fnDesc",
431
- label: "函数说明",
432
- kind: "map",
443
+ label: t("field.functionDescription"),
444
+ kind: "open",
433
445
  value: summarizeMultiline(def.function?.description ?? ""),
434
446
  open: () => go({ kind: "agent-text", agentKind: kind, agentId: def.id, field: "fnDesc" }),
435
447
  }, {
436
448
  key: "fnParams",
437
- label: "参数 schema",
438
- kind: "map",
449
+ label: t("field.paramsSchema"),
450
+ kind: "open",
439
451
  value: summarizeMultiline(JSON.stringify(def.function?.parameters ?? {}, null, 2)),
440
452
  open: () => go({ kind: "agent-text", agentKind: kind, agentId: def.id, field: "fnParams" }),
441
453
  });
@@ -445,17 +457,17 @@ export function createFieldBuilders(context) {
445
457
  /** 四维权限子屏字段(`allow: a, b` / `deny: x`;留空清除该维) */
446
458
  const agentPermFields = (kind, def) => PERMISSION_DIMENSIONS.map((dim) => ({
447
459
  key: dim,
448
- label: dim,
460
+ label: t(PERMISSION_DIMENSION_LABEL_KEY[dim]),
449
461
  kind: "text",
450
- value: formatAgentPermission(def.permissions, dim) || "(未设置)",
462
+ value: formatAgentPermission(def.permissions, dim) || t("common.unset"),
451
463
  initial: formatAgentPermission(def.permissions, dim),
452
464
  commit: (raw) => {
453
465
  const parsed = parsePermission(raw);
454
466
  if (typeof parsed === "string")
455
- return Promise.resolve(parsed);
467
+ return parsed;
456
468
  const managed = kind === "agent" && !def.custom;
457
469
  const next = setAgentPermission(managed ? { ...def, custom: true } : def, dim, parsed);
458
- return saveAgent(kind, next, `${agentKindLabel(kind)} ${def.id} 的 ${dim} 权限已更新`);
470
+ return saveAgent(kind, next, t("wiz.agentPermissionUpdated", { kind: agentKindLabel(kind), id: def.id, dim }));
459
471
  },
460
472
  }));
461
473
  return { endpointFields, modelFields, imageModelFields, mcpServerFields, agentFields, agentPermFields };