@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
@@ -2,6 +2,7 @@ import { createHash, randomUUID } from "node:crypto";
2
2
 
3
3
  import * as fs from "node:fs";
4
4
  import * as path from "node:path";
5
+ import * as util from "node:util";
5
6
 
6
7
  import type * as native from "@gajae-code/natives";
7
8
 
@@ -15,6 +16,7 @@ function nativeSessionStorage(): typeof import("@gajae-code/natives") {
15
16
  }
16
17
 
17
18
  import { isEnoent, pathIsWithin, peekFile, toError } from "@gajae-code/utils";
19
+ import type { ManagedGcProtocolScopeInspector } from "./internal/managed-session-scope";
18
20
  import {
19
21
  assertManagedDirectoryRoot,
20
22
  type ManagedDirectoryRoot,
@@ -28,7 +30,26 @@ import {
28
30
  type NativePublishOutcome,
29
31
  } from "./internal/native-publish-outcome";
30
32
  import { isDerivedSessionMemoryFile } from "./internal/session-memory-sidecar";
33
+ import { captureTaskArtifactOwnerDeletionEvidence } from "./internal/task-artifact-owner-access";
34
+ import {
35
+ hasSiblingTaskArtifactOwnerTranscript,
36
+ taskArtifactOwnerLocatorFromTranscriptBytes,
37
+ } from "./internal/task-artifact-owner-transcript";
31
38
  import { parseFirstJsonlLine } from "./session-transcript-header";
39
+ import {
40
+ parseTaskArtifactOwnerDeletionEvidence,
41
+ parseTaskArtifactOwnerRetirementOutcome,
42
+ type TaskArtifactOwnerDeletionEvidence,
43
+ type TaskArtifactOwnerLocator,
44
+ type TaskArtifactOwnerRetirementContinuation,
45
+ type TaskArtifactOwnerRetirementOutcome,
46
+ type TaskArtifactOwnerStorageContext,
47
+ } from "./task-artifact-owner-codec";
48
+ import {
49
+ retireTaskArtifactOwner,
50
+ verifyTaskArtifactOwnerPhysicalRetirement,
51
+ verifyTaskArtifactOwnerRetirementContinuation,
52
+ } from "./task-artifact-owner-retirement";
32
53
 
33
54
  const utf8Decoder = new TextDecoder("utf-8");
34
55
  const newlineBuffer = Buffer.from("\n", "utf8");
@@ -443,8 +464,24 @@ export interface VerifiedSessionDeleteTarget {
443
464
  retainedTranscriptSuccessorPath?: string;
444
465
  /** Native-retained exchange placeholder observed during transcript cleanup. */
445
466
  retainedTranscriptPlaceholderPath?: string;
446
- /** Native-retained transcript entry whose identity could not be verified. */
467
+ /** Native-retained entry whose identity could not be verified. */
447
468
  retainedTranscriptUnknownPath?: string;
469
+ /** Trusted managed authority for the path-free persisted task-artifact locator. */
470
+ taskArtifactOwnerStorageContext?: TaskArtifactOwnerStorageContext;
471
+ /** Exact owner-tree evidence captured before deletion and retained across retries. */
472
+ taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
473
+ /** Owning journal persists the full native disposition across delete effects. */
474
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
475
+ /** Native terminal evidence of logical transcript deletion; pathname absence alone is insufficient. */
476
+ taskArtifactOwnerTranscriptDeleted?: true;
477
+ /** Explicitly leave owner retirement to its owning coordinator. */
478
+ deferTaskArtifactOwnerRetirement?: true;
479
+ /** Durable evidence that exact owner retirement completed. */
480
+ taskArtifactOwnerRetired?: true;
481
+ /** Exact native remnant, separate from immutable original authority. */
482
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
483
+ taskArtifactOwnerPayloadRetired?: true;
484
+ taskArtifactOwnerNamespaceRetained?: true;
448
485
  /** Native-retained publisher successor observed during cleanup. */
449
486
  retainedArtifactsSuccessorPath?: string;
450
487
  /** Native-retained exchange placeholder observed during cleanup. */
@@ -467,8 +504,28 @@ export interface VerifiedSessionDeleteTarget {
467
504
  * `deleted` and never `{}`.
468
505
  */
469
506
  export type VerifiedSessionDeleteResult =
470
- | { kind: "artifacts_removed"; phase: "artifacts"; transcriptIdentity: SessionStorageFileIdentity }
471
- | { kind: "deleted" }
507
+ | {
508
+ kind: "artifacts_removed";
509
+ phase: "artifacts";
510
+ transcriptIdentity: SessionStorageFileIdentity;
511
+ taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
512
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
513
+ taskArtifactOwnerTranscriptDeleted?: true;
514
+ taskArtifactOwnerRetired?: true;
515
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
516
+ taskArtifactOwnerPayloadRetired?: true;
517
+ taskArtifactOwnerNamespaceRetained?: true;
518
+ }
519
+ | {
520
+ kind: "deleted";
521
+ taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
522
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
523
+ taskArtifactOwnerTranscriptDeleted?: true;
524
+ taskArtifactOwnerRetired?: true;
525
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
526
+ taskArtifactOwnerPayloadRetired?: true;
527
+ taskArtifactOwnerNamespaceRetained?: true;
528
+ }
472
529
  | {
473
530
  kind: "cleanup_pending";
474
531
  phase: "artifacts";
@@ -485,6 +542,28 @@ export type VerifiedSessionDeleteResult =
485
542
  retainedSuccessorPath?: string;
486
543
  retainedPlaceholderPath?: string;
487
544
  retainedUnknownPath?: string;
545
+ taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
546
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
547
+ taskArtifactOwnerTranscriptDeleted?: true;
548
+ taskArtifactOwnerRetired?: true;
549
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
550
+ taskArtifactOwnerPayloadRetired?: true;
551
+ taskArtifactOwnerNamespaceRetained?: true;
552
+ }
553
+ | {
554
+ kind: "cleanup_pending";
555
+ phase: "task_artifact_owner";
556
+ /** True only after verified artifact completion, never inferred from the failure phase. */
557
+ artifactsRemoved: boolean;
558
+ error: Error;
559
+ transcriptIdentity: SessionStorageFileIdentity;
560
+ taskArtifactOwnerDeletionEvidence: TaskArtifactOwnerDeletionEvidence;
561
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
562
+ taskArtifactOwnerTranscriptDeleted?: true;
563
+ taskArtifactOwnerRetired?: true;
564
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
565
+ taskArtifactOwnerPayloadRetired?: true;
566
+ taskArtifactOwnerNamespaceRetained?: true;
488
567
  }
489
568
  | {
490
569
  kind: "cleanup_pending";
@@ -498,6 +577,13 @@ export type VerifiedSessionDeleteResult =
498
577
  retainedSuccessorPath?: string;
499
578
  retainedPlaceholderPath?: string;
500
579
  retainedUnknownPath?: string;
580
+ taskArtifactOwnerDeletionEvidence?: TaskArtifactOwnerDeletionEvidence;
581
+ taskArtifactOwnerRetirementOutcome?: TaskArtifactOwnerRetirementOutcome;
582
+ taskArtifactOwnerTranscriptDeleted?: true;
583
+ taskArtifactOwnerRetired?: true;
584
+ taskArtifactOwnerRetirementContinuation?: TaskArtifactOwnerRetirementContinuation;
585
+ taskArtifactOwnerPayloadRetired?: true;
586
+ taskArtifactOwnerNamespaceRetained?: true;
501
587
  };
502
588
 
503
589
  /** Default OS-close dispatcher: a direct `fs.closeSync`. */
@@ -2265,7 +2351,10 @@ export class FileSessionStorage implements SessionStorage {
2265
2351
  * revalidate, transcript last. Partial deletion returns typed cleanup_pending
2266
2352
  * evidence; identity/symlink/containment/header/cwd mismatch throws.
2267
2353
  */
2268
- async deleteSessionVerified(target: VerifiedSessionDeleteTarget): Promise<VerifiedSessionDeleteResult> {
2354
+ async deleteSessionVerified(
2355
+ target: VerifiedSessionDeleteTarget,
2356
+ inspectProtocol?: ManagedGcProtocolScopeInspector,
2357
+ ): Promise<VerifiedSessionDeleteResult> {
2269
2358
  const {
2270
2359
  sessionsRoot,
2271
2360
  transcriptPath,
@@ -2287,6 +2376,15 @@ export class FileSessionStorage implements SessionStorage {
2287
2376
  plannedArtifactsPath,
2288
2377
  plannedTranscriptPath,
2289
2378
  artifactsRemoved,
2379
+ taskArtifactOwnerStorageContext,
2380
+ taskArtifactOwnerDeletionEvidence: ownerEvidenceValue,
2381
+ deferTaskArtifactOwnerRetirement,
2382
+ taskArtifactOwnerRetirementOutcome: ownerOutcomeValue,
2383
+ taskArtifactOwnerTranscriptDeleted: ownerTranscriptDeletedValue,
2384
+ taskArtifactOwnerRetired: ownerRetiredValue,
2385
+ taskArtifactOwnerRetirementContinuation: ownerContinuationValue,
2386
+ taskArtifactOwnerPayloadRetired: ownerPayloadRetiredValue,
2387
+ taskArtifactOwnerNamespaceRetained: ownerNamespaceRetainedValue,
2290
2388
  } = target;
2291
2389
  try {
2292
2390
  assertNoReparsePath(sessionsRoot);
@@ -2302,6 +2400,16 @@ export class FileSessionStorage implements SessionStorage {
2302
2400
  if (!pathIsWithin(sessionsRoot, transcriptPath)) {
2303
2401
  throw new SessionDeleteVerificationError("containment", "Transcript is outside the sessions root");
2304
2402
  }
2403
+ if (
2404
+ taskArtifactOwnerStorageContext &&
2405
+ path.resolve(taskArtifactOwnerStorageContext.sessionsRoot) !== path.resolve(sessionsRoot)
2406
+ )
2407
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_root_mismatch");
2408
+ if (
2409
+ (ownerTranscriptDeletedValue !== undefined && ownerTranscriptDeletedValue !== true) ||
2410
+ (deferTaskArtifactOwnerRetirement !== undefined && deferTaskArtifactOwnerRetirement !== true)
2411
+ )
2412
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_flag_invalid");
2305
2413
  if (
2306
2414
  !plannedArtifactsPath ||
2307
2415
  !plannedTranscriptPath ||
@@ -2355,6 +2463,243 @@ export class FileSessionStorage implements SessionStorage {
2355
2463
  "Transcript parent identity does not match authorization",
2356
2464
  );
2357
2465
  const authorizedTranscriptParentIdentity = transcriptParentIdentity ?? parentIdentity;
2466
+ let initial: { snapshot: SessionStorageSnapshot } | undefined;
2467
+ if (ownerTranscriptDeletedValue === true && fs.existsSync(transcriptPath))
2468
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_transcript_deleted_mismatch");
2469
+ if (!hasDetachedTranscript && ownerTranscriptDeletedValue !== true) {
2470
+ try {
2471
+ initial = this.#verifiedReadAndHeader(transcriptPath, sessionId, cwd);
2472
+ } catch (error) {
2473
+ const absent =
2474
+ error instanceof SessionDeleteVerificationError &&
2475
+ error.kind === "stat" &&
2476
+ (error.cause as NodeJS.ErrnoException | undefined)?.code === "ENOENT";
2477
+ if (!absent || !detachedArtifactsPath || artifactsRemoved) throw error;
2478
+ }
2479
+ }
2480
+ const ownerTranscript =
2481
+ ownerTranscriptDeletedValue === true
2482
+ ? undefined
2483
+ : (initial ??
2484
+ (hasDetachedTranscript && fs.existsSync(cleanupTranscriptPath)
2485
+ ? this.#verifiedReadAndHeader(cleanupTranscriptPath, sessionId, cwd)
2486
+ : undefined));
2487
+ let ownerLocator: TaskArtifactOwnerLocator | undefined;
2488
+ try {
2489
+ ownerLocator = ownerTranscript
2490
+ ? taskArtifactOwnerLocatorFromTranscriptBytes(ownerTranscript.snapshot.bytes, sessionId)
2491
+ : undefined;
2492
+ } catch (error) {
2493
+ const failure = toError(error);
2494
+ if (failure.message.startsWith("task_artifact_owner_")) throw failure;
2495
+ throw new SessionDeleteVerificationError("artifacts", `task_artifact_owner_patch_invalid:${failure.message}`, {
2496
+ cause: failure,
2497
+ });
2498
+ }
2499
+ const withTaskArtifactOwnerFailure = <T>(operation: () => T): T => {
2500
+ try {
2501
+ return operation();
2502
+ } catch (error) {
2503
+ const failure = toError(error);
2504
+ if (failure.message.startsWith("task_artifact_owner_")) throw failure;
2505
+ throw new SessionDeleteVerificationError(
2506
+ "artifacts",
2507
+ `task_artifact_owner_cleanup_failed:${failure.message}`,
2508
+ { cause: failure },
2509
+ );
2510
+ }
2511
+ };
2512
+ let ownerEvidence = ownerEvidenceValue
2513
+ ? withTaskArtifactOwnerFailure(() => parseTaskArtifactOwnerDeletionEvidence(ownerEvidenceValue))
2514
+ : undefined;
2515
+ if (ownerEvidence && ownerEvidence.sessionId !== sessionId)
2516
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_session_mismatch");
2517
+ if (ownerLocator && ownerEvidence && !util.isDeepStrictEqual(ownerLocator, ownerEvidence.locator))
2518
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_locator_mismatch");
2519
+ if (ownerLocator && !ownerEvidence && taskArtifactOwnerStorageContext)
2520
+ ownerEvidence = withTaskArtifactOwnerFailure(() =>
2521
+ captureTaskArtifactOwnerDeletionEvidence(taskArtifactOwnerStorageContext, sessionId, ownerLocator),
2522
+ );
2523
+ if (ownerLocator && !ownerEvidence)
2524
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_locator_missing");
2525
+ if (ownerEvidence && ownerTranscript && !ownerLocator)
2526
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_evidence_not_in_transcript");
2527
+ if (ownerEvidence && !taskArtifactOwnerStorageContext)
2528
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_context_missing");
2529
+ if (ownerLocator && deferTaskArtifactOwnerRetirement && (!ownerEvidence || !taskArtifactOwnerStorageContext))
2530
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_defer_evidence_missing");
2531
+ if (ownerTranscriptDeletedValue === true && !ownerEvidence)
2532
+ throw new SessionDeleteVerificationError(
2533
+ "artifacts",
2534
+ "task_artifact_owner_transcript_deleted_evidence_missing",
2535
+ );
2536
+ let ownerOutcome =
2537
+ ownerOutcomeValue !== undefined && ownerEvidence && taskArtifactOwnerStorageContext
2538
+ ? withTaskArtifactOwnerFailure(() =>
2539
+ parseTaskArtifactOwnerRetirementOutcome(
2540
+ taskArtifactOwnerStorageContext,
2541
+ ownerEvidence!,
2542
+ ownerOutcomeValue,
2543
+ ),
2544
+ )
2545
+ : undefined;
2546
+ if (ownerOutcomeValue !== undefined && !ownerOutcome)
2547
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_retirement_outcome_missing");
2548
+ if (
2549
+ ownerTranscriptDeletedValue === true &&
2550
+ ownerOutcome?.kind !== "completed" &&
2551
+ ownerOutcome?.kind !== "payload_retired"
2552
+ )
2553
+ throw new SessionDeleteVerificationError(
2554
+ "artifacts",
2555
+ "task_artifact_owner_transcript_deleted_outcome_missing",
2556
+ );
2557
+ if ((ownerContinuationValue !== undefined) !== (ownerOutcome !== undefined && ownerOutcome.kind !== "completed"))
2558
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_retirement_continuation_mismatch");
2559
+ if (
2560
+ ownerOutcome &&
2561
+ ownerOutcome.kind !== "completed" &&
2562
+ !util.isDeepStrictEqual(ownerContinuationValue, ownerOutcome.continuation)
2563
+ )
2564
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_retirement_continuation_mismatch");
2565
+ const ownerContinuationRecord =
2566
+ ownerOutcome && ownerOutcome.kind !== "completed" ? ownerOutcome.continuation : undefined;
2567
+ let ownerContinuation = ownerContinuationRecord
2568
+ ? withTaskArtifactOwnerFailure(() =>
2569
+ verifyTaskArtifactOwnerRetirementContinuation(
2570
+ taskArtifactOwnerStorageContext!,
2571
+ ownerEvidence!,
2572
+ ownerContinuationRecord,
2573
+ ),
2574
+ )
2575
+ : undefined;
2576
+ const payloadRetired = ownerOutcome?.kind === "payload_retired";
2577
+ if (
2578
+ (ownerRetiredValue !== undefined && ownerRetiredValue !== true) ||
2579
+ (ownerPayloadRetiredValue !== undefined && ownerPayloadRetiredValue !== true) ||
2580
+ (ownerNamespaceRetainedValue !== undefined && ownerNamespaceRetainedValue !== true) ||
2581
+ (ownerRetiredValue === true) !== (ownerOutcome?.kind === "completed") ||
2582
+ (ownerPayloadRetiredValue === true) !== payloadRetired ||
2583
+ (ownerNamespaceRetainedValue === true) !== payloadRetired
2584
+ )
2585
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_retirement_outcome_mismatch");
2586
+ if (ownerRetiredValue === true) {
2587
+ if (!ownerEvidence || !taskArtifactOwnerStorageContext || !ownerOutcome)
2588
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_retired_evidence_missing");
2589
+ withTaskArtifactOwnerFailure(() =>
2590
+ verifyTaskArtifactOwnerPhysicalRetirement(taskArtifactOwnerStorageContext, ownerEvidence!, ownerOutcome),
2591
+ );
2592
+ }
2593
+ if (
2594
+ ownerEvidence &&
2595
+ ownerLocator &&
2596
+ taskArtifactOwnerStorageContext &&
2597
+ !ownerContinuation &&
2598
+ !ownerRetiredValue
2599
+ ) {
2600
+ const current = withTaskArtifactOwnerFailure(() =>
2601
+ captureTaskArtifactOwnerDeletionEvidence(taskArtifactOwnerStorageContext, sessionId, ownerLocator),
2602
+ );
2603
+ if (!current || !util.isDeepStrictEqual(current, ownerEvidence))
2604
+ throw new SessionDeleteVerificationError("artifacts", "task_artifact_owner_changed_since_capture");
2605
+ }
2606
+ let ownerRetired = ownerRetiredValue === true;
2607
+ let ownerPayloadRetired = ownerPayloadRetiredValue === true;
2608
+ let ownerNamespaceRetained = ownerNamespaceRetainedValue === true;
2609
+ let ownerTranscriptDeleted = ownerTranscriptDeletedValue === true;
2610
+ const ownerSiblingRefusal = async (): Promise<Error | undefined> => {
2611
+ // Deferral changes who retires the owner, not the pre-artifact sibling authority boundary.
2612
+ if (!ownerEvidence) return undefined;
2613
+ if (!taskArtifactOwnerStorageContext)
2614
+ return new SessionDeleteVerificationError("artifacts", "task_artifact_owner_context_missing");
2615
+ try {
2616
+ if (
2617
+ await hasSiblingTaskArtifactOwnerTranscript(
2618
+ this,
2619
+ transcriptPath,
2620
+ ownerEvidence.locator,
2621
+ taskArtifactOwnerStorageContext,
2622
+ inspectProtocol,
2623
+ )
2624
+ )
2625
+ return new SessionDeleteVerificationError(
2626
+ "artifacts",
2627
+ "task_artifact_owner_shared_with_sibling_transcript",
2628
+ );
2629
+ return undefined;
2630
+ } catch (error) {
2631
+ return new SessionDeleteVerificationError(
2632
+ "artifacts",
2633
+ `task_artifact_owner_cleanup_failed:${toError(error).message}`,
2634
+ { cause: toError(error) },
2635
+ );
2636
+ }
2637
+ };
2638
+ const retireOwnerIfRequired = async (): Promise<Error | undefined> => {
2639
+ const refusal = await ownerSiblingRefusal();
2640
+ if (refusal) return refusal;
2641
+ if (deferTaskArtifactOwnerRetirement || ownerRetired || !ownerEvidence || !taskArtifactOwnerStorageContext)
2642
+ return undefined;
2643
+ try {
2644
+ ownerOutcome = withTaskArtifactOwnerFailure(() =>
2645
+ retireTaskArtifactOwner(taskArtifactOwnerStorageContext, ownerEvidence!, ownerContinuation),
2646
+ );
2647
+ if (ownerOutcome.kind === "completed") {
2648
+ ownerRetired = true;
2649
+ ownerContinuation = undefined;
2650
+ ownerPayloadRetired = false;
2651
+ ownerNamespaceRetained = false;
2652
+ return undefined;
2653
+ }
2654
+ ownerContinuation = ownerOutcome.continuation;
2655
+ ownerPayloadRetired = ownerOutcome.kind === "payload_retired";
2656
+ ownerNamespaceRetained = ownerOutcome.kind === "payload_retired";
2657
+ return new SessionDeleteVerificationError(
2658
+ "artifacts",
2659
+ ownerOutcome.kind === "uncertain"
2660
+ ? ownerOutcome.reason
2661
+ : "task_artifact_owner_namespace_cleanup_pending",
2662
+ );
2663
+ } catch (error) {
2664
+ return new SessionDeleteVerificationError(
2665
+ "artifacts",
2666
+ `task_artifact_owner_cleanup_failed:${toError(error).message}`,
2667
+ { cause: toError(error) },
2668
+ );
2669
+ }
2670
+ };
2671
+ const ownerResultFields = () => ({
2672
+ ...(ownerEvidence ? { taskArtifactOwnerDeletionEvidence: ownerEvidence } : {}),
2673
+ ...(ownerOutcome ? { taskArtifactOwnerRetirementOutcome: ownerOutcome } : {}),
2674
+ ...(ownerTranscriptDeleted ? { taskArtifactOwnerTranscriptDeleted: true as const } : {}),
2675
+ ...(ownerRetired ? { taskArtifactOwnerRetired: true as const } : {}),
2676
+ ...(ownerContinuation ? { taskArtifactOwnerRetirementContinuation: ownerContinuation } : {}),
2677
+ ...(ownerPayloadRetired ? { taskArtifactOwnerPayloadRetired: true as const } : {}),
2678
+ ...(ownerNamespaceRetained ? { taskArtifactOwnerNamespaceRetained: true as const } : {}),
2679
+ });
2680
+ const ownerCleanupPending = (error: Error, completedArtifacts: boolean): VerifiedSessionDeleteResult => ({
2681
+ kind: "cleanup_pending",
2682
+ phase: "task_artifact_owner",
2683
+ artifactsRemoved: completedArtifacts,
2684
+ error,
2685
+ transcriptIdentity,
2686
+ taskArtifactOwnerDeletionEvidence: ownerEvidence!,
2687
+ ...ownerResultFields(),
2688
+ });
2689
+ const finishArtifactPhase = async (): Promise<VerifiedSessionDeleteResult> => {
2690
+ const ownerError = await retireOwnerIfRequired();
2691
+ if (ownerError && ownerEvidence) return ownerCleanupPending(ownerError, true);
2692
+ if (ownerTranscriptDeleted) return { kind: "deleted", ...ownerResultFields() };
2693
+ return {
2694
+ kind: "artifacts_removed",
2695
+ phase: "artifacts",
2696
+ transcriptIdentity,
2697
+ ...ownerResultFields(),
2698
+ };
2699
+ };
2700
+ const ownerPreflightError = await ownerSiblingRefusal();
2701
+ if (ownerPreflightError && ownerEvidence)
2702
+ return ownerCleanupPending(ownerPreflightError, artifactsRemoved === true);
2358
2703
  if (detachedArtifactsPath && !artifactsRemoved) {
2359
2704
  if (
2360
2705
  !expectedArtifactsIdentity ||
@@ -2427,16 +2772,16 @@ export class FileSessionStorage implements SessionStorage {
2427
2772
  ? { retainedUnknownPath: removal.retainedUnknownPath ?? retainedArtifactsUnknownPath }
2428
2773
  : {}),
2429
2774
  transcriptIdentity,
2775
+ ...ownerResultFields(),
2430
2776
  };
2431
2777
  }
2432
- return { kind: "artifacts_removed", phase: "artifacts", transcriptIdentity };
2778
+ return await finishArtifactPhase();
2433
2779
  }
2434
2780
  if (transcriptIdentity.nlink === undefined || transcriptIdentity.nlink !== 1n)
2435
2781
  throw new SessionDeleteVerificationError(
2436
2782
  "identity",
2437
2783
  "Single-link transcript authority is required for exact deletion",
2438
2784
  );
2439
- const initial = hasDetachedTranscript ? undefined : this.#verifiedReadAndHeader(transcriptPath, sessionId, cwd);
2440
2785
  const initialStat = initial?.snapshot.stat;
2441
2786
  const initialDigest = initial ? createHash("sha256").update(initial.snapshot.bytes).digest("hex") : undefined;
2442
2787
  if (
@@ -2491,7 +2836,7 @@ export class FileSessionStorage implements SessionStorage {
2491
2836
  "artifacts",
2492
2837
  "Authorized artifact removal root remains after restart",
2493
2838
  );
2494
- return { kind: "artifacts_removed", phase: "artifacts", transcriptIdentity };
2839
+ return await finishArtifactPhase();
2495
2840
  }
2496
2841
 
2497
2842
  if (artifactsIdentity && !artifactsRemoved) {
@@ -2564,6 +2909,7 @@ export class FileSessionStorage implements SessionStorage {
2564
2909
  detachedArtifactsPath: detach.detachedPath,
2565
2910
  artifactsTree,
2566
2911
  transcriptIdentity,
2912
+ ...ownerResultFields(),
2567
2913
  };
2568
2914
  } finally {
2569
2915
  if (descriptor !== undefined) fs.closeSync(descriptor);
@@ -2581,6 +2927,7 @@ export class FileSessionStorage implements SessionStorage {
2581
2927
  ...(detach.retainedPlaceholderPath ? { retainedPlaceholderPath: detach.retainedPlaceholderPath } : {}),
2582
2928
  ...(detach.retainedUnknownPath ? { retainedUnknownPath: detach.retainedUnknownPath } : {}),
2583
2929
  transcriptIdentity,
2930
+ ...ownerResultFields(),
2584
2931
  };
2585
2932
  }
2586
2933
  const removal = removeDirectoryTreeExact(
@@ -2633,6 +2980,7 @@ export class FileSessionStorage implements SessionStorage {
2633
2980
  ? { retainedUnknownPath: removal.retainedUnknownPath ?? retainedArtifactsUnknownPath }
2634
2981
  : {}),
2635
2982
  transcriptIdentity,
2983
+ ...ownerResultFields(),
2636
2984
  };
2637
2985
  }
2638
2986
  }
@@ -2658,8 +3006,19 @@ export class FileSessionStorage implements SessionStorage {
2658
3006
  if (descriptor !== undefined) fs.closeSync(descriptor);
2659
3007
  }
2660
3008
  }
2661
- return { kind: "artifacts_removed", phase: "artifacts", transcriptIdentity };
3009
+ return await finishArtifactPhase();
2662
3010
  }
3011
+ if (deferTaskArtifactOwnerRetirement && ownerEvidence && !ownerRetired && !ownerPayloadRetired) {
3012
+ return {
3013
+ kind: "artifacts_removed",
3014
+ phase: "artifacts",
3015
+ transcriptIdentity,
3016
+ ...ownerResultFields(),
3017
+ };
3018
+ }
3019
+ const ownerError = await retireOwnerIfRequired();
3020
+ if (ownerError && ownerEvidence) return ownerCleanupPending(ownerError, true);
3021
+ if (ownerTranscriptDeleted) return { kind: "deleted", ...ownerResultFields() };
2663
3022
  if (hasDetachedTranscript) {
2664
3023
  const deletion = nativeExactUnlink(cleanupTranscriptPath, {
2665
3024
  dev: transcriptIdentity.dev,
@@ -2673,7 +3032,10 @@ export class FileSessionStorage implements SessionStorage {
2673
3032
  quarantineName: path.basename(plannedTranscriptPath),
2674
3033
  });
2675
3034
  if (!deletion.ok) {
2676
- if (transcriptDeletionTerminal(deletion)) return { kind: "deleted" };
3035
+ if (transcriptDeletionTerminal(deletion)) {
3036
+ if (ownerEvidence) ownerTranscriptDeleted = true;
3037
+ return { kind: "deleted", ...ownerResultFields() };
3038
+ }
2677
3039
  const error = exactUnlinkFailure(deletion);
2678
3040
  const retainedAuthority =
2679
3041
  deletion.detachedPath ||
@@ -2689,6 +3051,7 @@ export class FileSessionStorage implements SessionStorage {
2689
3051
  ? { transcriptPayloadDurable: true as const }
2690
3052
  : {}),
2691
3053
  transcriptIdentity,
3054
+ ...ownerResultFields(),
2692
3055
  detachedTranscriptPath: deletion.detachedPath ?? detachedTranscriptPath,
2693
3056
  ...((deletion.retainedSuccessorPath ?? retainedTranscriptSuccessorPath)
2694
3057
  ? { retainedSuccessorPath: deletion.retainedSuccessorPath ?? retainedTranscriptSuccessorPath }
@@ -2701,7 +3064,8 @@ export class FileSessionStorage implements SessionStorage {
2701
3064
  : {}),
2702
3065
  };
2703
3066
  }
2704
- return { kind: "deleted" };
3067
+ if (ownerEvidence) ownerTranscriptDeleted = true;
3068
+ return { kind: "deleted", ...ownerResultFields() };
2705
3069
  }
2706
3070
  if (!initialStat || !initialDigest)
2707
3071
  throw new SessionDeleteVerificationError("stat", "Transcript cleanup state is invalid");
@@ -2742,7 +3106,10 @@ export class FileSessionStorage implements SessionStorage {
2742
3106
  quarantineName: path.basename(plannedTranscriptPath),
2743
3107
  });
2744
3108
  if (!deletion.ok) {
2745
- if (transcriptDeletionTerminal(deletion)) return { kind: "deleted" };
3109
+ if (transcriptDeletionTerminal(deletion)) {
3110
+ if (ownerEvidence) ownerTranscriptDeleted = true;
3111
+ return { kind: "deleted", ...ownerResultFields() };
3112
+ }
2746
3113
  const error = exactUnlinkFailure(deletion);
2747
3114
  const retainedAuthority =
2748
3115
  deletion.detachedPath ||
@@ -2758,6 +3125,7 @@ export class FileSessionStorage implements SessionStorage {
2758
3125
  ? { transcriptPayloadDurable: true as const }
2759
3126
  : {}),
2760
3127
  transcriptIdentity,
3128
+ ...ownerResultFields(),
2761
3129
  detachedTranscriptPath: deletion.detachedPath,
2762
3130
  ...((deletion.retainedSuccessorPath ?? retainedTranscriptSuccessorPath)
2763
3131
  ? { retainedSuccessorPath: deletion.retainedSuccessorPath ?? retainedTranscriptSuccessorPath }
@@ -2770,7 +3138,8 @@ export class FileSessionStorage implements SessionStorage {
2770
3138
  : {}),
2771
3139
  };
2772
3140
  }
2773
- return { kind: "deleted" };
3141
+ if (ownerEvidence) ownerTranscriptDeleted = true;
3142
+ return { kind: "deleted", ...ownerResultFields() };
2774
3143
  }
2775
3144
 
2776
3145
  #verifiedReadAndHeader(
@@ -3085,9 +3454,11 @@ class MemorySessionStorageWriter implements SessionStorageBufferedWriter {
3085
3454
  this.#length = nextLength;
3086
3455
  }
3087
3456
 
3457
+ // Memory storage retains this view, so expose only visible bytes, never capacity.
3458
+ // Appends write after each published prefix; growth switches backing buffers.
3088
3459
  #writeCurrent(bytesWritten: number): void {
3089
3460
  this.#writeCalls++;
3090
- this.#storage.writeBytesOwnedSync(this.#path, Buffer.from(this.#bytes.subarray(0, this.#length)));
3461
+ this.#storage.writeBytesOwnedSync(this.#path, this.#bytes.subarray(0, this.#length));
3091
3462
  this.#bytesWritten += bytesWritten;
3092
3463
  }
3093
3464
 
@@ -3103,7 +3474,7 @@ class MemorySessionStorageWriter implements SessionStorageBufferedWriter {
3103
3474
  }
3104
3475
  this.#buffer.copy(this.#bytes, this.#length, 0, pendingBytes);
3105
3476
  this.#writeCalls++;
3106
- this.#storage.writeBytesOwnedSync(this.#path, Buffer.from(this.#bytes.subarray(0, nextLength)));
3477
+ this.#storage.writeBytesOwnedSync(this.#path, this.#bytes.subarray(0, nextLength));
3107
3478
  this.#length = nextLength;
3108
3479
  this.#bufferedBytes = 0;
3109
3480
  this.#bytesWritten += pendingBytes;
@@ -3453,6 +3824,23 @@ export class MemorySessionStorage implements SessionStorage {
3453
3824
  new SessionDeleteVerificationError("containment", "Transcript is outside the sessions root"),
3454
3825
  );
3455
3826
  }
3827
+ if (
3828
+ [
3829
+ target.taskArtifactOwnerStorageContext,
3830
+ target.taskArtifactOwnerDeletionEvidence,
3831
+ target.taskArtifactOwnerRetirementOutcome,
3832
+ target.taskArtifactOwnerTranscriptDeleted,
3833
+ target.deferTaskArtifactOwnerRetirement,
3834
+ target.taskArtifactOwnerRetired,
3835
+ target.taskArtifactOwnerRetirementContinuation,
3836
+ target.taskArtifactOwnerPayloadRetired,
3837
+ target.taskArtifactOwnerNamespaceRetained,
3838
+ ].some(value => value !== undefined)
3839
+ ) {
3840
+ return Promise.reject(
3841
+ new SessionDeleteVerificationError("artifacts", "task_artifact_owner_memory_backend_unsupported"),
3842
+ );
3843
+ }
3456
3844
  const entry = this.#files.get(transcriptPath);
3457
3845
  if (!entry) return Promise.resolve({ kind: "deleted" });
3458
3846
  const snapshot = this.readSnapshotSync(transcriptPath);
@@ -3485,6 +3873,21 @@ export class MemorySessionStorage implements SessionStorage {
3485
3873
  if (path.resolve(header.cwd) !== path.resolve(cwd)) {
3486
3874
  return Promise.reject(new SessionDeleteVerificationError("cwd", "Transcript header cwd mismatch"));
3487
3875
  }
3876
+ let ownerLocator: TaskArtifactOwnerLocator | undefined;
3877
+ try {
3878
+ ownerLocator = taskArtifactOwnerLocatorFromTranscriptBytes(snapshot.bytes, sessionId);
3879
+ } catch (error) {
3880
+ return Promise.reject(
3881
+ new SessionDeleteVerificationError("artifacts", "task_artifact_owner_memory_backend_unsupported", {
3882
+ cause: toError(error),
3883
+ }),
3884
+ );
3885
+ }
3886
+ if (ownerLocator) {
3887
+ return Promise.reject(
3888
+ new SessionDeleteVerificationError("artifacts", "task_artifact_owner_memory_backend_unsupported"),
3889
+ );
3890
+ }
3488
3891
  // Compatible artifact semantics: the memory backend models no directories, so
3489
3892
  // a key at the artifact path is a non-directory sibling that must fail closed
3490
3893
  // rather than be silently treated as an absent artifacts directory.