@cjhyy/code-shell-core 0.5.0-rc.0 → 0.5.0-rc.2

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 (283) hide show
  1. package/dist/agent/agent-definition-registry.d.ts +29 -0
  2. package/dist/agent/agent-definition-registry.js +74 -0
  3. package/dist/agent/agent-definition.d.ts +37 -0
  4. package/dist/agent/agent-definition.js +59 -0
  5. package/dist/arena/arena.js +11 -12
  6. package/dist/arena/context/context-tools.js +2 -4
  7. package/dist/arena/context/within-root.d.ts +7 -0
  8. package/dist/arena/context/within-root.js +15 -0
  9. package/dist/arena/iterate/phases/argue.js +8 -2
  10. package/dist/arena/iterate/phases/revise.js +1 -1
  11. package/dist/arena/iterate/phases/tournament.js +3 -3
  12. package/dist/arena/phases/adjudication.js +1 -4
  13. package/dist/arena/phases/build-consensus.js +1 -4
  14. package/dist/arena/phases/cross-review.js +2 -8
  15. package/dist/arena/phases/debate-rounds.js +1 -4
  16. package/dist/arena/phases/participant-research.js +1 -4
  17. package/dist/arena/phases/planning-detail-expansion.js +8 -10
  18. package/dist/arena/planner.js +0 -1
  19. package/dist/arena/providers/docs.d.ts +1 -0
  20. package/dist/arena/providers/docs.js +5 -2
  21. package/dist/arena/providers/repo.d.ts +1 -0
  22. package/dist/arena/providers/repo.js +5 -2
  23. package/dist/arena/strategies/utils.js +36 -3
  24. package/dist/arena/transitions.d.ts +7 -2
  25. package/dist/arena/transitions.js +9 -4
  26. package/dist/arena/types.d.ts +8 -2
  27. package/dist/automation/cron-expr.d.ts +31 -0
  28. package/dist/automation/cron-expr.js +151 -0
  29. package/dist/automation/index.d.ts +41 -0
  30. package/dist/automation/index.js +39 -0
  31. package/dist/automation/runner.d.ts +67 -0
  32. package/dist/automation/runner.js +56 -0
  33. package/dist/automation/scheduler.d.ts +156 -0
  34. package/dist/automation/scheduler.js +546 -0
  35. package/dist/automation/store.d.ts +39 -0
  36. package/dist/automation/store.js +119 -0
  37. package/dist/automation/write-policy.d.ts +34 -0
  38. package/dist/automation/write-policy.js +113 -0
  39. package/dist/automation/write-run.d.ts +51 -0
  40. package/dist/automation/write-run.js +38 -0
  41. package/dist/capability-control/index.d.ts +5 -0
  42. package/dist/capability-control/index.js +3 -0
  43. package/dist/capability-control/overlay.d.ts +49 -0
  44. package/dist/capability-control/overlay.js +89 -0
  45. package/dist/capability-control/project.d.ts +65 -0
  46. package/dist/capability-control/project.js +147 -0
  47. package/dist/capability-control/service.d.ts +70 -0
  48. package/dist/capability-control/service.js +147 -0
  49. package/dist/capability-control/types.d.ts +62 -0
  50. package/dist/capability-control/types.js +17 -0
  51. package/dist/cli/agent-server-stdio.d.ts +12 -1
  52. package/dist/cli/agent-server-stdio.js +118 -18
  53. package/dist/cli/agent-server-tcp.d.ts +20 -0
  54. package/dist/cli/agent-server-tcp.js +120 -0
  55. package/dist/cli/graceful-shutdown.d.ts +27 -0
  56. package/dist/cli/graceful-shutdown.js +30 -0
  57. package/dist/context/compaction.js +23 -15
  58. package/dist/context/manager.d.ts +0 -20
  59. package/dist/context/manager.js +0 -37
  60. package/dist/cron/cron-runtime.d.ts +2 -0
  61. package/dist/cron/cron-runtime.js +2 -0
  62. package/dist/cron/cron-store.d.ts +2 -0
  63. package/dist/cron/cron-store.js +2 -0
  64. package/dist/cron/scheduler.d.ts +5 -32
  65. package/dist/cron/scheduler.js +5 -113
  66. package/dist/data/openrouter-sync.js +1 -1
  67. package/dist/engine/engine.d.ts +256 -16
  68. package/dist/engine/engine.js +856 -200
  69. package/dist/engine/goal.d.ts +42 -0
  70. package/dist/engine/goal.js +52 -0
  71. package/dist/engine/image-compression.d.ts +81 -0
  72. package/dist/engine/image-compression.js +186 -0
  73. package/dist/engine/image-policy.d.ts +152 -0
  74. package/dist/engine/image-policy.js +165 -0
  75. package/dist/engine/reactive-threshold.d.ts +13 -0
  76. package/dist/engine/reactive-threshold.js +17 -0
  77. package/dist/engine/runtime.js +7 -0
  78. package/dist/engine/session-title.d.ts +13 -0
  79. package/dist/engine/session-title.js +34 -0
  80. package/dist/engine/turn-loop.d.ts +29 -8
  81. package/dist/engine/turn-loop.js +498 -316
  82. package/dist/git/parse-log.d.ts +13 -0
  83. package/dist/git/parse-log.js +21 -0
  84. package/dist/git/utils.d.ts +8 -6
  85. package/dist/git/utils.js +57 -26
  86. package/dist/git/worktree.js +33 -18
  87. package/dist/hooks/events.d.ts +23 -1
  88. package/dist/hooks/goal-stop-hook.d.ts +30 -0
  89. package/dist/hooks/goal-stop-hook.js +102 -0
  90. package/dist/hooks/hook-output.d.ts +33 -0
  91. package/dist/hooks/hook-output.js +79 -0
  92. package/dist/hooks/registry.d.ts +7 -0
  93. package/dist/hooks/registry.js +38 -1
  94. package/dist/hooks/shell-runner.d.ts +2 -0
  95. package/dist/hooks/shell-runner.js +43 -2
  96. package/dist/index.d.ts +32 -7
  97. package/dist/index.js +30 -3
  98. package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
  99. package/dist/llm/capabilities/reasoning-control.js +38 -0
  100. package/dist/llm/capabilities/rules.js +33 -3
  101. package/dist/llm/capabilities/types.d.ts +22 -2
  102. package/dist/llm/clamp-max-tokens.d.ts +11 -0
  103. package/dist/llm/clamp-max-tokens.js +17 -0
  104. package/dist/llm/client-base.d.ts +41 -4
  105. package/dist/llm/client-base.js +67 -13
  106. package/dist/llm/client-factory.d.ts +3 -3
  107. package/dist/llm/client-factory.js +2 -2
  108. package/dist/llm/model-pool.d.ts +15 -11
  109. package/dist/llm/model-pool.js +23 -20
  110. package/dist/llm/provider-catalog.d.ts +2 -2
  111. package/dist/llm/providers/anthropic.d.ts +32 -2
  112. package/dist/llm/providers/anthropic.js +147 -8
  113. package/dist/llm/providers/openai.d.ts +11 -2
  114. package/dist/llm/providers/openai.js +253 -52
  115. package/dist/llm/reasoning-setting.d.ts +51 -0
  116. package/dist/llm/reasoning-setting.js +32 -0
  117. package/dist/llm/stop-reason.d.ts +13 -0
  118. package/dist/llm/stop-reason.js +21 -0
  119. package/dist/llm/strip-vision.d.ts +32 -0
  120. package/dist/llm/strip-vision.js +94 -0
  121. package/dist/llm/types.d.ts +5 -6
  122. package/dist/logging/logger.js +18 -4
  123. package/dist/logging/sanitize-messages.d.ts +10 -0
  124. package/dist/logging/sanitize-messages.js +90 -0
  125. package/dist/lsp/client.js +28 -8
  126. package/dist/lsp/manager.js +2 -1
  127. package/dist/lsp/root-path.d.ts +9 -0
  128. package/dist/lsp/root-path.js +12 -0
  129. package/dist/onboarding.js +18 -11
  130. package/dist/plugins/gitOps.d.ts +34 -0
  131. package/dist/plugins/gitOps.js +59 -3
  132. package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
  133. package/dist/plugins/installer/codex/convertAgents.js +55 -0
  134. package/dist/plugins/installer/codex/convertMcp.d.ts +8 -0
  135. package/dist/plugins/installer/codex/convertMcp.js +45 -0
  136. package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
  137. package/dist/plugins/installer/codex/convertSkills.js +33 -0
  138. package/dist/plugins/installer/detectFormat.d.ts +2 -0
  139. package/dist/plugins/installer/detectFormat.js +6 -0
  140. package/dist/plugins/installer/install.d.ts +7 -0
  141. package/dist/plugins/installer/install.js +99 -0
  142. package/dist/plugins/installer/installFromSource.d.ts +13 -0
  143. package/dist/plugins/installer/installFromSource.js +45 -0
  144. package/dist/plugins/installer/list.d.ts +9 -0
  145. package/dist/plugins/installer/list.js +30 -0
  146. package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
  147. package/dist/plugins/installer/loadPluginAgents.js +23 -0
  148. package/dist/plugins/installer/loadPluginMcp.d.ts +7 -0
  149. package/dist/plugins/installer/loadPluginMcp.js +74 -0
  150. package/dist/plugins/installer/parseSource.d.ts +20 -0
  151. package/dist/plugins/installer/parseSource.js +74 -0
  152. package/dist/plugins/installer/paths.d.ts +5 -0
  153. package/dist/plugins/installer/paths.js +25 -0
  154. package/dist/plugins/installer/types.d.ts +49 -0
  155. package/dist/plugins/installer/types.js +27 -0
  156. package/dist/plugins/installer/uninstall.d.ts +2 -0
  157. package/dist/plugins/installer/uninstall.js +14 -0
  158. package/dist/plugins/installer/update.d.ts +14 -0
  159. package/dist/plugins/installer/update.js +65 -0
  160. package/dist/plugins/loadPluginHooks.d.ts +8 -1
  161. package/dist/plugins/loadPluginHooks.js +11 -1
  162. package/dist/plugins/marketplaceManager.d.ts +8 -1
  163. package/dist/plugins/marketplaceManager.js +38 -4
  164. package/dist/plugins/pluginCommandHook.js +34 -0
  165. package/dist/plugins/pluginInstaller.d.ts +21 -0
  166. package/dist/plugins/pluginInstaller.js +128 -29
  167. package/dist/plugins/schemas.js +40 -6
  168. package/dist/plugins/types.d.ts +4 -0
  169. package/dist/preset/index.js +16 -0
  170. package/dist/prompt/composer.d.ts +10 -0
  171. package/dist/prompt/composer.js +29 -4
  172. package/dist/prompt/sections/orchestration.md +8 -0
  173. package/dist/protocol/chat-session-manager.d.ts +8 -1
  174. package/dist/protocol/chat-session-manager.js +10 -0
  175. package/dist/protocol/chat-session.d.ts +17 -0
  176. package/dist/protocol/chat-session.js +28 -0
  177. package/dist/protocol/redact.d.ts +50 -0
  178. package/dist/protocol/redact.js +71 -0
  179. package/dist/protocol/server.d.ts +41 -2
  180. package/dist/protocol/server.js +231 -33
  181. package/dist/protocol/tcp-transport.d.ts +45 -0
  182. package/dist/protocol/tcp-transport.js +74 -0
  183. package/dist/protocol/types.d.ts +23 -0
  184. package/dist/protocol/types.js +6 -0
  185. package/dist/remote/bridge.d.ts +11 -2
  186. package/dist/remote/bridge.js +61 -33
  187. package/dist/run/ArtifactTracker.js +5 -4
  188. package/dist/run/EngineRunner.d.ts +27 -1
  189. package/dist/run/EngineRunner.js +46 -8
  190. package/dist/run/FileRunStore.js +32 -8
  191. package/dist/run/RunLock.d.ts +28 -2
  192. package/dist/run/RunLock.js +49 -7
  193. package/dist/run/RunManager.js +51 -3
  194. package/dist/run/RunQueue.d.ts +1 -0
  195. package/dist/run/RunQueue.js +8 -2
  196. package/dist/run/factory.d.ts +7 -0
  197. package/dist/run/factory.js +1 -0
  198. package/dist/run/index.d.ts +2 -2
  199. package/dist/run/index.js +1 -1
  200. package/dist/run/redirect-target.d.ts +7 -0
  201. package/dist/run/redirect-target.js +13 -0
  202. package/dist/run/types.js +1 -1
  203. package/dist/services/browser-open.d.ts +13 -0
  204. package/dist/services/browser-open.js +16 -0
  205. package/dist/services/dream-consolidation.d.ts +57 -0
  206. package/dist/services/dream-consolidation.js +151 -0
  207. package/dist/services/memory-orchestrator.js +18 -0
  208. package/dist/services/notifier.d.ts +8 -0
  209. package/dist/services/notifier.js +39 -25
  210. package/dist/services/oauth.js +5 -7
  211. package/dist/services/session-memory-sort.d.ts +8 -0
  212. package/dist/services/session-memory-sort.js +9 -0
  213. package/dist/services/session-memory.js +8 -9
  214. package/dist/session/file-history.js +10 -3
  215. package/dist/session/session-manager.d.ts +23 -1
  216. package/dist/session/session-manager.js +73 -2
  217. package/dist/settings/disk-defaults.d.ts +35 -0
  218. package/dist/settings/disk-defaults.js +24 -0
  219. package/dist/settings/manager.d.ts +45 -1
  220. package/dist/settings/manager.js +121 -17
  221. package/dist/settings/manager.test.d.ts +1 -0
  222. package/dist/settings/manager.test.js +73 -0
  223. package/dist/settings/personalization.d.ts +19 -0
  224. package/dist/settings/personalization.js +7 -0
  225. package/dist/settings/schema.d.ts +1163 -126
  226. package/dist/settings/schema.js +126 -10
  227. package/dist/skills/scanner.d.ts +13 -6
  228. package/dist/skills/scanner.js +23 -4
  229. package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
  230. package/dist/tool-system/builtin/add-marketplace.js +76 -0
  231. package/dist/tool-system/builtin/agent-registry.d.ts +15 -0
  232. package/dist/tool-system/builtin/agent-registry.js +14 -4
  233. package/dist/tool-system/builtin/agent.d.ts +55 -0
  234. package/dist/tool-system/builtin/agent.js +165 -17
  235. package/dist/tool-system/builtin/apply-patch/index.js +22 -3
  236. package/dist/tool-system/builtin/arena.js +6 -7
  237. package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
  238. package/dist/tool-system/builtin/complete-goal.js +45 -0
  239. package/dist/tool-system/builtin/cron.js +53 -9
  240. package/dist/tool-system/builtin/edit.d.ts +2 -1
  241. package/dist/tool-system/builtin/edit.js +6 -1
  242. package/dist/tool-system/builtin/generate-image.d.ts +25 -0
  243. package/dist/tool-system/builtin/generate-image.js +146 -0
  244. package/dist/tool-system/builtin/glob.js +7 -0
  245. package/dist/tool-system/builtin/grep.js +6 -0
  246. package/dist/tool-system/builtin/index.d.ts +18 -1
  247. package/dist/tool-system/builtin/index.js +62 -1
  248. package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
  249. package/dist/tool-system/builtin/notebook-edit.js +8 -1
  250. package/dist/tool-system/builtin/read.d.ts +2 -1
  251. package/dist/tool-system/builtin/read.js +9 -1
  252. package/dist/tool-system/builtin/skill.js +23 -5
  253. package/dist/tool-system/builtin/sleep.js +9 -3
  254. package/dist/tool-system/builtin/task.js +4 -1
  255. package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
  256. package/dist/tool-system/builtin/update-automation-memory.js +60 -0
  257. package/dist/tool-system/builtin/view-image.d.ts +18 -0
  258. package/dist/tool-system/builtin/view-image.js +96 -0
  259. package/dist/tool-system/builtin/web-search.d.ts +4 -1
  260. package/dist/tool-system/builtin/web-search.js +36 -3
  261. package/dist/tool-system/builtin/write.d.ts +2 -1
  262. package/dist/tool-system/builtin/write.js +7 -1
  263. package/dist/tool-system/context.d.ts +43 -0
  264. package/dist/tool-system/executor.d.ts +0 -1
  265. package/dist/tool-system/executor.js +34 -40
  266. package/dist/tool-system/investigation-guard.d.ts +4 -1
  267. package/dist/tool-system/investigation-guard.js +19 -3
  268. package/dist/tool-system/mcp-manager.d.ts +36 -12
  269. package/dist/tool-system/mcp-manager.js +173 -10
  270. package/dist/tool-system/path-policy.d.ts +94 -0
  271. package/dist/tool-system/path-policy.js +279 -0
  272. package/dist/tool-system/permission.js +43 -50
  273. package/dist/tool-system/plan-mode-allowlist.d.ts +21 -0
  274. package/dist/tool-system/plan-mode-allowlist.js +43 -0
  275. package/dist/tool-system/registry.js +12 -1
  276. package/dist/tool-system/validation.d.ts +10 -0
  277. package/dist/tool-system/validation.js +16 -3
  278. package/dist/types.d.ts +90 -15
  279. package/dist/utils/format.js +4 -2
  280. package/dist/utils/lockfile.js +9 -2
  281. package/dist/utils/theme.d.ts +6 -0
  282. package/dist/utils/theme.js +4 -2
  283. package/package.json +2 -1
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Pure projection functions: each turns one loader's output + the relevant
3
+ * slice of current settings into CapabilityDescriptor[]. No I/O, no state —
4
+ * the CapabilityService feeds them and composes the results.
5
+ *
6
+ * See docs/superpowers/specs/2026-05-29-capability-control-design.md
7
+ */
8
+ /**
9
+ * Builtin tools. A tool's switch lives in the denylist when it ships in the
10
+ * preset default set (turning it off = adding to agent.disabledBuiltinTools),
11
+ * and in the allowlist otherwise (turning it on = adding to
12
+ * agent.enabledBuiltinTools). This mirrors resolveBuiltinToolNames, whose
13
+ * effective set is `preset.builtinTools ∪ enabled − disabled`.
14
+ */
15
+ export function projectBuiltin(input) {
16
+ const defaults = new Set(input.presetDefaults);
17
+ const on = new Set(input.effective);
18
+ return input.tools.map((t) => {
19
+ const inPreset = defaults.has(t.name);
20
+ return {
21
+ id: `builtin:${t.name}`,
22
+ kind: "builtin",
23
+ name: t.name,
24
+ description: t.description,
25
+ enabled: on.has(t.name),
26
+ control: inPreset
27
+ ? {
28
+ settingsKey: "agent.disabledBuiltinTools",
29
+ mode: "denylist",
30
+ token: t.name,
31
+ }
32
+ : {
33
+ settingsKey: "agent.enabledBuiltinTools",
34
+ mode: "allowlist",
35
+ token: t.name,
36
+ },
37
+ origin: { isReadOnly: t.isReadOnly },
38
+ };
39
+ });
40
+ }
41
+ /**
42
+ * MCP, projected per server (not per tool). Every configured server gets a
43
+ * descriptor — including unconnected ones — driven by the mcpServers config;
44
+ * tool counts come from the registry's connected mcp tools (0 if none).
45
+ */
46
+ export function projectMcp(input) {
47
+ const counts = new Map();
48
+ for (const t of input.mcpTools) {
49
+ if (t.source !== "mcp" || !t.serverName)
50
+ continue;
51
+ counts.set(t.serverName, (counts.get(t.serverName) ?? 0) + 1);
52
+ }
53
+ return Object.entries(input.mcpServers).map(([serverName, cfg]) => {
54
+ const toolCount = counts.get(serverName) ?? 0;
55
+ return {
56
+ id: `mcp:${serverName}`,
57
+ kind: "mcp",
58
+ name: serverName,
59
+ description: `${toolCount} tools`,
60
+ enabled: cfg.enabled !== false,
61
+ control: {
62
+ settingsKey: "mcpServers",
63
+ mode: "record-flag",
64
+ token: serverName,
65
+ },
66
+ origin: { serverName, toolCount },
67
+ };
68
+ });
69
+ }
70
+ /**
71
+ * Project/user skills. The caller MUST pass the FULL skill set (scanSkills
72
+ * with empty opts), because scanSkills filters disabled entries out — passing
73
+ * a filtered set would drop disabled skills from the list, leaving the UI no
74
+ * way to re-enable them. Plugin-sourced skills are excluded here; they surface
75
+ * under their plugin via projectPlugins.
76
+ */
77
+ export function projectSkills(input) {
78
+ const disabled = new Set(input.disabledSkills);
79
+ return input.skills
80
+ .filter((s) => s.source === "project" || s.source === "user")
81
+ .map((s) => ({
82
+ id: `skill:${s.name}`,
83
+ kind: "skill",
84
+ name: s.name,
85
+ description: s.description,
86
+ enabled: !disabled.has(s.name),
87
+ control: {
88
+ settingsKey: "disabledSkills",
89
+ mode: "denylist",
90
+ token: s.name,
91
+ },
92
+ origin: { filePath: s.filePath },
93
+ }));
94
+ }
95
+ /**
96
+ * Project/user sub-agent roles, projected per role. Like projectSkills, the
97
+ * caller MUST pass the FULL agent set (loaded WITHOUT the disabled filter), so
98
+ * disabled roles still appear in the list and can be re-enabled. Plugin-sourced
99
+ * agents are excluded — they ride their plugin's switch via projectPlugins, and
100
+ * disabledAgents only governs user/project roles. Toggling writes the top-level
101
+ * `disabledAgents` denylist (same key the 子代理 tab uses), so the two stay in
102
+ * sync; the project overlay layers on via capabilityOverrides.agents.
103
+ */
104
+ export function projectAgents(input) {
105
+ const disabled = new Set(input.disabledAgents);
106
+ return input.agents
107
+ .filter((a) => a.source === "project" || a.source === "user")
108
+ .map((a) => ({
109
+ id: `agent:${a.name}`,
110
+ kind: "agent",
111
+ name: a.name,
112
+ description: a.description,
113
+ enabled: !disabled.has(a.name),
114
+ control: {
115
+ settingsKey: "disabledAgents",
116
+ mode: "denylist",
117
+ token: a.name,
118
+ },
119
+ origin: { filePath: a.filePath },
120
+ }));
121
+ }
122
+ /**
123
+ * Installed plugins, projected per plugin. Install keys are `<plugin>@<market>`;
124
+ * the bare plugin name is the substring before the last `@` and matches the
125
+ * `plugin:` prefix that disabledPlugins controls.
126
+ */
127
+ export function projectPlugins(input) {
128
+ const disabled = new Set(input.disabledPlugins);
129
+ const names = new Set();
130
+ for (const key of Object.keys(input.installed)) {
131
+ const at = key.lastIndexOf("@");
132
+ names.add(at > 0 ? key.slice(0, at) : key);
133
+ }
134
+ return [...names].map((name) => ({
135
+ id: `plugin:${name}`,
136
+ kind: "plugin",
137
+ name,
138
+ description: "",
139
+ enabled: !disabled.has(name),
140
+ control: {
141
+ settingsKey: "disabledPlugins",
142
+ mode: "denylist",
143
+ token: name,
144
+ },
145
+ origin: { pluginName: name },
146
+ }));
147
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * CapabilityService — the single control-layer entry point.
3
+ *
4
+ * - list(): composes the four projections into one CapabilityDescriptor[].
5
+ * - setEnabled(id, on): reads the target descriptor's inlined `control` and
6
+ * routes the write to the right settings key. It never branches on `kind`.
7
+ *
8
+ * Dependencies are injected (not imported) so the service is unit-testable
9
+ * without touching disk: the engine / desktop wiring supplies the real
10
+ * ToolRegistry, SettingsManager, and loaders.
11
+ *
12
+ * See docs/superpowers/specs/2026-05-29-capability-control-design.md
13
+ */
14
+ import type { ToolRegistry } from "../tool-system/registry.js";
15
+ import type { SettingsManager } from "../settings/manager.js";
16
+ import type { SkillDefinition } from "../skills/scanner.js";
17
+ import type { AgentDefinition } from "../agent/agent-definition.js";
18
+ import type { InstalledPluginsV2 } from "../plugins/types.js";
19
+ import type { CapabilityDescriptor, WriteScope, CapabilityOverrideState } from "./types.js";
20
+ export interface CapabilityServiceDeps {
21
+ registry: Pick<ToolRegistry, "listToolsDetailed">;
22
+ settings: Pick<SettingsManager, "get" | "saveUserSetting" | "saveProjectSetting" | "deleteProjectSetting" | "getForScope">;
23
+ cwd: string;
24
+ scanSkills: (cwd: string, opts?: {
25
+ disabledSkills?: string[];
26
+ disabledPlugins?: string[];
27
+ }) => SkillDefinition[];
28
+ /** Full agent role set for `cwd` (user + project), loaded WITHOUT the
29
+ * disabled filter so disabled roles still list and can be re-enabled. */
30
+ scanAgents: (cwd: string) => AgentDefinition[];
31
+ readInstalledPlugins: () => InstalledPluginsV2;
32
+ resolveBuiltinToolNames: (o?: {
33
+ preset?: string;
34
+ enabledBuiltinTools?: string[];
35
+ disabledBuiltinTools?: string[];
36
+ }) => string[];
37
+ }
38
+ export declare class CapabilityService {
39
+ private readonly deps;
40
+ constructor(deps: CapabilityServiceDeps);
41
+ /**
42
+ * List capability descriptors. With no `cwd` this is the user/global view
43
+ * (enabled === global baseline). With a `cwd` it's that project's view:
44
+ * each descriptor gains globalEnabled / projectOverride / effectiveSource
45
+ * and `enabled` reflects the tri-state overlay (spec §6.1).
46
+ */
47
+ list(cwd?: string): CapabilityDescriptor[];
48
+ /**
49
+ * Toggle a capability. Default scope is "user" (back-compat: old callers
50
+ * pass no opts → global write, unchanged). scope:"project" maps on/off to a
51
+ * tri-state override and writes capabilityOverrides (requires cwd).
52
+ */
53
+ setEnabled(id: string, on: boolean, opts?: {
54
+ scope?: WriteScope;
55
+ cwd?: string;
56
+ }): void;
57
+ /**
58
+ * Write a project tri-state override. "inherit" deletes the key (we never
59
+ * persist the literal). All capability kinds — including builtin, which
60
+ * writes to capabilityOverrides.builtin.<token> — now support project
61
+ * overrides; only a kind with no bucket (bucketForKind returns undefined)
62
+ * is rejected.
63
+ */
64
+ setOverride(id: string, state: CapabilityOverrideState, opts: {
65
+ scope: "project";
66
+ cwd: string;
67
+ }): void;
68
+ /** Existing global write path — unchanged behavior, refactored out of setEnabled. */
69
+ private writeUserScope;
70
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * CapabilityService — the single control-layer entry point.
3
+ *
4
+ * - list(): composes the four projections into one CapabilityDescriptor[].
5
+ * - setEnabled(id, on): reads the target descriptor's inlined `control` and
6
+ * routes the write to the right settings key. It never branches on `kind`.
7
+ *
8
+ * Dependencies are injected (not imported) so the service is unit-testable
9
+ * without touching disk: the engine / desktop wiring supplies the real
10
+ * ToolRegistry, SettingsManager, and loaders.
11
+ *
12
+ * See docs/superpowers/specs/2026-05-29-capability-control-design.md
13
+ */
14
+ import { CapabilityNotFoundError } from "./types.js";
15
+ import { projectBuiltin, projectMcp, projectSkills, projectPlugins, projectAgents, } from "./project.js";
16
+ import { applyOverride, bucketForKind, overrideTokenForId, overrideFor, } from "./overlay.js";
17
+ export class CapabilityService {
18
+ deps;
19
+ constructor(deps) {
20
+ this.deps = deps;
21
+ }
22
+ /**
23
+ * List capability descriptors. With no `cwd` this is the user/global view
24
+ * (enabled === global baseline). With a `cwd` it's that project's view:
25
+ * each descriptor gains globalEnabled / projectOverride / effectiveSource
26
+ * and `enabled` reflects the tri-state overlay (spec §6.1).
27
+ */
28
+ list(cwd) {
29
+ const s = this.deps.settings.get();
30
+ const agent = (s.agent ?? {});
31
+ const tools = this.deps.registry.listToolsDetailed();
32
+ const preset = agent.preset;
33
+ const base = [
34
+ ...projectBuiltin({
35
+ tools: tools.filter((t) => t.source === "builtin"),
36
+ presetDefaults: this.deps.resolveBuiltinToolNames({ preset }),
37
+ effective: this.deps.resolveBuiltinToolNames({
38
+ preset,
39
+ enabledBuiltinTools: agent.enabledBuiltinTools ?? [],
40
+ disabledBuiltinTools: agent.disabledBuiltinTools ?? [],
41
+ }),
42
+ }),
43
+ ...projectMcp({
44
+ mcpServers: s.mcpServers ?? {},
45
+ mcpTools: tools.filter((t) => t.source === "mcp"),
46
+ }),
47
+ ...projectSkills({
48
+ skills: this.deps.scanSkills(this.deps.cwd, {}),
49
+ disabledSkills: s.disabledSkills ?? [],
50
+ }),
51
+ ...projectPlugins({
52
+ installed: this.deps.readInstalledPlugins().plugins,
53
+ disabledPlugins: s.disabledPlugins ?? [],
54
+ }),
55
+ ...projectAgents({
56
+ agents: this.deps.scanAgents(this.deps.cwd),
57
+ disabledAgents: s.disabledAgents ?? [],
58
+ }),
59
+ ];
60
+ const overrides = cwd
61
+ ? this.deps.settings.getForScope("project", cwd).capabilityOverrides
62
+ : undefined;
63
+ return base.map((d) => {
64
+ const globalEnabled = d.enabled;
65
+ const token = overrideTokenForId(d.id);
66
+ const ov = cwd ? overrideFor(overrides, d.kind, token) : undefined;
67
+ const enabled = applyOverride(globalEnabled, ov);
68
+ return {
69
+ ...d,
70
+ enabled,
71
+ globalEnabled,
72
+ projectOverride: ov,
73
+ effectiveSource: ov ? "project" : cwd ? "default" : "user",
74
+ };
75
+ });
76
+ }
77
+ /**
78
+ * Toggle a capability. Default scope is "user" (back-compat: old callers
79
+ * pass no opts → global write, unchanged). scope:"project" maps on/off to a
80
+ * tri-state override and writes capabilityOverrides (requires cwd).
81
+ */
82
+ setEnabled(id, on, opts) {
83
+ if (opts?.scope === "project") {
84
+ this.setOverride(id, on ? "on" : "off", {
85
+ scope: "project",
86
+ cwd: opts.cwd ?? this.deps.cwd,
87
+ });
88
+ return;
89
+ }
90
+ this.writeUserScope(id, on);
91
+ }
92
+ /**
93
+ * Write a project tri-state override. "inherit" deletes the key (we never
94
+ * persist the literal). All capability kinds — including builtin, which
95
+ * writes to capabilityOverrides.builtin.<token> — now support project
96
+ * overrides; only a kind with no bucket (bucketForKind returns undefined)
97
+ * is rejected.
98
+ */
99
+ setOverride(id, state, opts) {
100
+ const descriptor = this.list().find((c) => c.id === id);
101
+ if (!descriptor)
102
+ throw new CapabilityNotFoundError(id);
103
+ const bucket = bucketForKind(descriptor.kind);
104
+ if (!bucket)
105
+ throw new Error(`Capability kind '${descriptor.kind}' has no project override`);
106
+ if (!opts.cwd)
107
+ throw new Error("project override requires cwd");
108
+ const token = overrideTokenForId(id);
109
+ const path = `capabilityOverrides.${bucket}.${token}`;
110
+ if (state === "inherit")
111
+ this.deps.settings.deleteProjectSetting(path, opts.cwd);
112
+ else
113
+ this.deps.settings.saveProjectSetting(path, state, opts.cwd);
114
+ }
115
+ /** Existing global write path — unchanged behavior, refactored out of setEnabled. */
116
+ writeUserScope(id, on) {
117
+ const descriptor = this.list().find((c) => c.id === id);
118
+ if (!descriptor)
119
+ throw new CapabilityNotFoundError(id);
120
+ const { settingsKey, mode, token } = descriptor.control;
121
+ const s = this.deps.settings.get();
122
+ if (mode === "record-flag") {
123
+ const servers = { ...(s.mcpServers ?? {}) };
124
+ // Never conjure a server that was never configured.
125
+ if (!servers[token])
126
+ return;
127
+ servers[token] = { ...servers[token], enabled: on };
128
+ this.deps.settings.saveUserSetting("mcpServers", servers);
129
+ return;
130
+ }
131
+ const arr = new Set(readArray(s, settingsKey));
132
+ // denylist: present ⇒ OFF, so we want it present when turning off.
133
+ const wantPresent = mode === "allowlist" ? on : !on;
134
+ if (wantPresent)
135
+ arr.add(token);
136
+ else
137
+ arr.delete(token);
138
+ this.deps.settings.saveUserSetting(settingsKey, [...arr]);
139
+ }
140
+ }
141
+ /** Read an array at a dotted settings path (e.g. agent.disabledBuiltinTools). */
142
+ function readArray(s, key) {
143
+ let cur = s;
144
+ for (const part of key.split("."))
145
+ cur = cur?.[part];
146
+ return Array.isArray(cur) ? cur : [];
147
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Capability-control descriptor types.
3
+ *
4
+ * A read-only projection layer over the four extension-capability loaders
5
+ * (builtin tools, MCP servers, skills, plugins). A CapabilityDescriptor is a
6
+ * computed view, never a source of truth — the truth stays in the loaders +
7
+ * settings. Each descriptor carries an inlined `control` describing how to
8
+ * toggle it, so the switch router never has to branch on `kind`.
9
+ *
10
+ * See docs/superpowers/specs/2026-05-29-capability-control-design.md
11
+ */
12
+ /** A uniform, read-only projection of one extension capability. */
13
+ export interface CapabilityDescriptor {
14
+ /** Globally unique; the source prefix isolates the namespace. */
15
+ id: string;
16
+ kind: "builtin" | "mcp" | "skill" | "plugin" | "agent";
17
+ /** Display name: builtin=tool, mcp=server, skill=skill, plugin=plugin, agent=role. */
18
+ name: string;
19
+ /** One-line description pulled from the underlying metadata. */
20
+ description: string;
21
+ /** Computed from preset defaults + the relevant switch config. */
22
+ enabled: boolean;
23
+ /** Which settings key the switch writes, and how. */
24
+ control: CapabilityControl;
25
+ /** user/global baseline enablement, before any project overlay. */
26
+ globalEnabled?: boolean;
27
+ /** Project overlay state in a project-scope view. Absent === inherit. */
28
+ projectOverride?: "on" | "off";
29
+ /** Where the effective `enabled` value came from. */
30
+ effectiveSource?: "user" | "project" | "default";
31
+ /** Source details for UI grouping / navigation. */
32
+ origin?: {
33
+ serverName?: string;
34
+ pluginName?: string;
35
+ filePath?: string;
36
+ toolCount?: number;
37
+ isReadOnly?: boolean;
38
+ };
39
+ }
40
+ /** Describes which settings key the switch writes and the write semantics. */
41
+ export interface CapabilityControl {
42
+ settingsKey: "agent.enabledBuiltinTools" | "agent.disabledBuiltinTools" | "mcpServers" | "disabledSkills" | "disabledPlugins" | "disabledAgents";
43
+ /**
44
+ * - "denylist" → off = token present in array (disabled*); on = removed
45
+ * - "allowlist" → on = token present in array (enabled*); off = removed
46
+ * - "record-flag" → flip mcpServers[token].enabled
47
+ */
48
+ mode: "denylist" | "allowlist" | "record-flag";
49
+ /** Identifier written into the array, or used as the record key. */
50
+ token: string;
51
+ }
52
+ export declare class CapabilityNotFoundError extends Error {
53
+ constructor(id: string);
54
+ }
55
+ /**
56
+ * Which settings file a capability write targets. Distinct from
57
+ * SettingsManager's disk-READ scope ("isolated" | "project" | "full"): this is
58
+ * the WRITE scope — user → global settings, project → capabilityOverrides.
59
+ */
60
+ export type WriteScope = "user" | "project";
61
+ /** Tri-state project override as seen by callers. */
62
+ export type CapabilityOverrideState = "inherit" | "on" | "off";
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Capability-control descriptor types.
3
+ *
4
+ * A read-only projection layer over the four extension-capability loaders
5
+ * (builtin tools, MCP servers, skills, plugins). A CapabilityDescriptor is a
6
+ * computed view, never a source of truth — the truth stays in the loaders +
7
+ * settings. Each descriptor carries an inlined `control` describing how to
8
+ * toggle it, so the switch router never has to branch on `kind`.
9
+ *
10
+ * See docs/superpowers/specs/2026-05-29-capability-control-design.md
11
+ */
12
+ export class CapabilityNotFoundError extends Error {
13
+ constructor(id) {
14
+ super(`Capability not found: ${id}`);
15
+ this.name = "CapabilityNotFoundError";
16
+ }
17
+ }
@@ -29,4 +29,15 @@
29
29
  * transport is stdio NDJSON and the protocol surface is unchanged, this
30
30
  * bootstrap is invisible to them.
31
31
  */
32
- export {};
32
+ import type { EngineConfigSlice } from "../protocol/chat-session-manager.js";
33
+ import type { ValidatedSettings } from "../settings/schema.js";
34
+ /**
35
+ * Resolve per-session agent config: protocol slice overrides win, else fall
36
+ * back to disk settings.agent.*. Fixes the bug where settings.agent.* never
37
+ * reached session engines (slice arrived with only permissionMode+cwd).
38
+ */
39
+ export declare function resolveSessionAgentConfig(slice: EngineConfigSlice, settings: ValidatedSettings): {
40
+ preset: string;
41
+ customSystemPrompt: string | undefined;
42
+ appendSystemPrompt: string | undefined;
43
+ };
@@ -35,33 +35,59 @@ import { ChatSessionManager } from "../protocol/chat-session-manager.js";
35
35
  import { AgentServer } from "../protocol/server.js";
36
36
  import { StdioTransport } from "../protocol/transport.js";
37
37
  import { SettingsManager } from "../settings/manager.js";
38
+ import { personalizationFrom } from "../settings/personalization.js";
38
39
  import { MCPManager } from "../tool-system/mcp-manager.js";
40
+ import { mergePluginMcpServers } from "../plugins/installer/loadPluginMcp.js";
39
41
  import { CostTracker } from "../cost-tracker.js";
42
+ import { installGracefulShutdown } from "./graceful-shutdown.js";
43
+ import { cronScheduler } from "../automation/scheduler.js";
44
+ import { CronStore, defaultCronStorePath } from "../automation/store.js";
45
+ /**
46
+ * Resolve per-session agent config: protocol slice overrides win, else fall
47
+ * back to disk settings.agent.*. Fixes the bug where settings.agent.* never
48
+ * reached session engines (slice arrived with only permissionMode+cwd).
49
+ */
50
+ export function resolveSessionAgentConfig(slice, settings) {
51
+ return {
52
+ preset: slice.preset ?? settings.agent.preset,
53
+ customSystemPrompt: slice.customSystemPrompt ?? settings.agent.customSystemPrompt,
54
+ appendSystemPrompt: slice.appendSystemPrompt ?? settings.agent.appendSystemPrompt,
55
+ };
56
+ }
40
57
  // ─── Read base config from environment / settings ─────────────────
41
58
  const cwd = process.env.AGENT_CWD ?? process.cwd();
42
59
  // Load settings once to derive llm config for the seed engine.
43
- const settingsManager = new SettingsManager(cwd);
60
+ // Desktop is a host application: read the full disk hierarchy (incl. the
61
+ // user's ~/.code-shell). The SDK default 'project' would skip user config.
62
+ const settingsManager = new SettingsManager(cwd, "full");
44
63
  const settings = settingsManager.get();
64
+ // LLMConfig is pure model identity now — only the bare identity fields go here.
65
+ // temperature/imageDetail/timeout/retryMaxAttempts are ClientDefaults, derived
66
+ // inside Engine.populateModelPoolFromSettings from settings.model.temperature
67
+ // and settings.images.detail.
45
68
  const llmConfig = {
46
69
  provider: settings.model.provider,
47
70
  model: settings.model.name,
48
71
  apiKey: settings.model.apiKey ?? "",
49
72
  baseUrl: settings.model.baseUrl,
50
- temperature: settings.model.temperature,
51
73
  maxTokens: settings.model.maxTokens,
52
74
  };
53
75
  // ─── Step 1: seed engine — populates model pool from settings ─────
54
76
  const seedEngine = new Engine({
55
77
  llm: llmConfig,
56
78
  cwd,
79
+ settingsScope: "full",
57
80
  // No runtime — Engine.populateModelPoolFromSettings() runs in ctor.
58
81
  });
59
82
  // ─── Step 2: extract shared resources ────────────────────────────
60
83
  const modelPool = seedEngine.getModelPool();
61
84
  const toolRegistry = seedEngine.getToolRegistry();
62
- // Capture the seed engine's resolved llmConfig (post-populateModelPoolFromSettings).
63
- // This includes resolved provider/baseUrl/apiKey from settings.providers[].
85
+ // Capture the seed engine's resolved llmConfig + clientDefaults
86
+ // (post-populateModelPoolFromSettings). Session engines inherit defaults so
87
+ // settings.model.temperature / images.detail apply uniformly without each
88
+ // factory call re-reading settings.
64
89
  const resolvedLlmConfig = seedEngine.getConfig().llm;
90
+ const resolvedClientDefaults = seedEngine.getConfig().clientDefaults;
65
91
  // Reuse the same SettingsManager instance for the runtime instead of constructing
66
92
  // a fresh one — avoids duplication and keeps the pattern cleaner.
67
93
  const sharedSettings = settingsManager;
@@ -87,30 +113,104 @@ const runtime = new EngineRuntime({
87
113
  costTracker,
88
114
  });
89
115
  // ─── Step 4: ChatSessionManager ──────────────────────────────────
116
+ // Re-read settings from disk on each new session so edits the user makes in
117
+ // the settings UI take effect on the NEXT session without restarting the
118
+ // worker (the `settings` bootstrap snapshot above is read once at process
119
+ // start and would otherwise pin every session to the launch-time values).
120
+ // This is the "pull on session creation" tier — mirrors how Codex's new
121
+ // threads call load_with_overrides() per start. (Hot-reloading ALREADY-RUNNING
122
+ // sessions is a separate, heavier push mechanism, intentionally out of scope.)
123
+ // Best-effort: if a freshly-edited settings.json is malformed, fall back to the
124
+ // last-known-good bootstrap snapshot rather than failing to create a session.
125
+ function freshSettings() {
126
+ try {
127
+ return settingsManager.load();
128
+ }
129
+ catch {
130
+ return settings;
131
+ }
132
+ }
90
133
  const chatManager = new ChatSessionManager({
91
134
  runtime,
92
- engineFactory: (slice) => new Engine({
93
- llm: resolvedLlmConfig,
94
- cwd,
95
- runtime,
96
- // Per-session overrides from the protocol request
97
- permissionMode: slice.permissionMode,
98
- preset: slice.preset,
99
- customSystemPrompt: slice.customSystemPrompt,
100
- appendSystemPrompt: slice.appendSystemPrompt,
101
- maxTurns: slice.maxTurns,
102
- maxContextTokens: slice.maxContextTokens,
103
- ...(slice.cwd ? { cwd: slice.cwd } : {}),
104
- }),
135
+ // resolvedLlmConfig is the bootstrap-time snapshot. When the user
136
+ // hot-switches models via configure() the modelPool.activeKey moves
137
+ // ahead of it, so newly-created sessions must re-resolve from the pool
138
+ // each time the factory fires; fall back to the snapshot only when the
139
+ // pool can't resolve (no active key — shouldn't happen in practice).
140
+ engineFactory: (slice) => {
141
+ const live = freshSettings();
142
+ return new Engine({
143
+ llm: runtime.modelPool.resolveLLMConfig() ?? resolvedLlmConfig,
144
+ // Inherit the seed engine's resolved clientDefaults so every session
145
+ // engine sees the user's temperature/imageDetail without each factory
146
+ // call re-running populateModelPoolFromSettings.
147
+ clientDefaults: resolvedClientDefaults,
148
+ cwd,
149
+ runtime,
150
+ // This stdio worker exists only to serve the desktop app, so every
151
+ // session it creates is a desktop-origin session.
152
+ origin: "desktop",
153
+ // Inherit full scope so spawned subagents read user config too.
154
+ settingsScope: "full",
155
+ // MCP servers from settings — the worker reads the full disk
156
+ // hierarchy at bootstrap (incl. ~/.code-shell). Without this the
157
+ // factory-built session Engine has config.mcpServers === undefined,
158
+ // so Engine.run()'s connectAll() guard never fires and no MCP server
159
+ // (stdio OR url) is ever connected. The shared runtime.mcpPool means
160
+ // the first session to connect populates connections for the worker.
161
+ // Plugin-provided MCP servers (mcp-servers.json in installed plugins)
162
+ // are merged in here so the model can actually call them.
163
+ mcpServers: mergePluginMcpServers(live.mcpServers ?? {}, live.disabledPlugins ?? []),
164
+ // Per-session overrides from the protocol request; fall back to
165
+ // settings.agent.* so the user's 个性化 settings actually apply
166
+ // (previously slice arrived with only permissionMode+cwd, so these
167
+ // were always undefined — the 自定义指令 box never took effect).
168
+ // `live` is re-read from disk per session, so settings edits take effect
169
+ // on the next session without a worker restart.
170
+ permissionMode: slice.permissionMode,
171
+ ...resolveSessionAgentConfig(slice, live),
172
+ // Personalization + instruction compat come from disk settings only
173
+ // (not per-request protocol overrides), so they read straight from
174
+ // `live` here rather than through the slice. Shared helper keeps the
175
+ // three fields wired identically across desktop / TUI / TCP.
176
+ ...personalizationFrom(live.agent),
177
+ maxTurns: slice.maxTurns,
178
+ maxContextTokens: slice.maxContextTokens,
179
+ ...(slice.cwd ? { cwd: slice.cwd } : {}),
180
+ });
181
+ },
105
182
  maxSessions: 16,
106
183
  idleTtlMs: 30 * 60 * 1000,
107
184
  });
108
185
  chatManager.startIdleSweeper();
186
+ // ─── Cron persistence ────────────────────────────────────────────
187
+ // The agent's CronCreate/Delete tools operate on the shared cronScheduler
188
+ // singleton. In the desktop host this worker is a SEPARATE process from the
189
+ // Electron main process that owns the live scheduler, so the only way a
190
+ // chat-created job reaches the automation UI is through the shared on-disk
191
+ // store (~/.code-shell/cron.json). Give this process's scheduler that store so
192
+ // CronCreate persists; loadJobs() so the agent can list/modify existing jobs.
193
+ // Execution is DISABLED here — this worker must not run scheduled jobs (the
194
+ // main process owns execution); persistence is its only cron role. Without
195
+ // this, loadJobs()/CronCreate would arm timers in this process too, double-
196
+ // running jobs and corrupting run stats.
197
+ cronScheduler.setStore(new CronStore(defaultCronStorePath()));
198
+ cronScheduler.setExecutionEnabled(false);
199
+ cronScheduler.loadJobs();
109
200
  // ─── Step 5: AgentServer over stdio ──────────────────────────────
110
201
  const stdioTransport = new StdioTransport(process.stdin, process.stdout);
111
- new AgentServer({
202
+ const agentServer = new AgentServer({
112
203
  chatManager,
113
204
  transport: stdioTransport,
205
+ // Config hot-reload (layer 2) reads disk through the SAME closure the
206
+ // engineFactory uses for new sessions, so a reloaded running session and a
207
+ // newly-created session converge on identical disk config (no divergence).
208
+ settingsReader: freshSettings,
114
209
  });
210
+ // Clean up on termination signals. Without this, SIGTERM (parent kill),
211
+ // SIGINT (Ctrl+C), or SIGHUP would drop the process without closing sessions,
212
+ // clearing the idle sweeper, or terminating child MCP/tool processes.
213
+ // AgentServer.close() also closes the chatManager's sessions.
214
+ installGracefulShutdown(agentServer);
115
215
  // Keep the process alive — readline in StdioTransport holds the event loop.
116
216
  // On parent close / stdin EOF the process will exit naturally.
@@ -0,0 +1,20 @@
1
+ /**
2
+ * agent-server-tcp — headless server entry point over TCP (Phase 6).
3
+ *
4
+ * Mirrors agent-server-stdio.ts (same EngineRuntime + ChatSessionManager +
5
+ * AgentServer bootstrap), but listens on a TCP socket instead of stdio and
6
+ * also starts the in-process automation scheduler so a deployed server runs
7
+ * scheduled jobs 7x24 with no Electron/GUI.
8
+ *
9
+ * The automation module is the SAME zero-env-dependency module the desktop
10
+ * loads (startAutomation) — this is the "thin server host" the plan's D2
11
+ * describes: one module, two hosts.
12
+ *
13
+ * Usage:
14
+ * AGENT_TCP_PORT=4321 node dist/cli/agent-server-tcp.js
15
+ *
16
+ * v1 SECURITY: binds 127.0.0.1 by default and has NO authentication. Do not
17
+ * expose to a public interface without adding auth (token/TLS). Use SSH
18
+ * tunneling for remote access in v1.
19
+ */
20
+ export {};