@astrosheep/keiyaku 4.5.24 → 4.5.25

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 (42) hide show
  1. package/build/src/akuma/akuma-handle.d.ts +10 -0
  2. package/build/src/akuma/akuma-handle.js +18 -18
  3. package/build/src/akuma/akuma-instance.d.ts +5 -10
  4. package/build/src/akuma/akuma-instance.js +55 -40
  5. package/build/src/akuma/akuma-observe.d.ts +40 -7
  6. package/build/src/akuma/akuma-observe.js +51 -16
  7. package/build/src/akuma/akuma-product.d.ts +1 -2
  8. package/build/src/akuma/akuma-product.js +8 -5
  9. package/build/src/akuma/akuma.d.ts +2 -0
  10. package/build/src/akuma/body.d.ts +1 -1
  11. package/build/src/akuma/body.js +48 -30
  12. package/build/src/akuma/call-request.d.ts +0 -1
  13. package/build/src/akuma/call-request.js +1 -2
  14. package/build/src/akuma/fleet-execution.d.ts +3 -1
  15. package/build/src/akuma/fleet-execution.js +30 -71
  16. package/build/src/akuma/fleet-observation.d.ts +13 -2
  17. package/build/src/akuma/fleet-observation.js +2 -1
  18. package/build/src/akuma/fleet-request.js +3 -2
  19. package/build/src/akuma/heart/timeline.d.ts +1 -1
  20. package/build/src/akuma/heart/timeline.js +5 -5
  21. package/build/src/akuma/projection-read.js +32 -7
  22. package/build/src/akuma/projection.d.ts +1 -0
  23. package/build/src/akuma/projection.js +24 -9
  24. package/build/src/akuma/providers/pi/index.d.ts +2 -1
  25. package/build/src/akuma/providers/pi/index.js +2 -1
  26. package/build/src/akuma/publication.js +7 -4
  27. package/build/src/akuma-body.js +1 -0
  28. package/build/src/cli/commands/akuma-invoke.d.ts +1 -0
  29. package/build/src/cli/commands/akuma-invoke.js +16 -3
  30. package/build/src/cli/invoke.js +1 -0
  31. package/build/src/cli/render/akuma-activity.d.ts +13 -5
  32. package/build/src/cli/render/akuma-activity.js +105 -105
  33. package/build/src/library/address.d.ts +1 -1
  34. package/build/src/library/address.js +10 -8
  35. package/build/src/library/akuma-creation.d.ts +3 -0
  36. package/build/src/library/akuma-creation.js +111 -46
  37. package/build/src/library/composition.d.ts +3 -1
  38. package/build/src/library/fleet.d.ts +7 -1
  39. package/build/src/library/fleet.js +35 -9
  40. package/build/src/library/keiyaku.d.ts +3 -1
  41. package/build/src/runtime/proc/windows-launch.exe +0 -0
  42. package/package.json +1 -1
@@ -2,6 +2,7 @@ import { type TellResult, type TellWakeRuntime } from "./body.js";
2
2
  import { HeldAkumaLeash, type KillEvidence } from "./heart/index.js";
3
3
  import { type AkuId, type AkumaPaths } from "./identity.js";
4
4
  import { type ActivityHistory, type ExactHistory } from "./projection.js";
5
+ import { type WaitReason } from "./akuma-observe.js";
5
6
  import type { AkumaCallExecution, AkumaStatus, ForkReceipt, InterruptReceipt } from "./akuma.js";
6
7
  import type { WorldRoot } from "../world.js";
7
8
  declare const CALL_EXECUTION: unique symbol;
@@ -25,12 +26,21 @@ export declare class AkumaHandle {
25
26
  since?: number;
26
27
  limit?: number;
27
28
  }>): Promise<ActivityHistory | ExactHistory>;
29
+ waitReceipt(predicate?: (status: AkumaStatus) => boolean, options?: Readonly<{
30
+ timeoutMs?: number;
31
+ signal?: AbortSignal;
32
+ }>): Promise<Readonly<{
33
+ reason: WaitReason;
34
+ status: AkumaStatus;
35
+ }>>;
28
36
  wait(predicate?: (status: AkumaStatus) => boolean, options?: Readonly<{
29
37
  timeoutMs?: number;
38
+ signal?: AbortSignal;
30
39
  }>): Promise<AkumaStatus>;
31
40
  tell(body: string, tellId?: string, recordedAt?: string, runtime?: TellWakeRuntime, options?: Readonly<{
32
41
  schemaJson?: string;
33
42
  initiator?: string;
43
+ signal?: AbortSignal;
34
44
  }>): Promise<TellResult>;
35
45
  interrupt(body: string, options?: Readonly<{
36
46
  tellId?: string;
@@ -8,10 +8,8 @@ import { resolveProviderExecution } from "./providers/index.js";
8
8
  import { publishAkuma } from "./publication.js";
9
9
  import { spawnAkumaBody } from "./body.js";
10
10
  import { AkumaNotBornError } from "./akuma-errors.js";
11
- import { bornStatus, defaultWaitComplete, readWaitComplete } from "./akuma-observe.js";
11
+ import { bornStatus, defaultWaitComplete, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
12
12
  const CALL_EXECUTION = Symbol("akuma-call-execution");
13
- const POLL_MS = 100;
14
- const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
15
13
  function diagnostic(error) {
16
14
  return error instanceof Error ? error.message : String(error);
17
15
  }
@@ -134,24 +132,26 @@ export class AkumaHandle {
134
132
  limit,
135
133
  });
136
134
  }
137
- async wait(predicate = defaultWaitComplete, options = {}) {
135
+ async waitReceipt(predicate = defaultWaitComplete, options = {}) {
138
136
  if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) {
139
137
  throw new TypeError("Akuma wait timeoutMs must be a nonnegative finite millisecond duration");
140
138
  }
141
- const deadline = options.timeoutMs === undefined ? undefined : performance.now() + options.timeoutMs;
142
- for (;;) {
143
- if (predicate !== defaultWaitComplete ||
144
- (deadline !== undefined && performance.now() >= deadline) ||
145
- (await readWaitComplete(this.worldPath, this.id))) {
146
- const status = await this.status();
147
- if (predicate(status) || (deadline !== undefined && performance.now() >= deadline))
148
- return status;
149
- }
150
- await wait(deadline === undefined ? POLL_MS : Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
151
- }
139
+ const waited = await waitForObservation({
140
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
141
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
142
+ ...(predicate === defaultWaitComplete
143
+ ? { probe: async () => await readWaitComplete(this.worldPath, this.id) }
144
+ : {}),
145
+ observe: async () => await this.status(),
146
+ complete: predicate,
147
+ });
148
+ return { reason: waited.reason, status: waited.value };
149
+ }
150
+ async wait(predicate = defaultWaitComplete, options = {}) {
151
+ return (await this.waitReceipt(predicate, options)).status;
152
152
  }
153
153
  async tell(body, tellId = randomUUID(), recordedAt = new Date().toISOString(), runtime, options = {}) {
154
- const { schemaJson, initiator } = options;
154
+ const { schemaJson, initiator, signal } = options;
155
155
  const admitted = await recordTell(this.paths, {
156
156
  kind: "tell",
157
157
  id: tellId,
@@ -162,7 +162,7 @@ export class AkumaHandle {
162
162
  });
163
163
  if (admitted.kind === "not-born")
164
164
  throw new AkumaNotBornError(this.id);
165
- return await wakeRecordedTell(this.paths, admitted.tell.id, runtime);
165
+ return await wakeRecordedTell(this.paths, admitted.tell.id, runtime, signal);
166
166
  }
167
167
  async interrupt(body, options = {}) {
168
168
  const request = await requestPause(this.paths, new Date().toISOString(), options.signal);
@@ -212,7 +212,7 @@ export class AkumaHandle {
212
212
  return {
213
213
  kind: "interrupted",
214
214
  putDown,
215
- tell: await wakeRecordedTell(this.paths, recorded.tellId, options.runtime),
215
+ tell: await wakeRecordedTell(this.paths, recorded.tellId, options.runtime, options.signal),
216
216
  };
217
217
  }
218
218
  async fork(input) {
@@ -1,6 +1,7 @@
1
1
  import type { AllowedAction } from "./allowed.js";
2
2
  import type { AkumaStatus } from "./akuma.js";
3
3
  import type { InterruptReceipt, KillEvidence } from "./akuma.js";
4
+ import { type WaitReason } from "./akuma-observe.js";
4
5
  import { type AkuId } from "./identity.js";
5
6
  import { type ActivityHistory } from "./projection.js";
6
7
  import type { Settings } from "../settings.js";
@@ -8,18 +9,11 @@ import type { WorldRoot } from "../world.js";
8
9
  import { type Schema, type StandardSchemaV1 } from "./schema.js";
9
10
  export type AkumaIdleOptions = Readonly<{
10
11
  timeoutMs?: number;
12
+ signal?: AbortSignal;
11
13
  }>;
12
14
  export type AkumaIdleResult = Readonly<{
13
- kind: "idle";
14
- status: AkumaStatus;
15
- reason: Exclude<AkumaStatus["life"], "running">;
16
- }> | Readonly<{
17
- kind: "timeout";
15
+ reason: WaitReason;
18
16
  status: AkumaStatus;
19
- reason: Readonly<{
20
- running: boolean;
21
- pendingTell: boolean;
22
- }>;
23
17
  }>;
24
18
  export type AkumaHistoryOptions = Readonly<{
25
19
  before?: number;
@@ -51,8 +45,9 @@ export declare class Akuma {
51
45
  static select(root: WorldRoot, selector: string): Akuma;
52
46
  tell(text: string, options?: Readonly<{
53
47
  initiator?: string;
48
+ signal?: AbortSignal;
54
49
  }>): Promise<string>;
55
- tell<T>(text: string, options: AkumaTellOptions<T>): Promise<T>;
50
+ tell<T>(text: string, options: AkumaTellOptions<T> & AkumaSignalOptions): Promise<T>;
56
51
  status(): Promise<AkumaStatus>;
57
52
  interrupt(text: string, options?: AkumaSignalOptions & Readonly<{
58
53
  initiator?: string;
@@ -4,8 +4,7 @@ import { spawnAkumaBody } from "./body.js";
4
4
  import { decodeAllowedActions, unionAllowedActions } from "./allowed.js";
5
5
  import { AkumaDecodeError, AkumaProviderError } from "./akuma-errors.js";
6
6
  import { AkumaHandle } from "./akuma-handle.js";
7
- import { POLL_MS, defaultWaitComplete } from "./akuma.js";
8
- import { bornStatus } from "./akuma-observe.js";
7
+ import { bornStatus, defaultWaitComplete, waitForObservation } from "./akuma-observe.js";
9
8
  import { loadArchetype } from "./archetype.js";
10
9
  import { activitySlice, readTell, readTurn } from "./heart/index.js";
11
10
  import { parseAkuId, pathsForAkuId } from "./identity.js";
@@ -22,27 +21,29 @@ function signalOption(value) {
22
21
  throw new TypeError("signal must be an AbortSignal");
23
22
  return value;
24
23
  }
25
- function wait(milliseconds) {
26
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
27
- }
28
- function pendingTellOf(status) {
29
- return status.timeline.entries.some((entry) => entry.kind === "row" && entry.row.kind === "tell" && entry.row.state === "pending");
30
- }
31
- function idleResult(status) {
32
- const pendingTell = pendingTellOf(status);
33
- if (status.life !== "running" && !pendingTell)
34
- return { kind: "idle", status, reason: status.life };
35
- return { kind: "timeout", status, reason: { running: status.life === "running", pendingTell } };
36
- }
37
24
  function recordedTell(result) {
38
25
  if (result.wake.kind === "failed")
39
26
  throw new AkumaProviderError(result.wake.diagnostic);
40
27
  return { tellId: result.admission.tellId };
41
28
  }
42
- async function recordPlainTell(id, root, body, tellId, initiator) {
43
- const admitted = await new AkumaHandle(id, root).tell(body, tellId, undefined, undefined, initiator === undefined ? {} : { initiator });
29
+ async function recordPlainTell(input) {
30
+ const { id, root, body, tellId, initiator, signal } = input;
31
+ const admitted = await new AkumaHandle(id, root).tell(body, tellId, undefined, undefined, {
32
+ ...(initiator === undefined ? {} : { initiator }),
33
+ ...(signal === undefined ? {} : { signal }),
34
+ });
44
35
  return recordedTell(admitted);
45
36
  }
37
+ function plainTellInput(input) {
38
+ return {
39
+ id: input.id,
40
+ root: input.root,
41
+ body: input.body,
42
+ tellId: input.tellId,
43
+ ...(input.options?.initiator === undefined ? {} : { initiator: input.options.initiator }),
44
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
45
+ };
46
+ }
46
47
  async function recordSchemaTell(input) {
47
48
  const { id, body, tellId, schema, root } = input;
48
49
  if (input.interrupt === true) {
@@ -50,6 +51,7 @@ async function recordSchemaTell(input) {
50
51
  tellId,
51
52
  schemaJson: schemaJsonText(schema),
52
53
  ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
54
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
53
55
  });
54
56
  if (interrupted.kind === "unavailable") {
55
57
  throw new AkumaProviderError(`schema interrupt unavailable: ${interrupted.evidence}`);
@@ -59,6 +61,7 @@ async function recordSchemaTell(input) {
59
61
  const admitted = await new AkumaHandle(id, root).tell(body, tellId, undefined, undefined, {
60
62
  schemaJson: schemaJsonText(schema),
61
63
  ...(input.initiator === undefined ? {} : { initiator: input.initiator }),
64
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
62
65
  });
63
66
  return recordedTell(admitted);
64
67
  }
@@ -75,19 +78,21 @@ async function boundOutcome(paths, tell) {
75
78
  const turn = await readTurn(paths, tell.binding.turnSequence);
76
79
  return turn?.end?.outcome ?? null;
77
80
  }
78
- async function awaitTellOutcome(paths, tellId) {
79
- for (;;) {
80
- const tell = await readTell(paths, tellId);
81
- if (tell === null)
82
- throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
83
- const outcome = await boundOutcome(paths, tell);
84
- if (outcome !== null)
85
- return outcome;
86
- if (tell.state === "told" && tell.binding === undefined) {
87
- throw new AkumaProviderError(`recorded Tell ${tellId} reached a terminal delivery without a Turn binding`);
88
- }
89
- await wait(POLL_MS);
90
- }
81
+ async function awaitTellOutcome(paths, tellId, signal) {
82
+ const waited = await waitForObservation({
83
+ ...(signal === undefined ? {} : { signal }),
84
+ observe: async () => {
85
+ const tell = await readTell(paths, tellId);
86
+ if (tell === null)
87
+ throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
88
+ const outcome = await boundOutcome(paths, tell);
89
+ return { outcome, terminalWithoutTurn: tell.state === "told" && tell.binding === undefined };
90
+ },
91
+ complete: (observed) => observed.outcome !== null || observed.terminalWithoutTurn,
92
+ });
93
+ if (waited.value.outcome !== null)
94
+ return waited.value.outcome;
95
+ throw new AkumaProviderError(`recorded Tell ${tellId} reached a terminal delivery without a Turn binding`);
91
96
  }
92
97
  export class Akuma {
93
98
  id;
@@ -143,11 +148,20 @@ export class Akuma {
143
148
  async tell(text, options) {
144
149
  if (typeof text !== "string")
145
150
  throw new TypeError("Akuma tell text must be a string");
151
+ const signal = signalOption(options?.signal);
152
+ signal?.throwIfAborted();
146
153
  const tellId = randomUUID();
147
154
  const schemaOptions = options !== undefined && "schema" in options ? options : undefined;
148
155
  const schema = schemaOptions === undefined ? undefined : schemaFromStandard(schemaOptions.schema);
149
156
  const recorded = schemaOptions === undefined || schema === undefined
150
- ? await recordPlainTell(this.id, this.root, text, tellId, options?.initiator)
157
+ ? await recordPlainTell(plainTellInput({
158
+ id: this.id,
159
+ root: this.root,
160
+ body: text,
161
+ tellId,
162
+ options,
163
+ signal,
164
+ }))
151
165
  : await recordSchemaTell({
152
166
  id: this.id,
153
167
  body: text,
@@ -156,8 +170,9 @@ export class Akuma {
156
170
  root: this.root,
157
171
  ...(schemaOptions.interrupt === undefined ? {} : { interrupt: schemaOptions.interrupt }),
158
172
  ...(schemaOptions.initiator === undefined ? {} : { initiator: schemaOptions.initiator }),
173
+ ...(signal === undefined ? {} : { signal }),
159
174
  });
160
- const outcome = await awaitTellOutcome(this.paths, recorded.tellId);
175
+ const outcome = await awaitTellOutcome(this.paths, recorded.tellId, signal);
161
176
  if (outcome.kind !== "answered")
162
177
  outcomeError(outcome);
163
178
  if (schema === undefined)
@@ -198,20 +213,20 @@ export class Akuma {
198
213
  if (typeof options !== "object" || options === null || Array.isArray(options)) {
199
214
  throw new TypeError("Akuma idle options must be an object");
200
215
  }
201
- const unknown = Object.keys(options).find((key) => key !== "timeoutMs");
216
+ const unknown = Object.keys(options).find((key) => key !== "timeoutMs" && key !== "signal");
202
217
  if (unknown !== undefined)
203
218
  throw new TypeError(`Akuma idle options has unknown field: ${unknown}`);
204
219
  if (options.timeoutMs !== undefined && (!Number.isFinite(options.timeoutMs) || options.timeoutMs < 0)) {
205
220
  throw new TypeError("Akuma idle timeoutMs must be a nonnegative finite millisecond duration");
206
221
  }
207
- const deadline = options.timeoutMs === undefined ? undefined : performance.now() + options.timeoutMs;
208
- for (;;) {
209
- const observed = await bornStatus(this.paths, this.id, { aperture: "monitoring" });
210
- if (defaultWaitComplete(observed.status) || (deadline !== undefined && performance.now() >= deadline)) {
211
- return idleResult(observed.status);
212
- }
213
- await wait(deadline === undefined ? POLL_MS : Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
214
- }
222
+ const signal = signalOption(options.signal);
223
+ const waited = await waitForObservation({
224
+ ...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
225
+ ...(signal === undefined ? {} : { signal }),
226
+ observe: async () => (await bornStatus(this.paths, this.id, { aperture: "monitoring" })).status,
227
+ complete: defaultWaitComplete,
228
+ });
229
+ return { reason: waited.reason, status: waited.value };
215
230
  }
216
231
  async history(options = {}) {
217
232
  if (typeof options !== "object" || options === null || Array.isArray(options)) {
@@ -1,5 +1,5 @@
1
1
  import { type AkuId, type AkumaPaths } from "./identity.js";
2
- import { selectHistory, type ActivityHistory, type ActivitySnapshot } from "./projection.js";
2
+ import { selectHistory, type ActivityHistory, type ActivityRow, type ActivitySnapshot } from "./projection.js";
3
3
  import type { WorldRoot } from "../world.js";
4
4
  import type { AkumaListRow, AkumaStatus, UnbornAkumaListRow } from "./akuma.js";
5
5
  export declare function fleetListRow(paths: AkumaPaths, expected: AkuId): Promise<AkumaListRow | UnbornAkumaListRow>;
@@ -7,6 +7,14 @@ export type BudgetedStatusObservation = Readonly<{
7
7
  status: AkumaStatus;
8
8
  ordinarySelected: number;
9
9
  }>;
10
+ /**
11
+ * The internal live-observation companion for one status frontier. It is not
12
+ * part of status or any returned facade result: viewers receive it only while
13
+ * an observation loop is still streaming.
14
+ */
15
+ export type LiveStatusObservation = BudgetedStatusObservation & Readonly<{
16
+ rows: readonly ActivityRow[];
17
+ }>;
10
18
  export declare function bornStatus(paths: AkumaPaths, expected: AkuId, input: Readonly<{
11
19
  aperture: "monitoring" | "receipt";
12
20
  ordinaryBudget?: number;
@@ -17,18 +25,43 @@ export declare function readBudgetedStatus(worldPath: WorldRoot, id: AkuId, inpu
17
25
  ordinaryBudget?: number;
18
26
  admittedTellId?: string;
19
27
  }>): Promise<BudgetedStatusObservation>;
28
+ export declare function readLiveStatus(worldPath: WorldRoot, id: AkuId, input: Readonly<{
29
+ aperture: "monitoring" | "receipt";
30
+ ordinaryBudget?: number;
31
+ admittedTellId?: string;
32
+ }>): Promise<LiveStatusObservation>;
20
33
  export declare function defaultWaitComplete(status: AkumaStatus): boolean;
21
34
  export declare function readWaitComplete(worldPath: WorldRoot, id: AkuId): Promise<boolean>;
35
+ export type WaitReason = "completed" | "deadline";
36
+ /**
37
+ * The one deadline-aware observation loop for public Akuma waiting. It always
38
+ * reads once before judging a passed deadline, so a zero-duration wait remains
39
+ * an honest final snapshot and completion wins at the deadline edge.
40
+ */
41
+ export declare function waitForObservation<T>(input: Readonly<{
42
+ timeoutMs?: number;
43
+ signal?: AbortSignal;
44
+ probe?(): Promise<boolean>;
45
+ observe(): Promise<T>;
46
+ complete(value: T): boolean;
47
+ onObserve?(value: T): void | Promise<void>;
48
+ }>): Promise<Readonly<{
49
+ reason: WaitReason;
50
+ value: T;
51
+ }>>;
22
52
  /**
23
53
  * Successive status observations of one already born Akuma until its
24
- * observation window closes. Every status observed while the window is open is
25
- * reported to `observe`; the window's last status is returned. A window that is
26
- * already closed, or an Akuma already at its completion judgment, reports
27
- * nothing and returns the current status.
54
+ * observation window closes. Every acquired observation is reported to
55
+ * `observe` before completion or deadline judgment, including the first
56
+ * already-complete observation; the last status is returned.
28
57
  */
29
58
  export declare function observeAkumaStatus(worldPath: WorldRoot, expected: AkuId, input: Readonly<{
30
59
  timeoutMs: number;
31
- observe: (status: AkumaStatus) => void;
32
- }>): Promise<AkumaStatus>;
60
+ signal?: AbortSignal;
61
+ observe: (status: LiveStatusObservation) => void;
62
+ }>): Promise<Readonly<{
63
+ reason: WaitReason;
64
+ status: AkumaStatus;
65
+ }>>;
33
66
  export declare function readAkumaBirthCwd(worldPath: WorldRoot, id: AkuId): Promise<string>;
34
67
  export { selectHistory, type ActivityHistory, type ActivitySnapshot };
@@ -2,6 +2,7 @@ import { readStatusFacts, readLifeSnapshot, HeldAkumaLeash, isHeartAbsent, life,
2
2
  import { pathsForAkuId } from "./identity.js";
3
3
  import { ordinarySnapshotBudget, projectTurns, selectHistory, selectSnapshot, } from "./projection.js";
4
4
  import { resolveProviderExecution } from "./providers/index.js";
5
+ import { abortableDelay } from "./abort.js";
5
6
  import { AkumaNotBornError } from "./akuma-errors.js";
6
7
  export async function fleetListRow(paths, expected) {
7
8
  const snapshot = await readHeart(paths);
@@ -55,7 +56,7 @@ async function bornObservation(paths, expected, read, snapshot) {
55
56
  claim?.release();
56
57
  }
57
58
  }
58
- export async function bornStatus(paths, expected, input) {
59
+ async function bornLiveStatus(paths, expected, input) {
59
60
  if (input.ordinaryBudget !== undefined && (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0))
60
61
  throw new TypeError("ordinary budget must be a nonnegative safe integer");
61
62
  const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths));
@@ -63,7 +64,8 @@ export async function bornStatus(paths, expected, input) {
63
64
  snapshot.latestSession?.provider === soul.provider.name &&
64
65
  (await resolveProviderExecution(soul.provider)).adapter.resume === undefined;
65
66
  const facts = await readStatusFacts(paths, input);
66
- const selected = selectSnapshot(projectTurns(facts), {
67
+ const ledger = projectTurns(facts);
68
+ const selected = selectSnapshot(ledger, {
67
69
  aperture: input.aperture,
68
70
  budget: ordinarySnapshotBudget(input.ordinaryBudget),
69
71
  ...(input.admittedTellId === undefined ? {} : { admittedTellId: input.admittedTellId }),
@@ -78,11 +80,19 @@ export async function bornStatus(paths, expected, input) {
78
80
  timeline: selected.snapshot,
79
81
  },
80
82
  ordinarySelected: selected.ordinaryCount,
83
+ rows: ledger.rows,
81
84
  };
82
85
  }
86
+ export async function bornStatus(paths, expected, input) {
87
+ const { rows: _rows, ...status } = await bornLiveStatus(paths, expected, input);
88
+ return status;
89
+ }
83
90
  export async function readBudgetedStatus(worldPath, id, input) {
84
91
  return await bornStatus(pathsForAkuId(worldPath, id), id, input);
85
92
  }
93
+ export async function readLiveStatus(worldPath, id, input) {
94
+ return await bornLiveStatus(pathsForAkuId(worldPath, id), id, input);
95
+ }
86
96
  function complete(life, pending) {
87
97
  return life !== "running" && !pending;
88
98
  }
@@ -95,26 +105,51 @@ export async function readWaitComplete(worldPath, id) {
95
105
  return complete(observed.currentLife, observed.snapshot.hasPendingTell);
96
106
  }
97
107
  const OBSERVATION_POLL_MS = 100;
98
- function observeDelay(milliseconds) {
99
- return new Promise((resolve) => setTimeout(resolve, milliseconds));
108
+ /**
109
+ * The one deadline-aware observation loop for public Akuma waiting. It always
110
+ * reads once before judging a passed deadline, so a zero-duration wait remains
111
+ * an honest final snapshot and completion wins at the deadline edge.
112
+ */
113
+ export async function waitForObservation(input) {
114
+ const deadline = input.timeoutMs === undefined ? undefined : performance.now() + input.timeoutMs;
115
+ for (;;) {
116
+ input.signal?.throwIfAborted();
117
+ const ready = input.probe === undefined || (await input.probe());
118
+ input.signal?.throwIfAborted();
119
+ if (!ready && (deadline === undefined || performance.now() < deadline)) {
120
+ await abortableDelay(deadline === undefined
121
+ ? OBSERVATION_POLL_MS
122
+ : Math.min(OBSERVATION_POLL_MS, Math.max(0, deadline - performance.now())), input.signal);
123
+ continue;
124
+ }
125
+ const value = await input.observe();
126
+ input.signal?.throwIfAborted();
127
+ await input.onObserve?.(value);
128
+ if (input.complete(value))
129
+ return { reason: "completed", value };
130
+ if (deadline !== undefined && performance.now() >= deadline)
131
+ return { reason: "deadline", value };
132
+ await abortableDelay(deadline === undefined
133
+ ? OBSERVATION_POLL_MS
134
+ : Math.min(OBSERVATION_POLL_MS, Math.max(0, deadline - performance.now())), input.signal);
135
+ }
100
136
  }
101
137
  /**
102
138
  * Successive status observations of one already born Akuma until its
103
- * observation window closes. Every status observed while the window is open is
104
- * reported to `observe`; the window's last status is returned. A window that is
105
- * already closed, or an Akuma already at its completion judgment, reports
106
- * nothing and returns the current status.
139
+ * observation window closes. Every acquired observation is reported to
140
+ * `observe` before completion or deadline judgment, including the first
141
+ * already-complete observation; the last status is returned.
107
142
  */
108
143
  export async function observeAkumaStatus(worldPath, expected, input) {
109
144
  const paths = pathsForAkuId(worldPath, expected);
110
- const deadline = performance.now() + input.timeoutMs;
111
- for (;;) {
112
- const status = (await bornStatus(paths, expected, { aperture: "monitoring" })).status;
113
- if (defaultWaitComplete(status) || performance.now() >= deadline)
114
- return status;
115
- input.observe(status);
116
- await observeDelay(Math.min(OBSERVATION_POLL_MS, Math.max(0, deadline - performance.now())));
117
- }
145
+ const waited = await waitForObservation({
146
+ timeoutMs: input.timeoutMs,
147
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
148
+ observe: async () => await bornLiveStatus(paths, expected, { aperture: "monitoring" }),
149
+ complete: (observation) => defaultWaitComplete(observation.status),
150
+ onObserve: input.observe,
151
+ });
152
+ return { reason: waited.reason, status: waited.value.status };
118
153
  }
119
154
  export async function readAkumaBirthCwd(worldPath, id) {
120
155
  const soul = await readSoul(pathsForAkuId(worldPath, id));
@@ -23,7 +23,6 @@ export type BornAkumaCall = Readonly<{
23
23
  initialBody?: string;
24
24
  initiator?: string;
25
25
  initialSchemaJson?: string;
26
- awaitAsleep?: true;
27
26
  execution: BornExecution;
28
27
  }>;
29
28
  export type RequestedAkumaCall = Readonly<{
@@ -51,7 +50,7 @@ declare class AkumaProduct {
51
50
  admit(input: AkumaCallLaunchInput, context: AkumaCallContext): Promise<AkumaBornCall>;
52
51
  publish(born: AkumaBornCall, completion?: Readonly<{
53
52
  contractId?: string;
54
- }>): Promise<AkumaHandle>;
53
+ }>, signal?: AbortSignal): Promise<AkumaHandle>;
55
54
  [CALL_WITH_CONTEXT](input: AkumaCallLaunchInput, context: AkumaCallContext): Promise<AkumaHandle>;
56
55
  listComplete(input?: Readonly<{
57
56
  archetype?: string;
@@ -27,9 +27,9 @@ async function admitBodyRequest(input) {
27
27
  archetype: input.name,
28
28
  ...(input.call.body === undefined ? {} : { body: input.call.body }),
29
29
  ...(input.call.initiator === undefined ? {} : { initiator: input.call.initiator }),
30
- ...(input.call.schema === undefined ? {} : { awaitAsleep: true }),
31
30
  ...(cwd === undefined ? {} : { cwd }),
32
31
  recipe: input.recipe,
32
+ ...(input.call.signal === undefined ? {} : { signal: input.call.signal }),
33
33
  });
34
34
  const bornCwd = await readAkumaBirthCwd(input.path, child);
35
35
  return {
@@ -45,7 +45,11 @@ async function admitDirect(input) {
45
45
  const cwd = input.call.cwd !== undefined && input.context.cwdCanonical === true
46
46
  ? input.call.cwd
47
47
  : await canonicalBirthCwd(selectedCwd);
48
- const allocated = await birthAkuma({ worldPath: input.path, archetype: input.archetype.name });
48
+ const allocated = await birthAkuma({
49
+ worldPath: input.path,
50
+ archetype: input.archetype.name,
51
+ ...(input.call.signal === undefined ? {} : { signal: input.call.signal }),
52
+ });
49
53
  return {
50
54
  kind: "born",
51
55
  allocated,
@@ -59,7 +63,6 @@ async function admitDirect(input) {
59
63
  ...(input.call.body === undefined ? {} : { initialBody: input.call.body }),
60
64
  ...(input.call.initiator === undefined ? {} : { initiator: input.call.initiator }),
61
65
  ...(input.call.schema === undefined ? {} : { initialSchemaJson: schemaJsonText(input.call.schema) }),
62
- ...(input.call.schema === undefined ? {} : { awaitAsleep: true }),
63
66
  execution: {
64
67
  cwd,
65
68
  source: input.call.cwd !== undefined ? "input" : initiatorCwd === undefined ? "world" : "process",
@@ -204,13 +207,13 @@ class AkumaProduct {
204
207
  return await admitBodyRequest({ call: input, context, path: this.path, name, recipe: requestRecipe, execution });
205
208
  return await admitDirect({ call: input, context, path: this.path, archetype, recipe: requestRecipe });
206
209
  }
207
- async publish(born, completion = {}) {
210
+ async publish(born, completion = {}, signal) {
208
211
  if (born.kind === "requested") {
209
212
  return new AkumaHandle(born.id, this.path, { cwd: born.cwd, source: born.execution.source });
210
213
  }
211
214
  const published = await launchAkuma({
212
215
  allocated: born.allocated,
213
- ...(born.awaitAsleep === undefined ? {} : { awaitAsleep: born.awaitAsleep }),
216
+ ...(signal === undefined ? {} : { signal }),
214
217
  launch: async (allocated) => await spawnAkumaBody({
215
218
  paths: allocated.paths,
216
219
  seed: born.seed,
@@ -267,6 +267,7 @@ export declare const akumaStatusSchema: z.ZodObject<{
267
267
  }, z.core.$strict>]>;
268
268
  }, z.core.$strict>]>>>;
269
269
  omitted: z.ZodNumber;
270
+ openingSequence: z.ZodOptional<z.ZodNumber>;
270
271
  }, z.core.$strict>, z.ZodObject<{
271
272
  reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
272
273
  sequence: z.ZodNumber;
@@ -459,6 +460,7 @@ export type AkumaCallInput = Readonly<{
459
460
  allowed?: readonly AllowedAction[];
460
461
  schema?: Schema<unknown>;
461
462
  initiator?: string;
463
+ signal?: AbortSignal;
462
464
  }>;
463
465
  export type AkumaCallContext = Readonly<{
464
466
  initiatorCwd?: string;
@@ -85,4 +85,4 @@ export declare function handoffPendingTells(paths: AkumaPaths, spawn?: (launch:
85
85
  export declare function driveAkumaBody(launch: BodyLaunch, adapter?: ProviderAdapter, runtimeInput?: Partial<BodyRuntime>): Promise<"held" | void>;
86
86
  export declare function spawnAkumaBody(launch: BodyLaunch, runtime?: BodyLaunchRuntime): Promise<OwnedProcess>;
87
87
  export declare function runAkumaBody(launch: BodyLaunch, world: WorldRoot, externalCommands: Readonly<Record<string, ErasedRequestCommand>>): Promise<"held" | void>;
88
- export declare function wakeRecordedTell(paths: AkumaPaths, tellId: string, runtime?: TellWakeRuntime): Promise<TellResult>;
88
+ export declare function wakeRecordedTell(paths: AkumaPaths, tellId: string, runtime?: TellWakeRuntime, signal?: AbortSignal): Promise<TellResult>;