@vincemakes/kiso-code 0.15.12 → 0.16.1
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/dispatch.js +42 -9
- package/dist/index.js +27 -5
- package/dist/session-cards.js +14 -2
- package/dist/state.d.ts +15 -0
- package/dist/state.js +17 -0
- package/package.json +14 -14
package/dist/dispatch.js
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { contextRows, contextUnavailableRows, displayVerb, escapeTerminal, helpRows, kUnit, modelPickView, palette } from "@vincemakes/kiso-tui";
|
|
7
7
|
import { newSessionId } from "./session-id.js";
|
|
8
|
-
import { buildAdapter } from "@vincemakes/kiso-runtime/internal";
|
|
8
|
+
import { buildAdapter, resolveContinuationScope, resolveReasoning } from "@vincemakes/kiso-runtime/internal";
|
|
9
9
|
import { MODES, getMode, setMode } from "./mode.js";
|
|
10
|
-
import { agentModel, body, bodyLog, configModels, dock, readContextLedger, sessionsDir, setAgentModel, setCurrentModelName } from "./state.js";
|
|
10
|
+
import { agentModel, body, bodyLog, configModels, dock, readContextLedger, sessionsDir, setAgentModel, setCurrentModelName, setLastBinding } from "./state.js";
|
|
11
11
|
import { directWriteProfile, profileAvailable } from "./config.js";
|
|
12
12
|
/** The ONE dispatcher — slash commands, exit, and turns. The recovery
|
|
13
13
|
* replay routes through it too — a queued "/last" must never become a
|
|
@@ -228,10 +228,15 @@ export function dispatch(line, ctx) {
|
|
|
228
228
|
}
|
|
229
229
|
else {
|
|
230
230
|
try {
|
|
231
|
-
|
|
232
|
-
|
|
231
|
+
// XP-1: /model owns the model PLUS the reasoning selector —
|
|
232
|
+
// an optional second token is the effort, validated
|
|
233
|
+
// against the NATIVE matrix (refused with the levels
|
|
234
|
+
// named; never silently downgraded).
|
|
235
|
+
const [profName = "", effortTok] = arg.split(/\s+/);
|
|
236
|
+
const direct = directWriteProfile(profName);
|
|
237
|
+
const profile = direct ?? configModels[profName];
|
|
233
238
|
if (profile === undefined) {
|
|
234
|
-
bodyLog(`no such model profile: ${
|
|
239
|
+
bodyLog(`no such model profile: ${profName}`);
|
|
235
240
|
}
|
|
236
241
|
else if (!profileAvailable(profile)) {
|
|
237
242
|
bodyLog(`model ${arg}: unavailable — the env var ${profile.apiKeyEnv} is not set (configs never store keys, only the env-var name)`);
|
|
@@ -250,10 +255,38 @@ export function dispatch(line, ctx) {
|
|
|
250
255
|
// carrying the OLD model, so the status row claimed the
|
|
251
256
|
// new model while every request still sent the old id
|
|
252
257
|
// (and usage canonicalized under the old route).
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
258
|
+
// MG-1 (A5): the scope moves WITH the adapter — the same
|
|
259
|
+
// atomic switch PH-F8 demanded, one more passenger.
|
|
260
|
+
const scope = resolveContinuationScope(profile.kind, profile.model, profile.baseUrl);
|
|
261
|
+
let reasoning;
|
|
262
|
+
let refused = null;
|
|
263
|
+
if (effortTok !== undefined) {
|
|
264
|
+
const candidate = { thinking: "default", effort: effortTok };
|
|
265
|
+
const resolved = resolveReasoning(profile.model, candidate);
|
|
266
|
+
if (resolved.ok)
|
|
267
|
+
reasoning = candidate;
|
|
268
|
+
else
|
|
269
|
+
refused = resolved.reason;
|
|
270
|
+
}
|
|
271
|
+
if (refused !== null) {
|
|
272
|
+
// native-only, never a silent downgrade: the switch
|
|
273
|
+
// does NOT happen — the refusal names the levels.
|
|
274
|
+
bodyLog(refused);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
const binding = {
|
|
278
|
+
adapter,
|
|
279
|
+
model: profile.model,
|
|
280
|
+
provider: profile.kind,
|
|
281
|
+
...(scope !== undefined ? { scope } : {}),
|
|
282
|
+
...(reasoning !== undefined ? { reasoning } : {}),
|
|
283
|
+
};
|
|
284
|
+
ctx.session.setModelBinding(binding);
|
|
285
|
+
setLastBinding(binding);
|
|
286
|
+
setAgentModel(profile.model);
|
|
287
|
+
setCurrentModelName(arg);
|
|
288
|
+
body.notice(`model → ${profName} (${profile.model}${effortTok !== undefined ? ` · ${effortTok}` : ""}) — takes effect on the next turn`);
|
|
289
|
+
}
|
|
257
290
|
}
|
|
258
291
|
}
|
|
259
292
|
catch (err) {
|
package/dist/index.js
CHANGED
|
@@ -34,7 +34,7 @@ import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
|
34
34
|
import { createCodingTools } from "@vincemakes/kiso-tools-node";
|
|
35
35
|
import { MODES, getMode, modeExtensions, modeFromEnv, modeSystemPrompt, setMode } from "./mode.js";
|
|
36
36
|
import { builtInLayer } from "./builtin.js";
|
|
37
|
-
import { agentModel, atFiles, body, bodyLog, kisoHome, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, projectExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setMergedConfig, setSessionStore, userExtensions, VERSION } from "./state.js";
|
|
37
|
+
import { agentModel, atFiles, body, bodyLog, kisoHome, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, projectExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setMergedConfig, setSessionStore, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift } from "./state.js";
|
|
38
38
|
import { askUi, resolveProjectTrust } from "./trust-ui.js";
|
|
39
39
|
import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
|
|
40
40
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
@@ -299,7 +299,7 @@ async function recentSessions(id, agent) {
|
|
|
299
299
|
for (const m of picked) {
|
|
300
300
|
let badge;
|
|
301
301
|
if (store !== null) {
|
|
302
|
-
const session = await agent.session({ id: m.id });
|
|
302
|
+
const session = await agent.session({ id: m.id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
303
303
|
const card = projectSessionCard({ id: m.id, updatedAt: m.updatedAt, records: store.load(m.id), asks: session.pendingApprovals().length });
|
|
304
304
|
badge = BADGE_GLYPH[card.badge];
|
|
305
305
|
}
|
|
@@ -598,7 +598,7 @@ async function chatLoop(agent, firstId, input, autoCompact) {
|
|
|
598
598
|
let id = firstId;
|
|
599
599
|
let prev = null;
|
|
600
600
|
for (;;) {
|
|
601
|
-
const session = await agent.session({ id });
|
|
601
|
+
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
602
602
|
if (prev === null) {
|
|
603
603
|
bodyLog(`session ${id}\n`);
|
|
604
604
|
// REL-0152-D5: a session with history says what that history WAS.
|
|
@@ -617,6 +617,18 @@ async function chatLoop(agent, firstId, input, autoCompact) {
|
|
|
617
617
|
if (currentFaux)
|
|
618
618
|
session.setAdapter(createFauxProvider(readFauxScript().slice(fauxSkip(id))));
|
|
619
619
|
}
|
|
620
|
+
// XP-1 §3.3.6: a /clear-fresh session INHERITS the live selection,
|
|
621
|
+
// recorded as its next revision — clearing context never silently
|
|
622
|
+
// reverts the model.
|
|
623
|
+
const inherited = lastBinding();
|
|
624
|
+
if (session.log.all.length === 0 && inherited !== null && !currentFaux) {
|
|
625
|
+
session.setModelBinding(inherited);
|
|
626
|
+
}
|
|
627
|
+
// XP-1 §2.1: the switched-to session's OWN truth repaints the row —
|
|
628
|
+
// the global display state never outlives the session it described
|
|
629
|
+
// (pre-XP the row kept the previous session's /model selection).
|
|
630
|
+
setAgentModel(session.model);
|
|
631
|
+
setCurrentModelName(session.model);
|
|
620
632
|
paintBootStatus(session);
|
|
621
633
|
const nav = {
|
|
622
634
|
sessions: () => agent.sessions().map((m) => m.id),
|
|
@@ -646,6 +658,16 @@ async function main() {
|
|
|
646
658
|
// first makeAgent (the tier extensions read `current` live). The flag
|
|
647
659
|
// is stripped from the positional args, so it works in any position.
|
|
648
660
|
const args = process.argv.slice(2);
|
|
661
|
+
// XP-1: --accept-drift (a flag, never an env var) authorizes opening a
|
|
662
|
+
// session whose recorded profile materially drifted — the
|
|
663
|
+
// acknowledgement is recorded as a new revision by the runtime.
|
|
664
|
+
{
|
|
665
|
+
const i = args.indexOf("--accept-drift");
|
|
666
|
+
if (i !== -1) {
|
|
667
|
+
args.splice(i, 1);
|
|
668
|
+
setAcceptDrift(true);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
649
671
|
// PH-1a (finding PH-F2): --help/-h/--version/-v are FLAGS, not session
|
|
650
672
|
// ids. They used to fall through the default case and START A SESSION
|
|
651
673
|
// literally named "--help" (writing ~/.kiso/sessions/--help.jsonl) —
|
|
@@ -793,7 +815,7 @@ async function main() {
|
|
|
793
815
|
const id = command ?? newSessionId(sessionsDir());
|
|
794
816
|
agent = await makeAgent(id, input, modelFlag);
|
|
795
817
|
applyConfigMode();
|
|
796
|
-
const session = await agent.session({ id });
|
|
818
|
+
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
797
819
|
faux = currentFaux;
|
|
798
820
|
await resume(session, printPrompt, faux, input);
|
|
799
821
|
const last = [...session.log.all].reverse().find((e) => e.type === "terminal");
|
|
@@ -847,7 +869,7 @@ async function main() {
|
|
|
847
869
|
await chatLoop(agent, picked, input, resolveAutoCompact(mergedConfig));
|
|
848
870
|
break;
|
|
849
871
|
}
|
|
850
|
-
const session = await agent.session({ id });
|
|
872
|
+
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
851
873
|
faux = currentFaux;
|
|
852
874
|
// E area: the durable script position is computed from the
|
|
853
875
|
// session id, and on the picker path the id did not exist when
|
package/dist/session-cards.js
CHANGED
|
@@ -88,8 +88,20 @@ export function projectSessionCard(input) {
|
|
|
88
88
|
export async function collectSessionCards(agent, load) {
|
|
89
89
|
const cards = [];
|
|
90
90
|
for (const meta of [...agent.sessions()].sort((a, b) => b.updatedAt - a.updatedAt)) {
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
// XP-1: the LISTING never enforces the profile contract — a session
|
|
92
|
+
// whose recorded profile drifted (or whose sidecar is damaged) still
|
|
93
|
+
// LISTS; the honest refusal happens at the open, where the message
|
|
94
|
+
// can be acted on. acceptDrift is never passed here: it RECORDS an
|
|
95
|
+
// acknowledgement, and a listing must write nothing.
|
|
96
|
+
let asks = 0;
|
|
97
|
+
try {
|
|
98
|
+
const session = await agent.session({ id: meta.id });
|
|
99
|
+
asks = session.pendingApprovals().length;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
// blocked by the profile contract — the card carries no ask badge
|
|
103
|
+
}
|
|
104
|
+
cards.push(projectSessionCard({ id: meta.id, updatedAt: meta.updatedAt, records: load(meta.id), asks }));
|
|
93
105
|
}
|
|
94
106
|
return cards;
|
|
95
107
|
}
|
package/dist/state.d.ts
CHANGED
|
@@ -195,3 +195,18 @@ export declare const VERSION: string;
|
|
|
195
195
|
* real user answer (the empty line). The empty answer and the cancellation
|
|
196
196
|
* are distinct facts. */
|
|
197
197
|
export declare const CANCELLED: unique symbol;
|
|
198
|
+
/** XP-1: the last EXPLICIT model binding this process applied — a
|
|
199
|
+
* /clear-fresh session inherits it (clearing context never silently
|
|
200
|
+
* reverts the model). Never persisted here; the runtime records the
|
|
201
|
+
* durable revision when the binding is applied. */
|
|
202
|
+
export interface LastBinding {
|
|
203
|
+
readonly adapter: import("@vincemakes/kiso-core").Adapter;
|
|
204
|
+
readonly model: string;
|
|
205
|
+
readonly provider?: "anthropic" | "openai-compat";
|
|
206
|
+
readonly scope?: import("@vincemakes/kiso-core").ContinuationScope;
|
|
207
|
+
readonly reasoning?: import("@vincemakes/kiso-runtime/internal").ReasoningSetting;
|
|
208
|
+
}
|
|
209
|
+
export declare function setLastBinding(b: LastBinding): void;
|
|
210
|
+
export declare function lastBinding(): LastBinding | null;
|
|
211
|
+
export declare function setAcceptDrift(v: boolean): void;
|
|
212
|
+
export declare function acceptDrift(): boolean;
|
package/dist/state.js
CHANGED
|
@@ -251,3 +251,20 @@ export const VERSION = (() => {
|
|
|
251
251
|
* real user answer (the empty line). The empty answer and the cancellation
|
|
252
252
|
* are distinct facts. */
|
|
253
253
|
export const CANCELLED = Symbol("kiso-question-cancelled");
|
|
254
|
+
let lastBindingValue = null;
|
|
255
|
+
export function setLastBinding(b) {
|
|
256
|
+
lastBindingValue = b;
|
|
257
|
+
}
|
|
258
|
+
export function lastBinding() {
|
|
259
|
+
return lastBindingValue;
|
|
260
|
+
}
|
|
261
|
+
/** XP-1 (the adjudicated Q6): --accept-drift is a per-invocation FLAG,
|
|
262
|
+
* never an env var — a standing env would be a silent policy, the exact
|
|
263
|
+
* failure the drift protocol forbids. */
|
|
264
|
+
let acceptDriftValue = false;
|
|
265
|
+
export function setAcceptDrift(v) {
|
|
266
|
+
acceptDriftValue = v;
|
|
267
|
+
}
|
|
268
|
+
export function acceptDrift() {
|
|
269
|
+
return acceptDriftValue;
|
|
270
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "kiso CLI \u2014 the durable coding agent that survives kill -9: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,19 +18,19 @@
|
|
|
18
18
|
"test": "vitest run"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@vincemakes/kiso-ask-ext": "0.
|
|
22
|
-
"@vincemakes/kiso-core": "0.
|
|
23
|
-
"@vincemakes/kiso-evals": "0.
|
|
24
|
-
"@vincemakes/kiso-mcp-ext": "0.
|
|
25
|
-
"@vincemakes/kiso-provider-anthropic": "0.
|
|
26
|
-
"@vincemakes/kiso-provider-openai": "0.
|
|
27
|
-
"@vincemakes/kiso-runtime": "0.
|
|
28
|
-
"@vincemakes/kiso-skills-ext": "0.
|
|
29
|
-
"@vincemakes/kiso-subagent-ext": "0.
|
|
30
|
-
"@vincemakes/kiso-task-ext": "0.
|
|
31
|
-
"@vincemakes/kiso-tools-node": "0.
|
|
32
|
-
"@vincemakes/kiso-tui": "0.
|
|
33
|
-
"@vincemakes/kiso-tui-cells": "0.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.16.1",
|
|
22
|
+
"@vincemakes/kiso-core": "0.16.1",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.16.1",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.16.1",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.16.1",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.16.1",
|
|
27
|
+
"@vincemakes/kiso-runtime": "0.16.1",
|
|
28
|
+
"@vincemakes/kiso-skills-ext": "0.16.1",
|
|
29
|
+
"@vincemakes/kiso-subagent-ext": "0.16.1",
|
|
30
|
+
"@vincemakes/kiso-task-ext": "0.16.1",
|
|
31
|
+
"@vincemakes/kiso-tools-node": "0.16.1",
|
|
32
|
+
"@vincemakes/kiso-tui": "0.16.1",
|
|
33
|
+
"@vincemakes/kiso-tui-cells": "0.16.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^26.1.2",
|