@astrosheep/keiyaku 4.6.11 → 4.6.13

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 (138) hide show
  1. package/build/plugins/claude/skills/keiyaku/SKILL.md +3 -1
  2. package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
  3. package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +3 -2
  4. package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +9 -8
  5. package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -1
  6. package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
  7. package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +3 -2
  8. package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +9 -8
  9. package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -1
  10. package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
  11. package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +3 -2
  12. package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +9 -8
  13. package/build/skills/keiyaku/SKILL.md +3 -1
  14. package/build/skills/keiyaku-babysit/SKILL.md +1 -1
  15. package/build/skills/keiyaku-bind/SKILL.md +3 -2
  16. package/build/skills/keiyaku-workflow/SKILL.md +9 -8
  17. package/build/src/akuma/akuma-errors.d.ts +5 -0
  18. package/build/src/akuma/akuma-errors.js +9 -0
  19. package/build/src/akuma/akuma-owner.d.ts +14 -19
  20. package/build/src/akuma/akuma-owner.js +56 -54
  21. package/build/src/akuma/akuma-selection-execution.d.ts +5 -4
  22. package/build/src/akuma/akuma-selection-execution.js +59 -17
  23. package/build/src/akuma/akuma.d.ts +1 -2
  24. package/build/src/akuma/allowed.d.ts +2 -3
  25. package/build/src/akuma/allowed.js +1 -3
  26. package/build/src/akuma/body.js +17 -7
  27. package/build/src/akuma/call-initial-tell.d.ts +18 -0
  28. package/build/src/akuma/call-initial-tell.js +18 -0
  29. package/build/src/akuma/call-request.d.ts +20 -4
  30. package/build/src/akuma/heart/facts.d.ts +13 -0
  31. package/build/src/akuma/heart/facts.js +6 -0
  32. package/build/src/akuma/heart/index.d.ts +29 -14
  33. package/build/src/akuma/heart/index.js +75 -29
  34. package/build/src/akuma/heart/rows.d.ts +9 -2
  35. package/build/src/akuma/heart/rows.js +72 -11
  36. package/build/src/akuma/heart/storage.d.ts +2 -8
  37. package/build/src/akuma/heart/storage.js +13 -13
  38. package/build/src/akuma/heart/tells.d.ts +3 -1
  39. package/build/src/akuma/heart/tells.js +18 -2
  40. package/build/src/akuma/provider.d.ts +2 -4
  41. package/build/src/akuma/provider.js +29 -6
  42. package/build/src/akuma/providers/acp/core.js +23 -21
  43. package/build/src/akuma/providers/claude/index.js +0 -8
  44. package/build/src/akuma/providers/codex-app-server/index.js +9 -8
  45. package/build/src/akuma/providers/execution-environment.d.ts +1 -1
  46. package/build/src/akuma/providers/execution-environment.js +1 -0
  47. package/build/src/akuma/providers/opencode-sdk/events.js +111 -81
  48. package/build/src/akuma/providers/opencode-sdk/index.js +179 -150
  49. package/build/src/akuma/providers/opencode-sdk/native-http.js +7 -3
  50. package/build/src/akuma/providers/opencode-sdk/session.d.ts +5 -3
  51. package/build/src/akuma/providers/opencode-sdk/session.js +32 -27
  52. package/build/src/akuma/providers/paseo/index.js +0 -2
  53. package/build/src/akuma/providers/pi/index.js +23 -20
  54. package/build/src/akuma/selection-observation.d.ts +78 -9
  55. package/build/src/akuma/selection-owner-port.d.ts +2 -1
  56. package/build/src/akuma/selection-owner-port.js +6 -1
  57. package/build/src/akuma/selection-request.d.ts +1 -1
  58. package/build/src/akuma/selection-request.js +8 -3
  59. package/build/src/akuma/turn-drive.js +79 -48
  60. package/build/src/akuma-body.js +5 -3
  61. package/build/src/cli/commands/akuma-grammar.js +2 -2
  62. package/build/src/cli/commands/akuma.js +24 -16
  63. package/build/src/cli/commands/contract-grammar.d.ts +3 -7
  64. package/build/src/cli/commands/contract-grammar.js +12 -10
  65. package/build/src/cli/commands/contract-help.d.ts +3 -13
  66. package/build/src/cli/commands/contract-help.js +7 -16
  67. package/build/src/cli/commands/contract.js +19 -35
  68. package/build/src/cli/commands/debt.js +30 -29
  69. package/build/src/cli/parse.js +0 -1
  70. package/build/src/cli/render/akuma-activity.d.ts +36 -9
  71. package/build/src/cli/render/akuma-activity.js +142 -65
  72. package/build/src/cli/render/akuma.d.ts +6 -0
  73. package/build/src/cli/render/akuma.js +67 -24
  74. package/build/src/cli/render/catalog.js +0 -1
  75. package/build/src/cli/render/contract-observation.d.ts +16 -3
  76. package/build/src/cli/render/contract-observation.js +3 -0
  77. package/build/src/cli/render/contract.d.ts +2 -2
  78. package/build/src/cli/render/contract.js +4 -4
  79. package/build/src/cli/render/delivery-preview.d.ts +7 -0
  80. package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
  81. package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
  82. package/build/src/cli/render/kanshi-akuma.js +23 -8
  83. package/build/src/cli/render/kanshi.js +4 -1
  84. package/build/src/cli/render/receipt.js +3 -3
  85. package/build/src/cli/render/refusal.js +2 -2
  86. package/build/src/cli/render/terminal.d.ts +0 -1
  87. package/build/src/cli/render/terminal.js +1 -1
  88. package/build/src/cli/square-identity.d.ts +15 -0
  89. package/build/src/cli/square-identity.js +180 -0
  90. package/build/src/contract-worktree.js +1 -1
  91. package/build/src/core/verbs/placement.d.ts +2 -1
  92. package/build/src/core/verbs/placement.js +1 -1
  93. package/build/src/debt/context.d.ts +0 -5
  94. package/build/src/debt/context.js +32 -44
  95. package/build/src/git/process.d.ts +1 -0
  96. package/build/src/git/process.js +18 -1
  97. package/build/src/git/read-observation.js +2 -1
  98. package/build/src/git/scratch.d.ts +5 -1
  99. package/build/src/git/scratch.js +41 -12
  100. package/build/src/git/target-placement.d.ts +22 -4
  101. package/build/src/git/target-placement.js +44 -20
  102. package/build/src/index.d.ts +2 -2
  103. package/build/src/kanshi/read.js +187 -105
  104. package/build/src/kanshi/report.d.ts +5 -0
  105. package/build/src/library/address.d.ts +18 -4
  106. package/build/src/library/address.js +27 -6
  107. package/build/src/library/contract-address.d.ts +6 -0
  108. package/build/src/library/contract-address.js +12 -1
  109. package/build/src/library/contract-execution.d.ts +2 -2
  110. package/build/src/library/contract-execution.js +13 -17
  111. package/build/src/library/contract-operations.d.ts +59 -94
  112. package/build/src/library/contract-operations.js +23 -19
  113. package/build/src/library/contract-outcomes.d.ts +3 -3
  114. package/build/src/library/contract-settings.d.ts +1 -0
  115. package/build/src/library/contract-settings.js +1 -1
  116. package/build/src/library/invocation.d.ts +2 -2
  117. package/build/src/library/invocation.js +1 -1
  118. package/build/src/library/keiyaku.d.ts +2 -2
  119. package/build/src/library/keiyaku.js +2 -2
  120. package/build/src/library/outcome.d.ts +148 -268
  121. package/build/src/library/outcome.js +4 -8
  122. package/build/src/library/refusal.d.ts +2 -2
  123. package/build/src/library/refusal.js +2 -2
  124. package/build/src/plugin/runtime.js +15 -19
  125. package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
  126. package/build/src/protocol/delivery-preview.js +167 -0
  127. package/build/src/protocol/progress.d.ts +1 -1
  128. package/build/src/runtime/proc/run.js +22 -4
  129. package/build/src/runtime/proc/windows-launch.exe +0 -0
  130. package/build/src/verification/execution.d.ts +1 -1
  131. package/build/src/verification/execution.js +5 -3
  132. package/package.json +5 -2
  133. package/skills/keiyaku/SKILL.md +3 -1
  134. package/skills/keiyaku-babysit/SKILL.md +1 -1
  135. package/skills/keiyaku-bind/SKILL.md +3 -2
  136. package/skills/keiyaku-workflow/SKILL.md +9 -8
  137. package/build/src/cli/render/audit.d.ts +0 -7
  138. package/build/src/protocol/audit.js +0 -203
@@ -54,7 +54,7 @@ export type OpencodeSdkLoader = (cwd: string, execution: ProviderExecution, sign
54
54
  ready?: Promise<void>;
55
55
  }>>;
56
56
  export declare const OPENCODE_SDK_PROVIDER: "opencode-sdk";
57
- export declare function messageId(sequence?: number): string;
57
+ export declare function messageId(): string;
58
58
  export declare function parseModel(model: string): Readonly<{
59
59
  providerID: string;
60
60
  id: string;
@@ -69,12 +69,14 @@ export type OpencodeRuntime = Readonly<{
69
69
  }>;
70
70
  /** A successful HTML fallback, or a JSON response from another API, is not readiness. */
71
71
  export declare function waitReady(json: (path: string) => Promise<unknown>, signal: AbortSignal): Promise<void>;
72
- export declare function loadOpencode(input: Readonly<{
72
+ type LoadOpencodeInput = Readonly<{
73
73
  execution: ProviderExecution;
74
74
  cwd: string;
75
75
  signal: AbortSignal;
76
76
  loader?: OpencodeSdkLoader;
77
77
  onRuntime?: (runtime: OpencodeRuntime) => void;
78
78
  requests?: string;
79
- }>): Promise<OpencodeRuntime>;
79
+ }>;
80
+ export declare function loadOpencode(input: LoadOpencodeInput): Promise<OpencodeRuntime>;
80
81
  export declare function coordinate(sessionId: string): ResumeCoordinate;
82
+ export {};
@@ -1,3 +1,4 @@
1
+ import { SessionMessage } from "@opencode/schema/session-message";
1
2
  import net from "node:net";
2
3
  import { randomBytes } from "node:crypto";
3
4
  import { abortable } from "../../abort.js";
@@ -6,9 +7,8 @@ import { spawnDetachedProcess } from "../../../runtime/proc/run.js";
6
7
  import { object } from "../decode.js";
7
8
  import { createNativeClient } from "./native-http.js";
8
9
  export const OPENCODE_SDK_PROVIDER = "opencode-sdk";
9
- export function messageId(sequence = 0) {
10
- const timestamp = BigInt(Date.now()) * 0x1000n + BigInt(sequence);
11
- return `msg_${timestamp.toString(16)}${randomBytes(14).toString("hex")}`;
10
+ export function messageId() {
11
+ return SessionMessage.ID.create();
12
12
  }
13
13
  export function parseModel(model) {
14
14
  const slash = model.indexOf("/");
@@ -73,31 +73,36 @@ async function availablePort() {
73
73
  });
74
74
  }
75
75
  export async function loadOpencode(input) {
76
- const { execution, cwd, signal, loader, onRuntime, requests } = input;
77
- if (loader !== undefined) {
78
- const loaded = await abortable(loader(cwd, {
79
- ...execution,
80
- env: akumaExecutionEnvironment(process.env, execution.env, requests),
81
- }, signal), signal);
82
- let closing;
83
- const runtime = {
84
- client: loaded.client,
85
- close: () => (closing ??= Promise.resolve()
86
- .then(() => loaded.close?.())
87
- .then(() => undefined)),
88
- };
89
- onRuntime?.(runtime);
90
- try {
91
- if (loaded.ready !== undefined)
92
- await abortable(loaded.ready, signal);
93
- signal.throwIfAborted();
94
- return runtime;
95
- }
96
- catch (error) {
97
- await runtime.close();
98
- throw error;
99
- }
76
+ const { loader } = input;
77
+ return loader === undefined ? loadNativeOpencode(input) : loadInjectedOpencode(input, loader);
78
+ }
79
+ async function loadInjectedOpencode(input, loader) {
80
+ const { execution, cwd, signal, onRuntime, requests } = input;
81
+ const loaded = await abortable(loader(cwd, {
82
+ ...execution,
83
+ env: akumaExecutionEnvironment(process.env, execution.env, requests),
84
+ }, signal), signal);
85
+ let closing;
86
+ const runtime = {
87
+ client: loaded.client,
88
+ close: () => (closing ??= Promise.resolve()
89
+ .then(() => loaded.close?.())
90
+ .then(() => undefined)),
91
+ };
92
+ onRuntime?.(runtime);
93
+ try {
94
+ if (loaded.ready !== undefined)
95
+ await abortable(loaded.ready, signal);
96
+ signal.throwIfAborted();
97
+ return runtime;
100
98
  }
99
+ catch (error) {
100
+ await runtime.close();
101
+ throw error;
102
+ }
103
+ }
104
+ async function loadNativeOpencode(input) {
105
+ const { execution, cwd, signal, onRuntime, requests } = input;
101
106
  const port = await availablePort();
102
107
  signal.throwIfAborted();
103
108
  const password = execution.env?.OPENCODE_PASSWORD ??
@@ -248,8 +248,6 @@ class PaseoDrive {
248
248
  admission: { fence },
249
249
  events: this.turn.events,
250
250
  completion,
251
- abort: () => this.retire(true),
252
- forceDispose: () => this.retire(true),
253
251
  };
254
252
  }
255
253
  async existingAgent(coordinate, signal) {
@@ -1,6 +1,6 @@
1
1
  import { abortable } from "../../abort.js";
2
2
  import { akumaExecutionEnvironment } from "../execution-environment.js";
3
- import { AgentEventChannel, createProviderAttempt, launchPrompt, modelEvent, tellRegistry, } from "../../provider.js";
3
+ import { AgentEventChannel, createProviderAttempt, launchPrompt, modelEvent, noteEvent, tellRegistry, } from "../../provider.js";
4
4
  import { piSessionModel, piTerminalFailure, translatePiEvent } from "./events.js";
5
5
  const PI_THINKING_LEVELS = new Set(["minimal", "low", "medium", "high", "xhigh", "max"]);
6
6
  const MODEL_PATTERN = /^[^/\s]+\/[^\s]+$/u;
@@ -70,9 +70,13 @@ async function createPiSession(sdk, execution, input) {
70
70
  : { systemPromptOverride: () => input.options.systemPrompt },
71
71
  }),
72
72
  });
73
+ const extensionErrors = services.resourceLoader.getExtensions().errors ?? [];
74
+ for (const failure of extensionErrors)
75
+ console.error(`Pi extension load failed: ${failure.path}\n${failure.error}`);
73
76
  try {
74
77
  input.signal?.throwIfAborted();
75
- return await sdk.createAgentSessionFromServices(piCreateOptions(sdk, input, services));
78
+ const created = await sdk.createAgentSessionFromServices(piCreateOptions(sdk, input, services));
79
+ return { created, extensionErrors };
76
80
  }
77
81
  catch (error) {
78
82
  // Before a session owns the extension runtime, failed selection/setup must
@@ -139,7 +143,7 @@ async function retirePiSession(native) {
139
143
  throw failure;
140
144
  }
141
145
  async function drivePi(sdk, execution, input, signal, custody) {
142
- const created = await createPiSession(sdk, execution, input);
146
+ const { created, extensionErrors } = await createPiSession(sdk, execution, input);
143
147
  const native = created.session;
144
148
  let settleRetired;
145
149
  let failRetired;
@@ -201,12 +205,24 @@ async function drivePi(sdk, execution, input, signal, custody) {
201
205
  })().then(settleRetired, failRetired);
202
206
  return closed;
203
207
  };
208
+ const abort = async () => {
209
+ if (state.settled)
210
+ return;
211
+ state.aborting = true;
212
+ try {
213
+ await native.abort();
214
+ }
215
+ catch {
216
+ /* prompt settlement still proves local cleanup */
217
+ }
218
+ await settle({ kind: "failed", diagnostic: "Pi session aborted" });
219
+ };
204
220
  const forceDispose = async () => {
205
221
  if (!state.settled)
206
222
  state.aborting = true;
207
223
  await settle({ kind: "failed", diagnostic: "Pi session force-disposed" });
208
224
  };
209
- custody?.own({ closed, abort: forceDispose, forceDispose });
225
+ custody?.own({ closed, abort, forceDispose });
210
226
  try {
211
227
  unsubscribeAgent = agent.subscribe((event) => {
212
228
  if (event.type === "message_end")
@@ -236,6 +252,9 @@ async function drivePi(sdk, execution, input, signal, custody) {
236
252
  await abortable(binding, signal);
237
253
  signal.throwIfAborted();
238
254
  events.emit({ type: "session", coordinate: { sessionFile: native.sessionFile, sessionId: native.sessionId } });
255
+ for (const failure of extensionErrors) {
256
+ events.emit(noteEvent(`Pi extension load failed: ${failure.path}: ${failure.error}`));
257
+ }
239
258
  const sessionModel = piSessionModel(native.model);
240
259
  if (sessionModel !== undefined)
241
260
  events.emit(modelEvent(sessionModel));
@@ -263,22 +282,6 @@ async function drivePi(sdk, execution, input, signal, custody) {
263
282
  }
264
283
  return submission;
265
284
  },
266
- abort: () => {
267
- state.abortRequest ??= (async () => {
268
- if (state.settled)
269
- return;
270
- state.aborting = true;
271
- try {
272
- await native.abort();
273
- }
274
- catch {
275
- /* prompt settlement still proves local cleanup */
276
- }
277
- await settle({ kind: "failed", diagnostic: "Pi session aborted" });
278
- })();
279
- return state.abortRequest;
280
- },
281
- forceDispose,
282
285
  };
283
286
  }
284
287
  function piSessionFile(coordinate) {
@@ -47,10 +47,9 @@ declare const akumaObservationSchema: z.ZodObject<{
47
47
  "akuma.call": "akuma.call";
48
48
  "akuma.kill": "akuma.kill";
49
49
  "akuma.tell": "akuma.tell";
50
- "contract.audit": "contract.audit";
51
50
  "contract.deliver": "contract.deliver";
52
51
  "contract.review": "contract.review";
53
- }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
52
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.deliver" | "contract.review")[]>>;
54
53
  timeline: z.ZodUnion<readonly [z.ZodObject<{
55
54
  reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
56
55
  sequence: z.ZodNumber;
@@ -537,10 +536,9 @@ declare const akumaWaitResultSchema: z.ZodObject<{
537
536
  "akuma.call": "akuma.call";
538
537
  "akuma.kill": "akuma.kill";
539
538
  "akuma.tell": "akuma.tell";
540
- "contract.audit": "contract.audit";
541
539
  "contract.deliver": "contract.deliver";
542
540
  "contract.review": "contract.review";
543
- }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
541
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.deliver" | "contract.review")[]>>;
544
542
  timeline: z.ZodUnion<readonly [z.ZodObject<{
545
543
  reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
546
544
  sequence: z.ZodNumber;
@@ -979,9 +977,9 @@ declare const akumaKillResultSchema: z.ZodObject<{
979
977
  killed: "killed";
980
978
  hung: "hung";
981
979
  unavailable: "unavailable";
980
+ untidy: "untidy";
982
981
  "already-killed": "already-killed";
983
982
  "already-stopped": "already-stopped";
984
- untidy: "untidy";
985
983
  }>;
986
984
  }, z.core.$strict>>>;
987
985
  }, z.core.$strict>;
@@ -1072,6 +1070,24 @@ declare const akumaTellResultSchema: z.ZodObject<{
1072
1070
  };
1073
1071
  } | undefined;
1074
1072
  }>>]>;
1073
+ interruption: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1074
+ kind: z.ZodLiteral<"completed">;
1075
+ bodySequence: z.ZodNumber;
1076
+ putDown: z.ZodEnum<{
1077
+ "was-idle": "was-idle";
1078
+ "self-aborted": "self-aborted";
1079
+ }>;
1080
+ }, z.core.$strict>, z.ZodObject<{
1081
+ kind: z.ZodLiteral<"pending">;
1082
+ bodySequence: z.ZodNumber;
1083
+ }, z.core.$strict>, z.ZodObject<{
1084
+ kind: z.ZodLiteral<"unavailable">;
1085
+ bodySequence: z.ZodNumber;
1086
+ evidence: z.ZodEnum<{
1087
+ hung: "hung";
1088
+ untidy: "untidy";
1089
+ }>;
1090
+ }, z.core.$strict>], "kind">>;
1075
1091
  }, z.core.$strict>;
1076
1092
  }, z.core.$strict>;
1077
1093
  declare const askObservationSchema: z.ZodUnion<readonly [z.ZodObject<{
@@ -1176,6 +1192,24 @@ declare const akumaAskResultSchema: z.ZodObject<{
1176
1192
  };
1177
1193
  } | undefined;
1178
1194
  }>>]>;
1195
+ interruption: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1196
+ kind: z.ZodLiteral<"completed">;
1197
+ bodySequence: z.ZodNumber;
1198
+ putDown: z.ZodEnum<{
1199
+ "was-idle": "was-idle";
1200
+ "self-aborted": "self-aborted";
1201
+ }>;
1202
+ }, z.core.$strict>, z.ZodObject<{
1203
+ kind: z.ZodLiteral<"pending">;
1204
+ bodySequence: z.ZodNumber;
1205
+ }, z.core.$strict>, z.ZodObject<{
1206
+ kind: z.ZodLiteral<"unavailable">;
1207
+ bodySequence: z.ZodNumber;
1208
+ evidence: z.ZodEnum<{
1209
+ hung: "hung";
1210
+ untidy: "untidy";
1211
+ }>;
1212
+ }, z.core.$strict>], "kind">>;
1179
1213
  }, z.core.$strict>;
1180
1214
  observation: z.ZodUnion<readonly [z.ZodObject<{
1181
1215
  reason: z.ZodLiteral<"answered">;
@@ -1273,10 +1307,9 @@ export declare const selectionResultSchemas: {
1273
1307
  "akuma.call": "akuma.call";
1274
1308
  "akuma.kill": "akuma.kill";
1275
1309
  "akuma.tell": "akuma.tell";
1276
- "contract.audit": "contract.audit";
1277
1310
  "contract.deliver": "contract.deliver";
1278
1311
  "contract.review": "contract.review";
1279
- }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
1312
+ }>>, z.ZodTransform<import("./allowed.js").AllowedActions, ("debt.add" | "debt.addDocument" | "debt.done" | "debt.drop" | "debt.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.deliver" | "contract.review")[]>>;
1280
1313
  timeline: z.ZodUnion<readonly [z.ZodObject<{
1281
1314
  reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
1282
1315
  sequence: z.ZodNumber;
@@ -1795,6 +1828,24 @@ export declare const selectionResultSchemas: {
1795
1828
  };
1796
1829
  } | undefined;
1797
1830
  }>>]>;
1831
+ interruption: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1832
+ kind: z.ZodLiteral<"completed">;
1833
+ bodySequence: z.ZodNumber;
1834
+ putDown: z.ZodEnum<{
1835
+ "was-idle": "was-idle";
1836
+ "self-aborted": "self-aborted";
1837
+ }>;
1838
+ }, z.core.$strict>, z.ZodObject<{
1839
+ kind: z.ZodLiteral<"pending">;
1840
+ bodySequence: z.ZodNumber;
1841
+ }, z.core.$strict>, z.ZodObject<{
1842
+ kind: z.ZodLiteral<"unavailable">;
1843
+ bodySequence: z.ZodNumber;
1844
+ evidence: z.ZodEnum<{
1845
+ hung: "hung";
1846
+ untidy: "untidy";
1847
+ }>;
1848
+ }, z.core.$strict>], "kind">>;
1798
1849
  }, z.core.$strict>;
1799
1850
  }, z.core.$strict>;
1800
1851
  ask: z.ZodObject<{
@@ -1884,6 +1935,24 @@ export declare const selectionResultSchemas: {
1884
1935
  };
1885
1936
  } | undefined;
1886
1937
  }>>]>;
1938
+ interruption: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
1939
+ kind: z.ZodLiteral<"completed">;
1940
+ bodySequence: z.ZodNumber;
1941
+ putDown: z.ZodEnum<{
1942
+ "was-idle": "was-idle";
1943
+ "self-aborted": "self-aborted";
1944
+ }>;
1945
+ }, z.core.$strict>, z.ZodObject<{
1946
+ kind: z.ZodLiteral<"pending">;
1947
+ bodySequence: z.ZodNumber;
1948
+ }, z.core.$strict>, z.ZodObject<{
1949
+ kind: z.ZodLiteral<"unavailable">;
1950
+ bodySequence: z.ZodNumber;
1951
+ evidence: z.ZodEnum<{
1952
+ hung: "hung";
1953
+ untidy: "untidy";
1954
+ }>;
1955
+ }, z.core.$strict>], "kind">>;
1887
1956
  }, z.core.$strict>;
1888
1957
  observation: z.ZodUnion<readonly [z.ZodObject<{
1889
1958
  reason: z.ZodLiteral<"answered">;
@@ -1909,9 +1978,9 @@ export declare const selectionResultSchemas: {
1909
1978
  killed: "killed";
1910
1979
  hung: "hung";
1911
1980
  unavailable: "unavailable";
1981
+ untidy: "untidy";
1912
1982
  "already-killed": "already-killed";
1913
1983
  "already-stopped": "already-stopped";
1914
- untidy: "untidy";
1915
1984
  }>;
1916
1985
  }, z.core.$strict>>>;
1917
1986
  }, z.core.$strict>;
@@ -1919,9 +1988,9 @@ export declare const selectionResultSchemas: {
1919
1988
  killed: "killed";
1920
1989
  hung: "hung";
1921
1990
  unavailable: "unavailable";
1991
+ untidy: "untidy";
1922
1992
  "already-killed": "already-killed";
1923
1993
  "already-stopped": "already-stopped";
1924
- untidy: "untidy";
1925
1994
  }>;
1926
1995
  };
1927
1996
  export {};
@@ -1,4 +1,5 @@
1
1
  import type { WorldRoot } from "../world.js";
2
+ import type { AkumaStatus } from "./akuma.js";
2
3
  import type { SelectionRequestPort } from "./selection-request.js";
3
4
  /**
4
5
  * The parent's Selection owner boundary: one forwarded request arrives as complete
@@ -9,4 +10,4 @@ import type { SelectionRequestPort } from "./selection-request.js";
9
10
  * unaddressable member never starts; the executor's own access to the target is
10
11
  * then the product act, never a second addressing probe.
11
12
  */
12
- export declare function selectionRequestPort(world: WorldRoot, reportDiagnostic: (message: string) => void): SelectionRequestPort;
13
+ export declare function selectionRequestPort(world: WorldRoot, reportDiagnostic: (message: string) => void, servingBodyId?: AkumaStatus["id"]): SelectionRequestPort;
@@ -1,3 +1,4 @@
1
+ import { AkumaSelfInterruptError } from "./akuma-errors.js";
1
2
  import { outcomePluginObserver } from "../plugin/akuma-signals.js";
2
3
  import { requireBornAkuma } from "./akuma-probe.js";
3
4
  import { executeAskAkuma, executeKillAkuma, executeTellAkuma } from "./akuma-selection-execution.js";
@@ -12,7 +13,7 @@ import { akumaObservationOf } from "./selection-observation.js";
12
13
  * unaddressable member never starts; the executor's own access to the target is
13
14
  * then the product act, never a second addressing probe.
14
15
  */
15
- export function selectionRequestPort(world, reportDiagnostic) {
16
+ export function selectionRequestPort(world, reportDiagnostic, servingBodyId) {
16
17
  const prove = async (targets) => {
17
18
  for (const id of targets)
18
19
  await requireBornAkuma(world, id);
@@ -31,10 +32,14 @@ export function selectionRequestPort(world, reportDiagnostic) {
31
32
  return { ...native, observations: native.observations.map(akumaObservationOf) };
32
33
  },
33
34
  tell: async ({ target, ...request }) => {
35
+ if (request.interrupt === true && servingBodyId === target)
36
+ throw new AkumaSelfInterruptError(target);
34
37
  await prove([target]);
35
38
  return await executeTellAkuma({ path: world, id: target, ...request });
36
39
  },
37
40
  ask: async ({ target, observer, ...request }) => {
41
+ if (request.interrupt === true && servingBodyId === target)
42
+ throw new AkumaSelfInterruptError(target);
38
43
  await prove([target]);
39
44
  return await executeAskAkuma({
40
45
  path: world,
@@ -90,9 +90,9 @@ declare const killServiceSchema: z.ZodObject<{
90
90
  killed: "killed";
91
91
  hung: "hung";
92
92
  unavailable: "unavailable";
93
+ untidy: "untidy";
93
94
  "already-killed": "already-killed";
94
95
  "already-stopped": "already-stopped";
95
- untidy: "untidy";
96
96
  }>;
97
97
  }, z.core.$strict>>>;
98
98
  }, z.core.$strict>;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { AkumaNotBornError, AkumaObservationError } from "./akuma-errors.js";
2
+ import { AkumaNotBornError, AkumaObservationError, AkumaSelfInterruptError } from "./akuma-errors.js";
3
3
  import { akumaIdSchema } from "./identity.js";
4
4
  import { requestBodyCommand } from "./request-rendezvous.js";
5
5
  import { eraseRequestCommand, } from "./request-wire.js";
@@ -80,6 +80,7 @@ const killServiceSchema = z
80
80
  const selectionRefusalSchema = z.union([
81
81
  z.object({ kind: z.literal("akuma-not-born"), id: akumaIdSchema }).strict(),
82
82
  z.object({ kind: z.literal("akuma-observation"), id: akumaIdSchema, diagnostic: z.string() }).strict(),
83
+ z.object({ kind: z.literal("akuma-self-interrupt"), id: akumaIdSchema }).strict(),
83
84
  ]);
84
85
  const selectionLiveFailureSchema = z.object({ kind: z.literal("refused"), failure: selectionRefusalSchema }).strict();
85
86
  export function encodeSelectionLiveFailure(error) {
@@ -87,7 +88,9 @@ export function encodeSelectionLiveFailure(error) {
87
88
  ? { kind: "akuma-not-born", id: error.id }
88
89
  : error instanceof AkumaObservationError
89
90
  ? { kind: "akuma-observation", id: error.id, diagnostic: error.diagnostic }
90
- : null;
91
+ : error instanceof AkumaSelfInterruptError
92
+ ? { kind: "akuma-self-interrupt", id: error.id }
93
+ : null;
91
94
  return failure === null ? null : { kind: "refused", failure };
92
95
  }
93
96
  export function decodeSelectionLiveFailure(value) {
@@ -97,7 +100,9 @@ export function decodeSelectionLiveFailure(value) {
97
100
  const failure = parsed.data.failure;
98
101
  return failure.kind === "akuma-not-born"
99
102
  ? new AkumaNotBornError(failure.id)
100
- : new AkumaObservationError(failure.id, failure.diagnostic);
103
+ : failure.kind === "akuma-self-interrupt"
104
+ ? new AkumaSelfInterruptError(failure.id)
105
+ : new AkumaObservationError(failure.id, failure.diagnostic);
101
106
  }
102
107
  function decodeSelectionRequest(action, value) {
103
108
  const schema = action === "akuma.wait"
@@ -1,6 +1,6 @@
1
1
  import { abortableDelay } from "./abort.js";
2
2
  /* eslint-disable max-lines-per-function -- Turn setup and consumption each preserve one ordered lifecycle transaction. */
3
- import { appendActivity, beginTurn, bindTellsToTurn, breakBody, drainPendingTells, heartExists, readHeart, recordCurrentModel, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
3
+ import { appendActivity, beginTurn, bindTellsToTurn, BodyControlledError, breakBody, drainPendingTells, heartExists, readHeart, recordCurrentModel, recordSession, recordTellDeliveries, recordTellReceipt, } from "./heart/index.js";
4
4
  import { withoutModel } from "./provider-recipe.js";
5
5
  import { encodeAgentEvent, } from "./provider.js";
6
6
  import { akumaCallRequestCommands } from "./call-request.js";
@@ -168,7 +168,6 @@ async function startTurnDrive(input) {
168
168
  return {
169
169
  turnSequence: turn.sequence,
170
170
  attempt,
171
- custodyFailure,
172
171
  drive: selected,
173
172
  requests,
174
173
  cwd,
@@ -252,9 +251,6 @@ function pumpReceipts(writers) {
252
251
  function observeFailure(settlement) {
253
252
  return settlement.then(() => new Promise(() => { }), (error) => Promise.reject(error));
254
253
  }
255
- function observeCompletionFailure(drive) {
256
- return drive.completion.then(() => new Promise(() => { }), (error) => ({ kind: "completion-failed", error }));
257
- }
258
254
  async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
259
255
  const { input, turnSequence, drive, writeWitness, mayWrite } = writers;
260
256
  for (const tell of pending) {
@@ -262,10 +258,10 @@ async function submitPendingLiveTells(writers, pending, attempted, tellLive) {
262
258
  continue;
263
259
  attempted.add(tell.id);
264
260
  const outcome = await writeWitness(async () => {
261
+ await bindTellsToTurn(input.paths, { turnSequence, tellIds: [tell.id], boundAt: input.now() });
265
262
  const submission = await tellLive({ id: tell.id, text: tell.body });
266
263
  if (!mayWrite() || submission.kind === "turn-ended")
267
264
  return "turn-ended";
268
- await bindTellsToTurn(input.paths, { turnSequence, tellIds: [tell.id], boundAt: input.now() });
269
265
  await recordTellDeliveries(input.paths, [
270
266
  {
271
267
  tellId: tell.id,
@@ -344,8 +340,14 @@ function createTurnWakeups(observeHeart) {
344
340
  failure: (source) => {
345
341
  void source.then(() => undefined, (error) => publish({ kind: "failed", error }));
346
342
  },
347
- completionFailed: (source) => {
348
- void source.then((wakeup) => publish(wakeup));
343
+ completion: (source) => {
344
+ void source.then((result) => publish({ kind: "completion", result }), (error) => publish({ kind: "failed", error }));
345
+ },
346
+ closure: (source) => {
347
+ void source.then(() => publish({ kind: "closed" }), (error) => publish({ kind: "failed", error }));
348
+ },
349
+ drained: (source) => {
350
+ void source.then(() => publish({ kind: "drained" }), (error) => publish({ kind: "failed", error }));
349
351
  },
350
352
  next: () => {
351
353
  const ready = queue.shift();
@@ -372,72 +374,101 @@ async function consumeTurnDrive(input, active) {
372
374
  const mayWrite = () => writesOpen && !input.supervisor.signal.aborted;
373
375
  const writers = { input, turnSequence, drive, writeWitness, mayWrite };
374
376
  const receiptFailure = observeFailure(pumpReceipts(writers));
375
- const completionFailure = observeCompletionFailure(drive);
376
377
  const iterator = drive.events[Symbol.asyncIterator]();
377
378
  const witness = { written: false, model: undefined };
378
379
  let liveTells = true;
379
380
  let tellPump = null;
381
+ let eventsEnded = false;
382
+ let result;
383
+ let attemptClosed = false;
384
+ let effectsDrained = false;
385
+ let drainArmed = false;
386
+ let drainingEffects;
380
387
  const wakeups = createTurnWakeups((after) => input.supervisor.next(after));
388
+ /**
389
+ * Consumes exactly one wake. A replaced Heart snapshot rearms its own observation, a settled Tell
390
+ * pump releases that source, and a provider event keeps its order: end, write, coordinate, next pull.
391
+ */
392
+ const reduceWakeup = async (next) => {
393
+ switch (next.kind) {
394
+ case "failed":
395
+ throw next.error;
396
+ case "heart":
397
+ heart = next.observation;
398
+ wakeups.heart(heart);
399
+ return;
400
+ case "tell":
401
+ tellPump = null;
402
+ liveTells = next.result === "live";
403
+ return;
404
+ case "completion":
405
+ result = next.result;
406
+ liveTells = false;
407
+ return;
408
+ case "closed":
409
+ attemptClosed = true;
410
+ return;
411
+ case "drained":
412
+ effectsDrained = true;
413
+ drainArmed = false;
414
+ return;
415
+ case "event":
416
+ break;
417
+ }
418
+ if (next.event.done) {
419
+ eventsEnded = true;
420
+ return;
421
+ }
422
+ await writeProviderEvent(input, active, next.event.value, witness);
423
+ if (next.event.value.type === "session")
424
+ turnSession = next.event.value.coordinate;
425
+ wakeups.event(iterator.next());
426
+ };
427
+ /** Completion waits for ended events, an outcome, a closed attempt, and no live Tell pump. */
428
+ const ready = () => eventsEnded && result !== undefined && attemptClosed && tellPump === null;
429
+ /** Retirement decides the ending: only a provider that could not retire replaces the requested one. */
430
+ const stopAndReturn = async (outcome) => {
431
+ const retirement = await stopActiveDrive(input, active);
432
+ return retirement.kind === "hung" ? retirement : outcome;
433
+ };
381
434
  wakeups.event(iterator.next());
382
435
  wakeups.heart(heart);
383
436
  wakeups.failure(receiptFailure);
384
437
  wakeups.failure(requests.failure);
385
- wakeups.failure(active.custodyFailure);
386
- wakeups.completionFailed(completionFailure);
438
+ wakeups.completion(drive.completion);
439
+ wakeups.closure(active.attempt.closed);
387
440
  try {
388
441
  for (;;) {
389
442
  if (input.supervisor.signal.aborted) {
390
443
  writesOpen = false;
391
- const retirement = await stopActiveDrive(input, active);
392
- return retirement.kind === "hung" ? retirement : { kind: "stopped" };
444
+ return await stopAndReturn({ kind: "stopped" });
393
445
  }
394
- if (hasUnattemptedTell(liveTells, tellPump, heart.pending, attempted)) {
446
+ if (result === undefined && hasUnattemptedTell(liveTells, tellPump, heart.pending, attempted)) {
395
447
  if (drive.tell === undefined) {
396
448
  writesOpen = false;
397
- const retirement = await stopActiveDrive(input, active);
398
- return retirement.kind === "hung" ? retirement : { kind: "handoff" };
449
+ return await stopAndReturn({ kind: "handoff" });
399
450
  }
400
451
  tellPump = submitPendingLiveTells(writers, heart.pending, attempted, drive.tell);
401
452
  wakeups.tell(tellPump);
402
453
  }
403
- const next = await wakeups.next();
404
- if (next.kind === "completion-failed") {
405
- requests.stopAdmission();
406
- throw next.error;
454
+ await reduceWakeup(await wakeups.next());
455
+ if (ready() && !drainArmed) {
456
+ drainingEffects ??= writeWitness.drain();
457
+ drainArmed = true;
458
+ wakeups.drained(drainingEffects);
407
459
  }
408
- if (next.kind === "failed")
409
- throw next.error;
410
- if (next.kind === "heart") {
411
- heart = next.observation;
412
- wakeups.heart(heart);
413
- continue;
414
- }
415
- if (next.kind === "tell") {
416
- tellPump = null;
417
- liveTells = next.result === "live";
418
- continue;
460
+ if (ready() && effectsDrained) {
461
+ writesOpen = false;
462
+ return await settleCompletion(result, turnSession, active);
419
463
  }
420
- if (next.event.done)
421
- break;
422
- await writeProviderEvent(input, active, next.event.value, witness);
423
- if (next.event.value.type === "session")
424
- turnSession = next.event.value.coordinate;
425
- wakeups.event(iterator.next());
426
464
  }
427
- const result = await drive.completion;
428
- await active.attempt.closed;
429
- if (tellPump !== null)
430
- await tellPump;
431
- await writeWitness.drain();
432
- writesOpen = false;
433
- return await settleCompletion(result, turnSession, active);
434
465
  }
435
466
  catch (error) {
436
467
  writesOpen = false;
437
- if (input.supervisor.signal.aborted) {
438
- const retirement = await stopActiveDrive(input, active);
439
- return retirement.kind === "hung" ? retirement : { kind: "stopped" };
440
- }
468
+ if (error instanceof BodyControlledError)
469
+ input.supervisor.cancel("control");
470
+ if (input.supervisor.signal.aborted)
471
+ return await stopAndReturn({ kind: "stopped" });
441
472
  const retirement = await retireProviderCustody(input, turnSequence, active.attempt);
442
473
  try {
443
474
  await requests.close();