@astrosheep/keiyaku 4.5.26 → 4.5.27

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.
Files changed (78) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +5 -4
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +16 -14
  3. package/build/src/akuma/akuma-errors.d.ts +6 -0
  4. package/build/src/akuma/akuma-errors.js +11 -0
  5. package/build/src/akuma/akuma-handle.d.ts +53 -1
  6. package/build/src/akuma/akuma-handle.js +75 -7
  7. package/build/src/akuma/akuma-instance.js +6 -22
  8. package/build/src/akuma/akuma-probe.d.ts +20 -1
  9. package/build/src/akuma/akuma-probe.js +20 -3
  10. package/build/src/akuma/akuma.d.ts +12 -0
  11. package/build/src/akuma/allowed.d.ts +2 -1
  12. package/build/src/akuma/allowed.js +9 -4
  13. package/build/src/akuma/archetype.js +3 -3
  14. package/build/src/akuma/body.js +8 -3
  15. package/build/src/akuma/fleet-execution.d.ts +6 -1
  16. package/build/src/akuma/fleet-execution.js +44 -0
  17. package/build/src/akuma/fleet-observation.d.ts +238 -0
  18. package/build/src/akuma/fleet-observation.js +13 -0
  19. package/build/src/akuma/fleet-owner-port.d.ts +12 -0
  20. package/build/src/akuma/fleet-owner-port.js +46 -0
  21. package/build/src/akuma/fleet-request.d.ts +55 -4
  22. package/build/src/akuma/fleet-request.js +101 -6
  23. package/build/src/akuma/heart/index.d.ts +1 -0
  24. package/build/src/akuma/heart/index.js +4 -1
  25. package/build/src/akuma/heart/rows.d.ts +1 -0
  26. package/build/src/akuma/heart/rows.js +8 -0
  27. package/build/src/akuma/heart/soul.js +2 -2
  28. package/build/src/akuma/projection.d.ts +36 -0
  29. package/build/src/akuma/projection.js +2 -1
  30. package/build/src/akuma/provider.d.ts +14 -0
  31. package/build/src/akuma/provider.js +66 -4
  32. package/build/src/akuma/providers/acp/events.js +16 -8
  33. package/build/src/akuma/providers/claude/events.js +5 -7
  34. package/build/src/akuma/providers/opencode-sdk/events.js +9 -5
  35. package/build/src/akuma/providers/pi/events.js +4 -3
  36. package/build/src/akuma/request-lifecycle.js +10 -1
  37. package/build/src/akuma-body.js +1 -33
  38. package/build/src/cli/commands/akuma-invoke.d.ts +8 -0
  39. package/build/src/cli/commands/akuma-invoke.js +58 -6
  40. package/build/src/cli/commands/akuma.d.ts +1 -0
  41. package/build/src/cli/commands/akuma.js +10 -15
  42. package/build/src/cli/commands/contract-help.js +8 -5
  43. package/build/src/cli/render/akuma-activity.d.ts +7 -1
  44. package/build/src/cli/render/akuma-activity.js +158 -49
  45. package/build/src/cli/render/akuma-tool.d.ts +5 -0
  46. package/build/src/cli/render/akuma-tool.js +118 -14
  47. package/build/src/cli/render/akuma.d.ts +3 -1
  48. package/build/src/cli/render/akuma.js +34 -2
  49. package/build/src/cli/render/catalog.js +2 -3
  50. package/build/src/cli/render/contract-observation.d.ts +1 -0
  51. package/build/src/cli/render/contract-observation.js +20 -1
  52. package/build/src/cli/render/contract.js +4 -4
  53. package/build/src/cli/render/execution-progress.d.ts +1 -0
  54. package/build/src/cli/render/execution-progress.js +77 -3
  55. package/build/src/cli/render/kanshi.js +5 -19
  56. package/build/src/cli/render/terminal.js +3 -1
  57. package/build/src/cli/runtime.d.ts +6 -0
  58. package/build/src/cli/runtime.js +35 -17
  59. package/build/src/core/facts/offer.d.ts +1 -2
  60. package/build/src/core/verbs/abandon.js +1 -1
  61. package/build/src/core/verbs/amend.js +1 -1
  62. package/build/src/core/verbs/arc.js +1 -1
  63. package/build/src/core/verbs/attestation.js +1 -1
  64. package/build/src/core/verbs/bind.js +1 -1
  65. package/build/src/core/verbs/deliver.js +1 -1
  66. package/build/src/core/verbs/placement.js +1 -1
  67. package/build/src/core/verbs/reintegrate.js +1 -1
  68. package/build/src/git/admission.js +18 -7
  69. package/build/src/identity/coordinates.js +1 -1
  70. package/build/src/library/address.d.ts +33 -3
  71. package/build/src/library/address.js +89 -28
  72. package/build/src/library/composition.d.ts +12 -0
  73. package/build/src/library/fleet.d.ts +11 -1
  74. package/build/src/library/fleet.js +138 -48
  75. package/build/src/library/keiyaku.d.ts +12 -0
  76. package/build/src/plugin/public.d.ts +2 -0
  77. package/build/src/runtime/proc/windows-launch.exe +0 -0
  78. package/package.json +1 -1
@@ -45,7 +45,16 @@ export class BodyRequestPump {
45
45
  if (this.handled.has(transportId))
46
46
  continue;
47
47
  const path = join(this.directory, name);
48
- const claim = decodeEnvelope(await readFile(path, "utf8"), transportId);
48
+ let serialized;
49
+ try {
50
+ serialized = await readFile(path, "utf8");
51
+ }
52
+ catch (error) {
53
+ if (error.code !== "ENOENT")
54
+ throw error;
55
+ continue;
56
+ }
57
+ const claim = decodeEnvelope(serialized, transportId);
49
58
  if (claim === null) {
50
59
  await rm(path, { force: true });
51
60
  this.handled.add(transportId);
@@ -1,9 +1,7 @@
1
1
  import { LEASH_HELD_EXIT, runAkumaBody } from "./akuma/body.js";
2
2
  import { worldRootForAkumaPaths } from "./akuma/identity.js";
3
3
  import { World } from "./world.js";
4
- import { executeKillAkuma, executeTellAkuma, executeWaitAkuma } from "./akuma/fleet-execution.js";
5
- import { Akuma as PublicAkuma } from "./akuma/akuma-instance.js";
6
- import { Schema } from "./akuma/schema.js";
4
+ import { fleetRequestPort } from "./akuma/fleet-owner-port.js";
7
5
  import { fleetRequestCommands } from "./akuma/fleet-request.js";
8
6
  import { worktreeHooksFrom } from "./git/hooks.js";
9
7
  import { contractRequestCommands, executeForwardedAudit, executeForwardedDeliver, executeForwardedReview, } from "./library/contract-operations.js";
@@ -71,36 +69,6 @@ function contractUpstream(processConfiguration) {
71
69
  },
72
70
  };
73
71
  }
74
- function fleetRequestPort(world) {
75
- return {
76
- wait: async (input) => await executeWaitAkuma({
77
- path: world,
78
- ids: input.targets,
79
- completion: input.completion,
80
- ...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
81
- signal: input.signal,
82
- }),
83
- tell: async (input) => await executeTellAkuma({
84
- path: world,
85
- id: input.target,
86
- body: input.body,
87
- tellId: input.tellId,
88
- recordedAt: input.recordedAt,
89
- ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
90
- signal: input.signal,
91
- }),
92
- tellAnswer: async (input) => await PublicAkuma.select(world, input.target).tell(input.body, {
93
- schema: Schema.json(JSON.parse(input.schemaJson), (value) => value),
94
- ...(input.interrupt === undefined ? {} : { interrupt: input.interrupt }),
95
- ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
96
- signal: input.signal,
97
- }),
98
- kill: async (input) => {
99
- const result = await executeKillAkuma({ path: world, ids: input.targets, signal: input.signal });
100
- return result;
101
- },
102
- };
103
- }
104
72
  function taskMutationRequestPort() {
105
73
  return {
106
74
  task: async (input) => await executeTaskMutation({
@@ -6,6 +6,7 @@ import type { Settings } from "../../settings.js";
6
6
  import type { WorldRoot } from "../../world.js";
7
7
  import type { InvokedAkumaCommand } from "./akuma.js";
8
8
  import { type ExecutionContext } from "../../akuma/requests.js";
9
+ import type { AkumaTellWaitResult } from "../../akuma/fleet-observation.js";
9
10
  export type AkumaInvocationResult = Readonly<{
10
11
  kind: "akuma";
11
12
  action: "call";
@@ -42,6 +43,13 @@ export type AkumaInvocationResult = Readonly<{
42
43
  result: unknown;
43
44
  body: string;
44
45
  alias?: string;
46
+ }> | Readonly<{
47
+ kind: "akuma";
48
+ action: "tell";
49
+ mode: "wait";
50
+ result: AkumaTellWaitResult;
51
+ body: string;
52
+ alias?: string;
45
53
  }> | Readonly<{
46
54
  kind: "akuma";
47
55
  action: "tell";
@@ -4,12 +4,13 @@ import { emitInitiatingPluginSignal } from "../../plugin/akuma-signals.js";
4
4
  import { observeAkumaStatus } from "../../akuma/akuma-observe.js";
5
5
  import { AuthorityCorruptionError, Keiyaku, } from "../../index.js";
6
6
  import { callObservationStream, waitObservationStream } from "../render/akuma-activity.js";
7
- import { callObservationHead } from "../render/akuma.js";
8
- import { killAkuma, tellAkuma, waitAkuma } from "../../library/fleet.js";
7
+ import { callObservationHead, waitedTellProgress } from "../render/akuma.js";
8
+ import { killAkuma, tellAkuma, tellWaitAkuma, waitAkuma } from "../../library/fleet.js";
9
9
  import { localExecutionContext } from "../../akuma/requests.js";
10
10
  import { Akuma, Schema } from "../../akuma/index.js";
11
- import { addressAkuma } from "../../library/address.js";
11
+ import { addressAkuma, resolveAkuma } from "../../library/address.js";
12
12
  import { executionChannel } from "../../akuma/requests.js";
13
+ import { AkumaDecodeError } from "../../akuma/akuma-errors.js";
13
14
  import { requestForwardedFleetTellAnswer } from "../../akuma/fleet-request.js";
14
15
  /** The window a call observes for when the caller gives no `--wait` duration. */
15
16
  const CALL_TIMEOUT_MS = 300_000;
@@ -165,17 +166,68 @@ async function inputInitiator(input) {
165
166
  }
166
167
  return { initiator };
167
168
  }
169
+ function decodeWaitedTellSchema(result, schema) {
170
+ if (result.observation.reason !== "answered")
171
+ return result;
172
+ if (typeof result.observation.answer !== "string") {
173
+ throw new AkumaDecodeError("Answer is not valid JSON", String(result.observation.answer));
174
+ }
175
+ let parsed;
176
+ try {
177
+ parsed = JSON.parse(result.observation.answer);
178
+ }
179
+ catch (error) {
180
+ throw new AkumaDecodeError(error instanceof Error ? error.message : "Answer is not valid JSON", result.observation.answer);
181
+ }
182
+ try {
183
+ return { ...result, observation: { reason: "answered", answer: schema.decode(parsed) } };
184
+ }
185
+ catch (error) {
186
+ throw new AkumaDecodeError(error instanceof Error ? error.message : "Answer failed schema decode", result.observation.answer);
187
+ }
188
+ }
189
+ async function invokeWaitedTell(command, input, body) {
190
+ const schema = command.schema === undefined ? undefined : await schemaFromFile(command.schema);
191
+ const result = await tellWaitAkuma({
192
+ ...(await inputInitiator(input)),
193
+ path: input.path,
194
+ akuma: command.akuma,
195
+ body,
196
+ timeoutMs: command.timeoutMs,
197
+ ...(schema === undefined ? {} : { schema }),
198
+ ...(command.interrupt ? { interrupt: true } : {}),
199
+ ...(input.repo === undefined ? {} : { repo: input.repo }),
200
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
201
+ }, input.execution ?? localExecutionContext());
202
+ const rendered = schema === undefined ? result : decodeWaitedTellSchema(result, schema);
203
+ const alias = inputAlias(command.akuma);
204
+ if (command.output === "text")
205
+ writeProgress(waitedTellProgress(rendered, alias, resultContext()));
206
+ return {
207
+ kind: "akuma",
208
+ action: "tell",
209
+ mode: "wait",
210
+ result: rendered,
211
+ body,
212
+ ...(alias === undefined ? {} : { alias }),
213
+ };
214
+ }
168
215
  async function invokeTell(command, input) {
169
216
  const body = await promptBody(command, input);
217
+ if (command.timeoutMs !== undefined)
218
+ return await invokeWaitedTell(command, input, body);
170
219
  if (command.schema !== undefined) {
171
220
  const schema = await schemaFromFile(command.schema);
172
- const addressed = await addressAkuma({
221
+ const channel = executionChannel(input.execution);
222
+ const values = {
173
223
  path: input.path,
174
224
  akuma: command.akuma,
175
225
  ...(input.repo === undefined ? {} : { repo: input.repo }),
176
- });
226
+ };
227
+ // A forwarded answer lets the parent Fleet prove the target, so it resolves
228
+ // coordinates here and never reads this process's own Heart files.
229
+ const addressed = channel.kind === "body-request" ? await resolveAkuma(values) : await addressAkuma(values);
177
230
  const initiator = await inputInitiator(input);
178
- const channel = executionChannel(input.execution);
179
231
  const answer = channel.kind === "body-request"
180
232
  ? await requestForwardedFleetTellAnswer({
181
233
  directory: channel.directory,
@@ -37,6 +37,7 @@ export type ParsedAkumaCommand = Output & ((Readonly<{
37
37
  command: "tell";
38
38
  interrupt: boolean;
39
39
  schema?: string;
40
+ timeoutMs?: number;
40
41
  }> & Addressed & Prompted) | (Readonly<{
41
42
  command: "history";
42
43
  last: boolean;
@@ -1,8 +1,7 @@
1
1
  import { CliUsageError, commandGuide, isBlankInput, usageLine } from "../usage.js";
2
- import { parseAkuId } from "../../akuma/identity.js";
3
2
  import { parseDuration as decodeDuration } from "../../duration.js";
4
3
  import { parseAkumaAlias, parseAkumaGlob } from "../../identity/selector.js";
5
- import { ALLOWED_ACTIONS, decodeAllowedActions } from "../../akuma/allowed.js";
4
+ import { ALLOWED_ACTIONS, DEFAULT_ALLOWED_ACTIONS, decodeAllowedActions, } from "../../akuma/allowed.js";
6
5
  import { parsePublicHistoryId } from "../../akuma/identity.js";
7
6
  const AKUMA_COMMAND_SPECS = {
8
7
  call: {
@@ -27,8 +26,9 @@ const AKUMA_COMMAND_SPECS = {
27
26
  "Without --workdir, a Contract call uses its appointed worktree; an unassociated call uses the invocation cwd.",
28
27
  "--alias assigns the world-local @name selector to the born Akuma.",
29
28
  `Legal actions: ${ALLOWED_ACTIONS.join(", ")}.`,
29
+ `Default actions: ${DEFAULT_ALLOWED_ACTIONS.join(", ")}.`,
30
30
  "Repeated --allowed adds actions to the selected Akuma's defaults; it never narrows them.",
31
- "An omitted Archetype default permits every legal action; an explicit empty default permits none.",
31
+ "An omitted Archetype uses the default actions above; an explicit empty default permits none.",
32
32
  "A nested birth is clipped to its direct parent's frozen actions. status <aku/...|@alias> shows the born effective set.",
33
33
  "--schema reads a JSON Schema file for the answer contract; stdin remains the prompt source.",
34
34
  "With --contract, Dispatch succeeds first. If @name exists, the alias then moves.",
@@ -54,13 +54,14 @@ const AKUMA_COMMAND_SPECS = {
54
54
  tell: {
55
55
  arity: 1,
56
56
  stdin: true,
57
- flags: { interrupt: "boolean", schema: "value", json: "boolean" },
58
- usage: "tell <aku/...|@alias> [--interrupt] [--schema <file>] (<prompt> | -)",
57
+ flags: { interrupt: "boolean", schema: "value", wait: "value", json: "boolean" },
58
+ usage: "tell <aku/...|@alias> [--interrupt] [--schema <file>] [--wait <duration>] (<prompt> | -)",
59
59
  purpose: "Send one prompt to an existing Akuma and wake it.",
60
60
  details: [
61
61
  "Give <prompt> as one argument, or use - to read stdin.",
62
62
  "--interrupt ends the current Body before recording the prompt and waking its successor.",
63
63
  "--schema reads a JSON Schema file for the answer contract; stdin remains the prompt source.",
64
+ "--wait observes this exact Tell for the supplied duration after it is admitted.",
64
65
  ].join("\n"),
65
66
  },
66
67
  history: {
@@ -180,16 +181,9 @@ function positiveIndex(raw, option, fail) {
180
181
  fail(`${option} exceeds the safe integer range`);
181
182
  return value;
182
183
  }
183
- function validateDirect(value, fail) {
184
- try {
185
- if (value.startsWith("@"))
186
- parseAkumaAlias(value);
187
- else
188
- parseAkuId(value);
189
- }
190
- catch (error) {
191
- fail(error instanceof Error ? error.message : "invalid Akuma selector");
192
- }
184
+ function validateDirect(value, _fail) {
185
+ // Address validation belongs to the operation boundary so callers receive
186
+ // the compact Akuma refusal instead of a generic usage page.
193
187
  return value;
194
188
  }
195
189
  function validateSet(value, fail) {
@@ -287,6 +281,7 @@ function parseTell(flags, subject, prompt, output, fail) {
287
281
  akuma: validateDirect(subject, fail),
288
282
  interrupt: flags.interrupt === true,
289
283
  ...(schema === undefined ? {} : { schema }),
284
+ ...(flags.wait === undefined ? {} : { timeoutMs: parseDuration(flags.wait, "--wait", fail) }),
290
285
  prompt,
291
286
  output,
292
287
  };
@@ -25,14 +25,17 @@ export const CONTRACT_COMMAND_SPECS = {
25
25
  " # <title>",
26
26
  " ## Context motivation, authority, baseline, and boundaries",
27
27
  " ## Objective one observable end state",
28
- " ## Design closed decisions and ordering",
29
- " ## Region intended path patterns as fenced lines, list items, or bare lines",
28
+ " ## Design existing owner modules/entry points, reuse or change, implementation approach, and critical ordering",
29
+ " unresolved architectural choices are settled before binding; private helper names",
30
+ " and equivalent control flow remain Deliverer freedom",
31
+ " ## Region narrowest justified intended writes for this approach, one pattern per line",
30
32
  " ## Criteria one or more ### <criterion> entries",
31
33
  " ## Verification optional fenced executor declarations",
32
34
  "",
33
- "Region accepts intended path patterns as fenced lines, list items, or bare",
34
- "lines; the three forms union. Put one repository-relative path pattern on",
35
- "each nonblank line. A trailing '/' is directory shorthand for 'path/**'.",
35
+ "Region accepts the narrowest justified intended writes for this approach, not every potentially",
36
+ "involved file. Do not use broad directory fallbacks or redundant parent/child patterns. Patterns",
37
+ "are fenced lines, list items, or bare lines; the three forms union. Put one repository-relative",
38
+ "path pattern on each nonblank line. A trailing '/' is directory shorthand for 'path/**'.",
36
39
  "A pattern containing whitespace binds with a warning. A fence carries no",
37
40
  "info string or exactly 'txt'.",
38
41
  "",
@@ -25,9 +25,15 @@ export declare function snapshotHeading(id: string, alias: string | undefined, c
25
25
  * source column a plural wait aligns across its selected set.
26
26
  */
27
27
  type RowLayout = Readonly<{
28
- head: (time: string | undefined, glyph: string, verb: string) => string;
28
+ head: (time: string | undefined, glyph: string, verb: string, columns: number) => string;
29
29
  continuation: () => string;
30
30
  marker: (count: number) => string;
31
+ /** A plural wait shares one minute clock across all of its attributed rows. */
32
+ clock?: {
33
+ previous?: string;
34
+ };
35
+ /** Plural wait rows spend their full remaining width on one terminal line. */
36
+ singleLine?: true;
31
37
  }>;
32
38
  /**
33
39
  * Shared snapshot activity rendering. Full snapshots render the selected