@astrosheep/keiyaku 4.5.7 → 4.5.9

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 (244) hide show
  1. package/README.md +10 -0
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +12 -11
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +33 -12
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
  12. package/build/src/akuma/abort.d.ts +2 -1
  13. package/build/src/akuma/abort.js +6 -23
  14. package/build/src/akuma/akuma-handle.js +4 -2
  15. package/build/src/akuma/akuma-observe.d.ts +2 -0
  16. package/build/src/akuma/akuma-observe.js +1 -0
  17. package/build/src/akuma/akuma-product.js +9 -7
  18. package/build/src/akuma/akuma.d.ts +392 -9
  19. package/build/src/akuma/akuma.js +31 -1
  20. package/build/src/akuma/allowed.d.ts +1 -1
  21. package/build/src/akuma/allowed.js +1 -0
  22. package/build/src/akuma/archetype.js +1 -1
  23. package/build/src/akuma/body.d.ts +8 -5
  24. package/build/src/akuma/body.js +12 -5
  25. package/build/src/akuma/call-request.d.ts +80 -0
  26. package/build/src/akuma/call-request.js +211 -0
  27. package/build/src/akuma/heart/facts.d.ts +16 -78
  28. package/build/src/akuma/heart/facts.js +11 -0
  29. package/build/src/akuma/heart/index.d.ts +3 -2
  30. package/build/src/akuma/heart/index.js +4 -1
  31. package/build/src/akuma/heart/request-authority.d.ts +5 -4
  32. package/build/src/akuma/heart/request-authority.js +20 -34
  33. package/build/src/akuma/heart/request-rows.js +12 -23
  34. package/build/src/akuma/heart/schema.d.ts +1 -1
  35. package/build/src/akuma/heart/schema.js +5 -13
  36. package/build/src/akuma/index.d.ts +1 -1
  37. package/build/src/akuma/index.js +1 -1
  38. package/build/src/akuma/projection-read.d.ts +1 -0
  39. package/build/src/akuma/projection-read.js +8 -1
  40. package/build/src/akuma/projection.d.ts +907 -137
  41. package/build/src/akuma/projection.js +193 -9
  42. package/build/src/akuma/provider.d.ts +30 -3
  43. package/build/src/akuma/provider.js +111 -0
  44. package/build/src/akuma/providers/acp/core.d.ts +2 -2
  45. package/build/src/akuma/providers/acp/core.js +13 -6
  46. package/build/src/akuma/providers/acp/index.js +5 -4
  47. package/build/src/akuma/providers/claude/events.d.ts +2 -2
  48. package/build/src/akuma/providers/claude/events.js +16 -3
  49. package/build/src/akuma/providers/claude/index.d.ts +3 -3
  50. package/build/src/akuma/providers/claude/index.js +16 -5
  51. package/build/src/akuma/providers/codex-app-server/events.d.ts +2 -2
  52. package/build/src/akuma/providers/codex-app-server/events.js +25 -4
  53. package/build/src/akuma/providers/codex-app-server/index.js +18 -6
  54. package/build/src/akuma/providers/grok-build/index.js +5 -4
  55. package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
  56. package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
  57. package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
  58. package/build/src/akuma/providers/pi/index.js +72 -58
  59. package/build/src/akuma/request-lifecycle.d.ts +4 -10
  60. package/build/src/akuma/request-lifecycle.js +7 -5
  61. package/build/src/akuma/request-rendezvous.d.ts +26 -0
  62. package/build/src/akuma/request-rendezvous.js +100 -0
  63. package/build/src/akuma/request-serve.d.ts +6 -66
  64. package/build/src/akuma/request-serve.js +83 -210
  65. package/build/src/akuma/request-wire.d.ts +109 -115
  66. package/build/src/akuma/request-wire.js +63 -318
  67. package/build/src/akuma/requests.d.ts +19 -47
  68. package/build/src/akuma/requests.js +51 -107
  69. package/build/src/akuma/turn-drive.d.ts +5 -3
  70. package/build/src/akuma/turn-drive.js +39 -11
  71. package/build/src/akuma-body.d.ts +7 -2
  72. package/build/src/akuma-body.js +68 -46
  73. package/build/src/body/amend.js +18 -19
  74. package/build/src/cli/accepted.d.ts +1 -1
  75. package/build/src/cli/accepted.js +2 -2
  76. package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
  77. package/build/src/cli/commands/akuma-invoke.js +17 -9
  78. package/build/src/cli/commands/akuma.js +8 -8
  79. package/build/src/cli/commands/contract-invoke.d.ts +3 -2
  80. package/build/src/cli/commands/contract-invoke.js +42 -30
  81. package/build/src/cli/commands/contract.d.ts +16 -20
  82. package/build/src/cli/commands/contract.js +58 -25
  83. package/build/src/cli/commands/install.d.ts +2 -1
  84. package/build/src/cli/commands/install.js +3 -2
  85. package/build/src/cli/commands/task-invoke.d.ts +3 -0
  86. package/build/src/cli/commands/task-invoke.js +23 -140
  87. package/build/src/cli/commands/task.js +54 -20
  88. package/build/src/cli/invoke.js +39 -25
  89. package/build/src/cli/main.js +2 -1
  90. package/build/src/cli/parse.d.ts +2 -2
  91. package/build/src/cli/parse.js +56 -27
  92. package/build/src/cli/render/akuma-activity.d.ts +3 -0
  93. package/build/src/cli/render/akuma-activity.js +45 -29
  94. package/build/src/cli/render/akuma-tool.d.ts +5 -1
  95. package/build/src/cli/render/akuma.js +4 -8
  96. package/build/src/cli/render/audit.js +1 -1
  97. package/build/src/cli/render/catalog.js +80 -21
  98. package/build/src/cli/render/contract-observation.d.ts +2 -0
  99. package/build/src/cli/render/contract-observation.js +11 -0
  100. package/build/src/cli/render/contract.js +35 -62
  101. package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
  102. package/build/src/cli/render/kanshi-akuma.js +132 -0
  103. package/build/src/cli/render/kanshi.js +131 -213
  104. package/build/src/cli/render/receipt.d.ts +1 -2
  105. package/build/src/cli/render/receipt.js +76 -26
  106. package/build/src/cli/render/refusal.js +2 -10
  107. package/build/src/cli/render/region.js +5 -2
  108. package/build/src/cli/render/settings.d.ts +1 -1
  109. package/build/src/cli/render/settings.js +27 -8
  110. package/build/src/cli/render/task.js +22 -5
  111. package/build/src/cli/render/terminal.d.ts +32 -1
  112. package/build/src/cli/render/terminal.js +77 -1
  113. package/build/src/cli/result.d.ts +3 -3
  114. package/build/src/cli/runtime.js +4 -2
  115. package/build/src/cli/selectors.d.ts +2 -1
  116. package/build/src/cli/selectors.js +4 -3
  117. package/build/src/cli/square-edge.js +120 -36
  118. package/build/src/cli/usage.js +2 -1
  119. package/build/src/contract-guidance.d.ts +5 -0
  120. package/build/src/contract-guidance.js +121 -0
  121. package/build/src/contract-worktree.d.ts +0 -1
  122. package/build/src/contract-worktree.js +32 -83
  123. package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
  124. package/build/src/coordination/sqlite-transaction-lock.js +5 -0
  125. package/build/src/core/facts/codec.d.ts +2 -0
  126. package/build/src/core/facts/codec.js +4 -0
  127. package/build/src/core/verbs/placement.d.ts +6 -1
  128. package/build/src/core/verbs/placement.js +5 -3
  129. package/build/src/dispatch/index.d.ts +0 -2
  130. package/build/src/dispatch/index.js +54 -55
  131. package/build/src/git/admission.js +2 -2
  132. package/build/src/git/hooks.d.ts +9 -15
  133. package/build/src/git/hooks.js +23 -317
  134. package/build/src/git/nuke.d.ts +2 -1
  135. package/build/src/git/nuke.js +39 -21
  136. package/build/src/git/private-state-seat.d.ts +12 -0
  137. package/build/src/git/private-state-seat.js +39 -0
  138. package/build/src/git/process.d.ts +6 -0
  139. package/build/src/git/process.js +26 -11
  140. package/build/src/git/read-observation.js +29 -20
  141. package/build/src/git/reconcile.d.ts +13 -1
  142. package/build/src/git/reconcile.js +70 -11
  143. package/build/src/git/ref-migration.d.ts +22 -0
  144. package/build/src/git/ref-migration.js +55 -0
  145. package/build/src/git/repository.d.ts +10 -6
  146. package/build/src/git/repository.js +16 -8
  147. package/build/src/git/target-placement.d.ts +1 -0
  148. package/build/src/git/target-placement.js +5 -0
  149. package/build/src/git/tender.d.ts +1 -0
  150. package/build/src/git/terminal-reconcile.d.ts +1 -1
  151. package/build/src/git/terminal-reconcile.js +22 -20
  152. package/build/src/git/workspace.d.ts +14 -0
  153. package/build/src/git/workspace.js +44 -0
  154. package/build/src/kanshi/index.d.ts +1 -1
  155. package/build/src/kanshi/read.js +16 -16
  156. package/build/src/kanshi/report.d.ts +2 -2
  157. package/build/src/library/address.d.ts +9 -3
  158. package/build/src/library/address.js +3 -2
  159. package/build/src/library/akuma-creation.d.ts +4 -3
  160. package/build/src/library/akuma-creation.js +19 -13
  161. package/build/src/library/audit.d.ts +14 -6
  162. package/build/src/library/audit.js +13 -23
  163. package/build/src/library/catalog.d.ts +3 -1
  164. package/build/src/library/catalog.js +20 -6
  165. package/build/src/library/composition.d.ts +385 -0
  166. package/build/src/library/composition.js +28 -0
  167. package/build/src/library/configuration.js +8 -2
  168. package/build/src/library/continuation.js +66 -30
  169. package/build/src/library/contract-bind.js +10 -2
  170. package/build/src/library/contract-forwarding-reconciliation-result.d.ts +102 -0
  171. package/build/src/library/contract-forwarding-reconciliation-result.js +92 -0
  172. package/build/src/library/contract-forwarding-result.d.ts +4464 -0
  173. package/build/src/library/contract-forwarding-result.js +521 -0
  174. package/build/src/library/contract-forwarding.d.ts +71 -0
  175. package/build/src/library/contract-forwarding.js +114 -0
  176. package/build/src/library/contract-handle.d.ts +38 -0
  177. package/build/src/library/contract-handle.js +314 -0
  178. package/build/src/library/contract-operations.d.ts +214 -69
  179. package/build/src/library/contract-operations.js +189 -118
  180. package/build/src/library/contract-types.d.ts +7 -3
  181. package/build/src/library/contract.d.ts +21 -34
  182. package/build/src/library/contract.js +29 -287
  183. package/build/src/library/fleet-result.d.ts +1580 -0
  184. package/build/src/library/fleet-result.js +98 -0
  185. package/build/src/library/fleet.d.ts +112 -54
  186. package/build/src/library/fleet.js +211 -71
  187. package/build/src/library/input.d.ts +3 -1
  188. package/build/src/library/input.js +11 -1
  189. package/build/src/library/keiyaku.d.ts +388 -20
  190. package/build/src/library/keiyaku.js +13 -21
  191. package/build/src/library/mutation.d.ts +3 -3
  192. package/build/src/library/mutation.js +5 -9
  193. package/build/src/library/nuke.d.ts +1 -1
  194. package/build/src/library/nuke.js +4 -3
  195. package/build/src/library/reconcile.d.ts +4 -0
  196. package/build/src/library/reconcile.js +2 -0
  197. package/build/src/library/refusal.d.ts +0 -9
  198. package/build/src/library/refusal.js +0 -7
  199. package/build/src/protocol/amend.js +56 -50
  200. package/build/src/protocol/attempt.d.ts +2 -0
  201. package/build/src/protocol/attempt.js +8 -1
  202. package/build/src/protocol/completion.js +7 -0
  203. package/build/src/protocol/deliver.js +6 -2
  204. package/build/src/protocol/operations.d.ts +4 -1
  205. package/build/src/protocol/operations.js +5 -2
  206. package/build/src/protocol/placement.d.ts +1 -0
  207. package/build/src/protocol/placement.js +52 -38
  208. package/build/src/protocol/read/observation.d.ts +1 -4
  209. package/build/src/protocol/read/observation.js +2 -15
  210. package/build/src/protocol/reintegrate.js +62 -58
  211. package/build/src/protocol/review.js +5 -0
  212. package/build/src/protocol/run.js +17 -13
  213. package/build/src/runtime/proc/run.d.ts +9 -0
  214. package/build/src/runtime/proc/run.js +51 -4
  215. package/build/src/runtime/proc/termination.js +26 -22
  216. package/build/src/runtime/proc/windows-launch.exe +0 -0
  217. package/build/src/settlement/holder.d.ts +2 -1
  218. package/build/src/settlement/holder.js +15 -4
  219. package/build/src/settlement/settle.js +99 -33
  220. package/build/src/task/board.d.ts +68 -27
  221. package/build/src/task/board.js +31 -1
  222. package/build/src/task/catalog.d.ts +4 -0
  223. package/build/src/task/catalog.js +23 -0
  224. package/build/src/task/compose-language.js +33 -7
  225. package/build/src/task/compose-parser.d.ts +1 -1
  226. package/build/src/task/compose-parser.js +1 -1
  227. package/build/src/task/compose.js +2 -0
  228. package/build/src/task/index.d.ts +12 -4
  229. package/build/src/task/index.js +97 -16
  230. package/build/src/task/mutation-result.d.ts +923 -0
  231. package/build/src/task/mutation-result.js +140 -0
  232. package/build/src/task/mutation.d.ts +552 -28
  233. package/build/src/task/mutation.js +304 -97
  234. package/build/src/task/operations.d.ts +1 -4
  235. package/build/src/task/operations.js +0 -6
  236. package/build/src/task/public.d.ts +2 -0
  237. package/build/src/task/public.js +1 -0
  238. package/build/src/workspace-place.d.ts +7 -2
  239. package/build/src/workspace-place.js +34 -24
  240. package/build/src/world.d.ts +1 -0
  241. package/build/src/world.js +11 -0
  242. package/package.json +8 -6
  243. package/build/src/akuma/request-execution.d.ts +0 -8
  244. package/build/src/akuma/request-execution.js +0 -98
@@ -0,0 +1,121 @@
1
+ const APPOINTMENT_DESCRIPTION = "This is a read-only projection. Do not edit manually.";
2
+ export const CONTRACT_DELIVERER_SKILL = [
3
+ "---",
4
+ "name: keiyaku-deliver",
5
+ "description: Fulfill the appointed Contract as its Deliverer — produce the candidate the journaled terms describe.",
6
+ "---",
7
+ "",
8
+ "# Deliverer",
9
+ "",
10
+ "You are appointed Deliverer for the Contract in this worktree. The Contract document in `KEIYAKU.md` carries the journaled terms: Objective, Design, Region, Criteria, Verification. Your commission — the call and any tells — genuinely directs this round: what to build or investigate first, what evidence to gather, what to return. Both bind you; neither replaces the other. The terms are the standing acceptance floor; the commission is the round's direction and can never quietly add to that floor.",
11
+ "",
12
+ "## Common Workflow",
13
+ "",
14
+ "1. Read the Contract document, the current Arc if one is dispatched, and the read-first owners and source your commission names.",
15
+ "2. Do the work. Public outcomes — surfaces, semantics, observable behavior — are what the terms pin. Private decomposition, helper names, and control flow are yours unless the Contract explicitly pins them. Stay within the dispatched Arc; Contract lifecycle is not yours to decide.",
16
+ "3. Stop and ask upward when you hit a contradiction between terms, an ungrounded term — one that presupposes a decision nobody has made — or an open design choice. Do not silently pick a public meaning, and do not treat an assumption in a prompt as a decided term. Standing terms change only as journaled amends.",
17
+ "4. Run the Contract's Verification and gather the evidence the terms and your commission require.",
18
+ "5. Deliver the candidate. You owe a candidate, not decisions about the Contract: you do not hold its fulfillment loop unless your commission explicitly hands you the whole loop.",
19
+ "",
20
+ "## Deliver",
21
+ "",
22
+ "```bash",
23
+ "keiyaku deliver <contract> --include-dirty",
24
+ "keiyaku deliver <contract> --materialize-conflict",
25
+ "```",
26
+ "",
27
+ "Delivery submits the full current worktree state as the candidate for review and placement. Deliver when Verification passes and the evidence is in place; the Reviewer judges the rest.",
28
+ ]
29
+ .join("\n")
30
+ .concat("\n");
31
+ export const CONTRACT_REVIEWER_SKILL = [
32
+ "---",
33
+ "name: keiyaku-review",
34
+ "description: Review the appointed Contract's candidate — the commission owns the question, you own the answer.",
35
+ "---",
36
+ "",
37
+ "# Reviewer",
38
+ "",
39
+ "You are appointed Reviewer for the Contract in this worktree. Your commission — the call and any tells — owns the question: what to examine, how deep, which risks to watch, what evidence to demand, what to return. Follow it; it is why this review exists. You own the answer: every observation, finding, and the verdict are yours alone. An expectation stated in your commission is never evidence — it may tell you where to look, never what you found.",
40
+ "",
41
+ "## Common Workflow",
42
+ "",
43
+ "1. Read the Contract document in `KEIYAKU.md` and your commission.",
44
+ "2. Examine the full current candidate — the whole worktree as it stands, not the latest round's diff.",
45
+ "3. First decide whether each journaled Criterion is adjudicable as written — judgeable from the candidate and its evidence without asking the author anything further. Then judge the full candidate against every adjudicable Criterion — the floor a gate review always covers — and against whatever your commission asked. Criteria are a floor, not a ceiling: a real current defect you observe is a finding whether or not a Criterion names it.",
46
+ "4. Write the testimony.",
47
+ "",
48
+ "## Verdict",
49
+ "",
50
+ "Testimony is two-valued: satisfied or unsatisfied, over the current document identity and full worktree state. Satisfied requests placement; unsatisfied records testimony and requests nothing.",
51
+ "",
52
+ "Unsatisfied when: a current defect stands against the terms; required evidence is missing, failed, or stale; or a Criterion is not adjudicable as written — ambiguous, contradictory, or presupposing an unmade decision. That last case is a term defect, and a term defect is not a third outcome: testify unsatisfied and name the defective term in the summary as the blocker, so the holder can amend — which stales this testimony naturally. There is no withheld verdict: you always testify.",
53
+ "",
54
+ "The summary reports which Criteria you covered, your findings, any term defects, and any missing evidence.",
55
+ "",
56
+ "Advice beyond the terms — simplifications, risks, out-of-scope observations — belongs in the summary and never changes the verdict by itself. You never modify the candidate. A repeat review examines the full current candidate again from the current terms; earlier rounds bind nothing.",
57
+ "",
58
+ "## Review",
59
+ "",
60
+ "```bash",
61
+ "keiyaku review <contract> --satisfied --summary <conclusion>",
62
+ "keiyaku review <contract> --unsatisfied --summary <finding>",
63
+ "```",
64
+ ]
65
+ .join("\n")
66
+ .concat("\n");
67
+ export function renderContractAppointment(contract) {
68
+ return `---\ncontract: ${contract}\ndescription: ${APPOINTMENT_DESCRIPTION}\n---\n`;
69
+ }
70
+ function renderArc(arc) {
71
+ return [
72
+ "## Arc",
73
+ "",
74
+ "### Sequence",
75
+ "",
76
+ String(arc.seq),
77
+ "",
78
+ "### Title",
79
+ "",
80
+ arc.title.trimEnd(),
81
+ "",
82
+ "### Objective",
83
+ "",
84
+ arc.objective.trimEnd(),
85
+ "",
86
+ "### Brief",
87
+ "",
88
+ arc.brief.trimEnd(),
89
+ ].join("\n");
90
+ }
91
+ const FULFILLMENT = [
92
+ "## Fulfillment",
93
+ "",
94
+ "### Appointment",
95
+ "",
96
+ "This worktree is materialized for one Appointment to the Contract above, and every commission into it names exactly one seat — Deliverer or Reviewer. The Contract document is journal-authoritative: its terms are the standing acceptance floor, changed only by journaled amend. If an Arc is dispatched, it is the current chapter of delivery.",
97
+ "",
98
+ "### Worktree",
99
+ "",
100
+ "This worktree is the derived view of the Contract's subject. All Contract work happens here and stays here; the full current worktree state is the candidate.",
101
+ "",
102
+ "### Deliverer",
103
+ "",
104
+ "The Deliverer implements and verifies the journaled terms, staying within the dispatched Arc; it does not decide Contract lifecycle. It stops and asks upward on contradictions, ungrounded terms, and open design choices.",
105
+ "Read the Deliverer operating procedures at `.agents/skills/keiyaku-deliver/SKILL.md`.",
106
+ "",
107
+ "### Reviewer",
108
+ "",
109
+ "The Reviewer examines the full current candidate snapshot, first decides whether each Criterion is adjudicable as written, and testifies satisfied or unsatisfied over the current document and worktree — reporting covered Criteria, findings, term defects, and missing evidence in the summary.",
110
+ "Read the Reviewer operating procedures at `.agents/skills/keiyaku-review/SKILL.md`.",
111
+ ].join("\n");
112
+ export function renderContractGuidance(state) {
113
+ return [
114
+ renderContractAppointment(state.id).trimEnd(),
115
+ state.terms.document.bytes.trimEnd(),
116
+ ...(state.currentArc === undefined ? [] : [renderArc(state.currentArc.data)]),
117
+ FULFILLMENT,
118
+ ]
119
+ .join("\n\n")
120
+ .concat("\n");
121
+ }
@@ -13,7 +13,6 @@ export type ContractAppointment = Readonly<{
13
13
  kind: "invalid";
14
14
  path: string;
15
15
  }>;
16
- export declare function renderContractGuidance(state: ContractState): string;
17
16
  export type ContractFileEffect = Readonly<{
18
17
  kind: "contract-file";
19
18
  path: string;
@@ -3,94 +3,18 @@ import { join } from "node:path";
3
3
  import { acquireSqliteTransactionLock } from "./coordination/sqlite-transaction-lock.js";
4
4
  import { repairDerivedFile } from "./coordination/durable-file.js";
5
5
  import { contractId } from "./core/facts/types.js";
6
+ import { CONTRACT_DELIVERER_SKILL, CONTRACT_REVIEWER_SKILL, renderContractAppointment, renderContractGuidance, } from "./contract-guidance.js";
6
7
  import { worktreeGitDirectory, worktreeRoot } from "./git/repository.js";
7
8
  import { GitPlumbingError, runGit } from "./git/process.js";
8
9
  import { worktreePath } from "./git/workspace.js";
9
10
  import { appointmentFor, placeRegisterPath } from "./workspace-place.js";
10
11
  const IGNORE_BYTES = ".gitignore\nKEIYAKU.md\n";
11
12
  const PRIMARY_IGNORE_BYTES = "*\n!settings.json\n!tasks/\n!tasks/**\n";
12
- const APPOINTMENT_DESCRIPTION = "This is a read-only projection. Do not edit manually.";
13
- function appointmentBytes(contract) {
14
- return `---\ncontract: ${contract}\ndescription: ${APPOINTMENT_DESCRIPTION}\n---\n`;
15
- }
16
- function renderArc(arc) {
17
- return [
18
- "## Arc",
19
- "",
20
- "### Sequence",
21
- "",
22
- String(arc.seq),
23
- "",
24
- "### Title",
25
- "",
26
- arc.title.trimEnd(),
27
- "",
28
- "### Objective",
29
- "",
30
- arc.objective.trimEnd(),
31
- "",
32
- "### Brief",
33
- "",
34
- arc.brief.trimEnd(),
35
- ].join("\n");
36
- }
37
- const FULFILLMENT = [
38
- "## Fulfillment",
39
- "",
40
- "### Appointment",
41
- "",
42
- "Each commission names exactly one seat: Deliverer or Reviewer.",
43
- "If no seat was named, stop and ask the caller. Never infer it.",
44
- "",
45
- "### Worktree",
46
- "",
47
- "This file is a derived view of the journal-authoritative Contract. Never edit it to change the Contract.",
48
- "Treat the directory containing `.keiyaku/KEIYAKU.md` as the Contract worktree root.",
49
- "Read the complete Contract before acting and keep work inside that worktree.",
50
- "",
51
- "### Deliverer",
52
- "",
53
- "Re-read this file on each wake-up; it may have been updated between sessions.",
54
- "Implement and verify the Objective under the Design, Region, and Criteria in this Contract.",
55
- "Region is a rough intent, not a hard boundary — natural ripple outside it is fine and not a blocker.",
56
- "When an Arc is active, stay within that current chapter.",
57
- "If you discover a contradiction with this Contract or an unclosed point in its terms,",
58
- "stop and report it before continuing.",
59
- "",
60
- "For work requiring three or more steps, prefer `keiyaku task -C <worktree>` to organize and manage Tasks.",
61
- "Promptly update progress for Tasks already present in the current worktree.",
62
- "",
63
- "Deliver from this worktree. A clean worktree delivers HEAD; uncommitted work",
64
- "needs `deliver --include-dirty`, which captures the final non-ignored tree and",
65
- "stages or commits nothing. If deliver reports a conflict, run",
66
- "`deliver --materialize-conflict`, resolve the conflicted files, stage them,",
67
- "and deliver again; while the merge stays uncommitted that continuation uses",
68
- "`--include-dirty`. Unresolved paths always refuse.",
69
- "",
70
- "### Reviewer",
71
- "",
72
- "Re-read this file on each wake-up; it may have been updated between sessions.",
73
- "Review the complete current worktree snapshot against this Contract. Do not modify it.",
74
- "Understand the original intent behind the Objective, not just its literal text.",
75
- "Region is a rough intent, not a hard boundary — natural ripple outside it is not a blocker.",
76
- "Compare each Criterion individually against the delivered work.",
77
- "Consolidate findings by root cause — group symptoms that share an underlying issue",
78
- "rather than listing each occurrence separately.",
79
- "Dig to the architectural or structural root; flag it directly rather than routing around it.",
80
- "If you discover a contradiction within the Contract or an unclosed point in its terms,",
81
- "report it as a finding.",
82
- "Report covered Criteria, findings, and missing evidence.",
83
- ].join("\n");
84
- export function renderContractGuidance(state) {
85
- return [
86
- appointmentBytes(state.id).trimEnd(),
87
- state.terms.document.bytes.trimEnd(),
88
- ...(state.currentArc === undefined ? [] : [renderArc(state.currentArc.data)]),
89
- FULFILLMENT,
90
- ]
91
- .join("\n\n")
92
- .concat("\n");
93
- }
13
+ const SEAT_IGNORE_BYTES = ".gitignore\nSKILL.md\n";
14
+ const SEAT_SKILLS = [
15
+ ["keiyaku-deliver", CONTRACT_DELIVERER_SKILL],
16
+ ["keiyaku-review", CONTRACT_REVIEWER_SKILL],
17
+ ];
94
18
  async function isTracked(repository, relativePath) {
95
19
  try {
96
20
  await runGit(repository, ["ls-files", "--error-unmatch", "--", relativePath]);
@@ -145,7 +69,7 @@ export async function releaseContractWorktree(repository, contract) {
145
69
  const appointment = await readContractAppointment(repository);
146
70
  if (appointment.kind !== "appointed" || appointment.contract !== contract)
147
71
  return;
148
- if ((await readFile(appointment.path, "utf8")) !== appointmentBytes(contract))
72
+ if ((await readFile(appointment.path, "utf8")) !== renderContractAppointment(contract))
149
73
  return;
150
74
  try {
151
75
  await unlink(appointment.path);
@@ -169,6 +93,23 @@ async function repair(repository, worktree, relativePath, bytes) {
169
93
  }
170
94
  return { kind: "contract-file", path, action };
171
95
  }
96
+ async function isKeiyakuSeatLeaf(worktree, seat) {
97
+ const sentinel = join(worktree, ".agents", "skills", seat, ".gitignore");
98
+ const stat = await lstat(sentinel).catch((error) => error.code === "ENOENT" ? undefined : Promise.reject(error));
99
+ return stat?.isFile() === true && !stat.isSymbolicLink() && (await readFile(sentinel, "utf8")) === SEAT_IGNORE_BYTES;
100
+ }
101
+ async function materializeSeatSkill(repository, worktree, seat, bytes) {
102
+ const leaf = `.agents/skills/${seat}`;
103
+ const skill = `${leaf}/SKILL.md`;
104
+ const skillPath = join(worktree, skill);
105
+ const skillExists = await lstat(skillPath).catch((error) => error.code === "ENOENT" ? false : Promise.reject(error));
106
+ if (!(await isKeiyakuSeatLeaf(worktree, seat)) && skillExists)
107
+ return [];
108
+ return [
109
+ await repair(repository, worktree, `${leaf}/.gitignore`, SEAT_IGNORE_BYTES),
110
+ await repair(repository, worktree, skill, bytes),
111
+ ];
112
+ }
172
113
  async function materialize(repository, worktree, guidance) {
173
114
  const effects = [];
174
115
  const failed = (target, path, error) => ({
@@ -218,6 +159,14 @@ async function materialize(repository, worktree, guidance) {
218
159
  return failed(worktree, join(worktree, relativePath), error);
219
160
  }
220
161
  }
162
+ for (const [seat, bytes] of SEAT_SKILLS) {
163
+ try {
164
+ effects.push(...(await materializeSeatSkill(scoped, worktree, seat, bytes)));
165
+ }
166
+ catch (error) {
167
+ return failed(worktree, join(worktree, ".agents", "skills", seat), error);
168
+ }
169
+ }
221
170
  return { effects, lag: [] };
222
171
  }
223
172
  export async function projectContractWorktree(repository, state, register, _onConflict) {
@@ -11,6 +11,7 @@ export declare function acquireSqliteTransactionLock(input: {
11
11
  mode: SqliteTransactionLockMode;
12
12
  timeoutMs?: number;
13
13
  signal?: AbortSignal;
14
+ onContended?: () => void;
14
15
  }): Promise<HeldSqliteTransactionLock>;
15
16
  export declare function tryAcquireSqliteTransactionLock(input: {
16
17
  path: string;
@@ -119,6 +119,7 @@ export async function acquireSqliteTransactionLock(input) {
119
119
  }
120
120
  const started = performance.now();
121
121
  let cap = INITIAL_RETRY_MS;
122
+ let contended = false;
122
123
  for (;;) {
123
124
  input.signal?.throwIfAborted();
124
125
  try {
@@ -127,6 +128,10 @@ export async function acquireSqliteTransactionLock(input) {
127
128
  catch (error) {
128
129
  if (!isBusy(error))
129
130
  throw error;
131
+ if (!contended) {
132
+ contended = true;
133
+ input.onContended?.();
134
+ }
130
135
  const elapsed = performance.now() - started;
131
136
  if (input.timeoutMs !== undefined && elapsed >= input.timeoutMs) {
132
137
  throw new SqliteTransactionLockError(`SQLite lock timed out after ${input.timeoutMs}ms: ${input.path}`, "timeout", { cause: error });
@@ -1,3 +1,5 @@
1
1
  import type { JournalEntry } from "./types.js";
2
+ /** Validate one in-memory journal value with the persisted-fact authority. */
3
+ export declare function decodeJournalEntry(value: unknown): JournalEntry;
2
4
  export declare function encodeEntry(entry: JournalEntry): string;
3
5
  export declare function decodeJournal(journal: string): JournalEntry[];
@@ -235,6 +235,10 @@ function validateEntry(value) {
235
235
  }
236
236
  return entry;
237
237
  }
238
+ /** Validate one in-memory journal value with the persisted-fact authority. */
239
+ export function decodeJournalEntry(value) {
240
+ return validateEntry(value);
241
+ }
238
242
  function canonicalValue(value) {
239
243
  if (value === null)
240
244
  return "null";
@@ -1,3 +1,4 @@
1
+ import { type GateReport } from "../facts/gate.js";
1
2
  import type { ActorId, ContractId } from "../facts/types.js";
2
3
  import type { DecideInput, OfferDecision } from "../decide.js";
3
4
  type PlacementInput = Readonly<{
@@ -10,8 +11,12 @@ export type UnmetPrerequisite = Readonly<{
10
11
  state: "missing" | "active" | "abandoned";
11
12
  }>;
12
13
  export type PlacementRefusal = Readonly<{
13
- kind: "contract-missing" | "delivery-missing" | "terminal" | "gates-unsatisfied";
14
+ kind: "contract-missing" | "delivery-missing" | "terminal";
14
15
  contractId: ContractId;
16
+ }> | Readonly<{
17
+ kind: "gates-unsatisfied";
18
+ contractId: ContractId;
19
+ unmet: readonly GateReport[];
15
20
  }> | Readonly<{
16
21
  kind: "prerequisites-unsatisfied";
17
22
  contractId: ContractId;
@@ -1,4 +1,4 @@
1
- import { gatesSatisfied } from "../facts/gate.js";
1
+ import { gateReports } from "../facts/gate.js";
2
2
  import { activeContract, contractState } from "../facts/observation.js";
3
3
  function unmetPrerequisites(prerequisites, observation) {
4
4
  const unmet = [];
@@ -30,8 +30,10 @@ export function decidePlacement({ input, attempt, observation, }) {
30
30
  if (unmet.length > 0) {
31
31
  return { kind: "refused", refusal: { kind: "prerequisites-unsatisfied", contractId: id, unmet } };
32
32
  }
33
- if (!gatesSatisfied(current)) {
34
- return { kind: "refused", refusal: { kind: "gates-unsatisfied", contractId: id } };
33
+ const gates = gateReports(current);
34
+ if (!gates.satisfied) {
35
+ const unmetGates = gates.reports.filter((report) => report.current.kind !== "attested" || report.current.verdict !== "satisfied");
36
+ return { kind: "refused", refusal: { kind: "gates-unsatisfied", contractId: id, unmet: unmetGates } };
35
37
  }
36
38
  const claimed = {
37
39
  v: 1,
@@ -10,8 +10,6 @@ export type Dispatch = Readonly<{
10
10
  export type DispatchFailure = Readonly<{
11
11
  kind: "conflict";
12
12
  current: Dispatch;
13
- }> | Readonly<{
14
- kind: "contention";
15
13
  }> | Readonly<{
16
14
  kind: "publication-failed";
17
15
  diagnostic: string;
@@ -1,15 +1,13 @@
1
1
  import { createHash } from "node:crypto";
2
- import { join } from "node:path";
3
2
  import { AuthorityCorruptionError } from "../core/facts/errors.js";
4
3
  import { contractId } from "../core/facts/types.js";
5
4
  import { parseAkuId } from "../akuma/identity.js";
6
- import { acquireSqliteTransactionLock } from "../coordination/sqlite-transaction-lock.js";
7
- import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readBlob, readGitPaths, updateGitTree, updateRefsAtomically, writeBlob, writeCommit, } from "../git/repository.js";
5
+ import { confirmPrivateStatePublication, withPrivateStatePublicationSeat } from "../git/private-state-seat.js";
6
+ import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readBlob, readGitPaths, updateGitTree, updateRefsAtomically, writeBlob, writeStateCommit, } from "../git/repository.js";
8
7
  import { withGitDecodeChannel, withGitReadObservation } from "../git/read-observation.js";
9
8
  const DISPATCH_ROOT = "dispatch";
10
9
  const DISPATCH_PREFIX = `${DISPATCH_ROOT}/`;
11
10
  const DISPATCH_SUFFIX = ".json";
12
- const MAX_ATTEMPTS = 3;
13
11
  function pathFor(akuId) {
14
12
  return `${DISPATCH_PREFIX}${createHash("sha256").update(akuId).digest("hex")}${DISPATCH_SUFFIX}`;
15
13
  }
@@ -125,57 +123,58 @@ export async function publishDispatch(input) {
125
123
  const owner = contractId(input.contractId);
126
124
  const intended = { akuId, contractId: owner, dispatchedAt: new Date().toISOString() };
127
125
  const path = pathFor(akuId);
128
- const held = await acquireSqliteTransactionLock({
129
- path: join(input.repository.commonDirectory, "keiyaku", "locks", "dispatch.sqlite"),
130
- mode: "immediate",
131
- });
132
- try {
133
- for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt += 1) {
134
- const snapshot = await readGitPaths(input.repository, [path]);
135
- const current = await dispatchFromSnapshot(input.repository, snapshot, akuId);
136
- if (current !== null) {
137
- return current.contractId === owner
138
- ? { kind: "dispatched", dispatch: current }
139
- : { kind: "failed", failure: { kind: "conflict", current } };
140
- }
141
- const changes = new Map();
142
- if (snapshot.commit === null) {
143
- changes.set(GIT_FORMAT_PATH, { oid: await writeBlob(input.repository, GIT_FORMAT_BYTES) });
144
- }
145
- changes.set(path, { oid: await writeBlob(input.repository, bytesFor(intended)) });
146
- const tree = await updateGitTree(input.repository, snapshot.tree, changes);
147
- const commit = await writeCommit({
148
- repository: input.repository,
149
- tree,
150
- parent: snapshot.commit,
151
- message: `dispatch ${akuId}`,
152
- at: intended.dispatchedAt,
153
- });
154
- const publication = await updateRefsAtomically(input.repository, [
155
- {
156
- ref: GIT_REF,
157
- newOid: commit,
158
- expectedOid: snapshot.commit,
159
- },
160
- ]);
161
- if (publication.kind === "published")
162
- return { kind: "dispatched", dispatch: intended };
163
- const observed = await observedPublication(input.repository, akuId, owner);
164
- if (observed !== null)
165
- return observed;
166
- if (publication.kind === "non-published") {
167
- const fresh = await readGitPaths(input.repository, [path]);
168
- if (fresh.commit === snapshot.commit) {
169
- return {
170
- kind: "failed",
171
- failure: { kind: "publication-failed", diagnostic: diagnostic(publication.error) },
172
- };
173
- }
126
+ return await withPrivateStatePublicationSeat(input.repository, async (seat) => {
127
+ const snapshot = await readGitPaths(input.repository, [path]);
128
+ const current = await dispatchFromSnapshot(input.repository, snapshot, akuId);
129
+ if (current !== null) {
130
+ if (current.contractId === owner)
131
+ confirmPrivateStatePublication(seat);
132
+ return current.contractId === owner
133
+ ? { kind: "dispatched", dispatch: current }
134
+ : { kind: "failed", failure: { kind: "conflict", current } };
135
+ }
136
+ const changes = new Map();
137
+ if (snapshot.commit === null) {
138
+ changes.set(GIT_FORMAT_PATH, { oid: await writeBlob(input.repository, GIT_FORMAT_BYTES) });
139
+ }
140
+ changes.set(path, { oid: await writeBlob(input.repository, bytesFor(intended)) });
141
+ const tree = await updateGitTree(input.repository, snapshot.tree, changes);
142
+ const commit = await writeStateCommit({
143
+ repository: input.repository,
144
+ tree,
145
+ parent: snapshot.commit,
146
+ message: `dispatch ${akuId}`,
147
+ at: intended.dispatchedAt,
148
+ });
149
+ const publication = await updateRefsAtomically(input.repository, [
150
+ {
151
+ ref: GIT_REF,
152
+ newOid: commit,
153
+ expectedOid: snapshot.commit,
154
+ },
155
+ ]);
156
+ if (publication.kind === "published") {
157
+ confirmPrivateStatePublication(seat);
158
+ return { kind: "dispatched", dispatch: intended };
159
+ }
160
+ const observed = await observedPublication(input.repository, akuId, owner);
161
+ if (observed !== null) {
162
+ if (observed.kind === "dispatched")
163
+ confirmPrivateStatePublication(seat);
164
+ return observed;
165
+ }
166
+ if (publication.kind === "non-published") {
167
+ const fresh = await readGitPaths(input.repository, [path]);
168
+ if (fresh.commit === snapshot.commit) {
169
+ return {
170
+ kind: "failed",
171
+ failure: { kind: "publication-failed", diagnostic: diagnostic(publication.error) },
172
+ };
174
173
  }
175
174
  }
176
- return { kind: "failed", failure: { kind: "contention" } };
177
- }
178
- finally {
179
- held.close();
180
- }
175
+ return {
176
+ kind: "failed",
177
+ failure: { kind: "publication-failed", diagnostic: "Dispatch publication outcome is unknown" },
178
+ };
179
+ });
181
180
  }
@@ -1,5 +1,5 @@
1
1
  import { decodeJournal, encodeEntry } from "../core/facts/codec.js";
2
- import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, updateGitTreeFromFrozenDirectories, updateRefsAtomically, writeBlob, writeCommit, } from "./repository.js";
2
+ import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, updateGitTreeFromFrozenDirectories, updateRefsAtomically, writeBlob, writeStateCommit, } from "./repository.js";
3
3
  import { contractJournalPath, contractJournalPaths, gitObjectIdForSnapshot, mintContractHead, mintSnapshotId, } from "./identity.js";
4
4
  import { validPath } from "./tree.js";
5
5
  const CONTRACT_JOURNAL_PATH = /^contracts\/(?:active|terminal)\/[0-9a-f]{2}\/[0-9a-f]{2}\/[0-9a-f]{60}\.jsonl$/u;
@@ -86,7 +86,7 @@ async function buildOffer(repository, admission, appends, companions) {
86
86
  async function publishOffer(repository, admission, target, changes, assertions) {
87
87
  const { snapshot } = admission;
88
88
  const gitTree = await updateGitTreeFromFrozenDirectories(repository, snapshot.tree, admission.treeDirectories, changes);
89
- const gitCommit = mintSnapshotId(await writeCommit({
89
+ const gitCommit = mintSnapshotId(await writeStateCommit({
90
90
  repository,
91
91
  tree: gitTree,
92
92
  parent: snapshot.commit,
@@ -1,4 +1,5 @@
1
1
  export type HookCommand = Readonly<{
2
+ name: string;
2
3
  argv: readonly string[];
3
4
  timeoutMs: number;
4
5
  }>;
@@ -25,18 +26,10 @@ export type WorktreeHookLag = Readonly<{
25
26
  phase: HookPhase;
26
27
  path: string;
27
28
  command: number;
29
+ name: string;
28
30
  failure: HookFailure;
29
31
  }>;
30
- type HookPhase = "create" | "destroy";
31
- export declare function hookMarkerPath(administrationDirectory: string): string;
32
- export type WorktreeHookMarkerObservation = Readonly<{
33
- kind: "absent" | "pending" | "ok";
34
- }> | Readonly<{
35
- kind: "failed";
36
- diagnostic: string;
37
- }>;
38
- /** Read the durable hook marker without executing commands or taking locks. */
39
- export declare function observeWorktreeHookMarker(administrationDirectory: string): Promise<WorktreeHookMarkerObservation>;
32
+ export type HookPhase = "create" | "destroy";
40
33
  export type HookCommandRun = Readonly<{
41
34
  kind: "ok";
42
35
  }> | Readonly<{
@@ -48,8 +41,9 @@ export type HookCommandRun = Readonly<{
48
41
  }>;
49
42
  /** Execute an ordered command list without lifecycle state. Scratch owns this policy. */
50
43
  export declare function runHookCommands(worktree: string, commands: readonly HookCommand[], signal?: AbortSignal): Promise<HookCommandRun>;
51
- /** Remove validated Keiyaku hook state after its worktree has been reset. */
52
- export declare function nukeWorktreeHookResidue(administrationDirectory: string): Promise<void>;
53
- export declare function runCreateHooks(worktree: string, administrationDirectory: string, hooks: WorktreeHooks, retryHooks: boolean): Promise<WorktreeHookLag | null>;
54
- export declare function runDestroyHooks(worktree: string, administrationDirectory: string, hooks: WorktreeHooks, retryHooks: boolean): Promise<WorktreeHookLag | null>;
55
- export {};
44
+ export type HookPhaseRun = Readonly<{
45
+ lag: WorktreeHookLag | null;
46
+ runs: readonly string[];
47
+ }>;
48
+ export declare function runCreateHooks(worktree: string, hooks: WorktreeHooks): Promise<HookPhaseRun>;
49
+ export declare function runDestroyHooks(worktree: string, hooks: WorktreeHooks): Promise<HookPhaseRun>;