@vincemakes/kiso-code 0.16.3 → 0.16.4
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/chat.js +8 -4
- package/dist/dispatch.js +6 -2
- package/dist/index.js +31 -37
- package/dist/resume-tail.d.ts +1 -1
- package/dist/resume-tail.js +16 -3
- package/package.json +14 -14
package/dist/chat.js
CHANGED
|
@@ -378,7 +378,7 @@ function taskVerdictWords(kind) {
|
|
|
378
378
|
}
|
|
379
379
|
/** W21 — the panel view for a permission_requested: the rule line (the
|
|
380
380
|
* why-asked speaker + the §3.5 fix hint), the toolTarget title, the
|
|
381
|
-
* "
|
|
381
|
+
* "⏸ run paused" status, and the ALWAYS-verbose args. */
|
|
382
382
|
function approvalView(name, ev, amended = false) {
|
|
383
383
|
const speaker = ev.speaker ?? "kiso";
|
|
384
384
|
const input = ev.input ?? {};
|
|
@@ -396,7 +396,7 @@ function approvalView(name, ev, amended = false) {
|
|
|
396
396
|
speaker,
|
|
397
397
|
...(hint !== undefined ? { hint } : {}),
|
|
398
398
|
...(risk !== null ? { riskHint: risk } : {}),
|
|
399
|
-
statusText: "
|
|
399
|
+
statusText: "⏸ run paused",
|
|
400
400
|
args: approvalArgs(name, input),
|
|
401
401
|
fallbackQuestion: `approve ${escapeTerminal(name)}? (y/n) `,
|
|
402
402
|
// TUI2-R3v2 ③: the v4 frame's "(amended)" marker. It says WHY this
|
|
@@ -549,7 +549,9 @@ submitTurn) {
|
|
|
549
549
|
// user's words. Provenance is honest on screen, not only in
|
|
550
550
|
// the log.
|
|
551
551
|
if (ev.source === "system") {
|
|
552
|
-
|
|
552
|
+
// R2 (law 1.3): the ◆ said nothing the words did not. What
|
|
553
|
+
// makes this row honest is that it NAMES itself machinery.
|
|
554
|
+
body.notice("verification pass");
|
|
553
555
|
body.notice(` ${typeof ev.content === "string" ? ev.content : ""}`);
|
|
554
556
|
break;
|
|
555
557
|
}
|
|
@@ -761,7 +763,9 @@ submitTurn) {
|
|
|
761
763
|
// recap (the truncation-guard philosophy: the cut is visible
|
|
762
764
|
// in the scrollback, the model's own text intact).
|
|
763
765
|
if (ev.outcome.kind === "max_tokens") {
|
|
764
|
-
|
|
766
|
+
// R2 (law 1.1): the notice was wearing a box corner. A notice
|
|
767
|
+
// is a sentence addressed to a human; it needs no edge.
|
|
768
|
+
body.notice('answer truncated at max_tokens — say "continue" to finish');
|
|
765
769
|
}
|
|
766
770
|
bodyLog(renderRecap({
|
|
767
771
|
seconds: Math.round((Date.now() - turnStart) / 1000),
|
package/dist/dispatch.js
CHANGED
|
@@ -203,7 +203,11 @@ export function dispatch(line, ctx) {
|
|
|
203
203
|
// user who sees it is exactly the user who needs
|
|
204
204
|
// the path spelled out
|
|
205
205
|
...(names.length === 0 ? { emptyNote: "no profiles — define models in ~/.kiso/config.json" } : {}),
|
|
206
|
-
},
|
|
206
|
+
},
|
|
207
|
+
// DC-12 (design §4): a panel WAITING ON A HUMAN says ⏸. The
|
|
208
|
+
// else-branch keeps ▸ — it names the current tier, which is
|
|
209
|
+
// what ▸ means everywhere else.
|
|
210
|
+
ctx.isRunning() ? "⏸ run paused" : `▸ ${getMode()}`), (v) => resolve(v.action === "picked" ? v.result : null));
|
|
207
211
|
});
|
|
208
212
|
ctx.paintIdle();
|
|
209
213
|
if (picked === null) {
|
|
@@ -365,7 +369,7 @@ export function dispatch(line, ctx) {
|
|
|
365
369
|
const elapsed = compactStart > 0 ? ((Date.now() - compactStart) / 1000).toFixed(1) : "?";
|
|
366
370
|
// a non-null result implies onStart ran — the "?" is
|
|
367
371
|
// reachable only at the type level
|
|
368
|
-
body.notice(`[/compact]
|
|
372
|
+
body.notice(`[/compact] ✦ compacted · ${compactInfo?.rounds ?? "?"} rounds → 1 summary · saved ~${kUnit(result.savedTokens)} · ctx ${ctxBefore ?? "?"}% → ${ctxAfter}% · ${elapsed}s`);
|
|
369
373
|
}
|
|
370
374
|
}
|
|
371
375
|
catch (err) {
|
package/dist/index.js
CHANGED
|
@@ -28,7 +28,7 @@ import { newSessionId } from "./session-id.js";
|
|
|
28
28
|
import { createInterface } from "node:readline";
|
|
29
29
|
import { fileURLToPath } from "node:url";
|
|
30
30
|
import { join } from "node:path";
|
|
31
|
-
import {
|
|
31
|
+
import { Body, Editor, bannerLines, currentGround, resolveGround, setGround, escapeTerminal, extensionsBannerText, idColumn, idleStatus, interactivePrompt, palette, renderSessionLine, sessionListFooter, sessionListRow } from "@vincemakes/kiso-tui";
|
|
32
32
|
import { createAgent, disposeExtensions, loadExtensions, loadProjectExtensions, SessionStore, } from "@vincemakes/kiso-runtime";
|
|
33
33
|
import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
34
34
|
import { createCodingTools } from "@vincemakes/kiso-tools-node";
|
|
@@ -245,6 +245,18 @@ function makeLineInput() {
|
|
|
245
245
|
// reader, nothing blocking: an answer that never arrives leaves the
|
|
246
246
|
// ground `unknown`, and `unknown` is a supported palette, not a
|
|
247
247
|
// failure — see packages/tui-cells/src/ground.ts.
|
|
248
|
+
// DC-14 (P1): the ladder is walked ONCE AT STARTUP, before the query
|
|
249
|
+
// and independently of it. It used to be walked only inside the
|
|
250
|
+
// reply callback below — so on a terminal that does not answer OSC
|
|
251
|
+
// 11 (tmux does not forward the reply by default), rung 1 never
|
|
252
|
+
// ran: `KISO_THEME=dark` is SETTLED as "an explicit answer always
|
|
253
|
+
// wins" and won nothing. Rung 3 was worse than dead — `COLORFGBG`
|
|
254
|
+
// exists FOR the terminals without OSC 11, and could only ever be
|
|
255
|
+
// consulted when an OSC reply had arrived and been malformed. With
|
|
256
|
+
// §3.2 recording that rung 2 is unmeasured, that was the mainline.
|
|
257
|
+
setGround(resolveGround({ theme: process.env.KISO_THEME, colorfgbg: process.env.COLORFGBG }));
|
|
258
|
+
// the reply, when there is one, re-walks the ladder WITH it — and
|
|
259
|
+
// `theme` goes in first again, so an explicit answer still wins.
|
|
248
260
|
editor.onOsc((reply) => {
|
|
249
261
|
const next = resolveGround({ theme: process.env.KISO_THEME, osc: reply, colorfgbg: process.env.COLORFGBG });
|
|
250
262
|
if (next === currentGround())
|
|
@@ -261,7 +273,12 @@ function makeLineInput() {
|
|
|
261
273
|
// W6: the box's prompt goes light — "› " (the box already says
|
|
262
274
|
// "input lives here"; the line-mode path keeps the brick ▌, so
|
|
263
275
|
// pipe bytes do not change)
|
|
264
|
-
|
|
276
|
+
// R2 (owner, 2026-08-27): no prompt glyph. The cursor sits at column
|
|
277
|
+
// one, between the two rules — the rules already say "input lives
|
|
278
|
+
// here", which is the argument W6 made for the box and the only part
|
|
279
|
+
// of it that survives. A prompt character is a third thing saying
|
|
280
|
+
// the same thing, and it cost the row a column.
|
|
281
|
+
dock.bindInput(() => editor.dockState(), "");
|
|
265
282
|
// TUI2-R3v2 ②: the click hit-test's wiring — the compositor places
|
|
266
283
|
// the panel's option rows, so the compositor is what the editor asks
|
|
267
284
|
// where they are. Neither side computes the other's geometry.
|
|
@@ -313,37 +330,6 @@ function extensionsBanner(resume = []) {
|
|
|
313
330
|
cwd: cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd,
|
|
314
331
|
});
|
|
315
332
|
}
|
|
316
|
-
/** W5: the opening-screen resume list — up to 3 recent sessions, newest
|
|
317
|
-
* first, the CURRENT session excluded (it is not something to pick back
|
|
318
|
-
* up). Every field already exists behind the store's SessionMeta (the
|
|
319
|
-
* `kiso sessions` line shows the same data) — only the projection and
|
|
320
|
-
* the sort live here.
|
|
321
|
-
*
|
|
322
|
-
* TT-1B (W5 unification): each row carries the picker's badge glyph,
|
|
323
|
-
* derived through the SAME projection the picker uses (session-cards —
|
|
324
|
-
* one source of truth about durability; a second derivation would be
|
|
325
|
-
* none). Only the 3 chosen sessions are opened — the read-only listing
|
|
326
|
-
* rule holds (projectSessionCard's own guarantee), and the cost is
|
|
327
|
-
* bounded by the list, never the home. */
|
|
328
|
-
async function recentSessions(id, agent) {
|
|
329
|
-
const picked = agent
|
|
330
|
-
.sessions()
|
|
331
|
-
.filter((m) => m.id !== id)
|
|
332
|
-
.sort((a, b) => b.updatedAt - a.updatedAt)
|
|
333
|
-
.slice(0, 3);
|
|
334
|
-
const store = sessionStoreRef;
|
|
335
|
-
const out = [];
|
|
336
|
-
for (const m of picked) {
|
|
337
|
-
let badge;
|
|
338
|
-
if (store !== null) {
|
|
339
|
-
const session = await agent.session({ id: m.id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
340
|
-
const card = projectSessionCard({ id: m.id, updatedAt: m.updatedAt, records: store.load(m.id), asks: session.pendingApprovals().length });
|
|
341
|
-
badge = BADGE_GLYPH[card.badge];
|
|
342
|
-
}
|
|
343
|
-
out.push({ title: m.title, events: m.events, runs: m.runs, updatedAt: m.updatedAt, ...(badge === undefined ? {} : { badge }) });
|
|
344
|
-
}
|
|
345
|
-
return out;
|
|
346
|
-
}
|
|
347
333
|
/**
|
|
348
334
|
* A area: the coding-agent system prompt — ONE constant, byte-stable for the
|
|
349
335
|
* session's lifetime (D area). Kept under ~80 lines; no template engine.
|
|
@@ -643,13 +629,21 @@ async function chatLoop(agent, firstId, input, autoCompact) {
|
|
|
643
629
|
// prompt inside a conversation with thousands of events — the
|
|
644
630
|
// durable log was right there and none of it was shown. Empty for
|
|
645
631
|
// a fresh session, so `kiso chat` is byte-identical.
|
|
646
|
-
for (const line of resumeTail(session.log.all))
|
|
632
|
+
for (const line of resumeTail(session.log.all, process.stdout.columns ?? 80))
|
|
647
633
|
bodyLog(line);
|
|
648
|
-
|
|
634
|
+
// R2 (owner, 2026-08-27): the resume list is NOT on the opening
|
|
635
|
+
// screen. `/resume` is where you go looking for a session; the
|
|
636
|
+
// opening's job is to say what THIS one is.
|
|
637
|
+
//
|
|
638
|
+
// It takes DC-8 with it: building those rows opened the three most
|
|
639
|
+
// recent sessions just to draw a badge, and `agent.session()`
|
|
640
|
+
// throws on profile drift — so one drifted session anywhere in the
|
|
641
|
+
// history stopped kiso from starting at all.
|
|
642
|
+
extensionsBanner();
|
|
649
643
|
}
|
|
650
644
|
else {
|
|
651
645
|
bodyLog(`session ${id} (switched — previous: ${prev}, /resume ${prev} returns)\n`);
|
|
652
|
-
for (const line of resumeTail(session.log.all))
|
|
646
|
+
for (const line of resumeTail(session.log.all, process.stdout.columns ?? 80))
|
|
653
647
|
bodyLog(line);
|
|
654
648
|
if (currentFaux)
|
|
655
649
|
session.setAdapter(createFauxProvider(readFauxScript().slice(fauxSkip(id))));
|
|
@@ -917,7 +911,7 @@ async function main() {
|
|
|
917
911
|
session.setAdapter(createFauxProvider(readFauxScript().slice(fauxSkip(id))));
|
|
918
912
|
// REL-0152-D5 — the same tail on the explicit-id form. NOT on
|
|
919
913
|
// the -p path above: that one's stdout is a machine's input.
|
|
920
|
-
for (const line of resumeTail(session.log.all))
|
|
914
|
+
for (const line of resumeTail(session.log.all, process.stdout.columns ?? 80))
|
|
921
915
|
bodyLog(line);
|
|
922
916
|
await resume(session, prompt, faux, input);
|
|
923
917
|
break;
|
package/dist/resume-tail.d.ts
CHANGED
package/dist/resume-tail.js
CHANGED
|
@@ -28,7 +28,7 @@ const clip = (s, n) => (s.length <= n ? s : `${s.slice(0, n - 1)}…`);
|
|
|
28
28
|
* prompt. Empty when there is nothing to show, and the caller prints
|
|
29
29
|
* nothing rather than an empty frame.
|
|
30
30
|
*/
|
|
31
|
-
export function resumeTail(events) {
|
|
31
|
+
export function resumeTail(events, W = 80) {
|
|
32
32
|
const turns = [];
|
|
33
33
|
let ask = null;
|
|
34
34
|
let reply = "";
|
|
@@ -51,9 +51,22 @@ export function resumeTail(events) {
|
|
|
51
51
|
return [];
|
|
52
52
|
const lines = [];
|
|
53
53
|
const skipped = turns.length - shown.length;
|
|
54
|
-
|
|
54
|
+
// R2 (law 1.1): the head is the ONE rule, labelled the way every
|
|
55
|
+
// other band on screen labels itself. It used to be `─ … ─`, a second
|
|
56
|
+
// divider weight that existed nowhere else in the product.
|
|
57
|
+
const label = skipped > 0 ? `resuming · ${turns.length} turns, showing the last ${shown.length}` : `resuming · ${turns.length} turn${turns.length === 1 ? "" : "s"}`;
|
|
58
|
+
const head = `\u254c\u254c\u254c ${label} `;
|
|
59
|
+
// the cut floor is the WIDTH, never a constant: `Math.max(4, W)` let a
|
|
60
|
+
// four-cell rule out at W=1..3, i.e. a chrome row wider than the
|
|
61
|
+
// terminal. Every glyph here is one cell (the label is ascii plus
|
|
62
|
+
// `·`), so a code-unit slice is a cell slice.
|
|
63
|
+
lines.push(`${head}${"\u254c".repeat(Math.max(1, W - head.length))}`.slice(0, Math.max(1, W)));
|
|
55
64
|
for (const t of shown) {
|
|
56
|
-
|
|
65
|
+
// the human's turn keeps the quote gutter — the one glyph in the
|
|
66
|
+
// product that means "these are somebody's exact words". The `\u203a`
|
|
67
|
+
// it used to carry is the composer's prompt, and the composer no
|
|
68
|
+
// longer has one.
|
|
69
|
+
lines.push(` \u2502 ${clip(oneLine(t.ask), 100)}`);
|
|
57
70
|
const body = oneLine(t.reply);
|
|
58
71
|
// A turn with no reply is a turn that was INTERRUPTED — the case
|
|
59
72
|
// resume exists for. Saying so beats printing a blank line.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.4",
|
|
4
4
|
"description": "kiso CLI — the durable coding agent that survives kill -9: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.16.
|
|
22
|
-
"@vincemakes/kiso-core": "0.16.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.16.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.16.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.16.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.16.
|
|
27
|
-
"@vincemakes/kiso-runtime": "0.16.
|
|
28
|
-
"@vincemakes/kiso-skills-ext": "0.16.
|
|
29
|
-
"@vincemakes/kiso-subagent-ext": "0.16.
|
|
30
|
-
"@vincemakes/kiso-task-ext": "0.16.
|
|
31
|
-
"@vincemakes/kiso-tools-node": "0.16.
|
|
32
|
-
"@vincemakes/kiso-tui": "0.16.
|
|
33
|
-
"@vincemakes/kiso-tui-cells": "0.16.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.16.4",
|
|
22
|
+
"@vincemakes/kiso-core": "0.16.4",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.16.4",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.16.4",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.16.4",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.16.4",
|
|
27
|
+
"@vincemakes/kiso-runtime": "0.16.4",
|
|
28
|
+
"@vincemakes/kiso-skills-ext": "0.16.4",
|
|
29
|
+
"@vincemakes/kiso-subagent-ext": "0.16.4",
|
|
30
|
+
"@vincemakes/kiso-task-ext": "0.16.4",
|
|
31
|
+
"@vincemakes/kiso-tools-node": "0.16.4",
|
|
32
|
+
"@vincemakes/kiso-tui": "0.16.4",
|
|
33
|
+
"@vincemakes/kiso-tui-cells": "0.16.4"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.2",
|