@astrosheep/keiyaku 4.1.0 → 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.
- package/README.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
- package/build/src/akuma/akuma-errors.d.ts +6 -0
- package/build/src/akuma/akuma-errors.js +9 -0
- package/build/src/akuma/akuma-handle.d.ts +39 -0
- package/build/src/akuma/akuma-handle.js +263 -0
- package/build/src/akuma/akuma-observe.d.ts +19 -0
- package/build/src/akuma/akuma-observe.js +74 -0
- package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
- package/build/src/akuma/akuma-product-symbols.js +1 -0
- package/build/src/akuma/akuma-product.d.ts +18 -0
- package/build/src/akuma/akuma-product.js +154 -0
- package/build/src/akuma/akuma.d.ts +37 -81
- package/build/src/akuma/akuma.js +39 -447
- package/build/src/akuma/allowed.d.ts +1 -0
- package/build/src/akuma/allowed.js +6 -0
- package/build/src/akuma/archetype.js +8 -5
- package/build/src/akuma/body-supervisor.d.ts +26 -0
- package/build/src/akuma/body-supervisor.js +89 -0
- package/build/src/akuma/body.d.ts +45 -4
- package/build/src/akuma/body.js +145 -35
- package/build/src/akuma/coordinate.js +17 -7
- package/build/src/akuma/heart/facts.js +1 -1
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/index.js +2 -4
- package/build/src/akuma/heart/request-authority.js +4 -4
- package/build/src/akuma/heart/request-rows.js +27 -16
- package/build/src/akuma/heart/rows.js +79 -41
- package/build/src/akuma/heart/soul.js +1 -1
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +76 -11
- package/build/src/akuma/heart/tells.js +35 -18
- package/build/src/akuma/heart/timeline.js +19 -11
- package/build/src/akuma/identity.d.ts +1 -0
- package/build/src/akuma/identity.js +1 -0
- package/build/src/akuma/index.d.ts +3 -3
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/nuke.js +106 -14
- package/build/src/akuma/projection-read.d.ts +17 -0
- package/build/src/akuma/projection-read.js +135 -0
- package/build/src/akuma/projection.d.ts +1 -16
- package/build/src/akuma/projection.js +77 -154
- package/build/src/akuma/provider-recipe.js +11 -5
- package/build/src/akuma/provider.js +105 -62
- package/build/src/akuma/providers/acp/config.js +5 -6
- package/build/src/akuma/providers/acp/core.js +17 -10
- package/build/src/akuma/providers/acp/events.js +38 -29
- package/build/src/akuma/providers/acp/index.js +13 -9
- package/build/src/akuma/providers/claude/events.js +8 -12
- package/build/src/akuma/providers/claude/index.d.ts +1 -0
- package/build/src/akuma/providers/claude/index.js +55 -26
- package/build/src/akuma/providers/claude/input.js +6 -2
- package/build/src/akuma/providers/codex-app-server/events.js +61 -36
- package/build/src/akuma/providers/codex-app-server/index.js +25 -13
- package/build/src/akuma/providers/grok-build/index.js +22 -25
- package/build/src/akuma/providers/index.js +2 -18
- package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
- package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
- package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
- package/build/src/akuma/providers/pi/events.js +26 -19
- package/build/src/akuma/providers/pi/index.js +58 -40
- package/build/src/akuma/publication.js +9 -9
- package/build/src/akuma/request-execution.d.ts +6 -0
- package/build/src/akuma/request-execution.js +86 -0
- package/build/src/akuma/request-serve.d.ts +12 -1
- package/build/src/akuma/request-serve.js +19 -122
- package/build/src/akuma/request-wire.d.ts +2 -2
- package/build/src/akuma/request-wire.js +75 -102
- package/build/src/akuma/requests.js +2 -2
- package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
- package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
- package/build/src/akuma-body.js +6 -5
- package/build/src/body/amend.d.ts +4 -1
- package/build/src/body/amend.js +14 -6
- package/build/src/body/decode.js +2 -4
- package/build/src/body/envelope.js +2 -4
- package/build/src/body/region.d.ts +1 -2
- package/build/src/body/region.js +2 -70
- package/build/src/body/render.js +17 -12
- package/build/src/body/shape.js +1 -7
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +8 -1
- package/build/src/cli/commands/akuma-invoke.js +18 -6
- package/build/src/cli/commands/akuma.d.ts +0 -6
- package/build/src/cli/commands/akuma.js +11 -24
- package/build/src/cli/commands/amend.d.ts +2 -2
- package/build/src/cli/commands/amend.js +2 -4
- package/build/src/cli/commands/bind.d.ts +4 -4
- package/build/src/cli/commands/bind.js +16 -6
- package/build/src/cli/commands/contract-invoke.d.ts +25 -0
- package/build/src/cli/commands/contract-invoke.js +193 -0
- package/build/src/cli/commands/contract.d.ts +109 -10
- package/build/src/cli/commands/contract.js +339 -16
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +23 -15
- package/build/src/cli/commands/task-invoke.js +187 -67
- package/build/src/cli/commands/task-query.js +48 -24
- package/build/src/cli/commands/task.js +150 -38
- package/build/src/cli/coordinates.js +2 -4
- package/build/src/cli/invoke.js +92 -208
- package/build/src/cli/main.js +4 -2
- package/build/src/cli/parse.d.ts +3 -90
- package/build/src/cli/parse.js +27 -233
- package/build/src/cli/render/akuma-activity.d.ts +38 -0
- package/build/src/cli/render/akuma-activity.js +362 -0
- package/build/src/cli/render/akuma-tool-command.js +6 -7
- package/build/src/cli/render/akuma-tool.js +10 -8
- package/build/src/cli/render/akuma.d.ts +1 -1
- package/build/src/cli/render/akuma.js +61 -353
- package/build/src/cli/render/audit.js +5 -15
- package/build/src/cli/render/board.d.ts +1 -0
- package/build/src/cli/render/board.js +17 -0
- package/build/src/cli/render/catalog.js +81 -8
- package/build/src/cli/render/contract-history.d.ts +2 -0
- package/build/src/cli/render/contract-history.js +83 -0
- package/build/src/cli/render/contract-observation.d.ts +10 -0
- package/build/src/cli/render/contract-observation.js +58 -0
- package/build/src/cli/render/contract.d.ts +1 -2
- package/build/src/cli/render/contract.js +41 -142
- package/build/src/cli/render/kanshi.js +239 -215
- package/build/src/cli/render/receipt.js +2 -9
- package/build/src/cli/render/refusal.js +10 -15
- package/build/src/cli/render/region.js +22 -6
- package/build/src/cli/render/settings.js +4 -4
- package/build/src/cli/render/task.js +34 -14
- package/build/src/cli/render/terminal.js +16 -5
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.d.ts +6 -1
- package/build/src/cli/runtime.js +84 -63
- package/build/src/cli/selectors.js +2 -4
- package/build/src/cli/usage.js +6 -5
- package/build/src/contract-worktree.d.ts +1 -23
- package/build/src/contract-worktree.js +79 -155
- package/build/src/coordination/durable-file.js +7 -3
- package/build/src/coordination/sqlite-transaction-lock.js +29 -12
- package/build/src/core/facts/codec.js +7 -3
- package/build/src/core/facts/types.d.ts +1 -1
- package/build/src/core/subject.js +16 -9
- package/build/src/core/verbs/abandon.d.ts +1 -1
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +7 -7
- package/build/src/core/verbs/attestation.js +4 -1
- package/build/src/core/verbs/bind.d.ts +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +10 -8
- package/build/src/dispatch/index.js +8 -6
- package/build/src/duration.js +5 -1
- package/build/src/git/admission.js +5 -3
- package/build/src/git/hooks.d.ts +8 -0
- package/build/src/git/hooks.js +63 -14
- package/build/src/git/identity.js +1 -4
- package/build/src/git/integration.d.ts +2 -3
- package/build/src/git/integration.js +32 -39
- package/build/src/git/nuke.d.ts +1 -1
- package/build/src/git/nuke.js +110 -57
- package/build/src/git/observe.d.ts +13 -1
- package/build/src/git/observe.js +51 -44
- package/build/src/git/process.js +4 -2
- package/build/src/git/read-observation.js +10 -8
- package/build/src/git/reconcile.d.ts +22 -2
- package/build/src/git/reconcile.js +38 -274
- package/build/src/git/repository.d.ts +2 -0
- package/build/src/git/repository.js +13 -22
- package/build/src/git/scratch.d.ts +8 -5
- package/build/src/git/scratch.js +29 -2
- package/build/src/git/target-placement.d.ts +9 -10
- package/build/src/git/target-placement.js +59 -62
- package/build/src/git/tender.js +13 -46
- package/build/src/git/terminal-reconcile.d.ts +21 -0
- package/build/src/git/terminal-reconcile.js +278 -0
- package/build/src/git/terminal-seal.js +15 -12
- package/build/src/git/tree.js +5 -2
- package/build/src/git/workspace.d.ts +24 -2
- package/build/src/git/workspace.js +120 -16
- package/build/src/identity/coordinates.js +3 -1
- package/build/src/identity/selector.js +6 -3
- package/build/src/kanshi/fleet.d.ts +6 -0
- package/build/src/kanshi/fleet.js +27 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +60 -48
- package/build/src/kanshi/report.d.ts +11 -23
- package/build/src/kanshi/select.js +25 -24
- package/build/src/library/address.d.ts +2 -1
- package/build/src/library/address.js +7 -8
- package/build/src/library/akuma-creation.js +20 -12
- package/build/src/library/audit.d.ts +0 -1
- package/build/src/library/audit.js +1 -2
- package/build/src/library/bind.d.ts +53 -5
- package/build/src/library/bind.js +98 -22
- package/build/src/library/catalog.d.ts +1 -0
- package/build/src/library/catalog.js +6 -3
- package/build/src/library/configuration.js +3 -1
- package/build/src/library/continuation.d.ts +15 -4
- package/build/src/library/continuation.js +24 -16
- package/build/src/library/contract-bind.d.ts +26 -0
- package/build/src/library/contract-bind.js +106 -0
- package/build/src/library/contract-operations.d.ts +77 -0
- package/build/src/library/contract-operations.js +130 -0
- package/build/src/library/contract-types.d.ts +95 -0
- package/build/src/library/contract-types.js +1 -0
- package/build/src/library/contract.d.ts +19 -154
- package/build/src/library/contract.js +46 -261
- package/build/src/library/fleet.d.ts +1 -1
- package/build/src/library/fleet.js +19 -11
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +14 -0
- package/build/src/library/keiyaku.d.ts +8 -7
- package/build/src/library/keiyaku.js +3 -3
- package/build/src/library/nuke.js +14 -5
- package/build/src/library/reconcile.d.ts +9 -4
- package/build/src/library/reconcile.js +30 -24
- package/build/src/library/refusal.d.ts +13 -5
- package/build/src/library/refusal.js +7 -0
- package/build/src/library/region.d.ts +8 -7
- package/build/src/library/region.js +31 -11
- package/build/src/library/repo.js +2 -2
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/parse.js +11 -7
- package/build/src/markdown/query.js +4 -2
- package/build/src/protocol/amend.js +3 -1
- package/build/src/protocol/attempt.d.ts +7 -3
- package/build/src/protocol/attempt.js +9 -5
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +4 -14
- package/build/src/protocol/bind.d.ts +19 -6
- package/build/src/protocol/bind.js +28 -13
- package/build/src/protocol/completion.d.ts +0 -1
- package/build/src/protocol/completion.js +1 -3
- package/build/src/protocol/deliver.d.ts +1 -3
- package/build/src/protocol/deliver.js +15 -39
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +9 -7
- package/build/src/protocol/operations.d.ts +3 -7
- package/build/src/protocol/operations.js +5 -3
- package/build/src/protocol/placement.d.ts +0 -1
- package/build/src/protocol/placement.js +6 -6
- package/build/src/protocol/read/observation.d.ts +11 -0
- package/build/src/protocol/read/observation.js +37 -0
- package/build/src/protocol/read/status.d.ts +23 -12
- package/build/src/protocol/read/status.js +90 -72
- package/build/src/protocol/reconcile.d.ts +1 -0
- package/build/src/protocol/reconcile.js +2 -3
- package/build/src/protocol/reintegrate.js +1 -1
- package/build/src/protocol/review.d.ts +0 -1
- package/build/src/protocol/review.js +15 -22
- package/build/src/protocol/run.d.ts +1 -0
- package/build/src/protocol/run.js +4 -5
- package/build/src/runtime/proc/launch.d.ts +33 -0
- package/build/src/runtime/proc/launch.js +98 -0
- package/build/src/runtime/proc/line-rpc.js +9 -3
- package/build/src/runtime/proc/run.d.ts +12 -6
- package/build/src/runtime/proc/run.js +78 -21
- package/build/src/runtime/proc/stdio.js +7 -10
- package/build/src/settings.js +6 -2
- package/build/src/settlement/holder.js +13 -10
- package/build/src/settlement/settle.js +39 -6
- package/build/src/task/board.js +12 -6
- package/build/src/task/compose.js +85 -22
- package/build/src/task/context.js +21 -8
- package/build/src/task/document.js +46 -10
- package/build/src/task/identity.js +5 -2
- package/build/src/task/index.d.ts +0 -1
- package/build/src/task/index.js +119 -34
- package/build/src/task/input.js +29 -7
- package/build/src/task/mutation.js +61 -19
- package/build/src/task/operations.d.ts +6 -1
- package/build/src/task/operations.js +83 -29
- package/build/src/task/query.js +55 -26
- package/build/src/task/store.d.ts +3 -1
- package/build/src/task/store.js +81 -17
- package/build/src/verification/execution.js +14 -11
- package/build/src/workspace-place.js +19 -7
- package/build/src/world.js +16 -6
- package/package.json +8 -3
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import { decodeContractDocument } from "../body/decode.js";
|
|
3
3
|
import { contractIdFromSegment } from "../core/facts/types.js";
|
|
4
|
+
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
4
5
|
import { fitIdentityStem, normalizeIdentityStem } from "../identity/normalize.js";
|
|
5
6
|
import { bindOperation } from "../protocol/bind.js";
|
|
6
|
-
import {
|
|
7
|
+
import { stateOperation } from "../protocol/operations.js";
|
|
8
|
+
import { claimTaskHolder, claimTaskHolderWithFence } from "../settlement/holder.js";
|
|
9
|
+
import { KeiyakuRefused } from "./refusal.js";
|
|
10
|
+
import { contractTerms, documentDerivation } from "./input.js";
|
|
7
11
|
function candidateId(title, collision) {
|
|
8
12
|
const stem = fitIdentityStem({ stem: normalizeIdentityStem({ source: title }) || "contract", maxBytes: 48 });
|
|
9
13
|
const suffix = collision === 0 ? "" : `-${randomBytes(8).toString("hex")}`;
|
|
@@ -16,11 +20,15 @@ async function attempt(input, id) {
|
|
|
16
20
|
terms: input.terms,
|
|
17
21
|
verification: input.verification,
|
|
18
22
|
workspace: input.workspace,
|
|
23
|
+
...(input.coordinates === undefined ? {} : { coordinates: input.coordinates }),
|
|
24
|
+
...(input.source === undefined ? {} : { source: input.source }),
|
|
19
25
|
contractId: id,
|
|
20
|
-
...(input.
|
|
21
|
-
...(input.task === undefined
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
...(input.targetSelection === undefined ? {} : { targetSelection: input.targetSelection }),
|
|
27
|
+
...(input.task === undefined
|
|
28
|
+
? {}
|
|
29
|
+
: {
|
|
30
|
+
decorateOffer: ({ contractId: owner }) => [claimTaskHolder(input.task, owner)],
|
|
31
|
+
}),
|
|
24
32
|
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
25
33
|
});
|
|
26
34
|
}
|
|
@@ -28,29 +36,97 @@ async function attemptCandidates(input) {
|
|
|
28
36
|
let result;
|
|
29
37
|
for (let collision = 0; collision <= 3; collision += 1) {
|
|
30
38
|
const id = candidateId(input.title, collision);
|
|
31
|
-
let reserved = false;
|
|
32
|
-
if (input.workspace === "here") {
|
|
33
|
-
const reservation = await reserveContractWorktree(input.scope, id);
|
|
34
|
-
if (reservation.kind !== "reserved") {
|
|
35
|
-
return { kind: "refused", refusal: {
|
|
36
|
-
kind: "here-worktree-appointed",
|
|
37
|
-
path: reservation.path,
|
|
38
|
-
...(reservation.kind === "appointed" ? { contract: reservation.contract } : {}),
|
|
39
|
-
} };
|
|
40
|
-
}
|
|
41
|
-
reserved = true;
|
|
42
|
-
}
|
|
43
39
|
result = await attempt(input, id);
|
|
44
40
|
if (result.kind === "accepted")
|
|
45
41
|
return result;
|
|
46
|
-
if (reserved)
|
|
47
|
-
await releaseContractWorktree(input.scope, id);
|
|
48
42
|
if (result.kind !== "refused" || result.refusal.kind !== "contract-exists")
|
|
49
43
|
return result;
|
|
50
44
|
}
|
|
51
45
|
return result;
|
|
52
46
|
}
|
|
53
47
|
export async function admitBindWithAppointment(input) {
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
return await attemptCandidates(input);
|
|
49
|
+
}
|
|
50
|
+
export async function admitForkBindWithAppointment(input) {
|
|
51
|
+
let source;
|
|
52
|
+
try {
|
|
53
|
+
source = await stateOperation({ scope: input.scope, channel: input.channel, contractId: input.sourceId });
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (error instanceof Error && error.message === `contract does not exist: ${input.sourceId}`) {
|
|
57
|
+
throw new KeiyakuRefused({ kind: "fork-source-missing", contractId: input.sourceId });
|
|
58
|
+
}
|
|
59
|
+
if (error instanceof AuthorityCorruptionError) {
|
|
60
|
+
throw new KeiyakuRefused({ kind: "fork-source-invalid", contractId: input.sourceId });
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
const sourceObject = (await input.channel.readObjects([source.coordinates.start])).get(source.coordinates.start);
|
|
65
|
+
if (sourceObject?.kind !== "present" || sourceObject.type !== "commit") {
|
|
66
|
+
throw new KeiyakuRefused({ kind: "fork-source-unavailable", contractId: input.sourceId });
|
|
67
|
+
}
|
|
68
|
+
const currentSource = await stateOperation({
|
|
69
|
+
scope: input.scope,
|
|
70
|
+
channel: input.channel,
|
|
71
|
+
contractId: input.sourceId,
|
|
72
|
+
});
|
|
73
|
+
if (currentSource.head !== source.head ||
|
|
74
|
+
currentSource.coordinates.start !== source.coordinates.start ||
|
|
75
|
+
currentSource.terms.document.key !== source.terms.document.key) {
|
|
76
|
+
throw new KeiyakuRefused({ kind: "fork-source-moved", contractId: input.sourceId });
|
|
77
|
+
}
|
|
78
|
+
let sourceDocument;
|
|
79
|
+
try {
|
|
80
|
+
sourceDocument = decodeContractDocument(source.terms.document.bytes);
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (error instanceof TypeError) {
|
|
84
|
+
throw new KeiyakuRefused({ kind: "fork-source-invalid", contractId: input.sourceId });
|
|
85
|
+
}
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
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"}`);
|
|
89
|
+
const document = decodeContractDocument(markdown);
|
|
90
|
+
const terms = contractTerms(document, source.terms.gates, source.terms.after);
|
|
91
|
+
const admission = await attemptCandidates({
|
|
92
|
+
scope: input.scope,
|
|
93
|
+
channel: input.channel,
|
|
94
|
+
title: document.title,
|
|
95
|
+
terms,
|
|
96
|
+
verification: documentDerivation(document, terms.gates).verification,
|
|
97
|
+
workspace: "worktree",
|
|
98
|
+
targetSelection: input.target === undefined
|
|
99
|
+
? source.coordinates.target === undefined
|
|
100
|
+
? { kind: "targetless" }
|
|
101
|
+
: { kind: "explicit", target: source.coordinates.target }
|
|
102
|
+
: { kind: "explicit", target: input.target },
|
|
103
|
+
coordinates: { start: source.coordinates.start },
|
|
104
|
+
source: {
|
|
105
|
+
contractId: input.sourceId,
|
|
106
|
+
head: source.head,
|
|
107
|
+
start: source.coordinates.start,
|
|
108
|
+
document: source.terms.document.key,
|
|
109
|
+
},
|
|
110
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
111
|
+
});
|
|
112
|
+
return { admission, document };
|
|
113
|
+
}
|
|
114
|
+
export async function admitMarkdownBind(input) {
|
|
115
|
+
return await admitBindWithAppointment(input);
|
|
116
|
+
}
|
|
117
|
+
export async function prepareMarkdownBind(input) {
|
|
118
|
+
const terms = contractTerms(input.document, input.gates, input.after);
|
|
119
|
+
const admitCandidate = () => admitMarkdownBind({
|
|
120
|
+
scope: input.scope,
|
|
121
|
+
channel: input.channel,
|
|
122
|
+
title: input.document.title,
|
|
123
|
+
terms,
|
|
124
|
+
verification: documentDerivation(input.document, terms.gates).verification,
|
|
125
|
+
workspace: input.workspace,
|
|
126
|
+
...(input.targetSelection === undefined ? {} : { targetSelection: input.targetSelection }),
|
|
127
|
+
...(input.task === undefined ? {} : { task: input.task }),
|
|
128
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
129
|
+
});
|
|
130
|
+
const admission = input.task === undefined ? null : await claimTaskHolderWithFence(input.scope, input.task, admitCandidate);
|
|
131
|
+
return { admission, result: admission === null ? await admitCandidate() : admission.result };
|
|
56
132
|
}
|
|
@@ -40,8 +40,11 @@ function queryValue(value) {
|
|
|
40
40
|
export async function listCatalog(input) {
|
|
41
41
|
const values = requireInput(input, "Keiyaku.ls input");
|
|
42
42
|
const query = queryValue(values.query);
|
|
43
|
-
const allowed = query.kind === "contracts"
|
|
44
|
-
|
|
43
|
+
const allowed = query.kind === "contracts"
|
|
44
|
+
? ["query", "repo"]
|
|
45
|
+
: query.kind === "archetypes"
|
|
46
|
+
? ["query", "home"]
|
|
47
|
+
: ["query", "path"];
|
|
45
48
|
for (const key of Object.keys(values)) {
|
|
46
49
|
if (!allowed.includes(key))
|
|
47
50
|
throw new TypeError(`Keiyaku.ls input has unknown field: ${key}`);
|
|
@@ -50,7 +53,7 @@ export async function listCatalog(input) {
|
|
|
50
53
|
if (!(values.repo instanceof Repo))
|
|
51
54
|
throw new TypeError("repo must be a Repo");
|
|
52
55
|
const board = await listKeiyaku({ repo: values.repo });
|
|
53
|
-
return { kind: "contracts", root: board.root, state: board.state, rows: board.rows };
|
|
56
|
+
return { kind: "contracts", root: board.root, state: board.state, observedAt: board.observedAt, rows: board.rows };
|
|
54
57
|
}
|
|
55
58
|
if (query.kind === "archetypes") {
|
|
56
59
|
const home = optionalHome(values.home);
|
|
@@ -81,7 +81,9 @@ function command(value, coordinate, ErrorType) {
|
|
|
81
81
|
}
|
|
82
82
|
if (value.argv[0].trim().length === 0)
|
|
83
83
|
throw new ErrorType(`${coordinate}.argv[0] must be nonblank`);
|
|
84
|
-
if (!Number.isSafeInteger(value.timeoutMs) ||
|
|
84
|
+
if (!Number.isSafeInteger(value.timeoutMs) ||
|
|
85
|
+
value.timeoutMs < 1 ||
|
|
86
|
+
value.timeoutMs > 2_147_483_647) {
|
|
85
87
|
throw new ErrorType(`${coordinate}.timeoutMs must be an integer from 1 through 2147483647`);
|
|
86
88
|
}
|
|
87
89
|
return Object.freeze({ argv: Object.freeze([...value.argv]), timeoutMs: value.timeoutMs });
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import type { ContractId, ContractState } from "../core/facts/types.js";
|
|
2
2
|
import { type GitDecodeChannel } from "../git/read-observation.js";
|
|
3
|
-
import type { DocumentDerivation,
|
|
3
|
+
import type { DocumentDerivation, PlacementStop, RepositoryScope } from "../protocol/operations.js";
|
|
4
4
|
import type { AcceptedIntent } from "./mutation.js";
|
|
5
5
|
export type ContinuationReport = Readonly<{
|
|
6
|
-
attempted: number;
|
|
7
6
|
claimed: readonly ContractId[];
|
|
8
7
|
stopped: readonly Readonly<{
|
|
9
8
|
contractId: ContractId;
|
|
10
9
|
stop: PlacementStop | Readonly<{
|
|
11
|
-
kind: "already-terminal"
|
|
10
|
+
kind: "already-terminal";
|
|
12
11
|
}>;
|
|
13
12
|
}>[];
|
|
14
13
|
}>;
|
|
@@ -18,7 +17,19 @@ export declare function continueDeliveredDependents<Value extends object>(input:
|
|
|
18
17
|
contractId: ContractId;
|
|
19
18
|
accepted: AcceptedIntent<Value>;
|
|
20
19
|
deriveDocument: (state: ContractState) => DocumentDerivation;
|
|
21
|
-
|
|
20
|
+
actor?: import("../core/facts/types.js").ActorId;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}>): Promise<AcceptedIntent<Value & Readonly<{
|
|
23
|
+
continuation?: ContinuationReport;
|
|
24
|
+
}>>>;
|
|
25
|
+
export declare function continueAcceptedCompletion<Value extends Readonly<{
|
|
26
|
+
completion?: unknown;
|
|
27
|
+
}>>(input: Readonly<{
|
|
28
|
+
scope: RepositoryScope;
|
|
29
|
+
channel: GitDecodeChannel;
|
|
30
|
+
contractId: ContractId;
|
|
31
|
+
accepted: AcceptedIntent<Value>;
|
|
32
|
+
deriveDocument: (state: ContractState) => DocumentDerivation;
|
|
22
33
|
actor?: import("../core/facts/types.js").ActorId;
|
|
23
34
|
signal?: AbortSignal;
|
|
24
35
|
}>): Promise<AcceptedIntent<Value & Readonly<{
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
import { observeActiveContractWorld } from "../git/observe.js";
|
|
2
2
|
import { withGitReadObservation } from "../git/read-observation.js";
|
|
3
3
|
import { continueDeliveryOperation } from "../protocol/deliver.js";
|
|
4
|
-
function
|
|
5
|
-
const
|
|
6
|
-
for (const
|
|
4
|
+
function reverseDependents(world) {
|
|
5
|
+
const index = new Map();
|
|
6
|
+
for (const record of world.contracts.values()) {
|
|
7
7
|
const state = record.state;
|
|
8
|
-
if (state === null
|
|
9
|
-
|| attempted.has(contractId)
|
|
10
|
-
|| !state.terms.after.includes(claimed)
|
|
11
|
-
|| state.delivery === null
|
|
12
|
-
|| !state.terms.after.every((dependency) => newlyClaimed.has(dependency) || world.eligibility.get(dependency)?.terminal?.kind === "claimed"))
|
|
8
|
+
if (state === null || state.delivery === null)
|
|
13
9
|
continue;
|
|
14
|
-
|
|
10
|
+
const dependent = { state, journal: record.entries };
|
|
11
|
+
for (const prerequisite of state.terms.after) {
|
|
12
|
+
const dependents = index.get(prerequisite) ?? [];
|
|
13
|
+
dependents.push(dependent);
|
|
14
|
+
index.set(prerequisite, dependents);
|
|
15
|
+
}
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
for (const dependents of index.values())
|
|
18
|
+
dependents.sort((left, right) => left.state.id.localeCompare(right.state.id));
|
|
19
|
+
return index;
|
|
17
20
|
}
|
|
18
21
|
function appendAccepted(primary, child) {
|
|
19
22
|
const effects = [...(primary.physical?.effects ?? []), ...(child.physical?.effects ?? [])];
|
|
@@ -26,6 +29,7 @@ function appendAccepted(primary, child) {
|
|
|
26
29
|
}
|
|
27
30
|
export async function continueDeliveredDependents(input) {
|
|
28
31
|
const world = await withGitReadObservation(input.scope, input.channel, async (observation) => await observeActiveContractWorld(observation));
|
|
32
|
+
const dependents = reverseDependents(world);
|
|
29
33
|
const pending = [input.contractId];
|
|
30
34
|
const attempted = new Set();
|
|
31
35
|
const newlyClaimed = new Set(pending);
|
|
@@ -34,8 +38,11 @@ export async function continueDeliveredDependents(input) {
|
|
|
34
38
|
let accepted = input.accepted;
|
|
35
39
|
while (pending.length > 0) {
|
|
36
40
|
const parent = pending.shift();
|
|
37
|
-
for (const candidate of
|
|
41
|
+
for (const candidate of dependents.get(parent) ?? []) {
|
|
38
42
|
const contractId = candidate.state.id;
|
|
43
|
+
if (attempted.has(contractId) ||
|
|
44
|
+
!candidate.state.terms.after.every((dependency) => newlyClaimed.has(dependency) || world.eligibility.get(dependency)?.terminal?.kind === "claimed"))
|
|
45
|
+
continue;
|
|
39
46
|
attempted.add(contractId);
|
|
40
47
|
const child = await continueDeliveryOperation({
|
|
41
48
|
scope: input.scope,
|
|
@@ -43,7 +50,6 @@ export async function continueDeliveredDependents(input) {
|
|
|
43
50
|
state: candidate.state,
|
|
44
51
|
journal: candidate.journal,
|
|
45
52
|
deriveDocument: input.deriveDocument,
|
|
46
|
-
...(input.resolveHereWorkspace === undefined ? {} : { resolveHereWorkspace: input.resolveHereWorkspace }),
|
|
47
53
|
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
48
54
|
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
49
55
|
});
|
|
@@ -60,9 +66,6 @@ export async function continueDeliveredDependents(input) {
|
|
|
60
66
|
if ("refusal" in stop && stop.refusal.kind === "terminal") {
|
|
61
67
|
stopped.push({ contractId, stop: { kind: "already-terminal" } });
|
|
62
68
|
}
|
|
63
|
-
else if ("refusal" in stop && stop.refusal.kind === "delivery-missing") {
|
|
64
|
-
stopped.push({ contractId, stop: { kind: "delivery-missing" } });
|
|
65
|
-
}
|
|
66
69
|
else {
|
|
67
70
|
stopped.push({ contractId, stop });
|
|
68
71
|
}
|
|
@@ -72,7 +75,12 @@ export async function continueDeliveredDependents(input) {
|
|
|
72
75
|
...accepted,
|
|
73
76
|
value: {
|
|
74
77
|
...accepted.value,
|
|
75
|
-
...(attempted.size === 0 ? {} : { continuation: {
|
|
78
|
+
...(attempted.size === 0 ? {} : { continuation: { claimed, stopped } }),
|
|
76
79
|
},
|
|
77
80
|
};
|
|
78
81
|
}
|
|
82
|
+
export async function continueAcceptedCompletion(input) {
|
|
83
|
+
if (input.accepted.value.completion === undefined)
|
|
84
|
+
return input.accepted;
|
|
85
|
+
return await continueDeliveredDependents(input);
|
|
86
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type ContractId } from "../core/facts/types.js";
|
|
2
|
+
import { type MutationResult } from "./mutation.js";
|
|
3
|
+
import { type RegionObservation } from "./region.js";
|
|
4
|
+
import { Repo } from "./repo.js";
|
|
5
|
+
import type { WorktreeHooks } from "./configuration.js";
|
|
6
|
+
import type { RepositoryScope } from "../protocol/operations.js";
|
|
7
|
+
type BindInput = Readonly<{
|
|
8
|
+
repo: Repo;
|
|
9
|
+
markdown?: unknown;
|
|
10
|
+
forkOf?: unknown;
|
|
11
|
+
task?: unknown;
|
|
12
|
+
target?: unknown;
|
|
13
|
+
workspace?: unknown;
|
|
14
|
+
actor?: unknown;
|
|
15
|
+
after?: unknown;
|
|
16
|
+
gates?: unknown;
|
|
17
|
+
hooks?: WorktreeHooks;
|
|
18
|
+
}>;
|
|
19
|
+
type BindResult<Handle> = Readonly<Omit<MutationResult<Handle>, "value"> & {
|
|
20
|
+
keiyaku: Handle;
|
|
21
|
+
} & RegionObservation>;
|
|
22
|
+
type HandleFactory<Handle> = (contractId: ContractId, scope: RepositoryScope) => Handle;
|
|
23
|
+
export declare function bindKeiyaku<Handle>(input: BindInput, createHandle: HandleFactory<Handle>): Promise<BindResult<Handle>>;
|
|
24
|
+
/** Internal CLI composition; not exported from the package root. */
|
|
25
|
+
export declare function bindFromCli<Handle>(input: BindInput, createHandle: HandleFactory<Handle>): Promise<BindResult<Handle>>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { decodeContractDocument } from "../body/decode.js";
|
|
2
|
+
import { contractId } from "../core/facts/types.js";
|
|
3
|
+
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
4
|
+
import { admitForkBindWithAppointment, prepareMarkdownBind } from "./bind.js";
|
|
5
|
+
import { actorOption, normalizedGates, normalizedList, requireInput, requireMarkdown, taskOption } from "./input.js";
|
|
6
|
+
import { completionInput, completeHolderMutation, completeMutation } from "./mutation.js";
|
|
7
|
+
import { requireAccepted } from "./refusal.js";
|
|
8
|
+
import { observeRegion } from "./region.js";
|
|
9
|
+
import { scopeForRepo } from "./repo.js";
|
|
10
|
+
import { worktreeHooksOption } from "./configuration.js";
|
|
11
|
+
function acceptedBindResult(result, region) {
|
|
12
|
+
const { facts, head, effects, lags, settlement } = result;
|
|
13
|
+
return { facts, head, keiyaku: result.value, effects, lags, settlement, ...region };
|
|
14
|
+
}
|
|
15
|
+
export async function bindKeiyaku(input, createHandle) {
|
|
16
|
+
const values = requireInput(input, "Keiyaku.bind input");
|
|
17
|
+
const hooks = worktreeHooksOption(values.hooks);
|
|
18
|
+
const forkOf = values.forkOf;
|
|
19
|
+
if (forkOf !== undefined) {
|
|
20
|
+
for (const key of Object.keys(values)) {
|
|
21
|
+
if (!["repo", "forkOf", "target", "workspace", "actor", "hooks"].includes(key)) {
|
|
22
|
+
throw new TypeError(`fork bind input has unknown field: ${key}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (typeof forkOf !== "string")
|
|
26
|
+
throw new TypeError("forkOf must be a ContractId");
|
|
27
|
+
let sourceId;
|
|
28
|
+
try {
|
|
29
|
+
sourceId = contractId(forkOf);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new TypeError(error instanceof Error ? error.message : "forkOf must be a ContractId");
|
|
33
|
+
}
|
|
34
|
+
const sourceScope = scopeForRepo(values.repo);
|
|
35
|
+
if ((values.workspace ?? "worktree") !== "worktree")
|
|
36
|
+
throw new TypeError("workspace must be worktree");
|
|
37
|
+
const target = values.target;
|
|
38
|
+
if (target !== undefined && typeof target !== "string")
|
|
39
|
+
throw new TypeError("target must be a string");
|
|
40
|
+
const actor = actorOption(values.actor);
|
|
41
|
+
return withGitDecodeChannel(sourceScope, async (channel) => {
|
|
42
|
+
const fork = await admitForkBindWithAppointment({
|
|
43
|
+
scope: sourceScope,
|
|
44
|
+
channel,
|
|
45
|
+
sourceId,
|
|
46
|
+
...(target === undefined ? {} : { target }),
|
|
47
|
+
...actor,
|
|
48
|
+
});
|
|
49
|
+
const admission = requireAccepted(fork.admission);
|
|
50
|
+
const id = admission.value.contractId;
|
|
51
|
+
const toHandle = ({ contractId: contract }) => createHandle(contract, sourceScope);
|
|
52
|
+
const result = await completeMutation({
|
|
53
|
+
...completionInput(sourceScope, channel, id, toHandle, hooks),
|
|
54
|
+
accepted: admission,
|
|
55
|
+
});
|
|
56
|
+
return acceptedBindResult(result, await observeRegion(sourceScope, channel, id, fork.document.region));
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
return bindMarkdownFromValues(values, "targetless", createHandle);
|
|
60
|
+
}
|
|
61
|
+
/** Internal CLI composition; not exported from the package root. */
|
|
62
|
+
export async function bindFromCli(input, createHandle) {
|
|
63
|
+
const values = requireInput(input, "Keiyaku.bind input");
|
|
64
|
+
return values.forkOf !== undefined
|
|
65
|
+
? bindKeiyaku(input, createHandle)
|
|
66
|
+
: bindMarkdownFromValues(values, "current-branch", createHandle);
|
|
67
|
+
}
|
|
68
|
+
async function bindMarkdownFromValues(values, omittedTarget, createHandle) {
|
|
69
|
+
const hooks = worktreeHooksOption(values.hooks);
|
|
70
|
+
const scope = scopeForRepo(values.repo);
|
|
71
|
+
const task = taskOption(values.task);
|
|
72
|
+
const document = decodeContractDocument(requireMarkdown(values.markdown));
|
|
73
|
+
if ((values.workspace ?? "worktree") !== "worktree")
|
|
74
|
+
throw new TypeError("workspace must be worktree");
|
|
75
|
+
const target = values.target;
|
|
76
|
+
if (target !== undefined && typeof target !== "string")
|
|
77
|
+
throw new TypeError("target must be a string");
|
|
78
|
+
const actor = actorOption(values.actor);
|
|
79
|
+
const gates = normalizedGates(values.gates);
|
|
80
|
+
const after = normalizedList(values.after, "after", contractId);
|
|
81
|
+
const targetSelection = target !== undefined ? { kind: "explicit", target } : { kind: omittedTarget };
|
|
82
|
+
return withGitDecodeChannel(scope, async (channel) => {
|
|
83
|
+
const admission = await prepareMarkdownBind({
|
|
84
|
+
scope,
|
|
85
|
+
channel,
|
|
86
|
+
document,
|
|
87
|
+
gates,
|
|
88
|
+
after,
|
|
89
|
+
workspace: "worktree",
|
|
90
|
+
targetSelection,
|
|
91
|
+
...(task === undefined ? {} : { task }),
|
|
92
|
+
...actor,
|
|
93
|
+
});
|
|
94
|
+
const accepted = requireAccepted(admission.admission === null ? admission.result : admission.admission.result);
|
|
95
|
+
const id = accepted.value.contractId;
|
|
96
|
+
const toHandle = ({ contractId: contract }) => createHandle(contract, scope);
|
|
97
|
+
const result = admission.admission === null
|
|
98
|
+
? await completeMutation({ ...completionInput(scope, channel, id, toHandle, hooks), accepted })
|
|
99
|
+
: await completeHolderMutation({
|
|
100
|
+
completion: completionInput(scope, channel, id, toHandle, hooks),
|
|
101
|
+
admission: admission.admission,
|
|
102
|
+
requireAccepted,
|
|
103
|
+
});
|
|
104
|
+
return acceptedBindResult(result, await observeRegion(scope, channel, id, document.region));
|
|
105
|
+
});
|
|
106
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { type RepositoryScope } from "../protocol/operations.js";
|
|
2
|
+
import { type IntegrationConflictMaterialized } from "../protocol/deliver.js";
|
|
3
|
+
import { type ReviewValue } from "../protocol/review.js";
|
|
4
|
+
import { type ContinuationReport } from "./continuation.js";
|
|
5
|
+
import { type MutationResult } from "./mutation.js";
|
|
6
|
+
import { type KeiyakuRefusal, type KeiyakuRetryReason } from "./refusal.js";
|
|
7
|
+
import { actorOption } from "./input.js";
|
|
8
|
+
import { type WorktreeHooks } from "./configuration.js";
|
|
9
|
+
import { Repo } from "./repo.js";
|
|
10
|
+
import { type ContractId } from "../core/facts/types.js";
|
|
11
|
+
import type { UpstreamRequestOutcome } from "../akuma/requests.js";
|
|
12
|
+
import type { DeliveryValue } from "./delivery.js";
|
|
13
|
+
export type DeliveryExecutionInput = Readonly<{
|
|
14
|
+
scope: RepositoryScope;
|
|
15
|
+
contractId: ContractId;
|
|
16
|
+
actor?: ReturnType<typeof actorOption>["actor"];
|
|
17
|
+
message?: string;
|
|
18
|
+
requireBranchesToBeUpToDate: boolean;
|
|
19
|
+
includeDirty: boolean;
|
|
20
|
+
materializeConflict: boolean;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
hooks: WorktreeHooks;
|
|
23
|
+
}>;
|
|
24
|
+
export type ReviewExecutionInput = Readonly<{
|
|
25
|
+
scope: RepositoryScope;
|
|
26
|
+
contractId: ContractId;
|
|
27
|
+
actor?: ReturnType<typeof actorOption>["actor"];
|
|
28
|
+
verdict: AttestationVerdict;
|
|
29
|
+
summary?: string;
|
|
30
|
+
hooks: WorktreeHooks;
|
|
31
|
+
}>;
|
|
32
|
+
export type AttestationVerdict = "satisfied" | "unsatisfied";
|
|
33
|
+
export type Review = ReviewValue & Readonly<{
|
|
34
|
+
continuation?: ContinuationReport;
|
|
35
|
+
}>;
|
|
36
|
+
export type ForwardedMutationReceipt<Value> = Readonly<{
|
|
37
|
+
kind: "accepted";
|
|
38
|
+
result: MutationResult<Value>;
|
|
39
|
+
}> | Readonly<{
|
|
40
|
+
kind: "refused";
|
|
41
|
+
refusal: KeiyakuRefusal;
|
|
42
|
+
}> | Readonly<{
|
|
43
|
+
kind: "retry";
|
|
44
|
+
reason: KeiyakuRetryReason;
|
|
45
|
+
}>;
|
|
46
|
+
export type ForwardedDeliveryReceipt = ForwardedMutationReceipt<DeliveryValue> | IntegrationConflictMaterialized;
|
|
47
|
+
export type ForwardedReviewReceipt = ForwardedMutationReceipt<Review>;
|
|
48
|
+
export declare function executeLocalDelivery(input: DeliveryExecutionInput): Promise<MutationResult<DeliveryValue> | IntegrationConflictMaterialized>;
|
|
49
|
+
export declare function executeLocalReview(input: ReviewExecutionInput): Promise<MutationResult<Review>>;
|
|
50
|
+
export declare function forwardedReceipt<Receipt>(outcome: UpstreamRequestOutcome, action: string): Receipt;
|
|
51
|
+
export declare function requireForwarded(receipt: ForwardedDeliveryReceipt): MutationResult<DeliveryValue> | IntegrationConflictMaterialized;
|
|
52
|
+
export declare function requireForwarded(receipt: ForwardedReviewReceipt): MutationResult<Review>;
|
|
53
|
+
export declare function executeForwardedDeliver(input: Readonly<{
|
|
54
|
+
repo: Repo;
|
|
55
|
+
contractId: string;
|
|
56
|
+
requester: string;
|
|
57
|
+
message?: string;
|
|
58
|
+
includeDirty: boolean;
|
|
59
|
+
materializeConflict: boolean;
|
|
60
|
+
requireBranchesToBeUpToDate: boolean;
|
|
61
|
+
hooks: WorktreeHooks;
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
}>): Promise<Readonly<{
|
|
64
|
+
result: ForwardedDeliveryReceipt;
|
|
65
|
+
deliveryFactId?: string;
|
|
66
|
+
}>>;
|
|
67
|
+
export declare function executeForwardedReview(input: Readonly<{
|
|
68
|
+
repo: Repo;
|
|
69
|
+
contractId: string;
|
|
70
|
+
requester: string;
|
|
71
|
+
verdict: AttestationVerdict;
|
|
72
|
+
summary?: string;
|
|
73
|
+
hooks: WorktreeHooks;
|
|
74
|
+
}>): Promise<Readonly<{
|
|
75
|
+
result: ForwardedReviewReceipt;
|
|
76
|
+
reviewFactId?: string;
|
|
77
|
+
}>>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { decodeContractDocument } from "../body/decode.js";
|
|
2
|
+
import { deliverOperation } from "../protocol/deliver.js";
|
|
3
|
+
import { reviewOperation } from "../protocol/review.js";
|
|
4
|
+
import { continueAcceptedCompletion } from "./continuation.js";
|
|
5
|
+
import { completionInput, completeMutation } from "./mutation.js";
|
|
6
|
+
import { forwardedMutationFailure, KeiyakuRefused, KeiyakuRetry, requireAccepted, } from "./refusal.js";
|
|
7
|
+
import { actorOption, documentDerivation, optionalNonblank } from "./input.js";
|
|
8
|
+
import { scopeForRepo } from "./repo.js";
|
|
9
|
+
import { contractId } from "../core/facts/types.js";
|
|
10
|
+
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
11
|
+
function derivedDocument(state) {
|
|
12
|
+
return documentDerivation(decodeContractDocument(state.terms.document.bytes), state.terms.gates, state.id);
|
|
13
|
+
}
|
|
14
|
+
function operationContext(scope, channel, contractId) {
|
|
15
|
+
return { scope, channel, contractId, deriveDocument: derivedDocument };
|
|
16
|
+
}
|
|
17
|
+
export async function executeLocalDelivery(input) {
|
|
18
|
+
return withGitDecodeChannel(input.scope, async (channel) => {
|
|
19
|
+
const operation = operationContext(input.scope, channel, input.contractId);
|
|
20
|
+
const outcome = await deliverOperation({
|
|
21
|
+
...operation,
|
|
22
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
23
|
+
...(input.message === undefined ? {} : { message: input.message }),
|
|
24
|
+
requireBranchesToBeUpToDate: input.requireBranchesToBeUpToDate,
|
|
25
|
+
includeDirty: input.includeDirty,
|
|
26
|
+
materializeConflict: input.materializeConflict,
|
|
27
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
28
|
+
});
|
|
29
|
+
if (outcome.kind === "integration-conflict-materialized")
|
|
30
|
+
return outcome;
|
|
31
|
+
const accepted = requireAccepted(outcome);
|
|
32
|
+
const continued = await continueAcceptedCompletion({
|
|
33
|
+
...operation,
|
|
34
|
+
accepted,
|
|
35
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
36
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
37
|
+
});
|
|
38
|
+
return completeMutation({
|
|
39
|
+
...completionInput(input.scope, channel, input.contractId, (delivery) => delivery, input.hooks),
|
|
40
|
+
accepted: continued,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
export async function executeLocalReview(input) {
|
|
45
|
+
return withGitDecodeChannel(input.scope, async (channel) => {
|
|
46
|
+
const operation = operationContext(input.scope, channel, input.contractId);
|
|
47
|
+
const accepted = requireAccepted(await reviewOperation({
|
|
48
|
+
...operation,
|
|
49
|
+
verdict: input.verdict,
|
|
50
|
+
...(input.summary === undefined ? {} : { summary: input.summary }),
|
|
51
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
52
|
+
}));
|
|
53
|
+
const continued = await continueAcceptedCompletion({
|
|
54
|
+
...operation,
|
|
55
|
+
accepted,
|
|
56
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
57
|
+
});
|
|
58
|
+
return completeMutation({
|
|
59
|
+
...completionInput(input.scope, channel, input.contractId, (review) => review, input.hooks),
|
|
60
|
+
accepted: continued,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
export function forwardedReceipt(outcome, action) {
|
|
65
|
+
if (outcome.kind === "failed") {
|
|
66
|
+
throw new Error(outcome.failure.kind === "failed"
|
|
67
|
+
? outcome.failure.diagnostic
|
|
68
|
+
: `Unexpected Akuma target failure for ${action}: ${outcome.failure.id}`);
|
|
69
|
+
}
|
|
70
|
+
return outcome.result;
|
|
71
|
+
}
|
|
72
|
+
export function requireForwarded(receipt) {
|
|
73
|
+
if (receipt.kind === "refused")
|
|
74
|
+
throw new KeiyakuRefused(receipt.refusal);
|
|
75
|
+
if (receipt.kind === "retry")
|
|
76
|
+
throw new KeiyakuRetry(receipt.reason);
|
|
77
|
+
return receipt.kind === "accepted" ? receipt.result : receipt;
|
|
78
|
+
}
|
|
79
|
+
export async function executeForwardedDeliver(input) {
|
|
80
|
+
const id = contractId(input.contractId);
|
|
81
|
+
const actor = actorOption(input.requester).actor;
|
|
82
|
+
const message = optionalNonblank(input.message, "deliver message");
|
|
83
|
+
try {
|
|
84
|
+
const result = await executeLocalDelivery({
|
|
85
|
+
scope: scopeForRepo(input.repo),
|
|
86
|
+
contractId: id,
|
|
87
|
+
...(actor === undefined ? {} : { actor }),
|
|
88
|
+
...(message === undefined ? {} : { message }),
|
|
89
|
+
requireBranchesToBeUpToDate: input.requireBranchesToBeUpToDate,
|
|
90
|
+
includeDirty: input.includeDirty,
|
|
91
|
+
materializeConflict: input.materializeConflict,
|
|
92
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
93
|
+
hooks: input.hooks,
|
|
94
|
+
});
|
|
95
|
+
if (!("facts" in result))
|
|
96
|
+
return { result };
|
|
97
|
+
const delivery = result.facts.find((fact) => fact.kind === "deliver");
|
|
98
|
+
if (delivery === undefined)
|
|
99
|
+
throw new Error("accepted delivery is missing its journal fact");
|
|
100
|
+
return { result: { kind: "accepted", result }, deliveryFactId: delivery.entry };
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
return forwardedMutationFailure(error);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export async function executeForwardedReview(input) {
|
|
107
|
+
const id = contractId(input.contractId);
|
|
108
|
+
const actor = actorOption(input.requester).actor;
|
|
109
|
+
if (input.verdict !== "satisfied" && input.verdict !== "unsatisfied") {
|
|
110
|
+
throw new TypeError("verdict must be satisfied or unsatisfied");
|
|
111
|
+
}
|
|
112
|
+
const summary = optionalNonblank(input.summary, "review summary");
|
|
113
|
+
try {
|
|
114
|
+
const result = await executeLocalReview({
|
|
115
|
+
scope: scopeForRepo(input.repo),
|
|
116
|
+
contractId: id,
|
|
117
|
+
...(actor === undefined ? {} : { actor }),
|
|
118
|
+
verdict: input.verdict,
|
|
119
|
+
...(summary === undefined ? {} : { summary }),
|
|
120
|
+
hooks: input.hooks,
|
|
121
|
+
});
|
|
122
|
+
const review = result.facts.find((fact) => fact.kind === "attestation");
|
|
123
|
+
if (review === undefined)
|
|
124
|
+
throw new Error("accepted review is missing its journal fact");
|
|
125
|
+
return { result: { kind: "accepted", result }, reviewFactId: review.entry };
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
return forwardedMutationFailure(error);
|
|
129
|
+
}
|
|
130
|
+
}
|