@vincemakes/kiso-code 0.12.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.
package/dist/chat.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * estimates. All bodies moved verbatim from index.ts.
6
6
  */
7
7
  import { type RunUsage } from "@vincemakes/kiso-tui";
8
- import { type SaferOption } from "@vincemakes/kiso-tui";
8
+ import { type SaferFailure, type SaferOption } from "@vincemakes/kiso-tui";
9
9
  import type { AgentSession, Run } from "@vincemakes/kiso-runtime";
10
10
  import { type LineInput } from "./state.js";
11
11
  /**
@@ -82,6 +82,45 @@ export declare function usageFromEvent(route: string | undefined, ev: import("@v
82
82
  * first event. */
83
83
  export declare function startStatusSpinner(onTick: (glyph: string) => void): () => void;
84
84
  export declare function startShellTail(sessionId: string, callId: string, command: string, startedAt: number): () => void;
85
+ /**
86
+ * R3v2-F1: the format contract, stated FIRMLY. The first cut asked for
87
+ * "JSON ONLY" and left it there, which a verbose model reads as a
88
+ * preference — it wrote three sentences of preamble, opened a fence, and
89
+ * the cap ended the reply mid-string. Forbidding prose, naming the exact
90
+ * schema, and giving the nothing-is-safer case its own literal answer
91
+ * are all the same instruction: there is one thing to emit and no room
92
+ * to be helpful in the margins.
93
+ *
94
+ * The schema is an ENVELOPE rather than a bare array because a single
95
+ * top-level object leaves the model nowhere to put a preamble.
96
+ */
97
+ export declare const SAFER_SYSTEM_PROMPT: string;
98
+ /**
99
+ * R3v2-F1: the side query's output ceiling — raised from 500, which was
100
+ * the cap the live failures hit EXACTLY.
101
+ *
102
+ * The JSON-only reply the prompt now asks for is about 200 tokens for
103
+ * three alternatives, so this ceiling is a runaway guard and not a
104
+ * budget the answer is expected to approach: it exists so a model that
105
+ * ignores the contract and writes an essay still stops, not so the
106
+ * answer has room. Output is billed only when generated, and the query
107
+ * fires only on a press, so the raise costs nothing on the path that
108
+ * works and removes the one that could not.
109
+ */
110
+ export declare const SAFER_MAX_TOKENS = 1500;
111
+ /**
112
+ * R3v2-F1: WHY the ask failed, when the reply's own text can prove it.
113
+ *
114
+ * This side reports the cause and never the copy — the sentences live in
115
+ * the panel package, next to each other, so there is one place where the
116
+ * words are chosen and one place they can drift from.
117
+ *
118
+ * "Cut short" is a DIAGNOSIS, so it is only claimed when the text shows
119
+ * it: a reply that closed its JSON and then failed our SHAPE returns
120
+ * null and gets the unqualified line, because telling that human their
121
+ * reply was truncated would be a confident wrong answer.
122
+ */
123
+ export declare function saferFailure(text: string): SaferFailure | null;
85
124
  /**
86
125
  * Parse the model's answer DEFENSIVELY — anything unexpected is a
87
126
  * failure, and a failure degrades honestly.
@@ -95,6 +134,14 @@ export declare function startShellTail(sessionId: string, callId: string, comman
95
134
  *
96
135
  * A fenced code block is the one accommodation, because models emit it
97
136
  * constantly and it changes no content.
137
+ *
138
+ * R3v2-F1 widens that accommodation and NOTHING else. Unwrapping the
139
+ * named `alternatives` envelope, and reading `reason` as the spelling of
140
+ * `why` the prompt now asks for, are transport details: the entries that
141
+ * come out are verbatim the entries the model put in. That is the line
142
+ * between an accommodation and the salvage this parser refuses — a
143
+ * salvage changes WHICH alternatives are shown, and every rule that does
144
+ * that is still here. One bad entry still poisons the batch.
98
145
  */
99
146
  export declare function parseSaferOptions(text: string): SaferOption[] | null;
100
147
  /**
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";
@@ -191,12 +191,106 @@ function approvalDiff(name, input) {
191
191
  * refusal — the "(amended)" marker's source. Per process, cleared as
192
192
  * soon as it is shown: the marker describes ONE call, not a mode. */
193
193
  const amendedCalls = new Set();
194
- const SAFER_SYSTEM_PROMPT = [
194
+ /**
195
+ * R3v2-F1: the format contract, stated FIRMLY. The first cut asked for
196
+ * "JSON ONLY" and left it there, which a verbose model reads as a
197
+ * preference — it wrote three sentences of preamble, opened a fence, and
198
+ * the cap ended the reply mid-string. Forbidding prose, naming the exact
199
+ * schema, and giving the nothing-is-safer case its own literal answer
200
+ * are all the same instruction: there is one thing to emit and no room
201
+ * to be helpful in the margins.
202
+ *
203
+ * The schema is an ENVELOPE rather than a bare array because a single
204
+ * top-level object leaves the model nowhere to put a preamble.
205
+ */
206
+ export const SAFER_SYSTEM_PROMPT = [
195
207
  "You propose safer alternatives to a single shell/tool call a human is being asked to approve.",
196
- "Answer with JSON ONLY: an array of 2-3 objects, each {\"command\": string, \"why\": string}.",
197
- '"command" is the full replacement call. "why" is ONE short plain-language line saying what it does differently.',
198
- "Prefer alternatives that avoid irreversible deletion. If you cannot improve on it, answer [].",
208
+ "Reply with JSON ONLY no prose, no preamble, no code fence, nothing before or after the JSON.",
209
+ 'The exact schema is {"alternatives":[{"command":"...","reason":"..."}]}, with 2-3 entries.',
210
+ '"command" is the full replacement call. "reason" is ONE line of plain language saying what it does differently.',
211
+ 'Prefer alternatives that avoid irreversible deletion. If you cannot improve on it, reply {"alternatives":[]}.',
199
212
  ].join(" ");
213
+ /**
214
+ * R3v2-F1: the side query's output ceiling — raised from 500, which was
215
+ * the cap the live failures hit EXACTLY.
216
+ *
217
+ * The JSON-only reply the prompt now asks for is about 200 tokens for
218
+ * three alternatives, so this ceiling is a runaway guard and not a
219
+ * budget the answer is expected to approach: it exists so a model that
220
+ * ignores the contract and writes an essay still stops, not so the
221
+ * answer has room. Output is billed only when generated, and the query
222
+ * fires only on a press, so the raise costs nothing on the path that
223
+ * works and removes the one that could not.
224
+ */
225
+ export const SAFER_MAX_TOKENS = 1500;
226
+ /**
227
+ * R3v2-F1: WHY the ask failed, when the reply's own text can prove it.
228
+ *
229
+ * This side reports the cause and never the copy — the sentences live in
230
+ * the panel package, next to each other, so there is one place where the
231
+ * words are chosen and one place they can drift from.
232
+ *
233
+ * "Cut short" is a DIAGNOSIS, so it is only claimed when the text shows
234
+ * it: a reply that closed its JSON and then failed our SHAPE returns
235
+ * null and gets the unqualified line, because telling that human their
236
+ * reply was truncated would be a confident wrong answer.
237
+ */
238
+ export function saferFailure(text) {
239
+ return jsonBody(text) === "truncated" ? { reason: "truncated" } : null;
240
+ }
241
+ /**
242
+ * R3v2-F1: find the reply's JSON body by BALANCING brackets rather than
243
+ * by first-and-last.
244
+ *
245
+ * `indexOf("[")` / `lastIndexOf("]")` had two failure modes a verbose
246
+ * model hits constantly: a bracket in the trailing prose moved the end
247
+ * past the array, and a reply the cap cut in half had no end at all.
248
+ * Both returned null, and null could not say which — which is why the
249
+ * degradation line could not either.
250
+ *
251
+ * Returns the balanced slice, `"truncated"` when a value opens and the
252
+ * text ends before it closes, or null when there is no JSON value at
253
+ * all.
254
+ */
255
+ function jsonBody(text) {
256
+ // a CLOSED fence is content-preserving to strip. An OPEN one means
257
+ // the reply ended inside the block — drop the opener and let the scan
258
+ // below reach the same verdict from the content.
259
+ const closed = text.match(/```(?:json)?\s*([\s\S]*?)```/);
260
+ const body = closed?.[1] ?? text.replace(/^[\s\S]*?```(?:json)?[ \t]*\r?\n/, "");
261
+ const start = body.search(/[[{]/);
262
+ if (start < 0)
263
+ return null;
264
+ let depth = 0;
265
+ let inString = false;
266
+ let escaped = false;
267
+ for (let i = start; i < body.length; i += 1) {
268
+ const c = body[i];
269
+ if (escaped) {
270
+ escaped = false;
271
+ }
272
+ else if (inString) {
273
+ if (c === "\\")
274
+ escaped = true;
275
+ else if (c === '"')
276
+ inString = false;
277
+ }
278
+ else if (c === '"') {
279
+ inString = true;
280
+ }
281
+ else if (c === "[" || c === "{") {
282
+ depth += 1;
283
+ }
284
+ else if (c === "]" || c === "}") {
285
+ depth -= 1;
286
+ if (depth === 0)
287
+ return body.slice(start, i + 1);
288
+ if (depth < 0)
289
+ return null;
290
+ }
291
+ }
292
+ return "truncated";
293
+ }
200
294
  /**
201
295
  * Parse the model's answer DEFENSIVELY — anything unexpected is a
202
296
  * failure, and a failure degrades honestly.
@@ -210,34 +304,59 @@ const SAFER_SYSTEM_PROMPT = [
210
304
  *
211
305
  * A fenced code block is the one accommodation, because models emit it
212
306
  * constantly and it changes no content.
307
+ *
308
+ * R3v2-F1 widens that accommodation and NOTHING else. Unwrapping the
309
+ * named `alternatives` envelope, and reading `reason` as the spelling of
310
+ * `why` the prompt now asks for, are transport details: the entries that
311
+ * come out are verbatim the entries the model put in. That is the line
312
+ * between an accommodation and the salvage this parser refuses — a
313
+ * salvage changes WHICH alternatives are shown, and every rule that does
314
+ * that is still here. One bad entry still poisons the batch.
213
315
  */
214
316
  export function parseSaferOptions(text) {
215
- const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
216
- const body = (fenced?.[1] ?? text).trim();
217
- const start = body.indexOf("[");
218
- const end = body.lastIndexOf("]");
219
- if (start < 0 || end <= start)
317
+ const body = jsonBody(text);
318
+ // truncation and absence part ways in saferFailureNote(), which reads
319
+ // the same scan; for the list itself both are the same nothing.
320
+ if (body === null || body === "truncated")
220
321
  return null;
221
322
  let parsed;
222
323
  try {
223
- parsed = JSON.parse(body.slice(start, end + 1));
324
+ parsed = JSON.parse(body);
224
325
  }
225
326
  catch {
226
327
  return null;
227
328
  }
228
- if (!Array.isArray(parsed) || parsed.length === 0)
329
+ const envelope = typeof parsed === "object" && parsed !== null ? parsed.alternatives : undefined;
330
+ const list = Array.isArray(parsed) ? parsed : Array.isArray(envelope) ? envelope : null;
331
+ if (list === null || list.length === 0)
229
332
  return null;
230
333
  const out = [];
231
- for (const item of parsed.slice(0, 3)) {
334
+ for (const item of list.slice(0, 3)) {
232
335
  if (typeof item !== "object" || item === null)
233
336
  return null;
234
- const { command, why } = item;
337
+ const { command, reason, why } = item;
235
338
  if (typeof command !== "string" || command.trim() === "")
236
339
  return null;
237
- out.push({ command: command.trim(), why: typeof why === "string" ? why.trim() : "" });
340
+ const line = typeof reason === "string" ? reason : typeof why === "string" ? why : "";
341
+ out.push({ command: command.trim(), why: line.trim() });
238
342
  }
239
343
  return out.length === 0 ? null : out;
240
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
+ }
241
360
  /** W21 — the panel view for a permission_requested: the rule line (the
242
361
  * why-asked speaker + the §3.5 fix hint), the toolTarget title, the
243
362
  * "▸ run paused" status, and the ALWAYS-verbose args. */
@@ -406,6 +525,15 @@ submitTurn) {
406
525
  // construction (ADR-0040).
407
526
  switch (ev.type) {
408
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
+ }
409
537
  body.userLine(typeof ev.content === "string" ? ev.content : "");
410
538
  break;
411
539
  case "thinking":
@@ -512,9 +640,13 @@ submitTurn) {
512
640
  purpose: "safer-options",
513
641
  systemPrompt: SAFER_SYSTEM_PROMPT,
514
642
  prompt: `the pending call is: ${name} ${JSON.stringify(ev.input ?? {})}`,
515
- maxTokens: 500,
643
+ maxTokens: SAFER_MAX_TOKENS,
516
644
  });
517
- return parseSaferOptions(answer);
645
+ // R3v2-F1: a failure reports its CAUSE when the reply can
646
+ // prove one, so the panel can say which failure this was.
647
+ // saferFailure() returns null for every cause we cannot
648
+ // demonstrate, which is the unqualified line — unchanged.
649
+ return parseSaferOptions(answer) ?? saferFailure(answer);
518
650
  };
519
651
  const verdict = await askPanel(input, approvalView(name, ev, amendedCalls.has(name)), { safer });
520
652
  amendedCalls.delete(name);
@@ -579,6 +711,19 @@ submitTurn) {
579
711
  // events (zero tokens). The dock's status bar still paints.
580
712
  statusCb?.(usage, estimateCtxRatio(session));
581
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
+ }
582
727
  // W14: the turn record closes HERE — before the recap logs, so
583
728
  // the commit loop folds the quiet turn's held cells first (the
584
729
  // fold line lands above the recap, natural cell order).
@@ -651,9 +796,9 @@ export async function chat(session, faux, input, autoCompact) {
651
796
  console.log("\n[exit requested]");
652
797
  input.close();
653
798
  };
654
- const turn = (text) => new Promise((resolve, reject) => {
799
+ const turn = (text, seedSource) => new Promise((resolve, reject) => {
655
800
  queued = Math.max(0, queued - 1); // a queued turn starts
656
- const run = session.run(text);
801
+ const run = seedSource !== undefined ? session.run(text, { source: seedSource }) : session.run(text);
657
802
  currentRun = run;
658
803
  turnNo += 1;
659
804
  const myTurn = turnNo;
@@ -684,6 +829,41 @@ export async function chat(session, faux, input, autoCompact) {
684
829
  // exit, so the release always runs.
685
830
  if (eotSeen)
686
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
+ }
687
867
  // round 8: after EVERY turn the prompt is re-armed — the human
688
868
  // never types blind after the first turn.
689
869
  input.prompt();
@@ -788,6 +968,14 @@ export async function chat(session, faux, input, autoCompact) {
788
968
  // A slot leaves the queue when its turn STARTS or when the user
789
969
  // pops it (cancelled — the chain segment skips it).
790
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.";
791
979
  // v2b: the live status bar (docked only). Modes: /mode switches repaint
792
980
  // it immediately through paintStatus (the last turn stats are kept).
793
981
  // v3 §03: the status bar has TWO states. Idle: the mode is ALWAYS
package/dist/state.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * creates the mutable ones (setBody / setAgentModel / setExtensionLists);
6
6
  * the moved modules read and mutate at call time.
7
7
  */
8
- import { Dock, type AtItem, type Body, type PanelVerdict, type PanelView, type SaferOption, type SessionCardView } from "@vincemakes/kiso-tui";
8
+ import { Dock, type AtItem, type Body, type PanelVerdict, type PanelView, type SaferAnswer, type SessionCardView } from "@vincemakes/kiso-tui";
9
9
  import type { KisoExtension, StoreRecord } from "@vincemakes/kiso-runtime";
10
10
  /** finding #11: KISO_HOME is the ONE root — every default path derives from
11
11
  * it (sessions, trust, extensions, mcp config, skills). The dedicated
@@ -82,9 +82,11 @@ export interface LineInput {
82
82
  * the tab-amend), the compositor renders the block + the leads. */
83
83
  /** TUI2-R3v2 ③: `opts.safer` is the on-demand alternatives provider —
84
84
  * absent for every panel that has no such option (the ask, the pick,
85
- * the trust gate), so those buttons cannot exist to be pressed. */
85
+ * the trust gate), so those buttons cannot exist to be pressed.
86
+ * R3v2-F1: it resolves a SaferAnswer, so a failure that can name its
87
+ * cause does — `null` still means a failure with nothing to add. */
86
88
  panelAsk(view: PanelView, onCommit: (v: PanelVerdict) => void, opts?: {
87
- safer?: () => Promise<readonly SaferOption[] | null>;
89
+ safer?: () => Promise<SaferAnswer>;
88
90
  }): void;
89
91
  /** W21: cancel the panel — the SIGINT pair to panelAsk. */
90
92
  panelCancel(): void;
@@ -5,7 +5,7 @@
5
5
  * chat.ts), the don't-ask-again rule writer, and the uncertain-execution
6
6
  * decisions. All bodies moved verbatim from index.ts.
7
7
  */
8
- import { type PanelVerdict, type PanelView, type SaferOption } from "@vincemakes/kiso-tui";
8
+ import { type PanelVerdict, type PanelView, type SaferAnswer } from "@vincemakes/kiso-tui";
9
9
  import type { AskUI } from "@vincemakes/kiso-ask-ext";
10
10
  import { type ProjectArtifacts } from "@vincemakes/kiso-runtime";
11
11
  import type { AgentSession } from "@vincemakes/kiso-runtime";
@@ -35,7 +35,7 @@ import { type LineInput } from "./state.js";
35
35
  */
36
36
  export declare let pendingAsk: (() => void) | null;
37
37
  export declare function askPanel(input: LineInput, view: PanelView, opts?: {
38
- safer?: () => Promise<readonly SaferOption[] | null>;
38
+ safer?: () => Promise<SaferAnswer>;
39
39
  }): Promise<PanelVerdict>;
40
40
  /**
41
41
  * KC3.5 — the AskUI bridge: the panel the ask extension asks through.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.12.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.12.0",
22
- "@vincemakes/kiso-core": "0.12.0",
23
- "@vincemakes/kiso-evals": "0.12.0",
24
- "@vincemakes/kiso-mcp-ext": "0.12.0",
25
- "@vincemakes/kiso-provider-anthropic": "0.12.0",
26
- "@vincemakes/kiso-provider-openai": "0.12.0",
27
- "@vincemakes/kiso-runtime": "0.12.0",
28
- "@vincemakes/kiso-skills-ext": "0.12.0",
29
- "@vincemakes/kiso-subagent-ext": "0.12.0",
30
- "@vincemakes/kiso-task-ext": "0.12.0",
31
- "@vincemakes/kiso-tools-node": "0.12.0",
32
- "@vincemakes/kiso-tui": "0.12.0",
33
- "@vincemakes/kiso-tui-cells": "0.12.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",