@timurproko/a1 0.2.6-dev.717 → 0.2.6-dev.734

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 (213) hide show
  1. package/bin/cli.js +13 -2
  2. package/bin/ui.js +13 -0
  3. package/dist/app/session-shell/clipboard-services.d.ts +19 -0
  4. package/dist/app/session-shell/clipboard-services.js +7 -0
  5. package/dist/app/session-shell/exit-notice.d.ts +9 -5
  6. package/dist/app/session-shell/exit-notice.js +5 -5
  7. package/dist/app/session-shell/index.d.ts +3 -1
  8. package/dist/app/session-shell/index.js +1 -0
  9. package/dist/app/session-shell/paste-preparation-client.d.ts +3 -0
  10. package/dist/app/session-shell/paste-preparation-client.js +5 -2
  11. package/dist/app/session-shell/path-chip-presentation.d.ts +10 -3
  12. package/dist/app/session-shell/path-chip-presentation.js +48 -6
  13. package/dist/app/session-shell/prompt-chips.js +30 -4
  14. package/dist/app/session-shell/prompt-suggestion-controller.d.ts +5 -4
  15. package/dist/app/session-shell/prompt-suggestion-controller.js +148 -58
  16. package/dist/app/session-shell/quit-outro.d.ts +3 -1
  17. package/dist/app/session-shell/quit-outro.js +23 -8
  18. package/dist/app/session-shell/response-copy-transport.d.ts +6 -1
  19. package/dist/app/session-shell/response-copy-transport.js +8 -2
  20. package/dist/app/session-shell/session-shell-root.d.ts +22 -11
  21. package/dist/app/session-shell/session-shell-root.js +19 -12
  22. package/dist/app/session-shell/session-shell.d.ts +19 -21
  23. package/dist/app/session-shell/session-shell.js +678 -840
  24. package/dist/app/session-shell/session-viewport-controller.js +33 -21
  25. package/dist/cli/dispatch.js +5 -3
  26. package/dist/cli/session-context.d.ts +5 -1
  27. package/dist/cli/session-context.js +25 -8
  28. package/dist/composition/owned-ui.d.ts +23 -2
  29. package/dist/composition/owned-ui.js +124 -33
  30. package/dist/composition/session-info-reference.d.ts +2 -2
  31. package/dist/composition/session-info-reference.js +2 -2
  32. package/dist/composition/settings-route-host.js +2 -1
  33. package/dist/contracts/agent-engine/capability-ports.d.ts +1 -85
  34. package/dist/contracts/agent-engine/capability-ports.js +1 -35
  35. package/dist/contracts/agent-engine/index.d.ts +1 -7
  36. package/dist/contracts/agent-engine/index.js +0 -4
  37. package/dist/contracts/owned-ui/index.d.ts +9 -3
  38. package/dist/contracts/owned-ui/index.js +2 -1
  39. package/dist/contracts/owned-ui/model.d.ts +10 -0
  40. package/dist/contracts/owned-ui/session-backend.d.ts +119 -0
  41. package/dist/contracts/owned-ui/session-presenters.d.ts +55 -0
  42. package/dist/contracts/owned-ui/session-presenters.js +1 -0
  43. package/dist/contracts/owned-ui/session-workflows.d.ts +342 -0
  44. package/dist/contracts/owned-ui/session-workflows.js +30 -0
  45. package/dist/contracts/owned-ui/suggestion-diagnostics.d.ts +5 -1
  46. package/dist/contracts/owned-ui/suggestion-diagnostics.js +3 -1
  47. package/dist/contracts/owned-ui/validation.js +7 -0
  48. package/dist/features/launch/index.d.ts +1 -1
  49. package/dist/features/launch/session-context.d.ts +17 -2
  50. package/dist/features/launch/session-context.js +9 -5
  51. package/dist/features/owned-ui/settings-app.js +56 -54
  52. package/dist/features/prompt-suggestions/diagnostics.js +4 -1
  53. package/dist/foundation/lifecycle/index.d.ts +2 -2
  54. package/dist/foundation/lifecycle/index.js +1 -1
  55. package/dist/foundation/lifecycle/session-repository-context.d.ts +19 -2
  56. package/dist/foundation/lifecycle/session-repository-context.js +434 -66
  57. package/dist/foundation/process-containment/index.d.ts +1 -0
  58. package/dist/foundation/process-containment/index.js +1 -0
  59. package/dist/foundation/process-containment/native-process-inspector.d.ts +3 -0
  60. package/dist/foundation/process-containment/native-process-inspector.js +21 -0
  61. package/dist/foundation/release/bootstrap.js +1 -2
  62. package/dist/foundation/release/progress-palette.generated.d.ts +2 -2
  63. package/dist/foundation/release/progress-palette.generated.js +2 -2
  64. package/dist/foundation/release/release-gc.js +1 -1
  65. package/dist/foundation/release/update.js +0 -4
  66. package/dist/foundation/startup/startup-descriptor.js +2 -2
  67. package/dist/foundation/storage/control-store.js +0 -12
  68. package/dist/integrations/pi/components/components.js +2 -18
  69. package/dist/integrations/pi/components/index.d.ts +4 -4
  70. package/dist/integrations/pi/components/index.js +2 -2
  71. package/dist/integrations/pi/components/modal-frame.js +3 -4
  72. package/dist/integrations/pi/components/models-dialog.js +6 -35
  73. package/dist/integrations/pi/components/prompt-input-port.d.ts +1 -0
  74. package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -2
  75. package/dist/integrations/pi/components/resources/builtin-themes.js +2 -2
  76. package/dist/integrations/pi/components/share-operation-dialog.js +3 -3
  77. package/dist/integrations/pi/components/shell-editor-autocomplete.js +19 -16
  78. package/dist/integrations/pi/components/shell-extension-ui.d.ts +5 -3
  79. package/dist/integrations/pi/components/shell-extension-ui.js +26 -12
  80. package/dist/integrations/pi/components/shell-hotkey-sections.js +2 -2
  81. package/dist/integrations/pi/components/shell-presenters-info.js +10 -10
  82. package/dist/integrations/pi/components/shell-presenters-transcript.js +13 -13
  83. package/dist/integrations/pi/components/shell-selectors-dialogs.js +5 -6
  84. package/dist/integrations/pi/components/shell-shared-facade.d.ts +21 -1
  85. package/dist/integrations/pi/components/shell-shared-facade.js +19 -3
  86. package/dist/integrations/pi/components/skills-dialog.js +3 -3
  87. package/dist/integrations/pi/components/submitted-prompt-adapter.js +2 -3
  88. package/dist/integrations/pi/components/theme.d.ts +9 -0
  89. package/dist/integrations/pi/components/theme.js +30 -0
  90. package/dist/integrations/pi/components/tool-result-adapter.js +6 -1
  91. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +1 -1
  92. package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.js +1 -1
  93. package/dist/integrations/pi/components/upstream/assets/earendil-image.json +2 -2
  94. package/dist/integrations/pi/components/upstream/components/countdown-timer.d.ts +1 -1
  95. package/dist/integrations/pi/components/upstream/components/earendil-announcement.js +1 -1
  96. package/dist/integrations/pi/components/upstream/components/extension-editor.d.ts +1 -1
  97. package/dist/integrations/pi/components/upstream/components/extension-editor.js +6 -6
  98. package/dist/integrations/pi/components/upstream/components/extension-input.js +4 -4
  99. package/dist/integrations/pi/components/upstream/components/extension-selector.js +4 -4
  100. package/dist/integrations/pi/components/upstream/components/mermaid.js +1 -1
  101. package/dist/integrations/pi/components/upstream/components/owned-editor.d.ts +5 -5
  102. package/dist/integrations/pi/components/upstream/components/owned-editor.js +8 -5
  103. package/dist/integrations/pi/components/upstream/components/pi-logo.js +1 -1
  104. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.d.ts +1 -1
  105. package/dist/integrations/pi/components/upstream/components/scoped-models-selector.js +3 -3
  106. package/dist/integrations/pi/components/upstream/components/session-footer.js +1 -1
  107. package/dist/integrations/pi/components/upstream/components/session-selector-search.js +1 -1
  108. package/dist/integrations/pi/components/upstream/components/session-selector.js +9 -9
  109. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.d.ts +3 -2
  110. package/dist/integrations/pi/components/upstream/components/skill-invocation-message.js +6 -3
  111. package/dist/integrations/pi/components/upstream/components/status-indicator.d.ts +1 -1
  112. package/dist/integrations/pi/components/upstream/components/status-indicator.js +1 -1
  113. package/dist/integrations/pi/components/upstream/components/themed-text.d.ts +1 -1
  114. package/dist/integrations/pi/components/upstream/components/themed-text.js +1 -1
  115. package/dist/integrations/pi/components/upstream/components/thinking-selector.d.ts +1 -1
  116. package/dist/integrations/pi/components/upstream/components/thinking-selector.js +2 -2
  117. package/dist/integrations/pi/components/upstream/components/tool-execution.d.ts +4 -0
  118. package/dist/integrations/pi/components/upstream/components/tool-execution.js +11 -1
  119. package/dist/integrations/pi/components/upstream/components/tree-selector.d.ts +2 -2
  120. package/dist/integrations/pi/components/upstream/components/tree-selector.js +27 -18
  121. package/dist/integrations/pi/components/upstream/components/trust-selector.js +1 -1
  122. package/dist/integrations/pi/components/upstream/external-editor.js +1 -1
  123. package/dist/integrations/pi/components/upstream/history/editor-core.d.ts +4 -4
  124. package/dist/integrations/pi/components/upstream/history/editor-core.js +11 -7
  125. package/dist/integrations/pi/components/upstream/history/kill-ring.d.ts +1 -1
  126. package/dist/integrations/pi/components/upstream/history/kill-ring.js +1 -1
  127. package/dist/integrations/pi/components/upstream/history/printable-key.js +1 -1
  128. package/dist/integrations/pi/components/upstream/history/text-helpers.js +1 -1
  129. package/dist/integrations/pi/components/upstream/history/undo-stack.d.ts +1 -1
  130. package/dist/integrations/pi/components/upstream/history/undo-stack.js +1 -1
  131. package/dist/integrations/pi/components/upstream/history/word-navigation.js +1 -1
  132. package/dist/integrations/pi/components/upstream/model-search.d.ts +1 -1
  133. package/dist/integrations/pi/components/upstream/program-status-reporter.d.ts +31 -0
  134. package/dist/integrations/pi/components/upstream/program-status-reporter.js +89 -0
  135. package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +1 -1
  136. package/dist/integrations/pi/components/upstream/theme/theme.d.ts +22 -1
  137. package/dist/integrations/pi/components/upstream/theme/theme.js +225 -10
  138. package/dist/integrations/pi/engine/adapter.d.ts +44 -24
  139. package/dist/integrations/pi/engine/adapter.js +130 -22
  140. package/dist/integrations/pi/engine/command-dispatch.d.ts +2 -5
  141. package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -11
  142. package/dist/integrations/pi/engine/host-ports.d.ts +20 -0
  143. package/dist/integrations/pi/engine/host-ports.js +13 -0
  144. package/dist/integrations/pi/engine/host.d.ts +70 -0
  145. package/dist/integrations/pi/engine/host.js +147 -0
  146. package/dist/integrations/pi/engine/index.d.ts +8 -4
  147. package/dist/integrations/pi/engine/index.js +3 -1
  148. package/dist/integrations/pi/engine/pi-settings-metadata.json +1 -1
  149. package/dist/integrations/pi/engine/resource-catalog.d.ts +4 -23
  150. package/dist/integrations/pi/engine/resources/changelog.json +4 -4
  151. package/dist/integrations/pi/engine/runtime-integration.d.ts +8 -2
  152. package/dist/integrations/pi/engine/runtime-integration.js +12 -7
  153. package/dist/integrations/pi/engine/session-events.js +10 -2
  154. package/dist/integrations/pi/engine/session-integration.d.ts +3 -8
  155. package/dist/integrations/pi/engine/session-integration.js +0 -49
  156. package/dist/integrations/pi/engine/session-runtime.d.ts +18 -3
  157. package/dist/integrations/pi/engine/session-runtime.js +18 -7
  158. package/dist/integrations/pi/engine/settings-bridge.d.ts +2 -2
  159. package/dist/integrations/pi/engine/settings-bridge.js +0 -2
  160. package/dist/integrations/pi/engine/settings-port.d.ts +2 -0
  161. package/dist/integrations/pi/engine/settings-port.js +3 -5
  162. package/dist/integrations/pi/engine/transcript-projection.js +2 -1
  163. package/dist/integrations/pi/engine/workflows.d.ts +33 -260
  164. package/dist/integrations/pi/engine/workflows.js +6 -28
  165. package/dist/integrations/pi/session-presenters/index.d.ts +2 -0
  166. package/dist/integrations/pi/session-presenters/index.js +1 -0
  167. package/dist/integrations/pi/session-presenters/presenters.d.ts +16 -0
  168. package/dist/integrations/pi/session-presenters/presenters.js +341 -0
  169. package/dist/integrations/pi/startup-public.js +306 -290
  170. package/dist/integrations/pi/startup-public.manifest.json +289 -265
  171. package/dist/integrations/pi/tui-runtime/adapter.d.ts +2 -1
  172. package/dist/integrations/pi/tui-runtime/adapter.js +7 -2
  173. package/dist/integrations/pi/tui-runtime/contracts.d.ts +3 -1
  174. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +8 -1
  175. package/dist/integrations/pi/tui-runtime/damage-aware-terminal.js +67 -2
  176. package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
  177. package/dist/integrations/pi/tui-runtime/index.js +1 -1
  178. package/dist/native/darwin-arm64/manifest.json +1 -1
  179. package/dist/native/linux-x64/manifest.json +1 -1
  180. package/dist/native/win32-x64/manifest.json +2 -2
  181. package/dist/native/win32-x64/process-guardian.exe +0 -0
  182. package/dist/product-identity.d.ts +2 -2
  183. package/dist/product-identity.js +2 -2
  184. package/dist/product-identity.json +3 -1
  185. package/dist/runtime-payload-inventory.json +3092 -2878
  186. package/dist/ui/components/prompt-input.d.ts +2 -0
  187. package/dist/ui/components/prompt-input.js +5 -1
  188. package/dist/ui/components/text-selection.d.ts +1 -1
  189. package/dist/ui/components/text-selection.js +3 -1
  190. package/dist/ui/components/theme.d.ts +2 -0
  191. package/dist/ui/components/transcript-viewport.d.ts +6 -4
  192. package/dist/ui/components/transcript-viewport.js +94 -16
  193. package/dist/ui/components/value-menu.d.ts +2 -0
  194. package/dist/ui/components/value-menu.js +13 -8
  195. package/dist/ui/settings/declarations.d.ts +38 -14
  196. package/dist/ui/settings/declarations.js +35 -11
  197. package/dist/ui/settings/migrations.js +23 -0
  198. package/docs/architecture/boundaries.md +9 -1
  199. package/docs/architecture/project-structure.md +7 -5
  200. package/docs/architecture/prompt-suggestions.md +14 -10
  201. package/docs/local-worktree-cleanup.md +11 -5
  202. package/docs/openspec-archive-automation.md +6 -5
  203. package/package.json +3 -3
  204. package/dist/contracts/agent-engine/model.d.ts +0 -78
  205. package/dist/contracts/agent-engine/model.js +0 -1
  206. package/dist/contracts/agent-engine/ports.d.ts +0 -18
  207. package/dist/contracts/agent-engine/serialization.d.ts +0 -7
  208. package/dist/contracts/agent-engine/serialization.js +0 -58
  209. package/dist/contracts/agent-engine/validation.d.ts +0 -5
  210. package/dist/contracts/agent-engine/validation.js +0 -128
  211. package/dist/integrations/pi/components/upstream/theme/system-theme.d.ts +0 -61
  212. package/dist/integrations/pi/components/upstream/theme/system-theme.js +0 -709
  213. /package/dist/contracts/{agent-engine/ports.js → owned-ui/session-backend.js} +0 -0
@@ -1,49 +1,112 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
- import { open, lstat, mkdir, readFile, realpath, rename, rm, writeFile } from "node:fs/promises";
2
+ import { open, lstat, mkdir, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
3
3
  import { dirname, isAbsolute, join, resolve } from "node:path";
4
4
  import { promisify } from "node:util";
5
5
  import { PRODUCT_IDENTITY } from "../../product-identity.js";
6
6
  import { resolveProductPaths } from "./paths.js";
7
- const SCHEMA = "a1-session-repository-context-v1";
7
+ const CONTEXT_SCHEMA = "a1-session-repository-context-v1";
8
+ const RUNTIME_SCHEMA = "a1-session-runtime-v1";
9
+ const CLAIM_SCHEMA = "a1-session-worktree-claim-v1";
8
10
  const MAX_RECORD_BYTES = 16 * 1024;
9
11
  const MAX_HEADER_BYTES = 64 * 1024;
12
+ const MAX_WORKTREES = 256;
10
13
  const GIT_TIMEOUT_MS = 5_000;
11
- /** Persist one explicit same-repository worktree association for a stable Pi session. */
14
+ const LOCK_TIMEOUT_MS = 2_000;
15
+ const LOCK_RETRY_MS = 20;
16
+ /** Publish the exact live runtime that may acquire a delivery worktree. */
17
+ export async function registerSessionRepositoryRuntime(identity, runtimeId, runtimeIdentity, options = {}) {
18
+ const header = await readSessionHeader(identity);
19
+ assertRuntimeId(runtimeId);
20
+ assertProcessIdentity(runtimeIdentity);
21
+ await withClaimLock(options, async () => {
22
+ await writeRuntimeRecord(header, runtimeId, runtimeIdentity, options);
23
+ });
24
+ }
25
+ /** Revalidate a durable association and acquire its live claim for this runtime. */
26
+ export async function activateSessionRepositoryContext(identity, runtimeId, runtimeIdentity, options = {}) {
27
+ const header = await readSessionHeader(identity);
28
+ assertRuntimeId(runtimeId);
29
+ assertProcessIdentity(runtimeIdentity);
30
+ return await withClaimLock(options, async () => {
31
+ await writeRuntimeRecord(header, runtimeId, runtimeIdentity, options);
32
+ const record = await readContextRecord(header, options);
33
+ if (record === null) {
34
+ await releaseClaimsOwnedBy(runtimeId, null, options);
35
+ return null;
36
+ }
37
+ const selected = await validateContextRecord(header, record, options.signal).catch(() => null);
38
+ if (selected === null) {
39
+ await releaseClaimsOwnedBy(runtimeId, null, options);
40
+ return null;
41
+ }
42
+ const status = await claimAvailability(selected, runtimeId, options);
43
+ if (status !== "available" && status !== "current") {
44
+ await releaseClaimsOwnedBy(runtimeId, null, options);
45
+ return null;
46
+ }
47
+ await writeClaim(header, selected, runtimeId, runtimeIdentity, options);
48
+ await releaseClaimsOwnedBy(runtimeId, selected.gitDir, options);
49
+ return { cwd: selected.root, branch: requireBranch(selected) };
50
+ });
51
+ }
52
+ /** Release only this exact runtime generation's cooperative editing claims. */
53
+ export async function releaseSessionRepositoryRuntime(runtimeId, runtimeIdentity, options = {}) {
54
+ assertRuntimeId(runtimeId);
55
+ assertProcessIdentity(runtimeIdentity);
56
+ await withClaimLock(options, async () => {
57
+ const runtime = await readRuntimeRecord(runtimeId, options);
58
+ if (runtime === null || runtime.pid !== runtimeIdentity.pid || runtime.startIdentity !== runtimeIdentity.startIdentity)
59
+ return;
60
+ await releaseClaimsOwnedBy(runtimeId, null, options);
61
+ await rm(runtimeRecordPath(runtimeId, options), { force: true });
62
+ });
63
+ }
64
+ /** Persist one explicit same-repository worktree association after atomically claiming it. */
12
65
  export async function setSessionRepositoryContext(identity, worktreePath, options = {}) {
13
66
  const header = await readSessionHeader(identity);
14
67
  const startup = await readGitWorktreeIdentity(header.cwd, false, options.signal);
15
68
  const selected = await readGitWorktreeIdentity(worktreePath, true, options.signal);
16
69
  if (!samePath(startup.commonDir, selected.commonDir)) {
17
- throw new Error("associated worktree belongs to a different Git repository");
70
+ throw contextError("associated worktree belongs to a different Git repository", "worktree-foreign-repository");
18
71
  }
19
- const record = {
20
- schema: SCHEMA,
21
- sessionId: header.id,
22
- sessionFile: header.file,
23
- startupRoot: startup.root,
24
- startupCommonDir: startup.commonDir,
25
- worktreeRoot: selected.root,
26
- worktreeCommonDir: selected.commonDir,
27
- worktreeGitDir: selected.gitDir,
28
- updatedAt: new Date().toISOString(),
29
- };
30
- const destination = recordPath(header, options);
31
- const directory = dirname(destination);
32
- await mkdir(directory, { recursive: true, mode: 0o700 });
33
- const temporary = `${destination}.${process.pid}.${randomUUID()}.tmp`;
34
- try {
35
- await writeFile(temporary, `${JSON.stringify(record)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
36
- await rename(temporary, destination);
37
- }
38
- finally {
39
- await rm(temporary, { force: true }).catch(() => undefined);
40
- }
41
- return { cwd: selected.root, branch: requireBranch(selected) };
72
+ const runtimeId = requireRuntimeId(options);
73
+ return await withClaimLock(options, async () => {
74
+ const runtime = await requireLiveRuntime(header, runtimeId, options);
75
+ const status = await claimAvailability(selected, runtimeId, options);
76
+ if (status === "busy")
77
+ throw contextError("worktree is active in another session", "worktree-active-in-another-session");
78
+ if (status === "unverifiable")
79
+ throw contextError("worktree ownership cannot be verified", "worktree-owner-unverifiable");
80
+ const prior = await readContextRecord(header, options);
81
+ await writeClaim(header, selected, runtimeId, processIdentityOf(runtime), options);
82
+ try {
83
+ await writeContextRecord(header, startup, selected, options);
84
+ }
85
+ catch (error) {
86
+ if (status !== "current")
87
+ await removeMatchingClaim(selected, runtimeId, options);
88
+ throw error;
89
+ }
90
+ await releaseClaimsOwnedBy(runtimeId, selected.gitDir, options);
91
+ if (prior !== null && !samePath(prior.worktreeGitDir, selected.gitDir)) {
92
+ await removeClaimByGitDir(prior.worktreeCommonDir, prior.worktreeGitDir, runtimeId, options);
93
+ }
94
+ return { cwd: selected.root, branch: requireBranch(selected) };
95
+ });
42
96
  }
43
- /** Remove only the association belonging to the supplied stable session. */
97
+ /** Remove only the association and live claim belonging to the supplied stable session/runtime. */
44
98
  export async function clearSessionRepositoryContext(identity, options = {}) {
45
99
  const header = await readSessionHeader(identity);
46
- await rm(recordPath(header, options), { force: true });
100
+ if (options.runtimeId === undefined) {
101
+ await rm(contextRecordPath(header, options), { force: true });
102
+ return;
103
+ }
104
+ const runtimeId = requireRuntimeId(options);
105
+ await withClaimLock(options, async () => {
106
+ await requireLiveRuntime(header, runtimeId, options);
107
+ await rm(contextRecordPath(header, options), { force: true });
108
+ await releaseClaimsOwnedBy(runtimeId, null, options);
109
+ });
47
110
  }
48
111
  /** Read and revalidate a persisted association; malformed or stale state fails closed to absence. */
49
112
  export async function readSessionRepositoryContext(identity, options = {}) {
@@ -54,39 +117,187 @@ export async function readSessionRepositoryContext(identity, options = {}) {
54
117
  catch {
55
118
  return null;
56
119
  }
120
+ const record = await readContextRecord(header, options);
121
+ if (record === null)
122
+ return null;
123
+ const selected = await validateContextRecord(header, record, options.signal).catch(() => null);
124
+ return selected === null ? null : { cwd: selected.root, branch: requireBranch(selected) };
125
+ }
126
+ /** List same-repository worktrees without acquiring, releasing, or repairing a claim. */
127
+ export async function listSessionRepositoryWorktrees(identity, options = {}) {
128
+ const header = await readSessionHeader(identity);
129
+ const runtimeId = requireRuntimeId(options);
130
+ await requireLiveRuntime(header, runtimeId, options);
131
+ const startup = await readGitWorktreeIdentity(header.cwd, false, options.signal);
132
+ const worktrees = await listGitWorktrees(startup.root, startup.commonDir, options.signal);
133
+ if (worktrees.length > MAX_WORKTREES)
134
+ throw contextError("worktree inventory exceeds its bounded limit", "worktree-inventory-limit");
135
+ const contended = await mutationLockExists(options);
136
+ const entries = [];
137
+ for (const selected of worktrees) {
138
+ if (selected.branch === null) {
139
+ entries.push({ cwd: selected.root, branch: "(detached)", status: "unverifiable" });
140
+ continue;
141
+ }
142
+ entries.push({
143
+ cwd: selected.root,
144
+ branch: selected.branch,
145
+ status: contended ? "unverifiable" : await claimAvailability(selected, runtimeId, options),
146
+ });
147
+ }
148
+ return entries.sort((left, right) => pathKey(left.cwd).localeCompare(pathKey(right.cwd)));
149
+ }
150
+ async function requireLiveRuntime(header, runtimeId, options) {
151
+ const runtime = await readRuntimeRecord(runtimeId, options);
152
+ if (runtime === null || runtime.sessionId !== header.id || runtime.sessionFile !== header.file) {
153
+ throw contextError("active session runtime is unavailable", "session-runtime-unavailable");
154
+ }
155
+ const inspection = requireInspector(options);
156
+ let observed;
157
+ try {
158
+ observed = await inspection(runtime.pid);
159
+ }
160
+ catch {
161
+ throw contextError("active session runtime cannot be verified", "session-runtime-unverifiable");
162
+ }
163
+ if (observed === null || observed.pid !== runtime.pid || observed.startIdentity !== runtime.startIdentity) {
164
+ throw contextError("active session runtime is no longer running", "session-runtime-stopped");
165
+ }
166
+ return runtime;
167
+ }
168
+ async function claimAvailability(selected, runtimeId, options) {
169
+ const claim = await readClaim(selected, options);
170
+ if (claim === undefined)
171
+ return "available";
172
+ if (claim === null || !claimMatchesWorktree(claim, selected))
173
+ return "unverifiable";
174
+ if (claim.runtimeId === runtimeId)
175
+ return "current";
176
+ const inspection = requireInspector(options);
177
+ let observed;
178
+ try {
179
+ observed = await inspection(claim.pid);
180
+ }
181
+ catch {
182
+ return "unverifiable";
183
+ }
184
+ const live = observed !== null && observed.pid === claim.pid && observed.startIdentity === claim.startIdentity;
185
+ return live ? "busy" : "available";
186
+ }
187
+ async function writeRuntimeRecord(header, runtimeId, runtimeIdentity, options) {
188
+ const existing = await readRuntimeRecord(runtimeId, options);
189
+ if (existing !== null && (existing.pid !== runtimeIdentity.pid || existing.startIdentity !== runtimeIdentity.startIdentity)) {
190
+ const inspection = requireInspector(options);
191
+ let observed;
192
+ try {
193
+ observed = await inspection(existing.pid);
194
+ }
195
+ catch {
196
+ throw contextError("session runtime ownership cannot be verified", "session-runtime-unverifiable");
197
+ }
198
+ if (observed !== null && observed.pid === existing.pid && observed.startIdentity === existing.startIdentity) {
199
+ throw contextError("session runtime identity is active in another process", "session-runtime-conflict");
200
+ }
201
+ }
202
+ const record = {
203
+ schema: RUNTIME_SCHEMA,
204
+ runtimeId,
205
+ sessionId: header.id,
206
+ sessionFile: header.file,
207
+ pid: runtimeIdentity.pid,
208
+ startIdentity: runtimeIdentity.startIdentity,
209
+ updatedAt: new Date().toISOString(),
210
+ };
211
+ await atomicWrite(runtimeRecordPath(runtimeId, options), record);
212
+ }
213
+ async function writeContextRecord(header, startup, selected, options) {
214
+ const record = {
215
+ schema: CONTEXT_SCHEMA,
216
+ sessionId: header.id,
217
+ sessionFile: header.file,
218
+ startupRoot: startup.root,
219
+ startupCommonDir: startup.commonDir,
220
+ worktreeRoot: selected.root,
221
+ worktreeCommonDir: selected.commonDir,
222
+ worktreeGitDir: selected.gitDir,
223
+ updatedAt: new Date().toISOString(),
224
+ };
225
+ await atomicWrite(contextRecordPath(header, options), record);
226
+ }
227
+ async function writeClaim(header, selected, runtimeId, runtimeIdentity, options) {
228
+ const claim = {
229
+ schema: CLAIM_SCHEMA,
230
+ runtimeId,
231
+ sessionId: header.id,
232
+ worktreeRoot: selected.root,
233
+ worktreeCommonDir: selected.commonDir,
234
+ worktreeGitDir: selected.gitDir,
235
+ pid: runtimeIdentity.pid,
236
+ startIdentity: runtimeIdentity.startIdentity,
237
+ updatedAt: new Date().toISOString(),
238
+ };
239
+ await atomicWrite(claimRecordPath(selected.commonDir, selected.gitDir, options), claim);
240
+ }
241
+ async function readContextRecord(header, options) {
242
+ return await readJsonRecord(contextRecordPath(header, options), isContextRecord);
243
+ }
244
+ async function readRuntimeRecord(runtimeId, options) {
245
+ return await readJsonRecord(runtimeRecordPath(runtimeId, options), isRuntimeRecord);
246
+ }
247
+ /** Undefined means absent; null means present but invalid. */
248
+ async function readClaim(selected, options) {
249
+ const path = claimRecordPath(selected.commonDir, selected.gitDir, options);
57
250
  try {
58
- const path = recordPath(header, options);
59
251
  const metadata = await lstat(path);
60
252
  if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size === 0 || metadata.size > MAX_RECORD_BYTES)
61
253
  return null;
62
- const bytes = await readFile(path, { signal: options.signal });
63
- const value = JSON.parse(bytes.toString("utf8"));
64
- if (!isRecord(value)
65
- || value.schema !== SCHEMA
66
- || value.sessionId !== header.id
67
- || value.sessionFile !== header.file
68
- || !validPath(value.startupRoot)
69
- || !validPath(value.startupCommonDir)
70
- || !validPath(value.worktreeRoot)
71
- || !validPath(value.worktreeCommonDir)
72
- || !validPath(value.worktreeGitDir)
73
- || typeof value.updatedAt !== "string")
74
- return null;
75
- const startup = await readGitWorktreeIdentity(header.cwd, false, options.signal);
76
- const selected = await readGitWorktreeIdentity(value.worktreeRoot, true, options.signal);
77
- if (!samePath(startup.root, value.startupRoot)
78
- || !samePath(startup.commonDir, value.startupCommonDir)
79
- || !samePath(selected.root, value.worktreeRoot)
80
- || !samePath(selected.commonDir, value.worktreeCommonDir)
81
- || !samePath(selected.gitDir, value.worktreeGitDir)
82
- || !samePath(startup.commonDir, selected.commonDir))
83
- return null;
84
- return { cwd: selected.root, branch: requireBranch(selected) };
254
+ const value = JSON.parse((await readFile(path, { signal: options.signal })).toString("utf8"));
255
+ return isClaimRecord(value) ? value : null;
85
256
  }
86
- catch {
257
+ catch (error) {
258
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
259
+ return undefined;
87
260
  return null;
88
261
  }
89
262
  }
263
+ async function validateContextRecord(header, record, signal) {
264
+ if (record.sessionId !== header.id || record.sessionFile !== header.file)
265
+ throw new Error("associated session identity changed");
266
+ const startup = await readGitWorktreeIdentity(header.cwd, false, signal);
267
+ const selected = await readGitWorktreeIdentity(record.worktreeRoot, true, signal);
268
+ if (!samePath(startup.root, record.startupRoot)
269
+ || !samePath(startup.commonDir, record.startupCommonDir)
270
+ || !samePath(selected.root, record.worktreeRoot)
271
+ || !samePath(selected.commonDir, record.worktreeCommonDir)
272
+ || !samePath(selected.gitDir, record.worktreeGitDir)
273
+ || !samePath(startup.commonDir, selected.commonDir))
274
+ throw new Error("associated worktree identity changed");
275
+ return selected;
276
+ }
277
+ async function releaseClaimsOwnedBy(runtimeId, keepGitDir, options) {
278
+ const directory = claimsDirectory(options);
279
+ const names = await readdir(directory).catch(() => []);
280
+ if (names.length > MAX_WORKTREES * 4)
281
+ throw contextError("worktree claim store exceeds its bounded limit", "worktree-claim-limit");
282
+ for (const name of names) {
283
+ if (!name.endsWith(".json"))
284
+ continue;
285
+ const path = join(directory, name);
286
+ const claim = await readJsonRecord(path, isClaimRecord);
287
+ if (claim?.runtimeId === runtimeId && (keepGitDir === null || !samePath(claim.worktreeGitDir, keepGitDir))) {
288
+ await rm(path, { force: true });
289
+ }
290
+ }
291
+ }
292
+ async function removeMatchingClaim(selected, runtimeId, options) {
293
+ await removeClaimByGitDir(selected.commonDir, selected.gitDir, runtimeId, options);
294
+ }
295
+ async function removeClaimByGitDir(commonDir, gitDir, runtimeId, options) {
296
+ const path = claimRecordPath(commonDir, gitDir, options);
297
+ const claim = await readJsonRecord(path, isClaimRecord);
298
+ if (claim?.runtimeId === runtimeId)
299
+ await rm(path, { force: true });
300
+ }
90
301
  async function readSessionHeader(identity) {
91
302
  if (!validSessionId(identity.sessionId) || !validPath(identity.sessionFile))
92
303
  throw new Error("active session identity is unavailable");
@@ -133,27 +344,151 @@ async function readGitWorktreeIdentity(path, requireWorktreeRoot, signal) {
133
344
  }
134
345
  return { root, commonDir, gitDir, branch };
135
346
  }
347
+ async function listGitWorktrees(cwd, commonDir, signal) {
348
+ const { stdout } = await executeGit(["worktree", "list", "--porcelain", "-z"], cwd, MAX_RECORD_BYTES * 16, signal);
349
+ const records = [];
350
+ let current = null;
351
+ for (const field of stdout.split("\0")) {
352
+ if (field.length === 0) {
353
+ if (current !== null)
354
+ records.push(current);
355
+ current = null;
356
+ continue;
357
+ }
358
+ if (field.startsWith("worktree "))
359
+ current = { root: field.slice("worktree ".length), branch: null };
360
+ else if (current !== null && field.startsWith("branch refs/heads/"))
361
+ current.branch = field.slice("branch refs/heads/".length);
362
+ }
363
+ if (current !== null)
364
+ records.push(current);
365
+ return await Promise.all(records.map(async (record) => {
366
+ const root = await realpath(record.root);
367
+ const dotGit = join(root, ".git");
368
+ const metadata = await lstat(dotGit);
369
+ let gitDir;
370
+ if (metadata.isDirectory() && !metadata.isSymbolicLink())
371
+ gitDir = await realpath(dotGit);
372
+ else if (metadata.isFile() && !metadata.isSymbolicLink() && metadata.size > 0 && metadata.size <= MAX_RECORD_BYTES) {
373
+ const pointer = (await readFile(dotGit, { signal })).toString("utf8").trim();
374
+ if (!pointer.startsWith("gitdir: "))
375
+ throw new Error("worktree Git pointer is invalid");
376
+ gitDir = await realpath(resolve(root, pointer.slice("gitdir: ".length)));
377
+ }
378
+ else
379
+ throw new Error("worktree Git identity is invalid");
380
+ return { root, commonDir, gitDir, branch: record.branch };
381
+ }));
382
+ }
136
383
  async function executeGit(arguments_, cwd, maxBuffer, signal) {
137
384
  const { execFile } = await import("node:child_process");
138
385
  const execute = promisify(execFile);
139
- return await execute("git", [...arguments_], {
140
- cwd,
141
- windowsHide: true,
142
- timeout: GIT_TIMEOUT_MS,
143
- maxBuffer,
144
- encoding: "utf8",
145
- signal,
146
- });
386
+ return await execute("git", [...arguments_], { cwd, windowsHide: true, timeout: GIT_TIMEOUT_MS, maxBuffer, encoding: "utf8", signal });
387
+ }
388
+ async function mutationLockExists(options) {
389
+ try {
390
+ await lstat(join(claimStoreRoot(options), "mutation.lock"));
391
+ return true;
392
+ }
393
+ catch (error) {
394
+ if (error instanceof Error && "code" in error && error.code === "ENOENT")
395
+ return false;
396
+ return true;
397
+ }
398
+ }
399
+ async function withClaimLock(options, operation) {
400
+ const directory = claimStoreRoot(options);
401
+ await mkdir(directory, { recursive: true, mode: 0o700 });
402
+ const path = join(directory, "mutation.lock");
403
+ const deadline = Date.now() + (options.lockTimeoutMs ?? LOCK_TIMEOUT_MS);
404
+ let handle;
405
+ while (handle === undefined) {
406
+ try {
407
+ handle = await open(path, "wx", 0o600);
408
+ }
409
+ catch (error) {
410
+ if (!(error instanceof Error && "code" in error && error.code === "EEXIST"))
411
+ throw error;
412
+ if (Date.now() >= deadline)
413
+ throw contextError("worktree claim mutation is busy", "worktree-claim-busy");
414
+ await new Promise(resolvePromise => setTimeout(resolvePromise, LOCK_RETRY_MS));
415
+ }
416
+ }
417
+ try {
418
+ await handle.writeFile(`${JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString() })}\n`);
419
+ return await operation();
420
+ }
421
+ finally {
422
+ await handle.close().catch(() => undefined);
423
+ await rm(path, { force: true }).catch(() => undefined);
424
+ }
425
+ }
426
+ async function atomicWrite(path, value) {
427
+ const directory = dirname(path);
428
+ await mkdir(directory, { recursive: true, mode: 0o700 });
429
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
430
+ try {
431
+ await writeFile(temporary, `${JSON.stringify(value)}\n`, { encoding: "utf8", mode: 0o600, flag: "wx" });
432
+ await rename(temporary, path);
433
+ }
434
+ finally {
435
+ await rm(temporary, { force: true }).catch(() => undefined);
436
+ }
437
+ }
438
+ async function readJsonRecord(path, validator) {
439
+ try {
440
+ const metadata = await lstat(path);
441
+ if (!metadata.isFile() || metadata.isSymbolicLink() || metadata.size === 0 || metadata.size > MAX_RECORD_BYTES)
442
+ return null;
443
+ const value = JSON.parse((await readFile(path)).toString("utf8"));
444
+ return validator(value) ? value : null;
445
+ }
446
+ catch {
447
+ return null;
448
+ }
449
+ }
450
+ function contextRecordPath(header, options) {
451
+ const dataDir = options.dataDir ?? resolveProductPaths().dataDir;
452
+ const digest = createHash("sha256").update(header.id).update("\0").update(pathKey(header.file)).digest("hex");
453
+ return join(dataDir, PRODUCT_IDENTITY.state.sessionRepositoryDirectory, `${digest}.json`);
454
+ }
455
+ function claimStoreRoot(options) {
456
+ return join(options.dataDir ?? resolveProductPaths().dataDir, PRODUCT_IDENTITY.state.sessionWorktreeClaimDirectory);
457
+ }
458
+ function runtimeRecordPath(runtimeId, options) {
459
+ return join(claimStoreRoot(options), "runtimes", `${digest(runtimeId)}.json`);
460
+ }
461
+ function claimsDirectory(options) {
462
+ return join(claimStoreRoot(options), "worktrees");
463
+ }
464
+ function claimRecordPath(commonDir, gitDir, options) {
465
+ return join(claimsDirectory(options), `${digest(`${pathKey(commonDir)}\0${pathKey(gitDir)}`)}.json`);
466
+ }
467
+ function digest(value) {
468
+ return createHash("sha256").update(value).digest("hex");
469
+ }
470
+ function requireRuntimeId(options) {
471
+ const runtimeId = options.runtimeId;
472
+ assertRuntimeId(runtimeId);
473
+ return runtimeId;
474
+ }
475
+ function requireInspector(options) {
476
+ if (options.inspectProcess === undefined)
477
+ throw contextError("native process identity inspection is unavailable", "process-inspection-unavailable");
478
+ return options.inspectProcess;
479
+ }
480
+ function processIdentityOf(record) {
481
+ return { pid: record.pid, startIdentity: record.startIdentity };
147
482
  }
148
483
  function requireBranch(identity) {
149
484
  if (identity.branch === null)
150
485
  throw new Error("associated worktree branch is unavailable");
151
486
  return identity.branch;
152
487
  }
153
- function recordPath(header, options) {
154
- const dataDir = options.dataDir ?? resolveProductPaths().dataDir;
155
- const digest = createHash("sha256").update(header.id).update("\0").update(pathKey(header.file)).digest("hex");
156
- return join(dataDir, PRODUCT_IDENTITY.state.sessionRepositoryDirectory, `${digest}.json`);
488
+ function claimMatchesWorktree(claim, worktree) {
489
+ return samePath(claim.worktreeRoot, worktree.root)
490
+ && samePath(claim.worktreeCommonDir, worktree.commonDir)
491
+ && samePath(claim.worktreeGitDir, worktree.gitDir);
157
492
  }
158
493
  function samePath(left, right) {
159
494
  return pathKey(left) === pathKey(right);
@@ -162,12 +497,45 @@ function pathKey(value) {
162
497
  const normalized = resolve(value);
163
498
  return process.platform === "win32" ? normalized.toLowerCase() : normalized;
164
499
  }
500
+ function assertRuntimeId(value) {
501
+ if (typeof value !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/u.test(value)) {
502
+ throw contextError("active session runtime identity is unavailable", "session-runtime-unavailable");
503
+ }
504
+ }
505
+ function assertProcessIdentity(value) {
506
+ if (!Number.isSafeInteger(value.pid) || value.pid <= 0 || typeof value.startIdentity !== "string"
507
+ || value.startIdentity.length === 0 || value.startIdentity.length > 512 || value.startIdentity.includes("\0")) {
508
+ throw contextError("native process identity is invalid", "process-identity-invalid");
509
+ }
510
+ }
165
511
  function validSessionId(value) {
166
512
  return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/u.test(value);
167
513
  }
168
514
  function validPath(value) {
169
515
  return typeof value === "string" && value.length > 0 && value.length <= 32_768 && !value.includes("\0") && isAbsolute(value);
170
516
  }
517
+ function isContextRecord(value) {
518
+ return isRecord(value) && value.schema === CONTEXT_SCHEMA && validSessionId(value.sessionId)
519
+ && validPath(value.sessionFile) && validPath(value.startupRoot) && validPath(value.startupCommonDir)
520
+ && validPath(value.worktreeRoot) && validPath(value.worktreeCommonDir) && validPath(value.worktreeGitDir)
521
+ && typeof value.updatedAt === "string";
522
+ }
523
+ function isRuntimeRecord(value) {
524
+ return isRecord(value) && value.schema === RUNTIME_SCHEMA && validSessionId(value.runtimeId) && validSessionId(value.sessionId)
525
+ && validPath(value.sessionFile) && Number.isSafeInteger(value.pid) && Number(value.pid) > 0
526
+ && typeof value.startIdentity === "string" && value.startIdentity.length > 0 && value.startIdentity.length <= 512
527
+ && !value.startIdentity.includes("\0") && typeof value.updatedAt === "string";
528
+ }
529
+ function isClaimRecord(value) {
530
+ return isRecord(value) && value.schema === CLAIM_SCHEMA && validSessionId(value.runtimeId) && validSessionId(value.sessionId)
531
+ && validPath(value.worktreeRoot) && validPath(value.worktreeCommonDir) && validPath(value.worktreeGitDir)
532
+ && Number.isSafeInteger(value.pid) && Number(value.pid) > 0
533
+ && typeof value.startIdentity === "string" && value.startIdentity.length > 0 && value.startIdentity.length <= 512
534
+ && !value.startIdentity.includes("\0") && typeof value.updatedAt === "string";
535
+ }
171
536
  function isRecord(value) {
172
537
  return typeof value === "object" && value !== null && !Array.isArray(value);
173
538
  }
539
+ function contextError(message, code) {
540
+ return Object.assign(new Error(message), { code });
541
+ }
@@ -4,5 +4,6 @@ export type { ContainedProcessHandle, ContainedSpawnOptions, ContainmentCloseRes
4
4
  export { DarwinNativeProcessInspector } from "./darwin-process-inspector.js";
5
5
  export { LinuxNativeProcessInspector } from "./linux-process-inspector.js";
6
6
  export { NativeGuardianContainment, resolveProcessGuardianPath } from "./native-guardian-containment.js";
7
+ export { createNativeProcessInspector } from "./native-process-inspector.js";
7
8
  export { WindowsNativeProcessInspector } from "./windows-process-inspector.js";
8
9
  export type { InspectorCommandResult, InspectorCommandRunner } from "./windows-process-inspector.js";
@@ -3,4 +3,5 @@ export { closeVerifiedContainment } from "./contracts.js";
3
3
  export { DarwinNativeProcessInspector } from "./darwin-process-inspector.js";
4
4
  export { LinuxNativeProcessInspector } from "./linux-process-inspector.js";
5
5
  export { NativeGuardianContainment, resolveProcessGuardianPath } from "./native-guardian-containment.js";
6
+ export { createNativeProcessInspector } from "./native-process-inspector.js";
6
7
  export { WindowsNativeProcessInspector } from "./windows-process-inspector.js";
@@ -0,0 +1,3 @@
1
+ import type { NativeProcessInspector } from "./contracts.js";
2
+ /** Resolve only the platform's exact-process inspector used by cooperative session ownership. */
3
+ export declare function createNativeProcessInspector(environment?: NodeJS.ProcessEnv, platform?: NodeJS.Platform, releaseRoot?: string): Promise<NativeProcessInspector>;
@@ -0,0 +1,21 @@
1
+ import { PRODUCT_IDENTITY } from "../../product-identity.js";
2
+ /** Resolve only the platform's exact-process inspector used by cooperative session ownership. */
3
+ export async function createNativeProcessInspector(environment = process.env, platform = process.platform, releaseRoot) {
4
+ if (platform === "linux") {
5
+ const { LinuxNativeProcessInspector } = await import("./linux-process-inspector.js");
6
+ return new LinuxNativeProcessInspector();
7
+ }
8
+ if (platform !== "win32" && platform !== "darwin")
9
+ throw new Error(`native process identity is unsupported on ${platform}`);
10
+ if (releaseRoot === undefined && !environment[PRODUCT_IDENTITY.environment.processGuardianPath]) {
11
+ throw new Error("native process identity helper is unavailable");
12
+ }
13
+ const { resolveProcessGuardianPath } = await import("./native-guardian-containment.js");
14
+ const helper = resolveProcessGuardianPath(releaseRoot ?? process.cwd(), environment, platform);
15
+ if (platform === "win32") {
16
+ const { WindowsNativeProcessInspector } = await import("./windows-process-inspector.js");
17
+ return new WindowsNativeProcessInspector(helper);
18
+ }
19
+ const { DarwinNativeProcessInspector } = await import("./darwin-process-inspector.js");
20
+ return new DarwinNativeProcessInspector(helper);
21
+ }
@@ -2,7 +2,6 @@ import { spawn } from "node:child_process";
2
2
  import { restoreAfterOwnedExit } from "../terminal-cleanup/index.js";
3
3
  import { chmod, mkdir, readFile, rm, writeFile } from "node:fs/promises";
4
4
  import { connect } from "node:net";
5
- import { platform } from "node:os";
6
5
  import { resolve } from "node:path";
7
6
  import { selectCohortLaunch } from "./cohort-selection.js";
8
7
  import { selectOrdinaryLaunchReleaseId } from "./ordinary-launch-selection.js";
@@ -16,7 +15,7 @@ import { selectUpdateLaunchRelease } from "./update-launch.js";
16
15
  import { consumeMaterializationProof, materializeRelease, readCertifiedReleaseManifest, readMaterializedRelease, resolveReleaseEntryPoint, verifyMaterializedRelease } from "./release-store.js";
17
16
  import { scheduleReleaseCleanup } from "./release-gc.js";
18
17
  import { createRestartSeal, readRestartCertifiedRelease, releaseCertificationDocument } from "./restart-certification.js";
19
- import { PRODUCT_IDENTITY, PRODUCT_TEXT } from "../../product-identity.js";
18
+ import { PRODUCT_TEXT } from "../../product-identity.js";
20
19
  import { markStartupPhase } from "../startup/index.js";
21
20
  import { launchContractTarget, readLaunchContext, withLaunchContext } from "../launch-context/index.js";
22
21
  const RELEASE_RESELECTION_MESSAGE = "a1-release-reselection";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generated by scripts/pi/sync-progress-palette.ts from @earendil-works/pi-coding-agent 1.0.4
3
- * (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df. Do not edit directly.
2
+ * Generated by scripts/pi/sync-progress-palette.ts from @earendil-works/pi-coding-agent 1.1.0
3
+ * (MIT), commit abe508e1b89912adde45528136c3221eb69acdd7. Do not edit directly.
4
4
  */
5
5
  export declare const SHARED_PROGRESS_ACCENT_ANSI = "\u001B[38;2;167;152;215m";
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Generated by scripts/pi/sync-progress-palette.ts from @earendil-works/pi-coding-agent 1.0.4
3
- * (MIT), commit 7c10bd4337495ee613f2224843ecdf349b80d1df. Do not edit directly.
2
+ * Generated by scripts/pi/sync-progress-palette.ts from @earendil-works/pi-coding-agent 1.1.0
3
+ * (MIT), commit abe508e1b89912adde45528136c3221eb69acdd7. Do not edit directly.
4
4
  */
5
5
  export const SHARED_PROGRESS_ACCENT_ANSI = "\u001b[38;2;167;152;215m";
@@ -3,7 +3,7 @@ import { spawn } from "node:child_process";
3
3
  import { lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat } from "node:fs/promises";
4
4
  import { dirname, isAbsolute, relative, resolve, sep } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
- import { CohortStateStore, planProtectedReleases, } from "./cohort-state.js";
6
+ import { CohortStateStore, } from "./cohort-state.js";
7
7
  import { liveReleaseIds } from "./endpoints.js";
8
8
  import { resolveProductPaths } from "../lifecycle/index.js";
9
9
  import { RELEASE_MANIFEST_FILENAME } from "./release-store.js";