@astrosheep/keiyaku 4.1.0 → 4.1.2

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 (278) hide show
  1. package/README.md +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
  5. package/build/src/akuma/akuma-errors.d.ts +6 -0
  6. package/build/src/akuma/akuma-errors.js +9 -0
  7. package/build/src/akuma/akuma-handle.d.ts +39 -0
  8. package/build/src/akuma/akuma-handle.js +263 -0
  9. package/build/src/akuma/akuma-observe.d.ts +19 -0
  10. package/build/src/akuma/akuma-observe.js +74 -0
  11. package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
  12. package/build/src/akuma/akuma-product-symbols.js +1 -0
  13. package/build/src/akuma/akuma-product.d.ts +18 -0
  14. package/build/src/akuma/akuma-product.js +154 -0
  15. package/build/src/akuma/akuma.d.ts +37 -81
  16. package/build/src/akuma/akuma.js +39 -447
  17. package/build/src/akuma/allowed.d.ts +1 -0
  18. package/build/src/akuma/allowed.js +6 -0
  19. package/build/src/akuma/archetype.js +8 -5
  20. package/build/src/akuma/body-supervisor.d.ts +26 -0
  21. package/build/src/akuma/body-supervisor.js +89 -0
  22. package/build/src/akuma/body.d.ts +45 -4
  23. package/build/src/akuma/body.js +145 -35
  24. package/build/src/akuma/coordinate.js +17 -7
  25. package/build/src/akuma/heart/facts.js +1 -1
  26. package/build/src/akuma/heart/index.d.ts +1 -1
  27. package/build/src/akuma/heart/index.js +2 -4
  28. package/build/src/akuma/heart/request-authority.js +4 -4
  29. package/build/src/akuma/heart/request-rows.js +27 -16
  30. package/build/src/akuma/heart/rows.js +79 -41
  31. package/build/src/akuma/heart/soul.js +1 -1
  32. package/build/src/akuma/heart/storage.d.ts +1 -0
  33. package/build/src/akuma/heart/storage.js +76 -11
  34. package/build/src/akuma/heart/tells.js +35 -18
  35. package/build/src/akuma/heart/timeline.js +19 -11
  36. package/build/src/akuma/identity.d.ts +1 -0
  37. package/build/src/akuma/identity.js +1 -0
  38. package/build/src/akuma/index.d.ts +3 -3
  39. package/build/src/akuma/index.js +1 -1
  40. package/build/src/akuma/nuke.js +106 -14
  41. package/build/src/akuma/projection-read.d.ts +17 -0
  42. package/build/src/akuma/projection-read.js +135 -0
  43. package/build/src/akuma/projection.d.ts +1 -16
  44. package/build/src/akuma/projection.js +77 -154
  45. package/build/src/akuma/provider-recipe.js +11 -5
  46. package/build/src/akuma/provider.js +105 -62
  47. package/build/src/akuma/providers/acp/config.js +5 -6
  48. package/build/src/akuma/providers/acp/core.js +17 -10
  49. package/build/src/akuma/providers/acp/events.js +38 -29
  50. package/build/src/akuma/providers/acp/index.js +13 -9
  51. package/build/src/akuma/providers/claude/events.js +8 -12
  52. package/build/src/akuma/providers/claude/index.d.ts +1 -0
  53. package/build/src/akuma/providers/claude/index.js +55 -26
  54. package/build/src/akuma/providers/claude/input.js +6 -2
  55. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  56. package/build/src/akuma/providers/codex-app-server/index.js +25 -13
  57. package/build/src/akuma/providers/grok-build/index.js +22 -25
  58. package/build/src/akuma/providers/index.js +2 -18
  59. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  60. package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
  61. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  62. package/build/src/akuma/providers/pi/events.js +26 -19
  63. package/build/src/akuma/providers/pi/index.js +58 -40
  64. package/build/src/akuma/publication.js +9 -9
  65. package/build/src/akuma/request-execution.d.ts +6 -0
  66. package/build/src/akuma/request-execution.js +86 -0
  67. package/build/src/akuma/request-serve.d.ts +12 -1
  68. package/build/src/akuma/request-serve.js +19 -122
  69. package/build/src/akuma/request-wire.d.ts +2 -2
  70. package/build/src/akuma/request-wire.js +75 -102
  71. package/build/src/akuma/requests.js +2 -2
  72. package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
  73. package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
  74. package/build/src/akuma-body.js +6 -5
  75. package/build/src/body/amend.d.ts +4 -1
  76. package/build/src/body/amend.js +14 -6
  77. package/build/src/body/decode.js +2 -4
  78. package/build/src/body/envelope.js +2 -4
  79. package/build/src/body/region.d.ts +1 -2
  80. package/build/src/body/region.js +2 -70
  81. package/build/src/body/render.js +17 -12
  82. package/build/src/body/shape.js +1 -7
  83. package/build/src/cli/accepted.d.ts +1 -1
  84. package/build/src/cli/accepted.js +8 -1
  85. package/build/src/cli/commands/akuma-invoke.js +18 -6
  86. package/build/src/cli/commands/akuma.d.ts +0 -6
  87. package/build/src/cli/commands/akuma.js +11 -24
  88. package/build/src/cli/commands/amend.d.ts +2 -2
  89. package/build/src/cli/commands/amend.js +2 -4
  90. package/build/src/cli/commands/bind.d.ts +4 -4
  91. package/build/src/cli/commands/bind.js +16 -6
  92. package/build/src/cli/commands/contract-invoke.d.ts +25 -0
  93. package/build/src/cli/commands/contract-invoke.js +193 -0
  94. package/build/src/cli/commands/contract.d.ts +109 -10
  95. package/build/src/cli/commands/contract.js +339 -16
  96. package/build/src/cli/commands/install.d.ts +1 -1
  97. package/build/src/cli/commands/install.js +23 -15
  98. package/build/src/cli/commands/task-invoke.js +187 -67
  99. package/build/src/cli/commands/task-query.js +48 -24
  100. package/build/src/cli/commands/task.js +150 -38
  101. package/build/src/cli/coordinates.js +2 -4
  102. package/build/src/cli/invoke.js +92 -208
  103. package/build/src/cli/main.js +4 -2
  104. package/build/src/cli/parse.d.ts +3 -90
  105. package/build/src/cli/parse.js +27 -233
  106. package/build/src/cli/render/akuma-activity.d.ts +38 -0
  107. package/build/src/cli/render/akuma-activity.js +362 -0
  108. package/build/src/cli/render/akuma-tool-command.js +6 -7
  109. package/build/src/cli/render/akuma-tool.js +10 -8
  110. package/build/src/cli/render/akuma.d.ts +1 -1
  111. package/build/src/cli/render/akuma.js +61 -353
  112. package/build/src/cli/render/audit.js +5 -15
  113. package/build/src/cli/render/board.d.ts +1 -0
  114. package/build/src/cli/render/board.js +17 -0
  115. package/build/src/cli/render/catalog.js +81 -8
  116. package/build/src/cli/render/contract-history.d.ts +2 -0
  117. package/build/src/cli/render/contract-history.js +83 -0
  118. package/build/src/cli/render/contract-observation.d.ts +10 -0
  119. package/build/src/cli/render/contract-observation.js +58 -0
  120. package/build/src/cli/render/contract.d.ts +1 -2
  121. package/build/src/cli/render/contract.js +41 -142
  122. package/build/src/cli/render/kanshi.js +239 -215
  123. package/build/src/cli/render/receipt.js +2 -9
  124. package/build/src/cli/render/refusal.js +10 -15
  125. package/build/src/cli/render/region.js +22 -6
  126. package/build/src/cli/render/settings.js +4 -4
  127. package/build/src/cli/render/task.js +34 -14
  128. package/build/src/cli/render/terminal.js +16 -5
  129. package/build/src/cli/result.d.ts +3 -3
  130. package/build/src/cli/runtime.d.ts +6 -1
  131. package/build/src/cli/runtime.js +84 -63
  132. package/build/src/cli/selectors.js +2 -4
  133. package/build/src/cli/usage.js +6 -5
  134. package/build/src/contract-worktree.d.ts +1 -23
  135. package/build/src/contract-worktree.js +79 -155
  136. package/build/src/coordination/durable-file.js +7 -3
  137. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  138. package/build/src/core/facts/codec.js +7 -3
  139. package/build/src/core/facts/types.d.ts +1 -1
  140. package/build/src/core/subject.js +16 -9
  141. package/build/src/core/verbs/abandon.d.ts +1 -1
  142. package/build/src/core/verbs/abandon.js +1 -1
  143. package/build/src/core/verbs/amend.d.ts +1 -1
  144. package/build/src/core/verbs/amend.js +7 -7
  145. package/build/src/core/verbs/attestation.js +4 -1
  146. package/build/src/core/verbs/bind.d.ts +1 -1
  147. package/build/src/core/verbs/bind.js +1 -1
  148. package/build/src/core/verbs/placement.d.ts +1 -1
  149. package/build/src/core/verbs/placement.js +10 -8
  150. package/build/src/dispatch/index.js +8 -6
  151. package/build/src/duration.js +5 -1
  152. package/build/src/git/admission.js +5 -3
  153. package/build/src/git/hooks.d.ts +8 -0
  154. package/build/src/git/hooks.js +63 -14
  155. package/build/src/git/identity.js +1 -4
  156. package/build/src/git/integration.d.ts +2 -3
  157. package/build/src/git/integration.js +32 -39
  158. package/build/src/git/nuke.d.ts +1 -1
  159. package/build/src/git/nuke.js +110 -57
  160. package/build/src/git/observe.d.ts +13 -1
  161. package/build/src/git/observe.js +51 -44
  162. package/build/src/git/process.js +4 -2
  163. package/build/src/git/read-observation.js +10 -8
  164. package/build/src/git/reconcile.d.ts +22 -2
  165. package/build/src/git/reconcile.js +38 -274
  166. package/build/src/git/repository.d.ts +2 -0
  167. package/build/src/git/repository.js +13 -22
  168. package/build/src/git/scratch.d.ts +8 -5
  169. package/build/src/git/scratch.js +29 -2
  170. package/build/src/git/target-placement.d.ts +9 -10
  171. package/build/src/git/target-placement.js +59 -62
  172. package/build/src/git/tender.js +13 -46
  173. package/build/src/git/terminal-reconcile.d.ts +21 -0
  174. package/build/src/git/terminal-reconcile.js +278 -0
  175. package/build/src/git/terminal-seal.js +15 -12
  176. package/build/src/git/tree.js +5 -2
  177. package/build/src/git/workspace.d.ts +24 -2
  178. package/build/src/git/workspace.js +120 -16
  179. package/build/src/identity/coordinates.js +3 -1
  180. package/build/src/identity/selector.js +6 -3
  181. package/build/src/kanshi/fleet.d.ts +6 -0
  182. package/build/src/kanshi/fleet.js +27 -0
  183. package/build/src/kanshi/index.d.ts +1 -1
  184. package/build/src/kanshi/read.js +60 -48
  185. package/build/src/kanshi/report.d.ts +11 -23
  186. package/build/src/kanshi/select.js +25 -24
  187. package/build/src/library/address.d.ts +2 -1
  188. package/build/src/library/address.js +7 -8
  189. package/build/src/library/akuma-creation.js +20 -12
  190. package/build/src/library/audit.d.ts +0 -1
  191. package/build/src/library/audit.js +1 -2
  192. package/build/src/library/bind.d.ts +53 -5
  193. package/build/src/library/bind.js +98 -22
  194. package/build/src/library/catalog.d.ts +1 -0
  195. package/build/src/library/catalog.js +6 -3
  196. package/build/src/library/configuration.js +3 -1
  197. package/build/src/library/continuation.d.ts +15 -4
  198. package/build/src/library/continuation.js +24 -16
  199. package/build/src/library/contract-bind.d.ts +26 -0
  200. package/build/src/library/contract-bind.js +106 -0
  201. package/build/src/library/contract-operations.d.ts +77 -0
  202. package/build/src/library/contract-operations.js +130 -0
  203. package/build/src/library/contract-types.d.ts +95 -0
  204. package/build/src/library/contract-types.js +1 -0
  205. package/build/src/library/contract.d.ts +19 -154
  206. package/build/src/library/contract.js +46 -261
  207. package/build/src/library/fleet.d.ts +1 -1
  208. package/build/src/library/fleet.js +19 -11
  209. package/build/src/library/input.d.ts +2 -0
  210. package/build/src/library/input.js +14 -0
  211. package/build/src/library/keiyaku.d.ts +8 -7
  212. package/build/src/library/keiyaku.js +3 -3
  213. package/build/src/library/nuke.js +14 -5
  214. package/build/src/library/reconcile.d.ts +9 -4
  215. package/build/src/library/reconcile.js +30 -24
  216. package/build/src/library/refusal.d.ts +13 -5
  217. package/build/src/library/refusal.js +7 -0
  218. package/build/src/library/region.d.ts +8 -7
  219. package/build/src/library/region.js +31 -11
  220. package/build/src/library/repo.js +2 -2
  221. package/build/src/markdown/lex.js +9 -2
  222. package/build/src/markdown/parse.js +11 -7
  223. package/build/src/markdown/query.js +4 -2
  224. package/build/src/protocol/amend.js +3 -1
  225. package/build/src/protocol/attempt.d.ts +7 -3
  226. package/build/src/protocol/attempt.js +9 -5
  227. package/build/src/protocol/audit.d.ts +1 -1
  228. package/build/src/protocol/audit.js +4 -14
  229. package/build/src/protocol/bind.d.ts +19 -6
  230. package/build/src/protocol/bind.js +28 -13
  231. package/build/src/protocol/completion.d.ts +0 -1
  232. package/build/src/protocol/completion.js +1 -3
  233. package/build/src/protocol/deliver.d.ts +1 -3
  234. package/build/src/protocol/deliver.js +15 -39
  235. package/build/src/protocol/intent.d.ts +1 -0
  236. package/build/src/protocol/intent.js +9 -7
  237. package/build/src/protocol/operations.d.ts +3 -7
  238. package/build/src/protocol/operations.js +5 -3
  239. package/build/src/protocol/placement.d.ts +0 -1
  240. package/build/src/protocol/placement.js +6 -6
  241. package/build/src/protocol/read/observation.d.ts +11 -0
  242. package/build/src/protocol/read/observation.js +37 -0
  243. package/build/src/protocol/read/status.d.ts +23 -12
  244. package/build/src/protocol/read/status.js +90 -72
  245. package/build/src/protocol/reconcile.d.ts +1 -0
  246. package/build/src/protocol/reconcile.js +2 -3
  247. package/build/src/protocol/reintegrate.js +1 -1
  248. package/build/src/protocol/review.d.ts +0 -1
  249. package/build/src/protocol/review.js +15 -22
  250. package/build/src/protocol/run.d.ts +1 -0
  251. package/build/src/protocol/run.js +4 -5
  252. package/build/src/runtime/proc/launch.d.ts +33 -0
  253. package/build/src/runtime/proc/launch.js +98 -0
  254. package/build/src/runtime/proc/line-rpc.js +9 -3
  255. package/build/src/runtime/proc/run.d.ts +12 -6
  256. package/build/src/runtime/proc/run.js +78 -21
  257. package/build/src/runtime/proc/stdio.js +7 -10
  258. package/build/src/settings.js +6 -2
  259. package/build/src/settlement/holder.js +13 -10
  260. package/build/src/settlement/settle.js +39 -6
  261. package/build/src/task/board.js +12 -6
  262. package/build/src/task/compose.js +85 -22
  263. package/build/src/task/context.js +21 -8
  264. package/build/src/task/document.js +46 -10
  265. package/build/src/task/identity.js +5 -2
  266. package/build/src/task/index.d.ts +0 -1
  267. package/build/src/task/index.js +119 -34
  268. package/build/src/task/input.js +29 -7
  269. package/build/src/task/mutation.js +61 -19
  270. package/build/src/task/operations.d.ts +6 -1
  271. package/build/src/task/operations.js +83 -29
  272. package/build/src/task/query.js +55 -26
  273. package/build/src/task/store.d.ts +3 -1
  274. package/build/src/task/store.js +81 -17
  275. package/build/src/verification/execution.js +14 -11
  276. package/build/src/workspace-place.js +19 -7
  277. package/build/src/world.js +16 -6
  278. package/package.json +8 -3
@@ -1,7 +1,7 @@
1
1
  import { observeActiveContractWorld, observeContractsForAdmissionInObservationAt, observeDeliveryTargetAt, withContractReadObservationAt, } from "../../git/observe.js";
2
2
  import { decodeContractDocument } from "../../body/decode.js";
3
- import { observeTargetLag, observeWorkspace, worktreePath, } from "../../git/workspace.js";
4
- import { appointmentFor, readPlaceRegister, } from "../../workspace-place.js";
3
+ import { observeTargetLag, observeWorkspace, worktreePath } from "../../git/workspace.js";
4
+ import { appointmentFor, readPlaceRegister } from "../../workspace-place.js";
5
5
  import { gateReports } from "../../core/facts/gate.js";
6
6
  function titleFor(state) {
7
7
  try {
@@ -19,7 +19,7 @@ function phaseFor(state) {
19
19
  if (state.terminal?.kind === "abandoned")
20
20
  return "abandoned";
21
21
  if (state.delivery !== null)
22
- return "pending-delivery";
22
+ return "tendered";
23
23
  if (state.bound !== null)
24
24
  return "bound";
25
25
  return "waiting";
@@ -49,37 +49,32 @@ async function managedWorkspaceFacts(repository, state, register, targetObservat
49
49
  ]);
50
50
  return { appointed, workspaceObservation, targetLag };
51
51
  }
52
- async function hereWorkspaceFacts(repository, contractId, targetObservation, resolveHereWorkspace) {
53
- const resolved = resolveHereWorkspace === undefined
54
- ? { kind: "unappointed" }
55
- : await resolveHereWorkspace(contractId);
56
- if (resolved.kind === "failed") {
57
- return {
58
- appointed: undefined,
59
- workspaceObservation: { kind: "failed", diagnostic: resolved.diagnostic },
60
- targetLag: targetObservation === null ? { kind: "none" } : { kind: "unknown" },
61
- };
62
- }
63
- if (resolved.kind === "unappointed") {
64
- return {
65
- appointed: undefined,
66
- workspaceObservation: { kind: "unappointed" },
67
- targetLag: targetObservation === null ? { kind: "none" } : { kind: "unknown" },
68
- };
69
- }
70
- const [workspaceObservation, targetLag] = await Promise.all([
71
- observeWorkspace(repository, { kind: "here" }, resolved.path),
72
- observeTargetLag(repository, resolved.path, targetObservation?.head),
73
- ]);
74
- return { appointed: undefined, workspaceObservation, targetLag };
52
+ function afterEndpoint(state) {
53
+ if (state === undefined || state === null)
54
+ return { kind: "missing" };
55
+ if (state.terminal?.kind === "claimed")
56
+ return { kind: "claimed" };
57
+ if (state.terminal?.kind === "abandoned")
58
+ return { kind: "abandoned" };
59
+ return { kind: "active", phase: phaseFor(state) };
60
+ }
61
+ function afterEdges(state, endpoints) {
62
+ return state.terms.after.map((contractId) => ({
63
+ contractId,
64
+ endpoint: afterEndpoint(endpoints.get(contractId)),
65
+ }));
66
+ }
67
+ function reverseDependents(id, rows) {
68
+ return rows
69
+ .filter((row) => row.disposition === "active" && row.after.some((edge) => edge.contractId === id))
70
+ .map((row) => ({ contractId: row.id, phase: row.phase }))
71
+ .sort((left, right) => left.contractId.localeCompare(right.contractId));
75
72
  }
76
73
  async function rowFor(input) {
77
- const { repository, state, bindAt, lastJournalAt, targetObservation, register, resolveHereWorkspace } = input;
74
+ const { repository, state, bindAt, lastJournalAt, targetObservation, register, after, dependents } = input;
78
75
  const workspace = state.coordinates.workspace;
79
76
  const gates = gateReports(state);
80
- const { appointed, workspaceObservation, targetLag } = workspace === "worktree"
81
- ? await managedWorkspaceFacts(repository, state, register, targetObservation)
82
- : await hereWorkspaceFacts(repository, state.id, targetObservation, resolveHereWorkspace);
77
+ const { appointed, workspaceObservation, targetLag } = await managedWorkspaceFacts(repository, state, register, targetObservation);
83
78
  return {
84
79
  id: state.id,
85
80
  title: titleFor(state),
@@ -100,62 +95,85 @@ async function rowFor(input) {
100
95
  reports: gates.reports.map((report) => ({ gate: report.gate, current: report.current })),
101
96
  satisfied: gates.satisfied,
102
97
  },
98
+ after,
99
+ dependents,
103
100
  };
104
101
  }
102
+ async function afterEndpointMap(observation, known, ids) {
103
+ const missing = ids.filter((id) => !known.has(id));
104
+ if (missing.length === 0)
105
+ return known;
106
+ const extra = await observeContractsForAdmissionInObservationAt(observation, missing);
107
+ return new Map([...known, ...[...extra.journals].map(([id, record]) => [id, record.state])]);
108
+ }
105
109
  /** Build the Contract board from one immutable git observation. */
106
- export async function readContractBoard(observation, selected, resolveHereWorkspace) {
107
- if (selected !== undefined) {
108
- const contract = await readContractObservation(observation, selected, resolveHereWorkspace);
109
- return {
110
- root: observation.repository.primaryWorktree,
111
- state: observation.snapshot.commit,
112
- rows: contract.kind === "missing" ? [] : [contract.row],
113
- };
114
- }
110
+ export async function readContractBoard(observation, include) {
111
+ const observedAt = new Date().toISOString();
115
112
  const observed = await observeActiveContractWorld(observation);
113
+ const contracts = new Map(observed.contracts);
114
+ let endpoints = new Map(observed.eligibility);
115
+ if (include !== undefined && !contracts.has(include)) {
116
+ const extra = await observeContractsForAdmissionInObservationAt(observation, [include]);
117
+ const record = extra.journals.get(include);
118
+ if (record === undefined)
119
+ throw new Error(`missing requested Contract observation: ${include}`);
120
+ contracts.set(include, record);
121
+ endpoints.set(include, record.state);
122
+ if (record.state !== null) {
123
+ endpoints = new Map(await afterEndpointMap(observation, endpoints, record.state.terms.after));
124
+ }
125
+ }
116
126
  const register = await readPlaceRegister(observation.repository);
117
- const rows = [];
118
- for (const value of observed.contracts.values()) {
127
+ const projected = await Promise.all([...contracts.values()].flatMap((value) => {
119
128
  if (value.state === null)
120
- continue;
129
+ return [];
121
130
  const state = value.state;
122
- const bindAt = value.entries[0].at;
123
- const lastJournalAt = lastJournalAtFor(value.entries);
124
- rows.push(observeDeliveryTargetAt(observation, state).then((target) => rowFor({
125
- repository: observation.repository,
126
- state,
127
- bindAt,
128
- lastJournalAt,
129
- targetObservation: target,
130
- register,
131
- ...(resolveHereWorkspace === undefined ? {} : { resolveHereWorkspace }),
132
- })));
133
- }
134
- return { root: observation.repository.primaryWorktree, state: observed.snapshot, rows: await Promise.all(rows) };
131
+ return [
132
+ observeDeliveryTargetAt(observation, state).then((target) => rowFor({
133
+ repository: observation.repository,
134
+ state,
135
+ bindAt: value.entries[0].at,
136
+ lastJournalAt: lastJournalAtFor(value.entries),
137
+ targetObservation: target,
138
+ register,
139
+ after: afterEdges(state, endpoints),
140
+ dependents: [],
141
+ })),
142
+ ];
143
+ }));
144
+ const rows = projected.map((row) => ({ ...row, dependents: reverseDependents(row.id, projected) }));
145
+ return {
146
+ root: observation.repository.primaryWorktree,
147
+ state: observed.snapshot,
148
+ observedAt,
149
+ rows,
150
+ };
135
151
  }
136
152
  /** Observe one Contract and its target from one fresh ref epoch. */
137
- export async function readContractObservation(observation, id, resolveHereWorkspace) {
153
+ export async function readContractObservation(observation, id) {
138
154
  const observed = await observeContractsForAdmissionInObservationAt(observation, [id]);
139
155
  const record = observed.journals.get(id);
140
156
  if (record === undefined)
141
157
  throw new Error(`missing requested Contract observation: ${id}`);
142
158
  const state = record.state;
143
- return state === null
144
- ? { kind: "missing", id }
145
- : {
146
- kind: "present",
147
- row: await rowFor({
148
- repository: observation.repository,
149
- state,
150
- bindAt: record.entries[0].at,
151
- lastJournalAt: lastJournalAtFor(record.entries),
152
- targetObservation: await observeDeliveryTargetAt(observation, state),
153
- register: await readPlaceRegister(observation.repository),
154
- ...(resolveHereWorkspace === undefined ? {} : { resolveHereWorkspace }),
155
- }),
156
- };
159
+ if (state === null)
160
+ return { kind: "missing", id };
161
+ const endpoints = await afterEndpointMap(observation, new Map([[id, state]]), state.terms.after);
162
+ return {
163
+ kind: "present",
164
+ row: await rowFor({
165
+ repository: observation.repository,
166
+ state,
167
+ bindAt: record.entries[0].at,
168
+ lastJournalAt: lastJournalAtFor(record.entries),
169
+ targetObservation: await observeDeliveryTargetAt(observation, state),
170
+ register: await readPlaceRegister(observation.repository),
171
+ after: afterEdges(state, endpoints),
172
+ dependents: [],
173
+ }),
174
+ };
157
175
  }
158
176
  /** Observe one Contract and its target from one fresh ref epoch. */
159
- export async function readContractObservationAt(repository, channel, id, resolveHereWorkspace) {
160
- return withContractReadObservationAt(repository, channel, id, async (observation) => await readContractObservation(observation, id, resolveHereWorkspace));
177
+ export async function readContractObservationAt(repository, channel, id) {
178
+ return withContractReadObservationAt(repository, channel, id, async (observation) => await readContractObservation(observation, id));
161
179
  }
@@ -31,5 +31,6 @@ export declare function worldContractStates(input: Readonly<{
31
31
  export declare function reconcileAllOperation(input: Readonly<{
32
32
  scope: RepositoryScope;
33
33
  channel: GitDecodeChannel;
34
+ states: readonly ContractState[];
34
35
  }> & ReconcileOptions): Promise<RepoReconcileReport>;
35
36
  export {};
@@ -23,11 +23,10 @@ export async function reconcileOperation(input) {
23
23
  }
24
24
  export async function worldContractStates(input) {
25
25
  const observation = await withGitReadObservation(input.scope, input.channel, async (read) => await observeContractWorld(read));
26
- return [...observation.contracts.values()].flatMap((value) => value.state === null ? [] : [value.state]);
26
+ return [...observation.contracts.values()].flatMap((value) => (value.state === null ? [] : [value.state]));
27
27
  }
28
28
  export async function reconcileAllOperation(input) {
29
- const observation = await withGitReadObservation(input.scope, input.channel, async (read) => await observeContractWorld(read));
30
- const contracts = (await reconcileBatch(input.scope, input.channel, observation.contracts.keys(), {
29
+ const contracts = (await reconcileBatch(input.scope, input.channel, input.states.map((state) => state.id), {
31
30
  hooks: input.hooks,
32
31
  retryHooks: input.retryHooks,
33
32
  retainTerminalWorktree: input.retainTerminalWorktree ?? false,
@@ -1,5 +1,5 @@
1
1
  import { contractState } from "../core/facts/observation.js";
2
- import { decideReintegrate, } from "../core/verbs/reintegrate.js";
2
+ import { decideReintegrate } from "../core/verbs/reintegrate.js";
3
3
  import { materializeReintegrationSnapshot, persistedTender, planIntegration, } from "../git/integration.js";
4
4
  import { observeContractsForAdmissionAt } from "../git/observe.js";
5
5
  import { admitDecidedOffer, mintAttempts } from "./attempt.js";
@@ -19,7 +19,6 @@ export type ReviewValue = CompletionEvidence & Readonly<{
19
19
  export declare function prepareReview(repository: RepositoryScope, stage: Readonly<{
20
20
  contractId: import("../core/facts/types.js").ContractId;
21
21
  coordinates: ContractState["coordinates"];
22
- workspacePath?: string;
23
22
  }>): Promise<{
24
23
  kind: "prepared";
25
24
  data: Readonly<{
@@ -18,7 +18,6 @@ async function captureReviewableWorktree(repository, stage) {
18
18
  const tender = await captureTender(repository, {
19
19
  ...stage,
20
20
  ...(appointed === undefined ? {} : { place: appointed.place }),
21
- ...(stage.workspacePath === undefined ? {} : { workspacePath: stage.workspacePath }),
22
21
  });
23
22
  if (tender.kind === "refused")
24
23
  return tender;
@@ -59,30 +58,26 @@ async function reviewAttempt(input, attempt) {
59
58
  let preparation;
60
59
  let workspace;
61
60
  let tender;
62
- let workspacePath;
63
61
  if (state !== null) {
64
- workspacePath = state.terminal === null && state.coordinates.workspace === "here"
65
- ? await input.resolveHereWorkspace?.(state.id)
66
- : undefined;
67
62
  const prepared = await captureReviewableWorktree(input.scope, {
68
63
  contractId: state.id,
69
64
  coordinates: state.coordinates,
70
- ...(workspacePath === undefined ? {} : { workspacePath }),
71
65
  });
72
- preparation = prepared.kind === "refused"
73
- ? { kind: "refused", refusal: prepared.refusal }
74
- : {
75
- kind: "prepared",
76
- data: {
77
- gate: REVIEWED,
78
- subject: dependencyKeySet([
79
- { kind: "document", value: state.terms.document.key },
80
- { kind: "change", value: prepared.data.changeId },
81
- ]),
82
- verdict: input.verdict,
83
- ...(input.summary === undefined ? {} : { summary: input.summary }),
84
- },
85
- };
66
+ preparation =
67
+ prepared.kind === "refused"
68
+ ? { kind: "refused", refusal: prepared.refusal }
69
+ : {
70
+ kind: "prepared",
71
+ data: {
72
+ gate: REVIEWED,
73
+ subject: dependencyKeySet([
74
+ { kind: "document", value: state.terms.document.key },
75
+ { kind: "change", value: prepared.data.changeId },
76
+ ]),
77
+ verdict: input.verdict,
78
+ ...(input.summary === undefined ? {} : { summary: input.summary }),
79
+ },
80
+ };
86
81
  if (prepared.kind === "prepared") {
87
82
  workspace = prepared.data.workspace;
88
83
  tender = prepared.data.tender;
@@ -114,7 +109,6 @@ async function reviewAttempt(input, attempt) {
114
109
  value: {
115
110
  ...(workspace === undefined ? {} : { workspace }),
116
111
  ...(tender === undefined ? {} : { tender }),
117
- ...(workspacePath === undefined ? {} : { workspacePath }),
118
112
  },
119
113
  };
120
114
  return admission;
@@ -150,7 +144,6 @@ export async function reviewOperation(input) {
150
144
  verification: derivation?.verification ?? { kind: "prepared", data: null },
151
145
  initial: review,
152
146
  verifyInitial: false,
153
- ...(review.value.workspacePath === undefined ? {} : { hereWorkspacePath: review.value.workspacePath }),
154
147
  });
155
148
  return admitted(completed.admission, reviewValue(review.value, completed.evidence));
156
149
  }
@@ -35,6 +35,7 @@ export type RunProtocolInput<Input extends Readonly<{
35
35
  extendAttempt?: (attempt: AttemptContext, observedContractCount: number) => AttemptContext;
36
36
  /** Add opaque companions from the exact immutable observation for this attempt. */
37
37
  decorateOffer?: CompanionDecorator;
38
+ validateAdmission?: (observation: GitDecisionObservation) => Refusal | undefined | Promise<Refusal | undefined>;
38
39
  observationSelection?: GitTreeSelection;
39
40
  }> & (Readonly<{
40
41
  input: Input;
@@ -1,4 +1,4 @@
1
- import { extendAdmissionPathsAt, observeContractsForAdmissionAt, } from "../git/observe.js";
1
+ import { extendAdmissionPathsAt, observeContractsForAdmissionAt } from "../git/observe.js";
2
2
  import { admitDecidedOffer } from "./attempt.js";
3
3
  /** Form one decided offer without admitting or reinterpreting it. */
4
4
  export async function prepareProtocolAttempt(input, baseAttempt) {
@@ -11,9 +11,7 @@ export async function prepareProtocolAttempt(input, baseAttempt) {
11
11
  : { kind: "prepared", input: input.input, assertions: [] };
12
12
  if (preparedInput.kind === "refused")
13
13
  return preparedInput;
14
- const attempt = input.extendAttempt === undefined
15
- ? baseAttempt
16
- : input.extendAttempt(baseAttempt, observation.size);
14
+ const attempt = input.extendAttempt === undefined ? baseAttempt : input.extendAttempt(baseAttempt, observation.size);
17
15
  const decision = input.decide({ input: preparedInput.input, attempt, observation });
18
16
  if (decision.kind === "refused")
19
17
  return decision;
@@ -54,8 +52,9 @@ export async function runProtocol(input) {
54
52
  offer: prepared.offer,
55
53
  primaryContract: input.input.contractId,
56
54
  assertions: prepared.assertions,
55
+ ...(input.validateAdmission === undefined ? {} : { validateAdmission: input.validateAdmission }),
57
56
  });
58
- if (result.kind === "accepted" || result.kind === "publication-failed")
57
+ if (result.kind === "accepted" || result.kind === "publication-failed" || result.kind === "refused")
59
58
  return result;
60
59
  if (result.kind === "collision" && index + 1 === attempts.length)
61
60
  return result;
@@ -0,0 +1,33 @@
1
+ import { type ChildProcess } from "node:child_process";
2
+ export type LaunchIntent = "handoff" | "retained";
3
+ export type DetachedProcessInput = Readonly<{
4
+ argv: readonly string[];
5
+ cwd: string;
6
+ env?: NodeJS.ProcessEnv;
7
+ log: string;
8
+ }>;
9
+ export type SpawnLaunchPolicy = Readonly<{
10
+ kind: "spawn";
11
+ detached: boolean;
12
+ windowsHide: true;
13
+ shell: false;
14
+ }>;
15
+ export type PlatformLaunchPolicy = Readonly<{
16
+ kind: "windows-launcher";
17
+ }> | SpawnLaunchPolicy;
18
+ export declare function platformLaunchPolicy(intent: LaunchIntent, platform?: NodeJS.Platform): PlatformLaunchPolicy;
19
+ export declare function spawnOptionsFor<Stdio>(intent: LaunchIntent, input: Readonly<{
20
+ cwd?: string;
21
+ env?: NodeJS.ProcessEnv;
22
+ }>, stdio: Stdio, platform?: NodeJS.Platform): Readonly<{
23
+ cwd: string | undefined;
24
+ env: NodeJS.ProcessEnv | undefined;
25
+ detached: boolean;
26
+ stdio: Stdio;
27
+ windowsHide: true;
28
+ shell: false;
29
+ }>;
30
+ export declare function windowsLauncherPath(): string;
31
+ export declare function spawnLoggedProcess(input: DetachedProcessInput, intent: LaunchIntent): Promise<ChildProcess>;
32
+ export declare function handoffWindowsLaunch(input: DetachedProcessInput, launcher?: string): Promise<void>;
33
+ export declare function handoffProcess(input: DetachedProcessInput): Promise<void>;
@@ -0,0 +1,98 @@
1
+ import { spawn } from "node:child_process";
2
+ import { open } from "node:fs/promises";
3
+ import { resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ export function platformLaunchPolicy(intent, platform = process.platform) {
6
+ if (platform === "win32" && intent === "handoff")
7
+ return { kind: "windows-launcher" };
8
+ return {
9
+ kind: "spawn",
10
+ detached: platform !== "win32",
11
+ windowsHide: true,
12
+ shell: false,
13
+ };
14
+ }
15
+ export function spawnOptionsFor(intent, input, stdio, platform = process.platform) {
16
+ const policy = platformLaunchPolicy(intent, platform);
17
+ if (policy.kind !== "spawn")
18
+ throw new Error("Windows Body handoff uses the GUI launcher");
19
+ return {
20
+ cwd: input.cwd,
21
+ env: input.env,
22
+ detached: policy.detached,
23
+ stdio,
24
+ windowsHide: policy.windowsHide,
25
+ shell: policy.shell,
26
+ };
27
+ }
28
+ export function windowsLauncherPath() {
29
+ const sourcePath = fileURLToPath(new URL("./windows-launch.exe", import.meta.url));
30
+ if (process.platform === "win32" && !/[\\/]build[\\/]/u.test(sourcePath)) {
31
+ return resolve(sourcePath, "../../../../build/src/runtime/proc/windows-launch.exe");
32
+ }
33
+ return sourcePath;
34
+ }
35
+ function launchFailure(command, diagnostic) {
36
+ const error = new Error(diagnostic.length > 0 ? diagnostic : `spawn ${command} UNKNOWN`);
37
+ const code = /\b(?:ENOENT|EACCES|EINVAL)\b/.exec(error.message)?.[0];
38
+ if (code)
39
+ error.code = code;
40
+ error.syscall = "spawn";
41
+ error.path = command;
42
+ return error;
43
+ }
44
+ async function waitSpawned(child) {
45
+ await new Promise((resolve, reject) => {
46
+ child.once("spawn", resolve);
47
+ child.once("error", reject);
48
+ });
49
+ if (child.pid === undefined)
50
+ throw new Error("detached process spawned without a pid");
51
+ }
52
+ export async function spawnLoggedProcess(input, intent) {
53
+ const log = await open(input.log, "a");
54
+ try {
55
+ const child = spawn(input.argv[0], input.argv.slice(1), spawnOptionsFor(intent, input, ["ignore", log.fd, log.fd]));
56
+ await waitSpawned(child);
57
+ return child;
58
+ }
59
+ finally {
60
+ await log.close();
61
+ }
62
+ }
63
+ export async function handoffWindowsLaunch(input, launcher = windowsLauncherPath()) {
64
+ const child = spawn(launcher, [input.log, ...input.argv], {
65
+ cwd: input.cwd,
66
+ env: input.env,
67
+ stdio: ["ignore", "ignore", "pipe"],
68
+ windowsHide: true,
69
+ shell: false,
70
+ });
71
+ let stderr = "";
72
+ child.stderr?.setEncoding("utf8");
73
+ child.stderr?.on("data", (chunk) => {
74
+ stderr = `${stderr}${chunk}`.slice(-4_000);
75
+ });
76
+ const closed = new Promise((resolve) => {
77
+ child.once("close", (exitCode) => resolve(exitCode));
78
+ });
79
+ try {
80
+ await waitSpawned(child);
81
+ }
82
+ catch (error) {
83
+ throw error instanceof Error ? error : new Error(String(error));
84
+ }
85
+ const code = await closed;
86
+ if (code === 0)
87
+ return;
88
+ throw launchFailure(input.argv[0] ?? launcher, stderr.trim());
89
+ }
90
+ export async function handoffProcess(input) {
91
+ const policy = platformLaunchPolicy("handoff");
92
+ if (policy.kind === "windows-launcher") {
93
+ await handoffWindowsLaunch(input);
94
+ return;
95
+ }
96
+ const child = await spawnLoggedProcess(input, "handoff");
97
+ child.unref();
98
+ }
@@ -24,9 +24,15 @@ export class LineRpcProcess {
24
24
  this.fail(new Error(`line RPC process exited${exit.code === null ? "" : ` with code ${exit.code}`}`));
25
25
  });
26
26
  }
27
- onNotification(listener) { this.notifications.add(listener); }
28
- onServerRequest(listener) { this.serverRequests.add(listener); }
29
- onExit(listener) { void this.process.exited.then(listener); }
27
+ onNotification(listener) {
28
+ this.notifications.add(listener);
29
+ }
30
+ onServerRequest(listener) {
31
+ this.serverRequests.add(listener);
32
+ }
33
+ onExit(listener) {
34
+ void this.process.exited.then(listener);
35
+ }
30
36
  consume(chunk) {
31
37
  this.stdout += chunk;
32
38
  for (;;) {
@@ -1,4 +1,6 @@
1
1
  import { type ChildProcess } from "node:child_process";
2
+ import { type DetachedProcessInput } from "./launch.js";
3
+ export { handoffProcess, type DetachedProcessInput } from "./launch.js";
2
4
  type ProcessLaunch = Readonly<{
3
5
  readonly argv: readonly string[];
4
6
  readonly cwd?: string;
@@ -37,14 +39,19 @@ export type ProcessConsumption = Readonly<{
37
39
  readonly outcome: ProcessOutcome | ProcessStreamError;
38
40
  readonly pid: number | null;
39
41
  }>;
40
- export type DetachedProcessInput = Readonly<{
41
- argv: readonly string[];
42
- cwd: string;
43
- env?: NodeJS.ProcessEnv;
44
- log: string;
42
+ export type RunLogReference = Readonly<{
43
+ path: string;
44
+ from: number;
45
+ to: number;
46
+ }>;
47
+ export type DetachedProcessExit = Readonly<{
48
+ code: number | null;
49
+ signal: NodeJS.Signals | null;
50
+ log: RunLogReference;
45
51
  }>;
46
52
  export type OwnedProcess = Readonly<{
47
53
  pid: number;
54
+ exited: Promise<DetachedProcessExit>;
48
55
  terminate(force?: boolean): Promise<void>;
49
56
  release(): void;
50
57
  }>;
@@ -54,4 +61,3 @@ export declare function runProcess(input: ProcessInput): Promise<ProcessOutcome>
54
61
  export declare function runCrossPlatformProcess(input: ProcessInput): Promise<ProcessOutcome>;
55
62
  export declare function runProcessToExit(input: ProcessLaunch): Promise<ProcessOutcome>;
56
63
  export declare function consumeProcessStdout(input: ProcessInput, consume: (chunk: Buffer) => void): Promise<ProcessConsumption>;
57
- export {};