@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.
- package/README.md +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +12 -11
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +33 -12
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +392 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/archetype.js +1 -1
- package/build/src/akuma/body.d.ts +8 -5
- package/build/src/akuma/body.js +12 -5
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +16 -78
- package/build/src/akuma/heart/facts.js +11 -0
- package/build/src/akuma/heart/index.d.ts +3 -2
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +907 -137
- package/build/src/akuma/projection.js +193 -9
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +111 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/events.d.ts +2 -2
- package/build/src/akuma/providers/claude/events.js +16 -3
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.d.ts +2 -2
- package/build/src/akuma/providers/codex-app-server/events.js +25 -4
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +72 -58
- package/build/src/akuma/request-lifecycle.d.ts +4 -10
- package/build/src/akuma/request-lifecycle.js +7 -5
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +6 -66
- package/build/src/akuma/request-serve.js +83 -210
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +39 -11
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/body/amend.js +18 -19
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +8 -8
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +42 -30
- package/build/src/cli/commands/contract.d.ts +16 -20
- package/build/src/cli/commands/contract.js +58 -25
- package/build/src/cli/commands/install.d.ts +2 -1
- package/build/src/cli/commands/install.js +3 -2
- package/build/src/cli/commands/task-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +56 -27
- package/build/src/cli/render/akuma-activity.d.ts +3 -0
- package/build/src/cli/render/akuma-activity.js +45 -29
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +4 -8
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +35 -62
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +132 -0
- package/build/src/cli/render/kanshi.js +131 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +32 -1
- package/build/src/cli/render/terminal.js +77 -1
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +4 -2
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +39 -21
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +26 -11
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +13 -1
- package/build/src/git/reconcile.js +70 -11
- package/build/src/git/ref-migration.d.ts +22 -0
- package/build/src/git/ref-migration.js +55 -0
- package/build/src/git/repository.d.ts +10 -6
- package/build/src/git/repository.js +16 -8
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +14 -6
- package/build/src/library/audit.js +13 -23
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +385 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +102 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +92 -0
- package/build/src/library/contract-forwarding-result.d.ts +4464 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +71 -0
- package/build/src/library/contract-forwarding.js +114 -0
- package/build/src/library/contract-handle.d.ts +38 -0
- package/build/src/library/contract-handle.js +314 -0
- package/build/src/library/contract-operations.d.ts +214 -69
- package/build/src/library/contract-operations.js +189 -118
- package/build/src/library/contract-types.d.ts +7 -3
- package/build/src/library/contract.d.ts +21 -34
- package/build/src/library/contract.js +29 -287
- package/build/src/library/fleet-result.d.ts +1580 -0
- package/build/src/library/fleet-result.js +98 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +3 -1
- package/build/src/library/input.js +11 -1
- package/build/src/library/keiyaku.d.ts +388 -20
- package/build/src/library/keiyaku.js +13 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +9 -0
- package/build/src/runtime/proc/run.js +51 -4
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- 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
|
+
}
|
|
@@ -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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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")) !==
|
|
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"
|
|
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 {
|
|
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
|
-
|
|
34
|
-
|
|
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,
|
|
@@ -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 {
|
|
7
|
-
import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readBlob, readGitPaths, updateGitTree, updateRefsAtomically, writeBlob,
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
if (observed
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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 {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
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,
|
|
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
|
|
89
|
+
const gitCommit = mintSnapshotId(await writeStateCommit({
|
|
90
90
|
repository,
|
|
91
91
|
tree: gitTree,
|
|
92
92
|
parent: snapshot.commit,
|
package/build/src/git/hooks.d.ts
CHANGED
|
@@ -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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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>;
|