@gajae-code/coding-agent 0.18.7 → 0.18.8

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 (279) hide show
  1. package/CHANGELOG.md +279 -1
  2. package/dist/types/async/job-manager.d.ts +1 -1
  3. package/dist/types/capability/mcp.d.ts +2 -0
  4. package/dist/types/capability/skill.d.ts +2 -0
  5. package/dist/types/capability/types.d.ts +2 -0
  6. package/dist/types/cli/public-command-errors.d.ts +3 -1
  7. package/dist/types/cli/setup-cli.d.ts +1 -1
  8. package/dist/types/commands/deep-interview.d.ts +3 -0
  9. package/dist/types/config/autorouting-tier-map.d.ts +348 -9
  10. package/dist/types/config/file-lock.d.ts +1 -0
  11. package/dist/types/config/model-bindings-applier.d.ts +2 -0
  12. package/dist/types/config/model-profile-activation.d.ts +11 -3
  13. package/dist/types/config/model-registry.d.ts +4 -9
  14. package/dist/types/config/skill-settings-defaults.d.ts +2 -0
  15. package/dist/types/cursor-delete-path.d.ts +1 -0
  16. package/dist/types/cursor-mcp-name.d.ts +8 -0
  17. package/dist/types/customization/inventory.d.ts +2 -0
  18. package/dist/types/debug/report-bundle-parent.d.ts +2 -0
  19. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +1 -0
  20. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.d.ts +31 -0
  21. package/dist/types/defaults/gjc-skills.generated.d.ts +5 -6
  22. package/dist/types/discovery/helpers.d.ts +6 -1
  23. package/dist/types/export/html/css-color.d.ts +2 -0
  24. package/dist/types/export/html/template.generated.d.ts +1 -1
  25. package/dist/types/extensibility/extensions/types.d.ts +7 -0
  26. package/dist/types/extensibility/gjc-plugins/runtime-adapters.d.ts +14 -1
  27. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +2 -0
  28. package/dist/types/extensibility/plugins/plugin-link-path.d.ts +2 -0
  29. package/dist/types/extensibility/runtime-skill-discovery.d.ts +3 -1
  30. package/dist/types/extensibility/skill-management.d.ts +3 -1
  31. package/dist/types/extensibility/skills.d.ts +2 -0
  32. package/dist/types/gjc-runtime/deep-interview-crystallize.d.ts +74 -0
  33. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +11 -0
  34. package/dist/types/gjc-runtime/gc-runtime.d.ts +5 -0
  35. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +0 -5
  36. package/dist/types/gjc-runtime/state-argv.d.ts +1 -1
  37. package/dist/types/gjc-runtime/state-migrations.d.ts +8 -0
  38. package/dist/types/gjc-runtime/state-runtime.d.ts +95 -0
  39. package/dist/types/gjc-runtime/state-writer.d.ts +11 -1
  40. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -0
  41. package/dist/types/internal-urls/skill-path.d.ts +1 -0
  42. package/dist/types/lsp/workspace-path.d.ts +1 -0
  43. package/dist/types/modes/acp/acp-agent.d.ts +7 -0
  44. package/dist/types/modes/components/custom-editor.d.ts +6 -0
  45. package/dist/types/modes/components/customization/customization-dashboard.d.ts +1 -0
  46. package/dist/types/modes/components/extensions/state-manager.d.ts +4 -3
  47. package/dist/types/modes/controllers/input-controller.d.ts +9 -0
  48. package/dist/types/modes/interactive-mode.d.ts +1 -0
  49. package/dist/types/modes/utils/interrupt-ownership.d.ts +3 -0
  50. package/dist/types/modes/utils/keybinding-matchers.d.ts +1 -0
  51. package/dist/types/modes/utils/macos-option-forwarding.d.ts +17 -0
  52. package/dist/types/progress/collect-project-progress.d.ts +38 -0
  53. package/dist/types/progress/progress-contract.d.ts +154 -0
  54. package/dist/types/progress/progress-snapshot.d.ts +11 -0
  55. package/dist/types/progress/project-progress.d.ts +141 -0
  56. package/dist/types/progress/render-progress.d.ts +28 -0
  57. package/dist/types/runtime-mcp/oauth-public-url.d.ts +1 -0
  58. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +1 -0
  59. package/dist/types/runtime-mcp/smithery-registry.d.ts +24 -0
  60. package/dist/types/runtime-mcp/types.d.ts +6 -0
  61. package/dist/types/sdk/acp/adapter.d.ts +1 -1
  62. package/dist/types/sdk/broker/broker-exit.d.ts +6 -2
  63. package/dist/types/sdk/broker/broker.d.ts +18 -1
  64. package/dist/types/sdk/broker/session-index.d.ts +12 -6
  65. package/dist/types/sdk/bus/index.d.ts +12 -1
  66. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +6 -1
  67. package/dist/types/sdk/client/client.d.ts +2 -0
  68. package/dist/types/sdk/host/query/handlers.d.ts +3 -0
  69. package/dist/types/sdk/index.d.ts +1 -0
  70. package/dist/types/sdk/router/session-router.d.ts +2 -0
  71. package/dist/types/sdk/session-list.d.ts +1 -1
  72. package/dist/types/sdk/session.d.ts +8 -0
  73. package/dist/types/session/agent-session.d.ts +38 -9
  74. package/dist/types/session/artifacts.d.ts +2 -2
  75. package/dist/types/session/internal/managed-gc-retirement-codec.d.ts +32 -0
  76. package/dist/types/session/internal/managed-session-scope.d.ts +79 -2
  77. package/dist/types/session/internal/managed-session-storage.d.ts +26 -1
  78. package/dist/types/session/internal/managed-task-owner-cleanup.d.ts +62 -0
  79. package/dist/types/session/internal/task-artifact-owner-access.d.ts +2 -0
  80. package/dist/types/session/internal/task-artifact-owner-transcript.d.ts +9 -1
  81. package/dist/types/session/session-manager.d.ts +31 -5
  82. package/dist/types/session/session-retirement.d.ts +31 -7
  83. package/dist/types/session/session-storage.d.ts +62 -2
  84. package/dist/types/session/task-artifact-owner-codec.d.ts +2 -0
  85. package/dist/types/setup/credential-auto-import.d.ts +1 -1
  86. package/dist/types/setup/credential-import.d.ts +6 -4
  87. package/dist/types/skill-state/active-state.d.ts +38 -0
  88. package/dist/types/slash-commands/helpers/progress-report.d.ts +8 -0
  89. package/dist/types/task/executor.d.ts +3 -0
  90. package/dist/types/tools/bash-skill-urls.d.ts +1 -1
  91. package/dist/types/tools/index.d.ts +3 -0
  92. package/dist/types/tools/python.d.ts +9 -1
  93. package/dist/types/tools/recipe/recipe-guard.d.ts +7 -0
  94. package/dist/types/tools/restricted-cwd.d.ts +1 -0
  95. package/dist/types/tools/todo-write.d.ts +6 -0
  96. package/dist/types/utils/tools-checksum.d.ts +7 -0
  97. package/package.json +7 -7
  98. package/scripts/generate-sdk-operation-inventory.ts +21 -0
  99. package/scripts/verify-managed-empty-stop.ts +28 -0
  100. package/src/async/job-manager.ts +228 -122
  101. package/src/capability/index.ts +17 -0
  102. package/src/capability/mcp.ts +2 -0
  103. package/src/capability/skill.ts +2 -0
  104. package/src/capability/types.ts +2 -0
  105. package/src/cli/auth-broker-cli.ts +1 -1
  106. package/src/cli/customize-doctor.ts +15 -2
  107. package/src/cli/public-command-errors.ts +21 -1
  108. package/src/cli/setup-cli.ts +4 -4
  109. package/src/cli/skills-cli.ts +5 -0
  110. package/src/commands/deep-interview.ts +47 -8
  111. package/src/commands/sdk.ts +28 -8
  112. package/src/config/autorouting-tier-map.ts +117 -7
  113. package/src/config/file-lock.ts +307 -68
  114. package/src/config/mcp-schema.json +4 -0
  115. package/src/config/model-bindings-applier.ts +20 -0
  116. package/src/config/model-profile-activation.ts +240 -46
  117. package/src/config/model-registry.ts +47 -153
  118. package/src/config/skill-settings-defaults.ts +7 -0
  119. package/src/coordinator-mcp/policy.ts +3 -2
  120. package/src/cursor-delete-path.ts +10 -0
  121. package/src/cursor-mcp-name.ts +15 -0
  122. package/src/cursor.ts +13 -2
  123. package/src/customization/inventory.ts +3 -0
  124. package/src/debug/report-bundle-parent.ts +22 -0
  125. package/src/debug/report-bundle.ts +3 -0
  126. package/src/debug/system-info.ts +13 -1
  127. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +67 -4
  128. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/version-manager.ts +80 -0
  129. package/src/defaults/gjc/skills/deep-interview/SKILL.md +105 -10
  130. package/src/defaults/gjc/skills/ralplan/SKILL.md +6 -4
  131. package/src/defaults/gjc-defaults.test.ts +18 -1
  132. package/src/defaults/gjc-defaults.ts +3 -0
  133. package/src/defaults/gjc-skills.generated.ts +58 -36
  134. package/src/discovery/agents.ts +6 -1
  135. package/src/discovery/builtin.ts +10 -0
  136. package/src/discovery/helpers.ts +159 -20
  137. package/src/discovery/mcp-json.ts +6 -0
  138. package/src/discovery/ssh.ts +1 -1
  139. package/src/discovery/substitute-plugin-root.ts +3 -1
  140. package/src/edit/file-read-cache.ts +1 -1
  141. package/src/eval/py/executor.ts +380 -120
  142. package/src/export/html/css-color.ts +9 -0
  143. package/src/export/html/index.ts +5 -4
  144. package/src/export/html/template.generated.ts +1 -1
  145. package/src/extensibility/extensions/runner.ts +4 -0
  146. package/src/extensibility/extensions/types.ts +7 -0
  147. package/src/extensibility/gjc-plugins/runtime-adapters.ts +73 -8
  148. package/src/extensibility/plugins/manager.ts +3 -2
  149. package/src/extensibility/plugins/marketplace/cache.ts +15 -0
  150. package/src/extensibility/plugins/marketplace/manager.ts +11 -3
  151. package/src/extensibility/plugins/plugin-link-path.ts +12 -0
  152. package/src/extensibility/runtime-skill-discovery.ts +20 -2
  153. package/src/extensibility/skill-management.ts +6 -2
  154. package/src/extensibility/skills.ts +6 -1
  155. package/src/gjc-runtime/deep-interview-crystallize.ts +1814 -0
  156. package/src/gjc-runtime/deep-interview-recorder.ts +20 -2
  157. package/src/gjc-runtime/deep-interview-runtime.ts +1415 -13
  158. package/src/gjc-runtime/deep-interview-stage.ts +98 -21
  159. package/src/gjc-runtime/gc-runtime.ts +206 -9
  160. package/src/gjc-runtime/launch-worktree.ts +14 -4
  161. package/src/gjc-runtime/ralplan-runtime.ts +447 -52
  162. package/src/gjc-runtime/state-argv.ts +2 -0
  163. package/src/gjc-runtime/state-migrations.ts +91 -29
  164. package/src/gjc-runtime/state-runtime.ts +3716 -135
  165. package/src/gjc-runtime/state-writer.ts +83 -8
  166. package/src/gjc-runtime/ultragoal-runtime.ts +16 -4
  167. package/src/gjc-runtime/workflow-manifest.generated.json +70 -42
  168. package/src/gjc-runtime/workflow-manifest.ts +54 -21
  169. package/src/harness-control-plane/operate.ts +12 -4
  170. package/src/harness-control-plane/owner.ts +5 -1
  171. package/src/hashline/parser.ts +48 -9
  172. package/src/hashline/recovery.ts +13 -4
  173. package/src/internal-urls/docs-index.generated.ts +18 -17
  174. package/src/internal-urls/skill-path.ts +19 -0
  175. package/src/internal-urls/skill-protocol.ts +2 -0
  176. package/src/lsp/edits.ts +6 -0
  177. package/src/lsp/workspace-path.ts +51 -0
  178. package/src/main.ts +195 -31
  179. package/src/modes/acp/acp-agent.ts +88 -4
  180. package/src/modes/components/custom-editor.ts +14 -0
  181. package/src/modes/components/customization/customization-dashboard.ts +12 -0
  182. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  183. package/src/modes/components/extensions/state-manager.ts +15 -5
  184. package/src/modes/components/model-selector.ts +1 -4
  185. package/src/modes/components/provider-onboarding-selector.ts +1 -1
  186. package/src/modes/components/status-line/segments.ts +4 -0
  187. package/src/modes/controllers/event-controller.ts +11 -4
  188. package/src/modes/controllers/input-controller.ts +74 -29
  189. package/src/modes/controllers/runtime-mcp-command-controller.ts +8 -3
  190. package/src/modes/controllers/selector-controller.ts +28 -15
  191. package/src/modes/interactive-mode.ts +4 -0
  192. package/src/modes/runtime-init.ts +4 -0
  193. package/src/modes/utils/abort-message.ts +3 -1
  194. package/src/modes/utils/interrupt-ownership.ts +12 -0
  195. package/src/modes/utils/keybinding-matchers.ts +4 -0
  196. package/src/modes/utils/macos-option-forwarding.ts +80 -0
  197. package/src/progress/collect-project-progress.ts +153 -0
  198. package/src/progress/progress-contract.ts +172 -0
  199. package/src/progress/progress-snapshot.ts +140 -0
  200. package/src/progress/project-progress.ts +446 -0
  201. package/src/progress/render-progress.ts +209 -0
  202. package/src/prompts/system/master-mode.md +1 -0
  203. package/src/prompts/tools/skill-discovery.md +1 -1
  204. package/src/runtime-mcp/config-writer.ts +10 -6
  205. package/src/runtime-mcp/config.ts +1 -0
  206. package/src/runtime-mcp/oauth-flow.ts +5 -0
  207. package/src/runtime-mcp/oauth-public-url.ts +8 -0
  208. package/src/runtime-mcp/plugin-network-boundary.ts +4 -0
  209. package/src/runtime-mcp/smithery-registry.ts +22 -3
  210. package/src/runtime-mcp/transports/http.ts +2 -2
  211. package/src/runtime-mcp/types.ts +6 -0
  212. package/src/sdk/acp/adapter.ts +93 -8
  213. package/src/sdk/broker/broker-exit.ts +52 -23
  214. package/src/sdk/broker/broker.ts +75 -6
  215. package/src/sdk/broker/ensure.ts +2 -0
  216. package/src/sdk/broker/lifecycle.ts +711 -66
  217. package/src/sdk/broker/session-index.ts +191 -81
  218. package/src/sdk/bus/chat-daemon-cli.ts +38 -1
  219. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  220. package/src/sdk/bus/index.ts +238 -43
  221. package/src/sdk/bus/telegram-daemon-contract.ts +6 -1
  222. package/src/sdk/cli/session-cli.ts +17 -3
  223. package/src/sdk/client/client.ts +28 -8
  224. package/src/sdk/host/query/handlers.ts +9 -1
  225. package/src/sdk/host/session-runtime.test.ts +2647 -294
  226. package/src/sdk/host/session-runtime.ts +426 -109
  227. package/src/sdk/host/surface-policy.ts +1 -0
  228. package/src/sdk/index.ts +8 -0
  229. package/src/sdk/lifecycle-session.ts +3 -1
  230. package/src/sdk/prompt-deadline-manager.ts +15 -0
  231. package/src/sdk/protocol/operation-inventory.generated.json +146 -0
  232. package/src/sdk/protocol/operation-registry.ts +9 -2
  233. package/src/sdk/router/session-router.ts +75 -12
  234. package/src/sdk/session-list.ts +1 -0
  235. package/src/sdk/session.ts +67 -38
  236. package/src/session/agent-session.ts +623 -224
  237. package/src/session/artifacts.ts +174 -70
  238. package/src/session/internal/managed-gc-retirement-codec.ts +319 -0
  239. package/src/session/internal/managed-session-scope.ts +3457 -462
  240. package/src/session/internal/managed-session-storage.ts +376 -61
  241. package/src/session/internal/managed-task-owner-cleanup.ts +473 -0
  242. package/src/session/internal/task-artifact-owner-access.ts +19 -3
  243. package/src/session/internal/task-artifact-owner-transcript.ts +547 -1
  244. package/src/session/session-manager.ts +939 -133
  245. package/src/session/session-retirement.ts +573 -14
  246. package/src/session/session-storage.ts +417 -14
  247. package/src/session/task-artifact-owner-codec.ts +71 -8
  248. package/src/session/task-artifact-owner-retirement.ts +21 -19
  249. package/src/setup/credential-auto-import.ts +12 -3
  250. package/src/setup/credential-import.ts +176 -5
  251. package/src/setup/paseo/announce.ts +6 -1
  252. package/src/skill-state/active-state.ts +132 -2
  253. package/src/slash-commands/builtin-registry.ts +39 -9
  254. package/src/slash-commands/helpers/progress-report.ts +23 -0
  255. package/src/stt/setup.ts +3 -5
  256. package/src/task/commands.ts +3 -1
  257. package/src/task/executor.ts +4 -0
  258. package/src/task/index.ts +6 -0
  259. package/src/tools/ask.ts +205 -6
  260. package/src/tools/ast-edit.ts +4 -0
  261. package/src/tools/bash-allowed-prefixes.ts +15 -0
  262. package/src/tools/bash-skill-urls.ts +56 -3
  263. package/src/tools/bash.ts +48 -79
  264. package/src/tools/descriptors.ts +5 -1
  265. package/src/tools/eval.ts +56 -36
  266. package/src/tools/image-gen.ts +1 -1
  267. package/src/tools/index.ts +3 -0
  268. package/src/tools/python.ts +187 -66
  269. package/src/tools/recipe/index.ts +9 -0
  270. package/src/tools/recipe/recipe-guard.ts +19 -0
  271. package/src/tools/restricted-cwd.ts +10 -0
  272. package/src/tools/skill-discovery.ts +5 -0
  273. package/src/tools/skill.ts +28 -1
  274. package/src/tools/todo-write.ts +10 -1
  275. package/src/tools/tool-catalog.generated.ts +1 -1
  276. package/src/tools/write.ts +1 -0
  277. package/src/utils/tools-checksum.ts +34 -0
  278. package/src/utils/tools-manager.ts +24 -6
  279. package/src/web/search/providers/codex.ts +3 -2
package/src/tools/bash.ts CHANGED
@@ -7,7 +7,6 @@ import { getProjectDir, isEnoent, logger, prompt } from "@gajae-code/utils";
7
7
  import * as z from "zod/v4";
8
8
  import { AsyncJobManager, type FoldReason } from "../async";
9
9
  import { type BashArtifactSaveResult, type BashResult, executeBash } from "../exec/bash-executor";
10
-
11
10
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
12
11
  import { buildGjcRuntimeSessionEnv } from "../gjc-runtime/goal-mode-request";
13
12
  import {
@@ -37,13 +36,13 @@ import { truncateToVisualLines } from "../modes/components/visual-truncate";
37
36
  import { highlightCode, type Theme } from "../modes/theme/theme";
38
37
  import bashDescription from "../prompts/tools/bash.md" with { type: "text" };
39
38
  import { renderSpawnTable, runSdkSpawn, type SdkSpawnArgs } from "../sdk/cli/master-cli";
40
- import type { ArtifactManager } from "../session/artifacts";
41
39
  import type {
42
40
  ClientBridgeTerminalExitStatus,
43
41
  ClientBridgeTerminalHandle,
44
42
  ClientBridgeTerminalOutput,
45
43
  } from "../session/client-bridge";
46
44
  import type { FoldAdapter } from "../session/fold-coordinator";
45
+ import type { SessionArtifactPublication } from "../session/session-manager";
47
46
  import {
48
47
  DEFAULT_ARTIFACT_MAX_BYTES,
49
48
  OutputSink,
@@ -60,7 +59,6 @@ import {
60
59
  registerOwnedIfLineaged,
61
60
  unregisterOwnedRegistration,
62
61
  } from "../session/terminal-abort";
63
-
64
62
  import { renderStatusLine } from "../tui";
65
63
  import { CachedOutputBlock, getOutputBlockContentWidth } from "../tui/output-block";
66
64
  import { truncateToWidth } from "../tui/utils";
@@ -84,6 +82,7 @@ import {
84
82
  } from "./output-meta";
85
83
  import { resolveToCwd } from "./path-utils";
86
84
  import { formatToolWorkingDirectory, replaceTabs } from "./render-utils";
85
+ import { assertCwdInsideWorkspace } from "./restricted-cwd";
87
86
  import { steerFoldReasonLine, watchSteerForFold } from "./steer-fold";
88
87
  import { checkTmuxSelfInjection } from "./tmux-self-injection-guard";
89
88
  import { ToolAbortError, ToolError } from "./tool-errors";
@@ -378,6 +377,7 @@ interface PreparedClientTerminalOutput {
378
377
  async function prepareClientTerminalOutput(
379
378
  session: ToolSession,
380
379
  current: ClientBridgeTerminalOutput,
380
+ artifactPublication: SessionArtifactPublication | undefined,
381
381
  ): Promise<PreparedClientTerminalOutput> {
382
382
  const { summary, locallyTruncated } = await boundClientTerminalOutput(
383
383
  current.output,
@@ -386,7 +386,7 @@ async function prepareClientTerminalOutput(
386
386
  );
387
387
  let artifactSaveResult: BashOriginalArtifactSaveResult | undefined;
388
388
  if (locallyTruncated && !current.truncated) {
389
- artifactSaveResult = await saveBashOriginalArtifact(session, current.output);
389
+ artifactSaveResult = await saveBashOriginalArtifact(artifactPublication, current.output);
390
390
  if (artifactSaveResult.status === "saved") appendRawArtifactFooter(summary, artifactSaveResult);
391
391
  }
392
392
  const artifactSaveNotice = artifactSaveResult
@@ -468,63 +468,26 @@ function appendArtifactDetails(text: string, result: BashResult | BashInteractiv
468
468
  }
469
469
 
470
470
  async function saveBashOriginalArtifact(
471
- session: ToolSession,
471
+ artifactPublication: SessionArtifactPublication | undefined,
472
472
  originalText: string,
473
473
  ): Promise<BashOriginalArtifactSaveResult> {
474
- let manager: ArtifactManager | null | undefined;
475
- try {
476
- manager = session.getArtifactManager?.();
477
- } catch (error) {
478
- return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
479
- }
480
- if (manager) {
481
- try {
482
- const artifactId = await manager.save(originalText, "bash-original");
483
- return artifactId
484
- ? summarizeOriginalArtifactSave(artifactId, originalText)
485
- : { status: "failed", diagnostic: "storage returned no artifact id" };
486
- } catch (error) {
487
- return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
488
- }
489
- }
490
-
491
- if (!session.allocateOutputArtifact) return { status: "unavailable" };
492
- let alloc: { id?: string; path?: string } | undefined;
493
- try {
494
- alloc = await session.allocateOutputArtifact("bash-original");
495
- } catch (error) {
496
- return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
497
- }
498
- if (!alloc?.path || !alloc.id) return { status: "unavailable" };
474
+ if (!artifactPublication) return { status: "unavailable" };
499
475
  try {
500
- const saveResult = summarizeOriginalArtifactSave(alloc.id, originalText);
501
- const payload = saveResult.complete
502
- ? originalText
503
- : (() => {
504
- const retained = truncateHeadBytes(originalText, DEFAULT_ARTIFACT_MAX_BYTES);
505
- return `${retained.text}\n[artifact truncated after ${retained.bytes} bytes; omitted at least ${saveResult.omittedBytes} bytes]\n`;
506
- })();
507
- await Bun.write(alloc.path, payload);
508
- return saveResult;
476
+ const artifactId = await artifactPublication(originalText, "bash-original");
477
+ return artifactId ? summarizeOriginalArtifactSave(artifactId, originalText) : { status: "unavailable" };
509
478
  } catch (error) {
510
479
  return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
511
480
  }
512
481
  }
513
482
 
514
- function createBashArtifactPublisher(session: ToolSession): TerminalArtifactPublisher {
483
+ function createBashArtifactPublisher(
484
+ artifactPublication: SessionArtifactPublication | undefined,
485
+ ): TerminalArtifactPublisher {
515
486
  return async (content, _info): Promise<TerminalArtifactPublishResult> => {
516
- let manager: ArtifactManager | null | undefined;
517
- try {
518
- manager = session.getArtifactManager?.();
519
- } catch (error) {
520
- return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
521
- }
522
- if (!manager) return { status: "unavailable" };
487
+ if (!artifactPublication) return { status: "unavailable" };
523
488
  try {
524
- const artifactId = await manager.save(content, "bash");
525
- return artifactId
526
- ? { status: "published", artifactId }
527
- : { status: "failed", diagnostic: "storage returned no artifact id" };
489
+ const artifactId = await artifactPublication(content, "bash");
490
+ return artifactId ? { status: "published", artifactId } : { status: "unavailable" };
528
491
  } catch (error) {
529
492
  return { status: "failed", diagnostic: boundArtifactSaveDiagnostic(error) };
530
493
  }
@@ -536,7 +499,8 @@ export async function saveBashOriginalArtifactForTests(
536
499
  originalText: string,
537
500
  onResult?: (result: BashOriginalArtifactSaveResult) => void,
538
501
  ): Promise<string | undefined> {
539
- const result = await saveBashOriginalArtifact(session, originalText);
502
+ const artifactPublication = session.captureArtifactPublication?.();
503
+ const result = await saveBashOriginalArtifact(artifactPublication, originalText);
540
504
  onResult?.(result);
541
505
  return result.status === "saved" ? result.artifactId : undefined;
542
506
  }
@@ -1128,6 +1092,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1128
1092
  onCompletion?: () => void;
1129
1093
  /** Immutable attempt-scoped tool call id, when executed via a tool call. */
1130
1094
  toolCallId?: string;
1095
+ artifactPublication: SessionArtifactPublication | undefined;
1131
1096
  /** Accepted activity declaration, mirrored into job progress and result details. */
1132
1097
  activity?: BashActivityDeclaration;
1133
1098
  }): ManagedBashJobHandle {
@@ -1156,8 +1121,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1156
1121
  "bash",
1157
1122
  label,
1158
1123
  async ({ jobId, signal: runSignal, reportProgress }) => {
1159
- const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
1160
- const artifactPublisher = createBashArtifactPublisher(this.session);
1124
+ const artifactPublisher = createBashArtifactPublisher(options.artifactPublication);
1161
1125
  const spillThreshold = resolveBashOutputSinkTailBytes(this.session.settings);
1162
1126
  const headBytes = resolveBashOutputSinkHeadBytes(this.session.settings);
1163
1127
  const tailBuffer = new TailBuffer(spillThreshold);
@@ -1180,8 +1144,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1180
1144
  signal: runSignal,
1181
1145
  env: options.resolvedEnv,
1182
1146
  unsetEnv: options.unsetEnv,
1183
- artifactPath,
1184
- artifactId,
1185
1147
  artifactPublisher,
1186
1148
  spillThreshold,
1187
1149
  headBytes,
@@ -1194,7 +1156,8 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1194
1156
  void reportProgress(latestText, runningDetails(jobId));
1195
1157
  },
1196
1158
  onRawChunk: chunk => manager.appendOutput(jobId, chunk),
1197
- onMinimizedSave: async originalText => saveBashOriginalArtifact(this.session, originalText),
1159
+ onMinimizedSave: async originalText =>
1160
+ saveBashOriginalArtifact(options.artifactPublication, originalText),
1198
1161
  });
1199
1162
  executionResult = result;
1200
1163
  const finalResult = this.#buildCompletedResult(result, options.timeoutSec, {
@@ -1561,6 +1524,9 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1561
1524
  if (!cwdStat.isDirectory()) {
1562
1525
  throw new ToolError(`Working directory is not a directory: ${commandCwd}`);
1563
1526
  }
1527
+ if (this.session.bashRestrictionProfile === "read-only" || (allowedPrefixes?.length ?? 0) > 0) {
1528
+ await assertCwdInsideWorkspace(this.session.cwd, commandCwd);
1529
+ }
1564
1530
 
1565
1531
  const requestedTimeoutSec = input.timeout ?? 300;
1566
1532
  const timeoutSec = clampTimeout("bash", requestedTimeoutSec);
@@ -1678,6 +1644,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1678
1644
  if (!manager.hasCapacity()) {
1679
1645
  throw new ToolError("Background job limit reached. Wait for running jobs to finish or cancel one.");
1680
1646
  }
1647
+ const artifactPublication = this.session.captureArtifactPublication?.();
1681
1648
  const prepared = await this.#prepareBashExecution(input, opts.ctx);
1682
1649
  const label =
1683
1650
  opts.label ?? (prepared.command.length > 120 ? `${prepared.command.slice(0, 117)}...` : prepared.command);
@@ -1725,8 +1692,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1725
1692
  "bash",
1726
1693
  label,
1727
1694
  async ({ jobId: id, signal, reportProgress }) => {
1728
- const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
1729
- const artifactPublisher = createBashArtifactPublisher(this.session);
1695
+ const artifactPublisher = createBashArtifactPublisher(artifactPublication);
1730
1696
  const spillThreshold = resolveBashOutputSinkTailBytes(this.session.settings);
1731
1697
  const headBytes = resolveBashOutputSinkHeadBytes(this.session.settings);
1732
1698
  const tailBuffer = new TailBuffer(spillThreshold);
@@ -1740,8 +1706,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1740
1706
  signal,
1741
1707
  env: prepared.resolvedEnv,
1742
1708
  unsetEnv: prepared.unsetEnv,
1743
- artifactPath,
1744
- artifactId,
1745
1709
  artifactPublisher,
1746
1710
  spillThreshold,
1747
1711
  headBytes,
@@ -1762,7 +1726,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1762
1726
  cursorOffset = slice.nextOffset;
1763
1727
  dispatchLines(slice.text);
1764
1728
  },
1765
- onMinimizedSave: async originalText => saveBashOriginalArtifact(this.session, originalText),
1729
+ onMinimizedSave: async originalText => saveBashOriginalArtifact(artifactPublication, originalText),
1766
1730
  });
1767
1731
  flushTrailingLine();
1768
1732
  const resultText = appendArtifactDetails(result.output || "(no output)", result);
@@ -1818,6 +1782,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1818
1782
  throw new ToolError("Background job limit reached. Wait for running jobs to finish or cancel one.");
1819
1783
  }
1820
1784
 
1785
+ const artifactPublication = this.session.captureArtifactPublication?.();
1821
1786
  const prepared = await this.#prepareBashExecution(
1822
1787
  { command: rawCommand, env: rawEnv, timeout: rawTimeout, cwd },
1823
1788
  ctx,
@@ -1871,6 +1836,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1871
1836
  onUpdate,
1872
1837
  startBackgrounded: true,
1873
1838
  toolCallId,
1839
+ artifactPublication,
1874
1840
  activity,
1875
1841
  });
1876
1842
  const jobGeneration = asyncManager.getJob(job.jobId)?.generation ?? job.jobId;
@@ -1927,6 +1893,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1927
1893
  managedForegroundSettled = true;
1928
1894
  },
1929
1895
  toolCallId,
1896
+ artifactPublication,
1930
1897
  activity,
1931
1898
  });
1932
1899
  const jobGeneration = ownedManager.getJob(job.jobId)?.generation ?? job.jobId;
@@ -2231,7 +2198,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2231
2198
  });
2232
2199
  }
2233
2200
  appendAcpSnapshot(current.output, current.truncated);
2234
- const prepared = await prepareClientTerminalOutput(this.session, current);
2201
+ const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
2235
2202
  throw new ToolAbortError(formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices));
2236
2203
  }
2237
2204
 
@@ -2263,7 +2230,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2263
2230
  });
2264
2231
  }
2265
2232
  appendAcpSnapshot(current.output, current.truncated);
2266
- const prepared = await prepareClientTerminalOutput(this.session, current);
2233
+ const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
2267
2234
  throw new ToolAbortError(
2268
2235
  formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices),
2269
2236
  );
@@ -2284,7 +2251,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2284
2251
  });
2285
2252
  }
2286
2253
  appendAcpSnapshot(current.output, current.truncated);
2287
- const prepared = await prepareClientTerminalOutput(this.session, current);
2254
+ const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
2288
2255
  throw new ToolError(
2289
2256
  formatClientTerminalWaitFailure(
2290
2257
  prepared,
@@ -2314,7 +2281,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2314
2281
  });
2315
2282
  }
2316
2283
  appendAcpSnapshot(current.output, current.truncated);
2317
- const prepared = await prepareClientTerminalOutput(this.session, current);
2284
+ const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
2318
2285
  const timeoutNotices = [
2319
2286
  ...pendingNotices,
2320
2287
  ...(current.truncated || prepared.locallyTruncated ? ["(output truncated)"] : []),
@@ -2351,7 +2318,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2351
2318
  const diagnostic = boundArtifactSaveDiagnostic(error);
2352
2319
  const recoveredOutput = retainedAcpOutput();
2353
2320
  appendAcpSnapshot(recoveredOutput.output, recoveredOutput.truncated);
2354
- const prepared = await prepareClientTerminalOutput(this.session, recoveredOutput);
2321
+ const prepared = await prepareClientTerminalOutput(
2322
+ this.session,
2323
+ recoveredOutput,
2324
+ artifactPublication,
2325
+ );
2355
2326
  logger.warn("ACP terminal poll output read failed", {
2356
2327
  terminalId: handle.terminalId,
2357
2328
  error,
@@ -2384,7 +2355,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2384
2355
  await boundedKill();
2385
2356
  const diagnostic = boundArtifactSaveDiagnostic(error);
2386
2357
  const recoveredOutput = retainedAcpOutput();
2387
- const prepared = await prepareClientTerminalOutput(this.session, recoveredOutput);
2358
+ const prepared = await prepareClientTerminalOutput(
2359
+ this.session,
2360
+ recoveredOutput,
2361
+ artifactPublication,
2362
+ );
2388
2363
  throw new ToolError(formatClientTerminalReadFailure(prepared, diagnostic, pendingNotices));
2389
2364
  }
2390
2365
  }
@@ -2408,7 +2383,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2408
2383
  });
2409
2384
  }
2410
2385
  appendAcpSnapshot(current.output, current.truncated);
2411
- const prepared = await prepareClientTerminalOutput(this.session, current);
2386
+ const prepared = await prepareClientTerminalOutput(this.session, current, artifactPublication);
2412
2387
  throw new ToolAbortError(formatClientTerminalAbortFailure(prepared, readDiagnostic, pendingNotices));
2413
2388
  }
2414
2389
 
@@ -2434,7 +2409,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2434
2409
  if (runSignal?.aborted) {
2435
2410
  await boundedKill();
2436
2411
  appendAcpSnapshot(finalOutput.output, finalOutput.truncated);
2437
- const prepared = await prepareClientTerminalOutput(this.session, finalOutput);
2412
+ const prepared = await prepareClientTerminalOutput(this.session, finalOutput, artifactPublication);
2438
2413
  throw new ToolAbortError(
2439
2414
  formatClientTerminalAbortFailure(prepared, finalReadDiagnostic, pendingNotices),
2440
2415
  );
@@ -2446,7 +2421,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2446
2421
  rawExitCode != null ? rawExitCode : exitStatus.signal ? 137 : undefined;
2447
2422
 
2448
2423
  appendAcpSnapshot(finalOutput.output, finalOutput.truncated);
2449
- const prepared = await prepareClientTerminalOutput(this.session, finalOutput);
2424
+ const prepared = await prepareClientTerminalOutput(this.session, finalOutput, artifactPublication);
2450
2425
 
2451
2426
  const bridgeResult: BashResult = {
2452
2427
  ...prepared.summary,
@@ -2663,9 +2638,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2663
2638
  // Track output for streaming updates (tail only)
2664
2639
  const tailBuffer = new TailBuffer(spillThreshold);
2665
2640
 
2666
- // Allocate artifact for truncated output storage
2667
- const { path: artifactPath, id: artifactId } = (await this.session.allocateOutputArtifact?.("bash")) ?? {};
2668
- const artifactPublisher = createBashArtifactPublisher(this.session);
2641
+ const artifactPublisher = createBashArtifactPublisher(artifactPublication);
2669
2642
 
2670
2643
  const interactiveUi =
2671
2644
  this.session.bashRestrictionProfile === "read-only" || directMasterSpawn
@@ -2693,8 +2666,6 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2693
2666
  signal,
2694
2667
  env: resolvedEnv,
2695
2668
  unsetEnv,
2696
- artifactPath,
2697
- artifactId,
2698
2669
  artifactPublisher,
2699
2670
  spillThreshold,
2700
2671
  headBytes,
@@ -2862,13 +2833,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
2862
2833
  signal,
2863
2834
  env: resolvedEnv,
2864
2835
  unsetEnv,
2865
- artifactPath,
2866
- artifactId,
2867
2836
  artifactPublisher,
2868
2837
  spillThreshold,
2869
2838
  headBytes,
2870
2839
  onChunk: streamTailUpdates(tailBuffer, onUpdate),
2871
- onMinimizedSave: async originalText => saveBashOriginalArtifact(this.session, originalText),
2840
+ onMinimizedSave: async originalText => saveBashOriginalArtifact(artifactPublication, originalText),
2872
2841
  ignoreShellPrefix: this.session.bashRestrictionProfile === "read-only" || directMasterSpawn,
2873
2842
  disableShellSnapshot: this.session.bashRestrictionProfile === "read-only" || directMasterSpawn,
2874
2843
  });
@@ -351,10 +351,14 @@ const loaders: Record<string, Loader> = {
351
351
  cwd: session.cwd,
352
352
  settings: session.settings,
353
353
  getCwd: () => session.cwd,
354
+ getSessionFile: () => session.getSessionFile(),
354
355
  getSessionId: () => session.getSessionId?.() ?? null,
355
356
  registerSessionCleanup: (cleanup: () => Promise<void> | void) => {
356
- session.registerSessionCleanup?.(cleanup);
357
+ return session.registerSessionCleanup?.(cleanup);
357
358
  },
359
+ assertEvalExecutionAllowed: () => session.assertEvalExecutionAllowed?.(),
360
+ trackEvalExecution: <T>(execution: Promise<T>, abortController: AbortController) =>
361
+ session.trackEvalExecution?.(execution, abortController) ?? execution,
358
362
  }),
359
363
  ),
360
364
  job: session => cached("job", () => import("./job")).then(module => module.JobTool.createIf(session)),
package/src/tools/eval.ts CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  } from "./output-meta";
21
21
  import { formatTitle, replaceTabs, shortenPath, truncateToWidth, wrapBrackets } from "./render-utils";
22
22
  import { evalToolDescriptionForSession } from "./session-descriptions";
23
- import { ToolAbortError, ToolError } from "./tool-errors";
23
+ import { ToolError, throwIfAborted } from "./tool-errors";
24
24
  import { toolResult } from "./tool-result";
25
25
  import { clampTimeout } from "./tool-timeouts";
26
26
 
@@ -233,24 +233,23 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
233
233
  throw new ToolError("Eval tool requires a session when not using proxy executor");
234
234
  }
235
235
  const session = this.session;
236
-
237
- const cells: ResolvedEvalCell[] = [];
238
- for (let i = 0; i < params.cells.length; i++) {
239
- const cell = params.cells[i];
240
- const language: EvalLanguage = cell.language === "py" ? "python" : "js";
241
- const resolved = await resolveBackend(session, language);
242
- cells.push({
243
- index: i,
244
- title: cell.title,
245
- code: cell.code,
246
- timeoutMs: (cell.timeout ?? 30) * 1000,
247
- reset: cell.reset ?? false,
248
- resolved,
249
- });
250
- }
251
- const languages = uniqueEvalLanguages(cells);
252
- const notice = detailsNotice(cells);
236
+ session.assertEvalExecutionAllowed?.();
237
+ const cwd = session.cwd;
238
+ const settings = session.settings;
239
+ const sessionFile = session.getSessionFile?.() ?? null;
240
+ const kernelOwnerId = session.getEvalKernelOwnerId?.() ?? null;
241
+ const sessionId = sessionFile ? `session:${sessionFile}:cwd:${cwd}` : `cwd:${cwd}`;
242
+ const evalSession = {
243
+ ...session,
244
+ cwd,
245
+ settings,
246
+ getSessionFile: () => sessionFile,
247
+ getEvalKernelOwnerId: () => kernelOwnerId,
248
+ };
253
249
  const sessionAbortController = new AbortController();
250
+ const abortFromCaller = (): void => sessionAbortController.abort(signal?.reason);
251
+ if (signal?.aborted) abortFromCaller();
252
+ else signal?.addEventListener("abort", abortFromCaller, { once: true });
254
253
  let outputSink: OutputSink | undefined;
255
254
  let outputSummary: OutputSummary | undefined;
256
255
  let outputDumped = false;
@@ -261,12 +260,30 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
261
260
  return outputSummary;
262
261
  };
263
262
 
264
- const execution = (async (): Promise<AgentToolResult<EvalToolDetails | undefined>> => {
263
+ const execution = Promise.resolve().then(async (): Promise<AgentToolResult<EvalToolDetails | undefined>> => {
265
264
  try {
266
- if (signal?.aborted) {
267
- throw new ToolAbortError();
268
- }
265
+ throwIfAborted(sessionAbortController.signal);
269
266
  session.assertEvalExecutionAllowed?.();
267
+ const cells: ResolvedEvalCell[] = [];
268
+ for (let i = 0; i < params.cells.length; i++) {
269
+ throwIfAborted(sessionAbortController.signal);
270
+ session.assertEvalExecutionAllowed?.();
271
+ const cell = params.cells[i];
272
+ const language: EvalLanguage = cell.language === "py" ? "python" : "js";
273
+ const resolved = await resolveBackend(evalSession, language);
274
+ throwIfAborted(sessionAbortController.signal);
275
+ session.assertEvalExecutionAllowed?.();
276
+ cells.push({
277
+ index: i,
278
+ title: cell.title,
279
+ code: cell.code,
280
+ timeoutMs: (cell.timeout ?? 30) * 1000,
281
+ reset: cell.reset ?? false,
282
+ resolved,
283
+ });
284
+ }
285
+ const languages = uniqueEvalLanguages(cells);
286
+ const notice = detailsNotice(cells);
270
287
 
271
288
  const tailBuffer = new TailBuffer(DEFAULT_MAX_BYTES * 2);
272
289
  const jsonOutputs: unknown[] = [];
@@ -320,31 +337,28 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
320
337
  });
321
338
  };
322
339
 
323
- const sessionFile = session.getSessionFile?.() ?? undefined;
324
- const kernelOwnerId = session.getEvalKernelOwnerId?.() ?? undefined;
340
+ throwIfAborted(sessionAbortController.signal);
341
+ session.assertEvalExecutionAllowed?.();
325
342
  const { path: artifactPath, id: artifactId } = (await session.allocateOutputArtifact?.("eval")) ?? {};
343
+ throwIfAborted(sessionAbortController.signal);
326
344
  session.assertEvalExecutionAllowed?.();
327
345
  outputSink = new OutputSink({
328
346
  artifactPath,
329
347
  artifactId,
330
- headBytes: resolveOutputSinkHeadBytes(session.settings),
331
- maxColumns: resolveOutputMaxColumns(session.settings),
348
+ headBytes: resolveOutputSinkHeadBytes(settings),
349
+ maxColumns: resolveOutputMaxColumns(settings),
332
350
  onChunk: chunk => {
333
351
  appendTail(chunk);
334
352
  pushUpdate();
335
353
  },
336
354
  });
337
- const sessionId = sessionFile ? `session:${sessionFile}:cwd:${session.cwd}` : `cwd:${session.cwd}`;
338
-
339
355
  for (let i = 0; i < cells.length; i++) {
340
356
  const cell = cells[i];
341
357
  const backend = cell.resolved.backend;
342
358
  const timeoutSec = timeoutSecondsFromMs(cell.timeoutMs);
343
359
  const deadlineMs = Date.now() + timeoutSec * 1000;
344
360
  const timeoutSignal = AbortSignal.timeout(Math.max(0, deadlineMs - Date.now()));
345
- const combinedSignal = signal
346
- ? AbortSignal.any([signal, timeoutSignal, sessionAbortController.signal])
347
- : AbortSignal.any([timeoutSignal, sessionAbortController.signal]);
361
+ const combinedSignal = AbortSignal.any([timeoutSignal, sessionAbortController.signal]);
348
362
 
349
363
  const cellResult = cellResults[i];
350
364
  cellResult.status = "running";
@@ -353,15 +367,17 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
353
367
  cellResult.exitCode = undefined;
354
368
  cellResult.durationMs = undefined;
355
369
  pushUpdate();
370
+ throwIfAborted(sessionAbortController.signal);
371
+ session.assertEvalExecutionAllowed?.();
356
372
 
357
373
  const startTime = Date.now();
358
374
  const result = await backend.execute(cell.code, {
359
- cwd: session.cwd,
375
+ cwd,
360
376
  sessionId,
361
377
  sessionFile: sessionFile ?? undefined,
362
- kernelOwnerId,
378
+ kernelOwnerId: kernelOwnerId ?? undefined,
363
379
  signal: combinedSignal,
364
- session,
380
+ session: evalSession,
365
381
  deadlineMs,
366
382
  reset: cell.reset,
367
383
  artifactPath,
@@ -511,9 +527,13 @@ export class EvalTool implements AgentTool<typeof evalSchema> {
511
527
  } catch {}
512
528
  }
513
529
  }
514
- })();
530
+ });
515
531
 
516
- return await (session.trackEvalExecution?.(execution, sessionAbortController) ?? execution);
532
+ try {
533
+ return await (session.trackEvalExecution?.(execution, sessionAbortController) ?? execution);
534
+ } finally {
535
+ signal?.removeEventListener("abort", abortFromCaller);
536
+ }
517
537
  }
518
538
  }
519
539
 
@@ -1273,7 +1273,7 @@ function buildOpenAIImageHeaders(model: Model, apiKey: string, sessionId: string
1273
1273
  headers.set(OPENAI_HEADERS.ORIGINATOR, OPENAI_HEADER_VALUES.ORIGINATOR_CODEX);
1274
1274
  headers.set(
1275
1275
  "User-Agent",
1276
- `pi/${packageJson.version} (${sanitizeHeaderComponent(os.platform())} ${sanitizeHeaderComponent(os.release())}; ${sanitizeHeaderComponent(os.arch())})`,
1276
+ `${OPENAI_HEADER_VALUES.ORIGINATOR_CODEX}/${packageJson.version} (${sanitizeHeaderComponent(os.platform())} ${sanitizeHeaderComponent(os.release())}; ${sanitizeHeaderComponent(os.arch())})`,
1277
1277
  );
1278
1278
  if (sessionId) {
1279
1279
  headers.set(OPENAI_HEADERS.CONVERSATION_ID, sessionId);
@@ -19,6 +19,7 @@ import type { ArtifactManager } from "../session/artifacts";
19
19
  import type { ClientBridge } from "../session/client-bridge";
20
20
  import type { FoldAdapter } from "../session/fold-coordinator";
21
21
  import type { CustomMessage } from "../session/messages";
22
+ import type { SessionArtifactPublication } from "../session/session-manager";
22
23
  import type { ToolChoiceQueue } from "../session/tool-choice-queue";
23
24
  import type { SkillActiveEntry } from "../skill-state/active-state";
24
25
  import type { AgentOutputManager } from "../task/output-manager";
@@ -308,6 +309,8 @@ export interface ToolSession {
308
309
  registerSessionCleanup?: (cleanup: () => Promise<void> | void) => () => void;
309
310
  /** Allocate a new artifact path and ID for session-scoped truncated output. */
310
311
  allocateOutputArtifact?: (toolType: string) => Promise<{ id?: string; path?: string }>;
312
+ /** Capture owner-bound artifact publication authority for one session lifecycle. */
313
+ captureArtifactPublication?: () => SessionArtifactPublication;
311
314
  /** Get session spawns */
312
315
  getSessionSpawns: () => string | null;
313
316
  /** Get resolved model string if explicitly set for this session */