@astrosheep/keiyaku 2.9.8 → 2.9.10
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 +50 -182
- 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 +10 -7
- 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 +242 -79
- 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 +65 -29
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +13 -35
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +45 -69
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +24 -1
- 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 +13 -6
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +29 -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 +35 -337
- 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 +125 -127
- 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
|
@@ -1,53 +1,12 @@
|
|
|
1
|
-
import * as fs from "fs/promises";
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
2
|
import { FlowError } from "../../flow-error.js";
|
|
3
3
|
import { assertGitObservation, observeGitRepository } from "../../git/branches.js";
|
|
4
|
-
import {
|
|
5
|
-
import { AddressResolutionError, buildResolutionAttempt, buildUncommissionedAddress, buildUncommissionedRepositoryAddress, resolveContractAddress, resolveCallWorktreeAddress, withResolvedAddress, } from "../addressing.js";
|
|
4
|
+
import { AddressResolutionError, buildResolutionAttempt, buildUncommissionedAddress, buildUncommissionedRepositoryAddress, resolveCallWorktreeAddressFromRead, resolveExplicitContractAddressFromRead, withResolvedAddress, } from "../addressing.js";
|
|
6
5
|
import { normalizeFilesystemCoordinate } from "../../fs/path-coordinate.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
async function findWorktreePathForContract(cwd, contractId) {
|
|
12
|
-
const git = createGit(cwd);
|
|
13
|
-
let output;
|
|
14
|
-
try {
|
|
15
|
-
output = await git.raw(["worktree", "list", "--porcelain"]);
|
|
16
|
-
}
|
|
17
|
-
catch (error) {
|
|
18
|
-
throw wrapGitError("worktree list --porcelain", error, cwd);
|
|
19
|
-
}
|
|
20
|
-
let currentPath;
|
|
21
|
-
for (const line of output.split(/\r?\n/)) {
|
|
22
|
-
if (line.startsWith("worktree ")) {
|
|
23
|
-
currentPath = line.slice("worktree ".length);
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
26
|
-
if (line === `branch refs/heads/keiyaku/${contractId}`) {
|
|
27
|
-
return currentPath;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
return undefined;
|
|
31
|
-
}
|
|
32
|
-
async function resolveWorkspaceCwd(cwd, contractId, bind) {
|
|
33
|
-
const repoRoot = cwd;
|
|
34
|
-
if (bind.data.workspace === "here")
|
|
35
|
-
return repoRoot;
|
|
36
|
-
const listedWorktreePath = await findWorktreePathForContract(cwd, contractId);
|
|
37
|
-
const worktreePath = listedWorktreePath ?? await contractWorktreePathFromBind(repoRoot, contractId, bind);
|
|
38
|
-
let stat;
|
|
39
|
-
try {
|
|
40
|
-
stat = await fs.stat(worktreePath);
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} worktree not found at ${worktreePath}`, { cause: error });
|
|
44
|
-
}
|
|
45
|
-
if (!stat.isDirectory()) {
|
|
46
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} worktree path is not a directory: ${worktreePath}`);
|
|
47
|
-
}
|
|
48
|
-
return worktreePath;
|
|
49
|
-
}
|
|
50
|
-
export async function readCallKeiyakuContext(executionCwd, input) {
|
|
6
|
+
import { readRepositoryLifecycle, } from "../repository-ledger/read-model.js";
|
|
7
|
+
import { isTerminalState } from "../status/lifecycle.js";
|
|
8
|
+
import { findRegisteredContractWorktreePathFromModel, stableRepoRoot, } from "../worktree-path.js";
|
|
9
|
+
export async function readCallKeiyakuContext(executionCwd, input, ports = {}) {
|
|
51
10
|
executionCwd = normalizeFilesystemCoordinate(executionCwd);
|
|
52
11
|
input.repoCwd = input.repoCwd === undefined ? undefined : normalizeFilesystemCoordinate(input.repoCwd);
|
|
53
12
|
const ledgerCandidate = input.repoCwd ?? executionCwd;
|
|
@@ -153,10 +112,23 @@ export async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
153
112
|
}),
|
|
154
113
|
};
|
|
155
114
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
115
|
+
// This immutable admission is the only lifecycle observation allowed to
|
|
116
|
+
// influence selection, intent, pins, or returned address facts.
|
|
117
|
+
const repository = await (ports.readRepositoryLifecycle ?? readRepositoryLifecycle)(ledgerCwd);
|
|
118
|
+
const admitted = input.contractId === undefined
|
|
119
|
+
? await resolveCallWorktreeAddressFromRead({
|
|
120
|
+
read: repository,
|
|
121
|
+
stableRoot: ledgerCwd,
|
|
122
|
+
workdir: executionCwd,
|
|
123
|
+
})
|
|
124
|
+
: resolveExplicitContractAddressFromRead({
|
|
125
|
+
read: repository,
|
|
126
|
+
stableRoot: ledgerCwd,
|
|
127
|
+
workdir: executionCwd,
|
|
128
|
+
raw: input.contractId,
|
|
129
|
+
source: input.contractAddressSource,
|
|
130
|
+
});
|
|
131
|
+
if (!admitted) {
|
|
160
132
|
return {
|
|
161
133
|
activeKeiyaku: false,
|
|
162
134
|
effectiveCwd: executionCwd,
|
|
@@ -170,44 +142,47 @@ export async function readCallKeiyakuContext(executionCwd, input) {
|
|
|
170
142
|
}),
|
|
171
143
|
};
|
|
172
144
|
}
|
|
145
|
+
const { address, model } = admitted;
|
|
173
146
|
return await withResolvedAddress(address, async () => {
|
|
174
|
-
const contractId =
|
|
175
|
-
|
|
176
|
-
if (!ledger) {
|
|
177
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} not found or not active`);
|
|
178
|
-
}
|
|
179
|
-
const state = deriveContractState(ledger.entries);
|
|
180
|
-
if (state.state === "corrupt") {
|
|
181
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} is corrupt at entry ${state.at}: ${state.reason}`);
|
|
182
|
-
}
|
|
183
|
-
if (isTerminalState(state)) {
|
|
147
|
+
const contractId = model.contract;
|
|
148
|
+
if (isTerminalState(address.lifecycle)) {
|
|
184
149
|
throw new FlowError("EMPTY_PARAM", `commission ${contractId} is terminal and cannot launch an Akuma`);
|
|
185
150
|
}
|
|
186
|
-
const bind =
|
|
187
|
-
if (!bind) {
|
|
151
|
+
const bind = model.history[0]?.entry;
|
|
152
|
+
if (!bind || bind.kind !== "bind") {
|
|
188
153
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} active ledger is missing bind entry`);
|
|
189
154
|
}
|
|
190
|
-
const effectiveCwd =
|
|
155
|
+
const effectiveCwd = model.resources.worktree
|
|
156
|
+
? await findRegisteredContractWorktreePathFromModel(ledgerCwd, model)
|
|
157
|
+
: await fs.realpath(ledgerCwd);
|
|
158
|
+
if (!effectiveCwd) {
|
|
159
|
+
throw new FlowError("INTERNAL_STATE", `contract ${contractId} has no verified registered engine worktree`);
|
|
160
|
+
}
|
|
191
161
|
const executionAddress = { ...address, workdir: effectiveCwd };
|
|
192
|
-
const openArc =
|
|
162
|
+
const openArc = model.phase === "active" && model.history.some(({ entry }) => entry.kind === "arc")
|
|
163
|
+
? model.intent
|
|
164
|
+
: null;
|
|
193
165
|
const currentIntent = openArc
|
|
194
166
|
? {
|
|
195
167
|
source: "arc",
|
|
196
168
|
arc: openArc.arc,
|
|
197
169
|
title: openArc.title,
|
|
198
170
|
objective: openArc.objective,
|
|
199
|
-
brief: openArc.brief,
|
|
171
|
+
brief: openArc.brief ?? "",
|
|
200
172
|
}
|
|
201
|
-
:
|
|
173
|
+
: model.history.some(({ entry }) => entry.kind === "arc")
|
|
202
174
|
? undefined
|
|
203
175
|
: {
|
|
204
176
|
source: "bind",
|
|
205
177
|
arc: 0,
|
|
206
|
-
|
|
178
|
+
title: bind.data.title,
|
|
179
|
+
context: bind.data.context,
|
|
207
180
|
objective: bind.data.objective,
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
181
|
+
design: bind.data.design,
|
|
182
|
+
scope: [...model.effectiveScope],
|
|
183
|
+
criteria: [...bind.data.criteria],
|
|
184
|
+
verification: [...bind.data.verification],
|
|
185
|
+
extensions: bind.data.extensions.map((extension) => ({ ...extension })),
|
|
211
186
|
};
|
|
212
187
|
return {
|
|
213
188
|
activeKeiyaku: true,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ACTOR_IDENTITY } from "../../keiyaku.js";
|
|
2
2
|
const COMMISSIONED_DELIVERY_BOUNDARY = [
|
|
3
3
|
"Delivery boundary: edit and test only inside this linked contract worktree.",
|
|
4
|
-
"Leave source changes uncommitted as a dirty working tree, then report changed files and
|
|
4
|
+
"Leave source changes uncommitted as a dirty working tree, then report changed files and verification run results.",
|
|
5
5
|
"Do not run git add, git commit, or any command that writes Git metadata. A refused Git metadata write is not a failed delivery.",
|
|
6
6
|
"The host coordinator reviews and commits accepted bytes, then continues arc, renew, or petition settlement.",
|
|
7
7
|
].join(" ");
|
|
@@ -32,10 +32,13 @@ export function buildCallPrompt(input) {
|
|
|
32
32
|
return [
|
|
33
33
|
`You are a called ${ACTOR_IDENTITY} working inside derived default arc a0.`,
|
|
34
34
|
"Stay within the contract scope and do the requested work directly.",
|
|
35
|
-
`Contract: ${bind.
|
|
35
|
+
`Contract: ${bind.title}`,
|
|
36
|
+
`Context:\n${bind.context}`,
|
|
36
37
|
`Objective:\n${bind.objective}`,
|
|
38
|
+
`Design:\n${bind.design}`,
|
|
37
39
|
`Scope:\n${bind.scope.map((value) => `- ${value}`).join("\n")}`,
|
|
38
|
-
`
|
|
40
|
+
`Criteria:\n${bind.criteria.map((value) => `- ${value}`).join("\n")}`,
|
|
41
|
+
`Verification:\n${bind.verification.map((value) => `- ${value}`).join("\n")}`,
|
|
39
42
|
extensionsBlock,
|
|
40
43
|
COMMISSIONED_DELIVERY_BOUNDARY,
|
|
41
44
|
`Task:\n${input.task}`,
|
package/build/core/context.js
CHANGED
|
@@ -2,32 +2,41 @@ import { KEIYAKU_BRANCH_PREFIX } from "../keiyaku.js";
|
|
|
2
2
|
import { FlowError } from "../flow-error.js";
|
|
3
3
|
import { createGit, errorContainsAnyPattern, MISSING_HEAD_PATTERNS, NOT_GIT_REPOSITORY_PATTERNS, wrapGitError } from "../git/core.js";
|
|
4
4
|
import { getCurrentBranch, listLocalBranches } from "../git/branches.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const state = deriveContractState(entries);
|
|
12
|
-
return state.state !== "corrupt" && !isTerminalState(state);
|
|
5
|
+
import { lookupCurrentContract, readRepositoryLifecycle, } from "./repository-ledger/read-model.js";
|
|
6
|
+
import { currentContractBoundByWorktreeWitness, stableRepoRoot } from "./worktree-path.js";
|
|
7
|
+
import { contractReadOutcomeError } from "./addressing.js";
|
|
8
|
+
import { admitRepositoryLifecycleContract } from "./repository-ledger/admission.js";
|
|
9
|
+
function isOperableContract(model) {
|
|
10
|
+
return model.phase !== "claimed" && model.phase !== "forfeited";
|
|
13
11
|
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const ledgers = await Promise.all(ids.map(async (id) => ({ id, ledger: await readLedger(cwd, id) })));
|
|
17
|
-
return ledgers.flatMap(({ id, ledger }) => {
|
|
18
|
-
if (!ledger)
|
|
19
|
-
return [];
|
|
20
|
-
return isOperableLedger(ledger.entries) ? [id] : [];
|
|
21
|
-
});
|
|
12
|
+
function operableContracts(read) {
|
|
13
|
+
return read.contracts.filter((model) => lookupCurrentContract(read, model.contract).status === "healthy" && isOperableContract(model));
|
|
22
14
|
}
|
|
23
|
-
|
|
24
|
-
return
|
|
15
|
+
function potentiallyOperableContracts(read) {
|
|
16
|
+
return read.contracts.filter(isOperableContract);
|
|
25
17
|
}
|
|
26
|
-
|
|
18
|
+
function admitOperableContractId(read, contractId) {
|
|
19
|
+
const outcome = admitRepositoryLifecycleContract(read, contractId);
|
|
20
|
+
if (outcome.status === "healthy")
|
|
21
|
+
return isOperableContract(outcome.model);
|
|
22
|
+
if (outcome.status === "absent")
|
|
23
|
+
return false;
|
|
24
|
+
throw contractReadOutcomeError(contractId, outcome);
|
|
25
|
+
}
|
|
26
|
+
export async function operableContractIds(cwd) {
|
|
27
|
+
const read = await readRepositoryLifecycle(cwd);
|
|
28
|
+
return operableContracts(read).map((model) => model.contract);
|
|
29
|
+
}
|
|
30
|
+
async function resolveImplicitCurrentContractIdFromRead(cwd, read) {
|
|
27
31
|
// Prefer the verified engine-worktree binding (same tier as existing-commission verbs).
|
|
28
32
|
try {
|
|
29
|
-
const
|
|
30
|
-
|
|
33
|
+
const stableRoot = await stableRepoRoot(cwd);
|
|
34
|
+
const bound = await currentContractBoundByWorktreeWitness({
|
|
35
|
+
cwd,
|
|
36
|
+
stableRoot,
|
|
37
|
+
contracts: potentiallyOperableContracts(read),
|
|
38
|
+
});
|
|
39
|
+
if (bound && admitOperableContractId(read, bound))
|
|
31
40
|
return bound;
|
|
32
41
|
}
|
|
33
42
|
catch (error) {
|
|
@@ -40,7 +49,10 @@ export async function resolveImplicitCurrentContractId(cwd) {
|
|
|
40
49
|
const branch = (await git.raw(["branch", "--show-current"])).trim();
|
|
41
50
|
if (branch.startsWith("keiyaku/")) {
|
|
42
51
|
const id = branch.slice("keiyaku/".length);
|
|
43
|
-
|
|
52
|
+
const outcome = lookupCurrentContract(read, id);
|
|
53
|
+
if ((outcome.status === "healthy" || outcome.status === "diseased") &&
|
|
54
|
+
outcome.model.resources.worktree === null &&
|
|
55
|
+
admitOperableContractId(read, id))
|
|
44
56
|
return id;
|
|
45
57
|
}
|
|
46
58
|
}
|
|
@@ -51,40 +63,42 @@ export async function resolveImplicitCurrentContractId(cwd) {
|
|
|
51
63
|
}
|
|
52
64
|
return undefined;
|
|
53
65
|
}
|
|
54
|
-
export async function
|
|
55
|
-
|
|
66
|
+
export async function resolveImplicitCurrentContractId(cwd) {
|
|
67
|
+
return resolveImplicitCurrentContractIdFromRead(cwd, await readRepositoryLifecycle(cwd));
|
|
68
|
+
}
|
|
69
|
+
async function resolveCurrentContractIdFromRead(cwd, read) {
|
|
70
|
+
const current = await resolveImplicitCurrentContractIdFromRead(cwd, read);
|
|
56
71
|
if (current)
|
|
57
72
|
return { status: "one", contractId: current };
|
|
58
|
-
const operable = (
|
|
73
|
+
const operable = operableContracts(read).map((model) => model.contract).sort();
|
|
59
74
|
if (operable.length === 0)
|
|
60
75
|
return { status: "none" };
|
|
61
76
|
if (operable.length === 1)
|
|
62
77
|
return { status: "one", contractId: operable[0] };
|
|
63
78
|
throw new FlowError("CONTRACT_AMBIGUOUS", `multiple active contracts found: ${operable.join(", ")}`);
|
|
64
79
|
}
|
|
80
|
+
export async function resolveCurrentContractId(cwd) {
|
|
81
|
+
return resolveCurrentContractIdFromRead(cwd, await readRepositoryLifecycle(cwd));
|
|
82
|
+
}
|
|
65
83
|
export async function listLocalKeiyakuBranches(cwd) {
|
|
66
84
|
return (await listLocalBranches(cwd)).filter((name) => name.startsWith(KEIYAKU_BRANCH_PREFIX));
|
|
67
85
|
}
|
|
68
86
|
export async function readCurrentContractContext(cwd) {
|
|
69
|
-
const
|
|
87
|
+
const read = await readRepositoryLifecycle(cwd);
|
|
88
|
+
const resolution = await resolveCurrentContractIdFromRead(cwd, read);
|
|
70
89
|
if (resolution.status === "none")
|
|
71
90
|
throw new FlowError("EMPTY_PARAM", "no active contract found");
|
|
72
91
|
const contractId = resolution.contractId;
|
|
73
|
-
const
|
|
74
|
-
if (
|
|
92
|
+
const outcome = lookupCurrentContract(read, contractId);
|
|
93
|
+
if (outcome.status !== "healthy" || !isOperableContract(outcome.model)) {
|
|
75
94
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} not found or not active`);
|
|
76
95
|
}
|
|
77
|
-
const base = latestBase(ledger.entries);
|
|
78
|
-
const bind = ledger.entries.find((entry) => entry.kind === "bind");
|
|
79
|
-
if (!base || !bind) {
|
|
80
|
-
throw new FlowError("INTERNAL_STATE", `contract ${contractId} active ledger is missing bind entry`);
|
|
81
|
-
}
|
|
82
96
|
const currentBranch = await getCurrentBranch(cwd);
|
|
83
|
-
const baseBranch =
|
|
97
|
+
const baseBranch = outcome.model.pins.target.ref.slice("refs/heads/".length);
|
|
84
98
|
return {
|
|
85
99
|
contractId,
|
|
86
100
|
currentBranch,
|
|
87
101
|
baseBranch,
|
|
88
|
-
base,
|
|
102
|
+
base: outcome.model.pins.base,
|
|
89
103
|
};
|
|
90
104
|
}
|