mu-harness 0.28.0 → 0.29.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/esm/commands/defaults.js +43 -15
- package/package.json +3 -3
- package/script/commands/defaults.js +43 -15
package/esm/commands/defaults.js
CHANGED
|
@@ -41,16 +41,24 @@ export const createQuitCommand = (onQuit) => ({
|
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
43
|
const estTokens = (chars) => Math.max(1, Math.round(chars / 4));
|
|
44
|
-
const GRID_COLS =
|
|
45
|
-
const GRID_ROWS =
|
|
44
|
+
const GRID_COLS = 20;
|
|
45
|
+
const GRID_ROWS = 10;
|
|
46
46
|
const GRID_CELLS = GRID_COLS * GRID_ROWS;
|
|
47
47
|
const BLOCK = '█';
|
|
48
48
|
const FREE = '·';
|
|
49
|
+
const BUFFER_COLOR = '\x1b[93m'; // bright yellow — the compaction reserve
|
|
49
50
|
// ANSI SGR colours — mu's TUI text utils are ANSI-aware so these render in the terminal;
|
|
50
51
|
// the companion strips them (plain text), keeping the labelled breakdown readable.
|
|
51
52
|
const RESET = '\x1b[0m';
|
|
52
53
|
const DIM = '\x1b[2m';
|
|
53
54
|
const paint = (s, color) => `${color}${s}${RESET}`;
|
|
55
|
+
const fmtTok = (n) => (n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1000 ? `${(n / 1000).toFixed(1)}k` : `${n}`);
|
|
56
|
+
const pctStr = (n, w) => {
|
|
57
|
+
if (w <= 0)
|
|
58
|
+
return '';
|
|
59
|
+
const p = (n / w) * 100;
|
|
60
|
+
return p > 0 && p < 0.1 ? '<0.1%' : `${p.toFixed(1)}%`;
|
|
61
|
+
};
|
|
54
62
|
const fillColor = (pct) => (pct >= 80 ? '\x1b[31m' : pct >= 50 ? '\x1b[33m' : '\x1b[32m');
|
|
55
63
|
/** Extract a `<tag>…</tag>` block (with tags), or '' when absent. */
|
|
56
64
|
function tagBlock(s, tag) {
|
|
@@ -127,26 +135,46 @@ export const createContextCommand = () => ({
|
|
|
127
135
|
const exact = measured.every((m) => m.exact);
|
|
128
136
|
const total = cats.reduce((s, c) => s + c.n, 0);
|
|
129
137
|
const window = (await ctx.session?.contextWindow?.()) ?? 0;
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
lines.push(` ${paint(BLOCK, c.color)} ${c.label.padEnd(13)} ${mark(c.n)}`);
|
|
138
|
+
const buffer = window > 0 ? Math.min(Math.round(window * 0.2), Math.max(0, window - total)) : 0;
|
|
139
|
+
const free = Math.max(0, window - total - buffer);
|
|
140
|
+
const mark = (n) => (exact ? fmtTok(n) : `~${fmtTok(n)}`);
|
|
134
141
|
const pctNum = window ? Math.round((total / window) * 100) : 0;
|
|
135
|
-
|
|
136
|
-
|
|
142
|
+
// Legend rows (categories, then buffer + free), Claude Code / oh-my-pi style.
|
|
143
|
+
const rows = cats.map((c) => ({ marker: paint(BLOCK, c.color), label: c.label, n: c.n }));
|
|
137
144
|
if (window > 0) {
|
|
145
|
+
rows.push({ marker: paint(BLOCK, BUFFER_COLOR), label: 'buffer', n: buffer });
|
|
146
|
+
rows.push({ marker: paint(FREE, DIM), label: 'free', n: free });
|
|
147
|
+
}
|
|
148
|
+
const legend = rows.map((r) => `${r.marker} ${r.label.padEnd(13)} ${mark(r.n).padStart(7)} ${pctStr(r.n, window).padStart(6)}`);
|
|
149
|
+
const header = window
|
|
150
|
+
? `context · ${mark(total)} / ${fmtTok(window)} ${paint(`(${pctStr(total, window)})`, fillColor(pctNum))}`
|
|
151
|
+
: `context · ${mark(total)} tokens (no model context window)`;
|
|
152
|
+
const lines = [header, ''];
|
|
153
|
+
if (window > 0) {
|
|
154
|
+
// Build the grid: category cells, then free, with the compaction buffer at the very end.
|
|
138
155
|
const cellTokens = Math.max(1, window / GRID_CELLS);
|
|
156
|
+
const ratio = (n) => (n <= 0 ? 0 : Math.max(1, Math.round(n / cellTokens)));
|
|
139
157
|
const cells = [];
|
|
140
|
-
for (const c of cats)
|
|
141
|
-
for (let i = 0; i <
|
|
158
|
+
for (const c of cats)
|
|
159
|
+
for (let i = 0; i < ratio(c.n) && cells.length < GRID_CELLS; i++)
|
|
142
160
|
cells.push(paint(BLOCK, c.color));
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
const bufCells = Math.min(ratio(buffer), Math.max(0, GRID_CELLS - cells.length));
|
|
162
|
+
const freeCells = Math.max(0, GRID_CELLS - cells.length - bufCells);
|
|
163
|
+
for (let i = 0; i < freeCells; i++)
|
|
145
164
|
cells.push(paint(FREE, DIM));
|
|
165
|
+
for (let i = 0; i < bufCells; i++)
|
|
166
|
+
cells.push(paint(BLOCK, BUFFER_COLOR));
|
|
146
167
|
cells.length = GRID_CELLS;
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
168
|
+
// Side-by-side: 20×10 grid on the left, the legend on the right.
|
|
169
|
+
const rowsCount = Math.max(GRID_ROWS, legend.length);
|
|
170
|
+
for (let r = 0; r < rowsCount; r++) {
|
|
171
|
+
const gridRow = r < GRID_ROWS ? cells.slice(r * GRID_COLS, (r + 1) * GRID_COLS).join('') : ' '.repeat(GRID_COLS);
|
|
172
|
+
lines.push(` ${gridRow} ${legend[r] ?? ''}`.trimEnd());
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
for (const l of legend)
|
|
177
|
+
lines.push(` ${l.trimEnd()}`);
|
|
150
178
|
}
|
|
151
179
|
return { ok: true, output: lines.join('\n') };
|
|
152
180
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mu-harness",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Agent harness: createHarness wires mu-core into a host — XDG paths, model registry, plugins, disk-loaded agents & skills, sub-agents, sessions (JSONL + SQLite catalog), slash commands, permission/approval hooks, an optional scheduler, and a composable TUI chat app",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./script/index.js",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"@swc/wasm-typescript": "^1.15.0",
|
|
24
24
|
"cli-highlight": "^2.1.11",
|
|
25
25
|
"croner": "^9.0.0",
|
|
26
|
-
"mu-core": "^0.
|
|
27
|
-
"mu-tui": "^0.
|
|
26
|
+
"mu-core": "^0.29.0",
|
|
27
|
+
"mu-tui": "^0.29.0",
|
|
28
28
|
"ws": "^8.18.0"
|
|
29
29
|
},
|
|
30
30
|
"_generatedBy": "dnt@dev",
|
|
@@ -48,16 +48,24 @@ const createQuitCommand = (onQuit) => ({
|
|
|
48
48
|
});
|
|
49
49
|
exports.createQuitCommand = createQuitCommand;
|
|
50
50
|
const estTokens = (chars) => Math.max(1, Math.round(chars / 4));
|
|
51
|
-
const GRID_COLS =
|
|
52
|
-
const GRID_ROWS =
|
|
51
|
+
const GRID_COLS = 20;
|
|
52
|
+
const GRID_ROWS = 10;
|
|
53
53
|
const GRID_CELLS = GRID_COLS * GRID_ROWS;
|
|
54
54
|
const BLOCK = '█';
|
|
55
55
|
const FREE = '·';
|
|
56
|
+
const BUFFER_COLOR = '\x1b[93m'; // bright yellow — the compaction reserve
|
|
56
57
|
// ANSI SGR colours — mu's TUI text utils are ANSI-aware so these render in the terminal;
|
|
57
58
|
// the companion strips them (plain text), keeping the labelled breakdown readable.
|
|
58
59
|
const RESET = '\x1b[0m';
|
|
59
60
|
const DIM = '\x1b[2m';
|
|
60
61
|
const paint = (s, color) => `${color}${s}${RESET}`;
|
|
62
|
+
const fmtTok = (n) => (n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1000 ? `${(n / 1000).toFixed(1)}k` : `${n}`);
|
|
63
|
+
const pctStr = (n, w) => {
|
|
64
|
+
if (w <= 0)
|
|
65
|
+
return '';
|
|
66
|
+
const p = (n / w) * 100;
|
|
67
|
+
return p > 0 && p < 0.1 ? '<0.1%' : `${p.toFixed(1)}%`;
|
|
68
|
+
};
|
|
61
69
|
const fillColor = (pct) => (pct >= 80 ? '\x1b[31m' : pct >= 50 ? '\x1b[33m' : '\x1b[32m');
|
|
62
70
|
/** Extract a `<tag>…</tag>` block (with tags), or '' when absent. */
|
|
63
71
|
function tagBlock(s, tag) {
|
|
@@ -134,26 +142,46 @@ const createContextCommand = () => ({
|
|
|
134
142
|
const exact = measured.every((m) => m.exact);
|
|
135
143
|
const total = cats.reduce((s, c) => s + c.n, 0);
|
|
136
144
|
const window = (await ctx.session?.contextWindow?.()) ?? 0;
|
|
137
|
-
const
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
lines.push(` ${paint(BLOCK, c.color)} ${c.label.padEnd(13)} ${mark(c.n)}`);
|
|
145
|
+
const buffer = window > 0 ? Math.min(Math.round(window * 0.2), Math.max(0, window - total)) : 0;
|
|
146
|
+
const free = Math.max(0, window - total - buffer);
|
|
147
|
+
const mark = (n) => (exact ? fmtTok(n) : `~${fmtTok(n)}`);
|
|
141
148
|
const pctNum = window ? Math.round((total / window) * 100) : 0;
|
|
142
|
-
|
|
143
|
-
|
|
149
|
+
// Legend rows (categories, then buffer + free), Claude Code / oh-my-pi style.
|
|
150
|
+
const rows = cats.map((c) => ({ marker: paint(BLOCK, c.color), label: c.label, n: c.n }));
|
|
144
151
|
if (window > 0) {
|
|
152
|
+
rows.push({ marker: paint(BLOCK, BUFFER_COLOR), label: 'buffer', n: buffer });
|
|
153
|
+
rows.push({ marker: paint(FREE, DIM), label: 'free', n: free });
|
|
154
|
+
}
|
|
155
|
+
const legend = rows.map((r) => `${r.marker} ${r.label.padEnd(13)} ${mark(r.n).padStart(7)} ${pctStr(r.n, window).padStart(6)}`);
|
|
156
|
+
const header = window
|
|
157
|
+
? `context · ${mark(total)} / ${fmtTok(window)} ${paint(`(${pctStr(total, window)})`, fillColor(pctNum))}`
|
|
158
|
+
: `context · ${mark(total)} tokens (no model context window)`;
|
|
159
|
+
const lines = [header, ''];
|
|
160
|
+
if (window > 0) {
|
|
161
|
+
// Build the grid: category cells, then free, with the compaction buffer at the very end.
|
|
145
162
|
const cellTokens = Math.max(1, window / GRID_CELLS);
|
|
163
|
+
const ratio = (n) => (n <= 0 ? 0 : Math.max(1, Math.round(n / cellTokens)));
|
|
146
164
|
const cells = [];
|
|
147
|
-
for (const c of cats)
|
|
148
|
-
for (let i = 0; i <
|
|
165
|
+
for (const c of cats)
|
|
166
|
+
for (let i = 0; i < ratio(c.n) && cells.length < GRID_CELLS; i++)
|
|
149
167
|
cells.push(paint(BLOCK, c.color));
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
const bufCells = Math.min(ratio(buffer), Math.max(0, GRID_CELLS - cells.length));
|
|
169
|
+
const freeCells = Math.max(0, GRID_CELLS - cells.length - bufCells);
|
|
170
|
+
for (let i = 0; i < freeCells; i++)
|
|
152
171
|
cells.push(paint(FREE, DIM));
|
|
172
|
+
for (let i = 0; i < bufCells; i++)
|
|
173
|
+
cells.push(paint(BLOCK, BUFFER_COLOR));
|
|
153
174
|
cells.length = GRID_CELLS;
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
175
|
+
// Side-by-side: 20×10 grid on the left, the legend on the right.
|
|
176
|
+
const rowsCount = Math.max(GRID_ROWS, legend.length);
|
|
177
|
+
for (let r = 0; r < rowsCount; r++) {
|
|
178
|
+
const gridRow = r < GRID_ROWS ? cells.slice(r * GRID_COLS, (r + 1) * GRID_COLS).join('') : ' '.repeat(GRID_COLS);
|
|
179
|
+
lines.push(` ${gridRow} ${legend[r] ?? ''}`.trimEnd());
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
for (const l of legend)
|
|
184
|
+
lines.push(` ${l.trimEnd()}`);
|
|
157
185
|
}
|
|
158
186
|
return { ok: true, output: lines.join('\n') };
|
|
159
187
|
},
|