@cjhyy/code-shell-core 0.5.0-rc.1 → 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 (278) hide show
  1. package/dist/agent/agent-definition-registry.d.ts +18 -3
  2. package/dist/agent/agent-definition-registry.js +47 -18
  3. package/dist/agent/agent-definition.d.ts +17 -0
  4. package/dist/agent/agent-definition.js +22 -1
  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 +114 -19
  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 +208 -14
  68. package/dist/engine/engine.js +754 -169
  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 +31 -6
  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 +4 -0
  171. package/dist/prompt/composer.js +28 -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 +33 -0
  220. package/dist/settings/manager.js +94 -1
  221. package/dist/settings/personalization.d.ts +19 -0
  222. package/dist/settings/personalization.js +7 -0
  223. package/dist/settings/schema.d.ts +1142 -126
  224. package/dist/settings/schema.js +119 -10
  225. package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
  226. package/dist/tool-system/builtin/add-marketplace.js +76 -0
  227. package/dist/tool-system/builtin/agent-registry.d.ts +11 -0
  228. package/dist/tool-system/builtin/agent-registry.js +8 -4
  229. package/dist/tool-system/builtin/agent.d.ts +29 -10
  230. package/dist/tool-system/builtin/agent.js +108 -52
  231. package/dist/tool-system/builtin/apply-patch/index.js +22 -3
  232. package/dist/tool-system/builtin/arena.js +6 -7
  233. package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
  234. package/dist/tool-system/builtin/complete-goal.js +45 -0
  235. package/dist/tool-system/builtin/cron.js +53 -9
  236. package/dist/tool-system/builtin/edit.d.ts +2 -1
  237. package/dist/tool-system/builtin/edit.js +6 -1
  238. package/dist/tool-system/builtin/generate-image.d.ts +25 -0
  239. package/dist/tool-system/builtin/generate-image.js +146 -0
  240. package/dist/tool-system/builtin/glob.js +7 -0
  241. package/dist/tool-system/builtin/grep.js +6 -0
  242. package/dist/tool-system/builtin/index.d.ts +18 -1
  243. package/dist/tool-system/builtin/index.js +62 -1
  244. package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
  245. package/dist/tool-system/builtin/notebook-edit.js +8 -1
  246. package/dist/tool-system/builtin/read.d.ts +2 -1
  247. package/dist/tool-system/builtin/read.js +9 -1
  248. package/dist/tool-system/builtin/sleep.js +9 -3
  249. package/dist/tool-system/builtin/task.js +4 -1
  250. package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
  251. package/dist/tool-system/builtin/update-automation-memory.js +60 -0
  252. package/dist/tool-system/builtin/view-image.d.ts +18 -0
  253. package/dist/tool-system/builtin/view-image.js +96 -0
  254. package/dist/tool-system/builtin/web-search.d.ts +4 -1
  255. package/dist/tool-system/builtin/web-search.js +36 -3
  256. package/dist/tool-system/builtin/write.d.ts +2 -1
  257. package/dist/tool-system/builtin/write.js +7 -1
  258. package/dist/tool-system/context.d.ts +12 -0
  259. package/dist/tool-system/executor.d.ts +0 -1
  260. package/dist/tool-system/executor.js +34 -40
  261. package/dist/tool-system/investigation-guard.d.ts +4 -1
  262. package/dist/tool-system/investigation-guard.js +19 -3
  263. package/dist/tool-system/mcp-manager.d.ts +36 -12
  264. package/dist/tool-system/mcp-manager.js +173 -10
  265. package/dist/tool-system/path-policy.d.ts +94 -0
  266. package/dist/tool-system/path-policy.js +279 -0
  267. package/dist/tool-system/permission.js +43 -50
  268. package/dist/tool-system/plan-mode-allowlist.d.ts +21 -0
  269. package/dist/tool-system/plan-mode-allowlist.js +43 -0
  270. package/dist/tool-system/registry.js +12 -1
  271. package/dist/tool-system/validation.d.ts +10 -0
  272. package/dist/tool-system/validation.js +16 -3
  273. package/dist/types.d.ts +90 -15
  274. package/dist/utils/format.js +4 -2
  275. package/dist/utils/lockfile.js +9 -2
  276. package/dist/utils/theme.d.ts +6 -0
  277. package/dist/utils/theme.js +4 -2
  278. package/package.json +2 -1
@@ -0,0 +1,120 @@
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
+ import { Engine } from "../engine/engine.js";
21
+ import { EngineRuntime } from "../engine/runtime.js";
22
+ import { ChatSessionManager } from "../protocol/chat-session-manager.js";
23
+ import { AgentServer } from "../protocol/server.js";
24
+ import { listenTcp } from "../protocol/tcp-transport.js";
25
+ import { SettingsManager } from "../settings/manager.js";
26
+ import { personalizationFrom } from "../settings/personalization.js";
27
+ import { MCPManager } from "../tool-system/mcp-manager.js";
28
+ import { mergePluginMcpServers } from "../plugins/installer/loadPluginMcp.js";
29
+ import { CostTracker } from "../cost-tracker.js";
30
+ import { HeadlessApprovalBackend } from "../tool-system/permission.js";
31
+ import { createRunManager } from "../run/factory.js";
32
+ import { startAutomation } from "../automation/index.js";
33
+ import { CronStore, defaultCronStorePath } from "../automation/store.js";
34
+ const cwd = process.env.AGENT_CWD ?? process.cwd();
35
+ const port = Number(process.env.AGENT_TCP_PORT ?? "4321");
36
+ const host = process.env.AGENT_TCP_HOST ?? "127.0.0.1";
37
+ const settingsManager = new SettingsManager(cwd, "full");
38
+ const settings = settingsManager.get();
39
+ const llmConfig = {
40
+ provider: settings.model.provider,
41
+ model: settings.model.name,
42
+ apiKey: settings.model.apiKey ?? "",
43
+ baseUrl: settings.model.baseUrl,
44
+ maxTokens: settings.model.maxTokens,
45
+ };
46
+ // ── Shared runtime (same bootstrap as stdio) ─────────────────────
47
+ const seedEngine = new Engine({ llm: llmConfig, cwd, settingsScope: "full" });
48
+ const modelPool = seedEngine.getModelPool();
49
+ const toolRegistry = seedEngine.getToolRegistry();
50
+ const resolvedLlmConfig = seedEngine.getConfig().llm;
51
+ const resolvedClientDefaults = seedEngine.getConfig().clientDefaults;
52
+ const mcpPool = new MCPManager(toolRegistry);
53
+ const costTracker = new CostTracker();
54
+ const runtime = new EngineRuntime({
55
+ modelPool,
56
+ toolRegistry,
57
+ settings: settingsManager,
58
+ mcpPool,
59
+ costTracker,
60
+ });
61
+ const chatManager = new ChatSessionManager({
62
+ runtime,
63
+ engineFactory: (slice) => new Engine({
64
+ llm: runtime.modelPool.resolveLLMConfig() ?? resolvedLlmConfig,
65
+ clientDefaults: resolvedClientDefaults,
66
+ cwd,
67
+ runtime,
68
+ settingsScope: "full",
69
+ mcpServers: mergePluginMcpServers(settings.mcpServers ?? {}, settings.disabledPlugins ?? []),
70
+ permissionMode: slice.permissionMode,
71
+ preset: slice.preset,
72
+ customSystemPrompt: slice.customSystemPrompt,
73
+ appendSystemPrompt: slice.appendSystemPrompt,
74
+ // Personalization + instruction compat come from disk settings only
75
+ // (not per-request slice overrides) — same disk-only contract as the
76
+ // stdio host. Shared helper keeps the three fields wired identically.
77
+ ...personalizationFrom(settings.agent),
78
+ maxTurns: slice.maxTurns,
79
+ maxContextTokens: slice.maxContextTokens,
80
+ ...(slice.cwd ? { cwd: slice.cwd } : {}),
81
+ }),
82
+ maxSessions: 16,
83
+ idleTtlMs: 30 * 60 * 1000,
84
+ });
85
+ chatManager.startIdleSweeper();
86
+ // ── Automation (same module the desktop loads) ──────────────────
87
+ // Read-only by default until write tiers are configured per job. Runs land in
88
+ // the RunStore so history is queryable.
89
+ const automationRunManager = createRunManager({
90
+ llm: resolvedLlmConfig,
91
+ cwd,
92
+ permissionMode: "default",
93
+ approvalBackend: new HeadlessApprovalBackend("approve-read-only"),
94
+ });
95
+ const automation = startAutomation({
96
+ store: new CronStore(defaultCronStorePath()),
97
+ runManager: automationRunManager,
98
+ });
99
+ // ── Serve over TCP ──────────────────────────────────────────────
100
+ // One AgentServer per accepted connection, all sharing the same chatManager.
101
+ const servers = new Set();
102
+ listenTcp({ port, host }, (transport) => {
103
+ const server = new AgentServer({ chatManager, transport });
104
+ servers.add(server);
105
+ })
106
+ .then((listener) => {
107
+ process.stderr.write(`[code-shell] automation server listening on ${host}:${listener.port}\n`);
108
+ const shutdown = () => {
109
+ automation.stop();
110
+ for (const s of servers)
111
+ s.close();
112
+ void listener.close().then(() => process.exit(0));
113
+ };
114
+ process.on("SIGTERM", shutdown);
115
+ process.on("SIGINT", shutdown);
116
+ })
117
+ .catch((err) => {
118
+ process.stderr.write(`[code-shell] failed to start automation server: ${String(err)}\n`);
119
+ process.exit(1);
120
+ });
@@ -0,0 +1,27 @@
1
+ /** Minimal surface we need from a server to shut it down cleanly. */
2
+ interface Closable {
3
+ close(): void;
4
+ }
5
+ /** Minimal surface we need from `process` (injectable for tests). */
6
+ interface ProcLike {
7
+ on(event: string, listener: (...args: unknown[]) => void): unknown;
8
+ exit(code?: number): void;
9
+ }
10
+ export interface GracefulShutdownOptions {
11
+ /** Defaults to the real `process`. */
12
+ proc?: ProcLike;
13
+ /** Signals to handle. Defaults to SIGTERM, SIGINT, SIGHUP. */
14
+ signals?: string[];
15
+ }
16
+ /**
17
+ * Register signal handlers that cleanly shut down a long-lived server before
18
+ * the process exits. Without this, SIGTERM/SIGINT (Ctrl+C)/SIGHUP terminate
19
+ * the process immediately, leaking the idle sweeper interval, open sessions,
20
+ * pending approvals, and child processes (MCP servers, tools).
21
+ *
22
+ * Idempotent: the first signal runs close() exactly once; later signals (or a
23
+ * second handler firing) are ignored. A throwing close() is swallowed so the
24
+ * process still exits.
25
+ */
26
+ export declare function installGracefulShutdown(server: Closable, options?: GracefulShutdownOptions): void;
27
+ export {};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Register signal handlers that cleanly shut down a long-lived server before
3
+ * the process exits. Without this, SIGTERM/SIGINT (Ctrl+C)/SIGHUP terminate
4
+ * the process immediately, leaking the idle sweeper interval, open sessions,
5
+ * pending approvals, and child processes (MCP servers, tools).
6
+ *
7
+ * Idempotent: the first signal runs close() exactly once; later signals (or a
8
+ * second handler firing) are ignored. A throwing close() is swallowed so the
9
+ * process still exits.
10
+ */
11
+ export function installGracefulShutdown(server, options = {}) {
12
+ const proc = options.proc ?? globalThis.process;
13
+ const signals = options.signals ?? ["SIGTERM", "SIGINT", "SIGHUP"];
14
+ let shuttingDown = false;
15
+ const shutdown = () => {
16
+ if (shuttingDown)
17
+ return;
18
+ shuttingDown = true;
19
+ try {
20
+ server.close();
21
+ }
22
+ catch {
23
+ // Best-effort cleanup — never block exit on a close() failure.
24
+ }
25
+ proc.exit(0);
26
+ };
27
+ for (const sig of signals) {
28
+ proc.on(sig, shutdown);
29
+ }
30
+ }
@@ -299,28 +299,36 @@ export function applyToolResultBudget(messages, maxTotalChars = 100_000) {
299
299
  return msg;
300
300
  // Sort by size descending — truncate largest first
301
301
  resultBlocks.sort((a, b) => b.size - a.size);
302
+ // Build the exact replacement for a block, so the running budget uses the
303
+ // real post-truncation length (the old code assumed a flat ~200 chars,
304
+ // but the replacement is ~150 boilerplate + up to 500 preview ≈ 650+,
305
+ // which under-truncated and could even leave the message LARGER).
306
+ const truncate = (content) => {
307
+ const preview = content.slice(0, 500);
308
+ const sizeKb = (content.length / 1000).toFixed(0);
309
+ return (`Output too large (${sizeKb}KB) — truncated to fit the per-message budget. ` +
310
+ `Re-run the originating tool if you need the full output.\n\n` +
311
+ `Preview (first 500 chars):\n${preview}`);
312
+ };
302
313
  let remaining = totalSize;
303
- const toTruncate = new Set();
314
+ const replacements = new Map();
304
315
  for (const rb of resultBlocks) {
305
316
  if (remaining <= maxTotalChars)
306
317
  break;
307
- toTruncate.add(rb.index);
308
- remaining -= rb.size;
309
- remaining += 200; // truncated replacement is ~200 chars
318
+ const original = msg.content[rb.index].content;
319
+ const replaced = truncate(original);
320
+ // Only truncate if it actually shrinks the block; otherwise skip it
321
+ // (truncating a barely-oversized block would grow the message).
322
+ if (replaced.length >= rb.size)
323
+ continue;
324
+ replacements.set(rb.index, replaced);
325
+ remaining -= rb.size - replaced.length;
310
326
  }
311
- if (toTruncate.size === 0)
327
+ if (replacements.size === 0)
312
328
  return msg;
313
329
  const newContent = msg.content.map((block, i) => {
314
- if (!toTruncate.has(i))
315
- return block;
316
- const preview = typeof block.content === "string" ? block.content.slice(0, 500) : "";
317
- const sizeKb = (block.content.length / 1000).toFixed(0);
318
- return {
319
- ...block,
320
- content: `Output too large (${sizeKb}KB) — truncated to fit the per-message budget. ` +
321
- `Re-run the originating tool if you need the full output.\n\n` +
322
- `Preview (first 500 chars):\n${preview}`,
323
- };
330
+ const replaced = replacements.get(i);
331
+ return replaced === undefined ? block : { ...block, content: replaced };
324
332
  });
325
333
  return { ...msg, content: newContent };
326
334
  });
@@ -39,7 +39,6 @@ export type OnCompactFn = (info: {
39
39
  }) => void;
40
40
  export declare class ContextManager {
41
41
  private config;
42
- private toolCallHashes;
43
42
  private summarizeFn;
44
43
  private consecutiveSummaryFailures;
45
44
  private lastSummary;
@@ -123,23 +122,4 @@ export declare class ContextManager {
123
122
  needsCompact: boolean;
124
123
  needsEmergency: boolean;
125
124
  };
126
- /**
127
- * Deduplicate tool calls by hashing arguments.
128
- */
129
- deduplicateToolCalls(calls: Array<{
130
- toolName: string;
131
- args: Record<string, unknown>;
132
- }>): {
133
- toExecute: typeof calls;
134
- cached: Array<{
135
- toolName: string;
136
- args: Record<string, unknown>;
137
- result: string;
138
- }>;
139
- };
140
- /**
141
- * Record a tool call result for dedup tracking.
142
- */
143
- recordToolResult(toolName: string, args: Record<string, unknown>, result: string): void;
144
- private hashCall;
145
125
  }
@@ -39,7 +39,6 @@ function defaultKeepRecent(maxTokens) {
39
39
  }
40
40
  export class ContextManager {
41
41
  config;
42
- toolCallHashes = new Map();
43
42
  summarizeFn;
44
43
  consecutiveSummaryFailures = 0;
45
44
  lastSummary;
@@ -384,40 +383,4 @@ export class ContextManager {
384
383
  needsEmergency: ratio >= this.config.summarizeAtRatio,
385
384
  };
386
385
  }
387
- /**
388
- * Deduplicate tool calls by hashing arguments.
389
- */
390
- deduplicateToolCalls(calls) {
391
- const toExecute = [];
392
- const cached = [];
393
- for (const call of calls) {
394
- const hash = this.hashCall(call.toolName, call.args);
395
- const existing = this.toolCallHashes.get(hash);
396
- if (existing && existing.count >= 2) {
397
- cached.push({ ...call, result: existing.lastResult });
398
- existing.count++;
399
- }
400
- else {
401
- toExecute.push(call);
402
- }
403
- }
404
- return { toExecute, cached };
405
- }
406
- /**
407
- * Record a tool call result for dedup tracking.
408
- */
409
- recordToolResult(toolName, args, result) {
410
- const hash = this.hashCall(toolName, args);
411
- const existing = this.toolCallHashes.get(hash);
412
- if (existing) {
413
- existing.count++;
414
- existing.lastResult = result;
415
- }
416
- else {
417
- this.toolCallHashes.set(hash, { count: 1, lastResult: result });
418
- }
419
- }
420
- hashCall(toolName, args) {
421
- return `${toolName}:${JSON.stringify(args)}`;
422
- }
423
386
  }
@@ -0,0 +1,2 @@
1
+ /** Back-compat shim — moved to `automation/runner.ts`. */
2
+ export * from "../automation/runner.js";
@@ -0,0 +1,2 @@
1
+ /** Back-compat shim — moved to `automation/runner.ts`. */
2
+ export * from "../automation/runner.js";
@@ -0,0 +1,2 @@
1
+ /** Back-compat shim — moved to `automation/store.ts`. */
2
+ export * from "../automation/store.js";
@@ -0,0 +1,2 @@
1
+ /** Back-compat shim — moved to `automation/store.ts`. */
2
+ export * from "../automation/store.js";
@@ -1,34 +1,7 @@
1
1
  /**
2
- * Cron scheduler schedule and manage recurring agent tasks.
3
- *
4
- * Supports simple cron-like intervals. Each job runs the Engine
5
- * with a predefined prompt on schedule.
2
+ * Back-compat shim. The cron scheduler moved to `automation/scheduler.ts`
3
+ * (see docs/automation-plan-2026-05-31.md). This re-export keeps existing
4
+ * `../cron/scheduler.js` importers working. New code should import from
5
+ * `../automation/scheduler.js`.
6
6
  */
7
- export interface CronJob {
8
- id: string;
9
- name: string;
10
- schedule: string;
11
- prompt: string;
12
- enabled: boolean;
13
- lastRun?: number;
14
- nextRun?: number;
15
- runCount: number;
16
- createdAt: number;
17
- }
18
- declare class CronScheduler {
19
- private jobs;
20
- private timers;
21
- private nextId;
22
- private onExecute?;
23
- setExecutor(fn: (job: CronJob) => Promise<void>): void;
24
- create(name: string, schedule: string, prompt: string): CronJob;
25
- delete(id: string): boolean;
26
- list(): CronJob[];
27
- get(id: string): CronJob | undefined;
28
- pause(id: string): boolean;
29
- resume(id: string): boolean;
30
- stopAll(): void;
31
- private startTimer;
32
- }
33
- export declare const cronScheduler: CronScheduler;
34
- export {};
7
+ export * from "../automation/scheduler.js";
@@ -1,115 +1,7 @@
1
1
  /**
2
- * Cron scheduler schedule and manage recurring agent tasks.
3
- *
4
- * Supports simple cron-like intervals. Each job runs the Engine
5
- * with a predefined prompt on schedule.
2
+ * Back-compat shim. The cron scheduler moved to `automation/scheduler.ts`
3
+ * (see docs/automation-plan-2026-05-31.md). This re-export keeps existing
4
+ * `../cron/scheduler.js` importers working. New code should import from
5
+ * `../automation/scheduler.js`.
6
6
  */
7
- class CronScheduler {
8
- jobs = new Map();
9
- timers = new Map();
10
- nextId = 1;
11
- onExecute;
12
- setExecutor(fn) {
13
- this.onExecute = fn;
14
- }
15
- create(name, schedule, prompt) {
16
- const id = String(this.nextId++);
17
- const intervalMs = parseSchedule(schedule);
18
- const job = {
19
- id,
20
- name,
21
- schedule,
22
- prompt,
23
- enabled: true,
24
- nextRun: Date.now() + intervalMs,
25
- runCount: 0,
26
- createdAt: Date.now(),
27
- };
28
- this.jobs.set(id, job);
29
- this.startTimer(job, intervalMs);
30
- return job;
31
- }
32
- delete(id) {
33
- const timer = this.timers.get(id);
34
- if (timer) {
35
- clearInterval(timer);
36
- this.timers.delete(id);
37
- }
38
- return this.jobs.delete(id);
39
- }
40
- list() {
41
- return [...this.jobs.values()];
42
- }
43
- get(id) {
44
- return this.jobs.get(id);
45
- }
46
- pause(id) {
47
- const job = this.jobs.get(id);
48
- if (!job)
49
- return false;
50
- job.enabled = false;
51
- const timer = this.timers.get(id);
52
- if (timer) {
53
- clearInterval(timer);
54
- this.timers.delete(id);
55
- }
56
- return true;
57
- }
58
- resume(id) {
59
- const job = this.jobs.get(id);
60
- if (!job)
61
- return false;
62
- job.enabled = true;
63
- const intervalMs = parseSchedule(job.schedule);
64
- this.startTimer(job, intervalMs);
65
- return true;
66
- }
67
- stopAll() {
68
- for (const timer of this.timers.values()) {
69
- clearInterval(timer);
70
- }
71
- this.timers.clear();
72
- }
73
- startTimer(job, intervalMs) {
74
- if (this.timers.has(job.id)) {
75
- clearInterval(this.timers.get(job.id));
76
- }
77
- const timer = setInterval(async () => {
78
- if (!job.enabled)
79
- return;
80
- job.lastRun = Date.now();
81
- job.runCount++;
82
- job.nextRun = Date.now() + intervalMs;
83
- try {
84
- await this.onExecute?.(job);
85
- }
86
- catch {
87
- // Job execution failed — continue scheduling
88
- }
89
- }, intervalMs);
90
- this.timers.set(job.id, timer);
91
- }
92
- }
93
- /**
94
- * Parse a schedule string into milliseconds.
95
- * Supports: "30s", "5m", "1h", "1d", or raw milliseconds.
96
- */
97
- function parseSchedule(schedule) {
98
- const match = schedule.match(/^(\d+)(s|m|h|d)$/);
99
- if (match) {
100
- const value = parseInt(match[1], 10);
101
- switch (match[2]) {
102
- case "s": return value * 1000;
103
- case "m": return value * 60 * 1000;
104
- case "h": return value * 60 * 60 * 1000;
105
- case "d": return value * 24 * 60 * 60 * 1000;
106
- }
107
- }
108
- // Try raw number (milliseconds)
109
- const ms = parseInt(schedule, 10);
110
- if (!isNaN(ms) && ms > 0)
111
- return ms;
112
- // Default: 10 minutes
113
- return 10 * 60 * 1000;
114
- }
115
- export const cronScheduler = new CronScheduler();
7
+ export * from "../automation/scheduler.js";
@@ -47,7 +47,7 @@ export async function syncOpenRouterCatalog(timeoutMs = 15_000) {
47
47
  return { ok: true, count: models.length };
48
48
  }
49
49
  catch (err) {
50
- return { ok: false, count: 0, error: err.message };
50
+ return { ok: false, count: 0, error: err instanceof Error ? err.message : String(err) };
51
51
  }
52
52
  }
53
53
  export { getOpenRouterSnapshot };