@astrosheep/keiyaku 4.0.0 → 4.0.1

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 (241) hide show
  1. package/README.md +2 -9
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +11 -3
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +9 -6
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +94 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +162 -45
  12. package/build/src/akuma/akuma.d.ts +33 -25
  13. package/build/src/akuma/akuma.js +93 -61
  14. package/build/src/akuma/archetype.d.ts +8 -0
  15. package/build/src/akuma/archetype.js +28 -9
  16. package/build/src/akuma/body.js +196 -84
  17. package/build/src/akuma/coordinate.d.ts +9 -0
  18. package/build/src/akuma/coordinate.js +22 -0
  19. package/build/src/akuma/heart/facts.d.ts +67 -15
  20. package/build/src/akuma/heart/facts.js +3 -3
  21. package/build/src/akuma/heart/index.d.ts +41 -29
  22. package/build/src/akuma/heart/index.js +72 -193
  23. package/build/src/akuma/heart/rows.d.ts +30 -53
  24. package/build/src/akuma/heart/rows.js +91 -111
  25. package/build/src/akuma/heart/schema.d.ts +1 -1
  26. package/build/src/akuma/heart/schema.js +55 -8
  27. package/build/src/akuma/heart/storage.d.ts +33 -0
  28. package/build/src/akuma/heart/storage.js +164 -0
  29. package/build/src/akuma/heart/tells.d.ts +12 -0
  30. package/build/src/akuma/heart/tells.js +79 -0
  31. package/build/src/akuma/heart/timeline.d.ts +15 -0
  32. package/build/src/akuma/heart/timeline.js +86 -0
  33. package/build/src/akuma/index.d.ts +4 -2
  34. package/build/src/akuma/index.js +1 -1
  35. package/build/src/akuma/projection.d.ts +97 -0
  36. package/build/src/akuma/projection.js +145 -0
  37. package/build/src/akuma/provider.d.ts +57 -11
  38. package/build/src/akuma/provider.js +57 -37
  39. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  40. package/build/src/akuma/providers/claude/events.js +185 -0
  41. package/build/src/akuma/providers/claude/index.d.ts +46 -0
  42. package/build/src/akuma/providers/claude/index.js +265 -0
  43. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  44. package/build/src/akuma/providers/claude/input.js +109 -0
  45. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  46. package/build/src/akuma/providers/codex-app-server/events.js +12 -12
  47. package/build/src/akuma/providers/codex-app-server/index.d.ts +13 -11
  48. package/build/src/akuma/providers/codex-app-server/index.js +73 -22
  49. package/build/src/akuma/providers/index.js +22 -8
  50. package/build/src/akuma/providers/opencode-sdk/events.d.ts +48 -0
  51. package/build/src/akuma/providers/opencode-sdk/events.js +116 -0
  52. package/build/src/akuma/providers/opencode-sdk/index.d.ts +32 -0
  53. package/build/src/akuma/providers/opencode-sdk/index.js +203 -0
  54. package/build/src/akuma/providers/opencode-sdk/session.d.ts +41 -0
  55. package/build/src/akuma/providers/opencode-sdk/session.js +62 -0
  56. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  57. package/build/src/akuma/providers/pi/events.js +128 -0
  58. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  59. package/build/src/akuma/providers/pi/index.js +162 -0
  60. package/build/src/akuma/requests.d.ts +1 -0
  61. package/build/src/akuma/requests.js +5 -2
  62. package/build/src/alias/index.d.ts +4 -3
  63. package/build/src/alias/index.js +2 -3
  64. package/build/src/body/render.js +2 -1
  65. package/build/src/body/shape.js +7 -1
  66. package/build/src/body/verification.js +19 -4
  67. package/build/src/cli/accepted.d.ts +2 -0
  68. package/build/src/cli/accepted.js +2 -1
  69. package/build/src/cli/commands/akuma-invoke.d.ts +42 -18
  70. package/build/src/cli/commands/akuma-invoke.js +94 -50
  71. package/build/src/cli/commands/akuma.d.ts +15 -7
  72. package/build/src/cli/commands/akuma.js +94 -56
  73. package/build/src/cli/commands/contract.d.ts +142 -0
  74. package/build/src/cli/commands/contract.js +14 -0
  75. package/build/src/cli/commands/install.js +2 -0
  76. package/build/src/cli/commands/task-invoke.d.ts +3 -1
  77. package/build/src/cli/commands/task-invoke.js +27 -2
  78. package/build/src/cli/commands/task.js +2 -2
  79. package/build/src/cli/invoke.d.ts +6 -1
  80. package/build/src/cli/invoke.js +241 -43
  81. package/build/src/cli/main.js +20 -1
  82. package/build/src/cli/parse.d.ts +13 -116
  83. package/build/src/cli/parse.js +51 -78
  84. package/build/src/cli/render/akuma-tool.d.ts +2 -0
  85. package/build/src/cli/render/akuma-tool.js +6 -2
  86. package/build/src/cli/render/akuma.d.ts +2 -1
  87. package/build/src/cli/render/akuma.js +157 -217
  88. package/build/src/cli/render/catalog.d.ts +2 -0
  89. package/build/src/cli/render/catalog.js +16 -0
  90. package/build/src/cli/render/contract.d.ts +1 -1
  91. package/build/src/cli/render/contract.js +38 -5
  92. package/build/src/cli/render/kanshi.js +53 -5
  93. package/build/src/cli/render/refusal.js +17 -0
  94. package/build/src/cli/render/terminal.d.ts +13 -0
  95. package/build/src/cli/render/terminal.js +75 -0
  96. package/build/src/cli/render/text.js +5 -0
  97. package/build/src/cli/result.d.ts +15 -3
  98. package/build/src/contract-worktree.d.ts +43 -0
  99. package/build/src/contract-worktree.js +213 -0
  100. package/build/src/coordination/durable-file.d.ts +3 -0
  101. package/build/src/coordination/durable-file.js +44 -1
  102. package/build/src/core/facts/codec.js +23 -4
  103. package/build/src/core/facts/eligibility.d.ts +1 -10
  104. package/build/src/core/facts/eligibility.js +0 -49
  105. package/build/src/core/facts/observation.d.ts +3 -0
  106. package/build/src/core/facts/observation.js +12 -0
  107. package/build/src/core/facts/types.d.ts +10 -3
  108. package/build/src/core/subject.js +2 -2
  109. package/build/src/core/verbs/amend.js +12 -16
  110. package/build/src/core/verbs/bind.js +2 -16
  111. package/build/src/core/verbs/deliver.js +20 -4
  112. package/build/src/core/verbs/placement.js +3 -8
  113. package/build/src/dispatch/index.d.ts +3 -1
  114. package/build/src/dispatch/index.js +14 -5
  115. package/build/src/duration.d.ts +10 -0
  116. package/build/src/duration.js +22 -0
  117. package/build/src/git/admission.d.ts +2 -2
  118. package/build/src/git/admission.js +26 -16
  119. package/build/src/git/hooks.d.ts +15 -0
  120. package/build/src/git/hooks.js +57 -5
  121. package/build/src/git/identity.d.ts +5 -1
  122. package/build/src/git/identity.js +23 -4
  123. package/build/src/git/integration.d.ts +49 -0
  124. package/build/src/git/integration.js +214 -0
  125. package/build/src/git/observe.d.ts +25 -13
  126. package/build/src/git/observe.js +175 -72
  127. package/build/src/git/read-observation.d.ts +41 -0
  128. package/build/src/git/read-observation.js +361 -0
  129. package/build/src/git/reconcile.d.ts +15 -5
  130. package/build/src/git/reconcile.js +238 -85
  131. package/build/src/git/repository.d.ts +19 -4
  132. package/build/src/git/repository.js +77 -43
  133. package/build/src/git/scratch.d.ts +13 -0
  134. package/build/src/git/scratch.js +66 -0
  135. package/build/src/git/target-placement.d.ts +56 -0
  136. package/build/src/git/target-placement.js +255 -0
  137. package/build/src/git/tender.d.ts +48 -0
  138. package/build/src/git/tender.js +82 -0
  139. package/build/src/git/terminal-seal.d.ts +24 -0
  140. package/build/src/git/terminal-seal.js +87 -0
  141. package/build/src/git/tree.d.ts +2 -2
  142. package/build/src/git/tree.js +4 -0
  143. package/build/src/git/workspace.d.ts +21 -0
  144. package/build/src/git/workspace.js +104 -0
  145. package/build/src/identity/selector.d.ts +6 -0
  146. package/build/src/identity/selector.js +19 -0
  147. package/build/src/index.d.ts +4 -2
  148. package/build/src/index.js +2 -1
  149. package/build/src/kanshi/index.d.ts +1 -1
  150. package/build/src/kanshi/read.d.ts +5 -2
  151. package/build/src/kanshi/read.js +154 -45
  152. package/build/src/kanshi/report.d.ts +31 -6
  153. package/build/src/kanshi/select.js +1 -1
  154. package/build/src/library/address.d.ts +48 -0
  155. package/build/src/library/address.js +134 -0
  156. package/build/src/library/akuma-creation.d.ts +10 -6
  157. package/build/src/library/akuma-creation.js +12 -11
  158. package/build/src/library/bind.d.ts +21 -0
  159. package/build/src/library/bind.js +56 -0
  160. package/build/src/library/catalog.d.ts +58 -0
  161. package/build/src/library/catalog.js +72 -0
  162. package/build/src/library/configuration.d.ts +6 -15
  163. package/build/src/library/configuration.js +14 -17
  164. package/build/src/library/contract.d.ts +21 -46
  165. package/build/src/library/contract.js +193 -183
  166. package/build/src/library/delivery.d.ts +23 -0
  167. package/build/src/library/delivery.js +21 -0
  168. package/build/src/library/fleet.d.ts +65 -0
  169. package/build/src/library/fleet.js +189 -0
  170. package/build/src/library/input.d.ts +3 -0
  171. package/build/src/library/input.js +19 -0
  172. package/build/src/library/keiyaku.d.ts +16 -2
  173. package/build/src/library/keiyaku.js +11 -1
  174. package/build/src/library/mutation.d.ts +38 -0
  175. package/build/src/library/mutation.js +39 -0
  176. package/build/src/library/refusal.d.ts +21 -0
  177. package/build/src/library/refusal.js +29 -0
  178. package/build/src/library/region.d.ts +2 -1
  179. package/build/src/library/region.js +3 -3
  180. package/build/src/library/repo.d.ts +4 -1
  181. package/build/src/library/repo.js +31 -16
  182. package/build/src/protocol/attempt.d.ts +16 -3
  183. package/build/src/protocol/attempt.js +39 -8
  184. package/build/src/protocol/bind.d.ts +9 -2
  185. package/build/src/protocol/bind.js +47 -39
  186. package/build/src/protocol/intent.d.ts +42 -18
  187. package/build/src/protocol/intent.js +36 -75
  188. package/build/src/protocol/operations.d.ts +93 -35
  189. package/build/src/protocol/operations.js +235 -123
  190. package/build/src/protocol/outcome.d.ts +7 -2
  191. package/build/src/protocol/outcome.js +9 -3
  192. package/build/src/protocol/placement.d.ts +30 -0
  193. package/build/src/protocol/placement.js +114 -0
  194. package/build/src/protocol/read/audit.d.ts +9 -3
  195. package/build/src/protocol/read/audit.js +25 -9
  196. package/build/src/protocol/read/documents.d.ts +2 -2
  197. package/build/src/protocol/read/documents.js +4 -4
  198. package/build/src/protocol/read/status.d.ts +11 -5
  199. package/build/src/protocol/read/status.js +28 -15
  200. package/build/src/protocol/run.d.ts +49 -7
  201. package/build/src/protocol/run.js +53 -25
  202. package/build/src/runtime/proc/line-rpc.d.ts +1 -0
  203. package/build/src/runtime/proc/line-rpc.js +21 -0
  204. package/build/src/runtime/proc/run.d.ts +18 -2
  205. package/build/src/runtime/proc/run.js +34 -8
  206. package/build/src/settings.d.ts +6 -0
  207. package/build/src/settings.js +29 -14
  208. package/build/src/settlement/fence.d.ts +9 -0
  209. package/build/src/settlement/fence.js +23 -0
  210. package/build/src/settlement/holder.d.ts +25 -4
  211. package/build/src/settlement/holder.js +102 -28
  212. package/build/src/settlement/settle.d.ts +8 -0
  213. package/build/src/settlement/settle.js +102 -28
  214. package/build/src/task/board.d.ts +20 -2
  215. package/build/src/task/board.js +11 -1
  216. package/build/src/task/compose.d.ts +2 -2
  217. package/build/src/task/compose.js +2 -2
  218. package/build/src/task/context.js +2 -7
  219. package/build/src/task/index.d.ts +9 -9
  220. package/build/src/task/index.js +15 -12
  221. package/build/src/task/operations.d.ts +31 -12
  222. package/build/src/task/operations.js +8 -4
  223. package/build/src/task/store.d.ts +4 -6
  224. package/build/src/task/store.js +3 -3
  225. package/build/src/verification/declaration.d.ts +1 -0
  226. package/build/src/verification/execution.d.ts +49 -0
  227. package/build/src/verification/execution.js +104 -0
  228. package/build/src/world.d.ts +13 -0
  229. package/build/src/world.js +103 -0
  230. package/package.json +7 -4
  231. package/build/src/akuma/activity.d.ts +0 -66
  232. package/build/src/akuma/activity.js +0 -139
  233. package/build/src/akuma/providers/claude.js +0 -305
  234. package/build/src/context-root.d.ts +0 -4
  235. package/build/src/context-root.js +0 -15
  236. package/build/src/git/delivery.d.ts +0 -20
  237. package/build/src/git/delivery.js +0 -109
  238. package/build/src/git/verification.d.ts +0 -14
  239. package/build/src/git/verification.js +0 -56
  240. package/build/src/verification/producer.d.ts +0 -23
  241. package/build/src/verification/producer.js +0 -54
@@ -0,0 +1,114 @@
1
+ import { SqliteTransactionLockError } from "../coordination/sqlite-transaction-lock.js";
2
+ import { AuthorityCorruptionError } from "../core/facts/errors.js";
3
+ import { contractState } from "../core/facts/observation.js";
4
+ import { decidePlacement } from "../core/verbs/placement.js";
5
+ import { reconcileEffectFailure } from "../git/reconcile.js";
6
+ import { GitPlumbingError } from "../git/repository.js";
7
+ import { acquireTargetPlacementFence, followTargetPlacement, prepareTargetPlacement, observeTargetHead, } from "../git/target-placement.js";
8
+ import { admitDecidedOffer, mintAttempts } from "./attempt.js";
9
+ import { prepareProtocolAttempt, runProtocol, } from "./run.js";
10
+ function placementFailure(error) {
11
+ return { kind: "placement-failed", diagnostic: error instanceof Error ? error.message : String(error) };
12
+ }
13
+ function expectedPlacementFailure(error) {
14
+ if (error instanceof GitPlumbingError || error instanceof SqliteTransactionLockError)
15
+ return placementFailure(error);
16
+ throw error;
17
+ }
18
+ async function runFencedPlacement(repository, input, protocol) {
19
+ for (let index = 0; index < protocol.attempts.length; index += 1) {
20
+ const prepared = await prepareProtocolAttempt(protocol, protocol.attempts[index]);
21
+ if (prepared.kind === "refused")
22
+ return prepared;
23
+ const state = contractState(prepared.observation.decision, input.contractId);
24
+ if (state === null)
25
+ throw new Error("placement offer has no contract state");
26
+ if (prepared.offer.target === undefined)
27
+ throw new Error("targeted placement offer is missing its target movement");
28
+ const observed = observeTargetHead(repository, prepared.offer.target.target);
29
+ if (observed !== prepared.offer.target.expectedOid) {
30
+ return {
31
+ kind: "target-moved",
32
+ contractId: input.contractId,
33
+ target: prepared.offer.target.target,
34
+ expected: prepared.offer.target.expectedOid,
35
+ observed,
36
+ };
37
+ }
38
+ const physical = prepareTargetPlacement(repository, state, prepared.offer.target);
39
+ if (physical.kind === "refused")
40
+ return physical;
41
+ const result = await admitDecidedOffer({
42
+ channel: protocol.channel,
43
+ repository,
44
+ decisionObservation: prepared.observation,
45
+ attempt: prepared.attempt,
46
+ offer: prepared.offer,
47
+ primaryContract: input.contractId,
48
+ });
49
+ if (result.kind === "accepted") {
50
+ return { ...result, physical: followTargetPlacement(repository, physical.placement) };
51
+ }
52
+ if (result.kind === "publication-failed")
53
+ return result;
54
+ if (result.kind === "collision" && index + 1 === protocol.attempts.length)
55
+ return result;
56
+ }
57
+ return { kind: "exhausted" };
58
+ }
59
+ /** Run the sole placement adjudicator inside the target's physical fence. */
60
+ export async function admitPlacement(channel, repository, target, input) {
61
+ const attempts = mintAttempts({ entryCount: 1 });
62
+ const protocol = {
63
+ input,
64
+ channel,
65
+ repository,
66
+ contracts: [input.contractId],
67
+ attempts,
68
+ decide: decidePlacement,
69
+ };
70
+ const run = () => runProtocol(protocol);
71
+ if (target === undefined)
72
+ return await run();
73
+ let held;
74
+ try {
75
+ held = await acquireTargetPlacementFence(repository, target);
76
+ }
77
+ catch (error) {
78
+ return placementFailure(error);
79
+ }
80
+ let result;
81
+ let exceptional;
82
+ try {
83
+ result = await runFencedPlacement(repository, input, protocol);
84
+ }
85
+ catch (error) {
86
+ if (error instanceof AuthorityCorruptionError || error instanceof TypeError)
87
+ exceptional = error;
88
+ else {
89
+ try {
90
+ result = expectedPlacementFailure(error);
91
+ }
92
+ catch (unexpected) {
93
+ exceptional = unexpected;
94
+ }
95
+ }
96
+ }
97
+ let releaseFailure;
98
+ try {
99
+ held.close();
100
+ }
101
+ catch (error) {
102
+ releaseFailure = error;
103
+ }
104
+ if (exceptional !== undefined)
105
+ throw exceptional;
106
+ if (result === undefined)
107
+ throw new Error("placement produced no result");
108
+ if (releaseFailure !== undefined) {
109
+ return result.kind === "accepted"
110
+ ? { ...result, physical: reconcileEffectFailure(releaseFailure, result.physical) }
111
+ : placementFailure(releaseFailure);
112
+ }
113
+ return result;
114
+ }
@@ -1,5 +1,6 @@
1
+ import { type GitDecodeChannel } from "../../git/read-observation.js";
1
2
  import type { GitRepository } from "../../git/repository.js";
2
- import type { ContractId, ContractState, FactKind, Gate, JournalEntry } from "../../core/facts/types.js";
3
+ import type { ContractId, ContractState, DeliverData, FactKind, Gate, JournalEntry, SnapshotId } from "../../core/facts/types.js";
3
4
  export type { FactKind } from "../../core/facts/types.js";
4
5
  export type TimelineEntry = Readonly<{
5
6
  kind: FactKind;
@@ -15,11 +16,16 @@ export type AuditReport = Readonly<{
15
16
  reworks: number;
16
17
  reviews: number;
17
18
  timeline: readonly TimelineEntry[];
19
+ delivery?: DeliverData;
20
+ targetObservation?: Readonly<{
21
+ head: SnapshotId | null;
22
+ drift: boolean;
23
+ }>;
18
24
  }>;
19
25
  type AuditRead = Readonly<{
20
26
  state: ContractState | null;
21
27
  entries: readonly JournalEntry[];
22
28
  report: AuditReport;
23
29
  }>;
24
- export declare function auditReport(entries: readonly JournalEntry[], reviewed: Gate): AuditReport;
25
- export declare function readAudit(repository: GitRepository, contract: ContractId, reviewed: Gate): AuditRead;
30
+ export declare function auditReport(entries: readonly JournalEntry[], reviewed: Gate, state?: ContractState, targetObservation?: AuditReport["targetObservation"]): AuditReport;
31
+ export declare function readAuditAt(repository: GitRepository, channel: GitDecodeChannel, contract: ContractId, reviewed: Gate): Promise<AuditRead>;
@@ -1,4 +1,5 @@
1
- import { observeContract } from "../../git/observe.js";
1
+ import { observeContractWorld, observeDeliveryTargetAt } from "../../git/observe.js";
2
+ import { withGitReadObservation } from "../../git/read-observation.js";
2
3
  function elapsedSince(prior, current) {
3
4
  if (prior === undefined)
4
5
  return null;
@@ -6,7 +7,7 @@ function elapsedSince(prior, current) {
6
7
  const currentMs = Date.parse(current);
7
8
  return currentMs - priorMs;
8
9
  }
9
- export function auditReport(entries, reviewed) {
10
+ export function auditReport(entries, reviewed, state, targetObservation) {
10
11
  let reworks = 0;
11
12
  let reviews = 0;
12
13
  const timeline = entries.map((entry, index) => {
@@ -27,13 +28,28 @@ export function auditReport(entries, reviewed) {
27
28
  } : {}),
28
29
  };
29
30
  });
30
- return { reworks, reviews, timeline };
31
- }
32
- export function readAudit(repository, contract, reviewed) {
33
- const observation = observeContract(repository, contract);
31
+ const delivery = state?.delivery?.data;
34
32
  return {
35
- state: observation.state,
36
- entries: observation.entries,
37
- report: auditReport(observation.entries, reviewed),
33
+ reworks,
34
+ reviews,
35
+ timeline,
36
+ ...(delivery === undefined ? {} : { delivery }),
37
+ ...(targetObservation === undefined ? {} : { targetObservation }),
38
38
  };
39
39
  }
40
+ export async function readAuditAt(repository, channel, contract, reviewed) {
41
+ return withGitReadObservation(repository, channel, async (observation) => {
42
+ const world = await observeContractWorld(observation, [contract]);
43
+ const record = world.contracts.get(contract);
44
+ if (record === undefined)
45
+ throw new Error(`missing requested contract observation: ${contract}`);
46
+ const targetObservation = record.state === null
47
+ ? undefined
48
+ : await observeDeliveryTargetAt(observation, record.state) ?? undefined;
49
+ return {
50
+ state: record.state,
51
+ entries: record.entries,
52
+ report: auditReport(record.entries, reviewed, record.state ?? undefined, targetObservation),
53
+ };
54
+ });
55
+ }
@@ -1,8 +1,8 @@
1
- import type { GitRepository } from "../../git/repository.js";
1
+ import type { GitReadObservation } from "../../git/read-observation.js";
2
2
  import type { ContractId } from "../../core/facts/types.js";
3
3
  export type ContractDocumentProjection = Readonly<{
4
4
  contract: ContractId;
5
5
  documentBytes: string;
6
6
  }>;
7
7
  /** Read every live contract document from one immutable Git snapshot. */
8
- export declare function readDocuments(repository: GitRepository): readonly ContractDocumentProjection[];
8
+ export declare function readDocuments(observation: GitReadObservation): Promise<readonly ContractDocumentProjection[]>;
@@ -1,11 +1,11 @@
1
- import { observeGit } from "../../git/observe.js";
1
+ import { observeActiveContractWorld } from "../../git/observe.js";
2
2
  /** Read every live contract document from one immutable Git snapshot. */
3
- export function readDocuments(repository) {
4
- const observed = observeGit(repository);
3
+ export async function readDocuments(observation) {
4
+ const observed = await observeActiveContractWorld(observation);
5
5
  const documents = [];
6
6
  for (const [contract, observation] of observed.contracts) {
7
7
  const state = observation.state;
8
- if (state === null || state.terminal !== null)
8
+ if (state === null)
9
9
  continue;
10
10
  documents.push({
11
11
  contract,
@@ -1,6 +1,7 @@
1
1
  import type { GitRepository } from "../../git/repository.js";
2
+ import type { GitDecodeChannel, GitReadObservation } from "../../git/read-observation.js";
2
3
  import { type GateCurrent } from "../../core/facts/gate.js";
3
- import type { ContractId, SnapshotId } from "../../core/facts/types.js";
4
+ import type { ContractId, DeliverData, SnapshotId } from "../../core/facts/types.js";
4
5
  export type ContractPhase = "waiting" | "bound" | "pending-delivery" | "claimed" | "abandoned";
5
6
  export type ContractDisposition = "active" | "terminal";
6
7
  export type ContractGateCurrent = GateCurrent;
@@ -15,7 +16,11 @@ export type ContractRow = Readonly<{
15
16
  workspace: "worktree" | "here";
16
17
  worktreePath: string | null;
17
18
  target: string | null;
18
- candidate: SnapshotId | null;
19
+ delivery: DeliverData | null;
20
+ targetObservation: Readonly<{
21
+ head: SnapshotId | null;
22
+ drift: boolean;
23
+ }> | null;
19
24
  gates: Readonly<{
20
25
  reports: readonly ContractGateReport[];
21
26
  satisfied: boolean;
@@ -23,6 +28,7 @@ export type ContractRow = Readonly<{
23
28
  }>;
24
29
  export type ContractBoard = Readonly<{
25
30
  root: string;
31
+ state: SnapshotId | null;
26
32
  rows: readonly ContractRow[];
27
33
  }>;
28
34
  export type ContractObservation = Readonly<{
@@ -33,6 +39,6 @@ export type ContractObservation = Readonly<{
33
39
  row: ContractRow;
34
40
  }>;
35
41
  /** Build the Contract board from one immutable git observation. */
36
- export declare function readContractBoard(repository: GitRepository): ContractBoard;
37
- /** Observe one Contract without enumerating the Contract world. */
38
- export declare function readContractObservation(repository: GitRepository, id: ContractId): ContractObservation;
42
+ export declare function readContractBoard(observation: GitReadObservation): Promise<ContractBoard>;
43
+ /** Observe one Contract and its target from one fresh ref epoch. */
44
+ export declare function readContractObservationAt(repository: GitRepository, channel: GitDecodeChannel, id: ContractId): Promise<ContractObservation>;
@@ -1,28 +1,30 @@
1
- import { observeGit, observeContract } from "../../git/observe.js";
2
- import { deliveryWorktreePath } from "../../git/reconcile.js";
1
+ import { extendContractsForAdmissionAt, observeActiveContractWorld, observeContractsForAdmissionInObservationAt, observeDeliveryTargetAt, withContractReadObservationAt, } from "../../git/observe.js";
2
+ import { deliveryWorktreePath } from "../../git/workspace.js";
3
3
  import { gateReports } from "../../core/facts/gate.js";
4
- function phaseFor(state) {
4
+ import { prerequisiteStatus } from "../../core/facts/observation.js";
5
+ function phaseFor(state, eligible) {
5
6
  if (state.terminal?.kind === "claimed")
6
7
  return "claimed";
7
8
  if (state.terminal?.kind === "abandoned")
8
9
  return "abandoned";
9
10
  if (state.delivery !== null)
10
11
  return "pending-delivery";
11
- if (state.bound !== null)
12
+ if (state.bound !== null || eligible)
12
13
  return "bound";
13
14
  return "waiting";
14
15
  }
15
- function rowFor(repository, state) {
16
+ function rowFor(repository, state, targetObservation, eligible) {
16
17
  const workspace = state.coordinates.workspace;
17
18
  const gates = gateReports(state);
18
19
  return {
19
20
  id: state.id,
20
- phase: phaseFor(state),
21
+ phase: phaseFor(state, eligible),
21
22
  disposition: state.terminal === null ? "active" : "terminal",
22
23
  workspace,
23
24
  worktreePath: workspace === "worktree" ? deliveryWorktreePath(repository, state.id) : null,
24
25
  target: state.coordinates.target ?? null,
25
- candidate: state.delivery?.data.candidate ?? null,
26
+ delivery: state.delivery?.data ?? null,
27
+ targetObservation,
26
28
  gates: {
27
29
  reports: gates.reports.map((report) => ({ gate: report.gate, current: report.current })),
28
30
  satisfied: gates.satisfied,
@@ -30,18 +32,29 @@ function rowFor(repository, state) {
30
32
  };
31
33
  }
32
34
  /** Build the Contract board from one immutable git observation. */
33
- export function readContractBoard(repository) {
34
- const observed = observeGit(repository);
35
+ export async function readContractBoard(observation) {
36
+ const observed = await observeActiveContractWorld(observation);
35
37
  const rows = [];
36
38
  for (const value of observed.contracts.values()) {
37
39
  if (value.state === null)
38
40
  continue;
39
- rows.push(rowFor(repository, value.state));
41
+ const state = value.state;
42
+ rows.push(observeDeliveryTargetAt(observation, state).then((target) => rowFor(observation.repository, state, target, prerequisiteStatus(state.terms.after, observed.eligibility) === "claimed")));
40
43
  }
41
- return { root: repository.primaryWorktree, rows };
44
+ return { root: observation.repository.primaryWorktree, state: observed.snapshot, rows: await Promise.all(rows) };
42
45
  }
43
- /** Observe one Contract without enumerating the Contract world. */
44
- export function readContractObservation(repository, id) {
45
- const state = observeContract(repository, id).state;
46
- return state === null ? { kind: "missing", id } : { kind: "present", row: rowFor(repository, state) };
46
+ /** Observe one Contract and its target from one fresh ref epoch. */
47
+ export async function readContractObservationAt(repository, channel, id) {
48
+ return withContractReadObservationAt(repository, channel, id, async (observation) => {
49
+ let observed = await observeContractsForAdmissionInObservationAt(observation, [id]);
50
+ const state = observed.decision.get(id) ?? null;
51
+ if (state !== null)
52
+ observed = await extendContractsForAdmissionAt(channel, observed, state.terms.after);
53
+ return state === null
54
+ ? { kind: "missing", id }
55
+ : {
56
+ kind: "present",
57
+ row: rowFor(observation.repository, state, await observeDeliveryTargetAt(observation, state), prerequisiteStatus(state.terms.after, observed.decision) === "claimed"),
58
+ };
59
+ });
47
60
  }
@@ -1,5 +1,7 @@
1
1
  import { type GitDecisionObservation } from "../git/observe.js";
2
+ import type { GitDecodeChannel, GitTreeSelection } from "../git/read-observation.js";
2
3
  import type { GitRepository } from "../git/repository.js";
4
+ import type { GitRefAssertion } from "../git/repository.js";
3
5
  import type { AttemptContext, DecideInput, OfferDecision } from "../core/decide.js";
4
6
  import type { Offer, TreeUpdate } from "../core/facts/offer.js";
5
7
  import { type ContractId } from "../core/facts/types.js";
@@ -16,24 +18,64 @@ export type CompanionDecorator = (input: Readonly<{
16
18
  observation: GitDecisionObservation;
17
19
  contractId: ContractId;
18
20
  offer: Offer;
19
- }>) => readonly TreeUpdate[];
20
- type RunProtocolInput<Input extends Readonly<{
21
+ }>) => readonly TreeUpdate[] | Promise<readonly TreeUpdate[]>;
22
+ export type RunProtocolInput<Input extends Readonly<{
21
23
  contractId: ContractId;
22
- }>, Refusal> = Readonly<{
23
- input: Input;
24
+ }>, Refusal, Seed extends Readonly<{
25
+ contractId: ContractId;
26
+ }> = Input> = Readonly<{
27
+ channel: GitDecodeChannel;
24
28
  repository: GitRepository;
25
29
  contracts: readonly ContractId[];
26
30
  attempts: readonly AttemptContext[];
27
31
  decide: (input: DecideInput<Input>) => OfferDecision<Refusal>;
28
32
  /** Override the targeted observer only for intents that need a full snapshot. */
29
- observe?: (repository: GitRepository, contracts: readonly ContractId[]) => GitDecisionObservation;
33
+ observe?: (repository: GitRepository, channel: GitDecodeChannel, contracts: readonly ContractId[]) => Promise<GitDecisionObservation>;
30
34
  /** Mint verb-owned entries from the exact size of this attempt's observation. */
31
35
  extendAttempt?: (attempt: AttemptContext, observedContractCount: number) => AttemptContext;
32
36
  /** Add opaque companions from the exact immutable observation for this attempt. */
33
37
  decorateOffer?: CompanionDecorator;
38
+ observationSelection?: GitTreeSelection;
39
+ }> & (Readonly<{
40
+ input: Input;
41
+ prepareInput?: never;
42
+ }> | Readonly<{
43
+ input: Seed;
44
+ prepareInput: (observation: GitDecisionObservation, input: Seed) => Readonly<{
45
+ kind: "prepared";
46
+ input: Input;
47
+ assertions?: readonly GitRefAssertion[];
48
+ }> | Readonly<{
49
+ kind: "refused";
50
+ refusal: Refusal;
51
+ }> | Promise<Readonly<{
52
+ kind: "prepared";
53
+ input: Input;
54
+ assertions?: readonly GitRefAssertion[];
55
+ }> | Readonly<{
56
+ kind: "refused";
57
+ refusal: Refusal;
58
+ }>>;
59
+ }>);
60
+ export type PreparedProtocolAttempt<Refusal> = Readonly<{
61
+ kind: "refused";
62
+ refusal: Refusal;
63
+ }> | Readonly<{
64
+ kind: "offered";
65
+ observation: GitDecisionObservation;
66
+ attempt: AttemptContext;
67
+ offer: Offer;
68
+ assertions: readonly GitRefAssertion[];
34
69
  }>;
70
+ /** Form one decided offer without admitting or reinterpreting it. */
71
+ export declare function prepareProtocolAttempt<Input extends Readonly<{
72
+ contractId: ContractId;
73
+ }>, Refusal, Seed extends Readonly<{
74
+ contractId: ContractId;
75
+ }> = Input>(input: RunProtocolInput<Input, Refusal, Seed>, baseAttempt: AttemptContext): Promise<PreparedProtocolAttempt<Refusal>>;
35
76
  /** Run bounded, verb-neutral attempts and return one real admission on acceptance. */
36
77
  export declare function runProtocol<Input extends Readonly<{
37
78
  contractId: ContractId;
38
- }>, Refusal>(input: RunProtocolInput<Input, Refusal>): ProtocolResult<Refusal>;
39
- export {};
79
+ }>, Refusal, Seed extends Readonly<{
80
+ contractId: ContractId;
81
+ }> = Input>(input: RunProtocolInput<Input, Refusal, Seed>): Promise<ProtocolResult<Refusal>>;
@@ -1,32 +1,60 @@
1
- import { observeContractsForAdmission } from "../git/observe.js";
1
+ import { extendAdmissionPathsAt, observeContractsForAdmissionAt, } from "../git/observe.js";
2
2
  import { admitDecidedOffer } from "./attempt.js";
3
+ /** Form one decided offer without admitting or reinterpreting it. */
4
+ export async function prepareProtocolAttempt(input, baseAttempt) {
5
+ const decisionObservation = input.observe === undefined
6
+ ? await observeContractsForAdmissionAt(input.repository, input.channel, input.contracts, input.observationSelection)
7
+ : await input.observe(input.repository, input.channel, input.contracts);
8
+ const observation = decisionObservation.decision;
9
+ const preparedInput = "prepareInput" in input && input.prepareInput !== undefined
10
+ ? await input.prepareInput(decisionObservation, input.input)
11
+ : { kind: "prepared", input: input.input, assertions: [] };
12
+ if (preparedInput.kind === "refused")
13
+ return preparedInput;
14
+ const attempt = input.extendAttempt === undefined
15
+ ? baseAttempt
16
+ : input.extendAttempt(baseAttempt, observation.size);
17
+ const decision = input.decide({ input: preparedInput.input, attempt, observation });
18
+ if (decision.kind === "refused")
19
+ return decision;
20
+ const companions = input.decorateOffer === undefined
21
+ ? []
22
+ : await input.decorateOffer({
23
+ repository: input.repository,
24
+ observation: decisionObservation,
25
+ contractId: input.input.contractId,
26
+ offer: decision.offer,
27
+ });
28
+ const offer = companions.length === 0
29
+ ? decision.offer
30
+ : { ...decision.offer, companions: [...(decision.offer.companions ?? []), ...companions] };
31
+ const admissionObservation = companions.length === 0
32
+ ? decisionObservation
33
+ : await extendAdmissionPathsAt(input.channel, decisionObservation, companions.map(({ path }) => path));
34
+ return {
35
+ kind: "offered",
36
+ observation: admissionObservation,
37
+ attempt,
38
+ offer,
39
+ assertions: preparedInput.assertions ?? [],
40
+ };
41
+ }
3
42
  /** Run bounded, verb-neutral attempts and return one real admission on acceptance. */
4
- export function runProtocol(input) {
43
+ export async function runProtocol(input) {
5
44
  const attempts = input.attempts;
6
- const contracts = input.contracts;
7
- const observe = input.observe ?? observeContractsForAdmission;
8
45
  for (let index = 0; index < attempts.length; index += 1) {
9
- const baseAttempt = attempts[index];
10
- const decisionObservation = observe(input.repository, contracts);
11
- const observation = decisionObservation.decision;
12
- const attempt = input.extendAttempt === undefined
13
- ? baseAttempt
14
- : input.extendAttempt(baseAttempt, observation.size);
15
- const decision = input.decide({ input: input.input, attempt, observation });
16
- if (decision.kind === "refused")
17
- return { kind: "refused", refusal: decision.refusal };
18
- const companions = input.decorateOffer === undefined
19
- ? []
20
- : input.decorateOffer({
21
- repository: input.repository,
22
- observation: decisionObservation,
23
- contractId: input.input.contractId,
24
- offer: decision.offer,
25
- });
26
- const offer = companions.length === 0
27
- ? decision.offer
28
- : { ...decision.offer, companions: [...(decision.offer.companions ?? []), ...companions] };
29
- const result = admitDecidedOffer(input.repository, decisionObservation, attempt, offer, input.input.contractId);
46
+ const prepared = await prepareProtocolAttempt(input, attempts[index]);
47
+ if (prepared.kind === "refused")
48
+ return prepared;
49
+ const result = await admitDecidedOffer({
50
+ channel: input.channel,
51
+ repository: input.repository,
52
+ decisionObservation: prepared.observation,
53
+ attempt: prepared.attempt,
54
+ offer: prepared.offer,
55
+ primaryContract: input.input.contractId,
56
+ assertions: prepared.assertions,
57
+ });
30
58
  if (result.kind === "accepted" || result.kind === "publication-failed")
31
59
  return result;
32
60
  if (result.kind === "collision" && index + 1 === attempts.length)
@@ -33,5 +33,6 @@ export declare class LineRpcProcess {
33
33
  private fail;
34
34
  request(method: string, params?: Readonly<Record<string, unknown>>): Promise<unknown>;
35
35
  notify(method: string): void;
36
+ endInputAndDrain(timeoutMs?: number): Promise<void>;
36
37
  close(force?: boolean): Promise<void>;
37
38
  }
@@ -1,5 +1,12 @@
1
1
  import { spawn } from "node:child_process";
2
2
  import { terminateProcessTree } from "./run.js";
3
+ const DEFAULT_DRAIN_TIMEOUT_MS = 1_000;
4
+ function bounded(promise, milliseconds) {
5
+ return new Promise((resolve, reject) => {
6
+ const timer = setTimeout(() => resolve(undefined), milliseconds);
7
+ void promise.then((value) => { clearTimeout(timer); resolve(value); }, (error) => { clearTimeout(timer); reject(error); });
8
+ });
9
+ }
3
10
  function object(value) {
4
11
  return value !== null && typeof value === "object" && !Array.isArray(value)
5
12
  ? value
@@ -110,6 +117,20 @@ export class LineRpcProcess {
110
117
  if (!this.closed)
111
118
  this.child.stdin.write(`${JSON.stringify({ method })}\n`);
112
119
  }
120
+ async endInputAndDrain(timeoutMs = DEFAULT_DRAIN_TIMEOUT_MS) {
121
+ if (this.closed) {
122
+ await this.exited;
123
+ return;
124
+ }
125
+ this.closed = true;
126
+ this.fail(new Error("line RPC process is closed"));
127
+ this.child.stdin.end();
128
+ const drained = await bounded(this.exited, timeoutMs);
129
+ if (drained === undefined) {
130
+ await terminateProcessTree(this.child.pid, true);
131
+ await this.exited;
132
+ }
133
+ }
113
134
  async close(force = false) {
114
135
  if (this.closed) {
115
136
  await this.exited;
@@ -2,9 +2,10 @@ type ProcessLaunch = Readonly<{
2
2
  readonly argv: readonly string[];
3
3
  readonly cwd?: string;
4
4
  readonly env?: NodeJS.ProcessEnv;
5
+ readonly signal?: AbortSignal;
5
6
  }>;
6
7
  export type ProcessInput = ProcessLaunch & Readonly<{
7
- readonly timeoutMs: number;
8
+ readonly timeoutMs?: number;
8
9
  }>;
9
10
  type ProcessTerminal = Readonly<{
10
11
  readonly kind: "terminal";
@@ -23,7 +24,20 @@ type ProcessSpawnError = Readonly<{
23
24
  type ProcessUnknownExit = Readonly<{
24
25
  readonly kind: "unknown-exit";
25
26
  }>;
26
- export type ProcessOutcome = ProcessTerminal | ProcessTimeout | ProcessSpawnError | ProcessUnknownExit;
27
+ type ProcessCancelled = Readonly<{
28
+ readonly kind: "cancelled";
29
+ }>;
30
+ export type ProcessOutcome = ProcessTerminal | ProcessTimeout | ProcessSpawnError | ProcessUnknownExit | ProcessCancelled;
31
+ export type ProcessIdentity = Readonly<{
32
+ pid: number;
33
+ spawnedAt: string;
34
+ }>;
35
+ export type ProcessIdentityProbe = Readonly<{
36
+ kind: "gone" | "alive" | "replaced";
37
+ }> | Readonly<{
38
+ kind: "unverifiable";
39
+ diagnostic: string;
40
+ }>;
27
41
  export type ProcessCollar = Readonly<{
28
42
  pid: number;
29
43
  processGroup: number;
@@ -46,6 +60,8 @@ export type DetachedProcessInput = Readonly<{
46
60
  }>;
47
61
  export declare function terminateProcessTree(pid: number | undefined, force?: boolean): Promise<void>;
48
62
  export declare function currentProcessCollar(): ProcessCollar;
63
+ export declare function currentProcessIdentity(): ProcessIdentity;
64
+ export declare function probeProcessIdentity(identity: ProcessIdentity): ProcessIdentityProbe;
49
65
  export declare function spawnDetachedProcess(input: DetachedProcessInput): Promise<ProcessCollar>;
50
66
  export declare function probeProcessTree(collar: ProcessCollar): ProcessTreeProbe;
51
67
  export declare function putDownProcessTree(collar: ProcessCollar): Promise<PutDownEvidence>;