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.
Files changed (69) hide show
  1. package/dist/cli/acp/command.js +5 -3
  2. package/dist/cli/acp/command.js.map +1 -1
  3. package/dist/cli/acp/framing.js +151 -19
  4. package/dist/cli/acp/framing.js.map +1 -1
  5. package/dist/cli/acp/invariants.js +183 -0
  6. package/dist/cli/acp/invariants.js.map +1 -0
  7. package/dist/cli/acp/protocol.js +40 -5
  8. package/dist/cli/acp/protocol.js.map +1 -1
  9. package/dist/cli/acp/server.js +57 -17
  10. package/dist/cli/acp/server.js.map +1 -1
  11. package/dist/cli/acp/turnAdapter.js +2 -1
  12. package/dist/cli/acp/turnAdapter.js.map +1 -1
  13. package/dist/cli/app.js +2 -2
  14. package/dist/cli/app.js.map +1 -1
  15. package/dist/cli/budget/cacheHitReport.js +94 -0
  16. package/dist/cli/budget/cacheHitReport.js.map +1 -0
  17. package/dist/cli/budget/messageUsage.js +77 -0
  18. package/dist/cli/budget/messageUsage.js.map +1 -0
  19. package/dist/cli/companion/framePolicy.js +116 -0
  20. package/dist/cli/companion/framePolicy.js.map +1 -0
  21. package/dist/cli/components/SelectList.js +51 -14
  22. package/dist/cli/components/SelectList.js.map +1 -1
  23. package/dist/cli/components/StatusBar.js +6 -2
  24. package/dist/cli/components/StatusBar.js.map +1 -1
  25. package/dist/cli/components/fuzzyMatch.js +108 -0
  26. package/dist/cli/components/fuzzyMatch.js.map +1 -0
  27. package/dist/cli/components/statusChips.js +47 -0
  28. package/dist/cli/components/statusChips.js.map +1 -1
  29. package/dist/cli/headless/protocol.js +39 -2
  30. package/dist/cli/headless/protocol.js.map +1 -1
  31. package/dist/cli/headless/runOneTurn.js +68 -18
  32. package/dist/cli/headless/runOneTurn.js.map +1 -1
  33. package/dist/cli/hooks/useChatTurn.js +76 -16
  34. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  35. package/dist/cli/hooks/useSlashDispatch.js +5 -2
  36. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  37. package/dist/cli/inbox.js +220 -0
  38. package/dist/cli/inbox.js.map +1 -0
  39. package/dist/cli/main.bundled.js +3959 -2560
  40. package/dist/cli/main.bundled.js.map +4 -4
  41. package/dist/cli/main.js +22 -0
  42. package/dist/cli/main.js.map +1 -1
  43. package/dist/cli/metrics.js.map +1 -1
  44. package/dist/cli/provider/anthropic.js +42 -6
  45. package/dist/cli/provider/anthropic.js.map +1 -1
  46. package/dist/cli/provider/chatgpt.js +4 -0
  47. package/dist/cli/provider/chatgpt.js.map +1 -1
  48. package/dist/cli/provider/openai-compatible.js +25 -3
  49. package/dist/cli/provider/openai-compatible.js.map +1 -1
  50. package/dist/cli/provider/responsesApi.js +4 -0
  51. package/dist/cli/provider/responsesApi.js.map +1 -1
  52. package/dist/cli/serve/harnessServer.js +7 -0
  53. package/dist/cli/serve/harnessServer.js.map +1 -1
  54. package/dist/cli/sessionManager.js +9 -2
  55. package/dist/cli/sessionManager.js.map +1 -1
  56. package/dist/cli/skillsCheck.js +209 -0
  57. package/dist/cli/skillsCheck.js.map +1 -0
  58. package/dist/cli/slashCommands.js +9 -0
  59. package/dist/cli/slashCommands.js.map +1 -1
  60. package/dist/cli/slashHandlers/provider.js.map +1 -1
  61. package/dist/cli/slashHandlers/sessions.js +131 -0
  62. package/dist/cli/slashHandlers/sessions.js.map +1 -0
  63. package/dist/cli/statusline/statuslineItems.js +22 -3
  64. package/dist/cli/statusline/statuslineItems.js.map +1 -1
  65. package/dist/cli/statusline/verdictFeed.js +245 -0
  66. package/dist/cli/statusline/verdictFeed.js.map +1 -0
  67. package/dist/cli/utils/doctor.js +30 -0
  68. package/dist/cli/utils/doctor.js.map +1 -1
  69. 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. The App swaps it in for the InputBar while
19
- * open, so ink-text-input never competes for keystrokes. ↑/↓ move (with
20
- * wrap-around), enter selects, esc cancels. Long lists scroll inside a
21
- * `maxVisible` window so the dynamic region stays under a screen.
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
- useInput((_input, key) => {
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((i) => (i - 1 + items.length) % items.length);
52
+ setIndex(() => (shown.length === 0 ? 0 : (active - 1 + shown.length) % shown.length));
30
53
  }
31
54
  else if (key.downArrow) {
32
- setIndex((i) => (i + 1) % items.length);
55
+ setIndex(() => (shown.length === 0 ? 0 : (active + 1) % shown.length));
33
56
  }
34
57
  else if (key.return) {
35
- const item = items[index];
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(index, items.length, maxVisible);
44
- const visible = items.slice(start, start + maxVisible);
45
- const below = items.length - (start + visible.length);
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 === index;
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 }, "\u2191/\u2193 move \u00B7 enter select \u00B7 esc cancel")));
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":"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"}
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":"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"}
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":"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"}
@@ -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;AAQzE;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,EAAU;IAC9C,IAAI,CAAC;QACH,OAAO,oBAAoB,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAyB,OAAO,CAAC,GAAG,EACpC,WAAmB,OAAO,CAAC,QAAQ;IAEnC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,EAAE,KAAK,EAAE,mBAAmB,KAAK,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACxE,CAAC;IACD,OAAO,IAAI,KAAK,UAAU;QACxB,CAAC,CAAC,EAAE,KAAK,EAAE,aAAa,KAAK,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE;QACzD,CAAC,CAAC,EAAE,KAAK,EAAE,mBAAmB,KAAK,CAAC,OAAO,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AACrE,CAAC;AAED,wEAAwE;AACxE,SAAS,WAAW,CAAC,GAAsB,EAAE,QAAgB;IAC3D,OAAO;QACL,QAAQ;QACR,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE;QACtB,GAAG,CAAC,wBAAwB,IAAI,EAAE;QAClC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE;QAC/B,GAAG,CAAC,EAAE,IAAI,EAAE;QACZ,uBAAuB,EAAE;KAC1B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,IAAI,SAAS,GAAoD,IAAI,CAAC;AAEtE;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAClC,MAAyB,OAAO,CAAC,GAAG,EACpC,WAAmB,OAAO,CAAC,QAAQ;IAEnC,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACvC,IAAI,SAAS,IAAI,SAAS,CAAC,GAAG,KAAK,GAAG;QAAE,OAAO,SAAS,CAAC,IAAI,CAAC;IAC9D,4EAA4E;IAC5E,qEAAqE;IACrE,MAAM,IAAI,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClF,SAAS,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAC1B,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B;IACxC,SAAS,GAAG,IAAI,CAAC;AACnB,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
- export function controlRejectedEvent(controlId, reason) {
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;AAWD,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,MAAM,UAAU,oBAAoB,CAClC,SAAiB,EACjB,MAAc;IAEd,OAAO;QACL,IAAI,EAAE,kBAAkB;QACxB,SAAS;QACT,MAAM;QACN,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
- systemMessages = systemMessagesFromSplit(split);
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
- const initialMessages = [
662
- ...systemMessages,
663
- ...historySeed,
664
- {
665
- role: 'user',
666
- content: effectiveTask,
667
- ...(opts.images && opts.images.length > 0
668
- ? { images: opts.images }
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
- const withSystem = [
762
- ...systemMessages,
763
- ...pass.messages.filter((m) => m.role !== 'system'),
764
- { role: 'user', content: repairPrompt },
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`);