@vincemakes/kiso-code 0.1.37 → 0.1.39
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 +45 -6
- package/dist/dispatch.js +29 -0
- package/dist/index.js +12 -3
- package/dist/state.d.ts +3 -0
- package/package.json +2 -2
package/dist/chat.js
CHANGED
|
@@ -100,8 +100,8 @@ function approvalDiff(name, input) {
|
|
|
100
100
|
* and the consumer skips them — the pipe bytes stay identical.
|
|
101
101
|
*/
|
|
102
102
|
/**
|
|
103
|
-
* round 6 (the
|
|
104
|
-
* content follows the
|
|
103
|
+
* round 6 (the task round): translate a do-not-compact-tagged tool result whose
|
|
104
|
+
* content follows the task echo contract (a [task] header line + one
|
|
105
105
|
* `[pending|active|done] text` line per item) into the checklist cell's
|
|
106
106
|
* structured items. Null = not a checklist — the ordinary result cell
|
|
107
107
|
* renders. Keyed on the TAG (what the extension declared), never on a
|
|
@@ -114,7 +114,7 @@ function parseChecklist(tags, content) {
|
|
|
114
114
|
const items = [];
|
|
115
115
|
let header = "";
|
|
116
116
|
for (const line of content.split("\n")) {
|
|
117
|
-
const head = /^\[
|
|
117
|
+
const head = /^\[task\] (.*)$/.exec(line);
|
|
118
118
|
if (head !== null) {
|
|
119
119
|
header = head[1];
|
|
120
120
|
continue;
|
|
@@ -177,9 +177,23 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
177
177
|
const turnStart = Date.now();
|
|
178
178
|
let toolCount = 0;
|
|
179
179
|
let editCount = 0;
|
|
180
|
+
// W14: the thinking event carries NO timestamp — the CLI wall-clocks
|
|
181
|
+
// the thinking window: it opens at the first thinking event and closes
|
|
182
|
+
// at the first non-thinking event (the fold needs the seconds).
|
|
183
|
+
let thoughtSeconds = 0;
|
|
184
|
+
let thinkingSince = null;
|
|
180
185
|
try {
|
|
181
186
|
for await (const ev of run) {
|
|
182
187
|
last = ev;
|
|
188
|
+
if (ev.type !== "thinking") {
|
|
189
|
+
if (thinkingSince !== null) {
|
|
190
|
+
thoughtSeconds += (Date.now() - thinkingSince) / 1000;
|
|
191
|
+
thinkingSince = null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
else if (thinkingSince === null) {
|
|
195
|
+
thinkingSince = Date.now();
|
|
196
|
+
}
|
|
183
197
|
// v2a (the double echo): the interactive echo was already rendered by the
|
|
184
198
|
// input source — rendering the event again is the double echo.
|
|
185
199
|
// v2b: DOCKED — the echo lives in the input row (H), NOT the body;
|
|
@@ -218,8 +232,19 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
218
232
|
break;
|
|
219
233
|
case "tool_result": {
|
|
220
234
|
const text = typeof ev.content === "string" ? ev.content : "";
|
|
221
|
-
|
|
222
|
-
//
|
|
235
|
+
// W19: a DENIED call carries its reason — extracted from the
|
|
236
|
+
// result's "[Permission denied] " prefix, keyed on the
|
|
237
|
+
// "denied" tag (the parseChecklist discipline: the tag
|
|
238
|
+
// declares, the prefix confirms). The ToolCell renders the
|
|
239
|
+
// pinned row (full name, target, reason, no timing).
|
|
240
|
+
let reason = null;
|
|
241
|
+
if ((ev.tags ?? []).includes("denied")) {
|
|
242
|
+
const m = /^\[Permission denied\] (.*)$/.exec(text);
|
|
243
|
+
if (m !== null)
|
|
244
|
+
reason = m[1];
|
|
245
|
+
}
|
|
246
|
+
body.toolResult(ev.callId, { content: text, isError: ev.isError, reason });
|
|
247
|
+
// round 6 (the task round): a result tagged do-not-compact whose content
|
|
223
248
|
// follows the checklist shape also renders as the durable
|
|
224
249
|
// checklist cell (the CLI translates Event → the tui's own
|
|
225
250
|
// shape; a non-matching parse falls back to the ordinary
|
|
@@ -271,12 +296,19 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
271
296
|
// events (zero tokens). The dock's status bar still paints.
|
|
272
297
|
statusCb?.(usage, estimateCtxRatio(session));
|
|
273
298
|
const ratio = estimateCtxRatio(session);
|
|
299
|
+
// W14: the turn record closes HERE — before the recap logs, so
|
|
300
|
+
// the commit loop folds the quiet turn's held cells first (the
|
|
301
|
+
// fold line lands above the recap, natural cell order).
|
|
302
|
+
body.endTurn(Math.round(thoughtSeconds));
|
|
274
303
|
bodyLog(renderRecap({
|
|
275
304
|
seconds: Math.round((Date.now() - turnStart) / 1000),
|
|
276
305
|
tools: toolCount,
|
|
277
306
|
edits: editCount,
|
|
278
307
|
usage,
|
|
279
308
|
ctxLeftPct: Number.isFinite(ratio) ? (1 - ratio) * 100 : null,
|
|
309
|
+
// W19: under plan the recap becomes the way-forward row
|
|
310
|
+
// (the /mode hints are the mode's exits).
|
|
311
|
+
mode: getMode(),
|
|
280
312
|
}));
|
|
281
313
|
break;
|
|
282
314
|
}
|
|
@@ -436,7 +468,10 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
436
468
|
return;
|
|
437
469
|
const ratio = estimateCtxRatio(session);
|
|
438
470
|
const pct = Number.isFinite(ratio) ? Math.round((1 - ratio) * 100) : null;
|
|
439
|
-
|
|
471
|
+
// W19: under plan the idle row makes the posture unmistakable —
|
|
472
|
+
// the W4 parentheses idiom names the read-only constraint.
|
|
473
|
+
const tier = getMode() === "plan" ? "plan (read-only)" : getMode();
|
|
474
|
+
dock.setStatus(`▸ ${tier} · /mode to switch · ${agentModel} · ctx left ~${pct}%`);
|
|
440
475
|
};
|
|
441
476
|
const statusCb = (u, ctx) => {
|
|
442
477
|
runUsage = u;
|
|
@@ -479,6 +514,10 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
479
514
|
}
|
|
480
515
|
dispatch(line, dispatchCtx);
|
|
481
516
|
});
|
|
517
|
+
// W15: the expand key — the editor forwards ctrl+r; dispatch runs the
|
|
518
|
+
// chain action (the sentinel's control char marks the key, so a typed
|
|
519
|
+
// "expand" turn is never intercepted).
|
|
520
|
+
input.onExpand(() => dispatch("\x12expand", dispatchCtx));
|
|
482
521
|
// Recovery first: a session with a dangling pause or uncertain
|
|
483
522
|
// executions must resolve them BEFORE the REPL accepts new turns —
|
|
484
523
|
// otherwise the interrupted run dangles while a new one starts.
|
package/dist/dispatch.js
CHANGED
|
@@ -66,6 +66,35 @@ export function dispatch(line, ctx) {
|
|
|
66
66
|
});
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
|
+
if (trimmed === "\x12expand") {
|
|
70
|
+
// W15: the expand key (ctrl+r) — /last aimed at a chosen cell.
|
|
71
|
+
// The TARGET is picked at press time: a LIVE tool cell toggles
|
|
72
|
+
// IMMEDIATELY in place (the compositor owns those rows and
|
|
73
|
+
// redraws them — the approval pause is exactly when the user
|
|
74
|
+
// reads a cut diff, and the key must answer then, never after
|
|
75
|
+
// the run). A COMMITTED cell can never toggle — history is never
|
|
76
|
+
// rewritten (ADR-0046) — so its expanded block and the empty
|
|
77
|
+
// answer queue on the chain like /last: the block lands as new
|
|
78
|
+
// content after any in-flight turn. The sentinel carries the
|
|
79
|
+
// control char so a typed "expand" turn is never intercepted.
|
|
80
|
+
const r = body.expandNext();
|
|
81
|
+
if (r.kind === "toggled") {
|
|
82
|
+
ctx.input.prompt(); // in place — the frame already repainted
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const land = async () => {
|
|
86
|
+
if (r.kind === "appended") {
|
|
87
|
+
for (const line of r.lines)
|
|
88
|
+
bodyLog(line);
|
|
89
|
+
}
|
|
90
|
+
else if (r.kind === "none") {
|
|
91
|
+
bodyLog("[nothing to expand]");
|
|
92
|
+
}
|
|
93
|
+
ctx.input.prompt();
|
|
94
|
+
};
|
|
95
|
+
ctx.chainRef.current = ctx.chainRef.current.then(land);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
69
98
|
if (trimmed === "/status") {
|
|
70
99
|
// B area: session id, durable event count, and the ~ context
|
|
71
100
|
// estimate — all read straight from the live session, nothing
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
import { readFileSync, rmSync } from "node:fs";
|
|
26
26
|
import { createInterface } from "node:readline";
|
|
27
27
|
import { join } from "node:path";
|
|
28
|
-
import { Body, Editor,
|
|
28
|
+
import { Body, Editor, bannerLines, palette, renderSessionLine } from "@vincemakes/kiso-tui";
|
|
29
29
|
import { escapeTerminal } from "@vincemakes/kiso-tui";
|
|
30
30
|
import { createAgent, disposeExtensions, loadExtensions, loadProjectExtensions, SessionStore, } from "@vincemakes/kiso-runtime";
|
|
31
31
|
import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
@@ -70,6 +70,10 @@ function readlineInput(rl) {
|
|
|
70
70
|
onEscape() {
|
|
71
71
|
/* readline has no bare-Esc semantics — ignored. */
|
|
72
72
|
},
|
|
73
|
+
onExpand() {
|
|
74
|
+
/* readline has no ctrl+r binding — ignored (W15 rides the
|
|
75
|
+
* editor path only). */
|
|
76
|
+
},
|
|
73
77
|
question(query, cb) {
|
|
74
78
|
rl.question(query, cb);
|
|
75
79
|
},
|
|
@@ -112,6 +116,9 @@ function editorInput(editor) {
|
|
|
112
116
|
onEscape(cb) {
|
|
113
117
|
editor.onEscape(cb);
|
|
114
118
|
},
|
|
119
|
+
onExpand(cb) {
|
|
120
|
+
editor.onExpand(cb);
|
|
121
|
+
},
|
|
115
122
|
question(query, cb) {
|
|
116
123
|
editor.question(query, cb);
|
|
117
124
|
},
|
|
@@ -145,8 +152,10 @@ function makeLineInput() {
|
|
|
145
152
|
if (process.stdin.isTTY) {
|
|
146
153
|
const editor = new Editor(() => (dock.active ? dock.redraw() : editor.selfRender()));
|
|
147
154
|
editor.enter();
|
|
148
|
-
|
|
149
|
-
|
|
155
|
+
// W6: the box's prompt goes light — "› " (the box already says
|
|
156
|
+
// "input lives here"; the line-mode path keeps the brick ▌, so
|
|
157
|
+
// pipe bytes do not change)
|
|
158
|
+
dock.bindInput(() => editor.dockState(), "› ");
|
|
150
159
|
dock.bindMenu(() => editor.menuState()); // v3 §04: the slash-command menu
|
|
151
160
|
return editorInput(editor);
|
|
152
161
|
}
|
package/dist/state.d.ts
CHANGED
|
@@ -27,6 +27,9 @@ export interface LineInput {
|
|
|
27
27
|
onSigint(cb: () => void): void;
|
|
28
28
|
onEot(cb: () => void): void;
|
|
29
29
|
onEscape(cb: () => void): void;
|
|
30
|
+
/** W15: the expand key (ctrl+r) — the chain-level action, never the
|
|
31
|
+
* editor's own interpretation. */
|
|
32
|
+
onExpand(cb: () => void): void;
|
|
30
33
|
question(query: string, cb: (answer: string) => void): void;
|
|
31
34
|
cancelQuestion(): void;
|
|
32
35
|
emitLine(line: string): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
4
4
|
"description": "kiso CLI — the coding-agent reference product: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"@vincemakes/kiso-provider-openai": "0.1.31",
|
|
25
25
|
"@vincemakes/kiso-runtime": "0.1.31",
|
|
26
26
|
"@vincemakes/kiso-tools-node": "0.1.31",
|
|
27
|
-
"@vincemakes/kiso-tui": "0.1.
|
|
27
|
+
"@vincemakes/kiso-tui": "0.1.39"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^26.1.2",
|