@astrosheep/keiyaku 4.0.2 → 4.0.4
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/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +3 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/src/akuma/akuma.d.ts +34 -11
- package/build/src/akuma/akuma.js +121 -61
- package/build/src/akuma/allowed.d.ts +7 -0
- package/build/src/akuma/allowed.js +40 -0
- package/build/src/akuma/archetype.d.ts +7 -4
- package/build/src/akuma/archetype.js +15 -16
- package/build/src/akuma/body.d.ts +3 -1
- package/build/src/akuma/body.js +19 -8
- package/build/src/akuma/heart/facts.d.ts +49 -7
- package/build/src/akuma/heart/index.d.ts +4 -8
- package/build/src/akuma/heart/index.js +76 -15
- package/build/src/akuma/heart/rows.d.ts +7 -5
- package/build/src/akuma/heart/rows.js +98 -11
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +15 -10
- package/build/src/akuma/heart/soul.js +3 -1
- package/build/src/akuma/heart/storage.d.ts +2 -0
- package/build/src/akuma/heart/storage.js +20 -0
- package/build/src/akuma/heart/timeline.d.ts +1 -5
- package/build/src/akuma/heart/timeline.js +8 -17
- package/build/src/akuma/index.d.ts +4 -1
- package/build/src/akuma/index.js +1 -0
- package/build/src/akuma/projection.d.ts +17 -3
- package/build/src/akuma/projection.js +40 -3
- package/build/src/akuma/provider.d.ts +1 -1
- package/build/src/akuma/provider.js +2 -1
- package/build/src/akuma/providers/acp/core.d.ts +3 -1
- package/build/src/akuma/providers/acp/core.js +4 -4
- package/build/src/akuma/providers/acp/events.d.ts +11 -3
- package/build/src/akuma/providers/acp/events.js +78 -4
- package/build/src/akuma/providers/claude/events.js +62 -3
- package/build/src/akuma/providers/codex-app-server/events.js +1 -13
- package/build/src/akuma/providers/grok-build/index.d.ts +2 -1
- package/build/src/akuma/providers/grok-build/index.js +72 -2
- package/build/src/akuma/providers/opencode-sdk/events.js +71 -6
- package/build/src/akuma/providers/pi/events.js +17 -3
- package/build/src/akuma/providers/unified-patch.d.ts +4 -0
- package/build/src/akuma/providers/unified-patch.js +14 -0
- package/build/src/akuma/publication.d.ts +1 -1
- package/build/src/akuma/publication.js +36 -7
- package/build/src/akuma/requests.d.ts +70 -4
- package/build/src/akuma/requests.js +288 -77
- package/build/src/akuma-body.d.ts +1 -0
- package/build/src/akuma-body.js +31 -0
- package/build/src/cli/accepted.d.ts +4 -1
- package/build/src/cli/accepted.js +26 -4
- package/build/src/cli/commands/akuma-invoke.d.ts +8 -7
- package/build/src/cli/commands/akuma-invoke.js +18 -10
- package/build/src/cli/commands/akuma.d.ts +11 -2
- package/build/src/cli/commands/akuma.js +67 -28
- package/build/src/cli/commands/amend.d.ts +1 -1
- package/build/src/cli/commands/amend.js +1 -1
- package/build/src/cli/commands/contract.d.ts +3 -3
- package/build/src/cli/commands/contract.js +1 -1
- package/build/src/cli/commands/install.js +4 -4
- package/build/src/cli/commands/task-query.d.ts +1 -1
- package/build/src/cli/commands/task-query.js +11 -5
- package/build/src/cli/commands/task.js +4 -4
- package/build/src/cli/coordinates.d.ts +1 -0
- package/build/src/cli/coordinates.js +5 -1
- package/build/src/cli/invoke.d.ts +1 -0
- package/build/src/cli/invoke.js +90 -73
- package/build/src/cli/main.d.ts +2 -0
- package/build/src/cli/main.js +29 -4
- package/build/src/cli/parse.d.ts +1 -0
- package/build/src/cli/parse.js +8 -4
- package/build/src/cli/render/akuma.d.ts +2 -2
- package/build/src/cli/render/akuma.js +84 -13
- package/build/src/cli/render/audit.js +16 -2
- package/build/src/cli/render/contract.d.ts +2 -0
- package/build/src/cli/render/contract.js +203 -36
- package/build/src/cli/render/kanshi.js +64 -29
- package/build/src/cli/render/receipt.d.ts +2 -1
- package/build/src/cli/render/receipt.js +9 -1
- package/build/src/cli/render/text.js +3 -1
- package/build/src/cli/result.d.ts +38 -3
- package/build/src/cli/selectors.d.ts +1 -0
- package/build/src/cli/selectors.js +9 -6
- package/build/src/cli/usage.d.ts +2 -0
- package/build/src/cli/usage.js +4 -0
- package/build/src/contract-worktree.js +3 -0
- package/build/src/dispatch/index.js +50 -39
- package/build/src/git/hooks.d.ts +0 -4
- package/build/src/git/hooks.js +0 -36
- package/build/src/git/integration.d.ts +2 -6
- package/build/src/git/integration.js +8 -8
- package/build/src/git/read-observation.js +1 -0
- package/build/src/git/reconcile.d.ts +6 -1
- package/build/src/git/reconcile.js +55 -9
- package/build/src/git/tender.d.ts +19 -4
- package/build/src/git/tender.js +44 -13
- package/build/src/git/terminal-seal.d.ts +14 -0
- package/build/src/git/terminal-seal.js +15 -2
- package/build/src/git/workspace.d.ts +1 -0
- package/build/src/git/workspace.js +12 -4
- package/build/src/index.d.ts +1 -1
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +9 -1
- package/build/src/kanshi/read.js +91 -37
- package/build/src/kanshi/report.d.ts +1 -0
- package/build/src/library/address.d.ts +5 -14
- package/build/src/library/address.js +20 -22
- package/build/src/library/akuma-creation.d.ts +4 -2
- package/build/src/library/akuma-creation.js +43 -26
- package/build/src/library/bind.js +3 -3
- package/build/src/library/catalog.d.ts +1 -2
- package/build/src/library/catalog.js +11 -6
- package/build/src/library/configuration.d.ts +4 -0
- package/build/src/library/configuration.js +19 -0
- package/build/src/library/contract.d.ts +15 -1
- package/build/src/library/contract.js +51 -4
- package/build/src/library/fleet.d.ts +47 -9
- package/build/src/library/fleet.js +184 -44
- package/build/src/library/input.js +1 -0
- package/build/src/library/keiyaku.d.ts +4 -4
- package/build/src/library/keiyaku.js +1 -2
- package/build/src/protocol/bind.d.ts +1 -2
- package/build/src/protocol/bind.js +2 -16
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +33 -27
- package/build/src/protocol/read/status.d.ts +3 -1
- package/build/src/protocol/read/status.js +24 -14
- package/build/src/runtime/proc/run.d.ts +1 -0
- package/build/src/runtime/proc/run.js +9 -2
- package/build/src/settlement/settle.d.ts +1 -0
- package/build/src/settlement/settle.js +4 -1
- package/build/src/task/board.d.ts +18 -3
- package/build/src/task/board.js +73 -26
- package/build/src/task/index.d.ts +3 -3
- package/build/src/task/index.js +7 -5
- package/build/src/task/operations.d.ts +2 -19
- package/build/src/task/operations.js +29 -7
- package/build/src/task/query.d.ts +9 -2
- package/build/src/task/query.js +32 -64
- package/build/src/verification/execution.js +2 -1
- package/package.json +3 -1
package/build/src/cli/invoke.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AkumaWorldScopeError, gatesFrom, Keiyaku, requireBranchesToBeUpToDateFrom, settings, SettingsError, worktreeHooksFrom } from "../index.js";
|
|
2
|
-
import { kanshi, selectKanshi, selectRegion } from "../kanshi/index.js";
|
|
1
|
+
import { AkumaWorldScopeError, gatesFrom, Keiyaku, KeiyakuRefused, requireBranchesToBeUpToDateFrom, settings, SettingsError, worktreeHooksFrom, } from "../index.js";
|
|
2
|
+
import { kanshi, observeKanshi, selectKanshi, selectRegion, } from "../kanshi/index.js";
|
|
3
3
|
import { resolveActor } from "./actor.js";
|
|
4
4
|
import { acceptedAbandon, acceptedAmend, acceptedArc, acceptedAudit, acceptedBind, acceptedDeliver, acceptedReview, resultFromMutationCall, } from "./accepted.js";
|
|
5
5
|
import { amendFromCommand } from "./commands/amend.js";
|
|
@@ -10,7 +10,7 @@ import { installHarnesses } from "./commands/install.js";
|
|
|
10
10
|
import { invokeTask } from "./commands/task-invoke.js";
|
|
11
11
|
import { CliUsageError, renderCommandUsage } from "./parse.js";
|
|
12
12
|
import { isBlankInput } from "./usage.js";
|
|
13
|
-
import { contractFromInput, resolveContextualContract, resolveKanshiContract } from "./selectors.js";
|
|
13
|
+
import { canonicalContractSelector, contractFromInput, resolveContextualContract, resolveKanshiContract, } from "./selectors.js";
|
|
14
14
|
import { resolveNamedAddress } from "../library/address.js";
|
|
15
15
|
import { assertExplicitRepoUse, resolveCliCoordinates } from "./coordinates.js";
|
|
16
16
|
import { BindDraftError, preserveBindDraft } from "./draft.js";
|
|
@@ -23,9 +23,10 @@ async function readStdin() {
|
|
|
23
23
|
function selectedStdinDiagnostic(command) {
|
|
24
24
|
switch (command.command) {
|
|
25
25
|
case "bind":
|
|
26
|
-
case "amend":
|
|
27
26
|
case "arc":
|
|
28
27
|
return `${command.command} requires a nonblank stdin document`;
|
|
28
|
+
case "amend":
|
|
29
|
+
return command.stdin === true ? "amend requires a nonblank stdin document" : undefined;
|
|
29
30
|
case "review":
|
|
30
31
|
return command.summaryFromStdin === true ? "review requires a nonblank summary" : undefined;
|
|
31
32
|
case "call":
|
|
@@ -53,13 +54,12 @@ async function withAcquiredStdin(command, runtime) {
|
|
|
53
54
|
throw new CliUsageError(diagnostic);
|
|
54
55
|
return { ...runtime, readStdin: async () => bytes };
|
|
55
56
|
}
|
|
56
|
-
function settingsAt(root,
|
|
57
|
-
|
|
58
|
-
return settings({ ...(root === undefined ? {} : { root }), ...(home === undefined || home.length === 0 ? {} : { home }) });
|
|
57
|
+
function settingsAt(root, home) {
|
|
58
|
+
return settings({ ...(root === undefined ? {} : { root }), ...(home === undefined ? {} : { home }) });
|
|
59
59
|
}
|
|
60
|
-
function
|
|
60
|
+
function consumeSettings(run) {
|
|
61
61
|
try {
|
|
62
|
-
return
|
|
62
|
+
return run();
|
|
63
63
|
}
|
|
64
64
|
catch (error) {
|
|
65
65
|
if (error instanceof SettingsError)
|
|
@@ -67,25 +67,11 @@ function selectedGates(value, name) {
|
|
|
67
67
|
throw error;
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
|
-
function
|
|
71
|
-
|
|
72
|
-
return worktreeHooksFrom({ settings: value });
|
|
73
|
-
}
|
|
74
|
-
catch (error) {
|
|
75
|
-
if (error instanceof SettingsError)
|
|
76
|
-
throw new CliUsageError(error.message);
|
|
77
|
-
throw error;
|
|
78
|
-
}
|
|
70
|
+
function selectedGates(value, name) {
|
|
71
|
+
return consumeSettings(() => gatesFrom({ settings: value, ...(name === undefined ? {} : { name }) }));
|
|
79
72
|
}
|
|
80
73
|
function selectedGitPolicy(value) {
|
|
81
|
-
|
|
82
|
-
return requireBranchesToBeUpToDateFrom({ settings: value });
|
|
83
|
-
}
|
|
84
|
-
catch (error) {
|
|
85
|
-
if (error instanceof SettingsError)
|
|
86
|
-
throw new CliUsageError(error.message);
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
74
|
+
return consumeSettings(() => requireBranchesToBeUpToDateFrom({ settings: value }));
|
|
89
75
|
}
|
|
90
76
|
function actorFromEdge(actor, environment) {
|
|
91
77
|
let resolved;
|
|
@@ -127,7 +113,7 @@ async function invokeBind({ parsed, repo, edge, configuration, hooks, establishW
|
|
|
127
113
|
const bound = accepted.facts.find((fact) => fact.kind === "bind");
|
|
128
114
|
if (bound === undefined || bound.kind !== "bind")
|
|
129
115
|
throw new Error("accepted bind is missing its bind fact");
|
|
130
|
-
return acceptedBind(accepted, bound.data.coordinates
|
|
116
|
+
return acceptedBind(accepted, bound.data.coordinates);
|
|
131
117
|
});
|
|
132
118
|
if (result.kind !== "refused")
|
|
133
119
|
return result;
|
|
@@ -182,11 +168,19 @@ async function invokeExisting({ parsed, repo, edge, scope, configuration, hooks
|
|
|
182
168
|
const seat = { contract, id, ...(actor === undefined ? {} : { actor }), hooks };
|
|
183
169
|
switch (parsed.command) {
|
|
184
170
|
case "amend": {
|
|
185
|
-
const markdown = await edge.readStdin();
|
|
171
|
+
const markdown = parsed.stdin === true ? await edge.readStdin() : undefined;
|
|
186
172
|
const gates = parsed.gates === undefined
|
|
187
173
|
? undefined
|
|
188
174
|
: selectedGates(configuration, parsed.gates);
|
|
189
|
-
return resultFromMutationCall("amend", () => amendFromCommand({
|
|
175
|
+
return resultFromMutationCall("amend", () => amendFromCommand({
|
|
176
|
+
command: parsed,
|
|
177
|
+
repo,
|
|
178
|
+
contract,
|
|
179
|
+
...(markdown === undefined ? {} : { markdown }),
|
|
180
|
+
gates,
|
|
181
|
+
...(actor === undefined ? {} : { actor }),
|
|
182
|
+
hooks,
|
|
183
|
+
}), (result) => acceptedAmend(result, id), { coordinate: id });
|
|
190
184
|
}
|
|
191
185
|
case "deliver":
|
|
192
186
|
return invokeDeliver(parsed, seat, selectedGitPolicy(configuration));
|
|
@@ -212,32 +206,23 @@ async function invokeExisting({ parsed, repo, edge, scope, configuration, hooks
|
|
|
212
206
|
return parsed;
|
|
213
207
|
}
|
|
214
208
|
}
|
|
215
|
-
async function
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if (repo === undefined)
|
|
209
|
+
async function invokeAkumaFromEdge(parsed, input) {
|
|
210
|
+
try {
|
|
211
|
+
const { path, statedCwd, repo, home, configuration, edge } = input;
|
|
212
|
+
if (parsed.command === "call" && parsed.contract !== undefined && repo === undefined) {
|
|
219
213
|
throw new Error("call with Contract requires a resolved Repo");
|
|
220
|
-
|
|
214
|
+
}
|
|
221
215
|
return await invokeAkuma(parsed, {
|
|
222
216
|
path,
|
|
223
|
-
...(
|
|
224
|
-
|
|
225
|
-
|
|
217
|
+
...(statedCwd === undefined ? {} : { statedCwd }),
|
|
218
|
+
...(home === undefined ? {} : { home }),
|
|
219
|
+
...(configuration === undefined ? {} : { settings: configuration }),
|
|
220
|
+
...(parsed.command === "call" && parsed.contract !== undefined
|
|
221
|
+
? { contract: contractFromInput(repo, parsed.contract).contract }
|
|
222
|
+
: repo === undefined ? {} : { repo }),
|
|
226
223
|
readStdin: edge.readStdin,
|
|
227
224
|
});
|
|
228
225
|
}
|
|
229
|
-
return await invokeAkuma(parsed, {
|
|
230
|
-
path,
|
|
231
|
-
...(executionCwd === undefined ? {} : { executionCwd }),
|
|
232
|
-
settings: configuration,
|
|
233
|
-
...(repo === undefined ? {} : { repo }),
|
|
234
|
-
readStdin: edge.readStdin,
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
async function invokeAkumaFromEdge(parsed, input) {
|
|
238
|
-
try {
|
|
239
|
-
return await invokeAkumaCommand(parsed, input);
|
|
240
|
-
}
|
|
241
226
|
catch (error) {
|
|
242
227
|
if (error instanceof AkumaWorldScopeError)
|
|
243
228
|
throw error;
|
|
@@ -252,7 +237,7 @@ async function akumaWorldFor(parsed, located, candidate, establish) {
|
|
|
252
237
|
throw new CliUsageError("no Keiyaku world contains the invocation cwd");
|
|
253
238
|
return world;
|
|
254
239
|
}
|
|
255
|
-
async function invokeCatalog(parsed, world, repo,
|
|
240
|
+
async function invokeCatalog(parsed, world, repo, home) {
|
|
256
241
|
try {
|
|
257
242
|
if (parsed.query.kind === "contracts") {
|
|
258
243
|
if (repo === undefined)
|
|
@@ -262,7 +247,7 @@ async function invokeCatalog(parsed, world, repo, edge) {
|
|
|
262
247
|
if (parsed.query.kind === "archetypes") {
|
|
263
248
|
return {
|
|
264
249
|
kind: "catalog",
|
|
265
|
-
catalog: await Keiyaku.ls({ query: parsed.query,
|
|
250
|
+
catalog: await Keiyaku.ls({ query: parsed.query, ...(home === undefined ? {} : { home }) }),
|
|
266
251
|
};
|
|
267
252
|
}
|
|
268
253
|
if (world === null)
|
|
@@ -278,12 +263,11 @@ async function invokeCatalog(parsed, world, repo, edge) {
|
|
|
278
263
|
throw error;
|
|
279
264
|
}
|
|
280
265
|
}
|
|
281
|
-
async function invokeStatus(parsed, world, repo
|
|
282
|
-
const configuration = await settingsAt(world ?? undefined, edge.environment);
|
|
266
|
+
async function invokeStatus(parsed, world, repo) {
|
|
283
267
|
if (parsed.akuma === true) {
|
|
284
268
|
if (world === null)
|
|
285
269
|
throw new CliUsageError("no Keiyaku world contains the invocation cwd");
|
|
286
|
-
return invokeAkumaStatus(world, parsed.contract,
|
|
270
|
+
return invokeAkumaStatus(world, parsed.contract, undefined, repo);
|
|
287
271
|
}
|
|
288
272
|
if (parsed.contract === undefined) {
|
|
289
273
|
const report = await kanshi({ world, ...(repo === undefined ? {} : { repo }) });
|
|
@@ -291,18 +275,18 @@ async function invokeStatus(parsed, world, repo, edge) {
|
|
|
291
275
|
}
|
|
292
276
|
if (parsed.contract.startsWith("@")) {
|
|
293
277
|
try {
|
|
294
|
-
const
|
|
295
|
-
|
|
278
|
+
const observation = await observeKanshi({ world, ...(repo === undefined ? {} : { repo }) });
|
|
279
|
+
const address = resolveNamedAddress({
|
|
296
280
|
selector: parsed.contract,
|
|
297
|
-
|
|
281
|
+
report: observation.report,
|
|
282
|
+
aliases: observation.aliases,
|
|
298
283
|
});
|
|
299
284
|
if (address.kind === "akuma") {
|
|
300
285
|
if (world === null)
|
|
301
286
|
throw new CliUsageError("no Keiyaku world contains the invocation cwd");
|
|
302
|
-
return invokeAkumaStatus(world, address.id,
|
|
287
|
+
return invokeAkumaStatus(world, address.id, parsed.contract, repo);
|
|
303
288
|
}
|
|
304
|
-
|
|
305
|
-
return { kind: "status", report: selectKanshi({ report, contract: address.id }), selection: "contract" };
|
|
289
|
+
return { kind: "status", report: selectKanshi({ report: observation.report, contract: address.id }), selection: "contract" };
|
|
306
290
|
}
|
|
307
291
|
catch (error) {
|
|
308
292
|
if (error instanceof TypeError)
|
|
@@ -310,6 +294,16 @@ async function invokeStatus(parsed, world, repo, edge) {
|
|
|
310
294
|
throw error;
|
|
311
295
|
}
|
|
312
296
|
}
|
|
297
|
+
if (parsed.contract.startsWith("kei/")) {
|
|
298
|
+
if (repo === undefined)
|
|
299
|
+
throw new CliUsageError("cannot select a contract while the Contract world is absent");
|
|
300
|
+
const contract = canonicalContractSelector(parsed.contract);
|
|
301
|
+
return {
|
|
302
|
+
kind: "status",
|
|
303
|
+
report: await kanshi({ world, repo, contract }),
|
|
304
|
+
selection: "contract",
|
|
305
|
+
};
|
|
306
|
+
}
|
|
313
307
|
const report = await kanshi({ world, ...(repo === undefined ? {} : { repo }) });
|
|
314
308
|
const contract = resolveKanshiContract(report, parsed.contract);
|
|
315
309
|
return { kind: "status", report: selectKanshi({ report, contract }), selection: "contract" };
|
|
@@ -343,6 +337,22 @@ async function invokeRegion(parsed, world, repo) {
|
|
|
343
337
|
const selection = parsed.overlap ? { kind: "overlap", contract } : { kind: "contract", contract };
|
|
344
338
|
return { kind: "region", region: { kind: "present", value: selectRegion({ declarations: report.region.value.declarations, selection }) } };
|
|
345
339
|
}
|
|
340
|
+
async function invokeContractHistory(repo, contract) {
|
|
341
|
+
if (repo === undefined)
|
|
342
|
+
throw new Error("history kei/... requires a resolved Repo");
|
|
343
|
+
const selected = contractFromInput(repo, contract);
|
|
344
|
+
try {
|
|
345
|
+
return { kind: "contract-history", history: await selected.contract.history() };
|
|
346
|
+
}
|
|
347
|
+
catch (error) {
|
|
348
|
+
if (error instanceof TypeError)
|
|
349
|
+
throw new CliUsageError(error.message);
|
|
350
|
+
if (error instanceof KeiyakuRefused) {
|
|
351
|
+
return { kind: "refused", verb: "history", contract: selected.id, refusal: error.refusal };
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
346
356
|
// eslint-disable-next-line complexity -- command dispatch keeps the CLI's existing boundary in one place.
|
|
347
357
|
async function invokeParsed(invocation, runtime) {
|
|
348
358
|
const coordinates = await resolveCliCoordinates({
|
|
@@ -351,14 +361,16 @@ async function invokeParsed(invocation, runtime) {
|
|
|
351
361
|
...(invocation.repo === undefined ? {} : { repo: invocation.repo }),
|
|
352
362
|
command: invocation.command,
|
|
353
363
|
});
|
|
354
|
-
const { cwd, repo, world, candidateWorld, establishWorld } = coordinates;
|
|
364
|
+
const { cwd, cwdSource, repo, world, candidateWorld, establishWorld } = coordinates;
|
|
355
365
|
const edge = {
|
|
356
366
|
environment: runtime.environment ?? process.env,
|
|
357
367
|
readStdin: runtime.readStdin ?? readStdin,
|
|
358
368
|
};
|
|
359
369
|
const parsed = invocation.command;
|
|
370
|
+
const mapped = edge.environment.KEIYAKU_HOME?.trim();
|
|
371
|
+
const home = mapped === undefined || mapped.length === 0 ? undefined : mapped;
|
|
360
372
|
if (parsed.command === "settings") {
|
|
361
|
-
return { kind: "settings", value: await settingsAt(world ?? undefined,
|
|
373
|
+
return { kind: "settings", value: await settingsAt(world ?? undefined, home) };
|
|
362
374
|
}
|
|
363
375
|
if (parsed.command === "task") {
|
|
364
376
|
try {
|
|
@@ -375,30 +387,31 @@ async function invokeParsed(invocation, runtime) {
|
|
|
375
387
|
throw error;
|
|
376
388
|
}
|
|
377
389
|
}
|
|
390
|
+
if (parsed.command === "history" && "contract" in parsed)
|
|
391
|
+
return await invokeContractHistory(repo, parsed.contract);
|
|
378
392
|
if (isParsedAkumaCommand(parsed)) {
|
|
379
393
|
const akumaWorld = await akumaWorldFor(parsed, world, candidateWorld, coordinates.establishWorld);
|
|
380
|
-
const configuration = await settingsAt(akumaWorld,
|
|
394
|
+
const configuration = parsed.command === "call" ? await settingsAt(akumaWorld, home) : undefined;
|
|
381
395
|
return await invokeAkumaFromEdge(parsed, {
|
|
382
396
|
path: akumaWorld,
|
|
383
|
-
...(
|
|
384
|
-
? {}
|
|
385
|
-
: { executionCwd: cwd }),
|
|
397
|
+
...(cwdSource === "input" ? { statedCwd: cwd } : {}),
|
|
386
398
|
...(repo === undefined ? {} : { repo }),
|
|
387
|
-
|
|
399
|
+
...(parsed.command === "call" && home !== undefined ? { home } : {}),
|
|
400
|
+
...(configuration === undefined ? {} : { configuration }),
|
|
388
401
|
edge,
|
|
389
402
|
});
|
|
390
403
|
}
|
|
391
404
|
if (parsed.command === "ls")
|
|
392
|
-
return await invokeCatalog(parsed, world, repo,
|
|
405
|
+
return await invokeCatalog(parsed, world, repo, home);
|
|
393
406
|
if (parsed.command === "status")
|
|
394
|
-
return await invokeStatus(parsed, world, repo
|
|
407
|
+
return await invokeStatus(parsed, world, repo);
|
|
395
408
|
if (repo === undefined)
|
|
396
409
|
throw new Error(`${parsed.command} requires a resolved Repo`);
|
|
397
410
|
if (parsed.command === "region")
|
|
398
411
|
return invokeRegion(parsed, world, repo);
|
|
399
412
|
const scope = cwd;
|
|
400
|
-
const configuration = await settingsAt(world ?? undefined,
|
|
401
|
-
const hooks =
|
|
413
|
+
const configuration = await settingsAt(world ?? undefined, home);
|
|
414
|
+
const hooks = consumeSettings(() => worktreeHooksFrom({ settings: configuration }));
|
|
402
415
|
if (parsed.command === "show") {
|
|
403
416
|
const selected = await selectContract(repo, parsed.contract, scope);
|
|
404
417
|
return { kind: "guidance", contract: selected.id, guidance: await selected.contract.guidance() };
|
|
@@ -427,13 +440,17 @@ export async function invoke(invocation, runtime = {}) {
|
|
|
427
440
|
try {
|
|
428
441
|
const command = invocation.command;
|
|
429
442
|
assertExplicitRepoUse(command, invocation.repo);
|
|
430
|
-
if (command.command === "install")
|
|
443
|
+
if (command.command === "install") {
|
|
444
|
+
runtime.onOperationStart?.();
|
|
431
445
|
return installHarnesses(command.harnesses, runtime.environment ?? process.env);
|
|
446
|
+
}
|
|
447
|
+
const acquiredRuntime = await withAcquiredStdin(command, withResolvedTaskActor(command, runtime));
|
|
448
|
+
runtime.onOperationStart?.();
|
|
432
449
|
return await invokeParsed({
|
|
433
450
|
...(invocation.cwd === undefined ? {} : { cwd: invocation.cwd }),
|
|
434
451
|
...(invocation.repo === undefined ? {} : { repo: invocation.repo }),
|
|
435
452
|
command,
|
|
436
|
-
},
|
|
453
|
+
}, acquiredRuntime);
|
|
437
454
|
}
|
|
438
455
|
catch (error) {
|
|
439
456
|
if (error instanceof CliUsageError && error.projection === undefined) {
|
package/build/src/cli/main.d.ts
CHANGED
package/build/src/cli/main.js
CHANGED
|
@@ -28,7 +28,7 @@ function writeTask(command, result) {
|
|
|
28
28
|
return taskExitCode(result);
|
|
29
29
|
}
|
|
30
30
|
function writeAkuma(command, result) {
|
|
31
|
-
const output = command.output === "json" ? renderAkumaJson(
|
|
31
|
+
const output = command.output === "json" ? renderAkumaJson(result) : renderAkumaText(command, result, {
|
|
32
32
|
columns: process.stdout.isTTY === true && Number.isInteger(process.stdout.columns) ? process.stdout.columns : 80,
|
|
33
33
|
color: process.stdout.isTTY === true && process.env.NO_COLOR === undefined,
|
|
34
34
|
});
|
|
@@ -46,6 +46,18 @@ function renderHelp(coordinate) {
|
|
|
46
46
|
case "akuma": return renderAkumaHelp(coordinate.action);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
export function invocationStart(command) {
|
|
50
|
+
if (command.output === "json")
|
|
51
|
+
return undefined;
|
|
52
|
+
switch (command.command) {
|
|
53
|
+
case "bind": return "⧖ preparing keiyaku";
|
|
54
|
+
case "deliver": return "⧖ delivering";
|
|
55
|
+
case "audit": return "⧖ auditing";
|
|
56
|
+
case "reconcile": return "⧖ reconciling";
|
|
57
|
+
case "install": return "⧖ installing skills";
|
|
58
|
+
default: return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
49
61
|
function writeGuidance(command, result) {
|
|
50
62
|
if (command.output === "json")
|
|
51
63
|
process.stdout.write(`${JSON.stringify({ contract: result.contract, guidance: result.guidance })}\n`);
|
|
@@ -71,8 +83,17 @@ function writeResult(command, result) {
|
|
|
71
83
|
process.stdout.write(`${command.output === "json" ? JSON.stringify(settingsJsonValue(value)) : renderSettingsText(value)}\n`);
|
|
72
84
|
return 0;
|
|
73
85
|
}
|
|
74
|
-
if (
|
|
75
|
-
|
|
86
|
+
if (typeof result === "object" && result !== null && "kind" in result && result.kind === "contract-history") {
|
|
87
|
+
const history = result.history;
|
|
88
|
+
const output = command.output === "json" ? JSON.stringify(history) : renderText(result);
|
|
89
|
+
process.stdout.write(`${output}\n`);
|
|
90
|
+
return 0;
|
|
91
|
+
}
|
|
92
|
+
const akumaResult = typeof result === "object" && result !== null && "kind" in result && result.kind === "akuma";
|
|
93
|
+
if (isParsedAkumaCommand(command)) {
|
|
94
|
+
return writeAkuma(command, result);
|
|
95
|
+
}
|
|
96
|
+
if (akumaResult && command.command === "status") {
|
|
76
97
|
return writeAkuma(command, result);
|
|
77
98
|
}
|
|
78
99
|
const contractResult = result;
|
|
@@ -111,7 +132,11 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
111
132
|
}
|
|
112
133
|
output = parsed.command.output;
|
|
113
134
|
const { invoke } = await import("./invoke.js");
|
|
114
|
-
const
|
|
135
|
+
const start = invocationStart(parsed.command);
|
|
136
|
+
const result = await invoke(parsed, {
|
|
137
|
+
cwd: process.cwd(),
|
|
138
|
+
...(start === undefined ? {} : { onOperationStart: () => { process.stderr.write(`${start}\n`); } }),
|
|
139
|
+
});
|
|
115
140
|
return writeResult(parsed.command, result);
|
|
116
141
|
}
|
|
117
142
|
catch (error) {
|
package/build/src/cli/parse.d.ts
CHANGED
package/build/src/cli/parse.js
CHANGED
|
@@ -2,11 +2,11 @@ import { isTaskAction, parseTaskCommand, renderTaskUsage, } from "./commands/tas
|
|
|
2
2
|
import { isAkumaAction, parseAkumaCatalogPath, parseAkumaCommand, renderAkumaRootRows, renderAkumaUsage, } from "./commands/akuma.js";
|
|
3
3
|
import { INSTALL_USAGE, parseInstallCommand, renderInstallHelp } from "./commands/install.js";
|
|
4
4
|
import { AMEND_MINIMAL_STDIN_HELP, CONTRACT_COMMAND_SPECS } from "./commands/contract.js";
|
|
5
|
-
import { CliUsageError, isBlankInput, usageLine } from "./usage.js";
|
|
5
|
+
import { CliUsageError, isBlankInput, usageLine, withJsonAutomationHelp } from "./usage.js";
|
|
6
6
|
export { CliUsageError } from "./usage.js";
|
|
7
7
|
const ROOT_USAGE = "usage: keiyaku [-C <path>] [--repo <path>] <command> [<contract>|@<contract>] [--flag ...] [-]";
|
|
8
8
|
export function renderRootHelp() {
|
|
9
|
-
return [
|
|
9
|
+
return withJsonAutomationHelp([
|
|
10
10
|
ROOT_USAGE,
|
|
11
11
|
"",
|
|
12
12
|
"global options:",
|
|
@@ -20,12 +20,12 @@ export function renderRootHelp() {
|
|
|
20
20
|
" task ...",
|
|
21
21
|
" Task coordination; see `keiyaku task --help`.",
|
|
22
22
|
...renderAkumaRootRows(),
|
|
23
|
-
].join("\n");
|
|
23
|
+
].join("\n"));
|
|
24
24
|
}
|
|
25
25
|
export function renderContractHelp(command) {
|
|
26
26
|
const spec = CONTRACT_COMMAND_SPECS[command];
|
|
27
27
|
const help = `${spec.purpose}\n\n${usageLine(spec.usage)}`;
|
|
28
|
-
return command === "amend" ? `${help}\n\n${AMEND_MINIMAL_STDIN_HELP}` : help;
|
|
28
|
+
return withJsonAutomationHelp(command === "amend" ? `${help}\n\n${AMEND_MINIMAL_STDIN_HELP}` : help);
|
|
29
29
|
}
|
|
30
30
|
function contractUsage(command) {
|
|
31
31
|
return usageLine(CONTRACT_COMMAND_SPECS[command].usage);
|
|
@@ -139,6 +139,9 @@ function parseAmend(parts) {
|
|
|
139
139
|
if (parts.flags["clear-after"] === true && after.length > 0)
|
|
140
140
|
refuse("amend", "--clear-after and --after are mutually exclusive");
|
|
141
141
|
const gates = optionalFlag(parts.flags, "gates");
|
|
142
|
+
if (!parts.stdin && parts.flags.after === undefined && parts.flags["clear-after"] !== true && gates === undefined) {
|
|
143
|
+
refuse("amend", "amend requires stdin or --after, --clear-after, or --gates");
|
|
144
|
+
}
|
|
142
145
|
return {
|
|
143
146
|
command: "amend",
|
|
144
147
|
...(contract === undefined ? {} : { contract }),
|
|
@@ -146,6 +149,7 @@ function parseAmend(parts) {
|
|
|
146
149
|
...(parts.flags["clear-after"] === true ? { clearAfter: true } : {}),
|
|
147
150
|
...(gates === undefined ? {} : { gates }),
|
|
148
151
|
...(parts.actor === undefined ? {} : { actor: parts.actor }),
|
|
152
|
+
...(parts.stdin ? { stdin: true } : {}),
|
|
149
153
|
output: parts.output,
|
|
150
154
|
};
|
|
151
155
|
}
|
|
@@ -4,5 +4,5 @@ import { type TextRenderContext } from "./terminal.js";
|
|
|
4
4
|
export declare function akumaRawAnswer(result: AkumaInvocationResult): string | undefined;
|
|
5
5
|
export declare function renderAkumaText(command: ParsedCommand, result: AkumaInvocationResult, context?: TextRenderContext): string;
|
|
6
6
|
export declare function akumaExitCode(result: AkumaInvocationResult): number;
|
|
7
|
-
export declare function akumaJsonValue(
|
|
8
|
-
export declare function renderAkumaJson(
|
|
7
|
+
export declare function akumaJsonValue(result: AkumaInvocationResult): unknown;
|
|
8
|
+
export declare function renderAkumaJson(result: AkumaInvocationResult): string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { toolRepr } from "./akuma-tool.js";
|
|
2
|
-
import { displayColumns, renderBoundedTextBlock, safeText, truncateMiddleDisplayText } from "./terminal.js";
|
|
2
|
+
import { displayColumns, renderBoundedTextBlock, renderTextBlock, safeText, truncateMiddleDisplayText, } from "./terminal.js";
|
|
3
3
|
const DEFAULT_CONTEXT = { columns: 80, color: false };
|
|
4
4
|
const OPENING_STROKE = "─────";
|
|
5
5
|
const TIME_WIDTH = 5;
|
|
@@ -138,6 +138,59 @@ function groupedEntries(entries, context, history = false) {
|
|
|
138
138
|
function groupedRows(rows, context, history = false) {
|
|
139
139
|
return groupedEntries(rows.filter((row) => row.kind !== "turn").map((row) => ({ kind: "row", row })), context, history);
|
|
140
140
|
}
|
|
141
|
+
function taskDispositionMark(disposition) {
|
|
142
|
+
if (disposition === "done")
|
|
143
|
+
return "✓";
|
|
144
|
+
if (disposition === "drop")
|
|
145
|
+
return "×";
|
|
146
|
+
if (disposition === "on_hold")
|
|
147
|
+
return "⧗";
|
|
148
|
+
if (disposition === "in_progress")
|
|
149
|
+
return "●";
|
|
150
|
+
return disposition === "blocked" ? "‖" : "○";
|
|
151
|
+
}
|
|
152
|
+
function taskScanLine(row, indent = "") {
|
|
153
|
+
return `${indent}${taskDispositionMark(row.disposition)} ${row.id} · P${row.priority} ${row.disposition}`;
|
|
154
|
+
}
|
|
155
|
+
function changeOp(op) {
|
|
156
|
+
return op === "add" ? "write" : op === "delete" ? "delete" : "edit";
|
|
157
|
+
}
|
|
158
|
+
function renderReportedChangeLines(snapshot, columns) {
|
|
159
|
+
const lines = [` changes ${snapshot.reportedChanges.length + snapshot.reportedChangesOmitted}`];
|
|
160
|
+
for (const change of snapshot.reportedChanges) {
|
|
161
|
+
const scan = ` ${changeOp(change.op)}`;
|
|
162
|
+
const path = safeText(change.path);
|
|
163
|
+
const stat = change.diffstat === undefined
|
|
164
|
+
? ""
|
|
165
|
+
: ` — +${change.diffstat.added} -${change.diffstat.removed}`;
|
|
166
|
+
const inline = `${scan} ${path}${stat}`;
|
|
167
|
+
if (displayColumns(inline) <= columns)
|
|
168
|
+
lines.push(inline);
|
|
169
|
+
else
|
|
170
|
+
lines.push(`${scan}`, ...renderTextBlock(`${path}${stat}`, " ", columns));
|
|
171
|
+
}
|
|
172
|
+
if (snapshot.reportedChangesOmitted > 0) {
|
|
173
|
+
lines.push(` ⋮ ${snapshot.reportedChangesOmitted} earlier changes`);
|
|
174
|
+
}
|
|
175
|
+
return lines;
|
|
176
|
+
}
|
|
177
|
+
function renderTaskContextLines(created, columns) {
|
|
178
|
+
if (created === undefined)
|
|
179
|
+
return [];
|
|
180
|
+
if (created.kind === "failed")
|
|
181
|
+
return [`! tasks failed ${safeText(created.diagnostic)}`];
|
|
182
|
+
const lines = [` tasks ${created.rows.length}`];
|
|
183
|
+
for (const row of created.rows) {
|
|
184
|
+
const scan = ` ${taskScanLine(row)}`;
|
|
185
|
+
const title = safeText(row.title);
|
|
186
|
+
const inline = `${scan} — ${title}`;
|
|
187
|
+
if (displayColumns(inline) <= columns)
|
|
188
|
+
lines.push(inline);
|
|
189
|
+
else
|
|
190
|
+
lines.push(`${scan} —`, ...renderTextBlock(title, " ", columns));
|
|
191
|
+
}
|
|
192
|
+
return lines;
|
|
193
|
+
}
|
|
141
194
|
function snapshotText(view, context, options = {}) {
|
|
142
195
|
const snapshot = view.status.timeline;
|
|
143
196
|
const activity = snapshot.kind === "idle" && snapshot.outcome !== undefined
|
|
@@ -151,7 +204,14 @@ function snapshotText(view, context, options = {}) {
|
|
|
151
204
|
...(options.facts ?? []),
|
|
152
205
|
];
|
|
153
206
|
const footer = options.showLife === false ? [] : [` ${lifeLabel(view.status.life)}`];
|
|
154
|
-
return [
|
|
207
|
+
return [
|
|
208
|
+
...snapshotHeading(view.status.id, options.alias, view.contractId),
|
|
209
|
+
...facts,
|
|
210
|
+
...activity,
|
|
211
|
+
...footer,
|
|
212
|
+
...renderReportedChangeLines(snapshot, context.columns),
|
|
213
|
+
...renderTaskContextLines(view.createdTasks, context.columns),
|
|
214
|
+
].join("\n");
|
|
155
215
|
}
|
|
156
216
|
function historyText(command, result, context) {
|
|
157
217
|
if (command.last)
|
|
@@ -195,8 +255,9 @@ export function akumaRawAnswer(result) {
|
|
|
195
255
|
return undefined;
|
|
196
256
|
return statusAnswer({ status: result.result.observation.status });
|
|
197
257
|
}
|
|
198
|
-
if (result.action === "wait" && result.result.
|
|
199
|
-
return statusAnswer(result.result.
|
|
258
|
+
if (result.action === "wait" && result.result.observations.length === 1) {
|
|
259
|
+
return statusAnswer(result.result.observations[0]);
|
|
260
|
+
}
|
|
200
261
|
return undefined;
|
|
201
262
|
}
|
|
202
263
|
function executionCwdLine(result) {
|
|
@@ -237,9 +298,11 @@ export function renderAkumaText(command, result, context = DEFAULT_CONTEXT) {
|
|
|
237
298
|
switch (result.action) {
|
|
238
299
|
case "call": return callText(result, context);
|
|
239
300
|
case "status": return snapshotText(result.status, context, { ...(result.alias === undefined ? {} : { alias: result.alias }) });
|
|
240
|
-
case "wait":
|
|
301
|
+
case "wait":
|
|
302
|
+
return result.result.observations.map((observation) => snapshotText(observation, context, { ...(result.alias === undefined ? {} : { alias: result.alias }) })).join("\n\n");
|
|
241
303
|
case "tell": return result.mode === "ordinary" ? tellText(result, context) : snapshotText(result.result.observation, context, { ...(result.alias === undefined ? {} : { alias: result.alias }), showLife: false });
|
|
242
|
-
case "history":
|
|
304
|
+
case "history":
|
|
305
|
+
return historyText(command, result, context);
|
|
243
306
|
case "fork": {
|
|
244
307
|
if (result.receipt.kind !== "forked")
|
|
245
308
|
return result.receipt.kind === "unknown-history" ? `${result.receipt.at} has no matching retained answered turn` : result.receipt.kind === "provider-cannot-fork" ? `${result.receipt.provider} cannot fork` : result.receipt.diagnostic;
|
|
@@ -277,13 +340,21 @@ export function akumaExitCode(result) {
|
|
|
277
340
|
default: return 0;
|
|
278
341
|
}
|
|
279
342
|
}
|
|
280
|
-
export function akumaJsonValue(
|
|
281
|
-
if (result.action === "call"
|
|
282
|
-
return result.
|
|
283
|
-
if (
|
|
284
|
-
|
|
343
|
+
export function akumaJsonValue(result) {
|
|
344
|
+
if (result.action === "call")
|
|
345
|
+
return result.result;
|
|
346
|
+
if (result.action === "fork")
|
|
347
|
+
return result.receipt;
|
|
348
|
+
if (result.action === "status")
|
|
349
|
+
return result.status;
|
|
350
|
+
if (result.action === "wait")
|
|
351
|
+
return result.result;
|
|
352
|
+
if (result.action === "tell")
|
|
353
|
+
return result.result;
|
|
354
|
+
if (result.action === "kill")
|
|
355
|
+
return result.result;
|
|
285
356
|
return result.historyResult;
|
|
286
357
|
}
|
|
287
|
-
export function renderAkumaJson(
|
|
288
|
-
return JSON.stringify(akumaJsonValue(
|
|
358
|
+
export function renderAkumaJson(result) {
|
|
359
|
+
return JSON.stringify(akumaJsonValue(result));
|
|
289
360
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cleanupLines, leakLines,
|
|
1
|
+
import { cleanupLines, leakLines, receiptPayload, receiptRow, stopLines, titleLines, } from "./receipt.js";
|
|
2
2
|
import { renderRefusalFacts } from "./refusal.js";
|
|
3
3
|
import { gitShortStat, renderBoundedTextBlock, renderOpaqueBlock, } from "./terminal.js";
|
|
4
4
|
const CHILD = " ";
|
|
@@ -91,14 +91,28 @@ function obligationLines(result, columns) {
|
|
|
91
91
|
...(result.leak === undefined ? [] : leakLines(result.leak, columns)),
|
|
92
92
|
];
|
|
93
93
|
}
|
|
94
|
+
function recordLines(result, columns) {
|
|
95
|
+
if (result.facts.length === 0)
|
|
96
|
+
return [];
|
|
97
|
+
const rows = [];
|
|
98
|
+
for (const fact of result.facts) {
|
|
99
|
+
receiptRow(rows, " ", "journal", [
|
|
100
|
+
{ text: fact.entry, opaque: true },
|
|
101
|
+
{ text: `· ${fact.kind}` },
|
|
102
|
+
], columns);
|
|
103
|
+
}
|
|
104
|
+
receiptRow(rows, " ", "head", [{ text: result.head, opaque: true }], columns);
|
|
105
|
+
return [" record", ...rows.map((line) => ` ${line}`)];
|
|
106
|
+
}
|
|
94
107
|
export function renderAcceptedAudit(result, context) {
|
|
95
108
|
const report = result.report;
|
|
96
109
|
const columns = context?.columns ?? 80;
|
|
97
110
|
return [
|
|
98
|
-
...
|
|
111
|
+
...titleLines("✓", "audit", result.contract, columns),
|
|
99
112
|
...candidateLines(report, columns, result.contract),
|
|
100
113
|
...verificationLines(report.verification, columns, result.contract),
|
|
101
114
|
...targetLines(report.target, columns, result.contract),
|
|
102
115
|
...obligationLines(result, columns),
|
|
116
|
+
...recordLines(result, columns),
|
|
103
117
|
].join("\n");
|
|
104
118
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { ContractHistory } from "../../index.js";
|
|
1
2
|
import type { AcceptedResult, RetryResult } from "../result.js";
|
|
2
3
|
import { type TextRenderContext } from "./terminal.js";
|
|
3
4
|
export declare function renderAccepted(result: AcceptedResult, context?: TextRenderContext): string;
|
|
4
5
|
export declare function renderRetry(result: RetryResult, context?: TextRenderContext): string;
|
|
6
|
+
export declare function renderContractHistory(history: ContractHistory): string;
|