@skrr-ai/cli 0.1.118 → 0.1.120

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 (285) hide show
  1. package/dist/base-command.d.ts +32 -0
  2. package/dist/base-command.js +113 -5
  3. package/dist/commands/commands.js +11 -0
  4. package/dist/commands/commitments/action-proposal.d.ts +13 -0
  5. package/dist/commands/commitments/action-proposal.js +39 -0
  6. package/dist/commands/commitments/action-proposals/decide.js +8 -1
  7. package/dist/commands/commitments/action-proposals/execute.js +11 -1
  8. package/dist/commands/commitments/create.js +2 -2
  9. package/dist/commands/commitments/doctor.d.ts +8 -0
  10. package/dist/commands/commitments/doctor.js +22 -0
  11. package/dist/commands/commitments/execute-remediation.js +12 -1
  12. package/dist/commands/commitments/observations.js +2 -2
  13. package/dist/commands/commitments/pack/bind.d.ts +18 -1
  14. package/dist/commands/commitments/pack/bind.js +66 -8
  15. package/dist/commands/commitments/pack/plan.d.ts +4 -1
  16. package/dist/commands/commitments/pack/plan.js +30 -2
  17. package/dist/commands/commitments/update.js +8 -2
  18. package/dist/commands/completion/index.js +1 -1
  19. package/dist/commands/completion/values.js +1 -1
  20. package/dist/commands/computer-use/audio.d.ts +1 -0
  21. package/dist/commands/computer-use/audio.js +1 -0
  22. package/dist/commands/computer-use/browser.d.ts +1 -0
  23. package/dist/commands/computer-use/browser.js +1 -0
  24. package/dist/commands/computer-use/disable.d.ts +1 -0
  25. package/dist/commands/computer-use/disable.js +1 -0
  26. package/dist/commands/computer-use/enable.d.ts +1 -0
  27. package/dist/commands/computer-use/enable.js +1 -0
  28. package/dist/commands/computer-use/index.d.ts +1 -0
  29. package/dist/commands/computer-use/index.js +1 -0
  30. package/dist/commands/computer-use/install.d.ts +1 -0
  31. package/dist/commands/computer-use/install.js +1 -0
  32. package/dist/commands/computer-use/recover.d.ts +1 -0
  33. package/dist/commands/computer-use/recover.js +1 -0
  34. package/dist/commands/computer-use/status.d.ts +1 -0
  35. package/dist/commands/computer-use/status.js +1 -0
  36. package/dist/commands/computer-use/stop.d.ts +1 -0
  37. package/dist/commands/computer-use/stop.js +1 -0
  38. package/dist/commands/context.js +16 -11
  39. package/dist/commands/convos/recovery.js +1 -1
  40. package/dist/commands/daemon/diagnostics.d.ts +9 -0
  41. package/dist/commands/daemon/diagnostics.js +53 -0
  42. package/dist/commands/daemon/index.js +2 -0
  43. package/dist/commands/daemon/maintenance/attest.d.ts +15 -0
  44. package/dist/commands/daemon/maintenance/attest.js +52 -0
  45. package/dist/commands/daemon/maintenance/hold.d.ts +17 -0
  46. package/dist/commands/daemon/maintenance/hold.js +70 -0
  47. package/dist/commands/daemon/maintenance/index.d.ts +12 -0
  48. package/dist/commands/daemon/maintenance/index.js +30 -0
  49. package/dist/commands/daemon/maintenance/resume.d.ts +13 -0
  50. package/dist/commands/daemon/maintenance/resume.js +36 -0
  51. package/dist/commands/daemon/maintenance/status.d.ts +13 -0
  52. package/dist/commands/daemon/maintenance/status.js +36 -0
  53. package/dist/commands/doctor.d.ts +4 -1
  54. package/dist/commands/doctor.js +50 -6
  55. package/dist/commands/followups/plans/cancel-batch.js +6 -3
  56. package/dist/commands/followups/plans/capacity.js +7 -3
  57. package/dist/commands/followups/plans/observability.js +11 -3
  58. package/dist/commands/followups/plans/preferences/set.js +26 -8
  59. package/dist/commands/followups/plans/preferences.js +1 -1
  60. package/dist/commands/followups/plans/show.js +1 -1
  61. package/dist/commands/goals/key-results/assess.d.ts +36 -0
  62. package/dist/commands/goals/key-results/assess.js +110 -0
  63. package/dist/commands/goals/key-results/history.d.ts +30 -0
  64. package/dist/commands/goals/key-results/history.js +104 -0
  65. package/dist/commands/goals/key-results/list.d.ts +5 -4
  66. package/dist/commands/goals/key-results/list.js +12 -6
  67. package/dist/commands/goals/key-results/show.d.ts +4 -2
  68. package/dist/commands/goals/key-results/show.js +25 -4
  69. package/dist/commands/goals/key-results/update.d.ts +4 -0
  70. package/dist/commands/goals/key-results/update.js +18 -24
  71. package/dist/commands/goals/plan-now.js +12 -1
  72. package/dist/commands/goals/planner-compare.d.ts +30 -0
  73. package/dist/commands/goals/planner-compare.js +136 -0
  74. package/dist/commands/machines/dedicated/service/exec.d.ts +3 -0
  75. package/dist/commands/machines/dedicated/service/exec.js +70 -11
  76. package/dist/commands/machines/hosted/destroy.d.ts +1 -0
  77. package/dist/commands/machines/hosted/destroy.js +11 -1
  78. package/dist/commands/machines/hosted/exec.d.ts +1 -0
  79. package/dist/commands/machines/hosted/exec.js +12 -1
  80. package/dist/commands/machines/hosted/index.js +1 -0
  81. package/dist/commands/machines/hosted/operation.d.ts +14 -0
  82. package/dist/commands/machines/hosted/operation.js +51 -0
  83. package/dist/commands/machines/hosted/pull.js +1 -1
  84. package/dist/commands/machines/hosted/start.js +6 -2
  85. package/dist/commands/memory/versions/list.d.ts +2 -0
  86. package/dist/commands/memory/versions/list.js +3 -2
  87. package/dist/commands/memory/versions/show.d.ts +2 -0
  88. package/dist/commands/memory/versions/show.js +3 -2
  89. package/dist/commands/spaces/auto-executor/compare.d.ts +18 -0
  90. package/dist/commands/spaces/auto-executor/compare.js +139 -0
  91. package/dist/commands/spaces/auto-executor/runs.d.ts +3 -0
  92. package/dist/commands/spaces/auto-executor/runs.js +13 -1
  93. package/dist/commands/spaces/charter/create-from-description.d.ts +21 -0
  94. package/dist/commands/spaces/charter/create-from-description.js +77 -0
  95. package/dist/commands/spaces/charter/show.d.ts +22 -0
  96. package/dist/commands/spaces/charter/show.js +61 -0
  97. package/dist/commands/spaces/heartbeats/list.d.ts +1 -16
  98. package/dist/commands/spaces/heartbeats/list.js +13 -0
  99. package/dist/commands/spaces/install-template.js +3 -0
  100. package/dist/commands/spaces/loops/migrate.d.ts +32 -0
  101. package/dist/commands/spaces/loops/migrate.js +103 -0
  102. package/dist/commands/spaces/loops/release.d.ts +14 -0
  103. package/dist/commands/spaces/loops/release.js +59 -0
  104. package/dist/commands/spaces/notebook.d.ts +25 -0
  105. package/dist/commands/spaces/notebook.js +75 -0
  106. package/dist/commands/spaces/proposals/discard.d.ts +17 -0
  107. package/dist/commands/spaces/proposals/discard.js +17 -0
  108. package/dist/commands/spaces/proposals/keep.d.ts +17 -0
  109. package/dist/commands/spaces/proposals/keep.js +17 -0
  110. package/dist/commands/spaces/proposals/list.d.ts +24 -0
  111. package/dist/commands/spaces/proposals/list.js +89 -0
  112. package/dist/commands/spaces/skills/propose.d.ts +29 -0
  113. package/dist/commands/spaces/skills/propose.js +82 -0
  114. package/dist/commands/spaces/templates/fork.js +3 -0
  115. package/dist/commands/spaces/triggers/show.js +6 -0
  116. package/dist/commands/spaces/workflows/retry.d.ts +1 -0
  117. package/dist/commands/spaces/workflows/retry.js +8 -1
  118. package/dist/commands/spaces/workflows/triggers/create.js +3 -2
  119. package/dist/commands/spaces/workflows/triggers/fire.js +4 -0
  120. package/dist/commands/spaces/workflows/triggers/update.js +2 -1
  121. package/dist/commands/spaces/write-policy/set.d.ts +22 -0
  122. package/dist/commands/spaces/write-policy/set.js +82 -0
  123. package/dist/commands/spaces/write-policy/show.d.ts +19 -0
  124. package/dist/commands/spaces/write-policy/show.js +49 -0
  125. package/dist/commands/store/artifacts/receipt.d.ts +14 -0
  126. package/dist/commands/store/artifacts/receipt.js +34 -0
  127. package/dist/commands/store/artifacts/release.d.ts +2 -0
  128. package/dist/commands/store/artifacts/release.js +11 -0
  129. package/dist/commands/store/governance/publish-release.d.ts +2 -0
  130. package/dist/commands/store/governance/publish-release.js +30 -1
  131. package/dist/commands/store/governance/release-receipt.d.ts +12 -0
  132. package/dist/commands/store/governance/release-receipt.js +32 -0
  133. package/dist/commands/tasks/approvals/list.d.ts +11 -5
  134. package/dist/commands/tasks/approvals/list.js +13 -6
  135. package/dist/commands/tasks/attachments/facts.d.ts +12 -0
  136. package/dist/commands/tasks/attachments/facts.js +29 -0
  137. package/dist/commands/tasks/attachments/upload.d.ts +1 -0
  138. package/dist/commands/tasks/attachments/upload.js +16 -0
  139. package/dist/commands/tasks/bulk-update.js +35 -1
  140. package/dist/commands/tasks/context.d.ts +15 -0
  141. package/dist/commands/tasks/context.js +69 -0
  142. package/dist/commands/tasks/copy.d.ts +18 -0
  143. package/dist/commands/tasks/copy.js +85 -0
  144. package/dist/commands/tasks/create-tree.js +97 -23
  145. package/dist/commands/tasks/create.js +9 -1
  146. package/dist/commands/tasks/deliverable/add.js +20 -10
  147. package/dist/commands/tasks/move.js +8 -1
  148. package/dist/commands/tasks/operations/show.d.ts +16 -0
  149. package/dist/commands/tasks/operations/show.js +98 -0
  150. package/dist/commands/tasks/operations/wait.d.ts +22 -0
  151. package/dist/commands/tasks/operations/wait.js +114 -0
  152. package/dist/commands/tasks/preflight.d.ts +1 -0
  153. package/dist/commands/tasks/preflight.js +11 -1
  154. package/dist/commands/tasks/rearm-recurrence.js +4 -0
  155. package/dist/commands/tasks/result/show.js +22 -0
  156. package/dist/commands/tasks/result/submit.d.ts +1 -0
  157. package/dist/commands/tasks/result/submit.js +3 -0
  158. package/dist/commands/tasks/retry-receipt.d.ts +15 -0
  159. package/dist/commands/tasks/retry-receipt.js +89 -0
  160. package/dist/commands/tasks/retry-review.d.ts +16 -0
  161. package/dist/commands/tasks/retry-review.js +66 -0
  162. package/dist/commands/tasks/retry.d.ts +4 -8
  163. package/dist/commands/tasks/retry.js +34 -68
  164. package/dist/commands/tasks/runs.d.ts +21 -0
  165. package/dist/commands/tasks/runs.js +95 -0
  166. package/dist/commands/tasks/show.d.ts +2 -0
  167. package/dist/commands/tasks/show.js +15 -1
  168. package/dist/commands/tasks/start-receipt.d.ts +15 -0
  169. package/dist/commands/tasks/start-receipt.js +95 -0
  170. package/dist/commands/tasks/start.d.ts +4 -0
  171. package/dist/commands/tasks/start.js +49 -3
  172. package/dist/commands/tasks/update.js +3 -0
  173. package/dist/commands/tasks/upsert.js +17 -3
  174. package/dist/commands/tasks/watch.d.ts +3 -0
  175. package/dist/commands/tasks/watch.js +85 -20
  176. package/dist/commands/wiki/history.d.ts +33 -0
  177. package/dist/commands/wiki/history.js +134 -0
  178. package/dist/commands/wiki/ls.d.ts +2 -0
  179. package/dist/commands/wiki/ls.js +8 -0
  180. package/dist/commands/wiki/update.d.ts +3 -1
  181. package/dist/commands/wiki/update.js +24 -2
  182. package/dist/commands/wiki/write.d.ts +22 -0
  183. package/dist/commands/wiki/write.js +144 -6
  184. package/dist/generated/agent-guides.json +81 -81
  185. package/dist/generated/managed-instruction-guides.json +1 -1
  186. package/dist/lib/agent-guides.d.ts +9 -0
  187. package/dist/lib/agent-guides.js +23 -1
  188. package/dist/lib/agentic-stream.d.ts +5 -0
  189. package/dist/lib/agentic-stream.js +122 -3
  190. package/dist/lib/api-fetch.d.ts +4 -0
  191. package/dist/lib/api-fetch.js +25 -7
  192. package/dist/lib/auth-diagnostics.d.ts +39 -0
  193. package/dist/lib/auth-diagnostics.js +71 -0
  194. package/dist/lib/cli-client-identity.d.ts +6 -0
  195. package/dist/lib/cli-client-identity.js +16 -0
  196. package/dist/lib/cli-installation-diagnostics.d.ts +52 -0
  197. package/dist/lib/cli-installation-diagnostics.js +254 -0
  198. package/dist/lib/command-hygiene.d.ts +45 -0
  199. package/dist/lib/command-hygiene.js +413 -0
  200. package/dist/lib/commitments.d.ts +64 -3
  201. package/dist/lib/commitments.js +34 -6
  202. package/dist/lib/completion-index.d.ts +16 -4
  203. package/dist/lib/completion-index.js +50 -14
  204. package/dist/lib/config.js +7 -1
  205. package/dist/lib/daemon-maintenance-command.d.ts +22 -0
  206. package/dist/lib/daemon-maintenance-command.js +39 -0
  207. package/dist/lib/daemon-maintenance.d.ts +275 -0
  208. package/dist/lib/daemon-maintenance.js +1035 -0
  209. package/dist/lib/dedicated-service.d.ts +3 -2
  210. package/dist/lib/dedicated-service.js +11 -3
  211. package/dist/lib/governed-store.d.ts +8 -0
  212. package/dist/lib/governed-store.js +5 -0
  213. package/dist/lib/hosted-machines.d.ts +33 -2
  214. package/dist/lib/hosted-machines.js +19 -1
  215. package/dist/lib/json-output.d.ts +1 -1
  216. package/dist/lib/machines.d.ts +9 -1
  217. package/dist/lib/machines.js +15 -1
  218. package/dist/lib/memory-history-session.d.ts +14 -0
  219. package/dist/lib/memory-history-session.js +60 -0
  220. package/dist/lib/node-adapter.js +13 -0
  221. package/dist/lib/record-output.d.ts +22 -0
  222. package/dist/lib/record-output.js +78 -0
  223. package/dist/lib/roles.d.ts +3 -3
  224. package/dist/lib/scoped-memory-command.d.ts +24 -0
  225. package/dist/lib/scoped-memory-command.js +87 -5
  226. package/dist/lib/space-charter.d.ts +49 -0
  227. package/dist/lib/space-charter.js +78 -0
  228. package/dist/lib/space-loop-migration.d.ts +18 -0
  229. package/dist/lib/space-loop-migration.js +128 -0
  230. package/dist/lib/space-notebook.d.ts +22 -0
  231. package/dist/lib/space-notebook.js +140 -0
  232. package/dist/lib/space-proposal-decision-command.d.ts +36 -0
  233. package/dist/lib/space-proposal-decision-command.js +108 -0
  234. package/dist/lib/space-proposals.d.ts +44 -0
  235. package/dist/lib/space-proposals.js +186 -0
  236. package/dist/lib/space-templates.d.ts +8 -0
  237. package/dist/lib/space-templates.js +17 -0
  238. package/dist/lib/space-write-policy.d.ts +24 -0
  239. package/dist/lib/space-write-policy.js +103 -0
  240. package/dist/lib/task-agent-context-capabilities.d.ts +10 -0
  241. package/dist/lib/task-agent-context-capabilities.js +22 -0
  242. package/dist/lib/task-agent-context-compatibility.d.ts +9 -0
  243. package/dist/lib/task-agent-context-compatibility.js +30 -0
  244. package/dist/lib/task-asset-upload.d.ts +22 -0
  245. package/dist/lib/task-asset-upload.js +257 -29
  246. package/dist/lib/task-batch.d.ts +15 -1
  247. package/dist/lib/task-batch.js +35 -2
  248. package/dist/lib/task-operation-watch.d.ts +66 -0
  249. package/dist/lib/task-operation-watch.js +159 -0
  250. package/dist/lib/task-resolver.d.ts +1 -1
  251. package/dist/lib/task-resolver.js +4 -3
  252. package/dist/lib/task-runtime-headers.js +13 -3
  253. package/dist/lib/task-work.d.ts +1 -1
  254. package/dist/lib/task-work.js +35 -1
  255. package/dist/lib/task-write-attribution.d.ts +14 -0
  256. package/dist/lib/task-write-attribution.js +35 -2
  257. package/dist/lib/triggers.d.ts +11 -0
  258. package/dist/lib/triggers.js +7 -0
  259. package/dist/lib/wiki-update.d.ts +1 -0
  260. package/dist/lib/wiki-update.js +10 -1
  261. package/dist/lib/wiki.js +4 -1
  262. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.d.ts +9 -1
  263. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/computerWire.js +31 -15
  264. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonToolApproval.js +1 -0
  265. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/daemonWire.js +13 -7
  266. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.d.ts +370 -0
  267. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/guidedUpdate.js +315 -0
  268. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.d.ts +178 -0
  269. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/maintenanceReportWire.js +262 -0
  270. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.d.ts +51 -0
  271. package/dist/node_modules/@skrr-ai/auth-core/dist/cjs/toolApprovalSignature.js +106 -0
  272. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.d.ts +9 -1
  273. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/computerWire.js +32 -5
  274. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonToolApproval.js +1 -0
  275. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/daemonWire.js +33 -14
  276. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.d.ts +370 -0
  277. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/guidedUpdate.js +404 -0
  278. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.d.ts +178 -0
  279. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/maintenanceReportWire.js +342 -0
  280. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.d.ts +51 -0
  281. package/dist/node_modules/@skrr-ai/auth-core/dist/esm/toolApprovalSignature.js +138 -0
  282. package/dist/node_modules/@skrr-ai/auth-core/package.json +20 -0
  283. package/dist/node_modules/@skrr-ai/data-provider/index.js +27085 -20250
  284. package/oclif.manifest.json +10570 -7247
  285. package/package.json +20 -2
@@ -0,0 +1,370 @@
1
+ /**
2
+ * The pure core of a GUIDED update (OSK-19107, Space OSK-S-524, tasks M51 to M53):
3
+ * hold the machine, wait for it to be quiet, update, verify, and give the machine
4
+ * back. The Desktop app and a standalone `skrr` install both run it, so what they
5
+ * decide on, and the words they use for what is in the way, cannot drift apart.
6
+ *
7
+ * This file is DECISIONS ONLY. It performs no I/O, reads no clock and holds no
8
+ * state, so every rule below is a table test. The orchestration (a persisted flow
9
+ * record, polling, the installer, the supervisor) lives with each caller, because
10
+ * that is the part that differs between a Desktop that quits mid-flow and a CLI that
11
+ * runs in the foreground.
12
+ *
13
+ * ## Why these rules (each names the failure it prevents)
14
+ *
15
+ * - **`prepare` is a probe that briefly refuses admitted work.** While it runs the
16
+ * daemon refuses admitted tool calls with an infra-class error, and a tool-proxy Run
17
+ * that sees one drops its tools to the Hosted Machine for good. So a guided flow
18
+ * calls it ONLY when the server's reading says there is nothing admitted to refuse
19
+ * ({@link prepareBasis}), never to find out whether there is.
20
+ * - **`unknown` is an answer.** A source nobody could read is never zero and never
21
+ * ready. {@link noServerVeto} is deliberately strict: every server source must have
22
+ * been read, and none may list active or unproven work.
23
+ * - **A server source can only veto.** Only the daemon's own positively announced
24
+ * report grants `ready`; the owner's attestation and the daemon's own `prepare`
25
+ * (labelled `no_veto`, D38) are the two other bases, and each is labelled as what
26
+ * it is wherever it is shown.
27
+ * - **Blockers are shown in the words of whoever knows them.** The daemon's blocker
28
+ * `reason` and the server's holder `label` are the vocabulary; nothing here
29
+ * re-spells them. They are bounded and never a raw path, because a diagnostic can
30
+ * carry one.
31
+ * - **A new PID, an exit code or a cloud connection is not a verified update.**
32
+ * {@link verifyReplacement} requires the daemon's own `verified`, from a process
33
+ * other than the one that was replaced, for the build that was asked for, and the
34
+ * same machine identity afterwards. A different identity is the reinstall case: the
35
+ * hold is left in place and shown, never resumed.
36
+ *
37
+ * The shapes are STRUCTURAL SUBSETS of `DaemonMaintenanceView` in
38
+ * `@skrr-ai/data-provider` (`daemonMaintenance.ts`), which is the one vocabulary.
39
+ * This package cannot import it (it sits below it), so `guidedUpdate.test.ts` reads
40
+ * that file and fails when a list mirrored here drifts from it.
41
+ */
42
+ export type GuidedHolderClass = 'active' | 'pending_delivery' | 'unproven' | 'forensic';
43
+ export interface GuidedHolder {
44
+ kind: string;
45
+ class: GuidedHolderClass | string;
46
+ ref?: string;
47
+ label?: string;
48
+ since?: string | null;
49
+ detail?: string;
50
+ }
51
+ export interface GuidedSourceReading {
52
+ source: string;
53
+ read: 'ok' | 'unreadable' | 'not_announced' | string;
54
+ cause?: string;
55
+ readAt?: string;
56
+ total?: number;
57
+ holders?: GuidedHolder[];
58
+ truncated?: boolean;
59
+ }
60
+ export interface GuidedViewLike {
61
+ runtimeKey?: string;
62
+ hold: {
63
+ generation: number;
64
+ lifecycle: 'held' | 'released' | string;
65
+ reason?: string;
66
+ requestedAt?: string;
67
+ heldBy?: {
68
+ kind?: string;
69
+ id?: string;
70
+ name?: string;
71
+ };
72
+ attestation?: {
73
+ at?: string;
74
+ by?: string;
75
+ } | null;
76
+ } | null;
77
+ reading: {
78
+ state: 'draining' | 'ready' | 'unknown' | string;
79
+ cause: string | null;
80
+ readAt?: string;
81
+ sources?: GuidedSourceReading[];
82
+ } | null;
83
+ journey: {
84
+ phase: string;
85
+ modifiers?: string[];
86
+ cause?: string | null;
87
+ controls?: string[];
88
+ };
89
+ }
90
+ /** The server sources that can only veto. `daemon_report` is the only one that grants. */
91
+ export declare const GUIDED_SERVER_SOURCES: readonly ["claims", "receipts", "sessions", "runs", "leases", "custody"];
92
+ /** The refusals the owner API names, mirrored from `DAEMON_MAINTENANCE_REFUSALS`. */
93
+ export declare const GUIDED_REFUSALS: readonly ["managed_machine", "no_stable_identity", "not_found", "ambiguous", "generation_conflict", "not_held", "already_held", "attestation_not_applicable", "not_owner", "held_by_other"];
94
+ export type GuidedRefusal = (typeof GUIDED_REFUSALS)[number];
95
+ export declare function isGuidedRefusal(value: unknown): value is GuidedRefusal;
96
+ /** The daemon handoff phases, mirrored from `daemon/src/update/handoff.ts`. */
97
+ export declare const GUIDED_HANDOFF_PHASES: readonly ["ready", "deferred", "reconnecting", "verified", "failed", "rolled-back"];
98
+ /**
99
+ * What a guided flow may do with the server's answer. The flow reads `reading` and
100
+ * the fence, never the Journey's phase alone: a Journey says `back_held` for any
101
+ * process that registered after the fence, and that masks the reading it would
102
+ * otherwise carry.
103
+ */
104
+ export type Readiness =
105
+ /** No live hold on this machine (it was released, or never existed). */
106
+ {
107
+ kind: 'not_held';
108
+ }
109
+ /** A live hold, but not the generation this flow took. Never adopted. */
110
+ | {
111
+ kind: 'generation_changed';
112
+ currentGeneration: number;
113
+ }
114
+ /** The fence is not confirmed on every row, so no reading means anything yet. */
115
+ | {
116
+ kind: 'pausing';
117
+ }
118
+ /** Nothing admitted is running: the daemon's report said so, or the owner vouched. */
119
+ | {
120
+ kind: 'ready';
121
+ basis: 'evidence' | 'attested';
122
+ }
123
+ /** The daemon cannot report. No server source vetoes. Only the daemon's own check may decide. */
124
+ | {
125
+ kind: 'no_report';
126
+ } | {
127
+ kind: 'draining';
128
+ } | {
129
+ kind: 'unknown';
130
+ cause: string | null;
131
+ };
132
+ /**
133
+ * Whether the server holds a reading that nothing vetoes, for a daemon that cannot
134
+ * report (D38). Strict on purpose: a source that is absent from the list, unreadable,
135
+ * truncated, or that names active or unproven work, is a veto. `daemon_report` must
136
+ * be `not_announced`: any other answer means the reading is not the
137
+ * `no_inventory_capability` case this is for.
138
+ */
139
+ export declare function noServerVeto(sources: readonly GuidedSourceReading[] | undefined): boolean;
140
+ /**
141
+ * Read the owner API's view for a flow that took `generation`.
142
+ *
143
+ * Order matters and is the rule set (each is a test):
144
+ * 1. No live hold: `not_held`. A different live generation: `generation_changed`.
145
+ * 2. The fence is not confirmed (`pausing`): nothing below it means anything.
146
+ * 3. The reading is `ready` (the daemon's own report): `ready` by evidence.
147
+ * 4. `draining`: work is running. Evidence, never overridden.
148
+ * 5. `unknown`: ready by attestation if the Journey says the owner vouched for this
149
+ * cause; `no_report` if the daemon cannot report and no source vetoes; else
150
+ * `unknown`. No reading at all is `unknown (source_unreadable)`, never ready.
151
+ */
152
+ export declare function evaluateReadiness(view: GuidedViewLike | null | undefined, expectedGeneration: number | null): Readiness;
153
+ /** How a `prepare` is justified. Labelled on every surface as exactly this. */
154
+ export type PrepareBasis = 'evidence' | 'attested' | 'no_veto';
155
+ /**
156
+ * Whether a guided flow may call the daemon's `prepare`, and on what basis. `null`
157
+ * means NO: `prepare` is never a way to find out. A legacy daemon never gets one:
158
+ * it has no endpoint, and its restart is the owner's attested decision, not a probe.
159
+ */
160
+ export declare function prepareBasis(readiness: Readiness, opts: {
161
+ legacy: boolean;
162
+ }): PrepareBasis | null;
163
+ /**
164
+ * Whether a legacy daemon (no handoff endpoint) may be restarted by the supervisor.
165
+ * Only on the owner's attestation: the daemon cannot report what it is doing and a
166
+ * SIGTERM ends its wrappers, so nothing but the owner's word can vouch for it.
167
+ */
168
+ export declare function legacyRestartAllowed(readiness: Readiness): boolean;
169
+ export interface DaemonBlockerLike {
170
+ kind: string;
171
+ id?: string;
172
+ reason?: string;
173
+ }
174
+ export interface DesktopWorkLike {
175
+ localSessions: number;
176
+ agentBrowserWindows: number;
177
+ }
178
+ export type OwnerBlockerSource = 'server' | 'daemon' | 'desktop';
179
+ export interface OwnerBlocker {
180
+ source: OwnerBlockerSource;
181
+ /** The holder or blocker kind as its owner spelled it, or a `desktop_*` id for the app's own work. */
182
+ kind: string;
183
+ /** The server's label, or the daemon's reason, verbatim after bounding. Absent when it was unsafe to show. */
184
+ text?: string;
185
+ /** A server label for a daemon blocker the server holds under the same ref. */
186
+ label?: string;
187
+ /** A bounded identifier (a session or request id), never a path. */
188
+ id?: string;
189
+ since?: string | null;
190
+ /** For the app's own work: how many. */
191
+ count?: number;
192
+ }
193
+ export declare const MAX_OWNER_BLOCKERS = 20;
194
+ /** A sentence safe to put in front of the owner, or `undefined` when it is not. */
195
+ export declare function sanitizeBlockerText(value: unknown, max?: number): string | undefined;
196
+ /**
197
+ * Everything in the way, from the three places that know: the server's holders
198
+ * (active and unproven work: `pending_delivery` and `forensic` never block), the
199
+ * daemon's own refusal from `prepare`, and the work the Desktop app itself hosts and
200
+ * ends when it quits (`LocalSessionService` processes and agent browser windows,
201
+ * which the daemon's inventory cannot see).
202
+ *
203
+ * A daemon blocker whose id equals a server holder's ref is the same work seen twice:
204
+ * it is listed once, with the daemon's reason and the server's label. Whether the two
205
+ * ids are in fact comparable was never established (review §6.2 item 2), so a match
206
+ * only MERGES the wording and never hides a blocker that has no match.
207
+ */
208
+ export declare function describeBlockers(input: {
209
+ view?: GuidedViewLike | null;
210
+ daemon?: readonly DaemonBlockerLike[] | null;
211
+ desktop?: DesktopWorkLike | null;
212
+ }): OwnerBlocker[];
213
+ /**
214
+ * A string that changes whenever the set of things in the way changes. The "update
215
+ * now anyway" confirmation carries the one it was shown, and the action is refused
216
+ * when it no longer matches: a confirmation that names what WAS running is not a
217
+ * confirmation of what is.
218
+ */
219
+ export declare function blockersFingerprint(blockers: readonly OwnerBlocker[]): string;
220
+ /**
221
+ * The labels the owner is shown, as the server records them in the outcome
222
+ * (`acknowledged`): each bounded to the server's 160-character limit.
223
+ */
224
+ export declare function acknowledgedLabels(blockers: readonly OwnerBlocker[], max?: number): string[];
225
+ export interface HandoffBlocker {
226
+ kind: string;
227
+ id?: string;
228
+ reason: string;
229
+ }
230
+ export interface HandoffStatusLike {
231
+ protocolVersion: 1;
232
+ handoffId: string;
233
+ phase: 'ready' | 'deferred' | 'reconnecting' | 'verified' | 'failed' | 'rolled-back';
234
+ reason: string;
235
+ sourceProcessId: string;
236
+ sourceVersion: string;
237
+ target: {
238
+ path?: string;
239
+ mtimeMs?: number;
240
+ sha256: string;
241
+ };
242
+ blockers: HandoffBlocker[];
243
+ expectedSessions: unknown[];
244
+ adoptedSessionCount?: number;
245
+ verifiedBy?: {
246
+ processId: string;
247
+ version: string;
248
+ };
249
+ observer?: {
250
+ processId: string;
251
+ version: string;
252
+ buildMatches: boolean;
253
+ ready: boolean;
254
+ };
255
+ }
256
+ /**
257
+ * What a call to the daemon's loopback `/v1/update-handoff` came back as.
258
+ *
259
+ * - `absent`: a 404. The daemon answered and has no such endpoint: it predates the
260
+ * handoff (the installed 0.8.117 answers 404 to every path it does not serve). This
261
+ * is the ONLY reply that means "legacy". A refused connection is not.
262
+ * - `unauthorized`: the bootstrap secret was refused (it rotates when the daemon
263
+ * restarts). Re-read the bootstrap and try again.
264
+ * - `refused`: reachable, speaks the protocol, said no (409: no handoff owned, or the
265
+ * lease expired; 400; 413). A refusal is a value the caller shows.
266
+ * - `unreachable`: no bootstrap file, a connection error, a timeout, a malformed or
267
+ * unexpected body. Unknown: never `absent`, never `ready`.
268
+ */
269
+ export type HandoffReply = {
270
+ kind: 'ok';
271
+ status: HandoffStatusLike;
272
+ } | {
273
+ kind: 'absent';
274
+ } | {
275
+ kind: 'unauthorized';
276
+ } | {
277
+ kind: 'refused';
278
+ code?: string;
279
+ } | {
280
+ kind: 'unreachable';
281
+ };
282
+ export declare function classifyHandoffReply(input: {
283
+ /** `null` when no HTTP response arrived at all. */
284
+ statusCode: number | null;
285
+ /** The parsed JSON body, or `undefined` when there was none or it did not parse. */
286
+ body?: unknown;
287
+ }): HandoffReply;
288
+ export interface ReplacementEvidence {
289
+ /** The daemon's own answer to `status` for the handoff, or null when it did not answer. */
290
+ handoff: Pick<HandoffStatusLike, 'phase' | 'verifiedBy' | 'target' | 'reason' | 'observer'> | null;
291
+ expect: {
292
+ sourceProcessId: string;
293
+ targetSha256: string;
294
+ /** The bundled daemon's version, or null when it could not be read (the hash binds it anyway). */
295
+ version: string | null;
296
+ };
297
+ identity: {
298
+ recordedDaemonId: string;
299
+ recordedRuntimeKey: string;
300
+ /** The daemon id of the process now holding the loopback bootstrap, or null when unreadable. */
301
+ bootstrapDaemonId: string | null;
302
+ /** The runtimeKey the machine payload lists for `recordedDaemonId` now, or null when it lists none or could not be read. */
303
+ runtimeKeyNow: string | null;
304
+ };
305
+ }
306
+ export type ReplacementVerdict =
307
+ /** (1) the daemon's `verified` for this build by another process, and (2) the same identity. */
308
+ {
309
+ kind: 'verified';
310
+ } | {
311
+ kind: 'not_yet';
312
+ missing: 'daemon_status' | 'verified' | 'identity_unreadable';
313
+ }
314
+ /** The daemon id or the machine's runtimeKey changed: a reinstall. The hold is left and shown. */
315
+ | {
316
+ kind: 'reinstall';
317
+ what: 'daemon_id' | 'runtime_key';
318
+ } | {
319
+ kind: 'failed';
320
+ phase: 'failed' | 'rolled-back';
321
+ reason: string;
322
+ sameProcess: boolean;
323
+ };
324
+ /**
325
+ * Decide whether a committed replacement is complete. All of (1) and (2) must hold
326
+ * before anything else is asked of the server (3, {@link serverSawNewProcess}), and
327
+ * nothing here resumes: the verdict only says what was seen.
328
+ *
329
+ * An identity that is merely UNREADABLE (the bootstrap is mid-rotation, the machine
330
+ * payload could not be fetched) is `not_yet`, never a reinstall and never verified.
331
+ */
332
+ export declare function verifyReplacement(evidence: ReplacementEvidence): ReplacementVerdict;
333
+ export interface LegacyRestartEvidence {
334
+ before: {
335
+ startedAt: number | null;
336
+ processId: number | null;
337
+ };
338
+ after: {
339
+ daemonId: string | null;
340
+ version: string | null;
341
+ startedAt: number | null;
342
+ processId: number | null;
343
+ };
344
+ expect: {
345
+ daemonId: string;
346
+ version: string | null;
347
+ };
348
+ runtimeKeyNow: string | null;
349
+ recordedRuntimeKey: string;
350
+ }
351
+ /**
352
+ * The legacy counterpart: a daemon with no handoff cannot say `verified`, so the copy
353
+ * claims only what was seen ("restarted on version X"), never "adopted N sessions".
354
+ * A new process (a different start time and, where known, a different PID), the same
355
+ * identity, and the version it announces equal to the bundled one.
356
+ */
357
+ export declare function verifyLegacyRestart(evidence: LegacyRestartEvidence): ReplacementVerdict;
358
+ /**
359
+ * Whether the server independently saw a new process register under the held key
360
+ * (condition 3). The Journey says `back_held` for ANY process that registered since
361
+ * the fence, so it can only corroborate THIS replacement when it did not already say
362
+ * so before the commit. When it did, the answer is `not_independent`: the flow rests
363
+ * on (1) and (2) and says so.
364
+ */
365
+ export declare function serverSawNewProcess(input: {
366
+ journeyPhase: string | null | undefined;
367
+ backHeldAtCommit: boolean;
368
+ }): 'seen' | 'not_yet' | 'not_independent';
369
+ /** Whether an observed hold is the one this flow took, and still live. */
370
+ export declare function isOurLiveHold(view: GuidedViewLike | null | undefined, generation: number | null): boolean;
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var guidedUpdate_exports = {};
20
+ __export(guidedUpdate_exports, {
21
+ GUIDED_HANDOFF_PHASES: () => GUIDED_HANDOFF_PHASES,
22
+ GUIDED_REFUSALS: () => GUIDED_REFUSALS,
23
+ GUIDED_SERVER_SOURCES: () => GUIDED_SERVER_SOURCES,
24
+ MAX_OWNER_BLOCKERS: () => MAX_OWNER_BLOCKERS,
25
+ acknowledgedLabels: () => acknowledgedLabels,
26
+ blockersFingerprint: () => blockersFingerprint,
27
+ classifyHandoffReply: () => classifyHandoffReply,
28
+ describeBlockers: () => describeBlockers,
29
+ evaluateReadiness: () => evaluateReadiness,
30
+ isGuidedRefusal: () => isGuidedRefusal,
31
+ isOurLiveHold: () => isOurLiveHold,
32
+ legacyRestartAllowed: () => legacyRestartAllowed,
33
+ noServerVeto: () => noServerVeto,
34
+ prepareBasis: () => prepareBasis,
35
+ sanitizeBlockerText: () => sanitizeBlockerText,
36
+ serverSawNewProcess: () => serverSawNewProcess,
37
+ verifyLegacyRestart: () => verifyLegacyRestart,
38
+ verifyReplacement: () => verifyReplacement
39
+ });
40
+ module.exports = __toCommonJS(guidedUpdate_exports);
41
+ const GUIDED_SERVER_SOURCES = [
42
+ "claims",
43
+ "receipts",
44
+ "sessions",
45
+ "runs",
46
+ "leases",
47
+ "custody"
48
+ ];
49
+ const GUIDED_REFUSALS = [
50
+ "managed_machine",
51
+ "no_stable_identity",
52
+ "not_found",
53
+ "ambiguous",
54
+ "generation_conflict",
55
+ "not_held",
56
+ "already_held",
57
+ "attestation_not_applicable",
58
+ "not_owner",
59
+ "held_by_other"
60
+ ];
61
+ function isGuidedRefusal(value) {
62
+ return typeof value === "string" && GUIDED_REFUSALS.includes(value);
63
+ }
64
+ const GUIDED_HANDOFF_PHASES = [
65
+ "ready",
66
+ "deferred",
67
+ "reconnecting",
68
+ "verified",
69
+ "failed",
70
+ "rolled-back"
71
+ ];
72
+ function noServerVeto(sources) {
73
+ if (!Array.isArray(sources))
74
+ return false;
75
+ const list = sources;
76
+ for (const name of GUIDED_SERVER_SOURCES) {
77
+ const source = list.find((s) => s && s.source === name);
78
+ if (!source || source.read !== "ok" || source.truncated === true)
79
+ return false;
80
+ const holders = Array.isArray(source.holders) ? source.holders : null;
81
+ if (!holders)
82
+ return false;
83
+ if (holders.some((h) => h && (h.class === "active" || h.class === "unproven")))
84
+ return false;
85
+ }
86
+ const report = list.find((s) => s && s.source === "daemon_report");
87
+ return report !== void 0 && report.read === "not_announced";
88
+ }
89
+ function evaluateReadiness(view, expectedGeneration) {
90
+ const hold = view?.hold;
91
+ if (!view || !hold || hold.lifecycle !== "held")
92
+ return { kind: "not_held" };
93
+ if (expectedGeneration !== null && hold.generation !== expectedGeneration) {
94
+ return { kind: "generation_changed", currentGeneration: hold.generation };
95
+ }
96
+ if (view.journey?.phase === "pausing")
97
+ return { kind: "pausing" };
98
+ const reading = view.reading;
99
+ if (!reading)
100
+ return { kind: "unknown", cause: "source_unreadable" };
101
+ if (reading.state === "ready")
102
+ return { kind: "ready", basis: "evidence" };
103
+ if (reading.state === "draining")
104
+ return { kind: "draining" };
105
+ if (reading.state !== "unknown")
106
+ return { kind: "unknown", cause: "source_unreadable" };
107
+ if (view.journey?.phase === "ready" && view.journey.modifiers?.includes("attested")) {
108
+ return { kind: "ready", basis: "attested" };
109
+ }
110
+ if (reading.cause === "no_inventory_capability" && noServerVeto(reading.sources)) {
111
+ return { kind: "no_report" };
112
+ }
113
+ return { kind: "unknown", cause: reading.cause ?? null };
114
+ }
115
+ function prepareBasis(readiness, opts) {
116
+ if (opts.legacy)
117
+ return null;
118
+ if (readiness.kind === "ready")
119
+ return readiness.basis;
120
+ if (readiness.kind === "no_report")
121
+ return "no_veto";
122
+ return null;
123
+ }
124
+ function legacyRestartAllowed(readiness) {
125
+ return readiness.kind === "ready" && readiness.basis === "attested";
126
+ }
127
+ const MAX_OWNER_BLOCKERS = 20;
128
+ const BLOCKER_TEXT_MAX = 200;
129
+ const ID_PATTERN = /^[A-Za-z0-9_-]{1,120}$/;
130
+ const PATHLIKE = /(?:^|[\s("'=])(?:~|\.{1,2})?[\\/](?:[\w.-]+[\\/])+|[A-Za-z]:[\\/]|\\\\|file:\/\/|\/(?:Users|home|var|tmp|private|opt|etc|usr)\//i;
131
+ function sanitizeBlockerText(value, max = BLOCKER_TEXT_MAX) {
132
+ if (typeof value !== "string")
133
+ return void 0;
134
+ const cleaned = Array.from(value, (ch) => {
135
+ const code = ch.charCodeAt(0);
136
+ return code < 32 || code === 127 ? " " : ch;
137
+ }).join("").replace(/\s+/g, " ").trim();
138
+ if (!cleaned || PATHLIKE.test(cleaned))
139
+ return void 0;
140
+ return cleaned.length > max ? `${cleaned.slice(0, max - 1)}\u2026` : cleaned;
141
+ }
142
+ function boundedId(value) {
143
+ return typeof value === "string" && ID_PATTERN.test(value) ? value : void 0;
144
+ }
145
+ function describeBlockers(input) {
146
+ const out = [];
147
+ const serverByRef = /* @__PURE__ */ new Map();
148
+ const serverHolders = [];
149
+ for (const source of input.view?.reading?.sources ?? []) {
150
+ for (const holder of source?.holders ?? []) {
151
+ if (!holder || holder.class !== "active" && holder.class !== "unproven")
152
+ continue;
153
+ serverHolders.push(holder);
154
+ if (typeof holder.ref === "string")
155
+ serverByRef.set(holder.ref, holder);
156
+ }
157
+ }
158
+ const merged = /* @__PURE__ */ new Set();
159
+ for (const blocker of input.daemon ?? []) {
160
+ if (!blocker || typeof blocker.kind !== "string")
161
+ continue;
162
+ const id = boundedId(blocker.id);
163
+ const holder = blocker.id ? serverByRef.get(blocker.id) : void 0;
164
+ if (holder)
165
+ merged.add(holder);
166
+ const label = holder ? sanitizeBlockerText(holder.label, 120) : void 0;
167
+ out.push({
168
+ source: "daemon",
169
+ kind: blocker.kind.slice(0, 64),
170
+ text: sanitizeBlockerText(blocker.reason),
171
+ ...label ? { label } : {},
172
+ ...id ? { id } : {},
173
+ ...holder?.since !== void 0 ? { since: holder.since } : {}
174
+ });
175
+ }
176
+ for (const holder of serverHolders) {
177
+ if (merged.has(holder))
178
+ continue;
179
+ const id = boundedId(holder.ref);
180
+ out.push({
181
+ source: "server",
182
+ kind: String(holder.kind || "work").slice(0, 64),
183
+ text: sanitizeBlockerText(holder.label, 120),
184
+ ...id ? { id } : {},
185
+ ...holder.since !== void 0 ? { since: holder.since } : {}
186
+ });
187
+ }
188
+ const desktop = input.desktop;
189
+ if (desktop && desktop.localSessions > 0) {
190
+ out.push({ source: "desktop", kind: "desktop_local_sessions", count: desktop.localSessions });
191
+ }
192
+ if (desktop && desktop.agentBrowserWindows > 0) {
193
+ out.push({
194
+ source: "desktop",
195
+ kind: "desktop_agent_browser",
196
+ count: desktop.agentBrowserWindows
197
+ });
198
+ }
199
+ return out.slice(0, MAX_OWNER_BLOCKERS);
200
+ }
201
+ function blockersFingerprint(blockers) {
202
+ return blockers.map((b) => [b.source, b.kind, b.id ?? "", b.count ?? ""].join("|")).sort().join(";");
203
+ }
204
+ function acknowledgedLabels(blockers, max = 20) {
205
+ const labels = [];
206
+ for (const b of blockers) {
207
+ const detail = b.label ?? b.text;
208
+ const text = b.count ? `${b.kind} (${b.count})` : detail ? `${b.kind}: ${detail}` : b.kind;
209
+ labels.push(text.slice(0, 160));
210
+ if (labels.length >= max)
211
+ break;
212
+ }
213
+ return labels;
214
+ }
215
+ function isHandoffStatus(value) {
216
+ if (!value || typeof value !== "object")
217
+ return false;
218
+ const v = value;
219
+ return v.protocolVersion === 1 && typeof v.handoffId === "string" && typeof v.phase === "string" && GUIDED_HANDOFF_PHASES.includes(v.phase) && typeof v.sourceProcessId === "string" && !!v.target && typeof v.target.sha256 === "string" && Array.isArray(v.blockers) && Array.isArray(v.expectedSessions);
220
+ }
221
+ function classifyHandoffReply(input) {
222
+ const { statusCode, body } = input;
223
+ if (statusCode === null)
224
+ return { kind: "unreachable" };
225
+ if (statusCode === 200) {
226
+ return isHandoffStatus(body) ? { kind: "ok", status: body } : { kind: "unreachable" };
227
+ }
228
+ if (statusCode === 404)
229
+ return { kind: "absent" };
230
+ if (statusCode === 401 || statusCode === 403)
231
+ return { kind: "unauthorized" };
232
+ if (statusCode === 400 || statusCode === 409 || statusCode === 413 || statusCode === 405) {
233
+ const code = body && typeof body === "object" && typeof body.error === "string" ? String(body.error).slice(0, 64) : void 0;
234
+ return { kind: "refused", ...code ? { code } : {} };
235
+ }
236
+ return { kind: "unreachable" };
237
+ }
238
+ function verifyReplacement(evidence) {
239
+ const { handoff, expect, identity } = evidence;
240
+ if (!handoff)
241
+ return { kind: "not_yet", missing: "daemon_status" };
242
+ if (handoff.phase === "failed" || handoff.phase === "rolled-back") {
243
+ return {
244
+ kind: "failed",
245
+ phase: handoff.phase,
246
+ reason: String(handoff.reason || handoff.phase).slice(0, 64),
247
+ // A failed handoff observed by the SAME process is a replacement that never
248
+ // happened: the old daemon is still the one running, and a retry is meaningful.
249
+ sameProcess: handoff.observer?.processId === expect.sourceProcessId
250
+ };
251
+ }
252
+ if (handoff.phase !== "verified")
253
+ return { kind: "not_yet", missing: "verified" };
254
+ const by = handoff.verifiedBy;
255
+ if (!by || by.processId === expect.sourceProcessId || handoff.target.sha256 !== expect.targetSha256 || expect.version !== null && by.version !== expect.version) {
256
+ return { kind: "not_yet", missing: "verified" };
257
+ }
258
+ if (identity.bootstrapDaemonId === null || identity.runtimeKeyNow === null) {
259
+ return { kind: "not_yet", missing: "identity_unreadable" };
260
+ }
261
+ if (identity.bootstrapDaemonId !== identity.recordedDaemonId) {
262
+ return { kind: "reinstall", what: "daemon_id" };
263
+ }
264
+ if (identity.runtimeKeyNow !== identity.recordedRuntimeKey) {
265
+ return { kind: "reinstall", what: "runtime_key" };
266
+ }
267
+ return { kind: "verified" };
268
+ }
269
+ function verifyLegacyRestart(evidence) {
270
+ const { before, after, expect } = evidence;
271
+ if (after.daemonId === null || after.startedAt === null || evidence.runtimeKeyNow === null) {
272
+ return { kind: "not_yet", missing: "identity_unreadable" };
273
+ }
274
+ const newProcess = before.startedAt === null ? after.processId !== null && after.processId !== before.processId : after.startedAt > before.startedAt && (after.processId === null || before.processId === null || after.processId !== before.processId);
275
+ if (!newProcess)
276
+ return { kind: "not_yet", missing: "verified" };
277
+ if (after.daemonId !== expect.daemonId)
278
+ return { kind: "reinstall", what: "daemon_id" };
279
+ if (evidence.runtimeKeyNow !== evidence.recordedRuntimeKey) {
280
+ return { kind: "reinstall", what: "runtime_key" };
281
+ }
282
+ if (expect.version !== null && after.version !== expect.version) {
283
+ return { kind: "not_yet", missing: "verified" };
284
+ }
285
+ return { kind: "verified" };
286
+ }
287
+ function serverSawNewProcess(input) {
288
+ if (input.backHeldAtCommit)
289
+ return "not_independent";
290
+ return input.journeyPhase === "back_held" ? "seen" : "not_yet";
291
+ }
292
+ function isOurLiveHold(view, generation) {
293
+ return generation !== null && !!view?.hold && view.hold.lifecycle === "held" && view.hold.generation === generation;
294
+ }
295
+ // Annotate the CommonJS export names for ESM import in node:
296
+ 0 && (module.exports = {
297
+ GUIDED_HANDOFF_PHASES,
298
+ GUIDED_REFUSALS,
299
+ GUIDED_SERVER_SOURCES,
300
+ MAX_OWNER_BLOCKERS,
301
+ acknowledgedLabels,
302
+ blockersFingerprint,
303
+ classifyHandoffReply,
304
+ describeBlockers,
305
+ evaluateReadiness,
306
+ isGuidedRefusal,
307
+ isOurLiveHold,
308
+ legacyRestartAllowed,
309
+ noServerVeto,
310
+ prepareBasis,
311
+ sanitizeBlockerText,
312
+ serverSawNewProcess,
313
+ verifyLegacyRestart,
314
+ verifyReplacement
315
+ });