@astrosheep/keiyaku 4.5.26 → 4.5.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +82 -162
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +153 -76
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +68 -64
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +115 -146
- package/build/src/akuma/akuma-errors.d.ts +6 -0
- package/build/src/akuma/akuma-errors.js +11 -0
- package/build/src/akuma/akuma-handle.d.ts +54 -1
- package/build/src/akuma/akuma-handle.js +79 -8
- package/build/src/akuma/akuma-instance.js +6 -22
- package/build/src/akuma/akuma-observe.d.ts +6 -0
- package/build/src/akuma/akuma-observe.js +3 -1
- package/build/src/akuma/akuma-probe.d.ts +20 -1
- package/build/src/akuma/akuma-probe.js +20 -3
- package/build/src/akuma/akuma.d.ts +13 -0
- package/build/src/akuma/akuma.js +1 -0
- package/build/src/akuma/allowed.d.ts +2 -1
- package/build/src/akuma/allowed.js +9 -4
- package/build/src/akuma/archetype.js +3 -3
- package/build/src/akuma/body.js +8 -3
- package/build/src/akuma/fleet-execution.d.ts +13 -2
- package/build/src/akuma/fleet-execution.js +45 -0
- package/build/src/akuma/fleet-observation.d.ts +241 -0
- package/build/src/akuma/fleet-observation.js +13 -0
- package/build/src/akuma/fleet-owner-port.d.ts +12 -0
- package/build/src/akuma/fleet-owner-port.js +46 -0
- package/build/src/akuma/fleet-request.d.ts +55 -4
- package/build/src/akuma/fleet-request.js +101 -6
- package/build/src/akuma/heart/index.d.ts +1 -0
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/heart/rows.d.ts +1 -0
- package/build/src/akuma/heart/rows.js +8 -0
- package/build/src/akuma/heart/soul.js +2 -2
- package/build/src/akuma/identity.js +11 -9
- package/build/src/akuma/projection.d.ts +36 -0
- package/build/src/akuma/projection.js +2 -1
- package/build/src/akuma/provider.d.ts +14 -0
- package/build/src/akuma/provider.js +66 -4
- package/build/src/akuma/providers/acp/events.js +16 -8
- package/build/src/akuma/providers/claude/events.js +5 -7
- package/build/src/akuma/providers/opencode-sdk/events.js +9 -5
- package/build/src/akuma/providers/pi/events.js +4 -3
- package/build/src/akuma/request-lifecycle.js +10 -1
- package/build/src/akuma-body.js +1 -33
- package/build/src/alias/index.js +3 -3
- package/build/src/cli/commands/akuma-invoke.d.ts +8 -0
- package/build/src/cli/commands/akuma-invoke.js +67 -6
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +19 -30
- package/build/src/cli/commands/contract-help.d.ts +1 -0
- package/build/src/cli/commands/contract-help.js +9 -5
- package/build/src/cli/invoke.js +1 -1
- package/build/src/cli/render/akuma-activity.d.ts +7 -1
- package/build/src/cli/render/akuma-activity.js +164 -50
- package/build/src/cli/render/akuma-tool.d.ts +5 -0
- package/build/src/cli/render/akuma-tool.js +118 -14
- package/build/src/cli/render/akuma.d.ts +12 -1
- package/build/src/cli/render/akuma.js +74 -2
- package/build/src/cli/render/catalog.js +2 -3
- package/build/src/cli/render/contract-observation.d.ts +1 -0
- package/build/src/cli/render/contract-observation.js +20 -1
- package/build/src/cli/render/contract.js +4 -4
- package/build/src/cli/render/execution-progress.d.ts +1 -0
- package/build/src/cli/render/execution-progress.js +77 -3
- package/build/src/cli/render/kanshi.js +5 -19
- package/build/src/cli/render/terminal.js +3 -1
- package/build/src/cli/runtime.d.ts +6 -0
- package/build/src/cli/runtime.js +35 -17
- package/build/src/core/facts/offer.d.ts +1 -2
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.js +1 -1
- package/build/src/core/verbs/arc.js +1 -1
- package/build/src/core/verbs/attestation.js +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/deliver.js +1 -1
- package/build/src/core/verbs/placement.js +1 -1
- package/build/src/core/verbs/reintegrate.js +1 -1
- package/build/src/git/admission.js +18 -7
- package/build/src/identity/coordinates.js +1 -1
- package/build/src/identity/normalize.d.ts +3 -0
- package/build/src/identity/normalize.js +10 -0
- package/build/src/identity/selector.d.ts +1 -0
- package/build/src/identity/selector.js +15 -4
- package/build/src/library/address.d.ts +33 -3
- package/build/src/library/address.js +90 -29
- package/build/src/library/akuma-creation.d.ts +1 -1
- package/build/src/library/akuma-creation.js +10 -52
- package/build/src/library/composition.d.ts +14 -1
- package/build/src/library/fleet.d.ts +13 -2
- package/build/src/library/fleet.js +142 -48
- package/build/src/library/keiyaku.d.ts +14 -1
- package/build/src/plugin/public.d.ts +2 -0
- package/build/src/protocol/completion.js +9 -2
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +1 -1
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { handoffPendingTells, wakeRecordedTell } from "./body.js";
|
|
3
|
-
import { HeldAkumaLeash, activitySlice, readForkPoint, readHeart, readKill, readLastAnsweredTurn, readSoul, recordTell, requestPause, requestStop, } from "./heart/index.js";
|
|
3
|
+
import { HeldAkumaLeash, activitySlice, readForkPoint, readHeart, readKill, readLastAnsweredTurn, readSoul, readTell, readTurn, recordTell, requestPause, requestStop, projectTell, } from "./heart/index.js";
|
|
4
4
|
import { acquireLeash } from "./control.js";
|
|
5
5
|
import { parsePublicHistoryId, pathsForAkuId } from "./identity.js";
|
|
6
6
|
import { projectTurns, selectHistory, selectExactHistory, } from "./projection.js";
|
|
7
7
|
import { resolveProviderExecution } from "./providers/index.js";
|
|
8
8
|
import { publishAkuma } from "./publication.js";
|
|
9
9
|
import { spawnAkumaBody } from "./body.js";
|
|
10
|
-
import { AkumaNotBornError } from "./akuma-errors.js";
|
|
11
|
-
import { bornStatus, defaultWaitComplete, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
|
|
10
|
+
import { AkumaNotBornError, AkumaProviderError } from "./akuma-errors.js";
|
|
11
|
+
import { bornStatus, bornLiveStatus, defaultWaitComplete, readWaitComplete, waitForObservation, } from "./akuma-observe.js";
|
|
12
12
|
const CALL_EXECUTION = Symbol("akuma-call-execution");
|
|
13
13
|
function diagnostic(error) {
|
|
14
14
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -151,6 +151,17 @@ export class AkumaHandle {
|
|
|
151
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 admitted = await this.admitTell(body, tellId, recordedAt, runtime, options);
|
|
155
|
+
if (admitted.kind === "not-born")
|
|
156
|
+
throw new AkumaNotBornError(this.id);
|
|
157
|
+
return await admitted.wake;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Record one Tell and start its wake without waiting for delivery. A bounded
|
|
161
|
+
* caller starts its own deadline at this admission boundary while the wake
|
|
162
|
+
* continues in the background; the unbounded public Tell awaits `wake`.
|
|
163
|
+
*/
|
|
164
|
+
async admitTell(body, tellId = randomUUID(), recordedAt = new Date().toISOString(), runtime, options = {}) {
|
|
154
165
|
const { schemaJson, initiator, signal } = options;
|
|
155
166
|
const admitted = await recordTell(this.paths, {
|
|
156
167
|
kind: "tell",
|
|
@@ -161,10 +172,69 @@ export class AkumaHandle {
|
|
|
161
172
|
...(schemaJson === undefined ? {} : { schemaJson }),
|
|
162
173
|
});
|
|
163
174
|
if (admitted.kind === "not-born")
|
|
164
|
-
|
|
165
|
-
return
|
|
175
|
+
return admitted;
|
|
176
|
+
return {
|
|
177
|
+
kind: "admitted",
|
|
178
|
+
tell: admitted.tell,
|
|
179
|
+
wake: wakeRecordedTell(this.paths, admitted.tell.id, runtime, signal),
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The admitted Tell's receipt as it stands now. A bounded caller that stops
|
|
184
|
+
* waiting before the wake settles reports this honest instant rather than a
|
|
185
|
+
* delivery that has not happened yet.
|
|
186
|
+
*/
|
|
187
|
+
async admittedReceipt(tellId) {
|
|
188
|
+
const tell = await readTell(this.paths, tellId);
|
|
189
|
+
if (tell === null)
|
|
190
|
+
throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
|
|
191
|
+
const latestBody = (await readHeart(this.paths)).latestBody;
|
|
192
|
+
return {
|
|
193
|
+
admission: { tellId, fact: "recorded" },
|
|
194
|
+
row: projectTell(tell),
|
|
195
|
+
wake: tell.state === "told" || tell.binding !== undefined
|
|
196
|
+
? { kind: "told" }
|
|
197
|
+
: latestBody !== null && latestBody.end === undefined && latestBody.hung === undefined
|
|
198
|
+
? { kind: "pursuing", bodySequence: latestBody.sequence }
|
|
199
|
+
: { kind: "held" },
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/** Observe the exact admitted Tell's bound Turn without substituting Akuma-wide idleness. */
|
|
203
|
+
async tellOutcome(tellId, options = {}) {
|
|
204
|
+
const waited = await waitForObservation({
|
|
205
|
+
...(options.timeoutMs === undefined ? {} : { timeoutMs: options.timeoutMs }),
|
|
206
|
+
...(options.signal === undefined ? {} : { signal: options.signal }),
|
|
207
|
+
observe: async () => {
|
|
208
|
+
const tell = await readTell(this.paths, tellId);
|
|
209
|
+
if (tell === null)
|
|
210
|
+
throw new AkumaProviderError(`recorded Tell ${tellId} is missing from Heart`);
|
|
211
|
+
const outcome = await this.boundTellOutcome(tell);
|
|
212
|
+
if (options.observe !== undefined) {
|
|
213
|
+
await options.observe(await bornLiveStatus(this.paths, this.id, { aperture: "monitoring", admittedTellId: tellId }));
|
|
214
|
+
}
|
|
215
|
+
return { outcome, terminalWithoutTurn: tell.state === "told" && tell.binding === undefined };
|
|
216
|
+
},
|
|
217
|
+
complete: (observed) => observed.outcome !== null || observed.terminalWithoutTurn,
|
|
218
|
+
});
|
|
219
|
+
return { reason: waited.reason, outcome: waited.value.outcome };
|
|
220
|
+
}
|
|
221
|
+
async boundTellOutcome(tell) {
|
|
222
|
+
if (tell.binding === undefined)
|
|
223
|
+
return null;
|
|
224
|
+
const turn = await readTurn(this.paths, tell.binding.turnSequence);
|
|
225
|
+
return turn?.end?.outcome ?? null;
|
|
166
226
|
}
|
|
167
227
|
async interrupt(body, options = {}) {
|
|
228
|
+
const admitted = await this.admitInterrupt(body, options);
|
|
229
|
+
if (admitted.kind === "unavailable")
|
|
230
|
+
return admitted;
|
|
231
|
+
return { kind: "interrupted", putDown: admitted.putDown, tell: await admitted.wake };
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Settle the predecessor and record the interrupt Tell, returning at the
|
|
235
|
+
* admission boundary so a bounded caller owns the wake wait.
|
|
236
|
+
*/
|
|
237
|
+
async admitInterrupt(body, options = {}) {
|
|
168
238
|
const request = await requestPause(this.paths, new Date().toISOString(), options.signal);
|
|
169
239
|
if (request.kind === "not-born") {
|
|
170
240
|
throw new AkumaNotBornError(this.id);
|
|
@@ -204,15 +274,16 @@ export class AkumaHandle {
|
|
|
204
274
|
});
|
|
205
275
|
if (admitted.kind === "not-born")
|
|
206
276
|
throw new AkumaNotBornError(this.id);
|
|
207
|
-
recorded =
|
|
277
|
+
recorded = admitted.tell;
|
|
208
278
|
}
|
|
209
279
|
finally {
|
|
210
280
|
leash.release();
|
|
211
281
|
}
|
|
212
282
|
return {
|
|
213
|
-
kind: "
|
|
283
|
+
kind: "admitted",
|
|
284
|
+
tell: recorded,
|
|
214
285
|
putDown,
|
|
215
|
-
|
|
286
|
+
wake: wakeRecordedTell(this.paths, recorded.id, options.runtime, options.signal),
|
|
216
287
|
};
|
|
217
288
|
}
|
|
218
289
|
async fork(input) {
|
|
@@ -6,7 +6,7 @@ import { AkumaDecodeError, AkumaProviderError } from "./akuma-errors.js";
|
|
|
6
6
|
import { AkumaHandle } from "./akuma-handle.js";
|
|
7
7
|
import { bornStatus, defaultWaitComplete, waitForObservation } from "./akuma-observe.js";
|
|
8
8
|
import { loadArchetype } from "./archetype.js";
|
|
9
|
-
import { activitySlice
|
|
9
|
+
import { activitySlice } from "./heart/index.js";
|
|
10
10
|
import { parseAkuId, pathsForAkuId } from "./identity.js";
|
|
11
11
|
import { birthAkuma, launchAkuma } from "./publication.js";
|
|
12
12
|
import { projectTurns, selectHistory } from "./projection.js";
|
|
@@ -72,26 +72,10 @@ function outcomeError(outcome) {
|
|
|
72
72
|
throw new AkumaProviderError(outcome.diagnostic);
|
|
73
73
|
throw new AkumaProviderError("Akuma answered without a value");
|
|
74
74
|
}
|
|
75
|
-
async function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return turn?.end?.outcome ?? null;
|
|
80
|
-
}
|
|
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;
|
|
75
|
+
async function awaitTellOutcome(handle, tellId, signal) {
|
|
76
|
+
const observed = await handle.tellOutcome(tellId, signal === undefined ? {} : { signal });
|
|
77
|
+
if (observed.outcome !== null)
|
|
78
|
+
return observed.outcome;
|
|
95
79
|
throw new AkumaProviderError(`recorded Tell ${tellId} reached a terminal delivery without a Turn binding`);
|
|
96
80
|
}
|
|
97
81
|
export class Akuma {
|
|
@@ -172,7 +156,7 @@ export class Akuma {
|
|
|
172
156
|
...(schemaOptions.initiator === undefined ? {} : { initiator: schemaOptions.initiator }),
|
|
173
157
|
...(signal === undefined ? {} : { signal }),
|
|
174
158
|
});
|
|
175
|
-
const outcome = await awaitTellOutcome(this.
|
|
159
|
+
const outcome = await awaitTellOutcome(new AkumaHandle(this.id, this.root), recorded.tellId, signal);
|
|
176
160
|
if (outcome.kind !== "answered")
|
|
177
161
|
outcomeError(outcome);
|
|
178
162
|
if (schema === undefined)
|
|
@@ -15,6 +15,12 @@ export type BudgetedStatusObservation = Readonly<{
|
|
|
15
15
|
export type LiveStatusObservation = BudgetedStatusObservation & Readonly<{
|
|
16
16
|
rows: readonly ActivityRow[];
|
|
17
17
|
}>;
|
|
18
|
+
/** Internal live companion for an observation loop; it is not a public result. */
|
|
19
|
+
export declare function bornLiveStatus(paths: AkumaPaths, expected: AkuId, input: Readonly<{
|
|
20
|
+
aperture: "monitoring" | "receipt";
|
|
21
|
+
ordinaryBudget?: number;
|
|
22
|
+
admittedTellId?: string;
|
|
23
|
+
}>): Promise<LiveStatusObservation>;
|
|
18
24
|
export declare function bornStatus(paths: AkumaPaths, expected: AkuId, input: Readonly<{
|
|
19
25
|
aperture: "monitoring" | "receipt";
|
|
20
26
|
ordinaryBudget?: number;
|
|
@@ -56,7 +56,8 @@ async function bornObservation(paths, expected, read, snapshot) {
|
|
|
56
56
|
claim?.release();
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
/** Internal live companion for an observation loop; it is not a public result. */
|
|
60
|
+
export async function bornLiveStatus(paths, expected, input) {
|
|
60
61
|
if (input.ordinaryBudget !== undefined && (!Number.isSafeInteger(input.ordinaryBudget) || input.ordinaryBudget < 0))
|
|
61
62
|
throw new TypeError("ordinary budget must be a nonnegative safe integer");
|
|
62
63
|
const { snapshot, soul, currentLife } = await bornObservation(paths, expected, () => readLifeSnapshot(paths));
|
|
@@ -74,6 +75,7 @@ async function bornLiveStatus(paths, expected, input) {
|
|
|
74
75
|
status: {
|
|
75
76
|
id: soul.id,
|
|
76
77
|
life: currentLife,
|
|
78
|
+
cwd: soul.cwd,
|
|
77
79
|
allowed: soul.allowed,
|
|
78
80
|
...(soul.readonly === undefined ? {} : { readonly: soul.readonly }),
|
|
79
81
|
...(resumeUnsupported ? { strandedReason: "resume-unsupported" } : {}),
|
|
@@ -1,3 +1,22 @@
|
|
|
1
1
|
import { type AkuId } from "./identity.js";
|
|
2
2
|
import type { WorldRoot } from "../world.js";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* How one Akuma coordinate stands in a World, decided in the single place that
|
|
5
|
+
* reads a Heart for addressing. Absence and unreadability are different facts,
|
|
6
|
+
* and each consumer below maps them to its own caller terms.
|
|
7
|
+
*/
|
|
8
|
+
export type AkumaAddressability = Readonly<{
|
|
9
|
+
kind: "born";
|
|
10
|
+
}> | Readonly<{
|
|
11
|
+
kind: "absent";
|
|
12
|
+
}> | Readonly<{
|
|
13
|
+
kind: "unreadable";
|
|
14
|
+
reason: string;
|
|
15
|
+
}>;
|
|
16
|
+
export declare function akumaAddressability(worldPath: WorldRoot, id: AkuId): Promise<AkumaAddressability>;
|
|
17
|
+
/**
|
|
18
|
+
* The one normalization of addressability into caller terms: an Akuma whose
|
|
19
|
+
* Heart is absent was never born, and one whose Heart cannot be read is an
|
|
20
|
+
* observation failure that keeps its reason with the identity.
|
|
21
|
+
*/
|
|
22
|
+
export declare function requireBornAkuma(worldPath: WorldRoot, id: AkuId): Promise<void>;
|
|
@@ -1,6 +1,23 @@
|
|
|
1
|
+
import { AkumaNotBornError, AkumaObservationError } from "./akuma-errors.js";
|
|
1
2
|
import { readSoul } from "./heart/index.js";
|
|
2
3
|
import { pathsForAkuId } from "./identity.js";
|
|
3
|
-
export async function
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export async function akumaAddressability(worldPath, id) {
|
|
5
|
+
try {
|
|
6
|
+
return (await readSoul(pathsForAkuId(worldPath, id))) === null ? { kind: "absent" } : { kind: "born" };
|
|
7
|
+
}
|
|
8
|
+
catch (error) {
|
|
9
|
+
return { kind: "unreadable", reason: error instanceof Error ? error.message : String(error) };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The one normalization of addressability into caller terms: an Akuma whose
|
|
14
|
+
* Heart is absent was never born, and one whose Heart cannot be read is an
|
|
15
|
+
* observation failure that keeps its reason with the identity.
|
|
16
|
+
*/
|
|
17
|
+
export async function requireBornAkuma(worldPath, id) {
|
|
18
|
+
const addressability = await akumaAddressability(worldPath, id);
|
|
19
|
+
if (addressability.kind === "absent")
|
|
20
|
+
throw new AkumaNotBornError(id);
|
|
21
|
+
if (addressability.kind === "unreadable")
|
|
22
|
+
throw new AkumaObservationError(id, addressability.reason);
|
|
6
23
|
}
|
|
@@ -32,6 +32,7 @@ export declare const akumaStatusSchema: z.ZodObject<{
|
|
|
32
32
|
asleep: "asleep";
|
|
33
33
|
stranded: "stranded";
|
|
34
34
|
}>;
|
|
35
|
+
cwd: z.ZodOptional<z.ZodString>;
|
|
35
36
|
allowed: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
36
37
|
"task.add": "task.add";
|
|
37
38
|
"task.addDocument": "task.addDocument";
|
|
@@ -207,6 +208,10 @@ export declare const akumaStatusSchema: z.ZodObject<{
|
|
|
207
208
|
}, z.core.$strict>, z.ZodObject<{
|
|
208
209
|
kind: z.ZodLiteral<"other">;
|
|
209
210
|
display: z.ZodString;
|
|
211
|
+
input: z.ZodOptional<z.ZodObject<{
|
|
212
|
+
json: z.ZodString;
|
|
213
|
+
truncated: z.ZodBoolean;
|
|
214
|
+
}, z.core.$strict>>;
|
|
210
215
|
}, z.core.$strict>]>;
|
|
211
216
|
state: z.ZodLiteral<"active">;
|
|
212
217
|
truncated: z.ZodOptional<z.ZodLiteral<true>>;
|
|
@@ -254,6 +259,10 @@ export declare const akumaStatusSchema: z.ZodObject<{
|
|
|
254
259
|
}, z.core.$strict>, z.ZodObject<{
|
|
255
260
|
kind: z.ZodLiteral<"other">;
|
|
256
261
|
display: z.ZodString;
|
|
262
|
+
input: z.ZodOptional<z.ZodObject<{
|
|
263
|
+
json: z.ZodString;
|
|
264
|
+
truncated: z.ZodBoolean;
|
|
265
|
+
}, z.core.$strict>>;
|
|
257
266
|
}, z.core.$strict>]>;
|
|
258
267
|
state: z.ZodObject<{
|
|
259
268
|
status: z.ZodEnum<{
|
|
@@ -409,6 +418,10 @@ export declare const akumaStatusSchema: z.ZodObject<{
|
|
|
409
418
|
}, z.core.$strict>, z.ZodObject<{
|
|
410
419
|
kind: z.ZodLiteral<"other">;
|
|
411
420
|
display: z.ZodString;
|
|
421
|
+
input: z.ZodOptional<z.ZodObject<{
|
|
422
|
+
json: z.ZodString;
|
|
423
|
+
truncated: z.ZodBoolean;
|
|
424
|
+
}, z.core.$strict>>;
|
|
412
425
|
}, z.core.$strict>]>;
|
|
413
426
|
state: z.ZodObject<{
|
|
414
427
|
status: z.ZodEnum<{
|
package/build/src/akuma/akuma.js
CHANGED
|
@@ -26,6 +26,7 @@ export const akumaStatusSchema = z
|
|
|
26
26
|
.object({
|
|
27
27
|
id: akumaIdSchema,
|
|
28
28
|
life: z.enum(["running", "asleep", "stranded", "hung", "untidy", "killed"]),
|
|
29
|
+
cwd: z.string().optional(),
|
|
29
30
|
allowed: allowedActionsSchema,
|
|
30
31
|
readonly: readonlySchema.optional(),
|
|
31
32
|
timeline: activitySnapshotSchema,
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
export declare const ALLOWED_ACTIONS: readonly ["akuma.call", "akuma.kill", "akuma.tell", "contract.audit", "contract.deliver", "contract.review", "task.add", "task.addDocument", "task.compose", "task.done", "task.drop", "task.hold", "task.resume", "task.start", "task.stop", "task.update"];
|
|
3
3
|
export type AllowedAction = (typeof ALLOWED_ACTIONS)[number];
|
|
4
4
|
export type AllowedActions = readonly AllowedAction[];
|
|
5
|
+
export declare const DEFAULT_ALLOWED_ACTIONS: AllowedActions;
|
|
5
6
|
export declare function isAllowedAction(value: unknown): value is AllowedAction;
|
|
6
7
|
export declare function decodeAllowedActions(value: unknown, label?: string): AllowedActions;
|
|
7
8
|
/** Public codecs retain the Soul's canonical, duplicate-free action membership. */
|
|
@@ -23,6 +24,6 @@ export declare const allowedActionsSchema: z.ZodPipe<z.ZodArray<z.ZodEnum<{
|
|
|
23
24
|
"contract.deliver": "contract.deliver";
|
|
24
25
|
"contract.review": "contract.review";
|
|
25
26
|
}>>, z.ZodTransform<AllowedActions, ("task.add" | "task.addDocument" | "task.compose" | "task.done" | "task.drop" | "task.hold" | "task.resume" | "task.start" | "task.stop" | "task.update" | "akuma.call" | "akuma.kill" | "akuma.tell" | "contract.audit" | "contract.deliver" | "contract.review")[]>>;
|
|
26
|
-
export declare function
|
|
27
|
+
export declare function historicalAllowedActions(value: unknown): AllowedActions;
|
|
27
28
|
export declare function unionAllowedActions(base: AllowedActions, additions: AllowedActions): AllowedActions;
|
|
28
29
|
export declare function clipAllowedActions(requested: AllowedActions, parent: AllowedActions): AllowedActions;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { TASK_MUTATION_ACTIONS } from "../task/mutation.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
const AKUMA_MUTATION_ACTIONS = Object.freeze(["akuma.call", "akuma.kill", "akuma.tell"]);
|
|
3
4
|
export const ALLOWED_ACTIONS = Object.freeze([
|
|
4
|
-
|
|
5
|
-
"akuma.kill",
|
|
6
|
-
"akuma.tell",
|
|
5
|
+
...AKUMA_MUTATION_ACTIONS,
|
|
7
6
|
"contract.audit",
|
|
8
7
|
"contract.deliver",
|
|
9
8
|
"contract.review",
|
|
10
9
|
...TASK_MUTATION_ACTIONS,
|
|
11
10
|
]);
|
|
11
|
+
export const DEFAULT_ALLOWED_ACTIONS = Object.freeze([
|
|
12
|
+
...AKUMA_MUTATION_ACTIONS,
|
|
13
|
+
"contract.audit",
|
|
14
|
+
"contract.deliver",
|
|
15
|
+
...TASK_MUTATION_ACTIONS,
|
|
16
|
+
]);
|
|
12
17
|
const ALLOWED_ACTION_SET = new Set(ALLOWED_ACTIONS);
|
|
13
18
|
export function isAllowedAction(value) {
|
|
14
19
|
return typeof value === "string" && ALLOWED_ACTION_SET.has(value);
|
|
@@ -36,7 +41,7 @@ export const allowedActionsSchema = z.array(z.enum(ALLOWED_ACTIONS)).transform((
|
|
|
36
41
|
return z.NEVER;
|
|
37
42
|
}
|
|
38
43
|
});
|
|
39
|
-
export function
|
|
44
|
+
export function historicalAllowedActions(value) {
|
|
40
45
|
return value === undefined ? ALLOWED_ACTIONS : decodeAllowedActions(value);
|
|
41
46
|
}
|
|
42
47
|
export function unionAllowedActions(base, additions) {
|
|
@@ -5,7 +5,7 @@ import { parseDocument } from "yaml";
|
|
|
5
5
|
import { archetypeName } from "./identity.js";
|
|
6
6
|
import { decodeProviderOptions, decodeProviderRecipe, } from "./provider-recipe.js";
|
|
7
7
|
import { resolveProviderExecution } from "./providers/index.js";
|
|
8
|
-
import {
|
|
8
|
+
import { DEFAULT_ALLOWED_ACTIONS, decodeAllowedActions } from "./allowed.js";
|
|
9
9
|
export class AkumaArchetypeError extends Error {
|
|
10
10
|
archetype;
|
|
11
11
|
searched;
|
|
@@ -135,7 +135,7 @@ function decodeArchetypeFields(values) {
|
|
|
135
135
|
const sandbox = archetypeEnum(values, "sandbox", ["full-access"]);
|
|
136
136
|
const description = archetypeField(values, "description");
|
|
137
137
|
const allowedPresent = "allowed" in values;
|
|
138
|
-
const allowed = allowedPresent ?
|
|
138
|
+
const allowed = allowedPresent ? decodeAllowedActions(values.allowed) : undefined;
|
|
139
139
|
const systemPromptMode = archetypeEnum(values, "systemPromptMode", ["append", "replace"]);
|
|
140
140
|
return {
|
|
141
141
|
...(base === undefined ? {} : { base }),
|
|
@@ -186,7 +186,7 @@ function mergeArchetype(base, local) {
|
|
|
186
186
|
if (provider === undefined)
|
|
187
187
|
throw new TypeError("Akuma provider must be a nonblank string");
|
|
188
188
|
const options = decodeProviderOptions({ ...(base?.options ?? {}), ...local.options });
|
|
189
|
-
const allowed = local.allowedPresent ? local.allowed : (base?.allowed ??
|
|
189
|
+
const allowed = local.allowedPresent ? local.allowed : (base?.allowed ?? DEFAULT_ALLOWED_ACTIONS);
|
|
190
190
|
return Object.freeze({
|
|
191
191
|
name: local.name,
|
|
192
192
|
path: local.path,
|
package/build/src/akuma/body.js
CHANGED
|
@@ -4,7 +4,7 @@ import { fileURLToPath } from "node:url";
|
|
|
4
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
|
-
import { HeldAkumaLeash, breakBody, decidePendingTellDisposition, drainPendingTells, endTurn, failOpenBoundTurns, finishBodyIfIdle, heartExists, isHeartAbsent, probeLeash, projectTell, readHeart, readOpenBoundTurns, readOpenPendingTellDisposition, readTell, readTurn, readNonterminalRequests, resolvePendingTellDisposition, } from "./heart/index.js";
|
|
7
|
+
import { HeldAkumaLeash, breakBody, decidePendingTellDisposition, drainPendingTells, endTurn, failOpenBoundTurns, finishBodyIfIdle, heartExists, isHeartAbsent, probeLeash, projectTell, readHeart, readLatestTurnForBody, readOpenBoundTurns, readOpenPendingTellDisposition, readTell, readTurn, readNonterminalRequests, resolvePendingTellDisposition, } from "./heart/index.js";
|
|
8
8
|
import { worldRootForAkumaPaths } from "./identity.js";
|
|
9
9
|
import { akumaExecutionEnvironment } from "./providers/execution-environment.js";
|
|
10
10
|
import { pluginRuntime } from "../plugin/runtime.js";
|
|
@@ -291,7 +291,9 @@ function turnOutcomeEmitter(launch, soul) {
|
|
|
291
291
|
return {
|
|
292
292
|
async emit(turnSequence, outcome) {
|
|
293
293
|
try {
|
|
294
|
-
const
|
|
294
|
+
const turn = await readTurn(launch.paths, turnSequence);
|
|
295
|
+
if (turn === null)
|
|
296
|
+
throw new Error(`Committed Turn ${turnSequence} is missing from Heart`);
|
|
295
297
|
plugins ??= pluginRuntime({
|
|
296
298
|
world: await World.at(worldRootForAkumaPaths(launch.paths)),
|
|
297
299
|
reportDiagnostic,
|
|
@@ -299,8 +301,9 @@ function turnOutcomeEmitter(launch, soul) {
|
|
|
299
301
|
await (await plugins).emit({
|
|
300
302
|
kind: "akuma.turn-outcome",
|
|
301
303
|
akumaId: soul.id,
|
|
304
|
+
bodySequence: turn.bodySequence,
|
|
302
305
|
turnSequence,
|
|
303
|
-
...(initiator === undefined ? {} : { initiator }),
|
|
306
|
+
...(turn.initiator === undefined ? {} : { initiator: turn.initiator }),
|
|
304
307
|
outcome: outcome.outcome === "answered"
|
|
305
308
|
? { kind: "answered", text: outcome.answer }
|
|
306
309
|
: { kind: "failed", reason: outcome.diagnostic },
|
|
@@ -320,6 +323,7 @@ function bodyEndEmitter(launch, soul) {
|
|
|
320
323
|
};
|
|
321
324
|
return (bodySequence, end, diagnostic) => (async () => {
|
|
322
325
|
try {
|
|
326
|
+
const initiator = (await readLatestTurnForBody(launch.paths, bodySequence))?.initiator;
|
|
323
327
|
plugins ??= pluginRuntime({
|
|
324
328
|
world: await World.at(worldRootForAkumaPaths(launch.paths)),
|
|
325
329
|
reportDiagnostic,
|
|
@@ -330,6 +334,7 @@ function bodyEndEmitter(launch, soul) {
|
|
|
330
334
|
akumaId: soul.id,
|
|
331
335
|
bodySequence,
|
|
332
336
|
end,
|
|
337
|
+
...(initiator === undefined ? {} : { initiator }),
|
|
333
338
|
...(diagnostic === undefined ? {} : { diagnostic }),
|
|
334
339
|
...(launch.completion?.contractId === undefined ? {} : { contractId: launch.completion.contractId }),
|
|
335
340
|
}, reportDiagnostic);
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { type AkumaStatus } from "./akuma.js";
|
|
1
|
+
import { type AkumaStatus, type TellResult } from "./akuma.js";
|
|
2
|
+
import { type LiveStatusObservation } from "./akuma-observe.js";
|
|
2
3
|
import type { ActivityRow } from "./projection.js";
|
|
3
4
|
import { type DispatchAssociation } from "./dispatch-association.js";
|
|
4
5
|
import type { AkumaAlias } from "../identity/selector.js";
|
|
5
6
|
import type { WorldRoot } from "../world.js";
|
|
6
|
-
import { type AkumaKillResult, type AkumaTellResult, type AkumaWaitResult } from "./fleet-observation.js";
|
|
7
|
+
import { type AkumaKillResult, type AkumaTellResult, type AkumaTellWaitResult, type AkumaWaitResult } from "./fleet-observation.js";
|
|
7
8
|
export type WaitIdentityFacts = Readonly<{
|
|
8
9
|
/** The alias currently addressing this Akuma in its world, when one is bound to it. */
|
|
9
10
|
alias?: AkumaAlias;
|
|
@@ -40,6 +41,10 @@ export type WaitExecutionInput = Readonly<{
|
|
|
40
41
|
observe?: (observed: readonly WaitObservedAkuma[]) => void;
|
|
41
42
|
}>;
|
|
42
43
|
export declare function executeWaitAkuma(input: WaitExecutionInput): Promise<AkumaWaitResult>;
|
|
44
|
+
export type TellWaitObserver = Readonly<{
|
|
45
|
+
admitted?: (tell: TellResult, id: AkumaStatus["id"]) => void | Promise<void>;
|
|
46
|
+
observe?: (observation: LiveStatusObservation) => void | Promise<void>;
|
|
47
|
+
}>;
|
|
43
48
|
export type TellExecutionInput = Readonly<{
|
|
44
49
|
path: WorldRoot;
|
|
45
50
|
id: AkumaStatus["id"];
|
|
@@ -48,8 +53,14 @@ export type TellExecutionInput = Readonly<{
|
|
|
48
53
|
recordedAt?: string;
|
|
49
54
|
initiator?: string;
|
|
50
55
|
signal?: AbortSignal;
|
|
56
|
+
onObserve?: TellWaitObserver;
|
|
51
57
|
}>;
|
|
52
58
|
export declare function executeTellAkuma(input: TellExecutionInput): Promise<AkumaTellResult>;
|
|
59
|
+
export declare function executeTellWaitAkuma(input: TellExecutionInput & Readonly<{
|
|
60
|
+
timeoutMs: number;
|
|
61
|
+
schemaJson?: string;
|
|
62
|
+
interrupt?: boolean;
|
|
63
|
+
}>): Promise<AkumaTellWaitResult>;
|
|
53
64
|
export type KillExecutionInput = Readonly<{
|
|
54
65
|
path: WorldRoot;
|
|
55
66
|
ids: readonly AkumaStatus["id"][];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AkumaDecodeError, AkumaProviderError } from "./akuma-errors.js";
|
|
1
2
|
import { AkumaNotBornError, defaultWaitComplete } from "./akuma.js";
|
|
2
3
|
import { createAkumaProduct } from "./akuma-product.js";
|
|
3
4
|
import { readLiveStatus, waitForObservation } from "./akuma-observe.js";
|
|
@@ -125,6 +126,50 @@ export async function executeTellAkuma(input) {
|
|
|
125
126
|
tell,
|
|
126
127
|
});
|
|
127
128
|
}
|
|
129
|
+
function tellWaitObservation(observed) {
|
|
130
|
+
if (observed.outcome === null)
|
|
131
|
+
return observed.reason === "deadline" ? { reason: "deadline" } : { reason: "unanswered" };
|
|
132
|
+
if (observed.outcome.kind === "answered")
|
|
133
|
+
return { reason: "answered", answer: observed.outcome.answerJson ?? observed.outcome.answer };
|
|
134
|
+
if (observed.outcome.kind === "failed")
|
|
135
|
+
return { reason: "failed", diagnostic: observed.outcome.diagnostic };
|
|
136
|
+
throw new AkumaDecodeError(observed.outcome.diagnostic, observed.outcome.answer);
|
|
137
|
+
}
|
|
138
|
+
export async function executeTellWaitAkuma(input) {
|
|
139
|
+
input.signal?.throwIfAborted();
|
|
140
|
+
const handle = source(input.path).selectHandle({ id: input.id });
|
|
141
|
+
const admission = input.interrupt === true
|
|
142
|
+
? await handle.admitInterrupt(input.body, {
|
|
143
|
+
...(input.tellId === undefined ? {} : { tellId: input.tellId }),
|
|
144
|
+
...(input.schemaJson === undefined ? {} : { schemaJson: input.schemaJson }),
|
|
145
|
+
...(input.initiator === undefined ? {} : { initiator: input.initiator }),
|
|
146
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
147
|
+
})
|
|
148
|
+
: await handle.admitTell(input.body, input.tellId, input.recordedAt, undefined, {
|
|
149
|
+
...(input.schemaJson === undefined ? {} : { schemaJson: input.schemaJson }),
|
|
150
|
+
...(input.initiator === undefined ? {} : { initiator: input.initiator }),
|
|
151
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
152
|
+
});
|
|
153
|
+
if (admission.kind === "unavailable")
|
|
154
|
+
throw new AkumaProviderError(`Tell interrupt unavailable: ${admission.evidence}`);
|
|
155
|
+
if (admission.kind === "not-born")
|
|
156
|
+
throw new AkumaNotBornError(input.id);
|
|
157
|
+
await input.onObserve?.admitted?.(await handle.admittedReceipt(admission.tell.id), input.id);
|
|
158
|
+
// The wake runs behind the window; a settled wake is preferred, otherwise the
|
|
159
|
+
// receipt reports the admitted Tell as it stands when the window closes.
|
|
160
|
+
let settled;
|
|
161
|
+
void admission.wake.then((receipt) => {
|
|
162
|
+
settled = receipt;
|
|
163
|
+
}, () => undefined);
|
|
164
|
+
const observed = await handle.tellOutcome(admission.tell.id, {
|
|
165
|
+
timeoutMs: input.timeoutMs,
|
|
166
|
+
...(input.signal === undefined ? {} : { signal: input.signal }),
|
|
167
|
+
...(input.onObserve?.observe === undefined ? {} : { observe: input.onObserve.observe }),
|
|
168
|
+
});
|
|
169
|
+
const observation = tellWaitObservation(observed);
|
|
170
|
+
const tell = settled ?? (await handle.admittedReceipt(admission.tell.id));
|
|
171
|
+
return fleetResultSchemas.tellWait.parse({ akuma: input.id, tell, observation });
|
|
172
|
+
}
|
|
128
173
|
export async function executeKillAkuma(input) {
|
|
129
174
|
input.signal?.throwIfAborted();
|
|
130
175
|
const handles = input.ids.map((id) => source(input.path).selectHandle({ id }));
|