@astrosheep/keiyaku 4.1.1 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/build/src/akuma/akuma-errors.d.ts +6 -0
  2. package/build/src/akuma/akuma-errors.js +9 -0
  3. package/build/src/akuma/akuma-handle.d.ts +39 -0
  4. package/build/src/akuma/akuma-handle.js +263 -0
  5. package/build/src/akuma/akuma-observe.d.ts +19 -0
  6. package/build/src/akuma/akuma-observe.js +74 -0
  7. package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
  8. package/build/src/akuma/akuma-product-symbols.js +1 -0
  9. package/build/src/akuma/akuma-product.d.ts +18 -0
  10. package/build/src/akuma/akuma-product.js +154 -0
  11. package/build/src/akuma/akuma.d.ts +23 -70
  12. package/build/src/akuma/akuma.js +17 -433
  13. package/build/src/akuma/body-supervisor.d.ts +26 -0
  14. package/build/src/akuma/body-supervisor.js +89 -0
  15. package/build/src/akuma/body.d.ts +1 -1
  16. package/build/src/akuma/body.js +3 -2
  17. package/build/src/akuma/projection-read.d.ts +17 -0
  18. package/build/src/akuma/projection-read.js +135 -0
  19. package/build/src/akuma/projection.d.ts +1 -18
  20. package/build/src/akuma/projection.js +21 -155
  21. package/build/src/akuma/request-execution.d.ts +6 -0
  22. package/build/src/akuma/request-execution.js +86 -0
  23. package/build/src/akuma/request-serve.d.ts +12 -1
  24. package/build/src/akuma/request-serve.js +2 -102
  25. package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
  26. package/build/src/akuma/{body-turn.js → turn-drive.js} +4 -99
  27. package/build/src/cli/commands/akuma.d.ts +0 -6
  28. package/build/src/cli/commands/akuma.js +1 -11
  29. package/build/src/cli/commands/contract-invoke.d.ts +25 -0
  30. package/build/src/cli/commands/contract-invoke.js +193 -0
  31. package/build/src/cli/commands/contract.d.ts +12 -0
  32. package/build/src/cli/commands/contract.js +229 -0
  33. package/build/src/cli/invoke.js +24 -184
  34. package/build/src/cli/parse.d.ts +1 -1
  35. package/build/src/cli/parse.js +8 -222
  36. package/build/src/cli/render/akuma-activity.d.ts +38 -0
  37. package/build/src/cli/render/akuma-activity.js +362 -0
  38. package/build/src/cli/render/akuma.d.ts +1 -1
  39. package/build/src/cli/render/akuma.js +14 -371
  40. package/build/src/cli/render/contract-history.d.ts +2 -0
  41. package/build/src/cli/render/contract-history.js +83 -0
  42. package/build/src/cli/render/contract.d.ts +1 -2
  43. package/build/src/cli/render/contract.js +1 -83
  44. package/build/src/git/reconcile.d.ts +8 -1
  45. package/build/src/git/reconcile.js +13 -301
  46. package/build/src/git/scratch.d.ts +8 -5
  47. package/build/src/git/scratch.js +29 -2
  48. package/build/src/git/terminal-reconcile.d.ts +21 -0
  49. package/build/src/git/terminal-reconcile.js +278 -0
  50. package/build/src/library/contract-bind.d.ts +26 -0
  51. package/build/src/library/contract-bind.js +106 -0
  52. package/build/src/library/contract-operations.d.ts +77 -0
  53. package/build/src/library/contract-operations.js +130 -0
  54. package/build/src/library/contract-types.d.ts +95 -0
  55. package/build/src/library/contract-types.js +1 -0
  56. package/build/src/library/contract.d.ts +11 -136
  57. package/build/src/library/contract.js +9 -222
  58. package/package.json +1 -1
@@ -6,6 +6,7 @@ import { pathsForAkuId, worldRootForAkumaPaths } from "./identity.js";
6
6
  import { BIRTH_TIMEOUT_MS, publishAkuma } from "./publication.js";
7
7
  import { atomicJson, canonicalAkuId, decodeClaim, decodeRecipe, receiptPath, } from "./request-wire.js";
8
8
  import { isTaskMutationAction } from "../task/mutation.js";
9
+ import { executeRequest } from "./request-execution.js";
9
10
  const POLL_MS = 100;
10
11
  function diagnostic(error) {
11
12
  return error instanceof Error ? error.message : String(error);
@@ -161,107 +162,6 @@ function failure(error) {
161
162
  }
162
163
  return { kind: "failed", diagnostic: diagnostic(error) };
163
164
  }
164
- async function execute(input, request) {
165
- if (input.upstream === undefined)
166
- throw new Error("upstream execution port is unavailable");
167
- if (request.action === "akuma.wait") {
168
- const result = await input.upstream.wait({
169
- targets: request.targets,
170
- completion: request.completion,
171
- ...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
172
- signal: input.signal,
173
- });
174
- return { result, service: { action: request.action } };
175
- }
176
- if (request.action === "akuma.tell") {
177
- const result = await input.upstream.tell({
178
- target: request.target,
179
- body: request.body,
180
- tellId: request.id,
181
- recordedAt: request.admittedAt,
182
- signal: input.signal,
183
- });
184
- return {
185
- result,
186
- service: { action: request.action, target: request.target, tellId: request.id },
187
- };
188
- }
189
- if (request.action === "akuma.kill") {
190
- const served = await input.upstream.kill({
191
- targets: request.targets,
192
- signal: input.signal,
193
- });
194
- return {
195
- result: served.result,
196
- service: { action: request.action, results: served.service },
197
- };
198
- }
199
- if (request.action === "contract.deliver") {
200
- return await executeDeliver(input, request);
201
- }
202
- if (request.action === "contract.review") {
203
- return await executeReview(input, request);
204
- }
205
- const task = request;
206
- const result = await input.upstream.task({
207
- world: task.world,
208
- request: task.request,
209
- requester: task.requester,
210
- signal: input.signal,
211
- });
212
- return { result, service: { action: task.action } };
213
- }
214
- async function executeDeliver(input, request) {
215
- if (input.upstream === undefined)
216
- throw new Error("upstream execution port is unavailable");
217
- const served = await input.upstream.deliver({
218
- repoRoot: request.repoRoot,
219
- contractId: request.contractId,
220
- ...(request.message === undefined ? {} : { message: request.message }),
221
- includeDirty: request.includeDirty,
222
- materializeConflict: request.materializeConflict,
223
- requester: request.requester,
224
- signal: input.signal,
225
- });
226
- return {
227
- result: served.result,
228
- ...(served.deliveryFactId === undefined
229
- ? {}
230
- : {
231
- service: {
232
- action: request.action,
233
- repoRoot: request.repoRoot,
234
- contractId: request.contractId,
235
- deliveryFactId: served.deliveryFactId,
236
- },
237
- }),
238
- };
239
- }
240
- async function executeReview(input, request) {
241
- if (input.upstream === undefined)
242
- throw new Error("upstream execution port is unavailable");
243
- const served = await input.upstream.review({
244
- repoRoot: request.repoRoot,
245
- contractId: request.contractId,
246
- verdict: request.verdict,
247
- ...(request.summary === undefined ? {} : { summary: request.summary }),
248
- requester: request.requester,
249
- signal: input.signal,
250
- });
251
- return {
252
- result: served.result,
253
- ...(served.reviewFactId === undefined
254
- ? {}
255
- : {
256
- service: {
257
- action: request.action,
258
- repoRoot: request.repoRoot,
259
- contractId: request.contractId,
260
- reviewFactId: served.reviewFactId,
261
- },
262
- }),
263
- };
264
- }
265
165
  function pendingService(request) {
266
166
  if (request.action === "akuma.wait")
267
167
  return { action: request.action };
@@ -303,7 +203,7 @@ async function serveUpstream(input) {
303
203
  let outcome;
304
204
  let service = pendingService(request);
305
205
  try {
306
- const served = await execute(input, request);
206
+ const served = await executeRequest(input, request);
307
207
  outcome = { kind: "returned", result: served.result };
308
208
  if (served.service !== undefined)
309
209
  service = served.service;
@@ -1,31 +1,8 @@
1
- import { type HeartSnapshot, type HeldAkumaLeash, type ResumeCoordinate, type Soul, type TellFact } from "./heart/index.js";
1
+ import { type ResumeCoordinate, type Soul, type TellFact } from "./heart/index.js";
2
2
  import type { AkumaPaths } from "./identity.js";
3
3
  import { type ProviderAdapter, type TurnResult } from "./provider.js";
4
4
  import { type RequestChildLaunch, type UpstreamExecutionPort } from "./request-serve.js";
5
- export declare const CONTROL_RESPONSE_MS = 1000;
6
- export declare class BodySupervisor {
7
- private readonly paths;
8
- private readonly bodySequence;
9
- private readonly leash;
10
- readonly signal: AbortSignal;
11
- private readonly controller;
12
- private readonly finished;
13
- private readonly observer;
14
- private waiter;
15
- private observation;
16
- private stopping?;
17
- private constructor();
18
- static open(paths: AkumaPaths, bodySequence: number, leash: HeldAkumaLeash): Promise<BodySupervisor>;
19
- get reason(): "control" | "heart-gone" | undefined;
20
- current(): HeartSnapshot;
21
- recordHung(diagnostic: string, at: string): Promise<void>;
22
- refresh(): Promise<HeartSnapshot>;
23
- next(after: HeartSnapshot): Promise<HeartSnapshot>;
24
- cancel(reason: "control" | "heart-gone"): void;
25
- close(): Promise<void>;
26
- private publish;
27
- private observe;
28
- }
5
+ import { BodySupervisor } from "./body-supervisor.js";
29
6
  export declare function turnRecipe(paths: AkumaPaths, soul: Soul): Promise<Readonly<{
30
7
  cwd: string;
31
8
  options: Soul["options"];
@@ -2,93 +2,7 @@ import { abortableDelay } from "./abort.js";
2
2
  import { appendActivity, beginTurn, breakBody, heartExists, readHeart, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
3
3
  import { encodeAgentEvent } from "./provider.js";
4
4
  import { BodyRequestPump } from "./request-serve.js";
5
- const BODY_CONTROL_OBSERVATION_MS = 100;
6
- export const CONTROL_RESPONSE_MS = 1_000;
7
- export class BodySupervisor {
8
- paths;
9
- bodySequence;
10
- leash;
11
- signal;
12
- controller = new AbortController();
13
- finished = new AbortController();
14
- observer;
15
- waiter;
16
- observation;
17
- stopping;
18
- constructor(paths, bodySequence, leash, observation) {
19
- this.paths = paths;
20
- this.bodySequence = bodySequence;
21
- this.leash = leash;
22
- this.signal = this.controller.signal;
23
- this.observation = observation;
24
- this.observer = this.observe();
25
- }
26
- static async open(paths, bodySequence, leash) {
27
- return new BodySupervisor(paths, bodySequence, leash, await readHeart(paths));
28
- }
29
- get reason() {
30
- return this.stopping;
31
- }
32
- current() {
33
- return this.observation;
34
- }
35
- async recordHung(diagnostic, at) {
36
- await this.leash.recordBodyHung(this.paths, { sequence: this.bodySequence, diagnostic, at });
37
- }
38
- async refresh() {
39
- this.publish(await readHeart(this.paths));
40
- return this.observation;
41
- }
42
- next(after) {
43
- if (this.observation !== after)
44
- return Promise.resolve(this.observation);
45
- return new Promise((resolve) => {
46
- this.waiter = resolve;
47
- });
48
- }
49
- cancel(reason) {
50
- if (this.stopping !== undefined)
51
- return;
52
- this.stopping = reason;
53
- this.controller.abort(new Error(reason === "control" ? "Akuma Body interrupted by durable control" : "Akuma Heart disappeared"));
54
- this.waiter?.(this.observation);
55
- this.waiter = undefined;
56
- }
57
- async close() {
58
- this.finished.abort();
59
- await this.observer;
60
- this.waiter = undefined;
61
- }
62
- publish(snapshot) {
63
- this.observation = snapshot;
64
- this.waiter?.(snapshot);
65
- this.waiter = undefined;
66
- }
67
- async observe() {
68
- for (;;) {
69
- const snapshot = this.observation;
70
- if (!(await heartExists(this.paths)))
71
- return this.cancel("heart-gone");
72
- if (snapshot.stop?.bodySequence === this.bodySequence || snapshot.pause?.bodySequence === this.bodySequence) {
73
- return this.cancel("control");
74
- }
75
- try {
76
- await abortableDelay(BODY_CONTROL_OBSERVATION_MS, this.finished.signal);
77
- }
78
- catch {
79
- return;
80
- }
81
- try {
82
- await this.refresh();
83
- }
84
- catch (error) {
85
- if (await heartExists(this.paths))
86
- throw error;
87
- return this.cancel("heart-gone");
88
- }
89
- }
90
- }
91
- }
5
+ import { CONTROL_RESPONSE_MS } from "./body-supervisor.js";
92
6
  function serializeEffects() {
93
7
  let tail = Promise.resolve();
94
8
  let failed = false;
@@ -132,11 +46,7 @@ async function failedTurnSetup(input, turnSequence, requests, cancelDrive, error
132
46
  throw error;
133
47
  return { kind: "stopped" };
134
48
  }
135
- return {
136
- kind: "failed",
137
- turnSequence,
138
- diagnostic: error instanceof Error ? error.message : String(error),
139
- };
49
+ return { kind: "failed", turnSequence, diagnostic: error instanceof Error ? error.message : String(error) };
140
50
  }
141
51
  async function writeProviderEvent(input, active, event) {
142
52
  if (input.supervisor.signal.aborted)
@@ -151,11 +61,7 @@ async function writeProviderEvent(input, active, event) {
151
61
  admittedAt: at,
152
62
  });
153
63
  }
154
- await appendActivity(input.paths, {
155
- turnSequence: active.turnSequence,
156
- event: encodeAgentEvent(event),
157
- at,
158
- });
64
+ await appendActivity(input.paths, { turnSequence: active.turnSequence, event: encodeAgentEvent(event), at });
159
65
  }
160
66
  async function startTurnDrive(input) {
161
67
  const { cwd, options, session } = await turnRecipe(input.paths, input.soul);
@@ -212,7 +118,7 @@ async function startTurnDrive(input) {
212
118
  }
213
119
  return { kind: "stopped" };
214
120
  }
215
- if (input.launchTells.length > 0) {
121
+ if (input.launchTells.length > 0)
216
122
  await recordTellDeliveries(input.paths, input.launchTells.map((tell) => ({
217
123
  tellId: tell.id,
218
124
  route: "launch",
@@ -220,7 +126,6 @@ async function startTurnDrive(input) {
220
126
  fence: selected.admission.fence,
221
127
  deliveredAt: input.now(),
222
128
  })));
223
- }
224
129
  void selected.completion.then(() => requests.stopAdmission());
225
130
  return {
226
131
  turnSequence: turn.sequence,
@@ -60,11 +60,5 @@ export declare function isParsedAkumaCommand(command: Readonly<{
60
60
  export declare function renderAkumaRootRows(): readonly string[];
61
61
  export declare function renderAkumaHelp(action: AkumaAction): string;
62
62
  export declare function renderAkumaUsage(action: AkumaAction): string;
63
- export declare function parseAkumaCatalogPath(value: string): Readonly<{
64
- kind: "archetypes";
65
- } | {
66
- kind: "akuma";
67
- archetype?: string;
68
- }> | null;
69
63
  export declare function parseAkumaCommand(argv: readonly string[]): ParsedAkumaCommand;
70
64
  export {};
@@ -1,5 +1,5 @@
1
1
  import { CliUsageError, isBlankInput, usageLine } from "../usage.js";
2
- import { archetypeName, parseAkuId } from "../../akuma/identity.js";
2
+ import { parseAkuId } from "../../akuma/identity.js";
3
3
  import { parseDuration as decodeDuration } from "../../duration.js";
4
4
  import { parseAkumaAlias, parseAkumaGlob } from "../../identity/selector.js";
5
5
  import { decodeAllowedActions } from "../../akuma/allowed.js";
@@ -84,16 +84,6 @@ export function renderAkumaHelp(action) {
84
84
  export function renderAkumaUsage(action) {
85
85
  return usageLine(AKUMA_COMMAND_SPECS[action].usage);
86
86
  }
87
- export function parseAkumaCatalogPath(value) {
88
- if (value === "aku" || value === "aku/")
89
- return { kind: "archetypes" };
90
- if (value === "aku/*/*")
91
- return { kind: "akuma" };
92
- const match = /^aku\/([^/]+)\/?$/u.exec(value);
93
- if (match === null)
94
- return null;
95
- return { kind: "akuma", archetype: archetypeName(match[1]) };
96
- }
97
87
  function stringFlag(value, diagnostic, fail) {
98
88
  if (typeof value !== "string")
99
89
  fail(diagnostic);
@@ -0,0 +1,25 @@
1
+ import type { InvocationResult } from "../result.js";
2
+ import type { ParsedCommand } from "../parse.js";
3
+ import type { WorktreeHooks } from "../../library/configuration.js";
4
+ import type { Repo } from "../../library/repo.js";
5
+ import type { Settings } from "../../settings.js";
6
+ import type { WorldRoot } from "../../world.js";
7
+ type ContractMutation = Extract<ParsedCommand, {
8
+ command: "bind" | "amend" | "deliver" | "review" | "arc" | "abandon" | "audit";
9
+ }>;
10
+ type InvocationEdge = Readonly<{
11
+ environment: NodeJS.ProcessEnv;
12
+ readStdin: () => Promise<string>;
13
+ }>;
14
+ export type ContractMutationInput = Readonly<{
15
+ parsed: ContractMutation;
16
+ repo: Repo;
17
+ edge: InvocationEdge;
18
+ scope: string;
19
+ configuration?: Settings;
20
+ hooks: WorktreeHooks;
21
+ establishWorld: () => Promise<WorldRoot>;
22
+ forwarded?: true;
23
+ }>;
24
+ export declare function invokeContractMutation(input: ContractMutationInput): Promise<InvocationResult>;
25
+ export {};
@@ -0,0 +1,193 @@
1
+ import { resolveActor } from "../actor.js";
2
+ import { CliUsageError } from "../usage.js";
3
+ function actorFromEdge(actor, environment) {
4
+ try {
5
+ return resolveActor({ env: environment, ...(actor === undefined ? {} : { actor }) });
6
+ }
7
+ catch (error) {
8
+ throw new CliUsageError(error instanceof Error ? error.message : String(error));
9
+ }
10
+ }
11
+ function consumeSettings(run, ErrorType) {
12
+ try {
13
+ return run();
14
+ }
15
+ catch (error) {
16
+ if (error instanceof ErrorType)
17
+ throw new CliUsageError(error.message);
18
+ throw error;
19
+ }
20
+ }
21
+ async function selectedGates(value, names) {
22
+ const { gatesFrom, SettingsError } = await import("../../library/configuration.js");
23
+ return consumeSettings(() => gatesFrom({ settings: value, ...(names === undefined ? {} : { names }) }), SettingsError);
24
+ }
25
+ async function selectedGitPolicy(value) {
26
+ const { requireBranchesToBeUpToDateFrom, SettingsError } = await import("../../library/configuration.js");
27
+ return consumeSettings(() => requireBranchesToBeUpToDateFrom({ settings: value }), SettingsError);
28
+ }
29
+ async function selectContract(repo, selector, scope) {
30
+ const { contractFromInput, resolveContextualContract } = await import("../selectors.js");
31
+ if (selector !== undefined && !selector.startsWith("@"))
32
+ return contractFromInput(repo, selector);
33
+ const { Keiyaku } = await import("../../library/keiyaku.js");
34
+ const id = resolveContextualContract(await Keiyaku.list({ repo }), selector, scope);
35
+ return contractFromInput(repo, id);
36
+ }
37
+ async function bindDraftReceipt(establishWorld, markdown) {
38
+ const { preserveBindDraft } = await import("../draft.js");
39
+ try {
40
+ return preserveBindDraft(await establishWorld(), markdown);
41
+ }
42
+ catch (error) {
43
+ return { warning: `bind draft could not be preserved: ${error instanceof Error ? error.message : String(error)}` };
44
+ }
45
+ }
46
+ async function invokeBind(input) {
47
+ const { parsed, repo, edge, configuration, hooks, establishWorld } = input;
48
+ if (parsed.command !== "bind")
49
+ throw new Error("bind invocation requires bind syntax");
50
+ const actor = actorFromEdge(parsed.actor, edge.environment);
51
+ const { bindFromCommand } = await import("./bind.js");
52
+ const { acceptedBind, resultFromMutationCall } = await import("../accepted.js");
53
+ if (parsed.forkOf !== undefined) {
54
+ return resultFromMutationCall("bind", () => bindFromCommand({ command: parsed, repo, ...(actor === undefined ? {} : { actor }), hooks }), (accepted) => {
55
+ const bound = accepted.facts.find((fact) => fact.kind === "bind");
56
+ if (bound === undefined || bound.kind !== "bind")
57
+ throw new Error("accepted bind is missing its bind fact");
58
+ return acceptedBind(accepted, bound.data.coordinates);
59
+ });
60
+ }
61
+ if (configuration === undefined)
62
+ throw new Error("bind invocation requires Settings");
63
+ const markdown = await edge.readStdin();
64
+ const gates = await selectedGates(configuration, parsed.gates);
65
+ try {
66
+ const result = await resultFromMutationCall("bind", () => bindFromCommand({
67
+ command: parsed,
68
+ repo,
69
+ markdown,
70
+ gates,
71
+ ...(actor === undefined ? {} : { actor }),
72
+ hooks,
73
+ }), (accepted) => {
74
+ const bound = accepted.facts.find((fact) => fact.kind === "bind");
75
+ if (bound === undefined || bound.kind !== "bind")
76
+ throw new Error("accepted bind is missing its bind fact");
77
+ return acceptedBind(accepted, bound.data.coordinates);
78
+ });
79
+ if (result.kind !== "refused")
80
+ return result;
81
+ return { ...result, draft: await bindDraftReceipt(establishWorld, markdown) };
82
+ }
83
+ catch (error) {
84
+ if (!(error instanceof TypeError))
85
+ throw error;
86
+ const { BindDraftError } = await import("../draft.js");
87
+ throw new BindDraftError(error, await bindDraftReceipt(establishWorld, markdown));
88
+ }
89
+ }
90
+ function deliverRefusal(refusal) {
91
+ if (typeof refusal !== "object" || refusal === null || !("kind" in refusal) || refusal.kind !== "dirty-workspace") {
92
+ return refusal;
93
+ }
94
+ const submodules = "submodules" in refusal && Array.isArray(refusal.submodules) ? refusal.submodules : [];
95
+ return { ...refusal, option: { flag: "--include-dirty", available: submodules.length === 0 } };
96
+ }
97
+ async function existingSeat(input, parsed) {
98
+ const { repo, edge, scope, hooks } = input;
99
+ const { id, contract } = await selectContract(repo, parsed.contract, scope);
100
+ const actor = actorFromEdge(parsed.actor, edge.environment);
101
+ return { contract, id, ...(actor === undefined ? {} : { actor }), hooks };
102
+ }
103
+ async function invokeDeliver(parsed, seat, requireBranchesToBeUpToDate) {
104
+ const { acceptedDeliver } = await import("../accepted.js");
105
+ try {
106
+ const delivered = await seat.contract.deliver({
107
+ ...(seat.actor === undefined ? {} : { actor: seat.actor }),
108
+ ...(parsed.message === undefined ? {} : { message: parsed.message }),
109
+ requireBranchesToBeUpToDate,
110
+ includeDirty: parsed.includeDirty,
111
+ materializeConflict: parsed.materializeConflict,
112
+ hooks: seat.hooks,
113
+ });
114
+ if (!("facts" in delivered))
115
+ return delivered;
116
+ return acceptedDeliver(delivered, seat.id);
117
+ }
118
+ catch (error) {
119
+ const { KeiyakuRefused, KeiyakuRetry } = await import("../../library/keiyaku.js");
120
+ if (error instanceof KeiyakuRefused) {
121
+ return { kind: "refused", verb: "deliver", contract: seat.id, refusal: deliverRefusal(error.refusal) };
122
+ }
123
+ if (error instanceof KeiyakuRetry)
124
+ return { kind: "retry", verb: "deliver", contract: seat.id, detail: error.reason };
125
+ throw error;
126
+ }
127
+ }
128
+ async function invokeReview(parsed, seat, readStdin) {
129
+ const summary = parsed.summaryFromStdin === true ? await readStdin() : parsed.summary;
130
+ const { acceptedReview, resultFromMutationCall } = await import("../accepted.js");
131
+ return resultFromMutationCall("review", () => seat.contract.review({
132
+ verdict: parsed.verdict,
133
+ ...(seat.actor === undefined ? {} : { actor: seat.actor }),
134
+ ...(summary === undefined ? {} : { summary }),
135
+ hooks: seat.hooks,
136
+ }), (result) => acceptedReview(result, seat.id), { coordinate: seat.id });
137
+ }
138
+ export async function invokeContractMutation(input) {
139
+ const { parsed, repo, edge, configuration, hooks, forwarded } = input;
140
+ if (parsed.command === "bind")
141
+ return invokeBind(input);
142
+ const seat = await existingSeat(input, parsed);
143
+ const { id, contract, actor } = seat;
144
+ switch (parsed.command) {
145
+ case "amend": {
146
+ if (configuration === undefined)
147
+ throw new Error("amend invocation requires Settings");
148
+ const markdown = parsed.stdin === true ? await edge.readStdin() : undefined;
149
+ const gates = parsed.gates === undefined ? undefined : await selectedGates(configuration, parsed.gates);
150
+ const { amendFromCommand } = await import("./amend.js");
151
+ const { acceptedAmend, resultFromMutationCall } = await import("../accepted.js");
152
+ return resultFromMutationCall("amend", () => amendFromCommand({
153
+ command: parsed,
154
+ repo,
155
+ contract,
156
+ ...(markdown === undefined ? {} : { markdown }),
157
+ gates,
158
+ ...(actor === undefined ? {} : { actor }),
159
+ hooks,
160
+ }), (result) => acceptedAmend(result, id), { coordinate: id });
161
+ }
162
+ case "deliver":
163
+ return invokeDeliver(parsed, seat, forwarded === true ? false : await selectedGitPolicy(configuration));
164
+ case "review":
165
+ return invokeReview(parsed, seat, edge.readStdin);
166
+ case "arc": {
167
+ const markdown = await edge.readStdin();
168
+ const { acceptedArc, resultFromMutationCall } = await import("../accepted.js");
169
+ return resultFromMutationCall("arc", () => contract.arc({ markdown, ...(actor === undefined ? {} : { actor }), hooks }), (result) => acceptedArc(result, id), { coordinate: id });
170
+ }
171
+ case "abandon": {
172
+ const { acceptedAbandon, resultFromMutationCall } = await import("../accepted.js");
173
+ return resultFromMutationCall("abandon", () => contract.abandon({
174
+ ...(actor === undefined ? {} : { actor }),
175
+ ...(parsed.note === undefined ? {} : { note: parsed.note }),
176
+ hooks,
177
+ }), (result) => acceptedAbandon(result, id), { coordinate: id });
178
+ }
179
+ case "audit": {
180
+ if (configuration === undefined)
181
+ throw new Error("audit invocation requires Settings");
182
+ const requireBranchesToBeUpToDate = await selectedGitPolicy(configuration);
183
+ const { acceptedAudit, resultFromMutationCall } = await import("../accepted.js");
184
+ return resultFromMutationCall("audit", () => contract.audit({
185
+ ...(actor === undefined ? {} : { actor }),
186
+ includeDirty: parsed.includeDirty,
187
+ showDiff: parsed.showDiff,
188
+ requireBranchesToBeUpToDate,
189
+ hooks,
190
+ }), (result) => acceptedAudit(result, id), { coordinate: id });
191
+ }
192
+ }
193
+ }
@@ -252,4 +252,16 @@ export declare const CONTRACT_COMMAND_SPECS: {
252
252
  };
253
253
  };
254
254
  export type ContractCommand = keyof typeof CONTRACT_COMMAND_SPECS;
255
+ export type ParsedContractParts = Readonly<{
256
+ command: ContractCommand;
257
+ flags: Readonly<Record<string, string | true | readonly string[]>>;
258
+ positionals: readonly string[];
259
+ stdin: boolean;
260
+ output: "text" | "json";
261
+ actor?: string;
262
+ }>;
263
+ export type ParsedContractCommand = ParsedBind | ParsedAmend | ParsedDeliver | ParsedReview | ParsedArc | ParsedAbandon | ParsedStatus | ParsedShow | ParsedLs | ParsedAudit | ParsedReconcile | ParsedNuke | ParsedSettings | ParsedRegion;
264
+ export declare function renderContractHelp(command: ContractCommand): string;
265
+ export declare function renderContractUsage(command: ContractCommand): string;
266
+ export declare function parseContractCommand(parts: ParsedContractParts): ParsedContractCommand;
255
267
  export {};