@vincemakes/kiso-code 0.13.0 → 0.14.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.
Files changed (2) hide show
  1. package/dist/chat.js +83 -3
  2. package/package.json +14 -14
package/dist/chat.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * estimates. All bodies moved verbatim from index.ts.
6
6
  */
7
7
  import { readFileSync, statSync } from "node:fs";
8
- import { escapeTerminal, cacheHitPct, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, STATUS_GLYPHS, } from "@vincemakes/kiso-tui";
8
+ import { escapeTerminal, cacheHitPct, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, } from "@vincemakes/kiso-tui";
9
9
  import { deletionRiskHint, editFileDiff, writeFileDiff } from "@vincemakes/kiso-tui";
10
10
  import { canonicalTargetPath, shellProgressPath } from "@vincemakes/kiso-tools-node";
11
11
  import { canonicalizeUsage } from "@vincemakes/kiso-runtime";
@@ -342,6 +342,21 @@ export function parseSaferOptions(text) {
342
342
  }
343
343
  return out.length === 0 ? null : out;
344
344
  }
345
+ /** TV-1B — the plain-word verdict tail for the settled checklist.
346
+ * "no passing check yet" covers both never-ran and ran-and-failed
347
+ * without lying; "outdated" claims only what the trajectory proves. */
348
+ function taskVerdictWords(kind) {
349
+ switch (kind) {
350
+ case "verified":
351
+ return "checked \u2713";
352
+ case "stale":
353
+ return "check outdated \u2014 work may have changed after it";
354
+ case "none":
355
+ return "no passing check yet";
356
+ case "unreadable":
357
+ return "task list unreadable";
358
+ }
359
+ }
345
360
  /** W21 — the panel view for a permission_requested: the rule line (the
346
361
  * why-asked speaker + the §3.5 fix hint), the toolTarget title, the
347
362
  * "▸ run paused" status, and the ALWAYS-verbose args. */
@@ -510,6 +525,15 @@ submitTurn) {
510
525
  // construction (ADR-0040).
511
526
  switch (ev.type) {
512
527
  case "user_input":
528
+ // TV-1B: a system-sourced input is PRODUCT MACHINERY — visible
529
+ // (every durable input renders) but never painted as the
530
+ // user's words. Provenance is honest on screen, not only in
531
+ // the log.
532
+ if (ev.source === "system") {
533
+ body.notice("\u25c6 verification pass");
534
+ body.notice(` ${typeof ev.content === "string" ? ev.content : ""}`);
535
+ break;
536
+ }
513
537
  body.userLine(typeof ev.content === "string" ? ev.content : "");
514
538
  break;
515
539
  case "thinking":
@@ -687,6 +711,19 @@ submitTurn) {
687
711
  // events (zero tokens). The dock's status bar still paints.
688
712
  statusCb?.(usage, estimateCtxRatio(session));
689
713
  const ratio = estimateCtxRatio(session);
714
+ // TV-1B: the settle verdict — the checklist stops lying. When
715
+ // every item is CLAIMED done, the settled block's tail says
716
+ // what the projection actually proves ("no passing check yet"
717
+ // covers never-ran AND ran-and-failed; "may have changed"
718
+ // claims trajectory knowledge, never filesystem knowledge).
719
+ // A run that emitted no task_set still gets the block: the
720
+ // claims live in the durable log, and the settle SYNTHESIZES
721
+ // the display from session.assessTasks() — a UI projection,
722
+ // never a new durable fact.
723
+ const tv = session.assessTasks();
724
+ if (tv.claims.length > 0 && tv.allClaimedDone) {
725
+ body.checklist(taskVerdictWords(tv.evidence.kind), tv.claims.map((c) => ({ text: c.text, status: c.status })));
726
+ }
690
727
  // W14: the turn record closes HERE — before the recap logs, so
691
728
  // the commit loop folds the quiet turn's held cells first (the
692
729
  // fold line lands above the recap, natural cell order).
@@ -759,9 +796,9 @@ export async function chat(session, faux, input, autoCompact) {
759
796
  console.log("\n[exit requested]");
760
797
  input.close();
761
798
  };
762
- const turn = (text) => new Promise((resolve, reject) => {
799
+ const turn = (text, seedSource) => new Promise((resolve, reject) => {
763
800
  queued = Math.max(0, queued - 1); // a queued turn starts
764
- const run = session.run(text);
801
+ const run = seedSource !== undefined ? session.run(text, { source: seedSource }) : session.run(text);
765
802
  currentRun = run;
766
803
  turnNo += 1;
767
804
  const myTurn = turnNo;
@@ -792,6 +829,41 @@ export async function chat(session, faux, input, autoCompact) {
792
829
  // exit, so the release always runs.
793
830
  if (eotSeen)
794
831
  exitAtEmptyPrompt();
832
+ // TV-1B — the thin task driver. A VERIFICATION turn settling
833
+ // consumes the task-set identity it produced (a verifier's
834
+ // own task_set belongs to the SAME accepted offer) and never
835
+ // opens another offer. A normal COMPLETED settle may offer —
836
+ // gated so the suggestion always yields to human intent.
837
+ if (seedSource === "system") {
838
+ const after = session.assessTasks();
839
+ if (after.lastTaskSetSeq !== null)
840
+ offeredTaskSeqs.add(after.lastTaskSetSeq);
841
+ }
842
+ else if (last?.type === "terminal" &&
843
+ last.outcome.kind === "completed" &&
844
+ process.stdin.isTTY &&
845
+ !cancelled &&
846
+ !eotSeen &&
847
+ pendingAsk === null &&
848
+ pendingTurns.length === 0 &&
849
+ input.line() === "") {
850
+ const tv = session.assessTasks();
851
+ if (tv.claims.length > 0 &&
852
+ tv.allClaimedDone &&
853
+ (tv.evidence.kind === "none" || tv.evidence.kind === "stale") &&
854
+ tv.lastTaskSetSeq !== null &&
855
+ !offeredTaskSeqs.has(tv.lastTaskSetSeq)) {
856
+ const verdict = await askPanel(input, verifyOfferView());
857
+ // an explicit answer — Yes, Not now, OR Esc — consumes
858
+ // the offer for THIS claims-set; only gate-suppression
859
+ // (above) leaves it live for a later settle.
860
+ offeredTaskSeqs.add(tv.lastTaskSetSeq);
861
+ if (verdict.action === "allow") {
862
+ queued += 1; // turn() decrements — keep the ledger honest
863
+ chainRef.current = chainRef.current.then(() => turn(VERIFY_SEED, "system"));
864
+ }
865
+ }
866
+ }
795
867
  // round 8: after EVERY turn the prompt is re-armed — the human
796
868
  // never types blind after the first turn.
797
869
  input.prompt();
@@ -896,6 +968,14 @@ export async function chat(session, faux, input, autoCompact) {
896
968
  // A slot leaves the queue when its turn STARTS or when the user
897
969
  // pops it (cancelled — the chain segment skips it).
898
970
  const pendingTurns = [];
971
+ // TV-1B — the offer memory: session-local BY DESIGN (a dead process's
972
+ // "not now" should not silence a live one; resume re-offers once,
973
+ // honestly), keyed by the assessed claims' identity.
974
+ const offeredTaskSeqs = new Set();
975
+ // The fixed verification seed — durable with source:"system": WHO asked
976
+ // is provenance in the log; on the provider wire it stays an ordinary
977
+ // user-role message (never a system-prompt escalation).
978
+ const VERIFY_SEED = "Verify the completed work: run the project's checks and report what passes and what fails.";
899
979
  // v2b: the live status bar (docked only). Modes: /mode switches repaint
900
980
  // it immediately through paintStatus (the last turn stats are kept).
901
981
  // v3 §03: the status bar has TWO states. Idle: the mode is ALWAYS
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.13.0",
3
+ "version": "0.14.0",
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.13.0",
22
- "@vincemakes/kiso-core": "0.13.0",
23
- "@vincemakes/kiso-evals": "0.13.0",
24
- "@vincemakes/kiso-mcp-ext": "0.13.0",
25
- "@vincemakes/kiso-provider-anthropic": "0.13.0",
26
- "@vincemakes/kiso-provider-openai": "0.13.0",
27
- "@vincemakes/kiso-runtime": "0.13.0",
28
- "@vincemakes/kiso-skills-ext": "0.13.0",
29
- "@vincemakes/kiso-subagent-ext": "0.13.0",
30
- "@vincemakes/kiso-task-ext": "0.13.0",
31
- "@vincemakes/kiso-tools-node": "0.13.0",
32
- "@vincemakes/kiso-tui": "0.13.0",
33
- "@vincemakes/kiso-tui-cells": "0.13.0"
21
+ "@vincemakes/kiso-ask-ext": "0.14.0",
22
+ "@vincemakes/kiso-core": "0.14.0",
23
+ "@vincemakes/kiso-evals": "0.14.0",
24
+ "@vincemakes/kiso-mcp-ext": "0.14.0",
25
+ "@vincemakes/kiso-provider-anthropic": "0.14.0",
26
+ "@vincemakes/kiso-provider-openai": "0.14.0",
27
+ "@vincemakes/kiso-runtime": "0.14.0",
28
+ "@vincemakes/kiso-skills-ext": "0.14.0",
29
+ "@vincemakes/kiso-subagent-ext": "0.14.0",
30
+ "@vincemakes/kiso-task-ext": "0.14.0",
31
+ "@vincemakes/kiso-tools-node": "0.14.0",
32
+ "@vincemakes/kiso-tui": "0.14.0",
33
+ "@vincemakes/kiso-tui-cells": "0.14.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "^26.1.2",