@corenel/term 0.2.9 → 0.4.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/{chunk-L4KCEKIT.js → chunk-2MGDL3I4.js} +7 -2
- package/dist/chunk-5RPHYXND.js +138 -0
- package/dist/{chunk-QZJTOVZL.js → chunk-HUVRQX53.js} +513 -34
- package/dist/commands.d.ts +39 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +11 -3
- package/dist/contextText.d.ts +37 -0
- package/dist/contextText.d.ts.map +1 -0
- package/dist/ink/App.d.ts +14 -0
- package/dist/ink/App.d.ts.map +1 -1
- package/dist/ink/ContextOverlay.d.ts +19 -0
- package/dist/ink/ContextOverlay.d.ts.map +1 -0
- package/dist/ink/HelpOverlay.d.ts +19 -0
- package/dist/ink/HelpOverlay.d.ts.map +1 -0
- package/dist/ink/McpOverlay.d.ts +7 -0
- package/dist/ink/McpOverlay.d.ts.map +1 -0
- package/dist/ink/Modal.d.ts +11 -3
- package/dist/ink/Modal.d.ts.map +1 -1
- package/dist/ink/index.d.ts.map +1 -1
- package/dist/ink/index.js +400 -92
- package/dist/ink/overlayBudget.d.ts +27 -0
- package/dist/ink/overlayBudget.d.ts.map +1 -0
- package/dist/ink/scroll.d.ts.map +1 -1
- package/dist/mcpText.d.ts +20 -0
- package/dist/mcpText.d.ts.map +1 -0
- package/dist/session.d.ts +175 -6
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +3 -3
- package/dist/state.d.ts +83 -2
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-VTJEWHM3.js +0 -65
package/dist/ink/index.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TermSession,
|
|
3
|
+
ageWord,
|
|
4
|
+
formatContext,
|
|
5
|
+
mcpStatusWord,
|
|
3
6
|
parseMarkdown
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
7
|
+
} from "../chunk-HUVRQX53.js";
|
|
8
|
+
import "../chunk-2MGDL3I4.js";
|
|
6
9
|
import {
|
|
10
|
+
TERM_COMMANDS,
|
|
7
11
|
filterCommands,
|
|
8
12
|
parseCommand
|
|
9
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-5RPHYXND.js";
|
|
10
14
|
import "../chunk-M44CET5L.js";
|
|
11
15
|
import {
|
|
12
16
|
formatEndingChange
|
|
@@ -28,7 +32,7 @@ import { STANDARD_POLICY } from "@corenel/harness/guardrail/builtins";
|
|
|
28
32
|
// src/ink/App.tsx
|
|
29
33
|
import { useEffect, useState } from "react";
|
|
30
34
|
import { homedir } from "node:os";
|
|
31
|
-
import { Box as
|
|
35
|
+
import { Box as Box8, Static, Text as Text8, useStdout } from "ink";
|
|
32
36
|
import TextInput from "ink-text-input";
|
|
33
37
|
|
|
34
38
|
// src/ink/items.tsx
|
|
@@ -169,29 +173,226 @@ function LiveToolRow({ tool }) {
|
|
|
169
173
|
] });
|
|
170
174
|
}
|
|
171
175
|
|
|
172
|
-
// src/ink/
|
|
176
|
+
// src/ink/McpOverlay.tsx
|
|
173
177
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
|
|
179
|
+
// src/ink/overlayBudget.ts
|
|
180
|
+
var RESERVED_CHROME_ROWS = 6;
|
|
181
|
+
function overlayBoxBudget(rows) {
|
|
182
|
+
if (rows === void 0) return Number.MAX_SAFE_INTEGER;
|
|
183
|
+
return Math.max(rows - RESERVED_CHROME_ROWS, 3);
|
|
184
|
+
}
|
|
185
|
+
function capList(items, cap, overflowLabel) {
|
|
186
|
+
const rowCap = Math.max(cap, 0);
|
|
187
|
+
if (items.length <= rowCap) return { shown: items, overflow: null };
|
|
188
|
+
if (rowCap <= 0) return { shown: [], overflow: null };
|
|
189
|
+
const shown = Math.max(rowCap - 1, 0);
|
|
190
|
+
const hidden = items.length - shown;
|
|
191
|
+
return { shown: items.slice(0, shown), overflow: overflowLabel(hidden) };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/ink/McpOverlay.tsx
|
|
195
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
196
|
+
function statusColor(word) {
|
|
197
|
+
if (word === "connected") return palette.good;
|
|
198
|
+
if (word === "unreachable") return palette.bad;
|
|
199
|
+
return palette.warn;
|
|
200
|
+
}
|
|
201
|
+
var BORDER_ROWS = 2;
|
|
202
|
+
function McpOverlay({ modal, rows }) {
|
|
203
|
+
let content = Math.max(overlayBoxBudget(rows) - BORDER_ROWS, 0);
|
|
204
|
+
const take = (n) => {
|
|
205
|
+
if (content < n) return false;
|
|
206
|
+
content -= n;
|
|
207
|
+
return true;
|
|
208
|
+
};
|
|
209
|
+
if (modal.login) {
|
|
210
|
+
const haveCore = take(1);
|
|
211
|
+
const showEsc = haveCore && modal.login.url !== null && take(1);
|
|
212
|
+
const showMessage = haveCore && modal.login.url !== null && take(1);
|
|
213
|
+
const showHeader2 = take(1);
|
|
214
|
+
const showFooter2 = take(1);
|
|
215
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", borderStyle: "round", borderColor: palette.tool, paddingX: 1, children: [
|
|
216
|
+
showHeader2 ? /* @__PURE__ */ jsx2(Text2, { color: palette.tool, bold: true, children: "MCP servers" }) : null,
|
|
217
|
+
haveCore && modal.login.url ? /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
218
|
+
showMessage ? /* @__PURE__ */ jsxs2(Text2, { color: palette.amber, children: [
|
|
219
|
+
"signing in to ",
|
|
220
|
+
modal.login.server,
|
|
221
|
+
" -- open this URL:"
|
|
222
|
+
] }) : null,
|
|
223
|
+
/* @__PURE__ */ jsx2(Text2, { wrap: "truncate-end", children: modal.login.url }),
|
|
224
|
+
showEsc ? /* @__PURE__ */ jsx2(Text2, { color: palette.dim, children: "esc cancels" }) : null
|
|
225
|
+
] }) : haveCore ? /* @__PURE__ */ jsxs2(Text2, { color: palette.amber, wrap: "truncate-end", children: [
|
|
226
|
+
"signing in to ",
|
|
227
|
+
modal.login.server,
|
|
228
|
+
" -- waiting for a login URL..."
|
|
229
|
+
] }) : null,
|
|
230
|
+
showFooter2 ? /* @__PURE__ */ jsxs2(Text2, { color: palette.dim, children: [
|
|
231
|
+
glyph.active,
|
|
232
|
+
" select ",
|
|
233
|
+
glyph.sep,
|
|
234
|
+
" a add ",
|
|
235
|
+
glyph.sep,
|
|
236
|
+
" x remove ",
|
|
237
|
+
glyph.sep,
|
|
238
|
+
" l login ",
|
|
239
|
+
glyph.sep,
|
|
240
|
+
" r refresh ",
|
|
241
|
+
glyph.sep,
|
|
242
|
+
" esc close"
|
|
243
|
+
] }) : null
|
|
244
|
+
] });
|
|
245
|
+
}
|
|
246
|
+
const showHeader = take(1);
|
|
247
|
+
const emptyRows = modal.servers.length === 0 && take(1);
|
|
248
|
+
const showFooter = take(1);
|
|
249
|
+
const { shown, overflow } = capList(modal.servers, content, (n) => `\u2026 ${n} more server${n === 1 ? "" : "s"}`);
|
|
250
|
+
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", borderStyle: "round", borderColor: palette.tool, paddingX: 1, children: [
|
|
251
|
+
showHeader ? /* @__PURE__ */ jsx2(Text2, { color: palette.tool, bold: true, children: "MCP servers" }) : null,
|
|
252
|
+
emptyRows ? /* @__PURE__ */ jsx2(Text2, { color: palette.dim, children: "none configured -- press a to add one" }) : /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", children: [
|
|
253
|
+
shown.map((s) => {
|
|
254
|
+
const i = modal.servers.indexOf(s);
|
|
255
|
+
const word = mcpStatusWord(s);
|
|
256
|
+
const isSelected = i === modal.selected;
|
|
257
|
+
return /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
258
|
+
/* @__PURE__ */ jsx2(Text2, { color: palette.ember, children: isSelected ? `${glyph.active} ` : " " }),
|
|
259
|
+
/* @__PURE__ */ jsx2(Text2, { bold: isSelected, wrap: "truncate-end", children: s.name }),
|
|
260
|
+
/* @__PURE__ */ jsx2(Text2, { color: palette.dim, children: " " }),
|
|
261
|
+
/* @__PURE__ */ jsx2(Text2, { color: statusColor(word), children: word }),
|
|
262
|
+
/* @__PURE__ */ jsxs2(Text2, { color: palette.dim, wrap: "truncate-end", children: [
|
|
263
|
+
" ",
|
|
264
|
+
s.toolCount,
|
|
265
|
+
" tool",
|
|
266
|
+
s.toolCount === 1 ? "" : "s",
|
|
267
|
+
", ",
|
|
268
|
+
ageWord(s.fetchedAt, Date.now())
|
|
269
|
+
] })
|
|
270
|
+
] }, s.name);
|
|
271
|
+
}),
|
|
272
|
+
overflow ? /* @__PURE__ */ jsxs2(Text2, { color: palette.dim, children: [
|
|
273
|
+
" ",
|
|
274
|
+
overflow
|
|
275
|
+
] }) : null
|
|
276
|
+
] }),
|
|
277
|
+
showFooter ? /* @__PURE__ */ jsxs2(Text2, { color: palette.dim, children: [
|
|
278
|
+
glyph.active,
|
|
279
|
+
" select ",
|
|
280
|
+
glyph.sep,
|
|
281
|
+
" a add ",
|
|
282
|
+
glyph.sep,
|
|
283
|
+
" x remove ",
|
|
284
|
+
glyph.sep,
|
|
285
|
+
" l login ",
|
|
286
|
+
glyph.sep,
|
|
287
|
+
" r refresh ",
|
|
288
|
+
glyph.sep,
|
|
289
|
+
" esc close"
|
|
290
|
+
] }) : null
|
|
291
|
+
] });
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// src/ink/HelpOverlay.tsx
|
|
295
|
+
import { Box as Box3, Text as Text3 } from "ink";
|
|
296
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
297
|
+
var FIXED_CHROME_ROWS = 4;
|
|
298
|
+
function HelpOverlay({ rows }) {
|
|
299
|
+
const width = Math.max(...TERM_COMMANDS.map((c) => `${c.name} ${c.args ?? ""}`.trim().length));
|
|
300
|
+
const bodyBudget = Math.max(overlayBoxBudget(rows) - FIXED_CHROME_ROWS, 0);
|
|
301
|
+
const { shown, overflow } = capList(TERM_COMMANDS, bodyBudget, (n) => `\u2026 ${n} more command${n === 1 ? "" : "s"}`);
|
|
302
|
+
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", borderStyle: "round", borderColor: palette.tool, paddingX: 1, children: [
|
|
303
|
+
/* @__PURE__ */ jsx3(Text3, { color: palette.tool, bold: true, children: "Commands" }),
|
|
304
|
+
/* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", children: [
|
|
305
|
+
shown.map((c) => {
|
|
306
|
+
const usage = `${c.name} ${c.args ?? ""}`.trim();
|
|
307
|
+
return /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
308
|
+
/* @__PURE__ */ jsxs3(Text3, { color: palette.ember, wrap: "truncate-end", children: [
|
|
309
|
+
"/",
|
|
310
|
+
usage.padEnd(width)
|
|
311
|
+
] }),
|
|
312
|
+
/* @__PURE__ */ jsxs3(Text3, { color: palette.dim, wrap: "truncate-end", children: [
|
|
313
|
+
" ",
|
|
314
|
+
c.summary
|
|
315
|
+
] })
|
|
316
|
+
] }, c.name);
|
|
317
|
+
}),
|
|
318
|
+
overflow ? /* @__PURE__ */ jsxs3(Text3, { color: palette.dim, children: [
|
|
319
|
+
" ",
|
|
320
|
+
overflow
|
|
321
|
+
] }) : null
|
|
322
|
+
] }),
|
|
323
|
+
/* @__PURE__ */ jsx3(Text3, { color: palette.dim, children: "esc close" })
|
|
324
|
+
] });
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// src/ink/ContextOverlay.tsx
|
|
328
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
329
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
330
|
+
var FIXED_CHROME_ROWS2 = 4;
|
|
331
|
+
function ContextOverlay({ snapshot, rows }) {
|
|
332
|
+
const lines = formatContext(snapshot).split("\n");
|
|
333
|
+
const bodyBudget = Math.max(overlayBoxBudget(rows) - FIXED_CHROME_ROWS2, 0);
|
|
334
|
+
const { shown, overflow } = capList(lines, bodyBudget, (n) => `\u2026 ${n} more line${n === 1 ? "" : "s"}`);
|
|
335
|
+
return /* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", borderStyle: "round", borderColor: palette.tool, paddingX: 1, children: [
|
|
336
|
+
/* @__PURE__ */ jsx4(Text4, { color: palette.tool, bold: true, children: "Context window" }),
|
|
337
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", children: [
|
|
338
|
+
shown.map((line, i) => /* @__PURE__ */ jsx4(Text4, { wrap: "truncate-end", children: line === "" ? " " : line }, i)),
|
|
339
|
+
overflow ? /* @__PURE__ */ jsx4(Text4, { color: palette.dim, children: overflow }) : null
|
|
340
|
+
] }),
|
|
341
|
+
/* @__PURE__ */ jsx4(Text4, { color: palette.dim, children: "esc close" })
|
|
342
|
+
] });
|
|
343
|
+
}
|
|
344
|
+
function contextSnapshotFromState(state, contextWindow, toolCount) {
|
|
345
|
+
return {
|
|
346
|
+
sentTokens: state.sentTokens,
|
|
347
|
+
contextWindow,
|
|
348
|
+
offloaded: state.offloaded,
|
|
349
|
+
checkpoints: state.checkpoints,
|
|
350
|
+
toolCount,
|
|
351
|
+
loadedToolNames: state.toolNames
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/ink/Modal.tsx
|
|
356
|
+
import { Box as Box5, Text as Text5 } from "ink";
|
|
357
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
358
|
+
function capDiffRows(rows, max) {
|
|
359
|
+
if (rows.length <= max || max <= 0) return max <= 0 ? [] : rows;
|
|
360
|
+
const kept = rows.slice(0, Math.max(max - 1, 0));
|
|
361
|
+
const dropped = rows.slice(kept.length);
|
|
362
|
+
const hidden = dropped.reduce((n, r) => n + (r.kind === "skip" ? r.count : 1), 0);
|
|
363
|
+
return [...kept, { kind: "skip", count: hidden, reason: "context" }];
|
|
364
|
+
}
|
|
365
|
+
function DiffPreview({ diff, budget }) {
|
|
366
|
+
if (budget !== void 0 && budget <= 0) return null;
|
|
179
367
|
if (diff.noop) {
|
|
180
|
-
return /* @__PURE__ */
|
|
368
|
+
return /* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: "(no change -- new content is identical to what's on disk)" });
|
|
181
369
|
}
|
|
182
|
-
|
|
370
|
+
const contentUnchanged = diff.added === 0 && diff.removed === 0;
|
|
371
|
+
let remaining = budget !== void 0 ? budget - 1 : void 0;
|
|
372
|
+
const fits = () => {
|
|
373
|
+
if (remaining === void 0) return true;
|
|
374
|
+
if (remaining < 1) return false;
|
|
375
|
+
remaining -= 1;
|
|
376
|
+
return true;
|
|
377
|
+
};
|
|
378
|
+
const endingRow = diff.endingChange && fits() && /* @__PURE__ */ jsx5(Text5, { color: palette.amber, bold: true, children: formatEndingChange(diff.endingChange, contentUnchanged) });
|
|
379
|
+
const unexplainedRow = diff.unexplainedChange && fits() && /* @__PURE__ */ jsx5(Text5, { color: palette.amber, bold: true, children: "the file changes in a way not shown above (e.g. trailing whitespace or encoding)" });
|
|
380
|
+
const newFileRow = diff.isNewFile && fits() && /* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: "(new file)" });
|
|
381
|
+
const rows = remaining !== void 0 ? capDiffRows(diff.rows, remaining) : diff.rows;
|
|
382
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
183
383
|
endingRow,
|
|
184
384
|
unexplainedRow,
|
|
185
|
-
|
|
186
|
-
|
|
385
|
+
newFileRow,
|
|
386
|
+
rows.map((r, i) => {
|
|
187
387
|
if (r.kind === "skip") {
|
|
188
388
|
const label = r.reason === "changes" ? `\u2026 ${r.count} more changed line${r.count === 1 ? "" : "s"}` : `\u2026 ${r.count} unchanged line${r.count === 1 ? "" : "s"}`;
|
|
189
|
-
return /* @__PURE__ */
|
|
389
|
+
return /* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: label }, i);
|
|
190
390
|
}
|
|
191
|
-
return /* @__PURE__ */
|
|
192
|
-
|
|
391
|
+
return /* @__PURE__ */ jsxs5(
|
|
392
|
+
Text5,
|
|
193
393
|
{
|
|
194
394
|
color: r.kind === "add" ? palette.good : r.kind === "del" ? palette.bad : palette.dim,
|
|
395
|
+
wrap: "truncate-end",
|
|
195
396
|
children: [
|
|
196
397
|
r.kind === "add" ? "+ " : r.kind === "del" ? "- " : " ",
|
|
197
398
|
r.text
|
|
@@ -200,7 +401,7 @@ function DiffPreview({ diff }) {
|
|
|
200
401
|
i
|
|
201
402
|
);
|
|
202
403
|
}),
|
|
203
|
-
/* @__PURE__ */
|
|
404
|
+
/* @__PURE__ */ jsxs5(Text5, { color: palette.dim, children: [
|
|
204
405
|
"+",
|
|
205
406
|
diff.added,
|
|
206
407
|
" \u2212",
|
|
@@ -208,69 +409,90 @@ function DiffPreview({ diff }) {
|
|
|
208
409
|
] })
|
|
209
410
|
] });
|
|
210
411
|
}
|
|
211
|
-
|
|
412
|
+
var PERMISSION_BORDER_ROWS = 2;
|
|
413
|
+
var QUESTION_FIXED_ROWS = 5;
|
|
414
|
+
function ModalView({ modal, rows }) {
|
|
212
415
|
if (modal.kind === "permission") {
|
|
213
|
-
|
|
214
|
-
|
|
416
|
+
let content = Math.max(overlayBoxBudget(rows) - PERMISSION_BORDER_ROWS, 0);
|
|
417
|
+
const take = (n) => {
|
|
418
|
+
if (content < n) return false;
|
|
419
|
+
content -= n;
|
|
420
|
+
return true;
|
|
421
|
+
};
|
|
422
|
+
const showButtons = take(1);
|
|
423
|
+
const showTool = take(1);
|
|
424
|
+
const showDetail = take(1);
|
|
425
|
+
const diffBudget = modal.diff ? content : void 0;
|
|
426
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: palette.warn, paddingX: 1, children: [
|
|
427
|
+
showTool ? /* @__PURE__ */ jsxs5(Text5, { color: palette.warn, children: [
|
|
215
428
|
modal.tool,
|
|
216
429
|
" wants to run"
|
|
217
|
-
] }),
|
|
218
|
-
/* @__PURE__ */
|
|
219
|
-
modal.diff && /* @__PURE__ */
|
|
220
|
-
/* @__PURE__ */
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
-
/* @__PURE__ */
|
|
223
|
-
/* @__PURE__ */
|
|
224
|
-
/* @__PURE__ */
|
|
225
|
-
] })
|
|
430
|
+
] }) : null,
|
|
431
|
+
showDetail ? /* @__PURE__ */ jsx5(Text5, { bold: true, wrap: "truncate-end", children: modal.detail }) : null,
|
|
432
|
+
modal.diff && /* @__PURE__ */ jsx5(DiffPreview, { diff: modal.diff, budget: diffBudget }),
|
|
433
|
+
showButtons ? /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
434
|
+
/* @__PURE__ */ jsx5(Text5, { color: palette.good, children: "[y]" }),
|
|
435
|
+
/* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: " run it " }),
|
|
436
|
+
/* @__PURE__ */ jsx5(Text5, { color: palette.bad, children: "[n]" }),
|
|
437
|
+
/* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: " deny esc denies" })
|
|
438
|
+
] }) : null
|
|
226
439
|
] });
|
|
227
440
|
}
|
|
228
441
|
const q = modal.questions[0];
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
442
|
+
const options = q?.options ?? [];
|
|
443
|
+
const optionsBudget = Math.max(overlayBoxBudget(rows) - QUESTION_FIXED_ROWS, 0);
|
|
444
|
+
const { shown, overflow } = capList(options, optionsBudget, (n) => `\u2026 ${n} more option${n === 1 ? "" : "s"}`);
|
|
445
|
+
return /* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", borderStyle: "round", borderColor: palette.ember, paddingX: 1, children: [
|
|
446
|
+
/* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: q?.header }),
|
|
447
|
+
/* @__PURE__ */ jsx5(Text5, { bold: true, wrap: "truncate-end", children: q?.question }),
|
|
448
|
+
/* @__PURE__ */ jsxs5(Box5, { flexDirection: "column", children: [
|
|
449
|
+
shown.map((o) => {
|
|
450
|
+
const i = options.indexOf(o);
|
|
451
|
+
return /* @__PURE__ */ jsxs5(Box5, { children: [
|
|
452
|
+
/* @__PURE__ */ jsxs5(Text5, { color: palette.amber, children: [
|
|
453
|
+
i + 1,
|
|
454
|
+
" "
|
|
455
|
+
] }),
|
|
456
|
+
/* @__PURE__ */ jsx5(Text5, { wrap: "truncate-end", children: o.label }),
|
|
457
|
+
o.description ? /* @__PURE__ */ jsxs5(Text5, { color: palette.dim, wrap: "truncate-end", children: [
|
|
458
|
+
" ",
|
|
459
|
+
o.description
|
|
460
|
+
] }) : null
|
|
461
|
+
] }, o.label);
|
|
462
|
+
}),
|
|
463
|
+
overflow ? /* @__PURE__ */ jsx5(Text5, { color: palette.dim, children: overflow }) : null
|
|
464
|
+
] }),
|
|
465
|
+
/* @__PURE__ */ jsxs5(Text5, { color: palette.dim, children: [
|
|
244
466
|
"1-",
|
|
245
|
-
|
|
467
|
+
options.length,
|
|
246
468
|
" choose \xB7 \u21B5 confirm \xB7 or type your own answer \xB7 esc dismisses"
|
|
247
|
-
] })
|
|
469
|
+
] })
|
|
248
470
|
] });
|
|
249
471
|
}
|
|
250
472
|
|
|
251
473
|
// src/ink/Palette.tsx
|
|
252
|
-
import { Box as
|
|
253
|
-
import { jsx as
|
|
474
|
+
import { Box as Box6, Text as Text6 } from "ink";
|
|
475
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
254
476
|
function PaletteView({ items, selected }) {
|
|
255
|
-
return /* @__PURE__ */
|
|
256
|
-
items.map((c, i) => /* @__PURE__ */
|
|
257
|
-
/* @__PURE__ */
|
|
477
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
|
478
|
+
items.map((c, i) => /* @__PURE__ */ jsxs6(Box6, { children: [
|
|
479
|
+
/* @__PURE__ */ jsxs6(Text6, { color: i === selected ? palette.ember : palette.dim, children: [
|
|
258
480
|
i === selected ? "\u203A " : " ",
|
|
259
481
|
"/",
|
|
260
482
|
c.name,
|
|
261
483
|
c.args ? ` ${c.args}` : ""
|
|
262
484
|
] }),
|
|
263
|
-
/* @__PURE__ */
|
|
485
|
+
/* @__PURE__ */ jsxs6(Text6, { color: palette.dim, children: [
|
|
264
486
|
" ",
|
|
265
487
|
c.summary
|
|
266
488
|
] })
|
|
267
489
|
] }, c.name)),
|
|
268
|
-
/* @__PURE__ */
|
|
490
|
+
/* @__PURE__ */ jsx6(Text6, { color: palette.dim, children: " \u2191\u2193 choose \xB7 tab completes \xB7 esc closes" })
|
|
269
491
|
] });
|
|
270
492
|
}
|
|
271
493
|
|
|
272
494
|
// src/ink/TodoBlock.tsx
|
|
273
|
-
import { Box as
|
|
495
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
274
496
|
|
|
275
497
|
// src/ink/todos.ts
|
|
276
498
|
var DEFAULT_TODO_ROW_CAP = 4;
|
|
@@ -300,7 +522,7 @@ function toRows(items) {
|
|
|
300
522
|
}
|
|
301
523
|
|
|
302
524
|
// src/ink/TodoBlock.tsx
|
|
303
|
-
import { jsx as
|
|
525
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
304
526
|
function marker(status) {
|
|
305
527
|
switch (status) {
|
|
306
528
|
case "in_progress":
|
|
@@ -316,21 +538,21 @@ function marker(status) {
|
|
|
316
538
|
}
|
|
317
539
|
function TodoRowView({ row }) {
|
|
318
540
|
const { char, color } = marker(row.status);
|
|
319
|
-
return /* @__PURE__ */
|
|
320
|
-
/* @__PURE__ */
|
|
541
|
+
return /* @__PURE__ */ jsxs7(Box7, { children: [
|
|
542
|
+
/* @__PURE__ */ jsxs7(Text7, { color, children: [
|
|
321
543
|
char,
|
|
322
544
|
" "
|
|
323
545
|
] }),
|
|
324
|
-
/* @__PURE__ */
|
|
546
|
+
/* @__PURE__ */ jsx7(Text7, { color: row.status === "in_progress" ? palette.ink : palette.soft, children: row.title })
|
|
325
547
|
] });
|
|
326
548
|
}
|
|
327
549
|
function TodoBlock({ todos }) {
|
|
328
550
|
const view = visibleTodos(todos);
|
|
329
551
|
if (!view) return null;
|
|
330
|
-
return /* @__PURE__ */
|
|
331
|
-
/* @__PURE__ */
|
|
332
|
-
view.rows.map((row) => /* @__PURE__ */
|
|
333
|
-
view.overflow ? /* @__PURE__ */
|
|
552
|
+
return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", marginTop: 1, children: [
|
|
553
|
+
/* @__PURE__ */ jsx7(Text7, { color: palette.dim, children: view.header }),
|
|
554
|
+
view.rows.map((row) => /* @__PURE__ */ jsx7(TodoRowView, { row }, row.id)),
|
|
555
|
+
view.overflow ? /* @__PURE__ */ jsxs7(Text7, { color: palette.dim, children: [
|
|
334
556
|
" ",
|
|
335
557
|
view.overflow
|
|
336
558
|
] }) : null
|
|
@@ -380,7 +602,7 @@ function fitStatus(left, identity, columns) {
|
|
|
380
602
|
}
|
|
381
603
|
|
|
382
604
|
// src/ink/App.tsx
|
|
383
|
-
import { jsx as
|
|
605
|
+
import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
384
606
|
function useColumns() {
|
|
385
607
|
const { stdout } = useStdout();
|
|
386
608
|
const [columns, setColumns] = useState(stdout?.columns ?? DEFAULT_COLUMNS);
|
|
@@ -395,6 +617,23 @@ function useColumns() {
|
|
|
395
617
|
}, [stdout]);
|
|
396
618
|
return columns;
|
|
397
619
|
}
|
|
620
|
+
function usableRows(rows) {
|
|
621
|
+
return rows !== void 0 && Number.isFinite(rows) && rows > 0 ? rows : void 0;
|
|
622
|
+
}
|
|
623
|
+
function useRows() {
|
|
624
|
+
const { stdout } = useStdout();
|
|
625
|
+
const [rows, setRows] = useState(usableRows(stdout?.rows));
|
|
626
|
+
useEffect(() => {
|
|
627
|
+
if (!stdout) return;
|
|
628
|
+
const onResize = () => setRows(usableRows(stdout.rows));
|
|
629
|
+
onResize();
|
|
630
|
+
stdout.on("resize", onResize);
|
|
631
|
+
return () => {
|
|
632
|
+
stdout.off("resize", onResize);
|
|
633
|
+
};
|
|
634
|
+
}, [stdout]);
|
|
635
|
+
return rows;
|
|
636
|
+
}
|
|
398
637
|
function usd(v) {
|
|
399
638
|
return v < 0.01 ? `$${v.toFixed(4)}` : `$${v.toFixed(2)}`;
|
|
400
639
|
}
|
|
@@ -404,6 +643,8 @@ function App(props) {
|
|
|
404
643
|
const paletteSelected = Math.min(props.paletteSelected, Math.max(paletteItems.length - 1, 0));
|
|
405
644
|
const busy = state.status !== "idle";
|
|
406
645
|
const columns = useColumns();
|
|
646
|
+
const rows = useRows();
|
|
647
|
+
const modalOpen = state.modal != null;
|
|
407
648
|
const statusWord = busy ? "running" : "idle";
|
|
408
649
|
const roundSeg = state.live ? ` ${glyph.sep} turn ${state.live.turn}` : ` ${glyph.sep} ${props.toolCount} tools`;
|
|
409
650
|
const turnTokens = tokens(state.turnUsage.promptTokens + state.turnUsage.completionTokens);
|
|
@@ -412,31 +653,31 @@ function App(props) {
|
|
|
412
653
|
const costSeg = state.costUsd > 0 ? ` ${glyph.sep} ${usd(state.costUsd)}` : "";
|
|
413
654
|
const escSeg = busy ? ` ${glyph.sep} esc stops` : "";
|
|
414
655
|
const queuedSeg = state.queued.length ? ` ${glyph.sep} ${state.queued.length} queued` : "";
|
|
415
|
-
const shellSeg =
|
|
656
|
+
const shellSeg = ` ${glyph.sep} shell ${props.approveAll ? "auto-approved" : "asks first"}`;
|
|
416
657
|
const statusLeft = ` ${statusWord}${roundSeg}${tokenSeg}${costSeg}${escSeg}${queuedSeg}${shellSeg}`;
|
|
417
|
-
const { right: statusRight } = fitStatus(statusLeft, { model:
|
|
418
|
-
return /* @__PURE__ */
|
|
419
|
-
/* @__PURE__ */
|
|
420
|
-
state.live?.tools.map((t) => /* @__PURE__ */
|
|
421
|
-
state.live?.streaming ? /* @__PURE__ */
|
|
422
|
-
/* @__PURE__ */
|
|
423
|
-
state.modal ? /* @__PURE__ */
|
|
424
|
-
paletteItems.length && !
|
|
425
|
-
state.pendingSkill ? /* @__PURE__ */
|
|
426
|
-
/* @__PURE__ */
|
|
658
|
+
const { right: statusRight } = fitStatus(statusLeft, { model: state.model, cwd: props.cwd, home: homedir() }, columns);
|
|
659
|
+
return /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
660
|
+
/* @__PURE__ */ jsx8(Static, { items: state.committed, children: (item) => /* @__PURE__ */ jsx8(CommittedRow, { item }, item.id) }, `transcript-${state.transcriptGen}`),
|
|
661
|
+
!modalOpen && state.live?.tools.map((t) => /* @__PURE__ */ jsx8(LiveToolRow, { tool: t }, t.callId)),
|
|
662
|
+
!modalOpen && state.live?.streaming ? /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: palette.soft, children: state.live.streaming }) }) : null,
|
|
663
|
+
!modalOpen ? /* @__PURE__ */ jsx8(TodoBlock, { todos: state.todos }) : null,
|
|
664
|
+
state.modal ? /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: state.modal.kind === "mcp" ? /* @__PURE__ */ jsx8(McpOverlay, { modal: state.modal, rows }) : state.modal.kind === "help" ? /* @__PURE__ */ jsx8(HelpOverlay, { rows }) : state.modal.kind === "context" ? /* @__PURE__ */ jsx8(ContextOverlay, { snapshot: contextSnapshotFromState(state, props.contextWindow ?? null, props.toolCount), rows }) : state.modal.kind === "permission" || state.modal.kind === "user" ? /* @__PURE__ */ jsx8(ModalView, { modal: state.modal, rows }) : null }) : null,
|
|
665
|
+
paletteItems.length && !modalOpen ? /* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(PaletteView, { items: paletteItems, selected: paletteSelected }) }) : null,
|
|
666
|
+
state.pendingSkill && !modalOpen ? /* @__PURE__ */ jsxs8(Box8, { marginTop: 1, children: [
|
|
667
|
+
/* @__PURE__ */ jsxs8(Text8, { color: palette.ember, children: [
|
|
427
668
|
glyph.sep,
|
|
428
669
|
" skill armed: ",
|
|
429
670
|
state.pendingSkill,
|
|
430
671
|
" "
|
|
431
672
|
] }),
|
|
432
|
-
/* @__PURE__ */
|
|
673
|
+
/* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: "-- applies to your next message, then clears" })
|
|
433
674
|
] }) : null,
|
|
434
|
-
/* @__PURE__ */
|
|
435
|
-
/* @__PURE__ */
|
|
675
|
+
/* @__PURE__ */ jsxs8(Box8, { borderStyle: "round", borderColor: palette.dim, paddingX: 1, marginTop: 1, children: [
|
|
676
|
+
/* @__PURE__ */ jsxs8(Text8, { color: palette.ember, children: [
|
|
436
677
|
glyph.prompt,
|
|
437
678
|
" "
|
|
438
679
|
] }),
|
|
439
|
-
/* @__PURE__ */
|
|
680
|
+
/* @__PURE__ */ jsx8(
|
|
440
681
|
TextInput,
|
|
441
682
|
{
|
|
442
683
|
value: props.value,
|
|
@@ -448,9 +689,9 @@ function App(props) {
|
|
|
448
689
|
props.inputKey
|
|
449
690
|
)
|
|
450
691
|
] }),
|
|
451
|
-
state.committed.length === 0 ? /* @__PURE__ */
|
|
692
|
+
state.committed.length === 0 && !modalOpen ? /* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: palette.soft, children: [
|
|
452
693
|
"Type a request. ",
|
|
453
|
-
/* @__PURE__ */
|
|
694
|
+
/* @__PURE__ */ jsxs8(Text8, { color: palette.dim, children: [
|
|
454
695
|
"/help for commands ",
|
|
455
696
|
glyph.sep,
|
|
456
697
|
" Ctrl-C stops a turn ",
|
|
@@ -458,22 +699,22 @@ function App(props) {
|
|
|
458
699
|
" Ctrl-D leaves"
|
|
459
700
|
] })
|
|
460
701
|
] }) }) : null,
|
|
461
|
-
/* @__PURE__ */
|
|
462
|
-
/* @__PURE__ */
|
|
463
|
-
/* @__PURE__ */
|
|
702
|
+
/* @__PURE__ */ jsxs8(Box8, { justifyContent: "space-between", children: [
|
|
703
|
+
/* @__PURE__ */ jsxs8(Box8, { children: [
|
|
704
|
+
/* @__PURE__ */ jsxs8(Text8, { color: busy ? palette.amber : palette.dim, children: [
|
|
464
705
|
" ",
|
|
465
706
|
statusWord
|
|
466
707
|
] }),
|
|
467
|
-
/* @__PURE__ */
|
|
708
|
+
/* @__PURE__ */ jsxs8(Text8, { color: palette.dim, children: [
|
|
468
709
|
roundSeg,
|
|
469
710
|
tokenSeg,
|
|
470
711
|
costSeg,
|
|
471
712
|
escSeg,
|
|
472
713
|
queuedSeg
|
|
473
714
|
] }),
|
|
474
|
-
|
|
715
|
+
/* @__PURE__ */ jsx8(Text8, { color: props.approveAll ? palette.ember : palette.warn, children: shellSeg })
|
|
475
716
|
] }),
|
|
476
|
-
statusRight ? /* @__PURE__ */
|
|
717
|
+
statusRight ? /* @__PURE__ */ jsx8(Text8, { color: palette.dim, children: statusRight }) : null
|
|
477
718
|
] })
|
|
478
719
|
] });
|
|
479
720
|
}
|
|
@@ -561,7 +802,7 @@ function writeBanner(out, opts) {
|
|
|
561
802
|
}
|
|
562
803
|
|
|
563
804
|
// src/ink/index.tsx
|
|
564
|
-
import { jsx as
|
|
805
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
565
806
|
function Root({ session, deps }) {
|
|
566
807
|
const state = useSyncExternalStore(
|
|
567
808
|
useCallback((fn) => session.subscribe(fn), [session]),
|
|
@@ -592,6 +833,53 @@ function Root({ session, deps }) {
|
|
|
592
833
|
};
|
|
593
834
|
useInput((input, key) => {
|
|
594
835
|
if (state.modal) {
|
|
836
|
+
if (state.modal.kind === "mcp") {
|
|
837
|
+
if (key.escape) {
|
|
838
|
+
session.closeMcpManager();
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
if (key.upArrow) {
|
|
842
|
+
session.moveMcpSelection(-1);
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
if (key.downArrow) {
|
|
846
|
+
session.moveMcpSelection(1);
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const lower = input.toLowerCase();
|
|
850
|
+
if (lower === "x") {
|
|
851
|
+
void session.removeMcpSelection();
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
if (lower === "l") {
|
|
855
|
+
void session.loginMcpSelection();
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
if (lower === "r") {
|
|
859
|
+
void session.refreshMcpSelection();
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
if (lower === "a") {
|
|
863
|
+
session.closeMcpManager();
|
|
864
|
+
completeTo("/mcp add ");
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
if (state.modal.kind === "help") {
|
|
870
|
+
if (key.escape) {
|
|
871
|
+
session.closeHelp();
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
if (state.modal.kind === "context") {
|
|
877
|
+
if (key.escape) {
|
|
878
|
+
session.closeContext();
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
595
883
|
if (key.escape) {
|
|
596
884
|
session.answer(state.modal.kind === "permission" ? "deny" : null);
|
|
597
885
|
return;
|
|
@@ -649,7 +937,7 @@ function Root({ session, deps }) {
|
|
|
649
937
|
}
|
|
650
938
|
if (sawSigint) setSawSigint(false);
|
|
651
939
|
});
|
|
652
|
-
return /* @__PURE__ */
|
|
940
|
+
return /* @__PURE__ */ jsx9(
|
|
653
941
|
App,
|
|
654
942
|
{
|
|
655
943
|
state,
|
|
@@ -657,10 +945,26 @@ function Root({ session, deps }) {
|
|
|
657
945
|
cwd: deps.cwd,
|
|
658
946
|
version: deps.version,
|
|
659
947
|
toolCount: deps.tools.length,
|
|
948
|
+
contextWindow: deps.contextWindow?.() ?? null,
|
|
660
949
|
approveAll: deps.approveAll === true,
|
|
661
950
|
value,
|
|
662
951
|
onChange: handleChange,
|
|
663
952
|
onSubmit: (v) => {
|
|
953
|
+
if (v.trim() === "/help") {
|
|
954
|
+
setValue("");
|
|
955
|
+
session.openHelp();
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (v.trim() === "/mcp") {
|
|
959
|
+
setValue("");
|
|
960
|
+
void session.openMcpManager();
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
if (v.trim() === "/context") {
|
|
964
|
+
setValue("");
|
|
965
|
+
session.openContext();
|
|
966
|
+
return;
|
|
967
|
+
}
|
|
664
968
|
const items = v.startsWith("/") ? filterCommands(v) : [];
|
|
665
969
|
if (items.length > 0 && !parseCommand(v)) {
|
|
666
970
|
const chosen = items[Math.min(paletteIndex, items.length - 1)];
|
|
@@ -677,6 +981,10 @@ function Root({ session, deps }) {
|
|
|
677
981
|
return;
|
|
678
982
|
}
|
|
679
983
|
}
|
|
984
|
+
if (session.willReject(v)) {
|
|
985
|
+
void session.submit(v);
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
680
988
|
setValue("");
|
|
681
989
|
void session.submit(v).then(() => {
|
|
682
990
|
if (session.wantsExit) exit();
|
|
@@ -687,9 +995,9 @@ function Root({ session, deps }) {
|
|
|
687
995
|
const modal = session.getSnapshot().modal;
|
|
688
996
|
if (!modal) return;
|
|
689
997
|
if (modal.kind === "permission") session.answer(/^y(es)?$/i.test(v.trim()) ? "allow" : "deny");
|
|
690
|
-
else session.answer(v.trim() ? { [modal.questions[0].header]: [v.trim()] } : null);
|
|
998
|
+
else if (modal.kind === "user") session.answer(v.trim() ? { [modal.questions[0].header]: [v.trim()] } : null);
|
|
691
999
|
},
|
|
692
|
-
focus: state.modal
|
|
1000
|
+
focus: state.modal == null || state.modal.kind === "user",
|
|
693
1001
|
paletteSelected: paletteIndex,
|
|
694
1002
|
inputKey: fieldGen
|
|
695
1003
|
}
|
|
@@ -714,7 +1022,7 @@ async function runTui(deps) {
|
|
|
714
1022
|
reserve: bannerHeight(process.stdout, bannerOpts)
|
|
715
1023
|
});
|
|
716
1024
|
writeBanner(process.stdout, bannerOpts);
|
|
717
|
-
const app = render(/* @__PURE__ */
|
|
1025
|
+
const app = render(/* @__PURE__ */ jsx9(Root, { session, deps }), {
|
|
718
1026
|
/* LOAD-BEARING — do not "clean up" or default this away. Ink's own App
|
|
719
1027
|
* component (build/components/App.js, handleInput) intercepts the raw
|
|
720
1028
|
* \x03 byte and calls handleExit() BEFORE it ever emits the 'input'
|