@astrosheep/keiyaku 4.0.4 → 4.0.6
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 +4 -4
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -7
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +5 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +24 -4
- package/build/src/akuma/akuma.d.ts +2 -1
- package/build/src/akuma/akuma.js +27 -9
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +3 -10
- package/build/src/akuma/archetype.d.ts +3 -1
- package/build/src/akuma/archetype.js +11 -6
- package/build/src/akuma/body-turn.d.ts +64 -0
- package/build/src/akuma/body-turn.js +449 -0
- package/build/src/akuma/body.d.ts +4 -5
- package/build/src/akuma/body.js +9 -414
- package/build/src/akuma/heart/facts.d.ts +37 -9
- package/build/src/akuma/heart/facts.js +3 -1
- package/build/src/akuma/heart/index.d.ts +4 -13
- package/build/src/akuma/heart/index.js +14 -135
- package/build/src/akuma/heart/request-authority.d.ts +12 -0
- package/build/src/akuma/heart/request-authority.js +119 -0
- package/build/src/akuma/heart/request-rows.d.ts +16 -0
- package/build/src/akuma/heart/request-rows.js +88 -0
- package/build/src/akuma/heart/rows.d.ts +1 -28
- package/build/src/akuma/heart/rows.js +4 -138
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +11 -3
- package/build/src/akuma/heart/soul.js +0 -36
- package/build/src/akuma/heart/timeline.d.ts +1 -0
- package/build/src/akuma/heart/timeline.js +19 -0
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/nuke.d.ts +2 -0
- package/build/src/akuma/nuke.js +152 -0
- package/build/src/akuma/provider-recipe.js +1 -11
- package/build/src/akuma/provider.d.ts +4 -7
- package/build/src/akuma/providers/acp/config.d.ts +8 -0
- package/build/src/akuma/providers/acp/config.js +37 -0
- package/build/src/akuma/providers/acp/core.js +12 -2
- package/build/src/akuma/providers/acp/index.d.ts +1 -8
- package/build/src/akuma/providers/acp/index.js +2 -38
- package/build/src/akuma/providers/claude/index.d.ts +0 -4
- package/build/src/akuma/providers/claude/index.js +12 -3
- package/build/src/akuma/providers/codex-app-server/index.d.ts +2 -27
- package/build/src/akuma/providers/codex-app-server/index.js +5 -2
- package/build/src/akuma/providers/grok-build/index.js +1 -2
- package/build/src/akuma/providers/index.d.ts +3 -2
- package/build/src/akuma/providers/index.js +36 -36
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +2 -28
- package/build/src/akuma/providers/opencode-sdk/index.js +14 -4
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +2 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +2 -2
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +29 -6
- package/build/src/akuma/request-serve.d.ts +88 -0
- package/build/src/akuma/request-serve.js +484 -0
- package/build/src/akuma/request-wire.d.ts +125 -0
- package/build/src/akuma/request-wire.js +383 -0
- package/build/src/akuma/requests.d.ts +28 -94
- package/build/src/akuma/requests.js +52 -562
- package/build/src/akuma-body.d.ts +7 -0
- package/build/src/akuma-body.js +69 -2
- package/build/src/alias/index.d.ts +1 -0
- package/build/src/alias/index.js +34 -1
- package/build/src/body/arc.js +4 -29
- package/build/src/body/decode.js +5 -39
- package/build/src/body/envelope.d.ts +7 -0
- package/build/src/body/envelope.js +37 -0
- package/build/src/cli/accepted.js +21 -9
- package/build/src/cli/commands/akuma-invoke.js +1 -0
- package/build/src/cli/commands/akuma.d.ts +1 -0
- package/build/src/cli/commands/akuma.js +13 -10
- package/build/src/cli/commands/contract.d.ts +28 -17
- package/build/src/cli/commands/contract.js +23 -17
- package/build/src/cli/commands/install.d.ts +2 -2
- package/build/src/cli/commands/install.js +6 -6
- package/build/src/cli/commands/nuke.d.ts +10 -0
- package/build/src/cli/commands/nuke.js +20 -0
- package/build/src/cli/commands/task-invoke.d.ts +15 -0
- package/build/src/cli/commands/task-invoke.js +144 -24
- package/build/src/cli/commands/task-query.d.ts +2 -2
- package/build/src/cli/commands/task-query.js +1 -2
- package/build/src/cli/commands/task.js +22 -22
- package/build/src/cli/coordinates.d.ts +6 -2
- package/build/src/cli/coordinates.js +12 -56
- package/build/src/cli/invoke.d.ts +5 -4
- package/build/src/cli/invoke.js +112 -58
- package/build/src/cli/main.d.ts +0 -2
- package/build/src/cli/main.js +4 -140
- package/build/src/cli/parse.d.ts +17 -4
- package/build/src/cli/parse.js +93 -15
- package/build/src/cli/render/akuma.js +111 -53
- package/build/src/cli/render/audit.js +2 -6
- package/build/src/cli/render/contract.js +61 -20
- package/build/src/cli/render/kanshi.js +15 -5
- package/build/src/cli/render/nuke.d.ts +3 -0
- package/build/src/cli/render/nuke.js +8 -0
- package/build/src/cli/render/receipt.js +28 -1
- package/build/src/cli/render/refusal.d.ts +2 -1
- package/build/src/cli/render/refusal.js +31 -0
- package/build/src/cli/render/terminal.d.ts +0 -2
- package/build/src/cli/render/terminal.js +0 -29
- package/build/src/cli/render/text.js +6 -1
- package/build/src/cli/result.d.ts +36 -9
- package/build/src/cli/runtime.d.ts +2 -0
- package/build/src/cli/runtime.js +140 -0
- package/build/src/cli/usage.d.ts +0 -2
- package/build/src/cli/usage.js +0 -4
- package/build/src/contract-worktree.d.ts +29 -14
- package/build/src/contract-worktree.js +131 -70
- package/build/src/core/facts/codec.js +9 -0
- package/build/src/core/facts/fold.js +13 -1
- package/build/src/core/facts/types.d.ts +8 -1
- package/build/src/core/subject.js +4 -3
- package/build/src/core/verbs/placement.d.ts +9 -1
- package/build/src/core/verbs/placement.js +24 -6
- package/build/src/core/verbs/reintegrate.d.ts +13 -0
- package/build/src/core/verbs/reintegrate.js +24 -0
- package/build/src/dispatch/index.d.ts +1 -1
- package/build/src/git/admission.d.ts +2 -1
- package/build/src/git/hooks.d.ts +2 -0
- package/build/src/git/hooks.js +34 -1
- package/build/src/git/integration.d.ts +9 -2
- package/build/src/git/integration.js +92 -1
- package/build/src/git/nuke.d.ts +2 -0
- package/build/src/git/nuke.js +97 -0
- package/build/src/git/observe.d.ts +2 -1
- package/build/src/git/observe.js +6 -5
- package/build/src/git/process.d.ts +28 -0
- package/build/src/git/process.js +94 -0
- package/build/src/git/read-observation.d.ts +2 -1
- package/build/src/git/read-observation.js +3 -2
- package/build/src/git/reconcile.d.ts +4 -1
- package/build/src/git/reconcile.js +42 -8
- package/build/src/git/repository.d.ts +2 -29
- package/build/src/git/repository.js +7 -118
- package/build/src/git/scratch.d.ts +1 -1
- package/build/src/git/scratch.js +1 -1
- package/build/src/git/target-placement.d.ts +3 -2
- package/build/src/git/target-placement.js +15 -14
- package/build/src/git/tender.d.ts +2 -1
- package/build/src/git/tender.js +4 -3
- package/build/src/git/terminal-seal.d.ts +2 -2
- package/build/src/git/terminal-seal.js +3 -6
- package/build/src/git/workspace.d.ts +4 -1
- package/build/src/git/workspace.js +1 -1
- package/build/src/index.d.ts +1 -2
- package/build/src/index.js +1 -1
- package/build/src/kanshi/read.js +5 -1
- package/build/src/library/address.js +7 -1
- package/build/src/library/akuma-creation.d.ts +1 -0
- package/build/src/library/akuma-creation.js +8 -1
- package/build/src/library/audit.d.ts +3 -1
- package/build/src/library/audit.js +2 -1
- package/build/src/library/bind.d.ts +2 -1
- package/build/src/library/bind.js +1 -1
- package/build/src/library/configuration.d.ts +1 -1
- package/build/src/library/configuration.js +52 -18
- package/build/src/library/contract.d.ts +59 -4
- package/build/src/library/contract.js +195 -34
- package/build/src/library/delivery.d.ts +4 -2
- package/build/src/library/fleet.d.ts +27 -7
- package/build/src/library/fleet.js +79 -39
- package/build/src/library/input.d.ts +0 -1
- package/build/src/library/input.js +0 -5
- package/build/src/library/keiyaku.d.ts +6 -2
- package/build/src/library/keiyaku.js +2 -0
- package/build/src/library/mutation.d.ts +3 -1
- package/build/src/library/mutation.js +3 -0
- package/build/src/library/nuke.d.ts +14 -0
- package/build/src/library/nuke.js +54 -0
- package/build/src/library/reconcile.d.ts +2 -1
- package/build/src/library/reconcile.js +8 -3
- package/build/src/library/refusal.d.ts +10 -1
- package/build/src/library/region.d.ts +1 -1
- package/build/src/library/repo.d.ts +4 -1
- package/build/src/library/repo.js +10 -4
- package/build/src/protocol/abandon.d.ts +9 -0
- package/build/src/protocol/abandon.js +15 -0
- package/build/src/protocol/amend.d.ts +16 -0
- package/build/src/protocol/amend.js +77 -0
- package/build/src/protocol/arc.d.ts +6 -0
- package/build/src/protocol/arc.js +12 -0
- package/build/src/protocol/attempt.d.ts +2 -1
- package/build/src/protocol/audit.d.ts +53 -0
- package/build/src/protocol/audit.js +147 -0
- package/build/src/protocol/bind.d.ts +1 -1
- package/build/src/protocol/completion.d.ts +42 -0
- package/build/src/protocol/completion.js +183 -0
- package/build/src/protocol/deliver.d.ts +49 -0
- package/build/src/protocol/deliver.js +261 -0
- package/build/src/protocol/intent.d.ts +2 -1
- package/build/src/protocol/intent.js +8 -2
- package/build/src/protocol/operations.d.ts +93 -202
- package/build/src/protocol/operations.js +23 -642
- package/build/src/protocol/placement.d.ts +12 -13
- package/build/src/protocol/placement.js +8 -19
- package/build/src/protocol/read/status.d.ts +17 -5
- package/build/src/protocol/read/status.js +57 -13
- package/build/src/protocol/reconcile.d.ts +35 -0
- package/build/src/protocol/reconcile.js +41 -0
- package/build/src/protocol/reintegrate.d.ts +31 -0
- package/build/src/protocol/reintegrate.js +74 -0
- package/build/src/protocol/review.d.ts +34 -0
- package/build/src/protocol/review.js +156 -0
- package/build/src/protocol/run.d.ts +1 -1
- package/build/src/runtime/proc/run.js +9 -5
- package/build/src/settlement/fence.d.ts +3 -1
- package/build/src/settlement/fence.js +24 -0
- package/build/src/settlement/holder.d.ts +1 -1
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +1 -2
- package/build/src/task/board.d.ts +0 -1
- package/build/src/task/board.js +0 -3
- package/build/src/task/compose.d.ts +2 -2
- package/build/src/task/compose.js +13 -11
- package/build/src/task/context.d.ts +14 -2
- package/build/src/task/context.js +30 -7
- package/build/src/task/index.d.ts +7 -6
- package/build/src/task/index.js +17 -145
- package/build/src/task/input.d.ts +18 -0
- package/build/src/task/input.js +189 -0
- package/build/src/task/mutation.d.ts +44 -0
- package/build/src/task/mutation.js +93 -0
- package/build/src/task/operations.d.ts +14 -6
- package/build/src/task/operations.js +57 -57
- package/build/src/task/store.d.ts +1 -0
- package/build/src/task/store.js +91 -3
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/workspace-place.d.ts +3 -4
- package/build/src/workspace-place.js +26 -15
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DatabaseSync } from "node:sqlite";
|
|
2
2
|
export declare function assertHeartSchemaVersion(database: DatabaseSync): void;
|
|
3
3
|
export declare function assertLeashSchemaVersion(database: DatabaseSync): void;
|
|
4
|
-
export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version =
|
|
4
|
+
export declare const HEART_SCHEMA = "\n CREATE TABLE IF NOT EXISTS akuma_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 20)\n ) STRICT;\n INSERT OR IGNORE INTO akuma_schema(singleton, version) VALUES (1, 20);\n CREATE TABLE IF NOT EXISTS soul (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n soul_json TEXT NOT NULL CHECK (json_valid(soul_json))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS bodies (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n leash_taken_at TEXT NOT NULL,\n hung_diagnostic TEXT,\n hung_at TEXT,\n end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),\n ended_at TEXT,\n CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)\n OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS sessions (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n provider TEXT NOT NULL,\n coordinate_json TEXT NOT NULL CHECK (json_valid(coordinate_json)),\n cwd TEXT NOT NULL,\n options_json TEXT NOT NULL CHECK (json_valid(options_json)),\n admitted_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS turns (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n body_sequence INTEGER NOT NULL REFERENCES bodies(sequence),\n started_at TEXT NOT NULL,\n end_sequence INTEGER UNIQUE REFERENCES timeline(sequence) ON DELETE SET NULL,\n outcome TEXT CHECK (outcome IN ('answered', 'failed')),\n history_id TEXT UNIQUE,\n session_json TEXT CHECK (session_json IS NULL OR json_valid(session_json)),\n answer TEXT,\n diagnostic TEXT,\n completed_at TEXT,\n CHECK (\n (outcome = 'answered' AND session_json IS NOT NULL AND answer IS NOT NULL AND diagnostic IS NULL)\n OR (outcome = 'failed' AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NOT NULL)\n OR (outcome IS NULL AND end_sequence IS NULL AND history_id IS NULL AND session_json IS NULL AND answer IS NULL AND diagnostic IS NULL AND completed_at IS NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS timeline (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n kind TEXT NOT NULL CHECK (kind IN ('turn-start', 'call', 'activity', 'tell', 'turn-end'))\n ) STRICT;\n CREATE TABLE IF NOT EXISTS calls (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS activity (\n sequence INTEGER PRIMARY KEY REFERENCES timeline(sequence) ON DELETE CASCADE,\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n event_json TEXT NOT NULL CHECK (json_valid(event_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tells (\n id TEXT PRIMARY KEY,\n sequence INTEGER NOT NULL UNIQUE REFERENCES timeline(sequence) ON DELETE CASCADE,\n body TEXT NOT NULL,\n recorded_at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_deliveries (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n tell_id TEXT NOT NULL REFERENCES tells(id) ON DELETE CASCADE,\n route TEXT NOT NULL CHECK (route IN ('launch', 'live')),\n turn_sequence INTEGER NOT NULL REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT NOT NULL,\n receipt TEXT CHECK (receipt IN ('unavailable', 'required')),\n delivered_at TEXT NOT NULL,\n CHECK ((route = 'launch' AND receipt IS NULL) OR (route = 'live' AND receipt IS NOT NULL)),\n UNIQUE (tell_id, turn_sequence, fence)\n ) STRICT;\n CREATE TABLE IF NOT EXISTS tell_receipts (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n evidence TEXT NOT NULL CHECK (evidence IN ('exact', 'fence')),\n tell_id TEXT REFERENCES tells(id) ON DELETE CASCADE,\n turn_sequence INTEGER REFERENCES turns(sequence) ON DELETE CASCADE,\n fence TEXT,\n kind TEXT NOT NULL,\n received_at TEXT NOT NULL,\n CHECK (\n (evidence = 'exact' AND tell_id IS NOT NULL AND turn_sequence IS NULL AND fence IS NULL)\n OR (evidence = 'fence' AND tell_id IS NULL AND turn_sequence IS NOT NULL AND fence IS NOT NULL)\n )\n ) STRICT;\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_exact\n ON tell_receipts(tell_id, kind) WHERE evidence = 'exact';\n CREATE UNIQUE INDEX IF NOT EXISTS tell_receipts_fence\n ON tell_receipts(turn_sequence, fence, kind) WHERE evidence = 'fence';\n CREATE TABLE IF NOT EXISTS requests (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n id TEXT NOT NULL UNIQUE,\n requester TEXT NOT NULL,\n action TEXT NOT NULL CHECK (\n action IN (\n 'akuma.call', 'akuma.wait', 'akuma.tell', 'akuma.kill',\n 'contract.deliver', 'contract.review',\n 'task.add', 'task.addDocument', 'task.compose', 'task.update', 'task.start',\n 'task.stop', 'task.hold', 'task.resume', 'task.done', 'task.drop'\n )\n ),\n payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),\n admitted_at TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),\n child TEXT,\n service_json TEXT CHECK (service_json IS NULL OR json_valid(service_json)),\n diagnostic TEXT,\n evidence TEXT,\n CHECK (\n (state = 'admitted' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'reserved' AND action = 'akuma.call'\n AND child IS NOT NULL AND service_json IS NULL\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'served'\n AND ((action = 'akuma.call' AND child IS NOT NULL AND service_json IS NULL)\n OR (action != 'akuma.call' AND child IS NULL AND service_json IS NOT NULL))\n AND diagnostic IS NULL AND evidence IS NULL)\n OR (state = 'refused' AND child IS NULL AND service_json IS NULL AND diagnostic IS NOT NULL AND evidence IS NULL)\n OR (state = 'voided' AND child IS NULL AND service_json IS NULL AND diagnostic IS NULL AND evidence IS NOT NULL)\n )\n ) STRICT;\n CREATE TABLE IF NOT EXISTS control (\n kind TEXT PRIMARY KEY CHECK (kind IN ('stop', 'pause')),\n value_json TEXT NOT NULL CHECK (json_valid(value_json)),\n at TEXT NOT NULL\n ) STRICT;\n CREATE TABLE IF NOT EXISTS kills (\n sequence INTEGER PRIMARY KEY AUTOINCREMENT,\n body_sequence INTEGER NOT NULL UNIQUE REFERENCES bodies(sequence),\n evidence TEXT NOT NULL CHECK (evidence = 'killed'),\n at TEXT NOT NULL\n ) STRICT;\n";
|
|
5
5
|
export declare const LEASH_SCHEMA = "\n PRAGMA journal_mode=DELETE;\n CREATE TABLE IF NOT EXISTS leash_schema (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n version INTEGER NOT NULL CHECK (version = 4)\n ) STRICT;\n INSERT OR IGNORE INTO leash_schema(singleton, version) VALUES (1, 4);\n CREATE TABLE IF NOT EXISTS seal (\n singleton INTEGER PRIMARY KEY CHECK (singleton = 1),\n evidence TEXT NOT NULL,\n at TEXT NOT NULL\n ) STRICT;\n";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const HEART_SCHEMA_VERSION =
|
|
1
|
+
const HEART_SCHEMA_VERSION = 20;
|
|
2
2
|
const LEASH_SCHEMA_VERSION = 4;
|
|
3
3
|
function assertSchemaVersion(database, table, expected) {
|
|
4
4
|
const row = database.prepare(`SELECT version FROM ${table} WHERE singleton = 1`).get();
|
|
@@ -28,7 +28,8 @@ export const HEART_SCHEMA = `
|
|
|
28
28
|
hung_at TEXT,
|
|
29
29
|
end TEXT CHECK (end IN ('exited', 'broke-off', 'put-down')),
|
|
30
30
|
ended_at TEXT,
|
|
31
|
-
CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)
|
|
31
|
+
CHECK ((hung_diagnostic IS NULL AND hung_at IS NULL)
|
|
32
|
+
OR (hung_diagnostic IS NOT NULL AND hung_at IS NOT NULL))
|
|
32
33
|
) STRICT;
|
|
33
34
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
34
35
|
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -109,7 +110,14 @@ export const HEART_SCHEMA = `
|
|
|
109
110
|
sequence INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
110
111
|
id TEXT NOT NULL UNIQUE,
|
|
111
112
|
requester TEXT NOT NULL,
|
|
112
|
-
action TEXT NOT NULL CHECK (
|
|
113
|
+
action TEXT NOT NULL CHECK (
|
|
114
|
+
action IN (
|
|
115
|
+
'akuma.call', 'akuma.wait', 'akuma.tell', 'akuma.kill',
|
|
116
|
+
'contract.deliver', 'contract.review',
|
|
117
|
+
'task.add', 'task.addDocument', 'task.compose', 'task.update', 'task.start',
|
|
118
|
+
'task.stop', 'task.hold', 'task.resume', 'task.done', 'task.drop'
|
|
119
|
+
)
|
|
120
|
+
),
|
|
113
121
|
payload_json TEXT NOT NULL CHECK (json_valid(payload_json)),
|
|
114
122
|
admitted_at TEXT NOT NULL,
|
|
115
123
|
state TEXT NOT NULL CHECK (state IN ('admitted', 'reserved', 'served', 'refused', 'voided')),
|
|
@@ -6,9 +6,6 @@ function record(value) {
|
|
|
6
6
|
? value
|
|
7
7
|
: null;
|
|
8
8
|
}
|
|
9
|
-
function unknownKey(value, allowed) {
|
|
10
|
-
return Object.keys(value).find((key) => !allowed.includes(key));
|
|
11
|
-
}
|
|
12
9
|
function nonblank(value, what) {
|
|
13
10
|
if (typeof value !== "string" || value.trim().length === 0) {
|
|
14
11
|
throw new Error(`Akuma soul ${what} must be a nonblank string`);
|
|
@@ -28,14 +25,9 @@ function decodeOrigin(value) {
|
|
|
28
25
|
if (origin === null)
|
|
29
26
|
throw new Error("Akuma soul origin must be an object");
|
|
30
27
|
if (origin.kind === "direct") {
|
|
31
|
-
if (unknownKey(origin, ["kind"]) !== undefined)
|
|
32
|
-
throw new Error("Akuma soul direct origin must have only kind");
|
|
33
28
|
return { kind: "direct" };
|
|
34
29
|
}
|
|
35
30
|
if (origin.kind === "request") {
|
|
36
|
-
if (unknownKey(origin, ["kind", "parent", "requestId"]) !== undefined) {
|
|
37
|
-
throw new Error("Akuma soul request origin must have only kind, parent, and requestId");
|
|
38
|
-
}
|
|
39
31
|
return {
|
|
40
32
|
kind: "request",
|
|
41
33
|
parent: soulAkuIdentity(origin.parent, "request parent").id,
|
|
@@ -43,9 +35,6 @@ function decodeOrigin(value) {
|
|
|
43
35
|
};
|
|
44
36
|
}
|
|
45
37
|
if (origin.kind === "fork") {
|
|
46
|
-
if (unknownKey(origin, ["at", "kind", "parent"]) !== undefined) {
|
|
47
|
-
throw new Error("Akuma soul fork origin must have only kind, parent, and at");
|
|
48
|
-
}
|
|
49
38
|
return {
|
|
50
39
|
kind: "fork",
|
|
51
40
|
parent: soulAkuIdentity(origin.parent, "fork parent").id,
|
|
@@ -54,34 +43,10 @@ function decodeOrigin(value) {
|
|
|
54
43
|
}
|
|
55
44
|
throw new Error("Akuma soul origin must be direct, request, or fork");
|
|
56
45
|
}
|
|
57
|
-
function decodeConfinement(value) {
|
|
58
|
-
const confinement = record(value);
|
|
59
|
-
if (confinement === null)
|
|
60
|
-
throw new Error("Akuma soul confinement must be an object");
|
|
61
|
-
if (confinement.kind === "unconfined") {
|
|
62
|
-
if (unknownKey(confinement, ["kind"]) !== undefined)
|
|
63
|
-
throw new Error("Akuma soul unconfined confinement must have only kind");
|
|
64
|
-
return { kind: "unconfined" };
|
|
65
|
-
}
|
|
66
|
-
if (confinement.kind === "declared") {
|
|
67
|
-
if (unknownKey(confinement, ["kind", "writableRoots"]) !== undefined) {
|
|
68
|
-
throw new Error("Akuma soul declared confinement must have only kind and writableRoots");
|
|
69
|
-
}
|
|
70
|
-
if (!Array.isArray(confinement.writableRoots)
|
|
71
|
-
|| confinement.writableRoots.some((root) => typeof root !== "string" || root.trim().length === 0)) {
|
|
72
|
-
throw new Error("Akuma soul declared confinement writableRoots must be nonblank strings");
|
|
73
|
-
}
|
|
74
|
-
return { kind: "declared", writableRoots: [...confinement.writableRoots] };
|
|
75
|
-
}
|
|
76
|
-
throw new Error("Akuma soul confinement must be unconfined or declared");
|
|
77
|
-
}
|
|
78
46
|
function validateSoul(value) {
|
|
79
47
|
const soul = record(value);
|
|
80
48
|
if (soul === null)
|
|
81
49
|
throw new Error("Akuma soul must be an object");
|
|
82
|
-
if (unknownKey(soul, ["allowed", "archetype", "confinement", "createdAt", "cwd", "description", "id", "options", "origin", "provider", "readonly"]) !== undefined) {
|
|
83
|
-
throw new Error("Akuma soul has an unknown field");
|
|
84
|
-
}
|
|
85
50
|
const identity = soulAkuIdentity(soul.id, "id");
|
|
86
51
|
const id = identity.id;
|
|
87
52
|
const archetype = nonblank(soul.archetype, "name");
|
|
@@ -103,7 +68,6 @@ function validateSoul(value) {
|
|
|
103
68
|
...(restraint === undefined ? {} : { readonly: restraint }),
|
|
104
69
|
cwd: nonblank(soul.cwd, "cwd"),
|
|
105
70
|
origin: decodeOrigin(soul.origin),
|
|
106
|
-
confinement: decodeConfinement(soul.confinement),
|
|
107
71
|
allowed: effectiveAllowedActions(soul.allowed),
|
|
108
72
|
createdAt: nonblank(soul.createdAt, "createdAt"),
|
|
109
73
|
};
|
|
@@ -7,5 +7,6 @@ export type ActivityFactSlice = Readonly<{
|
|
|
7
7
|
lowestRetained: number | null;
|
|
8
8
|
highest: number | null;
|
|
9
9
|
}>;
|
|
10
|
+
export declare function lastActivityAt(database: DatabaseSync): string | null;
|
|
10
11
|
export declare function pruneActivityFacts(database: DatabaseSync, limit: number): void;
|
|
11
12
|
export declare function activityFactSlice(database: DatabaseSync): ActivityFactSlice;
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
import { decodeActivityRow, decodeCallRow, decodeTurnRow, } from "./rows.js";
|
|
2
2
|
import { decodeTellAtSequence, pendingTellProtectionSql, pendingTellSequencesSql } from "./tells.js";
|
|
3
|
+
export function lastActivityAt(database) {
|
|
4
|
+
const row = database.prepare(`SELECT CASE timeline.kind
|
|
5
|
+
WHEN 'turn-start' THEN started_turn.started_at
|
|
6
|
+
WHEN 'call' THEN calls.at
|
|
7
|
+
WHEN 'activity' THEN activity.at
|
|
8
|
+
WHEN 'tell' THEN tells.recorded_at
|
|
9
|
+
WHEN 'turn-end' THEN ended_turn.completed_at
|
|
10
|
+
END AS at
|
|
11
|
+
FROM timeline
|
|
12
|
+
LEFT JOIN turns AS started_turn ON timeline.kind = 'turn-start' AND started_turn.sequence = timeline.sequence
|
|
13
|
+
LEFT JOIN calls ON timeline.kind = 'call' AND calls.sequence = timeline.sequence
|
|
14
|
+
LEFT JOIN activity ON timeline.kind = 'activity' AND activity.sequence = timeline.sequence
|
|
15
|
+
LEFT JOIN tells ON timeline.kind = 'tell' AND tells.sequence = timeline.sequence
|
|
16
|
+
LEFT JOIN turns AS ended_turn ON timeline.kind = 'turn-end' AND ended_turn.end_sequence = timeline.sequence
|
|
17
|
+
ORDER BY timeline.sequence DESC LIMIT 1`).get();
|
|
18
|
+
if (row === undefined || row.at === null)
|
|
19
|
+
return null;
|
|
20
|
+
return row.at;
|
|
21
|
+
}
|
|
3
22
|
export function pruneActivityFacts(database, limit) {
|
|
4
23
|
const count = database.prepare("SELECT COUNT(*) AS count FROM timeline").get();
|
|
5
24
|
if (count.count <= limit + 500)
|
|
@@ -13,5 +13,5 @@ export type { AkumaList, AkumaListInput, AkumaListRow, AkumaStatus, ActivityHist
|
|
|
13
13
|
export type { ActiveToolRow, ClosedTurn, ClosedTurnRow, CompletedToolRow, HistoryCursor, HistoryPage, IdleSnapshotRow, OpenSnapshotRow, OpenTurn, OpenTurnRow, OutcomeRow, ReportedFileChange, RetainedWindow, Snapshot, SnapshotRow, TellRow, TurnLedger, TurnOutcome, TurnStartRow, UnsettledToolRow, } from "./akuma.js";
|
|
14
14
|
export type { AgentEvent, ToolCall, ToolEvent, ToolResult } from "./provider.js";
|
|
15
15
|
export type { AkuId } from "./identity.js";
|
|
16
|
-
export type {
|
|
16
|
+
export type { KillEvidence, ResumeCoordinate, TurnFact, } from "./heart/index.js";
|
|
17
17
|
export type { ProviderOptions, ReadonlyRestraint } from "./provider-recipe.js";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { lstat, readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { nukeAliases } from "../alias/index.js";
|
|
3
|
+
import { CONTROL_RESPONSE_MS } from "./body.js";
|
|
4
|
+
import { HeldAkumaLeash, readHeart, readKill, requestStop, } from "./heart/index.js";
|
|
5
|
+
import { akuIdFromDirectoryName, akumaPaths, akumaRunRoot, } from "./identity.js";
|
|
6
|
+
const POLL_MS = 25;
|
|
7
|
+
async function hasAkumaCustody(paths) {
|
|
8
|
+
try {
|
|
9
|
+
const value = await lstat(paths.heart);
|
|
10
|
+
return value.isFile() && !value.isSymbolicLink();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code !== "ENOENT")
|
|
14
|
+
throw error;
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function wait(milliseconds) {
|
|
19
|
+
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
20
|
+
}
|
|
21
|
+
async function takeLeashUntil(paths, deadline) {
|
|
22
|
+
for (;;) {
|
|
23
|
+
const leash = await HeldAkumaLeash.try(paths);
|
|
24
|
+
if (leash !== null)
|
|
25
|
+
return leash;
|
|
26
|
+
if (performance.now() >= deadline)
|
|
27
|
+
return null;
|
|
28
|
+
await wait(POLL_MS);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function stopRunningAkuma(entry) {
|
|
32
|
+
const request = await requestStop(entry.paths, new Date().toISOString());
|
|
33
|
+
const leash = await takeLeashUntil(entry.paths, performance.now() + CONTROL_RESPONSE_MS);
|
|
34
|
+
if (leash === null)
|
|
35
|
+
throw new Error(`Akuma ${entry.id} could not be stopped: unavailable`);
|
|
36
|
+
try {
|
|
37
|
+
if (request.kind === "already-killed" || request.kind === "already-stopped")
|
|
38
|
+
return leash;
|
|
39
|
+
if (await readKill(entry.paths, request.body.sequence) !== null)
|
|
40
|
+
return leash;
|
|
41
|
+
const current = await readHeart(entry.paths);
|
|
42
|
+
if (current.latestBody?.sequence !== request.body.sequence) {
|
|
43
|
+
if (await readKill(entry.paths, request.body.sequence) !== null)
|
|
44
|
+
return leash;
|
|
45
|
+
throw new Error(`Akuma ${entry.id} could not be stopped: unavailable`);
|
|
46
|
+
}
|
|
47
|
+
if (current.latestBody.end !== "put-down") {
|
|
48
|
+
await leash.clearStop(entry.paths);
|
|
49
|
+
throw new Error(`Akuma ${entry.id} could not be stopped: untidy`);
|
|
50
|
+
}
|
|
51
|
+
if (await leash.settleStop(entry.paths, request.body.sequence) === null) {
|
|
52
|
+
throw new Error(`Akuma ${entry.id} could not be stopped: unavailable`);
|
|
53
|
+
}
|
|
54
|
+
return leash;
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
leash.release();
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function removeRegularFile(path) {
|
|
62
|
+
try {
|
|
63
|
+
const value = await lstat(path);
|
|
64
|
+
if (value.isFile() && !value.isSymbolicLink())
|
|
65
|
+
await rm(path, { force: true });
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (error.code !== "ENOENT")
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async function removeAkumaEntry(entry) {
|
|
73
|
+
for (const path of [entry.paths.heart, entry.paths.log,
|
|
74
|
+
`${entry.paths.heart}-wal`, `${entry.paths.heart}-shm`]) {
|
|
75
|
+
await removeRegularFile(path);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function nukeAkumaEntries(world) {
|
|
79
|
+
const runRoot = akumaRunRoot(world);
|
|
80
|
+
let names;
|
|
81
|
+
try {
|
|
82
|
+
names = (await readdir(runRoot, { withFileTypes: true }))
|
|
83
|
+
.filter((entry) => entry.isDirectory())
|
|
84
|
+
.map((entry) => entry.name)
|
|
85
|
+
.sort();
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error.code === "ENOENT")
|
|
89
|
+
names = [];
|
|
90
|
+
else
|
|
91
|
+
throw error;
|
|
92
|
+
}
|
|
93
|
+
const entries = [];
|
|
94
|
+
for (const name of names) {
|
|
95
|
+
let physical;
|
|
96
|
+
try {
|
|
97
|
+
physical = akuIdFromDirectoryName(name);
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// The run root can contain bytes not produced by Keiyaku. Preserve them.
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const paths = akumaPaths({ runRoot, archetype: physical.archetype, suffix: physical.suffix });
|
|
104
|
+
if (!(await hasAkumaCustody(paths)))
|
|
105
|
+
continue;
|
|
106
|
+
entries.push({ id: physical.id, paths });
|
|
107
|
+
}
|
|
108
|
+
return entries;
|
|
109
|
+
}
|
|
110
|
+
export async function stopAkuma(world) {
|
|
111
|
+
const entries = await nukeAkumaEntries(world);
|
|
112
|
+
const held = [];
|
|
113
|
+
try {
|
|
114
|
+
for (const entry of entries) {
|
|
115
|
+
const snapshot = await readHeart(entry.paths);
|
|
116
|
+
const leash = snapshot.soul !== null && snapshot.latestBody?.end === undefined
|
|
117
|
+
? await stopRunningAkuma(entry)
|
|
118
|
+
: await takeLeashUntil(entry.paths, performance.now() + CONTROL_RESPONSE_MS);
|
|
119
|
+
if (leash === null)
|
|
120
|
+
throw new Error(`Akuma ${entry.id} could not be verified stopped`);
|
|
121
|
+
try {
|
|
122
|
+
const after = await readHeart(entry.paths);
|
|
123
|
+
if (after.soul === null || after.latestBody?.end !== undefined) {
|
|
124
|
+
held.push(leash);
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
throw new Error(`Akuma ${entry.id} stopped without a durable end`);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
leash.release();
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return async () => {
|
|
135
|
+
try {
|
|
136
|
+
await nukeAliases(world);
|
|
137
|
+
for (const entry of entries)
|
|
138
|
+
await removeAkumaEntry(entry);
|
|
139
|
+
}
|
|
140
|
+
finally {
|
|
141
|
+
for (const leash of held.reverse())
|
|
142
|
+
leash.release();
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
if (held.length !== entries.length) {
|
|
148
|
+
for (const leash of held.reverse())
|
|
149
|
+
leash.release();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -24,10 +24,6 @@ export function decodeProviderOptions(value) {
|
|
|
24
24
|
const options = record(value);
|
|
25
25
|
if (options === null)
|
|
26
26
|
throw new TypeError("provider options must be an object");
|
|
27
|
-
const allowed = ["effort", "model", "network", "readonly", "systemPrompt"];
|
|
28
|
-
const unknown = Object.keys(options).find((key) => !allowed.includes(key));
|
|
29
|
-
if (unknown !== undefined)
|
|
30
|
-
throw new TypeError(`provider options have unknown field ${unknown}`);
|
|
31
27
|
const model = optionText(options, "model", "refuse");
|
|
32
28
|
const effort = optionText(options, "effort", "refuse");
|
|
33
29
|
if (options.readonly !== undefined && options.readonly !== true) {
|
|
@@ -50,12 +46,10 @@ export function decodeReadonlyRestraint(value) {
|
|
|
50
46
|
const restraint = record(value);
|
|
51
47
|
if (restraint === null)
|
|
52
48
|
throw new TypeError("readonly restraint must be an object");
|
|
53
|
-
|
|
54
|
-
if (restraint.enforcement === "native" && keys.length === 1 && keys[0] === "enforcement") {
|
|
49
|
+
if (restraint.enforcement === "native") {
|
|
55
50
|
return Object.freeze({ enforcement: "native" });
|
|
56
51
|
}
|
|
57
52
|
if (restraint.enforcement === "none"
|
|
58
|
-
&& keys.length === 2 && keys[0] === "diagnostic" && keys[1] === "enforcement"
|
|
59
53
|
&& typeof restraint.diagnostic === "string" && restraint.diagnostic.trim().length > 0) {
|
|
60
54
|
return Object.freeze({ enforcement: "none", diagnostic: restraint.diagnostic });
|
|
61
55
|
}
|
|
@@ -69,10 +63,6 @@ export function decodeProviderRecipe(input) {
|
|
|
69
63
|
const value = record(input);
|
|
70
64
|
if (value === null)
|
|
71
65
|
throw new TypeError("provider execution must be an object");
|
|
72
|
-
const allowed = ["config", "env", "executable", "kind", "name"];
|
|
73
|
-
const unknown = Object.keys(value).find((key) => !allowed.includes(key));
|
|
74
|
-
if (unknown !== undefined)
|
|
75
|
-
throw new TypeError(`provider execution has unknown field ${unknown}`);
|
|
76
66
|
if (typeof value.name !== "string" || value.name.trim().length === 0) {
|
|
77
67
|
throw new TypeError("provider execution name must be a nonblank string");
|
|
78
68
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Confinement } from "./heart/index.js";
|
|
2
1
|
import { decodeResumeCoordinate, encodeResumeCoordinate, type ResumeCoordinate } from "./coordinate.js";
|
|
3
2
|
import type { ProviderOptions, ReadonlyRestraint } from "./provider-recipe.js";
|
|
4
3
|
export type { ResumeCoordinate } from "./coordinate.js";
|
|
@@ -122,8 +121,10 @@ export type Session = Readonly<{
|
|
|
122
121
|
events: AsyncIterable<AgentEvent>;
|
|
123
122
|
receipts?: AsyncIterable<TellReceipt>;
|
|
124
123
|
completion: Promise<TurnResult>;
|
|
125
|
-
/**
|
|
124
|
+
/** Requests graceful adapter-owned cancellation. */
|
|
126
125
|
abort(): Promise<void>;
|
|
126
|
+
/** Fulfills only after forced adapter-owned disposal is proved. */
|
|
127
|
+
forceDispose(): Promise<void>;
|
|
127
128
|
tell?(tell: Readonly<{
|
|
128
129
|
id: string;
|
|
129
130
|
text: string;
|
|
@@ -138,7 +139,7 @@ export type DriveInput = Readonly<{
|
|
|
138
139
|
cwd: string;
|
|
139
140
|
options: ProviderOptions;
|
|
140
141
|
signal: AbortSignal;
|
|
141
|
-
requests
|
|
142
|
+
requests: Readonly<{
|
|
142
143
|
dir: string;
|
|
143
144
|
}>;
|
|
144
145
|
}>;
|
|
@@ -151,10 +152,6 @@ export type ProviderOptionAdmission = Readonly<{
|
|
|
151
152
|
diagnostic: string;
|
|
152
153
|
}>;
|
|
153
154
|
export type ProviderAdapter = Readonly<{
|
|
154
|
-
confinement(input: Readonly<{
|
|
155
|
-
cwd: string;
|
|
156
|
-
options: ProviderOptions;
|
|
157
|
-
}>): Confinement;
|
|
158
155
|
admitOptions(options: ProviderOptions): ProviderOptionAdmission;
|
|
159
156
|
fork?(input: Readonly<{
|
|
160
157
|
session: ResumeCoordinate;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
function argumentName(value, key) {
|
|
2
|
+
const selected = value[key];
|
|
3
|
+
if (selected === undefined)
|
|
4
|
+
return undefined;
|
|
5
|
+
if (typeof selected !== "string" || selected.trim().length === 0) {
|
|
6
|
+
throw new TypeError(`ACP provider config ${key} must be a nonblank string`);
|
|
7
|
+
}
|
|
8
|
+
return selected;
|
|
9
|
+
}
|
|
10
|
+
export function decodeAcpConfig(value) {
|
|
11
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
12
|
+
throw new TypeError("ACP provider config must be an object");
|
|
13
|
+
}
|
|
14
|
+
const config = value;
|
|
15
|
+
const unknown = Object.keys(config)
|
|
16
|
+
.find((key) => !["argvBefore", "argvAfter", "effortArg", "modelArg", "systemPromptArg"].includes(key));
|
|
17
|
+
if (unknown !== undefined)
|
|
18
|
+
throw new TypeError(`ACP provider config has unknown field ${unknown}`);
|
|
19
|
+
if (!Array.isArray(config.argvBefore)
|
|
20
|
+
|| config.argvBefore.some((arg) => typeof arg !== "string" || arg.trim().length === 0)) {
|
|
21
|
+
throw new TypeError("ACP provider config argvBefore must be an array of nonblank strings");
|
|
22
|
+
}
|
|
23
|
+
if (!Array.isArray(config.argvAfter)
|
|
24
|
+
|| config.argvAfter.some((arg) => typeof arg !== "string" || arg.trim().length === 0)) {
|
|
25
|
+
throw new TypeError("ACP provider config argvAfter must be an array of nonblank strings");
|
|
26
|
+
}
|
|
27
|
+
const modelArg = argumentName(config, "modelArg");
|
|
28
|
+
const effortArg = argumentName(config, "effortArg");
|
|
29
|
+
const systemPromptArg = argumentName(config, "systemPromptArg");
|
|
30
|
+
return Object.freeze({
|
|
31
|
+
argvBefore: Object.freeze([...config.argvBefore]),
|
|
32
|
+
argvAfter: Object.freeze([...config.argvAfter]),
|
|
33
|
+
...(modelArg === undefined ? {} : { modelArg }),
|
|
34
|
+
...(effortArg === undefined ? {} : { effortArg }),
|
|
35
|
+
...(systemPromptArg === undefined ? {} : { systemPromptArg }),
|
|
36
|
+
});
|
|
37
|
+
}
|
|
@@ -2,7 +2,7 @@ import * as acp from "@agentclientprotocol/sdk";
|
|
|
2
2
|
import { Readable, Writable } from "node:stream";
|
|
3
3
|
import { spawnStdioProcess } from "../../../runtime/proc/stdio.js";
|
|
4
4
|
import { abortable } from "../../abort.js";
|
|
5
|
-
import { AgentEventChannel, } from "../../provider.js";
|
|
5
|
+
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
6
6
|
import { EMPTY_ACP_EVENT_STATE, flushAcpEvents, mapAcpUpdate, } from "./events.js";
|
|
7
7
|
function diagnostic(error) {
|
|
8
8
|
if (!(error instanceof Error))
|
|
@@ -122,6 +122,12 @@ function beginAcpPrompt(agent, child, turn, sessionId, input) {
|
|
|
122
122
|
else
|
|
123
123
|
await turn.finish(result, () => child.close(true));
|
|
124
124
|
},
|
|
125
|
+
forceDispose: async () => {
|
|
126
|
+
if (!turn.open())
|
|
127
|
+
await child.close(true);
|
|
128
|
+
else
|
|
129
|
+
await turn.finish({ kind: "failed", diagnostic: "ACP turn force-disposed" }, () => child.close(true));
|
|
130
|
+
},
|
|
125
131
|
};
|
|
126
132
|
}
|
|
127
133
|
export async function startAcpSession(launch, input, dependencies = {}) {
|
|
@@ -130,7 +136,11 @@ export async function startAcpSession(launch, input, dependencies = {}) {
|
|
|
130
136
|
const child = (dependencies.spawnProcess ?? spawnStdioProcess)({
|
|
131
137
|
argv: launch.argv,
|
|
132
138
|
cwd: input.cwd,
|
|
133
|
-
env: {
|
|
139
|
+
env: {
|
|
140
|
+
...globalThis.process.env,
|
|
141
|
+
...launch.env,
|
|
142
|
+
...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
|
|
143
|
+
},
|
|
134
144
|
});
|
|
135
145
|
let sessionId;
|
|
136
146
|
let turn;
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { ProviderAdapter } from "../../provider.js";
|
|
2
2
|
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
3
3
|
import { type AcpDependencies } from "./core.js";
|
|
4
|
-
export type AcpExecutionConfig
|
|
5
|
-
argvBefore: readonly string[];
|
|
6
|
-
argvAfter: readonly string[];
|
|
7
|
-
modelArg?: string;
|
|
8
|
-
effortArg?: string;
|
|
9
|
-
systemPromptArg?: string;
|
|
10
|
-
}>;
|
|
11
|
-
export declare function decodeAcpConfig(value: unknown): AcpExecutionConfig;
|
|
4
|
+
export { decodeAcpConfig, type AcpExecutionConfig } from "./config.js";
|
|
12
5
|
export declare function createAcpProvider(execution: ProviderExecution, dependencies?: AcpDependencies): ProviderAdapter;
|
|
@@ -1,41 +1,6 @@
|
|
|
1
|
+
import { decodeAcpConfig } from "./config.js";
|
|
1
2
|
import { startAcpSession } from "./core.js";
|
|
2
|
-
|
|
3
|
-
const selected = value[key];
|
|
4
|
-
if (selected === undefined)
|
|
5
|
-
return undefined;
|
|
6
|
-
if (typeof selected !== "string" || selected.trim().length === 0) {
|
|
7
|
-
throw new TypeError(`ACP provider config ${key} must be a nonblank string`);
|
|
8
|
-
}
|
|
9
|
-
return selected;
|
|
10
|
-
}
|
|
11
|
-
export function decodeAcpConfig(value) {
|
|
12
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
13
|
-
throw new TypeError("ACP provider config must be an object");
|
|
14
|
-
}
|
|
15
|
-
const config = value;
|
|
16
|
-
const unknown = Object.keys(config)
|
|
17
|
-
.find((key) => !["argvBefore", "argvAfter", "effortArg", "modelArg", "systemPromptArg"].includes(key));
|
|
18
|
-
if (unknown !== undefined)
|
|
19
|
-
throw new TypeError(`ACP provider config has unknown field ${unknown}`);
|
|
20
|
-
if (!Array.isArray(config.argvBefore)
|
|
21
|
-
|| config.argvBefore.some((arg) => typeof arg !== "string" || arg.trim().length === 0)) {
|
|
22
|
-
throw new TypeError("ACP provider config argvBefore must be an array of nonblank strings");
|
|
23
|
-
}
|
|
24
|
-
if (!Array.isArray(config.argvAfter)
|
|
25
|
-
|| config.argvAfter.some((arg) => typeof arg !== "string" || arg.trim().length === 0)) {
|
|
26
|
-
throw new TypeError("ACP provider config argvAfter must be an array of nonblank strings");
|
|
27
|
-
}
|
|
28
|
-
const modelArg = argumentName(config, "modelArg");
|
|
29
|
-
const effortArg = argumentName(config, "effortArg");
|
|
30
|
-
const systemPromptArg = argumentName(config, "systemPromptArg");
|
|
31
|
-
return Object.freeze({
|
|
32
|
-
argvBefore: Object.freeze([...config.argvBefore]),
|
|
33
|
-
argvAfter: Object.freeze([...config.argvAfter]),
|
|
34
|
-
...(modelArg === undefined ? {} : { modelArg }),
|
|
35
|
-
...(effortArg === undefined ? {} : { effortArg }),
|
|
36
|
-
...(systemPromptArg === undefined ? {} : { systemPromptArg }),
|
|
37
|
-
});
|
|
38
|
-
}
|
|
3
|
+
export { decodeAcpConfig } from "./config.js";
|
|
39
4
|
function optionAdmission(options, config) {
|
|
40
5
|
if (options.network !== undefined) {
|
|
41
6
|
return { kind: "refused", diagnostic: "ACP provider does not support the network option" };
|
|
@@ -86,7 +51,6 @@ export function createAcpProvider(execution, dependencies = {}) {
|
|
|
86
51
|
return (await startAcpSession(launch, input, dependencies)).session;
|
|
87
52
|
};
|
|
88
53
|
return {
|
|
89
|
-
confinement: () => ({ kind: "unconfined" }),
|
|
90
54
|
admitOptions: (options) => optionAdmission(options, config),
|
|
91
55
|
start: async (input) => await drive(input),
|
|
92
56
|
resume: async (input) => await drive(input),
|
|
@@ -21,10 +21,6 @@ export type ClaudeSdk = Readonly<{
|
|
|
21
21
|
}>;
|
|
22
22
|
export declare function createClaudeProvider(load: () => Promise<ClaudeSdk>, execution?: ClaudeExecution): ProviderAdapter;
|
|
23
23
|
export declare const claudeProvider: Readonly<{
|
|
24
|
-
confinement(input: Readonly<{
|
|
25
|
-
cwd: string;
|
|
26
|
-
options: ProviderOptions;
|
|
27
|
-
}>): import("../../index.js").Confinement;
|
|
28
24
|
admitOptions(options: ProviderOptions): import("../../provider.js").ProviderOptionAdmission;
|
|
29
25
|
fork?(input: Readonly<{
|
|
30
26
|
session: ResumeCoordinate;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { abortable } from "../../abort.js";
|
|
3
|
-
import { AgentEventChannel, } from "../../provider.js";
|
|
3
|
+
import { AKUMA_REQUESTS_ENV, AgentEventChannel, } from "../../provider.js";
|
|
4
4
|
import { emitClaudeMessage, } from "./events.js";
|
|
5
5
|
import { claudeUserMessage, createClaudeInput, isClaudeTurnEnded } from "./input.js";
|
|
6
6
|
export { CLAUDE_MESSAGE_DISPOSITIONS, CLAUDE_SYSTEM_DISPOSITIONS } from "./events.js";
|
|
@@ -61,8 +61,13 @@ function claudeQueryOptions(input, execution, abortController) {
|
|
|
61
61
|
return {
|
|
62
62
|
cwd: input.cwd,
|
|
63
63
|
abortController,
|
|
64
|
+
...(input.requests === undefined ? {} : { additionalDirectories: [input.requests.dir] }),
|
|
64
65
|
...(execution.executable === undefined ? {} : { pathToClaudeCodeExecutable: execution.executable }),
|
|
65
|
-
...(execution.env === undefined ? {} : { env: {
|
|
66
|
+
...((execution.env === undefined && input.requests === undefined) ? {} : { env: {
|
|
67
|
+
...process.env,
|
|
68
|
+
...execution.env,
|
|
69
|
+
...(input.requests === undefined ? {} : { [AKUMA_REQUESTS_ENV]: input.requests.dir }),
|
|
70
|
+
} }),
|
|
66
71
|
permissionMode: mode,
|
|
67
72
|
...(mode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {}),
|
|
68
73
|
settingSources: ["user", "project", "local"],
|
|
@@ -264,12 +269,16 @@ async function driveClaude(load, execution, drive) {
|
|
|
264
269
|
},
|
|
265
270
|
async abort() {
|
|
266
271
|
shutDown(new Error("Claude query aborted"));
|
|
272
|
+
await observed.completion;
|
|
273
|
+
},
|
|
274
|
+
async forceDispose() {
|
|
275
|
+
shutDown(new Error("Claude query force-disposed"));
|
|
276
|
+
await observed.completion;
|
|
267
277
|
},
|
|
268
278
|
};
|
|
269
279
|
}
|
|
270
280
|
export function createClaudeProvider(load, execution = {}) {
|
|
271
281
|
return {
|
|
272
|
-
confinement: () => ({ kind: "unconfined" }),
|
|
273
282
|
admitOptions: admitClaudeOptions,
|
|
274
283
|
fork: (input) => forkClaude(load, execution, input),
|
|
275
284
|
start: (input) => driveClaude(load, execution, input),
|
|
@@ -1,29 +1,4 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import type { ProviderExecution
|
|
1
|
+
import { type ProviderAdapter } from "../../provider.js";
|
|
2
|
+
import type { ProviderExecution } from "../../provider-recipe.js";
|
|
3
3
|
export { CODEX_ITEM_DISPOSITIONS, CODEX_NOTIFICATION_DISPOSITIONS } from "./events.js";
|
|
4
4
|
export declare function createCodexAppServerProvider(input?: string | ProviderExecution): ProviderAdapter;
|
|
5
|
-
export declare const codexAppServerProvider: Readonly<{
|
|
6
|
-
confinement(input: Readonly<{
|
|
7
|
-
cwd: string;
|
|
8
|
-
options: ProviderOptions;
|
|
9
|
-
}>): import("../../index.js").Confinement;
|
|
10
|
-
admitOptions(options: ProviderOptions): import("../../provider.js").ProviderOptionAdmission;
|
|
11
|
-
fork?(input: Readonly<{
|
|
12
|
-
session: import("../../coordinate.js").ResumeCoordinate;
|
|
13
|
-
at: string;
|
|
14
|
-
cwd: string;
|
|
15
|
-
}>): Promise<Readonly<{
|
|
16
|
-
session: import("../../coordinate.js").ResumeCoordinate;
|
|
17
|
-
}>>;
|
|
18
|
-
start(input: import("../../provider.js").DriveInput & Readonly<{
|
|
19
|
-
session: Readonly<{
|
|
20
|
-
kind: "fresh";
|
|
21
|
-
}>;
|
|
22
|
-
}>): Promise<Session>;
|
|
23
|
-
resume?(input: import("../../provider.js").DriveInput & Readonly<{
|
|
24
|
-
session: Readonly<{
|
|
25
|
-
kind: "resume";
|
|
26
|
-
coordinate: import("../../coordinate.js").ResumeCoordinate;
|
|
27
|
-
}>;
|
|
28
|
-
}>): Promise<Session>;
|
|
29
|
-
}>;
|