@astrosheep/keiyaku 2.9.4 → 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 +1 -0
- package/build/agents/harness/execution-handle.js +1 -0
- package/build/agents/harness/outcome.js +21 -1
- package/build/agents/harness/projection.js +147 -75
- package/build/agents/providers/codex-app-server/adapter.js +32 -0
- package/build/agents/providers/codex-app-server/events.js +23 -0
- package/build/agents/providers/pi/events.js +4 -3
- 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/flags.js +18 -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/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.js +650 -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 +172 -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 +42 -13
|
@@ -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],
|
package/build/core/amend.js
CHANGED
|
@@ -5,91 +5,33 @@ import { refreshContractView } from "./contract-view.js";
|
|
|
5
5
|
import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
|
|
6
6
|
import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
|
|
7
7
|
import { resolveDefaultBranch } from "./status/drift.js";
|
|
8
|
-
import {
|
|
8
|
+
import { markdownSourceSections, normalizeScopePattern, validateScopeFragmentLines } from "./scope.js";
|
|
9
9
|
import { normalizeSectionTitle } from "./markdown/titles.js";
|
|
10
10
|
import { resolveContractDeliveryCwd } from "./worktree-path.js";
|
|
11
11
|
function amendScopeHeading(name) {
|
|
12
12
|
return `## Scope ${name[0].toUpperCase()}${name.slice(1)}`;
|
|
13
13
|
}
|
|
14
|
-
function sourceLines(markdown) {
|
|
15
|
-
const lines = [];
|
|
16
|
-
let start = 0;
|
|
17
|
-
while (start < markdown.length) {
|
|
18
|
-
const newline = markdown.indexOf("\n", start);
|
|
19
|
-
const end = newline === -1 ? markdown.length : newline;
|
|
20
|
-
const next = newline === -1 ? markdown.length : newline + 1;
|
|
21
|
-
const raw = markdown.slice(start, end);
|
|
22
|
-
lines.push({ text: raw.endsWith("\r") ? raw.slice(0, -1) : raw, start, end, next });
|
|
23
|
-
start = next;
|
|
24
|
-
}
|
|
25
|
-
return lines;
|
|
26
|
-
}
|
|
27
|
-
function amendHeading(line) {
|
|
28
|
-
const match = line.match(/^ {0,3}(#{1,2})(?!#)[ \t]+(.+)$/);
|
|
29
|
-
if (!match)
|
|
30
|
-
return null;
|
|
31
|
-
const level = match[1].length;
|
|
32
|
-
const title = normalizeSectionTitle(match[2]);
|
|
33
|
-
if (level !== 2)
|
|
34
|
-
return { level };
|
|
35
|
-
if (title === "scope add")
|
|
36
|
-
return { level, name: "add" };
|
|
37
|
-
return { level };
|
|
38
|
-
}
|
|
39
|
-
function amendFence(line) {
|
|
40
|
-
const match = line.match(/^ {0,3}(`{3,}|~{3,})/);
|
|
41
|
-
if (!match)
|
|
42
|
-
return null;
|
|
43
|
-
const marker = match[1];
|
|
44
|
-
return { delimiter: marker[0], length: marker.length };
|
|
45
|
-
}
|
|
46
14
|
function parseAmendScopeSections(markdown) {
|
|
47
|
-
const lines = sourceLines(markdown);
|
|
48
15
|
const sections = {};
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
let frontMatterEnd = -1;
|
|
52
|
-
if (lines[0]?.text.trim() === "---") {
|
|
53
|
-
for (let index = 1; index < lines.length; index += 1) {
|
|
54
|
-
if (lines[index].text.trim() === "---") {
|
|
55
|
-
frontMatterEnd = index;
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
const finishActive = (end) => {
|
|
61
|
-
if (!active)
|
|
62
|
-
return;
|
|
63
|
-
sections[active.name] = { ...active, end };
|
|
64
|
-
active = undefined;
|
|
65
|
-
};
|
|
66
|
-
for (let index = 0; index < lines.length; index += 1) {
|
|
67
|
-
const line = lines[index];
|
|
68
|
-
if (index <= frontMatterEnd)
|
|
69
|
-
continue;
|
|
70
|
-
const marker = amendFence(line.text);
|
|
71
|
-
if (fence) {
|
|
72
|
-
if (marker && marker.delimiter === fence.delimiter && marker.length >= fence.length) {
|
|
73
|
-
fence = undefined;
|
|
74
|
-
}
|
|
16
|
+
for (const section of markdownSourceSections(markdown)) {
|
|
17
|
+
if (section.level !== 2)
|
|
75
18
|
continue;
|
|
19
|
+
const title = normalizeSectionTitle(section.title);
|
|
20
|
+
if (title === "scope add") {
|
|
21
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", "Scope Add is obsolete; use ## Scope Append with a fenced gitignore-subset block");
|
|
76
22
|
}
|
|
77
|
-
if (
|
|
78
|
-
fence = marker;
|
|
23
|
+
if (title !== "scope append")
|
|
79
24
|
continue;
|
|
25
|
+
if (sections.append) {
|
|
26
|
+
throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input may contain ${amendScopeHeading("append")} at most once`);
|
|
80
27
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (sections[heading.name]) {
|
|
88
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input may contain ${amendScopeHeading(heading.name)} at most once`);
|
|
89
|
-
}
|
|
90
|
-
active = { name: heading.name, start: line.start, contentStart: line.next };
|
|
28
|
+
sections.append = {
|
|
29
|
+
name: "append",
|
|
30
|
+
start: section.start,
|
|
31
|
+
contentStart: section.contentStart,
|
|
32
|
+
end: section.end,
|
|
33
|
+
};
|
|
91
34
|
}
|
|
92
|
-
finishActive(markdown.length);
|
|
93
35
|
let prose = markdown;
|
|
94
36
|
for (const section of Object.values(sections).sort((left, right) => right.start - left.start)) {
|
|
95
37
|
prose = `${prose.slice(0, section.start)}${prose.slice(section.end)}`;
|
|
@@ -97,30 +39,14 @@ function parseAmendScopeSections(markdown) {
|
|
|
97
39
|
return { sections, prose };
|
|
98
40
|
}
|
|
99
41
|
function scopePatterns(markdown, section) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
.
|
|
103
|
-
.filter((line) => !isBlankScopePatternLine(line))
|
|
104
|
-
.map((pattern) => {
|
|
105
|
-
try {
|
|
106
|
-
// Do not trim() here: gitignore treats trailing `\ ` as a significant space.
|
|
107
|
-
return normalizeScopePattern(pattern);
|
|
108
|
-
}
|
|
109
|
-
catch (error) {
|
|
110
|
-
if (error instanceof ScopePatternError) {
|
|
111
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", error.message);
|
|
112
|
-
}
|
|
113
|
-
throw error;
|
|
114
|
-
}
|
|
42
|
+
return validateScopeFragmentLines(markdown.slice(section.contentStart, section.end).split(/\r?\n/), {
|
|
43
|
+
heading: amendScopeHeading(section.name),
|
|
44
|
+
emptyMessage: `amend input has an empty ${amendScopeHeading(section.name)} section`,
|
|
115
45
|
});
|
|
116
|
-
if (patterns.length === 0) {
|
|
117
|
-
throw new FlowError("INVALID_KEIYAKU_DRAFT", `amend input has an empty ${amendScopeHeading(section.name)} section`);
|
|
118
|
-
}
|
|
119
|
-
return patterns;
|
|
120
46
|
}
|
|
121
47
|
export function buildAmendInput(markdown, cwd, contractId, contractAddressSource) {
|
|
122
48
|
const { sections, prose } = parseAmendScopeSections(markdown);
|
|
123
|
-
const
|
|
49
|
+
const append = sections.append ? scopePatterns(markdown, sections.append) : [];
|
|
124
50
|
if (!prose.trim()) {
|
|
125
51
|
throw new FlowError("EMPTY_PARAM", "amendment cannot be empty");
|
|
126
52
|
}
|
|
@@ -129,7 +55,7 @@ export function buildAmendInput(markdown, cwd, contractId, contractAddressSource
|
|
|
129
55
|
...(contractId ? { contractId } : {}),
|
|
130
56
|
...(contractAddressSource ? { contractAddressSource } : {}),
|
|
131
57
|
amendment: prose,
|
|
132
|
-
...(sections.
|
|
58
|
+
...(sections.append ? { scopeDelta: { add: append } } : {}),
|
|
133
59
|
};
|
|
134
60
|
}
|
|
135
61
|
function requireAmendment(value) {
|
package/build/core/arc.js
CHANGED
|
@@ -9,7 +9,7 @@ import { parseCommandMarkdown, requireMarkdownTextSection, requireMarkdownTitle,
|
|
|
9
9
|
import { resolveContractAddress, withResolvedAddress } from "./addressing.js";
|
|
10
10
|
import { activeLedgerRef, appendWithRetry, readLedger } from "./ledger.js";
|
|
11
11
|
import { refreshContractView } from "./contract-view.js";
|
|
12
|
-
import { findOpenArc, getMaxArc, sealCurrentArc } from "./seal.js";
|
|
12
|
+
import { appendScopeTerms, findOpenArc, getMaxArc, sealCurrentArc } from "./seal.js";
|
|
13
13
|
import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
|
|
14
14
|
import { resolveDefaultBranch } from "./status/drift.js";
|
|
15
15
|
import { persistResponseHistory } from "./transcripts.js";
|
|
@@ -61,6 +61,14 @@ export async function openArc(input) {
|
|
|
61
61
|
throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} not found or not active`);
|
|
62
62
|
}
|
|
63
63
|
assertArcOpenable(input.contractId, ledger.entries);
|
|
64
|
+
await appendScopeTerms({
|
|
65
|
+
cwd: input.cwd,
|
|
66
|
+
renderCwd,
|
|
67
|
+
contractId: input.contractId,
|
|
68
|
+
patterns: input.appendScope,
|
|
69
|
+
actor: input.actor,
|
|
70
|
+
nowMs: input.nowMs,
|
|
71
|
+
});
|
|
64
72
|
// Seal capture needs delivery HEAD; ledger append may use hub or delivery (shared refs).
|
|
65
73
|
const sealed = await sealCurrentArc({
|
|
66
74
|
cwd: renderCwd,
|
|
@@ -68,7 +76,6 @@ export async function openArc(input) {
|
|
|
68
76
|
contractId: input.contractId,
|
|
69
77
|
sealedBy: "arc",
|
|
70
78
|
nowMs: input.nowMs,
|
|
71
|
-
waivePaths: input.waivePaths,
|
|
72
79
|
});
|
|
73
80
|
const at = new Date(input.nowMs).toISOString();
|
|
74
81
|
let arcNumber = 0;
|
|
@@ -93,7 +100,7 @@ export async function openArc(input) {
|
|
|
93
100
|
await refreshContractView({ ledgerCwd: input.cwd, renderCwd, contractId: input.contractId });
|
|
94
101
|
return { contractId: input.contractId, arc: arcNumber, ledgerHead: result.head, sealed };
|
|
95
102
|
}
|
|
96
|
-
export function buildArcInput(content, cwd,
|
|
103
|
+
export function buildArcInput(content, cwd, appendScope = [], contractId, contractAddressSource) {
|
|
97
104
|
const parts = parseCommandMarkdown(content);
|
|
98
105
|
return {
|
|
99
106
|
cwd,
|
|
@@ -102,7 +109,7 @@ export function buildArcInput(content, cwd, waivePaths = [], contractId, contrac
|
|
|
102
109
|
title: requireMarkdownTitle(parts),
|
|
103
110
|
objective: requireMarkdownTextSection(parts, "Objective"),
|
|
104
111
|
brief: requireMarkdownTextSection(parts, "Brief"),
|
|
105
|
-
|
|
112
|
+
appendScope,
|
|
106
113
|
};
|
|
107
114
|
}
|
|
108
115
|
async function readBranchLabels(cwd) {
|
|
@@ -126,16 +133,17 @@ export async function arcKeiyaku(input) {
|
|
|
126
133
|
const title = normalizeInlineTitle(requireText("title", input.title));
|
|
127
134
|
const objective = requireText("objective", input.objective);
|
|
128
135
|
const brief = requireText("brief", input.brief);
|
|
136
|
+
const nowMs = Date.now();
|
|
129
137
|
const opened = await openArc({
|
|
130
138
|
cwd: input.cwd,
|
|
131
139
|
renderCwd,
|
|
132
140
|
contractId,
|
|
133
141
|
actor: ACTOR_IDENTITY,
|
|
134
|
-
nowMs
|
|
142
|
+
nowMs,
|
|
135
143
|
title,
|
|
136
144
|
objective,
|
|
137
145
|
brief,
|
|
138
|
-
|
|
146
|
+
appendScope: input.appendScope,
|
|
139
147
|
});
|
|
140
148
|
const { currentBranch, baseBranch } = await readBranchLabels(renderCwd);
|
|
141
149
|
const summary = opened.sealed
|