@vincemakes/kiso-code 0.34.0 → 0.37.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/auth/adapter-options.d.ts +22 -0
- package/dist/auth/adapter-options.js +57 -0
- package/dist/auth/credentials.d.ts +23 -0
- package/dist/auth/credentials.js +39 -9
- package/dist/breaker.d.ts +2 -2
- package/dist/breaker.js +2 -2
- package/dist/builtin.d.ts +6 -1
- package/dist/builtin.js +7 -2
- package/dist/chat.d.ts +101 -14
- package/dist/chat.js +194 -53
- package/dist/config.d.ts +16 -1
- package/dist/config.js +48 -21
- package/dist/dispatch.js +33 -15
- package/dist/index.d.ts +1 -1
- package/dist/index.js +129 -28
- package/dist/mode.d.ts +10 -1
- package/dist/mode.js +15 -6
- package/dist/state.d.ts +10 -0
- package/dist/state.js +16 -1
- package/package.json +16 -16
package/dist/index.js
CHANGED
|
@@ -37,13 +37,13 @@ import { createCodingTools } from "@vincemakes/kiso-tools-node";
|
|
|
37
37
|
import { MODES, getMode, modeExtensions, modeFromEnv, modeSystemPrompt, setMode } from "./mode.js";
|
|
38
38
|
import { breakerExtension } from "./breaker.js";
|
|
39
39
|
import { builtInLayer } from "./builtin.js";
|
|
40
|
-
import { agentModel, atFiles, body, bodyLog, codingToolOptions, kisoHome, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, modelChoice, projectExtensions, configModels, configuredWindow, agentBaseUrl, currentModelName, currentAgentExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setMergedConfig, setModelChoice, setSessionStore, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift } from "./state.js";
|
|
40
|
+
import { agentModel, atFiles, body, bodyLog, codingToolOptions, kisoHome, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, modelChoice, projectExtensions, configModels, configuredWindow, agentBaseUrl, currentModelName, currentAgentExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setMergedConfig, setModelChoice, setSessionStore, secretEnvNamesOf, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift } from "./state.js";
|
|
41
41
|
import { askUi, resolveProjectTrust } from "./trust-ui.js";
|
|
42
42
|
import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
|
|
43
43
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
44
|
-
import { chat,
|
|
44
|
+
import { chat, displayCtxRatio, microcompactThresholdFor, statusModelLabel } from "./chat.js";
|
|
45
|
+
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
45
46
|
import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveAutoCompact, resolveContextWindow, resolveModel } from "./config.js";
|
|
46
|
-
import { oauthTokenThunk } from "./auth/token.js";
|
|
47
47
|
import { checkForUpdate, knownUpdate, updateCardLines } from "./update-check.js";
|
|
48
48
|
import { tmuxMouseHint } from "./tmux-hint.js";
|
|
49
49
|
import { resume } from "./resume.js";
|
|
@@ -96,6 +96,47 @@ function streamIdleFromEnv() {
|
|
|
96
96
|
* OR-9 adds `update`: npm inherits the terminal for the install's own
|
|
97
97
|
* progress and prompts, so no editor may hold stdin while it runs. */
|
|
98
98
|
const CREDENTIAL_COMMANDS = new Set(["login", "logout", "auth", "update"]);
|
|
99
|
+
/**
|
|
100
|
+
* Astra F3 — A STORED CREDENTIAL IS NOT A SELECTED MODEL.
|
|
101
|
+
*
|
|
102
|
+
* `kiso login` exits 0, says the key is stored, and stops. With no profile
|
|
103
|
+
* the very next command still announces the demo and runs the scripted
|
|
104
|
+
* listing, so a person who has just signed in reasonably concludes that
|
|
105
|
+
* sign-in failed or is being ignored. Nothing was broken: a credential is
|
|
106
|
+
* stored under a PROVIDER, and a PROFILE is what selects the model that
|
|
107
|
+
* uses it. The gap was that nobody said so at the one moment it matters.
|
|
108
|
+
*
|
|
109
|
+
* These are onboarding EXAMPLES, not a resolution path — nothing here ever
|
|
110
|
+
* decides where a credential goes (that is `effectiveBaseUrl` and
|
|
111
|
+
* `providerIdOf`, and it stays there).
|
|
112
|
+
*/
|
|
113
|
+
const PROFILE_EXAMPLE = {
|
|
114
|
+
anthropic: '{"model":"claude","models":{"claude":{"kind":"anthropic","model":"claude-sonnet-5"}}}',
|
|
115
|
+
openai: '{"model":"gpt","models":{"gpt":{"kind":"openai-compat","model":"gpt-4o"}}}',
|
|
116
|
+
chatgpt: '{"model":"codex","models":{"codex":{"kind":"openai-responses","model":"gpt-5-codex","baseUrl":"https://chatgpt.com/backend-api/codex"}}}',
|
|
117
|
+
deepseek: '{"model":"deepseek","models":{"deepseek":{"kind":"openai-compat","model":"deepseek-flash","baseUrl":"https://api.deepseek.com"}}}',
|
|
118
|
+
zai: '{"model":"glm","models":{"glm":{"kind":"openai-compat","model":"glm-5.3-flash","baseUrl":"https://api.z.ai"}}}',
|
|
119
|
+
};
|
|
120
|
+
/** The line a fresh sign-in needs, or nothing when profiles already exist.
|
|
121
|
+
* Read from the USER config alone: a credential command resolves no
|
|
122
|
+
* project trust, and profiles live in the user's own file. */
|
|
123
|
+
function nextStepAfterLogin(provider) {
|
|
124
|
+
let hasProfile = false;
|
|
125
|
+
try {
|
|
126
|
+
hasProfile = Object.keys(loadUserConfig()?.models ?? {}).length > 0;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// A config that cannot be read is its own loud error elsewhere; here
|
|
130
|
+
// it only means we cannot prove a profile exists, so we say the step.
|
|
131
|
+
}
|
|
132
|
+
if (hasProfile)
|
|
133
|
+
return "\nkiso already has profiles — `/model` in a session lists them and switches.\n";
|
|
134
|
+
const example = PROFILE_EXAMPLE[provider];
|
|
135
|
+
return (`\nThe key is stored, but nothing selects a model yet: a PROFILE does that,` +
|
|
136
|
+
` and without one kiso stays in the keyless faux mode.\nPut one in ${join(kisoHome(), "config.json")}` +
|
|
137
|
+
(example === undefined ? ":\n" : `, for example:\n\n ${example}\n`) +
|
|
138
|
+
`\nThen run kiso. \`/model\` lists your profiles and switches between them.\n`);
|
|
139
|
+
}
|
|
99
140
|
/** OR-9: the one install command the README gives, which `kiso update`
|
|
100
141
|
* runs and the failure message names. */
|
|
101
142
|
const INSTALL_COMMAND = ["npm", "i", "-g", "@vincemakes/kiso-code@latest"];
|
|
@@ -539,6 +580,13 @@ directory and change code with tools. Be concise: answer in a few lines
|
|
|
539
580
|
unless the task genuinely needs more. Never claim a file was changed
|
|
540
581
|
unless a tool confirmed it.
|
|
541
582
|
|
|
583
|
+
What you can reach:
|
|
584
|
+
- The workspace: read_file, list_dir, search_text, write_file, edit_file.
|
|
585
|
+
- This machine and the network: shell — builds, tests, git, package
|
|
586
|
+
managers, curl for HTTP, system queries. A request one command can
|
|
587
|
+
answer is answered by running it.
|
|
588
|
+
- The human: ask_user, for a decision that is theirs.
|
|
589
|
+
|
|
542
590
|
Tool discipline:
|
|
543
591
|
- READ BEFORE YOU EDIT. For any file you are about to change, read it
|
|
544
592
|
first — never guess its content.
|
|
@@ -550,11 +598,18 @@ Tool discipline:
|
|
|
550
598
|
- Batch independent tool calls into one reply — they run in parallel.
|
|
551
599
|
- search_text and list_dir are cheap — locate first, then read ranges
|
|
552
600
|
with read_file offset/limit; never read a whole large file in one call.
|
|
553
|
-
- Do not re-read a file you already read unchanged
|
|
554
|
-
result
|
|
601
|
+
- Do not re-read a file you already read unchanged, or one you changed
|
|
602
|
+
yourself through a confirmed edit — rely on the earlier result and
|
|
603
|
+
on the change you just made.
|
|
555
604
|
- When a tool fails, read the error and adjust; do not repeat the same
|
|
556
605
|
call blindly.
|
|
557
606
|
|
|
607
|
+
An authorization covers what it NAMES: when the scope is not named —
|
|
608
|
+
which files, which branches, whether to push — ask before acting.
|
|
609
|
+
Delivering, sharing or handing over changes means committing locally and
|
|
610
|
+
stopping; pushing, publishing or sending happens only when the human
|
|
611
|
+
names it.
|
|
612
|
+
|
|
558
613
|
Workflow: understand the request, find the relevant code, make the
|
|
559
614
|
smallest change that works, then verify with a command (tests/build).
|
|
560
615
|
Report what you did in one or two lines per change.`;
|
|
@@ -664,24 +719,33 @@ async function makeAgent(sessionId, input, modelFlag) {
|
|
|
664
719
|
// the panel bridge is the argument, and a non-TTY session has none to
|
|
665
720
|
// give. A piped run's composed tool table therefore cannot contain
|
|
666
721
|
// ask_user (T-Q3: the bench's structural byte-identity proof).
|
|
667
|
-
|
|
722
|
+
// Astra F7: the config is READ here — a pure read, its setters still run
|
|
723
|
+
// below with the rest of merge round B — because the mcp extension spawns
|
|
724
|
+
// its stdio children while it is being constructed, and the strip needs
|
|
725
|
+
// the configured secret names by then.
|
|
726
|
+
const userCfg = loadUserConfig();
|
|
727
|
+
const projectCfg = loadProjectConfig(process.cwd(), project !== null);
|
|
728
|
+
const merged = mergeConfigs(userCfg, projectCfg);
|
|
729
|
+
const secretEnvNames = secretEnvNamesOf(merged.models ?? {});
|
|
730
|
+
const builtIn = await builtInLayer(user, proj, input !== undefined && process.stdin.isTTY ? askUi(input) : undefined, secretEnvNames);
|
|
668
731
|
setExtensionLists(builtIn, user, proj, [...builtIn, ...user, ...proj]);
|
|
669
732
|
// merge round B — the config surface: user config + (trusted) project config,
|
|
670
733
|
// resolved with flags > env > project > user > default. The CLI never
|
|
671
734
|
// imports provider SDKs directly — the runtime's lazy provider
|
|
672
735
|
// resolution owns them (a config profile only ever NAMES an env var for
|
|
673
736
|
// its key; the key itself never sits in a config file).
|
|
674
|
-
const userCfg = loadUserConfig();
|
|
675
|
-
const projectCfg = loadProjectConfig(process.cwd(), project !== null);
|
|
676
|
-
const merged = mergeConfigs(userCfg, projectCfg);
|
|
677
737
|
setMergedConfig(merged);
|
|
678
738
|
// DT-1a: what a delegated task may NAME — the configured checks and the
|
|
679
739
|
// model profiles — handed to the (in-process) subagent extension through
|
|
680
740
|
// the environment. A model never supplies a command; it names a check.
|
|
681
741
|
process.env.KISO_DELEGATION_CONFIG_JSON = JSON.stringify({ checks: merged.checks ?? {}, profiles: Object.keys(merged.models ?? {}) });
|
|
682
742
|
setConfigModels(merged.models ?? {});
|
|
683
|
-
setConfiguredWindow(resolveContextWindow(merged));
|
|
684
743
|
const resolved = resolveModel(modelFlag, merged);
|
|
744
|
+
// AFTER the model resolves: the window a PROFILE states is about that
|
|
745
|
+
// profile's model, so it cannot be read before we know which profile is
|
|
746
|
+
// selected. Reading it a line too early is how the compaction threshold
|
|
747
|
+
// ended up frozen at the wrong model's value (CTX-1).
|
|
748
|
+
setConfiguredWindow(resolveContextWindow(merged, resolved?.profile));
|
|
685
749
|
const model = resolved === null ? "faux" : resolved.profile.model;
|
|
686
750
|
if (resolved === null) {
|
|
687
751
|
console.log("[faux mode — set ANTHROPIC_API_KEY or OPENAI_API_KEY, or configure models in ~/.kiso/config.json]\n");
|
|
@@ -725,7 +789,9 @@ async function makeAgent(sessionId, input, modelFlag) {
|
|
|
725
789
|
// half the model window (KISO_CONTEXT_WINDOW override included;
|
|
726
790
|
// 200k window → 100k tokens). Long sessions compact old read/list/
|
|
727
791
|
// search/shell outputs instead of silently growing past the window.
|
|
728
|
-
|
|
792
|
+
// CTX-1: the startup value; `/model` recomputes it through the same
|
|
793
|
+
// function, so the two can never drift apart.
|
|
794
|
+
microcompact: { thresholdTokens: microcompactThresholdFor() },
|
|
729
795
|
// E6: the run-start context policy — OFF unless env-armed (beats the microcompact default when both fire).
|
|
730
796
|
...(contextPolicy !== undefined ? { contextPolicy } : {}),
|
|
731
797
|
// R3e (owner ruling, 2026-08-28): NO turn limit on an interactive
|
|
@@ -741,21 +807,18 @@ async function makeAgent(sessionId, input, modelFlag) {
|
|
|
741
807
|
...(resolved !== null
|
|
742
808
|
? {
|
|
743
809
|
provider: resolved.profile.kind,
|
|
744
|
-
//
|
|
745
|
-
//
|
|
746
|
-
// the
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
//
|
|
753
|
-
//
|
|
754
|
-
//
|
|
755
|
-
|
|
756
|
-
...(resolved.profile.baseUrl !== undefined ? { baseUrl: resolved.profile.baseUrl } : {}),
|
|
757
|
-
...(resolved.profile.promptCaching !== undefined ? { promptCaching: resolved.profile.promptCaching } : {}),
|
|
758
|
-
// LT-1: the profile's stream watchdog bound, if it states one
|
|
810
|
+
// Astra F1 (P0): the wire config is built in ONE place
|
|
811
|
+
// (auth/adapter-options.ts) — credential shape, the ALWAYS
|
|
812
|
+
// EXPLICIT endpoint, the session's cache key and the
|
|
813
|
+
// profile's caching flag. This site and the `/model` site
|
|
814
|
+
// were the same spread written twice.
|
|
815
|
+
...adapterOptionsFor(resolved.profile, resolved.oauthProviderId !== undefined
|
|
816
|
+
? { type: "oauth", providerId: resolved.oauthProviderId }
|
|
817
|
+
: { type: "api-key", apiKey: resolved.apiKey ?? "none" }, sessionId),
|
|
818
|
+
// LT-1: the profile's stream watchdog bound, if it states one.
|
|
819
|
+
// NOT an adapter option — an agent-definition field the
|
|
820
|
+
// runtime reads — so it stays here rather than moving into
|
|
821
|
+
// adapterOptionsFor.
|
|
759
822
|
...(resolved.profile.streamIdleMs !== undefined ? { streamIdleMs: resolved.profile.streamIdleMs } : {}),
|
|
760
823
|
}
|
|
761
824
|
: { adapter: createFauxProvider(readFauxScript().slice(fauxSkipTurns)) }),
|
|
@@ -831,6 +894,33 @@ async function pickSession(agent, input) {
|
|
|
831
894
|
* formatter — never a boot-time copy, which would drift from the real
|
|
832
895
|
* row the moment either changed.
|
|
833
896
|
*/
|
|
897
|
+
/**
|
|
898
|
+
* CTX-1 (Astra F34-1): EVERY entry point that opens a session must bind the
|
|
899
|
+
* policy that follows the session's OWN model.
|
|
900
|
+
*
|
|
901
|
+
* `agent.session()` restores the model recorded in the durable profile —
|
|
902
|
+
* any model that session ever used, not necessarily the one this process
|
|
903
|
+
* started on. The display and the compaction threshold are both derived
|
|
904
|
+
* from it, so both belong here.
|
|
905
|
+
*
|
|
906
|
+
* The first fix put these two lines in chatLoop only. `kiso resume <id>`
|
|
907
|
+
* and `kiso -p <text> <id>` open through their own paths, restored the
|
|
908
|
+
* model, and kept the STARTUP threshold: a session recorded on a 1M model,
|
|
909
|
+
* resumed from a 200k start, cleared its tool results at 100,000 while the
|
|
910
|
+
* interactive entry point cleared at 500,000. Three doors, one of them
|
|
911
|
+
* fixed, is the same defect with a smaller blast radius.
|
|
912
|
+
*
|
|
913
|
+
* The pair is passed EXPLICITLY, never read back out of the display state
|
|
914
|
+
* set on the line above: depending on two lines staying in order is how the
|
|
915
|
+
* threshold got stuck in the first place.
|
|
916
|
+
*/
|
|
917
|
+
function bindRestoredSession(session) {
|
|
918
|
+
setAgentModel(session.model, session.baseUrl);
|
|
919
|
+
session.setMicrocompactThreshold(microcompactThresholdFor({
|
|
920
|
+
model: session.model,
|
|
921
|
+
...(session.baseUrl !== undefined ? { baseUrl: session.baseUrl } : {}),
|
|
922
|
+
}));
|
|
923
|
+
}
|
|
834
924
|
function paintBootStatus(session) {
|
|
835
925
|
if (!dock.active)
|
|
836
926
|
return;
|
|
@@ -1033,7 +1123,9 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1033
1123
|
// XP-1 §2.1: the switched-to session's OWN truth repaints the row —
|
|
1034
1124
|
// the global display state never outlives the session it described
|
|
1035
1125
|
// (pre-XP the row kept the previous session's /model selection).
|
|
1036
|
-
|
|
1126
|
+
// CTX-1: the restored session's own model decides the display AND
|
|
1127
|
+
// the threshold. One step, shared by all three entry points.
|
|
1128
|
+
bindRestoredSession(session);
|
|
1037
1129
|
setCurrentModelName(session.model);
|
|
1038
1130
|
paintBootStatus(session);
|
|
1039
1131
|
const nav = {
|
|
@@ -1296,7 +1388,12 @@ async function main() {
|
|
|
1296
1388
|
input.onClipboardPaste?.(() => {
|
|
1297
1389
|
const shot = clipboardImage(tmpdir());
|
|
1298
1390
|
if (shot === null) {
|
|
1299
|
-
|
|
1391
|
+
// Astra F8: on a platform with no clipboard reader kiso never
|
|
1392
|
+
// LOOKED, so "no image on the clipboard" blamed the clipboard for
|
|
1393
|
+
// a limit of the build. Say which of the two it is.
|
|
1394
|
+
bodyLog(process.platform === "darwin"
|
|
1395
|
+
? "[no image on the clipboard — ctrl+V attaches one; a file dragged into the window works too]"
|
|
1396
|
+
: "[clipboard images are macOS-only — put the image's path in your message instead; a file dragged into the window leaves one]");
|
|
1300
1397
|
return null;
|
|
1301
1398
|
}
|
|
1302
1399
|
return shot;
|
|
@@ -1316,6 +1413,7 @@ async function main() {
|
|
|
1316
1413
|
agent = await makeAgent(id, input, modelFlag);
|
|
1317
1414
|
applyConfigMode();
|
|
1318
1415
|
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
1416
|
+
bindRestoredSession(session); // CTX-1 (F34-1): the -p door, too
|
|
1319
1417
|
faux = currentFaux;
|
|
1320
1418
|
await resume(session, printPrompt, faux, input);
|
|
1321
1419
|
const last = [...session.log.all].reverse().find((e) => e.type === "terminal");
|
|
@@ -1370,6 +1468,7 @@ async function main() {
|
|
|
1370
1468
|
break;
|
|
1371
1469
|
}
|
|
1372
1470
|
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
1471
|
+
bindRestoredSession(session); // CTX-1 (F34-1): the explicit-id door
|
|
1373
1472
|
faux = currentFaux;
|
|
1374
1473
|
// E area: the durable script position is computed from the
|
|
1375
1474
|
// session id, and on the picker path the id did not exist when
|
|
@@ -1465,6 +1564,7 @@ async function main() {
|
|
|
1465
1564
|
});
|
|
1466
1565
|
setCredential(provider, cred);
|
|
1467
1566
|
process.stdout.write(`signed in to ${provider} (${chatgptFlow.label}) — account ${cred.accountId ?? "?"}, expires ${new Date(cred.expires).toISOString()} — stored in ${authPath()}\n`);
|
|
1567
|
+
process.stdout.write(nextStepAfterLogin(provider));
|
|
1468
1568
|
}
|
|
1469
1569
|
finally {
|
|
1470
1570
|
rl.close();
|
|
@@ -1476,6 +1576,7 @@ async function main() {
|
|
|
1476
1576
|
throw new CliUsageError(`kiso login ${provider}: no key given`);
|
|
1477
1577
|
setCredential(provider, { type: "api-key", key, savedAt: Date.now() });
|
|
1478
1578
|
process.stdout.write(`signed in to ${provider} with an API key (${maskSecret(key)}) — stored in ${authPath()}\n`);
|
|
1579
|
+
process.stdout.write(nextStepAfterLogin(provider));
|
|
1479
1580
|
break;
|
|
1480
1581
|
}
|
|
1481
1582
|
case "update": {
|
package/dist/mode.d.ts
CHANGED
|
@@ -15,7 +15,16 @@ export declare const MODES: readonly Mode[];
|
|
|
15
15
|
/** DC-36 — one line per tier, for the picker, TRANSCRIBED FROM decide()
|
|
16
16
|
* below rather than written fresh. A description that drifts from the
|
|
17
17
|
* behaviour is worse than none: this is the row a human reads before
|
|
18
|
-
* handing over the approval gate.
|
|
18
|
+
* handing over the approval gate.
|
|
19
|
+
*
|
|
20
|
+
* Astra F4: these describe THE TIER'S CONTRIBUTION TO THE CHAIN, not the
|
|
21
|
+
* chain's verdict. "every tool asks" read as a promise that manual is a
|
|
22
|
+
* revocation — pick it and you are asked about everything again — and it
|
|
23
|
+
* is not. A tier that ASKS abstains in favour of anything that ALLOWS, so
|
|
24
|
+
* a saved don't-ask-again rule still allows, and the side effect runs with
|
|
25
|
+
* no new question. The composition (deny > allow > ask) is the ruling and
|
|
26
|
+
* is unchanged; the copy was the thing that was wrong. `plan` needs no
|
|
27
|
+
* qualification because it DENIES, and a deny is what nothing overrides. */
|
|
19
28
|
export declare const MODE_NOTE: Readonly<Record<Mode, string>>;
|
|
20
29
|
export declare function getMode(): Mode;
|
|
21
30
|
export declare function setMode(m: Mode): void;
|
package/dist/mode.js
CHANGED
|
@@ -13,13 +13,22 @@ export const MODES = ["manual", "default", "accept-edits", "plan", "bypass"];
|
|
|
13
13
|
/** DC-36 — one line per tier, for the picker, TRANSCRIBED FROM decide()
|
|
14
14
|
* below rather than written fresh. A description that drifts from the
|
|
15
15
|
* behaviour is worse than none: this is the row a human reads before
|
|
16
|
-
* handing over the approval gate.
|
|
16
|
+
* handing over the approval gate.
|
|
17
|
+
*
|
|
18
|
+
* Astra F4: these describe THE TIER'S CONTRIBUTION TO THE CHAIN, not the
|
|
19
|
+
* chain's verdict. "every tool asks" read as a promise that manual is a
|
|
20
|
+
* revocation — pick it and you are asked about everything again — and it
|
|
21
|
+
* is not. A tier that ASKS abstains in favour of anything that ALLOWS, so
|
|
22
|
+
* a saved don't-ask-again rule still allows, and the side effect runs with
|
|
23
|
+
* no new question. The composition (deny > allow > ask) is the ruling and
|
|
24
|
+
* is unchanged; the copy was the thing that was wrong. `plan` needs no
|
|
25
|
+
* qualification because it DENIES, and a deny is what nothing overrides. */
|
|
17
26
|
export const MODE_NOTE = {
|
|
18
|
-
manual: "every tool
|
|
19
|
-
default: "reads run; writes, edits and shell ask",
|
|
20
|
-
"accept-edits": "reads, writes and edits run; shell asks",
|
|
21
|
-
plan: "reads run; everything else is denied — read-only",
|
|
22
|
-
bypass: "everything runs, nothing asks",
|
|
27
|
+
manual: "asks for every tool — a saved allow still allows",
|
|
28
|
+
default: "reads run; writes, edits and shell ask — a saved allow still allows",
|
|
29
|
+
"accept-edits": "reads, writes and edits run; shell asks — a saved allow still allows",
|
|
30
|
+
plan: "reads run; everything else is denied — read-only, and a deny wins",
|
|
31
|
+
bypass: "everything runs, nothing asks — a user deny still wins",
|
|
23
32
|
};
|
|
24
33
|
/** The read-only tool set (plan): reading is allowed, everything else
|
|
25
34
|
* denied with the guiding reason. */
|
package/dist/state.d.ts
CHANGED
|
@@ -16,9 +16,19 @@ export declare function kisoHome(): string;
|
|
|
16
16
|
* is decided. The session's own tool set and the `!` command's runner both
|
|
17
17
|
* need it, and two copies of a ruling-bearing literal is how a later DC-49
|
|
18
18
|
* amendment reaches one caller and not the other. */
|
|
19
|
+
/**
|
|
20
|
+
* Astra F7 — every configured profile's `apiKeyEnv` NAME is a secret name.
|
|
21
|
+
* The strip's suffix rules cannot see `REVIEW_PROVIDER_TOKEN`, and only the
|
|
22
|
+
* config knows which names are keys, so the config says so. ONE derivation:
|
|
23
|
+
* the shell tool reads it through codingToolOptions, and startup reads it
|
|
24
|
+
* directly for the mcp extension, which spawns its stdio children before
|
|
25
|
+
* these state setters have run.
|
|
26
|
+
*/
|
|
27
|
+
export declare function secretEnvNamesOf(models: Readonly<Record<string, unknown>>): readonly string[];
|
|
19
28
|
export declare function codingToolOptions(): {
|
|
20
29
|
readonly workspaceRoot: string;
|
|
21
30
|
readonly excludeRoots: readonly string[];
|
|
31
|
+
readonly secretEnvNames: readonly string[];
|
|
22
32
|
};
|
|
23
33
|
export declare function sessionsDir(): string;
|
|
24
34
|
/** E1: the extension scan directory — KISO_EXTENSIONS_DIR overrides. */
|
package/dist/state.js
CHANGED
|
@@ -22,8 +22,23 @@ export function kisoHome() {
|
|
|
22
22
|
* is decided. The session's own tool set and the `!` command's runner both
|
|
23
23
|
* need it, and two copies of a ruling-bearing literal is how a later DC-49
|
|
24
24
|
* amendment reaches one caller and not the other. */
|
|
25
|
+
/**
|
|
26
|
+
* Astra F7 — every configured profile's `apiKeyEnv` NAME is a secret name.
|
|
27
|
+
* The strip's suffix rules cannot see `REVIEW_PROVIDER_TOKEN`, and only the
|
|
28
|
+
* config knows which names are keys, so the config says so. ONE derivation:
|
|
29
|
+
* the shell tool reads it through codingToolOptions, and startup reads it
|
|
30
|
+
* directly for the mcp extension, which spawns its stdio children before
|
|
31
|
+
* these state setters have run.
|
|
32
|
+
*/
|
|
33
|
+
export function secretEnvNamesOf(models) {
|
|
34
|
+
return [
|
|
35
|
+
...new Set(Object.values(models)
|
|
36
|
+
.map((p) => p.apiKeyEnv)
|
|
37
|
+
.filter((n) => typeof n === "string" && n.length > 0)),
|
|
38
|
+
];
|
|
39
|
+
}
|
|
25
40
|
export function codingToolOptions() {
|
|
26
|
-
return { workspaceRoot: process.cwd(), excludeRoots: [kisoHome()] };
|
|
41
|
+
return { workspaceRoot: process.cwd(), excludeRoots: [kisoHome()], secretEnvNames: secretEnvNamesOf(configModels) };
|
|
27
42
|
}
|
|
28
43
|
export function sessionsDir() {
|
|
29
44
|
return join(kisoHome(), "sessions");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "kiso-code
|
|
3
|
+
"version": "0.37.0",
|
|
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",
|
|
7
7
|
"bin": {
|
|
@@ -18,20 +18,20 @@
|
|
|
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-provider-openai-responses": "0.
|
|
28
|
-
"@vincemakes/kiso-runtime": "0.
|
|
29
|
-
"@vincemakes/kiso-skills-ext": "0.
|
|
30
|
-
"@vincemakes/kiso-subagent-ext": "0.
|
|
31
|
-
"@vincemakes/kiso-task-ext": "0.
|
|
32
|
-
"@vincemakes/kiso-tools-node": "0.
|
|
33
|
-
"@vincemakes/kiso-tui": "0.
|
|
34
|
-
"@vincemakes/kiso-tui-cells": "0.
|
|
21
|
+
"@vincemakes/kiso-ask-ext": "0.37.0",
|
|
22
|
+
"@vincemakes/kiso-core": "0.37.0",
|
|
23
|
+
"@vincemakes/kiso-evals": "0.37.0",
|
|
24
|
+
"@vincemakes/kiso-mcp-ext": "0.37.0",
|
|
25
|
+
"@vincemakes/kiso-provider-anthropic": "0.37.0",
|
|
26
|
+
"@vincemakes/kiso-provider-openai": "0.37.0",
|
|
27
|
+
"@vincemakes/kiso-provider-openai-responses": "0.37.0",
|
|
28
|
+
"@vincemakes/kiso-runtime": "0.37.0",
|
|
29
|
+
"@vincemakes/kiso-skills-ext": "0.37.0",
|
|
30
|
+
"@vincemakes/kiso-subagent-ext": "0.37.0",
|
|
31
|
+
"@vincemakes/kiso-task-ext": "0.37.0",
|
|
32
|
+
"@vincemakes/kiso-tools-node": "0.37.0",
|
|
33
|
+
"@vincemakes/kiso-tui": "0.37.0",
|
|
34
|
+
"@vincemakes/kiso-tui-cells": "0.37.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^26.1.2",
|