@astrosheep/keiyaku 4.6.7 → 4.6.8

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 (165) hide show
  1. package/README.md +6 -2
  2. package/build/plugins/pi/keiyaku.ts +0 -5
  3. package/build/src/akuma/akuma-call.d.ts +2 -0
  4. package/build/src/akuma/akuma-call.js +8 -2
  5. package/build/src/akuma/akuma-instance.d.ts +12 -1
  6. package/build/src/akuma/akuma-instance.js +27 -7
  7. package/build/src/akuma/akuma-observe.js +2 -0
  8. package/build/src/akuma/akuma-owner.d.ts +3 -0
  9. package/build/src/akuma/akuma-owner.js +4 -0
  10. package/build/src/akuma/akuma.d.ts +35 -5
  11. package/build/src/akuma/akuma.js +8 -10
  12. package/build/src/akuma/archetype.d.ts +7 -15
  13. package/build/src/akuma/archetype.js +36 -35
  14. package/build/src/akuma/body.d.ts +5 -3
  15. package/build/src/akuma/body.js +29 -7
  16. package/build/src/akuma/call-request.d.ts +18 -10
  17. package/build/src/akuma/call-request.js +10 -3
  18. package/build/src/akuma/caller.d.ts +39 -0
  19. package/build/src/akuma/caller.js +36 -0
  20. package/build/src/akuma/dispatch-association.d.ts +0 -1
  21. package/build/src/akuma/dispatch-association.js +0 -3
  22. package/build/src/akuma/heart/facts.d.ts +16 -12
  23. package/build/src/akuma/heart/facts.js +8 -0
  24. package/build/src/akuma/heart/index.d.ts +2 -7
  25. package/build/src/akuma/heart/index.js +3 -17
  26. package/build/src/akuma/heart/rows.d.ts +3 -3
  27. package/build/src/akuma/heart/soul.d.ts +1 -1
  28. package/build/src/akuma/heart/soul.js +5 -24
  29. package/build/src/akuma/heart/storage.d.ts +5 -0
  30. package/build/src/akuma/heart/storage.js +7 -3
  31. package/build/src/akuma/identity.d.ts +0 -1
  32. package/build/src/akuma/identity.js +2 -5
  33. package/build/src/akuma/index.d.ts +5 -2
  34. package/build/src/akuma/index.js +1 -0
  35. package/build/src/akuma/nuke.js +6 -28
  36. package/build/src/akuma/projection.d.ts +0 -11
  37. package/build/src/akuma/provider-recipe.d.ts +7 -6
  38. package/build/src/akuma/provider-recipe.js +1 -1
  39. package/build/src/akuma/provider.d.ts +6 -10
  40. package/build/src/akuma/provider.js +6 -7
  41. package/build/src/akuma/providers/acp/events.js +5 -18
  42. package/build/src/akuma/providers/acp/index.js +2 -3
  43. package/build/src/akuma/providers/claude/events.js +35 -60
  44. package/build/src/akuma/providers/claude/index.d.ts +2 -2
  45. package/build/src/akuma/providers/claude/index.js +2 -3
  46. package/build/src/akuma/providers/codex-app-server/index.js +2 -2
  47. package/build/src/akuma/providers/decode.d.ts +25 -0
  48. package/build/src/akuma/providers/decode.js +44 -0
  49. package/build/src/akuma/providers/execution-environment.d.ts +2 -1
  50. package/build/src/akuma/providers/execution-environment.js +3 -0
  51. package/build/src/akuma/providers/grok-build/index.js +6 -22
  52. package/build/src/akuma/providers/index.js +2 -0
  53. package/build/src/akuma/providers/lifecycle.d.ts +9 -0
  54. package/build/src/akuma/providers/lifecycle.js +10 -0
  55. package/build/src/akuma/providers/opencode-sdk/events.js +1 -14
  56. package/build/src/akuma/providers/opencode-sdk/index.js +10 -17
  57. package/build/src/akuma/providers/opencode-sdk/session.js +1 -3
  58. package/build/src/akuma/providers/paseo/events.d.ts +25 -0
  59. package/build/src/akuma/providers/paseo/events.js +157 -0
  60. package/build/src/akuma/providers/paseo/index.d.ts +9 -0
  61. package/build/src/akuma/providers/paseo/index.js +353 -0
  62. package/build/src/akuma/providers/pi/events.js +5 -15
  63. package/build/src/akuma/publication.d.ts +2 -0
  64. package/build/src/akuma/publication.js +5 -0
  65. package/build/src/akuma/request-lifecycle.d.ts +3 -0
  66. package/build/src/akuma/request-lifecycle.js +25 -4
  67. package/build/src/akuma/requests.d.ts +3 -1
  68. package/build/src/akuma/requests.js +32 -0
  69. package/build/src/akuma/selection-observation.d.ts +72 -2
  70. package/build/src/akuma/selection-observation.js +0 -6
  71. package/build/src/akuma/turn-drive.js +2 -5
  72. package/build/src/cli/akuma-caller.d.ts +3 -0
  73. package/build/src/cli/akuma-caller.js +21 -0
  74. package/build/src/cli/commands/akuma-grammar.js +7 -12
  75. package/build/src/cli/commands/akuma.js +12 -4
  76. package/build/src/cli/commands/contract-grammar.d.ts +2 -1
  77. package/build/src/cli/commands/contract-grammar.js +13 -15
  78. package/build/src/cli/commands/contract-help.d.ts +2 -1
  79. package/build/src/cli/commands/contract-help.js +31 -1
  80. package/build/src/cli/commands/contract.js +24 -53
  81. package/build/src/cli/commands/task.js +18 -35
  82. package/build/src/cli/parse.d.ts +2 -2
  83. package/build/src/cli/render/catalog.d.ts +2 -5
  84. package/build/src/cli/render/contract-history.js +3 -6
  85. package/build/src/cli/render/contract.js +15 -50
  86. package/build/src/cli/render/receipt.js +3 -10
  87. package/build/src/cli/render/task.d.ts +4 -6
  88. package/build/src/cli/render/task.js +9 -26
  89. package/build/src/cli/runtime.d.ts +1 -1
  90. package/build/src/cli/runtime.js +11 -17
  91. package/build/src/cli/selectors.d.ts +3 -6
  92. package/build/src/cli/selectors.js +22 -53
  93. package/build/src/dispatch/index.d.ts +3 -3
  94. package/build/src/dispatch/index.js +1 -2
  95. package/build/src/git/observe.d.ts +6 -2
  96. package/build/src/git/observe.js +6 -2
  97. package/build/src/index.d.ts +6 -6
  98. package/build/src/index.js +2 -2
  99. package/build/src/kanshi/index.d.ts +1 -1
  100. package/build/src/kanshi/read.js +21 -6
  101. package/build/src/library/address.js +2 -4
  102. package/build/src/library/akuma-creation.d.ts +5 -1
  103. package/build/src/library/akuma-creation.js +27 -47
  104. package/build/src/library/akumas.d.ts +5 -4
  105. package/build/src/library/akumas.js +13 -9
  106. package/build/src/library/bind.d.ts +14 -14
  107. package/build/src/library/bind.js +11 -7
  108. package/build/src/library/contract-address.d.ts +9 -0
  109. package/build/src/library/contract-address.js +71 -0
  110. package/build/src/library/contract-composition.d.ts +4 -7
  111. package/build/src/library/contract-composition.js +6 -18
  112. package/build/src/library/contract-creation.d.ts +3 -5
  113. package/build/src/library/contract-creation.js +19 -17
  114. package/build/src/library/contract-execution.js +18 -23
  115. package/build/src/library/contract-outcomes.d.ts +2 -14
  116. package/build/src/library/contract-outcomes.js +2 -13
  117. package/build/src/library/contract-types.d.ts +36 -2
  118. package/build/src/library/delivery.d.ts +0 -2
  119. package/build/src/library/delivery.js +2 -5
  120. package/build/src/library/keiyaku.d.ts +0 -5
  121. package/build/src/library/keiyaku.js +6 -12
  122. package/build/src/library/outcome.d.ts +500 -499
  123. package/build/src/library/outcome.js +10 -0
  124. package/build/src/library/reconcile.js +8 -16
  125. package/build/src/library/refusal.d.ts +2 -2
  126. package/build/src/library/repo.d.ts +3 -2
  127. package/build/src/library/repo.js +10 -5
  128. package/build/src/library/selection.d.ts +4 -4
  129. package/build/src/library/selection.js +12 -12
  130. package/build/src/plugin/akuma-signals.d.ts +2 -0
  131. package/build/src/plugin/akuma-signals.js +4 -0
  132. package/build/src/plugin/public.d.ts +27 -2
  133. package/build/src/plugin/runtime.js +2 -2
  134. package/build/src/protocol/amend.js +3 -2
  135. package/build/src/protocol/attempt.js +3 -8
  136. package/build/src/protocol/bind.d.ts +2 -2
  137. package/build/src/protocol/bind.js +1 -1
  138. package/build/src/protocol/deliver.js +3 -3
  139. package/build/src/protocol/operations.d.ts +1 -3
  140. package/build/src/protocol/operations.js +0 -8
  141. package/build/src/protocol/outcome.d.ts +1 -2
  142. package/build/src/protocol/outcome.js +1 -13
  143. package/build/src/protocol/placement.js +3 -10
  144. package/build/src/protocol/read/status.js +31 -70
  145. package/build/src/protocol/reintegrate.js +3 -10
  146. package/build/src/protocol/review.js +3 -3
  147. package/build/src/protocol/run.d.ts +5 -1
  148. package/build/src/protocol/run.js +3 -3
  149. package/build/src/runtime/proc/windows-launch.exe +0 -0
  150. package/package.json +8 -4
  151. package/plugins/pi/keiyaku.ts +57 -0
  152. package/skills/keiyaku/SKILL.md +44 -0
  153. package/skills/keiyaku-akuma/SKILL.md +130 -0
  154. package/skills/keiyaku-akuma/references/automation.md +269 -0
  155. package/skills/keiyaku-babysit/SKILL.md +65 -0
  156. package/skills/keiyaku-bind/SKILL.md +216 -0
  157. package/skills/keiyaku-bind/agents/openai.yaml +4 -0
  158. package/skills/keiyaku-task/SKILL.md +104 -0
  159. package/skills/keiyaku-workflow/SKILL.md +129 -0
  160. package/build/src/cli/commands/amend.d.ts +0 -12
  161. package/build/src/cli/commands/amend.js +0 -10
  162. package/build/src/cli/commands/bind.d.ts +0 -11
  163. package/build/src/cli/commands/bind.js +0 -23
  164. package/build/src/dispatch/association.d.ts +0 -1
  165. package/build/src/dispatch/association.js +0 -1
@@ -3,6 +3,30 @@ import { type AkumaStatus } from "./akuma.js";
3
3
  declare const akumaObservationSchema: z.ZodObject<{
4
4
  status: z.ZodObject<{
5
5
  id: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
6
+ birth: z.ZodObject<{
7
+ origin: z.ZodDiscriminatedUnion<[z.ZodObject<{
8
+ kind: z.ZodLiteral<"direct">;
9
+ }, z.core.$strip>, z.ZodObject<{
10
+ kind: z.ZodLiteral<"request">;
11
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
12
+ requestId: z.ZodString;
13
+ }, z.core.$strip>, z.ZodObject<{
14
+ kind: z.ZodLiteral<"fork">;
15
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
16
+ at: z.ZodString;
17
+ }, z.core.$strip>], "kind">;
18
+ caller: z.ZodUnion<readonly [z.ZodDiscriminatedUnion<[z.ZodObject<{
19
+ kind: z.ZodLiteral<"akuma">;
20
+ world: z.ZodCustom<import("../world.js").WorldRoot, import("../world.js").WorldRoot>;
21
+ akuId: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
22
+ }, z.core.$strict>, z.ZodObject<{
23
+ kind: z.ZodLiteral<"external">;
24
+ integration: z.ZodString;
25
+ id: z.ZodString;
26
+ }, z.core.$strict>], "kind">, z.ZodObject<{
27
+ kind: z.ZodLiteral<"unknown">;
28
+ }, z.core.$strict>]>;
29
+ }, z.core.$strict>;
6
30
  life: z.ZodEnum<{
7
31
  killed: "killed";
8
32
  hung: "hung";
@@ -467,6 +491,30 @@ declare const akumaWaitResultSchema: z.ZodObject<{
467
491
  observations: z.ZodReadonly<z.ZodArray<z.ZodObject<{
468
492
  status: z.ZodObject<{
469
493
  id: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
494
+ birth: z.ZodObject<{
495
+ origin: z.ZodDiscriminatedUnion<[z.ZodObject<{
496
+ kind: z.ZodLiteral<"direct">;
497
+ }, z.core.$strip>, z.ZodObject<{
498
+ kind: z.ZodLiteral<"request">;
499
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
500
+ requestId: z.ZodString;
501
+ }, z.core.$strip>, z.ZodObject<{
502
+ kind: z.ZodLiteral<"fork">;
503
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
504
+ at: z.ZodString;
505
+ }, z.core.$strip>], "kind">;
506
+ caller: z.ZodUnion<readonly [z.ZodDiscriminatedUnion<[z.ZodObject<{
507
+ kind: z.ZodLiteral<"akuma">;
508
+ world: z.ZodCustom<import("../world.js").WorldRoot, import("../world.js").WorldRoot>;
509
+ akuId: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
510
+ }, z.core.$strict>, z.ZodObject<{
511
+ kind: z.ZodLiteral<"external">;
512
+ integration: z.ZodString;
513
+ id: z.ZodString;
514
+ }, z.core.$strict>], "kind">, z.ZodObject<{
515
+ kind: z.ZodLiteral<"unknown">;
516
+ }, z.core.$strict>]>;
517
+ }, z.core.$strict>;
470
518
  life: z.ZodEnum<{
471
519
  killed: "killed";
472
520
  hung: "hung";
@@ -1164,8 +1212,6 @@ export type AkumaAskResult<T = unknown> = Omit<z.infer<typeof akumaAskResultSche
1164
1212
  }>;
1165
1213
  /** Compose one native status into the canonical observation its crossing transports. */
1166
1214
  export declare function akumaObservationOf(status: AkumaStatus): AkumaObservation;
1167
- export declare function isTellResult(value: unknown): value is AkumaTellResult;
1168
- export declare function isAskResult(value: unknown): value is AkumaAskResult;
1169
1215
  export declare const selectionResultSchemas: {
1170
1216
  wait: z.ZodObject<{
1171
1217
  mode: z.ZodEnum<{
@@ -1179,6 +1225,30 @@ export declare const selectionResultSchemas: {
1179
1225
  observations: z.ZodReadonly<z.ZodArray<z.ZodObject<{
1180
1226
  status: z.ZodObject<{
1181
1227
  id: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
1228
+ birth: z.ZodObject<{
1229
+ origin: z.ZodDiscriminatedUnion<[z.ZodObject<{
1230
+ kind: z.ZodLiteral<"direct">;
1231
+ }, z.core.$strip>, z.ZodObject<{
1232
+ kind: z.ZodLiteral<"request">;
1233
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
1234
+ requestId: z.ZodString;
1235
+ }, z.core.$strip>, z.ZodObject<{
1236
+ kind: z.ZodLiteral<"fork">;
1237
+ parent: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
1238
+ at: z.ZodString;
1239
+ }, z.core.$strip>], "kind">;
1240
+ caller: z.ZodUnion<readonly [z.ZodDiscriminatedUnion<[z.ZodObject<{
1241
+ kind: z.ZodLiteral<"akuma">;
1242
+ world: z.ZodCustom<import("../world.js").WorldRoot, import("../world.js").WorldRoot>;
1243
+ akuId: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
1244
+ }, z.core.$strict>, z.ZodObject<{
1245
+ kind: z.ZodLiteral<"external">;
1246
+ integration: z.ZodString;
1247
+ id: z.ZodString;
1248
+ }, z.core.$strict>], "kind">, z.ZodObject<{
1249
+ kind: z.ZodLiteral<"unknown">;
1250
+ }, z.core.$strict>]>;
1251
+ }, z.core.$strict>;
1182
1252
  life: z.ZodEnum<{
1183
1253
  killed: "killed";
1184
1254
  hung: "hung";
@@ -50,12 +50,6 @@ const akumaAskResultSchema = z
50
50
  export function akumaObservationOf(status) {
51
51
  return { status, contract: NO_DISPATCH_ASSOCIATION, createdTasks: EMPTY_CREATED_TASK_OBSERVATION };
52
52
  }
53
- export function isTellResult(value) {
54
- return akumaTellResultSchema.safeParse(value).success;
55
- }
56
- export function isAskResult(value) {
57
- return akumaAskResultSchema.safeParse(value).success;
58
- }
59
53
  export const selectionResultSchemas = {
60
54
  wait: akumaWaitResultSchema,
61
55
  tell: akumaTellResultSchema,
@@ -115,7 +115,7 @@ async function startTurnDrive(input) {
115
115
  cwd,
116
116
  options,
117
117
  signal: driveController.signal,
118
- requests: { dir: requests.directory },
118
+ requests: { dir: requests.directory, entry: requests.entry },
119
119
  ...(schemaJson === undefined ? {} : { schemaJson }),
120
120
  };
121
121
  const attempt = session === undefined
@@ -232,9 +232,6 @@ function pumpReceipts(writers) {
232
232
  function observeFailure(settlement) {
233
233
  return settlement.then(() => new Promise(() => { }), (error) => Promise.reject(error));
234
234
  }
235
- function observeReceiptFailure(receiptPump) {
236
- return observeFailure(receiptPump);
237
- }
238
235
  function observeCompletionFailure(drive) {
239
236
  return drive.completion.then(() => new Promise(() => { }), (error) => ({ kind: "completion-failed", error }));
240
237
  }
@@ -354,7 +351,7 @@ async function consumeTurnDrive(input, active) {
354
351
  let writesOpen = true;
355
352
  const mayWrite = () => writesOpen && !input.supervisor.signal.aborted;
356
353
  const writers = { input, turnSequence, drive, writeWitness, mayWrite };
357
- const receiptFailure = observeReceiptFailure(pumpReceipts(writers));
354
+ const receiptFailure = observeFailure(pumpReceipts(writers));
358
355
  const completionFailure = observeCompletionFailure(drive);
359
356
  const iterator = drive.events[Symbol.asyncIterator]();
360
357
  let liveTells = true;
@@ -0,0 +1,3 @@
1
+ import { type AkumaCaller } from "../akuma/caller.js";
2
+ /** Environment attribution belongs to the process edge, never SDK admission. */
3
+ export declare function akumaCallerFromEnvironment(environment: NodeJS.ProcessEnv): Promise<AkumaCaller | undefined>;
@@ -0,0 +1,21 @@
1
+ import { decodeAkumaCaller } from "../akuma/caller.js";
2
+ import { World } from "../world.js";
3
+ /** Environment attribution belongs to the process edge, never SDK admission. */
4
+ export async function akumaCallerFromEnvironment(environment) {
5
+ const id = environment.KEIYAKU_ACTOR_ID;
6
+ const world = environment.KEIYAKU_ACTOR_WORLD;
7
+ if ((id === undefined) !== (world === undefined)) {
8
+ throw new TypeError("Akuma caller requires both KEIYAKU_ACTOR_ID and KEIYAKU_ACTOR_WORLD");
9
+ }
10
+ if (id !== undefined && world !== undefined) {
11
+ const resolved = await World.resolve({ cwd: world, repositoryRoot: world });
12
+ return decodeAkumaCaller({ kind: "akuma", akuId: id, world: resolved.candidate });
13
+ }
14
+ const external = environment.KEIYAKU_EXTERNAL_CALLER;
15
+ if (external === undefined)
16
+ return undefined;
17
+ const colon = external.indexOf(":");
18
+ if (colon < 0)
19
+ throw new TypeError("KEIYAKU_EXTERNAL_CALLER must be <integration>:<id>");
20
+ return decodeAkumaCaller({ kind: "external", integration: external.slice(0, colon), id: external.slice(colon + 1) });
21
+ }
@@ -175,11 +175,6 @@ function positiveIndex(raw, option, fail) {
175
175
  fail(`${option} exceeds the safe integer range`);
176
176
  return value;
177
177
  }
178
- function validateDirect(value, _fail) {
179
- // Address validation belongs to the operation boundary so callers receive
180
- // the compact Akuma refusal instead of a generic usage page.
181
- return value;
182
- }
183
178
  function validateSet(value, fail) {
184
179
  if (value.startsWith("kei/"))
185
180
  return value;
@@ -192,7 +187,7 @@ function validateSet(value, fail) {
192
187
  }
193
188
  return value;
194
189
  }
195
- return validateDirect(value, fail);
190
+ return value;
196
191
  }
197
192
  function parseWait(rawSelectors, flags, output, fail) {
198
193
  if (flags.any === true && flags.all === true)
@@ -236,7 +231,7 @@ function parseAkumaHistory(selector, flags, output, fail) {
236
231
  fail("history --id requires turn/<positive safe integer>");
237
232
  return {
238
233
  command: "history",
239
- akuma: validateDirect(selector, fail),
234
+ akuma: selector,
240
235
  ...(id === undefined ? {} : { id }),
241
236
  last: flags.last === true,
242
237
  ...(flags.before === undefined ? {} : { before: positiveIndex(flags.before, "--before", fail) }),
@@ -256,7 +251,7 @@ function parseAddressed(action, rawSelectors, flags, output, fail) {
256
251
  fail("history accepts one complete aku/..., @alias, or kei/... selector");
257
252
  return parseHistory(selector, flags, output, fail);
258
253
  }
259
- const akuma = validateDirect(rawSelectors[0], fail);
254
+ const akuma = rawSelectors[0];
260
255
  const at = stringFlag(flags.at, "fork requires --at <historyId>", fail);
261
256
  return { command: action, akuma, at, output };
262
257
  }
@@ -279,10 +274,10 @@ function parsePrompted(action, positionals, stdin, fail) {
279
274
  : { prompt: { kind: "argument", value: argument } }),
280
275
  };
281
276
  }
282
- function parseTell(flags, subject, prompt, output, fail) {
277
+ function parseTell(flags, subject, prompt, output) {
283
278
  return {
284
279
  command: "tell",
285
- akuma: validateDirect(subject, fail),
280
+ akuma: subject,
286
281
  interrupt: flags.interrupt === true,
287
282
  prompt,
288
283
  output,
@@ -292,7 +287,7 @@ function parseAsk(flags, subject, prompt, output, fail) {
292
287
  const schema = flags.schema === undefined ? undefined : stringFlag(flags.schema, "ask --schema requires a file", fail);
293
288
  return {
294
289
  command: "ask",
295
- akuma: validateDirect(subject, fail),
290
+ akuma: subject,
296
291
  interrupt: flags.interrupt === true,
297
292
  ...(schema === undefined ? {} : { schema }),
298
293
  ...(flags.wait === undefined ? {} : { timeoutMs: parseDuration(flags.wait, "--wait", fail) }),
@@ -361,7 +356,7 @@ export function parseAkumaCommand(argv) {
361
356
  return action === "call"
362
357
  ? parseCall(flags, parsed.subject, parsed.prompt, output, fail)
363
358
  : action === "tell"
364
- ? parseTell(flags, parsed.subject, parsed.prompt, output, fail)
359
+ ? parseTell(flags, parsed.subject, parsed.prompt, output)
365
360
  : parseAsk(flags, parsed.subject, parsed.prompt, output, fail);
366
361
  }
367
362
  if (spec.arity === "one-or-more" ? positionals.length === 0 : positionals.length !== spec.arity) {
@@ -1,3 +1,4 @@
1
+ import { akumaCallerFromEnvironment } from "../akuma-caller.js";
1
2
  import { CliUsageError, isBlankInput } from "../usage.js";
2
3
  import { readFile } from "node:fs/promises";
3
4
  import { resolve } from "node:path";
@@ -27,7 +28,7 @@ async function settingsAt(root, home) {
27
28
  });
28
29
  }
29
30
  function akumas(input) {
30
- return akumasWithExecution(input.path, input.execution);
31
+ return akumasWithExecution(input.path, input.execution, { reportDiagnostic: writeStderr });
31
32
  }
32
33
  async function schemaFromFile(path) {
33
34
  try {
@@ -68,9 +69,7 @@ async function inputInitiator(input) {
68
69
  catch { }
69
70
  if (initiator === undefined)
70
71
  return {};
71
- // Plugins coordinate within an established World; a `call` may run where the
72
- // marker does not exist yet, and activating there would only fail noisily.
73
- // The initiator still travels with the request either way.
72
+ // Identity preparation needs established plugin custody, not just a candidate.
74
73
  if (!(await World.established(input.path)))
75
74
  return { initiator };
76
75
  await emitPluginSignal({
@@ -90,9 +89,15 @@ function emitAnswer(body, exact) {
90
89
  async function runCall(command, input) {
91
90
  const body = command.prompt === undefined ? undefined : await promptBody("call", { prompt: command.prompt }, input);
92
91
  const schema = command.schema === undefined ? undefined : await schemaFromFile(command.schema);
92
+ const declaredCaller = executionChannel(input.execution).kind === "body-request"
93
+ ? undefined
94
+ : await akumaCallerFromEnvironment(input.environment);
95
+ // Establish the selected World before preparing the submitting Square route.
96
+ await World.at(input.path);
93
97
  const caller = akumas(input);
94
98
  const request = {
95
99
  ...(await inputInitiator(input)),
100
+ ...(declaredCaller === undefined ? {} : { caller: declaredCaller }),
96
101
  archetype: command.archetype,
97
102
  ...(body === undefined ? {} : { body }),
98
103
  ...(input.home === undefined ? {} : { home: input.home }),
@@ -287,7 +292,10 @@ async function runHistory(command, input) {
287
292
  return historyExitCode(result, command.id);
288
293
  }
289
294
  async function runFork(command, input) {
295
+ const caller = await akumaCallerFromEnvironment(input.environment);
290
296
  const receipt = await akumas(input).fork({
297
+ ...(await inputInitiator(input)),
298
+ ...(caller === undefined ? {} : { caller }),
291
299
  akuma: command.akuma,
292
300
  at: command.at,
293
301
  ...(input.repo === undefined ? {} : { repo: input.repo }),
@@ -24,7 +24,8 @@ export type ParsedBind = Output & Actor & Readonly<{
24
24
  command: "bind";
25
25
  forkOf?: string;
26
26
  task?: string;
27
- target?: string;
27
+ /** A literal target branch, or `null` for a deliberately targetless bind. */
28
+ target?: string | null;
28
29
  after?: readonly string[];
29
30
  gates?: readonly string[];
30
31
  }>;
@@ -1,4 +1,4 @@
1
- import { archetypeName } from "../../akuma/identity.js";
1
+ import { validateAkumaName } from "../../identity/normalize.js";
2
2
  import { parseTaskNamespaceSelector } from "../../task/catalog.js";
3
3
  import { CliUsageError, commandGuide } from "../usage.js";
4
4
  import { CONTRACT_COMMAND_SPECS } from "./contract-help.js";
@@ -9,11 +9,11 @@ function parseAkumaCatalogPath(value) {
9
9
  return { kind: "akuma" };
10
10
  const scopedGlob = /^aku\/([^/]+)\/\*$/u.exec(value);
11
11
  if (scopedGlob !== null)
12
- return { kind: "akuma", archetype: archetypeName(scopedGlob[1]) };
12
+ return { kind: "akuma", archetype: validateAkumaName(scopedGlob[1]) };
13
13
  const match = /^aku\/([^/]+)\/?$/u.exec(value);
14
14
  if (match === null)
15
15
  return null;
16
- return { kind: "akuma", archetype: archetypeName(match[1]) };
16
+ return { kind: "akuma", archetype: validateAkumaName(match[1]) };
17
17
  }
18
18
  function optionalFlag(flags, name) {
19
19
  const value = flags[name];
@@ -41,6 +41,13 @@ function parseGateNames(parts, command) {
41
41
  }
42
42
  return names;
43
43
  }
44
+ function parseBindTarget(parts) {
45
+ const target = optionalFlag(parts.flags, "target");
46
+ const noTarget = parts.flags["no-target"] === true;
47
+ if (target !== undefined && noTarget)
48
+ refuse("bind", "--target and --no-target are mutually exclusive");
49
+ return noTarget ? null : target;
50
+ }
44
51
  function parseBind(parts) {
45
52
  const forkOf = optionalFlag(parts.flags, "fork-of");
46
53
  if (forkOf !== undefined) {
@@ -50,7 +57,7 @@ function parseBind(parts) {
50
57
  if (parts.flags[option] !== undefined)
51
58
  refuse("bind", `--${option} is not valid with --fork-of`);
52
59
  }
53
- const target = optionalFlag(parts.flags, "target");
60
+ const target = parseBindTarget(parts);
54
61
  return {
55
62
  command: "bind",
56
63
  forkOf,
@@ -62,7 +69,7 @@ function parseBind(parts) {
62
69
  if (!parts.stdin)
63
70
  refuse("bind", "bind requires stdin");
64
71
  const task = optionalFlag(parts.flags, "task");
65
- const target = optionalFlag(parts.flags, "target");
72
+ const target = parseBindTarget(parts);
66
73
  const after = parts.flags.after === undefined ? [] : Array.isArray(parts.flags.after) ? parts.flags.after : [parts.flags.after];
67
74
  const gates = parseGateNames(parts, "bind");
68
75
  return {
@@ -196,15 +203,6 @@ function parseRegion(parts) {
196
203
  output: parts.output,
197
204
  };
198
205
  }
199
- function akumaCatalogQuery(query, parts) {
200
- const limit = optionalFlag(parts.flags, "limit");
201
- if (limit !== undefined && (!/^[1-9][0-9]*$/u.test(limit) || !Number.isSafeInteger(Number(limit))))
202
- refuse("ls", "--limit requires a positive safe integer");
203
- return {
204
- ...query,
205
- ...(limit === undefined ? {} : { limit: Number(limit) }),
206
- };
207
- }
208
206
  function listLimit(parts, command = "ls") {
209
207
  const limit = optionalFlag(parts.flags, "limit");
210
208
  if (limit !== undefined && (!/^[1-9][0-9]*$/u.test(limit) || !Number.isSafeInteger(Number(limit))))
@@ -249,7 +247,7 @@ function parseLs(parts) {
249
247
  const query = parseAkumaCatalogPath(path);
250
248
  if (query === null)
251
249
  refuse("ls", "ls requires a supported identity directory selector");
252
- return { command: "ls", query: akumaCatalogQuery(query, parts), output: parts.output };
250
+ return { command: "ls", query: { ...query, ...(limit === undefined ? {} : { limit }) }, output: parts.output };
253
251
  }
254
252
  catch (error) {
255
253
  if (error instanceof CliUsageError)
@@ -15,12 +15,13 @@ export declare const CONTRACT_COMMAND_SPECS: {
15
15
  readonly actor: "value";
16
16
  readonly task: "value";
17
17
  readonly target: "value";
18
+ readonly "no-target": "boolean";
18
19
  readonly after: "repeat";
19
20
  readonly gates: "raw-value";
20
21
  readonly "fork-of": "value";
21
22
  readonly json: "boolean";
22
23
  };
23
- readonly usage: "bind [--task <task/...>] [--target <ref>] [--after <kei/...> ...] [--gates <name,...>] [--actor <actor>] - | bind --fork-of <kei/...> [--target <ref>] [--actor <actor>]";
24
+ readonly usage: "bind [--task <task/...>] [--target <ref> | --no-target] [--after <kei/...> ...] [--gates <name,...>] [--actor <actor>] - | bind --fork-of <kei/...> [--target <ref> | --no-target] [--actor <actor>]";
24
25
  readonly purpose: "Create a Contract from stdin Markdown or copy an existing Contract as a starting point.";
25
26
  readonly details: string;
26
27
  };
@@ -7,14 +7,21 @@ export const CONTRACT_COMMAND_SPECS = {
7
7
  actor: "value",
8
8
  task: "value",
9
9
  target: "value",
10
+ "no-target": "boolean",
10
11
  after: "repeat",
11
12
  gates: "raw-value",
12
13
  "fork-of": "value",
13
14
  json: "boolean",
14
15
  },
15
- usage: "bind [--task <task/...>] [--target <ref>] [--after <kei/...> ...] [--gates <name,...>] [--actor <actor>] - | bind --fork-of <kei/...> [--target <ref>] [--actor <actor>]",
16
+ usage: "bind [--task <task/...>] [--target <ref> | --no-target] [--after <kei/...> ...] [--gates <name,...>] [--actor <actor>] - | bind --fork-of <kei/...> [--target <ref> | --no-target] [--actor <actor>]",
16
17
  purpose: "Create a Contract from stdin Markdown or copy an existing Contract as a starting point.",
17
18
  details: [
19
+ "--target names one existing local branch literally; it is never created and never",
20
+ "guessed. Omitting it binds to the current branch of the invocation worktree",
21
+ "coordinate, or binds without a target on a detached committed HEAD. --no-target",
22
+ "binds without a target on purpose, and is refused together with --target.",
23
+ "A fork copies its source target when neither flag is given.",
24
+ "",
18
25
  "Gates are acceptance obligations checked at placement: reviewed awaits a",
19
26
  "satisfied review, verified awaits a passing Verification run.",
20
27
  "",
@@ -245,6 +252,29 @@ export function renderContractHelp(command) {
245
252
  "effort, network, allowed, systemPromptMode, and description; the body is",
246
253
  "an optional system prompt.",
247
254
  "",
255
+ "Local Paseo provider in settings.json:",
256
+ ' { "providers": { "paseo": {',
257
+ ' "kind": "paseo",',
258
+ ' "config": { "url": "ws://127.0.0.1:6767/ws", "provider": "claude" }',
259
+ " } } }",
260
+ "The native provider id is bare (claude, codex, pi), not provider/model.",
261
+ "Example .keiyaku/akuma/paseo-worker.md frontmatter:",
262
+ " ---",
263
+ " provider: paseo",
264
+ " model: <native-model-id>",
265
+ " effort: high",
266
+ " ---",
267
+ "Model and effort must be offered by the selected native provider;",
268
+ "effort names its native thinking option id.",
269
+ 'PASEO_PASSWORD=<password> keiyaku call paseo-worker "<prompt>"',
270
+ "Paseo must already be running locally. Resume keeps its live native",
271
+ "runtime; after Paseo native reload/restart create a fresh Akuma.",
272
+ "Observed busy agents refuse; native steer still has a check/send race.",
273
+ "Explicit control cancels native current execution session-wide and may",
274
+ "affect concurrent human work. Normal completion only retires the client",
275
+ "and its sockets; it never cancels later work or closes the native runtime.",
276
+ "Socket closure does not prove native cancellation succeeded.",
277
+ "",
248
278
  usageLine(spec.usage),
249
279
  ].join("\n");
250
280
  }
@@ -1,7 +1,6 @@
1
- import { listArchetypeDefinitions } from "../../akuma/archetype.js";
2
1
  import { executionChannel } from "../../akuma/requests.js";
3
- import { Akumas, Keiyaku, KeiyakuError, nuke } from "../../index.js";
4
- import { kanshi, kanshiCategory, observeKanshi, selectKanshi, selectRegion } from "../../kanshi/index.js";
2
+ import { Akumas, Keiyaku, KeiyakuError, kanshiCategory, listArchetypeDefinitions, nuke } from "../../index.js";
3
+ import { kanshi, observeKanshi, selectRegion } from "../../kanshi/index.js";
5
4
  import { resolveNamedAddress } from "../../library/address.js";
6
5
  import { composeContractLibrary, observeKeiyaku } from "../../library/contract-composition.js";
7
6
  import { validateArcMarkdown, validateContractMarkdown } from "../../library/input.js";
@@ -20,11 +19,9 @@ import { reconcileHasFailure, renderReconcile } from "../render/reconcile.js";
20
19
  import { renderConflictMaterialized, renderRefusal } from "../render/refusal.js";
21
20
  import { renderRegionText } from "../render/region.js";
22
21
  import { renderSettingsText, settingsJsonValue } from "../render/settings.js";
23
- import { canonicalContractSelector, contractFromInput, resolveContractId, resolveKanshiContract, } from "../selectors.js";
24
- import { displayContext, emit, writeJson, writeStdout } from "../streams.js";
22
+ import { canonicalContractSelector, contractFromInput, resolveContractId } from "../selectors.js";
23
+ import { displayContext, emit, writeJson, writeStderr, writeStdout } from "../streams.js";
25
24
  import { CliUsageError, isBlankInput } from "../usage.js";
26
- import { amendFromCommand } from "./amend.js";
27
- import { bindFromCommand } from "./bind.js";
28
25
  function requiredRepo(coordinates) {
29
26
  if (coordinates.repo === undefined)
30
27
  throw new CliUsageError("this command requires a resolved Repo");
@@ -50,17 +47,6 @@ async function contractSettings(command, execution, world, home) {
50
47
  function draftWarning(error) {
51
48
  return { warning: `bind draft could not be preserved: ${error instanceof Error ? error.message : String(error)}` };
52
49
  }
53
- /** Preserve a refused bind draft at the invocation cwd; coordinates are not yet available. */
54
- async function bindDraftReceiptAtCwd(input, markdown) {
55
- try {
56
- return await preserveBindDraft(await resolveInvocationCwd(input), markdown);
57
- }
58
- catch (error) {
59
- if (error instanceof Error && "executionReceipt" in error)
60
- throw error;
61
- return draftWarning(error);
62
- }
63
- }
64
50
  /**
65
51
  * The one bind-document admission that runs before coordinate resolution, so a malformed document
66
52
  * refuses as a draft-bearing refusal instead of a later Repo/Git failure. Reads the memoized stdin.
@@ -76,7 +62,7 @@ export async function admitBindMarkdown(input) {
76
62
  throw error;
77
63
  if (!(error instanceof TypeError) && !(error instanceof KeiyakuError && error.category === "invalid-input"))
78
64
  throw error;
79
- throw new BindDraftError(error, await bindDraftReceiptAtCwd(input, input.markdown));
65
+ throw new BindDraftError(error, await bindDraftReceipt(() => resolveInvocationCwd(input), input.markdown));
80
66
  }
81
67
  }
82
68
  async function bindDraftReceipt(world, markdown) {
@@ -145,41 +131,32 @@ async function contractLibrary(command, execution, configuration, runtime) {
145
131
  return composeContractLibrary(execution, createKeiyakuHandle, {
146
132
  ...(configuration === undefined ? {} : { settings: configuration }),
147
133
  ...(actor === undefined ? {} : { actor }),
148
- },
149
- // The CLI owns this default: an omitted Markdown --target names the invocation branch.
150
- { kind: "current-branch" });
134
+ });
151
135
  }
152
136
  async function runBind(command, input, library) {
153
137
  const { coordinates, runtime } = input;
154
138
  const repo = requiredRepo(coordinates);
155
139
  const actor = actorFromEdge(command.actor, runtime.environment);
156
140
  if (command.forkOf !== undefined) {
157
- const answer = await bindFromCommand({
158
- command,
141
+ const answer = await library.bind({
159
142
  repo,
160
- library,
143
+ forkOf: contractFromInput(repo, command.forkOf).id,
144
+ ...(command.target === undefined ? {} : { target: command.target }),
161
145
  ...(actor === undefined ? {} : { actor }),
162
146
  });
163
147
  return await finishContractAnswer(answer, command.output);
164
148
  }
165
149
  const markdown = await runtime.readStdin();
166
- if (isBlankInput(markdown))
167
- throw new CliUsageError("bind requires a nonblank stdin document");
168
150
  try {
169
- validateContractMarkdown(markdown);
170
- }
171
- catch (error) {
172
- if (!(error instanceof TypeError) && !(error instanceof KeiyakuError && error.category === "invalid-input"))
173
- throw error;
174
- throw new BindDraftError(error, await bindDraftReceipt(coordinates.establishWorld, markdown));
175
- }
176
- try {
177
- const answer = await bindFromCommand({
178
- command,
151
+ const after = command.after?.map((id) => contractFromInput(repo, id).id);
152
+ const answer = await library.bind({
179
153
  repo,
180
- library,
181
154
  markdown,
155
+ ...(command.task === undefined ? {} : { task: command.task }),
156
+ ...(command.target === undefined ? {} : { target: command.target }),
182
157
  ...(actor === undefined ? {} : { actor }),
158
+ ...(after === undefined ? {} : { after }),
159
+ ...(command.gates === undefined ? {} : { gates: command.gates }),
183
160
  });
184
161
  if (answer.kind !== "refused")
185
162
  return await finishContractAnswer(answer, command.output);
@@ -203,13 +180,13 @@ async function runAmend(command, input, seat) {
203
180
  const markdown = command.stdin === true ? await runtime.readStdin() : undefined;
204
181
  if (markdown !== undefined && isBlankInput(markdown))
205
182
  throw new CliUsageError("amend requires a nonblank stdin document");
206
- const answer = await amendFromCommand({
207
- command,
208
- repo: requiredRepo(coordinates),
209
- contract: seat.contract,
183
+ const repo = requiredRepo(coordinates);
184
+ const after = command.clearAfter === true ? [] : command.after?.map((id) => contractFromInput(repo, id).id);
185
+ const answer = await seat.contract.amend({
210
186
  ...(markdown === undefined ? {} : { markdown }),
211
- ...(command.gates === undefined ? {} : { gates: command.gates }),
212
187
  ...(seat.actor === undefined ? {} : { actor: seat.actor }),
188
+ ...(after === undefined ? {} : { after }),
189
+ ...(command.gates === undefined ? {} : { gates: command.gates }),
213
190
  });
214
191
  return await finishContractAnswer(answer, command.output);
215
192
  }
@@ -366,7 +343,7 @@ async function runLs(command, coordinates, home) {
366
343
  async function readAkumaStatus(akuma, alias, coordinates) {
367
344
  if (coordinates.world === null)
368
345
  throw new CliUsageError("no Keiyaku world contains the Akuma selector");
369
- const status = await Akumas.of(coordinates.world).status({
346
+ const status = await Akumas.of(coordinates.world, { reportDiagnostic: writeStderr }).status({
370
347
  akuma,
371
348
  ...(coordinates.repo === undefined ? {} : { repo: coordinates.repo }),
372
349
  });
@@ -473,13 +450,7 @@ async function runStatusIdentity(command, coordinates) {
473
450
  }
474
451
  return emit(command.output, report, () => renderKanshiText(report, displayContext(), "contract"), 0);
475
452
  }
476
- const report = await kanshi({
477
- world: coordinates.world,
478
- ...(coordinates.repo === undefined ? {} : { repo: coordinates.repo }),
479
- });
480
- const contract = resolveKanshiContract(report, command.contract);
481
- const selected = selectKanshi({ report, contract });
482
- return emit(command.output, selected, () => renderKanshiText(selected, displayContext(), "contract"), 0);
453
+ throw new CliUsageError(`contract selector must use kei/: ${command.contract}`);
483
454
  }
484
455
  async function runStatus(command, coordinates) {
485
456
  if (command.guidance === true)
@@ -501,10 +472,10 @@ async function runRegion(command, coordinates) {
501
472
  const report = await kanshi({ world: coordinates.world, repo, region: { kind: "path", patterns: command.paths } });
502
473
  return emitSection(report.region ?? { kind: "absent" });
503
474
  }
475
+ const contract = command.contract === undefined ? undefined : await resolveContractId(repo, command.contract, coordinates.cwd);
504
476
  const report = await kanshi({ world: coordinates.world, repo, region: { kind: "declarations" } });
505
- if (command.contract === undefined)
477
+ if (contract === undefined)
506
478
  return emitSection(report.region ?? { kind: "absent" });
507
- const contract = resolveKanshiContract(report, command.contract);
508
479
  const observed = await observeKeiyaku({ repo, id: contract });
509
480
  if (observed.kind === "missing" || observed.row.phase === "claimed" || observed.row.phase === "abandoned") {
510
481
  const refusal = {