@astrosheep/keiyaku 2.9.2 → 2.9.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +13 -94
- package/build/agents/harness/activity-values.js +16 -0
- package/build/agents/harness/event-persistence.js +218 -0
- package/build/agents/harness/execution-handle.js +25 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +47 -4
- package/build/agents/harness/projection.js +42 -59
- package/build/agents/harness/provider-adapter.js +58 -0
- package/build/agents/harness/router.js +11 -187
- package/build/agents/harness/runtime.js +17 -4
- package/build/agents/harness/session.js +15 -0
- package/build/agents/launch-snapshot/model.js +15 -236
- package/build/agents/launch-snapshot/parse-helpers.js +114 -0
- package/build/agents/launch-snapshot/resolve.js +17 -43
- package/build/agents/opencode-sdk.js +45 -12
- package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
- package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
- package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
- package/build/agents/providers/codex-app-server/adapter.js +50 -53
- package/build/agents/providers/codex-app-server/events.js +67 -11
- package/build/agents/providers/codex-app-server/identity.js +1 -0
- package/build/agents/providers/codex-app-server/policy.js +29 -0
- package/build/agents/providers/codex-app-server/registration.js +248 -0
- package/build/agents/providers/codex-app-server/session-schema.js +6 -0
- package/build/agents/providers/codex-app-server/session.js +23 -17
- package/build/agents/providers/codex-app-server/terms.js +1 -0
- package/build/agents/providers/opencode-sdk/adapter.js +94 -50
- package/build/agents/providers/opencode-sdk/events.js +8 -4
- package/build/agents/providers/opencode-sdk/registration.js +135 -0
- package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
- package/build/agents/providers/opencode-sdk/session.js +21 -14
- package/build/agents/providers/opencode-sdk/terms.js +1 -0
- package/build/agents/providers/pi/adapter.js +36 -30
- package/build/agents/providers/pi/registration.js +145 -0
- package/build/agents/providers/pi/session-schema.js +6 -0
- package/build/agents/providers/pi/terms.js +1 -0
- package/build/agents/providers/registration.js +7 -0
- package/build/agents/providers/registry.js +76 -0
- package/build/agents/selector.js +2 -29
- package/build/agents/types.js +8 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/arc/handler.js +7 -1
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +34 -7
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/petition/handler.js +4 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +5 -4
- package/build/cli/commands/metadata.js +58 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +7 -2
- package/build/cli/commands/registry.js +2 -54
- package/build/cli/commands/shared.js +10 -7
- package/build/cli/commands/skills/install/handler.js +2 -5
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/task/add/handler.js +5 -13
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/ls/handler.js +3 -5
- package/build/cli/commands/task/shared.js +14 -4
- package/build/cli/commands/task/{view → show}/handler.js +7 -8
- package/build/cli/commands/task/show/meta.js +8 -0
- package/build/cli/commands/task/start/handler.js +3 -6
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/update/handler.js +4 -8
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +19 -3
- package/build/cli/help.js +4 -11
- package/build/cli/index.js +57 -83
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/parse-flags.js +14 -5
- package/build/cli/parse-metadata.js +3 -3
- package/build/cli/parse-selectors.js +1 -1
- package/build/cli/parse.js +21 -0
- package/build/cli/projection-address.js +7 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/call.js +11 -5
- package/build/cli/render/errors.js +36 -1
- package/build/cli/render/format.js +4 -0
- package/build/cli/render/kanshi.js +6 -12
- package/build/cli/render/kill.js +9 -0
- package/build/cli/render/misc.js +55 -12
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +3 -0
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +37 -14
- package/build/cli/render/success-response.js +77 -0
- package/build/cli/render/task.js +54 -14
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +58 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +38 -36
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +1 -1
- package/build/config/provider-policy-ownership.js +3 -32
- package/build/config/settings/disease.js +8 -1
- package/build/config/settings/loader.js +11 -3
- package/build/config/settings/provider-instance-fields.js +51 -0
- package/build/config/settings/schema.js +6 -176
- package/build/core/addressing.js +66 -16
- package/build/core/amend.js +135 -18
- package/build/core/arc.js +19 -67
- package/build/core/bind.js +82 -35
- package/build/core/call/call.js +15 -9
- package/build/core/call/context.js +6 -51
- package/build/core/call/execution.js +21 -22
- package/build/core/call/prompt.js +14 -1
- package/build/core/command-markdown.js +45 -0
- package/build/core/context.js +13 -7
- package/build/core/contract-view.js +20 -3
- package/build/core/draft.js +123 -16
- package/build/core/forfeit.js +5 -2
- package/build/core/hints.js +1 -75
- package/build/core/identifier-slug.js +66 -0
- package/build/core/ids.js +25 -11
- package/build/core/ledger.js +20 -68
- package/build/core/markdown/parser.js +0 -68
- package/build/core/markdown/render.js +68 -0
- package/build/core/markdown/sections.js +2 -1
- package/build/core/outcome-base.js +4 -0
- package/build/core/projection/generation/database.js +2 -38
- package/build/core/projection/generation/model.js +42 -1
- package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
- package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +19 -49
- package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
- package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +5 -3
- package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
- package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +18 -3
- package/build/core/projection/generation/store.js +2 -2
- package/build/core/projection/generation/transitions.js +1 -1
- package/build/core/projection/index.js +27 -0
- package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
- package/build/core/{projection-alias.js → projection/projection-alias.js} +14 -19
- package/build/core/projection/projection-coordinate.js +61 -0
- package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
- package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +2 -57
- package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
- package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
- package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +1 -1
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +98 -25
- package/build/core/projection/projection-terminal-failure.js +104 -0
- package/build/core/projection/projection-wait.js +278 -0
- package/build/core/projection/projection-wake.js +203 -0
- package/build/core/provider-loader-ports.js +4 -0
- package/build/core/ref-log.js +65 -40
- package/build/core/registry.js +63 -10
- package/build/core/renew-session.js +128 -0
- package/build/core/renew.js +426 -99
- package/build/core/scope.js +143 -66
- package/build/core/seal.js +139 -35
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +9 -14
- package/build/core/{claim.js → settlement/claim.js} +32 -8
- package/build/core/settlement/index.js +19 -0
- package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +22 -18
- package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
- package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
- package/build/core/settlement/petition-io.js +1 -0
- package/build/core/{petition-preview.js → settlement/petition-preview.js} +1 -1
- package/build/core/{petition.js → settlement/petition.js} +12 -10
- package/build/core/settlement/queue-read-model.js +143 -0
- package/build/core/settlement/queue-seat-allocation.js +156 -0
- package/build/core/settlement/queue.js +6 -0
- package/build/core/settlement/settlement.js +295 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/status/board.js +24 -23
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +3 -0
- package/build/core/task/board.js +40 -4
- package/build/core/task/commands.js +30 -21
- package/build/core/task/index.js +12 -0
- package/build/core/task/settlement-git.js +157 -65
- package/build/core/task/settlement-policy.js +54 -24
- package/build/core/task/task-contract.js +370 -0
- package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
- package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
- package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
- package/build/core/{task-git-store.js → task/task-git-store.js} +92 -29
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +5 -4
- package/build/core/task/task-store.js +1 -0
- package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
- package/build/core/task/task.js +5 -0
- package/build/core/task/tree.js +37 -0
- package/build/core/task/validation.js +5 -2
- package/build/core/transcripts.js +15 -3
- package/build/core/worktree-path.js +43 -28
- package/build/flow-error.js +85 -39
- package/build/fs/durability.js +27 -0
- package/build/fs/path-coordinate.js +16 -0
- package/build/generated/version.js +3 -2
- package/build/git/branches.js +2 -1
- package/build/git/core.js +106 -2
- package/build/git/path-coordinate.js +17 -0
- package/build/git/refs.js +57 -0
- package/build/git/streaming-batch.js +301 -0
- package/build/git/worktree.js +65 -0
- package/build/index.js +3 -3
- package/build/keiyaku.js +2 -36
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +3 -2
- package/skills/keiyaku-akuma/SKILL.md +10 -6
- package/skills/keiyaku-task/SKILL.md +1 -1
- package/skills/keiyaku-workflow/SKILL.md +25 -4
- package/build/agents/providers/codex-sdk.js +0 -329
- package/build/cli/commands/task/view/meta.js +0 -8
- package/build/core/command-io.js +0 -174
- package/build/core/path-coordinate.js +0 -27
- package/build/core/petition-claim.js +0 -117
- package/build/core/petition-run.js +0 -83
- package/build/core/projection-coordinate.js +0 -63
- package/build/core/projection-wait.js +0 -165
- package/build/core/projection-wake.js +0 -136
- package/build/core/queue.js +0 -343
- package/build/core/task-contract.js +0 -237
- package/build/core/task.js +0 -4
- /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
- /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
- /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
- /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
- /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { FlowError } from "
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { deriveContractState } from "./status/lifecycle.js";
|
|
1
|
+
import { FlowError } from "../../flow-error.js";
|
|
2
|
+
import { activeLedgerRef, appendWithRetry, readLedger } from "../ledger.js";
|
|
3
|
+
import { assertClaimQueueHead, readQueueReadModel } from "./queue.js";
|
|
4
|
+
import { deriveContractState } from "../status/lifecycle.js";
|
|
6
5
|
function latestVerdict(entries) {
|
|
7
6
|
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
8
7
|
const entry = entries[index];
|
|
@@ -19,6 +18,10 @@ function assertPetitioned(contractId, entries) {
|
|
|
19
18
|
throw new FlowError("INTERNAL_STATE", `contract ${contractId} cannot verdict from state ${state.state}`);
|
|
20
19
|
}
|
|
21
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Append a verdict entry and return typed judgment facts.
|
|
23
|
+
* Does not claim, clean up, or otherwise execute delivery.
|
|
24
|
+
*/
|
|
22
25
|
export async function verdictContract(input) {
|
|
23
26
|
const at = new Date(input.nowMs).toISOString();
|
|
24
27
|
const current = await readLedger(input.cwd, input.contractId);
|
|
@@ -69,40 +72,9 @@ export async function verdictContract(input) {
|
|
|
69
72
|
if (verdict.data.result !== input.result) {
|
|
70
73
|
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} already has ${verdict.data.result} verdict`);
|
|
71
74
|
}
|
|
72
|
-
if (verdict.data.result === "rejected") {
|
|
73
|
-
// Rejected verdict naturally returns state to active and clears membership.
|
|
74
|
-
return {
|
|
75
|
-
contractId: input.contractId,
|
|
76
|
-
result: "rejected",
|
|
77
|
-
summary: verdict.data.summary,
|
|
78
|
-
queuePosition: null,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
const claimOnApproval = input.claimOnApproval ?? true;
|
|
82
|
-
if (claimOnApproval) {
|
|
83
|
-
const claimed = await claimContract({
|
|
84
|
-
cwd: input.cwd,
|
|
85
|
-
contractId: input.contractId,
|
|
86
|
-
actor: "keiyaku",
|
|
87
|
-
nowMs: input.nowMs,
|
|
88
|
-
mergeDelivery: input.mergeDelivery,
|
|
89
|
-
afterMerge: input.afterMerge,
|
|
90
|
-
});
|
|
91
|
-
return {
|
|
92
|
-
contractId: input.contractId,
|
|
93
|
-
result: "approved",
|
|
94
|
-
summary: verdict.data.summary,
|
|
95
|
-
claimed,
|
|
96
|
-
queuePosition: null,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
// claimOnApproval false remains petitioned at target-local position 1.
|
|
100
|
-
const model = await readQueueReadModel(input.cwd);
|
|
101
|
-
const membership = queueMembership(model, input.contractId);
|
|
102
75
|
return {
|
|
103
76
|
contractId: input.contractId,
|
|
104
|
-
result:
|
|
77
|
+
result: verdict.data.result,
|
|
105
78
|
summary: verdict.data.summary,
|
|
106
|
-
queuePosition: membership?.position ?? 1,
|
|
107
79
|
};
|
|
108
80
|
}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import { loadKeiyakuSettings } from "../../config/settings/loader.js";
|
|
2
2
|
import { observeGitRepository } from "../../git/branches.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { deriveQueueReadModel, queueMembership, } from "../queue.js";
|
|
3
|
+
import { readProjectionStatusBoard } from "../projection/index.js";
|
|
4
|
+
import { deriveQueueReadModel, queueMembership, } from "../settlement/index.js";
|
|
6
5
|
import { findOpenArc, getMaxArc, receiptsAfterFence } from "../seal.js";
|
|
7
|
-
import { readTaskBoard } from "../task.js";
|
|
8
|
-
import { openTaskStore } from "../task-git-store.js";
|
|
9
|
-
import { taskRepositoryFromStore } from "../task-store-repository.js";
|
|
6
|
+
import { openTaskStore, readTaskBoard, taskRepositoryFromStore, } from "../task/index.js";
|
|
10
7
|
import { deriveBootstrapDiagnostics, deriveContractState, hasCurrentPetitionVerdict, isTerminalState, } from "./lifecycle.js";
|
|
11
8
|
import { commissionTarget, evaluateBaseDrift, latestBase, resolveDefaultBranchFromSettings, } from "./drift.js";
|
|
12
9
|
import { computeClaimReconciliation, } from "./reconciliation.js";
|
|
10
|
+
import { readStatusLedgers } from "./ledger-batch.js";
|
|
13
11
|
function compareTaskStatusRows(left, right) {
|
|
14
12
|
if (left.pri !== right.pri)
|
|
15
13
|
return left.pri - right.pri;
|
|
@@ -32,7 +30,15 @@ async function readTaskStatusSummary(cwd) {
|
|
|
32
30
|
const blocked = eligible.filter((task) => task.state === "open" && task.blocked).length;
|
|
33
31
|
if (board.tasks.length === 0 && board.diseases.length === 0)
|
|
34
32
|
return undefined;
|
|
35
|
-
return {
|
|
33
|
+
return {
|
|
34
|
+
total: board.tasks.length,
|
|
35
|
+
inProgress,
|
|
36
|
+
ready,
|
|
37
|
+
blocked,
|
|
38
|
+
omitted: inProgress + ready - topTasks.length,
|
|
39
|
+
topTasks,
|
|
40
|
+
diseases: board.diseases,
|
|
41
|
+
};
|
|
36
42
|
}
|
|
37
43
|
catch (error) {
|
|
38
44
|
return {
|
|
@@ -40,6 +46,7 @@ async function readTaskStatusSummary(cwd) {
|
|
|
40
46
|
inProgress: 0,
|
|
41
47
|
ready: 0,
|
|
42
48
|
blocked: 0,
|
|
49
|
+
omitted: 0,
|
|
43
50
|
topTasks: [],
|
|
44
51
|
diseases: [],
|
|
45
52
|
diagnostic: error instanceof Error ? error.message : String(error),
|
|
@@ -148,7 +155,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
148
155
|
if (repository.capability !== "available" || repository.coordinate !== "repository") {
|
|
149
156
|
return {
|
|
150
157
|
contracts: [],
|
|
151
|
-
projections: readProjectionStatusBoard(cwd, now, { showAll: opts?.showAllProjections }),
|
|
158
|
+
projections: await readProjectionStatusBoard(cwd, now, { showAll: opts?.showAllProjections }),
|
|
152
159
|
queueLength: 0,
|
|
153
160
|
diseases: loadedSettings.diseases,
|
|
154
161
|
claimReconciliation: null,
|
|
@@ -165,22 +172,14 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
165
172
|
catch {
|
|
166
173
|
defaultBranch = null;
|
|
167
174
|
}
|
|
168
|
-
const contractIds = await listContractIds(cwd);
|
|
169
175
|
const terminalById = new Map();
|
|
170
|
-
const ledgers =
|
|
176
|
+
const ledgers = await readStatusLedgers(cwd);
|
|
171
177
|
const readableLedgers = [];
|
|
172
|
-
for (const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
readableLedgers.push(ledger);
|
|
178
|
-
terminalById.set(id, isTerminalState(deriveContractState(ledger.entries)));
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
catch (error) {
|
|
182
|
-
ledgers.push({ id, error: error instanceof Error ? error : new Error(String(error)) });
|
|
183
|
-
}
|
|
178
|
+
for (const ledger of ledgers) {
|
|
179
|
+
if ("error" in ledger)
|
|
180
|
+
continue;
|
|
181
|
+
readableLedgers.push(ledger);
|
|
182
|
+
terminalById.set(ledger.contractId, isTerminalState(deriveContractState(ledger.entries)));
|
|
184
183
|
}
|
|
185
184
|
const queueModel = deriveQueueReadModel(readableLedgers);
|
|
186
185
|
const boardQueueLength = queueModel.targetQueues.reduce((sum, queue) => sum + queue.ordered.length, 0);
|
|
@@ -194,6 +193,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
194
193
|
contracts.push({
|
|
195
194
|
id: item.id,
|
|
196
195
|
slug: contractSlugFromId(item.id),
|
|
196
|
+
title: contractSlugFromId(item.id),
|
|
197
197
|
state: { state: "corrupt", at: 0, reason: item.error.message },
|
|
198
198
|
queueHeadStalled: false,
|
|
199
199
|
arcs: 0,
|
|
@@ -245,6 +245,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
245
245
|
contracts.push({
|
|
246
246
|
id: item.contractId,
|
|
247
247
|
slug: contractSlugFromId(item.contractId),
|
|
248
|
+
title: bind?.data.name ?? contractSlugFromId(item.contractId),
|
|
248
249
|
state,
|
|
249
250
|
queuePosition,
|
|
250
251
|
queueHeadStalled: isQueueHeadStall({
|
|
@@ -277,7 +278,7 @@ export async function readKanshiBoard(cwd, now, opts) {
|
|
|
277
278
|
const claimReconciliation = await computeClaimReconciliation(cwd, defaultBranch);
|
|
278
279
|
return {
|
|
279
280
|
contracts: filteredContracts,
|
|
280
|
-
projections: readProjectionStatusBoard(cwd, now, { showAll: opts?.showAllProjections }),
|
|
281
|
+
projections: await readProjectionStatusBoard(cwd, now, { showAll: opts?.showAllProjections }),
|
|
281
282
|
queueLength,
|
|
282
283
|
defaultBranch: defaultBranch?.branch,
|
|
283
284
|
defaultHead: defaultBranch?.head,
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { wrapGitError, runGitProcess } from "../../git/core.js";
|
|
2
|
+
import { GitStreamingBatchFramingError, GitStreamingBatchResponseEndedError, openGitStreamingBatch, } from "../../git/streaming-batch.js";
|
|
3
|
+
import { parseLedgerEntryCommitMessage } from "../entry.js";
|
|
4
|
+
import { ACTIVE_LEDGER_REF_PREFIX, } from "../ledger.js";
|
|
5
|
+
const MAX_LEDGER_COMMIT_BYTES = 1024 * 1024;
|
|
6
|
+
async function runStatusGit(cwd, args) {
|
|
7
|
+
const result = await runGitProcess(cwd, args);
|
|
8
|
+
if (result.error || result.status !== 0) {
|
|
9
|
+
throw wrapGitError(args.join(" "), {
|
|
10
|
+
message: result.error?.message
|
|
11
|
+
?? `git exited with status ${result.status ?? "unknown"}`,
|
|
12
|
+
stderr: result.stderr,
|
|
13
|
+
stdout: result.stdout,
|
|
14
|
+
}, cwd);
|
|
15
|
+
}
|
|
16
|
+
return Buffer.from(result.stdout, "utf8");
|
|
17
|
+
}
|
|
18
|
+
async function queryBatchObject(batch, expression) {
|
|
19
|
+
const record = await batch.request(expression, {
|
|
20
|
+
maxContentBytes: MAX_LEDGER_COMMIT_BYTES,
|
|
21
|
+
});
|
|
22
|
+
if (record.kind === "missing" || record.kind === "ambiguous") {
|
|
23
|
+
throw new Error(`[git cat-file ${expression}] object is ${record.kind === "missing" ? "missing" : "ambiguous"}`);
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
oid: record.record.oid,
|
|
27
|
+
type: record.record.type,
|
|
28
|
+
content: record.record.content,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function parseCommitObject(object) {
|
|
32
|
+
if (object.type !== "commit") {
|
|
33
|
+
throw new Error(`git cat-file expected commit ${object.oid}, received ${object.type}`);
|
|
34
|
+
}
|
|
35
|
+
const content = object.content.toString("utf8");
|
|
36
|
+
const messageStart = content.indexOf("\n\n");
|
|
37
|
+
if (messageStart < 0)
|
|
38
|
+
throw new Error(`git commit ${object.oid} has no message separator`);
|
|
39
|
+
const parents = [];
|
|
40
|
+
for (const line of content.slice(0, messageStart).split("\n")) {
|
|
41
|
+
if (!line.startsWith("parent "))
|
|
42
|
+
continue;
|
|
43
|
+
const parent = line.slice("parent ".length);
|
|
44
|
+
if (!/^[0-9a-f]{40,64}$/.test(parent)) {
|
|
45
|
+
throw new Error(`git commit ${object.oid} has an invalid parent header`);
|
|
46
|
+
}
|
|
47
|
+
parents.push(parent);
|
|
48
|
+
}
|
|
49
|
+
return { oid: object.oid, parents, message: content.slice(messageStart + 2) };
|
|
50
|
+
}
|
|
51
|
+
function parseLedgerRefs(output) {
|
|
52
|
+
return output
|
|
53
|
+
.toString("utf8")
|
|
54
|
+
.split(/\r?\n/)
|
|
55
|
+
.filter((ref) => ref.startsWith(ACTIVE_LEDGER_REF_PREFIX))
|
|
56
|
+
.map((ref) => ({ contractId: ref.slice(ACTIVE_LEDGER_REF_PREFIX.length), ref }));
|
|
57
|
+
}
|
|
58
|
+
async function readLedgerFromBatch(batch, ref, commits) {
|
|
59
|
+
const headObject = await queryBatchObject(batch, `${ref.ref}^{commit}`);
|
|
60
|
+
const head = parseCommitObject(headObject);
|
|
61
|
+
commits.set(head.oid, Promise.resolve(head));
|
|
62
|
+
const ordered = [];
|
|
63
|
+
const visited = new Set();
|
|
64
|
+
const visiting = new Set();
|
|
65
|
+
const visit = async (oid) => {
|
|
66
|
+
if (visited.has(oid))
|
|
67
|
+
return;
|
|
68
|
+
if (visiting.has(oid))
|
|
69
|
+
throw new Error(`git ledger ancestry contains a cycle at ${oid}`);
|
|
70
|
+
visiting.add(oid);
|
|
71
|
+
let pending = commits.get(oid);
|
|
72
|
+
if (!pending) {
|
|
73
|
+
pending = queryBatchObject(batch, oid).then(parseCommitObject);
|
|
74
|
+
commits.set(oid, pending);
|
|
75
|
+
}
|
|
76
|
+
const commit = await pending;
|
|
77
|
+
for (const parent of commit.parents)
|
|
78
|
+
await visit(parent);
|
|
79
|
+
visiting.delete(oid);
|
|
80
|
+
visited.add(oid);
|
|
81
|
+
ordered.push(commit);
|
|
82
|
+
};
|
|
83
|
+
await visit(head.oid);
|
|
84
|
+
return {
|
|
85
|
+
contractId: ref.contractId,
|
|
86
|
+
ref: ref.ref,
|
|
87
|
+
head: head.oid,
|
|
88
|
+
entries: ordered.map((commit) => parseLedgerEntryCommitMessage(commit.message)),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Read the aggregate status ledger snapshot with at most two Git processes:
|
|
93
|
+
* ref-name discovery and one framed, streaming object session.
|
|
94
|
+
*/
|
|
95
|
+
export async function readStatusLedgers(cwd) {
|
|
96
|
+
const refOutput = await runStatusGit(cwd, [
|
|
97
|
+
"for-each-ref",
|
|
98
|
+
"--sort=refname",
|
|
99
|
+
"--format=%(refname)",
|
|
100
|
+
ACTIVE_LEDGER_REF_PREFIX,
|
|
101
|
+
]);
|
|
102
|
+
const refs = parseLedgerRefs(refOutput);
|
|
103
|
+
if (refs.length === 0)
|
|
104
|
+
return [];
|
|
105
|
+
const batch = openGitStreamingBatch(cwd);
|
|
106
|
+
const commits = new Map();
|
|
107
|
+
const results = [];
|
|
108
|
+
let readError;
|
|
109
|
+
try {
|
|
110
|
+
for (let index = 0; index < refs.length; index += 1) {
|
|
111
|
+
const ref = refs[index];
|
|
112
|
+
try {
|
|
113
|
+
results.push(await readLedgerFromBatch(batch, ref, commits));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
const diagnostic = error instanceof Error ? error : new Error(String(error));
|
|
117
|
+
results.push({ id: ref.contractId, error: diagnostic });
|
|
118
|
+
// Framing and mid-frame EOF both destroy the batch channel; isolate remaining refs.
|
|
119
|
+
if (error instanceof GitStreamingBatchFramingError
|
|
120
|
+
|| error instanceof GitStreamingBatchResponseEndedError) {
|
|
121
|
+
const isolationReason = error instanceof GitStreamingBatchResponseEndedError
|
|
122
|
+
? "response ended"
|
|
123
|
+
: "malformed frame";
|
|
124
|
+
for (const pending of refs.slice(index + 1)) {
|
|
125
|
+
results.push({
|
|
126
|
+
id: pending.contractId,
|
|
127
|
+
error: new Error(`git cat-file batch terminated after ${isolationReason}: ${diagnostic.message}`),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
readError = error;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const close = await batch.close();
|
|
140
|
+
if (!close.aborted && (close.timedOut || close.signal || close.code !== 0)) {
|
|
141
|
+
throw wrapGitError("cat-file --batch", {
|
|
142
|
+
message: close.timedOut
|
|
143
|
+
? "git timed out"
|
|
144
|
+
: close.signal
|
|
145
|
+
? `git exited from signal ${close.signal}`
|
|
146
|
+
: `git exited with status ${close.code ?? "unknown"}`,
|
|
147
|
+
stderr: close.stderr.toString("utf8"),
|
|
148
|
+
}, cwd);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
if (!readError)
|
|
153
|
+
readError = error;
|
|
154
|
+
}
|
|
155
|
+
if (readError)
|
|
156
|
+
throw readError;
|
|
157
|
+
return results;
|
|
158
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { createGit } from "../../git/core.js";
|
|
3
|
+
import { createGit, parseRevListOutput, wrapGitError } from "../../git/core.js";
|
|
4
4
|
import { stableRepoRoot } from "../worktree-path.js";
|
|
5
5
|
function isClaimReceipt(value) {
|
|
6
6
|
if (!value || typeof value !== "object")
|
|
@@ -51,7 +51,13 @@ export async function computeClaimReconciliation(cwd, defaultBranch) {
|
|
|
51
51
|
if (receiptLines.length === 0)
|
|
52
52
|
return null;
|
|
53
53
|
const git = createGit(cwd);
|
|
54
|
-
|
|
54
|
+
let firstParentHistory;
|
|
55
|
+
try {
|
|
56
|
+
firstParentHistory = parseRevListOutput(await git.raw(["rev-list", "--first-parent", defaultBranch.head]));
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw wrapGitError(`rev-list --first-parent ${defaultBranch.head}`, error, cwd);
|
|
60
|
+
}
|
|
55
61
|
const firstParentSet = new Set(firstParentHistory);
|
|
56
62
|
let baselineIndex = -1;
|
|
57
63
|
for (let index = receiptLines.length - 1; index >= 0; index -= 1) {
|
|
@@ -70,10 +76,10 @@ export async function computeClaimReconciliation(cwd, defaultBranch) {
|
|
|
70
76
|
return line.record?.kind === "baseline" ? [{ line: line.line, reason: "non-chain" }] : [];
|
|
71
77
|
});
|
|
72
78
|
// Only records after the latest valid baseline belong to this fence window.
|
|
79
|
+
// Intentional degrade: rev-list failure yields empty segments plus non-chain receipt issues.
|
|
73
80
|
let revList;
|
|
74
81
|
try {
|
|
75
|
-
|
|
76
|
-
revList = output.trim().split("\n").filter((h) => h.length > 0);
|
|
82
|
+
revList = parseRevListOutput(await git.raw(["rev-list", "--first-parent", "--reverse", `${baseline.head}..${defaultBranch.head}`]));
|
|
77
83
|
}
|
|
78
84
|
catch {
|
|
79
85
|
return {
|
|
@@ -8,6 +8,9 @@ const optionalString = (value, key) => value[key] === undefined || typeof value[
|
|
|
8
8
|
const nonNegativeSafeInteger = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
9
9
|
const safeIntegerOrNull = (value) => value === null || (typeof value === "number" && Number.isSafeInteger(value));
|
|
10
10
|
function isValidStoredWarning(warning) {
|
|
11
|
+
if (warning.reason === "rate-limit") {
|
|
12
|
+
return warning.state === "exhausted" && Object.keys(warning).length === 2;
|
|
13
|
+
}
|
|
11
14
|
if (warning.reason === "retry") {
|
|
12
15
|
return nonNegativeSafeInteger(warning.attempt)
|
|
13
16
|
&& nonNegativeSafeInteger(warning.maxRetries)
|
package/build/core/task/board.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
-
import {
|
|
3
|
-
const TASK_READ_ID = /^k-[0-9a-f]{7,12}$/;
|
|
2
|
+
import { isTaskId } from "./validation.js";
|
|
4
3
|
function compareText(left, right) {
|
|
5
4
|
return left < right ? -1 : left > right ? 1 : 0;
|
|
6
5
|
}
|
|
@@ -60,6 +59,30 @@ function cycleComponents(tasks) {
|
|
|
60
59
|
visit(id);
|
|
61
60
|
return cycles;
|
|
62
61
|
}
|
|
62
|
+
function parentCycleComponents(tasks) {
|
|
63
|
+
const cycles = [];
|
|
64
|
+
const visited = new Set();
|
|
65
|
+
for (const start of [...tasks.keys()].sort()) {
|
|
66
|
+
if (visited.has(start))
|
|
67
|
+
continue;
|
|
68
|
+
const path = [];
|
|
69
|
+
const positions = new Map();
|
|
70
|
+
let current = start;
|
|
71
|
+
while (current !== null && tasks.has(current) && !visited.has(current)) {
|
|
72
|
+
const prior = positions.get(current);
|
|
73
|
+
if (prior !== undefined) {
|
|
74
|
+
cycles.push(new Set(path.slice(prior)));
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
positions.set(current, path.length);
|
|
78
|
+
path.push(current);
|
|
79
|
+
current = tasks.get(current).parent;
|
|
80
|
+
}
|
|
81
|
+
for (const id of path)
|
|
82
|
+
visited.add(id);
|
|
83
|
+
}
|
|
84
|
+
return cycles;
|
|
85
|
+
}
|
|
63
86
|
/** Derive the complete storage-neutral board from domain records. */
|
|
64
87
|
export function buildTaskBoardFromDocuments(documents) {
|
|
65
88
|
const diseases = [];
|
|
@@ -91,6 +114,17 @@ export function buildTaskBoardFromDocuments(documents) {
|
|
|
91
114
|
candidates.delete(id);
|
|
92
115
|
}
|
|
93
116
|
}
|
|
117
|
+
for (const component of parentCycleComponents(candidates)) {
|
|
118
|
+
const relatedIds = [...component].sort();
|
|
119
|
+
for (const id of relatedIds) {
|
|
120
|
+
diseases.push({
|
|
121
|
+
code: "parent_cycle",
|
|
122
|
+
message: `task ${id} participates in a parent cycle`,
|
|
123
|
+
id,
|
|
124
|
+
relatedIds,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
94
128
|
let changed = true;
|
|
95
129
|
while (changed) {
|
|
96
130
|
changed = false;
|
|
@@ -148,9 +182,11 @@ export function resolveTaskReadId(board, input) {
|
|
|
148
182
|
return resolveTaskId(board, input);
|
|
149
183
|
}
|
|
150
184
|
export function resolveTaskId(board, input) {
|
|
151
|
-
if (!
|
|
185
|
+
if (!isTaskId(input)) {
|
|
152
186
|
throw new FlowError("INVALID_TARGET", `invalid task id '${input}'`);
|
|
153
187
|
}
|
|
188
|
+
if (board.byId.has(input))
|
|
189
|
+
return input;
|
|
154
190
|
const matches = board.tasks
|
|
155
191
|
.map((task) => task.id)
|
|
156
192
|
.filter((id) => id.startsWith(input))
|
|
@@ -163,7 +199,7 @@ export function resolveTaskId(board, input) {
|
|
|
163
199
|
return matches[0];
|
|
164
200
|
}
|
|
165
201
|
export function requireCanonicalTaskId(input) {
|
|
166
|
-
if (!
|
|
202
|
+
if (!isTaskId(input)) {
|
|
167
203
|
throw new FlowError("INVALID_TARGET", "task mutations require a canonical full task id");
|
|
168
204
|
}
|
|
169
205
|
return input;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
+
import { IdentifierSlugError, normalizeIdentifierSlug, SUFFIXABLE_IDENTIFIER_SLUG_MAX_UTF8_BYTES, } from "../identifier-slug.js";
|
|
2
3
|
import { requireCanonicalTaskId, requireHealthy, resolveTaskId, } from "./board.js";
|
|
3
4
|
import { dateTimestamp, invalid, nonblank, } from "./validation.js";
|
|
4
5
|
export async function readTaskBoard(repository) {
|
|
@@ -20,9 +21,10 @@ function documentFromView(view) {
|
|
|
20
21
|
body: view.body,
|
|
21
22
|
};
|
|
22
23
|
}
|
|
23
|
-
function replaceDocument(document) {
|
|
24
|
+
function replaceDocument(document, subject) {
|
|
24
25
|
return {
|
|
25
26
|
replacements: [document],
|
|
27
|
+
subject,
|
|
26
28
|
select(resulting) {
|
|
27
29
|
const value = resulting.byId.get(document.id);
|
|
28
30
|
if (!value)
|
|
@@ -43,6 +45,16 @@ function resolveMutationIds(board, ids) {
|
|
|
43
45
|
export async function createTask(repository, input, deps) {
|
|
44
46
|
nonblank("title", input.title);
|
|
45
47
|
nonblank("creator", input.creator);
|
|
48
|
+
let baseId;
|
|
49
|
+
try {
|
|
50
|
+
baseId = normalizeIdentifierSlug(input.title, SUFFIXABLE_IDENTIFIER_SLUG_MAX_UTF8_BYTES);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
if (error instanceof IdentifierSlugError) {
|
|
54
|
+
throw new FlowError("INVALID_TARGET", `task title ${error.message}`, { cause: error });
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
46
58
|
const pri = input.pri ?? 2;
|
|
47
59
|
if (!Number.isInteger(pri) || pri < 0 || pri > 3)
|
|
48
60
|
invalid("task priority must be an integer from 0 through 3");
|
|
@@ -55,19 +67,13 @@ export async function createTask(repository, input, deps) {
|
|
|
55
67
|
const from = resolveMutationIds(board, input.from ?? []);
|
|
56
68
|
if (new Set(from).size !== from.length)
|
|
57
69
|
invalid("task from edges must be unique");
|
|
58
|
-
let id;
|
|
59
|
-
for (let
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw new FlowError("INTERNAL_STATE", "randomBytes(6) must return exactly 6 bytes");
|
|
63
|
-
const candidate = `k-${Buffer.from(bytes).toString("hex")}`;
|
|
64
|
-
if (!board.byId.has(candidate)) {
|
|
65
|
-
id = candidate;
|
|
66
|
-
break;
|
|
70
|
+
let id = baseId;
|
|
71
|
+
for (let ordinal = 2; board.byId.has(id); ordinal += 1) {
|
|
72
|
+
if (!Number.isSafeInteger(ordinal)) {
|
|
73
|
+
throw new FlowError("INTERNAL_STATE", `task id collision ordinal exceeded the safe integer range for ${baseId}`);
|
|
67
74
|
}
|
|
75
|
+
id = `${baseId}-${ordinal}`;
|
|
68
76
|
}
|
|
69
|
-
if (!id)
|
|
70
|
-
throw new FlowError("CONCURRENT_MODIFICATION", "could not allocate a unique task id after 32 attempts");
|
|
71
77
|
const document = {
|
|
72
78
|
id,
|
|
73
79
|
title: input.title,
|
|
@@ -80,7 +86,7 @@ export async function createTask(repository, input, deps) {
|
|
|
80
86
|
creator: input.creator,
|
|
81
87
|
body: input.body ?? "",
|
|
82
88
|
};
|
|
83
|
-
return replaceDocument(document);
|
|
89
|
+
return replaceDocument(document, `Add task ${id}`);
|
|
84
90
|
});
|
|
85
91
|
}
|
|
86
92
|
export async function updateTask(repository, fullIdValue, patch) {
|
|
@@ -112,10 +118,10 @@ export async function updateTask(repository, fullIdValue, patch) {
|
|
|
112
118
|
if (JSON.stringify(document) === JSON.stringify(documentFromView(current))) {
|
|
113
119
|
throw new FlowError("EMPTY_PARAM", "task update requires at least one change");
|
|
114
120
|
}
|
|
115
|
-
return replaceDocument(document);
|
|
121
|
+
return replaceDocument(document, `Update task ${id}`);
|
|
116
122
|
});
|
|
117
123
|
}
|
|
118
|
-
async function transition(repository, fullIdValue, apply) {
|
|
124
|
+
async function transition(repository, fullIdValue, apply, subject) {
|
|
119
125
|
return repository.mutate((board) => {
|
|
120
126
|
requireHealthy(board);
|
|
121
127
|
const id = fullIdValue === undefined
|
|
@@ -123,7 +129,7 @@ async function transition(repository, fullIdValue, apply) {
|
|
|
123
129
|
: resolveTaskId(board, fullIdValue);
|
|
124
130
|
const document = documentFromView(requireExisting(board, id));
|
|
125
131
|
apply(document);
|
|
126
|
-
return replaceDocument(document);
|
|
132
|
+
return replaceDocument(document, subject(id));
|
|
127
133
|
});
|
|
128
134
|
}
|
|
129
135
|
function rejectBound(document, action = "state") {
|
|
@@ -141,7 +147,7 @@ export async function startTask(repository, fullId, now) {
|
|
|
141
147
|
invalid(`task ${document.id} is ${document.state}, not open`);
|
|
142
148
|
document.state = "in_progress";
|
|
143
149
|
document.startedAt = dateTimestamp("startedAt", now);
|
|
144
|
-
});
|
|
150
|
+
}, (id) => `Start task ${id}`);
|
|
145
151
|
}
|
|
146
152
|
export async function stopTask(repository, fullId) {
|
|
147
153
|
return transition(repository, fullId, (document) => {
|
|
@@ -150,7 +156,7 @@ export async function stopTask(repository, fullId) {
|
|
|
150
156
|
invalid(`task ${document.id} is ${document.state}, not in_progress`);
|
|
151
157
|
document.state = "open";
|
|
152
158
|
delete document.startedAt;
|
|
153
|
-
});
|
|
159
|
+
}, (id) => `Stop task ${id}`);
|
|
154
160
|
}
|
|
155
161
|
export async function doneTask(repository, fullId) {
|
|
156
162
|
return transition(repository, fullId, (document) => {
|
|
@@ -160,7 +166,7 @@ export async function doneTask(repository, fullId) {
|
|
|
160
166
|
}
|
|
161
167
|
document.state = "done";
|
|
162
168
|
delete document.startedAt;
|
|
163
|
-
});
|
|
169
|
+
}, (id) => `Done task ${id}`);
|
|
164
170
|
}
|
|
165
171
|
export async function dropTask(repository, fullId) {
|
|
166
172
|
return transition(repository, fullId, (document) => {
|
|
@@ -170,7 +176,7 @@ export async function dropTask(repository, fullId) {
|
|
|
170
176
|
}
|
|
171
177
|
document.state = "drop";
|
|
172
178
|
delete document.startedAt;
|
|
173
|
-
});
|
|
179
|
+
}, (id) => `Drop task ${id}`);
|
|
174
180
|
}
|
|
175
181
|
export function selectSoleInProgress(board) {
|
|
176
182
|
const candidates = board.tasks.filter((task) => task.state === "in_progress");
|
|
@@ -205,7 +211,10 @@ export async function rollbackOrphanTaskPointers(repository, contractIds) {
|
|
|
205
211
|
});
|
|
206
212
|
if (replacements.length === 0)
|
|
207
213
|
throw new FlowError("CONCURRENT_MODIFICATION", "task pointers changed while doctor was reconciling them");
|
|
208
|
-
|
|
214
|
+
const subject = replacements.length === 1
|
|
215
|
+
? `Clear orphan contract pointer from task ${replacements[0].id}`
|
|
216
|
+
: `Clear orphan contract pointers from ${replacements.length} tasks`;
|
|
217
|
+
return { replacements, subject, select: () => undefined };
|
|
209
218
|
});
|
|
210
219
|
return orphans;
|
|
211
220
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public surface for the task package.
|
|
3
|
+
* Only symbols required by current external consumers are re-exported.
|
|
4
|
+
* Package-internal modules must import each other directly, not through this file.
|
|
5
|
+
*/
|
|
6
|
+
export { reconcileTaskForfeit, settleTaskBoardForBind, settleTaskBoardForLanding, } from "./task-contract.js";
|
|
7
|
+
export { resolveTaskCreator } from "./task-git-actor.js";
|
|
8
|
+
export { openTaskCommandRepository, readTaskDoctor, taskCommandContractId, } from "./task-git-runtime.js";
|
|
9
|
+
export { openTaskStore } from "./task-git-store.js";
|
|
10
|
+
export { taskRepositoryFromStore } from "./task-store-repository.js";
|
|
11
|
+
export { isTaskId } from "./validation.js";
|
|
12
|
+
export { buildTaskTree, createTask, doneTask, dropTask, parseTaskDocument, readTaskBoard, resolveTaskReadId, serializeTaskDocument, startTask, stopTask, updateTask, } from "./task.js";
|