@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
package/build/cli/index.js
CHANGED
|
@@ -5,16 +5,19 @@ import { compileBindDraftFlags } from "../core/draft.js";
|
|
|
5
5
|
import { handleCliError } from "./render/errors.js";
|
|
6
6
|
import { FLAG_SPECS } from "./flags.js";
|
|
7
7
|
import { renderCliCommandHelp as renderCliCommandHelpText, renderCliHelp as renderCliHelpText, } from "./help.js";
|
|
8
|
-
import {
|
|
8
|
+
import { isPetitionDryRunInvocation, parseCliArgs } from "./parse.js";
|
|
9
9
|
import { getCommandMetadata } from "./commands/metadata.js";
|
|
10
10
|
import { loadCommandHandler } from "./commands/registry.js";
|
|
11
11
|
import { shellQuote } from "./render/format.js";
|
|
12
12
|
import { writeSuccessResponse } from "./render/success-response.js";
|
|
13
|
+
import { writeCliOutput } from "./output-stream-error-policy.js";
|
|
13
14
|
function commandRequiresStdin(command) {
|
|
14
|
-
|
|
15
|
+
const stdin = getCommandMetadata(command).stdin;
|
|
16
|
+
return stdin.mode === "document" && stdin.selector.required;
|
|
15
17
|
}
|
|
16
18
|
function commandAcceptsOptionalStdin(command) {
|
|
17
|
-
|
|
19
|
+
const stdin = getCommandMetadata(command).stdin;
|
|
20
|
+
return stdin.mode === "document" && !stdin.selector.required;
|
|
18
21
|
}
|
|
19
22
|
function commandSavesFailedStdin(command) {
|
|
20
23
|
return (commandRequiresStdin(command) || commandAcceptsOptionalStdin(command)) && command !== "call";
|
|
@@ -67,8 +70,6 @@ function prepareBindInput(stdin, flags) {
|
|
|
67
70
|
return stdin;
|
|
68
71
|
}
|
|
69
72
|
async function readStdin() {
|
|
70
|
-
if (process.stdin.isTTY)
|
|
71
|
-
return "";
|
|
72
73
|
let data = "";
|
|
73
74
|
process.stdin.setEncoding("utf-8");
|
|
74
75
|
for await (const chunk of process.stdin)
|
|
@@ -129,12 +130,12 @@ function retryHint(input) {
|
|
|
129
130
|
if (input.command === "bind") {
|
|
130
131
|
const flagTokens = bindRetryFlagTokens(input.flags);
|
|
131
132
|
const flagPart = flagTokens.length > 0 ? ` ${flagTokens.join(" ")}` : "";
|
|
132
|
-
return `Retry: keiyaku bind${flagPart} < ${draftArg}`;
|
|
133
|
+
return `Retry: keiyaku bind${flagPart} - < ${draftArg}`;
|
|
133
134
|
}
|
|
134
135
|
if (input.flags.cwd === undefined) {
|
|
135
|
-
return `Retry: keiyaku ${input.command} < ${shellQuote(input.draftPath)}`;
|
|
136
|
+
return `Retry: keiyaku ${input.command} - < ${shellQuote(input.draftPath)}`;
|
|
136
137
|
}
|
|
137
|
-
return `Retry: keiyaku ${input.command} --cwd ${shellQuote(input.flags.cwd)} < ${draftArg}`;
|
|
138
|
+
return `Retry: keiyaku ${input.command} --cwd ${shellQuote(input.flags.cwd)} - < ${draftArg}`;
|
|
138
139
|
}
|
|
139
140
|
async function printFailure(error, cwd) {
|
|
140
141
|
const response = await handleCliError({
|
|
@@ -142,14 +143,14 @@ async function printFailure(error, cwd) {
|
|
|
142
143
|
cwd,
|
|
143
144
|
logLabel: "cli",
|
|
144
145
|
});
|
|
145
|
-
process.stderr
|
|
146
|
+
await writeCliOutput(process.stderr, `${responseText(response)}\n`);
|
|
146
147
|
}
|
|
147
148
|
function failureExitCode(error) {
|
|
148
149
|
return error instanceof Error && error.name === "AbortError" ? 130 : 1;
|
|
149
150
|
}
|
|
150
151
|
async function handleFailureAfterStdin(input) {
|
|
151
152
|
if (input.response) {
|
|
152
|
-
process.stderr
|
|
153
|
+
await writeCliOutput(process.stderr, `${responseText(input.response)}\n`);
|
|
153
154
|
}
|
|
154
155
|
else {
|
|
155
156
|
await printFailure(input.error ?? new Error("Unknown CLI failure"), input.cwd);
|
|
@@ -164,7 +165,7 @@ async function handleFailureAfterStdin(input) {
|
|
|
164
165
|
content: input.stdin,
|
|
165
166
|
});
|
|
166
167
|
if (draftPath) {
|
|
167
|
-
process.stderr
|
|
168
|
+
await writeCliOutput(process.stderr, `\nSaved stdin input to ${draftPath}.\n${retryHint({
|
|
168
169
|
command: input.command,
|
|
169
170
|
draftPath,
|
|
170
171
|
cwd: input.cwd,
|
|
@@ -173,7 +174,7 @@ async function handleFailureAfterStdin(input) {
|
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
catch (draftError) {
|
|
176
|
-
process.stderr
|
|
177
|
+
await writeCliOutput(process.stderr, `\nFailed to save stdin input: ${asMessage(draftError)}\n`);
|
|
177
178
|
}
|
|
178
179
|
return 1;
|
|
179
180
|
}
|
|
@@ -182,38 +183,42 @@ async function runResponse(command, flags, stdin, positional) {
|
|
|
182
183
|
const handler = await loadCommandHandler(command);
|
|
183
184
|
return await handler(stdin, flags, signal, positional);
|
|
184
185
|
}
|
|
185
|
-
function
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (command === "tell")
|
|
189
|
-
return positional[1];
|
|
190
|
-
if (command === "revive")
|
|
191
|
-
return positional[1];
|
|
192
|
-
return undefined;
|
|
193
|
-
}
|
|
194
|
-
async function readBodyInput(command, positional, cwd) {
|
|
195
|
-
if (!commandUsesPromptInput(command))
|
|
196
|
-
return undefined;
|
|
197
|
-
const token = bodyToken(command, positional);
|
|
198
|
-
if (token === undefined) {
|
|
199
|
-
if (command === "revive")
|
|
200
|
-
return "";
|
|
201
|
-
await printFailure(new FlowError("EMPTY_PARAM", `${command} body cannot be empty`), cwd);
|
|
202
|
-
return undefined;
|
|
203
|
-
}
|
|
204
|
-
if (token !== "-") {
|
|
205
|
-
if (!token.trim()) {
|
|
206
|
-
await printFailure(new FlowError("EMPTY_PARAM", `${command} body cannot be empty`), cwd);
|
|
207
|
-
return undefined;
|
|
208
|
-
}
|
|
209
|
-
return token;
|
|
210
|
-
}
|
|
211
|
-
const stdin = await readStdin();
|
|
212
|
-
if (!stdin.trim()) {
|
|
213
|
-
await printFailure(new FlowError("EMPTY_PARAM", `${command} body cannot be empty`), cwd);
|
|
186
|
+
function selectedArgument(parsed) {
|
|
187
|
+
const stdin = getCommandMetadata(parsed.command).stdin;
|
|
188
|
+
if (stdin.selector === undefined)
|
|
214
189
|
return undefined;
|
|
215
|
-
|
|
216
|
-
|
|
190
|
+
if (stdin.selector.kind === "positional") {
|
|
191
|
+
return { token: parsed.positional[stdin.selector.index], replace: () => parsed.flags };
|
|
192
|
+
}
|
|
193
|
+
const flagName = stdin.selector.name;
|
|
194
|
+
return {
|
|
195
|
+
token: parsed.flags[flagName],
|
|
196
|
+
replace: (value) => ({ ...parsed.flags, [flagName]: value }),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async function resolveCliInput(parsed) {
|
|
200
|
+
const stdinMeta = getCommandMetadata(parsed.command).stdin;
|
|
201
|
+
const selected = selectedArgument(parsed);
|
|
202
|
+
const token = selected?.token;
|
|
203
|
+
const selectsStdin = token === "-";
|
|
204
|
+
if (selectsStdin && process.stdin.isTTY) {
|
|
205
|
+
throw new FlowError("EMPTY_PARAM", `${parsed.command} literal '-' requires piped stdin`);
|
|
206
|
+
}
|
|
207
|
+
const piped = selectsStdin ? await readStdin() : "";
|
|
208
|
+
const input = selectsStdin ? piped : token ?? "";
|
|
209
|
+
if (stdinMeta.selector?.required && token === undefined) {
|
|
210
|
+
const message = stdinMeta.mode === "document"
|
|
211
|
+
? `${parsed.command} requires literal '-' to read Markdown from stdin`
|
|
212
|
+
: `${parsed.command} body cannot be empty`;
|
|
213
|
+
throw new FlowError("EMPTY_PARAM", message);
|
|
214
|
+
}
|
|
215
|
+
if (token !== undefined && stdinMeta.selector?.rejectBlank && !input.trim()) {
|
|
216
|
+
const message = stdinMeta.mode === "document"
|
|
217
|
+
? `No Markdown input received on stdin.\n\nExample:\n ${usageExample(parsed.command)}`
|
|
218
|
+
: `${parsed.command} body cannot be empty`;
|
|
219
|
+
throw new FlowError("EMPTY_PARAM", message);
|
|
220
|
+
}
|
|
221
|
+
return { stdin: input, flags: selected?.replace(input) ?? parsed.flags };
|
|
217
222
|
}
|
|
218
223
|
function usageExample(command) {
|
|
219
224
|
const meta = getCommandMetadata(command);
|
|
@@ -229,40 +234,19 @@ export async function runCliCommand(tokens) {
|
|
|
229
234
|
return isPetitionDryRunInvocation(tokens) ? 2 : 1;
|
|
230
235
|
}
|
|
231
236
|
if (parsed.helpRequested) {
|
|
232
|
-
process.stdout
|
|
237
|
+
await writeCliOutput(process.stdout, `${renderCliCommandHelp(resolveCliHelpCommand(parsed.command))}\n`);
|
|
233
238
|
return 0;
|
|
234
239
|
}
|
|
235
240
|
const cwd = parsed.flags.cwd ?? process.cwd();
|
|
236
|
-
let stdin
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
await printFailure(new FlowError("EMPTY_PARAM", "task add input cannot be blank"), cwd);
|
|
242
|
-
return 1;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
else if (parsed.command === "task update" && parsed.flags.taskBody === "-") {
|
|
246
|
-
stdin = await readStdin();
|
|
247
|
-
}
|
|
248
|
-
else if (commandRequiresStdin(parsed.command)) {
|
|
249
|
-
stdin = await readStdin();
|
|
250
|
-
if (!stdin.trim()) {
|
|
251
|
-
await printFailure(new FlowError("EMPTY_PARAM", `No Markdown input received on stdin.\n\nExample:\n ${usageExample(parsed.command)}`), cwd);
|
|
252
|
-
return 1;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
else if (commandAcceptsOptionalStdin(parsed.command)) {
|
|
256
|
-
// Optional stdin: bind prepares domain flags or blank-stdin errors itself;
|
|
257
|
-
// petition lets an empty body reach the oath gate as OATH_MISSING.
|
|
258
|
-
stdin = await readStdin();
|
|
241
|
+
let stdin;
|
|
242
|
+
try {
|
|
243
|
+
const resolved = await resolveCliInput(parsed);
|
|
244
|
+
stdin = resolved.stdin;
|
|
245
|
+
parsed = { ...parsed, flags: resolved.flags };
|
|
259
246
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
return 1;
|
|
264
|
-
}
|
|
265
|
-
stdin = body ?? "";
|
|
247
|
+
catch (error) {
|
|
248
|
+
await printFailure(error, cwd);
|
|
249
|
+
return 1;
|
|
266
250
|
}
|
|
267
251
|
// Bind dry-run must compile and return before repository/cwd resolution or filesystem effects.
|
|
268
252
|
if (parsed.command === "bind") {
|
|
@@ -296,7 +280,7 @@ export async function runCliCommand(tokens) {
|
|
|
296
280
|
}
|
|
297
281
|
const success = !response.payload || !("error" in response.payload);
|
|
298
282
|
if (success) {
|
|
299
|
-
writeSuccessResponse(parsed.command, parsed.flags, response);
|
|
283
|
+
await writeSuccessResponse(parsed.command, parsed.flags, response);
|
|
300
284
|
return response.exitCode ?? 0;
|
|
301
285
|
}
|
|
302
286
|
if (commandRequiresStdin(parsed.command) || (parsed.command === "bind" && !parsed.flags.dryRun)) {
|
|
@@ -309,7 +293,7 @@ export async function runCliCommand(tokens) {
|
|
|
309
293
|
saveStdin: !(parsed.command === "bind" && hasBindDomainFlags(parsed.flags)),
|
|
310
294
|
});
|
|
311
295
|
}
|
|
312
|
-
process.stderr
|
|
296
|
+
await writeCliOutput(process.stderr, `${responseText(response)}\n`);
|
|
313
297
|
return 1;
|
|
314
298
|
}
|
|
315
299
|
export function renderCliCommandHelp(command) {
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
export function isBrokenPipeError(error) {
|
|
2
|
+
return (typeof error === "object" &&
|
|
3
|
+
error !== null &&
|
|
4
|
+
"code" in error &&
|
|
5
|
+
error.code === "EPIPE");
|
|
6
|
+
}
|
|
7
|
+
/** Resolve only after Node reports that this chunk has been flushed. */
|
|
8
|
+
export function writeCliOutput(stream, chunk) {
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
stream.write(chunk, (error) => {
|
|
11
|
+
if (error && !isBrokenPipeError(error)) {
|
|
12
|
+
reject(error);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
resolve();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
1
19
|
/**
|
|
2
20
|
* Install a process-level broken-pipe policy on each supplied stream.
|
|
3
21
|
* EPIPE is silent; every other emitted value is rethrown unchanged.
|
|
@@ -5,12 +23,8 @@
|
|
|
5
23
|
export function installCliOutputStreamErrorPolicy(...streams) {
|
|
6
24
|
for (const stream of streams) {
|
|
7
25
|
stream.on("error", (error) => {
|
|
8
|
-
if (
|
|
9
|
-
error !== null &&
|
|
10
|
-
"code" in error &&
|
|
11
|
-
error.code === "EPIPE") {
|
|
26
|
+
if (isBrokenPipeError(error))
|
|
12
27
|
return;
|
|
13
|
-
}
|
|
14
28
|
throw error;
|
|
15
29
|
});
|
|
16
30
|
}
|
package/build/cli/parse-flags.js
CHANGED
|
@@ -99,8 +99,8 @@ export function assignFlag(flags, name, value) {
|
|
|
99
99
|
case "dry-run":
|
|
100
100
|
flags.dryRun = Boolean(value);
|
|
101
101
|
return;
|
|
102
|
-
case "
|
|
103
|
-
flags.
|
|
102
|
+
case "append-scope":
|
|
103
|
+
flags.appendScope = [...(flags.appendScope ?? []), String(value)];
|
|
104
104
|
return;
|
|
105
105
|
case "resolve":
|
|
106
106
|
flags.renewResolve = Boolean(value);
|
|
@@ -138,9 +138,26 @@ export function assignFlag(flags, name, value) {
|
|
|
138
138
|
case "json":
|
|
139
139
|
flags.json = Boolean(value);
|
|
140
140
|
return;
|
|
141
|
+
case "diff-budget": {
|
|
142
|
+
const parsed = Number(String(value));
|
|
143
|
+
if (!Number.isSafeInteger(parsed) || parsed < 0) {
|
|
144
|
+
throw new FlowError("EMPTY_PARAM", "option --diff-budget requires a non-negative safe integer byte count");
|
|
145
|
+
}
|
|
146
|
+
flags.auditDiffBudgetBytes = parsed;
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
141
149
|
case "done":
|
|
142
150
|
flags.done = Boolean(value);
|
|
143
151
|
return;
|
|
152
|
+
case "filter":
|
|
153
|
+
flags.taskFilters = [...(flags.taskFilters ?? []), String(value)];
|
|
154
|
+
return;
|
|
155
|
+
case "sort":
|
|
156
|
+
if (flags.taskSort !== undefined) {
|
|
157
|
+
throw new FlowError("EMPTY_PARAM", "option --sort may only be specified once");
|
|
158
|
+
}
|
|
159
|
+
flags.taskSort = String(value);
|
|
160
|
+
return;
|
|
144
161
|
case "pri": {
|
|
145
162
|
const raw = String(value);
|
|
146
163
|
if (!/^[0-3]$/.test(raw)) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { FlowError } from "../flow-error.js";
|
|
2
2
|
import { HELP_FLAGS, SHORT_FLAG_ALIASES, VALUE_FLAGS } from "./flags.js";
|
|
3
|
-
import { commandParseOrder
|
|
3
|
+
import { commandParseOrder } from "./commands/metadata.js";
|
|
4
4
|
import { TASK_SUBCOMMANDS } from "./types.js";
|
|
5
5
|
export function normalizeContractAddress(raw) {
|
|
6
6
|
const value = raw.startsWith("@") ? raw.slice(1) : raw;
|
|
@@ -42,9 +42,6 @@ export function isPetitionDryRunInvocation(tokens) {
|
|
|
42
42
|
}
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
|
-
export function commandUsesPromptInput(command) {
|
|
46
|
-
return isCallCommand(command) || command === "tell" || command === "revive";
|
|
47
|
-
}
|
|
48
45
|
export function parseWaitTimeout(value) {
|
|
49
46
|
const matched = /^(?<amount>[1-9][0-9]*)(?<unit>[smh])$/.exec(value);
|
|
50
47
|
if (!matched?.groups) {
|
|
@@ -97,9 +94,6 @@ export function commandPositionalRange(command) {
|
|
|
97
94
|
}
|
|
98
95
|
return { min: 0, max: 0 };
|
|
99
96
|
}
|
|
100
|
-
export function commandRequiresStdin(command) {
|
|
101
|
-
return getCommandMetadata(command).stdin === "required";
|
|
102
|
-
}
|
|
103
97
|
export function resolveCommand(tokens) {
|
|
104
98
|
if (tokens[0] === "petition" && (tokens[1] === "claim" || tokens[1] === "forfeit")) {
|
|
105
99
|
throw new FlowError("UNKNOWN_COMMAND", `unknown command: petition ${tokens[1]}`);
|
package/build/cli/parse.js
CHANGED
|
@@ -2,11 +2,12 @@ import { FlowError } from "../flow-error.js";
|
|
|
2
2
|
import { agentNameSchema } from "../config/settings/schema.js";
|
|
3
3
|
import { isResponseArtifactId } from "../core/response-artifact-id.js";
|
|
4
4
|
import { HELP_FLAGS } from "./flags.js";
|
|
5
|
+
import { getCommandMetadata } from "./commands/metadata.js";
|
|
5
6
|
import { assertAllowedFlag, assignFlag, BOOLEAN_FLAGS, CONTROL_FLAGS, parseFlagName, readValueFlag, SHORT_FLAG_ALIASES, VALUE_FLAGS, } from "./parse-flags.js";
|
|
6
|
-
import { commandPositionalRange,
|
|
7
|
+
import { commandPositionalRange, isCallCommand, resolveCommand, splitAtLiteralBoundary, TASK_SUBCOMMANDS, } from "./parse-metadata.js";
|
|
7
8
|
import { applyCommissionSelector, assertCommissionSelectorAllowed, assertProjectionSelectorPresent, } from "./parse-selectors.js";
|
|
8
9
|
import { WAIT_SET_SELECTION_ERROR } from "./commands/projection/wait/meta.js";
|
|
9
|
-
export { commandPositionalRange,
|
|
10
|
+
export { commandPositionalRange, isCallCommand, isPetitionDryRunInvocation, normalizeContractAddress, parseWaitTimeout, } from "./parse-metadata.js";
|
|
10
11
|
export function parseCliArgs(tokens) {
|
|
11
12
|
const { head, payload } = splitAtLiteralBoundary(tokens);
|
|
12
13
|
const flags = {};
|
|
@@ -135,13 +136,16 @@ export function parseCliArgs(tokens) {
|
|
|
135
136
|
if (command === "petition" && flags.json && !flags.dryRun) {
|
|
136
137
|
throw new FlowError("EMPTY_PARAM", "petition --json requires --dry-run");
|
|
137
138
|
}
|
|
139
|
+
if (command === "petition" && flags.dryRun && (flags.appendScope?.length ?? 0) > 0) {
|
|
140
|
+
throw new FlowError("EMPTY_PARAM", "petition --dry-run does not accept --append-scope");
|
|
141
|
+
}
|
|
138
142
|
if (command === "renew") {
|
|
139
143
|
const recoveryModes = [flags.renewResolve, flags.renewContinue, flags.renewAbort].filter(Boolean).length;
|
|
140
144
|
if (recoveryModes > 1) {
|
|
141
145
|
throw new FlowError("EMPTY_PARAM", "renew accepts only one of --resolve, --continue, or --abort");
|
|
142
146
|
}
|
|
143
|
-
if (flags.renewAbort && (flags.
|
|
144
|
-
throw new FlowError("EMPTY_PARAM", "renew --abort does not accept --
|
|
147
|
+
if (flags.renewAbort && (flags.appendScope?.length ?? 0) > 0) {
|
|
148
|
+
throw new FlowError("EMPTY_PARAM", "renew --abort does not accept --append-scope");
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
assertCommissionSelectorAllowed(command, flags);
|
|
@@ -184,9 +188,14 @@ export function parseCliArgs(tokens) {
|
|
|
184
188
|
if (positional.length < positionalRange.min) {
|
|
185
189
|
throw new FlowError("EMPTY_PARAM", `${command} requires ${positionalRange.label ?? "an argument"}`);
|
|
186
190
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
191
|
+
const stdin = getCommandMetadata(command).stdin;
|
|
192
|
+
const documentStdinSelector = stdin.mode === "document"
|
|
193
|
+
&& stdin.selector.kind === "positional"
|
|
194
|
+
&& positional.length === stdin.selector.index + 1
|
|
195
|
+
&& positional[stdin.selector.index] === "-";
|
|
196
|
+
if (positional.length > positionalRange.max && !documentStdinSelector) {
|
|
197
|
+
const message = stdin.mode === "document"
|
|
198
|
+
? `${command} reads Markdown only through literal '-'; file path arguments are not supported`
|
|
190
199
|
: `${command} does not accept positional arguments`;
|
|
191
200
|
throw new FlowError("EMPTY_PARAM", message);
|
|
192
201
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { AddressResolutionError, buildObjectResolutionAttempt, } from "../core/addressing.js";
|
|
4
|
-
import { resolveProjectionCoordinate } from "../core/projection/index.js";
|
|
4
|
+
import { assertProjectionTellable, resolveProjectionCoordinate } from "../core/projection/index.js";
|
|
5
5
|
import { isProjectionId, projectionDir } from "../core/projection/index.js";
|
|
6
6
|
import { isProjectionAlias, readProjectionAlias } from "../core/projection/index.js";
|
|
7
7
|
import { readProjectionIdentity } from "../core/projection/index.js";
|
|
@@ -80,6 +80,11 @@ export async function resolveProjectionAddress(input) {
|
|
|
80
80
|
const subject = alias ? `projection alias ${alias} points to missing projection ${id}` : `projection ${id}`;
|
|
81
81
|
throw new AddressResolutionError("EMPTY_PARAM", `${subject} has no match ${suffix}`, attempt);
|
|
82
82
|
}
|
|
83
|
+
// Historical projection storage has no current identity to resolve. Tell
|
|
84
|
+
// still reaches its typed no-mutation refusal instead of exposing storage
|
|
85
|
+
// parser details or creating a mailbox row.
|
|
86
|
+
if (input.verb === "tell")
|
|
87
|
+
assertProjectionTellable(directory);
|
|
83
88
|
let identity;
|
|
84
89
|
try {
|
|
85
90
|
identity = readProjectionIdentity(directory);
|
|
@@ -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
|
+
}
|
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
|
: [];
|