@astrosheep/keiyaku 4.6.10 → 4.6.12
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/plugins/claude/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/skills/keiyaku/SKILL.md +3 -1
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/src/akuma/akuma-errors.d.ts +5 -0
- package/build/src/akuma/akuma-errors.js +9 -0
- package/build/src/akuma/akuma-owner.d.ts +14 -19
- package/build/src/akuma/akuma-owner.js +56 -54
- package/build/src/akuma/akuma-selection-execution.d.ts +5 -4
- package/build/src/akuma/akuma-selection-execution.js +59 -17
- package/build/src/akuma/akuma.d.ts +1 -2
- package/build/src/akuma/allowed.d.ts +2 -3
- package/build/src/akuma/allowed.js +1 -3
- package/build/src/akuma/body.js +17 -7
- package/build/src/akuma/call-initial-tell.d.ts +18 -0
- package/build/src/akuma/call-initial-tell.js +18 -0
- package/build/src/akuma/call-request.d.ts +20 -4
- package/build/src/akuma/heart/facts.d.ts +13 -0
- package/build/src/akuma/heart/facts.js +6 -0
- package/build/src/akuma/heart/index.d.ts +29 -14
- package/build/src/akuma/heart/index.js +75 -29
- package/build/src/akuma/heart/rows.d.ts +9 -2
- package/build/src/akuma/heart/rows.js +72 -11
- package/build/src/akuma/heart/storage.d.ts +2 -8
- package/build/src/akuma/heart/storage.js +13 -13
- package/build/src/akuma/heart/tells.d.ts +3 -1
- package/build/src/akuma/heart/tells.js +18 -2
- package/build/src/akuma/provider.d.ts +2 -4
- package/build/src/akuma/provider.js +29 -6
- package/build/src/akuma/providers/acp/core.js +23 -21
- package/build/src/akuma/providers/claude/index.js +0 -8
- package/build/src/akuma/providers/codex-app-server/index.js +9 -8
- package/build/src/akuma/providers/execution-environment.d.ts +1 -1
- package/build/src/akuma/providers/execution-environment.js +1 -0
- package/build/src/akuma/providers/opencode-sdk/events.js +111 -81
- package/build/src/akuma/providers/opencode-sdk/index.js +179 -150
- package/build/src/akuma/providers/opencode-sdk/native-http.js +7 -3
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +5 -3
- package/build/src/akuma/providers/opencode-sdk/session.js +32 -27
- package/build/src/akuma/providers/paseo/index.js +0 -2
- package/build/src/akuma/providers/pi/index.js +13 -17
- package/build/src/akuma/selection-observation.d.ts +78 -9
- package/build/src/akuma/selection-owner-port.d.ts +2 -1
- package/build/src/akuma/selection-owner-port.js +6 -1
- package/build/src/akuma/selection-request.d.ts +1 -1
- package/build/src/akuma/selection-request.js +8 -3
- package/build/src/akuma/turn-drive.js +79 -48
- package/build/src/akuma-body.js +5 -3
- package/build/src/cli/commands/akuma-grammar.js +2 -2
- package/build/src/cli/commands/akuma.js +24 -16
- package/build/src/cli/commands/contract-grammar.d.ts +3 -7
- package/build/src/cli/commands/contract-grammar.js +12 -10
- package/build/src/cli/commands/contract-help.d.ts +3 -13
- package/build/src/cli/commands/contract-help.js +7 -16
- package/build/src/cli/commands/contract.js +19 -35
- package/build/src/cli/commands/debt.js +30 -29
- package/build/src/cli/parse.js +0 -1
- package/build/src/cli/render/akuma-activity.d.ts +35 -8
- package/build/src/cli/render/akuma-activity.js +132 -52
- package/build/src/cli/render/akuma.d.ts +6 -0
- package/build/src/cli/render/akuma.js +67 -24
- package/build/src/cli/render/contract-observation.d.ts +16 -3
- package/build/src/cli/render/contract-observation.js +3 -0
- package/build/src/cli/render/contract.d.ts +2 -2
- package/build/src/cli/render/contract.js +4 -4
- package/build/src/cli/render/delivery-preview.d.ts +7 -0
- package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
- package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
- package/build/src/cli/render/kanshi-akuma.js +23 -8
- package/build/src/cli/render/kanshi.js +4 -0
- package/build/src/cli/render/receipt.js +3 -3
- package/build/src/cli/render/refusal.js +2 -2
- package/build/src/cli/square-identity.d.ts +15 -0
- package/build/src/cli/square-identity.js +180 -0
- package/build/src/contract-worktree.js +1 -1
- package/build/src/core/verbs/placement.d.ts +2 -1
- package/build/src/core/verbs/placement.js +1 -1
- package/build/src/debt/context.d.ts +0 -5
- package/build/src/debt/context.js +32 -44
- package/build/src/git/process.d.ts +1 -0
- package/build/src/git/process.js +18 -1
- package/build/src/git/read-observation.js +2 -1
- package/build/src/git/scratch.d.ts +5 -1
- package/build/src/git/scratch.js +41 -12
- package/build/src/git/target-placement.d.ts +22 -4
- package/build/src/git/target-placement.js +44 -20
- package/build/src/index.d.ts +2 -2
- package/build/src/kanshi/read.js +187 -105
- package/build/src/kanshi/report.d.ts +5 -0
- package/build/src/library/address.d.ts +18 -4
- package/build/src/library/address.js +27 -6
- package/build/src/library/contract-address.d.ts +6 -0
- package/build/src/library/contract-address.js +12 -1
- package/build/src/library/contract-execution.d.ts +2 -2
- package/build/src/library/contract-execution.js +13 -17
- package/build/src/library/contract-operations.d.ts +59 -94
- package/build/src/library/contract-operations.js +23 -19
- package/build/src/library/contract-outcomes.d.ts +3 -3
- package/build/src/library/contract-settings.d.ts +1 -0
- package/build/src/library/contract-settings.js +1 -1
- package/build/src/library/invocation.d.ts +2 -2
- package/build/src/library/invocation.js +1 -1
- package/build/src/library/keiyaku.d.ts +2 -2
- package/build/src/library/keiyaku.js +2 -2
- package/build/src/library/outcome.d.ts +148 -268
- package/build/src/library/outcome.js +4 -8
- package/build/src/library/refusal.d.ts +2 -2
- package/build/src/library/refusal.js +2 -2
- package/build/src/plugin/runtime.js +16 -21
- package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
- package/build/src/protocol/delivery-preview.js +167 -0
- package/build/src/protocol/progress.d.ts +1 -1
- package/build/src/runtime/proc/run.js +22 -4
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/verification/execution.js +5 -3
- package/package.json +4 -2
- package/skills/keiyaku/SKILL.md +3 -1
- package/skills/keiyaku-babysit/SKILL.md +1 -1
- package/skills/keiyaku-bind/SKILL.md +3 -2
- package/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/src/cli/render/audit.d.ts +0 -7
- package/build/src/protocol/audit.js +0 -203
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { DatabaseSync } from "node:sqlite";
|
|
3
|
-
import type { BodyEnd, BodyFact, CallFact, KillFact, PauseFact, ResumeCoordinate, SessionFact, StopFact, TurnFact, TurnStartFact, TurnEndFact } from "./facts.js";
|
|
3
|
+
import type { BodyEnd, BodyFact, CallFact, InterruptCompletion, KillFact, PauseFact, ResumeCoordinate, SessionFact, StopFact, TurnFact, TurnStartFact, TurnEndFact } from "./facts.js";
|
|
4
4
|
import { type AgentEvent } from "./activity-schema.js";
|
|
5
5
|
export type SealRow = Readonly<{
|
|
6
6
|
evidence: string;
|
|
@@ -136,9 +136,16 @@ export declare function insertActivityFact(database: DatabaseSync, input: Readon
|
|
|
136
136
|
at: string;
|
|
137
137
|
}>): number;
|
|
138
138
|
export declare function insertStopControl(database: DatabaseSync, bodySequence: number, at: string): void;
|
|
139
|
-
export declare function
|
|
139
|
+
export declare function insertInterruptBarrier(database: DatabaseSync, input: Readonly<{
|
|
140
|
+
bodySequence: number;
|
|
141
|
+
tellId: string;
|
|
142
|
+
at: string;
|
|
143
|
+
}>): PauseFact;
|
|
144
|
+
export declare function completeInterruptBarrier(database: DatabaseSync, expected?: PauseFact, consume?: boolean): InterruptCompletion;
|
|
140
145
|
export declare function stopFact(database: DatabaseSync): StopFact | null;
|
|
141
146
|
export declare function pauseFact(database: DatabaseSync): PauseFact | null;
|
|
147
|
+
export declare function bodyFact(database: DatabaseSync, sequence: number): BodyFact | null;
|
|
148
|
+
export declare function isTellProtectedByPause(database: DatabaseSync, tellId: string, bodySequence: number): boolean;
|
|
142
149
|
export declare function insertKillFact(database: DatabaseSync, bodySequence: number, at: string): void;
|
|
143
150
|
export declare function endBodyFact(database: DatabaseSync, input: Readonly<{
|
|
144
151
|
sequence: number;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { providerOptionsSchema, withoutModel } from "../provider-recipe.js";
|
|
3
3
|
import { resumeCoordinateSchema } from "../coordinate.js";
|
|
4
|
+
import { HeartAuthorityCorruptionError } from "./facts.js";
|
|
4
5
|
import { decodeResumeCoordinate, encodeResumeCoordinate as encodeCoordinate } from "../coordinate.js";
|
|
5
6
|
import { agentEventSchema } from "./activity-schema.js";
|
|
6
7
|
const sessionText = z.string().refine((value) => value.trim() !== "");
|
|
@@ -160,13 +161,40 @@ export function insertStopControl(database, bodySequence, at) {
|
|
|
160
161
|
.prepare("INSERT OR IGNORE INTO control(kind, value_json, at) VALUES ('stop', ?, ?)")
|
|
161
162
|
.run(json({ bodySequence }), at);
|
|
162
163
|
}
|
|
163
|
-
export function
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
164
|
+
export function insertInterruptBarrier(database, input) {
|
|
165
|
+
const value = json({ bodySequence: input.bodySequence, frontierTellId: input.tellId });
|
|
166
|
+
database.prepare("INSERT INTO control(kind, value_json, at) VALUES ('pause', ?, ?)").run(value, input.at);
|
|
167
|
+
return { bodySequence: input.bodySequence, requestedAt: input.at, frontierTellId: input.tellId };
|
|
168
|
+
}
|
|
169
|
+
export function completeInterruptBarrier(database, expected, consume = true) {
|
|
170
|
+
const barrier = pauseFact(database);
|
|
171
|
+
if (expected !== undefined && barrier !== null && !samePause(barrier, expected))
|
|
172
|
+
return settledPreviousBarrier(database, expected);
|
|
173
|
+
if (barrier === null) {
|
|
174
|
+
if (expected === undefined)
|
|
175
|
+
return { kind: "clear" };
|
|
176
|
+
return settledPreviousBarrier(database, expected);
|
|
177
|
+
}
|
|
178
|
+
const latest = latestBodyFact(database);
|
|
179
|
+
if (latest?.sequence !== barrier.bodySequence)
|
|
180
|
+
return { kind: "unavailable", evidence: "untidy" };
|
|
181
|
+
if (latest.hung !== undefined)
|
|
182
|
+
return { kind: "unavailable", evidence: "hung" };
|
|
183
|
+
if (latest.end === undefined || !consume)
|
|
184
|
+
return { kind: "unavailable", evidence: "untidy" };
|
|
185
|
+
deletePauseControl(database);
|
|
186
|
+
return { kind: "completed", body: latest };
|
|
187
|
+
}
|
|
188
|
+
function settledPreviousBarrier(database, expected) {
|
|
189
|
+
const previous = bodyFact(database, expected.bodySequence);
|
|
190
|
+
if (previous?.hung !== undefined)
|
|
191
|
+
return { kind: "unavailable", evidence: "hung" };
|
|
192
|
+
if (previous?.end !== undefined)
|
|
193
|
+
return { kind: "completed", body: previous };
|
|
194
|
+
return { kind: "unavailable", evidence: "untidy" };
|
|
195
|
+
}
|
|
196
|
+
function samePause(left, right) {
|
|
197
|
+
return left.bodySequence === right.bodySequence && left.frontierTellId === right.frontierTellId;
|
|
170
198
|
}
|
|
171
199
|
export function stopFact(database) {
|
|
172
200
|
const row = database.prepare("SELECT value_json, at FROM control WHERE kind = 'stop'").get();
|
|
@@ -178,15 +206,48 @@ export function stopFact(database) {
|
|
|
178
206
|
}
|
|
179
207
|
return { bodySequence: value.bodySequence, requestedAt: row.at };
|
|
180
208
|
}
|
|
209
|
+
const pauseControlSchema = z
|
|
210
|
+
.object({ bodySequence: z.number().int().positive(), frontierTellId: sessionText.optional() })
|
|
211
|
+
.strict();
|
|
181
212
|
export function pauseFact(database) {
|
|
182
213
|
const row = database.prepare("SELECT value_json, at FROM control WHERE kind = 'pause'").get();
|
|
183
214
|
if (row === undefined)
|
|
184
215
|
return null;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
216
|
+
let value;
|
|
217
|
+
try {
|
|
218
|
+
value = pauseControlSchema.parse(parsed(row.value_json));
|
|
188
219
|
}
|
|
189
|
-
|
|
220
|
+
catch (error) {
|
|
221
|
+
throw new HeartAuthorityCorruptionError("Akuma pause control is malformed", { cause: error });
|
|
222
|
+
}
|
|
223
|
+
if (value.frontierTellId !== undefined) {
|
|
224
|
+
const tell = database.prepare("SELECT 1 FROM tells WHERE id = ?").get(value.frontierTellId);
|
|
225
|
+
if (tell === undefined)
|
|
226
|
+
throw new HeartAuthorityCorruptionError("Akuma pause control references a missing Tell frontier");
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
bodySequence: value.bodySequence,
|
|
230
|
+
requestedAt: row.at,
|
|
231
|
+
...(value.frontierTellId === undefined ? {} : { frontierTellId: value.frontierTellId }),
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
export function bodyFact(database, sequence) {
|
|
235
|
+
const row = database
|
|
236
|
+
.prepare(`SELECT sequence, leash_taken_at, hung_diagnostic, hung_at, end, ended_at FROM bodies WHERE sequence = ?`)
|
|
237
|
+
.get(sequence);
|
|
238
|
+
return row === undefined ? null : decodeBodyRow(row);
|
|
239
|
+
}
|
|
240
|
+
export function isTellProtectedByPause(database, tellId, bodySequence) {
|
|
241
|
+
const pause = pauseFact(database);
|
|
242
|
+
if (pause?.bodySequence !== bodySequence)
|
|
243
|
+
return false;
|
|
244
|
+
if (pause.frontierTellId === undefined)
|
|
245
|
+
return true;
|
|
246
|
+
const tell = database.prepare("SELECT sequence FROM tells WHERE id = ?").get(tellId);
|
|
247
|
+
const frontier = database.prepare("SELECT sequence FROM tells WHERE id = ?").get(pause.frontierTellId);
|
|
248
|
+
if (tell === undefined || frontier === undefined)
|
|
249
|
+
throw new HeartAuthorityCorruptionError("Akuma pause control references a missing Tell frontier");
|
|
250
|
+
return tell.sequence >= frontier.sequence;
|
|
190
251
|
}
|
|
191
252
|
export function insertKillFact(database, bodySequence, at) {
|
|
192
253
|
database
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import type { AkumaPaths } from "../identity.js";
|
|
3
|
-
import type { BodyFact, LeashProbe, SessionFact, Soul, StopFact, TellFact } from "./facts.js";
|
|
3
|
+
import type { BodyFact, InterruptCompletion, LeashProbe, PauseFact, SessionFact, Soul, StopFact, TellFact } from "./facts.js";
|
|
4
4
|
import { sealFact } from "./rows.js";
|
|
5
5
|
export declare class HeartAbsentError extends Error {
|
|
6
6
|
readonly path: string;
|
|
@@ -43,8 +43,8 @@ export declare class HeldAkumaLeash {
|
|
|
43
43
|
at: string;
|
|
44
44
|
}>): Promise<"born" | "sealed">;
|
|
45
45
|
readSeal(): ReturnType<typeof sealFact>;
|
|
46
|
-
clearPause(paths: AkumaPaths): Promise<void>;
|
|
47
46
|
clearStop(paths: AkumaPaths): Promise<void>;
|
|
47
|
+
completeInterruptBarrier(paths: AkumaPaths, expected?: PauseFact): Promise<InterruptCompletion>;
|
|
48
48
|
recordBody(paths: AkumaPaths, input: Readonly<{
|
|
49
49
|
leashTakenAt: string;
|
|
50
50
|
}>): Promise<BodyFact>;
|
|
@@ -57,12 +57,6 @@ export declare class HeldAkumaLeash {
|
|
|
57
57
|
target: StopFact;
|
|
58
58
|
result: "recorded" | "already-killed";
|
|
59
59
|
}> | null>;
|
|
60
|
-
recordInterruptTell(paths: AkumaPaths, tell: Omit<TellFact, "sequence" | "state" | "deliveries" | "binding">): Promise<Readonly<{
|
|
61
|
-
kind: "not-born";
|
|
62
|
-
} | {
|
|
63
|
-
kind: "recorded";
|
|
64
|
-
tell: TellFact;
|
|
65
|
-
}>>;
|
|
66
60
|
release(): void;
|
|
67
61
|
}
|
|
68
62
|
export declare function probeLeash(paths: AkumaPaths): Promise<LeashProbe>;
|
|
@@ -2,8 +2,9 @@ import { DatabaseSync } from "node:sqlite";
|
|
|
2
2
|
import { lstat } from "node:fs/promises";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import { setTimeout } from "node:timers/promises";
|
|
5
|
+
import { BodyControlledError } from "./facts.js";
|
|
5
6
|
import { HEART_SCHEMA, LEASH_SCHEMA, assertHeartSchemaVersion, assertLeashSchemaVersion, heartSchemaIsCurrent, } from "./schema.js";
|
|
6
|
-
import {
|
|
7
|
+
import { deleteStopControl, completeInterruptBarrier as judgeInterruptBarrier, insertBodyFact, insertKillFact, insertSealFact, insertSessionFact, killFactForBody, latestBodyFact, latestKillFact, markBodyHung, sealExists, sealFact, stopFact, } from "./rows.js";
|
|
7
8
|
import { insertTellFact } from "./tells.js";
|
|
8
9
|
import { pruneActivityFacts } from "./timeline.js";
|
|
9
10
|
import { insertSoulFact, soulFact } from "./soul.js";
|
|
@@ -269,16 +270,23 @@ export class HeldAkumaLeash {
|
|
|
269
270
|
readSeal() {
|
|
270
271
|
return sealFact(this.database);
|
|
271
272
|
}
|
|
272
|
-
async clearPause(paths) {
|
|
273
|
-
await withHeartTransaction(paths, deletePauseControl);
|
|
274
|
-
}
|
|
275
273
|
async clearStop(paths) {
|
|
276
274
|
await withHeartTransaction(paths, deleteStopControl);
|
|
277
275
|
}
|
|
276
|
+
async completeInterruptBarrier(paths, expected) {
|
|
277
|
+
if (this.closed)
|
|
278
|
+
throw new Error("Akuma interrupt completion requires a held leash");
|
|
279
|
+
return await withHeartTransaction(paths, (heart) => judgeInterruptBarrier(heart, expected));
|
|
280
|
+
}
|
|
278
281
|
async recordBody(paths, input) {
|
|
279
282
|
if (this.closed || this.bodySequence !== undefined)
|
|
280
283
|
throw new Error("Akuma leash cannot start another Body");
|
|
281
|
-
const sequence = await withHeartTransaction(paths, (heart) =>
|
|
284
|
+
const sequence = await withHeartTransaction(paths, (heart) => {
|
|
285
|
+
const completion = judgeInterruptBarrier(heart);
|
|
286
|
+
if (completion.kind === "unavailable")
|
|
287
|
+
throw new BodyControlledError();
|
|
288
|
+
return insertBodyFact(heart, input);
|
|
289
|
+
});
|
|
282
290
|
this.bodySequence = sequence;
|
|
283
291
|
return { sequence, leashTakenAt: input.leashTakenAt };
|
|
284
292
|
}
|
|
@@ -314,14 +322,6 @@ export class HeldAkumaLeash {
|
|
|
314
322
|
return { target, result };
|
|
315
323
|
});
|
|
316
324
|
}
|
|
317
|
-
async recordInterruptTell(paths, tell) {
|
|
318
|
-
return await withHeartTransaction(paths, (heart) => {
|
|
319
|
-
deletePauseControl(heart);
|
|
320
|
-
if (soulFact(heart) === null)
|
|
321
|
-
return { kind: "not-born" };
|
|
322
|
-
return recordPendingTell(heart, tell);
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
325
|
release() {
|
|
326
326
|
if (this.closed)
|
|
327
327
|
return;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PauseFact } from "./facts.js";
|
|
1
2
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
3
|
import { type TellDelivery, type TellDeliveryInput, type TellFact, type TellReceiptInput } from "./facts.js";
|
|
3
4
|
type TellRow = Readonly<{
|
|
@@ -37,6 +38,7 @@ export declare function tellBatchAtSequences(database: DatabaseSync, sequences:
|
|
|
37
38
|
export declare function hasPendingTell(database: DatabaseSync): boolean;
|
|
38
39
|
export declare function insertTellFact(database: DatabaseSync, tell: Omit<TellFact, "sequence" | "state" | "deliveries">): number;
|
|
39
40
|
export declare function tellFact(database: DatabaseSync, id: string): TellFact | null;
|
|
41
|
+
export declare function sameTellInput(existing: TellFact, tell: Omit<TellFact, "sequence" | "state" | "deliveries" | "binding">): boolean;
|
|
40
42
|
export declare function insertTellDeliveryFact(database: DatabaseSync, input: TellDeliveryInput): boolean;
|
|
41
43
|
export declare function insertTellReceiptFact(database: DatabaseSync, input: TellReceiptInput): boolean;
|
|
42
44
|
export declare function tellIdsForFence(database: DatabaseSync, turnSequence: number, fence: string): readonly string[];
|
|
@@ -58,6 +60,6 @@ export declare function insertTellBindingFact(database: DatabaseSync, input: Rea
|
|
|
58
60
|
boundAt: string;
|
|
59
61
|
}>): void;
|
|
60
62
|
export declare function turnParticipants(database: DatabaseSync, turnSequence: number): readonly string[];
|
|
61
|
-
export declare function drainPendingTells(pending: readonly TellFact[], activeTurnSequences?: readonly number[]): readonly TellFact[];
|
|
63
|
+
export declare function drainPendingTells(pending: readonly TellFact[], activeTurnSequences?: readonly number[], pause?: PauseFact | null, bodySequence?: number): readonly TellFact[];
|
|
62
64
|
export declare function openBoundTurns(database: DatabaseSync, bodySequence: number): readonly number[];
|
|
63
65
|
export {};
|
|
@@ -92,6 +92,12 @@ export function tellFact(database, id) {
|
|
|
92
92
|
.get(id);
|
|
93
93
|
return row === undefined ? null : decodeTellRows(database, [row])[0];
|
|
94
94
|
}
|
|
95
|
+
export function sameTellInput(existing, tell) {
|
|
96
|
+
return (existing.body === tell.body &&
|
|
97
|
+
existing.recordedAt === tell.recordedAt &&
|
|
98
|
+
existing.schemaJson === tell.schemaJson &&
|
|
99
|
+
existing.initiator === tell.initiator);
|
|
100
|
+
}
|
|
95
101
|
export function insertTellDeliveryFact(database, input) {
|
|
96
102
|
const result = database
|
|
97
103
|
.prepare(`INSERT OR IGNORE INTO tell_deliveries(
|
|
@@ -228,8 +234,18 @@ export function turnParticipants(database, turnSequence) {
|
|
|
228
234
|
}
|
|
229
235
|
return [...participants];
|
|
230
236
|
}
|
|
231
|
-
export function drainPendingTells(pending, activeTurnSequences = []) {
|
|
232
|
-
|
|
237
|
+
export function drainPendingTells(pending, activeTurnSequences = [], pause, bodySequence) {
|
|
238
|
+
let available = pending;
|
|
239
|
+
if (pause !== undefined && pause !== null && pause.bodySequence === bodySequence) {
|
|
240
|
+
if (pause.frontierTellId === undefined) {
|
|
241
|
+
available = [];
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
const frontier = pending.find((tell) => tell.id === pause.frontierTellId);
|
|
245
|
+
available = frontier === undefined ? [] : pending.filter((tell) => tell.sequence < frontier.sequence);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const eligible = available.filter((tell) => tell.binding === undefined || !activeTurnSequences.includes(tell.binding.turnSequence));
|
|
233
249
|
if (eligible.length === 0)
|
|
234
250
|
return [];
|
|
235
251
|
const first = eligible[0];
|
|
@@ -37,6 +37,8 @@ export declare class AgentEventChannel implements AsyncIterable<AgentEvent> {
|
|
|
37
37
|
private overflowCount;
|
|
38
38
|
private ended;
|
|
39
39
|
emit(event: AgentEvent): void;
|
|
40
|
+
/** Narration and protected slots; the reserved model slot is not one of them. */
|
|
41
|
+
private narrationCount;
|
|
40
42
|
end(): void;
|
|
41
43
|
[Symbol.asyncIterator](): AsyncIterator<AgentEvent>;
|
|
42
44
|
}
|
|
@@ -88,10 +90,6 @@ export type Session = Readonly<{
|
|
|
88
90
|
events: AsyncIterable<AgentEvent>;
|
|
89
91
|
receipts?: AsyncIterable<TellReceipt>;
|
|
90
92
|
completion: Promise<TurnResult>;
|
|
91
|
-
/** Requests graceful adapter-owned cancellation. */
|
|
92
|
-
abort(): Promise<void>;
|
|
93
|
-
/** Fulfills only after forced adapter-owned disposal is proved. */
|
|
94
|
-
forceDispose(): Promise<void>;
|
|
95
93
|
tell?(tell: Readonly<{
|
|
96
94
|
id: string;
|
|
97
95
|
text: string;
|
|
@@ -213,8 +213,11 @@ export function unknownEvent(kind) {
|
|
|
213
213
|
return { type: "unknown", kind };
|
|
214
214
|
}
|
|
215
215
|
// Slow consumers may lose reconstructible narration, but session coordinates,
|
|
216
|
-
// notes,
|
|
217
|
-
//
|
|
216
|
+
// notes, error events, and the latest runtime-model observation stay
|
|
217
|
+
// observable. The one queue reserves a single model slot, so that observation
|
|
218
|
+
// never competes for narration admission and no overflow can hide the model a
|
|
219
|
+
// Turn proved it ran. A full protected queue replaces one protected item with a
|
|
220
|
+
// bounded aggregate note; `end` ignores later emission.
|
|
218
221
|
function isErrorEvent(event) {
|
|
219
222
|
if (event.type === "note")
|
|
220
223
|
return true;
|
|
@@ -222,8 +225,11 @@ function isErrorEvent(event) {
|
|
|
222
225
|
return event.result.status === "error";
|
|
223
226
|
return event.type === "unknown" && /(?:error|fail|abort|cancel|stop|terminal)/iu.test(event.kind);
|
|
224
227
|
}
|
|
228
|
+
function isModelEvent(event) {
|
|
229
|
+
return event.type === "model";
|
|
230
|
+
}
|
|
225
231
|
function isReconstructibleEvent(event) {
|
|
226
|
-
return event.type !== "session" && !isErrorEvent(event);
|
|
232
|
+
return event.type !== "session" && !isModelEvent(event) && !isErrorEvent(event);
|
|
227
233
|
}
|
|
228
234
|
const AGENT_EVENT_OVERFLOW_PREFIX = "Agent event queue overflow";
|
|
229
235
|
function overflowEvent(count) {
|
|
@@ -243,7 +249,20 @@ export class AgentEventChannel {
|
|
|
243
249
|
waiter.resolve({ done: false, value: event });
|
|
244
250
|
return;
|
|
245
251
|
}
|
|
246
|
-
if (
|
|
252
|
+
if (isModelEvent(event)) {
|
|
253
|
+
// Model evidence is control state, never narration: it occupies the
|
|
254
|
+
// queue's one reserved model slot, so a narration flood and a full
|
|
255
|
+
// protected queue both leave it observable. An unconsumed predecessor is
|
|
256
|
+
// obsolete, and superseding it is what keeps the newest fact, an unnamed
|
|
257
|
+
// one clearing the confirmation it disconfirms.
|
|
258
|
+
const obsolete = this.queued.findIndex(isModelEvent);
|
|
259
|
+
if (obsolete === -1)
|
|
260
|
+
this.queued.push(event);
|
|
261
|
+
else
|
|
262
|
+
this.queued[obsolete] = event;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (this.narrationCount() >= AGENT_EVENT_QUEUE_LIMIT) {
|
|
247
266
|
const reconstructible = this.queued.findIndex(isReconstructibleEvent);
|
|
248
267
|
if (reconstructible === -1) {
|
|
249
268
|
if (isReconstructibleEvent(event))
|
|
@@ -259,8 +278,8 @@ export class AgentEventChannel {
|
|
|
259
278
|
}
|
|
260
279
|
this.overflowMarker = undefined;
|
|
261
280
|
}
|
|
262
|
-
const
|
|
263
|
-
const replacement =
|
|
281
|
+
const protectedItem = this.queued.findIndex((queued) => queued.type !== "session" && !isModelEvent(queued));
|
|
282
|
+
const replacement = protectedItem === -1 ? this.queued.findIndex((queued) => !isModelEvent(queued)) : protectedItem;
|
|
264
283
|
this.overflowCount += 1;
|
|
265
284
|
const marker = overflowEvent(this.overflowCount);
|
|
266
285
|
this.queued[replacement] = marker;
|
|
@@ -271,6 +290,10 @@ export class AgentEventChannel {
|
|
|
271
290
|
}
|
|
272
291
|
this.queued.push(event);
|
|
273
292
|
}
|
|
293
|
+
/** Narration and protected slots; the reserved model slot is not one of them. */
|
|
294
|
+
narrationCount() {
|
|
295
|
+
return this.queued.length - Number(this.queued.some(isModelEvent));
|
|
296
|
+
}
|
|
274
297
|
end() {
|
|
275
298
|
if (this.ended)
|
|
276
299
|
return;
|
|
@@ -160,25 +160,6 @@ function beginAcpPrompt(context, child, turn, sessionId, input) {
|
|
|
160
160
|
admission: { fence: sessionId },
|
|
161
161
|
events: turn.events,
|
|
162
162
|
completion: turn.completion,
|
|
163
|
-
abort: async () => {
|
|
164
|
-
let result = { kind: "failed", diagnostic: "ACP turn cancelled" };
|
|
165
|
-
try {
|
|
166
|
-
await agent.notify(acp.methods.agent.session.cancel, { sessionId });
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
result = { kind: "failed", diagnostic: diagnostic(acp, error) };
|
|
170
|
-
}
|
|
171
|
-
if (!turn.open())
|
|
172
|
-
await child.close(true);
|
|
173
|
-
else
|
|
174
|
-
await turn.finish(result, () => child.close(true));
|
|
175
|
-
},
|
|
176
|
-
forceDispose: async () => {
|
|
177
|
-
if (!turn.open())
|
|
178
|
-
await child.close(true);
|
|
179
|
-
else
|
|
180
|
-
await turn.finish({ kind: "failed", diagnostic: "ACP turn force-disposed" }, () => child.close(true));
|
|
181
|
-
},
|
|
182
163
|
};
|
|
183
164
|
}
|
|
184
165
|
export async function startAcpSession(launch, input, dependencies = {}, custody) {
|
|
@@ -190,10 +171,12 @@ export async function startAcpSession(launch, input, dependencies = {}, custody)
|
|
|
190
171
|
cwd: input.cwd,
|
|
191
172
|
env: akumaExecutionEnvironment(globalThis.process.env, launch.env, input.requests?.dir),
|
|
192
173
|
});
|
|
174
|
+
let abortOwned = async () => await child.close(true);
|
|
175
|
+
let forceDisposeOwned = async () => await child.close(true);
|
|
193
176
|
custody?.own({
|
|
194
177
|
closed: child.exited.then(() => undefined),
|
|
195
|
-
abort:
|
|
196
|
-
forceDispose:
|
|
178
|
+
abort: () => abortOwned(),
|
|
179
|
+
forceDispose: () => forceDisposeOwned(),
|
|
197
180
|
});
|
|
198
181
|
let sessionId;
|
|
199
182
|
let turn;
|
|
@@ -205,6 +188,25 @@ export async function startAcpSession(launch, input, dependencies = {}, custody)
|
|
|
205
188
|
try {
|
|
206
189
|
sessionId = await abortable(establishSession(acp, connection.agent, input, dependencies, launch.sessionOptions ?? []), signal);
|
|
207
190
|
turn.events.emit({ type: "session", coordinate: { sessionId } });
|
|
191
|
+
abortOwned = async () => {
|
|
192
|
+
let result = { kind: "failed", diagnostic: "ACP turn cancelled" };
|
|
193
|
+
try {
|
|
194
|
+
await connection.agent.notify(acp.methods.agent.session.cancel, { sessionId: sessionId });
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
result = { kind: "failed", diagnostic: diagnostic(acp, error) };
|
|
198
|
+
}
|
|
199
|
+
if (!turn.open())
|
|
200
|
+
await child.close(true);
|
|
201
|
+
else
|
|
202
|
+
await turn.finish(result, () => child.close(true));
|
|
203
|
+
};
|
|
204
|
+
forceDisposeOwned = async () => {
|
|
205
|
+
if (!turn.open())
|
|
206
|
+
await child.close(true);
|
|
207
|
+
else
|
|
208
|
+
await turn.finish({ kind: "failed", diagnostic: "ACP turn force-disposed" }, () => child.close(true));
|
|
209
|
+
};
|
|
208
210
|
const session = beginAcpPrompt({ acp, agent: connection.agent }, child, turn, sessionId, input);
|
|
209
211
|
return { session, agent: connection.agent, sessionId, open: turn.open };
|
|
210
212
|
}
|
|
@@ -343,14 +343,6 @@ async function driveClaude(load, execution, drive, custody) {
|
|
|
343
343
|
receipts,
|
|
344
344
|
completion: observed.completion,
|
|
345
345
|
tell: claudeTell(input, observed, accepted, driveState, run),
|
|
346
|
-
async abort() {
|
|
347
|
-
shutDown(new Error("Claude query aborted"));
|
|
348
|
-
await observed.completion;
|
|
349
|
-
},
|
|
350
|
-
async forceDispose() {
|
|
351
|
-
shutDown(new Error("Claude query force-disposed"));
|
|
352
|
-
await observed.completion;
|
|
353
|
-
},
|
|
354
346
|
};
|
|
355
347
|
}
|
|
356
348
|
export function createClaudeProvider(loadOrExecution = async () => (await import("@anthropic-ai/claude-agent-sdk")), execution = {}) {
|
|
@@ -140,8 +140,6 @@ async function startCodex(execution, input, custody) {
|
|
|
140
140
|
const events = new AgentEventChannel();
|
|
141
141
|
const server = codexServer(execution, input);
|
|
142
142
|
const closed = new Promise((resolve) => server.onExit(() => resolve()));
|
|
143
|
-
const close = async () => await server.close(true);
|
|
144
|
-
custody.own({ closed, abort: close, forceDispose: close });
|
|
145
143
|
const state = { settled: false, tools: new Map() };
|
|
146
144
|
let settle;
|
|
147
145
|
const completion = new Promise((resolve) => {
|
|
@@ -159,6 +157,15 @@ async function startCodex(execution, input, custody) {
|
|
|
159
157
|
};
|
|
160
158
|
void server.endInputAndDrain().then(done, done);
|
|
161
159
|
};
|
|
160
|
+
custody.own({
|
|
161
|
+
closed,
|
|
162
|
+
abort: async () => await abortTurn(server, state, finish),
|
|
163
|
+
forceDispose: async () => {
|
|
164
|
+
if (!state.settled)
|
|
165
|
+
settle({ kind: "failed", diagnostic: "codex app-server force-disposed" });
|
|
166
|
+
await server.close(true);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
162
169
|
server.onNotification((notification) => {
|
|
163
170
|
const result = codexNotificationResult(notification, state, events);
|
|
164
171
|
if (result !== undefined)
|
|
@@ -202,12 +209,6 @@ async function startCodex(execution, input, custody) {
|
|
|
202
209
|
admission: { fence: state.turnId },
|
|
203
210
|
events,
|
|
204
211
|
completion,
|
|
205
|
-
abort: () => abortTurn(server, state, finish),
|
|
206
|
-
forceDispose: async () => {
|
|
207
|
-
if (!state.settled)
|
|
208
|
-
settle({ kind: "failed", diagnostic: "codex app-server force-disposed" });
|
|
209
|
-
await server.close(true);
|
|
210
|
-
},
|
|
211
212
|
tell: (tell) => steerTurn(server, state, tell),
|
|
212
213
|
};
|
|
213
214
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
|
|
2
2
|
export declare const AKUMA_REQUESTS_ENTRY_ENV = "AKUMA_REQUESTS_ENTRY";
|
|
3
|
-
declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME", "KEIYAKU_EXTERNAL_CALLER"];
|
|
3
|
+
declare const PARENT_HARNESS_IDENTITY_KEYS: readonly ["CLAUDE_CODE_SESSION_ID", "CLAUDE_CODE_CHILD_SESSION", "CLAUDECODE", "CODEX_THREAD_ID", "OPENCODE_SESSION_ID", "PI_SESSION_ID", "PI_SESSION_FILE", "PASEO_AGENT_ID", "SQUARE_PARTICIPANT_NAME", "KEIYAKU_INITIATOR", "KEIYAKU_EXTERNAL_CALLER"];
|
|
4
4
|
type Environment = Readonly<Record<string, string | undefined>>;
|
|
5
5
|
/** Construct the environment for one isolated Akuma execution or native child. */
|
|
6
6
|
export declare function akumaExecutionEnvironment(inherited: Environment, overrides?: Environment, requests?: string, nativeIdentity?: readonly (typeof PARENT_HARNESS_IDENTITY_KEYS)[number][]): Record<string, string>;
|