@vincemakes/kiso-code 0.1.48 → 0.2.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/chat.d.ts CHANGED
@@ -32,6 +32,46 @@ export declare function contextWindowTokens(): number;
32
32
  * the model window. Marked ~ everywhere it is shown; no counting API.
33
33
  */
34
34
  export declare function estimateCtxRatio(session: AgentSession): number;
35
+ /** E2 (1.3.0) — the CLI's usage consumer: one event in, the RunUsage the
36
+ * status line and recap render plus the miss estimate. `total` is the
37
+ * carrier for the NEXT turn's miss estimate — the overlap of consecutive
38
+ * prompts is a total-side quantity, never a fresh delta. */
39
+ export interface UsageDelta {
40
+ readonly usage: RunUsage;
41
+ /** The canonical total (fresh + cache) — the miss estimate's carrier.
42
+ * null when the event carried no usage (the canonical total of an
43
+ * unknown event is 0, and a 0 carrier keeps the estimate below the
44
+ * floor — the old consumer's carrier stayed null forever; this one
45
+ * recovers on the next known event). */
46
+ readonly total: number | null;
47
+ readonly missed: number | null;
48
+ }
49
+ /**
50
+ * The CLI's usage consumer (E2 1.3.0, the R2a-1 ruling 2026-08-13) — the
51
+ * HEAL: the mixed-convention consumer is now CANONICAL at the route (the
52
+ * accounting boundary), the same derivation the trace block carries.
53
+ *
54
+ * EXISTING-BEHAVIOR CHANGE — declared, never a silent side-fix:
55
+ * - openai-compat: `in` was the provider-raw TOTAL (fresh + cache); it is
56
+ * now the canonical FRESH count. The >100% cache-ratio disease: raw
57
+ * {input 111, cacheRead 1024} previously rendered "in 111" and the
58
+ * recap's cache % (then cache/in) read 923%; now "in 0" and the recap
59
+ * divides cache by the TOTAL (in + cache — T5) — never > 100%.
60
+ * - the miss estimate is numerically IDENTICAL on openai-compat: its old
61
+ * `in` WAS the total, and the carrier is the canonical total
62
+ * (input + cacheRead), which equals the raw total by construction.
63
+ * - anthropic: `in` was already fresh — unchanged; the miss estimate was
64
+ * min-of-fresh-deltas − cacheRead (always below the floor — silent);
65
+ * it is now min-of-totals, the semantics the openai-compat side always
66
+ * had (a fix, and it can fire).
67
+ * - the unknown-usage carrier: the old consumer's null carrier killed the
68
+ * miss signal forever; the canonical total of an unknown event is 0, so
69
+ * the signal recovers on the next known event.
70
+ * The route key mirrors the trace path's fallback by construction: an
71
+ * absent provider resolves like the tracer's "adapter" identity — the
72
+ * total convention (INPUT_CONVENTIONS), never a crash.
73
+ */
74
+ export declare function usageFromEvent(route: string | undefined, ev: import("@vincemakes/kiso-core").Usage, prevTotal: number | null): UsageDelta;
35
75
  /** v2b: the spinner merged into the STATUS BAR (the v2a standalone glyph
36
76
  * is gone) — docked only, 200ms rotation between the request and the
37
77
  * first event. */
package/dist/chat.js CHANGED
@@ -8,6 +8,7 @@ import { readFileSync } from "node:fs";
8
8
  import { escapeTerminal, kUnit, palette, renderEvent, renderRecap, toolTarget, } from "@vincemakes/kiso-tui";
9
9
  import { editFileDiff, writeFileDiff } from "@vincemakes/kiso-tui";
10
10
  import { canonicalTargetPath } from "@vincemakes/kiso-tools-node";
11
+ import { canonicalizeUsage } from "@vincemakes/kiso-runtime";
11
12
  import { dispatch } from "./dispatch.js";
12
13
  import { agentModel, body, bodyLog, configuredWindow, dock } from "./state.js";
13
14
  import { addDontAskAgainRule, askPanel, fixHintFor, pendingAsk, resolveUncertains } from "./trust-ui.js";
@@ -47,6 +48,49 @@ export function estimateCtxRatio(session) {
47
48
  const chars = JSON.stringify(projected).length;
48
49
  return chars / 4 / contextWindowTokens();
49
50
  }
51
+ /** R-C item 4: the per-turn cache miss — the overlap with the previous
52
+ * prompt that SHOULD have been cached but was re-sent uncached:
53
+ * missed = min(prevIn, in) − cacheRead. Below the 1024-token floor
54
+ * (Anthropic's minimum cacheable block) it is noise — not surfaced. */
55
+ const CACHE_MISS_FLOOR = 1024;
56
+ /**
57
+ * The CLI's usage consumer (E2 1.3.0, the R2a-1 ruling 2026-08-13) — the
58
+ * HEAL: the mixed-convention consumer is now CANONICAL at the route (the
59
+ * accounting boundary), the same derivation the trace block carries.
60
+ *
61
+ * EXISTING-BEHAVIOR CHANGE — declared, never a silent side-fix:
62
+ * - openai-compat: `in` was the provider-raw TOTAL (fresh + cache); it is
63
+ * now the canonical FRESH count. The >100% cache-ratio disease: raw
64
+ * {input 111, cacheRead 1024} previously rendered "in 111" and the
65
+ * recap's cache % (then cache/in) read 923%; now "in 0" and the recap
66
+ * divides cache by the TOTAL (in + cache — T5) — never > 100%.
67
+ * - the miss estimate is numerically IDENTICAL on openai-compat: its old
68
+ * `in` WAS the total, and the carrier is the canonical total
69
+ * (input + cacheRead), which equals the raw total by construction.
70
+ * - anthropic: `in` was already fresh — unchanged; the miss estimate was
71
+ * min-of-fresh-deltas − cacheRead (always below the floor — silent);
72
+ * it is now min-of-totals, the semantics the openai-compat side always
73
+ * had (a fix, and it can fire).
74
+ * - the unknown-usage carrier: the old consumer's null carrier killed the
75
+ * miss signal forever; the canonical total of an unknown event is 0, so
76
+ * the signal recovers on the next known event.
77
+ * The route key mirrors the trace path's fallback by construction: an
78
+ * absent provider resolves like the tracer's "adapter" identity — the
79
+ * total convention (INPUT_CONVENTIONS), never a crash.
80
+ */
81
+ export function usageFromEvent(route, ev, prevTotal) {
82
+ const c = canonicalizeUsage(route ?? "adapter", ev);
83
+ const total = c.input + c.cacheRead + (c.cacheWrite ?? 0);
84
+ let missed = null;
85
+ // R-C item 4: min(prevTotal, total) is the part that could have been
86
+ // cached; what cacheRead did NOT cover is the miss. A below-floor or
87
+ // non-positive difference is noise — not surfaced.
88
+ if (prevTotal !== null) {
89
+ const m = Math.min(prevTotal, total) - c.cacheRead;
90
+ missed = m > CACHE_MISS_FLOOR ? m : null;
91
+ }
92
+ return { usage: { in: c.input, out: c.output, cache: c.cacheRead, known: ev.known }, total, missed };
93
+ }
50
94
  /** v2b: the spinner merged into the STATUS BAR (the v2a standalone glyph
51
95
  * is gone) — docked only, 200ms rotation between the request and the
52
96
  * first event. */
@@ -212,12 +256,7 @@ export async function consumeRun(session, run, input, turnNo, faux, statusCb,
212
256
  submitTurn) {
213
257
  let last;
214
258
  let usage = { in: null, out: null, cache: null, known: false };
215
- // R-C item 4: the per-turn cache miss — the overlap with the previous
216
- // prompt that SHOULD have been cached but was re-sent uncached:
217
- // missed = min(prevIn, in) − cacheRead. Below the 1024-token floor
218
- // (Anthropic's minimum cacheable block) it is noise — not surfaced.
219
- const CACHE_MISS_FLOOR = 1024;
220
- let prevIn = null;
259
+ let prevTotal = null;
221
260
  let missed = null;
222
261
  // v3 §02: the recap line derives ENTIRELY from the local event stream
223
262
  // (zero tokens) — wall seconds, tool/edit counts, usage, ctx left.
@@ -297,14 +336,10 @@ submitTurn) {
297
336
  body.textEnd();
298
337
  break;
299
338
  case "usage": {
300
- usage = { in: ev.inputTokens, out: ev.outputTokens, cache: ev.cacheRead, known: ev.known };
301
- // R-C item 4: min(prevIn, in) is the part that could have been
302
- // cached; what cacheRead did NOT cover is the miss.
303
- if (usage.in !== null && usage.cache !== null && prevIn !== null) {
304
- const m = Math.min(prevIn, usage.in) - usage.cache;
305
- missed = m > CACHE_MISS_FLOOR ? m : null;
306
- }
307
- prevIn = usage.in;
339
+ const delta = usageFromEvent(session.provider, ev, prevTotal);
340
+ usage = delta.usage;
341
+ prevTotal = delta.total;
342
+ missed = delta.missed;
308
343
  statusCb?.(usage, estimateCtxRatio(session));
309
344
  break;
310
345
  }
@@ -443,6 +478,23 @@ submitTurn) {
443
478
  export async function chat(session, faux, input, autoCompact) {
444
479
  let currentRun = null;
445
480
  let cancelled = false;
481
+ // E group (the graceful-exit gate ③, R-G 0.1.48): the terminal can
482
+ // close MID-run — the stream 'end' fires while currentRun is set, so
483
+ // the EOT callback defers. eotSeen remembers it; each run's end
484
+ // re-evaluates the exit condition (the safe point), so the release
485
+ // always runs.
486
+ let eotSeen = false;
487
+ /** The exit condition, shared by the EOT callback and the deferred
488
+ * re-check: no pending ask, an empty line. currentRun is checked by
489
+ * the callers (the callback when 'end' fires; the run-end re-checks
490
+ * run only after currentRun was nulled). */
491
+ const exitAtEmptyPrompt = () => {
492
+ if (pendingAsk !== null || input.line() !== "")
493
+ return;
494
+ cancelled = true;
495
+ console.log("\n[exit requested]");
496
+ input.close();
497
+ };
446
498
  const turn = (text) => new Promise((resolve, reject) => {
447
499
  queued = Math.max(0, queued - 1); // a queued turn starts
448
500
  const run = session.run(text);
@@ -471,6 +523,11 @@ export async function chat(session, faux, input, autoCompact) {
471
523
  // chat to main's finally/catch, never an orphaned
472
524
  // unhandled rejection from the IIFE.
473
525
  failOnFauxExhaustion(last, faux, input);
526
+ // E group (the graceful-exit gate ③): the fd may have closed
527
+ // mid-run — the run's end is the safe point for the deferred
528
+ // exit, so the release always runs.
529
+ if (eotSeen)
530
+ exitAtEmptyPrompt();
474
531
  // round 8: after EVERY turn the prompt is re-armed — the human
475
532
  // never types blind after the first turn.
476
533
  input.prompt();
@@ -517,11 +574,11 @@ export async function chat(session, faux, input, autoCompact) {
517
574
  }
518
575
  });
519
576
  input.onEot(() => {
520
- if (!currentRun && pendingAsk === null && input.line() === "") {
521
- cancelled = true;
522
- console.log("\n[exit requested]");
523
- input.close();
524
- }
577
+ // E group (the graceful-exit gate ③): the 'end' may fire MID-run
578
+ // the exit defers to the run's end (the re-checks below).
579
+ eotSeen = true;
580
+ if (!currentRun)
581
+ exitAtEmptyPrompt();
525
582
  });
526
583
  input.onEscape(() => {
527
584
  if (currentRun) {
@@ -662,6 +719,10 @@ export async function chat(session, faux, input, autoCompact) {
662
719
  const last = await consumeRun(session, recoveryRun, input, turnNo, faux, statusCb, submitTurn);
663
720
  currentRun = null;
664
721
  failOnFauxExhaustion(last, faux, input);
722
+ // E group (the graceful-exit gate ③): the same deferred re-check
723
+ // as the turn path — the recovery run's end is also a safe point.
724
+ if (eotSeen)
725
+ exitAtEmptyPrompt();
665
726
  maybeAutoCompact(); // the ergonomics batch C8: the recovery run ended too — same check (awaited by the exit re-await)
666
727
  }
667
728
  if (cancelled) {
package/dist/diff.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * v2e — the diff renderer: edit/write changes as inline ± lines, zero
3
+ * dependencies, no syntax highlighting (the spec's scope line). Shown at
4
+ * the approval moment ONLY — the frozen summary stays one line (v2d's
5
+ * anti-leak principle), /last has the full data.
6
+ *
7
+ * edit_file diffs IN PLACE (the search→replace windows are known — no
8
+ * general engine needed); write_file does a row-level LCS over the old
9
+ * file (small files are the target). Context: 2 rows each side. The
10
+ * RENDERER truncates (18 head + 18 tail + "… N lines"); the stats come
11
+ * from the full diff.
12
+ */
13
+ /** The diff block's per-row kind. */
14
+ export type DiffLine = {
15
+ kind: "-" | "+" | " ";
16
+ text: string;
17
+ };
18
+ export interface DiffResult {
19
+ /** The FULL diff (with context, not truncated) — the display truncates. */
20
+ lines: DiffLine[];
21
+ added: number;
22
+ removed: number;
23
+ }
24
+ /** The RENDERER's truncation: head + "… N lines (/last for full)" + tail. */
25
+ export declare function truncateDiff(diff: DiffLine[]): DiffLine[];
26
+ /** edit_file: the search→replace windows replace in place — the changed
27
+ * region is KNOWN, so the diff is the old window vs the new window,
28
+ * context from the surrounding file. */
29
+ export declare function editFileDiff(oldContent: string, search: string, replace: string): DiffResult;
30
+ /** write_file: a new file is all +; an existing file diffs row-level
31
+ * against its old content. */
32
+ export declare function writeFileDiff(oldContent: string | null, newContent: string): DiffResult;
package/dist/diff.js ADDED
@@ -0,0 +1,122 @@
1
+ /**
2
+ * v2e — the diff renderer: edit/write changes as inline ± lines, zero
3
+ * dependencies, no syntax highlighting (the spec's scope line). Shown at
4
+ * the approval moment ONLY — the frozen summary stays one line (v2d's
5
+ * anti-leak principle), /last has the full data.
6
+ *
7
+ * edit_file diffs IN PLACE (the search→replace windows are known — no
8
+ * general engine needed); write_file does a row-level LCS over the old
9
+ * file (small files are the target). Context: 2 rows each side. The
10
+ * RENDERER truncates (18 head + 18 tail + "… N lines"); the stats come
11
+ * from the full diff.
12
+ */
13
+ /** A line-level LCS diff — the classic two-row DP, ~small inputs. */
14
+ function lcsDiff(oldLines, newLines) {
15
+ const n = oldLines.length;
16
+ const m = newLines.length;
17
+ const dp = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
18
+ for (let i = n - 1; i >= 0; i -= 1) {
19
+ for (let j = m - 1; j >= 0; j -= 1) {
20
+ dp[i][j] = oldLines[i] === newLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
21
+ }
22
+ }
23
+ const out = [];
24
+ let i = 0;
25
+ let j = 0;
26
+ while (i < n && j < m) {
27
+ if (oldLines[i] === newLines[j]) {
28
+ out.push({ kind: " ", text: oldLines[i] });
29
+ i += 1;
30
+ j += 1;
31
+ }
32
+ else if (dp[i + 1][j] >= dp[i][j + 1]) {
33
+ out.push({ kind: "-", text: oldLines[i] });
34
+ i += 1;
35
+ }
36
+ else {
37
+ out.push({ kind: "+", text: newLines[j] });
38
+ j += 1;
39
+ }
40
+ }
41
+ while (i < n) {
42
+ out.push({ kind: "-", text: oldLines[i] });
43
+ i += 1;
44
+ }
45
+ while (j < m) {
46
+ out.push({ kind: "+", text: newLines[j] });
47
+ j += 1;
48
+ }
49
+ return out;
50
+ }
51
+ /** Keep 2 context rows around each change — the unified-style window. */
52
+ function withContext(diff) {
53
+ const out = [];
54
+ let lastAdded = -10;
55
+ for (let k = 0; k < diff.length; k += 1) {
56
+ if (diff[k].kind === " ")
57
+ continue;
58
+ const from = Math.max(0, k - 2);
59
+ const to = Math.min(diff.length - 1, k + 2);
60
+ for (let c = from; c <= to; c += 1) {
61
+ if (c > lastAdded) {
62
+ out.push(diff[c]);
63
+ lastAdded = c;
64
+ }
65
+ }
66
+ lastAdded = to;
67
+ }
68
+ return out;
69
+ }
70
+ const MAX_DIFF_LINES = 40; // the RENDERED cap
71
+ const TRUNCATE_KEEP = 18;
72
+ /** The RENDERER's truncation: head + "… N lines (/last for full)" + tail. */
73
+ export function truncateDiff(diff) {
74
+ if (diff.length <= MAX_DIFF_LINES)
75
+ return diff;
76
+ const omitted = diff.length - 2 * TRUNCATE_KEEP;
77
+ return [
78
+ ...diff.slice(0, TRUNCATE_KEEP),
79
+ { kind: " ", text: `… ${omitted} lines (/last for full)` },
80
+ ...diff.slice(diff.length - TRUNCATE_KEEP),
81
+ ];
82
+ }
83
+ function stats(diff) {
84
+ let added = 0;
85
+ let removed = 0;
86
+ for (const d of diff) {
87
+ if (d.kind === "+")
88
+ added += 1;
89
+ else if (d.kind === "-")
90
+ removed += 1;
91
+ }
92
+ return { added, removed };
93
+ }
94
+ /** edit_file: the search→replace windows replace in place — the changed
95
+ * region is KNOWN, so the diff is the old window vs the new window,
96
+ * context from the surrounding file. */
97
+ export function editFileDiff(oldContent, search, replace) {
98
+ const oldLines = oldContent.split("\n");
99
+ const searchLines = search.split("\n");
100
+ const replaceLines = replace.split("\n");
101
+ // Locate the search window (the first occurrence — the edit tool's own
102
+ // semantics); no occurrence → the whole file is the old side.
103
+ let at = -1;
104
+ for (let i = 0; i + searchLines.length <= oldLines.length; i += 1) {
105
+ if (oldLines.slice(i, i + searchLines.length).join("\n") === search) {
106
+ at = i;
107
+ break;
108
+ }
109
+ }
110
+ const lines = at < 0 ? withContext(lcsDiff(oldLines, replaceLines)) : withContext(lcsDiff(oldLines, [...oldLines.slice(0, at), ...replaceLines, ...oldLines.slice(at + searchLines.length)]));
111
+ return { lines, ...stats(lines) };
112
+ }
113
+ /** write_file: a new file is all +; an existing file diffs row-level
114
+ * against its old content. */
115
+ export function writeFileDiff(oldContent, newContent) {
116
+ if (oldContent === null) {
117
+ const lines = newContent.split("\n").map((text) => ({ kind: "+", text }));
118
+ return { lines, added: lines.length, removed: 0 };
119
+ }
120
+ const lines = withContext(lcsDiff(oldContent.split("\n"), newContent.split("\n")));
121
+ return { lines, ...stats(lines) };
122
+ }
@@ -3,7 +3,7 @@
3
3
  * turns. The bodies moved verbatim from chat()'s closure; chat provides
4
4
  * the context (the chain, the run state, the prompt arming).
5
5
  */
6
- import { type AgentSession } from "@vincemakes/kiso-runtime";
6
+ import type { AgentSession } from "@vincemakes/kiso-runtime";
7
7
  import { type LineInput } from "./state.js";
8
8
  /** Everything dispatch touches that chat() owns. */
9
9
  export interface DispatchCtx {
package/dist/dispatch.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * the context (the chain, the run state, the prompt arming).
5
5
  */
6
6
  import { escapeTerminal, kUnit, palette } from "@vincemakes/kiso-tui";
7
- import { buildAdapter } from "@vincemakes/kiso-runtime";
7
+ import { buildAdapter } from "@vincemakes/kiso-runtime/internal";
8
8
  import { MODES, getMode, setMode } from "./mode.js";
9
9
  import { agentModel, body, bodyLog, configModels, dock, setAgentModel, setCurrentModelName } from "./state.js";
10
10
  import { directWriteProfile, profileAvailable } from "./config.js";
package/dist/index.js CHANGED
@@ -395,6 +395,15 @@ async function makeAgent(sessionId, input, modelFlag) {
395
395
  return createAgent(definition);
396
396
  }
397
397
  async function main() {
398
+ // E group (the graceful-exit gate ③, R-G 0.1.48): a terminal closing
399
+ // turns the in-flight stdout/stderr writes into EIO, and node's
400
+ // unhandled 'error' event on the WriteStream kills the process —
401
+ // mid-exit the release never runs (the 60-byte residue the gate
402
+ // caught). The bytes are undeliverable anyway (the terminal is
403
+ // gone): the error must never abort the exit sequence. The listener
404
+ // swallows it — the standard "the stream may die under me" idiom.
405
+ process.stdout.on("error", () => { });
406
+ process.stderr.on("error", () => { });
398
407
  // Modes: --mode <name> wins over KISO_MODE — both applied before the
399
408
  // first makeAgent (the tier extensions read `current` live). The flag
400
409
  // is stripped from the positional args, so it works in any position.
@@ -493,7 +502,15 @@ async function main() {
493
502
  break;
494
503
  }
495
504
  case "sessions": {
496
- agent = await makeAgent(undefined, undefined, modelFlag);
505
+ // R-I-p2 audit (the argument-consistency mandate): the
506
+ // read-only listing NEVER writes through the input, but the
507
+ // trust gate lives inside makeAgent and ASKS through it — on
508
+ // a TTY with a first-discovery .kiso, the undefined input
509
+ // crashed identically to the bare command (finding R-I-p-2,
510
+ // "reading 'question'" on the dock-less branch). The input
511
+ // exists so the gate's ask can be answered; the listing
512
+ // itself never touches it.
513
+ agent = await makeAgent(undefined, input, modelFlag);
497
514
  for (const meta of agent.sessions()) {
498
515
  console.log(renderSessionLine(meta));
499
516
  }
@@ -516,7 +533,13 @@ async function main() {
516
533
  // chat — the first argument is the session id.
517
534
  const id = command ?? new Date().toISOString().replace(/[:.]/g, "-").slice(0, 16);
518
535
  dock.enter();
519
- agent = await makeAgent(id);
536
+ // R-I-p2 (finding R-I-p-2): the bare command passes the SAME
537
+ // input source and model flag as chat/resume — the pre-patch
538
+ // call dropped both, and the first-run trust gate read
539
+ // through the undefined input: "Cannot read properties of
540
+ // undefined" at the ask (panelAsk with the dock, question on
541
+ // the dock-less fallback).
542
+ agent = await makeAgent(id, input, modelFlag);
520
543
  const session = await agent.session({ id });
521
544
  bodyLog(`session ${id}\n`);
522
545
  extensionsBanner(recentSessions(id, agent));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.1.48",
3
+ "version": "0.2.0",
4
4
  "description": "kiso CLI — the coding-agent reference product: kiso chat / kiso resume / kiso sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -18,18 +18,18 @@
18
18
  "test": "vitest run"
19
19
  },
20
20
  "dependencies": {
21
- "@vincemakes/kiso-core": "0.1.35",
22
- "@vincemakes/kiso-evals": "0.1.36",
23
- "@vincemakes/kiso-mcp-ext": "0.1.48",
24
- "@vincemakes/kiso-provider-anthropic": "0.1.36",
25
- "@vincemakes/kiso-provider-openai": "0.1.36",
26
- "@vincemakes/kiso-runtime": "0.1.38",
27
- "@vincemakes/kiso-skills-ext": "0.1.48",
28
- "@vincemakes/kiso-subagent-ext": "0.1.48",
29
- "@vincemakes/kiso-task-ext": "0.1.48",
30
- "@vincemakes/kiso-tools-node": "0.1.36",
31
- "@vincemakes/kiso-tui": "0.1.42",
32
- "@vincemakes/kiso-tui-cells": "0.1.42"
21
+ "@vincemakes/kiso-core": "0.2.0",
22
+ "@vincemakes/kiso-evals": "0.2.0",
23
+ "@vincemakes/kiso-mcp-ext": "0.2.0",
24
+ "@vincemakes/kiso-provider-anthropic": "0.2.0",
25
+ "@vincemakes/kiso-provider-openai": "0.2.0",
26
+ "@vincemakes/kiso-runtime": "0.2.0",
27
+ "@vincemakes/kiso-skills-ext": "0.2.0",
28
+ "@vincemakes/kiso-subagent-ext": "0.2.0",
29
+ "@vincemakes/kiso-task-ext": "0.2.0",
30
+ "@vincemakes/kiso-tools-node": "0.2.0",
31
+ "@vincemakes/kiso-tui": "0.2.0",
32
+ "@vincemakes/kiso-tui-cells": "0.2.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^26.1.2",