zelari-code 2.52.0 → 2.54.0
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/dist/cli/acp/command.js +5 -3
- package/dist/cli/acp/command.js.map +1 -1
- package/dist/cli/acp/framing.js +151 -19
- package/dist/cli/acp/framing.js.map +1 -1
- package/dist/cli/acp/invariants.js +183 -0
- package/dist/cli/acp/invariants.js.map +1 -0
- package/dist/cli/acp/protocol.js +40 -5
- package/dist/cli/acp/protocol.js.map +1 -1
- package/dist/cli/acp/server.js +57 -17
- package/dist/cli/acp/server.js.map +1 -1
- package/dist/cli/acp/turnAdapter.js +2 -1
- package/dist/cli/acp/turnAdapter.js.map +1 -1
- package/dist/cli/app.js +2 -2
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/budget/cacheHitReport.js +94 -0
- package/dist/cli/budget/cacheHitReport.js.map +1 -0
- package/dist/cli/budget/messageUsage.js +77 -0
- package/dist/cli/budget/messageUsage.js.map +1 -0
- package/dist/cli/companion/framePolicy.js +116 -0
- package/dist/cli/companion/framePolicy.js.map +1 -0
- package/dist/cli/components/SelectList.js +51 -14
- package/dist/cli/components/SelectList.js.map +1 -1
- package/dist/cli/components/StatusBar.js +6 -2
- package/dist/cli/components/StatusBar.js.map +1 -1
- package/dist/cli/components/fuzzyMatch.js +108 -0
- package/dist/cli/components/fuzzyMatch.js.map +1 -0
- package/dist/cli/components/statusChips.js +47 -0
- package/dist/cli/components/statusChips.js.map +1 -1
- package/dist/cli/headless/protocol.js +39 -2
- package/dist/cli/headless/protocol.js.map +1 -1
- package/dist/cli/headless/runOneTurn.js +68 -18
- package/dist/cli/headless/runOneTurn.js.map +1 -1
- package/dist/cli/hooks/useChatTurn.js +76 -16
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +5 -2
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/inbox.js +220 -0
- package/dist/cli/inbox.js.map +1 -0
- package/dist/cli/main.bundled.js +3959 -2560
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +22 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/metrics.js.map +1 -1
- package/dist/cli/provider/anthropic.js +42 -6
- package/dist/cli/provider/anthropic.js.map +1 -1
- package/dist/cli/provider/chatgpt.js +4 -0
- package/dist/cli/provider/chatgpt.js.map +1 -1
- package/dist/cli/provider/openai-compatible.js +25 -3
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/provider/responsesApi.js +4 -0
- package/dist/cli/provider/responsesApi.js.map +1 -1
- package/dist/cli/serve/harnessServer.js +7 -0
- package/dist/cli/serve/harnessServer.js.map +1 -1
- package/dist/cli/sessionManager.js +9 -2
- package/dist/cli/sessionManager.js.map +1 -1
- package/dist/cli/skillsCheck.js +209 -0
- package/dist/cli/skillsCheck.js.map +1 -0
- package/dist/cli/slashCommands.js +9 -0
- package/dist/cli/slashCommands.js.map +1 -1
- package/dist/cli/slashHandlers/provider.js.map +1 -1
- package/dist/cli/slashHandlers/sessions.js +131 -0
- package/dist/cli/slashHandlers/sessions.js.map +1 -0
- package/dist/cli/statusline/statuslineItems.js +22 -3
- package/dist/cli/statusline/statuslineItems.js.map +1 -1
- package/dist/cli/statusline/verdictFeed.js +245 -0
- package/dist/cli/statusline/verdictFeed.js.map +1 -0
- package/dist/cli/utils/doctor.js +30 -0
- package/dist/cli/utils/doctor.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import { Box, Text, useInput, useStdin } from 'ink';
|
|
3
3
|
import { TUI_PALETTE } from './tuiPalette.js';
|
|
4
|
+
import { fuzzyMatch } from './fuzzyMatch.js';
|
|
4
5
|
/**
|
|
5
6
|
* Pure windowing helper (exported for tests): index of the first visible
|
|
6
7
|
* item so the cursor stays roughly centered while the list scrolls.
|
|
@@ -11,46 +12,79 @@ export function windowStart(index, count, maxVisible) {
|
|
|
11
12
|
const half = Math.floor(maxVisible / 2);
|
|
12
13
|
return Math.max(0, Math.min(index - half, count - maxVisible));
|
|
13
14
|
}
|
|
15
|
+
/** Anything a terminal can deliver as a literal character (no control codes). */
|
|
16
|
+
const PRINTABLE_INPUT = /^[^\u0000-\u001f\u007f]+$/;
|
|
14
17
|
/**
|
|
15
18
|
* SelectList — arrow-key picker rendered in the dynamic region (v0.7.10).
|
|
16
19
|
*
|
|
17
20
|
* Used by `/provider` and `/model` (no args) to make providers and models
|
|
18
|
-
* selectable instead of typed
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* selectable instead of typed, and by `/sessions` (v2.53) for the fuzzy
|
|
22
|
+
* session picker. The App swaps it in for the InputBar while open, so
|
|
23
|
+
* ink-text-input never competes for keystrokes. ↑/↓ move (with wrap-around),
|
|
24
|
+
* enter selects, esc cancels. Long lists scroll inside a `maxVisible` window
|
|
25
|
+
* so the dynamic region stays under a screen.
|
|
26
|
+
*
|
|
27
|
+
* v2.53 filter: when filterable, typed characters build a query and the list
|
|
28
|
+
* is re-ranked live by `fuzzyMatch` (every whitespace-separated term must
|
|
29
|
+
* match — multi-term AND). An empty query shows the unfiltered list, so the
|
|
30
|
+
* picker behaves exactly like the pre-filter one until the user types.
|
|
31
|
+
* Backspace widens; esc cancels (the query is only ever a view over the list,
|
|
32
|
+
* never state the caller sees).
|
|
22
33
|
*/
|
|
23
|
-
export function SelectList({ title, items, onSelect, onCancel, maxVisible = 8, }) {
|
|
34
|
+
export function SelectList({ title, items, onSelect, onCancel, maxVisible = 8, filterable, filterPlaceholder = 'type to filter', }) {
|
|
24
35
|
const firstCurrent = items.findIndex((i) => i.current);
|
|
25
36
|
const [index, setIndex] = useState(firstCurrent === -1 ? 0 : firstCurrent);
|
|
37
|
+
const [query, setQuery] = useState('');
|
|
26
38
|
const { isRawModeSupported } = useStdin();
|
|
27
|
-
|
|
39
|
+
const searchable = filterable ?? items.some((i) => (i.searchText ?? '').length > 0);
|
|
40
|
+
// The filter is a VIEW over `items`: with an empty query the original order
|
|
41
|
+
// (and therefore the original picker behavior) is preserved.
|
|
42
|
+
const shown = searchable ? fuzzyMatch(query, items) : items;
|
|
43
|
+
// The active cursor can fall outside the shown list (query narrowed, or
|
|
44
|
+
// `items` changed under a non-empty query) — clamp for keys and render alike.
|
|
45
|
+
const active = shown.length === 0 ? 0 : Math.min(index, shown.length - 1);
|
|
46
|
+
const typeQuery = (next) => {
|
|
47
|
+
setQuery(next);
|
|
48
|
+
setIndex(0); // best match first: the cursor jumps to the head of the list
|
|
49
|
+
};
|
|
50
|
+
useInput((input, key) => {
|
|
28
51
|
if (key.upArrow) {
|
|
29
|
-
setIndex((
|
|
52
|
+
setIndex(() => (shown.length === 0 ? 0 : (active - 1 + shown.length) % shown.length));
|
|
30
53
|
}
|
|
31
54
|
else if (key.downArrow) {
|
|
32
|
-
setIndex((
|
|
55
|
+
setIndex(() => (shown.length === 0 ? 0 : (active + 1) % shown.length));
|
|
33
56
|
}
|
|
34
57
|
else if (key.return) {
|
|
35
|
-
const item =
|
|
58
|
+
const item = shown[active];
|
|
36
59
|
if (item)
|
|
37
60
|
onSelect(item.value);
|
|
38
61
|
}
|
|
39
62
|
else if (key.escape) {
|
|
40
63
|
onCancel();
|
|
41
64
|
}
|
|
65
|
+
else if (searchable) {
|
|
66
|
+
if (key.backspace || key.delete)
|
|
67
|
+
typeQuery(query.slice(0, -1));
|
|
68
|
+
else if (PRINTABLE_INPUT.test(input))
|
|
69
|
+
typeQuery(query + input);
|
|
70
|
+
}
|
|
42
71
|
}, { isActive: isRawModeSupported === true });
|
|
43
|
-
const start = windowStart(
|
|
44
|
-
const visible =
|
|
45
|
-
const below =
|
|
72
|
+
const start = windowStart(active, shown.length, maxVisible);
|
|
73
|
+
const visible = shown.slice(start, start + maxVisible);
|
|
74
|
+
const below = shown.length - (start + visible.length);
|
|
46
75
|
return (React.createElement(Box, { flexDirection: "column", borderStyle: "round", borderColor: TUI_PALETTE.borderFocus, paddingX: 1 },
|
|
47
76
|
React.createElement(Text, { bold: true, color: TUI_PALETTE.brand }, title),
|
|
77
|
+
searchable && (React.createElement(Text, { wrap: "truncate" },
|
|
78
|
+
'filter: ',
|
|
79
|
+
query.length > 0
|
|
80
|
+
? React.createElement(Text, { color: TUI_PALETTE.brandAlt }, query)
|
|
81
|
+
: React.createElement(Text, { dimColor: true }, filterPlaceholder))),
|
|
48
82
|
start > 0 && React.createElement(Text, { dimColor: true },
|
|
49
83
|
" \u2191 ",
|
|
50
84
|
start,
|
|
51
85
|
" more"),
|
|
52
86
|
visible.map((item, i) => {
|
|
53
|
-
const selected = start + i ===
|
|
87
|
+
const selected = start + i === active;
|
|
54
88
|
return (React.createElement(Text, { key: item.value, wrap: "truncate", color: selected ? TUI_PALETTE.brand : undefined },
|
|
55
89
|
selected ? '❯ ' : ' ',
|
|
56
90
|
React.createElement(Text, { bold: selected }, item.label),
|
|
@@ -63,6 +97,9 @@ export function SelectList({ title, items, onSelect, onCancel, maxVisible = 8, }
|
|
|
63
97
|
" \u2193 ",
|
|
64
98
|
below,
|
|
65
99
|
" more"),
|
|
66
|
-
React.createElement(Text, { dimColor: true }, "
|
|
100
|
+
shown.length === 0 && React.createElement(Text, { dimColor: true }, " no matches \u2014 backspace widens"),
|
|
101
|
+
React.createElement(Text, { dimColor: true }, searchable
|
|
102
|
+
? '↑/↓ move · type to filter · enter select · esc cancel'
|
|
103
|
+
: '↑/↓ move · enter select · esc cancel')));
|
|
67
104
|
}
|
|
68
105
|
//# sourceMappingURL=SelectList.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectList.js","sourceRoot":"","sources":["../../../src/cli/components/SelectList.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"SelectList.js","sourceRoot":"","sources":["../../../src/cli/components/SelectList.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ import { TUI_PALETTE, modeColor } from './tuiPalette.js';
|
|
|
17
17
|
* region as short as possible. A single status line + the input bar + the
|
|
18
18
|
* streaming tail is always well under a screen, so no full repaint.
|
|
19
19
|
*/
|
|
20
|
-
function StatusBarImpl({ model, provider, sessionId, sessionActive, queueCount = 0, busy = false, mode = 'kraken', phase = 'build', cwd, elapsedMs = null, lastMs = null, costUsd = 0, cachedTokens = 0, cacheHitRate = 0, contextUsed = 0, contextLimit = 0, todoSummary = null, krakenLive = null, krakenGraph = null, verify = null, permissions = null, jail = null, }) {
|
|
20
|
+
function StatusBarImpl({ model, provider, sessionId, sessionActive, queueCount = 0, busy = false, mode = 'kraken', phase = 'build', cwd, elapsedMs = null, lastMs = null, costUsd = 0, cachedTokens = 0, cacheHitRate = 0, contextUsed = 0, contextLimit = 0, todoSummary = null, krakenLive = null, krakenGraph = null, verify = null, permissions = null, jail = null, verdict = null, }) {
|
|
21
21
|
const ctxLabel = contextLimit > 0
|
|
22
22
|
? `${formatTokens(contextUsed)}/${formatTokens(contextLimit)}`
|
|
23
23
|
: contextUsed > 0
|
|
@@ -45,6 +45,9 @@ function StatusBarImpl({ model, provider, sessionId, sessionActive, queueCount =
|
|
|
45
45
|
jail ? (React.createElement(React.Fragment, null,
|
|
46
46
|
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
47
47
|
React.createElement(Text, { bold: true, color: jail.tone }, jail.label))) : null,
|
|
48
|
+
verdict ? (React.createElement(React.Fragment, null,
|
|
49
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
50
|
+
React.createElement(Text, { bold: true, color: verdict.tone }, verdict.label))) : null,
|
|
48
51
|
React.createElement(Text, { bold: true, color: TUI_PALETTE.brand }, provider),
|
|
49
52
|
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
50
53
|
React.createElement(Text, null, model),
|
|
@@ -136,7 +139,8 @@ export function statusBarPropsEqual(prev, next) {
|
|
|
136
139
|
prev.krakenGraph === next.krakenGraph &&
|
|
137
140
|
statusChipPropsEqual(prev.verify, next.verify) &&
|
|
138
141
|
statusChipPropsEqual(prev.permissions, next.permissions) &&
|
|
139
|
-
statusChipPropsEqual(prev.jail, next.jail)
|
|
142
|
+
statusChipPropsEqual(prev.jail, next.jail) &&
|
|
143
|
+
statusChipPropsEqual(prev.verdict, next.verdict));
|
|
140
144
|
}
|
|
141
145
|
export const StatusBar = React.memo(StatusBarImpl, statusBarPropsEqual);
|
|
142
146
|
//# sourceMappingURL=StatusBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../src/cli/components/StatusBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../src/cli/components/StatusBar.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fuzzyMatch — dependency-free fuzzy filter for the interactive pickers.
|
|
3
|
+
*
|
|
4
|
+
* Matching (documented choice): the query is split on whitespace into terms
|
|
5
|
+
* and EVERY term must match — a multi-term query is an AND, never an OR. Each
|
|
6
|
+
* term matches when its characters appear IN ORDER anywhere in the candidate's
|
|
7
|
+
* lowercased `searchText` (classic fuzzy-finder subsequence matching, the
|
|
8
|
+
* fzf/`:Telescope` model): "kr gr" hits "kraken graph", "kwk" hits
|
|
9
|
+
* "kraken-worktree-key". Terms run against the whole searchText, not per-field,
|
|
10
|
+
* so a single term may span fields ("kraken /repo").
|
|
11
|
+
*
|
|
12
|
+
* Ranking (deliberately small and deterministic):
|
|
13
|
+
* 1. a whole-query substring hit outranks scattered term hits;
|
|
14
|
+
* 2. prefix hits outrank mid-string hits;
|
|
15
|
+
* 3. earlier first-match and word-start hits score higher;
|
|
16
|
+
* 4. adjacent (consecutive) matches score higher;
|
|
17
|
+
* 5. shorter searchText wins remaining ties; original order breaks the rest.
|
|
18
|
+
*
|
|
19
|
+
* Pure: no DOM, no I/O, no deps — the pickers pass plain `{searchText}` items.
|
|
20
|
+
*/
|
|
21
|
+
/** True for characters that continue a word (`-`, `_`, `/`, `.` are separators). */
|
|
22
|
+
function isWordChar(ch) {
|
|
23
|
+
return /[a-z0-9]/i.test(ch);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Score one term against one haystack (lowercased by the caller).
|
|
27
|
+
* Returns null when the term is not a subsequence of `text`.
|
|
28
|
+
*/
|
|
29
|
+
function scoreTerm(term, text) {
|
|
30
|
+
let ti = 0;
|
|
31
|
+
let last = -1;
|
|
32
|
+
let first = -1;
|
|
33
|
+
let score = 0;
|
|
34
|
+
for (let i = 0; i < text.length && ti < term.length; i++) {
|
|
35
|
+
if (text[i] !== term[ti])
|
|
36
|
+
continue;
|
|
37
|
+
if (first < 0)
|
|
38
|
+
first = i;
|
|
39
|
+
// Word-start hits (index 0 or right after a separator) are the strongest
|
|
40
|
+
// signal a fuzzy finder has: "gr" should find "graph", not "grep".
|
|
41
|
+
score += i === 0 || !isWordChar(text[i - 1] ?? '') ? 3 : 1;
|
|
42
|
+
if (last >= 0 && i === last + 1)
|
|
43
|
+
score += 1; // consecutive run
|
|
44
|
+
last = i;
|
|
45
|
+
ti++;
|
|
46
|
+
}
|
|
47
|
+
if (ti < term.length)
|
|
48
|
+
return null;
|
|
49
|
+
if (first === 0)
|
|
50
|
+
score += 4; // starts the haystack
|
|
51
|
+
else if (first > 0 && !isWordChar(text[first - 1] ?? ''))
|
|
52
|
+
score += 2; // word start
|
|
53
|
+
// Earlier matches win: a hit at index 0-3 gets a small positional bonus.
|
|
54
|
+
score += Math.max(0, 3 - first);
|
|
55
|
+
return score;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Score a full query (possibly several whitespace-separated terms) against a
|
|
59
|
+
* haystack. `null` = no match; 0 = empty query (matches everything).
|
|
60
|
+
*/
|
|
61
|
+
export function fuzzyScore(query, searchText) {
|
|
62
|
+
const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
63
|
+
if (terms.length === 0)
|
|
64
|
+
return 0;
|
|
65
|
+
const text = searchText.toLowerCase();
|
|
66
|
+
let total = 0;
|
|
67
|
+
for (const term of terms) {
|
|
68
|
+
const s = scoreTerm(term, text);
|
|
69
|
+
if (s === null)
|
|
70
|
+
return null; // AND: one failing term drops the candidate
|
|
71
|
+
total += s;
|
|
72
|
+
}
|
|
73
|
+
const whole = query.toLowerCase().trim().replace(/\s+/g, ' ');
|
|
74
|
+
// Exact-ish feel: the query as typed (spaces squashed) appearing verbatim.
|
|
75
|
+
if (whole.length > 1 && text.includes(whole))
|
|
76
|
+
total += 20;
|
|
77
|
+
else if (text.startsWith(terms[0]))
|
|
78
|
+
total += 4; // prefix of the haystack
|
|
79
|
+
return total;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Rank `items` for `query`. An empty/whitespace-only query returns every item
|
|
83
|
+
* in its ORIGINAL order (the picker then shows the unfiltered list); otherwise
|
|
84
|
+
* matching items come back best-first, ties broken by original order.
|
|
85
|
+
*/
|
|
86
|
+
export function fuzzyMatch(query, items) {
|
|
87
|
+
const terms = query.split(/\s+/).filter((t) => t.length > 0);
|
|
88
|
+
if (terms.length === 0)
|
|
89
|
+
return [...items];
|
|
90
|
+
const ranked = [];
|
|
91
|
+
items.forEach((item, index) => {
|
|
92
|
+
const score = fuzzyScore(query, item.searchText ?? '');
|
|
93
|
+
if (score === null)
|
|
94
|
+
return;
|
|
95
|
+
ranked.push({ item, score, index });
|
|
96
|
+
});
|
|
97
|
+
ranked.sort((a, b) => {
|
|
98
|
+
if (b.score !== a.score)
|
|
99
|
+
return b.score - a.score;
|
|
100
|
+
const la = (a.item.searchText ?? '').length;
|
|
101
|
+
const lb = (b.item.searchText ?? '').length;
|
|
102
|
+
if (la !== lb)
|
|
103
|
+
return la - lb; // denser haystacks win
|
|
104
|
+
return a.index - b.index; // stable
|
|
105
|
+
});
|
|
106
|
+
return ranked.map((r) => r.item);
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=fuzzyMatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fuzzyMatch.js","sourceRoot":"","sources":["../../../src/cli/components/fuzzyMatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAQH,oFAAoF;AACpF,SAAS,UAAU,CAAC,EAAU;IAC5B,OAAO,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,IAAY;IAC3C,IAAI,EAAE,GAAG,CAAC,CAAC;IACX,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzD,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,EAAE,CAAC;YAAE,SAAS;QACnC,IAAI,KAAK,GAAG,CAAC;YAAE,KAAK,GAAG,CAAC,CAAC;QACzB,yEAAyE;QACzE,mEAAmE;QACnE,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3D,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC,CAAC,kBAAkB;QAC/D,IAAI,GAAG,CAAC,CAAC;QACT,EAAE,EAAE,CAAC;IACP,CAAC;IACD,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,IAAI,KAAK,KAAK,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC,CAAC,sBAAsB;SAC9C,IAAI,KAAK,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa;IACnF,yEAAyE;IACzE,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,UAAkB;IAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3E,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,UAAU,CAAC,WAAW,EAAE,CAAC;IACtC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC,CAAC,4CAA4C;QACzE,KAAK,IAAI,CAAC,CAAC;IACb,CAAC;IACD,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC9D,2EAA2E;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,KAAK,IAAI,EAAE,CAAC;SACrD,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC,CAAC,yBAAyB;IAC1E,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,KAAmB;IAEnB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAgD,EAAE,CAAC;IAC/D,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC5B,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QACvD,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO;QAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACnB,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YAAE,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;QAClD,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAC5C,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAC5C,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,uBAAuB;QACtD,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS;IACrC,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -16,9 +16,14 @@
|
|
|
16
16
|
* permission / policy-load env vars, the CI flag and the registered
|
|
17
17
|
* policy-load surface. A runtime change of any of them re-resolves the chip.
|
|
18
18
|
*/
|
|
19
|
+
import { existsSync, statSync } from 'node:fs';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { resolveSessionsDir } from '@zelari/core/session';
|
|
19
22
|
import { activeJailMode, probeJailBackend, OS_JAIL_ENV } from '../safety/osJail.js';
|
|
20
23
|
import { activePolicyLoadSurface, POLICY_LOAD_MODE_ENV } from '../safety/policyLoadMode.js';
|
|
21
24
|
import { loadStatusLineConfig } from '../statusline/statuslineConfig.js';
|
|
25
|
+
import { readVerdictFeed, verdictFeedText } from '../statusline/verdictFeed.js';
|
|
26
|
+
import { getCurrentSessionId } from '../sessionManager.js';
|
|
22
27
|
/**
|
|
23
28
|
* t114: is this item part of the user's (or default) status-line order?
|
|
24
29
|
* Answers from the persisted config, so `/statusline off jail` hides the chip
|
|
@@ -85,4 +90,46 @@ export function cachedJailStatusChip(env = process.env, platform = process.platf
|
|
|
85
90
|
export function resetJailChipCacheForTests() {
|
|
86
91
|
chipCache = null;
|
|
87
92
|
}
|
|
93
|
+
/** Pure: feed -> chip. Exported for tests; never touches disk. */
|
|
94
|
+
export function verdictChipFromFeed(feed, env = process.env) {
|
|
95
|
+
const label = verdictFeedText(feed, env);
|
|
96
|
+
if (label === null)
|
|
97
|
+
return null;
|
|
98
|
+
const tone = feed?.ready === true ? 'green' : feed?.verdict === 'BLOCKED' ? 'red' : 'yellow';
|
|
99
|
+
return { label, tone };
|
|
100
|
+
}
|
|
101
|
+
/** Every input the verdict chip depends on, flattened into a comparable key. */
|
|
102
|
+
function verdictChipKey(env) {
|
|
103
|
+
const sessionId = getCurrentSessionId();
|
|
104
|
+
let mtime = 'none';
|
|
105
|
+
if (sessionId) {
|
|
106
|
+
try {
|
|
107
|
+
const file = path.join(resolveSessionsDir({ env }), sessionId, 'events.jsonl');
|
|
108
|
+
mtime = existsSync(file) ? String(statSync(file).mtimeMs) : 'none';
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
mtime = 'none';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return `${sessionId ?? 'no-session'}|${env.ZELARI_VERDICT_FEED ?? ''}|${mtime}`;
|
|
115
|
+
}
|
|
116
|
+
let verdictChipCache = null;
|
|
117
|
+
/**
|
|
118
|
+
* Cached verdict chip — safe to call from a render body. Opt-in item: it only
|
|
119
|
+
* paints when `/statusline on verdict` added it to the configured order.
|
|
120
|
+
*/
|
|
121
|
+
export function cachedVerdictStatusChip(env = process.env) {
|
|
122
|
+
if (!statusLineItemEnabled('verdict'))
|
|
123
|
+
return null;
|
|
124
|
+
const key = verdictChipKey(env);
|
|
125
|
+
if (verdictChipCache && verdictChipCache.key === key)
|
|
126
|
+
return verdictChipCache.chip;
|
|
127
|
+
const chip = verdictChipFromFeed(readVerdictFeed({ env }), env);
|
|
128
|
+
verdictChipCache = { key, chip };
|
|
129
|
+
return chip;
|
|
130
|
+
}
|
|
131
|
+
/** TEST-ONLY: drop the memoized verdict chip (same discipline as the jail chip). */
|
|
132
|
+
export function resetVerdictChipCacheForTests() {
|
|
133
|
+
verdictChipCache = null;
|
|
134
|
+
}
|
|
88
135
|
//# sourceMappingURL=statusChips.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"statusChips.js","sourceRoot":"","sources":["../../../src/cli/components/statusChips.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACpF,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"statusChips.js","sourceRoot":"","sources":["../../../src/cli/components/statusChips.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,34 @@
|
|
|
10
10
|
*/
|
|
11
11
|
/** Bump when the stdout event set or stdin contract changes. */
|
|
12
12
|
export const HEADLESS_PROTOCOL_VERSION = 2;
|
|
13
|
+
/**
|
|
14
|
+
* STABLE STRING error codes for the headless control plane (invariant 3, same
|
|
15
|
+
* rule as acp/protocol.ts): a code is a stable identifier a host can branch
|
|
16
|
+
* on, never a number and never a human message. Rejection acks carry theirs in
|
|
17
|
+
* `code`; `reason` stays the human-readable detail.
|
|
18
|
+
*/
|
|
19
|
+
export const HEADLESS_ERROR_CODES = {
|
|
20
|
+
/** The control line/params were unusable (malformed JSON, bad shape). */
|
|
21
|
+
CONTROL_REJECTED: 'control_rejected',
|
|
22
|
+
/** Carried by the ControlEvent union but not mapped onto runtime semantics. */
|
|
23
|
+
CONTROL_UNSUPPORTED: 'control_unsupported',
|
|
24
|
+
/** The run was already finished — the control arrived too late. */
|
|
25
|
+
RUN_ALREADY_FINISHED: 'run_already_finished',
|
|
26
|
+
/** A turn ended without delivering. */
|
|
27
|
+
TURN_FAILED: 'turn_failed',
|
|
28
|
+
/** A stream invariant was violated (see acp/invariants.ts). */
|
|
29
|
+
PROTOCOL_ERROR: 'protocol_error',
|
|
30
|
+
/** A payload was clamped to the cap below. */
|
|
31
|
+
TRUNCATED_PAYLOAD: 'truncated_payload',
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Cap for ONE outbound `reason` string. A control rejection can carry a
|
|
35
|
+
* provider/fs error message of arbitrary size; the cap keeps the NDJSON frame
|
|
36
|
+
* bounded and — invariant 2 — a clamped reason is ALWAYS disclosed with
|
|
37
|
+
* `truncated: true` (see `controlRejectedEvent`). Generous on purpose: it
|
|
38
|
+
* never fires on normal traffic.
|
|
39
|
+
*/
|
|
40
|
+
export const HEADLESS_REASON_MAX_CHARS = 2000;
|
|
13
41
|
/** Capabilities advertised by this CLI build (§35). */
|
|
14
42
|
export const HEADLESS_PROTOCOL_CAPABILITIES = [
|
|
15
43
|
'stdin-control',
|
|
@@ -42,11 +70,20 @@ export function controlAppliedEvent(controlId, controlType, boundary) {
|
|
|
42
70
|
ts: Date.now(),
|
|
43
71
|
};
|
|
44
72
|
}
|
|
45
|
-
|
|
73
|
+
/**
|
|
74
|
+
* A rejected control. `code` is a stable string code (invariant 3) chosen by
|
|
75
|
+
* the caller — default `control_rejected` — and `reason` is the human detail.
|
|
76
|
+
* The reason is clamped to HEADLESS_REASON_MAX_CHARS and the clamp is ALWAYS
|
|
77
|
+
* disclosed with `truncated: true` (invariant 2: no silent truncation).
|
|
78
|
+
*/
|
|
79
|
+
export function controlRejectedEvent(controlId, reason, code = HEADLESS_ERROR_CODES.CONTROL_REJECTED) {
|
|
80
|
+
const clamped = reason.length > HEADLESS_REASON_MAX_CHARS;
|
|
46
81
|
return {
|
|
47
82
|
type: 'control_rejected',
|
|
48
83
|
controlId,
|
|
49
|
-
reason,
|
|
84
|
+
reason: clamped ? reason.slice(0, HEADLESS_REASON_MAX_CHARS) : reason,
|
|
85
|
+
code,
|
|
86
|
+
...(clamped ? { truncated: true } : {}),
|
|
50
87
|
ts: Date.now(),
|
|
51
88
|
};
|
|
52
89
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/cli/headless/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAE3C,uDAAuD;AACvD,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,eAAe;IACf,OAAO;IACP,WAAW;IACX,QAAQ;CACA,CAAC;AAEX,MAAM,UAAU,iBAAiB;IAM/B,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,yBAAyB;QAClC,YAAY,EAAE,8BAA8B;QAC5C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;AACJ,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/cli/headless/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,yEAAyE;IACzE,gBAAgB,EAAE,kBAAkB;IACpC,+EAA+E;IAC/E,mBAAmB,EAAE,qBAAqB;IAC1C,mEAAmE;IACnE,oBAAoB,EAAE,sBAAsB;IAC5C,uCAAuC;IACvC,WAAW,EAAE,aAAa;IAC1B,+DAA+D;IAC/D,cAAc,EAAE,gBAAgB;IAChC,8CAA8C;IAC9C,iBAAiB,EAAE,mBAAmB;CAC9B,CAAC;AAIX;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C,uDAAuD;AACvD,MAAM,CAAC,MAAM,8BAA8B,GAAG;IAC5C,eAAe;IACf,OAAO;IACP,WAAW;IACX,QAAQ;CACA,CAAC;AAEX,MAAM,UAAU,iBAAiB;IAM/B,OAAO;QACL,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,yBAAyB;QAClC,YAAY,EAAE,8BAA8B;QAC5C,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;AACJ,CAAC;AAeD,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,WAAmB;IAEnB,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,SAAS;QACT,WAAW;QACX,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,SAAiB,EACjB,WAAmB,EACnB,QAAgB;IAEhB,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,SAAS;QACT,WAAW;QACX,QAAQ;QACR,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,MAAc,EACd,OAA0B,oBAAoB,CAAC,gBAAgB;IAE/D,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,GAAG,yBAAyB,CAAC;IAC1D,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,SAAS;QACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC,CAAC,CAAC,MAAM;QACrE,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAa,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -28,7 +28,7 @@ import { spineOrchestrationNote } from '../orchestration/facts.js';
|
|
|
28
28
|
import { flushMemorySpineNotes, memorySinkFor } from '../memory/spineTelemetry.js';
|
|
29
29
|
import { emitEvent, resolveHeadlessCwd, resolveHeadlessKey } from '../headless.js';
|
|
30
30
|
import { isKrakenMode } from '../mode.js';
|
|
31
|
-
import { buildSystemPromptSplit, systemMessagesFromSplit, getAllTools, KRAKEN_IDENTITY_MODULE, KRAKEN_LEAD_PLAYBOOK_MODULE, buildLanguagePolicyModuleFor } from '@zelari/core/skills';
|
|
31
|
+
import { buildSystemPromptSplit, systemMessagesFromSplit, assembleRequestMessages, isTrailingContextContent, resolvePromptLayout, getAllTools, KRAKEN_IDENTITY_MODULE, KRAKEN_LEAD_PLAYBOOK_MODULE, buildLanguagePolicyModuleFor } from '@zelari/core/skills';
|
|
32
32
|
import { envNumber } from '../utils/envNumber.js';
|
|
33
33
|
import { createStreamScrubber } from '../utils/streamScrub.js';
|
|
34
34
|
import { promises as fs } from 'node:fs';
|
|
@@ -46,6 +46,7 @@ import { nativePackEnabled } from '../kraken/nativeVerification.js';
|
|
|
46
46
|
import { runAdvisoryVerifierReview } from '../kraken/verifierLifecycle.js';
|
|
47
47
|
import { buildModelContext, resourceStatusTail } from '../budget/modelContextBuilder.js';
|
|
48
48
|
import { recordCompactionMetrics } from '../metrics.js';
|
|
49
|
+
import { flushMessageUsage, recordMessageUsage } from '../budget/messageUsage.js';
|
|
49
50
|
import { openHeadlessSpine, seedHeadlessModelHistory, sessionStartedEvent } from '../headlessSpine.js';
|
|
50
51
|
// HarnessState inc.3: shared final-NDJSON read-model emitter (ADR-0023 lens)
|
|
51
52
|
// for this host + council/mission/kraken-graph (H1 inc.2 → inc.3).
|
|
@@ -352,7 +353,15 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
352
353
|
parameters: t.function.parameters,
|
|
353
354
|
}));
|
|
354
355
|
const toolNames = tools.map((t) => t.name);
|
|
356
|
+
// Header/measurement shape: `[stable, volatile]` exactly as before M2.1 —
|
|
357
|
+
// the budget pipeline measures occupancy and fingerprints the system surface
|
|
358
|
+
// from this array, so keeping the pre-M2 bytes here leaves compaction policy
|
|
359
|
+
// and cache anchoring untouched. The WIRE shape is `wireSplit` below.
|
|
355
360
|
let systemMessages;
|
|
361
|
+
// M2.1 wire split: the request layout moves the volatile segment out of the
|
|
362
|
+
// system prefix (see `initialMessages`). In the degraded fallback the single
|
|
363
|
+
// fallback system message becomes `stable` with an empty volatile part.
|
|
364
|
+
let wireSplit;
|
|
356
365
|
let languageDirectiveContent;
|
|
357
366
|
try {
|
|
358
367
|
languageDirectiveContent = buildLanguagePolicyModuleFor(opts.task).content;
|
|
@@ -459,7 +468,12 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
459
468
|
agentSkillConfigs: [],
|
|
460
469
|
},
|
|
461
470
|
});
|
|
462
|
-
|
|
471
|
+
// Measurement/header shape (pre-M2 bytes): occupancy + header fingerprint.
|
|
472
|
+
systemMessages = systemMessagesFromSplit(split, { includeVolatile: true });
|
|
473
|
+
// Wire shape (M2.1): the volatile segment is no longer a second system
|
|
474
|
+
// message — `initialMessages` places it as an EPHEMERAL trailing user
|
|
475
|
+
// message after the history (stable-only system prefix = cacheable).
|
|
476
|
+
wireSplit = split;
|
|
463
477
|
}
|
|
464
478
|
catch {
|
|
465
479
|
// Minimal fallback if buildSystemPromptSplit fails — still include IP secrecy.
|
|
@@ -476,6 +490,9 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
476
490
|
].join('\n'),
|
|
477
491
|
},
|
|
478
492
|
];
|
|
493
|
+
// Same single-message shape on the wire, expressed as a split so the
|
|
494
|
+
// request assembly stays uniform (no trailing context in this path).
|
|
495
|
+
wireSplit = { stable: systemMessages[0].content, volatile: '' };
|
|
479
496
|
}
|
|
480
497
|
// Exit-1/E1.2: prior turns come from the session spine (see
|
|
481
498
|
// seedHeadlessModelHistory above) — user/assistant only, assistant
|
|
@@ -579,6 +596,20 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
579
596
|
for await (const event of harness.run()) {
|
|
580
597
|
progressRuntime.observe(event);
|
|
581
598
|
spine.observe(event);
|
|
599
|
+
// M1.1 (cache-hit-rate plan): the headless path used to persist NO
|
|
600
|
+
// per-call usage at all (only compaction counters), so metrics.jsonl
|
|
601
|
+
// stayed cache-blind for every autonomous run. One `kind:'message'`
|
|
602
|
+
// row per LLM call, carrying the provider-verified cache split.
|
|
603
|
+
if (event.type === 'message_end' && event.usage) {
|
|
604
|
+
recordMessageUsage({
|
|
605
|
+
sessionId: passSessionId,
|
|
606
|
+
provider,
|
|
607
|
+
model,
|
|
608
|
+
promptTokens: event.usage.promptTokens,
|
|
609
|
+
completionTokens: event.usage.completionTokens,
|
|
610
|
+
cachedPromptTokens: event.usage.cachedPromptTokens ?? 0,
|
|
611
|
+
});
|
|
612
|
+
}
|
|
582
613
|
if (event.type === 'message_start') {
|
|
583
614
|
scrub.reset();
|
|
584
615
|
}
|
|
@@ -634,6 +665,9 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
634
665
|
};
|
|
635
666
|
}
|
|
636
667
|
const buildProgress = readBuildProgress();
|
|
668
|
+
// M1.1: drain the metrics queue before this call returns — the headless
|
|
669
|
+
// process must not exit with the last usage row still in memory.
|
|
670
|
+
await flushMessageUsage();
|
|
637
671
|
return {
|
|
638
672
|
finalReason,
|
|
639
673
|
exitCode,
|
|
@@ -658,17 +692,26 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
658
692
|
},
|
|
659
693
|
});
|
|
660
694
|
progressRuntime.beginTurn();
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
695
|
+
// M2.1 (cache-hit-rate plan): the request seed is assembled by the layout
|
|
696
|
+
// helper — `trailing` (default) = [stable system][history][EPHEMERAL trailing
|
|
697
|
+
// context][task], `legacy` = [stable, volatile system][history][task]. The
|
|
698
|
+
// trailing message exists only in this array (the HTTP body): it must never
|
|
699
|
+
// reach the session spine or the seeded history, or the volatile context
|
|
700
|
+
// would duplicate on every turn.
|
|
701
|
+
const initialMessages = assembleRequestMessages({
|
|
702
|
+
split: wireSplit,
|
|
703
|
+
history: historySeed,
|
|
704
|
+
turn: [
|
|
705
|
+
{
|
|
706
|
+
role: 'user',
|
|
707
|
+
content: effectiveTask,
|
|
708
|
+
...(opts.images && opts.images.length > 0
|
|
709
|
+
? { images: opts.images }
|
|
710
|
+
: {}),
|
|
711
|
+
},
|
|
712
|
+
],
|
|
713
|
+
layout: resolvePromptLayout(),
|
|
714
|
+
}).messages;
|
|
672
715
|
let pass = await runSinglePass(initialMessages, sessionId);
|
|
673
716
|
// E2.2: when strict mode is on and the gate stays blocked after the repair
|
|
674
717
|
// pass, the run closes non-success (dedicated exit code + session status).
|
|
@@ -758,11 +801,18 @@ export async function runOneTurn(opts, provider, model, providerStream, extras)
|
|
|
758
801
|
}
|
|
759
802
|
// Same continuation shape as the write-retry: full prior messages
|
|
760
803
|
// plus a hard user directive, so the model sees what it already did.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
804
|
+
// M2.1: the previous pass' trailing context is EPHEMERAL — drop it and
|
|
805
|
+
// let the assembler put a fresh one right before the repair directive,
|
|
806
|
+
// instead of carrying a stale volatile snapshot mid-transcript.
|
|
807
|
+
const withSystem = assembleRequestMessages({
|
|
808
|
+
split: wireSplit,
|
|
809
|
+
history: [],
|
|
810
|
+
turn: [
|
|
811
|
+
...pass.messages.filter((m) => m.role !== 'system' && !isTrailingContextContent(m.content)),
|
|
812
|
+
{ role: 'user', content: repairPrompt },
|
|
813
|
+
],
|
|
814
|
+
layout: resolvePromptLayout(),
|
|
815
|
+
}).messages;
|
|
766
816
|
progressRuntime.beginPass(true);
|
|
767
817
|
markRepairTriggered();
|
|
768
818
|
const repair = await runSinglePass(withSystem, `${sessionId}-check-repair`);
|