@astrosheep/keiyaku 4.0.1 → 4.0.2
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 +137 -5
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
- package/build/src/akuma/abort.d.ts +2 -0
- package/build/src/akuma/abort.js +50 -0
- package/build/src/akuma/akuma.d.ts +23 -14
- package/build/src/akuma/akuma.js +120 -104
- package/build/src/akuma/archetype.d.ts +7 -6
- package/build/src/akuma/archetype.js +68 -41
- package/build/src/akuma/body.d.ts +3 -5
- package/build/src/akuma/body.js +408 -213
- package/build/src/akuma/heart/facts.d.ts +25 -34
- package/build/src/akuma/heart/facts.js +18 -7
- package/build/src/akuma/heart/index.d.ts +39 -42
- package/build/src/akuma/heart/index.js +134 -93
- package/build/src/akuma/heart/rows.d.ts +9 -31
- package/build/src/akuma/heart/rows.js +26 -44
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +7 -15
- package/build/src/akuma/heart/soul.d.ts +8 -0
- package/build/src/akuma/heart/soul.js +136 -0
- package/build/src/akuma/heart/storage.d.ts +28 -14
- package/build/src/akuma/heart/storage.js +86 -26
- package/build/src/akuma/identity.d.ts +2 -2
- package/build/src/akuma/identity.js +9 -9
- package/build/src/akuma/index.d.ts +6 -1
- package/build/src/akuma/index.js +6 -0
- package/build/src/akuma/projection.d.ts +117 -38
- package/build/src/akuma/projection.js +208 -97
- package/build/src/akuma/provider-recipe.d.ts +24 -0
- package/build/src/akuma/provider-recipe.js +100 -0
- package/build/src/akuma/provider.d.ts +12 -4
- package/build/src/akuma/provider.js +117 -70
- package/build/src/akuma/providers/acp/core.d.ts +19 -0
- package/build/src/akuma/providers/acp/core.js +159 -0
- package/build/src/akuma/providers/acp/events.d.ts +20 -0
- package/build/src/akuma/providers/acp/events.js +73 -0
- package/build/src/akuma/providers/acp/index.d.ts +12 -0
- package/build/src/akuma/providers/acp/index.js +94 -0
- package/build/src/akuma/providers/claude/events.js +66 -13
- package/build/src/akuma/providers/claude/index.d.ts +2 -1
- package/build/src/akuma/providers/claude/index.js +35 -21
- package/build/src/akuma/providers/codex-app-server/events.js +4 -1
- package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
- package/build/src/akuma/providers/codex-app-server/index.js +24 -31
- package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
- package/build/src/akuma/providers/grok-build/index.js +70 -0
- package/build/src/akuma/providers/index.d.ts +5 -3
- package/build/src/akuma/providers/index.js +24 -59
- package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
- package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
- package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
- package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
- package/build/src/akuma/providers/pi/events.js +49 -11
- package/build/src/akuma/providers/pi/index.d.ts +1 -1
- package/build/src/akuma/providers/pi/index.js +50 -21
- package/build/src/akuma/publication.d.ts +3 -3
- package/build/src/akuma/publication.js +28 -40
- package/build/src/akuma/requests.d.ts +9 -7
- package/build/src/akuma/requests.js +92 -65
- package/build/src/alias/index.d.ts +2 -2
- package/build/src/alias/index.js +10 -10
- package/build/src/body/decode.js +7 -1
- package/build/src/body/region.d.ts +2 -0
- package/build/src/body/region.js +77 -7
- package/build/src/cli/accepted.d.ts +17 -13
- package/build/src/cli/accepted.js +72 -34
- package/build/src/cli/actor.js +3 -3
- package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
- package/build/src/cli/commands/akuma-invoke.js +14 -9
- package/build/src/cli/commands/akuma.d.ts +13 -3
- package/build/src/cli/commands/akuma.js +67 -34
- package/build/src/cli/commands/contract.d.ts +18 -5
- package/build/src/cli/commands/contract.js +9 -3
- package/build/src/cli/commands/task-invoke.d.ts +17 -4
- package/build/src/cli/commands/task-invoke.js +43 -20
- package/build/src/cli/commands/task-query.d.ts +5 -0
- package/build/src/cli/commands/task-query.js +247 -0
- package/build/src/cli/commands/task.d.ts +3 -1
- package/build/src/cli/commands/task.js +51 -13
- package/build/src/cli/coordinates.d.ts +18 -0
- package/build/src/cli/coordinates.js +120 -0
- package/build/src/cli/draft.d.ts +8 -0
- package/build/src/cli/draft.js +96 -0
- package/build/src/cli/invoke.d.ts +4 -3
- package/build/src/cli/invoke.js +160 -179
- package/build/src/cli/main.js +34 -6
- package/build/src/cli/parse.d.ts +9 -2
- package/build/src/cli/parse.js +29 -7
- package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
- package/build/src/cli/render/akuma-tool-command.js +144 -0
- package/build/src/cli/render/akuma-tool.d.ts +2 -2
- package/build/src/cli/render/akuma-tool.js +30 -4
- package/build/src/cli/render/akuma.d.ts +1 -0
- package/build/src/cli/render/akuma.js +211 -116
- package/build/src/cli/render/audit.d.ts +3 -0
- package/build/src/cli/render/audit.js +104 -0
- package/build/src/cli/render/contract.d.ts +3 -3
- package/build/src/cli/render/contract.js +192 -79
- package/build/src/cli/render/kanshi.js +263 -168
- package/build/src/cli/render/receipt.d.ts +19 -0
- package/build/src/cli/render/receipt.js +106 -0
- package/build/src/cli/render/refusal.d.ts +16 -2
- package/build/src/cli/render/refusal.js +88 -20
- package/build/src/cli/render/region.d.ts +2 -0
- package/build/src/cli/render/region.js +17 -0
- package/build/src/cli/render/task.d.ts +2 -1
- package/build/src/cli/render/task.js +223 -60
- package/build/src/cli/render/terminal.d.ts +7 -0
- package/build/src/cli/render/terminal.js +46 -0
- package/build/src/cli/render/text.js +6 -3
- package/build/src/cli/result.d.ts +115 -20
- package/build/src/cli/usage.d.ts +1 -0
- package/build/src/cli/usage.js +3 -0
- package/build/src/contract-worktree.d.ts +6 -5
- package/build/src/contract-worktree.js +95 -57
- package/build/src/coordination/durable-file.d.ts +4 -3
- package/build/src/coordination/durable-file.js +29 -25
- package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
- package/build/src/coordination/sqlite-transaction-lock.js +22 -5
- package/build/src/core/facts/fold.js +1 -6
- package/build/src/core/facts/gate.d.ts +1 -0
- package/build/src/core/facts/gate.js +1 -0
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +0 -11
- package/build/src/core/verbs/deliver.d.ts +1 -1
- package/build/src/core/verbs/deliver.js +1 -7
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +4 -1
- package/build/src/dispatch/index.d.ts +2 -2
- package/build/src/dispatch/index.js +17 -17
- package/build/src/git/admission.d.ts +1 -1
- package/build/src/git/admission.js +11 -11
- package/build/src/git/hooks.js +13 -13
- package/build/src/git/integration.d.ts +14 -15
- package/build/src/git/integration.js +80 -44
- package/build/src/git/observe.d.ts +5 -3
- package/build/src/git/observe.js +18 -12
- package/build/src/git/read-observation.js +9 -9
- package/build/src/git/reconcile.d.ts +2 -0
- package/build/src/git/reconcile.js +138 -95
- package/build/src/git/repository.d.ts +27 -19
- package/build/src/git/repository.js +155 -83
- package/build/src/git/scratch.d.ts +7 -3
- package/build/src/git/scratch.js +44 -37
- package/build/src/git/target-placement.d.ts +40 -4
- package/build/src/git/target-placement.js +221 -101
- package/build/src/git/tender.d.ts +6 -5
- package/build/src/git/tender.js +24 -43
- package/build/src/git/terminal-seal.d.ts +1 -1
- package/build/src/git/terminal-seal.js +7 -5
- package/build/src/git/workspace.d.ts +36 -4
- package/build/src/git/workspace.js +53 -18
- package/build/src/identity/selector.js +1 -1
- package/build/src/index.d.ts +3 -3
- package/build/src/index.js +1 -1
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +2 -1
- package/build/src/kanshi/read.js +118 -27
- package/build/src/kanshi/report.d.ts +50 -0
- package/build/src/kanshi/select.d.ts +5 -0
- package/build/src/kanshi/select.js +32 -0
- package/build/src/library/address.d.ts +12 -3
- package/build/src/library/address.js +77 -46
- package/build/src/library/akuma-creation.d.ts +6 -1
- package/build/src/library/akuma-creation.js +86 -13
- package/build/src/library/audit.d.ts +18 -0
- package/build/src/library/audit.js +44 -0
- package/build/src/library/bind.js +4 -4
- package/build/src/library/catalog.d.ts +1 -1
- package/build/src/library/catalog.js +5 -8
- package/build/src/library/contract.d.ts +5 -6
- package/build/src/library/contract.js +11 -35
- package/build/src/library/delivery.d.ts +2 -1
- package/build/src/library/fleet.d.ts +2 -2
- package/build/src/library/fleet.js +35 -71
- package/build/src/library/keiyaku.d.ts +3 -2
- package/build/src/library/keiyaku.js +1 -0
- package/build/src/library/mutation.d.ts +7 -6
- package/build/src/library/mutation.js +23 -25
- package/build/src/library/reconcile.d.ts +29 -0
- package/build/src/library/reconcile.js +179 -0
- package/build/src/library/region.d.ts +12 -0
- package/build/src/library/region.js +15 -1
- package/build/src/library/repo.d.ts +4 -16
- package/build/src/library/repo.js +13 -38
- package/build/src/protocol/attempt.js +6 -6
- package/build/src/protocol/bind.js +4 -4
- package/build/src/protocol/intent.d.ts +15 -2
- package/build/src/protocol/intent.js +21 -6
- package/build/src/protocol/operations.d.ts +73 -22
- package/build/src/protocol/operations.js +292 -88
- package/build/src/protocol/outcome.d.ts +9 -3
- package/build/src/protocol/outcome.js +3 -1
- package/build/src/protocol/placement.d.ts +15 -4
- package/build/src/protocol/placement.js +58 -25
- package/build/src/protocol/read/status.d.ts +8 -1
- package/build/src/protocol/read/status.js +61 -14
- package/build/src/runtime/proc/line-rpc.d.ts +3 -8
- package/build/src/runtime/proc/line-rpc.js +16 -43
- package/build/src/runtime/proc/run.d.ts +15 -29
- package/build/src/runtime/proc/run.js +113 -105
- package/build/src/runtime/proc/stdio.d.ts +18 -0
- package/build/src/runtime/proc/stdio.js +58 -0
- package/build/src/settings.d.ts +2 -2
- package/build/src/settings.js +8 -8
- package/build/src/settlement/fence.d.ts +0 -4
- package/build/src/settlement/fence.js +0 -9
- package/build/src/settlement/holder.d.ts +11 -1
- package/build/src/settlement/holder.js +25 -0
- package/build/src/settlement/settle.d.ts +1 -1
- package/build/src/settlement/settle.js +52 -89
- package/build/src/task/board.d.ts +3 -3
- package/build/src/task/board.js +6 -9
- package/build/src/task/compose.d.ts +1 -1
- package/build/src/task/compose.js +18 -10
- package/build/src/task/context.d.ts +3 -3
- package/build/src/task/context.js +14 -14
- package/build/src/task/document.d.ts +2 -1
- package/build/src/task/document.js +15 -5
- package/build/src/task/index.d.ts +19 -7
- package/build/src/task/index.js +42 -23
- package/build/src/task/operations.d.ts +15 -9
- package/build/src/task/operations.js +78 -48
- package/build/src/task/query.d.ts +67 -0
- package/build/src/task/query.js +279 -0
- package/build/src/task/store.d.ts +2 -2
- package/build/src/task/store.js +40 -25
- package/build/src/verification/execution.d.ts +4 -2
- package/build/src/verification/execution.js +9 -5
- package/build/src/workspace-place.d.ts +41 -0
- package/build/src/workspace-place.js +386 -0
- package/build/src/world.d.ts +13 -2
- package/build/src/world.js +81 -48
- package/package.json +3 -2
- package/build/src/protocol/read/audit.d.ts +0 -31
- package/build/src/protocol/read/audit.js +0 -55
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { decodeAgentEvent } from "./provider.js";
|
|
2
|
-
const
|
|
3
|
-
const
|
|
2
|
+
const DEFAULT_TAIL = 3;
|
|
3
|
+
const DEFAULT_VOICE = 3;
|
|
4
4
|
function duration(startedAt, completedAt) {
|
|
5
5
|
const start = Date.parse(startedAt);
|
|
6
6
|
const end = Date.parse(completedAt);
|
|
@@ -22,124 +22,235 @@ function narrationRow(fact, event) {
|
|
|
22
22
|
}
|
|
23
23
|
return null;
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
state
|
|
37
|
-
|
|
38
|
-
|
|
25
|
+
function projectToolEvent(rows, running, fact, event, phase) {
|
|
26
|
+
const key = toolKey(fact.turnSequence, event.id);
|
|
27
|
+
if (event.phase === "started") {
|
|
28
|
+
running.set(key, rows.length);
|
|
29
|
+
rows.push({
|
|
30
|
+
kind: "tool",
|
|
31
|
+
sequence: fact.sequence,
|
|
32
|
+
turnSequence: fact.turnSequence,
|
|
33
|
+
at: fact.at,
|
|
34
|
+
name: event.name,
|
|
35
|
+
call: event.call,
|
|
36
|
+
state: phase === "open" ? "active" : "unsettled",
|
|
37
|
+
...(event.truncated === true ? { truncated: true } : {}),
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const index = running.get(key);
|
|
42
|
+
const started = index === undefined ? undefined : rows[index];
|
|
43
|
+
if (started?.kind !== "tool") {
|
|
44
|
+
rows.push({ kind: "tool", sequence: fact.sequence, turnSequence: fact.turnSequence, at: fact.at, name: event.name, call: event.call, state: event.result, ...(event.truncated === true ? { truncated: true } : {}) });
|
|
45
|
+
return;
|
|
39
46
|
}
|
|
40
|
-
|
|
47
|
+
const durationMs = duration(started.at, fact.at);
|
|
48
|
+
rows[index] = {
|
|
49
|
+
kind: "tool",
|
|
50
|
+
sequence: started.sequence,
|
|
51
|
+
turnSequence: fact.turnSequence,
|
|
52
|
+
at: started.at,
|
|
53
|
+
completedAt: fact.at,
|
|
54
|
+
...(durationMs === undefined ? {} : { durationMs }),
|
|
55
|
+
name: event.name,
|
|
56
|
+
call: event.call,
|
|
57
|
+
state: event.result,
|
|
58
|
+
...(started.truncated === true || event.truncated === true ? { truncated: true } : {}),
|
|
59
|
+
};
|
|
60
|
+
running.delete(key);
|
|
41
61
|
}
|
|
42
62
|
function projectActivityEvent(state, fact) {
|
|
43
63
|
const event = decodeAgentEvent(fact.event);
|
|
44
64
|
const narration = narrationRow(fact, event);
|
|
45
65
|
if (narration !== null) {
|
|
46
|
-
state.
|
|
66
|
+
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
67
|
+
if (turn === undefined)
|
|
68
|
+
state.orphanRows.push(narration);
|
|
69
|
+
else
|
|
70
|
+
turn.rows.push(narration);
|
|
47
71
|
return;
|
|
48
72
|
}
|
|
49
73
|
if (event.type !== "tool")
|
|
50
74
|
return;
|
|
51
|
-
const
|
|
52
|
-
if (
|
|
53
|
-
state.
|
|
54
|
-
|
|
55
|
-
|
|
75
|
+
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
76
|
+
if (turn === undefined)
|
|
77
|
+
projectToolEvent(state.orphanRows, state.orphanRunning, fact, event, "closed");
|
|
78
|
+
else
|
|
79
|
+
projectToolEvent(turn.rows, turn.running, fact, event, turn.phase);
|
|
80
|
+
}
|
|
81
|
+
function demoteActive(row) {
|
|
82
|
+
if (row.kind !== "tool" || row.state !== "active")
|
|
83
|
+
return row;
|
|
84
|
+
return { ...row, state: "unsettled" };
|
|
85
|
+
}
|
|
86
|
+
function foldOutcomeVoice(rows, outcome) {
|
|
87
|
+
if (outcome?.outcome.kind !== "answered")
|
|
88
|
+
return rows;
|
|
89
|
+
const finalVoice = rows.findLast((row) => row.kind === "said");
|
|
90
|
+
return finalVoice?.text === outcome.outcome.answer && finalVoice.truncated !== true
|
|
91
|
+
? rows.filter((row) => row !== finalVoice)
|
|
92
|
+
: rows;
|
|
93
|
+
}
|
|
94
|
+
function finishTurn(turn) {
|
|
95
|
+
const rows = foldOutcomeVoice(turn.rows, turn.outcome);
|
|
96
|
+
if (turn.phase === "closed" && turn.outcome !== undefined) {
|
|
97
|
+
return { kind: "closed", turn: turn.turn, rows: rows.map(demoteActive), outcome: turn.outcome };
|
|
56
98
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (started?.kind !== "tool") {
|
|
60
|
-
state.rows.push({ settled: true, row: {
|
|
61
|
-
kind: "tool", sequence: fact.sequence, turnSequence: fact.turnSequence, at: fact.at,
|
|
62
|
-
name: event.name, call: event.call, state: event.result,
|
|
63
|
-
...(event.truncated === true ? { truncated: true } : {}),
|
|
64
|
-
} });
|
|
65
|
-
return;
|
|
99
|
+
if (rows.some((row) => row.kind === "tool" && row.state === "unsettled")) {
|
|
100
|
+
throw new Error(`open Turn ${turn.turn.turnSequence} contains an unsettled tool`);
|
|
66
101
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
102
|
+
return { kind: "open", turn: turn.turn, rows: rows };
|
|
103
|
+
}
|
|
104
|
+
/** Fold the retained fact timeline into Turn-owned rows without inventing provider facts. */
|
|
105
|
+
export function projectTurns(facts, retained = {
|
|
106
|
+
lowestRetained: facts[0]?.sequence ?? null,
|
|
107
|
+
highest: facts.at(-1)?.sequence ?? null,
|
|
108
|
+
}) {
|
|
109
|
+
const state = {
|
|
110
|
+
turns: [],
|
|
111
|
+
turnsBySequence: new Map(),
|
|
112
|
+
tells: [],
|
|
113
|
+
orphanRows: [],
|
|
114
|
+
orphanOutcomes: [],
|
|
115
|
+
orphanRunning: new Map(),
|
|
74
116
|
};
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
117
|
+
for (const fact of facts) {
|
|
118
|
+
if (fact.kind === "turn-start") {
|
|
119
|
+
const turn = { kind: "turn", sequence: fact.sequence, turnSequence: fact.sequence, bodySequence: fact.bodySequence, at: fact.startedAt };
|
|
120
|
+
const projected = { phase: "open", turn, rows: [], running: new Map() };
|
|
121
|
+
state.turns.push(projected);
|
|
122
|
+
state.turnsBySequence.set(turn.turnSequence, projected);
|
|
123
|
+
}
|
|
124
|
+
else if (fact.kind === "turn-end") {
|
|
125
|
+
const outcome = { kind: "outcome", sequence: fact.sequence, turnSequence: fact.turnSequence, at: fact.completedAt, outcome: fact.outcome };
|
|
126
|
+
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
127
|
+
if (turn === undefined)
|
|
128
|
+
state.orphanOutcomes.push(outcome);
|
|
129
|
+
else {
|
|
130
|
+
turn.phase = "closed";
|
|
131
|
+
turn.rows = turn.rows.map(demoteActive);
|
|
132
|
+
turn.outcome = outcome;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else if (fact.kind === "call") {
|
|
136
|
+
const row = { kind: "call", sequence: fact.sequence, turnSequence: fact.turnSequence, at: fact.at, text: fact.body };
|
|
137
|
+
const turn = state.turnsBySequence.get(fact.turnSequence);
|
|
138
|
+
if (turn === undefined)
|
|
139
|
+
state.orphanRows.push(row);
|
|
140
|
+
else
|
|
141
|
+
turn.rows.push(row);
|
|
142
|
+
}
|
|
143
|
+
else if (fact.kind === "tell") {
|
|
144
|
+
state.tells.push({ kind: "tell", sequence: fact.sequence, at: fact.recordedAt, tellId: fact.id, text: fact.body, state: fact.state, deliveries: fact.deliveries });
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
projectActivityEvent(state, fact);
|
|
96
148
|
}
|
|
97
149
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
150
|
+
const turns = state.turns.map(finishTurn);
|
|
151
|
+
const rows = [
|
|
152
|
+
...turns.flatMap((turn) => [turn.turn, ...turn.rows, ...(turn.kind === "closed" ? [turn.outcome] : [])]),
|
|
153
|
+
...state.tells,
|
|
154
|
+
...state.orphanRows,
|
|
155
|
+
...state.orphanOutcomes,
|
|
156
|
+
].sort((left, right) => left.sequence - right.sequence);
|
|
157
|
+
const frontier = turns.at(-1);
|
|
158
|
+
const openTurn = frontier?.kind === "open" ? frontier : undefined;
|
|
159
|
+
const latestOutcome = rows.findLast((row) => row.kind === "outcome");
|
|
160
|
+
return { rows, turns, retained, ...(openTurn === undefined ? {} : { openTurn }), ...(latestOutcome === undefined ? {} : { latestOutcome }) };
|
|
161
|
+
}
|
|
162
|
+
function entries(rows) {
|
|
163
|
+
return rows.map((row) => ({ kind: "row", row }));
|
|
164
|
+
}
|
|
165
|
+
function openEntries(ledger, window, selected) {
|
|
166
|
+
const windowRows = new Set(window);
|
|
167
|
+
const result = [];
|
|
168
|
+
let hidden = 0;
|
|
169
|
+
const flushGap = () => {
|
|
170
|
+
if (hidden === 0)
|
|
171
|
+
return;
|
|
172
|
+
result.push({ kind: "gap", count: hidden });
|
|
173
|
+
hidden = 0;
|
|
109
174
|
};
|
|
110
|
-
for (const row of
|
|
175
|
+
for (const row of ledger.rows) {
|
|
176
|
+
if (windowRows.has(row) && !selected.has(row)) {
|
|
177
|
+
hidden += 1;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
111
180
|
if (!selected.has(row))
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
181
|
+
continue;
|
|
182
|
+
flushGap();
|
|
183
|
+
if (row.kind !== "turn" && row.kind !== "outcome" && !(row.kind === "tool" && row.state === "unsettled")) {
|
|
184
|
+
result.push({ kind: "row", row });
|
|
116
185
|
}
|
|
117
186
|
}
|
|
118
|
-
|
|
187
|
+
flushGap();
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
/** Split one nonnegative ordinary allowance into newest tail first, then pre-tail voice. */
|
|
191
|
+
export function ordinarySnapshotBudget(ordinaryBudget) {
|
|
192
|
+
const tail = Math.min(DEFAULT_TAIL, Math.max(0, ordinaryBudget));
|
|
193
|
+
return { tail, voice: Math.min(DEFAULT_VOICE, Math.max(0, ordinaryBudget) - tail) };
|
|
194
|
+
}
|
|
195
|
+
/** Count selected ordinary rows; active tools and pending tells stay outside this total. */
|
|
196
|
+
export function ordinarySelectedCount(snapshot) {
|
|
197
|
+
return snapshot.entries.reduce((count, entry) => {
|
|
198
|
+
if (entry.kind !== "row")
|
|
199
|
+
return count;
|
|
200
|
+
if (entry.row.kind === "tool" && entry.row.state === "active")
|
|
201
|
+
return count;
|
|
202
|
+
if (entry.row.kind === "tell" && entry.row.state === "pending")
|
|
203
|
+
return count;
|
|
204
|
+
return count + 1;
|
|
205
|
+
}, 0);
|
|
206
|
+
}
|
|
207
|
+
/** Select one current Turn, one latest outcome, or no focus; pending tells stay actionable. */
|
|
208
|
+
export function selectSnapshot(ledger, budget = { tail: DEFAULT_TAIL, voice: DEFAULT_VOICE }) {
|
|
209
|
+
if (ledger.turns.length === 0 && !ledger.rows.some((row) => row.kind === "tell"))
|
|
210
|
+
return { kind: "unborn", entries: [], omitted: 0 };
|
|
211
|
+
const pending = ledger.rows.filter((row) => row.kind === "tell" && row.state === "pending");
|
|
212
|
+
if (ledger.openTurn !== undefined) {
|
|
213
|
+
const window = ledger.openTurn.rows;
|
|
214
|
+
const active = window.filter((row) => row.kind === "tool" && row.state === "active");
|
|
215
|
+
const ordinary = window.filter((row) => !(row.kind === "tool" && row.state === "active"));
|
|
216
|
+
const tailCount = Math.max(0, budget.tail);
|
|
217
|
+
const tail = tailCount === 0 ? [] : ordinary.slice(-tailCount);
|
|
218
|
+
const tailSet = new Set(tail);
|
|
219
|
+
const voiceCount = Math.max(0, budget.voice ?? DEFAULT_VOICE);
|
|
220
|
+
const voiceCandidates = ordinary
|
|
221
|
+
.filter((row) => !tailSet.has(row) && (row.kind === "said" || row.kind === "thought"));
|
|
222
|
+
const voice = voiceCount === 0 ? [] : voiceCandidates.slice(-voiceCount);
|
|
223
|
+
const selected = new Set([...tail, ...voice, ...active, ...pending]);
|
|
224
|
+
const omitted = window.filter((row) => !selected.has(row)).length;
|
|
225
|
+
return { kind: "open", turn: ledger.openTurn.turn, entries: openEntries(ledger, window, selected), omitted };
|
|
226
|
+
}
|
|
119
227
|
return {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
228
|
+
kind: "idle",
|
|
229
|
+
...(ledger.latestOutcome === undefined ? {} : { outcome: ledger.latestOutcome }),
|
|
230
|
+
entries: entries(pending),
|
|
231
|
+
omitted: 0,
|
|
123
232
|
};
|
|
124
233
|
}
|
|
125
|
-
/** Apply
|
|
126
|
-
export function
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
234
|
+
/** Apply the one snapshot policy used by every public observation consumer. */
|
|
235
|
+
export function selectActivitySnapshot(facts) {
|
|
236
|
+
return selectSnapshot(projectTurns(facts));
|
|
237
|
+
}
|
|
238
|
+
export function selectHistory(ledger, cursor) {
|
|
239
|
+
const eligible = ledger.rows.filter((row) => cursor.before !== undefined
|
|
240
|
+
? row.sequence < cursor.before
|
|
241
|
+
: cursor.since !== undefined ? row.sequence > cursor.since : true);
|
|
242
|
+
const rows = cursor.since !== undefined ? eligible.slice(0, cursor.limit) : eligible.slice(-cursor.limit);
|
|
243
|
+
const omitted = Math.max(0, eligible.length - rows.length);
|
|
244
|
+
const historyLost = cursor.since !== undefined
|
|
245
|
+
? (ledger.rows[0] !== undefined && ledger.rows[0].sequence > cursor.since + 1)
|
|
246
|
+
: (ledger.retained.lowestRetained !== null && ledger.retained.lowestRetained > 1 && omitted === 0);
|
|
135
247
|
return {
|
|
136
248
|
rows,
|
|
137
|
-
omitted
|
|
138
|
-
hasEarlier:
|
|
139
|
-
hasLater:
|
|
140
|
-
historyLost
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
highest: slice.highest,
|
|
249
|
+
omitted,
|
|
250
|
+
hasEarlier: cursor.since === undefined && eligible.length > rows.length,
|
|
251
|
+
hasLater: cursor.since !== undefined && eligible.length > rows.length,
|
|
252
|
+
historyLost,
|
|
253
|
+
lowestRetained: ledger.retained.lowestRetained,
|
|
254
|
+
highest: ledger.retained.highest,
|
|
144
255
|
};
|
|
145
256
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type ProviderOptions = Readonly<{
|
|
2
|
+
model?: string;
|
|
3
|
+
effort?: string;
|
|
4
|
+
readonly?: true;
|
|
5
|
+
network?: "disabled" | "enabled";
|
|
6
|
+
systemPrompt?: string;
|
|
7
|
+
}>;
|
|
8
|
+
export type ReadonlyRestraint = Readonly<{
|
|
9
|
+
enforcement: "native";
|
|
10
|
+
diagnostic?: never;
|
|
11
|
+
} | {
|
|
12
|
+
enforcement: "none";
|
|
13
|
+
diagnostic: string;
|
|
14
|
+
}>;
|
|
15
|
+
export type ProviderExecution = Readonly<{
|
|
16
|
+
name: string;
|
|
17
|
+
kind: "acp" | "claude-agent-sdk" | "codex-app-server" | "grok-build" | "opencode-sdk" | "pi";
|
|
18
|
+
executable?: string;
|
|
19
|
+
config?: Readonly<Record<string, unknown>>;
|
|
20
|
+
env?: Readonly<Record<string, string>>;
|
|
21
|
+
}>;
|
|
22
|
+
export declare function decodeProviderOptions(value: unknown): ProviderOptions;
|
|
23
|
+
export declare function decodeReadonlyRestraint(value: unknown): ReadonlyRestraint;
|
|
24
|
+
export declare function decodeProviderRecipe(input: unknown): ProviderExecution;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
function record(value) {
|
|
2
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
3
|
+
? value
|
|
4
|
+
: null;
|
|
5
|
+
}
|
|
6
|
+
function snapshot(value) {
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return Object.freeze(value.map(snapshot));
|
|
9
|
+
const object = record(value);
|
|
10
|
+
if (object === null)
|
|
11
|
+
return value;
|
|
12
|
+
return Object.freeze(Object.fromEntries(Object.entries(object).map(([key, item]) => [key, snapshot(item)])));
|
|
13
|
+
}
|
|
14
|
+
function optionText(options, field, blank) {
|
|
15
|
+
const selected = options[field];
|
|
16
|
+
if (selected === undefined)
|
|
17
|
+
return undefined;
|
|
18
|
+
if (typeof selected !== "string" || (blank === "refuse" && selected.trim().length === 0)) {
|
|
19
|
+
throw new TypeError(`provider option ${field} must be ${blank === "allow" ? "a string" : "a nonblank string"}`);
|
|
20
|
+
}
|
|
21
|
+
return selected;
|
|
22
|
+
}
|
|
23
|
+
export function decodeProviderOptions(value) {
|
|
24
|
+
const options = record(value);
|
|
25
|
+
if (options === null)
|
|
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
|
+
const model = optionText(options, "model", "refuse");
|
|
32
|
+
const effort = optionText(options, "effort", "refuse");
|
|
33
|
+
if (options.readonly !== undefined && options.readonly !== true) {
|
|
34
|
+
throw new TypeError("provider option readonly must be true");
|
|
35
|
+
}
|
|
36
|
+
const network = options.network;
|
|
37
|
+
if (network !== undefined && network !== "disabled" && network !== "enabled") {
|
|
38
|
+
throw new TypeError("provider option network must be disabled, enabled");
|
|
39
|
+
}
|
|
40
|
+
const systemPrompt = optionText(options, "systemPrompt", "allow");
|
|
41
|
+
return Object.freeze({
|
|
42
|
+
...(model === undefined ? {} : { model }),
|
|
43
|
+
...(effort === undefined ? {} : { effort }),
|
|
44
|
+
...(options.readonly === undefined ? {} : { readonly: true }),
|
|
45
|
+
...(network === undefined ? {} : { network }),
|
|
46
|
+
...(systemPrompt === undefined ? {} : { systemPrompt }),
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
export function decodeReadonlyRestraint(value) {
|
|
50
|
+
const restraint = record(value);
|
|
51
|
+
if (restraint === null)
|
|
52
|
+
throw new TypeError("readonly restraint must be an object");
|
|
53
|
+
const keys = Object.keys(restraint).sort();
|
|
54
|
+
if (restraint.enforcement === "native" && keys.length === 1 && keys[0] === "enforcement") {
|
|
55
|
+
return Object.freeze({ enforcement: "native" });
|
|
56
|
+
}
|
|
57
|
+
if (restraint.enforcement === "none"
|
|
58
|
+
&& keys.length === 2 && keys[0] === "diagnostic" && keys[1] === "enforcement"
|
|
59
|
+
&& typeof restraint.diagnostic === "string" && restraint.diagnostic.trim().length > 0) {
|
|
60
|
+
return Object.freeze({ enforcement: "none", diagnostic: restraint.diagnostic });
|
|
61
|
+
}
|
|
62
|
+
throw new TypeError("readonly restraint must be native or none with a diagnostic");
|
|
63
|
+
}
|
|
64
|
+
function providerKind(value) {
|
|
65
|
+
return value === "acp" || value === "claude-agent-sdk" || value === "codex-app-server" || value === "grok-build"
|
|
66
|
+
|| value === "opencode-sdk" || value === "pi";
|
|
67
|
+
}
|
|
68
|
+
export function decodeProviderRecipe(input) {
|
|
69
|
+
const value = record(input);
|
|
70
|
+
if (value === null)
|
|
71
|
+
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
|
+
if (typeof value.name !== "string" || value.name.trim().length === 0) {
|
|
77
|
+
throw new TypeError("provider execution name must be a nonblank string");
|
|
78
|
+
}
|
|
79
|
+
if (!providerKind(value.kind))
|
|
80
|
+
throw new TypeError("provider execution has unknown kind");
|
|
81
|
+
if (value.executable !== undefined && (typeof value.executable !== "string" || value.executable.trim().length === 0)) {
|
|
82
|
+
throw new TypeError("provider execution executable must be a nonblank string");
|
|
83
|
+
}
|
|
84
|
+
const config = value.config === undefined ? undefined : record(value.config);
|
|
85
|
+
if (config === null)
|
|
86
|
+
throw new TypeError("provider execution config must be an object");
|
|
87
|
+
const env = value.env === undefined ? undefined : record(value.env);
|
|
88
|
+
if (env === null)
|
|
89
|
+
throw new TypeError("provider execution env must be an object");
|
|
90
|
+
if (env !== undefined && Object.values(env).some((item) => typeof item !== "string")) {
|
|
91
|
+
throw new TypeError("provider execution env must contain only string values");
|
|
92
|
+
}
|
|
93
|
+
return Object.freeze({
|
|
94
|
+
name: value.name,
|
|
95
|
+
kind: value.kind,
|
|
96
|
+
...(value.executable === undefined ? {} : { executable: value.executable }),
|
|
97
|
+
...(config === undefined ? {} : { config: snapshot(config) }),
|
|
98
|
+
...(env === undefined ? {} : { env: Object.freeze({ ...env }) }),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
import type { Confinement
|
|
1
|
+
import type { Confinement } from "./heart/index.js";
|
|
2
2
|
import { decodeResumeCoordinate, encodeResumeCoordinate, type ResumeCoordinate } from "./coordinate.js";
|
|
3
|
+
import type { ProviderOptions, ReadonlyRestraint } from "./provider-recipe.js";
|
|
3
4
|
export type { ResumeCoordinate } from "./coordinate.js";
|
|
4
|
-
export type { ProviderOptions } from "./heart/index.js";
|
|
5
5
|
export declare const AKUMA_REQUESTS_ENV = "AKUMA_REQUESTS";
|
|
6
6
|
export declare const AGENT_EVENT_TEXT_LIMIT = 16384;
|
|
7
7
|
export declare const AGENT_THOUGHT_TEXT_LIMIT = 4000;
|
|
8
|
+
export type SearchScope = "content" | "files" | "web";
|
|
8
9
|
export type ToolCall = Readonly<{
|
|
9
10
|
kind: "run";
|
|
10
11
|
command: string;
|
|
11
12
|
}> | Readonly<{
|
|
12
13
|
kind: "read";
|
|
13
14
|
path: string;
|
|
15
|
+
offset?: number;
|
|
16
|
+
limit?: number;
|
|
14
17
|
}> | Readonly<{
|
|
15
18
|
kind: "search";
|
|
16
19
|
query: string;
|
|
20
|
+
scope?: SearchScope;
|
|
21
|
+
path?: string;
|
|
22
|
+
glob?: string;
|
|
17
23
|
}> | Readonly<{
|
|
18
24
|
kind: "fileChange";
|
|
19
25
|
changes: readonly Readonly<{
|
|
@@ -67,7 +73,6 @@ export type AgentEvent = Readonly<{
|
|
|
67
73
|
truncated?: true;
|
|
68
74
|
}>;
|
|
69
75
|
export { decodeResumeCoordinate, encodeResumeCoordinate };
|
|
70
|
-
export declare function decodeProviderOptions(value: unknown): ProviderOptions;
|
|
71
76
|
export declare function decodeAgentEvent(value: unknown): AgentEvent;
|
|
72
77
|
export declare function encodeAgentEvent(event: AgentEvent): unknown;
|
|
73
78
|
export declare function boundedEventText(value: string): string;
|
|
@@ -89,7 +94,7 @@ export declare class AgentEventChannel implements AsyncIterable<AgentEvent> {
|
|
|
89
94
|
export type TurnResult = Readonly<{
|
|
90
95
|
kind: "answered";
|
|
91
96
|
answer: string;
|
|
92
|
-
historyId
|
|
97
|
+
historyId?: string;
|
|
93
98
|
}> | Readonly<{
|
|
94
99
|
kind: "failed";
|
|
95
100
|
diagnostic: string;
|
|
@@ -117,6 +122,7 @@ export type Session = Readonly<{
|
|
|
117
122
|
events: AsyncIterable<AgentEvent>;
|
|
118
123
|
receipts?: AsyncIterable<TellReceipt>;
|
|
119
124
|
completion: Promise<TurnResult>;
|
|
125
|
+
/** Fulfills after every adapter-owned OS child or native session is disposed. */
|
|
120
126
|
abort(): Promise<void>;
|
|
121
127
|
tell?(tell: Readonly<{
|
|
122
128
|
id: string;
|
|
@@ -131,6 +137,7 @@ export type DriveInput = Readonly<{
|
|
|
131
137
|
}>[];
|
|
132
138
|
cwd: string;
|
|
133
139
|
options: ProviderOptions;
|
|
140
|
+
signal: AbortSignal;
|
|
134
141
|
requests?: Readonly<{
|
|
135
142
|
dir: string;
|
|
136
143
|
}>;
|
|
@@ -138,6 +145,7 @@ export type DriveInput = Readonly<{
|
|
|
138
145
|
export type ProviderOptionAdmission = Readonly<{
|
|
139
146
|
kind: "admitted";
|
|
140
147
|
options: ProviderOptions;
|
|
148
|
+
readonly?: ReadonlyRestraint;
|
|
141
149
|
}> | Readonly<{
|
|
142
150
|
kind: "refused";
|
|
143
151
|
diagnostic: string;
|