@vincemakes/kiso-code 0.40.0 → 0.40.2
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 +15 -1
- package/dist/chat.js +44 -7
- package/dist/dispatch.d.ts +2 -0
- package/dist/dispatch.js +48 -5
- package/dist/index.js +88 -8
- package/dist/provider-label.d.ts +32 -0
- package/dist/provider-label.js +53 -0
- package/dist/state.d.ts +13 -0
- package/dist/state.js +15 -0
- package/package.json +15 -15
package/dist/chat.d.ts
CHANGED
|
@@ -100,6 +100,18 @@ export declare function statusModelLabel(session: {
|
|
|
100
100
|
readonly effort: string;
|
|
101
101
|
};
|
|
102
102
|
}): string;
|
|
103
|
+
/** ADR-0055 Amendment 2 (decision 5): with no stated window the status row
|
|
104
|
+
* shows `ctx ?`, yet the compaction tiers still assume the 200K fallback
|
|
105
|
+
* — the assumption is said out loud once, at agent build. */
|
|
106
|
+
export declare function unknownWindowNotice(model: string): string;
|
|
107
|
+
/** ADR-0055 Amendment 2: the notice for a checkpoint the shrink invariant
|
|
108
|
+
* discarded — chars/4 sizes only; the checkpoint's text is the owner's
|
|
109
|
+
* work and never reaches the screen. */
|
|
110
|
+
export declare function compactionDiscardedNotice(d: {
|
|
111
|
+
readonly pre: number;
|
|
112
|
+
readonly post: number;
|
|
113
|
+
readonly summary: number;
|
|
114
|
+
}): string;
|
|
103
115
|
export declare function displayCtxRatio(session: AgentSession): number;
|
|
104
116
|
/** 0.40.0 item 9: how long a prompt cache is assumed to live. PROVISIONAL:
|
|
105
117
|
* DeepSeek does not publish its TTL (the owner's cache was gone after 27
|
|
@@ -309,6 +321,7 @@ export type ChatEnd = {
|
|
|
309
321
|
} | {
|
|
310
322
|
readonly next: "switch";
|
|
311
323
|
readonly id: string;
|
|
324
|
+
readonly lines?: readonly string[];
|
|
312
325
|
}
|
|
313
326
|
/** §2.5: the caller REBUILDS the agent and re-enters on the same id.
|
|
314
327
|
* Not "switch": switching keeps the agent and only changes the id,
|
|
@@ -317,6 +330,7 @@ export type ChatEnd = {
|
|
|
317
330
|
| {
|
|
318
331
|
readonly next: "reload";
|
|
319
332
|
readonly id: string;
|
|
333
|
+
readonly lines?: readonly string[];
|
|
320
334
|
};
|
|
321
335
|
/** The session-navigation seam main provides: the OTHER sessions'
|
|
322
336
|
* ids, and (when a dock is up) the existing picker. */
|
|
@@ -326,4 +340,4 @@ export interface ChatNav {
|
|
|
326
340
|
readonly route?: (id: string) => SessionRoute | null;
|
|
327
341
|
readonly pick?: () => Promise<string | null>;
|
|
328
342
|
}
|
|
329
|
-
export declare function chat(session: AgentSession, faux: boolean, input: LineInput, autoCompact?: AutoCompact, nav?: ChatNav): Promise<ChatEnd>;
|
|
343
|
+
export declare function chat(session: AgentSession, faux: boolean, input: LineInput, autoCompact?: AutoCompact, nav?: ChatNav, seed?: readonly string[]): Promise<ChatEnd>;
|
package/dist/chat.js
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
* estimates. All bodies moved verbatim from index.ts.
|
|
6
6
|
*/
|
|
7
7
|
import { readFileSync, statSync } from "node:fs";
|
|
8
|
-
import { escapeTerminal, cacheHitPct, decodeRate, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, } from "@vincemakes/kiso-tui";
|
|
8
|
+
import { escapeTerminal, cacheHitPct, decodeRate, idleStatus, palette, renderEvent, renderRecap, runningStatus, toolTarget, verifyOfferView, STATUS_GLYPHS, kUnit, } from "@vincemakes/kiso-tui";
|
|
9
9
|
import { askView, coldResumeLine, coldResumeView, deletionRiskHint, editFileDiff, writeFileDiff } from "@vincemakes/kiso-tui";
|
|
10
10
|
import { canonicalTargetPath, isProtectedPath, protectedIdentity, shellProgressPath } from "@vincemakes/kiso-tools-node";
|
|
11
|
+
import { queuedSwitchLines } from "./state.js";
|
|
11
12
|
import { echoText } from "@vincemakes/kiso-tui-cells/render";
|
|
12
13
|
import { canonicalizeUsage } from "@vincemakes/kiso-runtime";
|
|
13
14
|
import { canonicalizeUsageForModel, requestBudget } from "@vincemakes/kiso-runtime/internal";
|
|
@@ -153,7 +154,29 @@ export function estimateCtxRatio(session) {
|
|
|
153
154
|
* is the session's own (the durable profile), never the CLI's memory. */
|
|
154
155
|
export function statusModelLabel(session) {
|
|
155
156
|
const effort = session.reasoning?.effort;
|
|
156
|
-
|
|
157
|
+
// The owner's dogfood, 2026-09-21 (the second pass): the status row under
|
|
158
|
+
// the composer is the MODEL's, and only the model's — a host belongs where
|
|
159
|
+
// a choice is being made (`/model`'s rows, the switch notice) and where the
|
|
160
|
+
// identity is asked for (`/status`), not in a row that has ~40 columns and
|
|
161
|
+
// cut the host to `deepseek/d…ndcode.ai`. Unnecessary at best, misleading at
|
|
162
|
+
// worst: it read as a path, not as an account.
|
|
163
|
+
// The owner, 2026-09-22: the row shows the MODEL's name only — a vendor
|
|
164
|
+
// prefix (`deepseek/deepseek-v4.1-flash`) cost the row its tail. The full
|
|
165
|
+
// id stays in `/status` and `/model`, where identity is asked for.
|
|
166
|
+
const name = agentModel.slice(agentModel.lastIndexOf("/") + 1) || agentModel;
|
|
167
|
+
return effort !== undefined && effort !== "default" ? `${name} · ${effort}` : name;
|
|
168
|
+
}
|
|
169
|
+
/** ADR-0055 Amendment 2 (decision 5): with no stated window the status row
|
|
170
|
+
* shows `ctx ?`, yet the compaction tiers still assume the 200K fallback
|
|
171
|
+
* — the assumption is said out loud once, at agent build. */
|
|
172
|
+
export function unknownWindowNotice(model) {
|
|
173
|
+
return `[kiso] context window unknown for ${model} at this endpoint — compaction assumes ${DEFAULT_CONTEXT_WINDOW / 1000}K; set contextWindow on the profile to state it`;
|
|
174
|
+
}
|
|
175
|
+
/** ADR-0055 Amendment 2: the notice for a checkpoint the shrink invariant
|
|
176
|
+
* discarded — chars/4 sizes only; the checkpoint's text is the owner's
|
|
177
|
+
* work and never reaches the screen. */
|
|
178
|
+
export function compactionDiscardedNotice(d) {
|
|
179
|
+
return `✦ compaction discarded — the checkpoint did not shrink the context (~${kUnit(d.pre)} → ~${kUnit(d.post)}; it wrote ~${kUnit(d.summary)})`;
|
|
157
180
|
}
|
|
158
181
|
export function displayCtxRatio(session) {
|
|
159
182
|
// CAPACITY is not POLICY. `contextWindowTokens` falls back to 200,000 so
|
|
@@ -1164,7 +1187,7 @@ submitTurn) {
|
|
|
1164
1187
|
}
|
|
1165
1188
|
return last;
|
|
1166
1189
|
}
|
|
1167
|
-
export async function chat(session, faux, input, autoCompact, nav) {
|
|
1190
|
+
export async function chat(session, faux, input, autoCompact, nav, seed) {
|
|
1168
1191
|
// the switch directive — set once by dispatch's /clear or /resume,
|
|
1169
1192
|
// resolved through the end signal so the final awaits still run
|
|
1170
1193
|
let switchTo = null;
|
|
@@ -1379,7 +1402,15 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1379
1402
|
// REPL is ready (they are never dropped).
|
|
1380
1403
|
const chainRef = { current: Promise.resolve() };
|
|
1381
1404
|
let replReady = false;
|
|
1382
|
-
const queuedLines = [];
|
|
1405
|
+
const queuedLines = [...(seed ?? []), ...queuedSwitchLines.splice(0)];
|
|
1406
|
+
// DC-57 (the owner's ruling, 2026-09-21): once the session is LEAVING —
|
|
1407
|
+
// a switch or a reload has been requested — a line that arrives belongs
|
|
1408
|
+
// to the session the person asked for, not to the one they are leaving.
|
|
1409
|
+
// One read can carry several lines (a paste, a pipe, a scripted
|
|
1410
|
+
// driver), and the departing instance used to dispatch them; they are
|
|
1411
|
+
// queued here and replayed by the NEXT chat() entry, exactly as
|
|
1412
|
+
// pre-ready lines are replayed by this one.
|
|
1413
|
+
let leaving = false;
|
|
1383
1414
|
// B area: user-turn counter for the status line. /last and /think read
|
|
1384
1415
|
// the body (the ToolCell / ThinkingCell final states).
|
|
1385
1416
|
let turnNo = 0;
|
|
@@ -1565,12 +1596,18 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1565
1596
|
// the /resume+/clear mini-spec: the switch directive and the
|
|
1566
1597
|
// session-navigation seam (absent nav = the commands degrade to
|
|
1567
1598
|
// an honest refusal in dispatch)
|
|
1599
|
+
// DC-57: the dispatch edge asks this before it answers a line, so the
|
|
1600
|
+
// decision is made when the line's segment runs — not when its bytes
|
|
1601
|
+
// arrived, which can be before the switch was even requested.
|
|
1602
|
+
leaving: () => leaving,
|
|
1568
1603
|
requestSwitch: (id) => {
|
|
1569
1604
|
switchTo = id;
|
|
1605
|
+
leaving = true;
|
|
1570
1606
|
resolveEnd();
|
|
1571
1607
|
},
|
|
1572
1608
|
requestReload: () => {
|
|
1573
1609
|
reloadReq = true;
|
|
1610
|
+
leaving = true;
|
|
1574
1611
|
resolveEnd();
|
|
1575
1612
|
},
|
|
1576
1613
|
sessions: () => nav?.sessions() ?? [],
|
|
@@ -1603,7 +1640,7 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1603
1640
|
dispatch(line, dispatchCtx);
|
|
1604
1641
|
};
|
|
1605
1642
|
input.onLine((line) => {
|
|
1606
|
-
if (!replReady) {
|
|
1643
|
+
if (!replReady || leaving) {
|
|
1607
1644
|
queuedLines.push(line);
|
|
1608
1645
|
return;
|
|
1609
1646
|
}
|
|
@@ -1708,8 +1745,8 @@ export async function chat(session, faux, input, autoCompact, nav) {
|
|
|
1708
1745
|
// enough: the /compact segment appends nothing of its own.
|
|
1709
1746
|
await chainRef.current;
|
|
1710
1747
|
if (switchTo !== null)
|
|
1711
|
-
return { next: "switch", id: switchTo };
|
|
1748
|
+
return { next: "switch", id: switchTo, lines: queuedLines.slice() };
|
|
1712
1749
|
// a switch beats a reload: /resume and /clear are going somewhere else,
|
|
1713
1750
|
// and the agent they land on is rebuilt by the caller either way.
|
|
1714
|
-
return reloadReq ? { next: "reload", id: session.id } : { next: "exit" };
|
|
1751
|
+
return reloadReq ? { next: "reload", id: session.id, lines: queuedLines.slice() } : { next: "exit" };
|
|
1715
1752
|
}
|
package/dist/dispatch.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface DispatchCtx {
|
|
|
37
37
|
/** the /resume+/clear mini-spec: end this chat() with a switch to
|
|
38
38
|
* another session — main re-enters chat there; the editor survives. */
|
|
39
39
|
readonly requestSwitch: (id: string) => void;
|
|
40
|
+
/** DC-57: true once this entry has been asked to leave — the guard that keeps a departing session from answering a batch's later lines. */
|
|
41
|
+
readonly leaving: () => boolean;
|
|
40
42
|
/** §2.5: end this chat() with a REBUILD of the agent on the SAME
|
|
41
43
|
* session — extensions, skills and config are read again. */
|
|
42
44
|
readonly requestReload: () => void;
|
package/dist/dispatch.js
CHANGED
|
@@ -9,8 +9,10 @@ import { buildAdapter, lookupModelMetadata, resolveContinuationScope, resolveRea
|
|
|
9
9
|
import { MODES, MODE_NOTE, OFFERED_MODES, getMode, setMode } from "./mode.js";
|
|
10
10
|
import { clipboardWrite, lastAnswer } from "./clipboard.js";
|
|
11
11
|
import { protectedBangReason, protectedShellVerdict } from "./protected-shell.js";
|
|
12
|
-
import { agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, setLastBinding } from "./state.js";
|
|
12
|
+
import { agentBaseUrl, currentProfileName, setCurrentProfileName, currentModelName, agentModel, body, bodyLog, codingToolOptions, protectedFiles, kisoHome, configModels, dock, lastBinding, loadedSkillsCatalog, mergedConfig, readContextLedger, retryOnRow, sessionsDir, setAgentModel, setConfiguredWindow, setCurrentModelName, setModelChoice, setRetryShown, setLastBinding } from "./state.js";
|
|
13
13
|
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
14
|
+
import { profileProviderLabel, providerLabel } from "./provider-label.js";
|
|
15
|
+
import { queuedSwitchLines } from "./state.js";
|
|
14
16
|
import { contextWindowTokens, microcompactThresholdFor, startStatusSpinner } from "./chat.js";
|
|
15
17
|
import { authForProfile, directWriteProfile, profileAvailable, resolveContextWindow, unavailableReason } from "./config.js";
|
|
16
18
|
import { shellTool } from "@vincemakes/kiso-tools-node";
|
|
@@ -190,6 +192,18 @@ function runBang(command, send, ctx) {
|
|
|
190
192
|
});
|
|
191
193
|
}
|
|
192
194
|
export function dispatch(line, ctx) {
|
|
195
|
+
// DC-57 (the owner's ruling, 2026-09-21): a session that is LEAVING — a
|
|
196
|
+
// switch or a reload has been requested from an earlier segment of the
|
|
197
|
+
// chain — does not answer new lines. They are queued for the session the
|
|
198
|
+
// person asked for and replayed by its `chat()` entry. The guard lives
|
|
199
|
+
// HERE, not only at the input edge: a batch that arrived before the
|
|
200
|
+
// switch was requested still runs its segments after it (the chain is
|
|
201
|
+
// FIFO), which is exactly how a pasted prompt used to land in the
|
|
202
|
+
// departing session.
|
|
203
|
+
if (ctx.leaving()) {
|
|
204
|
+
queuedSwitchLines.push(line);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
193
207
|
const trimmed = line.trim();
|
|
194
208
|
// §2.2 — the `!` gesture is the COMPOSER's alone. A piped session, `-p`
|
|
195
209
|
// and `--task-file` keep `!` as ordinary text: those lines are content,
|
|
@@ -474,6 +488,21 @@ export function dispatch(line, ctx) {
|
|
|
474
488
|
bodyLog(`session ${ctx.session.id}`);
|
|
475
489
|
bodyLog(`${ctx.session.log.all.length} events`);
|
|
476
490
|
bodyLog(`ctx ${ctxPct}`);
|
|
491
|
+
// The owner, 2026-09-21: /status is where "what am I actually
|
|
492
|
+
// running on" is answered, so the identity is spelled out HERE —
|
|
493
|
+
// the model, the host the request goes to, the profile it came
|
|
494
|
+
// from and the key it spends. The status row stays short; this
|
|
495
|
+
// line is the disambiguation two same-named profiles need.
|
|
496
|
+
//
|
|
497
|
+
// REVIEW (2026-09-21): the profile is named only when what is in
|
|
498
|
+
// hand IS a profile key. `currentModelName` holds whatever the
|
|
499
|
+
// resolution produced — a profile alias after `/model`, a MODEL ID
|
|
500
|
+
// after a switch or a resume — so printing it unconditionally
|
|
501
|
+
// claimed `profile deepseek-v4-flash` for a session that was
|
|
502
|
+
// restored, not switched. (The real fix is to stop overloading that
|
|
503
|
+
// variable; until then, a label that cannot lie.)
|
|
504
|
+
const profileOf = currentProfileName === null ? "" : ` · profile ${currentProfileName}`;
|
|
505
|
+
bodyLog(`model ${agentModel}${providerLabel(agentBaseUrl)}${profileOf}`);
|
|
477
506
|
ctx.input.prompt();
|
|
478
507
|
});
|
|
479
508
|
return;
|
|
@@ -567,8 +596,20 @@ export function dispatch(line, ctx) {
|
|
|
567
596
|
// the note keeps what tells two rows apart; the levels
|
|
568
597
|
// left it for the axis below (they were being cut off
|
|
569
598
|
// the end of the note column at 100 columns).
|
|
570
|
-
|
|
571
|
-
|
|
599
|
+
// The owner, 2026-09-21: two profiles can name ONE model
|
|
600
|
+
// id and reach two accounts, so the current mark follows
|
|
601
|
+
// the PROFILE the session is on (`currentModelName`), not
|
|
602
|
+
// the model id — the id alone marked both such rows, or
|
|
603
|
+
// neither. The row's own provider rides the label, so two
|
|
604
|
+
// rows that share an id still read differently.
|
|
605
|
+
// 0.40.1 (the owner's dogfood, 2026-09-21): the `profile: <key>` prefix
|
|
606
|
+
// is gone — the row already names the model and its endpoint, and the
|
|
607
|
+
// profile key is what `/model <name>` takes, not what a chooser
|
|
608
|
+
// reading a list needs. What remains is what the chooser CANNOT
|
|
609
|
+
// infer: availability, and which one is live.
|
|
610
|
+
const marks = [...(profileAvailable(profile) ? [] : ["unavailable"]), ...(name === currentProfileName ? ["current"] : [])];
|
|
611
|
+
const host = profileProviderLabel(profile.kind, profile.baseUrl);
|
|
612
|
+
return { label: `${profile.kind}/${profile.model}${host === "" ? "" : ` ${host}`}`, note: marks.join(" · "), ...effortAxis(profile) };
|
|
572
613
|
}),
|
|
573
614
|
// PH-1a (finding PH-F4): the example must be a syntax
|
|
574
615
|
// directWriteProfile actually ACCEPTS — the old
|
|
@@ -617,7 +658,8 @@ export function dispatch(line, ctx) {
|
|
|
617
658
|
else {
|
|
618
659
|
for (const name of names) {
|
|
619
660
|
const p = configModels[name];
|
|
620
|
-
|
|
661
|
+
const hostOf = profileProviderLabel(p.kind, p.baseUrl);
|
|
662
|
+
bodyLog(` ${name} → ${p.kind}/${p.model}${hostOf === "" ? "" : ` ${hostOf}`} · ${signInNote(p)} ${profileAvailable(p) ? "(available)" : "(unavailable)"} · ${effortNote(p)}`);
|
|
621
663
|
}
|
|
622
664
|
}
|
|
623
665
|
bodyLog("switch with /model <profile-name|provider/model>");
|
|
@@ -713,6 +755,7 @@ export function dispatch(line, ctx) {
|
|
|
713
755
|
setLastBinding(binding);
|
|
714
756
|
setAgentModel(profile.model, profile.baseUrl);
|
|
715
757
|
setCurrentModelName(arg);
|
|
758
|
+
setCurrentProfileName(direct === null ? null : profName);
|
|
716
759
|
// §2.5: the ONE source a reload reads for the model — a
|
|
717
760
|
// switch made here must survive the rebuild.
|
|
718
761
|
setModelChoice(arg);
|
|
@@ -732,7 +775,7 @@ export function dispatch(line, ctx) {
|
|
|
732
775
|
// (and the owner's) read `gpt-6-astra · CH 92%`, the new
|
|
733
776
|
// model beside the previous model's figure.
|
|
734
777
|
ctx.modelSwitched();
|
|
735
|
-
body.notice(`model → ${profName} (${profile.model}${effortTok !== undefined ? ` · ${effortTok}` : ""}) — takes effect on the next turn`);
|
|
778
|
+
body.notice(`model → ${profName} (${profile.model}${providerLabel(profile.baseUrl) === "" ? "" : ` ${providerLabel(profile.baseUrl)}`}${effortTok !== undefined ? ` · ${effortTok}` : ""}) — takes effect on the next turn`);
|
|
736
779
|
}
|
|
737
780
|
}
|
|
738
781
|
}
|
package/dist/index.js
CHANGED
|
@@ -45,12 +45,12 @@ import { floorExtension, isDestructiveCall } from "./floor.js";
|
|
|
45
45
|
import { protectedShellExtension } from "./protected-shell.js";
|
|
46
46
|
import { breakerExtension } from "./breaker.js";
|
|
47
47
|
import { builtInLayer } from "./builtin.js";
|
|
48
|
-
import { agentModel, atFiles, body, bodyLog, codingToolOptions, kisoHome, workspaceRoot, projectRoot, ownSessionsDir, setOpenSessionFolder, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, modelChoice, projectExtensions, configModels, configuredWindow, agentBaseUrl, currentModelName, currentAgentExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setUserProtectedPaths, protectedFiles, setMergedConfig, setModelChoice, setSessionStore, setRetryShown, setNeverInherited, secretEnvNamesOf, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift, setFloorOn, floorOn, loadedSkillsCatalog } from "./state.js";
|
|
48
|
+
import { agentModel, atFiles, body, bodyLog, codingToolOptions, kisoHome, workspaceRoot, projectRoot, ownSessionsDir, setOpenSessionFolder, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, modelChoice, projectExtensions, configModels, configuredWindow, agentBaseUrl, currentModelName, currentAgentExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setCurrentProfileName, setExtensionLists, setUserProtectedPaths, protectedFiles, setMergedConfig, setModelChoice, setSessionStore, setRetryShown, setNeverInherited, secretEnvNamesOf, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift, setFloorOn, floorOn, loadedSkillsCatalog, queuedSwitchLines } from "./state.js";
|
|
49
49
|
import { maxRetriesFromEnv } from "./retries.js";
|
|
50
50
|
import { askUi, resolveProjectTrust } from "./trust-ui.js";
|
|
51
51
|
import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
|
|
52
52
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
53
|
-
import { chat, contextWindowTokens, displayCtxRatio, microcompactThresholdFor, statusModelLabel } from "./chat.js";
|
|
53
|
+
import { chat, compactionDiscardedNotice, contextWindowTokens, displayCtxRatio, knownContextWindow, microcompactThresholdFor, statusModelLabel, unknownWindowNotice } from "./chat.js";
|
|
54
54
|
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
55
55
|
import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveAutoCompact, resolveContextWindow, resolveModel } from "./config.js";
|
|
56
56
|
import { checkForUpdate, knownUpdate, updateCardLines } from "./update-check.js";
|
|
@@ -468,6 +468,7 @@ function makeLineInput() {
|
|
|
468
468
|
// the panel's option rows, so the compositor is what the editor asks
|
|
469
469
|
// where they are. Neither side computes the other's geometry.
|
|
470
470
|
editor.bindPanelRows(() => dock.panelOptionRows());
|
|
471
|
+
editor.bindPickWindow(() => dock.visiblePickWindow());
|
|
471
472
|
dock.bindMenu(() => editor.menuState()); // v3 §04: the slash-command menu
|
|
472
473
|
editor.bindAtItems(atFiles); // KC3 §5: the file source — listed per OPEN
|
|
473
474
|
dock.bindAt(() => editor.atState()); // KC3 §4: the picker's band
|
|
@@ -785,12 +786,20 @@ async function makeAgent(sessionId, input, modelFlag) {
|
|
|
785
786
|
console.log("[faux mode — set ANTHROPIC_API_KEY or OPENAI_API_KEY, or configure models in ~/.kiso/config.json]\n");
|
|
786
787
|
setCurrentFaux(true);
|
|
787
788
|
setCurrentModelName("faux");
|
|
789
|
+
setCurrentProfileName(null);
|
|
788
790
|
}
|
|
789
791
|
else {
|
|
790
792
|
setCurrentFaux(false);
|
|
791
793
|
setCurrentModelName(resolved.name);
|
|
794
|
+
setCurrentProfileName(resolved.name);
|
|
792
795
|
}
|
|
793
796
|
setAgentModel(model, resolved?.profile.baseUrl); // v2b: the status bar shows it; OR-1: the endpoint rides along
|
|
797
|
+
// ADR-0055 Amendment 2: the row says `ctx ?` for an unstated window, but
|
|
798
|
+
// the tiers still need a number and assume 200K — say so, once, at build.
|
|
799
|
+
if (!unknownWindowNoticed && knownContextWindow() === null) {
|
|
800
|
+
unknownWindowNoticed = true;
|
|
801
|
+
console.error(unknownWindowNotice(model));
|
|
802
|
+
}
|
|
794
803
|
// W21: the extensions array is built ONCE per agent and shared with
|
|
795
804
|
// the runtime by reference — the don't-ask-again writer pushes the
|
|
796
805
|
// generated extension into it so a first-time rule joins the chain
|
|
@@ -857,7 +866,16 @@ async function makeAgent(sessionId, input, modelFlag) {
|
|
|
857
866
|
// 1 reads the user's configured checks first, then the runner table.
|
|
858
867
|
contextPolicy: {
|
|
859
868
|
...(contextPolicy ?? {}),
|
|
860
|
-
tiers: {
|
|
869
|
+
tiers: {
|
|
870
|
+
windowTokens: contextWindowTokens(),
|
|
871
|
+
isCheck: (command) => runsACheck(command, Object.values(merged.checks ?? {})),
|
|
872
|
+
// ADR-0055 Amendment 2: a discarded checkpoint says so, in sizes only.
|
|
873
|
+
onDiscard: (d) => body.notice(compactionDiscardedNotice(d)),
|
|
874
|
+
// ADR-0055 Amendment 2 (decision 3): only a window someone stated
|
|
875
|
+
// arms the overflow belt — read from the LIVE binding, so it moves
|
|
876
|
+
// with /model and /resume; the 200K fallback reads as null.
|
|
877
|
+
statedWindow: () => knownContextWindow(),
|
|
878
|
+
},
|
|
861
879
|
},
|
|
862
880
|
// R3e (owner ruling, 2026-08-28): NO turn limit on an interactive
|
|
863
881
|
// session. This was `maxTurns: 20`, hardcoded on 2026-08-03 with no
|
|
@@ -1106,6 +1124,7 @@ async function pickSession(agent, input) {
|
|
|
1106
1124
|
* once; 0.41.0 removes it.
|
|
1107
1125
|
*/
|
|
1108
1126
|
let autoCompactNoticed = false;
|
|
1127
|
+
let unknownWindowNoticed = false;
|
|
1109
1128
|
function retiredAutoCompact(merged) {
|
|
1110
1129
|
if (!autoCompactNoticed && (process.env.KISO_AUTO_COMPACT !== undefined || resolveAutoCompact(merged) !== undefined)) {
|
|
1111
1130
|
autoCompactNoticed = true;
|
|
@@ -1134,13 +1153,15 @@ function retiredAutoCompact(merged) {
|
|
|
1134
1153
|
* threshold got stuck in the first place.
|
|
1135
1154
|
*/
|
|
1136
1155
|
function bindRestoredSession(session) {
|
|
1137
|
-
// 0.40.
|
|
1138
|
-
//
|
|
1156
|
+
// 0.40.1 (the owner's ruling of 2026-09-21): a changed binding is neither
|
|
1157
|
+
// blocked nor "acknowledged" — it is recorded as the next revision under
|
|
1158
|
+
// the CURRENT configuration, and this ONE line says which binding and why
|
|
1159
|
+
// (the owner-ruled reasoning reset rides with it, silently until 0.40.0).
|
|
1139
1160
|
const ack = session.driftAcknowledgement ?? null;
|
|
1140
1161
|
if (ack !== null) {
|
|
1141
1162
|
const was = ack.reasoningReset;
|
|
1142
1163
|
const prior = [was.effort !== "default" ? `effort ${was.effort}` : "", was.thinking !== "default" ? `thinking ${was.thinking}` : ""].filter((s) => s !== "").join(", ");
|
|
1143
|
-
bodyLog(`
|
|
1164
|
+
bodyLog(`binding changed — now on ${session.model}: ${ack.reasons.join("; ")}; reasoning reset to defaults${prior === "" ? "" : ` (was ${prior})`}`);
|
|
1144
1165
|
}
|
|
1145
1166
|
setAgentModel(session.model, session.baseUrl);
|
|
1146
1167
|
session.setMicrocompactThreshold(microcompactThresholdFor({
|
|
@@ -1261,6 +1282,7 @@ async function reloadAgent(old, id, input, announce = true) {
|
|
|
1261
1282
|
setConfiguredWindow(oldCfg.window);
|
|
1262
1283
|
setCurrentFaux(oldCfg.faux);
|
|
1263
1284
|
setCurrentModelName(oldCfg.modelName);
|
|
1285
|
+
setCurrentProfileName(null); // the reload snapshot carries no profile name: no mark beats a guessed one
|
|
1264
1286
|
setModelChoice(oldCfg.choice);
|
|
1265
1287
|
setAgentModel(oldCfg.agent, oldCfg.endpoint);
|
|
1266
1288
|
if (oldCfg.delegation === undefined)
|
|
@@ -1294,6 +1316,15 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1294
1316
|
// reload said what it did; repeating the session's opening would read
|
|
1295
1317
|
// as a new session, which is the one thing it is not.
|
|
1296
1318
|
let rebuilt = false;
|
|
1319
|
+
// XP-1: the id of the session that IS open — null until the first open
|
|
1320
|
+
// succeeds, and cleared by a refused switch, so one refusal can never
|
|
1321
|
+
// recurse into another.
|
|
1322
|
+
let opened = null;
|
|
1323
|
+
// XP-1: the re-open that follows a refused switch. The session is the one
|
|
1324
|
+
// already on screen, so this step prints neither banner nor tail.
|
|
1325
|
+
let refused = false;
|
|
1326
|
+
/** DC-57: lines that arrived with a switch command belong to the session being asked for. */
|
|
1327
|
+
let seed = [];
|
|
1297
1328
|
for (;;) {
|
|
1298
1329
|
// 0.40.0 (the lead's ruling): a session opens in the folder that holds
|
|
1299
1330
|
// it, never moved — a switch that crosses folders rebuilds the agent
|
|
@@ -1318,10 +1349,50 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1318
1349
|
}
|
|
1319
1350
|
agent = next;
|
|
1320
1351
|
}
|
|
1321
|
-
|
|
1352
|
+
let session;
|
|
1353
|
+
try {
|
|
1354
|
+
session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
1355
|
+
}
|
|
1356
|
+
catch (err) {
|
|
1357
|
+
// The profile contract's BLOCKED cases — a sidecar that cannot be
|
|
1358
|
+
// read, an XP-era log without one — belong to the ENTRY: nothing is
|
|
1359
|
+
// on screen yet, and the message says what to do. An in-session
|
|
1360
|
+
// SWITCH is a LINE: it switches NOTHING and the session you were in
|
|
1361
|
+
// stays open. The throw used to escape chatLoop, which killed the
|
|
1362
|
+
// REPL and left the session that was open behind with no log at all
|
|
1363
|
+
// (announced once, then empty and unopenable). Every refusal this
|
|
1364
|
+
// open can throw is treated the same way — the message itself is
|
|
1365
|
+
// what says what to do about it.
|
|
1366
|
+
if (opened === null)
|
|
1367
|
+
throw err;
|
|
1368
|
+
bodyLog(escapeTerminal(err.message));
|
|
1369
|
+
// DC-57's other half + DC-55 (the owner's ruling of 2026-09-21,
|
|
1370
|
+
// option ①): the lines that arrived WITH the refused switch were aimed
|
|
1371
|
+
// at a session that EXISTS and could not be opened. They are NOT run
|
|
1372
|
+
// here — a departing session never answers lines meant for the target —
|
|
1373
|
+
// and not dropped in silence either: what was held is printed, so
|
|
1374
|
+
// nothing vanishes without the person seeing it. (Leaving them in the
|
|
1375
|
+
// queue would hand them to the old session on its next entry, which is
|
|
1376
|
+
// the thing this ruling forbids.)
|
|
1377
|
+
seed = [];
|
|
1378
|
+
const held = queuedSwitchLines.splice(0);
|
|
1379
|
+
if (held.length > 0) {
|
|
1380
|
+
bodyLog(`[${held.length} line${held.length === 1 ? "" : "s"} held back — the switch was refused, so nothing was run]`);
|
|
1381
|
+
for (const line of held)
|
|
1382
|
+
bodyLog(` ${escapeTerminal(line)}`);
|
|
1383
|
+
}
|
|
1384
|
+
id = opened; // the switch is undone
|
|
1385
|
+
opened = null;
|
|
1386
|
+
refused = true;
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1389
|
+
opened = id;
|
|
1322
1390
|
if (rebuilt) {
|
|
1323
1391
|
rebuilt = false;
|
|
1324
1392
|
}
|
|
1393
|
+
else if (refused) {
|
|
1394
|
+
refused = false; // back in the session that was already on screen
|
|
1395
|
+
}
|
|
1325
1396
|
else if (prev === null) {
|
|
1326
1397
|
bodyLog(`session ${id}\n`);
|
|
1327
1398
|
// REL-0152-D5: a session with history says what that history WAS.
|
|
@@ -1379,6 +1450,12 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1379
1450
|
// the threshold. One step, shared by all three entry points.
|
|
1380
1451
|
bindRestoredSession(session);
|
|
1381
1452
|
setCurrentModelName(session.model);
|
|
1453
|
+
// A SWITCH knows only a model id here — nothing that names the profile —
|
|
1454
|
+
// so the mark is cleared rather than guessed. A FRESH start keeps what
|
|
1455
|
+
// makeAgent resolved from `--model <profile>`, which is the one place
|
|
1456
|
+
// the name is known (prev is null only on the first entry).
|
|
1457
|
+
if (prev !== null)
|
|
1458
|
+
setCurrentProfileName(null);
|
|
1382
1459
|
paintBootStatus(session);
|
|
1383
1460
|
// The terminal's window title, HERE for the same reason the three
|
|
1384
1461
|
// lines above are here: this is the one step all three entry points
|
|
@@ -1392,9 +1469,12 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1392
1469
|
route: (sessionId) => routeSession(sessionId),
|
|
1393
1470
|
...(process.stdin.isTTY ? { pick: () => pickSession(agent, input) } : {}),
|
|
1394
1471
|
};
|
|
1395
|
-
const end = await chat(session, currentFaux, input, autoCompact, nav);
|
|
1472
|
+
const end = await chat(session, currentFaux, input, autoCompact, nav, seed);
|
|
1396
1473
|
if (end.next === "exit")
|
|
1397
1474
|
return;
|
|
1475
|
+
// DC-57: the lines that arrived with the switch command ride INTO the
|
|
1476
|
+
// next entry — they were aimed at the session being asked for.
|
|
1477
|
+
seed = end.lines ?? [];
|
|
1398
1478
|
if (end.next === "reload") {
|
|
1399
1479
|
agent = await reloadAgent(agent, id, input);
|
|
1400
1480
|
rebuilt = true;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider's NAME on screen — the host the request will actually go to.
|
|
3
|
+
*
|
|
4
|
+
* The owner, 2026-09-21: switching models must say WHO is being billed. Two
|
|
5
|
+
* profiles can name the same model id and reach two different accounts; the
|
|
6
|
+
* model id alone leaves the person unable to tell which one they are about
|
|
7
|
+
* to spend, which is exactly the mistake a picker exists to prevent.
|
|
8
|
+
*
|
|
9
|
+
* The fact is already in hand: `agentBaseUrl` rides with `agentModel` (one
|
|
10
|
+
* `setAgentModel(model, baseUrl)` call, so the two cannot drift), and a
|
|
11
|
+
* profile's `baseUrl` is what its row shows. This module turns that URL into
|
|
12
|
+
* the one label worth spending columns on — the HOST — with the provider id
|
|
13
|
+
* as the fallback for a binding that names no URL at all.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately not a new rule: `providerIdOf` (auth/credentials) is the CLI's
|
|
16
|
+
* copy of the runtime's origin rule (KNOWN_ORIGINS / resolveContinuationScope),
|
|
17
|
+
* and this function only chooses what to PRINT from the same inputs.
|
|
18
|
+
*/
|
|
19
|
+
/** The host of a base URL, without scheme, credentials or any path:
|
|
20
|
+
* `https://api.commandcode.ai/provider/v1` → `commandcode.ai`.
|
|
21
|
+
*
|
|
22
|
+
* `null` when there is no URL to read — never a guess. A URL that does not
|
|
23
|
+
* parse is not invented either: the caller falls back to the provider id. */
|
|
24
|
+
export declare function providerHost(baseUrl?: string): string | null;
|
|
25
|
+
/** `@commandcode.ai` — the provider named beside a model. `""` when the
|
|
26
|
+
* binding names no endpoint (the provider's own default origin), so a row
|
|
27
|
+
* that has nothing to say does not print a stray `@`. */
|
|
28
|
+
export declare function providerLabel(baseUrl?: string): string;
|
|
29
|
+
/** The same label for a PROFILE, which knows its kind as well as its URL: a
|
|
30
|
+
* profile with no baseUrl (a first-party provider) still names itself by
|
|
31
|
+
* providerId, because a row that shows two profiles must tell them apart. */
|
|
32
|
+
export declare function profileProviderLabel(kind: string, baseUrl?: string): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider's NAME on screen — the host the request will actually go to.
|
|
3
|
+
*
|
|
4
|
+
* The owner, 2026-09-21: switching models must say WHO is being billed. Two
|
|
5
|
+
* profiles can name the same model id and reach two different accounts; the
|
|
6
|
+
* model id alone leaves the person unable to tell which one they are about
|
|
7
|
+
* to spend, which is exactly the mistake a picker exists to prevent.
|
|
8
|
+
*
|
|
9
|
+
* The fact is already in hand: `agentBaseUrl` rides with `agentModel` (one
|
|
10
|
+
* `setAgentModel(model, baseUrl)` call, so the two cannot drift), and a
|
|
11
|
+
* profile's `baseUrl` is what its row shows. This module turns that URL into
|
|
12
|
+
* the one label worth spending columns on — the HOST — with the provider id
|
|
13
|
+
* as the fallback for a binding that names no URL at all.
|
|
14
|
+
*
|
|
15
|
+
* Deliberately not a new rule: `providerIdOf` (auth/credentials) is the CLI's
|
|
16
|
+
* copy of the runtime's origin rule (KNOWN_ORIGINS / resolveContinuationScope),
|
|
17
|
+
* and this function only chooses what to PRINT from the same inputs.
|
|
18
|
+
*/
|
|
19
|
+
import { providerIdOf } from "./auth/credentials.js";
|
|
20
|
+
/** The host of a base URL, without scheme, credentials or any path:
|
|
21
|
+
* `https://api.commandcode.ai/provider/v1` → `commandcode.ai`.
|
|
22
|
+
*
|
|
23
|
+
* `null` when there is no URL to read — never a guess. A URL that does not
|
|
24
|
+
* parse is not invented either: the caller falls back to the provider id. */
|
|
25
|
+
export function providerHost(baseUrl) {
|
|
26
|
+
if (baseUrl === undefined || baseUrl.trim() === "")
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
const url = new URL(baseUrl);
|
|
30
|
+
// REVIEW (2026-09-21): `host`, not `hostname` — the PORT is part of the
|
|
31
|
+
// answer this label exists to give (`localhost:11434` and
|
|
32
|
+
// `localhost:8000` are two different places to spend, and both read as
|
|
33
|
+
// `@localhost` under `hostname`).
|
|
34
|
+
const host = url.host;
|
|
35
|
+
return host === "" ? null : host;
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** `@commandcode.ai` — the provider named beside a model. `""` when the
|
|
42
|
+
* binding names no endpoint (the provider's own default origin), so a row
|
|
43
|
+
* that has nothing to say does not print a stray `@`. */
|
|
44
|
+
export function providerLabel(baseUrl) {
|
|
45
|
+
const host = providerHost(baseUrl);
|
|
46
|
+
return host === null ? "" : `@${host}`;
|
|
47
|
+
}
|
|
48
|
+
/** The same label for a PROFILE, which knows its kind as well as its URL: a
|
|
49
|
+
* profile with no baseUrl (a first-party provider) still names itself by
|
|
50
|
+
* providerId, because a row that shows two profiles must tell them apart. */
|
|
51
|
+
export function profileProviderLabel(kind, baseUrl) {
|
|
52
|
+
return providerLabel(baseUrl) || `@${providerIdOf(kind, baseUrl)}`;
|
|
53
|
+
}
|
package/dist/state.d.ts
CHANGED
|
@@ -275,6 +275,19 @@ export declare let modelChoice: string | undefined;
|
|
|
275
275
|
export declare function setModelChoice(value: string | undefined): void;
|
|
276
276
|
export declare let currentModelName: string;
|
|
277
277
|
export declare function setCurrentModelName(value: string): void;
|
|
278
|
+
/** REVIEW (2026-09-21): WHO the binding came from is a different fact from
|
|
279
|
+
* WHICH model it names, and `currentModelName` carried both — a profile alias
|
|
280
|
+
* after `/model`, a model id after a switch, a resume or a reload. Surfaces
|
|
281
|
+
* that want to name the PROFILE ask this one; an unknown profile is null, and
|
|
282
|
+
* nothing guesses a credential identity out of a model name and a host. */
|
|
283
|
+
export declare let currentProfileName: string | null;
|
|
284
|
+
export declare function setCurrentProfileName(value: string | null): void;
|
|
285
|
+
/** DC-57 (the owner's ruling, 2026-09-21): lines that arrived with a switch
|
|
286
|
+
* command — a paste, a pipe, a scripted driver — belong to the session the
|
|
287
|
+
* person asked for. The departing entry queues them here and the next
|
|
288
|
+
* `chat()` drains them into its own replay, so no line is answered by the
|
|
289
|
+
* session being left and none is dropped. */
|
|
290
|
+
export declare const queuedSwitchLines: string[];
|
|
278
291
|
/** E1: the extensions loaded by makeAgent — their names feed the banner. */
|
|
279
292
|
/** 0.40.0: whether the catastrophe floor is on (floor.ts) — the user
|
|
280
293
|
* config's `floor`, read where the chain is assembled. */
|
package/dist/state.js
CHANGED
|
@@ -368,6 +368,21 @@ export let currentModelName = "faux";
|
|
|
368
368
|
export function setCurrentModelName(value) {
|
|
369
369
|
currentModelName = value;
|
|
370
370
|
}
|
|
371
|
+
/** REVIEW (2026-09-21): WHO the binding came from is a different fact from
|
|
372
|
+
* WHICH model it names, and `currentModelName` carried both — a profile alias
|
|
373
|
+
* after `/model`, a model id after a switch, a resume or a reload. Surfaces
|
|
374
|
+
* that want to name the PROFILE ask this one; an unknown profile is null, and
|
|
375
|
+
* nothing guesses a credential identity out of a model name and a host. */
|
|
376
|
+
export let currentProfileName = null;
|
|
377
|
+
export function setCurrentProfileName(value) {
|
|
378
|
+
currentProfileName = value;
|
|
379
|
+
}
|
|
380
|
+
/** DC-57 (the owner's ruling, 2026-09-21): lines that arrived with a switch
|
|
381
|
+
* command — a paste, a pipe, a scripted driver — belong to the session the
|
|
382
|
+
* person asked for. The departing entry queues them here and the next
|
|
383
|
+
* `chat()` drains them into its own replay, so no line is answered by the
|
|
384
|
+
* session being left and none is dropped. */
|
|
385
|
+
export const queuedSwitchLines = [];
|
|
371
386
|
/** E1: the extensions loaded by makeAgent — their names feed the banner. */
|
|
372
387
|
/** 0.40.0: whether the catastrophe floor is on (floor.ts) — the user
|
|
373
388
|
* config's `floor`, read where the chain is assembled. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.2",
|
|
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",
|
|
@@ -18,20 +18,20 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.40.
|
|
22
|
-
"@vincemakes/kiso-core": "0.40.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.40.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.40.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.40.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.40.
|
|
27
|
-
"@vincemakes/kiso-provider-openai-responses": "0.40.
|
|
28
|
-
"@vincemakes/kiso-runtime": "0.40.
|
|
29
|
-
"@vincemakes/kiso-skills-ext": "0.40.
|
|
30
|
-
"@vincemakes/kiso-subagent-ext": "0.40.
|
|
31
|
-
"@vincemakes/kiso-task-ext": "0.40.
|
|
32
|
-
"@vincemakes/kiso-tools-node": "0.40.
|
|
33
|
-
"@vincemakes/kiso-tui": "0.40.
|
|
34
|
-
"@vincemakes/kiso-tui-cells": "0.40.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.40.2",
|
|
22
|
+
"@vincemakes/kiso-core": "0.40.2",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.40.2",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.40.2",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.40.2",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.40.2",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.40.2",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.40.2",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.40.2",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.40.2",
|
|
31
|
+
"@vincemakes/kiso-task-ext": "0.40.2",
|
|
32
|
+
"@vincemakes/kiso-tools-node": "0.40.2",
|
|
33
|
+
"@vincemakes/kiso-tui": "0.40.2",
|
|
34
|
+
"@vincemakes/kiso-tui-cells": "0.40.2"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^26.1.2",
|