@astrosheep/keiyaku 2.9.9 → 2.9.11
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 +93 -174
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +2 -1
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +6 -1
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +3 -2
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +9 -16
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +3 -5
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +2 -0
- package/build/config/env.js +23 -0
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +6 -5
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +27 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +21 -358
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +114 -119
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- package/build/core/status/reconciliation.js +0 -137
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { FlowError } from "../flow-error.js";
|
|
3
|
+
const ADDRESS_CARRIER = Symbol.for("keiyaku.address-carrier");
|
|
4
|
+
export class AddressResolutionError extends FlowError {
|
|
5
|
+
attempt;
|
|
6
|
+
constructor(code, message, attempt, options) {
|
|
7
|
+
super(code, message, options);
|
|
8
|
+
this.name = "AddressResolutionError";
|
|
9
|
+
this.attempt = attempt;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
class AddressedFlowError extends FlowError {
|
|
13
|
+
[ADDRESS_CARRIER];
|
|
14
|
+
constructor(error, carrier) {
|
|
15
|
+
super(error.code, error.message, {
|
|
16
|
+
cause: error,
|
|
17
|
+
review: error.review,
|
|
18
|
+
facts: error.facts,
|
|
19
|
+
});
|
|
20
|
+
this.name = error.name;
|
|
21
|
+
this[ADDRESS_CARRIER] = carrier;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
class AddressedError extends Error {
|
|
25
|
+
[ADDRESS_CARRIER];
|
|
26
|
+
constructor(error, carrier) {
|
|
27
|
+
super(error instanceof Error ? error.message : String(error), { cause: error });
|
|
28
|
+
this.name = error instanceof Error ? error.name : "Error";
|
|
29
|
+
this[ADDRESS_CARRIER] = carrier;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function attachAddressCarrier(error, carrier) {
|
|
33
|
+
if (addressCarrierFromError(error))
|
|
34
|
+
return error;
|
|
35
|
+
return error instanceof FlowError
|
|
36
|
+
? new AddressedFlowError(error, carrier)
|
|
37
|
+
: new AddressedError(error, carrier);
|
|
38
|
+
}
|
|
39
|
+
export function addressCarrierFromError(error) {
|
|
40
|
+
const seen = new Set();
|
|
41
|
+
let current = error;
|
|
42
|
+
while (((typeof current === "object" && current !== null) || typeof current === "function") && !seen.has(current)) {
|
|
43
|
+
seen.add(current);
|
|
44
|
+
if (current instanceof AddressResolutionError)
|
|
45
|
+
return current.attempt;
|
|
46
|
+
const addressed = current;
|
|
47
|
+
if (addressed[ADDRESS_CARRIER])
|
|
48
|
+
return addressed[ADDRESS_CARRIER];
|
|
49
|
+
current = addressed.cause;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
export async function withResolvedAddress(address, operation) {
|
|
54
|
+
try {
|
|
55
|
+
return await operation();
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
throw attachAddressCarrier(error, address);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function buildResolutionAttempt(input) {
|
|
62
|
+
return {
|
|
63
|
+
repo: input.repo,
|
|
64
|
+
workdir: path.resolve(input.workdir),
|
|
65
|
+
expected: "commission",
|
|
66
|
+
...(input.spelling ? { spelling: input.spelling } : {}),
|
|
67
|
+
...(input.actual !== undefined ? { actual: input.actual } : {}),
|
|
68
|
+
candidates: [...(input.candidates ?? [])],
|
|
69
|
+
inference: [...(input.inference ?? [])],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function buildObjectResolutionAttempt(input) {
|
|
73
|
+
return {
|
|
74
|
+
repo: input.repo,
|
|
75
|
+
workdir: path.resolve(input.workdir),
|
|
76
|
+
expected: input.expected,
|
|
77
|
+
supplied: input.supplied,
|
|
78
|
+
...(input.actual !== undefined ? { actual: input.actual } : {}),
|
|
79
|
+
...(input.scope ? { scope: input.scope } : {}),
|
|
80
|
+
candidates: [...(input.candidates ?? [])],
|
|
81
|
+
inference: [...(input.inference ?? [])],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export function buildArtifactResolutionAttempt(input) {
|
|
85
|
+
return {
|
|
86
|
+
...buildObjectResolutionAttempt({ ...input, expected: "artifact" }),
|
|
87
|
+
expected: "artifact",
|
|
88
|
+
};
|
|
89
|
+
}
|
package/build/core/addressing.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { FlowError } from "../flow-error.js";
|
|
3
3
|
import { errorContainsAnyPattern, NOT_GIT_REPOSITORY_PATTERNS } from "../git/core.js";
|
|
4
|
-
import { commissionSlug, formatCommissionCoordinate
|
|
5
|
-
import {
|
|
4
|
+
import { commissionSlug, formatCommissionCoordinate } from "./ids.js";
|
|
5
|
+
import { readRepositoryLifecycle, } from "./repository-ledger/read-model.js";
|
|
6
|
+
import { admitRepositoryLifecycleContract, } from "./repository-ledger/admission.js";
|
|
6
7
|
import { isResponseArtifactId } from "./response-artifact-id.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { currentContractBoundByWorktreeWitness, stableRepoRoot } from "./worktree-path.js";
|
|
9
|
+
import { isTerminalState, } from "./status/lifecycle.js";
|
|
10
|
+
import { AddressResolutionError, } from "./address-carrier.js";
|
|
11
|
+
export { AddressResolutionError, addressCarrierFromError, attachAddressCarrier, buildArtifactResolutionAttempt, buildObjectResolutionAttempt, buildResolutionAttempt, withResolvedAddress, } from "./address-carrier.js";
|
|
10
12
|
const AMBIGUOUS_OBJECTIVE_MAX_CHARS = 60;
|
|
11
13
|
function normalizeAddressQuery(raw) {
|
|
12
14
|
const value = raw.startsWith("@") ? raw.slice(1) : raw;
|
|
@@ -15,88 +17,6 @@ function normalizeAddressQuery(raw) {
|
|
|
15
17
|
}
|
|
16
18
|
return value.trim();
|
|
17
19
|
}
|
|
18
|
-
const ADDRESS_CARRIER = Symbol.for("keiyaku.address-carrier");
|
|
19
|
-
class AddressedFlowError extends FlowError {
|
|
20
|
-
[ADDRESS_CARRIER];
|
|
21
|
-
constructor(error, carrier) {
|
|
22
|
-
super(error.code, error.message, {
|
|
23
|
-
cause: error,
|
|
24
|
-
review: error.review,
|
|
25
|
-
facts: error.facts,
|
|
26
|
-
});
|
|
27
|
-
this.name = error.name;
|
|
28
|
-
this[ADDRESS_CARRIER] = carrier;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
class AddressedError extends Error {
|
|
32
|
-
[ADDRESS_CARRIER];
|
|
33
|
-
constructor(error, carrier) {
|
|
34
|
-
super(error instanceof Error ? error.message : String(error), { cause: error });
|
|
35
|
-
this.name = error instanceof Error ? error.name : "Error";
|
|
36
|
-
this[ADDRESS_CARRIER] = carrier;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
export function attachAddressCarrier(error, carrier) {
|
|
40
|
-
if (addressCarrierFromError(error))
|
|
41
|
-
return error;
|
|
42
|
-
return error instanceof FlowError
|
|
43
|
-
? new AddressedFlowError(error, carrier)
|
|
44
|
-
: new AddressedError(error, carrier);
|
|
45
|
-
}
|
|
46
|
-
export function addressCarrierFromError(error) {
|
|
47
|
-
const seen = new Set();
|
|
48
|
-
let current = error;
|
|
49
|
-
while (((typeof current === "object" && current !== null) || typeof current === "function") && !seen.has(current)) {
|
|
50
|
-
seen.add(current);
|
|
51
|
-
if (current instanceof AddressResolutionError)
|
|
52
|
-
return current.attempt;
|
|
53
|
-
const addressed = current;
|
|
54
|
-
if (addressed[ADDRESS_CARRIER])
|
|
55
|
-
return addressed[ADDRESS_CARRIER];
|
|
56
|
-
current = addressed.cause;
|
|
57
|
-
}
|
|
58
|
-
return undefined;
|
|
59
|
-
}
|
|
60
|
-
export async function withResolvedAddress(address, operation) {
|
|
61
|
-
try {
|
|
62
|
-
return await operation();
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
throw attachAddressCarrier(error, address);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
export function buildResolutionAttempt(input) {
|
|
69
|
-
return {
|
|
70
|
-
repo: input.repo,
|
|
71
|
-
workdir: path.resolve(input.workdir),
|
|
72
|
-
expected: "commission",
|
|
73
|
-
...(input.spelling ? { spelling: input.spelling } : {}),
|
|
74
|
-
...(input.actual !== undefined ? { actual: input.actual } : {}),
|
|
75
|
-
candidates: [...(input.candidates ?? [])],
|
|
76
|
-
inference: [...(input.inference ?? [])],
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
export function buildObjectResolutionAttempt(input) {
|
|
80
|
-
return {
|
|
81
|
-
repo: input.repo,
|
|
82
|
-
workdir: path.resolve(input.workdir),
|
|
83
|
-
expected: input.expected,
|
|
84
|
-
supplied: input.supplied,
|
|
85
|
-
...(input.actual !== undefined ? { actual: input.actual } : {}),
|
|
86
|
-
...(input.scope ? { scope: input.scope } : {}),
|
|
87
|
-
candidates: [...(input.candidates ?? [])],
|
|
88
|
-
inference: [...(input.inference ?? [])],
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
export function buildArtifactResolutionAttempt(input) {
|
|
92
|
-
return {
|
|
93
|
-
...buildObjectResolutionAttempt({
|
|
94
|
-
...input,
|
|
95
|
-
expected: "artifact",
|
|
96
|
-
}),
|
|
97
|
-
expected: "artifact",
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
20
|
function commissionSelectorAsTyped(query, source) {
|
|
101
21
|
if (source === "at-address")
|
|
102
22
|
return `@${query}`;
|
|
@@ -104,63 +24,163 @@ function commissionSelectorAsTyped(query, source) {
|
|
|
104
24
|
return `--contract ${query}`;
|
|
105
25
|
return query;
|
|
106
26
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
27
|
+
function candidatePlace(candidate) {
|
|
28
|
+
return candidate.model.resources.worktree?.place ?? null;
|
|
29
|
+
}
|
|
30
|
+
function legacyLifecycle(model) {
|
|
31
|
+
switch (model.phase) {
|
|
32
|
+
case "active":
|
|
33
|
+
return model.history.every((row) => row.entry.kind === "bind" || row.entry.kind === "bootstrap")
|
|
34
|
+
? { state: "bound" }
|
|
35
|
+
: { state: "active" };
|
|
36
|
+
case "sealed":
|
|
37
|
+
return { state: "active" };
|
|
38
|
+
case "awaiting-verdict":
|
|
39
|
+
case "approved":
|
|
40
|
+
return { state: "petitioned" };
|
|
41
|
+
case "claimed":
|
|
42
|
+
return { state: "claimed" };
|
|
43
|
+
case "forfeited":
|
|
44
|
+
return { state: "forfeited" };
|
|
113
45
|
}
|
|
114
46
|
}
|
|
115
|
-
function
|
|
116
|
-
return
|
|
47
|
+
function commissionAddressCandidates(read) {
|
|
48
|
+
return read.contracts.map((model) => {
|
|
49
|
+
const lifecycle = legacyLifecycle(model);
|
|
50
|
+
return {
|
|
51
|
+
contractId: model.contract,
|
|
52
|
+
model,
|
|
53
|
+
operable: !isTerminalState(lifecycle),
|
|
54
|
+
lifecycle,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
117
57
|
}
|
|
118
|
-
function
|
|
119
|
-
return
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
58
|
+
export function contractReadOutcomeError(contractId, outcome) {
|
|
59
|
+
return new FlowError("INTERNAL_STATE", `contract ${contractId} is unavailable because repository lifecycle evidence is ${outcome.status}`, {
|
|
60
|
+
facts: {
|
|
61
|
+
kind: "repository_lifecycle_disease",
|
|
62
|
+
contractId,
|
|
63
|
+
status: outcome.status,
|
|
64
|
+
diagnostics: outcome.diagnostics.map((diagnostic) => ({
|
|
65
|
+
objectId: diagnostic.objectId,
|
|
66
|
+
code: diagnostic.code,
|
|
67
|
+
detail: diagnostic.detail,
|
|
68
|
+
...(diagnostic.contract === undefined ? {} : { contract: diagnostic.contract }),
|
|
69
|
+
})),
|
|
70
|
+
},
|
|
130
71
|
});
|
|
131
72
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
return
|
|
73
|
+
function admitContractCandidate(read, candidate) {
|
|
74
|
+
const outcome = admitRepositoryLifecycleContract(read, candidate.contractId);
|
|
75
|
+
if (outcome.status === "healthy")
|
|
76
|
+
return candidate;
|
|
77
|
+
if (outcome.status === "absent") {
|
|
78
|
+
throw new FlowError("INTERNAL_STATE", `contract ${candidate.contractId} disappeared from the repository lifecycle read model`);
|
|
79
|
+
}
|
|
80
|
+
throw contractReadOutcomeError(candidate.contractId, outcome);
|
|
81
|
+
}
|
|
82
|
+
function admittedAddress(read, candidate, address) {
|
|
83
|
+
admitContractCandidate(read, candidate);
|
|
84
|
+
return { address, model: candidate.model };
|
|
85
|
+
}
|
|
86
|
+
function matchedCommissionSpellings(query, candidate) {
|
|
87
|
+
const matches = [];
|
|
88
|
+
if (candidate.contractId === query)
|
|
89
|
+
matches.push("id");
|
|
90
|
+
if (commissionSlug(candidate.contractId) === query)
|
|
91
|
+
matches.push("slug");
|
|
92
|
+
if (candidate.operable && candidatePlace(candidate) === query) {
|
|
93
|
+
matches.push("place");
|
|
136
94
|
}
|
|
137
|
-
|
|
138
|
-
const failed = reads.find((read) => "error" in read);
|
|
139
|
-
if (failed && "error" in failed)
|
|
140
|
-
throw failed.error;
|
|
141
|
-
return commissionAddressCandidatesFromLedgers(reads.filter((read) => !("error" in read)));
|
|
95
|
+
return matches;
|
|
142
96
|
}
|
|
143
|
-
function
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
97
|
+
function preferredCommissionSpelling(spellings) {
|
|
98
|
+
for (const spelling of ["id", "slug", "place"]) {
|
|
99
|
+
if (spellings.has(spelling))
|
|
100
|
+
return spelling;
|
|
101
|
+
}
|
|
102
|
+
throw new FlowError("INTERNAL_STATE", "contract address identity has no matched spelling");
|
|
103
|
+
}
|
|
104
|
+
function explicitAddressIdentities(read, query) {
|
|
105
|
+
const identities = new Map();
|
|
106
|
+
const upsert = (contractId, spellings, candidate) => {
|
|
107
|
+
if (spellings.length === 0)
|
|
108
|
+
return;
|
|
109
|
+
const current = identities.get(contractId);
|
|
110
|
+
if (current) {
|
|
111
|
+
for (const spelling of spellings)
|
|
112
|
+
current.matchedSpellings.add(spelling);
|
|
113
|
+
if (!current.candidate && candidate)
|
|
114
|
+
current.candidate = candidate;
|
|
115
|
+
return;
|
|
152
116
|
}
|
|
153
|
-
|
|
154
|
-
|
|
117
|
+
identities.set(contractId, {
|
|
118
|
+
contractId,
|
|
119
|
+
matchedSpellings: new Set(spellings),
|
|
120
|
+
...(candidate ? { candidate } : {}),
|
|
121
|
+
outcome: admitRepositoryLifecycleContract(read, contractId),
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
for (const candidate of commissionAddressCandidates(read)) {
|
|
125
|
+
upsert(candidate.contractId, matchedCommissionSpellings(query, candidate), candidate);
|
|
126
|
+
}
|
|
127
|
+
for (const contractId of read.isolatedContracts) {
|
|
128
|
+
const spellings = [];
|
|
129
|
+
if (contractId === query)
|
|
130
|
+
spellings.push("id");
|
|
131
|
+
if (commissionSlug(contractId) === query)
|
|
132
|
+
spellings.push("slug");
|
|
133
|
+
upsert(contractId, spellings);
|
|
134
|
+
}
|
|
135
|
+
return [...identities.values()].sort((left, right) => left.contractId.localeCompare(right.contractId));
|
|
136
|
+
}
|
|
137
|
+
function resolutionCandidateForIdentity(identity) {
|
|
138
|
+
const matchedBy = preferredCommissionSpelling(identity.matchedSpellings);
|
|
139
|
+
if (identity.candidate) {
|
|
140
|
+
const candidate = identity.candidate;
|
|
141
|
+
return {
|
|
142
|
+
commissionId: candidate.contractId,
|
|
143
|
+
matchedBy,
|
|
144
|
+
place: candidatePlace(candidate),
|
|
145
|
+
name: candidate.model.history[0].entry.kind === "bind" ? candidate.model.history[0].entry.data.title : candidate.model.intent.title,
|
|
146
|
+
objective: candidate.model.intent.objective,
|
|
147
|
+
lifecycle: candidate.lifecycle,
|
|
148
|
+
target: { branch: candidate.model.pins.target.ref },
|
|
149
|
+
...(identity.outcome.status === "diseased" || identity.outcome.status === "isolated" || identity.outcome.status === "indeterminate"
|
|
150
|
+
? {
|
|
151
|
+
availability: {
|
|
152
|
+
status: identity.outcome.status,
|
|
153
|
+
diagnostics: identity.outcome.diagnostics,
|
|
154
|
+
},
|
|
155
|
+
}
|
|
156
|
+
: {}),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
if (identity.outcome.status === "healthy" || identity.outcome.status === "absent") {
|
|
160
|
+
throw new FlowError("INTERNAL_STATE", `contract ${identity.contractId} matched without a lifecycle model`);
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
commissionId: identity.contractId,
|
|
164
|
+
matchedBy,
|
|
165
|
+
place: null,
|
|
166
|
+
name: identity.contractId,
|
|
167
|
+
objective: `repository lifecycle evidence is ${identity.outcome.status}`,
|
|
168
|
+
lifecycle: { state: "corrupt", at: 0, reason: `repository lifecycle evidence is ${identity.outcome.status}` },
|
|
169
|
+
target: { branch: "" },
|
|
170
|
+
availability: {
|
|
171
|
+
status: identity.outcome.status,
|
|
172
|
+
diagnostics: identity.outcome.diagnostics,
|
|
173
|
+
},
|
|
174
|
+
};
|
|
155
175
|
}
|
|
156
176
|
function attemptCandidates(candidates) {
|
|
157
177
|
return candidates.map((candidate) => ({
|
|
158
178
|
commissionId: candidate.contractId,
|
|
159
179
|
place: candidatePlace(candidate),
|
|
160
|
-
name: candidate.bind.data.
|
|
161
|
-
objective: candidate.
|
|
180
|
+
name: candidate.model.history[0].entry.kind === "bind" ? candidate.model.history[0].entry.data.title : candidate.model.intent.title,
|
|
181
|
+
objective: candidate.model.intent.objective,
|
|
162
182
|
lifecycle: candidate.lifecycle,
|
|
163
|
-
target: { branch: candidate.
|
|
183
|
+
target: { branch: candidate.model.pins.target.ref },
|
|
164
184
|
}));
|
|
165
185
|
}
|
|
166
186
|
function truncateObjectiveFirstLine(objective) {
|
|
@@ -190,7 +210,7 @@ function buildResolvedAddress(input) {
|
|
|
190
210
|
spelling: { asTyped: input.asTyped, source: input.source, matchedBy: input.matchedBy },
|
|
191
211
|
place: { display: candidatePlace(input.candidate) },
|
|
192
212
|
lifecycle: input.candidate.lifecycle,
|
|
193
|
-
target: { branch: input.candidate.
|
|
213
|
+
target: { branch: input.candidate.model.pins.target.ref },
|
|
194
214
|
inference: input.inference,
|
|
195
215
|
};
|
|
196
216
|
}
|
|
@@ -210,64 +230,83 @@ export function buildUncommissionedRepositoryAddress(input) {
|
|
|
210
230
|
inference: input.inference,
|
|
211
231
|
});
|
|
212
232
|
}
|
|
233
|
+
export function resolveExplicitContractAddressFromRead(input) {
|
|
234
|
+
const workdir = path.resolve(input.workdir);
|
|
235
|
+
const repo = { kind: "repository", stableRoot: input.stableRoot };
|
|
236
|
+
const query = normalizeAddressQuery(input.raw);
|
|
237
|
+
const source = input.source ?? (input.raw.startsWith("@") ? "at-address" : "explicit-flag");
|
|
238
|
+
const spelling = { asTyped: commissionSelectorAsTyped(query, source), source };
|
|
239
|
+
if (isResponseArtifactId(query)) {
|
|
240
|
+
throw new AddressResolutionError("EMPTY_PARAM", `artifact ${query} is a response artifact; expected a commission address`, { repo, workdir, expected: "commission", spelling, candidates: [], inference: [], actual: "artifact" });
|
|
241
|
+
}
|
|
242
|
+
const identities = explicitAddressIdentities(input.read, query);
|
|
243
|
+
const attempt = {
|
|
244
|
+
repo,
|
|
245
|
+
workdir,
|
|
246
|
+
expected: "commission",
|
|
247
|
+
spelling,
|
|
248
|
+
candidates: identities.map(resolutionCandidateForIdentity),
|
|
249
|
+
inference: [],
|
|
250
|
+
};
|
|
251
|
+
if (identities.length > 1) {
|
|
252
|
+
const detail = attempt.candidates.length > 0
|
|
253
|
+
? `:\n${attempt.candidates.map((candidate) => ` ${formatAmbiguousCandidate(candidate)}`).join("\n")}`
|
|
254
|
+
: "";
|
|
255
|
+
throw new AddressResolutionError("CONTRACT_AMBIGUOUS", `@${query} is ambiguous${detail}\nuse a full @commission-id`, attempt);
|
|
256
|
+
}
|
|
257
|
+
if (identities.length === 1) {
|
|
258
|
+
const identity = identities[0];
|
|
259
|
+
if (identity.outcome.status !== "healthy") {
|
|
260
|
+
if (identity.outcome.status === "absent") {
|
|
261
|
+
throw new FlowError("INTERNAL_STATE", `contract ${identity.contractId} disappeared from the repository lifecycle read model`);
|
|
262
|
+
}
|
|
263
|
+
throw contractReadOutcomeError(identity.contractId, identity.outcome);
|
|
264
|
+
}
|
|
265
|
+
const candidate = identity.candidate;
|
|
266
|
+
if (!candidate) {
|
|
267
|
+
throw new FlowError("INTERNAL_STATE", `healthy contract ${identity.contractId} matched without a lifecycle model`);
|
|
268
|
+
}
|
|
269
|
+
const matchedBy = preferredCommissionSpelling(identity.matchedSpellings);
|
|
270
|
+
const address = buildResolvedAddress({
|
|
271
|
+
repo,
|
|
272
|
+
workdir,
|
|
273
|
+
candidate,
|
|
274
|
+
matchedBy,
|
|
275
|
+
asTyped: spelling.asTyped,
|
|
276
|
+
source,
|
|
277
|
+
inference: [],
|
|
278
|
+
});
|
|
279
|
+
return { address, model: candidate.model };
|
|
280
|
+
}
|
|
281
|
+
const unknown = admitRepositoryLifecycleContract(input.read, query);
|
|
282
|
+
if (unknown.status === "diseased" || unknown.status === "isolated" || unknown.status === "indeterminate") {
|
|
283
|
+
throw contractReadOutcomeError(query, unknown);
|
|
284
|
+
}
|
|
285
|
+
throw new AddressResolutionError("EMPTY_PARAM", `unknown contract address @${query}`, attempt);
|
|
286
|
+
}
|
|
213
287
|
export async function resolveContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag", effectiveDirectory = cwd) {
|
|
214
288
|
const workdir = path.resolve(effectiveDirectory);
|
|
215
289
|
const repo = await resolvedRepository(cwd);
|
|
290
|
+
const read = await readRepositoryLifecycle(repo.stableRoot);
|
|
216
291
|
if (raw !== undefined) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
if (isResponseArtifactId(query)) {
|
|
221
|
-
throw new AddressResolutionError("EMPTY_PARAM", `artifact ${query} is a response artifact; expected a commission address`, {
|
|
222
|
-
repo,
|
|
223
|
-
workdir,
|
|
224
|
-
expected: "commission",
|
|
225
|
-
spelling,
|
|
226
|
-
candidates: [],
|
|
227
|
-
inference: [],
|
|
228
|
-
actual: "artifact",
|
|
229
|
-
});
|
|
230
|
-
}
|
|
231
|
-
const candidates = await commissionAddressCandidates(repo.stableRoot, isCommissionId(query) ? query : undefined);
|
|
232
|
-
const matches = matchCommissionAddress(query, candidates);
|
|
233
|
-
const attempt = {
|
|
234
|
-
repo,
|
|
292
|
+
return resolveExplicitContractAddressFromRead({
|
|
293
|
+
read,
|
|
294
|
+
stableRoot: repo.stableRoot,
|
|
235
295
|
workdir,
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
commissionId: candidate.contractId,
|
|
240
|
-
matchedBy: candidate.spelling,
|
|
241
|
-
place: candidatePlace(candidate),
|
|
242
|
-
name: candidate.bind.data.name,
|
|
243
|
-
objective: candidate.bind.data.objective,
|
|
244
|
-
lifecycle: candidate.lifecycle,
|
|
245
|
-
target: { branch: candidate.bind.data.target },
|
|
246
|
-
})),
|
|
247
|
-
inference: [],
|
|
248
|
-
};
|
|
249
|
-
if (matches.length === 1) {
|
|
250
|
-
return buildResolvedAddress({
|
|
251
|
-
repo,
|
|
252
|
-
workdir,
|
|
253
|
-
candidate: matches[0],
|
|
254
|
-
matchedBy: matches[0].spelling,
|
|
255
|
-
asTyped: attempt.spelling.asTyped,
|
|
256
|
-
source,
|
|
257
|
-
inference: [],
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
if (matches.length === 0) {
|
|
261
|
-
throw new AddressResolutionError("EMPTY_PARAM", `unknown contract address @${query}`, attempt);
|
|
262
|
-
}
|
|
263
|
-
throw new AddressResolutionError("CONTRACT_AMBIGUOUS", `@${query} is ambiguous:\n${attempt.candidates.map((candidate) => ` ${formatAmbiguousCandidate(candidate)}`).join("\n")}\nuse a full @commission-id`, attempt);
|
|
296
|
+
raw,
|
|
297
|
+
source,
|
|
298
|
+
}).address;
|
|
264
299
|
}
|
|
265
|
-
const candidates =
|
|
300
|
+
const candidates = commissionAddressCandidates(read);
|
|
266
301
|
let boundContractId;
|
|
267
302
|
try {
|
|
268
303
|
const effectiveRepo = await stableRepoRoot(workdir);
|
|
269
304
|
if (effectiveRepo === repo.stableRoot) {
|
|
270
|
-
boundContractId = await
|
|
305
|
+
boundContractId = await currentContractBoundByWorktreeWitness({
|
|
306
|
+
cwd: workdir,
|
|
307
|
+
stableRoot: effectiveRepo,
|
|
308
|
+
contracts: candidates.filter((candidate) => candidate.operable).map((candidate) => candidate.model),
|
|
309
|
+
});
|
|
271
310
|
}
|
|
272
311
|
}
|
|
273
312
|
catch (error) {
|
|
@@ -275,8 +314,9 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
|
|
|
275
314
|
throw error;
|
|
276
315
|
}
|
|
277
316
|
if (boundContractId) {
|
|
278
|
-
const candidate = candidates.find((item) => item.
|
|
317
|
+
const candidate = candidates.find((item) => item.operable && item.contractId === boundContractId);
|
|
279
318
|
if (candidate) {
|
|
319
|
+
admitContractCandidate(read, candidate);
|
|
280
320
|
return buildResolvedAddress({
|
|
281
321
|
repo,
|
|
282
322
|
workdir,
|
|
@@ -288,16 +328,16 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
|
|
|
288
328
|
});
|
|
289
329
|
}
|
|
290
330
|
}
|
|
291
|
-
const operable = candidates.filter((candidate) => candidate.
|
|
331
|
+
const operable = candidates.filter((candidate) => candidate.operable);
|
|
292
332
|
const attempt = {
|
|
293
333
|
repo,
|
|
294
334
|
workdir,
|
|
295
335
|
expected: "commission",
|
|
296
336
|
candidates: attemptCandidates(operable),
|
|
297
|
-
inference: ["consulted
|
|
337
|
+
inference: ["consulted repository lifecycle ledger"],
|
|
298
338
|
};
|
|
299
339
|
if (operable.length === 1) {
|
|
300
|
-
const candidate = operable[0];
|
|
340
|
+
const candidate = admitContractCandidate(read, operable[0]);
|
|
301
341
|
return buildResolvedAddress({
|
|
302
342
|
repo,
|
|
303
343
|
workdir,
|
|
@@ -317,15 +357,20 @@ export async function resolveContractAddress(cwd, raw, source = raw?.startsWith(
|
|
|
317
357
|
* engine-owned worktree. Unlike existing-contract resolution, this never
|
|
318
358
|
* considers sole-active cardinality.
|
|
319
359
|
*/
|
|
320
|
-
export async function
|
|
321
|
-
const repo =
|
|
322
|
-
const workdir = path.resolve(
|
|
360
|
+
export async function resolveCallWorktreeAddressFromRead(input) {
|
|
361
|
+
const repo = { kind: "repository", stableRoot: input.stableRoot };
|
|
362
|
+
const workdir = path.resolve(input.workdir);
|
|
363
|
+
const candidates = commissionAddressCandidates(input.read).filter((candidate) => candidate.operable);
|
|
323
364
|
let contractId;
|
|
324
365
|
try {
|
|
325
366
|
const effectiveRepo = await stableRepoRoot(workdir);
|
|
326
367
|
if (effectiveRepo !== repo.stableRoot)
|
|
327
368
|
return undefined;
|
|
328
|
-
contractId = await
|
|
369
|
+
contractId = await currentContractBoundByWorktreeWitness({
|
|
370
|
+
cwd: workdir,
|
|
371
|
+
stableRoot: effectiveRepo,
|
|
372
|
+
contracts: candidates.map((candidate) => candidate.model),
|
|
373
|
+
});
|
|
329
374
|
}
|
|
330
375
|
catch (error) {
|
|
331
376
|
if (!errorContainsAnyPattern(error, NOT_GIT_REPOSITORY_PATTERNS))
|
|
@@ -334,15 +379,29 @@ export async function resolveCallWorktreeAddress(cwd, effectiveDirectory = cwd)
|
|
|
334
379
|
}
|
|
335
380
|
if (!contractId)
|
|
336
381
|
return undefined;
|
|
337
|
-
|
|
382
|
+
const candidate = candidates.find((item) => item.contractId === contractId);
|
|
383
|
+
if (!candidate)
|
|
384
|
+
return undefined;
|
|
385
|
+
const address = buildResolvedAddress({
|
|
386
|
+
repo,
|
|
387
|
+
workdir,
|
|
388
|
+
candidate,
|
|
389
|
+
matchedBy: "id",
|
|
390
|
+
asTyped: `@${candidate.contractId}`,
|
|
391
|
+
source: "worktree-binding",
|
|
392
|
+
inference: ["verified active engine worktree binding"],
|
|
393
|
+
});
|
|
394
|
+
return admittedAddress(input.read, candidate, address);
|
|
395
|
+
}
|
|
396
|
+
export async function resolveCallWorktreeAddress(cwd, effectiveDirectory = cwd) {
|
|
397
|
+
const repo = await resolvedRepository(cwd);
|
|
398
|
+
const admitted = await resolveCallWorktreeAddressFromRead({
|
|
399
|
+
read: await readRepositoryLifecycle(repo.stableRoot),
|
|
400
|
+
stableRoot: repo.stableRoot,
|
|
401
|
+
workdir: effectiveDirectory,
|
|
402
|
+
});
|
|
403
|
+
return admitted?.address;
|
|
338
404
|
}
|
|
339
405
|
export async function resolveExistingContractAddress(cwd, raw, source = raw?.startsWith("@") ? "at-address" : "explicit-flag", effectiveDirectory = cwd) {
|
|
340
|
-
|
|
341
|
-
try {
|
|
342
|
-
await assertNoRenewRecoverySession(address.repo.stableRoot, address.binding.commissionId);
|
|
343
|
-
}
|
|
344
|
-
catch (error) {
|
|
345
|
-
throw attachAddressCarrier(error, address);
|
|
346
|
-
}
|
|
347
|
-
return address;
|
|
406
|
+
return resolveContractAddress(cwd, raw, source, effectiveDirectory);
|
|
348
407
|
}
|