@jingyi0605/codingns 0.3.0 → 0.3.6

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 (261) hide show
  1. package/README.md +13 -0
  2. package/bin/codingns.mjs +880 -9
  3. package/dist/public/assets/{TerminalPage-Dfw1QUqW.js → TerminalPage-D00S4KM6.js} +19 -19
  4. package/dist/public/assets/index-BlOinYqR.js +122 -0
  5. package/dist/public/assets/index-Dg_7g6lA.css +1 -0
  6. package/dist/public/index.html +2 -2
  7. package/dist/server/config/env.d.ts +2 -0
  8. package/dist/server/config/env.js +35 -0
  9. package/dist/server/config/env.js.map +1 -1
  10. package/dist/server/config/opencode-base-url-resolver.d.ts +7 -0
  11. package/dist/server/config/opencode-base-url-resolver.js +48 -11
  12. package/dist/server/config/opencode-base-url-resolver.js.map +1 -1
  13. package/dist/server/config/opencode-system-probe-helper-client.d.ts +4 -0
  14. package/dist/server/config/opencode-system-probe-helper-client.js +29 -0
  15. package/dist/server/config/opencode-system-probe-helper-client.js.map +1 -1
  16. package/dist/server/config/opencode-system-probe-helper-process.d.ts +12 -0
  17. package/dist/server/config/opencode-system-probe-helper-process.js +34 -7
  18. package/dist/server/config/opencode-system-probe-helper-process.js.map +1 -1
  19. package/dist/server/modules/assistant-capability/assistant-capability-controller.d.ts +144 -0
  20. package/dist/server/modules/assistant-capability/assistant-capability-controller.js +242 -1
  21. package/dist/server/modules/assistant-capability/assistant-capability-controller.js.map +1 -1
  22. package/dist/server/modules/assistant-capability/assistant-capability-service.d.ts +133 -2
  23. package/dist/server/modules/assistant-capability/assistant-capability-service.js +395 -2
  24. package/dist/server/modules/assistant-capability/assistant-capability-service.js.map +1 -1
  25. package/dist/server/modules/auth/auth-service.d.ts +18 -1
  26. package/dist/server/modules/auth/auth-service.js +168 -7
  27. package/dist/server/modules/auth/auth-service.js.map +1 -1
  28. package/dist/server/modules/butler/butler-codex-model-policy.d.ts +1 -0
  29. package/dist/server/modules/butler/butler-codex-model-policy.js +36 -0
  30. package/dist/server/modules/butler/butler-codex-model-policy.js.map +1 -0
  31. package/dist/server/modules/butler/butler-control-session-service.d.ts +13 -1
  32. package/dist/server/modules/butler/butler-control-session-service.js +55 -231
  33. package/dist/server/modules/butler/butler-control-session-service.js.map +1 -1
  34. package/dist/server/modules/butler/butler-controller.d.ts +17 -0
  35. package/dist/server/modules/butler/butler-controller.js +20 -1
  36. package/dist/server/modules/butler/butler-controller.js.map +1 -1
  37. package/dist/server/modules/butler/butler-follow-up-service.js +7 -3
  38. package/dist/server/modules/butler/butler-follow-up-service.js.map +1 -1
  39. package/dist/server/modules/butler/butler-inbox-analysis-service.d.ts +36 -0
  40. package/dist/server/modules/butler/butler-inbox-analysis-service.js +375 -0
  41. package/dist/server/modules/butler/butler-inbox-analysis-service.js.map +1 -0
  42. package/dist/server/modules/butler/butler-inbox-instruction-adapter.d.ts +23 -0
  43. package/dist/server/modules/butler/butler-inbox-instruction-adapter.js +97 -0
  44. package/dist/server/modules/butler/butler-inbox-instruction-adapter.js.map +1 -0
  45. package/dist/server/modules/butler/butler-inbox-service.d.ts +39 -2
  46. package/dist/server/modules/butler/butler-inbox-service.js +392 -2
  47. package/dist/server/modules/butler/butler-inbox-service.js.map +1 -1
  48. package/dist/server/modules/butler/butler-session-service.d.ts +8 -0
  49. package/dist/server/modules/butler/butler-session-service.js +205 -53
  50. package/dist/server/modules/butler/butler-session-service.js.map +1 -1
  51. package/dist/server/modules/butler/butler-session-summary-service.d.ts +1 -0
  52. package/dist/server/modules/butler/butler-session-summary-service.js +48 -23
  53. package/dist/server/modules/butler/butler-session-summary-service.js.map +1 -1
  54. package/dist/server/modules/butler/butler-workspace-context.d.ts +13 -0
  55. package/dist/server/modules/butler/butler-workspace-context.js +234 -0
  56. package/dist/server/modules/butler/butler-workspace-context.js.map +1 -0
  57. package/dist/server/modules/client/client-controller.d.ts +6 -0
  58. package/dist/server/modules/client/client-controller.js +30 -8
  59. package/dist/server/modules/client/client-controller.js.map +1 -1
  60. package/dist/server/modules/client/client-service.d.ts +22 -10
  61. package/dist/server/modules/client/client-service.js +77 -100
  62. package/dist/server/modules/client/client-service.js.map +1 -1
  63. package/dist/server/modules/client/npm-global-package-service.d.ts +21 -0
  64. package/dist/server/modules/client/npm-global-package-service.js +210 -0
  65. package/dist/server/modules/client/npm-global-package-service.js.map +1 -0
  66. package/dist/server/modules/client/service-update-task-service.d.ts +15 -0
  67. package/dist/server/modules/client/service-update-task-service.js +147 -0
  68. package/dist/server/modules/client/service-update-task-service.js.map +1 -0
  69. package/dist/server/modules/client/service-update-types.d.ts +30 -0
  70. package/dist/server/modules/client/service-update-types.js +2 -0
  71. package/dist/server/modules/client/service-update-types.js.map +1 -0
  72. package/dist/server/modules/debug-target/debug-target-controller.d.ts +13 -0
  73. package/dist/server/modules/debug-target/debug-target-controller.js +77 -2
  74. package/dist/server/modules/debug-target/debug-target-controller.js.map +1 -1
  75. package/dist/server/modules/debug-target/debug-target-service.d.ts +11 -2
  76. package/dist/server/modules/debug-target/debug-target-service.js +138 -3
  77. package/dist/server/modules/debug-target/debug-target-service.js.map +1 -1
  78. package/dist/server/modules/git/git-command-helper-client.d.ts +2 -0
  79. package/dist/server/modules/git/git-command-helper-client.js +52 -3
  80. package/dist/server/modules/git/git-command-helper-client.js.map +1 -1
  81. package/dist/server/modules/git/git-command-helper-process.js +62 -9
  82. package/dist/server/modules/git/git-command-helper-process.js.map +1 -1
  83. package/dist/server/modules/git/git-command-runner.d.ts +1 -0
  84. package/dist/server/modules/git/git-command-runner.js +25 -0
  85. package/dist/server/modules/git/git-command-runner.js.map +1 -1
  86. package/dist/server/modules/git/git-controller.js +8 -7
  87. package/dist/server/modules/git/git-controller.js.map +1 -1
  88. package/dist/server/modules/git/git-read-service.d.ts +7 -7
  89. package/dist/server/modules/git/git-read-service.js +41 -24
  90. package/dist/server/modules/git/git-read-service.js.map +1 -1
  91. package/dist/server/modules/model-switch/cc-switch-adapter.d.ts +36 -0
  92. package/dist/server/modules/model-switch/cc-switch-adapter.js +321 -0
  93. package/dist/server/modules/model-switch/cc-switch-adapter.js.map +1 -0
  94. package/dist/server/modules/model-switch/model-switch-controller.d.ts +11 -0
  95. package/dist/server/modules/model-switch/model-switch-controller.js +30 -0
  96. package/dist/server/modules/model-switch/model-switch-controller.js.map +1 -0
  97. package/dist/server/modules/model-switch/model-switch-service.d.ts +16 -0
  98. package/dist/server/modules/model-switch/model-switch-service.js +29 -0
  99. package/dist/server/modules/model-switch/model-switch-service.js.map +1 -0
  100. package/dist/server/modules/preferences/profile-service.d.ts +1 -0
  101. package/dist/server/modules/preferences/profile-service.js +9 -0
  102. package/dist/server/modules/preferences/profile-service.js.map +1 -1
  103. package/dist/server/modules/provider/codex-model-options.js +2 -3
  104. package/dist/server/modules/provider/codex-model-options.js.map +1 -1
  105. package/dist/server/modules/provider/opencode-model-options.js +2 -3
  106. package/dist/server/modules/provider/opencode-model-options.js.map +1 -1
  107. package/dist/server/modules/provider/provider-discovery-helper-client.d.ts +9 -4
  108. package/dist/server/modules/provider/provider-discovery-helper-client.js +87 -11
  109. package/dist/server/modules/provider/provider-discovery-helper-client.js.map +1 -1
  110. package/dist/server/modules/provider/provider-discovery-helper-process.js +52 -47
  111. package/dist/server/modules/provider/provider-discovery-helper-process.js.map +1 -1
  112. package/dist/server/modules/provider/provider-discovery-runtime.d.ts +4 -0
  113. package/dist/server/modules/provider/provider-discovery-runtime.js +65 -0
  114. package/dist/server/modules/provider/provider-discovery-runtime.js.map +1 -0
  115. package/dist/server/modules/sessions/codex-app-server-helper-process.js +3 -0
  116. package/dist/server/modules/sessions/codex-app-server-helper-process.js.map +1 -1
  117. package/dist/server/modules/sessions/session-activity-authority-service.d.ts +3 -1
  118. package/dist/server/modules/sessions/session-activity-authority-service.js +3 -0
  119. package/dist/server/modules/sessions/session-activity-authority-service.js.map +1 -1
  120. package/dist/server/modules/sessions/session-activity-inspector.d.ts +1 -1
  121. package/dist/server/modules/sessions/session-activity-inspector.js +43 -16
  122. package/dist/server/modules/sessions/session-activity-inspector.js.map +1 -1
  123. package/dist/server/modules/sessions/session-controller.d.ts +3 -3
  124. package/dist/server/modules/sessions/session-controller.js +3 -3
  125. package/dist/server/modules/sessions/session-controller.js.map +1 -1
  126. package/dist/server/modules/sessions/session-history-service.d.ts +8 -2
  127. package/dist/server/modules/sessions/session-history-service.js +473 -65
  128. package/dist/server/modules/sessions/session-history-service.js.map +1 -1
  129. package/dist/server/modules/sessions/session-live-runtime-service.d.ts +9 -3
  130. package/dist/server/modules/sessions/session-live-runtime-service.js +114 -34
  131. package/dist/server/modules/sessions/session-live-runtime-service.js.map +1 -1
  132. package/dist/server/modules/sessions/session-message-attachment-service.d.ts +8 -8
  133. package/dist/server/modules/sessions/session-message-attachment-service.js +25 -34
  134. package/dist/server/modules/sessions/session-message-attachment-service.js.map +1 -1
  135. package/dist/server/modules/sessions/session-provider-error-mapper.js +7 -0
  136. package/dist/server/modules/sessions/session-provider-error-mapper.js.map +1 -1
  137. package/dist/server/modules/skills/builtin-skill-service.d.ts +12 -0
  138. package/dist/server/modules/skills/builtin-skill-service.js +49 -0
  139. package/dist/server/modules/skills/builtin-skill-service.js.map +1 -0
  140. package/dist/server/modules/skills/builtin-skills/codingns-assistant/SKILL.md +75 -0
  141. package/dist/server/modules/skills/builtin-skills/codingns-assistant/agents/openai.yaml +4 -0
  142. package/dist/server/modules/skills/builtin-skills/codingns-assistant/references/cli-workflow.md +130 -0
  143. package/dist/server/modules/skills/skill-manager-service.d.ts +7 -0
  144. package/dist/server/modules/skills/skill-manager-service.js +98 -0
  145. package/dist/server/modules/skills/skill-manager-service.js.map +1 -1
  146. package/dist/server/modules/tailscale/tailscale-helper-client.d.ts +1 -0
  147. package/dist/server/modules/tailscale/tailscale-helper-client.js +12 -0
  148. package/dist/server/modules/tailscale/tailscale-helper-client.js.map +1 -1
  149. package/dist/server/modules/tailscale/tailscale-manager.js +5 -1
  150. package/dist/server/modules/tailscale/tailscale-manager.js.map +1 -1
  151. package/dist/server/modules/tasks/task-helper-client.d.ts +5 -0
  152. package/dist/server/modules/tasks/task-helper-client.js +45 -0
  153. package/dist/server/modules/tasks/task-helper-client.js.map +1 -1
  154. package/dist/server/modules/tasks/task-helper-process-handlers.d.ts +10 -3
  155. package/dist/server/modules/tasks/task-helper-process-handlers.js +7 -5
  156. package/dist/server/modules/tasks/task-helper-process-handlers.js.map +1 -1
  157. package/dist/server/modules/tasks/task-helper-process.js +11 -1
  158. package/dist/server/modules/tasks/task-helper-process.js.map +1 -1
  159. package/dist/server/modules/tasks/task-lane-executors.js +5 -2
  160. package/dist/server/modules/tasks/task-lane-executors.js.map +1 -1
  161. package/dist/server/modules/tasks/task-types.d.ts +3 -0
  162. package/dist/server/modules/tasks/task-types.js +4 -1
  163. package/dist/server/modules/tasks/task-types.js.map +1 -1
  164. package/dist/server/modules/terminal/command-template-service.d.ts +2 -2
  165. package/dist/server/modules/terminal/command-template-service.js +14 -5
  166. package/dist/server/modules/terminal/command-template-service.js.map +1 -1
  167. package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js +1 -1
  168. package/dist/server/modules/terminal/runtime/terminal-log-writer-client.js.map +1 -1
  169. package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js +160 -11
  170. package/dist/server/modules/terminal/runtime/terminal-log-writer-process.js.map +1 -1
  171. package/dist/server/modules/terminal/template-port-runtime.d.ts +13 -2
  172. package/dist/server/modules/terminal/template-port-runtime.js +266 -44
  173. package/dist/server/modules/terminal/template-port-runtime.js.map +1 -1
  174. package/dist/server/modules/terminal/terminal-service.d.ts +4 -0
  175. package/dist/server/modules/terminal/terminal-service.js +65 -4
  176. package/dist/server/modules/terminal/terminal-service.js.map +1 -1
  177. package/dist/server/modules/workbench/workbench-service.js +3 -3
  178. package/dist/server/modules/workbench/workbench-service.js.map +1 -1
  179. package/dist/server/modules/workbench/workspace-panel-snapshot-service.d.ts +1 -0
  180. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js +118 -39
  181. package/dist/server/modules/workbench/workspace-panel-snapshot-service.js.map +1 -1
  182. package/dist/server/modules/workspace/workspace-code-composition.d.ts +1 -0
  183. package/dist/server/modules/workspace/workspace-code-composition.js +277 -2
  184. package/dist/server/modules/workspace/workspace-code-composition.js.map +1 -1
  185. package/dist/server/modules/workspace/workspace-service.js +54 -17
  186. package/dist/server/modules/workspace/workspace-service.js.map +1 -1
  187. package/dist/server/modules/worktree/worktree-cleanup-service.d.ts +1 -1
  188. package/dist/server/modules/worktree/worktree-cleanup-service.js +22 -17
  189. package/dist/server/modules/worktree/worktree-cleanup-service.js.map +1 -1
  190. package/dist/server/modules/worktree/worktree-controller.js +6 -5
  191. package/dist/server/modules/worktree/worktree-controller.js.map +1 -1
  192. package/dist/server/modules/worktree/worktree-manager.d.ts +1 -1
  193. package/dist/server/modules/worktree/worktree-manager.js +26 -19
  194. package/dist/server/modules/worktree/worktree-manager.js.map +1 -1
  195. package/dist/server/modules/worktree/worktree-merge-service.d.ts +2 -2
  196. package/dist/server/modules/worktree/worktree-merge-service.js +34 -27
  197. package/dist/server/modules/worktree/worktree-merge-service.js.map +1 -1
  198. package/dist/server/modules/worktree/worktree-sync-service.d.ts +1 -1
  199. package/dist/server/modules/worktree/worktree-sync-service.js +5 -3
  200. package/dist/server/modules/worktree/worktree-sync-service.js.map +1 -1
  201. package/dist/server/routes/assistant.js +24 -0
  202. package/dist/server/routes/assistant.js.map +1 -1
  203. package/dist/server/routes/butler.js +4 -0
  204. package/dist/server/routes/butler.js.map +1 -1
  205. package/dist/server/routes/client.js +2 -0
  206. package/dist/server/routes/client.js.map +1 -1
  207. package/dist/server/routes/sessions.js +1 -1
  208. package/dist/server/routes/sessions.js.map +1 -1
  209. package/dist/server/routes/system.d.ts +2 -1
  210. package/dist/server/routes/system.js +3 -1
  211. package/dist/server/routes/system.js.map +1 -1
  212. package/dist/server/server/create-server.d.ts +4 -0
  213. package/dist/server/server/create-server.js +67 -8
  214. package/dist/server/server/create-server.js.map +1 -1
  215. package/dist/server/shared/errors/app-error.d.ts +2 -0
  216. package/dist/server/shared/errors/app-error.js +2 -0
  217. package/dist/server/shared/errors/app-error.js.map +1 -1
  218. package/dist/server/shared/http/error-handler.d.ts +2 -1
  219. package/dist/server/shared/http/error-handler.js +3 -2
  220. package/dist/server/shared/http/error-handler.js.map +1 -1
  221. package/dist/server/shared/http/request-abort.d.ts +2 -0
  222. package/dist/server/shared/http/request-abort.js +38 -0
  223. package/dist/server/shared/http/request-abort.js.map +1 -0
  224. package/dist/server/storage/repositories/auth-login-attempt-repository.d.ts +9 -0
  225. package/dist/server/storage/repositories/auth-login-attempt-repository.js +59 -0
  226. package/dist/server/storage/repositories/auth-login-attempt-repository.js.map +1 -0
  227. package/dist/server/storage/repositories/butler-control-session-repository.d.ts +3 -0
  228. package/dist/server/storage/repositories/butler-control-session-repository.js +80 -4
  229. package/dist/server/storage/repositories/butler-control-session-repository.js.map +1 -1
  230. package/dist/server/storage/repositories/butler-inbox-item-repository.js +54 -3
  231. package/dist/server/storage/repositories/butler-inbox-item-repository.js.map +1 -1
  232. package/dist/server/storage/repositories/terminal-instance-repository.js +1 -1
  233. package/dist/server/storage/repositories/terminal-instance-repository.js.map +1 -1
  234. package/dist/server/storage/repositories/user-preference-profile-repository.js +6 -3
  235. package/dist/server/storage/repositories/user-preference-profile-repository.js.map +1 -1
  236. package/dist/server/storage/sqlite/client.js +127 -0
  237. package/dist/server/storage/sqlite/client.js.map +1 -1
  238. package/dist/server/storage/sqlite/schema.sql +19 -1
  239. package/dist/server/types/domain.d.ts +37 -1
  240. package/dist/server/ws/workbench-ws-hub.d.ts +1 -0
  241. package/dist/server/ws/workbench-ws-hub.js +25 -3
  242. package/dist/server/ws/workbench-ws-hub.js.map +1 -1
  243. package/node_modules/@codingns/session-sync-core/dist/patch-builder.d.ts +23 -0
  244. package/node_modules/@codingns/session-sync-core/dist/patch-builder.js +162 -0
  245. package/node_modules/@codingns/session-sync-core/dist/patch-builder.js.map +1 -1
  246. package/node_modules/@codingns/session-sync-core/dist/providers/codex.d.ts +1 -0
  247. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js +89 -33
  248. package/node_modules/@codingns/session-sync-core/dist/providers/codex.js.map +1 -1
  249. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js +18 -2
  250. package/node_modules/@codingns/session-sync-core/dist/runtime/active-run-registry.js.map +1 -1
  251. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.d.ts +3 -1
  252. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js +238 -53
  253. package/node_modules/@codingns/session-sync-core/dist/runtime/codex-runtime.js.map +1 -1
  254. package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js +1 -0
  255. package/node_modules/@codingns/session-sync-core/dist/runtime/provider-runtime-service.js.map +1 -1
  256. package/node_modules/@codingns/session-sync-core/dist/runtime/types.d.ts +6 -2
  257. package/node_modules/@codingns/session-sync-core/dist/types.d.ts +1 -1
  258. package/package.json +1 -1
  259. package/scripts/postinstall.mjs +33 -0
  260. package/dist/public/assets/index-DR2rPNi7.css +0 -1
  261. package/dist/public/assets/index-DTOruahn.js +0 -114
@@ -0,0 +1,13 @@
1
+ import type { ButlerProfile } from "../../types/domain.js";
2
+ import type { ButlerPromptContext } from "./context-aggregator.js";
3
+ import type { ButlerAuthService } from "./butler-auth-service.js";
4
+ import type { SkillManagerService } from "../skills/skill-manager-service.js";
5
+ export declare function syncButlerWorkspaceContext(input: {
6
+ profile: ButlerProfile;
7
+ promptContext: ButlerPromptContext;
8
+ userId: string;
9
+ butlerAuthService: Pick<ButlerAuthService, "ensureWorkspaceCredential" | "getCredentialFilePath">;
10
+ skillManagerService: Pick<SkillManagerService, "getOverview" | "importUnmanagedSkill">;
11
+ codexHomeDir: string | null;
12
+ sourceCodexHomeDir: string | null;
13
+ }): void;
@@ -0,0 +1,234 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { ensureButlerWorkspaceIsolation } from "./butler-profile-service.js";
5
+ export function syncButlerWorkspaceContext(input) {
6
+ fs.mkdirSync(input.profile.workspacePath, { recursive: true });
7
+ ensureButlerWorkspaceIsolation(input.profile.workspacePath);
8
+ const auth = input.butlerAuthService.ensureWorkspaceCredential(input.profile.workspacePath, input.userId);
9
+ const authFilePath = input.butlerAuthService.getCredentialFilePath(input.profile.workspacePath);
10
+ writeInstructionFiles(input.profile, input.promptContext, auth, authFilePath);
11
+ syncCodexInstructionConfig(input.profile, input.skillManagerService, input.codexHomeDir, input.sourceCodexHomeDir);
12
+ }
13
+ function writeInstructionFiles(profile, promptContext, auth, authFilePath) {
14
+ const rootAgentsPath = path.join(profile.workspacePath, "AGENTS.md");
15
+ writeFileIfChanged(rootAgentsPath, composeInstructionContent(profile, promptContext));
16
+ if (profile.agentsMode === "file" && profile.agentsFilePath) {
17
+ writeFileIfChanged(profile.agentsFilePath, composeInstructionContent(profile, promptContext));
18
+ }
19
+ if (profile.providerId === "claude-code") {
20
+ const claudeFilePath = path.join(profile.workspacePath, "CLAUDE.md");
21
+ writeFileIfChanged(claudeFilePath, composeInstructionContent(profile, promptContext));
22
+ }
23
+ writeFileIfChanged(path.join(profile.workspacePath, "BUTLER_CONTEXT.md"), `${promptContext.prompt.trim()}\n`);
24
+ writeFileIfChanged(path.join(profile.workspacePath, "BUTLER_API.md"), buildApiGuideContent(auth, authFilePath));
25
+ }
26
+ function syncCodexInstructionConfig(profile, skillManagerService, codexHomeDir, sourceCodexHomeDir) {
27
+ if (profile.providerId !== "codex" || !codexHomeDir?.trim()) {
28
+ return;
29
+ }
30
+ const targetHomeDir = path.resolve(codexHomeDir);
31
+ const sourceHomeDir = resolveSourceCodexHomeDir(sourceCodexHomeDir, targetHomeDir);
32
+ const sourceConfigPath = path.join(sourceHomeDir, "config.toml");
33
+ const instructionFilePath = profile.agentsMode === "file" && profile.agentsFilePath
34
+ ? path.resolve(profile.agentsFilePath)
35
+ : path.join(profile.workspacePath, "AGENTS.md");
36
+ const sourceConfigContent = sourceHomeDir !== targetHomeDir && fs.existsSync(sourceConfigPath) && fs.statSync(sourceConfigPath).isFile()
37
+ ? fs.readFileSync(sourceConfigPath, "utf8")
38
+ : "";
39
+ const configContent = composeCodexConfigContent(sourceConfigContent, instructionFilePath);
40
+ fs.mkdirSync(targetHomeDir, { recursive: true });
41
+ removeFileIfExists(path.join(targetHomeDir, "AGENTS.md"));
42
+ removeFileIfExists(path.join(targetHomeDir, "AGENTS.override.md"));
43
+ // Butler 运行在独立 home,下游会话仍然需要沿用当前 Codex 登录态。
44
+ syncOptionalFile(path.join(sourceHomeDir, "auth.json"), path.join(targetHomeDir, "auth.json"));
45
+ syncButlerCodexSkill(skillManagerService, path.join(targetHomeDir, "skills", "codingns-assistant"));
46
+ writeFileIfChanged(path.join(targetHomeDir, "config.toml"), `${configContent}\n`);
47
+ }
48
+ function syncButlerCodexSkill(skillManagerService, targetSkillPath) {
49
+ const skillDirectoryName = "codingns-assistant";
50
+ const overview = skillManagerService.getOverview({
51
+ targetCli: ["codex"]
52
+ });
53
+ const managedSkill = overview.managedSkills.find((item) => item.skill.directoryName === skillDirectoryName);
54
+ if (managedSkill) {
55
+ syncOptionalDirectory(managedSkill.ssotPath, targetSkillPath);
56
+ return;
57
+ }
58
+ const unmanagedEntry = overview.unmanagedEntries.find((entry) => entry.targetCli === "codex" && entry.directoryName === skillDirectoryName);
59
+ if (unmanagedEntry) {
60
+ const imported = skillManagerService.importUnmanagedSkill({
61
+ targetCli: "codex",
62
+ directoryPath: unmanagedEntry.directoryPath,
63
+ expectedContentHash: unmanagedEntry.contentHash
64
+ });
65
+ syncOptionalDirectory(imported.ssotPath, targetSkillPath);
66
+ return;
67
+ }
68
+ fs.rmSync(targetSkillPath, { recursive: true, force: true });
69
+ }
70
+ function composeInstructionContent(profile, promptContext) {
71
+ return `${profile.agentsContent.trim()}
72
+
73
+ ## 代码助手运行附加说明(系统自动生成)
74
+
75
+ - 当前工作目录是代码助手专用目录,只使用这里的助手规则,不回退到普通项目会话规则。
76
+ - 你是代码助手控制面,不是项目实现者。默认职责只有:查看、分析、归纳、补查信息、安排下一步、把指令发送给真实项目会话或终端。
77
+ - 禁止直接改业务项目代码、禁止直接生成补丁并落盘、禁止自己在项目目录里写实现。用户要推进开发时,只能通过内部 API 续接/新建项目会话、发送消息、查询结果,或者操作受控终端。
78
+ - 如果用户要求“修改代码”“继续实现”“修 bug”,先定位目标项目和目标会话;没有会话就先新建/续接项目会话,再把任务发给那个会话继续做,不要自己在 Butler 工作目录里动手。
79
+ - 当前聚合后的平台摘要写在 \`BUTLER_CONTEXT.md\`,先看这里,不要把所有项目原始记录一股脑塞进回答。
80
+ - 当前摘要作用域以 \`BUTLER_CONTEXT.md\` 的最新内容为准;这次生成时记录的是:${promptContext.scope === "project" ? `项目 ${promptContext.projectId}` : "全局总览"}。如果后续上下文文件已刷新,以文件里的当前作用域为准,不要被旧缓存绑死。
81
+ - 你自己的主工具入口不是一堆 HTTP 路由,而是 \`codingns assistant ...\`。真正执行前,先用 \`codingns assistant --help\`、\`codingns assistant help <group>\`、\`codingns assistant <group> <action> --help\` 按需查命令。
82
+ - 如果当前 Codex 环境能发现 \`codingns-assistant\` skill,优先按这个 skill 的流程工作:先确认 CLI 的默认认证入口可用,再查能力,再查项目/会话/终端,再决定是否发送消息、fork 或发终端输入。
83
+ - 默认查询顺序固定为:先看 \`BUTLER_CONTEXT.md\`,再确认 CLI 认证入口可用,然后用 \`codingns assistant capabilities list\` 确认能力,再按 \`projects / sessions / terminals\` 分组查具体对象;不要先翻一大堆旧 REST 文档。
84
+ - 如果你在跟进开发会话,且目标或上下文里提到了 spec,只能围绕 spec 明确写出的必做项推进,不能顺着建议项无限扩展开发范围。
85
+ - 如果当前没有 spec,就先从用户要求和会话现状里归纳一句核心任务,后续只围绕这个核心任务推进;不要把建议项、最佳实践、顺手优化当成必做项。
86
+ - 如果用户的问题里已经带了项目名、会话名、错误词或任务关键词,先通过 \`codingns assistant projects --help\`、\`codingns assistant sessions --help\` 选对命令,再查目标对象;如果用户明确点名历史会话或归档会话,按 help 提示补充筛选参数。
87
+ - 如果 \`BUTLER_CONTEXT.md\` 里的项目数或会话数是 0,不能直接下结论,必须先确认 CLI 认证入口可用,再跑 \`codingns assistant capabilities list\` 和 \`codingns assistant projects list\` 确认真实状态。
88
+ - 如果用户追问的细节超出当前摘要,先明确缺口,再按 \`BUTLER_API.md\` 里记录的 CLI 顺序补查项目、会话、消息窗口或终端历史。
89
+ - 如果用户追问会话内容,先定位 \`sessionId\`,再优先用 \`codingns assistant sessions messages <sessionId>\` 查看最近消息,不要只复述摘要。
90
+ - 需要推进开发时,优先用 \`codingns assistant sessions send <sessionId> --message ...\`;只有明确需要 shell 链路时,才用 \`codingns assistant terminals send <terminalId> --input ...\`。
91
+ - 不要编造不存在的项目状态;信息不足时直接说缺什么。
92
+ `;
93
+ }
94
+ function buildApiGuideContent(auth, authFilePath) {
95
+ return `# 代码助手 CLI 与按需补查指南
96
+
97
+ 默认不要直接背 HTTP 路由。先用 \`codingns assistant ...\` 和分层 help 按需查询。
98
+
99
+ ## 固定认证方式
100
+
101
+ - Butler 专用凭证文件:\`${path.basename(authFilePath)}\`
102
+ - 凭证文件路径:\`${authFilePath}\`
103
+ - 当前 API 基地址:\`${auth.apiBaseUrl}\`
104
+ - 默认直接执行 \`codingns assistant ...\`;CLI 会优先按固定顺序读取认证。
105
+
106
+ ## CLI 默认认证顺序
107
+
108
+ 1. 显式传入的 \`--token\` / \`--base-url\`
109
+ 2. 环境变量 \`CODINGNS_ACCESS_TOKEN\` / \`CODINGNS_BASE_URL\`
110
+ 3. 环境变量 \`CODINGNS_AUTH_FILE\` 或 \`BUTLER_AUTH_FILE\` 指向的认证文件
111
+ 4. 当前目录及上级目录里的 \`BUTLER_AUTH.json\`
112
+
113
+ ## 什么时候手工导出环境变量
114
+
115
+ - 只有当你不在 Butler 工作区、CLI 自动发现失败,或者要临时切到别的 Host / 凭证文件时,才手工导出环境变量。
116
+ - 默认不要把“先 export 再执行”当成每轮固定动作。
117
+
118
+ \`\`\`bash
119
+ export CODINGNS_BASE_URL="$(jq -r '.apiBaseUrl' "${authFilePath}")"
120
+ export CODINGNS_ACCESS_TOKEN="$(jq -r '.accessToken' "${authFilePath}")"
121
+ \`\`\`
122
+
123
+ ## 默认读取顺序
124
+
125
+ 1. 先读 \`BUTLER_CONTEXT.md\` 的当前摘要。
126
+ 2. 先确认 CLI 认证入口可用;在 Butler 工作区里默认直接执行即可,必要时再核对上面的凭证文件路径。
127
+ 3. 认证入口可用后,再跑 \`codingns assistant capabilities list\`,确认当前开放能力。
128
+ 4. 不知道怎么查时,先跑 \`codingns assistant --help\`、\`codingns assistant help projects\`、\`codingns assistant help sessions\`、\`codingns assistant help terminals\`。
129
+ 5. 要找项目时,先 \`codingns assistant projects list\`,需要详情时再 \`projects get <projectId>\`。
130
+ 6. 要找会话时,先 \`codingns assistant sessions list --project <projectId>\`,再按需要用 \`sessions get\`、\`sessions runtime\`、\`sessions messages\`。
131
+ 7. 要推进开发时,优先 \`codingns assistant sessions send <sessionId> --message "..."\`。
132
+ 8. 只有明确需要 shell 链路时,先 \`terminals list\`、\`terminals history\`,再决定是否 \`terminals send\`。
133
+ 9. 要开新分支时,再用 \`codingns assistant sessions fork <sessionId>\`。
134
+
135
+ ## 执行边界
136
+
137
+ - 你不能直接修改项目代码,也不能把自己当成项目执行会话。
138
+ - 需要推进开发时,只能通过下面这些 CLI 命令驱动真实项目会话或受控终端。
139
+ - 需要命令结果时,优先查终端历史;确实要执行命令,再向受控终端发送输入。
140
+ - 需要分叉会话时,统一走 \`codingns assistant sessions fork\`,不要自己伪造一条“新上下文”继续编。
141
+
142
+ ## help 入口
143
+
144
+ \`\`\`bash
145
+ codingns assistant --help
146
+ codingns assistant help projects
147
+ codingns assistant help sessions
148
+ codingns assistant sessions send --help
149
+ codingns assistant terminals send --help
150
+ \`\`\`
151
+
152
+ ## 常用命令
153
+
154
+ - \`codingns assistant capabilities list\`:查看当前 Butler 可用能力。
155
+ - \`codingns assistant projects list\`:列出托管项目。
156
+ - \`codingns assistant projects get <projectId>\`:读取项目详情和项目下可操作会话。
157
+ - \`codingns assistant sessions list --project <projectId>\`:列出项目会话。
158
+ - \`codingns assistant sessions get <sessionId>\`:读取真实会话详情。
159
+ - \`codingns assistant sessions messages <sessionId> --limit 40\`:读取最近消息窗口。
160
+ - \`codingns assistant sessions runtime <sessionId>\`:查看会话是否还在运行。
161
+ - \`codingns assistant sessions send <sessionId> --message "..."\`:向真实项目会话发消息。
162
+ - \`codingns assistant sessions fork <sessionId> --message-id <messageId>\`:从消息点 fork 新会话。
163
+ - \`codingns assistant terminals list --project-id <projectId>\`:列出项目下终端。
164
+ - \`codingns assistant terminals history <terminalId> --limit 50\`:读取终端最近输出。
165
+ - \`codingns assistant terminals send <terminalId> --input "npm test\\n"\`:向终端发送输入。
166
+
167
+ ## 底层说明
168
+
169
+ - 上面这些命令最终还是调用宿主系统的 \`/api/assistant/*\`。
170
+ - 只有当 CLI 还没覆盖某个极少数细节时,才回退到底层 HTTP。
171
+ `;
172
+ }
173
+ function resolveSourceCodexHomeDir(sourceCodexHomeDir, targetHomeDir) {
174
+ const configuredSource = sourceCodexHomeDir?.trim();
175
+ if (configuredSource) {
176
+ const resolvedConfiguredSource = path.resolve(configuredSource);
177
+ if (resolvedConfiguredSource !== targetHomeDir) {
178
+ return resolvedConfiguredSource;
179
+ }
180
+ }
181
+ const fallbackHomeDir = path.resolve(path.join(os.homedir(), ".codex"));
182
+ if (fallbackHomeDir !== targetHomeDir) {
183
+ return fallbackHomeDir;
184
+ }
185
+ return targetHomeDir;
186
+ }
187
+ function composeCodexConfigContent(sourceConfigContent, instructionFilePath) {
188
+ const normalizedSource = sourceConfigContent
189
+ .split(/\r?\n/)
190
+ .filter((line) => {
191
+ const trimmed = line.trim();
192
+ return trimmed.length > 0 && !trimmed.startsWith("model_instructions_file");
193
+ })
194
+ .join("\n")
195
+ .trim();
196
+ return [
197
+ "# 代码助手专用 Codex 配置(系统自动生成)",
198
+ normalizedSource,
199
+ `model_instructions_file = ${toTomlString(instructionFilePath)}`
200
+ ]
201
+ .filter((part) => part.trim().length > 0)
202
+ .join("\n\n");
203
+ }
204
+ function writeFileIfChanged(filePath, content) {
205
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
206
+ if (fs.existsSync(filePath) && fs.readFileSync(filePath, "utf8") === content) {
207
+ return;
208
+ }
209
+ fs.writeFileSync(filePath, content, "utf8");
210
+ }
211
+ function syncOptionalFile(sourcePath, targetPath) {
212
+ if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isFile()) {
213
+ return;
214
+ }
215
+ writeFileIfChanged(targetPath, fs.readFileSync(sourcePath, "utf8"));
216
+ }
217
+ function syncOptionalDirectory(sourcePath, targetPath) {
218
+ if (!fs.existsSync(sourcePath) || !fs.statSync(sourcePath).isDirectory()) {
219
+ return;
220
+ }
221
+ fs.rmSync(targetPath, { recursive: true, force: true });
222
+ fs.mkdirSync(path.dirname(targetPath), { recursive: true });
223
+ fs.cpSync(sourcePath, targetPath, { recursive: true });
224
+ }
225
+ function removeFileIfExists(filePath) {
226
+ if (!fs.existsSync(filePath)) {
227
+ return;
228
+ }
229
+ fs.rmSync(filePath, { force: true });
230
+ }
231
+ function toTomlString(value) {
232
+ return `"${value.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"")}"`;
233
+ }
234
+ //# sourceMappingURL=butler-workspace-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"butler-workspace-context.js","sourceRoot":"","sources":["../../../../src/modules/butler/butler-workspace-context.ts"],"names":[],"mappings":"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"}
@@ -6,4 +6,10 @@ export declare class ClientController {
6
6
  readonly getRuntimeConfig: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
7
7
  readonly getReleaseManifest: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
8
8
  readonly getServiceUpdate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
9
+ readonly installServiceUpdate: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
10
+ readonly getServiceUpdateTask: (request: FastifyRequest<{
11
+ Params: {
12
+ taskId: string;
13
+ };
14
+ }>, reply: FastifyReply) => Promise<void>;
9
15
  }
@@ -31,7 +31,7 @@ export class ClientController {
31
31
  throw new AppError({
32
32
  statusCode: 400,
33
33
  errorCode: "INVALID_PLATFORM",
34
- detail: "缺少桌面平台标识",
34
+ detail: "缺少发布平台标识",
35
35
  field: "platform"
36
36
  });
37
37
  }
@@ -39,17 +39,29 @@ export class ClientController {
39
39
  reply.send(this.clientService.getReleaseManifest(channel, query.platform));
40
40
  };
41
41
  getServiceUpdate = async (request, reply) => {
42
- if (!request.auth?.user.userId) {
43
- throw new AppError({
44
- statusCode: 401,
45
- errorCode: "UNAUTHORIZED",
46
- detail: "当前请求缺少有效登录态"
47
- });
48
- }
42
+ ensureAuthenticated(request);
49
43
  const query = request.query;
50
44
  const channel = query.channel === "beta" ? "beta" : "stable";
51
45
  reply.send(await this.clientService.getServiceUpdate(channel));
52
46
  };
47
+ installServiceUpdate = async (request, reply) => {
48
+ ensureAuthenticated(request);
49
+ const body = request.body;
50
+ if (!body?.packageName) {
51
+ throw new AppError({
52
+ statusCode: 400,
53
+ errorCode: "SERVICE_UPDATE_PACKAGE_REQUIRED",
54
+ detail: "缺少需要升级的 npm 包名",
55
+ field: "packageName"
56
+ });
57
+ }
58
+ const channel = body.channel === "beta" ? "beta" : "stable";
59
+ reply.send(await this.clientService.installServiceUpdate(channel, body.packageName));
60
+ };
61
+ getServiceUpdateTask = async (request, reply) => {
62
+ ensureAuthenticated(request);
63
+ reply.send(this.clientService.getServiceUpdateTask(request.params.taskId));
64
+ };
53
65
  }
54
66
  function readRequestProtocol(request) {
55
67
  const forwarded = request.headers["x-forwarded-proto"];
@@ -62,4 +74,14 @@ function normalizePlatform(query) {
62
74
  const platform = query?.platform;
63
75
  return platform === "desktop" ? "desktop" : "web";
64
76
  }
77
+ function ensureAuthenticated(request) {
78
+ if (request.auth?.user.userId) {
79
+ return;
80
+ }
81
+ throw new AppError({
82
+ statusCode: 401,
83
+ errorCode: "UNAUTHORIZED",
84
+ detail: "当前请求缺少有效登录态"
85
+ });
86
+ }
65
87
  //# sourceMappingURL=client-controller.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-controller.js","sourceRoot":"","sources":["../../../../src/modules/client/client-controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client-controller.js","sourceRoot":"","sources":["../../../../src/modules/client/client-controller.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,7 @@
1
1
  import type { HostConfig } from "../../config/env.js";
2
+ import type { NpmGlobalPackageService } from "./npm-global-package-service.js";
3
+ import type { ServiceUpdateTaskService } from "./service-update-task-service.js";
4
+ import type { ServiceUpdateListDto, ServiceUpdateTaskDto } from "./service-update-types.js";
2
5
  export interface ClientRuntimeConfigDto {
3
6
  platform: "desktop" | "web";
4
7
  hostBaseUrl: string;
@@ -6,7 +9,7 @@ export interface ClientRuntimeConfigDto {
6
9
  autoReconnect: boolean;
7
10
  autoCheckUpdate: boolean;
8
11
  }
9
- export interface ReleaseManifestDto {
12
+ export interface DesktopReleaseManifestDto {
10
13
  channel: "stable" | "beta";
11
14
  platform: string;
12
15
  version: string;
@@ -15,23 +18,32 @@ export interface ReleaseManifestDto {
15
18
  signature: string;
16
19
  publishedAt: string;
17
20
  }
18
- export interface ServiceUpdateDto {
21
+ export interface AndroidReleaseManifestDto {
19
22
  channel: "stable" | "beta";
23
+ version: string;
24
+ versionCode: number;
20
25
  packageName: string;
21
- registryUrl: string;
22
- packagePageUrl: string;
23
- currentVersion: string;
24
- latestVersion: string | null;
25
- hasUpdate: boolean;
26
- updateCommand: string;
26
+ fileName: string;
27
+ downloadUrl: string;
28
+ sha256: string;
29
+ publishedAt: string;
30
+ notes: string;
31
+ minSupportedVersionCode: number | null;
32
+ htmlUrl: string | null;
27
33
  }
34
+ export type ReleaseManifestDto = DesktopReleaseManifestDto | AndroidReleaseManifestDto;
28
35
  export declare class ClientService {
29
36
  private readonly config;
30
- constructor(config: HostConfig);
37
+ private readonly npmGlobalPackageService;
38
+ private readonly serviceUpdateTaskService;
39
+ constructor(config: HostConfig, npmGlobalPackageService: NpmGlobalPackageService, serviceUpdateTaskService: ServiceUpdateTaskService);
31
40
  getRuntimeConfig(platform: "desktop" | "web", requestContext?: {
32
41
  readonly protocol?: string | null;
33
42
  readonly host?: string | null;
34
43
  }): ClientRuntimeConfigDto;
35
44
  getReleaseManifest(channel: "stable" | "beta", platform: string): ReleaseManifestDto;
36
- getServiceUpdate(channel: "stable" | "beta"): Promise<ServiceUpdateDto>;
45
+ getServiceUpdate(channel: "stable" | "beta"): Promise<ServiceUpdateListDto>;
46
+ installServiceUpdate(channel: "stable" | "beta", packageName: string): Promise<ServiceUpdateTaskDto>;
47
+ getServiceUpdateTask(taskId: string): ServiceUpdateTaskDto;
37
48
  }
49
+ export declare function readHostPackageVersion(): string;
@@ -4,8 +4,12 @@ import { fileURLToPath } from "node:url";
4
4
  import { AppError } from "../../shared/errors/app-error.js";
5
5
  export class ClientService {
6
6
  config;
7
- constructor(config) {
7
+ npmGlobalPackageService;
8
+ serviceUpdateTaskService;
9
+ constructor(config, npmGlobalPackageService, serviceUpdateTaskService) {
8
10
  this.config = config;
11
+ this.npmGlobalPackageService = npmGlobalPackageService;
12
+ this.serviceUpdateTaskService = serviceUpdateTaskService;
9
13
  }
10
14
  getRuntimeConfig(platform, requestContext) {
11
15
  return {
@@ -28,72 +32,89 @@ export class ClientService {
28
32
  const raw = fs.readFileSync(manifestPath, "utf8");
29
33
  try {
30
34
  const parsed = JSON.parse(raw);
31
- if (!parsed.channel ||
32
- !parsed.platform ||
33
- !parsed.version ||
34
- !parsed.packageUrl ||
35
- !parsed.signature ||
36
- !parsed.publishedAt) {
37
- throw new Error("manifest incomplete");
35
+ if (platform === "android-apk") {
36
+ return parseAndroidReleaseManifest(parsed);
38
37
  }
39
- return {
40
- channel: parsed.channel,
41
- platform: parsed.platform,
42
- version: parsed.version,
43
- notes: parsed.notes ?? "",
44
- packageUrl: parsed.packageUrl,
45
- signature: parsed.signature,
46
- publishedAt: parsed.publishedAt
47
- };
38
+ return parseDesktopReleaseManifest(parsed);
48
39
  }
49
40
  catch {
50
41
  throw new AppError({
51
42
  statusCode: 500,
52
43
  errorCode: "MANIFEST_INVALID",
53
- detail: `桌面发布清单 ${manifestPath} 格式无效`
44
+ detail: `发布清单 ${manifestPath} 格式无效`
54
45
  });
55
46
  }
56
47
  }
57
48
  async getServiceUpdate(channel) {
58
- const packageName = this.config.serverUpdatePackageName;
59
49
  const currentVersion = readHostPackageVersion();
60
- const packagePageUrl = `https://www.npmjs.com/package/${packageName}`;
61
- const registryUrl = buildRegistryPackageUrl(this.config.npmRegistryBaseUrl, packageName);
62
- try {
63
- const response = await fetch(registryUrl, {
64
- headers: {
65
- Accept: "application/json"
66
- }
67
- });
68
- if (!response.ok) {
69
- throw new Error(`HTTP ${response.status}`);
70
- }
71
- const raw = (await response.json());
72
- const latestVersion = pickServiceTargetVersion(raw, channel);
73
- return {
74
- channel,
75
- packageName,
76
- registryUrl,
77
- packagePageUrl,
78
- currentVersion,
79
- latestVersion,
80
- hasUpdate: latestVersion !== null && compareSemver(latestVersion, currentVersion) > 0,
81
- updateCommand: `npm install ${packageName}@${channel === "beta" ? "beta" : "latest"}`
82
- };
83
- }
84
- catch {
85
- return {
86
- channel,
87
- packageName,
88
- registryUrl,
89
- packagePageUrl,
90
- currentVersion,
91
- latestVersion: null,
92
- hasUpdate: false,
93
- updateCommand: `npm install ${packageName}@${channel === "beta" ? "beta" : "latest"}`
94
- };
95
- }
50
+ const packages = await this.npmGlobalPackageService.listManagedPackages(channel, currentVersion, (packageName) => this.serviceUpdateTaskService.getLatestTaskByPackageName(packageName));
51
+ return {
52
+ channel,
53
+ checkedAt: new Date().toISOString(),
54
+ packages
55
+ };
56
+ }
57
+ async installServiceUpdate(channel, packageName) {
58
+ return await this.serviceUpdateTaskService.installPackage(channel, packageName);
96
59
  }
60
+ getServiceUpdateTask(taskId) {
61
+ return this.serviceUpdateTaskService.getTask(taskId);
62
+ }
63
+ }
64
+ function parseDesktopReleaseManifest(parsed) {
65
+ if (!isReleaseChannel(parsed.channel) ||
66
+ !isNonEmptyString(parsed.platform) ||
67
+ !isNonEmptyString(parsed.version) ||
68
+ !isNonEmptyString(parsed.packageUrl) ||
69
+ !isNonEmptyString(parsed.signature) ||
70
+ !isNonEmptyString(parsed.publishedAt)) {
71
+ throw new Error("desktop manifest incomplete");
72
+ }
73
+ return {
74
+ channel: parsed.channel,
75
+ platform: parsed.platform,
76
+ version: parsed.version,
77
+ notes: isNonEmptyString(parsed.notes) ? parsed.notes : "",
78
+ packageUrl: parsed.packageUrl,
79
+ signature: parsed.signature,
80
+ publishedAt: parsed.publishedAt
81
+ };
82
+ }
83
+ function parseAndroidReleaseManifest(parsed) {
84
+ if (!isReleaseChannel(parsed.channel) ||
85
+ !isNonEmptyString(parsed.version) ||
86
+ !isPositiveInteger(parsed.versionCode) ||
87
+ !isNonEmptyString(parsed.packageName) ||
88
+ !isNonEmptyString(parsed.fileName) ||
89
+ !isNonEmptyString(parsed.downloadUrl) ||
90
+ !isNonEmptyString(parsed.sha256) ||
91
+ !isNonEmptyString(parsed.publishedAt)) {
92
+ throw new Error("android manifest incomplete");
93
+ }
94
+ return {
95
+ channel: parsed.channel,
96
+ version: parsed.version,
97
+ versionCode: parsed.versionCode,
98
+ packageName: parsed.packageName,
99
+ fileName: parsed.fileName,
100
+ downloadUrl: parsed.downloadUrl,
101
+ sha256: parsed.sha256,
102
+ publishedAt: parsed.publishedAt,
103
+ notes: isNonEmptyString(parsed.notes) ? parsed.notes : "",
104
+ minSupportedVersionCode: isPositiveInteger(parsed.minSupportedVersionCode)
105
+ ? parsed.minSupportedVersionCode
106
+ : null,
107
+ htmlUrl: isNonEmptyString(parsed.htmlUrl) ? parsed.htmlUrl : null
108
+ };
109
+ }
110
+ function isReleaseChannel(value) {
111
+ return value === "stable" || value === "beta";
112
+ }
113
+ function isNonEmptyString(value) {
114
+ return typeof value === "string" && value.trim().length > 0;
115
+ }
116
+ function isPositiveInteger(value) {
117
+ return typeof value === "number" && Number.isInteger(value) && value > 0;
97
118
  }
98
119
  function resolveClientHostBaseUrl(config, platform, requestContext) {
99
120
  if (platform === "web") {
@@ -114,7 +135,7 @@ function resolveAccessibleHost(host) {
114
135
  }
115
136
  return host;
116
137
  }
117
- function readHostPackageVersion() {
138
+ export function readHostPackageVersion() {
118
139
  const packageJsonPath = findNearestPackageJson(fileURLToPath(import.meta.url));
119
140
  if (!packageJsonPath) {
120
141
  return "0.0.0";
@@ -125,50 +146,6 @@ function readHostPackageVersion() {
125
146
  ? parsed.version
126
147
  : "0.0.0";
127
148
  }
128
- function buildRegistryPackageUrl(baseUrl, packageName) {
129
- const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
130
- return new URL(encodeURIComponent(packageName), normalizedBaseUrl).toString();
131
- }
132
- function pickServiceTargetVersion(payload, channel) {
133
- const distTags = payload["dist-tags"] ?? {};
134
- if (channel === "beta") {
135
- return distTags.beta ?? distTags.latest ?? null;
136
- }
137
- return distTags.latest ?? null;
138
- }
139
- function compareSemver(left, right) {
140
- const leftMeta = parseSemver(left);
141
- const rightMeta = parseSemver(right);
142
- for (let index = 0; index < 3; index += 1) {
143
- const diff = (leftMeta.numbers[index] ?? 0) - (rightMeta.numbers[index] ?? 0);
144
- if (diff !== 0) {
145
- return diff;
146
- }
147
- }
148
- if (leftMeta.prerelease === rightMeta.prerelease) {
149
- return 0;
150
- }
151
- if (!leftMeta.prerelease) {
152
- return 1;
153
- }
154
- if (!rightMeta.prerelease) {
155
- return -1;
156
- }
157
- return leftMeta.prerelease.localeCompare(rightMeta.prerelease);
158
- }
159
- function parseSemver(input) {
160
- const normalized = input.trim().replace(/^v/i, "");
161
- const [versionPart, prerelease = ""] = normalized.split("-", 2);
162
- const rawNumbers = versionPart.split(".");
163
- return {
164
- numbers: [
165
- Number.parseInt(rawNumbers[0] ?? "0", 10) || 0,
166
- Number.parseInt(rawNumbers[1] ?? "0", 10) || 0,
167
- Number.parseInt(rawNumbers[2] ?? "0", 10) || 0
168
- ],
169
- prerelease
170
- };
171
- }
172
149
  function findNearestPackageJson(fromFilePath) {
173
150
  let currentDir = path.dirname(fromFilePath);
174
151
  while (true) {