@astrosheep/keiyaku 2.9.11 → 2.9.13
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 +79 -85
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +1 -0
- package/build/agents/providers/claude-agent-sdk/adapter.js +17 -4
- package/build/cli/commands/akuma/akuma/handler.js +2 -1
- package/build/cli/commands/akuma/akuma/meta.js +4 -3
- package/build/cli/commands/akuma/catalog.js +2 -0
- package/build/cli/commands/akuma/list/handler.js +1 -1
- package/build/cli/commands/akuma/list/meta-list.js +12 -0
- package/build/cli/commands/akuma/list/meta-ls.js +2 -2
- package/build/cli/commands/akuma.js +5 -0
- package/build/cli/commands/contract/amend/meta.js +4 -3
- package/build/cli/commands/contract/arc/meta.js +2 -0
- package/build/cli/commands/contract/audit/handler.js +28 -2
- package/build/cli/commands/contract/audit/meta.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +4 -4
- package/build/cli/commands/contract/petition/handler.js +2 -1
- package/build/cli/commands/contract/petition/meta.js +2 -2
- package/build/cli/commands/contract/renew/handler.js +44 -3
- package/build/cli/commands/contract/renew/meta.js +5 -4
- package/build/cli/commands/metadata.js +14 -10
- package/build/cli/commands/projection/call/handler.js +1 -1
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -2
- package/build/cli/commands/projection/{revive → fork}/handler.js +10 -5
- package/build/cli/commands/projection/fork/meta.js +12 -0
- package/build/cli/commands/projection/history/handler.js +46 -2
- package/build/cli/commands/projection/history/meta.js +3 -3
- package/build/cli/commands/projection/kill/handler.js +4 -5
- package/build/cli/commands/projection/kill/meta.js +2 -2
- package/build/cli/commands/projection/status/handler.js +29 -13
- package/build/cli/commands/projection/status/meta.js +14 -3
- package/build/cli/commands/projection/tell/handler.js +8 -4
- package/build/cli/commands/projection/tell/meta.js +1 -1
- package/build/cli/commands/projection/wait/handler.js +45 -20
- package/build/cli/commands/projection/wait/meta.js +1 -1
- package/build/cli/commands/shared.js +2 -2
- package/build/cli/commands/system/catalog.js +2 -0
- package/build/cli/commands/task/add/handler.js +28 -12
- package/build/cli/commands/task/add/meta.js +18 -6
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/compose/handler.js +18 -0
- package/build/cli/commands/task/compose/meta.js +10 -0
- package/build/cli/commands/task/doctor/handler.js +2 -3
- package/build/cli/commands/task/doctor/meta.js +2 -2
- package/build/cli/commands/task/done/meta.js +2 -2
- package/build/cli/commands/task/drop/handler.js +7 -2
- package/build/cli/commands/task/drop/meta.js +6 -3
- package/build/cli/commands/task/hold/meta.js +2 -2
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/ls/meta.js +2 -2
- package/build/cli/commands/task/note/handler.js +6 -0
- package/build/cli/commands/task/note/meta.js +11 -0
- package/build/cli/commands/task/resume/meta.js +2 -2
- package/build/cli/commands/task/shared.js +29 -15
- package/build/cli/commands/task/show/meta.js +2 -2
- package/build/cli/commands/task/start/meta.js +2 -2
- package/build/cli/commands/task/stop/meta.js +2 -2
- package/build/cli/commands/task/update/meta.js +3 -2
- package/build/cli/commands/verification/handler.js +43 -0
- package/build/cli/commands/verification/meta.js +13 -0
- package/build/cli/completion.js +16 -13
- package/build/cli/flags.js +48 -12
- package/build/cli/help.js +29 -30
- package/build/cli/index.js +14 -8
- package/build/cli/parse-flags.js +60 -21
- package/build/cli/parse-metadata.js +10 -4
- package/build/cli/parse-selectors.js +22 -4
- package/build/cli/parse.js +43 -30
- package/build/cli/projection-address.js +7 -7
- package/build/cli/render/arc.js +12 -3
- package/build/cli/render/audit.js +2 -2
- package/build/cli/render/call.js +4 -4
- package/build/cli/render/kanshi.js +122 -85
- package/build/cli/render/misc.js +2 -2
- package/build/cli/render/petition.js +16 -1
- package/build/cli/render/projection-history.js +17 -4
- package/build/cli/render/shared.js +5 -5
- package/build/cli/render/status-indicator.js +47 -0
- package/build/cli/render/status.js +106 -76
- package/build/cli/render/success-response.js +20 -5
- package/build/cli/render/task.js +33 -5
- package/build/cli/render/tell.js +10 -4
- package/build/cli/render/tool-command-normalization.js +137 -0
- package/build/cli/render/tool-presentation.js +2 -1
- package/build/cli/render/verification.js +23 -0
- package/build/cli/render/wait.js +101 -33
- package/build/cli/types.js +2 -1
- package/build/config/akuma-loader.js +21 -1
- package/build/config/settings/knobs.js +7 -1
- package/build/config/settings/schema.js +10 -5
- package/build/core/addressing.js +3 -3
- package/build/core/amend.js +102 -17
- package/build/core/arc.js +4 -4
- package/build/core/audit/candidate.js +10 -18
- package/build/core/audit/coordinates.js +12 -17
- package/build/core/audit/evidence.js +6 -4
- package/build/core/audit/facade.js +3 -3
- package/build/core/audit/report.js +1 -1
- package/build/core/bind-reconciliation.js +42 -23
- package/build/core/bind.js +182 -81
- package/build/core/call/call.js +6 -7
- package/build/core/call/context.js +46 -33
- package/build/core/call/execution.js +21 -6
- package/build/core/call/prompt.js +11 -42
- package/build/core/contract-carrier-runtime.js +209 -105
- package/build/core/contract-carrier.js +156 -73
- package/build/core/contract-view.js +43 -6
- package/build/core/contract.js +2 -1
- package/build/core/derived-replay.js +168 -35
- package/build/core/draft.js +60 -27
- package/build/core/forfeit.js +1 -1
- package/build/core/lifecycle-history.js +13 -0
- package/build/core/lifecycle-recovery.js +32 -27
- package/build/core/lifecycle-runner.js +14 -14
- package/build/core/log.js +1 -1
- package/build/core/outcome-base.js +2 -2
- package/build/core/projection/akuma-name.js +43 -0
- package/build/core/projection/generation/database.js +141 -79
- package/build/core/projection/generation/ledger.js +91 -0
- package/build/core/projection/generation/model.js +19 -14
- package/build/core/projection/generation/projection-generation-continuation.js +1 -1
- package/build/core/projection/generation/projection-generation-doorbell.js +88 -0
- package/build/core/projection/generation/projection-generation-execution.js +24 -0
- package/build/core/projection/generation/projection-generation-identity.js +4 -0
- package/build/core/projection/generation/projection-generation-launcher.js +72 -138
- package/build/core/projection/generation/projection-generation-process.js +16 -15
- package/build/core/projection/generation/projection-generation-runner.js +132 -76
- package/build/core/projection/generation/projection-generation-runtime.js +10 -61
- package/build/core/projection/generation/protocol.js +68 -0
- package/build/core/projection/generation/store.js +17 -7
- package/build/core/projection/generation/transitions.js +24 -14
- package/build/core/projection/index.js +5 -5
- package/build/core/projection/projection-core.js +6 -2
- package/build/core/projection/projection-execution-observer.js +1 -1
- package/build/core/projection/projection-history.js +8 -8
- package/build/core/projection/projection-kill.js +20 -10
- package/build/core/projection/projection-life-observer.js +8 -8
- package/build/core/projection/projection-mint.js +6 -8
- package/build/core/projection/projection-status-observation.js +77 -8
- package/build/core/projection/projection-status.js +151 -4
- package/build/core/projection/projection-wait.js +48 -29
- package/build/core/projection/projection-wake.js +28 -88
- package/build/core/projection/tell/launch-store.js +1 -1
- package/build/core/projection/tell/store.js +1 -1
- package/build/core/renew-build.js +204 -74
- package/build/core/renew-plan.js +34 -9
- package/build/core/renew-rewrite.js +56 -15
- package/build/core/renew.js +39 -35
- package/build/core/repository-ledger/accepted-fold-read.js +6 -3
- package/build/core/repository-ledger/claim-evidence.js +1 -1
- package/build/core/repository-ledger/codec.js +11 -5
- package/build/core/repository-ledger/current-state-store.js +464 -349
- package/build/core/repository-ledger/fold-repository.js +5 -6
- package/build/core/repository-ledger/identity.js +60 -0
- package/build/core/repository-ledger/inventory.js +3 -3
- package/build/core/repository-ledger/read-model.js +57 -9
- package/build/core/repository-ledger/write-transaction.js +24 -17
- package/build/core/run-control/connection-bound-close.js +41 -0
- package/build/core/run-control/detached-lease-bootstrap.js +208 -0
- package/build/core/run-control/detached-process.js +14 -0
- package/build/core/run-control/index.js +6 -0
- package/build/core/{process-group.js → run-control/process-tree.js} +1 -1
- package/build/core/run-control/runner-lease.js +172 -0
- package/build/core/run-control/sqlite-process-lifetime-lock.js +174 -0
- package/build/core/seal.js +44 -32
- package/build/core/settlement/claim-delivery.js +22 -9
- package/build/core/settlement/claim.js +8 -6
- package/build/core/settlement/petition-claim-gates.js +9 -8
- package/build/core/settlement/petition-head-guard.js +5 -6
- package/build/core/settlement/petition-preview.js +21 -5
- package/build/core/settlement/petition.js +51 -17
- package/build/core/settlement/settlement.js +20 -15
- package/build/core/settlement/verdict.js +2 -2
- package/build/core/settlement/verification.js +492 -364
- package/build/core/status/board.js +184 -75
- package/build/core/status/drift.js +8 -10
- package/build/core/task/board.js +1 -0
- package/build/core/task/commands.js +25 -0
- package/build/core/task/compose.js +328 -0
- package/build/core/task/document.js +102 -39
- package/build/core/task/index.js +4 -3
- package/build/core/task/settlement-git.js +70 -30
- package/build/core/task/settlement-policy.js +27 -14
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-bind-preparation.js +59 -9
- package/build/core/task/task-contract.js +2 -2
- package/build/core/task/task-git-store.js +1 -0
- package/build/core/task/task-store-repository.js +2 -0
- package/build/core/task/task.js +2 -2
- package/build/core/transcripts.js +4 -4
- package/build/core/verification-declaration.js +95 -0
- package/build/core/worktree-bootstrap.js +1 -1
- package/build/core/worktree-path.js +7 -11
- package/build/flow-error.js +15 -2
- package/build/generated/version.js +2 -2
- package/build/git/branches.js +41 -70
- package/build/git/commits.js +92 -21
- package/build/git/core.js +9 -161
- package/build/git/diff/preview.js +4 -4
- package/build/git/diff/read.js +4 -4
- package/build/git/diff/structured.js +5 -5
- package/build/git/process.js +229 -0
- package/build/git/refs.js +30 -5
- package/build/git/staging.js +39 -115
- package/build/git/streaming-batch.js +9 -16
- package/build/git/worktree.js +104 -91
- package/build/index.js +7 -0
- package/package.json +2 -2
- package/skills/keiyaku-akuma/SKILL.md +27 -21
- package/skills/keiyaku-task/SKILL.md +61 -5
- package/skills/keiyaku-workflow/SKILL.md +81 -26
- package/build/cli/commands/projection/revive/meta.js +0 -12
- package/build/core/projection/projection-life-protocol.js +0 -115
- package/build/core/projection/projection-runner-lock.js +0 -382
- package/build/core/projection/tell/database.js +0 -127
- package/build/core/settlement/verification-coordination.js +0 -305
- package/build/core/settlement/verification-supervisor.js +0 -275
package/build/cli/render/wait.js
CHANGED
|
@@ -2,9 +2,6 @@ import { formatTimelineDuration, renderPendingProjectionTell, renderProjectionAc
|
|
|
2
2
|
import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
|
|
3
3
|
import { coreTextResponse, formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
|
|
4
4
|
import { renderTerminalFailureFace } from "./terminal-failure.js";
|
|
5
|
-
function shortAddress(projectionId) {
|
|
6
|
-
return /\/([0-9a-f]{8})$/.exec(projectionId)?.[1] ?? projectionId;
|
|
7
|
-
}
|
|
8
5
|
function phaseState(phase) {
|
|
9
6
|
switch (phase) {
|
|
10
7
|
case "done": return "returned";
|
|
@@ -34,16 +31,17 @@ function projectionIdentityParts(projectionId) {
|
|
|
34
31
|
const match = /^(.*)\/([0-9a-f]{8})$/.exec(projectionId);
|
|
35
32
|
return match ? { slug: match[1], shortId: match[2] } : { slug: "", shortId: projectionId };
|
|
36
33
|
}
|
|
37
|
-
function waitHeader(projectionId, akuma, snapshot, maxColumns) {
|
|
34
|
+
function waitHeader(projectionId, akuma, snapshot, maxColumns, alias) {
|
|
38
35
|
const state = waitStateText(snapshot);
|
|
39
36
|
const identity = projectionIdentityParts(projectionId);
|
|
40
37
|
// Slug often mirrors the Akuma name; print once when they are the same fact.
|
|
41
38
|
const description = identity.slug && akuma && identity.slug === akuma
|
|
42
39
|
? identity.slug
|
|
43
40
|
: [identity.slug, akuma].filter(Boolean).join(" · ");
|
|
44
|
-
const descriptionBudget = Math.max(0, maxColumns - displayColumns(`${
|
|
41
|
+
const descriptionBudget = Math.max(0, maxColumns - displayColumns(`${projectionId}${alias ? ` (${alias})` : ""} · ─ ${state}`));
|
|
45
42
|
const visibleDescription = truncateColumns(description, descriptionBudget);
|
|
46
|
-
const
|
|
43
|
+
const canonical = `${projectionId}${alias ? ` (${alias})` : ""}`;
|
|
44
|
+
const prefix = visibleDescription ? `${canonical} · ${visibleDescription}` : canonical;
|
|
47
45
|
const dashCount = Math.max(1, maxColumns - displayColumns(`${prefix} ${state}`));
|
|
48
46
|
return `${prefix} ${"─".repeat(dashCount)} ${state}`;
|
|
49
47
|
}
|
|
@@ -70,16 +68,16 @@ function ledgerHint(projectionId, snapshot) {
|
|
|
70
68
|
const file = snapshot.eventLedgerFile ?? "events.jsonl";
|
|
71
69
|
return `· ledger: .keiyaku/projection/${projectionId}/${file}`;
|
|
72
70
|
}
|
|
73
|
-
function
|
|
71
|
+
function recordForkLines(artifactId) {
|
|
74
72
|
return [
|
|
75
73
|
`record: ${artifactId}`,
|
|
76
|
-
"
|
|
77
|
-
` » keiyaku
|
|
74
|
+
"fork starts a new projection from the record:",
|
|
75
|
+
` » keiyaku fork ${artifactId}`,
|
|
78
76
|
];
|
|
79
77
|
}
|
|
80
78
|
function nextActionLines(projectionId, result, state) {
|
|
81
79
|
const snapshot = result.snapshot;
|
|
82
|
-
const address =
|
|
80
|
+
const address = projectionId;
|
|
83
81
|
if (state === "running") {
|
|
84
82
|
return [...projectionRejoinHintLines(address)];
|
|
85
83
|
}
|
|
@@ -101,11 +99,11 @@ function nextActionLines(projectionId, result, state) {
|
|
|
101
99
|
return snapshot.artifactId
|
|
102
100
|
? [
|
|
103
101
|
"The projection is lost — no terminal truth exists.",
|
|
104
|
-
...
|
|
102
|
+
...recordForkLines(snapshot.artifactId),
|
|
105
103
|
]
|
|
106
104
|
: [
|
|
107
105
|
"The projection is lost — no terminal truth exists.",
|
|
108
|
-
"no record survived — there is nothing to
|
|
106
|
+
"no record survived — there is nothing to fork.",
|
|
109
107
|
];
|
|
110
108
|
}
|
|
111
109
|
if (state === "stalled" || state === "unknown") {
|
|
@@ -166,18 +164,27 @@ function identityUnavailableResponse(projectionId, diagnostic) {
|
|
|
166
164
|
exitCode: 1,
|
|
167
165
|
};
|
|
168
166
|
}
|
|
169
|
-
function returnedResponse(projectionId, result) {
|
|
170
|
-
|
|
171
|
-
// diagnostics, or rollup. Typed outcomeText is the first byte when present.
|
|
167
|
+
function returnedResponse(projectionId, result, alias) {
|
|
168
|
+
const identity = `${projectionId}${alias ? ` (${alias})` : ""}`;
|
|
172
169
|
const nextActions = nextActionLines(projectionId, result, "returned");
|
|
173
170
|
if (result.state === "terminal" && result.outcomeText) {
|
|
174
|
-
return textResponse([result.outcomeText
|
|
171
|
+
return textResponse([identity, `answer: ${result.outcomeText}`, ...nextActions].join("\n"));
|
|
175
172
|
}
|
|
176
|
-
return textResponse(nextActions.join("\n"));
|
|
173
|
+
return textResponse([identity, ...nextActions].join("\n"));
|
|
177
174
|
}
|
|
178
175
|
export function buildWaitResponse(projectionId, result, options = {}) {
|
|
176
|
+
const payload = {
|
|
177
|
+
canonicalId: projectionId,
|
|
178
|
+
...(options.inputToken ? { inputToken: options.inputToken } : {}),
|
|
179
|
+
...(options.alias ? { alias: options.alias } : {}),
|
|
180
|
+
result,
|
|
181
|
+
};
|
|
182
|
+
const withPayload = (response) => ({
|
|
183
|
+
...response,
|
|
184
|
+
payload: payload,
|
|
185
|
+
});
|
|
179
186
|
if (result.state === "unknown") {
|
|
180
|
-
return identityUnavailableResponse(projectionId, result.diagnostic);
|
|
187
|
+
return withPayload({ ...identityUnavailableResponse(projectionId, result.diagnostic), exitCode: 4 });
|
|
181
188
|
}
|
|
182
189
|
// A plural deadline may observe a verdict whose timestamp is at or after
|
|
183
190
|
// the cutoff. The typed timeout result owns presentation in that case; the
|
|
@@ -188,20 +195,23 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
188
195
|
: result.snapshot;
|
|
189
196
|
const maxColumns = Math.min(120, options.maxColumns ?? resolveLineColumns());
|
|
190
197
|
if (result.state === "terminal" && result.verdict.state === "killed") {
|
|
191
|
-
return {
|
|
198
|
+
return withPayload({
|
|
192
199
|
...textResponse(`× killed ${projectionId}`),
|
|
193
200
|
exitCode: 1,
|
|
194
|
-
};
|
|
201
|
+
});
|
|
195
202
|
}
|
|
196
203
|
if (snapshot.phase === "startup-timeout") {
|
|
197
|
-
return startupTimeoutResponse(projectionId, result.pact.akuma);
|
|
204
|
+
return withPayload(startupTimeoutResponse(projectionId, result.pact.akuma));
|
|
198
205
|
}
|
|
199
206
|
if (snapshot.phase === "unknown") {
|
|
200
|
-
|
|
207
|
+
const response = unknownResponse(projectionId, result.pact.akuma, snapshot, maxColumns);
|
|
208
|
+
return result.state === "timeout"
|
|
209
|
+
? withPayload({ ...response, exitCode: 124 })
|
|
210
|
+
: withPayload({ ...response, exitCode: 4 });
|
|
201
211
|
}
|
|
202
212
|
const state = phaseState(snapshot.phase);
|
|
203
213
|
if (state === "returned") {
|
|
204
|
-
return returnedResponse(projectionId, result);
|
|
214
|
+
return withPayload(returnedResponse(projectionId, result, options.alias));
|
|
205
215
|
}
|
|
206
216
|
const rendered = renderProjectionActivity(snapshot.activity, {
|
|
207
217
|
anchorMs: snapshot.observedAtMs,
|
|
@@ -225,21 +235,26 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
225
235
|
...pendingTellRows(snapshot, maxColumns, activityRows.length),
|
|
226
236
|
]).map((row) => truncateColumns(row.line, maxColumns));
|
|
227
237
|
const lines = [
|
|
228
|
-
waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns),
|
|
238
|
+
waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns, options.alias),
|
|
229
239
|
...diagnosticLines,
|
|
230
240
|
...flowLines,
|
|
231
241
|
];
|
|
242
|
+
const commandToken = options.inputToken && options.inputToken === options.alias
|
|
243
|
+
? options.inputToken
|
|
244
|
+
: projectionId;
|
|
232
245
|
const nextActions = state === "running" && options.runningActions === false
|
|
233
246
|
? []
|
|
234
|
-
: nextActionLines(
|
|
247
|
+
: nextActionLines(commandToken, result, state);
|
|
235
248
|
if (nextActions.length > 0)
|
|
236
249
|
lines.push("");
|
|
237
250
|
lines.push(...nextActions);
|
|
238
|
-
const response = coreTextResponse(lines.join("\n"), result);
|
|
251
|
+
const response = withPayload(coreTextResponse(lines.join("\n"), result));
|
|
252
|
+
if (result.state === "timeout")
|
|
253
|
+
return { ...response, exitCode: 124 };
|
|
239
254
|
if (snapshot.phase === "dismissed")
|
|
240
255
|
return { ...response, exitCode: 130 };
|
|
241
|
-
if (
|
|
242
|
-
return { ...response, exitCode:
|
|
256
|
+
if (result.state === "lost") {
|
|
257
|
+
return { ...response, exitCode: 4 };
|
|
243
258
|
}
|
|
244
259
|
return response;
|
|
245
260
|
}
|
|
@@ -247,11 +262,20 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
247
262
|
export function buildProjectionWaitSetResponse(result) {
|
|
248
263
|
const rendered = result.results
|
|
249
264
|
.slice()
|
|
250
|
-
.sort((
|
|
265
|
+
.sort((left, right) => waitTriage(left) - waitTriage(right)
|
|
266
|
+
|| latestWaitActivity(right) - latestWaitActivity(left)
|
|
267
|
+
|| terminalWaitTime(right) - terminalWaitTime(left)
|
|
268
|
+
|| left.id.localeCompare(right.id))
|
|
251
269
|
.map((member) => ({
|
|
252
270
|
id: member.id,
|
|
253
271
|
result: member.result,
|
|
254
|
-
|
|
272
|
+
inputToken: member.inputToken,
|
|
273
|
+
alias: member.alias,
|
|
274
|
+
response: buildWaitResponse(member.id, member.result, {
|
|
275
|
+
alias: member.alias,
|
|
276
|
+
inputToken: member.inputToken,
|
|
277
|
+
runningActions: false,
|
|
278
|
+
}),
|
|
255
279
|
}));
|
|
256
280
|
const liveIds = rendered
|
|
257
281
|
.filter((member) => member.result.state === "timeout")
|
|
@@ -260,16 +284,60 @@ export function buildProjectionWaitSetResponse(result) {
|
|
|
260
284
|
if (liveIds.length > 0) {
|
|
261
285
|
blocks.push([
|
|
262
286
|
"Come back for the result:",
|
|
263
|
-
` » keiyaku wait ${
|
|
287
|
+
` » keiyaku wait ${rendered.filter((member) => member.result.state === "timeout").map((member) => member.inputToken ?? member.id).join(" ")} --${result.selection} [--timeout DURATION]`,
|
|
264
288
|
"Steer them while they work:",
|
|
265
289
|
` » ${formatTellCommand("<projection-id>", '"your words"')}`,
|
|
266
290
|
].join("\n"));
|
|
267
291
|
}
|
|
268
292
|
const text = blocks.join("\n\n");
|
|
293
|
+
const payload = {
|
|
294
|
+
selection: result.selection,
|
|
295
|
+
...(result.selectedId ? { selectedId: result.selectedId } : {}),
|
|
296
|
+
results: rendered.map((member) => ({
|
|
297
|
+
canonicalId: member.id,
|
|
298
|
+
...(member.inputToken ? { inputToken: member.inputToken } : {}),
|
|
299
|
+
...(member.alias ? { alias: member.alias } : {}),
|
|
300
|
+
result: member.result,
|
|
301
|
+
})),
|
|
302
|
+
};
|
|
303
|
+
const response = coreTextResponse(text, payload);
|
|
304
|
+
const conditionSatisfied = result.selection === "any" && result.selectedId !== undefined;
|
|
269
305
|
const exitCode = rendered.reduce((current, { response }) => {
|
|
306
|
+
if (current === 130)
|
|
307
|
+
return current;
|
|
270
308
|
if (response.exitCode === 130)
|
|
271
309
|
return 130;
|
|
272
|
-
|
|
310
|
+
if (current === 4)
|
|
311
|
+
return current;
|
|
312
|
+
if (response.exitCode === 4)
|
|
313
|
+
return 4;
|
|
314
|
+
return response.exitCode === 124 && !conditionSatisfied ? 124 : current;
|
|
273
315
|
}, undefined);
|
|
274
|
-
|
|
316
|
+
const deadline = !conditionSatisfied && rendered.some((member) => member.result.state === "timeout");
|
|
317
|
+
return exitCode === undefined && !deadline ? response : { ...response, exitCode: exitCode ?? 124 };
|
|
318
|
+
}
|
|
319
|
+
function waitSnapshot(result) {
|
|
320
|
+
return result.state === "unknown" ? undefined : result.snapshot;
|
|
321
|
+
}
|
|
322
|
+
function waitTriage(member) {
|
|
323
|
+
const snapshot = waitSnapshot(member.result);
|
|
324
|
+
if (member.result.state === "unknown" || member.result.state === "lost")
|
|
325
|
+
return 0;
|
|
326
|
+
if (member.result.state === "terminal" && (member.result.verdict.terminalFailure || member.result.verdict.state !== "completed"))
|
|
327
|
+
return 0;
|
|
328
|
+
if ((snapshot?.eventDiagnostics?.length ?? 0) > 0)
|
|
329
|
+
return 0;
|
|
330
|
+
return member.result.state === "timeout" ? 1 : 2;
|
|
331
|
+
}
|
|
332
|
+
function latestWaitActivity(member) {
|
|
333
|
+
const snapshot = waitSnapshot(member.result);
|
|
334
|
+
if (!snapshot || member.result.state !== "timeout")
|
|
335
|
+
return Number.NEGATIVE_INFINITY;
|
|
336
|
+
return snapshot.observedAtMs - (snapshot.activityAgeMs ?? snapshot.durationMs);
|
|
337
|
+
}
|
|
338
|
+
function terminalWaitTime(member) {
|
|
339
|
+
if (member.result.state !== "terminal")
|
|
340
|
+
return Number.NEGATIVE_INFINITY;
|
|
341
|
+
const parsed = Date.parse(member.result.verdict.at);
|
|
342
|
+
return Number.isFinite(parsed) ? parsed : Number.NEGATIVE_INFINITY;
|
|
275
343
|
}
|
package/build/cli/types.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export const TASK_SUBCOMMANDS = ["add", "show", "ls", "log", "start", "stop", "hold", "resume", "done", "drop", "update", "doctor"];
|
|
1
|
+
export const TASK_SUBCOMMANDS = ["add", "compose", "show", "ls", "log", "start", "stop", "hold", "resume", "done", "note", "drop", "update", "doctor"];
|
|
2
|
+
export const AKUMA_SUBCOMMANDS = ["list", "ls", "show"];
|
|
@@ -6,6 +6,7 @@ import { observeGitRepository } from "../git/branches.js";
|
|
|
6
6
|
import { BUILTIN_AGENT_PROFILES } from "../keiyaku.js";
|
|
7
7
|
import { getKeiyakuHome } from "./env.js";
|
|
8
8
|
import { agentNameSchema, providerInstanceNameSchema } from "./settings/schema.js";
|
|
9
|
+
import { canonicalizeAkumaName } from "../core/projection/akuma-name.js";
|
|
9
10
|
const nonblankString = z.string().refine((value) => value.trim().length > 0, { message: "must not be blank" });
|
|
10
11
|
const effortOptionsSchema = z.array(nonblankString).superRefine((values, ctx) => {
|
|
11
12
|
if (new Set(values).size !== values.length) {
|
|
@@ -129,9 +130,28 @@ async function readLayer(directory, source) {
|
|
|
129
130
|
};
|
|
130
131
|
}
|
|
131
132
|
const candidates = [];
|
|
133
|
+
const canonicalFiles = new Map();
|
|
134
|
+
for (const entry of entries.filter((candidate) => candidate.isFile() && candidate.name.endsWith(".md"))) {
|
|
135
|
+
const rawName = path.basename(entry.name, ".md");
|
|
136
|
+
const canonicalName = canonicalizeAkumaName(rawName);
|
|
137
|
+
const files = canonicalFiles.get(canonicalName) ?? [];
|
|
138
|
+
files.push(entry.name);
|
|
139
|
+
canonicalFiles.set(canonicalName, files);
|
|
140
|
+
}
|
|
132
141
|
for (const entry of entries.filter((candidate) => candidate.isFile() && candidate.name.endsWith(".md")).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
133
142
|
const file = path.join(directory, entry.name);
|
|
134
|
-
const
|
|
143
|
+
const rawName = path.basename(entry.name, ".md");
|
|
144
|
+
const name = canonicalizeAkumaName(rawName);
|
|
145
|
+
const collisions = canonicalFiles.get(name);
|
|
146
|
+
if (collisions.length > 1) {
|
|
147
|
+
candidates.push(freezeCandidate({
|
|
148
|
+
name,
|
|
149
|
+
source,
|
|
150
|
+
path: file,
|
|
151
|
+
reason: `akuma name collision after Unicode NFC normalization: ${collisions.sort().join(", ")}`,
|
|
152
|
+
}));
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
135
155
|
const nameResult = agentNameSchema.safeParse(name);
|
|
136
156
|
if (!nameResult.success) {
|
|
137
157
|
candidates.push(freezeCandidate({
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
export const
|
|
1
|
+
export const PROJECTION_ADOPTION_TIMEOUT_DEFAULT_MS = 30_000;
|
|
2
|
+
export const PROJECTION_ADOPTION_TIMEOUT_MIN_MS = 1_000;
|
|
3
|
+
export const PROJECTION_ADOPTION_TIMEOUT_MAX_MS = 600_000;
|
|
4
|
+
export const KNOWN_SETTINGS_KNOBS = ["default", "reviewer", "gate", "defaultBranch", "worktreeBootstrap", "projectionAdoptionTimeoutMs"];
|
|
2
5
|
export const KNOWN_SETTINGS_ROOT_KEYS = [...KNOWN_SETTINGS_KNOBS, "providers"];
|
|
6
|
+
export function resolveProjectionAdoptionTimeoutMs(settings) {
|
|
7
|
+
return settings?.projectionAdoptionTimeoutMs ?? PROJECTION_ADOPTION_TIMEOUT_DEFAULT_MS;
|
|
8
|
+
}
|
|
3
9
|
export function resolveDefaultAgentName(settings) {
|
|
4
10
|
return settings?.default ?? "akuma-codex";
|
|
5
11
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { BUILTIN_PROVIDER_INSTANCE_CANDIDATES as REGISTRY_BUILTIN_PROVIDER_INSTANCE_CANDIDATES, providerInstanceSchema as registryProviderInstanceSchema, } from "../../agents/providers/registry.js";
|
|
3
|
+
import { akumaNameSchema } from "../../core/projection/akuma-name.js";
|
|
4
|
+
import { PROJECTION_ADOPTION_TIMEOUT_MAX_MS, PROJECTION_ADOPTION_TIMEOUT_MIN_MS, } from "./knobs.js";
|
|
3
5
|
export const providerInstanceSchema = registryProviderInstanceSchema;
|
|
4
6
|
export const BUILTIN_PROVIDER_INSTANCE_CANDIDATES = REGISTRY_BUILTIN_PROVIDER_INSTANCE_CANDIDATES;
|
|
5
7
|
const PROVIDER_INSTANCE_NAME_PATTERN = /^[a-z0-9][a-z0-9-]*$/;
|
|
@@ -10,11 +12,7 @@ export const providerInstanceNameSchema = z
|
|
|
10
12
|
// Ensure the registry builtin map stays keyed by the closed provider vocabulary.
|
|
11
13
|
const _builtinCheck = BUILTIN_PROVIDER_INSTANCE_CANDIDATES;
|
|
12
14
|
void _builtinCheck;
|
|
13
|
-
const
|
|
14
|
-
export const agentNameSchema = z
|
|
15
|
-
.string()
|
|
16
|
-
.min(1, "must not be empty.")
|
|
17
|
-
.regex(AGENT_NAME_PATTERN, "must contain only alphanumeric characters, dots, and hyphens, and must not start or end with a separator.");
|
|
15
|
+
export const agentNameSchema = akumaNameSchema;
|
|
18
16
|
function optionalTrimmedString() {
|
|
19
17
|
return z.string().transform((value) => {
|
|
20
18
|
const trimmed = value.trim();
|
|
@@ -62,6 +60,11 @@ const gateSchema = z
|
|
|
62
60
|
const WORKTREE_BOOTSTRAP_DEFAULT_TIMEOUT_MS = 300_000;
|
|
63
61
|
const WORKTREE_BOOTSTRAP_MIN_TIMEOUT_MS = 1;
|
|
64
62
|
const WORKTREE_BOOTSTRAP_MAX_TIMEOUT_MS = 3_600_000;
|
|
63
|
+
export const projectionAdoptionTimeoutSchema = z
|
|
64
|
+
.number()
|
|
65
|
+
.int("projectionAdoptionTimeoutMs must be an integer.")
|
|
66
|
+
.min(PROJECTION_ADOPTION_TIMEOUT_MIN_MS, `projectionAdoptionTimeoutMs must be >= ${PROJECTION_ADOPTION_TIMEOUT_MIN_MS}.`)
|
|
67
|
+
.max(PROJECTION_ADOPTION_TIMEOUT_MAX_MS, `projectionAdoptionTimeoutMs must be <= ${PROJECTION_ADOPTION_TIMEOUT_MAX_MS}.`);
|
|
65
68
|
export const worktreeBootstrapSchema = z
|
|
66
69
|
.object({
|
|
67
70
|
command: z
|
|
@@ -97,6 +100,7 @@ const settingsSchema = z
|
|
|
97
100
|
gate: gateSchema.optional(),
|
|
98
101
|
defaultBranch: optionalTrimmedString(),
|
|
99
102
|
worktreeBootstrap: worktreeBootstrapSchema.optional(),
|
|
103
|
+
projectionAdoptionTimeoutMs: projectionAdoptionTimeoutSchema.optional(),
|
|
100
104
|
})
|
|
101
105
|
.strict();
|
|
102
106
|
export const knobSchemas = {
|
|
@@ -105,4 +109,5 @@ export const knobSchemas = {
|
|
|
105
109
|
gate: gateSchema,
|
|
106
110
|
defaultBranch: optionalTrimmedString(),
|
|
107
111
|
worktreeBootstrap: worktreeBootstrapSchema,
|
|
112
|
+
projectionAdoptionTimeoutMs: projectionAdoptionTimeoutSchema,
|
|
108
113
|
};
|
package/build/core/addressing.js
CHANGED
|
@@ -237,7 +237,7 @@ export function resolveExplicitContractAddressFromRead(input) {
|
|
|
237
237
|
const source = input.source ?? (input.raw.startsWith("@") ? "at-address" : "explicit-flag");
|
|
238
238
|
const spelling = { asTyped: commissionSelectorAsTyped(query, source), source };
|
|
239
239
|
if (isResponseArtifactId(query)) {
|
|
240
|
-
throw new AddressResolutionError("
|
|
240
|
+
throw new AddressResolutionError("UNKNOWN_ADDRESS", `artifact ${query} is a response artifact; expected a commission address`, { repo, workdir, expected: "commission", spelling, candidates: [], inference: [], actual: "artifact" });
|
|
241
241
|
}
|
|
242
242
|
const identities = explicitAddressIdentities(input.read, query);
|
|
243
243
|
const attempt = {
|
|
@@ -282,7 +282,7 @@ export function resolveExplicitContractAddressFromRead(input) {
|
|
|
282
282
|
if (unknown.status === "diseased" || unknown.status === "isolated" || unknown.status === "indeterminate") {
|
|
283
283
|
throw contractReadOutcomeError(query, unknown);
|
|
284
284
|
}
|
|
285
|
-
throw new AddressResolutionError("
|
|
285
|
+
throw new AddressResolutionError("UNKNOWN_ADDRESS", `unknown contract address @${query}`, attempt);
|
|
286
286
|
}
|
|
287
287
|
export async function resolveContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag", effectiveDirectory = cwd) {
|
|
288
288
|
const workdir = path.resolve(effectiveDirectory);
|
|
@@ -348,7 +348,7 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
|
|
|
348
348
|
inference: attempt.inference,
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
|
-
throw new AddressResolutionError(operable.length === 0 ? "
|
|
351
|
+
throw new AddressResolutionError(operable.length === 0 ? "UNKNOWN_ADDRESS" : "CONTRACT_AMBIGUOUS", operable.length === 0
|
|
352
352
|
? "no active commission found; pass @place, @slug, full @commission-id, or --contract <addr>"
|
|
353
353
|
: "multiple active commissions found; pass @place, @slug, full @commission-id, or --contract <addr>", attempt);
|
|
354
354
|
}
|
package/build/core/amend.js
CHANGED
|
@@ -9,18 +9,31 @@ import { markdownSourceSections, normalizeScopePattern, ScopePatternError, valid
|
|
|
9
9
|
import { normalizeSectionTitle } from "./markdown/titles.js";
|
|
10
10
|
import { isCompleteLifecycleOutcome } from "./outcome-base.js";
|
|
11
11
|
import { getConfig } from "../config/env.js";
|
|
12
|
+
import { parseVerificationDeclarations } from "./verification-declaration.js";
|
|
12
13
|
function amendScopeHeading(name) {
|
|
13
14
|
return `## Scope ${name[0].toUpperCase()}${name.slice(1)}`;
|
|
14
15
|
}
|
|
16
|
+
function normalizeReplaceVerificationsTitle(title) {
|
|
17
|
+
// ATX closing markers are structural syntax, not part of the section title.
|
|
18
|
+
return normalizeSectionTitle(title.replace(/[ \t]+#+[ \t]*$/, ""));
|
|
19
|
+
}
|
|
15
20
|
function parseAmendScopeSections(markdown) {
|
|
16
21
|
const sections = {};
|
|
17
22
|
for (const section of markdownSourceSections(markdown)) {
|
|
18
23
|
if (section.level !== 2)
|
|
19
24
|
continue;
|
|
20
25
|
const title = normalizeSectionTitle(section.title);
|
|
26
|
+
if (normalizeReplaceVerificationsTitle(section.title) === "replace verifications")
|
|
27
|
+
continue;
|
|
21
28
|
if (title === "scope add") {
|
|
22
29
|
throw new FlowError("INVALID_KEIYAKU_DRAFT", "Scope Add is obsolete; use ## Scope Append with a fenced gitignore-subset block");
|
|
23
30
|
}
|
|
31
|
+
if (title.startsWith("scope ") && title !== "scope append") {
|
|
32
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", `unknown structured amendment operation ## ${section.title}`);
|
|
33
|
+
}
|
|
34
|
+
if (title.startsWith("replace ") && title !== "replace verifications") {
|
|
35
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", `unknown structured amendment operation ## ${section.title}`);
|
|
36
|
+
}
|
|
24
37
|
if (title !== "scope append")
|
|
25
38
|
continue;
|
|
26
39
|
if (sections.append) {
|
|
@@ -33,11 +46,7 @@ function parseAmendScopeSections(markdown) {
|
|
|
33
46
|
end: section.end,
|
|
34
47
|
};
|
|
35
48
|
}
|
|
36
|
-
|
|
37
|
-
for (const section of Object.values(sections).sort((left, right) => right.start - left.start)) {
|
|
38
|
-
prose = `${prose.slice(0, section.start)}${prose.slice(section.end)}`;
|
|
39
|
-
}
|
|
40
|
-
return { sections, prose };
|
|
49
|
+
return { sections };
|
|
41
50
|
}
|
|
42
51
|
function scopePatterns(markdown, section) {
|
|
43
52
|
return validateScopeFragmentLines(markdown.slice(section.contentStart, section.end).split(/\r?\n/), {
|
|
@@ -56,29 +65,90 @@ function normalizeAmendScopePatterns(patterns) {
|
|
|
56
65
|
throw error;
|
|
57
66
|
}
|
|
58
67
|
}
|
|
68
|
+
/** Inspect every structural ATX level so a misplaced replacement never becomes prose. */
|
|
69
|
+
function amendAtxHeadings(markdown) {
|
|
70
|
+
const lines = markdown.split(/\r?\n/);
|
|
71
|
+
const frontMatterEnd = lines[0]?.trim() === "---"
|
|
72
|
+
? lines.findIndex((line, index) => index > 0 && line.trim() === "---")
|
|
73
|
+
: -1;
|
|
74
|
+
let fence;
|
|
75
|
+
const headings = [];
|
|
76
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
77
|
+
const line = lines[index];
|
|
78
|
+
if (index <= frontMatterEnd)
|
|
79
|
+
continue;
|
|
80
|
+
if (fence) {
|
|
81
|
+
const close = line.match(/^ {0,3}(`+|~+)[ \t]*$/);
|
|
82
|
+
if (close && close[1][0] === fence.delimiter && close[1].length >= fence.length)
|
|
83
|
+
fence = undefined;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const open = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/);
|
|
87
|
+
if (open && !(open[1][0] === "`" && open[2].includes("`"))) {
|
|
88
|
+
fence = { delimiter: open[1][0], length: open[1].length };
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const heading = line.match(/^(#{1,6})(?!#)[ \t]+(.+)$/);
|
|
92
|
+
if (heading)
|
|
93
|
+
headings.push({ level: heading[1].length, title: heading[2] });
|
|
94
|
+
}
|
|
95
|
+
return headings;
|
|
96
|
+
}
|
|
97
|
+
function parseReplaceVerificationsSection(markdown) {
|
|
98
|
+
const matchingHeadings = amendAtxHeadings(markdown)
|
|
99
|
+
.filter((heading) => normalizeReplaceVerificationsTitle(heading.title) === "replace verifications");
|
|
100
|
+
if (matchingHeadings.some((heading) => heading.level !== 2)) {
|
|
101
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", "Replace Verifications must use the H2 heading '## Replace Verifications'");
|
|
102
|
+
}
|
|
103
|
+
if (matchingHeadings.length > 1) {
|
|
104
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", "amend input may contain ## Replace Verifications at most once");
|
|
105
|
+
}
|
|
106
|
+
let replacement;
|
|
107
|
+
for (const section of markdownSourceSections(markdown)) {
|
|
108
|
+
if (normalizeReplaceVerificationsTitle(section.title) !== "replace verifications")
|
|
109
|
+
continue;
|
|
110
|
+
replacement = section;
|
|
111
|
+
}
|
|
112
|
+
return replacement;
|
|
113
|
+
}
|
|
114
|
+
function replacementDeclarations(markdown, section) {
|
|
115
|
+
return parseVerificationDeclarations(markdown.slice(section.contentStart, section.end), {
|
|
116
|
+
heading: "## Replace Verifications",
|
|
117
|
+
allowNone: true,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
59
120
|
export function buildAmendInput(markdown, cwd, contractId, contractAddressSource, appendScope) {
|
|
60
|
-
const { sections
|
|
121
|
+
const { sections } = parseAmendScopeSections(markdown);
|
|
122
|
+
const replacement = parseReplaceVerificationsSection(markdown);
|
|
61
123
|
if (sections.append && appendScope && appendScope.length > 0) {
|
|
62
124
|
throw new FlowError("INVALID_KEIYAKU_DRAFT", "amend input may use either --append-scope or ## Scope Append, not both");
|
|
63
125
|
}
|
|
64
126
|
const append = sections.append
|
|
65
127
|
? scopePatterns(markdown, sections.append)
|
|
66
128
|
: normalizeAmendScopePatterns(appendScope ?? []);
|
|
67
|
-
|
|
129
|
+
const verification = replacement ? replacementDeclarations(markdown, replacement) : undefined;
|
|
130
|
+
const sourceSections = [...Object.values(sections), ...(replacement ? [replacement] : [])];
|
|
131
|
+
let proseWithoutReplacement = markdown;
|
|
132
|
+
for (const section of sourceSections.sort((left, right) => right.start - left.start)) {
|
|
133
|
+
proseWithoutReplacement = `${proseWithoutReplacement.slice(0, section.start)}${proseWithoutReplacement.slice(section.end)}`;
|
|
134
|
+
}
|
|
135
|
+
if (!proseWithoutReplacement.trim() && append.length === 0 && verification === undefined) {
|
|
68
136
|
throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
|
|
69
137
|
}
|
|
70
138
|
return {
|
|
71
139
|
cwd,
|
|
72
140
|
...(contractId ? { contractId } : {}),
|
|
73
141
|
...(contractAddressSource ? { contractAddressSource } : {}),
|
|
74
|
-
amendment:
|
|
142
|
+
amendment: proseWithoutReplacement,
|
|
75
143
|
...(append.length > 0 ? { scopeDelta: { add: append } } : {}),
|
|
144
|
+
...(verification ? { verificationDelta: { replace: verification } } : {}),
|
|
76
145
|
};
|
|
77
146
|
}
|
|
78
|
-
function requireAmendment(
|
|
79
|
-
if (!
|
|
147
|
+
function requireAmendment(input) {
|
|
148
|
+
if (!input.amendment.trim() && !input.scopeDelta && !input.verificationDelta) {
|
|
80
149
|
throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
|
|
81
|
-
|
|
150
|
+
}
|
|
151
|
+
return input.amendment;
|
|
82
152
|
}
|
|
83
153
|
function assertContractOperable(contractId, model) {
|
|
84
154
|
const state = currentLifecycleState(model);
|
|
@@ -95,9 +165,19 @@ function normalizeScopeDelta(scopeDelta) {
|
|
|
95
165
|
return undefined;
|
|
96
166
|
return { add };
|
|
97
167
|
}
|
|
168
|
+
function normalizeVerificationDelta(verificationDelta) {
|
|
169
|
+
if (!verificationDelta)
|
|
170
|
+
return undefined;
|
|
171
|
+
const replace = verificationDelta.replace.map((declaration) => ({ ...declaration }));
|
|
172
|
+
if (replace.some((declaration) => !declaration.executor || !declaration.script.trim())) {
|
|
173
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", "Verification replacement declarations must have an executor and nonblank script");
|
|
174
|
+
}
|
|
175
|
+
return { replace };
|
|
176
|
+
}
|
|
98
177
|
export async function amendContract(input) {
|
|
99
|
-
const amendment = requireAmendment(input.amendment);
|
|
100
178
|
const scopeDelta = normalizeScopeDelta(input.scopeDelta);
|
|
179
|
+
const verificationDelta = normalizeVerificationDelta(input.verificationDelta);
|
|
180
|
+
const amendment = requireAmendment({ amendment: input.amendment, scopeDelta, verificationDelta });
|
|
101
181
|
const at = new Date(input.nowMs).toISOString();
|
|
102
182
|
const execution = await runLifecycle({
|
|
103
183
|
cwd: input.cwd,
|
|
@@ -135,12 +215,16 @@ export async function amendContract(input) {
|
|
|
135
215
|
return {
|
|
136
216
|
amendmentNumber: admission.business.amendmentNumber,
|
|
137
217
|
entry: {
|
|
138
|
-
v:
|
|
218
|
+
v: 2,
|
|
139
219
|
kind: "amend",
|
|
140
220
|
contract: input.contractId,
|
|
141
221
|
at,
|
|
142
222
|
actor: input.actor,
|
|
143
|
-
data: {
|
|
223
|
+
data: {
|
|
224
|
+
amendment,
|
|
225
|
+
...(scopeDelta ? { scopeDelta } : {}),
|
|
226
|
+
...(verificationDelta ? { verificationDelta } : {}),
|
|
227
|
+
},
|
|
144
228
|
},
|
|
145
229
|
};
|
|
146
230
|
},
|
|
@@ -162,12 +246,12 @@ export async function amendContract(input) {
|
|
|
162
246
|
effect: async ({ context, admission, prepared }) => {
|
|
163
247
|
const result = prepared.existing
|
|
164
248
|
? await context.replayCommitted({ transactionObjectId: prepared.existing.transactionObjectId })
|
|
165
|
-
: await context.publishAuthoritative({ verb: "amend", admittedLedgerHead: admission.ledgerHead, acceptedLifecycleTail: context.session.lifecycle.
|
|
249
|
+
: await context.publishAuthoritative({ verb: "amend", admittedLedgerHead: admission.ledgerHead, acceptedLifecycleTail: context.session.lifecycle.contractHead, entries: [prepared.entry] });
|
|
166
250
|
if (result.status === "indeterminate") {
|
|
167
251
|
return { kind: "precommit-effects-only", authoritativeHead: result.currentHead ?? admission.ledgerHead };
|
|
168
252
|
}
|
|
169
253
|
if (result.status !== "committed") {
|
|
170
|
-
return { kind: "refused-before-effects", authoritativeHead: result.currentHead ?? context.session.
|
|
254
|
+
return { kind: "refused-before-effects", authoritativeHead: result.currentHead ?? context.session.pins.repositoryLedgerHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed during amend` } };
|
|
171
255
|
}
|
|
172
256
|
return {
|
|
173
257
|
kind: "committed",
|
|
@@ -204,7 +288,7 @@ export async function amendKeiyaku(input) {
|
|
|
204
288
|
const address = input.address ?? await resolveContractAddress(input.cwd, input.contractId, input.contractAddressSource);
|
|
205
289
|
return await withResolvedAddress(address, async () => {
|
|
206
290
|
const contractId = address.binding.commissionId;
|
|
207
|
-
const amendment = requireAmendment(input
|
|
291
|
+
const amendment = requireAmendment(input);
|
|
208
292
|
const amendmentWarningThreshold = getConfig().amendmentWarning.threshold;
|
|
209
293
|
const amended = await amendContract({
|
|
210
294
|
cwd: input.cwd,
|
|
@@ -214,6 +298,7 @@ export async function amendKeiyaku(input) {
|
|
|
214
298
|
amendment,
|
|
215
299
|
amendmentWarningThreshold,
|
|
216
300
|
scopeDelta: input.scopeDelta,
|
|
301
|
+
verificationDelta: input.verificationDelta,
|
|
217
302
|
signal: input.signal,
|
|
218
303
|
});
|
|
219
304
|
if (!isCompleteLifecycleOutcome(amended))
|
package/build/core/arc.js
CHANGED
|
@@ -104,14 +104,14 @@ export async function openArc(input) {
|
|
|
104
104
|
};
|
|
105
105
|
}
|
|
106
106
|
const scopeEntry = patterns.length === 0 ? null : {
|
|
107
|
-
v:
|
|
107
|
+
v: 2,
|
|
108
108
|
kind: "amend",
|
|
109
109
|
contract: input.contractId,
|
|
110
110
|
at,
|
|
111
111
|
actor: input.actor,
|
|
112
112
|
data: { amendment: "Scope extended by lifecycle command.", scopeDelta: { add: patterns } },
|
|
113
113
|
};
|
|
114
|
-
const capture = await captureFoldedSeal(admission.business.targetRoot, admission.business.lifecycle, "HEAD", patterns);
|
|
114
|
+
const capture = await captureFoldedSeal(admission.business.targetRoot, admission.business.lifecycle, "HEAD", patterns, "refuse");
|
|
115
115
|
const arcNumber = admission.business.lifecycle.intent.arc + 1;
|
|
116
116
|
let sealEntry = null;
|
|
117
117
|
if (capture) {
|
|
@@ -158,14 +158,14 @@ export async function openArc(input) {
|
|
|
158
158
|
: await context.publishAuthoritative({
|
|
159
159
|
verb: "arc",
|
|
160
160
|
admittedLedgerHead: admission.ledgerHead,
|
|
161
|
-
acceptedLifecycleTail: context.session.lifecycle.
|
|
161
|
+
acceptedLifecycleTail: context.session.lifecycle.contractHead,
|
|
162
162
|
entries: prepared.additions,
|
|
163
163
|
});
|
|
164
164
|
if (result.status === "indeterminate") {
|
|
165
165
|
return { kind: "precommit-effects-only", authoritativeHead: result.currentHead ?? admission.ledgerHead };
|
|
166
166
|
}
|
|
167
167
|
if (result.status !== "committed" || prepared.arcNumber === 0) {
|
|
168
|
-
return { kind: "refused-before-effects", authoritativeHead: result.status === "committed" ? result.head : result.currentHead ?? context.session.
|
|
168
|
+
return { kind: "refused-before-effects", authoritativeHead: result.status === "committed" ? result.head : result.currentHead ?? context.session.pins.repositoryLedgerHead, refusal: { code: "LEDGER_CAS_CONFLICT", message: `contract ${input.contractId} changed during arc` } };
|
|
169
169
|
}
|
|
170
170
|
const committedCapture = prepared.capture;
|
|
171
171
|
const sealed = committedCapture && {
|