@astrosheep/keiyaku 4.6.1 → 4.6.3

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 (55) hide show
  1. package/README.md +93 -45
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +3 -2
  3. package/build/src/akuma/providers/pi/events.js +3 -2
  4. package/build/src/akuma/providers/pi/index.d.ts +3 -4
  5. package/build/src/akuma/providers/pi/index.js +30 -26
  6. package/build/src/body/render.d.ts +9 -1
  7. package/build/src/body/render.js +11 -0
  8. package/build/src/cli/commands/akuma-grammar.js +12 -3
  9. package/build/src/cli/commands/akuma.js +6 -0
  10. package/build/src/cli/commands/contract-grammar.js +7 -0
  11. package/build/src/cli/commands/contract-help.d.ts +1 -1
  12. package/build/src/cli/commands/contract-help.js +21 -9
  13. package/build/src/cli/commands/contract.js +3 -1
  14. package/build/src/cli/commands/task-grammar.js +9 -7
  15. package/build/src/cli/parse.js +5 -0
  16. package/build/src/cli/render/akuma-activity.d.ts +26 -6
  17. package/build/src/cli/render/akuma-activity.js +128 -118
  18. package/build/src/cli/render/akuma-tool.js +1 -1
  19. package/build/src/cli/render/audit.js +4 -6
  20. package/build/src/cli/render/catalog.js +7 -4
  21. package/build/src/cli/render/contract-history.js +8 -18
  22. package/build/src/cli/render/contract.js +5 -10
  23. package/build/src/cli/render/kanshi-akuma.js +1 -1
  24. package/build/src/cli/render/kanshi.js +24 -30
  25. package/build/src/cli/render/receipt.d.ts +1 -2
  26. package/build/src/cli/render/receipt.js +1 -6
  27. package/build/src/cli/render/refusal.js +2 -1
  28. package/build/src/cli/render/task.js +2 -1
  29. package/build/src/core/facts/codec.js +0 -6
  30. package/build/src/core/facts/fold.js +0 -7
  31. package/build/src/core/facts/types.d.ts +1 -4
  32. package/build/src/core/verbs/deliver.js +2 -14
  33. package/build/src/library/bind.d.ts +20 -20
  34. package/build/src/library/bind.js +2 -1
  35. package/build/src/library/contract-composition.d.ts +5 -2
  36. package/build/src/library/contract-composition.js +5 -3
  37. package/build/src/library/contract-creation.d.ts +7 -1
  38. package/build/src/library/contract-creation.js +19 -9
  39. package/build/src/library/contract-execution.d.ts +1 -0
  40. package/build/src/library/contract-execution.js +12 -4
  41. package/build/src/library/contract-settings.d.ts +2 -2
  42. package/build/src/library/contract-settings.js +21 -12
  43. package/build/src/library/outcome.d.ts +476 -652
  44. package/build/src/library/refusal.d.ts +2 -2
  45. package/build/src/protocol/bind.d.ts +1 -1
  46. package/build/src/protocol/deliver.js +1 -1
  47. package/build/src/protocol/execution-observation.d.ts +0 -8
  48. package/build/src/protocol/intent.js +2 -2
  49. package/build/src/protocol/operations.d.ts +1 -1
  50. package/build/src/protocol/read/status.d.ts +1 -1
  51. package/build/src/protocol/read/status.js +0 -2
  52. package/build/src/runtime/proc/windows-launch.exe +0 -0
  53. package/build/src/world.d.ts +1 -0
  54. package/build/src/world.js +14 -0
  55. package/package.json +3 -3
@@ -19,9 +19,9 @@ function contractStatusTone(row, observedAt) {
19
19
  if (contractHasError(row))
20
20
  return "alert";
21
21
  const phaseAge = elapsedMilliseconds(row.phaseAt, observedAt);
22
- if (row.phase === "delivered" && phaseAge !== null && phaseAge >= REVIEW_ATTENTION_MS)
22
+ if (row.phase === "bound" && row.delivery !== null && phaseAge !== null && phaseAge >= REVIEW_ATTENTION_MS)
23
23
  return "attention";
24
- if (row.phase === "bound" && phaseAge !== null && phaseAge >= PENDING_ATTENTION_MS)
24
+ if (row.phase === "bound" && row.delivery === null && phaseAge !== null && phaseAge >= PENDING_ATTENTION_MS)
25
25
  return "attention";
26
26
  const journalAge = elapsedMilliseconds(row.lastJournalAt, observedAt);
27
27
  return journalAge !== null && journalAge <= RECENT_TONE_MS ? "recent" : null;
@@ -153,34 +153,28 @@ function renderSelectedContractRow(row, report, context, abbreviations) {
153
153
  lines.push(...outcome.map((fact) => (fact.startsWith(" ") ? fact : ` ${safeText(fact)}`)));
154
154
  return lines;
155
155
  }
156
- if (row.phase === "bound") {
157
- lines.push(...semanticBlock("gates", row.gates.reports.map(gateFact), context));
158
- lines.push(...semanticBlock("prerequisites", row.after.filter((edge) => edge.endpoint.kind !== "claimed").map(afterWording), context));
159
- lines.push(...semanticBlock("ball", [progressStrip(row)], context));
160
- const akuma = linkedAkumaSummary(row, report);
161
- if (akuma !== undefined)
162
- lines.push(...semanticBlock("akuma", [akuma], context));
163
- if (row.worktreePath !== null)
164
- lines.push(...semanticBlock("worktree", [`worktree ${row.worktreePath}`], context));
165
- }
166
- else {
167
- lines.push(...semanticBlock("ball", [progressStrip(row)], context));
168
- lines.push(...semanticBlock("prerequisites", row.after.filter((edge) => edge.endpoint.kind !== "claimed").map(afterWording), context));
169
- if (row.delivery !== null) {
170
- lines.push(...semanticBlock("candidate", [
171
- `candidate ${displayGitId(row.delivery.tenderSnapshot, abbreviations)}`,
172
- `integration result ${displayGitId(row.delivery.integration.snapshot, abbreviations)}${row.verification?.kind === "recorded" && row.verification.snapshot === row.delivery.integration.snapshot ? ` · verification ${row.verification.verdict}` : ""}${row.targetObservation?.drift === true ? " · target moved since" : ""}`,
173
- ...(row.targetObservation?.drift === true ? targetMovementFacts(row, abbreviations) : []),
174
- ], context));
175
- }
156
+ const deniedReview = row.gates.reports.find((gate) => gate.gate === "reviewed" && gate.current.kind === "attested" && gate.current.verdict === "unsatisfied");
157
+ lines.push(...semanticBlock("ball", [progressStrip(row)], context));
158
+ lines.push(...semanticBlock("gates", row.gates.reports
159
+ .filter((gate) => gate.current.kind !== "missing")
160
+ .filter((gate) => gate !== deniedReview || gate.current.kind !== "attested" || gate.current.summary === undefined)
161
+ .map(gateFact), context));
162
+ lines.push(...semanticBlock("prerequisites", row.after.filter((edge) => edge.endpoint.kind !== "claimed").map(afterWording), context));
163
+ if (row.delivery !== null) {
164
+ lines.push(...semanticBlock("candidate", [
165
+ `candidate ${displayGitId(row.delivery.tenderSnapshot, abbreviations)}`,
166
+ `integration result ${displayGitId(row.delivery.integration.snapshot, abbreviations)}${row.verification?.kind === "recorded" && row.verification.snapshot === row.delivery.integration.snapshot ? ` · verification ${row.verification.verdict}` : ""}${row.targetObservation?.drift === true ? " · target moved since" : ""}`,
167
+ ...(row.targetObservation?.drift === true ? targetMovementFacts(row, abbreviations) : []),
168
+ ], context));
176
169
  lines.push(...semanticBlock("verification", staleVerificationFacts(row), context));
177
- const deniedReview = row.gates.reports.find((gate) => gate.gate === "reviewed" && gate.current.kind === "attested" && gate.current.verdict === "unsatisfied");
178
- lines.push(...semanticBlock("gates", row.gates.reports
179
- .filter((gate) => gate !== deniedReview || gate.current.kind !== "attested" || gate.current.summary === undefined)
180
- .map(gateFact), context));
181
- if (deniedReview?.current.kind === "attested" && deniedReview.current.summary !== undefined)
182
- lines.push(...payload("review ×", deniedReview.current.summary, context));
183
170
  }
171
+ if (deniedReview?.current.kind === "attested" && deniedReview.current.summary !== undefined)
172
+ lines.push(...payload("review ×", deniedReview.current.summary, context));
173
+ const akuma = linkedAkumaSummary(row, report);
174
+ if (akuma !== undefined)
175
+ lines.push(...semanticBlock("akuma", [akuma], context));
176
+ if (row.worktreePath !== null)
177
+ lines.push(...semanticBlock("worktree", [`worktree ${row.worktreePath}`], context));
184
178
  lines.push(...semanticBlock("alarms", liveAlarms(row, report), context));
185
179
  return lines;
186
180
  }
@@ -209,7 +203,7 @@ function renderWorldContractRow(row, report, context) {
209
203
  function renderContracts(report, context) {
210
204
  const section = report.contracts;
211
205
  if (section.kind === "absent")
212
- return ["CONTRACTS // absent", "", " contracts absent"];
206
+ return ["CONTRACTS // absent"];
213
207
  if (section.kind === "failed")
214
208
  return ["CONTRACTS // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
215
209
  if (section.value.rows.length === 0)
@@ -238,7 +232,7 @@ function taskFailureFact(failure) {
238
232
  function renderTasks(report, context) {
239
233
  const section = report.tasks;
240
234
  if (section.kind === "absent")
241
- return ["TASKS // absent", "", " tasks absent"];
235
+ return ["TASKS // absent"];
242
236
  if (section.kind === "failed")
243
237
  return [
244
238
  "TASKS // unavailable",
@@ -1,5 +1,5 @@
1
1
  import type { ExecutionCleanup, ExecutionStop, PartialOutcomeEnvelope, ReconciliationLag } from "../../index.js";
2
- import type { PlacementStop, VerificationReuse, VerificationStop } from "../../index.js";
2
+ import type { PlacementStop, VerificationStop } from "../../index.js";
3
3
  export type ReceiptSegment = Readonly<{
4
4
  text: string;
5
5
  opaque?: boolean;
@@ -14,7 +14,6 @@ export declare function refusalLines(verb: string, facts: readonly string[], col
14
14
  export declare function titleLines(mark: string, title: string, contract: string, columns?: number): string[];
15
15
  export declare function hookFailureSummary(failure: HookFailure): string;
16
16
  export declare function appendHookPayload(lines: string[], failure: HookFailure): void;
17
- export declare function reuseLines(reuse: VerificationReuse | undefined, columns: number): readonly string[];
18
17
  /**
19
18
  * The pending margin statement: the not-yet-happened requirements a refused placement awaits. A gate in stale
20
19
  * state awaits the same event; when every unmet gate already holds a recorded verdict there is nothing pending and
@@ -64,11 +64,6 @@ export function appendHookPayload(lines, failure) {
64
64
  if (failure.stderr !== undefined && failure.stderr.length > 0)
65
65
  receiptPayload(lines, "stderr", failure.stderr);
66
66
  }
67
- export function reuseLines(reuse, columns) {
68
- if (reuse === undefined)
69
- return [];
70
- return renderOpaqueBlock(`reuse verified · ${reuse.verdict}`, " ", columns);
71
- }
72
67
  function prerequisiteRows(stop, columns) {
73
68
  if (!("refusal" in stop) || stop.refusal?.kind !== "prerequisites-unsatisfied")
74
69
  return [];
@@ -97,7 +92,7 @@ function gateAlarmRows(stop, columns) {
97
92
  continue;
98
93
  receiptRow(lines, "!", eventNoun(gate), [{ text: `· ${current.verdict}` }, { text: `· at ${current.at}` }], columns);
99
94
  if (current.summary !== undefined)
100
- receiptPayload(lines, ` summary ${gate}`, current.summary);
95
+ receiptPayload(lines, " summary", current.summary);
101
96
  }
102
97
  return lines;
103
98
  }
@@ -104,7 +104,8 @@ function refusalFacts(refusal, indent, columns, addressed) {
104
104
  if (identity !== undefined)
105
105
  lines.push(`${indent}contract ${safeText(identity)}`);
106
106
  if ("diagnostic" in refusal && typeof refusal.diagnostic === "string")
107
- lines.push(`${indent}detail ${safeText(refusal.diagnostic)}`);
107
+ for (const detail of refusal.diagnostic.split("\n"))
108
+ lines.push(`${indent}detail ${safeText(detail)}`);
108
109
  return lines;
109
110
  }
110
111
  export function renderRefusalFacts(refusal, indent, columns, addressed) {
@@ -246,7 +246,8 @@ function renderBatchItem(verb, item, columns) {
246
246
  if (item.outcome.kind === "retry")
247
247
  return `? ${verb} ${item.id} ${item.outcome.reason}`;
248
248
  const facts = projectRefusal(item.outcome.refusal);
249
- return refusalLines(verb, [`task ${item.id}`, `reason ${facts.diagnostic}`, ...(facts.facts ?? [])], columns).join("\n");
249
+ const rest = (facts.facts ?? []).filter((fact) => fact !== `task ${item.id}`);
250
+ return refusalLines(verb, [`task ${item.id}`, `reason ${facts.diagnostic}`, ...rest], columns).join("\n");
250
251
  }
251
252
  function renderBatch(verb, batch, columns) {
252
253
  return batch.items.map((item) => renderBatchItem(verb, item, columns)).join("\n");
@@ -4,7 +4,6 @@ import { changeId, actorId, contractId, documentKey, documentSegmentKey, entryUl
4
4
  const VERSION_BY_KIND = {
5
5
  bind: 1,
6
6
  amend: 1,
7
- bound: 1,
8
7
  deliver: 1,
9
8
  reintegrated: 1,
10
9
  attestation: 1,
@@ -158,11 +157,6 @@ function validateData(kind, value) {
158
157
  }
159
158
  case "amend":
160
159
  return termsValue(value, path);
161
- case "bound": {
162
- const object = requireRecord(value, path);
163
- requireKeys(object, [], path);
164
- return {};
165
- }
166
160
  case "deliver": {
167
161
  const object = requireRecord(value, path);
168
162
  requireKeys(object, ["tenderSnapshot", "integration", "method", "policy"], path);
@@ -22,7 +22,6 @@ function stateFromBind(id, head, bind, attestations) {
22
22
  head,
23
23
  coordinates: cloneCoordinates(bind.data.coordinates),
24
24
  terms: cloneTerms(bind.data.terms),
25
- bound: null,
26
25
  delivery: null,
27
26
  currentIntegration: null,
28
27
  attestations,
@@ -49,13 +48,7 @@ function foldEntry(state, entry, attestations) {
49
48
  foldError("bind may appear only once");
50
49
  case "amend":
51
50
  return { ...state, terms: cloneTerms(entry.data) };
52
- case "bound":
53
- if (state.bound !== null)
54
- foldError("bound may appear only once");
55
- return { ...state, bound: entry };
56
51
  case "deliver":
57
- if (state.bound === null)
58
- foldError("deliver requires bound");
59
52
  return { ...state, delivery: entry, currentIntegration: { ...entry.data.integration } };
60
53
  case "reintegrated":
61
54
  if (state.delivery === null)
@@ -72,7 +72,6 @@ export type BindData = Readonly<{
72
72
  terms: ContractTerms;
73
73
  }>;
74
74
  export type AmendData = ContractTerms;
75
- export type BoundData = Readonly<Record<string, never>>;
76
75
  export type DeliverData = Readonly<{
77
76
  tenderSnapshot: SnapshotId;
78
77
  integration: Readonly<{
@@ -118,14 +117,13 @@ type JournalEnvelope<Kind extends string, Data> = Readonly<{
118
117
  }>;
119
118
  export type BindEntry = JournalEnvelope<"bind", BindData>;
120
119
  type AmendEntry = JournalEnvelope<"amend", AmendData>;
121
- type BoundEntry = JournalEnvelope<"bound", BoundData>;
122
120
  type DeliverEntry = JournalEnvelope<"deliver", DeliverData>;
123
121
  export type ReintegratedEntry = JournalEnvelope<"reintegrated", ReintegratedData>;
124
122
  export type AttestationEntry = JournalEnvelope<"attestation", AttestationData>;
125
123
  type ClaimedEntry = JournalEnvelope<"claimed", ClaimedData>;
126
124
  export type ArcEntry = JournalEnvelope<"arc", ArcData>;
127
125
  type AbandonedEntry = JournalEnvelope<"abandoned", AbandonedData>;
128
- export type JournalEntry = BindEntry | AmendEntry | BoundEntry | DeliverEntry | ReintegratedEntry | AttestationEntry | ClaimedEntry | ArcEntry | AbandonedEntry;
126
+ export type JournalEntry = BindEntry | AmendEntry | DeliverEntry | ReintegratedEntry | AttestationEntry | ClaimedEntry | ArcEntry | AbandonedEntry;
129
127
  export type FactKind = JournalEntry["kind"];
130
128
  type ContractTerminal = ClaimedEntry | AbandonedEntry;
131
129
  export type ContractState = Readonly<{
@@ -133,7 +131,6 @@ export type ContractState = Readonly<{
133
131
  head: ContractHead | null;
134
132
  coordinates: ContractCoordinates;
135
133
  terms: ContractTerms;
136
- bound: BoundEntry | null;
137
134
  delivery: DeliverEntry | null;
138
135
  currentIntegration: CurrentIntegration | null;
139
136
  attestations: readonly AttestationEntry[];
@@ -11,26 +11,14 @@ export function decideDeliver({ input, attempt, observation, }) {
11
11
  }
12
12
  if (input.preparation.kind === "refused")
13
13
  return { kind: "refused", refusal: input.preparation.refusal };
14
- const entries = [];
15
- if (state.bound === null)
16
- entries.push({
17
- v: 1,
18
- kind: "bound",
19
- contract: input.contractId,
20
- entry: attempt.entryUlids[0],
21
- at: input.at,
22
- ...(input.actor === undefined ? {} : { actor: input.actor }),
23
- data: {},
24
- });
25
14
  const deliver = {
26
15
  v: 1,
27
16
  kind: "deliver",
28
17
  contract: input.contractId,
29
- entry: attempt.entryUlids[state.bound === null ? 1 : 0],
18
+ entry: attempt.entryUlids[0],
30
19
  at: input.at,
31
20
  ...(input.actor === undefined ? {} : { actor: input.actor }),
32
21
  data: input.preparation.data,
33
22
  };
34
- entries.push(deliver);
35
- return { kind: "offer", offer: { facts: [{ contractId: input.contractId, entries }] } };
23
+ return { kind: "offer", offer: { facts: [{ contractId: input.contractId, entries: [deliver] }] } };
36
24
  }
@@ -26,16 +26,16 @@ type BindAttemptInput = Readonly<{
26
26
  export declare function admitBindWithAppointment(input: BindAttemptInput): Promise<IntentOutcome<Readonly<{
27
27
  contractId: ContractId;
28
28
  }>, {
29
+ kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
30
+ contractId: ContractId;
31
+ } | {
29
32
  kind: "verification-declaration-invalid";
30
33
  contractId?: ContractId | undefined;
31
- } | {
32
- kind: "target-missing" | "unborn-head" | "invalid-target";
33
34
  } | {
34
35
  kind: "fork-source-moved";
35
36
  contractId: ContractId;
36
37
  } | {
37
- kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
38
- contractId: ContractId;
38
+ kind: "unborn-head" | "target-missing" | "invalid-target";
39
39
  } | {
40
40
  kind: "fork-source-missing" | "fork-source-unavailable";
41
41
  contractId: ContractId;
@@ -76,16 +76,16 @@ export declare function admitMarkdownBind(input: Readonly<{
76
76
  }>): Promise<IntentOutcome<Readonly<{
77
77
  contractId: ContractId;
78
78
  }>, {
79
+ kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
80
+ contractId: ContractId;
81
+ } | {
79
82
  kind: "verification-declaration-invalid";
80
83
  contractId?: ContractId | undefined;
81
- } | {
82
- kind: "target-missing" | "unborn-head" | "invalid-target";
83
84
  } | {
84
85
  kind: "fork-source-moved";
85
86
  contractId: ContractId;
86
87
  } | {
87
- kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
88
- contractId: ContractId;
88
+ kind: "unborn-head" | "target-missing" | "invalid-target";
89
89
  } | {
90
90
  kind: "fork-source-missing" | "fork-source-unavailable";
91
91
  contractId: ContractId;
@@ -107,16 +107,16 @@ export declare function prepareMarkdownBind(input: Readonly<{
107
107
  result: IntentOutcome<Readonly<{
108
108
  contractId: ContractId;
109
109
  }>, {
110
+ kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
111
+ contractId: ContractId;
112
+ } | {
110
113
  kind: "verification-declaration-invalid";
111
114
  contractId?: ContractId | undefined;
112
- } | {
113
- kind: "target-missing" | "unborn-head" | "invalid-target";
114
115
  } | {
115
116
  kind: "fork-source-moved";
116
117
  contractId: ContractId;
117
118
  } | {
118
- kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
119
- contractId: ContractId;
119
+ kind: "unborn-head" | "target-missing" | "invalid-target";
120
120
  } | {
121
121
  kind: "fork-source-missing" | "fork-source-unavailable";
122
122
  contractId: ContractId;
@@ -126,16 +126,16 @@ export declare function prepareMarkdownBind(input: Readonly<{
126
126
  result: IntentOutcome<Readonly<{
127
127
  contractId: ContractId;
128
128
  }>, {
129
+ kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
130
+ contractId: ContractId;
131
+ } | {
129
132
  kind: "verification-declaration-invalid";
130
133
  contractId?: ContractId | undefined;
131
- } | {
132
- kind: "target-missing" | "unborn-head" | "invalid-target";
133
134
  } | {
134
135
  kind: "fork-source-moved";
135
136
  contractId: ContractId;
136
137
  } | {
137
- kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
138
- contractId: ContractId;
138
+ kind: "unborn-head" | "target-missing" | "invalid-target";
139
139
  } | {
140
140
  kind: "fork-source-missing" | "fork-source-unavailable";
141
141
  contractId: ContractId;
@@ -146,16 +146,16 @@ export declare function prepareMarkdownBind(input: Readonly<{
146
146
  result: IntentOutcome<Readonly<{
147
147
  contractId: ContractId;
148
148
  }>, {
149
+ kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
150
+ contractId: ContractId;
151
+ } | {
149
152
  kind: "verification-declaration-invalid";
150
153
  contractId?: ContractId | undefined;
151
- } | {
152
- kind: "target-missing" | "unborn-head" | "invalid-target";
153
154
  } | {
154
155
  kind: "fork-source-moved";
155
156
  contractId: ContractId;
156
157
  } | {
157
- kind: "contract-exists" | "invalid-after" | "unknown-prerequisite";
158
- contractId: ContractId;
158
+ kind: "unborn-head" | "target-missing" | "invalid-target";
159
159
  } | {
160
160
  kind: "fork-source-missing" | "fork-source-unavailable";
161
161
  contractId: ContractId;
@@ -1,5 +1,6 @@
1
1
  import { randomBytes } from "node:crypto";
2
2
  import { decodeContractDocument } from "../body/decode.js";
3
+ import { decodeCanonicalContractDocument } from "../body/render.js";
3
4
  import { contractIdFromSegment } from "../core/facts/types.js";
4
5
  import { AuthorityCorruptionError } from "../core/facts/errors.js";
5
6
  import { mintIdentitySegment } from "../identity/mint.js";
@@ -92,7 +93,7 @@ export async function admitForkBindWithAppointment(input) {
92
93
  });
93
94
  }
94
95
  const markdown = sourceDocument.document.bytes.replace(/^\s*#\s*[^\r\n]*(?:\r?\n|$)/u, `# Fork · ${sourceDocument.title}${sourceDocument.document.bytes.includes("\r\n") ? "\r\n" : "\n"}`);
95
- const document = decodeContractDocument(markdown, { requireTimeout: true });
96
+ const document = decodeCanonicalContractDocument(markdown, { requireTimeout: true });
96
97
  const terms = contractTerms(document, source.terms.gates, source.terms.after);
97
98
  const admission = await attemptCandidates({
98
99
  scope: input.scope,
@@ -1,5 +1,6 @@
1
1
  /** @architectureCompositionRoot */
2
2
  import { type LibraryExecution } from "../akuma/requests.js";
3
+ import type { BindTargetSelection } from "../protocol/bind.js";
3
4
  import type { ContractObservation } from "../protocol/read/status.js";
4
5
  import type { BindOutcome } from "./contract-outcomes.js";
5
6
  import type { BindInput, ContractList, ContractListInput, ContractObservationInput, KeiyakuSelectInput, LocalContractComposition } from "./contract-types.js";
@@ -31,9 +32,11 @@ export type KeiyakuLibrary = Readonly<{
31
32
  * The one private Contract composition constructor. `Keiyaku.with` fixes local execution; CLI and
32
33
  * Body pass their captured internal channel explicitly here instead of a second constructor. The
33
34
  * carrier is a positional argument, never a field of the public construction input, so no runtime
34
- * value reaching the public surface can select a private channel.
35
+ * value reaching the public surface can select a private channel. `omittedMarkdownTarget` is the
36
+ * internal bind intent an edge supplies for a Markdown bind whose caller omitted the target; the
37
+ * public package-root composition leaves it targetless.
35
38
  */
36
- export declare function composeContractLibrary(execution: LibraryExecution, createHandle: typeof createKeiyakuHandle, input?: LocalContractComposition): KeiyakuLibrary;
39
+ export declare function composeContractLibrary(execution: LibraryExecution, createHandle: typeof createKeiyakuHandle, input?: LocalContractComposition, omittedMarkdownTarget?: BindTargetSelection): KeiyakuLibrary;
37
40
  export declare function listKeiyaku(input: ContractListInput): Promise<ContractList>;
38
41
  export declare function observeKeiyaku(input: ContractObservationInput): Promise<ContractObservation>;
39
42
  export declare function readContractValue<Value>(operation: () => Promise<Value>): Promise<Value>;
@@ -13,12 +13,14 @@ import { scopeForRepo } from "./repo.js";
13
13
  * The one private Contract composition constructor. `Keiyaku.with` fixes local execution; CLI and
14
14
  * Body pass their captured internal channel explicitly here instead of a second constructor. The
15
15
  * carrier is a positional argument, never a field of the public construction input, so no runtime
16
- * value reaching the public surface can select a private channel.
16
+ * value reaching the public surface can select a private channel. `omittedMarkdownTarget` is the
17
+ * internal bind intent an edge supplies for a Markdown bind whose caller omitted the target; the
18
+ * public package-root composition leaves it targetless.
17
19
  */
18
- export function composeContractLibrary(execution, createHandle, input) {
20
+ export function composeContractLibrary(execution, createHandle, input, omittedMarkdownTarget = { kind: "targetless" }) {
19
21
  const composition = captureLocalContractComposition(input);
20
22
  return Object.freeze({
21
- bind: (operation) => bindKeiyaku(operation, createHandle, execution, composition),
23
+ bind: (operation) => bindKeiyaku(operation, createHandle, execution, composition, omittedMarkdownTarget),
22
24
  select: (operation) => selectKeiyaku(operation, createHandle, execution, composition),
23
25
  list: (operation) => listKeiyaku(operation),
24
26
  observe: (operation) => observeKeiyaku(operation),
@@ -1,7 +1,13 @@
1
1
  /** @architectureCompositionRoot */
2
2
  import { type ExecutionContext } from "../akuma/requests.js";
3
+ import type { BindTargetSelection } from "../protocol/bind.js";
3
4
  import type { BindOutcome } from "./contract-outcomes.js";
4
5
  import { type LocalContractCompositionCapture } from "./contract-settings.js";
5
6
  import type { BindInput } from "./contract-types.js";
6
7
  import type { createKeiyakuHandle } from "./keiyaku.js";
7
- export declare function bindKeiyaku(input: BindInput, createHandle: typeof createKeiyakuHandle, execution?: ExecutionContext, composition?: LocalContractCompositionCapture): Promise<BindOutcome>;
8
+ /**
9
+ * One Contract bind. `omittedMarkdownTarget` is the internal composition input an edge
10
+ * supplies for a Markdown bind whose caller omitted the target: the public package-root
11
+ * composition leaves it targetless, while the CLI names the invocation branch.
12
+ */
13
+ export declare function bindKeiyaku(input: BindInput, createHandle: typeof createKeiyakuHandle, execution?: ExecutionContext, composition?: LocalContractCompositionCapture, omittedMarkdownTarget?: BindTargetSelection): Promise<BindOutcome>;
@@ -1,6 +1,6 @@
1
1
  /** @architectureCompositionRoot */
2
2
  import { localExecutionContext } from "../akuma/requests.js";
3
- import { decodeContractDocument } from "../body/decode.js";
3
+ import { decodeCanonicalContractDocument } from "../body/render.js";
4
4
  import { regionWarnings } from "../body/region.js";
5
5
  import { contractId } from "../core/facts/types.js";
6
6
  import { withGitDecodeChannel } from "../git/read-observation.js";
@@ -33,6 +33,7 @@ function bindInput(input, composition) {
33
33
  if (typeof forkOf !== "string")
34
34
  throw new TypeError("forkOf must be a ContractId");
35
35
  }
36
+ const derived = forkOf === undefined ? derivedGates(composition, gateNames(values.gates)) : undefined;
36
37
  return {
37
38
  forkOf: forkOf === undefined ? undefined : contractId(forkOf),
38
39
  scope: scopeForRepo(values.repo),
@@ -40,12 +41,17 @@ function bindInput(input, composition) {
40
41
  actor,
41
42
  target: values.target,
42
43
  task: forkOf === undefined ? taskOption(values.task) : undefined,
43
- gates: forkOf === undefined ? derivedGates(composition, gateNames(values.gates)) : undefined,
44
+ gates: derived,
44
45
  after: forkOf === undefined ? normalizedList(values.after, "after", contractId) : undefined,
45
46
  };
46
47
  });
47
48
  }
48
- export async function bindKeiyaku(input, createHandle, execution = localExecutionContext(), composition = captureLocalContractComposition()) {
49
+ /**
50
+ * One Contract bind. `omittedMarkdownTarget` is the internal composition input an edge
51
+ * supplies for a Markdown bind whose caller omitted the target: the public package-root
52
+ * composition leaves it targetless, while the CLI names the invocation branch.
53
+ */
54
+ export async function bindKeiyaku(input, createHandle, execution = localExecutionContext(), composition = captureLocalContractComposition(), omittedMarkdownTarget = { kind: "targetless" }) {
49
55
  const prepared = bindInput(input, composition);
50
56
  const hooks = derivedHooks(composition);
51
57
  const { forkOf, scope, document, target, actor } = prepared;
@@ -78,7 +84,7 @@ export async function bindKeiyaku(input, createHandle, execution = localExecutio
78
84
  }
79
85
  if (document === undefined)
80
86
  throw new Error("Markdown bind requires its prepared document");
81
- return await markdownBind(prepared, document, hooks, scope, channel, accumulator, handle);
87
+ return await markdownBind(prepared, document, hooks, scope, channel, accumulator, handle, omittedMarkdownTarget);
82
88
  })();
83
89
  return completed;
84
90
  }, (error) => {
@@ -162,11 +168,11 @@ async function reconcileAll(accumulator, id, scope, channel, hooks) {
162
168
  }
163
169
  }
164
170
  // eslint-disable-next-line max-params -- Keep this local operation's custody, admission, and policy witnesses explicit.
165
- async function markdownBind(prepared, document, hooks, scope, channel, accumulator, handle) {
171
+ async function markdownBind(prepared, document, hooks, scope, channel, accumulator, handle, omittedMarkdownTarget) {
166
172
  const { task, target, actor, gates, after } = prepared;
167
173
  if (gates === undefined || after === undefined)
168
174
  throw new Error("Markdown bind requires prepared terms");
169
- const targetSelection = target !== undefined ? { kind: "explicit", target } : { kind: "targetless" };
175
+ const targetSelection = target !== undefined ? { kind: "explicit", target } : omittedMarkdownTarget;
170
176
  const admission = await prepareMarkdownBind({
171
177
  scope,
172
178
  channel,
@@ -183,10 +189,14 @@ async function markdownBind(prepared, document, hooks, scope, channel, accumulat
183
189
  if (leading.kind !== "accepted")
184
190
  return expected(undefined, leading);
185
191
  const id = leading.value.contractId;
186
- accumulator.extendConclusions(id, { keiyaku: handle(id), warnings: regionWarnings(document.region) });
187
- const value = await bindComplete(accumulator, id, scope, channel, leading, hooks, async () => bindValue(handle(id), await observeRegion(scope, channel, id, document.region), regionWarnings(document.region)));
192
+ const warnings = regionWarnings(document.region);
193
+ accumulator.extendConclusions(id, {
194
+ keiyaku: handle(id),
195
+ warnings,
196
+ });
197
+ const value = await bindComplete(accumulator, id, scope, channel, leading, hooks, async () => bindValue(handle(id), await observeRegion(scope, channel, id, document.region), warnings));
188
198
  return acceptedOutcome("bind", id, accumulator, value);
189
199
  }
190
200
  function parseMarkdown(markdown) {
191
- return decodeContractDocument(markdown, { requireTimeout: true });
201
+ return decodeCanonicalContractDocument(markdown, { requireTimeout: true });
192
202
  }
@@ -16,6 +16,7 @@ export declare class ContractExecution {
16
16
  private get scope();
17
17
  private get execution();
18
18
  private get composition();
19
+ private amendInput;
19
20
  amend(input: AmendInput): Promise<AmendOutcome>;
20
21
  /** One promise with an optional observation callback; observation never delays custody. */
21
22
  deliver(input?: DeliverInput, options?: MutationObservation): Promise<DeliverOutcome>;
@@ -44,16 +44,20 @@ export class ContractExecution {
44
44
  get composition() {
45
45
  return this.seat.composition;
46
46
  }
47
- async amend(input) {
48
- const { markdown, gates, prerequisites, actor } = validated(() => {
47
+ amendInput(input) {
48
+ return validated(() => {
49
49
  const values = requireInput(input, "amend input", ["actor", "markdown", "gates", "after"]);
50
+ const derived = values.gates === undefined ? undefined : derivedGates(this.composition, gateNames(values.gates));
50
51
  return {
51
52
  markdown: values.markdown === undefined ? undefined : requireMarkdown(values.markdown),
52
- gates: values.gates === undefined ? undefined : derivedGates(this.composition, gateNames(values.gates)),
53
+ gates: derived,
53
54
  prerequisites: values.after === undefined ? undefined : normalizedList(values.after, "after", contractId),
54
55
  actor: actorOption(values.actor).actor,
55
56
  };
56
57
  });
58
+ }
59
+ async amend(input) {
60
+ const { markdown, gates, prerequisites, actor } = this.amendInput(input);
57
61
  const hooks = derivedHooks(this.composition);
58
62
  const amendmentPlan = markdown === undefined ? undefined : validated(() => prepareAmendDocument(markdown));
59
63
  validated(() => {
@@ -97,7 +101,11 @@ export class ContractExecution {
97
101
  leading: accepted,
98
102
  hooks,
99
103
  verificationResidueRecorded: false,
100
- value: () => ({ documentDiff: diff, changes, ...region }),
104
+ value: () => ({
105
+ documentDiff: diff,
106
+ changes,
107
+ ...region,
108
+ }),
101
109
  });
102
110
  return acceptedOutcome("amend", this.id, accumulator, value);
103
111
  });
@@ -11,7 +11,7 @@ export type LocalContractCompositionCapture = Readonly<{
11
11
  /**
12
12
  * Hooks, freshness, and gate bundles are read from the captured Settings only at the operation
13
13
  * that consumes them. Bare core (omitted Settings) keeps empty hooks, false freshness, and
14
- * literal gate words; a broken selected namespace fails before any admission.
14
+ * built-in gate words; a broken selected namespace fails before any admission.
15
15
  */
16
16
  export declare function derivedHooks(composition: LocalContractCompositionCapture): WorktreeHooks;
17
17
  /** The two Settings-derived Contract policies one mutating operation may consume. */
@@ -20,6 +20,6 @@ export declare function derivedContractPolicy(composition: LocalContractComposit
20
20
  requireBranchesToBeUpToDate: boolean;
21
21
  }>;
22
22
  export declare function gateNames(value: unknown): readonly string[] | undefined;
23
- /** Bare words and configured bundles share validation, first-seen accumulation, and freezing. */
23
+ /** Built-in words and configured bundles share validation, first-seen accumulation, and freezing. */
24
24
  export declare function derivedGates(composition: LocalContractCompositionCapture, names: readonly string[] | undefined): readonly Gate[];
25
25
  export declare function captureLocalContractComposition(input?: LocalContractComposition): LocalContractCompositionCapture;