@astrosheep/keiyaku 4.5.24 → 4.5.26
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.
- package/build/src/akuma/akuma-handle.d.ts +10 -0
- package/build/src/akuma/akuma-handle.js +18 -18
- package/build/src/akuma/akuma-instance.d.ts +5 -10
- package/build/src/akuma/akuma-instance.js +55 -40
- package/build/src/akuma/akuma-observe.d.ts +40 -7
- package/build/src/akuma/akuma-observe.js +51 -16
- package/build/src/akuma/akuma-product.d.ts +1 -2
- package/build/src/akuma/akuma-product.js +8 -5
- package/build/src/akuma/akuma.d.ts +2 -0
- package/build/src/akuma/body.d.ts +1 -1
- package/build/src/akuma/body.js +48 -30
- package/build/src/akuma/call-request.d.ts +0 -1
- package/build/src/akuma/call-request.js +1 -2
- package/build/src/akuma/fleet-execution.d.ts +3 -1
- package/build/src/akuma/fleet-execution.js +30 -71
- package/build/src/akuma/fleet-observation.d.ts +13 -2
- package/build/src/akuma/fleet-observation.js +2 -1
- package/build/src/akuma/fleet-request.js +3 -2
- package/build/src/akuma/heart/timeline.d.ts +1 -1
- package/build/src/akuma/heart/timeline.js +5 -5
- package/build/src/akuma/projection-read.js +37 -7
- package/build/src/akuma/projection.d.ts +1 -0
- package/build/src/akuma/projection.js +24 -9
- package/build/src/akuma/providers/pi/index.d.ts +2 -1
- package/build/src/akuma/providers/pi/index.js +2 -1
- package/build/src/akuma/publication.js +7 -4
- package/build/src/akuma-body.js +1 -0
- package/build/src/cli/commands/akuma-invoke.d.ts +1 -0
- package/build/src/cli/commands/akuma-invoke.js +16 -3
- package/build/src/cli/invoke.js +1 -0
- package/build/src/cli/render/akuma-activity.d.ts +13 -5
- package/build/src/cli/render/akuma-activity.js +118 -112
- package/build/src/cli/render/akuma-tool.js +5 -3
- package/build/src/library/address.d.ts +1 -1
- package/build/src/library/address.js +10 -8
- package/build/src/library/akuma-creation.d.ts +3 -0
- package/build/src/library/akuma-creation.js +111 -46
- package/build/src/library/composition.d.ts +3 -1
- package/build/src/library/fleet.d.ts +7 -1
- package/build/src/library/fleet.js +35 -9
- package/build/src/library/keiyaku.d.ts +3 -1
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +3 -3
package/build/src/akuma/body.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { appendFile, stat } from "node:fs/promises";
|
|
2
2
|
import { basename, delimiter, join } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
-
import { abortableDelay } from "./abort.js";
|
|
4
|
+
import { abortable, abortableDelay } from "./abort.js";
|
|
5
5
|
import { BodySupervisor } from "./body-supervisor.js";
|
|
6
6
|
import { driveTurn, turnRecipe } from "./turn-drive.js";
|
|
7
7
|
import { HeldAkumaLeash, breakBody, decidePendingTellDisposition, drainPendingTells, endTurn, failOpenBoundTurns, finishBodyIfIdle, heartExists, isHeartAbsent, probeLeash, projectTell, readHeart, readOpenBoundTurns, readOpenPendingTellDisposition, readTell, readTurn, readNonterminalRequests, resolvePendingTellDisposition, } from "./heart/index.js";
|
|
@@ -587,50 +587,68 @@ function failedChild(exit) {
|
|
|
587
587
|
child: { code: exit.code, signal: exit.signal, log: exit.log },
|
|
588
588
|
};
|
|
589
589
|
}
|
|
590
|
-
async function awaitWake(paths,
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
590
|
+
async function awaitWake(paths, input) {
|
|
591
|
+
const { tellId, after, child, schedule, signal } = input;
|
|
592
|
+
try {
|
|
593
|
+
for (;;) {
|
|
594
|
+
signal?.throwIfAborted();
|
|
595
|
+
const settled = await settledWake(paths, tellId, after);
|
|
596
|
+
if (settled !== null) {
|
|
597
|
+
child.release();
|
|
598
|
+
return settled;
|
|
599
|
+
}
|
|
600
|
+
const timerController = new AbortController();
|
|
601
|
+
const timer = schedule(WAKE_REREAD_MS, timerController.signal).then(() => ({ kind: "timer" }));
|
|
602
|
+
let winner;
|
|
603
|
+
try {
|
|
604
|
+
const waited = Promise.race([child.exited.then((exit) => ({ kind: "exited", exit })), timer]);
|
|
605
|
+
winner = signal === undefined ? await waited : await abortable(waited, signal);
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
timerController.abort();
|
|
609
|
+
await timer.catch(() => undefined);
|
|
610
|
+
throw error;
|
|
611
|
+
}
|
|
612
|
+
if (winner.kind === "timer")
|
|
613
|
+
continue;
|
|
604
614
|
timerController.abort();
|
|
605
615
|
await timer.catch(() => undefined);
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
const final = await settledWake(paths, tellId, after);
|
|
613
|
-
if (final !== null) {
|
|
614
|
-
child.release();
|
|
615
|
-
return final;
|
|
616
|
+
const final = await settledWake(paths, tellId, after);
|
|
617
|
+
if (final !== null) {
|
|
618
|
+
child.release();
|
|
619
|
+
return final;
|
|
620
|
+
}
|
|
621
|
+
return winner.exit.code === LEASH_HELD_EXIT ? { kind: "held" } : failedChild(winner.exit);
|
|
616
622
|
}
|
|
617
|
-
|
|
623
|
+
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
child.release();
|
|
626
|
+
throw error;
|
|
618
627
|
}
|
|
619
628
|
}
|
|
620
|
-
async function wakePendingTells(paths, tellId, runtime) {
|
|
629
|
+
async function wakePendingTells(paths, tellId, runtime, signal) {
|
|
621
630
|
try {
|
|
631
|
+
signal?.throwIfAborted();
|
|
622
632
|
const beforeHeart = await readHeart(paths);
|
|
623
633
|
if (tellId === undefined && beforeHeart.pending.length === 0)
|
|
624
634
|
return null;
|
|
625
635
|
const before = beforeHeart.latestBody?.sequence ?? 0;
|
|
626
|
-
return await awaitWake(paths,
|
|
636
|
+
return await awaitWake(paths, {
|
|
637
|
+
...(tellId === undefined ? {} : { tellId }),
|
|
638
|
+
after: before,
|
|
639
|
+
child: await runtime.spawn(paths),
|
|
640
|
+
schedule: runtime.schedule ?? abortableDelay,
|
|
641
|
+
...(signal === undefined ? {} : { signal }),
|
|
642
|
+
});
|
|
627
643
|
}
|
|
628
644
|
catch (error) {
|
|
645
|
+
if (signal?.aborted)
|
|
646
|
+
throw error;
|
|
629
647
|
return { kind: "failed", diagnostic: diagnostic(error) };
|
|
630
648
|
}
|
|
631
649
|
}
|
|
632
|
-
export async function wakeRecordedTell(paths, tellId, runtime = DIRECT_TELL_WAKE) {
|
|
633
|
-
const wake = (await wakePendingTells(paths, tellId, runtime));
|
|
650
|
+
export async function wakeRecordedTell(paths, tellId, runtime = DIRECT_TELL_WAKE, signal) {
|
|
651
|
+
const wake = (await wakePendingTells(paths, tellId, runtime, signal));
|
|
634
652
|
const tell = await readTell(paths, tellId);
|
|
635
653
|
if (tell === null)
|
|
636
654
|
throw new Error(`recorded Tell ${tellId} is missing from Heart`);
|
|
@@ -30,7 +30,6 @@ declare const akumaCallPayloadSchema: z.ZodObject<{
|
|
|
30
30
|
archetype: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
|
|
31
31
|
body: z.ZodOptional<z.ZodString>;
|
|
32
32
|
initiator: z.ZodOptional<z.ZodString>;
|
|
33
|
-
awaitAsleep: z.ZodOptional<z.ZodLiteral<true>>;
|
|
34
33
|
cwd: z.ZodOptional<z.ZodString>;
|
|
35
34
|
recipe: z.ZodObject<{
|
|
36
35
|
description: z.ZodOptional<z.ZodString>;
|
|
@@ -68,7 +68,6 @@ const akumaCallPayloadSchema = z
|
|
|
68
68
|
archetype: archetypeSchema,
|
|
69
69
|
body: z.string().optional(),
|
|
70
70
|
initiator: z.string().min(1).optional(),
|
|
71
|
-
awaitAsleep: z.literal(true).optional(),
|
|
72
71
|
cwd: absolutePathSchema.optional(),
|
|
73
72
|
recipe: akumaCallRecipeSchema,
|
|
74
73
|
})
|
|
@@ -105,7 +104,6 @@ async function executeAkumaCall(request, facts, capabilities) {
|
|
|
105
104
|
worldPath: world,
|
|
106
105
|
archetype: request.archetype,
|
|
107
106
|
signal: facts.signal,
|
|
108
|
-
...(request.awaitAsleep === undefined ? {} : { awaitAsleep: request.awaitAsleep }),
|
|
109
107
|
launch: async (allocated) => {
|
|
110
108
|
if (!facts.admissionOpen())
|
|
111
109
|
throw new Error("body closed request admission");
|
|
@@ -129,6 +127,7 @@ async function executeAkumaCall(request, facts, capabilities) {
|
|
|
129
127
|
export function akumaCallRequestProtocol() {
|
|
130
128
|
return {
|
|
131
129
|
action: "akuma.call",
|
|
130
|
+
supportsCancellation: true,
|
|
132
131
|
encodeRequest: callPayload,
|
|
133
132
|
decodeRequest: decodeAkumaCallRequest,
|
|
134
133
|
encodeResult: (result) => result,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type AkumaStatus } from "./akuma.js";
|
|
2
|
+
import type { ActivityRow } from "./projection.js";
|
|
2
3
|
import { type DispatchAssociation } from "./dispatch-association.js";
|
|
3
4
|
import type { AkumaAlias } from "../identity/selector.js";
|
|
4
5
|
import type { WorldRoot } from "../world.js";
|
|
@@ -12,6 +13,7 @@ export type WaitIdentityFacts = Readonly<{
|
|
|
12
13
|
/** One observed Akuma as a live wait viewer sees it: its status plus its identity facts. */
|
|
13
14
|
export type WaitObservedAkuma = Readonly<{
|
|
14
15
|
status: AkumaStatus;
|
|
16
|
+
rows: readonly ActivityRow[];
|
|
15
17
|
}> & WaitIdentityFacts;
|
|
16
18
|
/** One selected Akuma's frozen identity, resolved before the first observation round. */
|
|
17
19
|
export type WaitSelectedAkuma = Readonly<{
|
|
@@ -34,7 +36,7 @@ export type WaitExecutionInput = Readonly<{
|
|
|
34
36
|
selectionOrder?: readonly AkumaStatus["id"][];
|
|
35
37
|
/** Reports the frozen selected set before the first round, so a viewer can fix its layout. */
|
|
36
38
|
onSelected?: (selected: readonly WaitSelectedAkuma[]) => void;
|
|
37
|
-
/** Reports every observation round to a live viewer
|
|
39
|
+
/** Reports every observation round to a live viewer. */
|
|
38
40
|
observe?: (observed: readonly WaitObservedAkuma[]) => void;
|
|
39
41
|
}>;
|
|
40
42
|
export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<AkumaWaitResult>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AkumaNotBornError, defaultWaitComplete } from "./akuma.js";
|
|
2
2
|
import { createAkumaProduct } from "./akuma-product.js";
|
|
3
|
-
import {
|
|
3
|
+
import { readLiveStatus, waitForObservation } from "./akuma-observe.js";
|
|
4
4
|
import { NO_DISPATCH_ASSOCIATION } from "./dispatch-association.js";
|
|
5
5
|
import { EMPTY_CREATED_TASK_OBSERVATION } from "../task/created-observation.js";
|
|
6
6
|
import { fleetResultSchemas, parseAkumaObservation, } from "./fleet-observation.js";
|
|
@@ -11,7 +11,6 @@ function observationDiagnostic(error) {
|
|
|
11
11
|
return error instanceof Error ? error.message : String(error);
|
|
12
12
|
}
|
|
13
13
|
const SHARED_ORDINARY_BUDGET = 30;
|
|
14
|
-
const POLL_MS = 100;
|
|
15
14
|
function akumaOnlyObservation(status) {
|
|
16
15
|
return parseAkumaObservation({
|
|
17
16
|
status,
|
|
@@ -22,19 +21,17 @@ function akumaOnlyObservation(status) {
|
|
|
22
21
|
async function observeWaitRound(path, ids, signal) {
|
|
23
22
|
signal?.throwIfAborted();
|
|
24
23
|
if (ids.length <= 1) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
unobserved: [],
|
|
28
|
-
};
|
|
24
|
+
const observations = await Promise.all(ids.map(async (id) => await readLiveStatus(path, id, { aperture: "monitoring" })));
|
|
25
|
+
return { observations, unobserved: [] };
|
|
29
26
|
}
|
|
30
27
|
let remaining = SHARED_ORDINARY_BUDGET;
|
|
31
|
-
const
|
|
28
|
+
const observations = [];
|
|
32
29
|
const unobserved = [];
|
|
33
30
|
for (const id of ids) {
|
|
34
31
|
signal?.throwIfAborted();
|
|
35
32
|
try {
|
|
36
|
-
const observed = await
|
|
37
|
-
|
|
33
|
+
const observed = await readLiveStatus(path, id, { aperture: "monitoring", ordinaryBudget: remaining });
|
|
34
|
+
observations.push(observed);
|
|
38
35
|
remaining -= observed.ordinarySelected;
|
|
39
36
|
}
|
|
40
37
|
catch (error) {
|
|
@@ -43,50 +40,13 @@ async function observeWaitRound(path, ids, signal) {
|
|
|
43
40
|
unobserved.push({ id, diagnostic: observationDiagnostic(error) });
|
|
44
41
|
}
|
|
45
42
|
}
|
|
46
|
-
return {
|
|
47
|
-
}
|
|
48
|
-
async function probeWaitRound(input) {
|
|
49
|
-
let observed = 0;
|
|
50
|
-
let complete = 0;
|
|
51
|
-
for (const id of input.ids) {
|
|
52
|
-
input.signal?.throwIfAborted();
|
|
53
|
-
try {
|
|
54
|
-
if (await readWaitComplete(input.path, id))
|
|
55
|
-
complete += 1;
|
|
56
|
-
observed += 1;
|
|
57
|
-
}
|
|
58
|
-
catch (error) {
|
|
59
|
-
if (input.ids.length <= 1 || error instanceof AkumaNotBornError)
|
|
60
|
-
throw error;
|
|
61
|
-
// Plural wait retries unreadable members; final rendering owns diagnostics.
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return observed > 0 && (input.completion === "any" ? complete > 0 : complete === input.ids.length);
|
|
43
|
+
return { observations, unobserved };
|
|
65
44
|
}
|
|
66
45
|
function roundComplete(round, completion) {
|
|
67
|
-
const settled = round.
|
|
46
|
+
const settled = round.observations.map((observation) => defaultWaitComplete(observation.status));
|
|
68
47
|
return (settled.length > 0 &&
|
|
69
48
|
(completion === "any" ? settled.some(Boolean) : round.unobserved.length === 0 && settled.every(Boolean)));
|
|
70
49
|
}
|
|
71
|
-
function delay(milliseconds, signal) {
|
|
72
|
-
return new Promise((resolve, reject) => {
|
|
73
|
-
let timer;
|
|
74
|
-
const done = () => {
|
|
75
|
-
signal?.removeEventListener("abort", abort);
|
|
76
|
-
resolve();
|
|
77
|
-
};
|
|
78
|
-
const abort = () => {
|
|
79
|
-
clearTimeout(timer);
|
|
80
|
-
signal?.removeEventListener("abort", abort);
|
|
81
|
-
reject(signal?.reason ?? new Error("upstream request aborted"));
|
|
82
|
-
};
|
|
83
|
-
timer = setTimeout(done, milliseconds);
|
|
84
|
-
if (signal?.aborted)
|
|
85
|
-
abort();
|
|
86
|
-
else
|
|
87
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
50
|
/** Canonical ids in the caller's selection order, appending any id the caller never named. */
|
|
91
51
|
function selectionOrderedIds(ids, order) {
|
|
92
52
|
const present = new Set(ids);
|
|
@@ -107,7 +67,6 @@ function selectionOrderedIds(ids, order) {
|
|
|
107
67
|
return ordered;
|
|
108
68
|
}
|
|
109
69
|
export async function executeWaitAkuma(input) {
|
|
110
|
-
const deadline = input.timeoutMs === undefined ? undefined : performance.now() + input.timeoutMs;
|
|
111
70
|
// Identity facts are read once per observed Akuma, not once per 100ms round.
|
|
112
71
|
const facts = new Map();
|
|
113
72
|
if (input.onSelected !== undefined) {
|
|
@@ -119,47 +78,47 @@ export async function executeWaitAkuma(input) {
|
|
|
119
78
|
const ordered = input.selectionOrder === undefined ? input.ids : selectionOrderedIds(input.ids, input.selectionOrder);
|
|
120
79
|
input.onSelected(ordered.map((id) => ({ id, ...facts.get(id) })));
|
|
121
80
|
}
|
|
122
|
-
const observeRound = async (
|
|
81
|
+
const observeRound = async (round) => {
|
|
123
82
|
if (input.observe === undefined)
|
|
124
83
|
return;
|
|
125
84
|
const observed = [];
|
|
126
|
-
for (const
|
|
85
|
+
for (const observation of round.observations) {
|
|
127
86
|
input.signal?.throwIfAborted();
|
|
87
|
+
const { status, rows } = observation;
|
|
128
88
|
let known = facts.get(status.id);
|
|
129
89
|
if (known === undefined && input.identity !== undefined) {
|
|
130
90
|
known = await input.identity(status.id);
|
|
131
91
|
facts.set(status.id, known);
|
|
132
92
|
}
|
|
133
93
|
if (known === undefined) {
|
|
134
|
-
observed.push({ status, contract: NO_DISPATCH_ASSOCIATION });
|
|
94
|
+
observed.push({ status, rows, contract: NO_DISPATCH_ASSOCIATION });
|
|
135
95
|
continue;
|
|
136
96
|
}
|
|
137
|
-
observed.push({ status, ...known });
|
|
97
|
+
observed.push({ status, rows, ...known });
|
|
138
98
|
}
|
|
139
99
|
input.observe(observed);
|
|
140
100
|
};
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
await delay(deadline === undefined ? POLL_MS : Math.min(POLL_MS, Math.max(0, deadline - performance.now())), input.signal);
|
|
157
|
-
}
|
|
101
|
+
const waited = await waitForObservation({
|
|
102
|
+
...(input.timeoutMs === undefined ? {} : { timeoutMs: input.timeoutMs }),
|
|
103
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
104
|
+
observe: async () => await observeWaitRound(input.path, input.ids, input.signal),
|
|
105
|
+
complete: (round) => roundComplete(round, input.completion),
|
|
106
|
+
onObserve: async (round) => await observeRound(round),
|
|
107
|
+
});
|
|
108
|
+
return fleetResultSchemas.wait.parse({
|
|
109
|
+
mode: input.completion,
|
|
110
|
+
reason: waited.reason,
|
|
111
|
+
observations: waited.value.observations.map((observation) => akumaOnlyObservation(observation.status)),
|
|
112
|
+
unobserved: waited.value.unobserved,
|
|
113
|
+
});
|
|
158
114
|
}
|
|
159
115
|
export async function executeTellAkuma(input) {
|
|
160
116
|
input.signal?.throwIfAborted();
|
|
161
117
|
const handle = source(input.path).selectHandle({ id: input.id });
|
|
162
|
-
const tell = await handle.tell(input.body, input.tellId, input.recordedAt, undefined,
|
|
118
|
+
const tell = await handle.tell(input.body, input.tellId, input.recordedAt, undefined, {
|
|
119
|
+
...(input.initiator === undefined ? {} : { initiator: input.initiator }),
|
|
120
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
121
|
+
});
|
|
163
122
|
input.signal?.throwIfAborted();
|
|
164
123
|
return fleetResultSchemas.tell.parse({
|
|
165
124
|
akuma: input.id,
|
|
@@ -245,6 +245,7 @@ declare const akumaObservationSchema: z.ZodObject<{
|
|
|
245
245
|
}, z.core.$strict>]>;
|
|
246
246
|
}, z.core.$strict>]>>>;
|
|
247
247
|
omitted: z.ZodNumber;
|
|
248
|
+
openingSequence: z.ZodOptional<z.ZodNumber>;
|
|
248
249
|
}, z.core.$strict>, z.ZodObject<{
|
|
249
250
|
reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
250
251
|
sequence: z.ZodNumber;
|
|
@@ -449,10 +450,14 @@ declare const akumaUnobservedSchema: z.ZodObject<{
|
|
|
449
450
|
diagnostic: z.ZodString;
|
|
450
451
|
}, z.core.$strict>;
|
|
451
452
|
declare const akumaWaitResultSchema: z.ZodObject<{
|
|
452
|
-
|
|
453
|
+
mode: z.ZodEnum<{
|
|
453
454
|
any: "any";
|
|
454
455
|
all: "all";
|
|
455
456
|
}>;
|
|
457
|
+
reason: z.ZodEnum<{
|
|
458
|
+
deadline: "deadline";
|
|
459
|
+
completed: "completed";
|
|
460
|
+
}>;
|
|
456
461
|
observations: z.ZodArray<z.ZodObject<{
|
|
457
462
|
status: z.ZodObject<{
|
|
458
463
|
id: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
|
|
@@ -699,6 +704,7 @@ declare const akumaWaitResultSchema: z.ZodObject<{
|
|
|
699
704
|
}, z.core.$strict>]>;
|
|
700
705
|
}, z.core.$strict>]>>>;
|
|
701
706
|
omitted: z.ZodNumber;
|
|
707
|
+
openingSequence: z.ZodOptional<z.ZodNumber>;
|
|
702
708
|
}, z.core.$strict>, z.ZodObject<{
|
|
703
709
|
reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
704
710
|
sequence: z.ZodNumber;
|
|
@@ -1022,10 +1028,14 @@ export declare function isKillResult(value: unknown): value is AkumaKillResult;
|
|
|
1022
1028
|
export declare function isTellResult(value: unknown): value is AkumaTellResult;
|
|
1023
1029
|
export declare const fleetResultSchemas: {
|
|
1024
1030
|
wait: z.ZodObject<{
|
|
1025
|
-
|
|
1031
|
+
mode: z.ZodEnum<{
|
|
1026
1032
|
any: "any";
|
|
1027
1033
|
all: "all";
|
|
1028
1034
|
}>;
|
|
1035
|
+
reason: z.ZodEnum<{
|
|
1036
|
+
deadline: "deadline";
|
|
1037
|
+
completed: "completed";
|
|
1038
|
+
}>;
|
|
1029
1039
|
observations: z.ZodArray<z.ZodObject<{
|
|
1030
1040
|
status: z.ZodObject<{
|
|
1031
1041
|
id: z.ZodPipe<z.ZodString, z.ZodTransform<import("./identity.js").AkuId, string>>;
|
|
@@ -1272,6 +1282,7 @@ export declare const fleetResultSchemas: {
|
|
|
1272
1282
|
}, z.core.$strict>]>;
|
|
1273
1283
|
}, z.core.$strict>]>>>;
|
|
1274
1284
|
omitted: z.ZodNumber;
|
|
1285
|
+
openingSequence: z.ZodOptional<z.ZodNumber>;
|
|
1275
1286
|
}, z.core.$strict>, z.ZodObject<{
|
|
1276
1287
|
reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
1277
1288
|
sequence: z.ZodNumber;
|
|
@@ -50,7 +50,8 @@ const akumaUnobservedSchema = z.object({ id: akumaIdSchema, diagnostic: z.string
|
|
|
50
50
|
const akumaKillResultItemSchema = z.object({ id: akumaIdSchema, evidence: killEvidenceSchema }).strict();
|
|
51
51
|
const akumaWaitResultSchema = z
|
|
52
52
|
.object({
|
|
53
|
-
|
|
53
|
+
mode: z.enum(["any", "all"]),
|
|
54
|
+
reason: z.enum(["completed", "deadline"]),
|
|
54
55
|
observations: z.array(akumaObservationSchema),
|
|
55
56
|
unobserved: z.array(akumaUnobservedSchema),
|
|
56
57
|
})
|
|
@@ -10,8 +10,8 @@ const fleetTargetsSchema = z
|
|
|
10
10
|
.array(akumaIdSchema)
|
|
11
11
|
.min(1)
|
|
12
12
|
.superRefine((ids, context) => {
|
|
13
|
-
if (ids.
|
|
14
|
-
context.addIssue({ code: "custom", message: "expected a
|
|
13
|
+
if (new Set(ids).size !== ids.length)
|
|
14
|
+
context.addIssue({ code: "custom", message: "expected a deduplicated target set" });
|
|
15
15
|
});
|
|
16
16
|
const waitRequestSchema = z
|
|
17
17
|
.object({
|
|
@@ -92,6 +92,7 @@ function decodedFleetResult(action, value) {
|
|
|
92
92
|
export function fleetRequestProtocol(action) {
|
|
93
93
|
return {
|
|
94
94
|
action,
|
|
95
|
+
supportsCancellation: true,
|
|
95
96
|
encodeRequest: (request) => {
|
|
96
97
|
const { action: _action, ...payload } = request;
|
|
97
98
|
return payload;
|
|
@@ -13,6 +13,6 @@ export type StatusFactInput = Readonly<{
|
|
|
13
13
|
aperture: "monitoring" | "receipt";
|
|
14
14
|
admittedTellId?: string;
|
|
15
15
|
}>;
|
|
16
|
-
/** Select the frontier and
|
|
16
|
+
/** Select the frontier and its delivered Tells, plus aperture-required Tell pins. */
|
|
17
17
|
export declare function statusFacts(database: DatabaseSync, input: StatusFactInput): readonly TimelineFact[];
|
|
18
18
|
export declare function activityFactSlice(database: DatabaseSync): ActivityFactSlice;
|
|
@@ -88,7 +88,7 @@ function decodeTimelineRows(database, rows) {
|
|
|
88
88
|
return fact;
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
|
-
/** Select the frontier and
|
|
91
|
+
/** Select the frontier and its delivered Tells, plus aperture-required Tell pins. */
|
|
92
92
|
export function statusFacts(database, input) {
|
|
93
93
|
const frontier = database.prepare("SELECT sequence FROM turns ORDER BY sequence DESC LIMIT 1").get();
|
|
94
94
|
const rows = database
|
|
@@ -97,13 +97,13 @@ export function statusFacts(database, input) {
|
|
|
97
97
|
UNION SELECT end_sequence FROM turns WHERE sequence = ? AND end_sequence IS NOT NULL
|
|
98
98
|
UNION SELECT sequence FROM calls WHERE turn_sequence = ?
|
|
99
99
|
UNION SELECT sequence FROM activity WHERE turn_sequence = ?
|
|
100
|
-
UNION SELECT
|
|
100
|
+
UNION SELECT tells.sequence FROM tells
|
|
101
|
+
JOIN tell_deliveries ON tell_deliveries.tell_id = tells.id
|
|
102
|
+
WHERE tell_deliveries.turn_sequence = ?
|
|
101
103
|
UNION SELECT sequence FROM tells WHERE id = ?
|
|
102
104
|
UNION SELECT sequence FROM tells WHERE ? AND ${tellStateSql} = 'pending'
|
|
103
|
-
UNION SELECT MAX(sequence) FROM tells WHERE ? AND ${tellStateSql} = 'told'
|
|
104
|
-
UNION SELECT MAX(sequence) FROM tells
|
|
105
105
|
) SELECT timeline.sequence, timeline.kind FROM timeline JOIN selected USING(sequence) ORDER BY sequence`)
|
|
106
|
-
.all(frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, input.admittedTellId ?? null, input.aperture === "monitoring" || input.admittedTellId === undefined ? 1 : 0
|
|
106
|
+
.all(frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, frontier?.sequence ?? null, input.admittedTellId ?? null, input.aperture === "monitoring" || input.admittedTellId === undefined ? 1 : 0);
|
|
107
107
|
return decodeTimelineRows(database, rows);
|
|
108
108
|
}
|
|
109
109
|
export function activityFactSlice(database) {
|
|
@@ -101,18 +101,41 @@ function frontierReportedChanges(ledger) {
|
|
|
101
101
|
function isPendingTell(row) {
|
|
102
102
|
return row.kind === "tell" && row.state === "pending";
|
|
103
103
|
}
|
|
104
|
-
function isToldTell(row) {
|
|
105
|
-
return row.kind === "tell" && row.state === "told";
|
|
106
|
-
}
|
|
107
104
|
function isActiveTool(row) {
|
|
108
105
|
return row.kind === "tool" && row.state === "active";
|
|
109
106
|
}
|
|
107
|
+
function isProtectedCurrentTurnActivity(row) {
|
|
108
|
+
return (row.kind === "said" ||
|
|
109
|
+
(row.kind === "tool" && row.call.kind === "fileChange" && row.state !== "active" && row.state !== "unsettled"));
|
|
110
|
+
}
|
|
111
|
+
function isSettledTellDeliveredTo(row, turnSequence) {
|
|
112
|
+
return (row.kind === "tell" &&
|
|
113
|
+
row.state === "told" &&
|
|
114
|
+
row.deliveries.some((delivery) => delivery.turnSequence === turnSequence));
|
|
115
|
+
}
|
|
116
|
+
function currentTurnWindow(ledger) {
|
|
117
|
+
const turn = ledger.openTurn;
|
|
118
|
+
if (turn === undefined)
|
|
119
|
+
return [];
|
|
120
|
+
const turnRows = new Set(turn.rows);
|
|
121
|
+
return ledger.rows.filter((row) => turnRows.has(row) || isSettledTellDeliveredTo(row, turn.turn.turnSequence));
|
|
122
|
+
}
|
|
123
|
+
function openingInput(ledger) {
|
|
124
|
+
const turn = ledger.openTurn;
|
|
125
|
+
if (turn === undefined)
|
|
126
|
+
return undefined;
|
|
127
|
+
const call = turn.rows.find((row) => row.kind === "call");
|
|
128
|
+
if (call !== undefined)
|
|
129
|
+
return call;
|
|
130
|
+
return ledger.rows.find((row) => row.kind === "tell" &&
|
|
131
|
+
row.state === "told" &&
|
|
132
|
+
row.deliveries.some((delivery) => delivery.route === "launch" && delivery.turnSequence === turn.turn.turnSequence));
|
|
133
|
+
}
|
|
110
134
|
export function selectSnapshot(ledger, input) {
|
|
111
135
|
const budget = input.budget ?? { tail: DEFAULT_TAIL, voice: DEFAULT_VOICE };
|
|
112
136
|
if (ledger.turns.length === 0 && !ledger.rows.some((row) => row.kind === "tell"))
|
|
113
137
|
return { snapshot: { kind: "unborn", entries: [], omitted: 0, ...EMPTY_REPORTED }, ordinaryCount: 0 };
|
|
114
138
|
const pending = ledger.rows.filter(isPendingTell);
|
|
115
|
-
const latestTold = input.aperture === "monitoring" ? ledger.rows.findLast(isToldTell) : undefined;
|
|
116
139
|
const admittedTell = input.aperture === "receipt" && input.admittedTellId !== undefined
|
|
117
140
|
? ledger.rows.find((row) => row.kind === "tell" && row.tellId === input.admittedTellId)
|
|
118
141
|
: undefined;
|
|
@@ -120,11 +143,17 @@ export function selectSnapshot(ledger, input) {
|
|
|
120
143
|
? admittedTell === undefined
|
|
121
144
|
? []
|
|
122
145
|
: [admittedTell]
|
|
123
|
-
:
|
|
146
|
+
: pending;
|
|
124
147
|
const reported = frontierReportedChanges(ledger);
|
|
125
148
|
if (ledger.openTurn !== undefined) {
|
|
126
|
-
const window = ledger
|
|
127
|
-
const
|
|
149
|
+
const window = currentTurnWindow(ledger);
|
|
150
|
+
const opening = openingInput(ledger);
|
|
151
|
+
const pinSet = new Set([
|
|
152
|
+
...window.filter(isActiveTool),
|
|
153
|
+
...window.filter(isProtectedCurrentTurnActivity),
|
|
154
|
+
...pins,
|
|
155
|
+
...(opening === undefined ? [] : [opening]),
|
|
156
|
+
]);
|
|
128
157
|
const ordinary = window.filter((row) => !pinSet.has(row));
|
|
129
158
|
const tailCount = Math.max(0, budget.tail);
|
|
130
159
|
const tail = tailCount === 0 ? [] : ordinary.slice(-tailCount);
|
|
@@ -140,6 +169,7 @@ export function selectSnapshot(ledger, input) {
|
|
|
140
169
|
turn: ledger.openTurn.turn,
|
|
141
170
|
entries: assembleEntries(ledger, window, selected),
|
|
142
171
|
omitted,
|
|
172
|
+
...(opening === undefined ? {} : { openingSequence: opening.sequence }),
|
|
143
173
|
...reported,
|
|
144
174
|
},
|
|
145
175
|
ordinaryCount: tail.length + voice.length,
|
|
@@ -733,6 +733,7 @@ export declare const activitySnapshotSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
|
733
733
|
}, z.core.$strict>]>;
|
|
734
734
|
}, z.core.$strict>]>>>;
|
|
735
735
|
omitted: z.ZodNumber;
|
|
736
|
+
openingSequence: z.ZodOptional<z.ZodNumber>;
|
|
736
737
|
}, z.core.$strict>, z.ZodObject<{
|
|
737
738
|
reportedChanges: z.ZodReadonly<z.ZodArray<z.ZodObject<{
|
|
738
739
|
sequence: z.ZodNumber;
|
|
@@ -3,6 +3,7 @@ import { projectTell } from "./heart/facts.js";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
const nonblankTextSchema = z.string().refine((value) => value.trim() !== "");
|
|
5
5
|
const countSchema = z.number().int().nonnegative();
|
|
6
|
+
const sequenceSchema = z.number().int().positive();
|
|
6
7
|
const timestampSchema = z.string().refine((value) => Number.isFinite(Date.parse(value)), "expected timestamp");
|
|
7
8
|
const diffstatSchema = z.object({ added: countSchema, removed: countSchema }).strict();
|
|
8
9
|
const fileChangeSchema = z
|
|
@@ -162,6 +163,28 @@ const reportedChangeFields = {
|
|
|
162
163
|
reportedChanges: z.array(reportedFileChangeSchema).readonly(),
|
|
163
164
|
reportedChangesOmitted: countSchema,
|
|
164
165
|
};
|
|
166
|
+
const openActivitySnapshotSchema = z
|
|
167
|
+
.object({
|
|
168
|
+
kind: z.literal("open"),
|
|
169
|
+
turn: turnRowSchema,
|
|
170
|
+
entries: z.array(snapshotEntrySchema(openSnapshotRowSchema)).readonly(),
|
|
171
|
+
omitted: countSchema,
|
|
172
|
+
openingSequence: sequenceSchema.optional(),
|
|
173
|
+
...reportedChangeFields,
|
|
174
|
+
})
|
|
175
|
+
.strict()
|
|
176
|
+
.superRefine((snapshot, context) => {
|
|
177
|
+
if (snapshot.openingSequence === undefined)
|
|
178
|
+
return;
|
|
179
|
+
const matches = snapshot.entries.filter((entry) => entry.kind === "row" && entry.row.sequence === snapshot.openingSequence);
|
|
180
|
+
if (matches.length !== 1) {
|
|
181
|
+
context.addIssue({
|
|
182
|
+
code: "custom",
|
|
183
|
+
path: ["openingSequence"],
|
|
184
|
+
message: "openingSequence must name exactly one snapshot entry",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
});
|
|
165
188
|
export const activitySnapshotSchema = z.union([
|
|
166
189
|
z
|
|
167
190
|
.object({
|
|
@@ -171,15 +194,7 @@ export const activitySnapshotSchema = z.union([
|
|
|
171
194
|
...reportedChangeFields,
|
|
172
195
|
})
|
|
173
196
|
.strict(),
|
|
174
|
-
|
|
175
|
-
.object({
|
|
176
|
-
kind: z.literal("open"),
|
|
177
|
-
turn: turnRowSchema,
|
|
178
|
-
entries: z.array(snapshotEntrySchema(openSnapshotRowSchema)).readonly(),
|
|
179
|
-
omitted: countSchema,
|
|
180
|
-
...reportedChangeFields,
|
|
181
|
-
})
|
|
182
|
-
.strict(),
|
|
197
|
+
openActivitySnapshotSchema,
|
|
183
198
|
z
|
|
184
199
|
.object({
|
|
185
200
|
kind: z.literal("idle"),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import type { createAgentSession, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager, CreateAgentSessionOptions } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import type { createAgentSession, createBashToolDefinition, DefaultResourceLoader, getAgentDir, ModelRuntime, SessionManager, CreateAgentSessionOptions } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
3
3
|
import { type ProviderAdapter } from "../../provider.js";
|
|
4
4
|
export type PiSdk = Readonly<{
|
|
5
5
|
createAgentSession(options?: CreateAgentSessionOptions): ReturnType<typeof createAgentSession>;
|
|
6
|
+
createBashToolDefinition: typeof createBashToolDefinition;
|
|
6
7
|
DefaultResourceLoader: typeof DefaultResourceLoader;
|
|
7
8
|
getAgentDir: typeof getAgentDir;
|
|
8
9
|
ModelRuntime: typeof ModelRuntime;
|
|
@@ -54,7 +54,7 @@ async function piCreateOptions(sdk, input) {
|
|
|
54
54
|
const customTools = input.requests === undefined || input.options.readonly === true
|
|
55
55
|
? undefined
|
|
56
56
|
: [
|
|
57
|
-
|
|
57
|
+
sdk.createBashToolDefinition(input.cwd, {
|
|
58
58
|
spawnHook: (context) => ({
|
|
59
59
|
...context,
|
|
60
60
|
env: akumaExecutionEnvironment(context.env, {}, input.requests.dir, ["PI_SESSION_ID", "PI_SESSION_FILE"]),
|
|
@@ -228,6 +228,7 @@ async function loadPiSdk() {
|
|
|
228
228
|
const sdk = await import("@earendil-works/pi-coding-agent");
|
|
229
229
|
return {
|
|
230
230
|
createAgentSession: sdk.createAgentSession,
|
|
231
|
+
createBashToolDefinition: sdk.createBashToolDefinition,
|
|
231
232
|
DefaultResourceLoader: sdk.DefaultResourceLoader,
|
|
232
233
|
getAgentDir: sdk.getAgentDir,
|
|
233
234
|
ModelRuntime: sdk.ModelRuntime,
|