@astrosheep/keiyaku 2.9.4 → 2.9.6
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 +1 -0
- package/build/agents/harness/execution-handle.js +1 -0
- package/build/agents/harness/outcome.js +31 -5
- package/build/agents/harness/projection.js +151 -78
- package/build/agents/harness/router.js +2 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +13 -1
- package/build/agents/providers/claude-agent-sdk/registration.js +2 -1
- package/build/agents/providers/codex-app-server/adapter.js +43 -10
- package/build/agents/providers/codex-app-server/events.js +23 -0
- package/build/agents/providers/codex-app-server/registration.js +2 -1
- package/build/agents/providers/opencode-sdk/adapter.js +7 -0
- package/build/agents/providers/opencode-sdk/registration.js +2 -1
- package/build/agents/providers/pi/adapter.js +10 -0
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/providers/pi/registration.js +3 -1
- package/build/agents/types.js +2 -0
- 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/meta.js +1 -1
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +1 -1
- 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/meta.js +20 -11
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +1 -2
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +2 -2
- package/build/cli/commands/contract/renew/meta.js +4 -4
- package/build/cli/commands/metadata.js +3 -2
- package/build/cli/commands/projection/call/meta.js +4 -1
- 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/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +1 -1
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/meta.js +1 -1
- package/build/cli/commands/skills/install/meta.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 +2 -2
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +10 -4
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +2 -3
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +9 -2
- package/build/cli/flags.js +19 -3
- package/build/cli/help.js +3 -3
- package/build/cli/index.js +59 -75
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +19 -2
- package/build/cli/parse-metadata.js +1 -7
- package/build/cli/parse-selectors.js +1 -0
- package/build/cli/parse.js +16 -7
- package/build/cli/projection-address.js +6 -1
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/errors.js +18 -1
- package/build/cli/render/format.js +5 -2
- package/build/cli/render/misc.js +3 -1
- package/build/cli/render/projection-activity.js +12 -6
- package/build/cli/render/status.js +28 -18
- package/build/cli/render/success-response.js +6 -5
- package/build/cli/render/task.js +12 -43
- package/build/cli/render/terminal-failure.js +7 -2
- package/build/cli/render/wait.js +36 -8
- package/build/config/env-keys.js +2 -0
- package/build/config/env.js +3 -0
- package/build/core/amend.js +20 -94
- package/build/core/arc.js +14 -6
- package/build/core/audit/candidate.js +48 -0
- package/build/core/audit/coordinates.js +180 -0
- package/build/core/audit/evidence.js +158 -0
- package/build/core/audit/facade.js +42 -0
- package/build/core/audit/readiness.js +4 -0
- package/build/core/audit/report.js +38 -0
- package/build/core/audit.js +1 -0
- package/build/core/bind.js +1 -1
- package/build/core/call/execution.js +1 -0
- package/build/core/contract-view.js +2 -3
- package/build/core/draft.js +33 -20
- package/build/core/entry.js +3 -4
- package/build/core/markdown/lex.js +2 -1
- package/build/core/projection/generation/database.js +41 -16
- package/build/core/projection/generation/model.js +22 -2
- package/build/core/projection/generation/projection-generation-execution.js +20 -7
- package/build/core/projection/generation/projection-generation-launcher.js +4 -4
- package/build/core/projection/generation/projection-generation-runner.js +1 -0
- package/build/core/projection/generation/store.js +1 -1
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +2 -2
- package/build/core/projection/projection-execution-observer.js +35 -21
- package/build/core/projection/projection-life-observer.js +16 -2
- package/build/core/projection/projection-status.js +67 -22
- package/build/core/projection/projection-terminal-failure.js +2 -0
- package/build/core/projection/projection-wait.js +6 -9
- package/build/core/projection/projection-wake.js +30 -6
- package/build/core/renew.js +41 -22
- package/build/core/scope.js +129 -2
- package/build/core/seal.js +36 -15
- package/build/core/settlement/petition-claim-gates.js +4 -33
- package/build/core/settlement/petition-preview.js +1 -1
- package/build/core/settlement/petition.js +10 -3
- package/build/core/settlement/settlement.js +3 -10
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +48 -28
- package/build/core/stored-agent-event.js +3 -2
- package/build/core/task/board.js +1 -0
- package/build/core/task/commands.js +20 -12
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +1 -1
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +214 -0
- package/build/core/task/settlement-git.js +115 -16
- package/build/core/task/settlement-policy.js +17 -9
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +125 -51
- package/build/core/task/task-store-repository.js +1 -0
- package/build/core/task/task.js +2 -0
- package/build/flow-error.js +2 -4
- package/build/generated/version.js +2 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/index.js +7 -7
- package/build/telemetry/logger.js +4 -2
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +2 -2
- package/skills/keiyaku-akuma/SKILL.md +17 -6
- package/skills/keiyaku-task/SKILL.md +16 -7
- package/skills/keiyaku-workflow/SKILL.md +48 -13
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { asMessage, FlowError } from "../../flow-error.js";
|
|
2
|
+
function streamLines(name, result) {
|
|
3
|
+
const stream = result[name];
|
|
4
|
+
return [
|
|
5
|
+
`${name} tail (${stream.truncated ? `truncated, ${stream.omittedBytes} bytes omitted` : "complete, 0 bytes omitted"}):`,
|
|
6
|
+
stream.tail || "(empty)",
|
|
7
|
+
];
|
|
8
|
+
}
|
|
9
|
+
function renderVerification(report) {
|
|
10
|
+
if (report.verification.status === "not_configured")
|
|
11
|
+
return ["not configured"];
|
|
12
|
+
if (report.verification.status === "not_evaluated")
|
|
13
|
+
return [`not evaluated: ${report.verification.reason}`];
|
|
14
|
+
if (report.verification.status === "unknown")
|
|
15
|
+
return [`unknown: ${report.verification.cause.code}: ${report.verification.cause.message}`];
|
|
16
|
+
const lines = [];
|
|
17
|
+
for (const result of report.verification.results) {
|
|
18
|
+
lines.push(`command ${result.label}`, `exec ${result.command}`, `argv ${JSON.stringify(result.argv)}`, `head ${result.head}`);
|
|
19
|
+
if (result.status === "unverifiable") {
|
|
20
|
+
lines.push(`not executable: ${result.cause}`, "");
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
lines.push(`\`\`\`${result.executor}`, result.body, "\`\`\`", `exit ${result.exitCode} · duration ${result.durationMs}ms`, ...streamLines("stdout", result), ...streamLines("stderr", result), "");
|
|
24
|
+
}
|
|
25
|
+
return lines;
|
|
26
|
+
}
|
|
27
|
+
function renderScope(report) {
|
|
28
|
+
if (!report.scope)
|
|
29
|
+
return ["not evaluated"];
|
|
30
|
+
return report.scope.flatMap((row) => {
|
|
31
|
+
const decisive = row.matcher.decisivePattern
|
|
32
|
+
? `rule ${row.matcher.decisivePattern.index}:${row.matcher.decisivePattern.pattern} (${row.matcher.decisivePattern.effect})`
|
|
33
|
+
: `rule none (${row.matcher.outcome})`;
|
|
34
|
+
const explanations = row.explanations.map((item) => {
|
|
35
|
+
if (item.kind === "file-rename")
|
|
36
|
+
return ` explain file rename ${item.from} -> ${item.to} (${item.similarity}%)`;
|
|
37
|
+
if (item.kind === "symbol-rename")
|
|
38
|
+
return ` explain symbol rename ${item.from} -> ${item.to} at h${item.hunk} old:${item.oldLine ?? "-"} new:${item.newLine ?? "-"}`;
|
|
39
|
+
return ` explain import at h${item.hunk} old:${item.oldLine ?? "-"} new:${item.newLine ?? "-"}`;
|
|
40
|
+
});
|
|
41
|
+
const residue = row.residue.map((item) => ` residue h${item.hunk} old:${item.oldLine ?? "-"} new:${item.newLine ?? "-"} ${item.kind} ${item.content}`);
|
|
42
|
+
return [`${row.class} ${row.path} · ${decisive}`, ...explanations, ...residue];
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function renderReadiness(report) {
|
|
46
|
+
const readiness = report.readiness;
|
|
47
|
+
if (!readiness)
|
|
48
|
+
return ["not evaluated: coordinate race"];
|
|
49
|
+
return [
|
|
50
|
+
`delivery residue tracked=${readiness.deliveryResidue.tracked.length} staged=${readiness.deliveryResidue.staged.length} unstaged=${readiness.deliveryResidue.unstaged.length} untracked=${readiness.deliveryResidue.untracked.length}`,
|
|
51
|
+
`arc open=${readiness.arc.open ?? "none"} max=${readiness.arc.max} fence=${readiness.arc.fence} loose=${readiness.arc.looseCommits.length}`,
|
|
52
|
+
`renew session=${readiness.renewSession.open ? "open" : "none"}`,
|
|
53
|
+
`rewrite guard=${readiness.rewriteGuard.liveProjection ? "live projection" : "clear"}`,
|
|
54
|
+
...readiness.dependencies.map((item) => `dependency ${item.id} ${item.satisfied ? "satisfied" : `open (${item.state})`}`),
|
|
55
|
+
`petition state=${readiness.petition.state}${readiness.petition.queue ? ` queue=${readiness.petition.queue.position ?? "?"}/${readiness.petition.queue.length}` : " queue=none"}`,
|
|
56
|
+
];
|
|
57
|
+
}
|
|
58
|
+
function omissionLine(omission) {
|
|
59
|
+
const subject = omission.hunk === null ? "file" : `hunk ${omission.hunk}`;
|
|
60
|
+
return `omit ${subject} ${omission.path} · ${omission.bytes} bytes · ${omission.reason} · retrieve ${omission.retrieval.argv.map((part) => JSON.stringify(part)).join(" ")}`;
|
|
61
|
+
}
|
|
62
|
+
function renderDiff(report) {
|
|
63
|
+
if (!report.diff || !report.presentation)
|
|
64
|
+
return ["not evaluated"];
|
|
65
|
+
const selected = report.presentation.selected.map((item) => item.content);
|
|
66
|
+
const omissions = report.presentation.omissions.map(omissionLine);
|
|
67
|
+
const rows = report.files?.map((file) => `${file.status} ${file.oldPath ? `${file.oldPath} -> ` : ""}${file.path} · +${file.stats.insertions} -${file.stats.deletions} · ${file.class}`) ?? [];
|
|
68
|
+
return [
|
|
69
|
+
`${report.diff.stat.filesChanged} files · +${report.diff.stat.insertions} -${report.diff.stat.deletions}`,
|
|
70
|
+
`budget ${report.presentation.budget.limit} bytes · used ${report.presentation.budget.used} bytes · omissions ${report.presentation.omissions.length}`,
|
|
71
|
+
...rows,
|
|
72
|
+
...selected,
|
|
73
|
+
...omissions,
|
|
74
|
+
];
|
|
75
|
+
}
|
|
76
|
+
export function buildAuditResponse(report, json) {
|
|
77
|
+
const payload = report;
|
|
78
|
+
if (json)
|
|
79
|
+
return { text: JSON.stringify(report), payload };
|
|
80
|
+
const text = [
|
|
81
|
+
`Audit ${report.contract}`,
|
|
82
|
+
"",
|
|
83
|
+
"Coordinates",
|
|
84
|
+
`ledger ${report.coordinates.ledger.head}`,
|
|
85
|
+
`delivery ${report.coordinates.delivery.ref} ${report.coordinates.delivery.head} tree ${report.coordinates.delivery.tree}`,
|
|
86
|
+
`target ${report.coordinates.target.ref} ${report.coordinates.target.head} tree ${report.coordinates.target.tree}`,
|
|
87
|
+
"",
|
|
88
|
+
"Criteria",
|
|
89
|
+
...report.terms.criteria.map((term) => `criterion ${term}`),
|
|
90
|
+
...report.terms.scope.map((term) => `scope ${term}`),
|
|
91
|
+
...report.terms.appendScope.map((term) => `append-scope ${term}`),
|
|
92
|
+
"",
|
|
93
|
+
"Renew Rehearsal",
|
|
94
|
+
JSON.stringify(report.rehearsal),
|
|
95
|
+
"",
|
|
96
|
+
"Diff",
|
|
97
|
+
...renderDiff(report),
|
|
98
|
+
`counts files=${report.counts.files} selected=${report.counts.selected} omitted=${report.counts.omitted} in-scope=${report.counts.inScope} downgraded=${report.counts.downgraded} violated=${report.counts.violated} findings=${report.counts.findings}`,
|
|
99
|
+
"",
|
|
100
|
+
"Scope",
|
|
101
|
+
...renderScope(report),
|
|
102
|
+
"",
|
|
103
|
+
"Verification",
|
|
104
|
+
...renderVerification(report),
|
|
105
|
+
"Readiness",
|
|
106
|
+
...renderReadiness(report),
|
|
107
|
+
"",
|
|
108
|
+
"Findings",
|
|
109
|
+
...(report.findings.length === 0 ? ["none"] : report.findings.flatMap((finding) => [`${finding.code}: ${finding.detail}`, `Next: ${finding.nextCommand}`])),
|
|
110
|
+
].join("\n");
|
|
111
|
+
return { text, payload };
|
|
112
|
+
}
|
|
113
|
+
export function buildAuditConstructionFailure(error, json) {
|
|
114
|
+
const cause = { code: error instanceof FlowError ? error.code : "INTERNAL_STATE", message: asMessage(error) };
|
|
115
|
+
const payload = { audit: { status: "construction_failed", cause } };
|
|
116
|
+
return {
|
|
117
|
+
text: json ? JSON.stringify(payload) : `Audit construction failure\n${cause.code}: ${cause.message}`,
|
|
118
|
+
payload,
|
|
119
|
+
exitCode: 1,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { asMessage, isFlowError, pickHintsFromError } from "../../flow-error.js";
|
|
1
|
+
import { asMessage, isFlowError, pickHintsFromError, } from "../../flow-error.js";
|
|
2
2
|
import { assertSettingsKnobUsable } from "../../config/settings/disease.js";
|
|
3
3
|
import { loadKeiyakuSettings } from "../../config/settings/loader.js";
|
|
4
4
|
import { loadAkumaCatalog } from "../../config/akuma-loader.js";
|
|
@@ -6,6 +6,20 @@ import { appendDebugLog } from "../../telemetry/debug-log.js";
|
|
|
6
6
|
import { ACTOR_IDENTITY, TOOL_NAMES, BUILTIN_AGENT_NAMES } from "../../keiyaku.js";
|
|
7
7
|
import { buildErrorResponse } from "./misc.js";
|
|
8
8
|
import { addressCarrierFromError } from "../../core/addressing.js";
|
|
9
|
+
import { shellQuote } from "./format.js";
|
|
10
|
+
const TASK_FILTER_GRAMMAR_EXAMPLE = "title~audit,scope";
|
|
11
|
+
function formatTaskFilterExpression(terms) {
|
|
12
|
+
return terms.map((term) => `${term.field}${term.operator}${term.values.join(",")}`).join("|");
|
|
13
|
+
}
|
|
14
|
+
function renderInvalidTaskFilterMessage(facts) {
|
|
15
|
+
const guidance = facts.recoveredTerms.length === 0
|
|
16
|
+
? `Grammar example: keiyaku task ls --filter ${shellQuote(TASK_FILTER_GRAMMAR_EXAMPLE)}`
|
|
17
|
+
: `Paste-ready equivalent for parsed terms: keiyaku task ls --filter ${shellQuote(formatTaskFilterExpression(facts.recoveredTerms))}`;
|
|
18
|
+
return `invalid task filter: ${facts.detail}. Valid fields: ${facts.fields.join(", ")}. `
|
|
19
|
+
+ `Valid operators: ${facts.operators.join(", ")}. `
|
|
20
|
+
+ `Repeat --filter for AND; use commas for same-field OR or | between complete filters. `
|
|
21
|
+
+ guidance;
|
|
22
|
+
}
|
|
9
23
|
function renderScopeViolation(evidence) {
|
|
10
24
|
if (evidence.outcome === "no-positive-match") {
|
|
11
25
|
return ` ${evidence.path}\n no positive pattern matched`;
|
|
@@ -35,6 +49,9 @@ export function renderScopeAuditMessage(scope, evidence) {
|
|
|
35
49
|
].join("\n");
|
|
36
50
|
}
|
|
37
51
|
function renderErrorMessage(error) {
|
|
52
|
+
if (isFlowError(error) && error.facts?.kind === "invalid_task_filter") {
|
|
53
|
+
return renderInvalidTaskFilterMessage(error.facts);
|
|
54
|
+
}
|
|
38
55
|
if (isFlowError(error) && error.facts?.kind === "scope_violation") {
|
|
39
56
|
return renderScopeAuditMessage(error.facts.scope, error.facts.violations);
|
|
40
57
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { getConfig } from "../../config/env.js";
|
|
2
2
|
import { SECTION_ICONS } from "./response-style.js";
|
|
3
|
-
|
|
3
|
+
// Command-copy output is POSIX shell syntax: close the quote, emit a literal
|
|
4
|
+
// apostrophe, then reopen the quote. Other shell dialects are not supported.
|
|
5
|
+
const POSIX_SINGLE_QUOTE_ESCAPE = "'\\''";
|
|
6
|
+
/** Quote a POSIX shell argument only when the token is not already a single safe word. */
|
|
4
7
|
export function shellQuote(value) {
|
|
5
8
|
if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value))
|
|
6
9
|
return value;
|
|
7
|
-
return `'${value.replace(/'/g,
|
|
10
|
+
return `'${value.replace(/'/g, POSIX_SINGLE_QUOTE_ESCAPE)}'`;
|
|
8
11
|
}
|
|
9
12
|
export function formatAgeMs(ms) {
|
|
10
13
|
if (ms === undefined)
|
package/build/cli/render/misc.js
CHANGED
|
@@ -5,7 +5,9 @@ import { prependAddressReceipt, renderAddressCarrier } from "./address.js";
|
|
|
5
5
|
import { commissionSlug } from "../../core/ids.js";
|
|
6
6
|
export function buildErrorResponse(input) {
|
|
7
7
|
const shouldRaiseProtocolError = input.errorType === "runtime_error";
|
|
8
|
-
const text =
|
|
8
|
+
const text = input.errorCode === "PROJECTION_INCOMPATIBLE"
|
|
9
|
+
? `${colorizeErrorStatus(`${RESPONSE_MARKERS.failure} Failed [${input.errorCode}]`)}\n ${input.message}`
|
|
10
|
+
: buildErrorText(input);
|
|
9
11
|
const payload = {
|
|
10
12
|
error: {
|
|
11
13
|
code: input.errorCode,
|
|
@@ -71,9 +71,19 @@ function summarizeProjectionToolLedger(activity, workspaceRoot) {
|
|
|
71
71
|
function toolCountSegments(summary) {
|
|
72
72
|
return summary.counts.map(({ semanticClass, count }) => `${count} ${rollupCountLabel(semanticClass)}`);
|
|
73
73
|
}
|
|
74
|
+
function projectionSummarySegments(summary) {
|
|
75
|
+
const segments = toolCountSegments(summary);
|
|
76
|
+
if (summary.tokens !== undefined) {
|
|
77
|
+
segments.push(`${compactTokens(summary.tokens)} tok`);
|
|
78
|
+
}
|
|
79
|
+
if (summary.costUsd !== undefined) {
|
|
80
|
+
segments.push(`$${summary.costUsd.toFixed(2)}`);
|
|
81
|
+
}
|
|
82
|
+
return segments;
|
|
83
|
+
}
|
|
74
84
|
export function renderProjectionActivitySummary(activity, input) {
|
|
75
85
|
const summary = summarizeProjectionToolLedger(activity, input.workspaceRoot);
|
|
76
|
-
const segments =
|
|
86
|
+
const segments = projectionSummarySegments(summary);
|
|
77
87
|
if (segments.length === 0)
|
|
78
88
|
return undefined;
|
|
79
89
|
const spine = input.state === "dead" || input.state === "lost" ? "┆" : "│";
|
|
@@ -81,11 +91,7 @@ export function renderProjectionActivitySummary(activity, input) {
|
|
|
81
91
|
}
|
|
82
92
|
function renderTerminalRollup(activity, input) {
|
|
83
93
|
const summary = summarizeProjectionToolLedger(activity, input.workspaceRoot);
|
|
84
|
-
const segments =
|
|
85
|
-
...toolCountSegments(summary),
|
|
86
|
-
...(summary.tokens === undefined ? [] : [`${compactTokens(summary.tokens)} tok`]),
|
|
87
|
-
...(summary.costUsd === undefined ? [] : [`$${summary.costUsd.toFixed(2)}`]),
|
|
88
|
-
];
|
|
94
|
+
const segments = projectionSummarySegments(summary);
|
|
89
95
|
const lines = input.diagnostic
|
|
90
96
|
? [fitVariableLine(`${elapsedLabel(input.anchorMs, input.diagnostic.at).padStart(TIME_GUTTER_WIDTH)}┆ ${"warning".padEnd(VERB_WIDTH)} `, compactText(input.diagnostic.text), input.maxColumns)]
|
|
91
97
|
: [];
|
|
@@ -25,6 +25,7 @@ function projectionGlyph(state) {
|
|
|
25
25
|
case "startup-timeout":
|
|
26
26
|
return "!";
|
|
27
27
|
case "unknown":
|
|
28
|
+
case "incompatible":
|
|
28
29
|
return "?";
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -44,9 +45,9 @@ function renderTaskStatusSection(tasks) {
|
|
|
44
45
|
tasks.blocked > 0 ? `${tasks.blocked} blocked` : undefined,
|
|
45
46
|
].filter((segment) => segment !== undefined);
|
|
46
47
|
const lines = [`tasks · ${segments.join(" / ")}`];
|
|
47
|
-
lines.push(...tasks.topTasks.map((task) => ` ${task.id} · P${task.pri} · ${task.state === "in_progress" ? "in_progress" : "ready"} · ${task.title}`));
|
|
48
|
+
lines.push(...tasks.topTasks.map((task) => ` ${task.id} · P${task.pri} · ${task.state === "in_progress" ? "in_progress" : "ready"} · age ${formatAgeMs(task.ageMs)} · active ${formatAgeMs(task.activityAgeMs)} · ${task.title}`));
|
|
48
49
|
if (tasks.omitted > 0) {
|
|
49
|
-
lines.push(` · +${tasks.omitted} more
|
|
50
|
+
lines.push(` · +${tasks.omitted} more — keiyaku task ls`);
|
|
50
51
|
}
|
|
51
52
|
return `${lines.join("\n")}\n`;
|
|
52
53
|
}
|
|
@@ -68,30 +69,34 @@ function terminalFailureSuffix(row) {
|
|
|
68
69
|
function renderProjectionOmission(board) {
|
|
69
70
|
if (!board.omitted)
|
|
70
71
|
return undefined;
|
|
71
|
-
const counts = ["failed", "dead", "done", "killed", "dismissed"]
|
|
72
|
+
const counts = ["failed", "dead", "done", "killed", "dismissed", "incompatible"]
|
|
72
73
|
.flatMap((state) => {
|
|
73
74
|
const count = board.omitted?.byState[state] ?? 0;
|
|
74
75
|
return count > 0 ? [`${count} ${state}`] : [];
|
|
75
76
|
});
|
|
76
|
-
return ` · +${board.omitted.total} not shown (${counts.join(" · ")}) — keiyaku status --all`;
|
|
77
|
+
return ` · +${board.omitted.total} historical projections not shown (${counts.join(" · ")}) — keiyaku status --all`;
|
|
77
78
|
}
|
|
78
79
|
function renderProjectionAge(row) {
|
|
79
|
-
const
|
|
80
|
+
const duration = formatAgeMs(row.durationMs) ?? "?";
|
|
81
|
+
const activity = formatAgeMs(row.activityAgeMs) ?? "?";
|
|
82
|
+
const facts = `dur ${duration} · active ${activity}`;
|
|
80
83
|
if (row.state === "done")
|
|
81
|
-
return
|
|
84
|
+
return `done · ${facts}`;
|
|
82
85
|
if (row.state === "killed")
|
|
83
|
-
return
|
|
86
|
+
return `killed · ${facts}`;
|
|
84
87
|
if (row.state === "dismissed")
|
|
85
|
-
return
|
|
88
|
+
return `dismissed · ${facts}`;
|
|
86
89
|
if (row.state === "failed")
|
|
87
|
-
return
|
|
90
|
+
return `failed · ${facts}`;
|
|
88
91
|
if (row.state === "dead")
|
|
89
|
-
return
|
|
92
|
+
return `dead · ${facts}`;
|
|
90
93
|
if (row.state === "startup-timeout")
|
|
91
|
-
return
|
|
94
|
+
return `startup timed out · ${facts}`;
|
|
92
95
|
if (row.state === "unknown")
|
|
93
|
-
return
|
|
94
|
-
|
|
96
|
+
return `unknown · ${facts}`;
|
|
97
|
+
if (row.state === "incompatible")
|
|
98
|
+
return "incompatible history";
|
|
99
|
+
return facts;
|
|
95
100
|
}
|
|
96
101
|
function renderProjectionTellCounts(row) {
|
|
97
102
|
const { inbox, inflight, submitted, consumed } = row.tellCounts;
|
|
@@ -111,10 +116,11 @@ function projectionActivityState(row) {
|
|
|
111
116
|
case "out": return "running";
|
|
112
117
|
case "startup-timeout": return "stalled";
|
|
113
118
|
case "unknown": return "unknown";
|
|
119
|
+
case "incompatible": return "unknown";
|
|
114
120
|
}
|
|
115
121
|
}
|
|
116
122
|
function renderProjectionActivityLine(row) {
|
|
117
|
-
if (row.state === "startup-timeout" || row.state === "unknown")
|
|
123
|
+
if (row.state === "startup-timeout" || row.state === "unknown" || row.state === "incompatible")
|
|
118
124
|
return undefined;
|
|
119
125
|
if (!row.activity)
|
|
120
126
|
return undefined;
|
|
@@ -133,15 +139,15 @@ function renderProjectionRow(row) {
|
|
|
133
139
|
: row.state);
|
|
134
140
|
const identity = row.alias ? `${row.id} (${row.alias})` : row.id;
|
|
135
141
|
let heading;
|
|
136
|
-
if (row.state === "startup-timeout" || row.state === "unknown") {
|
|
142
|
+
if (row.state === "startup-timeout" || row.state === "unknown" || row.state === "incompatible") {
|
|
137
143
|
const akuma = (row.akuma ?? "(unknown)").padEnd(18);
|
|
138
144
|
heading = ` ${glyph} ${identity} ${akuma} ${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
|
|
139
145
|
}
|
|
140
146
|
else if (row.state === "minting") {
|
|
141
|
-
heading = ` ${glyph} ${identity.padEnd(18)} (minting)${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
|
|
147
|
+
heading = ` ${glyph} ${identity.padEnd(18)} (minting) · ${renderProjectionAge(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
|
|
142
148
|
}
|
|
143
149
|
else {
|
|
144
|
-
const age = renderProjectionAge(row)
|
|
150
|
+
const age = renderProjectionAge(row);
|
|
145
151
|
const akuma = (row.akuma ?? "(unknown)").padEnd(18);
|
|
146
152
|
heading = ` ${glyph} ${identity} ${akuma} ${age}${renderProjectionTellCounts(row)}${terminalFailureSuffix(row)}${renderProjectionDiagnostics(row)}`.trimEnd();
|
|
147
153
|
}
|
|
@@ -154,7 +160,8 @@ function isTerminalProjectionStatus(row) {
|
|
|
154
160
|
|| row.state === "killed"
|
|
155
161
|
|| row.state === "dismissed"
|
|
156
162
|
|| row.state === "failed"
|
|
157
|
-
|| row.state === "dead"
|
|
163
|
+
|| row.state === "dead"
|
|
164
|
+
|| row.state === "incompatible";
|
|
158
165
|
}
|
|
159
166
|
export function renderProjectionFilteredStatus(board, projectionId) {
|
|
160
167
|
const head = board.defaultHead ? shortCommitHash(board.defaultHead) : "(no HEAD)";
|
|
@@ -167,6 +174,9 @@ export function renderProjectionFilteredStatus(board, projectionId) {
|
|
|
167
174
|
return renderTerminalFailureFace(projectionId, row.terminalFailure).join("\n");
|
|
168
175
|
}
|
|
169
176
|
const lines = [heading, "", ...renderProjectionRow(row), ""];
|
|
177
|
+
if (row.observation.compatibility === "incompatible") {
|
|
178
|
+
return `${lines.join("\n")}\n`;
|
|
179
|
+
}
|
|
170
180
|
if (!isTerminalProjectionStatus(row))
|
|
171
181
|
lines.push(`» ${formatTellCommand(projectionId, '"..."')}`);
|
|
172
182
|
lines.push(`» keiyaku wait ${projectionId}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { repositoryCoordinateFromAddress } from "../commands/shared.js";
|
|
2
|
+
import { writeCliOutput } from "../output-stream-error-policy.js";
|
|
2
3
|
import { renderResolvedAddressReceipt } from "./address.js";
|
|
3
4
|
import { formatCallNextAction } from "./shared.js";
|
|
4
5
|
function responseText(response) {
|
|
@@ -54,24 +55,24 @@ function conversationalFooter(response) {
|
|
|
54
55
|
}
|
|
55
56
|
return lines.join("\n");
|
|
56
57
|
}
|
|
57
|
-
export function writeSuccessResponse(command, flags, response) {
|
|
58
|
+
export async function writeSuccessResponse(command, flags, response) {
|
|
58
59
|
// Plain tell is always silent; tell --wait owns the ordinary wait response.
|
|
59
60
|
if (command === "tell" && flags.timeoutMs === undefined)
|
|
60
61
|
return;
|
|
61
62
|
if (command === "bind" && flags.dryRun) {
|
|
62
63
|
// Canonical Markdown already ends with exactly one newline.
|
|
63
|
-
process.stdout
|
|
64
|
+
await writeCliOutput(process.stdout, responseText(response));
|
|
64
65
|
return;
|
|
65
66
|
}
|
|
66
67
|
if (command !== "revive") {
|
|
67
|
-
process.stdout
|
|
68
|
+
await writeCliOutput(process.stdout, `${responseText(response)}\n`);
|
|
68
69
|
return;
|
|
69
70
|
}
|
|
70
71
|
const data = responseData(response);
|
|
71
72
|
const answer = typeof data.summary === "string" ? data.summary.trim() : responseText(response).trim();
|
|
72
73
|
const footer = conversationalFooter(response);
|
|
73
|
-
process.stdout
|
|
74
|
+
await writeCliOutput(process.stdout, `${answer}\n`);
|
|
74
75
|
if (footer) {
|
|
75
|
-
process.stderr
|
|
76
|
+
await writeCliOutput(process.stderr, `${footer}\n`);
|
|
76
77
|
}
|
|
77
78
|
}
|
package/build/cli/render/task.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
import { commissionSlug } from "../../core/ids.js";
|
|
2
|
+
import { deriveTaskDisplay as deriveStructuredTaskDisplay, selectTaskList, } from "../../core/task/index.js";
|
|
2
3
|
export function shortContractId(contractId) {
|
|
3
4
|
return commissionSlug(contractId);
|
|
4
5
|
}
|
|
5
6
|
export function deriveTaskDisplay(task) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
if (task.state === "drop")
|
|
9
|
-
return "dropped";
|
|
10
|
-
if (task.contractId !== undefined)
|
|
11
|
-
return `bound(${shortContractId(task.contractId)})`;
|
|
12
|
-
if (task.state === "in_progress")
|
|
13
|
-
return "in_progress";
|
|
14
|
-
return task.blocked ? "blocked" : "ready";
|
|
7
|
+
const display = deriveStructuredTaskDisplay(task);
|
|
8
|
+
return display === "bound" ? `bound(${shortContractId(task.contractId)})` : display;
|
|
15
9
|
}
|
|
16
10
|
function renderTaskRowWithId(task, id) {
|
|
17
11
|
return `${id} · P${task.pri} · ${deriveTaskDisplay(task)} · ${task.title}`;
|
|
@@ -25,43 +19,14 @@ export function renderTaskMutationRow(task) {
|
|
|
25
19
|
export function renderTaskRow(task, completeId = false) {
|
|
26
20
|
return completeId ? renderTaskMutationRow(task) : renderTaskListRow(task);
|
|
27
21
|
}
|
|
28
|
-
function displayOrder(display) {
|
|
29
|
-
if (display === "in_progress")
|
|
30
|
-
return 0;
|
|
31
|
-
if (display === "ready")
|
|
32
|
-
return 1;
|
|
33
|
-
if (display === "blocked")
|
|
34
|
-
return 2;
|
|
35
|
-
if (display.startsWith("bound("))
|
|
36
|
-
return 3;
|
|
37
|
-
return display === "done" ? 4 : 5;
|
|
38
|
-
}
|
|
39
|
-
function compareText(left, right) {
|
|
40
|
-
return left < right ? -1 : left > right ? 1 : 0;
|
|
41
|
-
}
|
|
42
|
-
function compareTasks(left, right) {
|
|
43
|
-
const displayDifference = displayOrder(deriveTaskDisplay(left)) - displayOrder(deriveTaskDisplay(right));
|
|
44
|
-
if (displayDifference !== 0)
|
|
45
|
-
return displayDifference;
|
|
46
|
-
if (left.pri !== right.pri)
|
|
47
|
-
return left.pri - right.pri;
|
|
48
|
-
const createdDifference = compareText(left.createdAt, right.createdAt);
|
|
49
|
-
return createdDifference || compareText(left.id, right.id);
|
|
50
|
-
}
|
|
51
|
-
function selected(task, selection) {
|
|
52
|
-
const display = deriveTaskDisplay(task);
|
|
53
|
-
const terminal = display === "done" || display === "dropped";
|
|
54
|
-
if (selection === "done")
|
|
55
|
-
return terminal;
|
|
56
|
-
if (selection === "default")
|
|
57
|
-
return !terminal;
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
22
|
export function groupAndSortTasks(tasks, selection = "default") {
|
|
61
|
-
return tasks
|
|
23
|
+
return selectTaskList(tasks, { selection });
|
|
62
24
|
}
|
|
63
25
|
export function renderTaskList(tasks, options = {}) {
|
|
64
|
-
return
|
|
26
|
+
return selectTaskList(tasks, options).map(renderTaskListRow).join("\n");
|
|
27
|
+
}
|
|
28
|
+
export function renderSelectedTaskList(tasks) {
|
|
29
|
+
return tasks.map(renderTaskListRow).join("\n");
|
|
65
30
|
}
|
|
66
31
|
function renderIds(ids) {
|
|
67
32
|
return ids.length === 0 ? "(none)" : ids.join(", ");
|
|
@@ -128,6 +93,7 @@ export function taskJson(task) {
|
|
|
128
93
|
from: [...task.from],
|
|
129
94
|
contractId: task.contractId ?? null,
|
|
130
95
|
createdAt: task.createdAt,
|
|
96
|
+
updatedAt: task.updatedAt ?? task.createdAt,
|
|
131
97
|
creator: task.creator,
|
|
132
98
|
};
|
|
133
99
|
}
|
|
@@ -151,3 +117,6 @@ export function renderTaskShowJson(task, tree) {
|
|
|
151
117
|
export function renderTaskListJson(tasks, selection = "default") {
|
|
152
118
|
return `${JSON.stringify(groupAndSortTasks(tasks, selection).map(taskJson))}\n`;
|
|
153
119
|
}
|
|
120
|
+
export function renderSelectedTaskListJson(tasks) {
|
|
121
|
+
return `${JSON.stringify(tasks.map(taskJson))}\n`;
|
|
122
|
+
}
|
|
@@ -14,6 +14,10 @@ export function terminalFailureColdStatement(failure) {
|
|
|
14
14
|
switch (failure.code) {
|
|
15
15
|
case "SUBAGENT_TIMEOUT":
|
|
16
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";
|
|
17
21
|
case "SUBAGENT_PROVIDER_UNAVAILABLE":
|
|
18
22
|
return "the provider did not answer";
|
|
19
23
|
case "SUBAGENT_NON_ZERO_EXIT":
|
|
@@ -29,8 +33,9 @@ function terminalFailureEvidence(failure, statement) {
|
|
|
29
33
|
&& failure.code === "SUBAGENT_NON_ZERO_EXIT"
|
|
30
34
|
&& failure.exitCode !== undefined;
|
|
31
35
|
const parts = [];
|
|
32
|
-
if (failure.timeoutMs !== undefined)
|
|
33
|
-
parts.push(`idle ${failure.timeoutMs}ms`);
|
|
36
|
+
if (failure.timeoutMs !== undefined) {
|
|
37
|
+
parts.push(failure.code === "SUBAGENT_POLICY_BUDGET" ? `budget ${failure.timeoutMs}ms` : `idle ${failure.timeoutMs}ms`);
|
|
38
|
+
}
|
|
34
39
|
if (failure.signal)
|
|
35
40
|
parts.push(`signal ${failure.signal}`);
|
|
36
41
|
if (!exitAlreadyInStatement && failure.exitCode !== undefined)
|
package/build/cli/render/wait.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
3
|
import { formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
|
|
4
4
|
import { renderTerminalFailureFace } from "./terminal-failure.js";
|
|
@@ -220,7 +220,22 @@ export function buildWaitResponse(projectionId, result, options = {}) {
|
|
|
220
220
|
if (rendered.lines.length === 0 && state === "running") {
|
|
221
221
|
lines.push(" not a word out of it yet — pulse is steady");
|
|
222
222
|
}
|
|
223
|
-
|
|
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);
|
|
224
239
|
if (nextActions.length > 0)
|
|
225
240
|
lines.push("");
|
|
226
241
|
lines.push(...nextActions);
|
|
@@ -237,15 +252,28 @@ export function buildProjectionWaitSetResponse(result) {
|
|
|
237
252
|
const rendered = result.results
|
|
238
253
|
.slice()
|
|
239
254
|
.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
240
|
-
.map((member) => ({
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
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");
|
|
245
273
|
const exitCode = rendered.reduce((current, { response }) => {
|
|
246
274
|
if (response.exitCode === 130)
|
|
247
275
|
return 130;
|
|
248
276
|
return response.exitCode === 1 ? 1 : current;
|
|
249
|
-
},
|
|
277
|
+
}, undefined);
|
|
250
278
|
return exitCode === undefined ? textResponse(text) : { ...textResponse(text), exitCode };
|
|
251
279
|
}
|
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",
|
|
@@ -26,6 +27,7 @@ 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
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],
|