@chainingintention/pi-web-cn 1.202610.3 → 1.202610.4

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 (202) hide show
  1. package/README.md +1 -0
  2. package/dist/cli.js +129 -122
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client/assets/PiWebApp-CN3g7SqA.js +4362 -0
  5. package/dist/client/assets/external-DUGCSDhZ.js +2 -0
  6. package/dist/client/assets/index-JduZlbIF.js +2 -0
  7. package/dist/client/index.html +4 -4
  8. package/dist/client/manifest.webmanifest +2 -1
  9. package/dist/localization.js +24 -0
  10. package/dist/localization.js.map +1 -0
  11. package/dist/nativeServices/serviceDoctor.js +45 -44
  12. package/dist/nativeServices/serviceDoctor.js.map +1 -1
  13. package/dist/pi-packages/captains-log/dist/browser/index.js +46 -45
  14. package/dist/pi-packages/captains-log/dist/browser/markdown.js +2 -1
  15. package/dist/pi-packages/captains-log/dist/browser/panel.js +56 -55
  16. package/dist/pi-packages/captains-log/i18n.js +7 -0
  17. package/dist/pi-packages/relays/i18n.js +7 -0
  18. package/dist/pi-packages/relays/markdownDocument.js +2 -1
  19. package/dist/pi-packages/relays/pi-web-plugin.js +8 -6
  20. package/dist/pi-packages/relays/relaysPanelElement.js +24 -23
  21. package/dist/pi-web-plugins/files/browser/pi-web-plugin.js +124 -124
  22. package/dist/pi-web-plugins/git/browser/git-contract.js +13 -12
  23. package/dist/pi-web-plugins/git/browser/git-panel.js +25 -24
  24. package/dist/pi-web-plugins/git/browser/i18n.js +7 -0
  25. package/dist/pi-web-plugins/git/browser/pi-web-plugin.js +7 -3
  26. package/dist/pi-web-plugins/git/git-backend.js +10 -9
  27. package/dist/pi-web-plugins/git/i18n.js +7 -0
  28. package/dist/pi-web-plugins/git/server-plugin.js +21 -19
  29. package/dist/pi-web-plugins/info/i18n.js +7 -0
  30. package/dist/pi-web-plugins/info/infoInternals.js +57 -62
  31. package/dist/pi-web-plugins/info/pi-web-plugin.js +34 -36
  32. package/dist/pi-web-plugins/mermaid/browser/pi-web-plugin.js +3 -3
  33. package/dist/pi-web-plugins/terminal/browser/pi-web-plugin.js +55 -52
  34. package/dist/pi-web-plugins/terminal/i18n.js +7 -0
  35. package/dist/pi-web-plugins/terminal/server-plugin.js +23 -21
  36. package/dist/pi-web-plugins/terminal/terminalService.js +22 -21
  37. package/dist/pi-web-plugins/updates/i18n.js +7 -0
  38. package/dist/pi-web-plugins/updates/pi-web-plugin.js +58 -54
  39. package/dist/pi-web-plugins/updates/updatesLogic.js +21 -20
  40. package/dist/pi-web-plugins/workspace-tasks/config.js +12 -11
  41. package/dist/pi-web-plugins/workspace-tasks/i18n.js +7 -0
  42. package/dist/pi-web-plugins/workspace-tasks/pi-web-plugin.js +8 -6
  43. package/dist/pi-web-plugins/workspace-tasks/tasksPanelElement.js +20 -19
  44. package/dist/pi-web-plugins/workspace-tasks/workspaceTasksClient.js +12 -11
  45. package/dist/pi-web-plugins/zh-cn/auth.json +9 -0
  46. package/dist/pi-web-plugins/zh-cn/bundled.json +176 -0
  47. package/dist/pi-web-plugins/zh-cn/cli.json +171 -0
  48. package/dist/pi-web-plugins/zh-cn/client.json +219 -0
  49. package/dist/pi-web-plugins/zh-cn/components.json +1002 -0
  50. package/dist/pi-web-plugins/zh-cn/config-errors.json +172 -0
  51. package/dist/pi-web-plugins/zh-cn/files.json +41 -0
  52. package/dist/pi-web-plugins/zh-cn/machines.json +28 -0
  53. package/dist/pi-web-plugins/zh-cn/main.json +459 -0
  54. package/dist/pi-web-plugins/zh-cn/management-errors.json +23 -0
  55. package/dist/pi-web-plugins/zh-cn/manifest.webmanifest +25 -0
  56. package/dist/pi-web-plugins/zh-cn/metadata.json +3 -0
  57. package/dist/pi-web-plugins/zh-cn/package.json +10 -0
  58. package/dist/pi-web-plugins/zh-cn/pi-web-plugin.js +16 -0
  59. package/dist/pi-web-plugins/zh-cn/projects.json +6 -0
  60. package/dist/pi-web-plugins/zh-cn/provider-auth.json +17 -0
  61. package/dist/pi-web-plugins/zh-cn/routing.json +68 -0
  62. package/dist/pi-web-plugins/zh-cn/server-main.json +99 -0
  63. package/dist/pi-web-plugins/zh-cn/server.json +174 -0
  64. package/dist/piWebVersionReport.js +17 -16
  65. package/dist/piWebVersionReport.js.map +1 -1
  66. package/dist/plugin-api.d.ts +4 -1
  67. package/dist/pluginRecoveryCli.js +25 -24
  68. package/dist/pluginRecoveryCli.js.map +1 -1
  69. package/dist/server/app.js +43 -28
  70. package/dist/server/app.js.map +1 -1
  71. package/dist/server/audit/normalToolAuditCli.js +45 -43
  72. package/dist/server/audit/normalToolAuditCli.js.map +1 -1
  73. package/dist/server/configRoutes.js +39 -30
  74. package/dist/server/configRoutes.js.map +1 -1
  75. package/dist/server/diagnostics/nodePtyNativeModule.js +7 -6
  76. package/dist/server/diagnostics/nodePtyNativeModule.js.map +1 -1
  77. package/dist/server/diagnostics/nodePtySpawnHelper.js +21 -20
  78. package/dist/server/diagnostics/nodePtySpawnHelper.js.map +1 -1
  79. package/dist/server/knownAutoInstallPiPackages.js +2 -2
  80. package/dist/server/knownAutoInstallPiPackages.js.map +1 -1
  81. package/dist/server/knownPiPackages.js +2 -2
  82. package/dist/server/knownPiPackages.js.map +1 -1
  83. package/dist/server/machines/machineClient.js +8 -6
  84. package/dist/server/machines/machineClient.js.map +1 -1
  85. package/dist/server/machines/machinePluginProxyRoutes.js +11 -10
  86. package/dist/server/machines/machinePluginProxyRoutes.js.map +1 -1
  87. package/dist/server/machines/machineProxyRoutes.js +27 -29
  88. package/dist/server/machines/machineProxyRoutes.js.map +1 -1
  89. package/dist/server/machines/machineRoutes.js +10 -12
  90. package/dist/server/machines/machineRoutes.js.map +1 -1
  91. package/dist/server/machines/machineService.js +17 -18
  92. package/dist/server/machines/machineService.js.map +1 -1
  93. package/dist/server/managementEmbed.js +26 -25
  94. package/dist/server/managementEmbed.js.map +1 -1
  95. package/dist/server/normalAuth.js +29 -26
  96. package/dist/server/normalAuth.js.map +1 -1
  97. package/dist/server/passwordVerifier.js +2 -1
  98. package/dist/server/passwordVerifier.js.map +1 -1
  99. package/dist/server/piPackageService.js +7 -5
  100. package/dist/server/piPackageService.js.map +1 -1
  101. package/dist/server/piWebPluginService.js +27 -11
  102. package/dist/server/piWebPluginService.js.map +1 -1
  103. package/dist/server/piWebStatus.js +16 -14
  104. package/dist/server/piWebStatus.js.map +1 -1
  105. package/dist/server/plugins/serverPluginRuntime.js +4 -2
  106. package/dist/server/plugins/serverPluginRuntime.js.map +1 -1
  107. package/dist/server/projects/projectService.js +4 -3
  108. package/dist/server/projects/projectService.js.map +1 -1
  109. package/dist/server/sessiond/projectMutationRoutes.js +5 -4
  110. package/dist/server/sessiond/projectMutationRoutes.js.map +1 -1
  111. package/dist/server/sessiond/sessionProxyRoutes.js +11 -8
  112. package/dist/server/sessiond/sessionProxyRoutes.js.map +1 -1
  113. package/dist/server/sessiond/workspaceCatalogRoutes.js +5 -3
  114. package/dist/server/sessiond/workspaceCatalogRoutes.js.map +1 -1
  115. package/dist/server/sessiond.js +8 -3
  116. package/dist/server/sessiond.js.map +1 -1
  117. package/dist/server/sessions/authRoutes.js +20 -19
  118. package/dist/server/sessions/authRoutes.js.map +1 -1
  119. package/dist/server/sessions/authService.js +13 -10
  120. package/dist/server/sessions/authService.js.map +1 -1
  121. package/dist/server/sessions/builtinCommands.js +28 -21
  122. package/dist/server/sessions/builtinCommands.js.map +1 -1
  123. package/dist/server/sessions/oauthLoginFlowService.js +17 -15
  124. package/dist/server/sessions/oauthLoginFlowService.js.map +1 -1
  125. package/dist/server/sessions/piSessionService.js +229 -208
  126. package/dist/server/sessions/piSessionService.js.map +1 -1
  127. package/dist/server/sessions/projectAuthService.js +5 -3
  128. package/dist/server/sessions/projectAuthService.js.map +1 -1
  129. package/dist/server/sessions/sessionArchiveMapping.js +8 -7
  130. package/dist/server/sessions/sessionArchiveMapping.js.map +1 -1
  131. package/dist/server/sessions/sessionCleanup.js +4 -3
  132. package/dist/server/sessions/sessionCleanup.js.map +1 -1
  133. package/dist/server/sessions/sessionCommandService.js +70 -67
  134. package/dist/server/sessions/sessionCommandService.js.map +1 -1
  135. package/dist/server/sessions/sessionNotificationStore.js +12 -11
  136. package/dist/server/sessions/sessionNotificationStore.js.map +1 -1
  137. package/dist/server/sessions/sessionRoutes.js +74 -72
  138. package/dist/server/sessions/sessionRoutes.js.map +1 -1
  139. package/dist/server/sessions/sessionTreeProjection.js +50 -49
  140. package/dist/server/sessions/sessionTreeProjection.js.map +1 -1
  141. package/dist/server/sessions/sessionUnreadStore.js +25 -2
  142. package/dist/server/sessions/sessionUnreadStore.js.map +1 -1
  143. package/dist/server/terminals/managementCommandRunService.js +13 -12
  144. package/dist/server/terminals/managementCommandRunService.js.map +1 -1
  145. package/dist/server/workbench/accessStateStore.js +9 -7
  146. package/dist/server/workbench/accessStateStore.js.map +1 -1
  147. package/dist/server/workbench/capabilitySearch.js +3 -2
  148. package/dist/server/workbench/capabilitySearch.js.map +1 -1
  149. package/dist/server/workbench/knowledgeSearch.js +8 -7
  150. package/dist/server/workbench/knowledgeSearch.js.map +1 -1
  151. package/dist/server/workbench/mcpClient.js +6 -5
  152. package/dist/server/workbench/mcpClient.js.map +1 -1
  153. package/dist/server/workbench/skillSync.js +4 -2
  154. package/dist/server/workbench/skillSync.js.map +1 -1
  155. package/dist/server/workbench/workbenchClient.js +8 -7
  156. package/dist/server/workbench/workbenchClient.js.map +1 -1
  157. package/dist/server/workbench/workbenchTools.js +8 -6
  158. package/dist/server/workbench/workbenchTools.js.map +1 -1
  159. package/dist/server/workingDirectory.js +3 -2
  160. package/dist/server/workingDirectory.js.map +1 -1
  161. package/dist/server/workspaceExplorerRoutes.js +16 -13
  162. package/dist/server/workspaceExplorerRoutes.js.map +1 -1
  163. package/dist/server/workspaces/fileContentService.js +11 -10
  164. package/dist/server/workspaces/fileContentService.js.map +1 -1
  165. package/dist/server/workspaces/fileOperationService.js +7 -6
  166. package/dist/server/workspaces/fileOperationService.js.map +1 -1
  167. package/dist/server/workspaces/filePreviewService.js +5 -4
  168. package/dist/server/workspaces/filePreviewService.js.map +1 -1
  169. package/dist/server/workspaces/fileSuggestions.js +2 -1
  170. package/dist/server/workspaces/fileSuggestions.js.map +1 -1
  171. package/dist/server/workspaces/pathAccessPolicy.js +24 -18
  172. package/dist/server/workspaces/pathAccessPolicy.js.map +1 -1
  173. package/dist/server/workspaces/pathSafety.js +6 -5
  174. package/dist/server/workspaces/pathSafety.js.map +1 -1
  175. package/dist/server/workspaces/projectPiWebConfig.js +3 -2
  176. package/dist/server/workspaces/projectPiWebConfig.js.map +1 -1
  177. package/dist/server/workspaces/workspaceRemovalService.js +4 -3
  178. package/dist/server/workspaces/workspaceRemovalService.js.map +1 -1
  179. package/dist/server/workspaces/workspaceRouteErrors.js +4 -2
  180. package/dist/server/workspaces/workspaceRouteErrors.js.map +1 -1
  181. package/dist/server/workspaces/workspaceUserError.js +18 -0
  182. package/dist/server/workspaces/workspaceUserError.js.map +1 -0
  183. package/dist/server-plugin-api.d.ts +3 -1
  184. package/dist/server-plugin-api.js.map +1 -1
  185. package/dist/serverPluginRecovery.js +3 -2
  186. package/dist/serverPluginRecovery.js.map +1 -1
  187. package/dist/shared/apiTypes.js.map +1 -1
  188. package/dist/shared/i18n.js +41 -0
  189. package/dist/shared/i18n.js.map +1 -0
  190. package/dist/shared/piWebConfigParsing.js +52 -49
  191. package/dist/shared/piWebConfigParsing.js.map +1 -1
  192. package/dist/shared/pluginApiTypes.d.ts +7 -0
  193. package/dist/shared/requiredTerminalPlugin.js +1 -1
  194. package/dist/shared/requiredTerminalPlugin.js.map +1 -1
  195. package/dist/shared/sessionDefaults.js +7 -6
  196. package/dist/shared/sessionDefaults.js.map +1 -1
  197. package/dist/shared/thinkingLevels.js +17 -16
  198. package/dist/shared/thinkingLevels.js.map +1 -1
  199. package/docs/config.md +10 -1
  200. package/docs/plugins.md +8 -0
  201. package/package.json +1 -1
  202. package/dist/client/assets/index-CFhaGb5m.js +0 -4357
@@ -1,4 +1,5 @@
1
1
  // Generated from pi-packages/captains-log/src/browser/panel.ts. Do not edit directly.
2
+ import { t } from "../../i18n.js";
2
3
  import { renderCaptainMarkdown } from "./markdown.js";
3
4
  export function selectedSourceSession(context) {
4
5
  if (context.state?.selectedMachine && context.state.selectedMachine.id !== context.machine.id)
@@ -6,49 +7,49 @@ export function selectedSourceSession(context) {
6
7
  const selected = context.state?.selectedSession;
7
8
  if (!selected || selected.archived || selected.pending || selected.cwd !== context.workspace.path)
8
9
  return;
9
- return { id: selected.id, name: selected.name !== undefined && selected.name.trim() !== "" ? selected.name : `会话 ${selected.id.slice(0, 8)}` };
10
+ return { id: selected.id, name: selected.name !== undefined && selected.name.trim() !== "" ? selected.name : t("ui.main.19976e58bf31", "Session {arg0}", { arg0: selected.id.slice(0, 8) }) };
10
11
  }
11
12
  export function captainStatusLabel(status) {
12
- return { running: "处理中", completed: "已完成", failed: "失败", interrupted: "已中断" }[status];
13
+ return { running: t("ui.main.fcb979ef0b91", "Working"), completed: t("ui.main.e99b48a29bdf", "Done"), failed: t("ui.toolExecutionView.failed", "Failed"), interrupted: t("ui.main.8dd5ad764e4b", "Interrupted") }[status];
13
14
  }
14
15
  const stageLabels = {
15
- "Backend admitted translation": "后端已接收转述请求",
16
- "Backend sent request to native companion": "后端已向原生伴随扩展发送请求",
17
- "Native companion received request": "原生伴随扩展已收到请求",
18
- "Native Pi agent running": "原生 Pi 代理正在运行",
19
- "Backend received correlated final reply": "后端已收到匹配请求的最终回复",
20
- "Source reply read without changing source": "已读取源回复,未改动源会话",
21
- "Pirate conversation selected": "已选择船长会话",
22
- "Backend recorded failure (not success)": "后端已记录失败,不是成功结果",
23
- "Backend saved completed roundtrip": "后端已保存完成结果",
16
+ "Backend admitted translation": t("ui.main.21e0dc881126", "Backend accepted the relay request"),
17
+ "Backend sent request to native companion": t("ui.main.269ce066984c", "Backend sent the request to the native companion extension"),
18
+ "Native companion received request": t("ui.main.2666275c64be", "Native companion extension received the request"),
19
+ "Native Pi agent running": t("ui.main.880fe7bb6b95", "Native Pi agent is running"),
20
+ "Backend received correlated final reply": t("ui.main.a7da535ace12", "Backend received the final reply matching the request"),
21
+ "Source reply read without changing source": t("ui.main.0883bfa9c8ef", "Source reply read; source session unchanged"),
22
+ "Pirate conversation selected": t("ui.main.9def3f08ac2e", "Captain session selected"),
23
+ "Backend recorded failure (not success)": t("ui.main.157309c7e4ca", "Backend recorded a failure, not a successful result"),
24
+ "Backend saved completed roundtrip": t("ui.main.f33a027a96b7", "Backend saved the completed result"),
24
25
  };
25
26
  const errorLabels = {
26
- "Captain is already working.": "船长正在处理,请等待当前转述完成。",
27
- "Select a source session other than the pirate conversation.": "请选择其他源会话,不能转述船长会话本身。",
28
- "Selected session is not hosted in this workspace on this machine": "所选会话不在当前机器的这个工作区中运行。",
29
- "Source session must be idle with no pending messages. Wait for it to finish, then translate again.": "源会话必须空闲且没有待处理消息。请等待它完成后再转述。",
30
- "Source session has no completed assistant text reply on its active branch.": "源会话当前分支没有已完成的助手文本回复。",
31
- "Source reply exceeds the translation limit (48000 characters).": "源回复超过转述长度上限(48000 个字符)。",
32
- "Companion not ready or session busy; open Captain's Log in Sessions, wait for idle, then retry": "伴随扩展尚未就绪或会话忙碌;请在会话列表中打开船长会话,等待空闲后重试。",
33
- "Captain request interrupted by session shutdown or reload": "会话关闭或重新加载中断了船长请求。",
34
- "Another prompt interfered with this Captain request; translation was not saved": "其他提示干扰了本次船长请求,转述结果未保存。",
35
- "Another user message interfered with this Captain request": "其他用户消息干扰了本次船长请求。",
36
- "Captain request error": "船长请求出错。",
37
- "Captain request aborted": "船长请求已中止。",
38
- "Captain request failed": "船长请求失败。",
39
- "Captain request ended without a successful final text response": "船长请求结束时没有成功的最终文本回复。",
40
- "Captain reply exceeded the storage limit": "船长回复超过存储长度上限。",
41
- "Invalid translation text": "转述文本无效。",
42
- "Invalid companion reply": "伴随扩展回复无效。",
43
- "Captain connection interrupted; agent work may continue in Sessions": "船长连接已中断,代理可能仍在会话中继续处理。",
44
- "No companion receipt within 5 seconds. Check package enablement/trust; inspect Sessions before retrying.": "5 秒内未收到伴随扩展确认。请检查包是否已启用并获得信任,重试前先查看会话。",
45
- "Captain request exceeded 10 minutes; agent work may continue in Sessions. No translation saved.": "船长请求已超过 10 分钟,代理可能仍在会话中继续处理;转述结果未保存。",
46
- "Captain's Log stopped before recording completion. Inspect the previous session before retrying. Nothing was resent automatically.": "船长日志在记录完成结果前已停止。请先检查之前的会话再重试,没有自动重发任何请求。",
27
+ "Captain is already working.": t("ui.main.09d17019ed2e", "Captain is working; wait for the current relay to complete."),
28
+ "Select a source session other than the pirate conversation.": t("ui.main.e4e81b805cf5", "Choose another source session; the Captain session cannot relay itself."),
29
+ "Selected session is not hosted in this workspace on this machine": t("ui.main.17dbe57aba6b", "The selected session is not running in this workspace on the current machine."),
30
+ "Source session must be idle with no pending messages. Wait for it to finish, then translate again.": t("ui.main.977c98d1294e", "The source session must be idle with no pending messages. Wait for it to finish before relaying."),
31
+ "Source session has no completed assistant text reply on its active branch.": t("ui.main.14ddd1ef21f6", "The current source branch has no completed assistant text reply."),
32
+ "Source reply exceeds the translation limit (48000 characters).": t("ui.main.eed449c7ce8e", "The source reply exceeds the relay limit of 48000 characters."),
33
+ "Companion not ready or session busy; open Captain's Log in Sessions, wait for idle, then retry": t("ui.main.c562cb9f79cb", "The companion extension is not ready or the session is busy. Open the Captain session and wait until idle before retrying."),
34
+ "Captain request interrupted by session shutdown or reload": t("ui.main.08ad1fcd5abc", "Closing or reloading the session interrupted the Captain request."),
35
+ "Another prompt interfered with this Captain request; translation was not saved": t("ui.main.ba11baa65750", "Another prompt interfered with the Captain request; the relay result was not saved."),
36
+ "Another user message interfered with this Captain request": t("ui.main.da152c51dbd7", "Another user message interfered with the Captain request."),
37
+ "Captain request error": t("ui.main.09896d6c5119", "The Captain request encountered an error."),
38
+ "Captain request aborted": t("ui.main.cf3f914e3924", "The Captain request was aborted."),
39
+ "Captain request failed": t("ui.main.b34409c59ab5", "The Captain request failed."),
40
+ "Captain request ended without a successful final text response": t("ui.main.e5b2393b01a1", "The Captain request ended without a successful final text reply."),
41
+ "Captain reply exceeded the storage limit": t("ui.main.3ea3beebb303", "The Captain reply exceeds the storage length limit."),
42
+ "Invalid translation text": t("ui.main.6f70b118900c", "Invalid relay text."),
43
+ "Invalid companion reply": t("ui.main.af43aa465d0a", "Invalid companion extension reply."),
44
+ "Captain connection interrupted; agent work may continue in Sessions": t("ui.main.dc807ddd54fa", "The Captain connection was interrupted; the agent may still be working in the session."),
45
+ "No companion receipt within 5 seconds. Check package enablement/trust; inspect Sessions before retrying.": t("ui.main.afdcdd4b929c", "No companion acknowledgement arrived within 5 seconds. Check that the package is enabled and trusted, and inspect the session before retrying."),
46
+ "Captain request exceeded 10 minutes; agent work may continue in Sessions. No translation saved.": t("ui.main.d2cd15752866", "The Captain request exceeded 10 minutes. The agent may still be working; the relay result was not saved."),
47
+ "Captain's Log stopped before recording completion. Inspect the previous session before retrying. Nothing was resent automatically.": t("ui.main.b8e0a313e94a", "Captain's Log stopped before recording a completed result. Inspect the previous session before retrying; no request was resent automatically."),
47
48
  };
48
49
  function displayCaptainError(text) {
49
50
  const prefix = "Captain could not finish this request. Inspect the session before retrying; nothing was resent automatically.\n";
50
51
  if (text.startsWith(prefix))
51
- return `船长未能完成本次请求。重试前请检查会话,没有自动重发任何请求。\n${displayCaptainError(text.slice(prefix.length))}`;
52
+ return t("ui.main.250d9fb3b162", "Captain could not complete the request. Inspect the session before retrying; no request was resent automatically.\n{arg0}", { arg0: displayCaptainError(text.slice(prefix.length)) });
52
53
  const message = text.startsWith("Error: ") ? text.slice(7) : text;
53
54
  return errorLabels[message] ?? text;
54
55
  }
@@ -62,38 +63,38 @@ export function renderCaptainPanel(html, view) {
62
63
  const disabled = !view.connected || view.connecting || view.pending || working || !view.source || pirateSelected;
63
64
  const selected = view.selected;
64
65
  const sourceSessionId = selected?.sourceSessionId;
65
- const status = view.connecting ? "连接中…" : !view.connected ? "连接已断开" : view.pending ? "正在读取最后一条回复…"
66
- : working ? "船长正在转述…" : !view.source ? "请先选择当前工作区中的会话。" : pirateSelected ? "请选择其他会话,当前会话是船长会话。"
67
- : "可以开始转述";
66
+ const status = view.connecting ? t("ui.main.9d02d121573c", "Connecting…") : !view.connected ? t("ui.main.570f6d331cce", "Connection lost") : view.pending ? t("ui.main.482617a8c265", "Fetching the last reply…")
67
+ : working ? t("ui.main.c13e5f4963ff", "The captain is translating…") : !view.source ? t("ui.main.3c86e23d60ea", "Select a session in this workspace first.") : pirateSelected ? t("ui.main.80a96f7d125e", "Select a different session — this one is the pirate.")
68
+ : t("ui.main.12fc65d7525d", "Ready to translate");
68
69
  return html `<style>${styles}</style>
69
- <section class="captains-log" aria-label="船长日志">
70
- <div class="captain-heading"><h2>⚓ 船长日志</h2><p class="muted">让戏剧化的海盗船长转述最后一条回复。</p></div>
71
- <div class="captain-source"><span class="muted">选中会话</span><strong>${view.source?.name ?? "未选择会话"}</strong></div>
72
- <button class="captain-primary" ?disabled=${disabled} @click=${view.onTranslate}>让船长转述</button>
70
+ <section class="captains-log" aria-label="${t("ui.main.40c450439267", "Captain's Log")}">
71
+ <div class="captain-heading"><h2>${t("ui.main.e841f99d77f0", "Captain's Log")}</h2><p class="muted">${t("ui.main.1c3532df737d", "Have a dramatic pirate captain relay the last reply.")}</p></div>
72
+ <div class="captain-source"><span class="muted">${t("ui.main.84521ab1f774", "Selected session")}</span><strong>${view.source?.name ?? t("ui.sessionList.noSessionSelected", "No session selected")}</strong></div>
73
+ <button class="captain-primary" ?disabled=${disabled} @click=${view.onTranslate}>${t("ui.main.09ee4046866f", "Let the Captain tell it")}</button>
73
74
  <p class="captain-status" role="status" aria-live="polite">${status}
74
- ${!view.connected && !view.connecting ? html `<button @click=${view.onReconnect}>重新连接</button>` : null}
75
+ ${!view.connected && !view.connecting ? html `<button @click=${view.onReconnect}>${t("ui.main.bac95e1e52fe", "Reconnect")}</button>` : null}
75
76
  </p>
76
- ${!view.connected && !view.connecting ? html `<p class="captain-notice">重新连接以查看结果。船长可能仍在处理,不会再次发送你的请求。</p>` : null}
77
+ ${!view.connected && !view.connecting ? html `<p class="captain-notice">${t("ui.main.3c3a8d4bb0ab", "Reconnect to see the result. The captain may still be working; your request will not be sent again.")}</p>` : null}
77
78
  ${view.notice !== undefined && view.notice !== "" ? html `<p class="captain-notice" role="alert">${displayCaptainError(view.notice)}</p>` : null}
78
- ${selected ? html `<article class="captain-reply" aria-label="船长转述">
79
- <div class="captain-reply-heading"><strong>${selected.status === "running" ? "转述中…" : selected.id === view.entries[0]?.id ? "最近转述" : "历史转述"}</strong><time datetime=${selected.createdAt}>${dateLabel(selected.createdAt)}</time></div>
80
- ${selected.status === "completed" ? html `<div class="captain-answer">${selected.text ? renderCaptainMarkdown(html, selected.text) : "正在接收船长回复…"}</div>`
81
- : selected.status === "running" ? html `<p class="muted">正在读取源回复并改写为海盗风格,不向源会话发送消息。</p>`
82
- : html `<div class="captain-notice" role="alert"><strong>${selected.status === "interrupted" ? "转述已中断" : "无法转述该回复"}</strong><p>${displayCaptainError(selected.text) || "请查看诊断详情,待会话就绪后重试。"}</p></div>`}
83
- ${sourceSessionId !== undefined && sourceSessionId !== "" ? html `<button @click=${() => { view.onOpenSource(sourceSessionId); }}>打开源会话</button>` : null}
84
- </article>` : html `<p class="captain-empty muted">选择会话后转述其最新已完成的助手回复,原会话保持不变。</p>`}
79
+ ${selected ? html `<article class="captain-reply" aria-label="${t("ui.main.e572c45a01a6", "Pirate translation")}">
80
+ <div class="captain-reply-heading"><strong>${selected.status === "running" ? t("ui.main.a3e678a94720", "Translating…") : selected.id === view.entries[0]?.id ? t("ui.main.aa1bf7a5ddbe", "Last translation") : t("ui.main.91515d50cc9e", "Earlier translation")}</strong><time datetime=${selected.createdAt}>${dateLabel(selected.createdAt)}</time></div>
81
+ ${selected.status === "completed" ? html `<div class="captain-answer">${selected.text ? renderCaptainMarkdown(html, selected.text) : t("ui.main.648d8128e3c7", "Receiving the captain's reply…")}</div>`
82
+ : selected.status === "running" ? html `<p class="muted">${t("ui.main.c61214cbad46", "Reading the source reply and turning it into pirate. No message is sent to the source conversation.")}</p>`
83
+ : html `<div class="captain-notice" role="alert"><strong>${selected.status === "interrupted" ? t("ui.main.8ac60a0f0b8e", "Translation interrupted") : t("ui.main.fe0e672c27d4", "Couldn't translate that reply")}</strong><p>${displayCaptainError(selected.text) || t("ui.main.72a4ca9f0124", "Check Diagnostics for details, then try again when the session is ready.")}</p></div>`}
84
+ ${sourceSessionId !== undefined && sourceSessionId !== "" ? html `<button @click=${() => { view.onOpenSource(sourceSessionId); }}>${t("ui.main.58ea40f79134", "Open source session")}</button>` : null}
85
+ </article>` : html `<p class="captain-empty muted">${t("ui.main.34a6d480c665", "Pick a conversation, then translate its latest finished assistant reply. The original stays untouched.")}</p>`}
85
86
  <div class="captain-secondary">
86
- ${view.entries.length > 1 ? html `<details><summary>历史转述 <span class="muted">(${view.entries.length})</span></summary>
87
+ ${view.entries.length > 1 ? html `<details><summary>${t("ui.main.91515d50cc9e", "Earlier translation")} <span class="muted">(${view.entries.length})</span></summary>
87
88
  <div class="captain-history">${view.entries.map((entry) => html `<button class=${entry.id === selected?.id ? "selected" : ""} ?disabled=${!view.connected} @click=${() => { view.onRead(entry.id); }}>
88
- <span>${dateLabel(entry.createdAt)} · ${entry.status === "completed" ? "已转述" : entry.status === "running" ? "处理中" : "未完成"}</span>
89
+ <span>${dateLabel(entry.createdAt)} · ${entry.status === "completed" ? t("ui.main.9f66d2a4d6f7", "Translated") : entry.status === "running" ? t("ui.main.fcb979ef0b91", "Working") : t("ui.main.b61b08aec3a9", "Not completed")}</span>
89
90
  </button>`)}</div>
90
91
  </details>` : null}
91
- <details class="captain-diagnostics"><summary>诊断</summary>
92
+ <details class="captain-diagnostics"><summary>${t("ui.main.e0b478941707", "Diagnostics")}</summary>
92
93
  <p>${displayCaptainError(view.status)}</p>
93
- ${selected ? html `<dl><dt>机器</dt><dd>${view.machineName}</dd><dt>源会话</dt><dd>${selected.sourceSessionId ?? "未知"}</dd><dt>船长会话</dt><dd>${selected.sessionId || "尚未创建"}</dd><dt>请求</dt><dd>${selected.id}</dd></dl>
94
- <p>${selected.question === "Translate last reply" ? "转述最后一条回复" : selected.question}</p><ol>${selected.stages.map((stage) => html `<li>${stageLabels[stage] ?? stage}</li>`)}</ol>` : null}
94
+ ${selected ? html `<dl><dt>${t("bundled.info.machine.ece969", "Machine")}</dt><dd>${view.machineName}</dd><dt>${t("ui.main.b92dc0c2297a", "Source session")}</dt><dd>${selected.sourceSessionId ?? t("bundled.updates.unknown.4d8c1c", "Unknown")}</dd><dt>${t("ui.main.62b811ff4549", "Pirate session")}</dt><dd>${selected.sessionId || t("ui.main.db03d9974969", "Not created")}</dd><dt>${t("ui.main.926f6b6b6a93", "Request")}</dt><dd>${selected.id}</dd></dl>
95
+ <p>${selected.question === "Translate last reply" ? t("ui.main.fc69d95b95b3", "Relay the last reply") : selected.question}</p><ol>${selected.stages.map((stage) => html `<li>${stageLabels[stage] ?? stage}</li>`)}</ol>` : null}
95
96
  </details>
96
- <p class="captain-footnote muted">使用你配置的模型,可能产生费用。可用时复用船长会话,否则自动创建。</p>
97
+ <p class="captain-footnote muted">${t("ui.main.8dbbd44d148a", "Uses your configured model. Reuses the pirate while it's available; otherwise starts one automatically.")}</p>
97
98
  </div>
98
99
  </section>`;
99
100
  }
@@ -0,0 +1,7 @@
1
+ // Generated from pi-packages/captains-log/i18n.ts. Do not edit directly.
2
+ let translate;
3
+ export function setTranslator(value) {
4
+ translate = value;
5
+ }
6
+ export const t = (key, fallback, params) => translate?.(key, fallback, params)
7
+ ?? fallback.replace(/\{([A-Za-z0-9_]+)\}/g, (match, name) => String(params?.[name] ?? match));
@@ -0,0 +1,7 @@
1
+ // Generated from pi-packages/relays/i18n.ts. Do not edit directly.
2
+ let translate;
3
+ export function setTranslator(value) {
4
+ translate = value;
5
+ }
6
+ export const t = (key, fallback, params) => translate?.(key, fallback, params)
7
+ ?? fallback.replace(/\{([A-Za-z0-9_]+)\}/g, (match, name) => String(params?.[name] ?? match));
@@ -1,4 +1,5 @@
1
1
  // Generated from pi-packages/relays/markdownDocument.ts. Do not edit directly.
2
+ import { t } from "./i18n.js";
2
3
  import { marked } from "./vendor/marked.esm.js";
3
4
  // Raw HTML inside relay documents is escaped before sanitizing, so the
4
5
  // sanitizer only ever sees marked-generated markup. This mirrors the safety
@@ -63,7 +64,7 @@ function wrapTablesInScrollRegions(root) {
63
64
  const wrapper = document.createElement("div");
64
65
  wrapper.className = TABLE_SCROLL_CLASS;
65
66
  wrapper.setAttribute("role", "region");
66
- wrapper.setAttribute("aria-label", "表格");
67
+ wrapper.setAttribute("aria-label", t("bundled.relays.table.22d9e7", "Table"));
67
68
  wrapper.setAttribute("tabindex", "0");
68
69
  table.before(wrapper);
69
70
  wrapper.append(table);
@@ -1,19 +1,21 @@
1
1
  // Generated from pi-packages/relays/pi-web-plugin.ts. Do not edit directly.
2
+ import { t, setTranslator } from "./i18n.js";
2
3
  import { RELAYS_ROOT } from "./relayDiscovery.js";
3
4
  import { defineRelaysPanelElement } from "./relaysPanelElement.js";
4
5
  const plugin = {
5
6
  apiVersion: 4,
6
- name: "中继",
7
- activate: ({ runtimePluginId, html, svg }) => {
7
+ name: t("bundled.relays.relays.715ce8", "Relays"),
8
+ activate: ({ runtimePluginId, html, svg, translate }) => {
9
+ setTranslator(translate);
8
10
  defineRelaysPanelElement();
9
11
  return {
10
12
  contributions: {
11
13
  actions: [
12
14
  {
13
15
  id: "workspace.open-relays",
14
- title: "打开工作区中继",
15
- description: `打开工作区的中继标签页。中继存放在 ${RELAYS_ROOT}。`,
16
- group: "工作区",
16
+ title: t("bundled.relays.open.workspace.relays.ead958", "Open workspace relays"),
17
+ description: t("bundled.relays.open.the.workspace.relays.tab.relays.are.stored.in.3d8901", "Open the workspace relays tab. Relays are stored in {value1}.", { value1: RELAYS_ROOT }),
18
+ group: t("bundled.workspace-tasks.workspace.379798", "Workspace"),
17
19
  enabled: (context) => context.state.selectedWorkspace !== undefined,
18
20
  run: (context) => {
19
21
  if (context.state.selectedWorkspace === undefined)
@@ -25,7 +27,7 @@ const plugin = {
25
27
  workspacePanels: [
26
28
  {
27
29
  id: "workspace.relays",
28
- title: "中继",
30
+ title: t("bundled.relays.relays.715ce8", "Relays"),
29
31
  icon: svg `
30
32
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
31
33
  <path d="M9 17H7A5 5 0 0 1 7 7h2"></path>
@@ -1,4 +1,5 @@
1
1
  // Generated from pi-packages/relays/relaysPanelElement.ts. Do not edit directly.
2
+ import { t } from "./i18n.js";
2
3
  import { isMarkdownDocumentPath, renderRelayDocumentHtml } from "./markdownDocument.js";
3
4
  import { ancestorDirectoryPaths, collectDirectoryPaths, defaultRelayDocument, flattenRelayTree, listRelayDocumentTree, listWorkspaceRelays, readRelayDocument, RELAYS_ROOT, } from "./relayDiscovery.js";
4
5
  export const relaysPanelTagName = "pi-web-relays-panel";
@@ -38,8 +39,8 @@ class PiWebRelaysPanel extends HTMLElement {
38
39
  this.root.innerHTML = `
39
40
  ${relaysStyles()}
40
41
  <section class="toolbar" hidden></section>
41
- <nav class="document-tabs" aria-label="中继文档" hidden></nav>
42
- <section class="viewer"><div class="empty">请选择工作区。</div></section>
42
+ <nav class="document-tabs" aria-label="${escapeAttr(t("bundled.relays.relay.documents.91711b", "Relay documents"))}" hidden></nav>
43
+ <section class="viewer"><div class="empty">${escapeHtml(t("bundled.relays.select.a.workspace.234859", "Select a workspace."))}</div></section>
43
44
  `;
44
45
  this.toolbar = requiredRegion(this.root, ".toolbar");
45
46
  this.tabStrip = requiredRegion(this.root, "nav.document-tabs");
@@ -247,10 +248,10 @@ class PiWebRelaysPanel extends HTMLElement {
247
248
  }
248
249
  this.toolbar.hidden = false;
249
250
  this.toolbar.innerHTML = `
250
- <strong>中继</strong>
251
+ <strong>${escapeHtml(t("bundled.relays.relays.715ce8", "Relays"))}</strong>
251
252
  <span class="toolbar-actions">
252
253
  ${this.renderRelayPicker()}
253
- <button class="icon-button" data-refresh aria-label="刷新" title="刷新">${refreshIconSvg()}</button>
254
+ <button class="icon-button" data-refresh aria-label="${escapeAttr(t("bundled.relays.refresh.aee887", "Refresh"))}" title="${escapeAttr(t("bundled.relays.refresh.aee887", "Refresh"))}">${refreshIconSvg()}</button>
254
255
  </span>
255
256
  `;
256
257
  }
@@ -267,7 +268,7 @@ class PiWebRelaysPanel extends HTMLElement {
267
268
  const selected = relay.path === this.selectedRelayPath ? " selected" : "";
268
269
  return `<option value="${escapeAttr(relay.path)}"${selected}>${escapeHtml(relay.name)}</option>`;
269
270
  }).join("");
270
- return `<select data-relay-picker aria-label="中继">${options}</select>`;
271
+ return `<select data-relay-picker aria-label="${escapeAttr(t("bundled.relays.relays.715ce8", "Relays"))}">${options}</select>`;
271
272
  }
272
273
  renderTabs() {
273
274
  const documents = this.documents;
@@ -303,7 +304,7 @@ class PiWebRelaysPanel extends HTMLElement {
303
304
  renderDirectoryChip(directory, containsActivePath) {
304
305
  const expanded = this.expandedDirs.has(directory.path);
305
306
  const containsActive = directory.path === containsActivePath;
306
- const title = containsActive ? "包含当前打开的文档" : directory.relativePath;
307
+ const title = containsActive ? t("ui.main.6a634d20bc86", "Contains the open document") : directory.relativePath;
307
308
  return `<button class="document-tab directory-tab${containsActive ? " contains-active" : ""}" data-directory-path="${escapeAttr(directory.path)}" title="${escapeAttr(title)}" aria-expanded="${expanded ? "true" : "false"}">${chevronSvg()}${escapeHtml(directory.name)}</button>`;
308
309
  }
309
310
  /** Move the active marker between the mounted tab buttons without rebuilding them. */
@@ -321,7 +322,7 @@ class PiWebRelaysPanel extends HTMLElement {
321
322
  }
322
323
  renderViewer() {
323
324
  if (this.contextValue === undefined) {
324
- this.viewer.innerHTML = `<div class="empty">请选择工作区。</div>`;
325
+ this.viewer.innerHTML = `<div class="empty">${escapeHtml(t("bundled.relays.select.a.workspace.234859", "Select a workspace."))}</div>`;
325
326
  return;
326
327
  }
327
328
  this.viewer.innerHTML = this.renderViewerContent();
@@ -329,9 +330,9 @@ class PiWebRelaysPanel extends HTMLElement {
329
330
  renderViewerContent() {
330
331
  const listing = this.listing;
331
332
  if (listing === undefined)
332
- return `<p class="muted">正在扫描 ${escapeHtml(RELAYS_ROOT)}…</p>`;
333
+ return `<p class="muted">${escapeHtml(t("bundled.relays.scanning.d7c334", "Scanning {value1}...", { value1: RELAYS_ROOT }))}</p>`;
333
334
  if (listing.kind === "unavailable")
334
- return renderErrorState("无法扫描工作区中继。", listing.detail);
335
+ return renderErrorState(t("bundled.relays.could.not.scan.workspace.relays.d8b2bc", "Could not scan workspace relays."), listing.detail);
335
336
  if (listing.kind === "missing" || listing.relays.length === 0)
336
337
  return renderEmptyState();
337
338
  return this.renderSelectedRelay();
@@ -339,20 +340,20 @@ class PiWebRelaysPanel extends HTMLElement {
339
340
  renderSelectedRelay() {
340
341
  const documents = this.documents;
341
342
  if (documents === undefined)
342
- return `<p class="muted">正在加载中继文档…</p>`;
343
+ return `<p class="muted">${escapeHtml(t("bundled.relays.loading.relay.documents.94db7f", "Loading relay documents..."))}</p>`;
343
344
  if (documents.kind === "unavailable")
344
- return renderErrorState("无法列出此中继的文档。", documents.detail);
345
+ return renderErrorState(t("bundled.relays.could.not.list.documents.for.this.relay.cad056", "Could not list documents for this relay."), documents.detail);
345
346
  if (documents.kind === "missing") {
346
- return `<div class="empty-state"><strong>此中继已不存在。</strong><p>点击“刷新”重新扫描 ${escapeHtml(RELAYS_ROOT)}。</p></div>`;
347
+ return `<div class="empty-state"><strong>${escapeHtml(t("bundled.relays.this.relay.no.longer.exists.f8d39d", "This relay no longer exists."))}</strong><p>${escapeHtml(t("bundled.relays.click.refresh.to.rescan.7a2ef0", "Click Refresh to rescan {value1}.", { value1: RELAYS_ROOT }))}</p></div>`;
347
348
  }
348
349
  const partialNotice = documents.partial
349
- ? `<div class="status info">部分嵌套内容未列出:此中继目录树超过了面板的深度或数量限制。</div>`
350
+ ? `<div class="status info">${escapeHtml(t("bundled.relays.partial", "Some nested content is omitted because this relay exceeds the panel depth or count limit."))}</div>`
350
351
  : "";
351
352
  if (documents.documentCount === 0) {
352
353
  return `${partialNotice}
353
354
  <div class="empty-state">
354
- <strong>此中继还没有文档。</strong>
355
- <p>Relay Runner 包通常包含 <code>status.md</code>、<code>charter.md</code>、<code>operations.md</code> 和 <code>log.md</code>。</p>
355
+ <strong>${escapeHtml(t("bundled.relays.this.relay.has.no.documents.yet.d5948c", "This relay has no documents yet."))}</strong>
356
+ <p>${escapeHtml(t("bundled.relays.document.files", "Relay packages usually include {files}.", { files: "status.md, charter.md, operations.md, log.md" }))}</p>
356
357
  </div>
357
358
  `;
358
359
  }
@@ -362,19 +363,19 @@ class PiWebRelaysPanel extends HTMLElement {
362
363
  const documentPath = this.selectedDocumentPath;
363
364
  const content = this.documentContent;
364
365
  if (documentPath === undefined)
365
- return `<p class="muted">请选择文档。</p>`;
366
+ return `<p class="muted">${escapeHtml(t("bundled.relays.select.a.document.1c46a5", "Select a document."))}</p>`;
366
367
  if (content === undefined)
367
- return `<p class="muted">正在加载 ${escapeHtml(documentName(documentPath))}…</p>`;
368
+ return `<p class="muted">${escapeHtml(t("bundled.relays.loading.9f624f", "Loading {value1}...", { value1: documentName(documentPath) }))}</p>`;
368
369
  if (content.kind === "unavailable")
369
- return renderErrorState("无法读取此文档。", content.detail);
370
+ return renderErrorState(t("bundled.relays.could.not.read.this.document.7cd2d0", "Could not read this document."), content.detail);
370
371
  if (content.kind === "missing") {
371
- return `<div class="empty-state"><strong>此文档已不存在。</strong><p>点击“刷新”重新扫描中继。</p></div>`;
372
+ return `<div class="empty-state"><strong>${escapeHtml(t("bundled.relays.this.document.no.longer.exists.6d4a00", "This document no longer exists."))}</strong><p>${escapeHtml(t("bundled.relays.click.refresh.to.rescan.relays.2fe15f", "Click Refresh to rescan relays."))}</p></div>`;
372
373
  }
373
374
  if (content.binary) {
374
- return `<div class="empty-state"><strong>二进制文件:${escapeHtml(documentName(documentPath))}</strong><p>二进制文档无法提供文本预览。</p></div>`;
375
+ return `<div class="empty-state"><strong>${escapeHtml(t("bundled.relays.binary.file.f080cb", "Binary file: {value1}", { value1: documentName(documentPath) }))}</strong><p>${escapeHtml(t("bundled.relays.binary.documents.cannot.be.previewed.as.text.535534", "Binary documents cannot be previewed as text."))}</p></div>`;
375
376
  }
376
377
  const truncation = content.truncated
377
- ? `<div class="status info">此文档已截断,仅显示开头内容。</div>`
378
+ ? `<div class="status info">${escapeHtml(t("bundled.relays.this.document.is.truncated.only.the.beginning.is.shown.bf465f", "This document was truncated; only its beginning is shown."))}</div>`
378
379
  : "";
379
380
  if (isMarkdownDocumentPath(documentPath)) {
380
381
  return `${truncation}<div class="document markdown">${renderRelayDocumentHtml(content.content)}</div>`;
@@ -432,8 +433,8 @@ function documentName(path) {
432
433
  function renderEmptyState() {
433
434
  return `
434
435
  <div class="empty-state">
435
- <strong>此工作区中没有中继。</strong>
436
- <p>中继包存放在 <code>${escapeHtml(RELAYS_ROOT)}/&lt;name&gt;/</code>,此工作区目前还没有中继包。</p>
436
+ <strong>${escapeHtml(t("bundled.relays.no.relays.in.this.workspace.6ba356", "No relays in this workspace."))}</strong>
437
+ <p>${escapeHtml(t("bundled.relays.empty.location", "Relay packages are stored in {path}. This workspace has none yet.", { path: `${RELAYS_ROOT}/<name>/` }))}</p>
437
438
  </div>
438
439
  `;
439
440
  }