@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
|
@@ -3,7 +3,7 @@ export const meta = {
|
|
|
3
3
|
command: "task",
|
|
4
4
|
summary: "Manage lightweight repository tasks",
|
|
5
5
|
usage: ["keiyaku task <subcommand>"],
|
|
6
|
-
stdin: "
|
|
6
|
+
stdin: { mode: "argument" },
|
|
7
7
|
flags: [],
|
|
8
8
|
purpose: "Manage the file-backed task board.",
|
|
9
9
|
subcommands: TASK_SUBCOMMANDS,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { updateTask } from "../../../../core/task/index.js";
|
|
2
2
|
import { runTaskMutationCommand } from "../shared.js";
|
|
3
|
-
export const handler = async (
|
|
4
|
-
const body = flags.taskBody === "-" ? stdin : flags.taskBody;
|
|
3
|
+
export const handler = async (_stdin, flags, _signal, positional) => {
|
|
5
4
|
return runTaskMutationCommand(flags, (repository) => updateTask(repository, positional[0], {
|
|
6
5
|
...(flags.taskTitle === undefined ? {} : { title: flags.taskTitle }),
|
|
7
|
-
...(
|
|
6
|
+
...(flags.taskBody === undefined ? {} : { body: flags.taskBody }),
|
|
8
7
|
...(flags.taskPri === undefined ? {} : { pri: flags.taskPri }),
|
|
9
8
|
...(flags.taskNeeds === undefined ? {} : { addNeeds: flags.taskNeeds }),
|
|
10
9
|
...(flags.taskDropNeeds === undefined ? {} : { dropNeeds: flags.taskDropNeeds }),
|
|
@@ -2,7 +2,10 @@ export const meta = {
|
|
|
2
2
|
command: "task update",
|
|
3
3
|
summary: "Update task facts",
|
|
4
4
|
usage: ["keiyaku task update [-C|--cwd DIR] ID [--title TEXT] [--body TEXT|-] [--pri 0-3] [--needs ID] [--drop-needs ID] [--parent ID|--no-parent] [--from ID]"],
|
|
5
|
-
stdin:
|
|
5
|
+
stdin: {
|
|
6
|
+
mode: "argument",
|
|
7
|
+
selector: { kind: "flag", name: "taskBody", required: false, rejectBlank: false },
|
|
8
|
+
},
|
|
6
9
|
flags: ["cwd", "title", "body", "pri", "needs", "drop-needs", "parent", "no-parent", "from"],
|
|
7
10
|
purpose: "Change mutable task facts.",
|
|
8
11
|
};
|
package/build/cli/completion.js
CHANGED
|
@@ -2,6 +2,7 @@ import { assertSettingsKnobUsable } from "../config/settings/disease.js";
|
|
|
2
2
|
import { loadKeiyakuSettings } from "../config/settings/loader.js";
|
|
3
3
|
import { loadAkumaCatalog } from "../config/akuma-loader.js";
|
|
4
4
|
import { listContractIds } from "../core/ledger.js";
|
|
5
|
+
import { TASK_FILTER_COMPLETION } from "../core/task/query.js";
|
|
5
6
|
import { allCommandMetadata, getCommandMetadata } from "./commands/metadata.js";
|
|
6
7
|
function topLevelCommands() {
|
|
7
8
|
return allCommandMetadata()
|
|
@@ -46,6 +47,9 @@ export async function renderCompletionCandidates(input) {
|
|
|
46
47
|
if (input.previous === "task") {
|
|
47
48
|
return filterPrefix(subcommandsFor("task"), word).join("\n");
|
|
48
49
|
}
|
|
50
|
+
if (input.previous === "--filter") {
|
|
51
|
+
return filterPrefix([TASK_FILTER_COMPLETION], word).join("\n");
|
|
52
|
+
}
|
|
49
53
|
return filterPrefix(topLevelCommands(), word).join("\n");
|
|
50
54
|
}
|
|
51
55
|
export function renderCompletionScript(shell = "bash") {
|
|
@@ -54,7 +58,7 @@ export function renderCompletionScript(shell = "bash") {
|
|
|
54
58
|
"#compdef keiyaku",
|
|
55
59
|
"_keiyaku() {",
|
|
56
60
|
" local -a candidates",
|
|
57
|
-
" candidates=(${(f)\"$(keiyaku completion --complete --word
|
|
61
|
+
" candidates=(${(f)\"$(keiyaku completion --complete --word=\"${words[CURRENT]}\" --previous=\"${words[CURRENT-1]}\" 2>/dev/null)\"})",
|
|
58
62
|
" compadd -- $candidates",
|
|
59
63
|
"}",
|
|
60
64
|
"_keiyaku \"$@\"",
|
|
@@ -65,7 +69,10 @@ export function renderCompletionScript(shell = "bash") {
|
|
|
65
69
|
" local cur prev",
|
|
66
70
|
" cur=\"${COMP_WORDS[COMP_CWORD]}\"",
|
|
67
71
|
" prev=\"${COMP_WORDS[COMP_CWORD-1]}\"",
|
|
68
|
-
" COMPREPLY=(
|
|
72
|
+
" COMPREPLY=()",
|
|
73
|
+
" while IFS= read -r candidate; do",
|
|
74
|
+
" COMPREPLY+=(\"$candidate\")",
|
|
75
|
+
" done < <(keiyaku completion --complete --word=\"$cur\" --previous=\"$prev\" 2>/dev/null)",
|
|
69
76
|
"}",
|
|
70
77
|
"complete -F _keiyaku_completion keiyaku",
|
|
71
78
|
].join("\n");
|
package/build/cli/flags.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ACTOR_IDENTITY } from "../keiyaku.js";
|
|
2
|
+
import { TASK_FILTER_GRAMMAR } from "../core/task/query.js";
|
|
2
3
|
export const HELP_FLAGS = new Set(["--help", "-h"]);
|
|
3
4
|
export const FLAG_SPECS = {
|
|
4
5
|
cwd: {
|
|
@@ -118,10 +119,10 @@ export const FLAG_SPECS = {
|
|
|
118
119
|
kind: "boolean",
|
|
119
120
|
description: "Preview bind input or petition preflight without mutation.",
|
|
120
121
|
},
|
|
121
|
-
|
|
122
|
+
"append-scope": {
|
|
122
123
|
kind: "value",
|
|
123
|
-
placeholder: "
|
|
124
|
-
description: "
|
|
124
|
+
placeholder: "PATTERN",
|
|
125
|
+
description: "Append one ordered scope pattern to the contract before audit. May be repeated.",
|
|
125
126
|
},
|
|
126
127
|
resolve: {
|
|
127
128
|
kind: "boolean",
|
|
@@ -167,10 +168,25 @@ export const FLAG_SPECS = {
|
|
|
167
168
|
kind: "boolean",
|
|
168
169
|
description: "Render task data as JSON.",
|
|
169
170
|
},
|
|
171
|
+
"diff-budget": {
|
|
172
|
+
kind: "value",
|
|
173
|
+
placeholder: "BYTES",
|
|
174
|
+
description: "Set the audit raw-diff presentation budget in bytes.",
|
|
175
|
+
},
|
|
170
176
|
done: {
|
|
171
177
|
kind: "boolean",
|
|
172
178
|
description: "Show terminal tasks.",
|
|
173
179
|
},
|
|
180
|
+
filter: {
|
|
181
|
+
kind: "value",
|
|
182
|
+
placeholder: TASK_FILTER_GRAMMAR,
|
|
183
|
+
description: "Filter structured task facts. Repeat --filter for AND; comma values or | terms are OR.",
|
|
184
|
+
},
|
|
185
|
+
sort: {
|
|
186
|
+
kind: "value",
|
|
187
|
+
placeholder: "KEY[,KEY...]",
|
|
188
|
+
description: "Sort by priority ascending, modified descending, or created descending.",
|
|
189
|
+
},
|
|
174
190
|
pri: {
|
|
175
191
|
kind: "value",
|
|
176
192
|
placeholder: "0-3",
|
package/build/cli/help.js
CHANGED
|
@@ -62,9 +62,9 @@ export function renderCliHelp(version) {
|
|
|
62
62
|
"",
|
|
63
63
|
"Input:",
|
|
64
64
|
" <> means required; [] means optional.",
|
|
65
|
-
" bind, arc, and
|
|
66
|
-
" call and tell require literal BODY or `-`;
|
|
67
|
-
" revive accepts an artifact plus optional BODY or `-`;
|
|
65
|
+
" bind, arc, amend, and petition read document stdin only when literal `-` selects it.",
|
|
66
|
+
" call and tell require literal BODY or `-`; literal `-` selects stdin.",
|
|
67
|
+
" revive accepts an artifact plus optional BODY or `-`; unselected stdin is ignored.",
|
|
68
68
|
"",
|
|
69
69
|
"Configuration:",
|
|
70
70
|
" Akuma profiles <KEIYAKU_HOME>/akuma/*.md or .keiyaku/akuma/*.md",
|
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);
|