@astrosheep/keiyaku 4.0.4 → 4.0.6
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/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +24 -4
- package/build/src/akuma/akuma.d.ts +2 -1
- package/build/src/akuma/akuma.js +27 -9
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +3 -10
- package/build/src/akuma/archetype.d.ts +3 -1
- package/build/src/akuma/archetype.js +11 -6
- package/build/src/akuma/body-turn.d.ts +64 -0
- package/build/src/akuma/body-turn.js +449 -0
- package/build/src/akuma/body.d.ts +4 -5
- package/build/src/akuma/body.js +9 -414
- package/build/src/akuma/heart/facts.d.ts +37 -9
- package/build/src/akuma/heart/facts.js +3 -1
- package/build/src/akuma/heart/index.d.ts +4 -13
- package/build/src/akuma/heart/index.js +14 -135
- package/build/src/akuma/heart/request-authority.d.ts +12 -0
- package/build/src/akuma/heart/request-authority.js +119 -0
- package/build/src/akuma/heart/request-rows.d.ts +16 -0
- package/build/src/akuma/heart/request-rows.js +88 -0
- package/build/src/akuma/heart/rows.d.ts +1 -28
- package/build/src/akuma/heart/rows.js +4 -138
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +11 -3
- package/build/src/akuma/heart/soul.js +0 -36
- package/build/src/akuma/heart/timeline.d.ts +1 -0
- package/build/src/akuma/heart/timeline.js +19 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/nuke.d.ts +2 -0
- package/build/src/akuma/nuke.js +152 -0
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +4 -7
- package/build/src/akuma/providers/acp/config.d.ts +8 -0
- package/build/src/akuma/providers/acp/config.js +37 -0
- package/build/src/akuma/providers/acp/core.js +12 -2
- package/build/src/akuma/providers/acp/index.d.ts +1 -8
- package/build/src/akuma/providers/acp/index.js +2 -38
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +12 -3
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +5 -2
- package/build/src/akuma/providers/grok-build/index.js +1 -2
- package/build/src/akuma/providers/index.d.ts +3 -2
- package/build/src/akuma/providers/index.js +36 -36
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +14 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +2 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +2 -2
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +29 -6
- package/build/src/akuma/request-serve.d.ts +88 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +125 -0
- package/build/src/akuma/request-wire.js +383 -0
- package/build/src/akuma/requests.d.ts +28 -94
- package/build/src/akuma/requests.js +52 -562
- package/build/src/akuma-body.d.ts +7 -0
- package/build/src/akuma-body.js +69 -2
- package/build/src/alias/index.d.ts +1 -0
- package/build/src/alias/index.js +34 -1
- package/build/src/body/arc.js +4 -29
- package/build/src/body/decode.js +5 -39
- package/build/src/body/envelope.d.ts +7 -0
- package/build/src/body/envelope.js +37 -0
- package/build/src/cli/accepted.js +21 -9
- package/build/src/cli/commands/akuma-invoke.js +1 -0
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +13 -10
- package/build/src/cli/commands/contract.d.ts +28 -17
- package/build/src/cli/commands/contract.js +23 -17
- package/build/src/cli/commands/install.d.ts +2 -2
- package/build/src/cli/commands/install.js +6 -6
- package/build/src/cli/commands/nuke.d.ts +10 -0
- package/build/src/cli/commands/nuke.js +20 -0
- package/build/src/cli/commands/task-invoke.d.ts +15 -0
- package/build/src/cli/commands/task-invoke.js +144 -24
- package/build/src/cli/commands/task-query.d.ts +2 -2
- package/build/src/cli/commands/task-query.js +1 -2
- package/build/src/cli/commands/task.js +22 -22
- package/build/src/cli/coordinates.d.ts +6 -2
- package/build/src/cli/coordinates.js +12 -56
- package/build/src/cli/invoke.d.ts +5 -4
- package/build/src/cli/invoke.js +112 -58
- package/build/src/cli/main.d.ts +0 -2
- package/build/src/cli/main.js +4 -140
- package/build/src/cli/parse.d.ts +17 -4
- package/build/src/cli/parse.js +93 -15
- package/build/src/cli/render/akuma.js +111 -53
- package/build/src/cli/render/audit.js +2 -6
- package/build/src/cli/render/contract.js +61 -20
- package/build/src/cli/render/kanshi.js +15 -5
- package/build/src/cli/render/nuke.d.ts +3 -0
- package/build/src/cli/render/nuke.js +8 -0
- package/build/src/cli/render/receipt.js +28 -1
- package/build/src/cli/render/refusal.d.ts +2 -1
- package/build/src/cli/render/refusal.js +31 -0
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/render/text.js +6 -1
- package/build/src/cli/result.d.ts +36 -9
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +140 -0
- package/build/src/cli/usage.d.ts +0 -2
- package/build/src/cli/usage.js +0 -4
- package/build/src/contract-worktree.d.ts +29 -14
- package/build/src/contract-worktree.js +131 -70
- package/build/src/core/facts/codec.js +9 -0
- package/build/src/core/facts/fold.js +13 -1
- package/build/src/core/facts/types.d.ts +8 -1
- package/build/src/core/subject.js +4 -3
- package/build/src/core/verbs/placement.d.ts +9 -1
- package/build/src/core/verbs/placement.js +24 -6
- package/build/src/core/verbs/reintegrate.d.ts +13 -0
- package/build/src/core/verbs/reintegrate.js +24 -0
- package/build/src/dispatch/index.d.ts +1 -1
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +2 -0
- package/build/src/git/hooks.js +34 -1
- package/build/src/git/integration.d.ts +9 -2
- package/build/src/git/integration.js +92 -1
- package/build/src/git/nuke.d.ts +2 -0
- package/build/src/git/nuke.js +97 -0
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +28 -0
- package/build/src/git/process.js +94 -0
- package/build/src/git/read-observation.d.ts +2 -1
- package/build/src/git/read-observation.js +3 -2
- package/build/src/git/reconcile.d.ts +4 -1
- package/build/src/git/reconcile.js +42 -8
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +7 -118
- package/build/src/git/scratch.d.ts +1 -1
- package/build/src/git/scratch.js +1 -1
- package/build/src/git/target-placement.d.ts +3 -2
- package/build/src/git/target-placement.js +15 -14
- package/build/src/git/tender.d.ts +2 -1
- package/build/src/git/tender.js +4 -3
- package/build/src/git/terminal-seal.d.ts +2 -2
- package/build/src/git/terminal-seal.js +3 -6
- package/build/src/git/workspace.d.ts +4 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/read.js +5 -1
- package/build/src/library/address.js +7 -1
- package/build/src/library/akuma-creation.d.ts +1 -0
- package/build/src/library/akuma-creation.js +8 -1
- package/build/src/library/audit.d.ts +3 -1
- package/build/src/library/audit.js +2 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +1 -1
- package/build/src/library/configuration.d.ts +1 -1
- package/build/src/library/configuration.js +52 -18
- package/build/src/library/contract.d.ts +59 -4
- package/build/src/library/contract.js +195 -34
- package/build/src/library/delivery.d.ts +4 -2
- package/build/src/library/fleet.d.ts +27 -7
- package/build/src/library/fleet.js +79 -39
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +0 -5
- package/build/src/library/keiyaku.d.ts +6 -2
- package/build/src/library/keiyaku.js +2 -0
- package/build/src/library/mutation.d.ts +3 -1
- package/build/src/library/mutation.js +3 -0
- package/build/src/library/nuke.d.ts +14 -0
- package/build/src/library/nuke.js +54 -0
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +8 -3
- package/build/src/library/refusal.d.ts +10 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +4 -1
- package/build/src/library/repo.js +10 -4
- package/build/src/protocol/abandon.d.ts +9 -0
- package/build/src/protocol/abandon.js +15 -0
- package/build/src/protocol/amend.d.ts +16 -0
- package/build/src/protocol/amend.js +77 -0
- package/build/src/protocol/arc.d.ts +6 -0
- package/build/src/protocol/arc.js +12 -0
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/audit.d.ts +53 -0
- package/build/src/protocol/audit.js +147 -0
- package/build/src/protocol/bind.d.ts +1 -1
- package/build/src/protocol/completion.d.ts +42 -0
- package/build/src/protocol/completion.js +183 -0
- package/build/src/protocol/deliver.d.ts +49 -0
- package/build/src/protocol/deliver.js +261 -0
- package/build/src/protocol/intent.d.ts +2 -1
- package/build/src/protocol/intent.js +8 -2
- package/build/src/protocol/operations.d.ts +93 -202
- package/build/src/protocol/operations.js +23 -642
- package/build/src/protocol/placement.d.ts +12 -13
- package/build/src/protocol/placement.js +8 -19
- package/build/src/protocol/read/status.d.ts +17 -5
- package/build/src/protocol/read/status.js +57 -13
- package/build/src/protocol/reconcile.d.ts +35 -0
- package/build/src/protocol/reconcile.js +41 -0
- package/build/src/protocol/reintegrate.d.ts +31 -0
- package/build/src/protocol/reintegrate.js +74 -0
- package/build/src/protocol/review.d.ts +34 -0
- package/build/src/protocol/review.js +156 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.js +9 -5
- package/build/src/settlement/fence.d.ts +3 -1
- package/build/src/settlement/fence.js +24 -0
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +1 -2
- package/build/src/task/board.d.ts +0 -1
- package/build/src/task/board.js +0 -3
- package/build/src/task/compose.d.ts +2 -2
- package/build/src/task/compose.js +13 -11
- package/build/src/task/context.d.ts +14 -2
- package/build/src/task/context.js +30 -7
- package/build/src/task/index.d.ts +7 -6
- package/build/src/task/index.js +17 -145
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +44 -0
- package/build/src/task/mutation.js +93 -0
- package/build/src/task/operations.d.ts +14 -6
- package/build/src/task/operations.js +57 -57
- package/build/src/task/store.d.ts +1 -0
- package/build/src/task/store.js +91 -3
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/workspace-place.d.ts +3 -4
- package/build/src/workspace-place.js +26 -15
- package/package.json +3 -3
|
@@ -9,12 +9,23 @@ import { scopeForRepo } from "./repo.js";
|
|
|
9
9
|
function source(path) {
|
|
10
10
|
return Akuma.of(path);
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
function observationDiagnostic(error) {
|
|
13
|
+
return error instanceof Error ? error.message : String(error);
|
|
14
|
+
}
|
|
15
|
+
const NO_DISPATCH = { kind: "none" };
|
|
16
|
+
async function dispatchAssociation(repo, id) {
|
|
17
|
+
if (repo === undefined)
|
|
18
|
+
return NO_DISPATCH;
|
|
19
|
+
try {
|
|
20
|
+
const dispatch = await readDispatch(scopeForRepo(repo), id);
|
|
21
|
+
return dispatch === null ? NO_DISPATCH : { kind: "associated", contractId: dispatch.contractId };
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
return { kind: "failed", diagnostic: observationDiagnostic(error) };
|
|
25
|
+
}
|
|
15
26
|
}
|
|
16
27
|
function createdTaskDiagnostic(error) {
|
|
17
|
-
return
|
|
28
|
+
return observationDiagnostic(error);
|
|
18
29
|
}
|
|
19
30
|
async function createdTasksFor(path, statuses) {
|
|
20
31
|
let board;
|
|
@@ -30,16 +41,23 @@ async function createdTasksFor(path, statuses) {
|
|
|
30
41
|
async function observeAkuma(status, path, repo) {
|
|
31
42
|
return (await observeAkumaSet([status], path, repo))[0];
|
|
32
43
|
}
|
|
44
|
+
async function observeAkumaStage(path, id, repo) {
|
|
45
|
+
try {
|
|
46
|
+
return { kind: "observed", ...await observeAkuma(await source(path).of({ id }).status(), path, repo) };
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof AkumaNotBornError)
|
|
50
|
+
throw error;
|
|
51
|
+
return { kind: "unobserved", diagnostic: observationDiagnostic(error) };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
33
54
|
async function observeAkumaSet(statuses, path, repo) {
|
|
34
55
|
const created = await createdTasksFor(path, statuses);
|
|
35
|
-
return await Promise.all(statuses.map(async (status, index) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
...(contractId === undefined ? {} : { contractId }),
|
|
41
|
-
};
|
|
42
|
-
}));
|
|
56
|
+
return await Promise.all(statuses.map(async (status, index) => ({
|
|
57
|
+
status,
|
|
58
|
+
contract: await dispatchAssociation(repo, status.id),
|
|
59
|
+
createdTasks: created[index],
|
|
60
|
+
})));
|
|
43
61
|
}
|
|
44
62
|
function timeout(value) {
|
|
45
63
|
if (value === undefined)
|
|
@@ -69,31 +87,45 @@ function delay(milliseconds, signal) {
|
|
|
69
87
|
});
|
|
70
88
|
}
|
|
71
89
|
const SHARED_ORDINARY_BUDGET = 30;
|
|
72
|
-
async function
|
|
90
|
+
async function observeWaitRound(path, ids, signal) {
|
|
73
91
|
signal?.throwIfAborted();
|
|
74
92
|
if (ids.length <= 1) {
|
|
75
|
-
return
|
|
93
|
+
return {
|
|
94
|
+
statuses: await Promise.all(ids.map(async (id) => await source(path).of({ id }).status())),
|
|
95
|
+
unobserved: [],
|
|
96
|
+
};
|
|
76
97
|
}
|
|
77
98
|
let remaining = SHARED_ORDINARY_BUDGET;
|
|
78
99
|
const statuses = [];
|
|
100
|
+
const unobserved = [];
|
|
79
101
|
for (const id of ids) {
|
|
80
102
|
signal?.throwIfAborted();
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
103
|
+
try {
|
|
104
|
+
const observed = await readBudgetedStatus(path, id, { ordinaryBudget: remaining });
|
|
105
|
+
statuses.push(observed.status);
|
|
106
|
+
remaining -= observed.ordinarySelected;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (error instanceof AkumaNotBornError)
|
|
110
|
+
throw error;
|
|
111
|
+
unobserved.push({ id, diagnostic: observationDiagnostic(error) });
|
|
112
|
+
}
|
|
84
113
|
}
|
|
85
|
-
return statuses;
|
|
114
|
+
return { statuses, unobserved };
|
|
86
115
|
}
|
|
87
116
|
export async function executeWaitAkuma(input) {
|
|
88
117
|
const deadline = input.timeoutMs === undefined ? undefined : performance.now() + input.timeoutMs;
|
|
89
118
|
for (;;) {
|
|
90
|
-
const
|
|
91
|
-
const settled = statuses.map((status) => status.life !== "running");
|
|
92
|
-
|
|
119
|
+
const round = await observeWaitRound(input.path, input.ids, input.signal);
|
|
120
|
+
const settled = round.statuses.map((status) => status.life !== "running");
|
|
121
|
+
const completed = round.statuses.length > 0
|
|
122
|
+
&& (input.completion === "any" ? settled.some(Boolean) : settled.every(Boolean));
|
|
123
|
+
if (completed
|
|
93
124
|
|| (deadline !== undefined && performance.now() >= deadline)) {
|
|
94
125
|
return {
|
|
95
126
|
completion: input.completion,
|
|
96
|
-
observations: await observeAkumaSet(statuses, input.path, input.repo),
|
|
127
|
+
observations: await observeAkumaSet(round.statuses, input.path, input.repo),
|
|
128
|
+
unobserved: round.unobserved,
|
|
97
129
|
};
|
|
98
130
|
}
|
|
99
131
|
await delay(deadline === undefined ? 25 : Math.min(25, Math.max(0, deadline - performance.now())), input.signal);
|
|
@@ -109,7 +141,7 @@ export async function executeTellAkuma(input) {
|
|
|
109
141
|
return {
|
|
110
142
|
akuma: input.id,
|
|
111
143
|
tell,
|
|
112
|
-
observation: await
|
|
144
|
+
observation: await observeAkumaStage(input.path, input.id, input.repo),
|
|
113
145
|
};
|
|
114
146
|
}
|
|
115
147
|
export async function executeKillAkuma(input) {
|
|
@@ -117,10 +149,12 @@ export async function executeKillAkuma(input) {
|
|
|
117
149
|
const handles = input.ids.map((id) => source(input.path).of({ id }));
|
|
118
150
|
const evidence = await Promise.all(handles.map(async (handle) => await handle.kill()));
|
|
119
151
|
input.signal?.throwIfAborted();
|
|
120
|
-
const statuses = await Promise.all(input.ids.map(async (id) => await source(input.path).of({ id }).status()));
|
|
121
|
-
const observations = await observeAkumaSet(statuses, input.path, input.repo);
|
|
122
152
|
return {
|
|
123
|
-
results: input.ids.map((id, index) => ({
|
|
153
|
+
results: await Promise.all(input.ids.map(async (id, index) => ({
|
|
154
|
+
id,
|
|
155
|
+
evidence: evidence[index],
|
|
156
|
+
observation: await observeAkumaStage(input.path, id, input.repo),
|
|
157
|
+
}))),
|
|
124
158
|
};
|
|
125
159
|
}
|
|
126
160
|
function upstreamResult(outcome) {
|
|
@@ -130,22 +164,29 @@ function upstreamResult(outcome) {
|
|
|
130
164
|
throw new AkumaNotBornError(outcome.failure.id);
|
|
131
165
|
throw new Error(outcome.failure.diagnostic);
|
|
132
166
|
}
|
|
133
|
-
|
|
134
|
-
|
|
167
|
+
function needsDispatchAttach(association) {
|
|
168
|
+
return association.kind === "none";
|
|
169
|
+
}
|
|
170
|
+
async function attachObservationContract(repo, observation) {
|
|
171
|
+
if (repo === undefined || !needsDispatchAttach(observation.contract))
|
|
172
|
+
return observation;
|
|
173
|
+
return { ...observation, contract: await dispatchAssociation(repo, observation.status.id) };
|
|
174
|
+
}
|
|
175
|
+
async function attachObservationStage(repo, observation) {
|
|
176
|
+
if (repo === undefined || observation.kind !== "observed")
|
|
135
177
|
return observation;
|
|
136
|
-
|
|
137
|
-
return contractId === undefined ? observation : { ...observation, contractId };
|
|
178
|
+
return { ...observation, ...(await attachObservationContract(repo, observation)) };
|
|
138
179
|
}
|
|
139
180
|
async function attachWaitContracts(repo, result) {
|
|
140
181
|
return repo === undefined
|
|
141
182
|
? result
|
|
142
183
|
: {
|
|
143
184
|
...result,
|
|
144
|
-
observations: await Promise.all(result.observations.map((observation) =>
|
|
185
|
+
observations: await Promise.all(result.observations.map((observation) => attachObservationContract(repo, observation))),
|
|
145
186
|
};
|
|
146
187
|
}
|
|
147
188
|
async function attachTellContract(repo, result) {
|
|
148
|
-
return repo === undefined ? result : { ...result, observation: await
|
|
189
|
+
return repo === undefined ? result : { ...result, observation: await attachObservationStage(repo, result.observation) };
|
|
149
190
|
}
|
|
150
191
|
async function attachKillContracts(repo, result) {
|
|
151
192
|
return repo === undefined
|
|
@@ -154,7 +195,7 @@ async function attachKillContracts(repo, result) {
|
|
|
154
195
|
...result,
|
|
155
196
|
results: await Promise.all(result.results.map(async (entry) => ({
|
|
156
197
|
...entry,
|
|
157
|
-
observation: await
|
|
198
|
+
observation: await attachObservationStage(repo, entry.observation),
|
|
158
199
|
}))),
|
|
159
200
|
};
|
|
160
201
|
}
|
|
@@ -262,7 +303,7 @@ export async function interruptAkuma(input) {
|
|
|
262
303
|
const addressed = await addressAkuma(directAddress(values));
|
|
263
304
|
const handle = source(addressed.path).of({ id: addressed.id });
|
|
264
305
|
const receipt = await handle.interrupt(values.body);
|
|
265
|
-
const observation = await
|
|
306
|
+
const observation = await observeAkumaStage(addressed.path, addressed.id, values.repo);
|
|
266
307
|
return { id: addressed.id, receipt, observation };
|
|
267
308
|
}
|
|
268
309
|
export async function historyAkuma(input) {
|
|
@@ -276,18 +317,17 @@ export async function historyAkuma(input) {
|
|
|
276
317
|
throw new TypeError("last must be a boolean");
|
|
277
318
|
const addressed = await addressAkuma(directAddress(values));
|
|
278
319
|
const handle = source(addressed.path).of({ id: addressed.id });
|
|
320
|
+
const contract = await dispatchAssociation(values.repo, addressed.id);
|
|
279
321
|
if (values.last === true) {
|
|
280
322
|
const answer = await handle.lastAnswer();
|
|
281
|
-
const contractId = await contractFor(values.repo, addressed.id);
|
|
282
323
|
return answer.kind === "answer"
|
|
283
|
-
? { kind: "last", id: addressed.id, answer: answer.answer,
|
|
284
|
-
: { kind: "no-answer", id: addressed.id,
|
|
324
|
+
? { kind: "last", id: addressed.id, answer: answer.answer, contract }
|
|
325
|
+
: { kind: "no-answer", id: addressed.id, contract };
|
|
285
326
|
}
|
|
286
327
|
const history = await handle.history({
|
|
287
328
|
...(values.before === undefined ? {} : { before: values.before }),
|
|
288
329
|
...(values.since === undefined ? {} : { since: values.since }),
|
|
289
330
|
...(values.limit === undefined ? {} : { limit: values.limit }),
|
|
290
331
|
});
|
|
291
|
-
|
|
292
|
-
return { kind: "history", id: addressed.id, history, ...(contractId === undefined ? {} : { contractId }) };
|
|
332
|
+
return { kind: "history", id: addressed.id, history, contract };
|
|
293
333
|
}
|
|
@@ -6,7 +6,6 @@ export declare function actorOption(actor: unknown): Readonly<{
|
|
|
6
6
|
}>;
|
|
7
7
|
export declare function requireMarkdown(value: unknown, label?: string): string;
|
|
8
8
|
export declare function requireInput(value: unknown, label: string): Record<string, unknown>;
|
|
9
|
-
export declare function rejectUnknownFields(values: Record<string, unknown>, allowed: readonly string[], label: string): void;
|
|
10
9
|
export declare function optionalNonblank(value: unknown, label: string): string | undefined;
|
|
11
10
|
export declare function optionalBoolean(value: unknown, label: string): boolean | undefined;
|
|
12
11
|
export declare function optionalSignal(value: unknown): AbortSignal | undefined;
|
|
@@ -22,11 +22,6 @@ export function requireInput(value, label) {
|
|
|
22
22
|
throw new TypeError(`${label} must be an object`);
|
|
23
23
|
return value;
|
|
24
24
|
}
|
|
25
|
-
export function rejectUnknownFields(values, allowed, label) {
|
|
26
|
-
for (const key of Object.keys(values))
|
|
27
|
-
if (!allowed.includes(key))
|
|
28
|
-
throw new TypeError(`${label} has unknown field: ${key}`);
|
|
29
|
-
}
|
|
30
25
|
export function optionalNonblank(value, label) {
|
|
31
26
|
if (value === undefined)
|
|
32
27
|
return undefined;
|
|
@@ -2,12 +2,13 @@ import { KeiyakuHandle, bindKeiyaku, keiyakuOf, listKeiyaku, observeKeiyaku, typ
|
|
|
2
2
|
import { callKeiyaku, forkKeiyaku } from "./akuma-creation.js";
|
|
3
3
|
import { historyAkuma, interruptAkuma, killAkuma, statusAkuma, tellAkuma, waitAkuma } from "./fleet.js";
|
|
4
4
|
import { listCatalog } from "./catalog.js";
|
|
5
|
+
import { nukeKeiyaku } from "./nuke.js";
|
|
5
6
|
export { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
6
7
|
export { Delivery, KeiyakuRefused, KeiyakuRetry, } from "./contract.js";
|
|
7
8
|
export { NoGitWorldError, Repo } from "./repo.js";
|
|
8
9
|
export { gatesFrom, requireBranchesToBeUpToDateFrom, SettingsError, worktreeHooksFrom, } from "./configuration.js";
|
|
9
10
|
export { AkumaWorldScopeError } from "./address.js";
|
|
10
|
-
export type { AbandonInput, ActorId, AmendInput, AmendResult, ArcInput, AttestationVerdict, AuditInput, AuditReport, DeliveryPreparationRefusal, BindInput, BindResult, ContractBoard, ContractDisposition, ContractGateCurrent, ContractGateReport, ContractHistory, ContractHistoryEvent, ContractListInput, ContractObservation, ContractObservationInput, ContractPhase, ContractRow, DeliverInput, Fact, FactKind, KeiyakuOfInput, KeiyakuRefusal, KeiyakuRetryReason, Lag, MutationResult, PlacementStop, ReconcileReport, Review, ReviewInput, TaskId, TopologyEffect, VerificationReuse, VerificationStop, } from "./contract.js";
|
|
11
|
+
export type { AbandonInput, ActorId, AmendInput, AmendResult, ArcInput, AttestationVerdict, AuditInput, AuditReport, DeliveryPreparationRefusal, BindInput, BindResult, ContractBoard, ContractDisposition, ContractGateCurrent, ContractGateReport, ContractHistory, ContractHistoryEvent, ContractListInput, ContractObservation, ContractObservationInput, ContractPhase, ContractRow, DeliverInput, Fact, IntegrationConflictMaterialized, FactKind, KeiyakuOfInput, KeiyakuRefusal, KeiyakuRetryReason, Lag, MutationResult, PlacementStop, ReconcileReport, Review, ReviewInput, TaskId, TopologyEffect, VerificationReuse, VerificationStop, } from "./contract.js";
|
|
11
12
|
export type { ContractId, ContractState, ChangeId, SnapshotId, } from "../core/facts/types.js";
|
|
12
13
|
export type { Gate, GatesFromInput, HookCommand, RequireBranchesToBeUpToDateFromInput, WorktreeHooks, } from "./configuration.js";
|
|
13
14
|
export type { RegionOverlap } from "./region.js";
|
|
@@ -21,8 +22,10 @@ export type { AkumaGlob } from "../identity/selector.js";
|
|
|
21
22
|
export type { AkuId } from "../akuma/identity.js";
|
|
22
23
|
export type { AllowedAction, AllowedActions } from "../akuma/allowed.js";
|
|
23
24
|
export type { Catalog, CatalogInput, CatalogQuery } from "./catalog.js";
|
|
25
|
+
export type { NukeInput, NukeResult, } from "./nuke.js";
|
|
26
|
+
export type { NukeConfirmationRefusal, NukeConfirmationRequiredRefusal } from "./refusal.js";
|
|
24
27
|
export type { AkumaAddressInput, AkumaSetAddressInput, AkumaWorldScopeRefusal, DirectAkumaSelector, SetAkumaSelector, } from "./address.js";
|
|
25
|
-
export type { AkumaHistoryInput, AkumaHistoryResult, AkumaInterruptInput, AkumaInterruptResult, AkumaKillResult, AkumaObservation, AkumaTellInput, CreatedTaskObservation, AkumaTellResult, AkumaWaitInput, AkumaWaitResult, } from "./fleet.js";
|
|
28
|
+
export type { AkumaHistoryInput, AkumaHistoryResult, AkumaInterruptInput, AkumaInterruptResult, AkumaKillResult, AkumaObservation, AkumaObservationStage, AkumaTellInput, AkumaUnobserved, CreatedTaskObservation, DispatchAssociation, AkumaTellResult, AkumaWaitInput, AkumaWaitResult, } from "./fleet.js";
|
|
26
29
|
export type Keiyaku = KeiyakuType;
|
|
27
30
|
export declare const Keiyaku: Readonly<{
|
|
28
31
|
prototype: KeiyakuHandle;
|
|
@@ -34,6 +37,7 @@ export declare const Keiyaku: Readonly<{
|
|
|
34
37
|
interrupt: typeof interruptAkuma;
|
|
35
38
|
kill: typeof killAkuma;
|
|
36
39
|
ls: typeof listCatalog;
|
|
40
|
+
nuke: typeof nukeKeiyaku;
|
|
37
41
|
list: typeof listKeiyaku;
|
|
38
42
|
observe: typeof observeKeiyaku;
|
|
39
43
|
of: typeof keiyakuOf;
|
|
@@ -2,6 +2,7 @@ import { KeiyakuHandle, bindKeiyaku, keiyakuOf, listKeiyaku, observeKeiyaku, } f
|
|
|
2
2
|
import { callKeiyaku, forkKeiyaku } from "./akuma-creation.js";
|
|
3
3
|
import { historyAkuma, interruptAkuma, killAkuma, statusAkuma, tellAkuma, waitAkuma, } from "./fleet.js";
|
|
4
4
|
import { listCatalog } from "./catalog.js";
|
|
5
|
+
import { nukeKeiyaku } from "./nuke.js";
|
|
5
6
|
export { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
6
7
|
export { Delivery, KeiyakuRefused, KeiyakuRetry, } from "./contract.js";
|
|
7
8
|
export { NoGitWorldError, Repo } from "./repo.js";
|
|
@@ -17,6 +18,7 @@ export const Keiyaku = Object.freeze({
|
|
|
17
18
|
interrupt: interruptAkuma,
|
|
18
19
|
kill: killAkuma,
|
|
19
20
|
ls: listCatalog,
|
|
21
|
+
nuke: nukeKeiyaku,
|
|
20
22
|
list: listKeiyaku,
|
|
21
23
|
observe: observeKeiyaku,
|
|
22
24
|
of: keiyakuOf,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ContractHead, ContractId, JournalEntry } from "../core/facts/types.js";
|
|
2
2
|
import type { GitDecodeChannel } from "../git/read-observation.js";
|
|
3
|
-
import type { ReconcileReport
|
|
3
|
+
import type { ReconcileReport } from "../protocol/reconcile.js";
|
|
4
|
+
import type { RepositoryScope } from "../protocol/operations.js";
|
|
4
5
|
import type { IntentOutcome } from "../protocol/operations.js";
|
|
5
6
|
import type { AcceptedObligations } from "../protocol/outcome.js";
|
|
6
7
|
import { type SettlementReport } from "../settlement/settle.js";
|
|
@@ -30,6 +31,7 @@ type Completion<Value, PublicValue> = Readonly<{
|
|
|
30
31
|
value: (result: Value) => PublicValue;
|
|
31
32
|
hooks: WorktreeHooks;
|
|
32
33
|
}>;
|
|
34
|
+
export declare function completionInput<Value, PublicValue>(scope: RepositoryScope, channel: GitDecodeChannel, contractId: ContractId, value: (result: Value) => PublicValue, hooks: WorktreeHooks): Omit<Completion<Value, PublicValue>, "accepted">;
|
|
33
35
|
export declare function completeMutation<Value, PublicValue>(input: Completion<Value, PublicValue>): Promise<MutationResult<PublicValue>>;
|
|
34
36
|
export declare function completeHolderMutation<Value, PublicValue, Refusal>(input: Readonly<{
|
|
35
37
|
completion: Omit<Completion<Value, PublicValue>, "accepted">;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { deferredTaskHolderSettlement } from "../settlement/settle.js";
|
|
2
2
|
import { completeReconcile } from "./reconcile.js";
|
|
3
|
+
export function completionInput(scope, channel, contractId, value, hooks) {
|
|
4
|
+
return { scope, channel, contractId, value, hooks };
|
|
5
|
+
}
|
|
3
6
|
export async function completeMutation(input) {
|
|
4
7
|
const { scope, channel, contractId, accepted, value, hooks } = input;
|
|
5
8
|
const report = await completeReconcile({ scope, channel, contractId, hooks, retryHooks: false });
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { WorldRoot } from "../world.js";
|
|
2
|
+
export type NukeInput = Readonly<{
|
|
3
|
+
world: WorldRoot;
|
|
4
|
+
confirm?: string;
|
|
5
|
+
}>;
|
|
6
|
+
export type NukeResult = Readonly<{
|
|
7
|
+
kind: "success";
|
|
8
|
+
world: WorldRoot;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
kind: "failed";
|
|
11
|
+
world: WorldRoot;
|
|
12
|
+
diagnostic: string;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function nukeKeiyaku(input: NukeInput): Promise<NukeResult>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { stopAkuma } from "../akuma/nuke.js";
|
|
2
|
+
import { nukeGit } from "../git/nuke.js";
|
|
3
|
+
import { nukeTask } from "../task/operations.js";
|
|
4
|
+
import { KeiyakuRefused } from "./refusal.js";
|
|
5
|
+
import { requireInput, requireMarkdown } from "./input.js";
|
|
6
|
+
function diagnostic(error) {
|
|
7
|
+
return error instanceof Error ? error.message : String(error);
|
|
8
|
+
}
|
|
9
|
+
function nukeInput(input) {
|
|
10
|
+
const value = requireInput(input, "nuke input");
|
|
11
|
+
const world = requireMarkdown(value.world, "world");
|
|
12
|
+
const confirm = value.confirm === undefined ? undefined : requireMarkdown(value.confirm, "confirm");
|
|
13
|
+
return { world, ...(confirm === undefined ? {} : { confirm }) };
|
|
14
|
+
}
|
|
15
|
+
export async function nukeKeiyaku(input) {
|
|
16
|
+
const value = nukeInput(input);
|
|
17
|
+
if (value.confirm === undefined) {
|
|
18
|
+
throw new KeiyakuRefused({ kind: "nuke-confirmation-required", world: value.world });
|
|
19
|
+
}
|
|
20
|
+
if (value.confirm !== value.world) {
|
|
21
|
+
throw new KeiyakuRefused({
|
|
22
|
+
kind: "nuke-confirmation-mismatch",
|
|
23
|
+
world: value.world,
|
|
24
|
+
confirmation: value.confirm,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const deleteAkuma = await stopAkuma(value.world);
|
|
29
|
+
let failed = false;
|
|
30
|
+
let firstDiagnostic;
|
|
31
|
+
const attempt = async (owner) => {
|
|
32
|
+
try {
|
|
33
|
+
await owner;
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (!failed) {
|
|
37
|
+
failed = true;
|
|
38
|
+
firstDiagnostic = error;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
await Promise.all([
|
|
43
|
+
attempt(deleteAkuma()),
|
|
44
|
+
attempt(nukeGit(value.world)),
|
|
45
|
+
attempt(nukeTask(value.world)),
|
|
46
|
+
]);
|
|
47
|
+
if (failed)
|
|
48
|
+
throw firstDiagnostic;
|
|
49
|
+
return { kind: "success", world: value.world };
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
return { kind: "failed", world: value.world, diagnostic: diagnostic(error) };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ContractId } from "../core/facts/types.js";
|
|
2
2
|
import type { GitDecodeChannel } from "../git/read-observation.js";
|
|
3
|
-
import { type ReconcileReport
|
|
3
|
+
import { type ReconcileReport } from "../protocol/reconcile.js";
|
|
4
|
+
import { type RepositoryScope } from "../protocol/operations.js";
|
|
4
5
|
import { type SettlementReport } from "../settlement/settle.js";
|
|
5
6
|
import type { WorktreeHooks } from "./configuration.js";
|
|
6
7
|
import { type ContractFileEffect, type ContractFileLag } from "../contract-worktree.js";
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
2
|
-
import { reconcileAllOperation,
|
|
2
|
+
import { reconcileAllOperation, reconcileOperation, worldContractStates, } from "../protocol/reconcile.js";
|
|
3
|
+
import { reconcileObservationFailure } from "../git/reconcile.js";
|
|
4
|
+
import { stateOperation } from "../protocol/operations.js";
|
|
3
5
|
import { settle, settleAll } from "../settlement/settle.js";
|
|
4
6
|
import { projectContractWorktree, } from "../contract-worktree.js";
|
|
5
7
|
import { appointManagedWorktrees, placeRegisterPath, releaseManagedWorktrees, } from "../workspace-place.js";
|
|
@@ -11,6 +13,9 @@ function registerLag(scope, error) {
|
|
|
11
13
|
diagnostic: error instanceof Error ? error.message : String(error),
|
|
12
14
|
};
|
|
13
15
|
}
|
|
16
|
+
function hereConflict(diagnostic) {
|
|
17
|
+
throw new AuthorityCorruptionError(diagnostic);
|
|
18
|
+
}
|
|
14
19
|
function emptySettlement() {
|
|
15
20
|
return { actions: [], lags: [] };
|
|
16
21
|
}
|
|
@@ -89,7 +94,7 @@ export async function completeReconcile(input) {
|
|
|
89
94
|
retainTerminalWorktree: true,
|
|
90
95
|
...appointed,
|
|
91
96
|
});
|
|
92
|
-
const projection = await projectContractWorktree(input.scope, retained.state, appointment.register);
|
|
97
|
+
const projection = await projectContractWorktree(input.scope, retained.state, appointment.register, hereConflict);
|
|
93
98
|
const settlement = await settle({
|
|
94
99
|
repository: input.scope,
|
|
95
100
|
channel: input.channel,
|
|
@@ -164,7 +169,7 @@ export async function completeRepoReconcile(input) {
|
|
|
164
169
|
if (releaseEligible(contract.state, report, places.has(contract.contractId))) {
|
|
165
170
|
released.push(contract.contractId);
|
|
166
171
|
}
|
|
167
|
-
const projection = await projectContractWorktree(input.scope, contract.state, appointed);
|
|
172
|
+
const projection = await projectContractWorktree(input.scope, contract.state, appointed, hereConflict);
|
|
168
173
|
contracts.push({
|
|
169
174
|
contractId: contract.contractId,
|
|
170
175
|
report: {
|
|
@@ -6,7 +6,16 @@ export type ContractAppointmentRefusal = Readonly<{
|
|
|
6
6
|
path: string;
|
|
7
7
|
contract?: ContractId;
|
|
8
8
|
}>;
|
|
9
|
-
export type
|
|
9
|
+
export type NukeConfirmationRefusal = Readonly<{
|
|
10
|
+
kind: "nuke-confirmation-mismatch";
|
|
11
|
+
world: string;
|
|
12
|
+
confirmation: string;
|
|
13
|
+
}>;
|
|
14
|
+
export type NukeConfirmationRequiredRefusal = Readonly<{
|
|
15
|
+
kind: "nuke-confirmation-required";
|
|
16
|
+
world: string;
|
|
17
|
+
}>;
|
|
18
|
+
export type KeiyakuRefusal = IntentRefusal | ContractAppointmentRefusal | NukeConfirmationRefusal | NukeConfirmationRequiredRefusal;
|
|
10
19
|
export type KeiyakuRetryReason = IntentRetry;
|
|
11
20
|
export declare class KeiyakuRefused extends Error {
|
|
12
21
|
readonly refusal: KeiyakuRefusal;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ContractId } from "../core/facts/types.js";
|
|
2
2
|
import type { GitDecodeChannel } from "../git/read-observation.js";
|
|
3
3
|
import { type RepositoryScope } from "../protocol/operations.js";
|
|
4
|
-
import type { ContractDocumentProjection } from "../protocol/
|
|
4
|
+
import type { ContractDocumentProjection } from "../protocol/read/documents.js";
|
|
5
5
|
export type RegionOverlap = Readonly<{
|
|
6
6
|
contract: ContractId;
|
|
7
7
|
patterns: readonly Readonly<{
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type RepositoryScope } from "../protocol/operations.js";
|
|
2
|
+
import { NoGitWorldError } from "../git/repository.js";
|
|
2
3
|
import { type WorktreeHooks } from "./configuration.js";
|
|
3
4
|
import { type RepoContractReconcileReport, type RepoReconcileReport } from "./reconcile.js";
|
|
4
5
|
export { NoGitWorldError };
|
|
5
6
|
export type { RepoContractReconcileReport, RepoReconcileReport };
|
|
6
7
|
export type RepoAtInput = Readonly<{
|
|
7
8
|
path?: string;
|
|
9
|
+
gitPath?: string;
|
|
8
10
|
}>;
|
|
9
11
|
export type ReconcileInput = Readonly<{
|
|
10
12
|
hooks?: WorktreeHooks;
|
|
@@ -16,6 +18,7 @@ export declare function reconcileInput(input: ReconcileInput | undefined): Reado
|
|
|
16
18
|
}>;
|
|
17
19
|
export declare class Repo {
|
|
18
20
|
readonly root: string;
|
|
21
|
+
readonly cwd: string;
|
|
19
22
|
private constructor();
|
|
20
23
|
static at(input?: RepoAtInput): Promise<Repo>;
|
|
21
24
|
currentBranch(): Promise<string | null>;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import { currentBranchOperation,
|
|
1
|
+
import { currentBranchOperation, scopeOperation, } from "../protocol/operations.js";
|
|
2
|
+
import { NoGitWorldError } from "../git/repository.js";
|
|
2
3
|
import { optionalNonblank, requireInput } from "./input.js";
|
|
3
4
|
import { worktreeHooksOption } from "./configuration.js";
|
|
4
5
|
import { withGitDecodeChannel } from "../git/read-observation.js";
|
|
5
6
|
import { completeRepoReconcile, } from "./reconcile.js";
|
|
6
7
|
export { NoGitWorldError };
|
|
7
8
|
const REPO_SCOPES = new WeakMap();
|
|
8
|
-
async function resolvePinnedScope(path) {
|
|
9
|
-
return await scopeOperation({
|
|
9
|
+
async function resolvePinnedScope(path, gitPath) {
|
|
10
|
+
return await scopeOperation({
|
|
11
|
+
coordinate: path === undefined ? process.cwd() : path,
|
|
12
|
+
...(gitPath === undefined ? {} : { gitPath }),
|
|
13
|
+
});
|
|
10
14
|
}
|
|
11
15
|
export function reconcileInput(input) {
|
|
12
16
|
const values = input === undefined ? undefined : requireInput(input, "reconcile input");
|
|
@@ -20,13 +24,15 @@ export function reconcileInput(input) {
|
|
|
20
24
|
}
|
|
21
25
|
export class Repo {
|
|
22
26
|
root;
|
|
27
|
+
cwd;
|
|
23
28
|
constructor(scope) {
|
|
24
29
|
this.root = scope.primaryWorktree;
|
|
30
|
+
this.cwd = scope.invocationWorktree;
|
|
25
31
|
REPO_SCOPES.set(this, scope);
|
|
26
32
|
}
|
|
27
33
|
static async at(input) {
|
|
28
34
|
const values = input === undefined ? undefined : requireInput(input, "Repo.at input");
|
|
29
|
-
return new Repo(await resolvePinnedScope(optionalNonblank(values?.path, "repository path")));
|
|
35
|
+
return new Repo(await resolvePinnedScope(optionalNonblank(values?.path, "repository path"), optionalNonblank(values?.gitPath, "Git executable path")));
|
|
30
36
|
}
|
|
31
37
|
async currentBranch() {
|
|
32
38
|
return await currentBranchOperation({ scope: scopeForRepo(this) });
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type AbandonRefusal } from "../core/verbs/abandon.js";
|
|
2
|
+
import type { GitTreeSelection } from "../git/read-observation.js";
|
|
3
|
+
import type { CompanionDecorator } from "./run.js";
|
|
4
|
+
import type { IntentOutcome, MutationOperationInput } from "./operations.js";
|
|
5
|
+
export declare function abandonOperation(input: MutationOperationInput & Readonly<{
|
|
6
|
+
note?: string;
|
|
7
|
+
decorateOffer?: CompanionDecorator;
|
|
8
|
+
observationSelection?: GitTreeSelection;
|
|
9
|
+
}>): Promise<IntentOutcome<void, AbandonRefusal>>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { decideAbandon } from "../core/verbs/abandon.js";
|
|
2
|
+
import { admitIntent } from "./intent.js";
|
|
3
|
+
import { complete } from "./outcome.js";
|
|
4
|
+
import { timestamp } from "./operations.js";
|
|
5
|
+
export async function abandonOperation(input) {
|
|
6
|
+
return complete(await admitIntent(input.channel, input.scope, {
|
|
7
|
+
contractId: input.contractId,
|
|
8
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
9
|
+
at: timestamp(),
|
|
10
|
+
...(input.note === undefined ? {} : { note: input.note }),
|
|
11
|
+
}, decideAbandon, {
|
|
12
|
+
...(input.decorateOffer === undefined ? {} : { decorateOffer: input.decorateOffer }),
|
|
13
|
+
...(input.observationSelection === undefined ? {} : { observationSelection: input.observationSelection }),
|
|
14
|
+
}), undefined);
|
|
15
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { AmendData, ContractTerms } from "../core/facts/types.js";
|
|
2
|
+
import { type AmendRefusal } from "../core/verbs/amend.js";
|
|
3
|
+
import type { VerificationDeclarationPreparation, VerificationDeclarationRefusal } from "../verification/declaration.js";
|
|
4
|
+
import type { MutationOperationInput, IntentOutcome } from "./operations.js";
|
|
5
|
+
type AmendOperationInput = MutationOperationInput & Readonly<{
|
|
6
|
+
source?: ContractTerms;
|
|
7
|
+
deriveAmendment?: (source: ContractTerms) => Readonly<{
|
|
8
|
+
terms: AmendData;
|
|
9
|
+
verification: VerificationDeclarationPreparation;
|
|
10
|
+
}>;
|
|
11
|
+
}>;
|
|
12
|
+
type Amendment = Readonly<{
|
|
13
|
+
source: ContractTerms;
|
|
14
|
+
}> & ReturnType<NonNullable<AmendOperationInput["deriveAmendment"]>>;
|
|
15
|
+
export declare function amendOperation(input: AmendOperationInput): Promise<IntentOutcome<Amendment, AmendRefusal | VerificationDeclarationRefusal>>;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { extendContractsForAdmissionAt, observeContractsForAdmissionAt } from "../git/observe.js";
|
|
2
|
+
import { contractState } from "../core/facts/observation.js";
|
|
3
|
+
import { decideAmend } from "../core/verbs/amend.js";
|
|
4
|
+
import { admitDecidedOffer, mintAttempts } from "./attempt.js";
|
|
5
|
+
import { admitted } from "./outcome.js";
|
|
6
|
+
import { timestamp } from "./operations.js";
|
|
7
|
+
async function extendPrerequisiteClosureAt(channel, observation, seeds) {
|
|
8
|
+
let current = observation;
|
|
9
|
+
const visited = new Set();
|
|
10
|
+
let pending = [...seeds];
|
|
11
|
+
while (pending.length > 0) {
|
|
12
|
+
const batch = [...new Set(pending.filter((id) => !visited.has(id)))];
|
|
13
|
+
pending = [];
|
|
14
|
+
if (batch.length === 0)
|
|
15
|
+
break;
|
|
16
|
+
current = await extendContractsForAdmissionAt(channel, current, batch);
|
|
17
|
+
for (const id of batch) {
|
|
18
|
+
visited.add(id);
|
|
19
|
+
const state = contractState(current.decision, id);
|
|
20
|
+
if (state !== null)
|
|
21
|
+
pending.push(...state.terms.after);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return current;
|
|
25
|
+
}
|
|
26
|
+
export async function amendOperation(input) {
|
|
27
|
+
const attempts = mintAttempts({ entryCount: 1 });
|
|
28
|
+
let source = input.source;
|
|
29
|
+
for (let index = 0; index < attempts.length; index += 1) {
|
|
30
|
+
let observation = await observeContractsForAdmissionAt(input.scope, input.channel, [input.contractId]);
|
|
31
|
+
const state = contractState(observation.decision, input.contractId);
|
|
32
|
+
if (source === undefined && state !== null)
|
|
33
|
+
source = state.terms;
|
|
34
|
+
const amendment = source === undefined || input.deriveAmendment === undefined
|
|
35
|
+
? undefined
|
|
36
|
+
: { source, ...input.deriveAmendment(source) };
|
|
37
|
+
if (amendment !== undefined) {
|
|
38
|
+
observation = await extendPrerequisiteClosureAt(input.channel, observation, [...new Set([...(state?.terms.after ?? []), ...amendment.terms.after])]);
|
|
39
|
+
}
|
|
40
|
+
const preparation = amendment === undefined
|
|
41
|
+
? undefined
|
|
42
|
+
: amendment.verification.kind === "prepared"
|
|
43
|
+
? { kind: "prepared", data: amendment.terms }
|
|
44
|
+
: { kind: "refused", refusal: amendment.verification.refusal };
|
|
45
|
+
const decision = decideAmend({
|
|
46
|
+
input: {
|
|
47
|
+
contractId: input.contractId,
|
|
48
|
+
...(input.actor === undefined ? {} : { actor: input.actor }),
|
|
49
|
+
at: timestamp(),
|
|
50
|
+
...(amendment === undefined ? {} : { source: amendment.source }),
|
|
51
|
+
...(preparation === undefined ? {} : { preparation }),
|
|
52
|
+
},
|
|
53
|
+
attempt: attempts[index],
|
|
54
|
+
observation: observation.decision,
|
|
55
|
+
});
|
|
56
|
+
if (decision.kind === "refused")
|
|
57
|
+
return decision;
|
|
58
|
+
const admission = await admitDecidedOffer({
|
|
59
|
+
channel: input.channel,
|
|
60
|
+
repository: input.scope,
|
|
61
|
+
decisionObservation: observation,
|
|
62
|
+
attempt: attempts[index],
|
|
63
|
+
offer: decision.offer,
|
|
64
|
+
primaryContract: input.contractId,
|
|
65
|
+
});
|
|
66
|
+
if (admission.kind === "accepted") {
|
|
67
|
+
if (amendment === undefined)
|
|
68
|
+
throw new Error("accepted amendment is missing its document derivation");
|
|
69
|
+
return admitted(admission, amendment);
|
|
70
|
+
}
|
|
71
|
+
if (admission.kind === "publication-failed")
|
|
72
|
+
return { kind: "retry", reason: admission };
|
|
73
|
+
if (admission.kind === "collision" && index + 1 === attempts.length)
|
|
74
|
+
return { kind: "retry", reason: admission };
|
|
75
|
+
}
|
|
76
|
+
return { kind: "retry", reason: { kind: "exhausted" } };
|
|
77
|
+
}
|