@astrosheep/keiyaku 4.0.6 → 4.1.1
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/README.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
- package/build/src/akuma/akuma.d.ts +17 -14
- package/build/src/akuma/akuma.js +122 -114
- package/build/src/akuma/allowed.d.ts +1 -0
- package/build/src/akuma/allowed.js +6 -0
- package/build/src/akuma/archetype.js +12 -2
- package/build/src/akuma/body-turn.js +27 -15
- package/build/src/akuma/body.d.ts +44 -3
- package/build/src/akuma/body.js +142 -33
- package/build/src/akuma/coordinate.js +17 -7
- package/build/src/akuma/heart/facts.js +1 -1
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/index.js +2 -4
- package/build/src/akuma/heart/request-authority.js +4 -4
- package/build/src/akuma/heart/request-rows.js +27 -16
- package/build/src/akuma/heart/rows.js +79 -41
- package/build/src/akuma/heart/soul.js +1 -1
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +76 -11
- package/build/src/akuma/heart/tells.js +35 -18
- package/build/src/akuma/heart/timeline.js +19 -11
- package/build/src/akuma/identity.d.ts +1 -0
- package/build/src/akuma/identity.js +1 -0
- package/build/src/akuma/index.d.ts +3 -3
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/nuke.js +106 -14
- package/build/src/akuma/projection.d.ts +11 -9
- package/build/src/akuma/projection.js +110 -53
- package/build/src/akuma/provider-recipe.d.ts +2 -0
- package/build/src/akuma/provider-recipe.js +21 -5
- package/build/src/akuma/provider.js +105 -62
- package/build/src/akuma/providers/acp/config.d.ts +2 -0
- package/build/src/akuma/providers/acp/config.js +13 -6
- package/build/src/akuma/providers/acp/core.d.ts +5 -2
- package/build/src/akuma/providers/acp/core.js +45 -25
- package/build/src/akuma/providers/acp/events.js +38 -29
- package/build/src/akuma/providers/acp/index.js +18 -8
- package/build/src/akuma/providers/claude/events.js +8 -12
- package/build/src/akuma/providers/claude/index.d.ts +2 -1
- package/build/src/akuma/providers/claude/index.js +59 -26
- package/build/src/akuma/providers/claude/input.js +6 -2
- package/build/src/akuma/providers/codex-app-server/events.js +61 -36
- package/build/src/akuma/providers/codex-app-server/index.js +29 -14
- package/build/src/akuma/providers/grok-build/index.js +28 -17
- package/build/src/akuma/providers/index.js +3 -19
- package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
- package/build/src/akuma/providers/opencode-sdk/index.js +29 -17
- package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
- package/build/src/akuma/providers/pi/events.js +26 -19
- package/build/src/akuma/providers/pi/index.js +58 -38
- package/build/src/akuma/publication.js +9 -9
- package/build/src/akuma/request-serve.js +37 -40
- package/build/src/akuma/request-wire.d.ts +2 -2
- package/build/src/akuma/request-wire.js +75 -102
- package/build/src/akuma/requests.js +2 -2
- package/build/src/akuma-body.js +6 -5
- package/build/src/body/amend.d.ts +4 -1
- package/build/src/body/amend.js +14 -15
- package/build/src/body/decode.js +2 -4
- package/build/src/body/envelope.js +2 -4
- package/build/src/body/region.d.ts +1 -2
- package/build/src/body/region.js +4 -72
- package/build/src/body/render.js +17 -12
- package/build/src/body/shape.js +1 -7
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +10 -1
- package/build/src/cli/commands/akuma-invoke.js +18 -6
- package/build/src/cli/commands/akuma.js +10 -13
- package/build/src/cli/commands/amend.d.ts +2 -2
- package/build/src/cli/commands/amend.js +2 -4
- package/build/src/cli/commands/bind.d.ts +4 -4
- package/build/src/cli/commands/bind.js +16 -6
- package/build/src/cli/commands/contract.d.ts +99 -10
- package/build/src/cli/commands/contract.js +128 -24
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +23 -15
- package/build/src/cli/commands/task-invoke.d.ts +4 -1
- package/build/src/cli/commands/task-invoke.js +191 -68
- package/build/src/cli/commands/task-query.js +48 -24
- package/build/src/cli/commands/task.js +150 -30
- package/build/src/cli/coordinates.js +2 -4
- package/build/src/cli/invoke.js +88 -44
- package/build/src/cli/main.js +4 -2
- package/build/src/cli/parse.d.ts +2 -89
- package/build/src/cli/parse.js +87 -79
- package/build/src/cli/render/akuma-tool-command.js +6 -7
- package/build/src/cli/render/akuma-tool.js +10 -8
- package/build/src/cli/render/akuma.js +149 -53
- package/build/src/cli/render/audit.js +5 -15
- package/build/src/cli/render/board.d.ts +1 -0
- package/build/src/cli/render/board.js +17 -0
- package/build/src/cli/render/catalog.js +84 -7
- package/build/src/cli/render/contract-observation.d.ts +10 -0
- package/build/src/cli/render/contract-observation.js +58 -0
- package/build/src/cli/render/contract.js +57 -54
- package/build/src/cli/render/kanshi.js +281 -209
- package/build/src/cli/render/receipt.d.ts +1 -0
- package/build/src/cli/render/receipt.js +20 -23
- package/build/src/cli/render/refusal.js +16 -15
- package/build/src/cli/render/region.js +22 -6
- package/build/src/cli/render/settings.js +4 -4
- package/build/src/cli/render/task.js +93 -21
- package/build/src/cli/render/terminal.js +16 -5
- package/build/src/cli/result.d.ts +11 -4
- package/build/src/cli/runtime.d.ts +6 -1
- package/build/src/cli/runtime.js +84 -63
- package/build/src/cli/selectors.js +2 -4
- package/build/src/cli/usage.js +6 -5
- package/build/src/contract-worktree.d.ts +1 -25
- package/build/src/contract-worktree.js +87 -174
- package/build/src/coordination/durable-file.js +7 -3
- package/build/src/coordination/sqlite-transaction-lock.js +29 -12
- package/build/src/core/facts/codec.js +7 -3
- package/build/src/core/facts/types.d.ts +1 -1
- package/build/src/core/subject.js +16 -9
- package/build/src/core/verbs/abandon.d.ts +1 -1
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +7 -7
- package/build/src/core/verbs/attestation.js +4 -1
- package/build/src/core/verbs/bind.d.ts +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +10 -8
- package/build/src/dispatch/index.js +8 -6
- package/build/src/duration.js +5 -1
- package/build/src/git/admission.js +5 -3
- package/build/src/git/hooks.d.ts +8 -0
- package/build/src/git/hooks.js +63 -14
- package/build/src/git/identity.js +1 -4
- package/build/src/git/integration.d.ts +2 -3
- package/build/src/git/integration.js +32 -39
- package/build/src/git/nuke.d.ts +1 -1
- package/build/src/git/nuke.js +110 -62
- package/build/src/git/observe.d.ts +13 -1
- package/build/src/git/observe.js +51 -44
- package/build/src/git/process.js +4 -2
- package/build/src/git/read-observation.js +10 -8
- package/build/src/git/reconcile.d.ts +14 -3
- package/build/src/git/reconcile.js +123 -102
- package/build/src/git/repository.d.ts +2 -0
- package/build/src/git/repository.js +13 -22
- package/build/src/git/target-placement.d.ts +9 -10
- package/build/src/git/target-placement.js +59 -62
- package/build/src/git/tender.d.ts +13 -2
- package/build/src/git/tender.js +28 -22
- package/build/src/git/terminal-seal.js +15 -12
- package/build/src/git/tree.js +5 -2
- package/build/src/git/workspace.d.ts +24 -2
- package/build/src/git/workspace.js +120 -16
- package/build/src/identity/coordinates.js +3 -1
- package/build/src/identity/selector.js +6 -3
- package/build/src/kanshi/fleet.d.ts +6 -0
- package/build/src/kanshi/fleet.js +27 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +77 -45
- package/build/src/kanshi/report.d.ts +13 -24
- package/build/src/kanshi/select.js +25 -24
- package/build/src/library/address.d.ts +2 -1
- package/build/src/library/address.js +7 -8
- package/build/src/library/akuma-creation.js +20 -12
- package/build/src/library/audit.d.ts +0 -1
- package/build/src/library/audit.js +1 -2
- package/build/src/library/bind.d.ts +53 -5
- package/build/src/library/bind.js +98 -22
- package/build/src/library/catalog.d.ts +1 -0
- package/build/src/library/catalog.js +6 -3
- package/build/src/library/configuration.js +3 -1
- package/build/src/library/continuation.d.ts +37 -0
- package/build/src/library/continuation.js +86 -0
- package/build/src/library/contract.d.ts +39 -45
- package/build/src/library/contract.js +141 -118
- package/build/src/library/delivery.d.ts +18 -13
- package/build/src/library/fleet.d.ts +1 -1
- package/build/src/library/fleet.js +19 -11
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +14 -0
- package/build/src/library/keiyaku.d.ts +8 -7
- package/build/src/library/keiyaku.js +3 -3
- package/build/src/library/mutation.js +11 -4
- package/build/src/library/nuke.js +14 -5
- package/build/src/library/reconcile.d.ts +9 -4
- package/build/src/library/reconcile.js +30 -24
- package/build/src/library/refusal.d.ts +13 -5
- package/build/src/library/refusal.js +7 -0
- package/build/src/library/region.d.ts +8 -7
- package/build/src/library/region.js +31 -11
- package/build/src/library/repo.js +2 -2
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/parse.js +11 -7
- package/build/src/markdown/query.js +4 -2
- package/build/src/protocol/amend.js +3 -1
- package/build/src/protocol/attempt.d.ts +7 -3
- package/build/src/protocol/attempt.js +9 -5
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +4 -14
- package/build/src/protocol/bind.d.ts +19 -6
- package/build/src/protocol/bind.js +28 -13
- package/build/src/protocol/completion.d.ts +0 -1
- package/build/src/protocol/completion.js +1 -3
- package/build/src/protocol/deliver.d.ts +12 -4
- package/build/src/protocol/deliver.js +60 -51
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +9 -7
- package/build/src/protocol/operations.d.ts +10 -9
- package/build/src/protocol/operations.js +5 -3
- package/build/src/protocol/placement.d.ts +0 -1
- package/build/src/protocol/placement.js +6 -6
- package/build/src/protocol/read/observation.d.ts +11 -0
- package/build/src/protocol/read/observation.js +37 -0
- package/build/src/protocol/read/status.d.ts +23 -12
- package/build/src/protocol/read/status.js +90 -72
- package/build/src/protocol/reconcile.d.ts +1 -0
- package/build/src/protocol/reconcile.js +2 -3
- package/build/src/protocol/reintegrate.js +1 -1
- package/build/src/protocol/review.d.ts +0 -1
- package/build/src/protocol/review.js +15 -22
- package/build/src/protocol/run.d.ts +1 -0
- package/build/src/protocol/run.js +4 -5
- package/build/src/runtime/proc/launch.d.ts +33 -0
- package/build/src/runtime/proc/launch.js +98 -0
- package/build/src/runtime/proc/line-rpc.js +9 -3
- package/build/src/runtime/proc/run.d.ts +12 -6
- package/build/src/runtime/proc/run.js +78 -21
- package/build/src/runtime/proc/stdio.js +7 -10
- package/build/src/settings.js +6 -2
- package/build/src/settlement/fence.d.ts +0 -2
- package/build/src/settlement/fence.js +0 -24
- package/build/src/settlement/holder.js +13 -10
- package/build/src/settlement/settle.js +39 -6
- package/build/src/task/board.d.ts +21 -2
- package/build/src/task/board.js +35 -16
- package/build/src/task/compose.js +85 -22
- package/build/src/task/context.js +21 -8
- package/build/src/task/document.js +46 -10
- package/build/src/task/identity.js +19 -6
- package/build/src/task/index.js +118 -27
- package/build/src/task/input.js +29 -7
- package/build/src/task/mutation.js +61 -19
- package/build/src/task/operations.d.ts +8 -2
- package/build/src/task/operations.js +97 -32
- package/build/src/task/query.js +57 -28
- package/build/src/task/store.d.ts +5 -1
- package/build/src/task/store.js +88 -95
- package/build/src/verification/execution.js +14 -11
- package/build/src/workspace-place.js +19 -7
- package/build/src/world.js +16 -6
- package/package.json +8 -3
package/build/src/akuma/nuke.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { lstat, readdir, rm } from "node:fs/promises";
|
|
1
|
+
import { lstat, readdir, rm, rmdir } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
2
3
|
import { nukeAliases } from "../alias/index.js";
|
|
3
4
|
import { CONTROL_RESPONSE_MS } from "./body.js";
|
|
4
|
-
import { HeldAkumaLeash, readHeart, readKill, requestStop
|
|
5
|
-
import { akuIdFromDirectoryName, akumaPaths, akumaRunRoot
|
|
6
|
-
const POLL_MS =
|
|
5
|
+
import { HeldAkumaLeash, readHeart, readKill, requestStop } from "./heart/index.js";
|
|
6
|
+
import { akuIdFromDirectoryName, akumaPaths, akumaRunRoot } from "./identity.js";
|
|
7
|
+
const POLL_MS = 100;
|
|
7
8
|
async function hasAkumaCustody(paths) {
|
|
8
9
|
try {
|
|
9
10
|
const value = await lstat(paths.heart);
|
|
@@ -25,7 +26,7 @@ async function takeLeashUntil(paths, deadline) {
|
|
|
25
26
|
return leash;
|
|
26
27
|
if (performance.now() >= deadline)
|
|
27
28
|
return null;
|
|
28
|
-
await wait(POLL_MS);
|
|
29
|
+
await wait(Math.min(POLL_MS, Math.max(0, deadline - performance.now())));
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
async function stopRunningAkuma(entry) {
|
|
@@ -36,11 +37,11 @@ async function stopRunningAkuma(entry) {
|
|
|
36
37
|
try {
|
|
37
38
|
if (request.kind === "already-killed" || request.kind === "already-stopped")
|
|
38
39
|
return leash;
|
|
39
|
-
if (await readKill(entry.paths, request.body.sequence) !== null)
|
|
40
|
+
if ((await readKill(entry.paths, request.body.sequence)) !== null)
|
|
40
41
|
return leash;
|
|
41
42
|
const current = await readHeart(entry.paths);
|
|
42
43
|
if (current.latestBody?.sequence !== request.body.sequence) {
|
|
43
|
-
if (await readKill(entry.paths, request.body.sequence) !== null)
|
|
44
|
+
if ((await readKill(entry.paths, request.body.sequence)) !== null)
|
|
44
45
|
return leash;
|
|
45
46
|
throw new Error(`Akuma ${entry.id} could not be stopped: unavailable`);
|
|
46
47
|
}
|
|
@@ -48,7 +49,7 @@ async function stopRunningAkuma(entry) {
|
|
|
48
49
|
await leash.clearStop(entry.paths);
|
|
49
50
|
throw new Error(`Akuma ${entry.id} could not be stopped: untidy`);
|
|
50
51
|
}
|
|
51
|
-
if (await leash.settleStop(entry.paths, request.body.sequence) === null) {
|
|
52
|
+
if ((await leash.settleStop(entry.paths, request.body.sequence)) === null) {
|
|
52
53
|
throw new Error(`Akuma ${entry.id} could not be stopped: unavailable`);
|
|
53
54
|
}
|
|
54
55
|
return leash;
|
|
@@ -58,22 +59,112 @@ async function stopRunningAkuma(entry) {
|
|
|
58
59
|
throw error;
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
|
-
async function
|
|
62
|
+
async function removeKnownRegularFile(path) {
|
|
62
63
|
try {
|
|
63
64
|
const value = await lstat(path);
|
|
64
|
-
if (value.isFile()
|
|
65
|
-
|
|
65
|
+
if (!value.isFile() || value.isSymbolicLink())
|
|
66
|
+
throw new Error(`Akuma custody is not a regular file: ${path}`);
|
|
67
|
+
await rm(path, { force: true });
|
|
66
68
|
}
|
|
67
69
|
catch (error) {
|
|
68
70
|
if (error.code !== "ENOENT")
|
|
69
71
|
throw error;
|
|
70
72
|
}
|
|
71
73
|
}
|
|
74
|
+
async function removeEmptyDirectory(path) {
|
|
75
|
+
try {
|
|
76
|
+
await rmdir(path);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error.code !== "ENOENT" && error.code !== "ENOTEMPTY")
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function isRequestSequenceName(name) {
|
|
84
|
+
const sequence = Number(name);
|
|
85
|
+
return /^\d+$/u.test(name) && Number.isSafeInteger(sequence) && String(sequence) === name;
|
|
86
|
+
}
|
|
87
|
+
const UUID_V4 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
88
|
+
function isRequestArtifactName(name) {
|
|
89
|
+
const match = /^(.*)\.(?:request|receipt)\.json$/u.exec(name);
|
|
90
|
+
return match !== null && UUID_V4.test(match[1]);
|
|
91
|
+
}
|
|
92
|
+
async function removeKnownRequestFile(path) {
|
|
93
|
+
try {
|
|
94
|
+
const value = await lstat(path);
|
|
95
|
+
if (!value.isFile() || value.isSymbolicLink())
|
|
96
|
+
return;
|
|
97
|
+
await rm(path, { force: true });
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
if (error.code !== "ENOENT")
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async function removeKnownRequestChannel(path) {
|
|
105
|
+
try {
|
|
106
|
+
const value = await lstat(path);
|
|
107
|
+
if (!value.isDirectory() || value.isSymbolicLink())
|
|
108
|
+
throw new Error(`Akuma custody is not a directory: ${path}`);
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error.code === "ENOENT")
|
|
112
|
+
return;
|
|
113
|
+
throw error;
|
|
114
|
+
}
|
|
115
|
+
for (const name of await readdir(path)) {
|
|
116
|
+
if (!isRequestSequenceName(name))
|
|
117
|
+
continue;
|
|
118
|
+
const sequenceDir = join(path, name);
|
|
119
|
+
try {
|
|
120
|
+
const sequence = await lstat(sequenceDir);
|
|
121
|
+
if (!sequence.isDirectory() || sequence.isSymbolicLink())
|
|
122
|
+
continue;
|
|
123
|
+
for (const child of await readdir(sequenceDir)) {
|
|
124
|
+
if (isRequestArtifactName(child))
|
|
125
|
+
await removeKnownRequestFile(join(sequenceDir, child));
|
|
126
|
+
}
|
|
127
|
+
await removeEmptyDirectory(sequenceDir);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
if (error.code !== "ENOENT")
|
|
131
|
+
throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
await removeEmptyDirectory(path);
|
|
135
|
+
}
|
|
72
136
|
async function removeAkumaEntry(entry) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
137
|
+
await removeKnownRequestChannel(entry.paths.requests);
|
|
138
|
+
for (const path of [
|
|
139
|
+
entry.paths.log,
|
|
140
|
+
`${entry.paths.heart}-wal`,
|
|
141
|
+
`${entry.paths.heart}-shm`,
|
|
142
|
+
`${entry.paths.leash}-wal`,
|
|
143
|
+
`${entry.paths.leash}-shm`,
|
|
144
|
+
entry.paths.leash,
|
|
145
|
+
entry.paths.heart,
|
|
146
|
+
]) {
|
|
147
|
+
await removeKnownRegularFile(path);
|
|
148
|
+
}
|
|
149
|
+
await removeEmptyDirectory(entry.paths.directory);
|
|
150
|
+
}
|
|
151
|
+
async function removeEmptyAkumaRunRoot(world) {
|
|
152
|
+
const runRoot = akumaRunRoot(world);
|
|
153
|
+
let names;
|
|
154
|
+
try {
|
|
155
|
+
names = await readdir(runRoot);
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
if (error.code === "ENOENT")
|
|
159
|
+
return;
|
|
160
|
+
throw error;
|
|
76
161
|
}
|
|
162
|
+
if (names.some((name) => name !== ".gitignore"))
|
|
163
|
+
return;
|
|
164
|
+
if (names.includes(".gitignore"))
|
|
165
|
+
await removeKnownRegularFile(join(runRoot, ".gitignore"));
|
|
166
|
+
await removeEmptyDirectory(runRoot);
|
|
167
|
+
await removeEmptyDirectory(dirname(runRoot));
|
|
77
168
|
}
|
|
78
169
|
async function nukeAkumaEntries(world) {
|
|
79
170
|
const runRoot = akumaRunRoot(world);
|
|
@@ -136,6 +227,7 @@ export async function stopAkuma(world) {
|
|
|
136
227
|
await nukeAliases(world);
|
|
137
228
|
for (const entry of entries)
|
|
138
229
|
await removeAkumaEntry(entry);
|
|
230
|
+
await removeEmptyAkumaRunRoot(world);
|
|
139
231
|
}
|
|
140
232
|
finally {
|
|
141
233
|
for (const leash of held.reverse())
|
|
@@ -173,18 +173,20 @@ export type TurnLedger = Readonly<{
|
|
|
173
173
|
/** Fold the retained fact timeline into Turn-owned rows without inventing provider facts. */
|
|
174
174
|
export declare function projectTurns(facts: readonly TimelineFact[], retained?: RetainedWindow): TurnLedger;
|
|
175
175
|
/** Split one nonnegative ordinary allowance into newest tail first, then pre-tail voice. */
|
|
176
|
-
export declare function ordinarySnapshotBudget(ordinaryBudget
|
|
176
|
+
export declare function ordinarySnapshotBudget(ordinaryBudget?: number): Readonly<{
|
|
177
177
|
tail: number;
|
|
178
178
|
voice: number;
|
|
179
179
|
}>;
|
|
180
|
-
/** Count selected ordinary rows; active tools and pending tells stay outside this total. */
|
|
181
|
-
export declare function ordinarySelectedCount(snapshot: ActivitySnapshot): number;
|
|
182
180
|
/** Select one current Turn, one latest outcome, or no focus; pending tells stay actionable. */
|
|
183
|
-
export declare function selectSnapshot(ledger: TurnLedger,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
181
|
+
export declare function selectSnapshot(ledger: TurnLedger, input: Readonly<{
|
|
182
|
+
aperture: "monitoring" | "receipt";
|
|
183
|
+
budget?: Readonly<{
|
|
184
|
+
tail: number;
|
|
185
|
+
voice?: number;
|
|
186
|
+
}>;
|
|
187
|
+
}>): Readonly<{
|
|
188
|
+
snapshot: ActivitySnapshot;
|
|
189
|
+
ordinaryCount: number;
|
|
190
|
+
}>;
|
|
189
191
|
export declare function selectHistory(ledger: TurnLedger, cursor: HistoryCursor): HistoryPage;
|
|
190
192
|
export {};
|
|
@@ -15,12 +15,24 @@ function toolKey(turnSequence, id) {
|
|
|
15
15
|
}
|
|
16
16
|
function narrationRow(fact, event) {
|
|
17
17
|
if (event.type === "assistant") {
|
|
18
|
-
return {
|
|
19
|
-
|
|
18
|
+
return {
|
|
19
|
+
kind: "said",
|
|
20
|
+
sequence: fact.sequence,
|
|
21
|
+
turnSequence: fact.turnSequence,
|
|
22
|
+
at: fact.at,
|
|
23
|
+
text: event.text,
|
|
24
|
+
...(event.truncated === true ? { truncated: true } : {}),
|
|
25
|
+
};
|
|
20
26
|
}
|
|
21
27
|
if (event.type === "thought" || event.type === "note") {
|
|
22
|
-
return {
|
|
23
|
-
|
|
28
|
+
return {
|
|
29
|
+
kind: event.type,
|
|
30
|
+
sequence: fact.sequence,
|
|
31
|
+
turnSequence: fact.turnSequence,
|
|
32
|
+
at: fact.at,
|
|
33
|
+
text: event.text,
|
|
34
|
+
...(event.truncated === true ? { truncated: true } : {}),
|
|
35
|
+
};
|
|
24
36
|
}
|
|
25
37
|
return null;
|
|
26
38
|
}
|
|
@@ -43,7 +55,16 @@ function projectToolEvent(rows, running, fact, event, phase) {
|
|
|
43
55
|
const index = running.get(key);
|
|
44
56
|
const started = index === undefined ? undefined : rows[index];
|
|
45
57
|
if (started?.kind !== "tool") {
|
|
46
|
-
rows.push({
|
|
58
|
+
rows.push({
|
|
59
|
+
kind: "tool",
|
|
60
|
+
sequence: fact.sequence,
|
|
61
|
+
turnSequence: fact.turnSequence,
|
|
62
|
+
at: fact.at,
|
|
63
|
+
name: event.name,
|
|
64
|
+
call: event.call,
|
|
65
|
+
state: event.result,
|
|
66
|
+
...(event.truncated === true ? { truncated: true } : {}),
|
|
67
|
+
});
|
|
47
68
|
return;
|
|
48
69
|
}
|
|
49
70
|
const durationMs = duration(started.at, fact.at);
|
|
@@ -118,13 +139,25 @@ export function projectTurns(facts, retained = {
|
|
|
118
139
|
};
|
|
119
140
|
for (const fact of facts) {
|
|
120
141
|
if (fact.kind === "turn-start") {
|
|
121
|
-
const turn = {
|
|
142
|
+
const turn = {
|
|
143
|
+
kind: "turn",
|
|
144
|
+
sequence: fact.sequence,
|
|
145
|
+
turnSequence: fact.sequence,
|
|
146
|
+
bodySequence: fact.bodySequence,
|
|
147
|
+
at: fact.startedAt,
|
|
148
|
+
};
|
|
122
149
|
const projected = { phase: "open", turn, rows: [], running: new Map() };
|
|
123
150
|
state.turns.push(projected);
|
|
124
151
|
state.turnsBySequence.set(turn.turnSequence, projected);
|
|
125
152
|
}
|
|
126
153
|
else if (fact.kind === "turn-end") {
|
|
127
|
-
const outcome = {
|
|
154
|
+
const outcome = {
|
|
155
|
+
kind: "outcome",
|
|
156
|
+
sequence: fact.sequence,
|
|
157
|
+
turnSequence: fact.turnSequence,
|
|
158
|
+
at: fact.completedAt,
|
|
159
|
+
outcome: fact.outcome,
|
|
160
|
+
};
|
|
128
161
|
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
129
162
|
if (turn === undefined)
|
|
130
163
|
state.orphanOutcomes.push(outcome);
|
|
@@ -135,7 +168,13 @@ export function projectTurns(facts, retained = {
|
|
|
135
168
|
}
|
|
136
169
|
}
|
|
137
170
|
else if (fact.kind === "call") {
|
|
138
|
-
const row = {
|
|
171
|
+
const row = {
|
|
172
|
+
kind: "call",
|
|
173
|
+
sequence: fact.sequence,
|
|
174
|
+
turnSequence: fact.turnSequence,
|
|
175
|
+
at: fact.at,
|
|
176
|
+
text: fact.body,
|
|
177
|
+
};
|
|
139
178
|
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
140
179
|
if (turn === undefined)
|
|
141
180
|
state.orphanRows.push(row);
|
|
@@ -143,7 +182,15 @@ export function projectTurns(facts, retained = {
|
|
|
143
182
|
turn.rows.push(row);
|
|
144
183
|
}
|
|
145
184
|
else if (fact.kind === "tell") {
|
|
146
|
-
state.tells.push({
|
|
185
|
+
state.tells.push({
|
|
186
|
+
kind: "tell",
|
|
187
|
+
sequence: fact.sequence,
|
|
188
|
+
at: fact.recordedAt,
|
|
189
|
+
tellId: fact.id,
|
|
190
|
+
text: fact.body,
|
|
191
|
+
state: fact.state,
|
|
192
|
+
deliveries: fact.deliveries,
|
|
193
|
+
});
|
|
147
194
|
}
|
|
148
195
|
else {
|
|
149
196
|
projectActivityEvent(state, fact);
|
|
@@ -159,12 +206,15 @@ export function projectTurns(facts, retained = {
|
|
|
159
206
|
const frontier = turns.at(-1);
|
|
160
207
|
const openTurn = frontier?.kind === "open" ? frontier : undefined;
|
|
161
208
|
const latestOutcome = rows.findLast((row) => row.kind === "outcome");
|
|
162
|
-
return {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
209
|
+
return {
|
|
210
|
+
rows,
|
|
211
|
+
turns,
|
|
212
|
+
retained,
|
|
213
|
+
...(openTurn === undefined ? {} : { openTurn }),
|
|
214
|
+
...(latestOutcome === undefined ? {} : { latestOutcome }),
|
|
215
|
+
};
|
|
166
216
|
}
|
|
167
|
-
function
|
|
217
|
+
function assembleEntries(ledger, window, selected) {
|
|
168
218
|
const windowRows = new Set(window);
|
|
169
219
|
const result = [];
|
|
170
220
|
let hidden = 0;
|
|
@@ -183,34 +233,20 @@ function openEntries(ledger, window, selected) {
|
|
|
183
233
|
continue;
|
|
184
234
|
flushGap();
|
|
185
235
|
if (row.kind !== "turn" && row.kind !== "outcome" && !(row.kind === "tool" && row.state === "unsettled")) {
|
|
186
|
-
result.push({ kind: "row", row });
|
|
236
|
+
result.push({ kind: "row", row: row });
|
|
187
237
|
}
|
|
188
238
|
}
|
|
189
239
|
flushGap();
|
|
190
240
|
return result;
|
|
191
241
|
}
|
|
242
|
+
const DEFAULT_ORDINARY = DEFAULT_TAIL + DEFAULT_VOICE;
|
|
192
243
|
/** Split one nonnegative ordinary allowance into newest tail first, then pre-tail voice. */
|
|
193
|
-
export function ordinarySnapshotBudget(ordinaryBudget) {
|
|
244
|
+
export function ordinarySnapshotBudget(ordinaryBudget = DEFAULT_ORDINARY) {
|
|
194
245
|
const tail = Math.min(DEFAULT_TAIL, Math.max(0, ordinaryBudget));
|
|
195
246
|
return { tail, voice: Math.min(DEFAULT_VOICE, Math.max(0, ordinaryBudget) - tail) };
|
|
196
247
|
}
|
|
197
|
-
/** Count selected ordinary rows; active tools and pending tells stay outside this total. */
|
|
198
|
-
export function ordinarySelectedCount(snapshot) {
|
|
199
|
-
return snapshot.entries.reduce((count, entry) => {
|
|
200
|
-
if (entry.kind !== "row")
|
|
201
|
-
return count;
|
|
202
|
-
if (entry.row.kind === "tool" && entry.row.state === "active")
|
|
203
|
-
return count;
|
|
204
|
-
if (entry.row.kind === "tell" && entry.row.state === "pending")
|
|
205
|
-
return count;
|
|
206
|
-
return count + 1;
|
|
207
|
-
}, 0);
|
|
208
|
-
}
|
|
209
248
|
function isSuccessfulFileChange(row) {
|
|
210
|
-
return row.kind === "tool"
|
|
211
|
-
&& typeof row.state === "object"
|
|
212
|
-
&& row.state.status === "ok"
|
|
213
|
-
&& row.call.kind === "fileChange";
|
|
249
|
+
return (row.kind === "tool" && typeof row.state === "object" && row.state.status === "ok" && row.call.kind === "fileChange");
|
|
214
250
|
}
|
|
215
251
|
function flattenReportedChanges(rows) {
|
|
216
252
|
return rows.flatMap((row) => {
|
|
@@ -238,49 +274,70 @@ function frontierReportedChanges(ledger) {
|
|
|
238
274
|
const closed = ledger.turns.findLast((turn) => turn.kind === "closed");
|
|
239
275
|
return closed === undefined ? EMPTY_REPORTED : summarizeReportedChanges(closed.rows);
|
|
240
276
|
}
|
|
277
|
+
function isPendingTell(row) {
|
|
278
|
+
return row.kind === "tell" && row.state === "pending";
|
|
279
|
+
}
|
|
280
|
+
function isToldTell(row) {
|
|
281
|
+
return row.kind === "tell" && row.state === "told";
|
|
282
|
+
}
|
|
283
|
+
function isActiveTool(row) {
|
|
284
|
+
return row.kind === "tool" && row.state === "active";
|
|
285
|
+
}
|
|
241
286
|
/** Select one current Turn, one latest outcome, or no focus; pending tells stay actionable. */
|
|
242
|
-
export function selectSnapshot(ledger,
|
|
287
|
+
export function selectSnapshot(ledger, input) {
|
|
288
|
+
const budget = input.budget ?? { tail: DEFAULT_TAIL, voice: DEFAULT_VOICE };
|
|
243
289
|
if (ledger.turns.length === 0 && !ledger.rows.some((row) => row.kind === "tell")) {
|
|
244
|
-
return { kind: "unborn", entries: [], omitted: 0, ...EMPTY_REPORTED };
|
|
290
|
+
return { snapshot: { kind: "unborn", entries: [], omitted: 0, ...EMPTY_REPORTED }, ordinaryCount: 0 };
|
|
245
291
|
}
|
|
246
|
-
const pending = ledger.rows.filter(
|
|
292
|
+
const pending = ledger.rows.filter(isPendingTell);
|
|
293
|
+
const latestTold = input.aperture === "monitoring" ? ledger.rows.findLast(isToldTell) : undefined;
|
|
294
|
+
const pins = latestTold === undefined ? pending : [...pending, latestTold];
|
|
247
295
|
const reported = frontierReportedChanges(ledger);
|
|
248
296
|
if (ledger.openTurn !== undefined) {
|
|
249
297
|
const window = ledger.openTurn.rows;
|
|
250
|
-
const
|
|
251
|
-
const ordinary = window.filter((row) => !(row
|
|
298
|
+
const pinSet = new Set([...window.filter(isActiveTool), ...pins]);
|
|
299
|
+
const ordinary = window.filter((row) => !pinSet.has(row));
|
|
252
300
|
const tailCount = Math.max(0, budget.tail);
|
|
253
301
|
const tail = tailCount === 0 ? [] : ordinary.slice(-tailCount);
|
|
254
302
|
const tailSet = new Set(tail);
|
|
255
303
|
const voiceCount = Math.max(0, budget.voice ?? DEFAULT_VOICE);
|
|
256
|
-
const voiceCandidates = ordinary
|
|
257
|
-
.filter((row) => !tailSet.has(row) && (row.kind === "said" || row.kind === "thought"));
|
|
304
|
+
const voiceCandidates = ordinary.filter((row) => !tailSet.has(row) && (row.kind === "said" || row.kind === "thought"));
|
|
258
305
|
const voice = voiceCount === 0 ? [] : voiceCandidates.slice(-voiceCount);
|
|
259
|
-
const selected = new Set([...
|
|
306
|
+
const selected = new Set([...pinSet, ...tail, ...voice]);
|
|
260
307
|
const omitted = window.filter((row) => !selected.has(row)).length;
|
|
261
|
-
return {
|
|
308
|
+
return {
|
|
309
|
+
snapshot: {
|
|
310
|
+
kind: "open",
|
|
311
|
+
turn: ledger.openTurn.turn,
|
|
312
|
+
entries: assembleEntries(ledger, window, selected),
|
|
313
|
+
omitted,
|
|
314
|
+
...reported,
|
|
315
|
+
},
|
|
316
|
+
ordinaryCount: tail.length + voice.length,
|
|
317
|
+
};
|
|
262
318
|
}
|
|
263
319
|
return {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
320
|
+
snapshot: {
|
|
321
|
+
kind: "idle",
|
|
322
|
+
...(ledger.latestOutcome === undefined ? {} : { outcome: ledger.latestOutcome }),
|
|
323
|
+
entries: assembleEntries(ledger, [], new Set(pins)),
|
|
324
|
+
omitted: 0,
|
|
325
|
+
...reported,
|
|
326
|
+
},
|
|
327
|
+
ordinaryCount: 0,
|
|
269
328
|
};
|
|
270
329
|
}
|
|
271
|
-
/** Apply the one snapshot policy used by every public observation consumer. */
|
|
272
|
-
export function selectActivitySnapshot(facts) {
|
|
273
|
-
return selectSnapshot(projectTurns(facts));
|
|
274
|
-
}
|
|
275
330
|
export function selectHistory(ledger, cursor) {
|
|
276
331
|
const eligible = ledger.rows.filter((row) => cursor.before !== undefined
|
|
277
332
|
? row.sequence < cursor.before
|
|
278
|
-
: cursor.since !== undefined
|
|
333
|
+
: cursor.since !== undefined
|
|
334
|
+
? row.sequence > cursor.since
|
|
335
|
+
: true);
|
|
279
336
|
const rows = cursor.since !== undefined ? eligible.slice(0, cursor.limit) : eligible.slice(-cursor.limit);
|
|
280
337
|
const omitted = Math.max(0, eligible.length - rows.length);
|
|
281
338
|
const historyLost = cursor.since !== undefined
|
|
282
|
-
?
|
|
283
|
-
:
|
|
339
|
+
? ledger.rows[0] !== undefined && ledger.rows[0].sequence > cursor.since + 1
|
|
340
|
+
: ledger.retained.lowestRetained !== null && ledger.retained.lowestRetained > 1 && omitted === 0;
|
|
284
341
|
return {
|
|
285
342
|
rows,
|
|
286
343
|
omitted,
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export type SystemPromptMode = "append" | "replace";
|
|
1
2
|
export type ProviderOptions = Readonly<{
|
|
2
3
|
model?: string;
|
|
3
4
|
effort?: string;
|
|
4
5
|
readonly?: true;
|
|
5
6
|
network?: "disabled" | "enabled";
|
|
6
7
|
systemPrompt?: string;
|
|
8
|
+
systemPromptMode?: SystemPromptMode;
|
|
7
9
|
}>;
|
|
8
10
|
export type ReadonlyRestraint = Readonly<{
|
|
9
11
|
enforcement: "native";
|
|
@@ -34,12 +34,22 @@ export function decodeProviderOptions(value) {
|
|
|
34
34
|
throw new TypeError("provider option network must be disabled, enabled");
|
|
35
35
|
}
|
|
36
36
|
const systemPrompt = optionText(options, "systemPrompt", "allow");
|
|
37
|
+
const systemPromptMode = options.systemPromptMode;
|
|
38
|
+
if (systemPromptMode !== undefined) {
|
|
39
|
+
if (systemPromptMode !== "append" && systemPromptMode !== "replace") {
|
|
40
|
+
throw new TypeError("provider option systemPromptMode must be append, replace");
|
|
41
|
+
}
|
|
42
|
+
if (systemPrompt === undefined) {
|
|
43
|
+
throw new TypeError("provider option systemPromptMode requires systemPrompt");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
37
46
|
return Object.freeze({
|
|
38
47
|
...(model === undefined ? {} : { model }),
|
|
39
48
|
...(effort === undefined ? {} : { effort }),
|
|
40
49
|
...(options.readonly === undefined ? {} : { readonly: true }),
|
|
41
50
|
...(network === undefined ? {} : { network }),
|
|
42
51
|
...(systemPrompt === undefined ? {} : { systemPrompt }),
|
|
52
|
+
...(systemPromptMode === undefined ? {} : { systemPromptMode }),
|
|
43
53
|
});
|
|
44
54
|
}
|
|
45
55
|
export function decodeReadonlyRestraint(value) {
|
|
@@ -49,15 +59,20 @@ export function decodeReadonlyRestraint(value) {
|
|
|
49
59
|
if (restraint.enforcement === "native") {
|
|
50
60
|
return Object.freeze({ enforcement: "native" });
|
|
51
61
|
}
|
|
52
|
-
if (restraint.enforcement === "none"
|
|
53
|
-
|
|
62
|
+
if (restraint.enforcement === "none" &&
|
|
63
|
+
typeof restraint.diagnostic === "string" &&
|
|
64
|
+
restraint.diagnostic.trim().length > 0) {
|
|
54
65
|
return Object.freeze({ enforcement: "none", diagnostic: restraint.diagnostic });
|
|
55
66
|
}
|
|
56
67
|
throw new TypeError("readonly restraint must be native or none with a diagnostic");
|
|
57
68
|
}
|
|
58
69
|
function providerKind(value) {
|
|
59
|
-
return value === "acp" ||
|
|
60
|
-
|
|
70
|
+
return (value === "acp" ||
|
|
71
|
+
value === "claude-agent-sdk" ||
|
|
72
|
+
value === "codex-app-server" ||
|
|
73
|
+
value === "grok-build" ||
|
|
74
|
+
value === "opencode-sdk" ||
|
|
75
|
+
value === "pi");
|
|
61
76
|
}
|
|
62
77
|
export function decodeProviderRecipe(input) {
|
|
63
78
|
const value = record(input);
|
|
@@ -68,7 +83,8 @@ export function decodeProviderRecipe(input) {
|
|
|
68
83
|
}
|
|
69
84
|
if (!providerKind(value.kind))
|
|
70
85
|
throw new TypeError("provider execution has unknown kind");
|
|
71
|
-
if (value.executable !== undefined &&
|
|
86
|
+
if (value.executable !== undefined &&
|
|
87
|
+
(typeof value.executable !== "string" || value.executable.trim().length === 0)) {
|
|
72
88
|
throw new TypeError("provider execution executable must be a nonblank string");
|
|
73
89
|
}
|
|
74
90
|
const config = value.config === undefined ? undefined : record(value.config);
|