@astrosheep/keiyaku 1.0.0 → 1.0.2
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/README.md +73 -56
- package/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms_v2.js +103 -0
- package/build/agents/harness/activity-values.js +54 -0
- package/build/agents/harness/event-channel.js +55 -20
- package/build/agents/harness/events.js +47 -1
- package/build/agents/harness/execution-handle.js +292 -61
- package/build/agents/harness/index.js +103 -121
- package/build/agents/harness/pump.js +36 -47
- package/build/agents/harness/runtime.js +3 -0
- package/build/agents/launch-snapshot_v2.js +348 -0
- package/build/agents/opencode-sdk.js +42 -169
- package/build/agents/providers/claude-agent-sdk.js +240 -79
- package/build/agents/providers/codex-app-server.js +280 -72
- package/build/agents/providers/codex-sdk.js +159 -41
- package/build/agents/providers/event-type-tail.js +16 -0
- package/build/agents/providers/opencode-sdk.js +165 -59
- package/build/agents/providers/pi.js +254 -42
- package/build/agents/selector_v2.js +122 -0
- package/build/cli/commands/akuma.js +120 -42
- package/build/cli/completion.js +6 -7
- package/build/cli/flags.js +36 -10
- package/build/cli/help.js +42 -26
- package/build/cli/index.js +225 -93
- package/build/cli/parse.js +194 -75
- package/build/cli/projection-address.js +11 -0
- package/build/cli/render/address.js +88 -0
- package/build/cli/render/arc.js +10 -10
- package/build/cli/render/call.js +59 -0
- package/build/cli/render/compact-text.js +3 -0
- package/build/cli/render/errors.js +4 -2
- package/build/cli/render/format.js +6 -0
- package/build/cli/render/line-width.js +70 -0
- package/build/cli/render/misc.js +7 -4
- package/build/cli/render/petition.js +4 -3
- package/build/cli/render/projection-activity.js +201 -0
- package/build/cli/render/shared.js +46 -12
- package/build/cli/render/status.js +59 -10
- package/build/cli/render/tool-ledger-rollup.js +74 -0
- package/build/cli/render/tool-presentation.js +97 -0
- package/build/cli/render/wait.js +229 -0
- package/build/cli/skills-install.js +42 -24
- package/build/cli/subagent-guard.js +1 -1
- package/build/config/akuma-loader_v2.js +222 -0
- package/build/config/env-keys.js +0 -4
- package/build/config/env.js +0 -6
- package/build/config/settings.js +325 -12
- package/build/core/addressing.js +224 -0
- package/build/core/amend.js +30 -47
- package/build/core/arc.js +68 -60
- package/build/core/bind.js +105 -25
- package/build/core/call-persist.js +69 -0
- package/build/core/call.js +658 -0
- package/build/core/claim.js +72 -44
- package/build/core/command-io.js +19 -19
- package/build/core/context.js +11 -36
- package/build/core/draft.js +2 -3
- package/build/core/entry.js +101 -6
- package/build/core/execution-coordinate.js +62 -0
- package/build/core/execution-pact.js +141 -0
- package/build/core/forfeit.js +2 -3
- package/build/core/hints.js +10 -10
- package/build/core/ids.js +6 -0
- package/build/core/ledger.js +16 -1
- package/build/core/petition-claim-gates.js +14 -12
- package/build/core/petition-claim.js +1 -0
- package/build/core/petition-run.js +6 -2
- package/build/core/petition.js +63 -21
- package/build/core/places.js +106 -13
- package/build/core/projection/generation.js +412 -0
- package/build/core/projection/heart.js +316 -0
- package/build/core/projection/identity.js +81 -0
- package/build/core/projection/leash.js +87 -0
- package/build/core/projection/mint.js +154 -0
- package/build/core/projection-activity.js +219 -0
- package/build/core/projection-coordinate.js +35 -0
- package/build/core/projection-core.js +69 -463
- package/build/core/projection-generation-continuation.js +31 -0
- package/build/core/projection-generation-execution.js +148 -0
- package/build/core/projection-generation-identity.js +17 -0
- package/build/core/projection-generation-launcher.js +90 -0
- package/build/core/projection-generation-process.js +43 -0
- package/build/core/projection-generation-runner.js +144 -0
- package/build/core/projection-generation-runtime.js +15 -0
- package/build/core/projection-generation-store.js +707 -0
- package/build/core/projection-identity.js +11 -0
- package/build/core/projection-life-observer.js +87 -0
- package/build/core/projection-life-protocol.js +95 -0
- package/build/core/projection-mint.js +96 -24
- package/build/core/projection-runner-lock.js +230 -0
- package/build/core/projection-status.js +207 -107
- package/build/core/projection-tells.js +401 -0
- package/build/core/projection-wait.js +155 -0
- package/build/core/projection-wake.js +109 -231
- package/build/core/queue_v2.js +342 -0
- package/build/core/registry.js +6 -3
- package/build/core/render.js +63 -1
- package/build/core/renew.js +80 -53
- package/build/core/scope.js +186 -137
- package/build/core/seal.js +16 -19
- package/build/core/status.js +88 -25
- package/build/core/stored-agent-event.js +101 -0
- package/build/core/transcripts.js +214 -228
- package/build/core/verdict.js +27 -15
- package/build/core/worktree-bootstrap.js +187 -0
- package/build/core/worktree-path.js +72 -18
- package/build/flow-error.js +4 -6
- package/build/generated/version.js +1 -1
- package/build/git/branches.js +6 -1
- package/build/index.js +8 -5
- package/build/keiyaku.js +1 -3
- package/package.json +6 -5
- package/skills/keiyaku/SKILL.md +6 -47
- package/skills/keiyaku-akuma/SKILL.md +75 -0
- package/build/agents/effective-policy.js +0 -32
- package/build/agents/index.js +0 -114
- package/build/agents/selector.js +0 -28
- package/build/cli/render/summon.js +0 -17
- package/build/cli/render/tell.js +0 -11
- package/build/config/akuma-loader.js +0 -268
- package/build/core/queue.js +0 -73
- package/build/core/summon-persist.js +0 -73
- package/build/core/summon.js +0 -377
package/build/cli/parse.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { FlowError } from "../flow-error.js";
|
|
2
2
|
import { agentNameSchema } from "../config/settings.js";
|
|
3
3
|
import { BOOLEAN_FLAGS, CONTROL_FLAGS, HELP_FLAGS, SHORT_FLAG_ALIASES, VALUE_FLAGS, } from "./flags.js";
|
|
4
|
-
|
|
5
|
-
const
|
|
4
|
+
/** Commands that may carry an explicit commission selector (@ or --contract). */
|
|
5
|
+
const COMMISSION_SELECTOR_COMMANDS = new Set([
|
|
6
|
+
"arc",
|
|
7
|
+
"amend",
|
|
8
|
+
"call",
|
|
9
|
+
"wait",
|
|
10
|
+
"tell",
|
|
6
11
|
"log",
|
|
7
12
|
"renew",
|
|
8
13
|
"petition",
|
|
@@ -11,9 +16,9 @@ const ADDRESSABLE_COMMANDS = new Set([
|
|
|
11
16
|
const CLI_COMMAND_ORDER = [
|
|
12
17
|
"bind",
|
|
13
18
|
"arc",
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
19
|
+
"call",
|
|
20
|
+
"revive",
|
|
21
|
+
"wait",
|
|
17
22
|
"tell",
|
|
18
23
|
"log",
|
|
19
24
|
"akuma list",
|
|
@@ -32,26 +37,27 @@ const CLI_COMMAND_ORDER = [
|
|
|
32
37
|
"dump-env",
|
|
33
38
|
];
|
|
34
39
|
const COMMAND_FLAGS = {
|
|
35
|
-
bind
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
// contract is parseable on bind only so the mouth can reject it with bind-specific copy.
|
|
41
|
+
bind: ["cwd", "repo", "contract", "after", "exclusive", "draft-only"],
|
|
42
|
+
arc: ["cwd", "repo", "contract", "waive"],
|
|
43
|
+
call: ["cwd", "repo", "contract", "akuma", "model", "effort", "incognito", "bare", "detach"],
|
|
44
|
+
revive: ["cwd", "repo", "model", "effort"],
|
|
45
|
+
wait: ["cwd", "repo", "contract", "timeout"],
|
|
46
|
+
tell: ["cwd", "repo", "contract", "effort"],
|
|
47
|
+
log: ["cwd", "repo", "contract"],
|
|
42
48
|
akuma: [],
|
|
43
|
-
"akuma ls": ["cwd"],
|
|
44
|
-
"akuma list": ["cwd"],
|
|
45
|
-
"akuma show": ["cwd"],
|
|
49
|
+
"akuma ls": ["cwd", "repo"],
|
|
50
|
+
"akuma list": ["cwd", "repo"],
|
|
51
|
+
"akuma show": ["cwd", "repo"],
|
|
46
52
|
skills: [],
|
|
47
53
|
"skills install": ["force"],
|
|
48
|
-
amend: ["cwd"],
|
|
49
|
-
renew: ["cwd"],
|
|
50
|
-
petition: ["cwd"],
|
|
51
|
-
forfeit: ["cwd", "reason"],
|
|
54
|
+
amend: ["cwd", "repo", "contract"],
|
|
55
|
+
renew: ["cwd", "repo", "contract", "waive"],
|
|
56
|
+
petition: ["cwd", "repo", "contract", "waive"],
|
|
57
|
+
forfeit: ["cwd", "repo", "contract", "reason"],
|
|
52
58
|
guide: [],
|
|
53
|
-
completion: ["cwd", "shell", "word", "previous", "complete"],
|
|
54
|
-
status: ["cwd"],
|
|
59
|
+
completion: ["cwd", "repo", "shell", "word", "previous", "complete"],
|
|
60
|
+
status: ["cwd", "repo", "target"],
|
|
55
61
|
"dump-env": [],
|
|
56
62
|
};
|
|
57
63
|
const STDIN_COMMANDS = new Set(["bind", "arc", "amend"]);
|
|
@@ -62,22 +68,37 @@ export function normalizeContractAddress(raw) {
|
|
|
62
68
|
}
|
|
63
69
|
return value.trim();
|
|
64
70
|
}
|
|
65
|
-
export function
|
|
66
|
-
return command === "
|
|
71
|
+
export function isCallCommand(command) {
|
|
72
|
+
return command === "call";
|
|
67
73
|
}
|
|
68
74
|
export function commandUsesPromptInput(command) {
|
|
69
|
-
return
|
|
75
|
+
return isCallCommand(command) || command === "revive";
|
|
76
|
+
}
|
|
77
|
+
export function parseWaitTimeout(value) {
|
|
78
|
+
const matched = /^(?<amount>[1-9][0-9]*)(?<unit>[smh])$/.exec(value);
|
|
79
|
+
if (!matched?.groups) {
|
|
80
|
+
throw new FlowError("EMPTY_PARAM", "wait timeout must use <positive integer><s|m|h>, for example 45s, 5m, or 2h (maximum 24h)");
|
|
81
|
+
}
|
|
82
|
+
const amount = Number(matched.groups.amount);
|
|
83
|
+
const multiplier = matched.groups.unit === "s" ? 1_000 : matched.groups.unit === "m" ? 60_000 : 3_600_000;
|
|
84
|
+
const timeoutMs = amount * multiplier;
|
|
85
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs > 24 * 3_600_000) {
|
|
86
|
+
throw new FlowError("EMPTY_PARAM", "wait timeout must use <positive integer><s|m|h>, for example 45s, 5m, or 2h (maximum 24h)");
|
|
87
|
+
}
|
|
88
|
+
return timeoutMs;
|
|
70
89
|
}
|
|
71
90
|
export function commandPositionalRange(command) {
|
|
72
91
|
if (command === "akuma show")
|
|
73
92
|
return { min: 1, max: 1, label: "<name>" };
|
|
74
93
|
if (command === "log")
|
|
75
|
-
return { min: 0, max:
|
|
76
|
-
if (command === "
|
|
77
|
-
return { min:
|
|
94
|
+
return { min: 0, max: 0, label: "" };
|
|
95
|
+
if (command === "revive")
|
|
96
|
+
return { min: 1, max: 1, label: "<artifact-id>" };
|
|
97
|
+
if (command === "wait")
|
|
98
|
+
return { min: 1, max: 1, label: "<short-id>" };
|
|
78
99
|
if (command === "tell")
|
|
79
100
|
return { min: 2, max: 2, label: "<projection> <message>" };
|
|
80
|
-
if (
|
|
101
|
+
if (isCallCommand(command))
|
|
81
102
|
return { min: 0, max: 1 };
|
|
82
103
|
return { min: 0, max: 0 };
|
|
83
104
|
}
|
|
@@ -95,20 +116,27 @@ function assignFlag(flags, name, value) {
|
|
|
95
116
|
case "cwd":
|
|
96
117
|
flags.cwd = String(value);
|
|
97
118
|
return;
|
|
98
|
-
case "
|
|
99
|
-
flags.
|
|
119
|
+
case "repo":
|
|
120
|
+
flags.repo = String(value);
|
|
121
|
+
return;
|
|
122
|
+
case "contract":
|
|
123
|
+
flags.contractId = normalizeContractAddress(String(value));
|
|
124
|
+
flags.contractAddressSource = "explicit-flag";
|
|
125
|
+
return;
|
|
126
|
+
case "akuma":
|
|
127
|
+
flags.akuma = String(value);
|
|
100
128
|
return;
|
|
101
129
|
case "projection":
|
|
102
130
|
flags.projection = String(value);
|
|
103
131
|
return;
|
|
132
|
+
case "timeout":
|
|
133
|
+
flags.timeoutMs = parseWaitTimeout(String(value));
|
|
134
|
+
return;
|
|
104
135
|
case "model":
|
|
105
136
|
flags.model = String(value);
|
|
106
137
|
return;
|
|
107
138
|
case "effort": {
|
|
108
139
|
const effort = String(value);
|
|
109
|
-
if (!EFFORT_LEVELS.includes(effort)) {
|
|
110
|
-
throw new FlowError("INVALID_EFFORT_OVERRIDE", `Invalid effort override '${effort}'. Expected low, medium, high, or max.`);
|
|
111
|
-
}
|
|
112
140
|
flags.effort = effort;
|
|
113
141
|
return;
|
|
114
142
|
}
|
|
@@ -118,12 +146,12 @@ function assignFlag(flags, name, value) {
|
|
|
118
146
|
case "bare":
|
|
119
147
|
flags.bare = Boolean(value);
|
|
120
148
|
return;
|
|
149
|
+
case "detach":
|
|
150
|
+
flags.detach = Boolean(value);
|
|
151
|
+
return;
|
|
121
152
|
case "draft-only":
|
|
122
153
|
flags.draftOnly = Boolean(value);
|
|
123
154
|
return;
|
|
124
|
-
case "worktree":
|
|
125
|
-
flags.worktree = Boolean(value);
|
|
126
|
-
return;
|
|
127
155
|
case "exclusive":
|
|
128
156
|
flags.exclusive = Boolean(value);
|
|
129
157
|
return;
|
|
@@ -139,6 +167,9 @@ function assignFlag(flags, name, value) {
|
|
|
139
167
|
case "dry-run":
|
|
140
168
|
flags.dryRun = Boolean(value);
|
|
141
169
|
return;
|
|
170
|
+
case "waive":
|
|
171
|
+
flags.waivePaths = [...(flags.waivePaths ?? []), String(value)];
|
|
172
|
+
return;
|
|
142
173
|
case "shell":
|
|
143
174
|
flags.shell = String(value);
|
|
144
175
|
return;
|
|
@@ -151,6 +182,12 @@ function assignFlag(flags, name, value) {
|
|
|
151
182
|
case "complete":
|
|
152
183
|
flags.complete = Boolean(value);
|
|
153
184
|
return;
|
|
185
|
+
case "target":
|
|
186
|
+
if (flags.target !== undefined) {
|
|
187
|
+
throw new FlowError("EMPTY_PARAM", "option --target may only be specified once");
|
|
188
|
+
}
|
|
189
|
+
flags.target = String(value);
|
|
190
|
+
return;
|
|
154
191
|
default:
|
|
155
192
|
throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
|
|
156
193
|
}
|
|
@@ -178,47 +215,94 @@ function resolveCommand(tokens) {
|
|
|
178
215
|
throw new FlowError("EMPTY_PARAM", "command cannot be empty");
|
|
179
216
|
throw new FlowError("UNKNOWN_COMMAND", `unknown command: ${head ?? ""}`.trim());
|
|
180
217
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
218
|
+
function splitAtLiteralBoundary(tokens) {
|
|
219
|
+
const boundary = tokens.indexOf("--");
|
|
220
|
+
if (boundary === -1)
|
|
221
|
+
return { head: tokens, payload: [] };
|
|
222
|
+
return { head: tokens.slice(0, boundary), payload: tokens.slice(boundary + 1) };
|
|
223
|
+
}
|
|
224
|
+
function readValueFlag(name, token, eq, tokens, index) {
|
|
225
|
+
// --target alone owns emptiness in core; empty remains a supplied value.
|
|
226
|
+
// Other value flags keep the historical requires-a-value rejection.
|
|
227
|
+
if (eq !== -1) {
|
|
228
|
+
const value = token.slice(eq + 1);
|
|
229
|
+
if (value === "" && name !== "target") {
|
|
230
|
+
throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
|
|
231
|
+
}
|
|
232
|
+
return { value, nextIndex: index };
|
|
190
233
|
}
|
|
191
|
-
|
|
192
|
-
|
|
234
|
+
const value = tokens[index + 1];
|
|
235
|
+
if (value === undefined || value === "--" || value.startsWith("--")) {
|
|
236
|
+
throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
|
|
193
237
|
}
|
|
194
|
-
if (
|
|
195
|
-
throw new FlowError("EMPTY_PARAM",
|
|
238
|
+
if (value === "" && name !== "target") {
|
|
239
|
+
throw new FlowError("EMPTY_PARAM", `option --${name} requires a value`);
|
|
196
240
|
}
|
|
197
|
-
|
|
198
|
-
|
|
241
|
+
// Short-flag values may begin with @; they are flag values, not commission tokens.
|
|
242
|
+
return { value, nextIndex: index + 1 };
|
|
243
|
+
}
|
|
244
|
+
function commissionConflictMessage(atForm, contractForm) {
|
|
245
|
+
return `commission address supplied twice: ${atForm} and --contract ${contractForm}; use exactly one form`;
|
|
246
|
+
}
|
|
247
|
+
function noteContractFlag(flags, raw, previousRaw) {
|
|
248
|
+
if (previousRaw !== undefined || flags.contractId !== undefined) {
|
|
249
|
+
throw new FlowError("EMPTY_PARAM", `commission address supplied twice: --contract ${previousRaw ?? flags.contractId} and --contract ${raw}; use exactly one form`);
|
|
199
250
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
251
|
+
assignFlag(flags, "contract", raw);
|
|
252
|
+
return raw;
|
|
253
|
+
}
|
|
254
|
+
export function parseCliArgs(tokens) {
|
|
255
|
+
const { head, payload } = splitAtLiteralBoundary(tokens);
|
|
256
|
+
const flags = {};
|
|
257
|
+
const free = [];
|
|
258
|
+
const seenFlagNames = new Set();
|
|
259
|
+
let atContractId;
|
|
260
|
+
let atToken;
|
|
261
|
+
let contractFlagRaw;
|
|
262
|
+
let helpRequested = false;
|
|
263
|
+
for (let index = 0; index < head.length; index += 1) {
|
|
264
|
+
const token = head[index];
|
|
265
|
+
if (HELP_FLAGS.has(token)) {
|
|
266
|
+
helpRequested = true;
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (token.startsWith("@")) {
|
|
270
|
+
if (atContractId !== undefined) {
|
|
271
|
+
throw new FlowError("EMPTY_PARAM", "command accepts at most one contract address");
|
|
207
272
|
}
|
|
208
|
-
|
|
273
|
+
atToken = token;
|
|
274
|
+
atContractId = normalizeContractAddress(token);
|
|
209
275
|
continue;
|
|
210
276
|
}
|
|
211
277
|
if (/^-[A-Za-z]$/.test(token)) {
|
|
212
|
-
const
|
|
278
|
+
const short = token.slice(1);
|
|
279
|
+
const name = SHORT_FLAG_ALIASES[short];
|
|
213
280
|
if (!name) {
|
|
214
281
|
throw new FlowError("EMPTY_PARAM", `unknown option: ${token}`);
|
|
215
282
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
283
|
+
seenFlagNames.add(name);
|
|
284
|
+
if (VALUE_FLAGS.has(name)) {
|
|
285
|
+
const value = head[index + 1];
|
|
286
|
+
if (value === undefined || value === "--" || /^--/.test(value) || (/^-[A-Za-z]$/.test(value) && SHORT_FLAG_ALIASES[value.slice(1)])) {
|
|
287
|
+
throw new FlowError("EMPTY_PARAM", `option -${short} requires a value`);
|
|
288
|
+
}
|
|
289
|
+
index += 1;
|
|
290
|
+
if (name === "contract") {
|
|
291
|
+
contractFlagRaw = noteContractFlag(flags, value, contractFlagRaw);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
assignFlag(flags, name, value);
|
|
295
|
+
}
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (BOOLEAN_FLAGS.has(name)) {
|
|
299
|
+
assignFlag(flags, name, true);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
throw new FlowError("EMPTY_PARAM", `unknown option: ${token}`);
|
|
219
303
|
}
|
|
220
304
|
if (!token.startsWith("--")) {
|
|
221
|
-
|
|
305
|
+
free.push(token);
|
|
222
306
|
continue;
|
|
223
307
|
}
|
|
224
308
|
const eq = token.indexOf("=");
|
|
@@ -226,15 +310,16 @@ export function parseCliArgs(tokens) {
|
|
|
226
310
|
if (!CONTROL_FLAGS.has(name)) {
|
|
227
311
|
throw new FlowError("EMPTY_PARAM", `unknown option: --${name}`);
|
|
228
312
|
}
|
|
229
|
-
|
|
313
|
+
seenFlagNames.add(name);
|
|
230
314
|
if (VALUE_FLAGS.has(name)) {
|
|
231
|
-
const value
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
315
|
+
const { value, nextIndex } = readValueFlag(name, token, eq, head, index);
|
|
316
|
+
index = nextIndex;
|
|
317
|
+
if (name === "contract") {
|
|
318
|
+
contractFlagRaw = noteContractFlag(flags, value, contractFlagRaw);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
assignFlag(flags, name, value);
|
|
236
322
|
}
|
|
237
|
-
assignFlag(flags, name, value);
|
|
238
323
|
continue;
|
|
239
324
|
}
|
|
240
325
|
if (BOOLEAN_FLAGS.has(name)) {
|
|
@@ -244,10 +329,44 @@ export function parseCliArgs(tokens) {
|
|
|
244
329
|
assignFlag(flags, name, true);
|
|
245
330
|
}
|
|
246
331
|
}
|
|
247
|
-
if (
|
|
248
|
-
|
|
332
|
+
if (atContractId !== undefined && flags.contractId !== undefined) {
|
|
333
|
+
throw new FlowError("EMPTY_PARAM", commissionConflictMessage(atToken ?? `@${atContractId}`, contractFlagRaw ?? flags.contractId));
|
|
334
|
+
}
|
|
335
|
+
if (atContractId !== undefined) {
|
|
336
|
+
flags.contractId = atContractId;
|
|
337
|
+
flags.contractAddressSource = "at-address";
|
|
338
|
+
}
|
|
339
|
+
const { command, rest } = resolveCommand(free);
|
|
340
|
+
if (helpRequested) {
|
|
341
|
+
return {
|
|
342
|
+
command,
|
|
343
|
+
flags: flags.contractId ? { contractId: flags.contractId, contractAddressSource: flags.contractAddressSource, ...(flags.cwd ? { cwd: flags.cwd } : {}), ...(flags.repo ? { repo: flags.repo } : {}) } : {
|
|
344
|
+
...(flags.cwd ? { cwd: flags.cwd } : {}),
|
|
345
|
+
...(flags.repo ? { repo: flags.repo } : {}),
|
|
346
|
+
},
|
|
347
|
+
positional: [],
|
|
348
|
+
helpRequested: true,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (command === "akuma") {
|
|
352
|
+
throw new FlowError("EMPTY_PARAM", "akuma requires subcommand: list, ls, or show");
|
|
353
|
+
}
|
|
354
|
+
if (command === "skills") {
|
|
355
|
+
throw new FlowError("EMPTY_PARAM", "skills requires subcommand: install");
|
|
356
|
+
}
|
|
357
|
+
for (const name of seenFlagNames) {
|
|
358
|
+
assertAllowedFlag(command, name);
|
|
359
|
+
}
|
|
360
|
+
if (flags.contractId !== undefined && !COMMISSION_SELECTOR_COMMANDS.has(command)) {
|
|
361
|
+
throw new FlowError("EMPTY_PARAM", command === "bind"
|
|
362
|
+
? `bind creates a commission and does not accept @${flags.contractId}; use -C/--cwd to select the repository`
|
|
363
|
+
: `contract address @${flags.contractId} is not valid for ${command}`);
|
|
364
|
+
}
|
|
365
|
+
const positional = [...rest, ...payload];
|
|
366
|
+
if (isCallCommand(command)) {
|
|
367
|
+
if (flags.akuma) {
|
|
249
368
|
if (positional.length > 1) {
|
|
250
|
-
throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument when --
|
|
369
|
+
throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument when --akuma is used`);
|
|
251
370
|
}
|
|
252
371
|
}
|
|
253
372
|
else {
|
|
@@ -259,7 +378,7 @@ export function parseCliArgs(tokens) {
|
|
|
259
378
|
if (!parsedName.success) {
|
|
260
379
|
throw new FlowError("EMPTY_PARAM", `${command} requires a valid agent name before the optional prompt`);
|
|
261
380
|
}
|
|
262
|
-
flags.
|
|
381
|
+
flags.akuma = parsedName.data;
|
|
263
382
|
positional.shift();
|
|
264
383
|
if (positional.length > 1) {
|
|
265
384
|
throw new FlowError("EMPTY_PARAM", `${command} accepts at most one prompt argument after the agent name`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { resolveProjectionPrefix } from "../core/projection-core.js";
|
|
2
|
+
import { FlowError } from "../flow-error.js";
|
|
3
|
+
export function resolveProjectionAddress(cwd, prefix, contractId) {
|
|
4
|
+
const resolved = resolveProjectionPrefix(cwd, prefix, contractId);
|
|
5
|
+
if (resolved.status === "resolved")
|
|
6
|
+
return resolved.id;
|
|
7
|
+
if (resolved.status === "none") {
|
|
8
|
+
throw new FlowError("EMPTY_PARAM", `projection not resolved${contractId ? ` within @${contractId}` : ""}: ${prefix}`);
|
|
9
|
+
}
|
|
10
|
+
throw new FlowError("EMPTY_PARAM", `projection address is ambiguous${contractId ? ` within @${contractId}` : ""}: ${prefix}; candidates:\n${resolved.candidates.join("\n")}`);
|
|
11
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
function sourceLabel(address) {
|
|
2
|
+
return sourceName(address.spelling.source);
|
|
3
|
+
}
|
|
4
|
+
function sourceName(source) {
|
|
5
|
+
switch (source) {
|
|
6
|
+
case "at-address": return "explicit @";
|
|
7
|
+
case "explicit-flag": return "explicit --contract";
|
|
8
|
+
case "worktree-presented": return "worktree cwd";
|
|
9
|
+
case "sole-active": return "only active commission";
|
|
10
|
+
case "artifact-provenance": return "artifact provenance";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isCommissionAddress(address) {
|
|
14
|
+
return address.binding.kind === "commission";
|
|
15
|
+
}
|
|
16
|
+
export function renderResolvedAddressReceipt(address, facts = {}) {
|
|
17
|
+
if (!isCommissionAddress(address)) {
|
|
18
|
+
if (address.binding.kind === "unbound") {
|
|
19
|
+
if (address.repo.kind !== "repository") {
|
|
20
|
+
throw new Error("unbound address receipt requires repository authority");
|
|
21
|
+
}
|
|
22
|
+
return [
|
|
23
|
+
"Unbound",
|
|
24
|
+
"no active commission",
|
|
25
|
+
`repo ${address.repo.stableRoot}`,
|
|
26
|
+
`workdir ${address.workdir}`,
|
|
27
|
+
facts.artifactId ? `artifact ${facts.artifactId}` : undefined,
|
|
28
|
+
facts.projectionId ? `projection ${facts.projectionId}` : undefined,
|
|
29
|
+
].filter((part) => part !== undefined).join(" · ");
|
|
30
|
+
}
|
|
31
|
+
const repository = address.repo.kind === "repository"
|
|
32
|
+
? `repo ${address.repo.stableRoot}`
|
|
33
|
+
: "no repository";
|
|
34
|
+
return [
|
|
35
|
+
"Bare",
|
|
36
|
+
"no contract",
|
|
37
|
+
repository,
|
|
38
|
+
`workdir ${address.workdir}`,
|
|
39
|
+
facts.artifactId ? `artifact ${facts.artifactId}` : undefined,
|
|
40
|
+
facts.projectionId ? `projection ${facts.projectionId}` : undefined,
|
|
41
|
+
].filter((part) => part !== undefined).join(" · ");
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
address.place.display ? `Bound @${address.place.display}` : "Bound",
|
|
45
|
+
`commission ${address.binding.commissionId}`,
|
|
46
|
+
`repo ${address.repo.stableRoot}`,
|
|
47
|
+
`target ${address.target.branch}`,
|
|
48
|
+
facts.artifactId ? `artifact ${facts.artifactId}` : undefined,
|
|
49
|
+
facts.projectionId ? `projection ${facts.projectionId}` : undefined,
|
|
50
|
+
`via ${sourceLabel(address)}`,
|
|
51
|
+
].filter((part) => part !== undefined).join(" · ");
|
|
52
|
+
}
|
|
53
|
+
function renderAttemptCandidate(candidate) {
|
|
54
|
+
return [
|
|
55
|
+
candidate.place ? `@${candidate.place}` : undefined,
|
|
56
|
+
candidate.name,
|
|
57
|
+
candidate.objective,
|
|
58
|
+
`target ${candidate.target.branch}`,
|
|
59
|
+
`commission ${candidate.commissionId}`,
|
|
60
|
+
`lifecycle ${candidate.lifecycle.state}`,
|
|
61
|
+
candidate.matchedBy ? `matched by ${candidate.matchedBy}` : undefined,
|
|
62
|
+
].filter((part) => part !== undefined).join(" · ");
|
|
63
|
+
}
|
|
64
|
+
export function renderResolutionAttemptPreamble(attempt) {
|
|
65
|
+
const parts = [
|
|
66
|
+
attempt.repo.kind === "repository" ? `At repo ${attempt.repo.stableRoot}` : "At no repository",
|
|
67
|
+
attempt.spelling ? `address ${attempt.spelling.asTyped}` : undefined,
|
|
68
|
+
attempt.candidates.length > 0
|
|
69
|
+
? `candidates ${attempt.candidates.map(renderAttemptCandidate).join("; ")}`
|
|
70
|
+
: undefined,
|
|
71
|
+
attempt.spelling ? `via ${sourceName(attempt.spelling.source)}` : undefined,
|
|
72
|
+
attempt.inference.length > 0 ? `inference ${attempt.inference.join("; ")}` : undefined,
|
|
73
|
+
];
|
|
74
|
+
return parts.filter((part) => part !== undefined).join(" · ");
|
|
75
|
+
}
|
|
76
|
+
export function renderAddressCarrier(carrier, facts = {}) {
|
|
77
|
+
return "expected" in carrier
|
|
78
|
+
? renderResolutionAttemptPreamble(carrier)
|
|
79
|
+
: renderResolvedAddressReceipt(carrier, facts);
|
|
80
|
+
}
|
|
81
|
+
export function prependAddressReceipt(output, address, facts = {}) {
|
|
82
|
+
if (!address)
|
|
83
|
+
return output;
|
|
84
|
+
return { ...output, address, text: `${renderResolvedAddressReceipt(address, facts)}\n${output.text}` };
|
|
85
|
+
}
|
|
86
|
+
export function carryAddress(output, address) {
|
|
87
|
+
return { ...output, address };
|
|
88
|
+
}
|
package/build/cli/render/arc.js
CHANGED
|
@@ -2,6 +2,7 @@ import { shortCommitHash } from "../../core/render.js";
|
|
|
2
2
|
import { assembleResponse, buildPayload, buildSection, formatHints, formatList, formatMaybe, formatWarnings, } from "./format.js";
|
|
3
3
|
import { DIFF_OVERVIEW_SECTION_TITLE, RESPONSE_MARKERS, WARNING_SECTION_TITLE } from "./response-style.js";
|
|
4
4
|
import { appendPersistenceSummary, BRANCH_LABEL, CONTENT_SECTION_TITLE, HINTS_LIST_MAX_ITEMS, HINTS_SECTION_TITLE, INFO_BRANCH_MAX_CHARS, INFO_COMMIT_MAX_CHARS, INFO_PLEA_MAX_CHARS, INFO_SECTION_TITLE, } from "./shared.js";
|
|
5
|
+
import { prependAddressReceipt } from "./address.js";
|
|
5
6
|
function sealLines(result) {
|
|
6
7
|
if (!result.sealed)
|
|
7
8
|
return ["nothing sealed"];
|
|
@@ -13,7 +14,7 @@ function sealLines(result) {
|
|
|
13
14
|
];
|
|
14
15
|
}
|
|
15
16
|
export function buildArcResponse(result) {
|
|
16
|
-
const { status: _status, ...resultData } = result;
|
|
17
|
+
const { status: _status, address: _address, ...resultData } = result;
|
|
17
18
|
const summarySection = buildSection(CONTENT_SECTION_TITLE, sealLines(result));
|
|
18
19
|
const warningSection = buildSection(WARNING_SECTION_TITLE, formatWarnings(result.meta?.warnings ?? []));
|
|
19
20
|
const hintsSection = buildSection(HINTS_SECTION_TITLE, formatHints(result.meta?.hints ?? [], { maxItems: HINTS_LIST_MAX_ITEMS }));
|
|
@@ -26,15 +27,14 @@ export function buildArcResponse(result) {
|
|
|
26
27
|
...formatMaybe("Base Branch", result.baseBranch, INFO_BRANCH_MAX_CHARS),
|
|
27
28
|
]);
|
|
28
29
|
const summaryLine = appendPersistenceSummary(result.summary, result.responsePath);
|
|
29
|
-
return {
|
|
30
|
+
return prependAddressReceipt({
|
|
30
31
|
text: assembleResponse(`${RESPONSE_MARKERS.arc} Arc Opened (a${result.arc})`, summaryLine, [summarySection, infoSection, buildSection(DIFF_OVERVIEW_SECTION_TITLE, result.diff), warningSection, hintsSection].filter((section) => section !== null)),
|
|
31
32
|
payload: buildPayload(resultData, result.responsePath),
|
|
32
|
-
};
|
|
33
|
+
}, result.address);
|
|
33
34
|
}
|
|
34
35
|
export function buildRenewResponse(result) {
|
|
35
|
-
const { status: _status, ...resultData } = result;
|
|
36
|
+
const { status: _status, address: _address, ...resultData } = result;
|
|
36
37
|
const infoSection = buildSection(INFO_SECTION_TITLE, [
|
|
37
|
-
...formatMaybe("Contract", result.contractId, INFO_BRANCH_MAX_CHARS),
|
|
38
38
|
...formatMaybe("Old Base", result.oldBase, INFO_COMMIT_MAX_CHARS),
|
|
39
39
|
...formatMaybe("New Base", result.newBase, INFO_COMMIT_MAX_CHARS),
|
|
40
40
|
...formatMaybe("Old Head", result.oldHead, INFO_COMMIT_MAX_CHARS),
|
|
@@ -42,13 +42,13 @@ export function buildRenewResponse(result) {
|
|
|
42
42
|
...formatMaybe("Ledger Head", result.ledgerHead, INFO_COMMIT_MAX_CHARS),
|
|
43
43
|
...formatList("Seal", sealLines(result)),
|
|
44
44
|
]);
|
|
45
|
-
return {
|
|
45
|
+
return prependAddressReceipt({
|
|
46
46
|
text: assembleResponse(`${RESPONSE_MARKERS.arc} Renewed`, appendPersistenceSummary(result.summary, result.responsePath), [buildSection(CONTENT_SECTION_TITLE, result.diff), infoSection].filter((section) => section !== null)),
|
|
47
47
|
payload: buildPayload(resultData, result.responsePath),
|
|
48
|
-
};
|
|
48
|
+
}, result.address);
|
|
49
49
|
}
|
|
50
50
|
export function buildAmendResponse(result) {
|
|
51
|
-
const { status: _status, ...resultData } = result;
|
|
51
|
+
const { status: _status, address: _address, ...resultData } = result;
|
|
52
52
|
const renderedLedgerCommit = shortCommitHash(result.ledgerCommit);
|
|
53
53
|
const infoSection = buildSection(INFO_SECTION_TITLE, [
|
|
54
54
|
...formatMaybe("Amendment", String(result.amendmentNumber), INFO_COMMIT_MAX_CHARS),
|
|
@@ -56,8 +56,8 @@ export function buildAmendResponse(result) {
|
|
|
56
56
|
...formatMaybe("Base Branch", result.baseBranch, INFO_BRANCH_MAX_CHARS),
|
|
57
57
|
...formatMaybe("Ledger Commit", renderedLedgerCommit, INFO_COMMIT_MAX_CHARS),
|
|
58
58
|
]);
|
|
59
|
-
return {
|
|
59
|
+
return prependAddressReceipt({
|
|
60
60
|
text: assembleResponse(`${RESPONSE_MARKERS.arc} Amended`, `Amended contract ledger on '${result.currentBranch}' with Amendment ${result.amendmentNumber} [${renderedLedgerCommit}].`, [buildSection(CONTENT_SECTION_TITLE, result.summary), infoSection].filter((section) => section !== null)),
|
|
61
61
|
payload: buildPayload(resultData),
|
|
62
|
-
};
|
|
62
|
+
}, result.address);
|
|
63
63
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { assembleResponse, buildPayload, buildSection, formatMaybe, formatWarnings } from "./format.js";
|
|
2
|
+
import { WARNING_SECTION_TITLE } from "./response-style.js";
|
|
3
|
+
import { CONTENT_SECTION_TITLE, formatPersistenceSummary, formatCallCompletionHeading, formatCallNextAction, INFO_AKUMA_MAX_CHARS, projectionRejoinHintLines, } from "./shared.js";
|
|
4
|
+
import { carryAddress, prependAddressReceipt, renderResolvedAddressReceipt } from "./address.js";
|
|
5
|
+
export function renderAdoptedLaunchReceipt(address, projectionId) {
|
|
6
|
+
return [
|
|
7
|
+
renderResolvedAddressReceipt(address, { projectionId }),
|
|
8
|
+
...projectionRejoinHintLines(projectionId),
|
|
9
|
+
].join("\n");
|
|
10
|
+
}
|
|
11
|
+
export function buildCallResponse(result, input) {
|
|
12
|
+
if (result.state === "launched") {
|
|
13
|
+
if (!result.projection)
|
|
14
|
+
throw new Error("launched call response requires projection facts");
|
|
15
|
+
const { session: _session, evidenceCwd: _evidenceCwd, address: _address, foregroundWait: _foregroundWait, ...responseData } = result;
|
|
16
|
+
const output = {
|
|
17
|
+
text: input.addressPlacement === "stdout"
|
|
18
|
+
? renderAdoptedLaunchReceipt(result.address, result.projection.id)
|
|
19
|
+
: projectionRejoinHintLines(result.projection.id).join("\n"),
|
|
20
|
+
payload: buildPayload(responseData),
|
|
21
|
+
};
|
|
22
|
+
switch (input.addressPlacement) {
|
|
23
|
+
case "stdout":
|
|
24
|
+
return { ...output, address: result.address };
|
|
25
|
+
case "footer":
|
|
26
|
+
return carryAddress(output, result.address);
|
|
27
|
+
case "none":
|
|
28
|
+
return output;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const infoLines = [
|
|
32
|
+
...formatMaybe("Akuma", result.agent ?? input.agent, INFO_AKUMA_MAX_CHARS),
|
|
33
|
+
];
|
|
34
|
+
const summarySection = buildSection(CONTENT_SECTION_TITLE, result.summary);
|
|
35
|
+
const warningSection = buildSection(WARNING_SECTION_TITLE, formatWarnings(result.meta?.warnings ?? []));
|
|
36
|
+
const persistedSummary = formatPersistenceSummary(input.responsePath);
|
|
37
|
+
const response = assembleResponse(formatCallCompletionHeading(result.projection) ?? "", persistedSummary, [summarySection, warningSection].filter((s) => s !== null), infoLines);
|
|
38
|
+
const repositoryCoordinate = result.address.repo.kind === "repository"
|
|
39
|
+
? result.address.repo.stableRoot
|
|
40
|
+
: undefined;
|
|
41
|
+
const text = `${response.trimStart()}\n\n${formatCallNextAction({
|
|
42
|
+
projection: result.projection,
|
|
43
|
+
artifactId: input.artifactId,
|
|
44
|
+
repositoryCoordinate,
|
|
45
|
+
})}`;
|
|
46
|
+
const { session: _session, evidenceCwd: _evidenceCwd, address: _address, foregroundWait: _foregroundWait, ...responseData } = result;
|
|
47
|
+
const output = {
|
|
48
|
+
text,
|
|
49
|
+
payload: buildPayload(responseData, input.responsePath),
|
|
50
|
+
};
|
|
51
|
+
switch (input.addressPlacement) {
|
|
52
|
+
case "stdout":
|
|
53
|
+
return prependAddressReceipt(output, result.address, { artifactId: result.artifactId, projectionId: result.projection?.id });
|
|
54
|
+
case "footer":
|
|
55
|
+
return carryAddress(output, result.address);
|
|
56
|
+
case "none":
|
|
57
|
+
return output;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { asMessage, isFlowError, pickHintsFromError } from "../../flow-error.js";
|
|
2
2
|
import { assertSettingsKnobUsable, loadKeiyakuSettings } from "../../config/settings.js";
|
|
3
|
-
import {
|
|
3
|
+
import { loadAkumaCatalogV2 } from "../../config/akuma-loader_v2.js";
|
|
4
4
|
import { appendDebugLog } from "../../telemetry/debug-log.js";
|
|
5
5
|
import { ACTOR_IDENTITY, TOOL_NAMES, BUILTIN_AGENT_NAMES } from "../../keiyaku.js";
|
|
6
6
|
import { buildErrorResponse } from "./misc.js";
|
|
7
|
+
import { addressCarrierFromError } from "../../core/addressing.js";
|
|
7
8
|
export function classifyCliError(error) {
|
|
8
9
|
if (isFlowError(error)) {
|
|
9
10
|
return { errorType: "keiyaku_error", errorCode: error.code };
|
|
@@ -17,7 +18,7 @@ async function getAvailableActorNames(cwd, fallback) {
|
|
|
17
18
|
try {
|
|
18
19
|
const loaded = await loadKeiyakuSettings(cwd);
|
|
19
20
|
assertSettingsKnobUsable(loaded, "agents");
|
|
20
|
-
return Object.keys((await
|
|
21
|
+
return Object.keys((await loadAkumaCatalogV2(cwd)).selected);
|
|
21
22
|
}
|
|
22
23
|
catch {
|
|
23
24
|
return [...fallback];
|
|
@@ -42,5 +43,6 @@ export async function handleCliError(input) {
|
|
|
42
43
|
review: isFlowError(input.error) ? input.error.review : undefined,
|
|
43
44
|
errorType,
|
|
44
45
|
errorCode,
|
|
46
|
+
addressCarrier: addressCarrierFromError(input.error),
|
|
45
47
|
});
|
|
46
48
|
}
|