@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
package/build/cli/render/task.js
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
}
|
|
1
|
+
import { commissionSlug } from "../../core/ids.js";
|
|
2
|
+
import { deriveTaskDisplay as deriveStructuredTaskDisplay, selectTaskList, } from "../../core/task/index.js";
|
|
4
3
|
export function shortContractId(contractId) {
|
|
5
|
-
|
|
6
|
-
return separator > 0 ? contractId.slice(0, separator) : contractId;
|
|
4
|
+
return commissionSlug(contractId);
|
|
7
5
|
}
|
|
8
6
|
export function deriveTaskDisplay(task) {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (task.state === "drop")
|
|
12
|
-
return "dropped";
|
|
13
|
-
if (task.contractId !== undefined)
|
|
14
|
-
return `bound(${shortContractId(task.contractId)})`;
|
|
15
|
-
if (task.state === "in_progress")
|
|
16
|
-
return "in_progress";
|
|
17
|
-
return task.blocked ? "blocked" : "ready";
|
|
7
|
+
const display = deriveStructuredTaskDisplay(task);
|
|
8
|
+
return display === "bound" ? `bound(${shortContractId(task.contractId)})` : display;
|
|
18
9
|
}
|
|
19
10
|
function renderTaskRowWithId(task, id) {
|
|
20
11
|
return `${id} · P${task.pri} · ${deriveTaskDisplay(task)} · ${task.title}`;
|
|
21
12
|
}
|
|
22
13
|
export function renderTaskListRow(task) {
|
|
23
|
-
return renderTaskRowWithId(task,
|
|
14
|
+
return renderTaskRowWithId(task, task.id);
|
|
24
15
|
}
|
|
25
16
|
export function renderTaskMutationRow(task) {
|
|
26
17
|
return renderTaskRowWithId(task, task.id);
|
|
@@ -28,66 +19,66 @@ export function renderTaskMutationRow(task) {
|
|
|
28
19
|
export function renderTaskRow(task, completeId = false) {
|
|
29
20
|
return completeId ? renderTaskMutationRow(task) : renderTaskListRow(task);
|
|
30
21
|
}
|
|
31
|
-
function displayOrder(display) {
|
|
32
|
-
if (display === "in_progress")
|
|
33
|
-
return 0;
|
|
34
|
-
if (display === "ready")
|
|
35
|
-
return 1;
|
|
36
|
-
if (display === "blocked")
|
|
37
|
-
return 2;
|
|
38
|
-
if (display.startsWith("bound("))
|
|
39
|
-
return 3;
|
|
40
|
-
return display === "done" ? 4 : 5;
|
|
41
|
-
}
|
|
42
|
-
function compareText(left, right) {
|
|
43
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
44
|
-
}
|
|
45
|
-
function compareTasks(left, right) {
|
|
46
|
-
const displayDifference = displayOrder(deriveTaskDisplay(left)) - displayOrder(deriveTaskDisplay(right));
|
|
47
|
-
if (displayDifference !== 0)
|
|
48
|
-
return displayDifference;
|
|
49
|
-
if (left.pri !== right.pri)
|
|
50
|
-
return left.pri - right.pri;
|
|
51
|
-
const createdDifference = compareText(left.createdAt, right.createdAt);
|
|
52
|
-
return createdDifference || compareText(left.id, right.id);
|
|
53
|
-
}
|
|
54
|
-
function selected(task, selection) {
|
|
55
|
-
const display = deriveTaskDisplay(task);
|
|
56
|
-
const terminal = display === "done" || display === "dropped";
|
|
57
|
-
if (selection === "done")
|
|
58
|
-
return terminal;
|
|
59
|
-
if (selection === "default")
|
|
60
|
-
return !terminal;
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
22
|
export function groupAndSortTasks(tasks, selection = "default") {
|
|
64
|
-
return tasks
|
|
23
|
+
return selectTaskList(tasks, { selection });
|
|
65
24
|
}
|
|
66
25
|
export function renderTaskList(tasks, options = {}) {
|
|
67
|
-
return
|
|
26
|
+
return selectTaskList(tasks, options).map(renderTaskListRow).join("\n");
|
|
27
|
+
}
|
|
28
|
+
export function renderSelectedTaskList(tasks) {
|
|
29
|
+
return tasks.map(renderTaskListRow).join("\n");
|
|
68
30
|
}
|
|
69
31
|
function renderIds(ids) {
|
|
70
|
-
return ids.length === 0 ? "(none)" : ids.
|
|
32
|
+
return ids.length === 0 ? "(none)" : ids.join(", ");
|
|
71
33
|
}
|
|
72
|
-
|
|
34
|
+
function renderTaskDetails(task) {
|
|
73
35
|
const released = new Set(task.releasedNeeds);
|
|
74
36
|
const needs = task.needs.length === 0
|
|
75
37
|
? "(none)"
|
|
76
38
|
: task.needs
|
|
77
|
-
.map((id) => `${
|
|
39
|
+
.map((id) => `${id}${released.has(id) ? " (dropped)" : ""}`)
|
|
78
40
|
.join(", ");
|
|
79
41
|
return [
|
|
80
|
-
`${
|
|
42
|
+
`${task.id} · ${task.title}`,
|
|
81
43
|
`state: ${deriveTaskDisplay(task)}`,
|
|
82
44
|
`priority: ${task.pri}`,
|
|
83
45
|
`needs: ${needs}`,
|
|
84
46
|
`blocks: ${renderIds(task.blocks)}`,
|
|
85
|
-
`parent: ${task.parent === null ? "(none)" :
|
|
47
|
+
`parent: ${task.parent === null ? "(none)" : task.parent}`,
|
|
86
48
|
`from: ${renderIds(task.from)}`,
|
|
87
49
|
`created: ${task.createdAt} by ${task.creator}`,
|
|
88
50
|
"",
|
|
89
51
|
task.body,
|
|
90
|
-
]
|
|
52
|
+
];
|
|
53
|
+
}
|
|
54
|
+
function renderTreeNode(node, prefix, last) {
|
|
55
|
+
const branch = last ? "`- " : "|- ";
|
|
56
|
+
const nestedPrefix = `${prefix}${last ? " " : "| "}`;
|
|
57
|
+
const task = node.task;
|
|
58
|
+
const released = new Set(task.releasedNeeds);
|
|
59
|
+
const needs = task.needs.length === 0
|
|
60
|
+
? "(none)"
|
|
61
|
+
: task.needs.map((id) => `${id}${released.has(id) ? " (dropped)" : ""}`).join(", ");
|
|
62
|
+
const lines = [
|
|
63
|
+
`${prefix}${branch}${task.id} · ${deriveTaskDisplay(task)} · P${task.pri} · ${task.title}`,
|
|
64
|
+
`${nestedPrefix}needs: ${needs}`,
|
|
65
|
+
`${nestedPrefix}blocks: ${renderIds(task.blocks)}`,
|
|
66
|
+
`${nestedPrefix}from: ${renderIds(task.from)}`,
|
|
67
|
+
];
|
|
68
|
+
node.children.forEach((child, index) => lines.push(...renderTreeNode(child, nestedPrefix, index === node.children.length - 1)));
|
|
69
|
+
return lines;
|
|
70
|
+
}
|
|
71
|
+
function treeDiagnostic(diagnostic) {
|
|
72
|
+
const id = diagnostic.id ? `${diagnostic.id} · ` : "";
|
|
73
|
+
return `! ${diagnostic.code}: ${id}${diagnostic.message}`;
|
|
74
|
+
}
|
|
75
|
+
export function renderTaskShow(task, tree) {
|
|
76
|
+
const treeLines = tree.descendants.length === 0
|
|
77
|
+
? ["children tree: (empty)"]
|
|
78
|
+
: ["children tree:", ...tree.descendants.flatMap((node, index) => renderTreeNode(node, "", index === tree.descendants.length - 1))];
|
|
79
|
+
if (tree.diagnostics.length > 0)
|
|
80
|
+
treeLines.push("tree diagnostics:", ...tree.diagnostics.map(treeDiagnostic));
|
|
81
|
+
return [...renderTaskDetails(task), "", ...treeLines].join("\n");
|
|
91
82
|
}
|
|
92
83
|
export function taskJson(task) {
|
|
93
84
|
return {
|
|
@@ -102,12 +93,30 @@ export function taskJson(task) {
|
|
|
102
93
|
from: [...task.from],
|
|
103
94
|
contractId: task.contractId ?? null,
|
|
104
95
|
createdAt: task.createdAt,
|
|
96
|
+
updatedAt: task.updatedAt ?? task.createdAt,
|
|
105
97
|
creator: task.creator,
|
|
106
98
|
};
|
|
107
99
|
}
|
|
108
|
-
|
|
109
|
-
return
|
|
100
|
+
function taskTreeNodeJson(node) {
|
|
101
|
+
return { ...taskJson(node.task), children: node.children.map(taskTreeNodeJson) };
|
|
102
|
+
}
|
|
103
|
+
export function taskTreeJson(tree) {
|
|
104
|
+
return {
|
|
105
|
+
children: tree.descendants.map(taskTreeNodeJson),
|
|
106
|
+
diagnostics: tree.diagnostics.map((diagnostic) => ({
|
|
107
|
+
code: diagnostic.code,
|
|
108
|
+
message: diagnostic.message,
|
|
109
|
+
id: diagnostic.id ?? null,
|
|
110
|
+
relatedIds: [...(diagnostic.relatedIds ?? [])],
|
|
111
|
+
})),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
export function renderTaskShowJson(task, tree) {
|
|
115
|
+
return `${JSON.stringify({ ...taskJson(task), body: task.body, descendants: taskTreeJson(tree) })}\n`;
|
|
110
116
|
}
|
|
111
117
|
export function renderTaskListJson(tasks, selection = "default") {
|
|
112
118
|
return `${JSON.stringify(groupAndSortTasks(tasks, selection).map(taskJson))}\n`;
|
|
113
119
|
}
|
|
120
|
+
export function renderSelectedTaskListJson(tasks) {
|
|
121
|
+
return `${JSON.stringify(tasks.map(taskJson))}\n`;
|
|
122
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** Aggregate status strips the SUBAGENT_ prefix from the public code suffix. */
|
|
2
|
+
export function terminalFailureCodeSuffix(code) {
|
|
3
|
+
return code.startsWith("SUBAGENT_") ? code.slice("SUBAGENT_".length) : code;
|
|
4
|
+
}
|
|
5
|
+
export function terminalFailureColdStatement(failure) {
|
|
6
|
+
if (failure.publicCause?.kind === "rate_limit_exhausted") {
|
|
7
|
+
return "the provider rate limit is exhausted";
|
|
8
|
+
}
|
|
9
|
+
if (failure.class === "runner") {
|
|
10
|
+
return failure.code === "SUBAGENT_SPAWN_ERROR"
|
|
11
|
+
? "the akuma never woke"
|
|
12
|
+
: "the akuma broke mid-flight";
|
|
13
|
+
}
|
|
14
|
+
switch (failure.code) {
|
|
15
|
+
case "SUBAGENT_TIMEOUT":
|
|
16
|
+
return "the akuma went silent";
|
|
17
|
+
case "SUBAGENT_TRANSPORT_ERROR":
|
|
18
|
+
return "the provider transport failed";
|
|
19
|
+
case "SUBAGENT_POLICY_BUDGET":
|
|
20
|
+
return "the execution policy budget expired";
|
|
21
|
+
case "SUBAGENT_PROVIDER_UNAVAILABLE":
|
|
22
|
+
return "the provider did not answer";
|
|
23
|
+
case "SUBAGENT_NON_ZERO_EXIT":
|
|
24
|
+
return failure.exitCode === undefined ? undefined : `the akuma died · exit ${failure.exitCode}`;
|
|
25
|
+
case "SUBAGENT_EXEC_ERROR":
|
|
26
|
+
return "the akuma broke mid-flight";
|
|
27
|
+
default:
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function terminalFailureEvidence(failure, statement) {
|
|
32
|
+
const exitAlreadyInStatement = statement !== undefined
|
|
33
|
+
&& failure.code === "SUBAGENT_NON_ZERO_EXIT"
|
|
34
|
+
&& failure.exitCode !== undefined;
|
|
35
|
+
const parts = [];
|
|
36
|
+
if (failure.timeoutMs !== undefined) {
|
|
37
|
+
parts.push(failure.code === "SUBAGENT_POLICY_BUDGET" ? `budget ${failure.timeoutMs}ms` : `idle ${failure.timeoutMs}ms`);
|
|
38
|
+
}
|
|
39
|
+
if (failure.signal)
|
|
40
|
+
parts.push(`signal ${failure.signal}`);
|
|
41
|
+
if (!exitAlreadyInStatement && failure.exitCode !== undefined)
|
|
42
|
+
parts.push(`exit ${failure.exitCode}`);
|
|
43
|
+
parts.push(`phase ${failure.phase}`);
|
|
44
|
+
return parts.length > 0 ? parts.join(" · ") : undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Ordinary wait / single-projection status terminal face.
|
|
48
|
+
* Shape is the locked error-line stream: ✕ cold · CODE, then typed evidence.
|
|
49
|
+
*/
|
|
50
|
+
export function renderTerminalFailureFace(_projectionId, failure) {
|
|
51
|
+
const lines = [];
|
|
52
|
+
if (failure) {
|
|
53
|
+
const statement = terminalFailureColdStatement(failure);
|
|
54
|
+
if (statement)
|
|
55
|
+
lines.push(`✕ ${statement} · ${failure.code}`);
|
|
56
|
+
const evidence = terminalFailureEvidence(failure, statement);
|
|
57
|
+
if (evidence)
|
|
58
|
+
lines.push(` ${evidence}`);
|
|
59
|
+
if (failure.artifactId)
|
|
60
|
+
lines.push(` record ${failure.artifactId}`);
|
|
61
|
+
}
|
|
62
|
+
return lines;
|
|
63
|
+
}
|
package/build/cli/render/wait.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { formatTimelineDuration, renderProjectionActivity, } from "./projection-activity.js";
|
|
1
|
+
import { formatTimelineDuration, renderProjectionActivity, renderProjectionActivitySummary, } from "./projection-activity.js";
|
|
2
2
|
import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
|
|
3
|
-
import { projectionRejoinHintLines, textResponse } from "./shared.js";
|
|
3
|
+
import { formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
|
|
4
|
+
import { renderTerminalFailureFace } from "./terminal-failure.js";
|
|
4
5
|
const WAIT_HEADER_MAX_COLUMNS = 60;
|
|
5
6
|
function shortAddress(projectionId) {
|
|
6
7
|
return /\/([0-9a-f]{8})$/.exec(projectionId)?.[1] ?? projectionId;
|
|
@@ -19,6 +20,11 @@ function phaseState(phase) {
|
|
|
19
20
|
case "quiescent": return "running";
|
|
20
21
|
}
|
|
21
22
|
}
|
|
23
|
+
function isTerminalPhase(phase) {
|
|
24
|
+
// `lost` is intentionally absent: it can be an observation failure without
|
|
25
|
+
// a verdict. Core marks the excluded lost-runner-verdict case explicitly.
|
|
26
|
+
return ["done", "failed", "killed", "dismissed"].includes(phase);
|
|
27
|
+
}
|
|
22
28
|
function waitStateText(snapshot) {
|
|
23
29
|
switch (snapshot.phase) {
|
|
24
30
|
case "active":
|
|
@@ -63,12 +69,6 @@ function waitHeader(projectionId, akuma, snapshot, outputColumns) {
|
|
|
63
69
|
const dashCount = Math.max(1, maxColumns - displayColumns(`${prefix} ${state}`));
|
|
64
70
|
return `${prefix} ${"─".repeat(dashCount)} ${state}`;
|
|
65
71
|
}
|
|
66
|
-
function terminalDiagnostic(result) {
|
|
67
|
-
if (result.state !== "terminal" || result.verdict.state !== "failed")
|
|
68
|
-
return undefined;
|
|
69
|
-
const text = result.verdict.detail?.replace(/\s+/g, " ").trim();
|
|
70
|
-
return text ? { at: result.verdict.at, text } : undefined;
|
|
71
|
-
}
|
|
72
72
|
function ledgerHint(projectionId, snapshot) {
|
|
73
73
|
const file = snapshot.eventLedgerFile ?? "events.jsonl";
|
|
74
74
|
return `· ledger: .keiyaku/projection/${projectionId}/${file}`;
|
|
@@ -91,33 +91,14 @@ function nextActionLines(projectionId, result, state) {
|
|
|
91
91
|
"The akuma is back.",
|
|
92
92
|
...(snapshot.artifactId ? [`record: ${snapshot.artifactId}`] : []),
|
|
93
93
|
"talk to it:",
|
|
94
|
-
` »
|
|
94
|
+
` » ${formatTellCommand(projectionId, '"your words"')}`,
|
|
95
95
|
];
|
|
96
96
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
if (result.state === "terminal" && result.verdict.state === "failed") {
|
|
104
|
-
if (snapshot.failureCode === "SUBAGENT_PROVIDER_UNAVAILABLE") {
|
|
105
|
-
return snapshot.sourceArtifactId
|
|
106
|
-
? [
|
|
107
|
-
"× provider unavailable — no turn accepted",
|
|
108
|
-
`» nothing was consumed · retry from the same artifact: keiyaku revive ${snapshot.sourceArtifactId}`,
|
|
109
|
-
]
|
|
110
|
-
: [
|
|
111
|
-
"× provider unavailable — no turn accepted",
|
|
112
|
-
"» nothing was consumed · safe to call again",
|
|
113
|
-
];
|
|
114
|
-
}
|
|
115
|
-
return [
|
|
116
|
-
"The akuma failed and stopped.",
|
|
117
|
-
...(snapshot.artifactId ? [`record: ${snapshot.artifactId}`] : []),
|
|
118
|
-
"talk to it:",
|
|
119
|
-
` » keiyaku tell ${projectionId} "your words"`,
|
|
120
|
-
];
|
|
97
|
+
if (result.state === "terminal" && (result.verdict.terminalFailure
|
|
98
|
+
|| result.verdict.state === "failed"
|
|
99
|
+
|| result.verdict.state === "launch-failed"
|
|
100
|
+
|| result.verdict.state === "lost-runner")) {
|
|
101
|
+
return renderTerminalFailureFace(projectionId, result.verdict.terminalFailure);
|
|
121
102
|
}
|
|
122
103
|
if (snapshot.phase === "lost") {
|
|
123
104
|
return snapshot.artifactId
|
|
@@ -142,7 +123,7 @@ function startupTimeoutResponse(projectionId, akuma) {
|
|
|
142
123
|
"the launch was never adopted — no akuma exists",
|
|
143
124
|
"",
|
|
144
125
|
"the next wake retries the launch:",
|
|
145
|
-
` »
|
|
126
|
+
` » ${formatTellCommand(projectionId, '"your words"')}`,
|
|
146
127
|
].join("\n")),
|
|
147
128
|
exitCode: 1,
|
|
148
129
|
};
|
|
@@ -198,7 +179,13 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
198
179
|
if (result.state === "unknown") {
|
|
199
180
|
return identityUnavailableResponse(projectionId, result.diagnostic);
|
|
200
181
|
}
|
|
201
|
-
|
|
182
|
+
// A plural deadline may observe a verdict whose timestamp is at or after
|
|
183
|
+
// the cutoff. The typed timeout result owns presentation in that case; the
|
|
184
|
+
// later terminal-looking snapshot must not turn it into a terminal face.
|
|
185
|
+
const snapshot = result.state === "timeout"
|
|
186
|
+
&& (result.terminalSnapshot || isTerminalPhase(result.snapshot.phase))
|
|
187
|
+
? { ...result.snapshot, phase: "active" }
|
|
188
|
+
: result.snapshot;
|
|
202
189
|
const maxColumns = options.maxColumns ?? resolveLineColumns();
|
|
203
190
|
if (result.state === "terminal" && result.verdict.state === "killed") {
|
|
204
191
|
return {
|
|
@@ -216,13 +203,11 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
216
203
|
if (state === "returned") {
|
|
217
204
|
return returnedResponse(projectionId, result);
|
|
218
205
|
}
|
|
219
|
-
const diagnostic = terminalDiagnostic(result);
|
|
220
206
|
const rendered = renderProjectionActivity(snapshot.activity, {
|
|
221
207
|
anchorMs: snapshot.observedAtMs,
|
|
222
208
|
state,
|
|
223
209
|
showPlan: state === "running",
|
|
224
210
|
...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
|
|
225
|
-
...(diagnostic ? { terminalDiagnostic: diagnostic } : {}),
|
|
226
211
|
maxColumns,
|
|
227
212
|
});
|
|
228
213
|
const storageDiagnostics = (snapshot.eventDiagnostics ?? []).map((diagnostic) => `‼ ${diagnostic.kind} · ${diagnostic.detail}`);
|
|
@@ -235,7 +220,22 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
235
220
|
if (rendered.lines.length === 0 && state === "running") {
|
|
236
221
|
lines.push(" not a word out of it yet — pulse is steady");
|
|
237
222
|
}
|
|
238
|
-
|
|
223
|
+
// Live/timeout observation faces keep the bounded activity window and add the
|
|
224
|
+
// existing compact rollup after those rows. Terminal faces already own end└
|
|
225
|
+
// and must not duplicate it; returned response-only faces never reach here.
|
|
226
|
+
if (!rendered.hasEndAnchor) {
|
|
227
|
+
const summary = renderProjectionActivitySummary(snapshot.activity, {
|
|
228
|
+
state,
|
|
229
|
+
...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
|
|
230
|
+
maxColumns,
|
|
231
|
+
});
|
|
232
|
+
if (summary) {
|
|
233
|
+
lines.push(summary);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const nextActions = state === "running" && options.runningActions === false
|
|
237
|
+
? []
|
|
238
|
+
: nextActionLines(options.alias ?? projectionId, result, state);
|
|
239
239
|
if (nextActions.length > 0)
|
|
240
240
|
lines.push("");
|
|
241
241
|
lines.push(...nextActions);
|
|
@@ -247,3 +247,33 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
247
247
|
}
|
|
248
248
|
return response;
|
|
249
249
|
}
|
|
250
|
+
/** The plural face labels every member because a successful singleton face is answer-only. */
|
|
251
|
+
export function buildProjectionWaitSetResponse(result) {
|
|
252
|
+
const rendered = result.results
|
|
253
|
+
.slice()
|
|
254
|
+
.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
255
|
+
.map((member) => ({
|
|
256
|
+
id: member.id,
|
|
257
|
+
result: member.result,
|
|
258
|
+
response: buildWaitResponse(member.id, member.result, { runningActions: false }),
|
|
259
|
+
}));
|
|
260
|
+
const liveIds = rendered
|
|
261
|
+
.filter((member) => member.result.state === "timeout")
|
|
262
|
+
.map((member) => member.id);
|
|
263
|
+
const blocks = rendered.map(({ id, response }) => `${id}\n${response.text}`);
|
|
264
|
+
if (liveIds.length > 0) {
|
|
265
|
+
blocks.push([
|
|
266
|
+
"Come back for the result:",
|
|
267
|
+
` » keiyaku wait ${liveIds.join(" ")} --${result.selection} [--timeout DURATION]`,
|
|
268
|
+
"Steer them while they work:",
|
|
269
|
+
` » ${formatTellCommand("<projection-id>", '"your words"')}`,
|
|
270
|
+
].join("\n"));
|
|
271
|
+
}
|
|
272
|
+
const text = blocks.join("\n\n");
|
|
273
|
+
const exitCode = rendered.reduce((current, { response }) => {
|
|
274
|
+
if (response.exitCode === 130)
|
|
275
|
+
return 130;
|
|
276
|
+
return response.exitCode === 1 ? 1 : current;
|
|
277
|
+
}, undefined);
|
|
278
|
+
return exitCode === undefined ? textResponse(text) : { ...textResponse(text), exitCode };
|
|
279
|
+
}
|
package/build/cli/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const TASK_SUBCOMMANDS = ["add", "
|
|
1
|
+
export const TASK_SUBCOMMANDS = ["add", "show", "ls", "start", "stop", "done", "drop", "update", "doctor"];
|
|
@@ -200,11 +200,6 @@ export async function loadAkumaCatalog(cwd) {
|
|
|
200
200
|
profile: freezeProfile({
|
|
201
201
|
provider: profile.provider,
|
|
202
202
|
...(profile.description !== undefined ? { description: profile.description } : {}),
|
|
203
|
-
...("model" in profile && profile.model !== undefined ? { model: profile.model } : {}),
|
|
204
|
-
...("effort" in profile && profile.effort !== undefined ? { effort: profile.effort } : {}),
|
|
205
|
-
...("effortOptions" in profile && profile.effortOptions !== undefined
|
|
206
|
-
? { effortOptions: Object.freeze([...profile.effortOptions]) }
|
|
207
|
-
: {}),
|
|
208
203
|
}),
|
|
209
204
|
});
|
|
210
205
|
candidates.push(candidate);
|
package/build/config/env-keys.js
CHANGED
|
@@ -10,6 +10,7 @@ export const ENV_KEYS = {
|
|
|
10
10
|
AGENT_OVERRIDE: "KEIYAKU_AGENT_OVERRIDE",
|
|
11
11
|
DISABLE_SUBAGENT_SPAWN: DISABLE_SUBAGENT_SPAWN_ENV_KEY,
|
|
12
12
|
SUBAGENT_EXEC_IDLE_TIMEOUT_MS: "KEIYAKU_SUBAGENT_EXEC_IDLE_TIMEOUT_MS",
|
|
13
|
+
SUBAGENT_EXEC_MAX_DURATION_MS: "KEIYAKU_SUBAGENT_EXEC_MAX_DURATION_MS",
|
|
13
14
|
CODEX_EXEC_MAX_CAPTURE_CHARS: "KEIYAKU_CODEX_EXEC_MAX_CAPTURE_CHARS",
|
|
14
15
|
CLAUDE_EXEC_MAX_CAPTURE_CHARS: "KEIYAKU_CLAUDE_EXEC_MAX_CAPTURE_CHARS",
|
|
15
16
|
OPENCODE_EXEC_MAX_CAPTURE_CHARS: "KEIYAKU_OPENCODE_EXEC_MAX_CAPTURE_CHARS",
|
|
@@ -25,7 +26,8 @@ export const ENV_KEYS = {
|
|
|
25
26
|
const ENV_KEY_ENTRIES = [
|
|
26
27
|
{ key: ENV_KEYS.AGENT_OVERRIDE, defaultValue: "", description: "Override default agent name", category: "subagent" },
|
|
27
28
|
{ key: ENV_KEYS.DISABLE_SUBAGENT_SPAWN, defaultValue: "0", description: "Disable subprocess subagent spawning when set to 1", category: "subagent" },
|
|
28
|
-
{ key: ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS, defaultValue: "
|
|
29
|
+
{ key: ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS, defaultValue: "300000", description: "Subagent provider-ingress idle timeout in milliseconds", category: "subagent" },
|
|
30
|
+
{ key: ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS, defaultValue: "3600000", description: "Subagent absolute execution policy budget in milliseconds", category: "subagent" },
|
|
29
31
|
{ key: ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Codex runtime output/diagnostics capture cap", category: "subagent" },
|
|
30
32
|
{ key: ENV_KEYS.CLAUDE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Claude runtime output/diagnostics capture cap", category: "subagent" },
|
|
31
33
|
{ key: ENV_KEYS.OPENCODE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "OpenCode runtime output/diagnostics capture cap", category: "subagent" },
|
package/build/config/env.js
CHANGED
|
@@ -141,6 +141,7 @@ const subagentSchema = z.object({
|
|
|
141
141
|
nameOverride: z.string().default(getEnvDefaultValue(ENV_KEYS.AGENT_OVERRIDE)).transform((value) => value.trim()),
|
|
142
142
|
disableSpawn: booleanFlagEnv(ENV_KEYS.DISABLE_SUBAGENT_SPAWN),
|
|
143
143
|
execIdleTimeoutMs: positiveIntEnv(ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS),
|
|
144
|
+
execMaxDurationMs: positiveIntEnv(ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS),
|
|
144
145
|
});
|
|
145
146
|
const codexSchema = z.object({
|
|
146
147
|
execMaxCaptureChars: positiveIntEnv(ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS),
|
|
@@ -175,6 +176,7 @@ const envSchema = z
|
|
|
175
176
|
[ENV_KEYS.AGENT_OVERRIDE]: z.string().optional(),
|
|
176
177
|
[ENV_KEYS.DISABLE_SUBAGENT_SPAWN]: z.string().optional(),
|
|
177
178
|
[ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS]: z.string().optional(),
|
|
179
|
+
[ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS]: z.string().optional(),
|
|
178
180
|
[ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS]: z.string().optional(),
|
|
179
181
|
[ENV_KEYS.CLAUDE_EXEC_MAX_CAPTURE_CHARS]: z.string().optional(),
|
|
180
182
|
[ENV_KEYS.OPENCODE_EXEC_MAX_CAPTURE_CHARS]: z.string().optional(),
|
|
@@ -195,6 +197,7 @@ const envSchema = z
|
|
|
195
197
|
nameOverride: rawEnv[ENV_KEYS.AGENT_OVERRIDE],
|
|
196
198
|
disableSpawn: rawEnv[ENV_KEYS.DISABLE_SUBAGENT_SPAWN],
|
|
197
199
|
execIdleTimeoutMs: rawEnv[ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS],
|
|
200
|
+
execMaxDurationMs: rawEnv[ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS],
|
|
198
201
|
}),
|
|
199
202
|
codex: codexSchema.parse({
|
|
200
203
|
execMaxCaptureChars: rawEnv[ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS],
|
|
@@ -1,39 +1,10 @@
|
|
|
1
|
+
import { getProviderRegistration } from "../agents/providers/registry.js";
|
|
1
2
|
const EMPTY_OWNERSHIP = Object.freeze({
|
|
2
3
|
access: Object.freeze([]),
|
|
3
4
|
network: Object.freeze([]),
|
|
4
5
|
webSearch: Object.freeze([]),
|
|
5
6
|
});
|
|
6
|
-
function owns(config, key) {
|
|
7
|
-
return Object.prototype.hasOwnProperty.call(config, key);
|
|
8
|
-
}
|
|
9
7
|
export function nativePolicyOwnership(instanceName, instance) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
const config = instance.config;
|
|
14
|
-
if (!config)
|
|
15
|
-
return EMPTY_OWNERSHIP;
|
|
16
|
-
const access = [];
|
|
17
|
-
const network = [];
|
|
18
|
-
const webSearch = [];
|
|
19
|
-
const add = (target, key) => {
|
|
20
|
-
target.push({ path: `providers.${instanceName}.config.${key}`, value: config[key] });
|
|
21
|
-
};
|
|
22
|
-
if (owns(config, "sandbox_mode"))
|
|
23
|
-
add(access, "sandbox_mode");
|
|
24
|
-
if (owns(config, "approval_policy"))
|
|
25
|
-
add(access, "approval_policy");
|
|
26
|
-
for (const key of Object.keys(config)) {
|
|
27
|
-
if (key !== "sandbox_workspace_write" && !key.startsWith("sandbox_workspace_write."))
|
|
28
|
-
continue;
|
|
29
|
-
add(access, key);
|
|
30
|
-
add(network, key);
|
|
31
|
-
}
|
|
32
|
-
if (owns(config, "web_search"))
|
|
33
|
-
add(webSearch, "web_search");
|
|
34
|
-
return Object.freeze({
|
|
35
|
-
access: Object.freeze(access),
|
|
36
|
-
network: Object.freeze(network),
|
|
37
|
-
webSearch: Object.freeze(webSearch),
|
|
38
|
-
});
|
|
8
|
+
const owned = getProviderRegistration(instance.kind).nativePolicyOwnership(instanceName, instance);
|
|
9
|
+
return owned ?? EMPTY_OWNERSHIP;
|
|
39
10
|
}
|
|
@@ -21,6 +21,13 @@ export function assertSettingsKnobUsable(loaded, knob) {
|
|
|
21
21
|
if (hits.length === 0)
|
|
22
22
|
return;
|
|
23
23
|
throw new FlowError("INVALID_SETTINGS", `Invalid settings in ${SETTINGS_FILE} (diseased knob '${knob}').`, {
|
|
24
|
-
|
|
24
|
+
facts: {
|
|
25
|
+
kind: "invalid_settings",
|
|
26
|
+
diseases: hits.map((disease) => ({
|
|
27
|
+
source: disease.source,
|
|
28
|
+
...(disease.knob !== undefined ? { knob: disease.knob } : {}),
|
|
29
|
+
reason: disease.reason,
|
|
30
|
+
})),
|
|
31
|
+
},
|
|
25
32
|
});
|
|
26
33
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { getProviderRegistration } from "../../agents/providers/registry.js";
|
|
3
4
|
import { isErrnoException } from "../../errno.js";
|
|
4
5
|
import { SETTINGS_FILE } from "../../keiyaku.js";
|
|
5
6
|
import { getKeiyakuHome } from "../env.js";
|
|
@@ -85,10 +86,17 @@ function collectProviderCandidates(source, rawProviders) {
|
|
|
85
86
|
continue;
|
|
86
87
|
}
|
|
87
88
|
const instance = instanceResult.data;
|
|
88
|
-
|
|
89
|
+
const registration = getProviderRegistration(instance.kind);
|
|
90
|
+
const writableRoots = registration.rejectsGlobalWritableRoots &&
|
|
91
|
+
instance &&
|
|
92
|
+
typeof instance === "object" &&
|
|
93
|
+
"writableRoots" in instance
|
|
94
|
+
? instance.writableRoots
|
|
95
|
+
: undefined;
|
|
96
|
+
if (writableRoots !== undefined && source === "global") {
|
|
89
97
|
let relativeIndex;
|
|
90
|
-
for (let i = 0; i <
|
|
91
|
-
if (!path.posix.isAbsolute(
|
|
98
|
+
for (let i = 0; i < writableRoots.length; i++) {
|
|
99
|
+
if (!path.posix.isAbsolute(writableRoots[i])) {
|
|
92
100
|
relativeIndex = i;
|
|
93
101
|
break;
|
|
94
102
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// Local leaf copy of the Claude setting-source vocabulary so this module never
|
|
3
|
+
// imports keiyaku.js (which re-exports the provider registry and would cycle).
|
|
4
|
+
const CLAUDE_SETTING_SOURCES = ["project", "user", "local"];
|
|
5
|
+
export const tomlValueSchema = z.lazy(() => z.union([
|
|
6
|
+
z.string(),
|
|
7
|
+
z.number(),
|
|
8
|
+
z.boolean(),
|
|
9
|
+
z.array(tomlValueSchema),
|
|
10
|
+
z.record(z.string(), tomlValueSchema),
|
|
11
|
+
]));
|
|
12
|
+
export const structuredTomlValueSchema = z.record(z.string(), tomlValueSchema);
|
|
13
|
+
export const executableSchema = z.string().superRefine((value, ctx) => {
|
|
14
|
+
if (value.length === 0 || /\s/.test(value) || value.includes("\"") || value.includes("'")) {
|
|
15
|
+
ctx.addIssue({
|
|
16
|
+
code: z.ZodIssueCode.custom,
|
|
17
|
+
message: "must be a single program name token with no spaces or quotes.",
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
export const nonblankOptionalString = z
|
|
22
|
+
.string()
|
|
23
|
+
.refine((value) => value.trim().length > 0, { message: "must not be blank." })
|
|
24
|
+
.optional();
|
|
25
|
+
export const providerCommonFields = {
|
|
26
|
+
description: nonblankOptionalString,
|
|
27
|
+
};
|
|
28
|
+
export const providerEnvSchema = z.record(z.string(), z.string()).optional();
|
|
29
|
+
export const FORBIDDEN_CONFIG_KEYS = ["model", "model_reasoning_effort"];
|
|
30
|
+
export function isConfigKeyForbidden(key) {
|
|
31
|
+
return FORBIDDEN_CONFIG_KEYS.includes(key);
|
|
32
|
+
}
|
|
33
|
+
export const claudeSettingSourceSchema = z.enum(CLAUDE_SETTING_SOURCES);
|
|
34
|
+
export const writableRootItemSchema = z.string().superRefine((value, ctx) => {
|
|
35
|
+
if (value.length === 0) {
|
|
36
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not be empty." });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (value.startsWith("~")) {
|
|
40
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not begin with tilde." });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (value.includes("\0")) {
|
|
44
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not contain NUL byte." });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (/\$[A-Za-z_]/.test(value) || /\$\{/.test(value)) {
|
|
48
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "must not contain environment variable references." });
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
});
|