@vincemakes/kiso-code 0.52.0 → 0.54.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 +15 -0
- package/dist/create-coding-agent.js +2 -2
- package/dist/dispatch.d.ts +8 -1
- package/dist/dispatch.js +69 -2
- package/dist/empty-sessions.js +2 -0
- package/dist/floor.d.ts +2 -2
- package/dist/floor.js +13 -6
- package/dist/index.js +35 -3
- package/dist/policy.d.ts +2 -0
- package/dist/policy.js +2 -0
- package/dist/projects.js +1 -1
- package/dist/replay.d.ts +1 -1
- package/dist/replay.js +5 -1
- package/dist/shell-facts.d.ts +9 -0
- package/dist/shell-facts.js +46 -0
- package/dist/shell-words.d.ts +2 -0
- package/dist/shell-words.js +4 -0
- package/dist/state.d.ts +7 -2
- package/dist/state.js +11 -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 && !leaving)
|
|
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).
|
|
@@ -1889,11 +1902,13 @@ export async function chat(session, faux, input, autoCompact, nav, seed) {
|
|
|
1889
1902
|
requestSwitch: (id) => {
|
|
1890
1903
|
switchTo = id;
|
|
1891
1904
|
leaving = true;
|
|
1905
|
+
input.setGhost?.(null); // REL-0530-F1: the follow-up belongs to the session being left
|
|
1892
1906
|
resolveEnd();
|
|
1893
1907
|
},
|
|
1894
1908
|
requestReload: () => {
|
|
1895
1909
|
reloadReq = true;
|
|
1896
1910
|
leaving = true;
|
|
1911
|
+
input.setGhost?.(null);
|
|
1897
1912
|
resolveEnd();
|
|
1898
1913
|
},
|
|
1899
1914
|
sessions: () => nav?.sessions() ?? [],
|
|
@@ -34,7 +34,7 @@ import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
|
34
34
|
import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
35
35
|
import { sweepStaleMergeDirs } from "./temp-sweep.js";
|
|
36
36
|
import { CODING_TOOL_RULES, composeSystemPrompt } from "./coding-prompt.js";
|
|
37
|
-
import { createAgent, loadExtensions, loadProjectExtensions, SessionStore } from "@vincemakes/kiso-runtime";
|
|
37
|
+
import { createAgent, loadExtensions, loadProjectExtensions, readEnvironment, SessionStore } from "@vincemakes/kiso-runtime";
|
|
38
38
|
import { preferences, startingEffort } from "./preferences.js";
|
|
39
39
|
/** LT-1: the stream watchdog's bound from the environment — a non-negative
|
|
40
40
|
* number of milliseconds (0 disables it); anything else is ignored. The
|
|
@@ -269,7 +269,7 @@ export async function createCodingAgent(sessionId, input, modelFlag) {
|
|
|
269
269
|
setUserProtectedPaths(userConfig?.protectedPaths);
|
|
270
270
|
const extensions = [
|
|
271
271
|
protectedShellExtension({ files: protectedFiles, workspaceRoot, env: () => ({ home: homedir(), kisoHome: kisoHome() }) }),
|
|
272
|
-
floorExtension(() => floorOn, workspaceRoot),
|
|
272
|
+
floorExtension(() => floorOn, workspaceRoot, undefined, () => (sessionId === undefined ? [] : readEnvironment(activeStoreDir, sessionId).added)),
|
|
273
273
|
breakerExtension(),
|
|
274
274
|
...modeExtensions(workspaceRoot),
|
|
275
275
|
readOnlyShellExtension(codingToolOptions),
|
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,8 @@ 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, newest first, by the person's message it answered and when it ended; the opened
|
|
78
|
+
* row shows the reply's first line under it (owner 2026-11-04: the person knows a turn by what they asked, and an
|
|
79
|
+
* "answered:" label over their own line read backwards). The card's id is the seq of the run's terminal, where
|
|
80
|
+
* SessionStore.fork cuts. */
|
|
81
|
+
export declare function replyCards(records: readonly StoreRecord[]): SessionCardView[];
|
package/dist/dispatch.js
CHANGED
|
@@ -5,11 +5,13 @@
|
|
|
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 { isEnvironmentNote } from "@vincemakes/kiso-runtime";
|
|
10
|
+
import { ForkRefusedError, SessionStore } from "@vincemakes/kiso-runtime";
|
|
9
11
|
import { MODE_LABEL, MODE_NOTE, OFFERED_MODES, applyModeSetting, getDontAsk, getMode, modeDisplay, parseMode, setDontAsk } from "./mode.js";
|
|
10
12
|
import { clipboardWrite, lastAnswer } from "./clipboard.js";
|
|
11
13
|
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";
|
|
14
|
+
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
15
|
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
14
16
|
import { profileProviderLabel, providerLabel } from "./provider-label.js";
|
|
15
17
|
import { installedVersion, versionStatusLine } from "./stale-version.js";
|
|
@@ -1384,6 +1386,44 @@ export function dispatch(line, ctx) {
|
|
|
1384
1386
|
ctx.requestReload();
|
|
1385
1387
|
return;
|
|
1386
1388
|
}
|
|
1389
|
+
if (trimmed === "/fork") {
|
|
1390
|
+
// owner 2026-11-03: the web app's fork, one rule — a new session from after one of this session's replies
|
|
1391
|
+
// (SessionStore.fork), then the terminal switches to it as /resume does; the replies are picked in /resume's band
|
|
1392
|
+
if (ctx.isRunning()) {
|
|
1393
|
+
body.notice("[/fork] a run is in flight — let it finish (esc stops it), then fork");
|
|
1394
|
+
ctx.input.prompt();
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
ctx.chainRef.current = ctx.chainRef.current.then(async () => {
|
|
1398
|
+
const cards = replyCards(sessionStoreRef?.load(ctx.session.id) ?? []);
|
|
1399
|
+
if (cards.length === 0) {
|
|
1400
|
+
body.notice("no finished reply to fork after yet");
|
|
1401
|
+
ctx.input.prompt();
|
|
1402
|
+
return;
|
|
1403
|
+
}
|
|
1404
|
+
const fork = (afterSeq) => {
|
|
1405
|
+
try {
|
|
1406
|
+
const made = new SessionStore(activeStoreDir).fork(ctx.session.id, { afterSeq });
|
|
1407
|
+
body.notice(`forked "${escapeTerminal(readSessionName(activeStoreDir, made.id) ?? made.id)}" — switching to it`);
|
|
1408
|
+
ctx.requestSwitch(made.id);
|
|
1409
|
+
}
|
|
1410
|
+
catch (error) {
|
|
1411
|
+
body.notice(error instanceof ForkRefusedError ? `[/fork] ${error.message}` : `[/fork] ${error instanceof Error ? error.message : String(error)}`);
|
|
1412
|
+
ctx.input.prompt();
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
// no band (a pipe, a dock-less terminal): after the last reply, the sidebar's Fork
|
|
1416
|
+
if (ctx.input.pick === undefined || !dock.active)
|
|
1417
|
+
return fork(Number(cards[0].id));
|
|
1418
|
+
ctx.input.pick(() => cards, (picked) => {
|
|
1419
|
+
if (picked === null)
|
|
1420
|
+
ctx.input.prompt(); // esc: nothing forked, nothing said
|
|
1421
|
+
else
|
|
1422
|
+
fork(Number(picked));
|
|
1423
|
+
}, undefined, "fork");
|
|
1424
|
+
});
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1387
1427
|
if (trimmed === "/resume" || trimmed.startsWith("/resume ")) {
|
|
1388
1428
|
// the mini-spec: the in-session door to the durable sessions —
|
|
1389
1429
|
// /resume <id> switches directly; bare /resume opens the SAME
|
|
@@ -1589,3 +1629,30 @@ async function tasksCommand(arg, ctx) {
|
|
|
1589
1629
|
else if (action === 1)
|
|
1590
1630
|
stop(task);
|
|
1591
1631
|
}
|
|
1632
|
+
/** /fork's rows: each finished run, newest first, by the person's message it answered and when it ended; the opened
|
|
1633
|
+
* row shows the reply's first line under it (owner 2026-11-04: the person knows a turn by what they asked, and an
|
|
1634
|
+
* "answered:" label over their own line read backwards). The card's id is the seq of the run's terminal, where
|
|
1635
|
+
* SessionStore.fork cuts. */
|
|
1636
|
+
export function replyCards(records) {
|
|
1637
|
+
const cards = [];
|
|
1638
|
+
let asked = "";
|
|
1639
|
+
let reply = "";
|
|
1640
|
+
for (const { event: e, ts } of records) {
|
|
1641
|
+
if (e.type === "user_input" && e.source !== "system") {
|
|
1642
|
+
const content = Array.isArray(e.content) ? e.content.filter((b) => !(b.type === "text" && (isForkNote(b.text ?? "") || isEnvironmentNote(b.text ?? "")))) : e.content;
|
|
1643
|
+
asked = (typeof content === "string" ? content : content.map((b) => (b.type === "text" ? (b.text ?? "") : "")).join(" ")).trim();
|
|
1644
|
+
reply = "";
|
|
1645
|
+
}
|
|
1646
|
+
else if (e.type === "tool_result")
|
|
1647
|
+
reply = "";
|
|
1648
|
+
else if (e.type === "text_delta")
|
|
1649
|
+
reply += e.text;
|
|
1650
|
+
else if (e.type === "terminal" && e.outcome.kind === "completed") {
|
|
1651
|
+
// the row is the person's own line; the reply's first line, inline code read as plain text, opens under it
|
|
1652
|
+
const first = (reply.split("\n").map((l) => l.trim()).find((l) => l !== "") ?? "(no reply text)").replace(/`([^`]*)`/g, "$1");
|
|
1653
|
+
const line = asked.split("\n").map((l) => l.trim()).find((l) => l !== "") ?? "(no message text)";
|
|
1654
|
+
cards.unshift({ id: String(e.seq), title: line, badge: "completed", turns: null, updatedAt: ts, uncertain: 0, asks: 0, outcome: null, detail: `└ ${first}` });
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
return cards;
|
|
1658
|
+
}
|
package/dist/empty-sessions.js
CHANGED
|
@@ -65,6 +65,8 @@ export function findEmptySessions(dirs, alive = pidAlive) {
|
|
|
65
65
|
const files = [name];
|
|
66
66
|
if (names.includes(lock))
|
|
67
67
|
files.push(lock);
|
|
68
|
+
if (names.includes(`${id}.environment.json`))
|
|
69
|
+
files.push(`${id}.environment.json`);
|
|
68
70
|
if (existsSync(join(dir, "traces", `${id}.jsonl`)))
|
|
69
71
|
files.push(join("traces", `${id}.jsonl`));
|
|
70
72
|
empty.push({ dir, id, files });
|
package/dist/floor.d.ts
CHANGED
|
@@ -88,12 +88,12 @@ export declare function gitInvocation(args: readonly LooseWord[]): GitInvocation
|
|
|
88
88
|
* Would the floor refuse this command line? `workspaceRoot` is where the
|
|
89
89
|
* shell runs it.
|
|
90
90
|
*/
|
|
91
|
-
export declare function floorCheck(commandLine: string, workspaceRoot: string, home?: string): FloorVerdict;
|
|
91
|
+
export declare function floorCheck(commandLine: string, workspaceRoot: string, home?: string, added?: readonly string[]): FloorVerdict;
|
|
92
92
|
/** Is there a destructive command anywhere in the line, whatever its
|
|
93
93
|
* target? A saved allow is never inherited by one (plan §4). */
|
|
94
94
|
export declare function isDestructive(commandLine: string): boolean;
|
|
95
95
|
/** The chain member, at the chain's head: DENY or ABSTAIN. */
|
|
96
|
-
export declare function floorExtension(on: () => boolean, workspaceRoot: () => string, check?: typeof floorCheck): KisoExtension;
|
|
96
|
+
export declare function floorExtension(on: () => boolean, workspaceRoot: () => string, check?: typeof floorCheck, added?: () => readonly string[]): KisoExtension;
|
|
97
97
|
/** Plan §4: "destructive commands never inherit a saved allow in the
|
|
98
98
|
* asking modes" — the predicate the saved-allow wrap
|
|
99
99
|
* (protected-writes.ts) is given, keyed on destructiveness, not on the
|
package/dist/floor.js
CHANGED
|
@@ -77,9 +77,9 @@ function windowsRoots(home) {
|
|
|
77
77
|
/** Memoized per (workspace, home): the roots do not move within a session,
|
|
78
78
|
* and resolving forty of them cost every shell call ~4 ms. */
|
|
79
79
|
const WHERE = new Map();
|
|
80
|
-
function where(root, home) {
|
|
80
|
+
function where(root, home, added = []) {
|
|
81
81
|
const dialect = hostDialect();
|
|
82
|
-
const key = `${dialect.msys ? "msys" : "posix"}\0${root}\0${home}`;
|
|
82
|
+
const key = `${dialect.msys ? "msys" : "posix"}\0${root}\0${home}\0${added.join("\0")}`;
|
|
83
83
|
const hit = WHERE.get(key);
|
|
84
84
|
if (hit !== undefined)
|
|
85
85
|
return hit;
|
|
@@ -94,6 +94,7 @@ function where(root, home) {
|
|
|
94
94
|
rootReal,
|
|
95
95
|
homeReal: real(home),
|
|
96
96
|
gitReal: join(rootReal, ".git"),
|
|
97
|
+
added: added.map(real),
|
|
97
98
|
sys: named(roots.sys),
|
|
98
99
|
mounts: named(roots.mounts),
|
|
99
100
|
temps: [...new Set(roots.temps.map(real))],
|
|
@@ -137,6 +138,12 @@ function unrecoverable(w, p, over) {
|
|
|
137
138
|
return what("the workspace root");
|
|
138
139
|
if (within(p, w.rootReal))
|
|
139
140
|
return what(`a directory above the workspace (${p})`);
|
|
141
|
+
for (const a of w.added) {
|
|
142
|
+
if (same(p, a) || within(p, a))
|
|
143
|
+
return what(`an added folder, or a directory above one (${p})`);
|
|
144
|
+
if (within(hostDialect().path.join(a, ".git"), p))
|
|
145
|
+
return what("an added folder's .git");
|
|
146
|
+
}
|
|
140
147
|
// R7: the workspace's history — without a remote, gone
|
|
141
148
|
if (within(w.gitReal, p))
|
|
142
149
|
return what("the workspace's .git");
|
|
@@ -519,8 +526,8 @@ const child = (s) => ({ cwds: [...s.cwds], lastCd: null, prev: s.prev });
|
|
|
519
526
|
* Would the floor refuse this command line? `workspaceRoot` is where the
|
|
520
527
|
* shell runs it.
|
|
521
528
|
*/
|
|
522
|
-
export function floorCheck(commandLine, workspaceRoot, home = homedir()) {
|
|
523
|
-
const w = where(workspaceRoot, home);
|
|
529
|
+
export function floorCheck(commandLine, workspaceRoot, home = homedir(), added = []) {
|
|
530
|
+
const w = where(workspaceRoot, home, added);
|
|
524
531
|
const seen = new Set();
|
|
525
532
|
const tilde = (word) => (word.tilde && (word.text === "~" || word.text.startsWith("~/")) ? home + word.text.slice(1) : word.text);
|
|
526
533
|
const walk = (nodes, state, depth) => {
|
|
@@ -652,7 +659,7 @@ export function isDestructive(commandLine) {
|
|
|
652
659
|
}
|
|
653
660
|
const ABSTAIN = { action: "abstain" };
|
|
654
661
|
/** The chain member, at the chain's head: DENY or ABSTAIN. */
|
|
655
|
-
export function floorExtension(on, workspaceRoot, check = floorCheck) {
|
|
662
|
+
export function floorExtension(on, workspaceRoot, check = floorCheck, added = () => []) {
|
|
656
663
|
return {
|
|
657
664
|
name: "floor",
|
|
658
665
|
approvals: [
|
|
@@ -669,7 +676,7 @@ export function floorExtension(on, workspaceRoot, check = floorCheck) {
|
|
|
669
676
|
// allow. The floor denies what it could not read.
|
|
670
677
|
let v;
|
|
671
678
|
try {
|
|
672
|
-
v = check(command, workspaceRoot());
|
|
679
|
+
v = check(command, workspaceRoot(), undefined, added());
|
|
673
680
|
}
|
|
674
681
|
catch (err) {
|
|
675
682
|
return { action: "deny", reason: `the floor could not read this line (${err instanceof Error ? err.name : "error"}) — kiso does not run it.` };
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,8 @@ 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 {
|
|
36
|
+
import { readEnvironment } from "@vincemakes/kiso-runtime";
|
|
37
|
+
import { listSessionSidecars, migrateSummaries, readProfile, readSessionName, summaryMigrationPending, writeSessionName } from "@vincemakes/kiso-runtime/internal";
|
|
37
38
|
import { skillMenuItems } from "./skill-invoke.js";
|
|
38
39
|
import { canonicalPath, hasSession, locateSession, projectLayoutActive, sessionFolders } from "./projects.js";
|
|
39
40
|
import { reverseMigration } from "./session-migration.js";
|
|
@@ -332,8 +333,8 @@ function editorInput(editor) {
|
|
|
332
333
|
// TUI2-R2 ②: the session picker — the editor owns the keys (the
|
|
333
334
|
// selection walk, the filter, enter/esc), the compositor draws the
|
|
334
335
|
// band, and the id comes back here.
|
|
335
|
-
pick(cards, onPick, here) {
|
|
336
|
-
editor.beginPick(cards, onPick, here);
|
|
336
|
+
pick(cards, onPick, here, kind) {
|
|
337
|
+
editor.beginPick(cards, onPick, here, kind);
|
|
337
338
|
},
|
|
338
339
|
// W22: the pending-turn queue — the ↑ pop walk (the keys); the
|
|
339
340
|
// chips are the compositor's bindQueue (the dock side).
|
|
@@ -341,6 +342,9 @@ function editorInput(editor) {
|
|
|
341
342
|
editor.bindQueue(state, pop);
|
|
342
343
|
},
|
|
343
344
|
// ADR-0057: the steers a stop handed back return to the buffer.
|
|
345
|
+
setGhost(text) {
|
|
346
|
+
editor.setGhost(text);
|
|
347
|
+
},
|
|
344
348
|
restore(text) {
|
|
345
349
|
editor.restore(text);
|
|
346
350
|
},
|
|
@@ -1070,6 +1074,10 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1070
1074
|
refused = true;
|
|
1071
1075
|
continue;
|
|
1072
1076
|
}
|
|
1077
|
+
// ADR-0058 Amendment 19: the folders a web Work added; the tools here honour them too
|
|
1078
|
+
const addedFolders = readEnvironment(activeStoreDir, id).added;
|
|
1079
|
+
if (addedFolders.length > 0)
|
|
1080
|
+
bodyLog(`also working in: ${addedFolders.map(tildeOf).join(", ")}`);
|
|
1073
1081
|
opened = id;
|
|
1074
1082
|
if (rebuilt) {
|
|
1075
1083
|
rebuilt = false;
|
|
@@ -1158,6 +1166,30 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1158
1166
|
sessions: () => agent.sessionIds(),
|
|
1159
1167
|
route: (sessionId) => routeSession(sessionId),
|
|
1160
1168
|
...(process.stdin.isTTY ? { pick: () => pickSession(agent, input) } : {}),
|
|
1169
|
+
// owner 2026-11-03: a session is titled by a summary of its first message, in the background; the person's own
|
|
1170
|
+
// name wins, before or after; off with KISO_AUTO_TITLE=off and with the faux model, and never without a TTY:
|
|
1171
|
+
// a piped chat is a script or a bench leg, where one more request per session is not the person's
|
|
1172
|
+
...(currentFaux || process.env["KISO_AUTO_TITLE"] === "off" || process.stdin.isTTY !== true
|
|
1173
|
+
? {}
|
|
1174
|
+
: {
|
|
1175
|
+
titled: (firstMessage) => {
|
|
1176
|
+
// the session and its folder as they are NOW: a /resume or a switch before the title lands must not
|
|
1177
|
+
// send it to another session, nor repaint another session's window title
|
|
1178
|
+
const [titling, mine, dir] = [session, session.id, activeStoreDir];
|
|
1179
|
+
if (readSessionName(dir, mine) !== null)
|
|
1180
|
+
return;
|
|
1181
|
+
void titling.title(firstMessage, { signal: AbortSignal.timeout(15_000) }).then((title) => {
|
|
1182
|
+
if (title === "" || readSessionName(dir, mine) !== null)
|
|
1183
|
+
return;
|
|
1184
|
+
writeSessionName(dir, mine, title);
|
|
1185
|
+
// `id` is the loop's: the session open now (a switch moves it on)
|
|
1186
|
+
if (id !== mine)
|
|
1187
|
+
return;
|
|
1188
|
+
setTitleName(title);
|
|
1189
|
+
paintWindowTitle();
|
|
1190
|
+
}, () => undefined);
|
|
1191
|
+
},
|
|
1192
|
+
}),
|
|
1161
1193
|
};
|
|
1162
1194
|
const end = await chat(session, currentFaux, input, autoCompact, nav, seed);
|
|
1163
1195
|
if (end.next === "exit") {
|
package/dist/policy.d.ts
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
export { CODING_TOOL_RULES, SYSTEM_PROMPT, composeSystemPrompt } from "./coding-prompt.js";
|
|
11
11
|
export { breakerExtension } from "./breaker.js";
|
|
12
12
|
export { floorExtension } from "./floor.js";
|
|
13
|
+
export { fileStopRoots } from "./shell-words.js";
|
|
13
14
|
export { MODE_LABEL, OFFERED_MODES, getMode, modeExtensions, modeSystemPrompt, setMode } from "./mode.js";
|
|
14
15
|
export { protectedShellExtension } from "./protected-shell.js";
|
|
15
16
|
export { guardSavedAllow, neverInheritedCall } from "./protected-writes.js";
|
|
16
17
|
export { readOnlyShellExtension } from "./readonly-shell.js";
|
|
18
|
+
export { cdTargets, isGhPrCreate } from "./shell-facts.js";
|
package/dist/policy.js
CHANGED
|
@@ -10,7 +10,9 @@
|
|
|
10
10
|
export { CODING_TOOL_RULES, SYSTEM_PROMPT, composeSystemPrompt } from "./coding-prompt.js";
|
|
11
11
|
export { breakerExtension } from "./breaker.js";
|
|
12
12
|
export { floorExtension } from "./floor.js";
|
|
13
|
+
export { fileStopRoots } from "./shell-words.js";
|
|
13
14
|
export { MODE_LABEL, OFFERED_MODES, getMode, modeExtensions, modeSystemPrompt, setMode } from "./mode.js";
|
|
14
15
|
export { protectedShellExtension } from "./protected-shell.js";
|
|
15
16
|
export { guardSavedAllow, neverInheritedCall } from "./protected-writes.js";
|
|
16
17
|
export { readOnlyShellExtension } from "./readonly-shell.js";
|
|
18
|
+
export { cdTargets, isGhPrCreate } from "./shell-facts.js";
|
package/dist/projects.js
CHANGED
|
@@ -153,7 +153,7 @@ export function locateSession(home, id, except) {
|
|
|
153
153
|
* repeated move is a no-op.
|
|
154
154
|
*/
|
|
155
155
|
export function sessionFiles(id) {
|
|
156
|
-
return [join("traces", `${id}.jsonl`), `${id}.meta.json`, `${id}.lock`, `${id}.jsonl`];
|
|
156
|
+
return [join("traces", `${id}.jsonl`), `${id}.meta.json`, `${id}.environment.json`, `${id}.environment.json.lock`, `${id}.lock`, `${id}.jsonl`];
|
|
157
157
|
}
|
|
158
158
|
export function moveSessionFiles(fromDir, toDir, id, files = sessionFiles(id)) {
|
|
159
159
|
let moved = 0;
|
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,8 @@
|
|
|
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";
|
|
26
|
+
import { isEnvironmentNote } from "@vincemakes/kiso-runtime";
|
|
25
27
|
/** How many turns stay on screen in full. */
|
|
26
28
|
const FULL_TURNS = 2;
|
|
27
29
|
/** A user turn's opening line, or null when this input does not open one
|
|
@@ -32,7 +34,9 @@ function askOf(e) {
|
|
|
32
34
|
if (e.type !== "user_input" || e.source === "system")
|
|
33
35
|
return null;
|
|
34
36
|
const via = e.via;
|
|
35
|
-
|
|
37
|
+
// a fork's first input carries the fork note before the person's words: the model's, not the line they typed
|
|
38
|
+
const content = Array.isArray(e.content) ? e.content.filter((b) => !(b.type === "text" && (isForkNote(b.text ?? "") || isEnvironmentNote(b.text ?? "")))) : e.content;
|
|
39
|
+
const text = typeof via?.line === "string" ? via.line : echoText(content);
|
|
36
40
|
return text.trim() === "" ? null : text;
|
|
37
41
|
}
|
|
38
42
|
/** Split events into turns: each starts at a user turn's input; anything
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The directories a line moves the shell to, in order, when the call that ran it did not fail: the literal `cd <path>` commands of a line
|
|
3
|
+
* that is one `&&` chain, so every one of them ran (`cd /nonexistent; echo hello` exits 0 without having moved, and so does
|
|
4
|
+
* `false && cd /x && ls || true`). Relative paths resolve against `base`, then against the previous `cd`; `~` is `home`. An option, a
|
|
5
|
+
* variable or a word the host's shell cannot spell stops the reading there.
|
|
6
|
+
*/
|
|
7
|
+
export declare function cdTargets(line: string, base: string, home: string): readonly string[];
|
|
8
|
+
/** Whether the line is one `&&` chain that ENDS in `gh pr create`: what its output ends with is the pull request it made (a mention in an echo, a `||` branch, or a command after it that prints another URL, is not one). */
|
|
9
|
+
export declare function isGhPrCreate(line: string): boolean;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Two facts a UI may read from a shell line, conservatively: literal words only, and what the reader cannot read yields nothing.
|
|
3
|
+
* They are DISPLAY facts (the web page's Recent folders and Repository rows): nothing here grants or refuses anything.
|
|
4
|
+
*/
|
|
5
|
+
import { hostDialect, msysPath, parseShellLooseChecked } from "./shell-words.js";
|
|
6
|
+
const literal = (w) => (w === undefined || w.unknownAt !== -1 || w.variableOnly ? null : w.text);
|
|
7
|
+
/** The commands of a line that is ONE `&&` chain (no `||`, `;`, pipe or group anywhere), or null: only then did every command run when the call did not fail. */
|
|
8
|
+
function chainOf(line) {
|
|
9
|
+
const { nodes, truncated } = parseShellLooseChecked(line);
|
|
10
|
+
if (truncated || nodes.some((n, i) => n.kind !== "cmd" || (i > 0 && n.joinedBy !== "&&")))
|
|
11
|
+
return null;
|
|
12
|
+
return nodes;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The directories a line moves the shell to, in order, when the call that ran it did not fail: the literal `cd <path>` commands of a line
|
|
16
|
+
* that is one `&&` chain, so every one of them ran (`cd /nonexistent; echo hello` exits 0 without having moved, and so does
|
|
17
|
+
* `false && cd /x && ls || true`). Relative paths resolve against `base`, then against the previous `cd`; `~` is `home`. An option, a
|
|
18
|
+
* variable or a word the host's shell cannot spell stops the reading there.
|
|
19
|
+
*/
|
|
20
|
+
export function cdTargets(line, base, home) {
|
|
21
|
+
const chain = chainOf(line);
|
|
22
|
+
if (chain === null)
|
|
23
|
+
return [];
|
|
24
|
+
const out = [];
|
|
25
|
+
const d = hostDialect(); // the shell's own spelling: Git Bash on Windows (`/c/x`, `C:/x`), POSIX elsewhere
|
|
26
|
+
let at = base;
|
|
27
|
+
for (const cmd of chain) {
|
|
28
|
+
if (literal(cmd.argv[0]) !== "cd")
|
|
29
|
+
continue;
|
|
30
|
+
const raw = cmd.argv.length === 2 ? literal(cmd.argv[1]) : null;
|
|
31
|
+
if (raw === null || raw === "-" || raw.startsWith("-"))
|
|
32
|
+
break;
|
|
33
|
+
const word = raw === "~" || raw.startsWith("~/") ? d.path.join(home, raw.slice(2)) : raw;
|
|
34
|
+
const read = d.msys ? msysPath(word) : { native: word };
|
|
35
|
+
if ("opaque" in read)
|
|
36
|
+
break;
|
|
37
|
+
at = d.path.resolve(at, read.native);
|
|
38
|
+
out.push(at);
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
/** Whether the line is one `&&` chain that ENDS in `gh pr create`: what its output ends with is the pull request it made (a mention in an echo, a `||` branch, or a command after it that prints another URL, is not one). */
|
|
43
|
+
export function isGhPrCreate(line) {
|
|
44
|
+
const c = chainOf(line)?.at(-1);
|
|
45
|
+
return c !== undefined && literal(c.argv[0]) === "gh" && literal(c.argv[1]) === "pr" && literal(c.argv[2]) === "create";
|
|
46
|
+
}
|
package/dist/shell-words.d.ts
CHANGED
|
@@ -93,6 +93,8 @@ export declare const HOME_SUBTREES: readonly string[];
|
|
|
93
93
|
/** The home subtrees for this host: on Windows, AppData too — credentials
|
|
94
94
|
* and configuration that runs live there (Windows P2). */
|
|
95
95
|
export declare function homeSubtrees(): readonly string[];
|
|
96
|
+
/** Folders the file tools' new reach never enters (ADR-0058 Amendment 19): kiso's own home and the credential homes. */
|
|
97
|
+
export declare function fileStopRoots(home: string, kisoHome: string): readonly string[];
|
|
96
98
|
/** A real path in the case the DISK holds it. The JS realpath keeps the
|
|
97
99
|
* case it was given, so on a case-insensitive disk `.ENV` stayed `.ENV`
|
|
98
100
|
* and walked past every name-based predicate (the lead's review, B2). */
|
package/dist/shell-words.js
CHANGED
|
@@ -334,6 +334,10 @@ export const HOME_SUBTREES = [".ssh", ".config", ".kiso", ".gnupg", ".aws"];
|
|
|
334
334
|
export function homeSubtrees() {
|
|
335
335
|
return hostDialect().msys ? [...HOME_SUBTREES, "AppData"] : HOME_SUBTREES;
|
|
336
336
|
}
|
|
337
|
+
/** Folders the file tools' new reach never enters (ADR-0058 Amendment 19): kiso's own home and the credential homes. */
|
|
338
|
+
export function fileStopRoots(home, kisoHome) {
|
|
339
|
+
return [kisoHome, ...homeSubtrees().map((s) => hostDialect().path.join(home, s))];
|
|
340
|
+
}
|
|
337
341
|
/** A real path in the case the DISK holds it. The JS realpath keeps the
|
|
338
342
|
* case it was given, so on a case-insensitive disk `.ENV` stayed `.ENV`
|
|
339
343
|
* and walked past every name-based predicate (the lead's review, B2). */
|
package/dist/state.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { TaskDeliveryItem } from "@vincemakes/kiso-core";
|
|
|
10
10
|
import { kisoHome, type KisoExtension, type StoreRecord } from "@vincemakes/kiso-runtime";
|
|
11
11
|
import type { ReasoningSetting } from "@vincemakes/kiso-runtime/internal";
|
|
12
12
|
import { TaskManager } from "@vincemakes/kiso-runtime/internal";
|
|
13
|
-
import { type ShellTasks } from "@vincemakes/kiso-tools-node";
|
|
13
|
+
import { type FileAccess, type ShellTasks } from "@vincemakes/kiso-tools-node";
|
|
14
14
|
/** finding #11: KISO_HOME is the ONE root — every default path derives from
|
|
15
15
|
* it (sessions, trust, extensions, mcp config, skills). The dedicated
|
|
16
16
|
* env vars (KISO_EXTENSIONS_DIR / KISO_MCP_CONFIG / KISO_SKILLS_DIR)
|
|
@@ -35,6 +35,8 @@ export declare function codingToolOptions(): {
|
|
|
35
35
|
readonly excludeRoots: readonly string[];
|
|
36
36
|
readonly secretEnvNames: readonly string[];
|
|
37
37
|
readonly protectedFiles: readonly string[];
|
|
38
|
+
readonly access: (sessionId: string | undefined) => FileAccess;
|
|
39
|
+
readonly stopRoots: readonly string[];
|
|
38
40
|
readonly tasks: (sessionId: string | undefined) => ShellTasks | undefined;
|
|
39
41
|
readonly observedRevision: (sessionId: string | undefined, full: string, kind?: "edit" | "write") => string | undefined;
|
|
40
42
|
readonly limits?: {
|
|
@@ -241,7 +243,7 @@ export interface LineInput {
|
|
|
241
243
|
* picked id, or null when the human leaves without picking.
|
|
242
244
|
* OPTIONAL: only the raw-mode editor has it, and the picker only
|
|
243
245
|
* ever opens on a TTY (a pipe has nobody to pick). */
|
|
244
|
-
pick?(cards: () => readonly SessionCardView[], onPick: (id: string | null) => void, here?: string): void;
|
|
246
|
+
pick?(cards: () => readonly SessionCardView[], onPick: (id: string | null) => void, here?: string, kind?: "resume" | "fork"): void;
|
|
245
247
|
/** W22: bind the pending-turn queue — the ↑ pop walks the CLI's
|
|
246
248
|
* live slots (each pop cancels the turn), esc ends the walk after
|
|
247
249
|
* one more pop. The chips are the compositor's own bindQueue. */
|
|
@@ -249,6 +251,9 @@ export interface LineInput {
|
|
|
249
251
|
/** ADR-0057: put text back into the editor — the steers a stop handed
|
|
250
252
|
* back before they landed. The pipe path has no editor; optional. */
|
|
251
253
|
restore?(text: string): void;
|
|
254
|
+
/** The follow-up: a line the person may send next, dim in the empty box, Tab takes it; null clears it. Optional: the
|
|
255
|
+
* readline input has no box to draw it in. */
|
|
256
|
+
setGhost?(text: string | null): void;
|
|
252
257
|
/** R3a: cross-session history — seed the recall buffer, register the
|
|
253
258
|
* append sink. The pipe path has no recall keys; optional. */
|
|
254
259
|
bindHistory?(seed: readonly string[], persist: (line: string) => void): void;
|
package/dist/state.js
CHANGED
|
@@ -12,12 +12,14 @@ import { dirname, join, resolve } from "node:path";
|
|
|
12
12
|
import { fileURLToPath } from "node:url";
|
|
13
13
|
import { AT_CAP, AT_SKIP, Dock } from "@vincemakes/kiso-tui";
|
|
14
14
|
import { projectMessages } from "@vincemakes/kiso-core";
|
|
15
|
-
import { kisoHome } from "@vincemakes/kiso-runtime";
|
|
15
|
+
import { kisoHome, readEnvironment } from "@vincemakes/kiso-runtime";
|
|
16
16
|
import { TaskManager } from "@vincemakes/kiso-runtime/internal";
|
|
17
17
|
import { processTaskBackend, readShowsWholeFile } from "@vincemakes/kiso-tools-node";
|
|
18
18
|
import { collectWriter } from "@vincemakes/kiso-subagent-ext";
|
|
19
19
|
import { canonicalPath, LEGACY_SESSIONS_DIR, projectDirFor, projectLayoutActive } from "./projects.js";
|
|
20
20
|
import { taskNoticeLines, taskWhat } from "./task-notice.js";
|
|
21
|
+
import { getMode } from "./mode.js";
|
|
22
|
+
import { fileStopRoots } from "./shell-words.js";
|
|
21
23
|
/** finding #11: KISO_HOME is the ONE root — every default path derives from
|
|
22
24
|
* it (sessions, trust, extensions, mcp config, skills). The dedicated
|
|
23
25
|
* env vars (KISO_EXTENSIONS_DIR / KISO_MCP_CONFIG / KISO_SKILLS_DIR)
|
|
@@ -49,6 +51,12 @@ let printRun = false;
|
|
|
49
51
|
export function setPrintRun() {
|
|
50
52
|
printRun = true;
|
|
51
53
|
}
|
|
54
|
+
/** ADR-0058 Amendment 19: the same list the web reads, per call; a delegate child gets none of it. */
|
|
55
|
+
function fileAccess(sessionId) {
|
|
56
|
+
if ((Number.parseInt(process.env.KISO_SUBAGENT_DEPTH ?? "0", 10) || 0) >= 1)
|
|
57
|
+
return { added: [], outside: "deny" };
|
|
58
|
+
return { added: sessionId === undefined || activeStoreDir === "" ? [] : readEnvironment(activeStoreDir, sessionId).added, outside: getMode() === "full-access" ? "allow" : "deny" };
|
|
59
|
+
}
|
|
52
60
|
export function codingToolOptions() {
|
|
53
61
|
// KISO_MIN_FOREGROUND_MS — the test rigs' knob (like KISO_AUTO_DETACH_MS):
|
|
54
62
|
// the least foreground wait (ADR-0058 Amendment 10, default 60 s). The
|
|
@@ -66,6 +74,8 @@ export function codingToolOptions() {
|
|
|
66
74
|
excludeRoots: [kisoHome()],
|
|
67
75
|
secretEnvNames: secretEnvNamesOf(configModels),
|
|
68
76
|
protectedFiles: protectedFiles(),
|
|
77
|
+
access: fileAccess,
|
|
78
|
+
stopRoots: fileStopRoots(homedir(), kisoHome()),
|
|
69
79
|
tasks: tasksFor,
|
|
70
80
|
observedRevision: observedRevisionFromLog,
|
|
71
81
|
...(Object.keys(limits).length > 0 ? { limits } : {}),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.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.54.0",
|
|
33
|
+
"@vincemakes/kiso-core": "0.54.0",
|
|
34
|
+
"@vincemakes/kiso-evals": "0.54.0",
|
|
35
|
+
"@vincemakes/kiso-mcp-ext": "0.54.0",
|
|
36
|
+
"@vincemakes/kiso-provider-anthropic": "0.54.0",
|
|
37
|
+
"@vincemakes/kiso-provider-openai": "0.54.0",
|
|
38
|
+
"@vincemakes/kiso-provider-openai-responses": "0.54.0",
|
|
39
|
+
"@vincemakes/kiso-runtime": "0.54.0",
|
|
40
|
+
"@vincemakes/kiso-skills-ext": "0.54.0",
|
|
41
|
+
"@vincemakes/kiso-subagent-ext": "0.54.0",
|
|
42
|
+
"@vincemakes/kiso-tools-node": "0.54.0",
|
|
43
|
+
"@vincemakes/kiso-tui": "0.54.0",
|
|
44
|
+
"@vincemakes/kiso-tui-cells": "0.54.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@types/node": "^26.1.2",
|