@vincemakes/kiso-code 0.52.0 → 0.53.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 +2 -0
- package/dist/chat.js +13 -0
- package/dist/dispatch.d.ts +6 -1
- package/dist/dispatch.js +65 -2
- package/dist/index.js +30 -3
- package/dist/replay.d.ts +1 -1
- package/dist/replay.js +4 -1
- package/dist/state.d.ts +4 -1
- package/package.json +14 -14
package/dist/chat.d.ts
CHANGED
|
@@ -411,5 +411,7 @@ export interface ChatNav {
|
|
|
411
411
|
/** 0.40.0: an id outside this project's folder — refused, or opened where it is */
|
|
412
412
|
readonly route?: (id: string) => SessionRoute | null;
|
|
413
413
|
readonly pick?: () => Promise<string | null>;
|
|
414
|
+
/** the session's first message was sent: the caller may title the session from it (Session.title) */
|
|
415
|
+
readonly titled?: (firstMessage: string) => void;
|
|
414
416
|
}
|
|
415
417
|
export declare function chat(session: AgentSession, faux: boolean, input: LineInput, autoCompact?: AutoCompact, nav?: ChatNav, seed?: readonly string[]): Promise<ChatEnd>;
|
package/dist/chat.js
CHANGED
|
@@ -1386,7 +1386,11 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
|
|
|
1386
1386
|
// 0.40.0: a skill turn is not scanned either — its text is a
|
|
1387
1387
|
// SKILL.md body, and a body that mentions `diagram.png` must not
|
|
1388
1388
|
// attach a file from the workspace the person never pointed at.
|
|
1389
|
+
input.setGhost?.(null); // a new turn: the last run's follow-up no longer applies
|
|
1389
1390
|
const content = via !== undefined ? text : attachImages(text, input.attachments?.(), protectedFiles());
|
|
1391
|
+
// the person's first message of the session: a title is made from it beside the run, never in its way
|
|
1392
|
+
if (via === undefined && !session.log.all.some((e) => e.type === "user_input"))
|
|
1393
|
+
nav?.titled?.(text);
|
|
1390
1394
|
// ADR-0058: a task notice is the runtime's input — source "system"
|
|
1391
1395
|
const run = via !== undefined ? session.run(content, { via, ...(via.kind === "tasks" ? { source: "system" } : {}) }) : session.run(content);
|
|
1392
1396
|
currentRun = run;
|
|
@@ -1435,6 +1439,15 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
|
|
|
1435
1439
|
// round 8: after EVERY turn the prompt is re-armed — the human
|
|
1436
1440
|
// never types blind after the first turn.
|
|
1437
1441
|
input.prompt();
|
|
1442
|
+
// the follow-up (owner 2026-11-03): after a run that ended well, the line the person may send next,
|
|
1443
|
+
// asked of the session's own model with the run's own prefix (Session.followUp); shown dim in the
|
|
1444
|
+
// empty box only while no other turn has started or waits; off with the faux model and KISO_FOLLOWUP=off
|
|
1445
|
+
if (last?.type === "terminal" && last.outcome.kind === "completed" && !faux && input.setGhost !== undefined && process.env["KISO_FOLLOWUP"] !== "off" && queued === 0) {
|
|
1446
|
+
void session.followUp({ maxTokens: 200, signal: AbortSignal.timeout(15_000) }).then((line) => {
|
|
1447
|
+
if (turnNo === myTurn && currentRun === null && queued === 0)
|
|
1448
|
+
input.setGhost?.(line === "" ? null : line);
|
|
1449
|
+
}, () => undefined);
|
|
1450
|
+
}
|
|
1438
1451
|
// the ergonomics batch C8: the opt-in auto-compact — checked AFTER the
|
|
1439
1452
|
// turn ended (the run's terminal is in the log, the ratio
|
|
1440
1453
|
// is post-run).
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* the context (the chain, the run state, the prompt arming).
|
|
5
5
|
*/
|
|
6
6
|
import type { SessionRoute } from "./projects.js";
|
|
7
|
-
import type
|
|
7
|
+
import { type StoreRecord } from "@vincemakes/kiso-runtime/internal";
|
|
8
|
+
import { type AgentSession } from "@vincemakes/kiso-runtime";
|
|
9
|
+
import type { SessionCardView } from "@vincemakes/kiso-tui";
|
|
8
10
|
import { type LineInput } from "./state.js";
|
|
9
11
|
import type { UserInputVia } from "@vincemakes/kiso-core";
|
|
10
12
|
/** Everything dispatch touches that chat() owns. */
|
|
@@ -72,3 +74,6 @@ export declare function parseBang(trimmed: string): {
|
|
|
72
74
|
export declare function markCompactWhy(why: string): void;
|
|
73
75
|
export declare function markAutoCompact(): void;
|
|
74
76
|
export declare function dispatch(line: string, ctx: DispatchCtx): void;
|
|
77
|
+
/** /fork's rows: each finished run's reply, newest first, by its first line and when it ended; the opened row says the
|
|
78
|
+
* line it answered. The card's id is the seq of the run's terminal, where SessionStore.fork cuts. */
|
|
79
|
+
export declare function replyCards(records: readonly StoreRecord[]): SessionCardView[];
|
package/dist/dispatch.js
CHANGED
|
@@ -5,11 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { STATUS_GLYPHS, contextRows, contextSheetRows, contextUnavailableRows, contextUnavailableSheetRows, displayVerb, escapeTerminal, helpRows, toolTarget, infoSheetRows, kUnit, modePickView, modelPickView, namedPickView, settingsPickView, compactingStatus, liveRow, palette, renderEvent, settledLabel, slashCommandNames } from "@vincemakes/kiso-tui";
|
|
7
7
|
import { newSessionId } from "./session-id.js";
|
|
8
|
-
import { buildAdapter, lookupModelMetadata, readSessionName, resolveContinuationScope, resolveReasoning, sessionTitle, tiersFor, writeSessionName } from "@vincemakes/kiso-runtime/internal";
|
|
8
|
+
import { buildAdapter, isForkNote, lookupModelMetadata, readSessionName, resolveContinuationScope, resolveReasoning, sessionTitle, tiersFor, writeSessionName } from "@vincemakes/kiso-runtime/internal";
|
|
9
|
+
import { ForkRefusedError, SessionStore } from "@vincemakes/kiso-runtime";
|
|
9
10
|
import { MODE_LABEL, MODE_NOTE, OFFERED_MODES, applyModeSetting, getDontAsk, getMode, modeDisplay, parseMode, setDontAsk } from "./mode.js";
|
|
10
11
|
import { clipboardWrite, lastAnswer } from "./clipboard.js";
|
|
11
12
|
import { protectedBangReason, protectedShellVerdict } from "./protected-shell.js";
|
|
12
|
-
import { activeStoreDir, agentBaseUrl, currentProfileName, setCurrentProfileName, currentModelName, agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, upstreamOf, VERSION, setLastBinding } from "./state.js";
|
|
13
|
+
import { activeStoreDir, sessionStoreRef, agentBaseUrl, currentProfileName, setCurrentProfileName, currentModelName, agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, upstreamOf, VERSION, setLastBinding } from "./state.js";
|
|
13
14
|
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
14
15
|
import { profileProviderLabel, providerLabel } from "./provider-label.js";
|
|
15
16
|
import { installedVersion, versionStatusLine } from "./stale-version.js";
|
|
@@ -1384,6 +1385,44 @@ export function dispatch(line, ctx) {
|
|
|
1384
1385
|
ctx.requestReload();
|
|
1385
1386
|
return;
|
|
1386
1387
|
}
|
|
1388
|
+
if (trimmed === "/fork") {
|
|
1389
|
+
// owner 2026-11-03: the web app's fork, one rule — a new session from after one of this session's replies
|
|
1390
|
+
// (SessionStore.fork), then the terminal switches to it as /resume does; the replies are picked in /resume's band
|
|
1391
|
+
if (ctx.isRunning()) {
|
|
1392
|
+
body.notice("[/fork] a run is in flight — let it finish (esc stops it), then fork");
|
|
1393
|
+
ctx.input.prompt();
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
ctx.chainRef.current = ctx.chainRef.current.then(async () => {
|
|
1397
|
+
const cards = replyCards(sessionStoreRef?.load(ctx.session.id) ?? []);
|
|
1398
|
+
if (cards.length === 0) {
|
|
1399
|
+
body.notice("no finished reply to fork after yet");
|
|
1400
|
+
ctx.input.prompt();
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
const fork = (afterSeq) => {
|
|
1404
|
+
try {
|
|
1405
|
+
const made = new SessionStore(activeStoreDir).fork(ctx.session.id, { afterSeq });
|
|
1406
|
+
body.notice(`forked "${escapeTerminal(readSessionName(activeStoreDir, made.id) ?? made.id)}" — switching to it`);
|
|
1407
|
+
ctx.requestSwitch(made.id);
|
|
1408
|
+
}
|
|
1409
|
+
catch (error) {
|
|
1410
|
+
body.notice(error instanceof ForkRefusedError ? `[/fork] ${error.message}` : `[/fork] ${error instanceof Error ? error.message : String(error)}`);
|
|
1411
|
+
ctx.input.prompt();
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
// no band (a pipe, a dock-less terminal): after the last reply, the sidebar's Fork
|
|
1415
|
+
if (ctx.input.pick === undefined || !dock.active)
|
|
1416
|
+
return fork(Number(cards[0].id));
|
|
1417
|
+
ctx.input.pick(() => cards, (picked) => {
|
|
1418
|
+
if (picked === null)
|
|
1419
|
+
ctx.input.prompt(); // esc: nothing forked, nothing said
|
|
1420
|
+
else
|
|
1421
|
+
fork(Number(picked));
|
|
1422
|
+
}, undefined, "fork");
|
|
1423
|
+
});
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1387
1426
|
if (trimmed === "/resume" || trimmed.startsWith("/resume ")) {
|
|
1388
1427
|
// the mini-spec: the in-session door to the durable sessions —
|
|
1389
1428
|
// /resume <id> switches directly; bare /resume opens the SAME
|
|
@@ -1589,3 +1628,27 @@ async function tasksCommand(arg, ctx) {
|
|
|
1589
1628
|
else if (action === 1)
|
|
1590
1629
|
stop(task);
|
|
1591
1630
|
}
|
|
1631
|
+
/** /fork's rows: each finished run's reply, newest first, by its first line and when it ended; the opened row says the
|
|
1632
|
+
* line it answered. The card's id is the seq of the run's terminal, where SessionStore.fork cuts. */
|
|
1633
|
+
export function replyCards(records) {
|
|
1634
|
+
const cards = [];
|
|
1635
|
+
let asked = "";
|
|
1636
|
+
let reply = "";
|
|
1637
|
+
for (const { event: e, ts } of records) {
|
|
1638
|
+
if (e.type === "user_input" && e.source !== "system") {
|
|
1639
|
+
const content = Array.isArray(e.content) ? e.content.filter((b) => !(b.type === "text" && isForkNote(b.text ?? ""))) : e.content;
|
|
1640
|
+
asked = (typeof content === "string" ? content : content.map((b) => (b.type === "text" ? (b.text ?? "") : "")).join(" ")).trim();
|
|
1641
|
+
reply = "";
|
|
1642
|
+
}
|
|
1643
|
+
else if (e.type === "tool_result")
|
|
1644
|
+
reply = "";
|
|
1645
|
+
else if (e.type === "text_delta")
|
|
1646
|
+
reply += e.text;
|
|
1647
|
+
else if (e.type === "terminal" && e.outcome.kind === "completed") {
|
|
1648
|
+
// the row is how the person recognizes the reply: its first line, inline code read as plain text
|
|
1649
|
+
const first = (reply.split("\n").map((l) => l.trim()).find((l) => l !== "") ?? "(no reply text)").replace(/`([^`]*)`/g, "$1");
|
|
1650
|
+
cards.unshift({ id: String(e.seq), title: first, badge: "completed", turns: null, updatedAt: ts, uncertain: 0, asks: 0, outcome: null, detail: `answered: ${asked.split("\n")[0] ?? ""}` });
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
return cards;
|
|
1654
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,7 @@ import { createRequire } from "node:module";
|
|
|
33
33
|
import { basename, dirname, join } from "node:path";
|
|
34
34
|
import { Body, Editor, PROMPT, bannerLines, currentGround, currentGroundRgb, parseOscColor, resolveGround, setGround, escapeTerminal, extensionsBannerText, extensionsFact, idColumn, interactivePrompt, palette, renderSessionLine, sessionListFooter, sessionListHeader, sessionListRow, sessionListUnknownLine, slashCommandNames } from "@vincemakes/kiso-tui";
|
|
35
35
|
import { disposeExtensions, SessionStore } from "@vincemakes/kiso-runtime";
|
|
36
|
-
import { listSessionSidecars, migrateSummaries, readProfile, readSessionName, summaryMigrationPending } from "@vincemakes/kiso-runtime/internal";
|
|
36
|
+
import { listSessionSidecars, migrateSummaries, readProfile, readSessionName, summaryMigrationPending, writeSessionName } from "@vincemakes/kiso-runtime/internal";
|
|
37
37
|
import { skillMenuItems } from "./skill-invoke.js";
|
|
38
38
|
import { canonicalPath, hasSession, locateSession, projectLayoutActive, sessionFolders } from "./projects.js";
|
|
39
39
|
import { reverseMigration } from "./session-migration.js";
|
|
@@ -332,8 +332,8 @@ function editorInput(editor) {
|
|
|
332
332
|
// TUI2-R2 ②: the session picker — the editor owns the keys (the
|
|
333
333
|
// selection walk, the filter, enter/esc), the compositor draws the
|
|
334
334
|
// band, and the id comes back here.
|
|
335
|
-
pick(cards, onPick, here) {
|
|
336
|
-
editor.beginPick(cards, onPick, here);
|
|
335
|
+
pick(cards, onPick, here, kind) {
|
|
336
|
+
editor.beginPick(cards, onPick, here, kind);
|
|
337
337
|
},
|
|
338
338
|
// W22: the pending-turn queue — the ↑ pop walk (the keys); the
|
|
339
339
|
// chips are the compositor's bindQueue (the dock side).
|
|
@@ -341,6 +341,9 @@ function editorInput(editor) {
|
|
|
341
341
|
editor.bindQueue(state, pop);
|
|
342
342
|
},
|
|
343
343
|
// ADR-0057: the steers a stop handed back return to the buffer.
|
|
344
|
+
setGhost(text) {
|
|
345
|
+
editor.setGhost(text);
|
|
346
|
+
},
|
|
344
347
|
restore(text) {
|
|
345
348
|
editor.restore(text);
|
|
346
349
|
},
|
|
@@ -1158,6 +1161,30 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1158
1161
|
sessions: () => agent.sessionIds(),
|
|
1159
1162
|
route: (sessionId) => routeSession(sessionId),
|
|
1160
1163
|
...(process.stdin.isTTY ? { pick: () => pickSession(agent, input) } : {}),
|
|
1164
|
+
// owner 2026-11-03: a session is titled by a summary of its first message, in the background; the person's own
|
|
1165
|
+
// name wins, before or after; off with KISO_AUTO_TITLE=off and with the faux model, and never without a TTY:
|
|
1166
|
+
// a piped chat is a script or a bench leg, where one more request per session is not the person's
|
|
1167
|
+
...(currentFaux || process.env["KISO_AUTO_TITLE"] === "off" || process.stdin.isTTY !== true
|
|
1168
|
+
? {}
|
|
1169
|
+
: {
|
|
1170
|
+
titled: (firstMessage) => {
|
|
1171
|
+
// the session and its folder as they are NOW: a /resume or a switch before the title lands must not
|
|
1172
|
+
// send it to another session, nor repaint another session's window title
|
|
1173
|
+
const [titling, mine, dir] = [session, session.id, activeStoreDir];
|
|
1174
|
+
if (readSessionName(dir, mine) !== null)
|
|
1175
|
+
return;
|
|
1176
|
+
void titling.title(firstMessage, { signal: AbortSignal.timeout(15_000) }).then((title) => {
|
|
1177
|
+
if (title === "" || readSessionName(dir, mine) !== null)
|
|
1178
|
+
return;
|
|
1179
|
+
writeSessionName(dir, mine, title);
|
|
1180
|
+
// `id` is the loop's: the session open now (a switch moves it on)
|
|
1181
|
+
if (id !== mine)
|
|
1182
|
+
return;
|
|
1183
|
+
setTitleName(title);
|
|
1184
|
+
paintWindowTitle();
|
|
1185
|
+
}, () => undefined);
|
|
1186
|
+
},
|
|
1187
|
+
}),
|
|
1161
1188
|
};
|
|
1162
1189
|
const end = await chat(session, currentFaux, input, autoCompact, nav, seed);
|
|
1163
1190
|
if (end.next === "exit") {
|
package/dist/replay.d.ts
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* summary (what the model sees next) and the turns it covers, read in
|
|
20
20
|
* the viewer — then any uncovered earlier turns folded as above.
|
|
21
21
|
*/
|
|
22
|
-
import type
|
|
22
|
+
import { type TaskInfo } from "@vincemakes/kiso-runtime/internal";
|
|
23
23
|
import type { NoticeMark } from "@vincemakes/kiso-tui";
|
|
24
24
|
/** The Body surface the replay drives — the live run's own mutations. */
|
|
25
25
|
export interface ReplayBody {
|
package/dist/replay.js
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
import { echoText } from "@vincemakes/kiso-tui-cells/render";
|
|
23
23
|
import { bandHeader } from "@vincemakes/kiso-tui-cells/strings";
|
|
24
24
|
import { cappedWaitLine, taskNoticeLines, taskNoticeRows, taskWhat } from "./task-notice.js";
|
|
25
|
+
import { isForkNote } from "@vincemakes/kiso-runtime/internal";
|
|
25
26
|
/** How many turns stay on screen in full. */
|
|
26
27
|
const FULL_TURNS = 2;
|
|
27
28
|
/** A user turn's opening line, or null when this input does not open one
|
|
@@ -32,7 +33,9 @@ function askOf(e) {
|
|
|
32
33
|
if (e.type !== "user_input" || e.source === "system")
|
|
33
34
|
return null;
|
|
34
35
|
const via = e.via;
|
|
35
|
-
|
|
36
|
+
// a fork's first input carries the fork note before the person's words: the model's, not the line they typed
|
|
37
|
+
const content = Array.isArray(e.content) ? e.content.filter((b) => !(b.type === "text" && isForkNote(b.text ?? ""))) : e.content;
|
|
38
|
+
const text = typeof via?.line === "string" ? via.line : echoText(content);
|
|
36
39
|
return text.trim() === "" ? null : text;
|
|
37
40
|
}
|
|
38
41
|
/** Split events into turns: each starts at a user turn's input; anything
|
package/dist/state.d.ts
CHANGED
|
@@ -241,7 +241,7 @@ export interface LineInput {
|
|
|
241
241
|
* picked id, or null when the human leaves without picking.
|
|
242
242
|
* OPTIONAL: only the raw-mode editor has it, and the picker only
|
|
243
243
|
* ever opens on a TTY (a pipe has nobody to pick). */
|
|
244
|
-
pick?(cards: () => readonly SessionCardView[], onPick: (id: string | null) => void, here?: string): void;
|
|
244
|
+
pick?(cards: () => readonly SessionCardView[], onPick: (id: string | null) => void, here?: string, kind?: "resume" | "fork"): void;
|
|
245
245
|
/** W22: bind the pending-turn queue — the ↑ pop walks the CLI's
|
|
246
246
|
* live slots (each pop cancels the turn), esc ends the walk after
|
|
247
247
|
* one more pop. The chips are the compositor's own bindQueue. */
|
|
@@ -249,6 +249,9 @@ export interface LineInput {
|
|
|
249
249
|
/** ADR-0057: put text back into the editor — the steers a stop handed
|
|
250
250
|
* back before they landed. The pipe path has no editor; optional. */
|
|
251
251
|
restore?(text: string): void;
|
|
252
|
+
/** The follow-up: a line the person may send next, dim in the empty box, Tab takes it; null clears it. Optional: the
|
|
253
|
+
* readline input has no box to draw it in. */
|
|
254
|
+
setGhost?(text: string | null): void;
|
|
252
255
|
/** R3a: cross-session history — seed the recall buffer, register the
|
|
253
256
|
* append sink. The pipe path has no recall keys; optional. */
|
|
254
257
|
bindHistory?(seed: readonly string[], persist: (line: string) => void): void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.53.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",
|
|
@@ -29,19 +29,19 @@
|
|
|
29
29
|
"test": "vitest run"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@vincemakes/kiso-ask-ext": "0.
|
|
33
|
-
"@vincemakes/kiso-core": "0.
|
|
34
|
-
"@vincemakes/kiso-evals": "0.
|
|
35
|
-
"@vincemakes/kiso-mcp-ext": "0.
|
|
36
|
-
"@vincemakes/kiso-provider-anthropic": "0.
|
|
37
|
-
"@vincemakes/kiso-provider-openai": "0.
|
|
38
|
-
"@vincemakes/kiso-provider-openai-responses": "0.
|
|
39
|
-
"@vincemakes/kiso-runtime": "0.
|
|
40
|
-
"@vincemakes/kiso-skills-ext": "0.
|
|
41
|
-
"@vincemakes/kiso-subagent-ext": "0.
|
|
42
|
-
"@vincemakes/kiso-tools-node": "0.
|
|
43
|
-
"@vincemakes/kiso-tui": "0.
|
|
44
|
-
"@vincemakes/kiso-tui-cells": "0.
|
|
32
|
+
"@vincemakes/kiso-ask-ext": "0.53.0",
|
|
33
|
+
"@vincemakes/kiso-core": "0.53.0",
|
|
34
|
+
"@vincemakes/kiso-evals": "0.53.0",
|
|
35
|
+
"@vincemakes/kiso-mcp-ext": "0.53.0",
|
|
36
|
+
"@vincemakes/kiso-provider-anthropic": "0.53.0",
|
|
37
|
+
"@vincemakes/kiso-provider-openai": "0.53.0",
|
|
38
|
+
"@vincemakes/kiso-provider-openai-responses": "0.53.0",
|
|
39
|
+
"@vincemakes/kiso-runtime": "0.53.0",
|
|
40
|
+
"@vincemakes/kiso-skills-ext": "0.53.0",
|
|
41
|
+
"@vincemakes/kiso-subagent-ext": "0.53.0",
|
|
42
|
+
"@vincemakes/kiso-tools-node": "0.53.0",
|
|
43
|
+
"@vincemakes/kiso-tui": "0.53.0",
|
|
44
|
+
"@vincemakes/kiso-tui-cells": "0.53.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^26.1.2",
|