@astrosheep/keiyaku 2.9.3 → 2.9.5
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 +14 -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 +26 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +68 -5
- package/build/agents/harness/projection.js +179 -124
- 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 +82 -53
- package/build/agents/providers/codex-app-server/events.js +90 -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/events.js +4 -3
- 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 +10 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +8 -2
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +44 -8
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +5 -8
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +6 -5
- package/build/cli/commands/metadata.js +59 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +8 -3
- 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/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +7 -15
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +12 -8
- package/build/cli/commands/task/ls/meta.js +3 -3
- 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/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +6 -11
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +37 -6
- package/build/cli/help.js +7 -14
- package/build/cli/index.js +112 -154
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +33 -7
- package/build/cli/parse-metadata.js +3 -9
- package/build/cli/parse-selectors.js +2 -1
- package/build/cli/parse.js +35 -5
- package/build/cli/projection-address.js +12 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/audit.js +121 -0
- 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 +58 -13
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +15 -6
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +56 -23
- package/build/cli/render/success-response.js +78 -0
- package/build/cli/render/task.js +66 -57
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +63 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +68 -38
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +3 -0
- 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 +61 -18
- package/build/core/arc.js +33 -73
- package/build/core/audit.js +650 -0
- 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 +22 -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 +22 -6
- package/build/core/draft.js +139 -19
- package/build/core/entry.js +3 -4
- 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/lex.js +2 -1
- 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 +41 -52
- package/build/core/projection/generation/model.js +63 -2
- 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} +36 -53
- 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} +9 -7
- 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} +19 -3
- package/build/core/projection/generation/store.js +3 -3
- package/build/core/projection/generation/transitions.js +19 -3
- 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} +13 -13
- 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} +37 -78
- 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} +16 -2
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
- package/build/core/projection/projection-terminal-failure.js +106 -0
- package/build/core/projection/projection-wait.js +275 -0
- package/build/core/projection/projection-wake.js +227 -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 +448 -102
- package/build/core/scope.js +272 -68
- package/build/core/seal.js +165 -40
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
- 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} +24 -49
- 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} +2 -2
- package/build/core/{petition.js → settlement/petition.js} +21 -12
- 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 +288 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +62 -41
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +6 -2
- package/build/core/task/board.js +41 -4
- package/build/core/task/commands.js +45 -28
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +12 -0
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +265 -74
- package/build/core/task/settlement-policy.js +67 -29
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +444 -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} +90 -19
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -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 +7 -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 +83 -39
- 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/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- 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 +9 -9
- package/build/keiyaku.js +2 -36
- package/build/telemetry/logger.js +4 -2
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +5 -4
- package/skills/keiyaku-akuma/SKILL.md +25 -11
- package/skills/keiyaku-task/SKILL.md +17 -8
- package/skills/keiyaku-workflow/SKILL.md +58 -9
- 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,16 +1,21 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
|
-
import { spawnSync } from "node:child_process";
|
|
3
2
|
import * as fs from "node:fs";
|
|
4
3
|
import * as path from "node:path";
|
|
5
4
|
import { DatabaseSync } from "node:sqlite";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
5
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6
|
+
import { FlowError } from "../../flow-error.js";
|
|
7
|
+
import { syncDirectorySync } from "../../fs/durability.js";
|
|
8
|
+
import { normalizeFilesystemCoordinate } from "../../fs/path-coordinate.js";
|
|
9
|
+
import { isGitExecutableUnavailable, NOT_GIT_REPOSITORY_PATTERNS, runGitProcess } from "../../git/core.js";
|
|
10
|
+
import { gitCommonRootPath, normalizeGitPath } from "../../git/path-coordinate.js";
|
|
11
|
+
import { inspectCurrentBranch, publishTaskMutationCommit } from "./settlement-git.js";
|
|
12
|
+
import { isTaskId } from "./validation.js";
|
|
11
13
|
const SQLITE_BUSY = 5;
|
|
12
14
|
const LOCK_FILE = "task-lock.sqlite";
|
|
13
15
|
const GIT_LOCK_FILE = "keiyaku-task-lock.sqlite";
|
|
16
|
+
export const TASK_LOCK_ADMISSION_TIMEOUT_MS = 4_000;
|
|
17
|
+
export const TASK_LOCK_ADMISSION_INITIAL_DELAY_MS = 10;
|
|
18
|
+
export const TASK_LOCK_ADMISSION_MAX_DELAY_MS = 100;
|
|
14
19
|
export class TaskLockHeldError extends Error {
|
|
15
20
|
path;
|
|
16
21
|
code = "TASK_LOCK_HELD";
|
|
@@ -20,6 +25,16 @@ export class TaskLockHeldError extends Error {
|
|
|
20
25
|
this.name = "TaskLockHeldError";
|
|
21
26
|
}
|
|
22
27
|
}
|
|
28
|
+
export class TaskLockAdmissionTimeoutError extends FlowError {
|
|
29
|
+
path;
|
|
30
|
+
timeoutMs;
|
|
31
|
+
constructor(path, timeoutMs, options) {
|
|
32
|
+
super("TASK_LOCK_ADMISSION_TIMEOUT", `task lock admission timed out after ${timeoutMs}ms: ${path}`, { cause: options?.cause });
|
|
33
|
+
this.path = path;
|
|
34
|
+
this.timeoutMs = timeoutMs;
|
|
35
|
+
this.name = "TaskLockAdmissionTimeoutError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
23
38
|
function errorText(error) {
|
|
24
39
|
return error instanceof Error ? error.message : String(error);
|
|
25
40
|
}
|
|
@@ -29,17 +44,11 @@ function isSqliteBusy(error) {
|
|
|
29
44
|
&& "errcode" in error
|
|
30
45
|
&& error.errcode === SQLITE_BUSY;
|
|
31
46
|
}
|
|
32
|
-
function defaultRunGit(cwd, args, input) {
|
|
33
|
-
return
|
|
34
|
-
cwd,
|
|
35
|
-
input,
|
|
36
|
-
encoding: "utf8",
|
|
37
|
-
env: { ...process.env, GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" },
|
|
38
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
39
|
-
});
|
|
47
|
+
async function defaultRunGit(cwd, args, input) {
|
|
48
|
+
return await runGitProcess(cwd, args, { input });
|
|
40
49
|
}
|
|
41
50
|
function nearestDirectoryBoard(cwd) {
|
|
42
|
-
const original = path.resolve(cwd);
|
|
51
|
+
const original = path.resolve(normalizeFilesystemCoordinate(cwd));
|
|
43
52
|
let candidate = original;
|
|
44
53
|
while (true) {
|
|
45
54
|
if (lstatIfPresent(path.join(candidate, ".keiyaku")))
|
|
@@ -54,7 +63,8 @@ export function taskBoardRootFromGitDir(rawGitDir, platform = process.platform)
|
|
|
54
63
|
return gitCommonRootPath(rawGitDir, platform);
|
|
55
64
|
}
|
|
56
65
|
export async function locateTaskBoard(cwd, runGitProbe = defaultRunGit) {
|
|
57
|
-
|
|
66
|
+
cwd = normalizeFilesystemCoordinate(cwd);
|
|
67
|
+
const probe = await runGitProbe(cwd, ["rev-parse", "--is-inside-work-tree", "--is-bare-repository"]);
|
|
58
68
|
if (probe.error && !isGitExecutableUnavailable(probe.error)) {
|
|
59
69
|
throw new FlowError("INTERNAL_STATE", `cannot inspect task repository: ${probe.error.message}`, { cause: probe.error });
|
|
60
70
|
}
|
|
@@ -72,7 +82,7 @@ export async function locateTaskBoard(cwd, runGitProbe = defaultRunGit) {
|
|
|
72
82
|
if (bare === "true" || insideWorktree !== "true") {
|
|
73
83
|
throw new FlowError("NOT_GIT_REPO", "bare repositories are not supported for task storage");
|
|
74
84
|
}
|
|
75
|
-
const facts = runGitProbe(cwd, ["rev-parse", "--path-format=absolute", "--show-toplevel", "--git-common-dir"]);
|
|
85
|
+
const facts = await runGitProbe(cwd, ["rev-parse", "--path-format=absolute", "--show-toplevel", "--git-common-dir"]);
|
|
76
86
|
if (facts.error) {
|
|
77
87
|
throw new FlowError("INTERNAL_STATE", `git rev-parse failed: ${facts.error.message}`, { cause: facts.error });
|
|
78
88
|
}
|
|
@@ -139,6 +149,31 @@ function acquireTaskLock(lockPath) {
|
|
|
139
149
|
throw new FlowError("INTERNAL_STATE", `cannot acquire task lock: ${errorText(error)}`, { cause: error });
|
|
140
150
|
}
|
|
141
151
|
}
|
|
152
|
+
async function acquireTaskLockWithAdmission(lockPath, deps) {
|
|
153
|
+
const now = deps.now ?? Date.now;
|
|
154
|
+
const random = deps.random ?? Math.random;
|
|
155
|
+
const sleep = deps.sleep ?? ((milliseconds, signal) => (delay(milliseconds, undefined, signal ? { signal } : undefined)));
|
|
156
|
+
const deadline = now() + TASK_LOCK_ADMISSION_TIMEOUT_MS;
|
|
157
|
+
let delayCapMs = TASK_LOCK_ADMISSION_INITIAL_DELAY_MS;
|
|
158
|
+
for (;;) {
|
|
159
|
+
deps.signal?.throwIfAborted();
|
|
160
|
+
try {
|
|
161
|
+
return acquireTaskLock(lockPath);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
if (!(error instanceof TaskLockHeldError))
|
|
165
|
+
throw error;
|
|
166
|
+
const observedAt = now();
|
|
167
|
+
if (observedAt >= deadline) {
|
|
168
|
+
throw new TaskLockAdmissionTimeoutError(lockPath, TASK_LOCK_ADMISSION_TIMEOUT_MS, { cause: error });
|
|
169
|
+
}
|
|
170
|
+
const unit = Math.max(0, Math.min(1, random()));
|
|
171
|
+
const jitteredDelayMs = Math.ceil((delayCapMs / 2) + ((delayCapMs / 2) * unit));
|
|
172
|
+
await sleep(Math.min(jitteredDelayMs, deadline - observedAt), deps.signal);
|
|
173
|
+
delayCapMs = Math.min(TASK_LOCK_ADMISSION_MAX_DELAY_MS, delayCapMs * 2);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
142
177
|
export async function inspectTaskLock(cwd) {
|
|
143
178
|
const lockPath = taskLockPath(await locateTaskBoard(cwd));
|
|
144
179
|
if (!fs.existsSync(lockPath))
|
|
@@ -236,7 +271,7 @@ function validateWrites(writes) {
|
|
|
236
271
|
const targets = new Set();
|
|
237
272
|
for (const write of writes) {
|
|
238
273
|
const target = `${write.id}.md`;
|
|
239
|
-
if (!
|
|
274
|
+
if (!isTaskId(write.id)) {
|
|
240
275
|
throw new FlowError("INTERNAL_STATE", `invalid task mutation id: ${write.id}`);
|
|
241
276
|
}
|
|
242
277
|
if (targets.has(target))
|
|
@@ -321,9 +356,32 @@ export async function openTaskStore(cwd, deps = {}) {
|
|
|
321
356
|
},
|
|
322
357
|
async mutate(apply) {
|
|
323
358
|
return withLockHeldTaskBoard(cwd, async (transaction) => {
|
|
359
|
+
const previousSources = transaction.sources;
|
|
324
360
|
const plan = await apply(transaction.sources);
|
|
325
361
|
validatePlan(plan);
|
|
362
|
+
let subject;
|
|
363
|
+
if (transaction.location.mode === "git") {
|
|
364
|
+
subject = plan.subject?.trim();
|
|
365
|
+
if (!subject) {
|
|
366
|
+
throw new FlowError("INTERNAL_STATE", "git task mutation requires a micro-commit subject");
|
|
367
|
+
}
|
|
368
|
+
await inspectCurrentBranch(transaction.location.root);
|
|
369
|
+
}
|
|
326
370
|
await transaction.replace(plan.writes);
|
|
371
|
+
if (transaction.location.mode === "git") {
|
|
372
|
+
try {
|
|
373
|
+
await (deps.publishMutation ?? publishTaskMutationCommit)({
|
|
374
|
+
cwd: transaction.location.root,
|
|
375
|
+
gitDir: transaction.location.gitDir,
|
|
376
|
+
writes: plan.writes,
|
|
377
|
+
subject: subject,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
await transaction.restore(plan.writes, previousSources);
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
327
385
|
return plan.value;
|
|
328
386
|
}, deps, board);
|
|
329
387
|
},
|
|
@@ -333,7 +391,7 @@ export async function withLockHeldTaskBoard(cwd, apply, deps = {}, locatedBoard)
|
|
|
333
391
|
const board = locatedBoard ?? await locateTaskBoard(cwd, deps.runGit);
|
|
334
392
|
const directory = taskDirectory(board);
|
|
335
393
|
assertKeiyakuDirectory(board);
|
|
336
|
-
const database =
|
|
394
|
+
const database = await acquireTaskLockWithAdmission(taskLockPath(board), deps);
|
|
337
395
|
try {
|
|
338
396
|
let sources = await readTaskSources(directory);
|
|
339
397
|
const transaction = {
|
|
@@ -368,6 +426,19 @@ export async function withLockHeldTaskBoard(cwd, apply, deps = {}, locatedBoard)
|
|
|
368
426
|
}
|
|
369
427
|
sources = await readTaskSources(directory);
|
|
370
428
|
},
|
|
429
|
+
async restore(writes, previousSources) {
|
|
430
|
+
validateWrites(writes);
|
|
431
|
+
const currentSources = await readTaskSources(directory);
|
|
432
|
+
if (!sameSources(sources, currentSources)) {
|
|
433
|
+
throw new FlowError("CONCURRENT_MODIFICATION", "task sources changed while rolling back a failed publication");
|
|
434
|
+
}
|
|
435
|
+
const previousById = new Map(previousSources.map((source) => [path.basename(source.path, ".md"), source.text]));
|
|
436
|
+
restoreFiles(writes.map((write) => ({
|
|
437
|
+
path: path.join(directory, mutationTarget(write)),
|
|
438
|
+
text: previousById.get(write.id),
|
|
439
|
+
})), deps);
|
|
440
|
+
sources = await readTaskSources(directory);
|
|
441
|
+
},
|
|
371
442
|
};
|
|
372
443
|
return await apply(transaction);
|
|
373
444
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { requireHealthy } from "./
|
|
2
|
-
import { parseTaskDocument, serializeTaskDocument } from "./
|
|
3
|
-
import { buildTaskSourceBoard } from "./
|
|
4
|
-
function taskBoardFromSourceBoard(sourceBoard) {
|
|
1
|
+
import { requireHealthy } from "./board.js";
|
|
2
|
+
import { parseTaskDocument, serializeTaskDocument } from "./document.js";
|
|
3
|
+
import { buildTaskSourceBoard } from "./source-board.js";
|
|
4
|
+
export function taskBoardFromSourceBoard(sourceBoard) {
|
|
5
5
|
const tasks = sourceBoard.tasks.map((task) => ({
|
|
6
6
|
id: task.id,
|
|
7
7
|
title: task.title,
|
|
@@ -11,6 +11,7 @@ function taskBoardFromSourceBoard(sourceBoard) {
|
|
|
11
11
|
parent: task.parent,
|
|
12
12
|
from: [...task.from],
|
|
13
13
|
createdAt: task.createdAt,
|
|
14
|
+
...(task.updatedAt === undefined ? {} : { updatedAt: task.updatedAt }),
|
|
14
15
|
creator: task.creator,
|
|
15
16
|
...(task.startedAt === undefined ? {} : { startedAt: task.startedAt }),
|
|
16
17
|
...(task.contractId === undefined ? {} : { contractId: task.contractId }),
|
|
@@ -66,6 +67,7 @@ function mutationPlan(sources, mutation) {
|
|
|
66
67
|
return {
|
|
67
68
|
writes: prepared.writes,
|
|
68
69
|
value: mutation.select(prepared.board),
|
|
70
|
+
...(mutation.subject === undefined ? {} : { subject: mutation.subject }),
|
|
69
71
|
};
|
|
70
72
|
}
|
|
71
73
|
export function taskRepositoryFromStore(store) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FlowError } from "
|
|
1
|
+
import { FlowError } from "../../flow-error.js";
|
|
2
2
|
function documentFacts(task) {
|
|
3
3
|
return JSON.stringify({
|
|
4
4
|
id: task.id,
|
|
@@ -41,6 +41,7 @@ export function withTaskWorktreePolicy(repository, contractId) {
|
|
|
41
41
|
const mutation = await apply(before);
|
|
42
42
|
return {
|
|
43
43
|
replacements: mutation.replacements,
|
|
44
|
+
...(mutation.subject === undefined ? {} : { subject: mutation.subject }),
|
|
44
45
|
select(after) {
|
|
45
46
|
validateTaskWorktreeMutation(before, mutation.replacements, after, contractId);
|
|
46
47
|
return mutation.select(after);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { deriveTaskDisplay, parseTaskFilter, parseTaskSort, selectTaskList } from "./query.js";
|
|
2
|
+
export { advancedTaskUpdatedAt, taskUpdatedAt } from "./model.js";
|
|
3
|
+
export { parseTaskDocument, serializeTaskDocument, } from "./document.js";
|
|
4
|
+
export { resolveTaskReadId, } from "./board.js";
|
|
5
|
+
export { buildTaskBoard } from "./source-board.js";
|
|
6
|
+
export { buildTaskTree } from "./tree.js";
|
|
7
|
+
export { readTaskBoard, createTask, updateTask, startTask, stopTask, doneTask, dropTask, selectSoleInProgress, rollbackOrphanTaskPointers, } from "./commands.js";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
function compareText(left, right) {
|
|
2
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
3
|
+
}
|
|
4
|
+
/** Board task order is the deterministic order for every parent child list. */
|
|
5
|
+
function compareBoardOrder(left, right) {
|
|
6
|
+
const leftTerminal = left.state === "done" || left.state === "drop" ? 1 : 0;
|
|
7
|
+
const rightTerminal = right.state === "done" || right.state === "drop" ? 1 : 0;
|
|
8
|
+
return leftTerminal - rightTerminal
|
|
9
|
+
|| left.pri - right.pri
|
|
10
|
+
|| compareText(left.createdAt, right.createdAt)
|
|
11
|
+
|| compareText(left.id, right.id);
|
|
12
|
+
}
|
|
13
|
+
function diagnosticOrder(left, right) {
|
|
14
|
+
return compareText(left.code, right.code)
|
|
15
|
+
|| compareText(left.id ?? "", right.id ?? "")
|
|
16
|
+
|| compareText(left.message, right.message);
|
|
17
|
+
}
|
|
18
|
+
export function buildTaskTree(board, rootId) {
|
|
19
|
+
const childrenByParent = new Map();
|
|
20
|
+
for (const task of board.tasks) {
|
|
21
|
+
if (task.parent === null)
|
|
22
|
+
continue;
|
|
23
|
+
childrenByParent.set(task.parent, [...(childrenByParent.get(task.parent) ?? []), task]);
|
|
24
|
+
}
|
|
25
|
+
for (const children of childrenByParent.values())
|
|
26
|
+
children.sort(compareBoardOrder);
|
|
27
|
+
const visit = (parentId, ancestors) => (childrenByParent.get(parentId) ?? [])
|
|
28
|
+
.filter((child) => !ancestors.has(child.id))
|
|
29
|
+
.map((child) => ({
|
|
30
|
+
task: child,
|
|
31
|
+
children: visit(child.id, new Set([...ancestors, child.id])),
|
|
32
|
+
}));
|
|
33
|
+
return {
|
|
34
|
+
descendants: visit(rootId, new Set([rootId])),
|
|
35
|
+
diagnostics: [...board.diseases].sort(diagnosticOrder),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FlowError } from "../../flow-error.js";
|
|
2
|
-
|
|
2
|
+
import { isNormalizedIdentifierSlug } from "../identifier-slug.js";
|
|
3
3
|
export const TASK_STATES = new Set(["open", "in_progress", "done", "drop"]);
|
|
4
4
|
const CANONICAL_ISO_UTC_MS = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
5
5
|
export function invalid(message) {
|
|
@@ -13,10 +13,13 @@ export function nonblank(field, value) {
|
|
|
13
13
|
}
|
|
14
14
|
export function fullId(field, value) {
|
|
15
15
|
const id = nonblank(field, value);
|
|
16
|
-
if (!
|
|
16
|
+
if (!isTaskId(id))
|
|
17
17
|
invalid(`task field '${field}' must be a canonical full task id`);
|
|
18
18
|
return id;
|
|
19
19
|
}
|
|
20
|
+
export function isTaskId(value) {
|
|
21
|
+
return isNormalizedIdentifierSlug(value);
|
|
22
|
+
}
|
|
20
23
|
export function canonicalTimestamp(field, value) {
|
|
21
24
|
const timestamp = nonblank(field, value);
|
|
22
25
|
if (!CANONICAL_ISO_UTC_MS.test(timestamp)) {
|
|
@@ -21,6 +21,15 @@ const RESPONSE_HISTORY_SESSION_KEY = "session";
|
|
|
21
21
|
const RESPONSE_HISTORY_LAUNCH_SNAPSHOT_KEY = "launch_snapshot";
|
|
22
22
|
const RESPONSE_HISTORY_PROVENANCE_KEY = "provenance";
|
|
23
23
|
const REVIEW_HISTORY_FILE_RE = /^\d{8}-\d{9}_REVIEW_(\d+)\.md$/;
|
|
24
|
+
/** Artifact-owner rendering of seal receipt/diffstat facts into the durable Diff section. */
|
|
25
|
+
export function renderSealDiffSection(sealed, emptyLabel) {
|
|
26
|
+
if (!sealed)
|
|
27
|
+
return emptyLabel;
|
|
28
|
+
if (sealed.receipts.length === 0)
|
|
29
|
+
return "nothing sealed";
|
|
30
|
+
const count = sealed.receipts.length;
|
|
31
|
+
return `${count} receipt${count === 1 ? "" : "s"} · +${sealed.diffstat.insertions} −${sealed.diffstat.deletions}`;
|
|
32
|
+
}
|
|
24
33
|
export const RESPONSE_ARTIFACT_HEADINGS = {
|
|
25
34
|
call: "# Call",
|
|
26
35
|
bind: "# Bind",
|
|
@@ -100,9 +109,12 @@ function buildMarkdown(input, iso, provenance) {
|
|
|
100
109
|
return [...frontmatter, "# Call", "", "## Task", section(input.task), "", "## Context", section(input.context), "", "## Response", section(input.response), ""].join("\n");
|
|
101
110
|
if (input.tool === "review")
|
|
102
111
|
return [...frontmatter, "# Review", "", "## Prompt", section(input.prompt), "", "## Response", section(input.response), ""].join("\n");
|
|
103
|
-
if (input.tool === "arc")
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
if (input.tool === "arc") {
|
|
113
|
+
const diff = renderSealDiffSection(input.sealed, input.emptyDiffLabel);
|
|
114
|
+
return [...frontmatter, "# Arc", "", "## Objective", section(input.objective), "", "## Brief", section(input.brief), "", "## Ledger Commit", section(input.ledgerCommit), "", "## Summary", section(input.summary), "", "## Diff", section(diff), ""].join("\n");
|
|
115
|
+
}
|
|
116
|
+
const diff = renderSealDiffSection(input.sealed, input.emptyDiffLabel);
|
|
117
|
+
return [...frontmatter, "# Renew", "", "## Base", `${input.oldBase} -> ${input.newBase}`, "", "## Head", `${input.oldHead} -> ${input.newHead}`, "", "## Ledger Commit", section(input.ledgerCommit), "", "## Summary", section(input.summary), "", "## Diff", section(diff), ""].join("\n");
|
|
106
118
|
}
|
|
107
119
|
/** The sole response artifact writer. */
|
|
108
120
|
export async function persistResponseHistory(input) {
|
|
@@ -3,9 +3,9 @@ import * as fs from "node:fs/promises";
|
|
|
3
3
|
import { FlowError } from "../flow-error.js";
|
|
4
4
|
import { createGit, wrapGitError } from "../git/core.js";
|
|
5
5
|
import { readLedger } from "./ledger.js";
|
|
6
|
-
import { listContractIds } from "./ledger.js";
|
|
7
6
|
import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
|
|
8
|
-
import {
|
|
7
|
+
import { normalizeFilesystemCoordinate } from "../fs/path-coordinate.js";
|
|
8
|
+
import { gitCommonRootPath, resolveGitCommonRoot } from "../git/path-coordinate.js";
|
|
9
9
|
export function findBindEntry(entries) {
|
|
10
10
|
return entries.find((entry) => entry.kind === "bind");
|
|
11
11
|
}
|
|
@@ -36,8 +36,10 @@ async function listWorktrees(cwd) {
|
|
|
36
36
|
throw wrapGitError("worktree list --porcelain -z", error, cwd);
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
function
|
|
40
|
-
const
|
|
39
|
+
export function worktreeContainsCoordinate(root, candidate) {
|
|
40
|
+
const normalizedRoot = normalizeFilesystemCoordinate(root);
|
|
41
|
+
const normalizedCandidate = normalizeFilesystemCoordinate(candidate);
|
|
42
|
+
const relative = path.relative(normalizedRoot, normalizedCandidate);
|
|
41
43
|
return relative === "" || (!path.isAbsolute(relative) && relative !== ".." && !relative.startsWith(`..${path.sep}`));
|
|
42
44
|
}
|
|
43
45
|
export async function stableRepoRoot(cwd) {
|
|
@@ -100,6 +102,37 @@ async function findContractWorktree(cwd, contractId) {
|
|
|
100
102
|
export async function findContractWorktreePath(cwd, contractId) {
|
|
101
103
|
return (await findContractWorktree(cwd, contractId)).path;
|
|
102
104
|
}
|
|
105
|
+
export async function findRegisteredContractWorktreePath(cwd, contractId) {
|
|
106
|
+
const stableRoot = await stableRepoRoot(cwd);
|
|
107
|
+
const ledger = await readLedger(stableRoot, contractId);
|
|
108
|
+
const bind = ledger ? findBindEntry(ledger.entries) : undefined;
|
|
109
|
+
if (!bind || bind.data.workspace !== "worktree")
|
|
110
|
+
return undefined;
|
|
111
|
+
let expected;
|
|
112
|
+
try {
|
|
113
|
+
expected = await fs.realpath(await contractWorktreePathFromBind(stableRoot, contractId, bind));
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
for (const worktree of await listWorktrees(stableRoot)) {
|
|
119
|
+
try {
|
|
120
|
+
if (await fs.realpath(worktree.path) === expected)
|
|
121
|
+
return worktree.path;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// A stale Git registration is not an engine-owned worktree fact.
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Delivery coordinate for dirty admission and KEIYAKU.md render: the linked
|
|
131
|
+
* contract worktree when Git registers one, otherwise cwd (workspace here).
|
|
132
|
+
*/
|
|
133
|
+
export async function resolveContractDeliveryCwd(cwd, contractId) {
|
|
134
|
+
return (await findContractWorktreePath(cwd, contractId)) ?? cwd;
|
|
135
|
+
}
|
|
103
136
|
/**
|
|
104
137
|
* Resolve the contract id for an engine-owned bound worktree containing cwd.
|
|
105
138
|
* Matches the canonical bind place path and worktree workspace only; ledger
|
|
@@ -132,27 +165,23 @@ async function contractIdForEngineOwnedWorktree(cwd, options) {
|
|
|
132
165
|
}
|
|
133
166
|
if (canonicalWorktree !== expectedWorktree)
|
|
134
167
|
continue;
|
|
135
|
-
if (
|
|
168
|
+
if (worktreeContainsCoordinate(canonicalWorktree, canonicalCwd))
|
|
136
169
|
return contractId;
|
|
137
170
|
}
|
|
138
171
|
return undefined;
|
|
139
172
|
}
|
|
140
|
-
/**
|
|
141
|
-
* Resolve the active commission presented by an engine-owned contract
|
|
142
|
-
* worktree containing cwd. Ordinary repository directories and arbitrary
|
|
143
|
-
* worktrees never present a commission address.
|
|
144
|
-
*/
|
|
145
|
-
export async function contractPresentedByWorktree(cwd) {
|
|
146
|
-
return contractIdForEngineOwnedWorktree(cwd, { requireActive: true });
|
|
147
|
-
}
|
|
148
173
|
/**
|
|
149
174
|
* Resolve the contract bound by an engine-owned worktree containing cwd,
|
|
150
175
|
* including when the ledger is already terminal. Task CLI contract context
|
|
151
|
-
* uses this residual binding; call
|
|
176
|
+
* uses this residual binding; call attachment never infers from cwd.
|
|
152
177
|
*/
|
|
153
178
|
export async function contractBoundByEngineWorktree(cwd) {
|
|
154
179
|
return contractIdForEngineOwnedWorktree(cwd, { requireActive: false });
|
|
155
180
|
}
|
|
181
|
+
/** Existing-contract verbs may infer only a verified, active engine binding. */
|
|
182
|
+
export async function activeContractBoundByEngineWorktree(cwd) {
|
|
183
|
+
return contractIdForEngineOwnedWorktree(cwd, { requireActive: true });
|
|
184
|
+
}
|
|
156
185
|
export async function cleanupContractWorkspace(cwd, contractId) {
|
|
157
186
|
const stableRoot = await stableRepoRoot(cwd);
|
|
158
187
|
const git = createGit(stableRoot);
|
|
@@ -197,17 +226,3 @@ export async function cleanupContractWorkspace(cwd, contractId) {
|
|
|
197
226
|
}
|
|
198
227
|
return facts;
|
|
199
228
|
}
|
|
200
|
-
export async function activeContractIdForWorktreeDir(cwd, dirname) {
|
|
201
|
-
const ids = await listContractIds(cwd);
|
|
202
|
-
for (const id of ids) {
|
|
203
|
-
const ledger = await readLedger(cwd, id);
|
|
204
|
-
if (!ledger || isTerminalState(deriveContractState(ledger.entries)))
|
|
205
|
-
continue;
|
|
206
|
-
if (id === dirname)
|
|
207
|
-
return id;
|
|
208
|
-
const place = ledger ? findBindEntry(ledger.entries)?.data.place : undefined;
|
|
209
|
-
if (place === dirname)
|
|
210
|
-
return id;
|
|
211
|
-
}
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
package/build/flow-error.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ACTOR_IDENTITY, SETTINGS_PATH_SEGMENTS } from "./keiyaku-constants.js";
|
|
2
|
+
import { formatArtifactDirectories, KEIYAKU_ARTIFACT_DIRS } from "./artifact-directories.js";
|
|
2
3
|
const SETTINGS_DISPLAY_PATH = SETTINGS_PATH_SEGMENTS.join("/");
|
|
3
4
|
const DEFAULT_HINT_CONTEXT = {
|
|
4
5
|
bindToolName: "bind",
|
|
@@ -17,69 +18,115 @@ export function renderTemplate(template, values) {
|
|
|
17
18
|
return Object.prototype.hasOwnProperty.call(values, key) ? values[key] : match;
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
|
-
function
|
|
21
|
+
function formatInvalidSettingsDiseaseHints(diseases) {
|
|
22
|
+
return diseases.map((disease) => {
|
|
23
|
+
const where = disease.knob ? `${disease.source}:${disease.knob}` : `${disease.source}:(root)`;
|
|
24
|
+
return `${where}: ${disease.reason}`;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** CLI-owned typed hint table. Domain code supplies code + facts only. */
|
|
28
|
+
export function resolveFlowErrorHints(code, context, facts) {
|
|
29
|
+
if (facts?.kind === "invalid_settings") {
|
|
30
|
+
return formatInvalidSettingsDiseaseHints(facts.diseases);
|
|
31
|
+
}
|
|
32
|
+
if (facts?.kind === "verification_failure") {
|
|
33
|
+
return [
|
|
34
|
+
`Fix failures from '${facts.label}', then retry CLAIM.`,
|
|
35
|
+
`stdout:\n${facts.stdout}`,
|
|
36
|
+
`stderr:\n${facts.stderr}`,
|
|
37
|
+
];
|
|
38
|
+
}
|
|
39
|
+
if (facts?.kind === "dirty_worktree") {
|
|
40
|
+
return [
|
|
41
|
+
`Files under \`.keiyaku/\` are blocking the operation. Add ${formatArtifactDirectories(KEIYAKU_ARTIFACT_DIRS)} to \`.gitignore\` if you do not want those artifacts tracked.`,
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
if (facts?.kind === "loose_commits") {
|
|
45
|
+
return [
|
|
46
|
+
`keiyaku @${facts.contractId} arc — opens a new arc to receipt them, then ${facts.nextVerb}`,
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
if (facts?.kind === "needs_renew") {
|
|
50
|
+
return [`keiyaku @${facts.contractId} renew — renews delivery before petition`];
|
|
51
|
+
}
|
|
52
|
+
if (facts?.kind === "projection_in_flight") {
|
|
53
|
+
return ["keiyaku status — watch for the akuma to land, then renew"];
|
|
54
|
+
}
|
|
55
|
+
if (facts?.kind === "projection_wake_failure") {
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
21
58
|
switch (code) {
|
|
22
59
|
case "NOT_GIT_REPO":
|
|
23
|
-
return "The provided `cwd` is not a git repository.";
|
|
60
|
+
return ["The provided `cwd` is not a git repository."];
|
|
24
61
|
case "GIT_UNAVAILABLE":
|
|
25
|
-
return "Install Git, or use an explicitly bare command that does not require repository authority.";
|
|
62
|
+
return ["Install Git, or use an explicitly bare command that does not require repository authority."];
|
|
26
63
|
case "ACTIVE_KEIYAKU_EXISTS":
|
|
27
|
-
return `Next: open an arc with \`${context.arcToolName}\`, then use \`${context.renewToolName}\` when delivery must follow the current base, or \`${context.closeToolName}\` to settle it
|
|
64
|
+
return [`Next: open an arc with \`${context.arcToolName}\`, then use \`${context.renewToolName}\` when delivery must follow the current base, or \`${context.closeToolName}\` to settle it.`];
|
|
28
65
|
case "CONTRACT_AMBIGUOUS":
|
|
29
|
-
return "Address a specific contract workspace, or use `call --bare` to run without contract attachment.";
|
|
66
|
+
return ["Address a specific contract workspace, or use `call --bare` to run without contract attachment."];
|
|
30
67
|
case "UNKNOWN_COMMAND":
|
|
31
|
-
return "Run `keiyaku --help` to inspect available commands.";
|
|
68
|
+
return ["Run `keiyaku --help` to inspect available commands."];
|
|
32
69
|
case "EMPTY_PARAM":
|
|
33
|
-
return "One or more required parameters are empty.";
|
|
70
|
+
return ["One or more required parameters are empty."];
|
|
34
71
|
case "DIRTY_WORKTREE":
|
|
35
|
-
return "The working tree has uncommitted changes.";
|
|
72
|
+
return ["The working tree has uncommitted changes."];
|
|
36
73
|
case "NOT_ACTIVE_KEIYAKU_BRANCH":
|
|
37
|
-
return "
|
|
74
|
+
return ["keiyaku bind — opens a new contract"];
|
|
38
75
|
case "MISSING_KEIYAKU_BASE":
|
|
39
|
-
return "Current branch is not associated with an active contract ledger.";
|
|
76
|
+
return ["Current branch is not associated with an active contract ledger."];
|
|
40
77
|
case "MISSING_PROTOCOL_FILES":
|
|
41
|
-
return "Required protocol file is missing (`KEIYAKU.md`).";
|
|
78
|
+
return ["Required protocol file is missing (`KEIYAKU.md`)."];
|
|
42
79
|
case "CLOSE_MERGE_CONFLICT":
|
|
43
|
-
return [
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
80
|
+
return [`Open a Keiyaku recovery session with \`keiyaku ${context.renewToolName} --resolve\`.`];
|
|
81
|
+
case "RENEW_COORDINATE_DRIFT":
|
|
82
|
+
return [`Restore the delivery to its ledger-recorded history with Git reflog, then retry \`keiyaku ${context.renewToolName}\`.`];
|
|
83
|
+
case "RENEW_SESSION_OPEN":
|
|
84
|
+
return [`Continue the owned rewrite with \`keiyaku ${context.renewToolName} --continue\`, or restore it with \`keiyaku ${context.renewToolName} --abort\`.`];
|
|
85
|
+
case "RENEW_SESSION_NOT_FOUND":
|
|
86
|
+
return [`No recovery session is open; run \`keiyaku ${context.renewToolName}\` normally.`];
|
|
48
87
|
case "CLOSE_QUALITY_GATE_FAILED":
|
|
49
|
-
return `CLAIM denied: a configured verification command failed. Use \`${context.arcToolName}\` after addressing the failure before petitioning again
|
|
88
|
+
return [`CLAIM denied: a configured verification command failed. Use \`${context.arcToolName}\` after addressing the failure before petitioning again.`];
|
|
50
89
|
case "INVALID_BRANCH_TITLE":
|
|
51
|
-
return "Title cannot be converted to a valid branch token for `keiyaku/<title>`.";
|
|
90
|
+
return ["Title cannot be converted to a valid branch token for `keiyaku/<title>`."];
|
|
52
91
|
case "UNKNOWN_SUBAGENT": {
|
|
53
92
|
const names = context.availableActorNames.join(", ");
|
|
54
|
-
return `Unknown ${context.actorIdentity.toLowerCase()} name. Valid options: ${names}
|
|
93
|
+
return [`Unknown ${context.actorIdentity.toLowerCase()} name. Valid options: ${names}.`];
|
|
55
94
|
}
|
|
56
95
|
case "FROM_DRAFT_NOT_FOUND":
|
|
57
|
-
return "The path in `from_draft` does not exist. `from_draft` must reference an existing file path (absolute or relative to `cwd`).";
|
|
96
|
+
return ["The path in `from_draft` does not exist. `from_draft` must reference an existing file path (absolute or relative to `cwd`)."];
|
|
58
97
|
case "INVALID_KEIYAKU_DRAFT":
|
|
59
|
-
return "Invalid draft/input. Use a `# <title>` heading with non-empty `## Objective` and `## Scope` sections (or the equivalent shape in `from_draft`).";
|
|
98
|
+
return ["Invalid draft/input. Use a `# <title>` heading with non-empty `## Objective` and `## Scope` sections (or the equivalent shape in `from_draft`)."];
|
|
99
|
+
case "BIND_TASK_INCOMPLETE":
|
|
100
|
+
return ["Task supplies name/objective defaults; pipe only the missing sections as partial contract Markdown on stdin."];
|
|
60
101
|
case "KEIYAKU_FILE_EXISTS":
|
|
61
|
-
return `\`${context.bindToolName}\` requires a clean slate. \`KEIYAKU.md\` must be removed before starting
|
|
102
|
+
return [`\`${context.bindToolName}\` requires a clean slate. \`KEIYAKU.md\` must be removed before starting.`];
|
|
62
103
|
case "DETACHED_HEAD":
|
|
63
|
-
return "Repository is in detached HEAD state. Address an active contract workspace before retrying.";
|
|
104
|
+
return ["Repository is in detached HEAD state. Address an active contract workspace before retrying."];
|
|
64
105
|
case "INVALID_RESPONSE_PATH":
|
|
65
|
-
return "`keiyaku revive ARTIFACT_ID` needs a valid previous Keiyaku response artifact that includes complete provenance plus `session` and `subagent_name`.";
|
|
106
|
+
return ["`keiyaku revive ARTIFACT_ID` needs a valid previous Keiyaku response artifact that includes complete provenance plus `session` and `subagent_name`."];
|
|
66
107
|
case "INVALID_CLOSE_INTENT":
|
|
67
|
-
return "Invalid close intent. Valid values are `CLAIM` and `FORFEIT`.";
|
|
108
|
+
return ["Invalid close intent. Valid values are `CLAIM` and `FORFEIT`."];
|
|
68
109
|
case "INVALID_SETTINGS":
|
|
69
|
-
return `Fix invalid configuration in \`${SETTINGS_DISPLAY_PATH}\` and retry
|
|
110
|
+
return [`Fix invalid configuration in \`${SETTINGS_DISPLAY_PATH}\` and retry.`];
|
|
70
111
|
case "INVALID_EFFORT_OVERRIDE":
|
|
71
|
-
return "Choose an effort value declared by the selected Akuma's effortOptions.";
|
|
112
|
+
return ["Choose an effort value declared by the selected Akuma's effortOptions."];
|
|
72
113
|
case "CONCURRENT_MODIFICATION":
|
|
73
|
-
return `Concurrent repository changes were detected during \`${context.arcToolName}\` or \`${context.renewToolName}\`. Retry on the latest branch state
|
|
114
|
+
return [`Concurrent repository changes were detected during \`${context.arcToolName}\` or \`${context.renewToolName}\`. Retry on the latest branch state.`];
|
|
115
|
+
case "TASK_LOCK_ADMISSION_TIMEOUT":
|
|
116
|
+
return ["Task coordination did not become available before the bounded deadline. Retry the command; repeated timeouts indicate a stuck or damaged repository lock."];
|
|
74
117
|
case "INTERNAL_STATE":
|
|
75
|
-
return "An internal state error occurred. Please verify your repository status.";
|
|
118
|
+
return ["An internal state error occurred. Please verify your repository status."];
|
|
119
|
+
case "SCOPE_VIOLATION":
|
|
120
|
+
return ["Files outside the contract's declared scope were modified. Append ordered scope terms with `--append-scope`, amend the contract, or move the changes back."];
|
|
121
|
+
case "NO_OPEN_ARC":
|
|
122
|
+
return ["Open an arc to receipt delivery commits after the fence, then retry."];
|
|
76
123
|
case "REVIEW_REJECTED":
|
|
77
|
-
return `CLAIM denied by the reviewer. Address the findings and retry \`${context.arcToolName}\` before petitioning again
|
|
124
|
+
return [`CLAIM denied by the reviewer. Address the findings and retry \`${context.arcToolName}\` before petitioning again.`];
|
|
78
125
|
case "VERDICT_DENIED":
|
|
79
126
|
case "OATH_MISSING":
|
|
80
|
-
return DEFAULT_ERROR_HINT;
|
|
127
|
+
return [DEFAULT_ERROR_HINT];
|
|
81
128
|
default:
|
|
82
|
-
return DEFAULT_ERROR_HINT;
|
|
129
|
+
return [DEFAULT_ERROR_HINT];
|
|
83
130
|
}
|
|
84
131
|
}
|
|
85
132
|
function getDefaultErrorHint() {
|
|
@@ -87,14 +134,14 @@ function getDefaultErrorHint() {
|
|
|
87
134
|
}
|
|
88
135
|
export class FlowError extends Error {
|
|
89
136
|
code;
|
|
90
|
-
hints;
|
|
91
137
|
review;
|
|
138
|
+
facts;
|
|
92
139
|
constructor(code, message, options) {
|
|
93
140
|
super(message, options?.cause === undefined ? undefined : { cause: options.cause });
|
|
94
141
|
this.name = "FlowError";
|
|
95
142
|
this.code = code;
|
|
96
|
-
this.hints = options?.hints;
|
|
97
143
|
this.review = options?.review;
|
|
144
|
+
this.facts = options?.facts;
|
|
98
145
|
}
|
|
99
146
|
}
|
|
100
147
|
export function isFlowError(err) {
|
|
@@ -117,18 +164,15 @@ export function wrapFlowError(action, err) {
|
|
|
117
164
|
if (isFlowError(err)) {
|
|
118
165
|
return new FlowError(err.code, `${action} failed: ${err.message}`, {
|
|
119
166
|
cause: err,
|
|
120
|
-
hints: err.hints,
|
|
121
167
|
review: err.review,
|
|
168
|
+
facts: err.facts,
|
|
122
169
|
});
|
|
123
170
|
}
|
|
124
171
|
return new Error(`${action} failed: ${asMessage(err)}`);
|
|
125
172
|
}
|
|
126
173
|
export function pickHintsFromError(err, hintContext = DEFAULT_HINT_CONTEXT) {
|
|
127
174
|
if (isFlowError(err)) {
|
|
128
|
-
|
|
129
|
-
return err.hints;
|
|
130
|
-
}
|
|
131
|
-
return [resolveFlowErrorHint(err.code, hintContext)];
|
|
175
|
+
return resolveFlowErrorHints(err.code, hintContext, err.facts);
|
|
132
176
|
}
|
|
133
177
|
return [getDefaultErrorHint()];
|
|
134
178
|
}
|