@astrosheep/keiyaku 4.5.26 → 4.5.28

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 (98) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +82 -162
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +153 -76
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +68 -64
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +115 -146
  9. package/build/src/akuma/akuma-errors.d.ts +6 -0
  10. package/build/src/akuma/akuma-errors.js +11 -0
  11. package/build/src/akuma/akuma-handle.d.ts +54 -1
  12. package/build/src/akuma/akuma-handle.js +79 -8
  13. package/build/src/akuma/akuma-instance.js +6 -22
  14. package/build/src/akuma/akuma-observe.d.ts +6 -0
  15. package/build/src/akuma/akuma-observe.js +3 -1
  16. package/build/src/akuma/akuma-probe.d.ts +20 -1
  17. package/build/src/akuma/akuma-probe.js +20 -3
  18. package/build/src/akuma/akuma.d.ts +13 -0
  19. package/build/src/akuma/akuma.js +1 -0
  20. package/build/src/akuma/allowed.d.ts +2 -1
  21. package/build/src/akuma/allowed.js +9 -4
  22. package/build/src/akuma/archetype.js +3 -3
  23. package/build/src/akuma/body.js +8 -3
  24. package/build/src/akuma/fleet-execution.d.ts +13 -2
  25. package/build/src/akuma/fleet-execution.js +45 -0
  26. package/build/src/akuma/fleet-observation.d.ts +241 -0
  27. package/build/src/akuma/fleet-observation.js +13 -0
  28. package/build/src/akuma/fleet-owner-port.d.ts +12 -0
  29. package/build/src/akuma/fleet-owner-port.js +46 -0
  30. package/build/src/akuma/fleet-request.d.ts +55 -4
  31. package/build/src/akuma/fleet-request.js +101 -6
  32. package/build/src/akuma/heart/index.d.ts +1 -0
  33. package/build/src/akuma/heart/index.js +4 -1
  34. package/build/src/akuma/heart/rows.d.ts +1 -0
  35. package/build/src/akuma/heart/rows.js +8 -0
  36. package/build/src/akuma/heart/soul.js +2 -2
  37. package/build/src/akuma/identity.js +11 -9
  38. package/build/src/akuma/projection.d.ts +36 -0
  39. package/build/src/akuma/projection.js +2 -1
  40. package/build/src/akuma/provider.d.ts +14 -0
  41. package/build/src/akuma/provider.js +66 -4
  42. package/build/src/akuma/providers/acp/events.js +16 -8
  43. package/build/src/akuma/providers/claude/events.js +5 -7
  44. package/build/src/akuma/providers/opencode-sdk/events.js +9 -5
  45. package/build/src/akuma/providers/pi/events.js +4 -3
  46. package/build/src/akuma/request-lifecycle.js +10 -1
  47. package/build/src/akuma-body.js +1 -33
  48. package/build/src/alias/index.js +3 -3
  49. package/build/src/cli/commands/akuma-invoke.d.ts +8 -0
  50. package/build/src/cli/commands/akuma-invoke.js +67 -6
  51. package/build/src/cli/commands/akuma.d.ts +1 -0
  52. package/build/src/cli/commands/akuma.js +19 -30
  53. package/build/src/cli/commands/contract-help.d.ts +1 -0
  54. package/build/src/cli/commands/contract-help.js +9 -5
  55. package/build/src/cli/invoke.js +1 -1
  56. package/build/src/cli/render/akuma-activity.d.ts +7 -1
  57. package/build/src/cli/render/akuma-activity.js +164 -50
  58. package/build/src/cli/render/akuma-tool.d.ts +5 -0
  59. package/build/src/cli/render/akuma-tool.js +118 -14
  60. package/build/src/cli/render/akuma.d.ts +12 -1
  61. package/build/src/cli/render/akuma.js +74 -2
  62. package/build/src/cli/render/catalog.js +2 -3
  63. package/build/src/cli/render/contract-observation.d.ts +1 -0
  64. package/build/src/cli/render/contract-observation.js +20 -1
  65. package/build/src/cli/render/contract.js +4 -4
  66. package/build/src/cli/render/execution-progress.d.ts +1 -0
  67. package/build/src/cli/render/execution-progress.js +77 -3
  68. package/build/src/cli/render/kanshi.js +5 -19
  69. package/build/src/cli/render/terminal.js +3 -1
  70. package/build/src/cli/runtime.d.ts +6 -0
  71. package/build/src/cli/runtime.js +35 -17
  72. package/build/src/core/facts/offer.d.ts +1 -2
  73. package/build/src/core/verbs/abandon.js +1 -1
  74. package/build/src/core/verbs/amend.js +1 -1
  75. package/build/src/core/verbs/arc.js +1 -1
  76. package/build/src/core/verbs/attestation.js +1 -1
  77. package/build/src/core/verbs/bind.js +1 -1
  78. package/build/src/core/verbs/deliver.js +1 -1
  79. package/build/src/core/verbs/placement.js +1 -1
  80. package/build/src/core/verbs/reintegrate.js +1 -1
  81. package/build/src/git/admission.js +18 -7
  82. package/build/src/identity/coordinates.js +1 -1
  83. package/build/src/identity/normalize.d.ts +3 -0
  84. package/build/src/identity/normalize.js +10 -0
  85. package/build/src/identity/selector.d.ts +1 -0
  86. package/build/src/identity/selector.js +15 -4
  87. package/build/src/library/address.d.ts +33 -3
  88. package/build/src/library/address.js +90 -29
  89. package/build/src/library/akuma-creation.d.ts +1 -1
  90. package/build/src/library/akuma-creation.js +10 -52
  91. package/build/src/library/composition.d.ts +14 -1
  92. package/build/src/library/fleet.d.ts +13 -2
  93. package/build/src/library/fleet.js +142 -48
  94. package/build/src/library/keiyaku.d.ts +14 -1
  95. package/build/src/plugin/public.d.ts +2 -0
  96. package/build/src/protocol/completion.js +9 -2
  97. package/build/src/runtime/proc/windows-launch.exe +0 -0
  98. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { noteEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall } from "../../provider.js";
2
2
  export const OPENCODE_EVENT_DISPOSITIONS = {
3
3
  "server.instance.disposed": "dropped",
4
4
  "installation.updated": "dropped",
@@ -115,6 +115,10 @@ function strongerCall(previous, next) {
115
115
  return previous;
116
116
  if (previous?.kind === "fileChange" && next.kind !== "fileChange")
117
117
  return previous;
118
+ // The correlated start's admitted preview is authority: a later update never
119
+ // overwrites it, empty or conflicting, while a start without one adopts supplied evidence.
120
+ if (next.kind === "other" && previous?.kind === "other" && previous.input !== undefined)
121
+ return { ...next, input: previous.input };
118
122
  return next;
119
123
  }
120
124
  function runCall(name, value) {
@@ -163,12 +167,12 @@ function callFor(name, input, metadata) {
163
167
  if (lower === "grep" || lower === "glob" || lower === "search")
164
168
  return searchCall(lower, value);
165
169
  if (lower === "edit")
166
- return editCall(value, meta) ?? { kind: "other", display: name };
170
+ return editCall(value, meta) ?? otherToolCall(name, input);
167
171
  if (lower === "write")
168
- return writeCall(value, meta) ?? { kind: "other", display: name };
172
+ return writeCall(value, meta) ?? otherToolCall(name, input);
169
173
  if (lower === "apply_patch")
170
- return applyPatchCall(meta) ?? { kind: "other", display: name };
171
- return { kind: "other", display: name };
174
+ return applyPatchCall(meta) ?? otherToolCall(name, input);
175
+ return otherToolCall(name, input);
172
176
  }
173
177
  function belongs(part, state) {
174
178
  return state.sessionId === undefined || part.sessionID === state.sessionId;
@@ -1,4 +1,4 @@
1
- import { noteEvent, unknownEvent } from "../../provider.js";
1
+ import { noteEvent, otherToolCall, unknownEvent } from "../../provider.js";
2
2
  import { diffstatFromUnifiedPatch } from "../unified-patch.js";
3
3
  export const PI_EVENT_DISPOSITIONS = {
4
4
  agent_end: "drop",
@@ -112,7 +112,8 @@ function toolCall(name, args) {
112
112
  return (runCall(name, value) ??
113
113
  readCall(name, value) ??
114
114
  searchCall(name, value) ??
115
- fileChangeCall(name, value) ?? { kind: "other", display: name });
115
+ fileChangeCall(name, value) ??
116
+ otherToolCall(name, args));
116
117
  }
117
118
  function translateNote(event) {
118
119
  if (event.type === "compaction_end")
@@ -129,7 +130,7 @@ function translateToolEnd(event, state) {
129
130
  const started = state.tools.get(event.toolCallId);
130
131
  state.tools.delete(event.toolCallId);
131
132
  const name = started?.name ?? event.toolName;
132
- const call = started?.call ?? { kind: "other", display: name };
133
+ const call = started?.call ?? otherToolCall(name);
133
134
  return [
134
135
  {
135
136
  type: "tool",
@@ -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({
@@ -4,7 +4,7 @@ import { parseAkuId } from "../akuma/identity.js";
4
4
  import { replaceFileDurably } from "../coordination/durable-file.js";
5
5
  import { acquireSqliteTransactionLock } from "../coordination/sqlite-transaction-lock.js";
6
6
  import { AuthorityCorruptionError } from "../core/facts/errors.js";
7
- import { parseAkumaAlias } from "../identity/selector.js";
7
+ import { parseAkumaAlias, parseReadableAkumaAlias } from "../identity/selector.js";
8
8
  const VERSION = 1;
9
9
  function paths(world) {
10
10
  if (typeof world !== "string" || world.trim().length === 0) {
@@ -56,7 +56,7 @@ function decode(path, bytes) {
56
56
  if (typeof rawAkuId !== "string")
57
57
  corruption(`Alias target must be an AkuId: ${path}`);
58
58
  try {
59
- bindings.push({ alias: parseAkumaAlias(rawAlias), akuId: parseAkuId(rawAkuId).id });
59
+ bindings.push({ alias: parseReadableAkumaAlias(rawAlias), akuId: parseAkuId(rawAkuId).id });
60
60
  }
61
61
  catch (error) {
62
62
  return corruption(`Alias binding is invalid: ${path}`, error);
@@ -114,7 +114,7 @@ export async function readAliases(world) {
114
114
  return await read(paths(world).authority);
115
115
  }
116
116
  export async function resolveAlias(world, value) {
117
- const alias = parseAkumaAlias(value);
117
+ const alias = parseReadableAkumaAlias(value);
118
118
  return (await readAliases(world)).find((binding) => binding.alias === alias)?.akuId ?? null;
119
119
  }
120
120
  export async function moveAlias(input) {
@@ -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, tellWaitProgressStream } 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,77 @@ 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 alias = inputAlias(command.akuma);
192
+ const progress = command.output === "text" ? tellWaitProgressStream(undefined, alias, resultContext()) : undefined;
193
+ const result = await tellWaitAkuma({
194
+ ...(await inputInitiator(input)),
195
+ path: input.path,
196
+ akuma: command.akuma,
197
+ body,
198
+ timeoutMs: command.timeoutMs,
199
+ ...(schema === undefined ? {} : { schema }),
200
+ ...(command.interrupt ? { interrupt: true } : {}),
201
+ ...(input.repo === undefined ? {} : { repo: input.repo }),
202
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
203
+ ...(progress === undefined
204
+ ? {}
205
+ : {
206
+ observe: {
207
+ admitted: (tell, id) => writeProgress(progress.admitted(tell, id).join("\n")),
208
+ observe: (observation) => writeProgress(progress.observe(observation).join("\n")),
209
+ },
210
+ }),
211
+ }, input.execution ?? localExecutionContext());
212
+ const rendered = schema === undefined ? result : decodeWaitedTellSchema(result, schema);
213
+ if (progress !== undefined)
214
+ writeProgress(progress.conclude(rendered).join("\n"));
215
+ return {
216
+ kind: "akuma",
217
+ action: "tell",
218
+ mode: "wait",
219
+ result: rendered,
220
+ body,
221
+ ...(alias === undefined ? {} : { alias }),
222
+ };
223
+ }
168
224
  async function invokeTell(command, input) {
169
225
  const body = await promptBody(command, input);
226
+ if (command.timeoutMs !== undefined)
227
+ return await invokeWaitedTell(command, input, body);
170
228
  if (command.schema !== undefined) {
171
229
  const schema = await schemaFromFile(command.schema);
172
- const addressed = await addressAkuma({
230
+ const channel = executionChannel(input.execution);
231
+ const values = {
173
232
  path: input.path,
174
233
  akuma: command.akuma,
175
234
  ...(input.repo === undefined ? {} : { repo: input.repo }),
176
- });
235
+ };
236
+ // A forwarded answer lets the parent Fleet prove the target, so it resolves
237
+ // coordinates here and never reads this process's own Heart files.
238
+ const addressed = channel.kind === "body-request" ? await resolveAkuma(values) : await addressAkuma(values);
177
239
  const initiator = await inputInitiator(input);
178
- const channel = executionChannel(input.execution);
179
240
  const answer = channel.kind === "body-request"
180
241
  ? await requestForwardedFleetTellAnswer({
181
242
  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: {
@@ -12,23 +11,23 @@ const AKUMA_COMMAND_SPECS = {
12
11
  contract: "value",
13
12
  alias: "value",
14
13
  wait: "value",
15
- detach: "boolean",
16
14
  allowed: "repeatable",
17
15
  json: "boolean",
18
16
  schema: "value",
19
17
  },
20
- usage: "call <akuma-name> [--contract <kei/...>] [--workdir <path>] [--alias @name] [--allowed <product.action>]... [--schema <file>] [--wait <duration> | -d | --detach] (<prompt> | -)",
18
+ usage: "call <akuma-name> [--contract <kei/...>] [--workdir <path>] [--alias <name>] [--allowed <product.action>]... [--schema <file>] [--wait <duration>] (<prompt> | -)",
21
19
  purpose: "Birth an Akuma from <akuma-name> with one prompt.",
22
20
  details: [
23
21
  "Give <prompt> as one argument, or use - to read stdin.",
24
- "Default: --wait 5m. An explicit --wait replaces that duration; -d and --detach return after birth.",
25
- "--contract dispatches the born Akuma to that Contract.",
22
+ "Default: return after birth without waiting for the first answer. Explicit --wait observes the first work for that duration.",
23
+ "--contract associates the born Akuma with that Contract for Dispatch; it never selects a workdir.",
26
24
  "--workdir selects the execution directory; a relative path is relative to the invocation cwd.",
27
- "Without --workdir, a Contract call uses its appointed worktree; an unassociated call uses the invocation cwd.",
28
- "--alias assigns the world-local @name selector to the born Akuma.",
25
+ "Without --workdir, the call uses the invocation cwd whether or not --contract is present.",
26
+ "--alias <name> assigns the world-local @name selector to the born Akuma; @name is also accepted.",
29
27
  `Legal actions: ${ALLOWED_ACTIONS.join(", ")}.`,
28
+ `Default actions: ${DEFAULT_ALLOWED_ACTIONS.join(", ")}.`,
30
29
  "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.",
30
+ "An omitted Archetype uses the default actions above; an explicit empty default permits none.",
32
31
  "A nested birth is clipped to its direct parent's frozen actions. status <aku/...|@alias> shows the born effective set.",
33
32
  "--schema reads a JSON Schema file for the answer contract; stdin remains the prompt source.",
34
33
  "With --contract, Dispatch succeeds first. If @name exists, the alias then moves.",
@@ -54,13 +53,14 @@ const AKUMA_COMMAND_SPECS = {
54
53
  tell: {
55
54
  arity: 1,
56
55
  stdin: true,
57
- flags: { interrupt: "boolean", schema: "value", json: "boolean" },
58
- usage: "tell <aku/...|@alias> [--interrupt] [--schema <file>] (<prompt> | -)",
56
+ flags: { interrupt: "boolean", schema: "value", wait: "value", json: "boolean" },
57
+ usage: "tell <aku/...|@alias> [--interrupt] [--schema <file>] [--wait <duration>] (<prompt> | -)",
59
58
  purpose: "Send one prompt to an existing Akuma and wake it.",
60
59
  details: [
61
60
  "Give <prompt> as one argument, or use - to read stdin.",
62
61
  "--interrupt ends the current Body before recording the prompt and waking its successor.",
63
62
  "--schema reads a JSON Schema file for the answer contract; stdin remains the prompt source.",
63
+ "--wait observes this exact Tell for the supplied duration after it is admitted.",
64
64
  ].join("\n"),
65
65
  },
66
66
  history: {
@@ -155,11 +155,7 @@ function scanAkuma(action, argv, fail) {
155
155
  stdin = true;
156
156
  }
157
157
  else if (token === "-d") {
158
- if (action !== "call")
159
- fail(`option ${token} is not valid for ${action}`);
160
- if (flags.detach !== undefined)
161
- fail("duplicate option: --detach");
162
- flags.detach = true;
158
+ fail(`option ${token} is not valid for ${action}`);
163
159
  }
164
160
  else if (!token.startsWith("--")) {
165
161
  if (isBlankInput(token))
@@ -180,16 +176,9 @@ function positiveIndex(raw, option, fail) {
180
176
  fail(`${option} exceeds the safe integer range`);
181
177
  return value;
182
178
  }
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
- }
179
+ function validateDirect(value, _fail) {
180
+ // Address validation belongs to the operation boundary so callers receive
181
+ // the compact Akuma refusal instead of a generic usage page.
193
182
  return value;
194
183
  }
195
184
  function validateSet(value, fail) {
@@ -287,6 +276,7 @@ function parseTell(flags, subject, prompt, output, fail) {
287
276
  akuma: validateDirect(subject, fail),
288
277
  interrupt: flags.interrupt === true,
289
278
  ...(schema === undefined ? {} : { schema }),
279
+ ...(flags.wait === undefined ? {} : { timeoutMs: parseDuration(flags.wait, "--wait", fail) }),
290
280
  prompt,
291
281
  output,
292
282
  };
@@ -308,15 +298,14 @@ function parseCall(flags, archetype, prompt, output, fail) {
308
298
  let alias;
309
299
  if (flags.alias !== undefined) {
310
300
  try {
311
- alias = parseAkumaAlias(stringFlag(flags.alias, "--alias requires @name", fail));
301
+ const name = stringFlag(flags.alias, "--alias requires a name", fail);
302
+ alias = parseAkumaAlias(name.startsWith("@") ? name : `@${name}`);
312
303
  }
313
304
  catch (error) {
314
305
  fail(error instanceof Error ? error.message : "invalid Akuma alias");
315
306
  }
316
307
  }
317
- if (flags.detach === true && flags.wait !== undefined)
318
- fail("call --wait and --detach are mutually exclusive");
319
- const mode = flags.detach === true ? "detach" : "wait";
308
+ const mode = flags.wait === undefined ? "detach" : "wait";
320
309
  const timeoutMs = flags.wait === undefined ? undefined : parseDuration(flags.wait, "--wait", fail);
321
310
  const allowed = parseAllowedFlag(flags.allowed, fail);
322
311
  const schema = flags.schema === undefined ? undefined : stringFlag(flags.schema, "call --schema requires a file", fail);
@@ -94,6 +94,7 @@ export declare const CONTRACT_COMMAND_SPECS: {
94
94
  };
95
95
  readonly usage: "status [<contract>|@name|<aku/...>]...";
96
96
  readonly purpose: "Read the world status board or one or more Contract and Akuma projections.";
97
+ readonly details: "An Akuma projection reports that Akuma's frozen execution workdir; --contract associates a Contract without selecting one.";
97
98
  };
98
99
  readonly show: {
99
100
  readonly positional: "optional";
@@ -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
  "",
@@ -163,6 +166,7 @@ export const CONTRACT_COMMAND_SPECS = {
163
166
  flags: { json: "boolean" },
164
167
  usage: "status [<contract>|@name|<aku/...>]...",
165
168
  purpose: "Read the world status board or one or more Contract and Akuma projections.",
169
+ details: "An Akuma projection reports that Akuma's frozen execution workdir; --contract associates a Contract without selecting one.",
166
170
  },
167
171
  show: {
168
172
  positional: "optional",
@@ -348,7 +348,7 @@ async function callExecutionCwd(input) {
348
348
  if (input.workdir !== undefined) {
349
349
  return await canonicalBirthCwd(resolve(input.cwd, input.workdir), `workdir is not an existing directory: ${input.workdir}`);
350
350
  }
351
- return input.command.contract === undefined ? input.cwd : undefined;
351
+ return input.cwd;
352
352
  }
353
353
  async function invokeParsedAkuma(input) {
354
354
  const executionCwd = await callExecutionCwd({
@@ -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