talon-agent 5.0.0 → 5.1.0

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 (136) hide show
  1. package/package.json +2 -2
  2. package/src/app.ts +3 -3
  3. package/src/backend/claude-sdk/factory.ts +21 -41
  4. package/src/backend/claude-sdk/handler.ts +191 -69
  5. package/src/backend/claude-sdk/host/in-process.ts +147 -0
  6. package/src/backend/claude-sdk/one-shot.ts +17 -2
  7. package/src/backend/claude-sdk/stream.ts +9 -0
  8. package/src/backend/codex/mcp-config.ts +1 -1
  9. package/src/backend/codex/one-shot.ts +18 -4
  10. package/src/backend/openai-agents/mcp-pool.ts +1 -1
  11. package/src/backend/remote-server/one-shot.ts +16 -3
  12. package/src/backend/runtime/index.ts +2 -2
  13. package/src/backend/runtime/one-shot-hooks.ts +45 -0
  14. package/src/backend/runtime/turn/delivery.ts +1 -1
  15. package/src/backend/runtime/turn/turn-phases.ts +1 -1
  16. package/src/bootstrap.ts +2 -2
  17. package/src/cli.ts +5 -2
  18. package/src/core/agent-runtime/README.md +15 -0
  19. package/src/core/agent-runtime/agent-host.ts +388 -0
  20. package/src/core/agent-runtime/capabilities.ts +3 -0
  21. package/src/core/background/cron/scheduler.ts +1 -1
  22. package/src/core/background/triggers/command.ts +1 -1
  23. package/src/{util → core/config}/harden.ts +1 -1
  24. package/src/core/config/index.ts +1 -1
  25. package/src/core/daemon/pidfile.ts +1 -1
  26. package/src/core/daemon/resource-sampler.ts +2 -2
  27. package/src/{util → core/daemon}/respawn.ts +1 -1
  28. package/src/core/doctor/index.ts +1 -1
  29. package/src/core/engine/gateway-actions/fetch-url.ts +1 -1
  30. package/src/core/engine/gateway-actions/index.ts +1 -1
  31. package/src/core/engine/gateway-actions/memory.ts +2 -2
  32. package/src/core/engine/gateway-actions/native/exec-background.ts +129 -0
  33. package/src/core/engine/gateway-actions/native/exec-remote.ts +85 -0
  34. package/src/core/engine/gateway-actions/native/exec.ts +182 -0
  35. package/src/core/engine/gateway-actions/native/index.ts +46 -0
  36. package/src/core/engine/gateway-actions/native/params.ts +46 -0
  37. package/src/core/engine/gateway-actions/native/read.ts +182 -0
  38. package/src/core/engine/gateway-actions/native/results.ts +34 -0
  39. package/src/core/engine/gateway-actions/native/search.ts +212 -0
  40. package/src/core/engine/gateway-actions/native/shell.ts +39 -0
  41. package/src/core/engine/gateway-actions/native/teleport.ts +55 -0
  42. package/src/core/engine/gateway-actions/native/write.ts +170 -0
  43. package/src/core/frontend-runtime/builtins.ts +2 -2
  44. package/src/core/mcp-hub/children.ts +21 -5
  45. package/src/core/mcp-hub/index.ts +1 -1
  46. package/src/core/mcp-hub/talon-server.ts +1 -1
  47. package/src/core/memory/taps.ts +1 -1
  48. package/src/core/plugin/mcp.ts +1 -1
  49. package/src/core/scripts/lua.ts +1 -1
  50. package/src/core/tools/{chat.ts → chat/chat.ts} +1 -1
  51. package/src/core/tools/{cross-send.ts → chat/cross-send.ts} +1 -1
  52. package/src/core/tools/{history.ts → chat/history.ts} +2 -2
  53. package/src/core/tools/{media.ts → chat/media.ts} +1 -1
  54. package/src/core/tools/{members.ts → chat/members.ts} +2 -2
  55. package/src/core/tools/{messaging.ts → chat/messaging.ts} +2 -2
  56. package/src/core/tools/{moderation.ts → chat/moderation.ts} +2 -2
  57. package/src/core/tools/{stickers.ts → chat/stickers.ts} +2 -2
  58. package/src/core/tools/{whatsapp.ts → chat/whatsapp.ts} +1 -1
  59. package/src/core/tools/{memory.ts → content/memory.ts} +2 -2
  60. package/src/core/tools/{web.ts → content/web.ts} +1 -1
  61. package/src/core/tools/index.ts +20 -20
  62. package/src/core/tools/{admin.ts → ops/admin.ts} +1 -1
  63. package/src/core/tools/{bridge.ts → ops/bridge.ts} +2 -2
  64. package/src/core/tools/{goals.ts → ops/goals.ts} +2 -2
  65. package/src/core/tools/{mesh.ts → ops/mesh.ts} +1 -1
  66. package/src/core/tools/{models.ts → ops/models.ts} +1 -1
  67. package/src/core/tools/{native.ts → ops/native.ts} +1 -1
  68. package/src/core/tools/{scheduling.ts → ops/scheduling.ts} +1 -1
  69. package/src/core/tools/{scripts.ts → ops/scripts.ts} +1 -1
  70. package/src/core/tools/{skills.ts → ops/skills.ts} +1 -1
  71. package/src/core/tools/{triggers.ts → ops/triggers.ts} +1 -1
  72. package/src/core/types.ts +11 -0
  73. package/src/{util → core/vfs}/workspace.ts +2 -2
  74. package/src/frontend/discord/callbacks/components/effort.ts +1 -1
  75. package/src/frontend/discord/callbacks/components/index.ts +1 -1
  76. package/src/frontend/discord/callbacks/components/settings.ts +1 -1
  77. package/src/frontend/discord/commands/admin.ts +1 -1
  78. package/src/frontend/discord/commands/info.ts +1 -1
  79. package/src/frontend/discord/commands/interaction.ts +1 -1
  80. package/src/frontend/discord/commands/session.ts +3 -3
  81. package/src/frontend/discord/commands/settings.ts +1 -1
  82. package/src/frontend/discord/handlers/messages.ts +1 -1
  83. package/src/frontend/discord/handlers/state.ts +1 -1
  84. package/src/frontend/discord/middleware.ts +1 -1
  85. package/src/frontend/discord/ready.ts +1 -1
  86. package/src/frontend/discord/render.ts +41 -259
  87. package/src/frontend/native/chats/chats.ts +1 -1
  88. package/src/frontend/native/surface/models.ts +1 -1
  89. package/src/frontend/native/turn/context.ts +1 -1
  90. package/src/frontend/native/turn/emit.ts +1 -1
  91. package/src/frontend/{shared → presentation}/format.ts +4 -3
  92. package/src/frontend/{shared → presentation}/reasoning-levels.ts +12 -0
  93. package/src/frontend/presentation/reports.ts +493 -0
  94. package/src/frontend/{shared → presentation}/session-status.ts +1 -1
  95. package/src/frontend/teams/commands.ts +2 -2
  96. package/src/frontend/teams/turn.ts +1 -1
  97. package/src/frontend/telegram/admin/health.ts +1 -1
  98. package/src/frontend/telegram/admin/sessions.ts +1 -1
  99. package/src/frontend/telegram/callbacks/effort.ts +2 -2
  100. package/src/frontend/telegram/callbacks/metrics.ts +1 -1
  101. package/src/frontend/telegram/callbacks/model/views.ts +1 -1
  102. package/src/frontend/telegram/callbacks/query.ts +1 -1
  103. package/src/frontend/telegram/callbacks/settings.ts +2 -2
  104. package/src/frontend/telegram/commands/admin.ts +4 -4
  105. package/src/frontend/telegram/commands/info.ts +2 -2
  106. package/src/frontend/telegram/commands/session.ts +4 -4
  107. package/src/frontend/telegram/commands/settings.ts +4 -2
  108. package/src/frontend/telegram/handlers/state.ts +1 -1
  109. package/src/frontend/telegram/model-menu.ts +1 -1
  110. package/src/frontend/telegram/render/html.ts +30 -0
  111. package/src/frontend/telegram/{helpers → render}/menu.ts +46 -19
  112. package/src/frontend/telegram/render/reports.ts +182 -0
  113. package/src/frontend/terminal/builtins/context.ts +2 -2
  114. package/src/frontend/terminal/builtins/session.ts +1 -1
  115. package/src/frontend/terminal/builtins/status.ts +2 -2
  116. package/src/frontend/terminal/index.ts +2 -2
  117. package/src/frontend/terminal/renderer.ts +1 -1
  118. package/src/frontend/whatsapp/commands.ts +5 -5
  119. package/src/frontend/whatsapp/registry.ts +1 -1
  120. package/src/index.ts +5 -2
  121. package/src/util/runtime.ts +1 -1
  122. package/src/core/engine/gateway-actions/native.ts +0 -1035
  123. package/src/frontend/telegram/helpers/diagnostics.ts +0 -428
  124. package/src/frontend/telegram/helpers/format.ts +0 -42
  125. package/src/frontend/telegram/helpers/index.ts +0 -13
  126. package/src/util/cleanup-registry.ts +0 -36
  127. /package/src/{util → core/daemon}/boot-timer.ts +0 -0
  128. /package/src/{util → core/frontend-runtime}/chat-id.ts +0 -0
  129. /package/src/{util/mcp-launcher.ts → core/mcp-hub/launcher.ts} +0 -0
  130. /package/src/{util → core/tools/content}/web-content.ts +0 -0
  131. /package/src/core/tools/{mcp-env.ts → ops/mcp-env.ts} +0 -0
  132. /package/src/{util → core/weaver}/session-name.ts +0 -0
  133. /package/src/frontend/{shared → presentation}/access.ts +0 -0
  134. /package/src/frontend/{shared → presentation}/model-commands.ts +0 -0
  135. /package/src/frontend/{shared → presentation}/plan-usage-report.ts +0 -0
  136. /package/src/frontend/{shared → presentation}/status-context.ts +0 -0
@@ -20,6 +20,7 @@ import { ALLOWED_TOOLS_BACKGROUND } from "../../core/constants.js";
20
20
  import { EFFORT_MAP } from "./constants.js";
21
21
  import { buildMcpServers, buildPluginMcpServers } from "./options.js";
22
22
  import { warnIfBelowCacheMinimum } from "../runtime/cache/cache-telemetry.js";
23
+ import { emitAssistantText } from "../runtime/one-shot-hooks.js";
23
24
 
24
25
  const DEFAULT_SUBPROCESS_KILL_GRACE_MS = 5 * 1000;
25
26
 
@@ -65,6 +66,7 @@ export async function runOneShotAgent(
65
66
  contextLabel,
66
67
  abortController,
67
68
  appendLog,
69
+ onAssistantText,
68
70
  } = params;
69
71
 
70
72
  // Reasoning effort is opt-in for background runs (config `heartbeatEffort`
@@ -126,7 +128,7 @@ export async function runOneShotAgent(
126
128
  // settlement figure the task table records.
127
129
  let usage: OneShotUsage | undefined;
128
130
  for await (const msg of qi) {
129
- await formatAndAppendMessage(appendLog, msg);
131
+ await formatAndAppendMessage(appendLog, msg, onAssistantText);
130
132
  if (msg.type === "result") {
131
133
  const u = msg.usage;
132
134
  usage = {
@@ -183,6 +185,7 @@ function assembleMcpServers(contextLabel: string): Record<string, unknown> {
183
185
  async function formatAndAppendMessage(
184
186
  appendLog: (text: string) => Promise<void>,
185
187
  msg: SDKMessage,
188
+ onAssistantText?: OneShotAgentParams["onAssistantText"],
186
189
  ): Promise<void> {
187
190
  try {
188
191
  const ts = new Date().toISOString().slice(11, 19);
@@ -200,7 +203,11 @@ async function formatAndAppendMessage(
200
203
  });
201
204
 
202
205
  if (textBlocks.length > 0) {
203
- await appendLog(`\n## [${ts}] Assistant\n${textBlocks.join("\n")}\n`);
206
+ const assistantText = textBlocks.join("\n");
207
+ // Report before the log write: an append failure (full disk, closed
208
+ // handle) must not also swallow the run's result for a hook caller.
209
+ emitAssistantText(onAssistantText, assistantText);
210
+ await appendLog(`\n## [${ts}] Assistant\n${assistantText}\n`);
204
211
  }
205
212
  if (toolUseBlocks.length > 0) {
206
213
  await appendLog(`\n${toolUseBlocks.join("\n\n")}\n`);
@@ -208,6 +215,14 @@ async function formatAndAppendMessage(
208
215
  break;
209
216
  }
210
217
  case "result": {
218
+ // Deliberately NOT reported through `onAssistantText`. The SDK's
219
+ // terminal `result` message restates the last assistant turn's text
220
+ // (`subtype: "success"`) or carries an error string (the
221
+ // `error_*` subtypes) — never anything the `assistant` case above
222
+ // has not already emitted. Reporting it too would hand every hook
223
+ // caller a duplicate final segment, and the truncated copy at that
224
+ // (2000 chars, below). The log keeps it because a run log wants the
225
+ // settlement line; a sub-agent result does not.
211
226
  const result =
212
227
  "result" in msg
213
228
  ? (msg as { result: string }).result
@@ -422,6 +422,15 @@ function readResultError(msg: SDKResultMessage, state: StreamState): void {
422
422
  .filter((e) => typeof e === "string" && !e.startsWith("[ede_diagnostic]"))
423
423
  .join("; ")
424
424
  .slice(0, 500);
425
+ // A known startup failure (SDK ≥ 0.3.274) names its cause — the CLI
426
+ // never ran a turn, so nothing else in the result says why. Lead with
427
+ // it; the diagnostics text is the same line stderr carried.
428
+ if (msg.startup_failure_reason) {
429
+ state.resultErrorText =
430
+ `Claude Code failed to start (${msg.startup_failure_reason})` +
431
+ (diagnostics ? `: ${diagnostics}` : "");
432
+ return;
433
+ }
425
434
  state.resultErrorText =
426
435
  state.lastTrailingText.trim() ||
427
436
  diagnostics ||
@@ -29,7 +29,7 @@ import {
29
29
  pluginHubUrl,
30
30
  hubPluginServerNames,
31
31
  } from "../../core/mcp-hub/index.js";
32
- import type { ToolExclusionConfig } from "../../core/tools/mcp-env.js";
32
+ import type { ToolExclusionConfig } from "../../core/tools/ops/mcp-env.js";
33
33
  import { frontendsForChat } from "../runtime/frontends.js";
34
34
 
35
35
  /**
@@ -20,6 +20,7 @@
20
20
  import type { OneShotAgentParams, OneShotUsage } from "../../core/types.js";
21
21
  import { log, logWarn } from "../../util/log.js";
22
22
  import { appendBackendSuffix } from "../runtime/index.js";
23
+ import { emitAssistantText } from "../runtime/one-shot-hooks.js";
23
24
  import { ensureCodex, getCodexAuthInfo } from "./init.js";
24
25
  import {
25
26
  CODEX_SYSTEM_PROMPT_SUFFIX,
@@ -79,6 +80,7 @@ export async function runOneShotAgent(
79
80
  contextLabel,
80
81
  abortController,
81
82
  appendLog,
83
+ onAssistantText,
82
84
  } = params;
83
85
 
84
86
  const codex = ensureCodex(contextLabel);
@@ -143,7 +145,7 @@ export async function runOneShotAgent(
143
145
  let usage: OneShotUsage | undefined;
144
146
  for await (const event of events) {
145
147
  if (abortController.signal.aborted) break;
146
- await appendCodexEvent(appendLog, event);
148
+ await appendCodexEvent(appendLog, event, onAssistantText);
147
149
  if (event.type === "turn.completed") {
148
150
  const u = (event as { usage?: Record<string, number> }).usage;
149
151
  if (u) {
@@ -217,6 +219,7 @@ export async function runOneShotAgent(
217
219
  async function appendCodexEvent(
218
220
  appendLog: (text: string) => Promise<void>,
219
221
  event: { type: string } & Record<string, unknown>,
222
+ onAssistantText?: OneShotAgentParams["onAssistantText"],
220
223
  ): Promise<void> {
221
224
  const ts = new Date().toISOString().slice(11, 19);
222
225
 
@@ -260,7 +263,7 @@ async function appendCodexEvent(
260
263
  case "item.completed": {
261
264
  const item = (event as unknown as { item?: Record<string, unknown> })
262
265
  .item;
263
- if (item) await appendCodexItem(appendLog, item, ts);
266
+ if (item) await appendCodexItem(appendLog, item, ts, onAssistantText);
264
267
  return;
265
268
  }
266
269
  default:
@@ -268,17 +271,28 @@ async function appendCodexEvent(
268
271
  }
269
272
  }
270
273
 
271
- /** Append one `ThreadItem` to the run log. */
274
+ /**
275
+ * Append one `ThreadItem` to the run log, and report the model's final
276
+ * answers to the run's optional `onAssistantText` consumer.
277
+ *
278
+ * Only `agent_message` items are reported: `reasoning` items are the model's
279
+ * thinking and the rest are tool/command/diff payloads, none of which is the
280
+ * run's answer.
281
+ */
272
282
  async function appendCodexItem(
273
283
  appendLog: (text: string) => Promise<void>,
274
284
  item: Record<string, unknown>,
275
285
  ts: string,
286
+ onAssistantText?: OneShotAgentParams["onAssistantText"],
276
287
  ): Promise<void> {
277
288
  const type = typeof item.type === "string" ? item.type : "unknown";
278
289
 
279
290
  if (type === "agent_message") {
280
291
  const text = typeof item.text === "string" ? item.text : "";
281
- if (text) await appendLog(`\n## [${ts}] Assistant\n${text}\n`);
292
+ if (text) {
293
+ emitAssistantText(onAssistantText, text);
294
+ await appendLog(`\n## [${ts}] Assistant\n${text}\n`);
295
+ }
282
296
  return;
283
297
  }
284
298
 
@@ -30,7 +30,7 @@ import {
30
30
  pluginHubUrl,
31
31
  hubPluginServerNames,
32
32
  } from "../../core/mcp-hub/index.js";
33
- import type { ToolExclusionConfig } from "../../core/tools/mcp-env.js";
33
+ import type { ToolExclusionConfig } from "../../core/tools/ops/mcp-env.js";
34
34
  import { frontendsForChat } from "../runtime/frontends.js";
35
35
  import { log, logWarn } from "../../util/log.js";
36
36
 
@@ -42,6 +42,7 @@ import {
42
42
  type RemoteAssistantInfo,
43
43
  } from "./session-helpers.js";
44
44
  import { appendBackendSuffix, sleep } from "../runtime/index.js";
45
+ import { emitAssistantText } from "../runtime/one-shot-hooks.js";
45
46
  import { buildPermissionRuleset } from "./sessions.js";
46
47
 
47
48
  // ── Client surface ──────────────────────────────────────────────────────────
@@ -108,6 +109,7 @@ export async function runRemoteOneShotAgent<
108
109
  contextLabel,
109
110
  abortController,
110
111
  appendLog,
112
+ onAssistantText,
111
113
  } = params;
112
114
  const { label, errMsg } = bindings;
113
115
 
@@ -210,7 +212,7 @@ export async function runRemoteOneShotAgent<
210
212
  : [];
211
213
 
212
214
  for (const part of parts) {
213
- await appendResponsePart(appendLog, part);
215
+ await appendResponsePart(appendLog, part, onAssistantText);
214
216
  }
215
217
 
216
218
  // The prompt response's assistant info carries the run's token usage —
@@ -250,17 +252,28 @@ export async function runRemoteOneShotAgent<
250
252
 
251
253
  // ── Run-log rendering ───────────────────────────────────────────────────────
252
254
 
253
- /** Render one response part into the Markdown run log. */
255
+ /**
256
+ * Render one response part into the Markdown run log, and report the
257
+ * assistant's final text to the run's optional `onAssistantText` consumer.
258
+ *
259
+ * Only the `text` parts are reported: `reasoning` parts are the model's
260
+ * thinking and tool parts are call payloads, neither of which is the run's
261
+ * answer.
262
+ */
254
263
  async function appendResponsePart(
255
264
  appendLog: (text: string) => Promise<void>,
256
265
  part: Record<string, unknown>,
266
+ onAssistantText?: OneShotAgentParams["onAssistantText"],
257
267
  ): Promise<void> {
258
268
  const ts = new Date().toISOString().slice(11, 19);
259
269
  const type = typeof part.type === "string" ? part.type : "unknown";
260
270
 
261
271
  if (type === "text") {
262
272
  const text = typeof part.text === "string" ? part.text : "";
263
- if (text) await appendLog(`\n## [${ts}] Assistant\n${text}\n`);
273
+ if (text) {
274
+ emitAssistantText(onAssistantText, text);
275
+ await appendLog(`\n## [${ts}] Assistant\n${text}\n`);
276
+ }
264
277
  return;
265
278
  }
266
279
 
@@ -20,7 +20,7 @@
20
20
  * - `prompt/prompt-format` — user-prompt formatter
21
21
  * ([time] [Name] [msg_id:N]).
22
22
  * - `frontends` — config `frontend` → messaging-frontend list.
23
- * - `extractSessionName` — re-exported from `util/session-name` so the
23
+ * - `extractSessionName` — re-exported from `core/weaver/session-name` so the
24
24
  * backends keep one import site; the helper itself is frontend-neutral.
25
25
  * - `usage` — cache-hit % + log summarisers.
26
26
  * - `prompt/system-prompt` — per-session prompt snapshots + backend
@@ -37,7 +37,7 @@
37
37
  * - SDK-specific event types — those live in each backend.
38
38
  * - Session storage — that's `src/storage/sessions.ts`.
39
39
  * - MCP server registration — backend-specific transport details
40
- * (the spawn/env contract they share is `core/tools/mcp-env.ts`).
40
+ * (the spawn/env contract they share is `core/tools/ops/mcp-env.ts`).
41
41
  */
42
42
 
43
43
  export { captureDeliveredText } from "./turn/delivered-text.js";
@@ -0,0 +1,45 @@
1
+ /**
2
+ * One-shot run hooks — the shared, throw-proof call site for
3
+ * `OneShotAgentParams.onAssistantText`.
4
+ *
5
+ * Every backend's isolated runner (`BackgroundRunner.runOneShotAgent`) already
6
+ * renders the model's assistant text into the run log as markdown. The hook is
7
+ * the same text as data, so a caller (the sub-agent runner) can take a run's
8
+ * result without parsing the log back apart. It lives here rather than in each
9
+ * backend so all four report it identically: same "final answer only" meaning,
10
+ * same empty-string skip, same swallow-and-log on a throwing callback.
11
+ *
12
+ * Contract:
13
+ * - Final assistant text only. Reasoning/thinking blocks and tool-call
14
+ * payloads are log-only; they never reach the hook.
15
+ * - Synchronous. The runner does not await the consumer, so a hook that
16
+ * wants to do async work owns its own queueing.
17
+ * - Never throws into the run. A consumer bug must not abort a heartbeat.
18
+ */
19
+
20
+ import type { OneShotAgentParams } from "../../core/types.js";
21
+ import { logWarn } from "../../util/log.js";
22
+
23
+ /**
24
+ * Report one assistant text segment to the run's optional consumer.
25
+ *
26
+ * No-ops when there is no hook (the heartbeat/dream/cron path) or when the
27
+ * text is empty — the backends guard their log appends the same way, so the
28
+ * hook sees exactly the segments the log does.
29
+ */
30
+ export function emitAssistantText(
31
+ onAssistantText: OneShotAgentParams["onAssistantText"],
32
+ text: string,
33
+ ): void {
34
+ if (!onAssistantText || !text) return;
35
+ try {
36
+ onAssistantText(text);
37
+ } catch (err) {
38
+ logWarn(
39
+ "agent",
40
+ `one-shot onAssistantText hook threw (ignored): ${
41
+ err instanceof Error ? err.message : String(err)
42
+ }`,
43
+ );
44
+ }
45
+ }
@@ -9,7 +9,7 @@
9
9
  * Routes:
10
10
  *
11
11
  * - `tool` — a delivery tool (`end_turn` / `send` / `react`) already
12
- * bridged the message to the platform via `core/tools/messaging.ts`.
12
+ * bridged the message to the platform via `core/tools/chat/messaging.ts`.
13
13
  * The message is already in the chat; we don't re-emit. We may
14
14
  * have captured `deliveredTextNorms` for dedup, or just have
15
15
  * `hadBridgeDelivery` set (e.g. `send(type="photo")` — non-text
@@ -25,7 +25,7 @@ import {
25
25
  setSessionName,
26
26
  } from "../../../storage/sessions.js";
27
27
  import { log } from "../../../util/log.js";
28
- import { extractSessionName } from "../../../util/session-name.js";
28
+ import { extractSessionName } from "../../../core/weaver/session-name.js";
29
29
  import { traceMessage } from "../../../util/trace.js";
30
30
  import {
31
31
  FLOW_VIOLATION_MAX_RETRIES,
package/src/bootstrap.ts CHANGED
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import { loadConfig, rebuildSystemPrompt } from "./core/config/index.js";
13
- import { initWorkspace } from "./util/workspace.js";
13
+ import { initWorkspace } from "./core/vfs/workspace.js";
14
14
  import { loadSessions, resetSession } from "./storage/sessions.js";
15
15
  import { loadChatSettings } from "./storage/chat-settings.js";
16
16
  import { loadCronJobs } from "./storage/cron.js";
@@ -36,7 +36,7 @@ import {
36
36
  import { initDream, maybeStartDream } from "./core/background/dream/index.js";
37
37
  import { initHeartbeat } from "./core/background/heartbeat/index.js";
38
38
  import { log, logWarn, logDebug } from "./util/log.js";
39
- import { bootPhase } from "./util/boot-timer.js";
39
+ import { bootPhase } from "./core/daemon/boot-timer.js";
40
40
  import { mapConcurrent } from "./util/concurrency.js";
41
41
  import type { TalonConfig } from "./core/config/index.js";
42
42
  import { resolveFrontendIdAmong } from "./core/frontend-runtime/routing.js";
package/src/cli.ts CHANGED
@@ -16,13 +16,16 @@
16
16
  * `cli/index.ts`. Everything else lives under `cli/`.
17
17
  */
18
18
 
19
- import { MCP_LAUNCH_SUBCOMMAND, runSupervisor } from "./util/mcp-launcher.js";
19
+ import {
20
+ MCP_LAUNCH_SUBCOMMAND,
21
+ runSupervisor,
22
+ } from "./core/mcp-hub/launcher.js";
20
23
  import { LUA_RUN_SUBCOMMAND, runLuaMain } from "./core/scripts/lua.js";
21
24
 
22
25
  // Hidden subcommand dispatch — must run before anything else. Talon
23
26
  // supervises MCP stdio children (`_mcp-launch`) and runs WASM-sandboxed
24
27
  // Lua trigger scripts (`_lua-run`) by re-invoking its own entrypoint
25
- // (see util/mcp-launcher.ts). Neither call resolves; the helper process
28
+ // (see core/mcp-hub/launcher.ts). Neither call resolves; the helper process
26
29
  // exits from its own handlers.
27
30
  if (process.argv[2] === MCP_LAUNCH_SUBCOMMAND) {
28
31
  await runSupervisor(process.argv.slice(3));
@@ -69,6 +69,21 @@ onto the SQLite layer in `src/storage/` (typed tables or the `kv`
69
69
  singleton store). Legacy files import once at boot via
70
70
  `storage/legacy-import.ts` and are renamed `*.imported`.
71
71
 
72
+ ### `agent-host.ts`
73
+
74
+ The seam the Claude Agent SDK moves out of the daemon across
75
+ (`docs/agent-host-sidecar.md`). Two halves: the NDJSON wire vocabulary
76
+ (`HostRequest` / `HostReply` / `HostEvent` / `HostNotice`, plus
77
+ `parseHostMessage` / `serializeHostMessage` — unknown types parse to a
78
+ typed `unknown` the reader logs and drops, never a throw), and
79
+ `AgentHostClient`, the interface the daemon holds. Phase 1 ships one
80
+ implementation, `backend/claude-sdk/host/in-process.ts`; Phase 2 adds a
81
+ process-backed one behind the same interface. Fixtures:
82
+ `protocol/fixtures/agent-host_v1.json`.
83
+
84
+ The interface and codec live here, not in `backend/`, because `core/` may
85
+ not import `backend/` — the implementations live under `backend/`.
86
+
72
87
  ### `contract-tests.ts`
73
88
 
74
89
  Backend contract assertions any conforming `Backend` must pass: