@vincemakes/kiso-code 0.43.0 → 0.45.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/builtin.js CHANGED
@@ -7,12 +7,11 @@
7
7
  *
8
8
  * E5 (the composition round, finding E5-F1/F2): the task extension left
9
9
  * the default composition — on 13 consecutive real-provider sessions it
10
- * paid its rent (system:ext:task + tool:task_set on every request) and
11
- * was never called, not even on the guidance's own designed trigger. It
12
- * stays an official extension, OPT-IN via the user layer: copy
13
- * extensions/task/src/kiso-task.mjs into ~/.kiso/extensions/ (a user or
14
- * project extension named "task" is now a plain extension — no built-in
15
- * to shadow or collide with).
10
+ * paid its rent (its guidance and its tool on every request) and
11
+ * was never called, not even on the guidance's own designed trigger —
12
+ * and 0.44.0 retired it outright (no host used it either). A user or
13
+ * project extension named "task" is a plain extension — no built-in to
14
+ * shadow or collide with.
16
15
  *
17
16
  * - a user extension may SHADOW a built-in by name — the user's deliberate
18
17
  * install wins (a built-in cannot be uninstalled), loudly, and the
package/dist/chat.d.ts CHANGED
@@ -369,7 +369,9 @@ export declare function consumeRun(session: AgentSession, run: Run, input: LineI
369
369
  /** W21: the amend words ("Yes + feedback") ride the NEXT user turn —
370
370
  * threaded from chat's submitTurn; absent in the recovery flow
371
371
  * (resume) where a dropped amend is noticed instead. */
372
- submitTurn?: (line: string) => void): Promise<import("@vincemakes/kiso-core").Event | undefined>;
372
+ submitTurn?: (line: string) => void,
373
+ /** ADR-0057: a steer landed — an input after the run's own. */
374
+ onInputLanded?: () => void): Promise<import("@vincemakes/kiso-core").Event | undefined>;
373
375
  /** Interactive REPL: stream events, pause for approvals, Ctrl+C aborts. */
374
376
  /** The chat loop's ENDING: exit closes the process's REPL for good; a
375
377
  * switch hands main another session id to re-enter chat with — the
package/dist/chat.js CHANGED
@@ -5,12 +5,12 @@
5
5
  * estimates. All bodies moved verbatim from index.ts.
6
6
  */
7
7
  import { readFileSync, statSync } from "node:fs";
8
- import { escapeTerminal, cacheHitPct, decodeRate, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, kUnit, } from "@vincemakes/kiso-tui";
8
+ import { escapeTerminal, cacheHitPct, decodeRate, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, STATUS_GLYPHS, kUnit, } from "@vincemakes/kiso-tui";
9
9
  import { askView, coldResumeLine, coldResumeView, deletionRiskHint, editFileDiff, writeFileDiff } from "@vincemakes/kiso-tui";
10
10
  import { canonicalTargetPath, isProtectedPath, protectedIdentity, shellProgressPath } from "@vincemakes/kiso-tools-node";
11
11
  import { queuedSwitchLines } from "./state.js";
12
12
  import { echoText } from "@vincemakes/kiso-tui-cells/render";
13
- import { canonicalizeUsage } from "@vincemakes/kiso-runtime";
13
+ import { canonicalizeUsage, RunClosedError } from "@vincemakes/kiso-runtime";
14
14
  import { canonicalizeUsageForModel, requestBudget } from "@vincemakes/kiso-runtime/internal";
15
15
  import { dispatch, abortBangCommand } from "./dispatch.js";
16
16
  import { paintWindowTitle } from "./window-title.js";
@@ -756,21 +756,6 @@ export function parseSaferOptions(text) {
756
756
  }
757
757
  return out.length === 0 ? null : out;
758
758
  }
759
- /** TV-1B — the plain-word verdict tail for the settled checklist.
760
- * "no passing check yet" covers both never-ran and ran-and-failed
761
- * without lying; "outdated" claims only what the trajectory proves. */
762
- function taskVerdictWords(kind) {
763
- switch (kind) {
764
- case "verified":
765
- return "checked \u2713";
766
- case "stale":
767
- return "check outdated \u2014 work may have changed after it";
768
- case "none":
769
- return "no passing check yet";
770
- case "unreadable":
771
- return "task list unreadable";
772
- }
773
- }
774
759
  /** W21 — the panel view for a permission_requested: the rule line (the
775
760
  * why-asked speaker + the §3.5 fix hint), the toolTarget title, the
776
761
  * "❯ run paused" status, and the ALWAYS-verbose args. */
@@ -821,34 +806,6 @@ function approvalArgs(name, input) {
821
806
  * stream here. Events without a render (stop, expired, resolved, …) → null,
822
807
  * and the consumer skips them — the pipe bytes stay identical.
823
808
  */
824
- /**
825
- * round 6 (the task round): translate a do-not-compact-tagged tool result whose
826
- * content follows the task echo contract (a [task] header line + one
827
- * `[pending|active|done] text` line per item) into the checklist cell's
828
- * structured items. Null = not a checklist — the ordinary result cell
829
- * renders. Keyed on the TAG (what the extension declared), never on a
830
- * tool name; the parse is graceful so a foreign tagged result still
831
- * renders normally.
832
- */
833
- function parseChecklist(tags, content) {
834
- if (!(tags ?? []).includes("do-not-compact"))
835
- return null;
836
- const items = [];
837
- let header = "";
838
- for (const line of content.split("\n")) {
839
- const head = /^\[task\] (.*)$/.exec(line);
840
- if (head !== null) {
841
- header = head[1];
842
- continue;
843
- }
844
- const m = /^\[(pending|active|done)\] (.*)$/.exec(line);
845
- if (m !== null)
846
- items.push({ text: m[2], status: m[1] });
847
- }
848
- if (items.length === 0)
849
- return null;
850
- return { header, items };
851
- }
852
809
  function toRenderInput(ev) {
853
810
  switch (ev.type) {
854
811
  case "user_input":
@@ -897,8 +854,11 @@ export async function consumeRun(session, run, input, turnNo, faux, statusCb,
897
854
  /** W21: the amend words ("Yes + feedback") ride the NEXT user turn —
898
855
  * threaded from chat's submitTurn; absent in the recovery flow
899
856
  * (resume) where a dropped amend is noticed instead. */
900
- submitTurn) {
857
+ submitTurn,
858
+ /** ADR-0057: a steer landed — an input after the run's own. */
859
+ onInputLanded) {
901
860
  let last;
861
+ let inputsSeen = 0;
902
862
  // W22: the TURN's usage — null until a call settles, then the sum of
903
863
  // every call in this turn (accumulateUsage). Null rather than an empty
904
864
  // accumulator, so the first call is the sum rather than an addition to
@@ -974,6 +934,9 @@ submitTurn) {
974
934
  // construction (ADR-0040).
975
935
  switch (ev.type) {
976
936
  case "user_input":
937
+ inputsSeen += 1;
938
+ if (inputsSeen > 1)
939
+ onInputLanded?.();
977
940
  // The window title is re-derived here because THIS is when a
978
941
  // session stops being nameless: the tab opened as `kiso —
979
942
  // <workspace>` and the first substantive prompt is what gives
@@ -984,7 +947,9 @@ submitTurn) {
984
947
  // TV-1B: a system-sourced input is PRODUCT MACHINERY — visible
985
948
  // (every durable input renders) but never painted as the
986
949
  // user's words. Provenance is honest on screen, not only in
987
- // the log.
950
+ // the log. Since 0.44.0 (the verify offer retired) the CLI
951
+ // starts no such run itself; the branch keeps the rule for
952
+ // any run that carries one, as replay.ts does for old logs.
988
953
  if (ev.source === "system") {
989
954
  // R2 (law 1.3): the ◆ said nothing the words did not. What
990
955
  // makes this row honest is that it NAMES itself machinery.
@@ -1033,8 +998,7 @@ submitTurn) {
1033
998
  const text = typeof ev.content === "string" ? ev.content : "";
1034
999
  // W19: a DENIED call carries its reason — extracted from the
1035
1000
  // result's "[Permission denied] " prefix, keyed on the
1036
- // "denied" tag (the parseChecklist discipline: the tag
1037
- // declares, the prefix confirms). The ToolCell renders the
1001
+ // "denied" tag (the tag declares, the prefix confirms). The ToolCell renders the
1038
1002
  // pinned row (full name, target, reason, no timing).
1039
1003
  let reason = null;
1040
1004
  if ((ev.tags ?? []).includes("denied")) {
@@ -1043,14 +1007,6 @@ submitTurn) {
1043
1007
  reason = m[1];
1044
1008
  }
1045
1009
  body.toolResult(ev.callId, { content: text, isError: ev.isError, reason });
1046
- // round 6 (the task round): a result tagged do-not-compact whose content
1047
- // follows the checklist shape also renders as the durable
1048
- // checklist cell (the CLI translates Event → the tui's own
1049
- // shape; a non-matching parse falls back to the ordinary
1050
- // result cell — never hide information).
1051
- const checklist = parseChecklist(ev.tags, text);
1052
- if (checklist !== null)
1053
- body.checklist(checklist.header, checklist.items);
1054
1010
  break;
1055
1011
  }
1056
1012
  case "text_delta":
@@ -1202,19 +1158,6 @@ submitTurn) {
1202
1158
  // events (zero tokens). The dock's status bar still paints.
1203
1159
  statusCb?.(turnUsage() ?? UNKNOWN_USAGE, displayCtxRatio(session));
1204
1160
  const ratio = displayCtxRatio(session);
1205
- // TV-1B: the settle verdict — the checklist stops lying. When
1206
- // every item is CLAIMED done, the settled block's tail says
1207
- // what the projection actually proves ("no passing check yet"
1208
- // covers never-ran AND ran-and-failed; "may have changed"
1209
- // claims trajectory knowledge, never filesystem knowledge).
1210
- // A run that emitted no task_set still gets the block: the
1211
- // claims live in the durable log, and the settle SYNTHESIZES
1212
- // the display from session.assessTasks() — a UI projection,
1213
- // never a new durable fact.
1214
- const tv = session.assessTasks();
1215
- if (tv.claims.length > 0 && tv.allClaimedDone) {
1216
- body.checklist(taskVerdictWords(tv.evidence.kind), tv.claims.map((c) => ({ text: c.text, status: c.status })));
1217
- }
1218
1161
  // W14: the turn record closes HERE — before the recap logs, so
1219
1162
  // the commit loop folds the quiet turn's held cells first (the
1220
1163
  // fold line lands above the recap, natural cell order).
@@ -1328,13 +1271,11 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1328
1271
  console.log("\n[exit requested]");
1329
1272
  input.close();
1330
1273
  };
1331
- const turn = (text, seedSource, via) => new Promise((resolve, reject) => {
1274
+ const turn = (text, via) => new Promise((resolve, reject) => {
1332
1275
  queued = Math.max(0, queued - 1); // a queued turn starts
1333
1276
  // REL-0152-D11: a turn that names an image file carries it. The
1334
1277
  // scan returns the STRING unchanged when it finds nothing, so a
1335
1278
  // turn without one is byte-identical to before the feature.
1336
- // Seeded turns are the product's own words and are never
1337
- // scanned — nothing it writes to itself is an attachment.
1338
1279
  // REL-0152-D16: the capsules' files come from the editor, which
1339
1280
  // is the only thing that knows which number stands for which
1340
1281
  // screenshot.
@@ -1342,8 +1283,8 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1342
1283
  // 0.40.0: a skill turn is not scanned either — its text is a
1343
1284
  // SKILL.md body, and a body that mentions `diagram.png` must not
1344
1285
  // attach a file from the workspace the person never pointed at.
1345
- const content = seedSource !== undefined || via !== undefined ? text : attachImages(text, input.attachments?.(), protectedFiles());
1346
- const run = seedSource !== undefined ? session.run(content, { source: seedSource }) : via !== undefined ? session.run(content, { via }) : session.run(content);
1286
+ const content = via !== undefined ? text : attachImages(text, input.attachments?.(), protectedFiles());
1287
+ const run = via !== undefined ? session.run(content, { via }) : session.run(content);
1347
1288
  currentRun = run;
1348
1289
  turnNo += 1;
1349
1290
  const myTurn = turnNo;
@@ -1359,10 +1300,11 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1359
1300
  (async () => {
1360
1301
  let last;
1361
1302
  try {
1362
- last = await consumeRun(session, run, input, myTurn, faux, statusCb, submitTurn);
1303
+ last = await consumeRun(session, run, input, myTurn, faux, statusCb, submitTurn, landed);
1363
1304
  stopSpinner();
1364
1305
  paintIdle();
1365
1306
  currentRun = null;
1307
+ handBack(run);
1366
1308
  // 0.40.5: the kiso on disk may no longer be the one this
1367
1309
  // session runs (an upgrade since it started) — said once per
1368
1310
  // installed version (stale-version.ts).
@@ -1381,41 +1323,6 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1381
1323
  // exit, so the release always runs.
1382
1324
  if (eotSeen)
1383
1325
  exitAtEmptyPrompt();
1384
- // TV-1B — the thin task driver. A VERIFICATION turn settling
1385
- // consumes the task-set identity it produced (a verifier's
1386
- // own task_set belongs to the SAME accepted offer) and never
1387
- // opens another offer. A normal COMPLETED settle may offer —
1388
- // gated so the suggestion always yields to human intent.
1389
- if (seedSource === "system") {
1390
- const after = session.assessTasks();
1391
- if (after.lastTaskSetSeq !== null)
1392
- offeredTaskSeqs.add(after.lastTaskSetSeq);
1393
- }
1394
- else if (last?.type === "terminal" &&
1395
- last.outcome.kind === "completed" &&
1396
- process.stdin.isTTY &&
1397
- !cancelled &&
1398
- !eotSeen &&
1399
- pendingAsk === null &&
1400
- pendingTurns.length === 0 &&
1401
- input.line() === "") {
1402
- const tv = session.assessTasks();
1403
- if (tv.claims.length > 0 &&
1404
- tv.allClaimedDone &&
1405
- (tv.evidence.kind === "none" || tv.evidence.kind === "stale") &&
1406
- tv.lastTaskSetSeq !== null &&
1407
- !offeredTaskSeqs.has(tv.lastTaskSetSeq)) {
1408
- const verdict = await askPanel(input, verifyOfferView());
1409
- // an explicit answer — Yes, Not now, OR Esc — consumes
1410
- // the offer for THIS claims-set; only gate-suppression
1411
- // (above) leaves it live for a later settle.
1412
- offeredTaskSeqs.add(tv.lastTaskSetSeq);
1413
- if (verdict.action === "allow") {
1414
- queued += 1; // turn() decrements — keep the ledger honest
1415
- chainRef.current = chainRef.current.then(() => turn(VERIFY_SEED, "system"));
1416
- }
1417
- }
1418
- }
1419
1326
  // round 8: after EVERY turn the prompt is re-armed — the human
1420
1327
  // never types blind after the first turn.
1421
1328
  input.prompt();
@@ -1435,6 +1342,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1435
1342
  }
1436
1343
  console.error(`\n[run failed] ${err instanceof Error ? err.message : String(err)}\n`);
1437
1344
  currentRun = null;
1345
+ handBack(run);
1438
1346
  input.prompt();
1439
1347
  resolve();
1440
1348
  }
@@ -1447,6 +1355,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1447
1355
  // aborted terminal, which the consumer keeps consuming.
1448
1356
  console.log("\n[aborting run]");
1449
1357
  pendingAsk?.();
1358
+ giveBack();
1450
1359
  currentRun.abort();
1451
1360
  }
1452
1361
  else if (pendingAsk !== null) {
@@ -1479,6 +1388,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1479
1388
  if (currentRun) {
1480
1389
  console.log("\n[aborting run]");
1481
1390
  pendingAsk?.();
1391
+ giveBack();
1482
1392
  currentRun.abort();
1483
1393
  }
1484
1394
  });
@@ -1492,6 +1402,9 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1492
1402
  return dispatch(line, dispatchCtx);
1493
1403
  console.log("\n[redirecting run]");
1494
1404
  pendingAsk?.();
1405
+ // ADR-0057: steers that had not landed ride the correction — one next
1406
+ // message, not a queue; the correction first (§3: it corrects them).
1407
+ const unsent = handed(currentRun.retract().length);
1495
1408
  currentRun.abort();
1496
1409
  // §3: a correction must run BEFORE the follow-ups queued earlier —
1497
1410
  // it is a correction OF them. The existing slot mechanics compose
@@ -1506,9 +1419,9 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1506
1419
  const jumped = pendingTurns.map((s) => ({ content: s.content, via: s.via }));
1507
1420
  for (let i = jumped.length; i > 0; i -= 1)
1508
1421
  popQueue();
1509
- submitTurn(line);
1422
+ queueTurn(unsent.length > 0 ? [line, ...unsent.map((u) => u.content)].join("\n\n") : line);
1510
1423
  for (const j of jumped)
1511
- submitTurn(j.content, j.via);
1424
+ queueTurn(j.content, j.via);
1512
1425
  });
1513
1426
  // round 5 (P1-11): the PERSISTENT line listener is installed BEFORE the
1514
1427
  // startup recovery — a cancelled question's re-emitted "line" needs a
@@ -1542,14 +1455,6 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1542
1455
  // the editor — for a skill, the line the person TYPED; `content` is
1543
1456
  // what the turn submits (the skill's body and args).
1544
1457
  const pendingTurns = [];
1545
- // TV-1B — the offer memory: session-local BY DESIGN (a dead process's
1546
- // "not now" should not silence a live one; resume re-offers once,
1547
- // honestly), keyed by the assessed claims' identity.
1548
- const offeredTaskSeqs = new Set();
1549
- // The fixed verification seed — durable with source:"system": WHO asked
1550
- // is provenance in the log; on the provider wire it stays an ordinary
1551
- // user-role message (never a system-prompt escalation).
1552
- const VERIFY_SEED = "Verify the completed work: run the project's checks and report what passes and what fails.";
1553
1458
  // v2b: the live status bar (docked only). Modes: /mode switches repaint
1554
1459
  // it immediately through paintStatus (the last turn stats are kept).
1555
1460
  // v3 §03: the status bar has TWO states. Idle: the mode is ALWAYS
@@ -1649,7 +1554,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1649
1554
  return;
1650
1555
  spentUsd = (spentUsd ?? 0) + usd;
1651
1556
  };
1652
- const submitTurn = (line, via) => {
1557
+ const queueTurn = (line, via) => {
1653
1558
  const slot = { line: via?.line ?? line, content: line, ...(via !== undefined ? { via } : {}), cancelled: false };
1654
1559
  pendingTurns.push(slot);
1655
1560
  queued += 1;
@@ -1674,7 +1579,7 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1674
1579
  if (session.uncertainExecutions().length > 0)
1675
1580
  await resolveUncertains(session, input, () => cancelled);
1676
1581
  if (session.uncertainExecutions().length === 0)
1677
- return turn(line, undefined, via);
1582
+ return turn(line, via);
1678
1583
  // The human declined (round 10: a cancelled ask records NOTHING —
1679
1584
  // the execution stays uncertain and durable), so the turn does not
1680
1585
  // start. It is never swallowed in silence: the held text is
@@ -1696,10 +1601,78 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1696
1601
  queued = Math.max(0, queued - 1);
1697
1602
  return slot.line;
1698
1603
  };
1604
+ // ADR-0057 (the owner's ruling, 2026-09-28): Enter while a run is live
1605
+ // is a STEER — there is no queue. `steering` mirrors what the run holds
1606
+ // and has not admitted; the run takes ALL of it at its next quiescent
1607
+ // boundary, and the landed user_input clears the rows. Piped and
1608
+ // task-file input keep one turn per line: a script has nobody steering.
1609
+ const steerable = process.stdin.isTTY === true && input.literal !== true;
1610
+ let steering = [];
1611
+ const steer = (line, via) => {
1612
+ if (!steerable || currentRun === null)
1613
+ return false;
1614
+ try {
1615
+ currentRun.steer(via !== undefined ? line : attachImages(line, input.attachments?.(), protectedFiles()));
1616
+ }
1617
+ catch (err) {
1618
+ if (err instanceof RunClosedError)
1619
+ return false; // the run is ending: this is the next turn
1620
+ throw err;
1621
+ }
1622
+ steering.push({ line: via?.line ?? line, content: line, ...(via !== undefined ? { via } : {}) });
1623
+ return true;
1624
+ };
1625
+ const submitTurn = (line, via) => {
1626
+ if (!steer(line, via))
1627
+ queueTurn(line, via);
1628
+ };
1629
+ /** The mirror of the last `n` steers the run handed back; clears it. */
1630
+ const handed = (n) => {
1631
+ const out = n > 0 ? steering.slice(-n) : [];
1632
+ steering = [];
1633
+ return out;
1634
+ };
1635
+ const landed = () => {
1636
+ steering = [];
1637
+ };
1638
+ /** A run sealed with steers still pending (max_turns, an END_TURN
1639
+ * result, an error): they are the person's next message, sent now. */
1640
+ const handBack = (run) => {
1641
+ const left = handed(run.unadmitted().length);
1642
+ if (left.length === 1)
1643
+ queueTurn(left[0].content, left[0].via);
1644
+ else if (left.length > 1)
1645
+ queueTurn(left.map((s) => s.content).join("\n\n"));
1646
+ };
1647
+ /** Esc / ctrl+c: a stop is not a send — steers that have not landed
1648
+ * go back to the editor. */
1649
+ const giveBack = () => {
1650
+ if (currentRun === null)
1651
+ return;
1652
+ const back = handed(currentRun.retract().length);
1653
+ if (back.length > 0)
1654
+ input.restore?.(back.map((s) => s.line).join("\n"));
1655
+ };
1656
+ /** ↑ takes back the LAST steer that has not landed (the others go back
1657
+ * in, in order); with none, the pipe-era queue pop. */
1658
+ const popPending = () => {
1659
+ if (currentRun !== null && steering.length > 0) {
1660
+ const back = currentRun.retract();
1661
+ const mine = handed(back.length);
1662
+ const last = mine.pop();
1663
+ for (const c of back.slice(0, -1))
1664
+ currentRun.steer(c);
1665
+ steering = mine;
1666
+ if (last !== undefined)
1667
+ return last.line;
1668
+ }
1669
+ return popQueue();
1670
+ };
1699
1671
  // W22: the visibility invariant's binds — the dock renders the
1700
- // pending chips (+N queued), the editor routes the pop keys.
1701
- dock.bindQueue(() => pendingTurns.map((s) => s.line));
1702
- input.bindQueue(() => pendingTurns.map((s) => s.line), popQueue);
1672
+ // pending chips, the editor routes the pop keys.
1673
+ const pendingLines = () => [...steering.map((s) => s.line), ...pendingTurns.map((s) => s.line)];
1674
+ dock.bindQueue(pendingLines);
1675
+ input.bindQueue(pendingLines, popPending);
1703
1676
  const dispatchCtx = {
1704
1677
  session,
1705
1678
  input,
@@ -1825,8 +1798,9 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
1825
1798
  runStart = Date.now();
1826
1799
  runUsage = { in: null, out: null, cache: null, known: false };
1827
1800
  lastTokPerSec = null; // TPS-1: nothing has settled in THIS turn yet
1828
- const last = await consumeRun(session, recoveryRun, input, turnNo, faux, statusCb, submitTurn);
1801
+ const last = await consumeRun(session, recoveryRun, input, turnNo, faux, statusCb, submitTurn, landed);
1829
1802
  currentRun = null;
1803
+ handBack(recoveryRun);
1830
1804
  failOnFauxExhaustion(last, faux, input);
1831
1805
  // E group (the graceful-exit gate ③): the same deferred re-check
1832
1806
  // as the turn path — the recovery run's end is also a safe point.
package/dist/index.js CHANGED
@@ -319,6 +319,10 @@ function editorInput(editor) {
319
319
  bindQueue(state, pop) {
320
320
  editor.bindQueue(state, pop);
321
321
  },
322
+ // ADR-0057: the steers a stop handed back return to the buffer.
323
+ restore(text) {
324
+ editor.restore(text);
325
+ },
322
326
  // R3a: cross-session history — the CLI owns the file I/O.
323
327
  bindHistory(seed, persist) {
324
328
  editor.bindHistory(seed, persist);
@@ -477,7 +481,8 @@ function makeLineInput() {
477
481
  * the user-level names, then the project-level ones marked `project:`.
478
482
  * The built-in column is the banner's truthful face of the built-in layer:
479
483
  * a fresh install reads `[3 extensions: built-in: mcp, skills, subagent]`
480
- * with zero disk setup (E5: the task extension is opt-in). */
484
+ * with zero disk setup (the task extension, opt-in from E5, was
485
+ * retired in 0.44.0). */
481
486
  function bannerExtensionText() {
482
487
  // KC3.5 slice ⓪ (the extraction): the composition moved to the
483
488
  // terminal layer (extensionsBannerText — a pure function of the three
package/dist/state.d.ts CHANGED
@@ -179,6 +179,9 @@ export interface LineInput {
179
179
  * live slots (each pop cancels the turn), esc ends the walk after
180
180
  * one more pop. The chips are the compositor's own bindQueue. */
181
181
  bindQueue(state: () => readonly string[], pop: () => string | null): void;
182
+ /** ADR-0057: put text back into the editor — the steers a stop handed
183
+ * back before they landed. The pipe path has no editor; optional. */
184
+ restore?(text: string): void;
182
185
  /** R3a: cross-session history — seed the recall buffer, register the
183
186
  * append sink. The pipe path has no recall keys; optional. */
184
187
  bindHistory?(seed: readonly string[], persist: (line: string) => void): void;
@@ -318,8 +321,8 @@ export declare function setNeverInherited(value: (call: import("@vincemakes/kiso
318
321
  export declare let loadedExtensions: readonly KisoExtension[];
319
322
  /** R-D 0.1.45: the BUILT-IN layer — the three default official extensions,
320
323
  * shipped with the cli (module imports, never a disk scan; builtin.ts).
321
- * E5: the task extension is opt-in, not built-in. The banner's marked
322
- * column; a user extension may shadow a built-in. */
324
+ * The task extension, opt-in from E5, was retired in 0.44.0. The
325
+ * banner's marked column; a user extension may shadow a built-in. */
323
326
  export declare let builtInExtensions: readonly KisoExtension[];
324
327
  /** E1: the USER-level extensions alone — the banner's unmarked part (E3:
325
328
  * loadedExtensions later includes the project-level ones too). */
package/dist/state.js CHANGED
@@ -420,8 +420,8 @@ export function setNeverInherited(value) {
420
420
  export let loadedExtensions = [];
421
421
  /** R-D 0.1.45: the BUILT-IN layer — the three default official extensions,
422
422
  * shipped with the cli (module imports, never a disk scan; builtin.ts).
423
- * E5: the task extension is opt-in, not built-in. The banner's marked
424
- * column; a user extension may shadow a built-in. */
423
+ * The task extension, opt-in from E5, was retired in 0.44.0. The
424
+ * banner's marked column; a user extension may shadow a built-in. */
425
425
  export let builtInExtensions = [];
426
426
  /** E1: the USER-level extensions alone — the banner's unmarked part (E3:
427
427
  * loadedExtensions later includes the project-level ones too). */
package/dist/trust-ui.js CHANGED
@@ -87,8 +87,8 @@ opts) {
87
87
  // line typed at it was discarded anyway.
88
88
  //
89
89
  // The y/n fallback below still serves the views that really
90
- // do take a yes or no — the uncertainty gate, the trust
91
- // prompt, the verify offer. Those have a dock-less form.
90
+ // do take a yes or no — the uncertainty gate and the trust
91
+ // prompt. Those have a dock-less form.
92
92
  settled = true;
93
93
  pendingAsk = null;
94
94
  bodyLog(view.fallbackQuestion);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.43.0",
3
+ "version": "0.45.0",
4
4
  "description": "kiso-code \u2014 the coding agent on kiso, the durable runtime for AI agents: kiso chat / kiso resume / kiso sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -18,20 +18,19 @@
18
18
  "test": "vitest run"
19
19
  },
20
20
  "dependencies": {
21
- "@vincemakes/kiso-ask-ext": "0.43.0",
22
- "@vincemakes/kiso-core": "0.43.0",
23
- "@vincemakes/kiso-evals": "0.43.0",
24
- "@vincemakes/kiso-mcp-ext": "0.43.0",
25
- "@vincemakes/kiso-provider-anthropic": "0.43.0",
26
- "@vincemakes/kiso-provider-openai": "0.43.0",
27
- "@vincemakes/kiso-provider-openai-responses": "0.43.0",
28
- "@vincemakes/kiso-runtime": "0.43.0",
29
- "@vincemakes/kiso-skills-ext": "0.43.0",
30
- "@vincemakes/kiso-subagent-ext": "0.43.0",
31
- "@vincemakes/kiso-task-ext": "0.43.0",
32
- "@vincemakes/kiso-tools-node": "0.43.0",
33
- "@vincemakes/kiso-tui": "0.43.0",
34
- "@vincemakes/kiso-tui-cells": "0.43.0"
21
+ "@vincemakes/kiso-ask-ext": "0.45.0",
22
+ "@vincemakes/kiso-core": "0.45.0",
23
+ "@vincemakes/kiso-evals": "0.45.0",
24
+ "@vincemakes/kiso-mcp-ext": "0.45.0",
25
+ "@vincemakes/kiso-provider-anthropic": "0.45.0",
26
+ "@vincemakes/kiso-provider-openai": "0.45.0",
27
+ "@vincemakes/kiso-provider-openai-responses": "0.45.0",
28
+ "@vincemakes/kiso-runtime": "0.45.0",
29
+ "@vincemakes/kiso-skills-ext": "0.45.0",
30
+ "@vincemakes/kiso-subagent-ext": "0.45.0",
31
+ "@vincemakes/kiso-tools-node": "0.45.0",
32
+ "@vincemakes/kiso-tui": "0.45.0",
33
+ "@vincemakes/kiso-tui-cells": "0.45.0"
35
34
  },
36
35
  "devDependencies": {
37
36
  "@types/node": "^26.1.2",