@vincemakes/kiso-code 0.40.6 → 0.41.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/credentials.d.ts +4 -0
- package/dist/auth/oauth/chatgpt.d.ts +1 -1
- package/dist/auth/oauth/chatgpt.js +6 -1
- package/dist/auth/oauth/index.d.ts +8 -0
- package/dist/auth/oauth/index.js +8 -1
- package/dist/auth/refresh.d.ts +1 -1
- package/dist/auth/refresh.js +20 -1
- package/dist/coding-prompt.d.ts +45 -0
- package/dist/coding-prompt.js +105 -0
- package/dist/config.d.ts +9 -1
- package/dist/config.js +19 -2
- package/dist/create-coding-agent.d.ts +30 -0
- package/dist/create-coding-agent.js +350 -0
- package/dist/dispatch.js +37 -3
- package/dist/index.d.ts +3 -44
- package/dist/index.js +41 -434
- package/dist/mode.d.ts +1 -1
- package/dist/mode.js +1 -1
- package/dist/readonly-shell.js +5 -9
- package/dist/state.d.ts +11 -7
- package/dist/state.js +13 -7
- package/dist/temp-sweep.d.ts +12 -0
- package/dist/temp-sweep.js +76 -0
- package/dist/trust-ui.js +4 -3
- package/package.json +15 -15
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* resume.ts, trust-ui.ts (the question surface + E3 merges), faux-glue.ts
|
|
22
22
|
* (the scripted-model plumbing), state.ts (the shared process state).
|
|
23
23
|
* index.ts keeps the entry: banner, input sources, the A area prompt,
|
|
24
|
-
*
|
|
24
|
+
* createCodingAgent, and main.
|
|
25
25
|
*/
|
|
26
26
|
import { appendFileSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
27
27
|
import { spawn, spawnSync } from "node:child_process";
|
|
@@ -31,33 +31,21 @@ import { Readable } from "node:stream";
|
|
|
31
31
|
import { fileURLToPath } from "node:url";
|
|
32
32
|
import { basename, join } from "node:path";
|
|
33
33
|
import { Body, Editor, PROMPT, bannerLines, currentGround, resolveGround, setGround, escapeTerminal, extensionsBannerText, idColumn, idleStatus, interactivePrompt, palette, renderSessionLine, sessionListFooter, sessionListHeader, sessionListRow, sessionListUnknownLine, slashCommandNames } from "@vincemakes/kiso-tui";
|
|
34
|
-
import {
|
|
35
|
-
import { listSessionSidecars, migrateSummaries, readProfile,
|
|
34
|
+
import { disposeExtensions, SessionStore } from "@vincemakes/kiso-runtime";
|
|
35
|
+
import { listSessionSidecars, migrateSummaries, readProfile, summaryMigrationPending } from "@vincemakes/kiso-runtime/internal";
|
|
36
36
|
import { skillMenuItems } from "./skill-invoke.js";
|
|
37
|
-
import { canonicalPath,
|
|
38
|
-
import {
|
|
37
|
+
import { canonicalPath, hasSession, locateSession, projectLayoutActive, sessionFolders } from "./projects.js";
|
|
38
|
+
import { reverseMigration } from "./session-migration.js";
|
|
39
39
|
import { defaultTrashRoot, findEmptySessions, moveToTrash } from "./empty-sessions.js";
|
|
40
40
|
import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
41
|
-
import {
|
|
42
|
-
import { MODES, OFFERED_MODES, getMode,
|
|
43
|
-
import {
|
|
44
|
-
import { guardSavedAllow, isProtectedWrite } from "./protected-writes.js";
|
|
45
|
-
import { floorExtension, isDestructiveCall } from "./floor.js";
|
|
46
|
-
import { protectedShellExtension } from "./protected-shell.js";
|
|
47
|
-
import { breakerExtension } from "./breaker.js";
|
|
48
|
-
import { builtInLayer } from "./builtin.js";
|
|
49
|
-
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";
|
|
50
|
-
import { maxRetriesFromEnv } from "./retries.js";
|
|
51
|
-
import { askUi, resolveProjectTrust } from "./trust-ui.js";
|
|
52
|
-
import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
|
|
41
|
+
import { isProtectedPath, protectedIdentity, PROTECTED_REFUSAL } from "@vincemakes/kiso-tools-node";
|
|
42
|
+
import { MODES, OFFERED_MODES, getMode, modeFromEnv, setMode } from "./mode.js";
|
|
43
|
+
import { activeStoreDir, setActiveStoreDir, agentModel, atFiles, body, bodyLog, kisoHome, workspaceRoot, projectRoot, ownSessionsDir, setOpenSessionFolder, builtInExtensions, currentFaux, dock, loadedExtensions, mergedConfig, mergedTempPaths, modelChoice, projectExtensions, configModels, configuredWindow, agentBaseUrl, currentModelName, currentAgentExtensions, sessionStoreRef, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setCurrentProfileName, setExtensionLists, protectedFiles, setMergedConfig, setModelChoice, setSessionStore, userExtensions, VERSION, lastBinding, acceptDrift, setAcceptDrift, loadedSkillsCatalog, queuedSwitchLines } from "./state.js";
|
|
53
44
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
54
|
-
import { chat,
|
|
55
|
-
import { recordLearnedWindow, useLearnedWindows } from "./learned-windows.js";
|
|
45
|
+
import { chat, contextWindowTokens, displayCtxRatio, microcompactThresholdFor, statusModelLabel } from "./chat.js";
|
|
56
46
|
import { preferences, usePreferences } from "./preferences.js";
|
|
57
47
|
import { settingsLayers } from "./state.js";
|
|
58
|
-
import {
|
|
59
|
-
import { adapterOptionsFor } from "./auth/adapter-options.js";
|
|
60
|
-
import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveAutoCompact, resolveContextWindow, resolveModel } from "./config.js";
|
|
48
|
+
import { loadUserConfig, resolveAutoCompact } from "./config.js";
|
|
61
49
|
import { checkForUpdate, knownUpdate, updateCardLines } from "./update-check.js";
|
|
62
50
|
import { tmuxMouseHint } from "./tmux-hint.js";
|
|
63
51
|
import { resume } from "./resume.js";
|
|
@@ -68,6 +56,9 @@ import { armByteTrace } from "./byte-trace.js";
|
|
|
68
56
|
import { tmpdir, homedir } from "node:os";
|
|
69
57
|
import { clipboardImage } from "./clipboard.js";
|
|
70
58
|
import { cardsFromListings } from "./session-cards.js";
|
|
59
|
+
import { createCodingAgent } from "./create-coding-agent.js";
|
|
60
|
+
export { contextPolicyFromEnv } from "./create-coding-agent.js";
|
|
61
|
+
export { SYSTEM_PROMPT, composeSystemPrompt, readProjectInstructions } from "./coding-prompt.js";
|
|
71
62
|
// The moved exports stay reachable from this entry — the test imports
|
|
72
63
|
// (project-trust, coding-agent) never change (B4: zero assertion changes).
|
|
73
64
|
export { applyProjectMerges } from "./trust-ui.js";
|
|
@@ -96,17 +87,6 @@ function openInBrowser(url) {
|
|
|
96
87
|
// the URL is on screen; opening it is the person's fallback
|
|
97
88
|
}
|
|
98
89
|
}
|
|
99
|
-
/** LT-1: the stream watchdog's bound from the environment — a non-negative
|
|
100
|
-
* number of milliseconds (0 disables it); anything else is ignored. The
|
|
101
|
-
* PTY rigs use it to trip the watchdog in seconds against a stub that
|
|
102
|
-
* never finishes a stream. */
|
|
103
|
-
function streamIdleFromEnv() {
|
|
104
|
-
const raw = process.env.KISO_STREAM_IDLE_MS;
|
|
105
|
-
if (raw === undefined || raw === "")
|
|
106
|
-
return undefined;
|
|
107
|
-
const n = Number(raw);
|
|
108
|
-
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
109
|
-
}
|
|
110
90
|
/** OR-3: the commands that own their own stdin reader (a hidden key prompt,
|
|
111
91
|
* an OAuth paste prompt) or read nothing at all — never the editor.
|
|
112
92
|
* OR-9 adds `update`: npm inherits the terminal for the install's own
|
|
@@ -593,354 +573,6 @@ function extensionsBanner(resume = []) {
|
|
|
593
573
|
homeWorkspace: realOf(cwd) === realOf(home),
|
|
594
574
|
});
|
|
595
575
|
}
|
|
596
|
-
/**
|
|
597
|
-
* A area: the coding-agent system prompt — ONE constant, byte-stable for the
|
|
598
|
-
* session's lifetime (D area). Kept under ~80 lines; no template engine.
|
|
599
|
-
*/
|
|
600
|
-
/** The built-in prompt. Exported for scripts/request-surface.mjs — the
|
|
601
|
-
* model-side token-rent counter measures the REAL bytes, never a copy. */
|
|
602
|
-
export const SYSTEM_PROMPT = `You are kiso, a coding agent. You work in a workspace
|
|
603
|
-
directory and change code with tools. Be concise: answer in a few lines
|
|
604
|
-
unless the task genuinely needs more. Never claim a file was changed
|
|
605
|
-
unless a tool confirmed it.
|
|
606
|
-
|
|
607
|
-
What you can reach:
|
|
608
|
-
- The workspace: read_file, list_dir, search_text, write_file, edit_file.
|
|
609
|
-
- This machine and the network: shell — builds, tests, git, package
|
|
610
|
-
managers, curl for HTTP, system queries. A request one command can
|
|
611
|
-
answer is answered by running it.
|
|
612
|
-
- The human: ask_user, for a decision that is theirs.
|
|
613
|
-
|
|
614
|
-
Tool discipline:
|
|
615
|
-
- READ BEFORE YOU EDIT. For any file you are about to change, read it
|
|
616
|
-
first — never guess its content.
|
|
617
|
-
- Use edit_file for targeted changes and write_file for full rewrites.
|
|
618
|
-
Prefer many small edits over one large write.
|
|
619
|
-
- Be careful — shell has side effects and may take time.
|
|
620
|
-
- search_text and list_dir are cheap — locate first, then read ranges
|
|
621
|
-
with read_file offset/limit; never read a whole large file in one call.
|
|
622
|
-
- Do not re-read a file you already read unchanged, or one you changed
|
|
623
|
-
yourself through a confirmed edit — rely on the earlier result and
|
|
624
|
-
on the change you just made.
|
|
625
|
-
- When a tool fails, read the error and adjust; do not repeat the same
|
|
626
|
-
call blindly.
|
|
627
|
-
|
|
628
|
-
An authorization covers what it NAMES: when the scope is not named —
|
|
629
|
-
which files, which branches, whether to push — ask before acting.
|
|
630
|
-
Delivering, sharing or handing over changes means committing locally and
|
|
631
|
-
stopping; pushing, publishing or sending happens only when the human
|
|
632
|
-
names it.
|
|
633
|
-
|
|
634
|
-
Workflow: understand the request, find the relevant code, make the
|
|
635
|
-
smallest change that works, then verify with a command (tests/build).
|
|
636
|
-
Report what you did in one or two lines per change.`;
|
|
637
|
-
/** The project-instructions file names, in priority order (A area). */
|
|
638
|
-
const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
639
|
-
/** Hard cap for injected instructions — truncate and say so. */
|
|
640
|
-
/**
|
|
641
|
-
* A area: read the FIRST present instruction file (AGENTS.md preferred) and
|
|
642
|
-
* return it as an injected section, or "" when none exists. Truncated at
|
|
643
|
-
* 8KB with an explicit note. Pure — read once per session, so the prompt
|
|
644
|
-
* is byte-stable for the session's lifetime.
|
|
645
|
-
*
|
|
646
|
-
* kiso never serves its own credential store to a model, and this read is
|
|
647
|
-
* the one that needs no model at all: a cloned repository whose AGENTS.md
|
|
648
|
-
* is a symlink to the store would put it in the SYSTEM PROMPT of every
|
|
649
|
-
* request, with no tool call and no trust prompt. A file that resolves to
|
|
650
|
-
* a protected one is skipped as though absent.
|
|
651
|
-
*/
|
|
652
|
-
export function readProjectInstructions(cwd, protectedFiles = []) {
|
|
653
|
-
const id = protectedIdentity(protectedFiles);
|
|
654
|
-
for (const name of INSTRUCTION_FILES) {
|
|
655
|
-
if (isProtectedPath(join(cwd, name), id))
|
|
656
|
-
continue;
|
|
657
|
-
let text;
|
|
658
|
-
try {
|
|
659
|
-
text = readFileSync(join(cwd, name), "utf8");
|
|
660
|
-
}
|
|
661
|
-
catch {
|
|
662
|
-
continue; // not present — try the next
|
|
663
|
-
}
|
|
664
|
-
return `\n\n=== Project instructions (${name}) ===\n${text.length > 8 * 1024 ? text.slice(0, 8 * 1024) + `\n\n[truncated at ${8 * 1024} chars]` : text}`;
|
|
665
|
-
}
|
|
666
|
-
return "";
|
|
667
|
-
}
|
|
668
|
-
/** A area: the session's system prompt — the constant plus any project
|
|
669
|
-
* instructions found in the workspace. Deterministic per cwd. */
|
|
670
|
-
export function composeSystemPrompt(cwd, protectedFiles = []) {
|
|
671
|
-
const injected = readProjectInstructions(cwd, protectedFiles);
|
|
672
|
-
return injected === "" ? SYSTEM_PROMPT : `${SYSTEM_PROMPT}\n${injected}`;
|
|
673
|
-
}
|
|
674
|
-
/**
|
|
675
|
-
* E6: the run-start context policy, OFF unless env-armed (invalid values
|
|
676
|
-
* are ABSENT, never a crash — the autoCompactFromEnv convention).
|
|
677
|
-
* The product arming is KISO_CONTEXT_WINDOW → window − POLICY_RESERVE
|
|
678
|
-
* (the window rides the config as windowTokens; the runtime owns the
|
|
679
|
-
* arithmetic — never a fixed low absolute). KISO_POLICY_SUMMARY_TRIGGER
|
|
680
|
-
* survives ONLY as the legacy absolute override when no window is set
|
|
681
|
-
* (bench back-compat); the window wins when both are set.
|
|
682
|
-
* KISO_POLICY_SUMMARY_KEEP (rounds) and KISO_POLICY_SUMMARY_KEEP_TOKENS
|
|
683
|
-
* override the runtime defaults (KEEP_RECENT_ROUNDS = 4,
|
|
684
|
-
* KEEP_TOKENS_DEFAULT = 20,000) — emitted only when set.
|
|
685
|
-
* KISO_POLICY_SUMMARY_MAX_FAILURES overrides the (h) circuit-breaker
|
|
686
|
-
* default (MAX_SUMMARY_FAILURES = 3).
|
|
687
|
-
* KISO_POLICY_DROP=1 switches the armed mode to the crux C arm
|
|
688
|
-
* (mechanical drop — same trigger/keep envs); KISO_POLICY_MICROCOMPACT
|
|
689
|
-
* arms the session-aware override (MIN_TURNS = the no-fire guard).
|
|
690
|
-
*/
|
|
691
|
-
export function contextPolicyFromEnv() {
|
|
692
|
-
const summaryTrigger = positiveIntEnv("KISO_POLICY_SUMMARY_TRIGGER");
|
|
693
|
-
const contextWindow = positiveIntEnv("KISO_CONTEXT_WINDOW");
|
|
694
|
-
const microcompactTrigger = positiveIntEnv("KISO_POLICY_MICROCOMPACT");
|
|
695
|
-
if (summaryTrigger === undefined && contextWindow === undefined && microcompactTrigger === undefined)
|
|
696
|
-
return undefined;
|
|
697
|
-
return {
|
|
698
|
-
...(summaryTrigger === undefined && contextWindow === undefined ? {} : {
|
|
699
|
-
[(process.env.KISO_POLICY_DROP === "1" ? "drop" : "summary")]: {
|
|
700
|
-
...(contextWindow !== undefined ? { windowTokens: contextWindow } : summaryTrigger !== undefined ? { triggerTokens: summaryTrigger } : {}),
|
|
701
|
-
...kv("keepRounds", "KISO_POLICY_SUMMARY_KEEP"),
|
|
702
|
-
...kv("keepTokens", "KISO_POLICY_SUMMARY_KEEP_TOKENS"),
|
|
703
|
-
...kv("maxFailures", "KISO_POLICY_SUMMARY_MAX_FAILURES"),
|
|
704
|
-
},
|
|
705
|
-
}),
|
|
706
|
-
...(microcompactTrigger !== undefined ? { microcompact: { thresholdTokens: microcompactTrigger, ...kv("keepResults", "KISO_POLICY_MICROCOMPACT_KEEP"), ...kv("minTurns", "KISO_POLICY_MICROCOMPACT_MIN_TURNS") } } : {}),
|
|
707
|
-
};
|
|
708
|
-
}
|
|
709
|
-
/** { [key]: value } when the env int is set — the spread-friendly optional field. */
|
|
710
|
-
function kv(key, env) {
|
|
711
|
-
const v = positiveIntEnv(env);
|
|
712
|
-
return v !== undefined ? { [key]: v } : {};
|
|
713
|
-
}
|
|
714
|
-
/** Parse a positive-int env var — absent or invalid is undefined (no crash). */
|
|
715
|
-
function positiveIntEnv(name) {
|
|
716
|
-
const n = Number.parseInt(process.env[name] ?? "", 10);
|
|
717
|
-
return Number.isFinite(n) && n > 0 ? n : undefined;
|
|
718
|
-
}
|
|
719
|
-
async function makeAgent(sessionId, input, modelFlag) {
|
|
720
|
-
// §2.5: the ONE source a reload reads for the model, seeded here from
|
|
721
|
-
// the startup flag. Without this a session started with `--model X`
|
|
722
|
-
// would silently revert to the env/config default on its first reload.
|
|
723
|
-
if (modelFlag !== undefined)
|
|
724
|
-
setModelChoice(modelFlag);
|
|
725
|
-
// E3: the project-level trust gate runs BEFORE any extension load (the
|
|
726
|
-
// mcp/skills merges must be in the env when the user-level extensions
|
|
727
|
-
// load). Untrusted project capability is never loaded — never silently.
|
|
728
|
-
const project = input !== undefined ? await resolveProjectTrust(input) : await resolveProjectTrust(undefined);
|
|
729
|
-
// R-D 0.1.45 (deliverable B): the first-run scaffold lands AFTER the
|
|
730
|
-
// verdict — pre-trust zero-read/write/scan is absolute. The sessions
|
|
731
|
-
// dir (SessionStore's constructor mkdirs) moved behind the gate too:
|
|
732
|
-
// the trust record is the first home write, the scaffold the second.
|
|
733
|
-
if (isFirstRun())
|
|
734
|
-
scaffoldFirstRun();
|
|
735
|
-
// 0.40.0 — one folder per project: the one-time move of the legacy
|
|
736
|
-
// folder, then this project's folder claimed (made, its workspace
|
|
737
|
-
// recorded). Both write, so both sit behind the verdict, with the store.
|
|
738
|
-
prepareSessionFolders();
|
|
739
|
-
activeStoreDir = sessionsDir();
|
|
740
|
-
const store = new SessionStore(activeStoreDir);
|
|
741
|
-
// TUI2-R2 ②/③: the navigation surfaces read through THIS store — one
|
|
742
|
-
// store per process, and the picker/listing never write through it.
|
|
743
|
-
setSessionStore(store);
|
|
744
|
-
// E area: the durable script position — computed AFTER the verdict
|
|
745
|
-
// (fauxSkip's session-log read is a home read: pre-trust zero-read).
|
|
746
|
-
const fauxSkipTurns = sessionId === undefined ? 0 : fauxSkip(sessionId);
|
|
747
|
-
// E1: the startup extension scan — a broken extension fails the process
|
|
748
|
-
// LOUDLY here (loadExtensions throws), never silently.
|
|
749
|
-
const user = await loadExtensions(extensionsDir());
|
|
750
|
-
const proj = project !== null ? await loadProjectExtensions(process.cwd(), user) : [];
|
|
751
|
-
// R-D 0.1.45: the built-in layer registers by module import (builtin.ts)
|
|
752
|
-
// — a user extension may shadow a built-in, a project one may not.
|
|
753
|
-
// KC3.5: built-in #4 (ask) registers ONLY where a human can answer —
|
|
754
|
-
// the panel bridge is the argument, and a non-TTY session has none to
|
|
755
|
-
// give. A piped run's composed tool table therefore cannot contain
|
|
756
|
-
// ask_user (T-Q3: the bench's structural byte-identity proof).
|
|
757
|
-
// Astra F7: the config is READ here — a pure read, its setters still run
|
|
758
|
-
// below with the rest of merge round B — because the mcp extension spawns
|
|
759
|
-
// its stdio children while it is being constructed, and the strip needs
|
|
760
|
-
// the configured secret names by then.
|
|
761
|
-
const userCfg = loadUserConfig();
|
|
762
|
-
const projectCfg = loadProjectConfig(process.cwd(), project !== null);
|
|
763
|
-
const merged = mergeConfigs(userCfg, projectCfg);
|
|
764
|
-
// 0.40.6: /settings names each value's layer from these
|
|
765
|
-
settingsLayers.user = userCfg;
|
|
766
|
-
settingsLayers.project = projectCfg;
|
|
767
|
-
settingsLayers.modelFlag = modelFlag;
|
|
768
|
-
const secretEnvNames = secretEnvNamesOf(merged.models ?? {});
|
|
769
|
-
const builtIn = await builtInLayer(user, proj, input !== undefined && process.stdin.isTTY ? askUi(input) : undefined, secretEnvNames);
|
|
770
|
-
setExtensionLists(builtIn, user, proj, [...builtIn, ...user, ...proj]);
|
|
771
|
-
// merge round B — the config surface: user config + (trusted) project config,
|
|
772
|
-
// resolved with flags > env > project > user > default. The CLI never
|
|
773
|
-
// imports provider SDKs directly — the runtime's lazy provider
|
|
774
|
-
// resolution owns them (a config profile only ever NAMES an env var for
|
|
775
|
-
// its key; the key itself never sits in a config file).
|
|
776
|
-
setMergedConfig(merged);
|
|
777
|
-
// DT-1a: what a delegated task may NAME — the configured checks and the
|
|
778
|
-
// model profiles — handed to the (in-process) subagent extension through
|
|
779
|
-
// the environment. A model never supplies a command; it names a check.
|
|
780
|
-
// 0.40.0: and the folder this process keeps its sessions in — a child
|
|
781
|
-
// writes beside its parent, whatever directory it runs in. Through this
|
|
782
|
-
// channel and not an exported KISO_SESSIONS_DIR: a variable in
|
|
783
|
-
// process.env would reach every shell child, and a kiso started from a
|
|
784
|
-
// shell tool would then write into this project's folder.
|
|
785
|
-
process.env.KISO_DELEGATION_CONFIG_JSON = JSON.stringify({ checks: merged.checks ?? {}, profiles: Object.keys(merged.models ?? {}), sessionsDir: sessionsDir() });
|
|
786
|
-
setConfigModels(merged.models ?? {});
|
|
787
|
-
// CW-1 batch 2: the windows endpoints stated by refusing — read before the
|
|
788
|
-
// first window is asked for (the unknown-window notice below).
|
|
789
|
-
useLearnedWindows();
|
|
790
|
-
const resolved = resolveModel(modelFlag, merged);
|
|
791
|
-
// AFTER the model resolves: the window a PROFILE states is about that
|
|
792
|
-
// profile's model, so it cannot be read before we know which profile is
|
|
793
|
-
// selected. Reading it a line too early is how the compaction threshold
|
|
794
|
-
// ended up frozen at the wrong model's value (CTX-1).
|
|
795
|
-
setConfiguredWindow(resolveContextWindow(merged, resolved?.profile));
|
|
796
|
-
const model = resolved === null ? "faux" : resolved.profile.model;
|
|
797
|
-
if (resolved === null) {
|
|
798
|
-
console.log("[faux mode — set ANTHROPIC_API_KEY or OPENAI_API_KEY, or configure models in ~/.kiso/config.json]\n");
|
|
799
|
-
setCurrentFaux(true);
|
|
800
|
-
setCurrentModelName("faux");
|
|
801
|
-
setCurrentProfileName(null);
|
|
802
|
-
}
|
|
803
|
-
else {
|
|
804
|
-
setCurrentFaux(false);
|
|
805
|
-
setCurrentModelName(resolved.name);
|
|
806
|
-
setCurrentProfileName(resolved.name);
|
|
807
|
-
}
|
|
808
|
-
setAgentModel(model, resolved?.profile.baseUrl); // v2b: the status bar shows it; OR-1: the endpoint rides along
|
|
809
|
-
// ADR-0055 Amendment 2: the row says `ctx ?` for an unstated window, but
|
|
810
|
-
// the tiers still need a number and assume the fallback — say so, once,
|
|
811
|
-
// at build.
|
|
812
|
-
if (!unknownWindowNoticed && knownContextWindow() === null) {
|
|
813
|
-
unknownWindowNoticed = true;
|
|
814
|
-
console.error(unknownWindowNotice(model));
|
|
815
|
-
}
|
|
816
|
-
// W21: the extensions array is built ONCE per agent and shared with
|
|
817
|
-
// the runtime by reference — the don't-ask-again writer pushes the
|
|
818
|
-
// generated extension into it so a first-time rule joins the chain
|
|
819
|
-
// at the NEXT run (the run's policies are fixed at its start; run.ts
|
|
820
|
-
// re-reads the config's extensions array per run).
|
|
821
|
-
// LT-2: the loop breaker at the chain HEAD — it speaks first when it speaks,
|
|
822
|
-
// so `decidedBy` names it; a deny there beats every tier, bypass included.
|
|
823
|
-
// 0.40.0: the read-only shell allow sits after the tiers — an allow from
|
|
824
|
-
// it outranks a tier's ask and names itself in decidedBy.
|
|
825
|
-
// 0.40.0: a saved allow never carries a write into .git/ or .kiso/, nor
|
|
826
|
-
// a destructive shell command.
|
|
827
|
-
const workspaceRoot = () => codingToolOptions().workspaceRoot;
|
|
828
|
-
const neverInherited = (call) => isProtectedWrite(call, workspaceRoot()) || isDestructiveCall(call);
|
|
829
|
-
setNeverInherited(neverInherited);
|
|
830
|
-
// 0.40.0: the catastrophe floor, at the chain's HEAD — a deny there
|
|
831
|
-
// names itself in decidedBy and outranks every tier, bypass included.
|
|
832
|
-
// Read per agent, so /reload picks up an edited user config.
|
|
833
|
-
const userConfig = loadUserConfig();
|
|
834
|
-
setFloorOn(userConfig?.floor !== "off");
|
|
835
|
-
// kiso never serves its own credential store to a model: the file tools
|
|
836
|
-
// refuse it through codingToolOptions, and this member denies a shell
|
|
837
|
-
// line naming it — at the HEAD with the floor, in every mode, and NOT
|
|
838
|
-
// switched off with it (`floor: "off"` lowers the catastrophe floor,
|
|
839
|
-
// never this).
|
|
840
|
-
setUserProtectedPaths(userConfig?.protectedPaths);
|
|
841
|
-
const extensions = [
|
|
842
|
-
protectedShellExtension({ files: protectedFiles, workspaceRoot, env: () => ({ home: homedir(), kisoHome: kisoHome() }) }),
|
|
843
|
-
floorExtension(() => floorOn, workspaceRoot),
|
|
844
|
-
breakerExtension(),
|
|
845
|
-
...modeExtensions(workspaceRoot),
|
|
846
|
-
readOnlyShellExtension(codingToolOptions),
|
|
847
|
-
...loadedExtensions.map((e) => guardSavedAllow(e, neverInherited)),
|
|
848
|
-
];
|
|
849
|
-
setCurrentAgentExtensions(extensions);
|
|
850
|
-
// E6: the run-start context policy (captured once — exactOptionalPropertyTypes).
|
|
851
|
-
const contextPolicy = contextPolicyFromEnv();
|
|
852
|
-
const idleFromEnv = streamIdleFromEnv(); // read once: a narrowed const, not a call per spread
|
|
853
|
-
const retriesFromEnv = maxRetriesFromEnv();
|
|
854
|
-
const definition = {
|
|
855
|
-
model,
|
|
856
|
-
store,
|
|
857
|
-
// 0.40.0: a NEW session records where it started; the picker scopes by
|
|
858
|
-
// it. The profile name is recorded only when the model came from a
|
|
859
|
-
// config profile — a direct provider/model or an env key names none.
|
|
860
|
-
workspace: workspaceRoot(),
|
|
861
|
-
...(resolved !== null && merged.models?.[resolved.name] === resolved.profile ? { profileName: resolved.name } : {}),
|
|
862
|
-
// Area 5: the coding tools are bound to the workspace — every path
|
|
863
|
-
// they touch is canonicalized inside cwd, escapes are refused.
|
|
864
|
-
tools: [...createCodingTools(codingToolOptions())], // DC-49 — the options live in state.ts, shared with the `!` command's runner
|
|
865
|
-
// Modes: the five tiers ride the E1 policy chain (mode:<tier>
|
|
866
|
-
// extensions, current tier first) — the old static PERMISSION_POLICY
|
|
867
|
-
// is gone, its semantics live in the "default" tier. The banner
|
|
868
|
-
// still counts loadedExtensions only — the modes are in-process,
|
|
869
|
-
// never a file extension.
|
|
870
|
-
systemPrompt: (() => {
|
|
871
|
-
const sp = composeSystemPrompt(process.cwd(), protectedFiles());
|
|
872
|
-
const extra = modeSystemPrompt();
|
|
873
|
-
return extra === undefined ? sp : `${sp}\n\n${extra}`;
|
|
874
|
-
})(),
|
|
875
|
-
// ADR-0055 Amendment 1 (A1b): compaction is ON by default and runs
|
|
876
|
-
// INSIDE a run, by tiers drawn from the model's window (CTX-1: the
|
|
877
|
-
// binding step moves the window with /model and /resume). The
|
|
878
|
-
// standing microcompact at half the window is gone (A4). Phase rule
|
|
879
|
-
// 1 reads the user's configured checks first, then the runner table.
|
|
880
|
-
contextPolicy: {
|
|
881
|
-
...(contextPolicy ?? {}),
|
|
882
|
-
tiers: {
|
|
883
|
-
windowTokens: contextWindowTokens(),
|
|
884
|
-
isCheck: (command) => runsACheck(command, Object.values(merged.checks ?? {})),
|
|
885
|
-
// ADR-0055 Amendment 2: a discarded checkpoint says so, in sizes only.
|
|
886
|
-
onDiscard: (d) => body.notice(compactionDiscardedNotice(d)),
|
|
887
|
-
// ADR-0055 Amendment 2 (decision 3): only a window someone stated
|
|
888
|
-
// arms the overflow belt — read from the LIVE binding, so it moves
|
|
889
|
-
// with /model and /resume; the fallback reads as null.
|
|
890
|
-
statedWindow: () => knownContextWindow(),
|
|
891
|
-
// CW-1 batch 2: an endpoint's refusal stated its cap. The tiers
|
|
892
|
-
// took it already; kept, it is where the next session starts, and
|
|
893
|
-
// the status row's denominator moves with it. Said once per new
|
|
894
|
-
// figure — a refusal at a cap already kept says nothing.
|
|
895
|
-
onWindowLearned: (w) => {
|
|
896
|
-
if (recordLearnedWindow(w.model, w.baseUrl, w.tokens))
|
|
897
|
-
body.notice(windowLearnedNotice(w.model, providerHost(w.baseUrl) ?? "", w.tokens));
|
|
898
|
-
},
|
|
899
|
-
},
|
|
900
|
-
},
|
|
901
|
-
// R3e (owner ruling, 2026-08-28): NO turn limit on an interactive
|
|
902
|
-
// session. This was `maxTurns: 20`, hardcoded on 2026-08-03 with no
|
|
903
|
-
// stated reason and no way to change it — and it was the thing that
|
|
904
|
-
// stopped a real 43-call session dead, mid-task, in silence. The
|
|
905
|
-
// field survives for the callers that want a bound (subagents, the
|
|
906
|
-
// SDK, `kiso run`); the interactive front door does not set one.
|
|
907
|
-
// Modes: the five tiers join at the CHAIN HEAD, before the user/
|
|
908
|
-
// project extensions (the deny>allow>ask composition keeps a user
|
|
909
|
-
// deny winning over any mode tier — bypass included).
|
|
910
|
-
extensions,
|
|
911
|
-
...(resolved !== null
|
|
912
|
-
? {
|
|
913
|
-
provider: resolved.profile.kind,
|
|
914
|
-
// Astra F1 (P0): the wire config is built in ONE place
|
|
915
|
-
// (auth/adapter-options.ts) — credential shape, the ALWAYS
|
|
916
|
-
// EXPLICIT endpoint, the session's cache key and the
|
|
917
|
-
// profile's caching flag. This site and the `/model` site
|
|
918
|
-
// were the same spread written twice.
|
|
919
|
-
...adapterOptionsFor(resolved.profile, resolved.oauthProviderId !== undefined
|
|
920
|
-
? { type: "oauth", providerId: resolved.oauthProviderId }
|
|
921
|
-
: { type: "api-key", apiKey: resolved.apiKey ?? "none" }, sessionId),
|
|
922
|
-
// LT-1: the profile's stream watchdog bound, if it states one.
|
|
923
|
-
// NOT an adapter option — an agent-definition field the
|
|
924
|
-
// runtime reads — so it stays here rather than moving into
|
|
925
|
-
// adapterOptionsFor.
|
|
926
|
-
...(resolved.profile.streamIdleMs !== undefined ? { streamIdleMs: resolved.profile.streamIdleMs } : {}),
|
|
927
|
-
}
|
|
928
|
-
: { adapter: createFauxProvider(readFauxScript().slice(fauxSkipTurns)) }),
|
|
929
|
-
// LT-1: KISO_STREAM_IDLE_MS (the test rigs' knob) beats the profile —
|
|
930
|
-
// the last spread wins, which is why it sits after the profile's.
|
|
931
|
-
...(idleFromEnv !== undefined ? { streamIdleMs: idleFromEnv } : {}),
|
|
932
|
-
...(retriesFromEnv !== undefined ? { maxRetries: retriesFromEnv } : {}),
|
|
933
|
-
// ADR-0005 Amendment 2: the kernel announces each retry before its
|
|
934
|
-
// wait; the running row shows it. Composed with every extension's
|
|
935
|
-
// hooks by the runtime — an extension observing retries too is heard.
|
|
936
|
-
hooks: {
|
|
937
|
-
onRetry: async (info) => {
|
|
938
|
-
setRetryShown({ attempt: info.attempt, maxRetries: info.maxRetries, code: info.code, until: Date.now() + info.delayMs });
|
|
939
|
-
},
|
|
940
|
-
},
|
|
941
|
-
};
|
|
942
|
-
return createAgent(definition);
|
|
943
|
-
}
|
|
944
576
|
export { workspaceRoot } from "./state.js";
|
|
945
577
|
/** TUI2-R2 ② — the picker's affordance row: the keys, said where the
|
|
946
578
|
* keys are useful. */
|
|
@@ -953,7 +585,7 @@ const PICKER_HINT = "↑↓ pick · ⏎ resumes · type filters · esc";
|
|
|
953
585
|
async function sessionCards(_agent, announce = (l) => bodyLog(l)) {
|
|
954
586
|
const store = sessionStoreRef;
|
|
955
587
|
if (store === null)
|
|
956
|
-
return []; // unreachable:
|
|
588
|
+
return []; // unreachable: createCodingAgent builds the store first
|
|
957
589
|
const folders = listingFolders();
|
|
958
590
|
// 0.40.0 dogfood (item 2, lead's ruling A): the ONE-TIME migration — the
|
|
959
591
|
// first list after the upgrade reads each legacy log exactly once and
|
|
@@ -987,28 +619,6 @@ function listingFolders() {
|
|
|
987
619
|
const mine = all.find((f) => f.dir === here) ?? { dir: here, workspace: projectRoot(), kind: "project" };
|
|
988
620
|
return [mine, ...all.filter((f) => f.dir !== here)];
|
|
989
621
|
}
|
|
990
|
-
/**
|
|
991
|
-
* 0.40.0 — before any session opens: the one-time move of the legacy
|
|
992
|
-
* folder into project folders (announced once, with the undo), then this
|
|
993
|
-
* project's folder claimed. Nothing happens under a pinned folder or after
|
|
994
|
-
* a reversed migration.
|
|
995
|
-
*/
|
|
996
|
-
function prepareSessionFolders() {
|
|
997
|
-
const home = kisoHome();
|
|
998
|
-
if (!projectLayoutActive(home))
|
|
999
|
-
return;
|
|
1000
|
-
if (pendingLegacyIds(home).length > 0) {
|
|
1001
|
-
const result = runMigration(home, planMigration(home));
|
|
1002
|
-
if (result !== null && result.moved > 0) {
|
|
1003
|
-
const line = migrationNotice(result);
|
|
1004
|
-
if (process.stdout.isTTY)
|
|
1005
|
-
bodyLog(line);
|
|
1006
|
-
else
|
|
1007
|
-
process.stderr.write(`${line}\n`);
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
claimProjectDir(ownSessionsDir(), projectRoot());
|
|
1011
|
-
}
|
|
1012
622
|
/**
|
|
1013
623
|
* 0.40.0 (the owner's dogfood: a uooki session resumed from flowpix2) —
|
|
1014
624
|
* whether a session id may open in this project. Its own folder: yes. A
|
|
@@ -1052,8 +662,6 @@ function sessionFolderOf(id) {
|
|
|
1052
662
|
const route = routeSession(id);
|
|
1053
663
|
return route?.kind === "elsewhere" ? route.dir : ownSessionsDir();
|
|
1054
664
|
}
|
|
1055
|
-
/** The folder makeAgent built the store on. */
|
|
1056
|
-
let activeStoreDir = "";
|
|
1057
665
|
/** The workspace a listing is scoped to: a project folder's identity under
|
|
1058
666
|
* the per-project layout, the recorded realpath in one pinned folder. */
|
|
1059
667
|
function scopeRoot() {
|
|
@@ -1064,7 +672,7 @@ function tildeOf(path) {
|
|
|
1064
672
|
return path === home || path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;
|
|
1065
673
|
}
|
|
1066
674
|
/** The explicit-id doors (`chat <id>`, `resume <id>`, `-p … <id>`), BEFORE
|
|
1067
|
-
*
|
|
675
|
+
* createCodingAgent builds the store: a refusal is the entry's error (the line on
|
|
1068
676
|
* stderr, exit 2); a session in another folder opens there. Returns the
|
|
1069
677
|
* line to say once the session is up. */
|
|
1070
678
|
function enterRouted(id) {
|
|
@@ -1126,7 +734,7 @@ async function pickSession(agent, input) {
|
|
|
1126
734
|
* tier, the /mode hint, the model and the remaining context belong.
|
|
1127
735
|
*
|
|
1128
736
|
* It is painted HERE, at the first moment every field is TRUE: after
|
|
1129
|
-
*
|
|
737
|
+
* createCodingAgent, because that is where the model is resolved. Painting it at
|
|
1130
738
|
* dock.enter() — the literally-first frame — would have to name a model
|
|
1131
739
|
* nobody had chosen yet, and a status row that guesses is worse than a
|
|
1132
740
|
* status row that waits two hundred milliseconds.
|
|
@@ -1145,7 +753,6 @@ async function pickSession(agent, input) {
|
|
|
1145
753
|
* once; 0.41.0 removes it.
|
|
1146
754
|
*/
|
|
1147
755
|
let autoCompactNoticed = false;
|
|
1148
|
-
let unknownWindowNoticed = false;
|
|
1149
756
|
function retiredAutoCompact(merged) {
|
|
1150
757
|
if (!autoCompactNoticed && (process.env.KISO_AUTO_COMPACT !== undefined || resolveAutoCompact(merged) !== undefined)) {
|
|
1151
758
|
autoCompactNoticed = true;
|
|
@@ -1244,21 +851,21 @@ function skillCount() {
|
|
|
1244
851
|
* invisible in it, because nothing the model said or did changes.
|
|
1245
852
|
*/
|
|
1246
853
|
async function reloadAgent(old, id, input, announce = true) {
|
|
1247
|
-
// Snapshot BEFORE
|
|
854
|
+
// Snapshot BEFORE createCodingAgent: it overwrites every one of these, so the
|
|
1248
855
|
// old set would be unreachable by the time we needed to dispose it.
|
|
1249
856
|
const oldLoaded = loadedExtensions;
|
|
1250
857
|
const oldBuiltIn = builtInExtensions;
|
|
1251
858
|
const oldUser = userExtensions;
|
|
1252
859
|
const oldProject = projectExtensions;
|
|
1253
860
|
const oldTemps = mergedTempPaths.splice(0);
|
|
1254
|
-
//
|
|
861
|
+
// createCodingAgent publishes the config side BEFORE it can fail on the model,
|
|
1255
862
|
// so a failure past the extension load would leave a NEW window, model
|
|
1256
863
|
// name and profile table beside the OLD agent — and the failure line
|
|
1257
864
|
// says nothing changed. Rather than soften the line, the snapshot makes
|
|
1258
865
|
// it true: a failed reload is atomic, which is what load-then-swap
|
|
1259
866
|
// promises. (Lead's review of 5bee644, observation 1.)
|
|
1260
867
|
const oldCfg = {
|
|
1261
|
-
// RL-F6:
|
|
868
|
+
// RL-F6: createCodingAgent publishes this BEFORE createAgent, and createAgent
|
|
1262
869
|
// throws on a tool-name collision — a user extension exposing
|
|
1263
870
|
// `read_file` is enough — so a failure CAN land after it. Left
|
|
1264
871
|
// unrestored, the new array stands beside the old agent, whose config
|
|
@@ -1280,19 +887,19 @@ async function reloadAgent(old, id, input, announce = true) {
|
|
|
1280
887
|
};
|
|
1281
888
|
let next;
|
|
1282
889
|
try {
|
|
1283
|
-
next = await
|
|
890
|
+
next = await createCodingAgent(id, input, modelChoice);
|
|
1284
891
|
}
|
|
1285
892
|
catch (err) {
|
|
1286
893
|
// Nothing is swapped. Clean up whatever the failed attempt managed
|
|
1287
894
|
// to create, put the old set's own temp paths back so exit still
|
|
1288
|
-
// removes them, and restore the lists in case
|
|
895
|
+
// removes them, and restore the lists in case createCodingAgent got far
|
|
1289
896
|
// enough to publish new ones.
|
|
1290
897
|
for (const p of mergedTempPaths.splice(0)) {
|
|
1291
898
|
try {
|
|
1292
899
|
rmSync(p, { recursive: true, force: true });
|
|
1293
900
|
}
|
|
1294
901
|
catch {
|
|
1295
|
-
// best-effort —
|
|
902
|
+
// best-effort — a survivor is removed by a later startup's sweep (temp-sweep.ts) once this process is gone
|
|
1296
903
|
}
|
|
1297
904
|
}
|
|
1298
905
|
mergedTempPaths.push(...oldTemps);
|
|
@@ -1321,7 +928,7 @@ async function reloadAgent(old, id, input, announce = true) {
|
|
|
1321
928
|
rmSync(p, { recursive: true, force: true });
|
|
1322
929
|
}
|
|
1323
930
|
catch {
|
|
1324
|
-
// best-effort —
|
|
931
|
+
// best-effort — a survivor is removed by a later startup's sweep (temp-sweep.ts) once this process is gone
|
|
1325
932
|
}
|
|
1326
933
|
}
|
|
1327
934
|
if (announce)
|
|
@@ -1357,8 +964,8 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1357
964
|
setOpenSessionFolder(folder === ownSessionsDir() ? null : folder);
|
|
1358
965
|
const next = await reloadAgent(agent, id, input, false);
|
|
1359
966
|
if (next === agent) {
|
|
1360
|
-
//
|
|
1361
|
-
|
|
967
|
+
// createCodingAgent may have built the new store before it failed
|
|
968
|
+
setActiveStoreDir(was.dir);
|
|
1362
969
|
if (was.store !== null)
|
|
1363
970
|
setSessionStore(was.store);
|
|
1364
971
|
setOpenSessionFolder(was.dir === ownSessionsDir() ? null : was.dir);
|
|
@@ -1473,7 +1080,7 @@ async function chatLoop(first, firstId, input, autoCompact) {
|
|
|
1473
1080
|
setCurrentModelName(session.model);
|
|
1474
1081
|
// A SWITCH knows only a model id here — nothing that names the profile —
|
|
1475
1082
|
// so the mark is cleared rather than guessed. A FRESH start keeps what
|
|
1476
|
-
//
|
|
1083
|
+
// createCodingAgent resolved from `--model <profile>`, which is the one place
|
|
1477
1084
|
// the name is known (prev is null only on the first entry).
|
|
1478
1085
|
if (prev !== null)
|
|
1479
1086
|
setCurrentProfileName(null);
|
|
@@ -1583,7 +1190,7 @@ async function main() {
|
|
|
1583
1190
|
// banner and the first frame are in the record. Off by default.
|
|
1584
1191
|
armByteTrace();
|
|
1585
1192
|
// Modes: --mode <name> wins over KISO_MODE — both applied before the
|
|
1586
|
-
// first
|
|
1193
|
+
// first createCodingAgent (the tier extensions read `current` live). The flag
|
|
1587
1194
|
// is stripped from the positional args, so it works in any position.
|
|
1588
1195
|
const args = process.argv.slice(2);
|
|
1589
1196
|
// XP-1: --accept-drift (a flag, never an env var) authorizes opening a
|
|
@@ -1627,7 +1234,7 @@ async function main() {
|
|
|
1627
1234
|
args.splice(printIdx, 2);
|
|
1628
1235
|
}
|
|
1629
1236
|
// merge round B: --model <profile|provider/model> — the top of the model
|
|
1630
|
-
// precedence chain; the value flows into
|
|
1237
|
+
// precedence chain; the value flows into createCodingAgent's config resolution.
|
|
1631
1238
|
let modelFlag;
|
|
1632
1239
|
const modelArgIdx = args.indexOf("--model");
|
|
1633
1240
|
if (modelArgIdx !== -1) {
|
|
@@ -1640,7 +1247,7 @@ async function main() {
|
|
|
1640
1247
|
}
|
|
1641
1248
|
// Modes: --mode wins over KISO_MODE, which wins over the USER config's
|
|
1642
1249
|
// mode (the project config's mode applies later — after the trust gate,
|
|
1643
|
-
// inside
|
|
1250
|
+
// inside createCodingAgent — unless a higher layer already decided).
|
|
1644
1251
|
const modeFlag = args.indexOf("--mode");
|
|
1645
1252
|
if (modeFlag !== -1) {
|
|
1646
1253
|
const m = MODES.find((x) => x === args[modeFlag + 1]);
|
|
@@ -1717,7 +1324,7 @@ async function main() {
|
|
|
1717
1324
|
const [command, arg] = args;
|
|
1718
1325
|
// round 8: faux mode is the keyless demo script — an exhausted script must
|
|
1719
1326
|
// exit non-zero, never masquerade as a successful provider run. The
|
|
1720
|
-
// verdict comes from
|
|
1327
|
+
// verdict comes from createCodingAgent's config resolution now (a config
|
|
1721
1328
|
// profile can provide a real model with no OPENAI_* env).
|
|
1722
1329
|
let faux = true;
|
|
1723
1330
|
let agent;
|
|
@@ -1831,7 +1438,7 @@ async function main() {
|
|
|
1831
1438
|
// verbatim (a fresh id makes the recovery a no-op)
|
|
1832
1439
|
const id = command ?? newSessionId(sessionsDir());
|
|
1833
1440
|
const routeLine = command !== undefined ? enterRouted(id) : null;
|
|
1834
|
-
agent = await
|
|
1441
|
+
agent = await createCodingAgent(id, input, modelFlag);
|
|
1835
1442
|
applyConfigMode();
|
|
1836
1443
|
sayRouteLine(routeLine);
|
|
1837
1444
|
const session = await agent.session({ id, ...(acceptDrift() ? { acceptDrift: true } : {}) });
|
|
@@ -1851,7 +1458,7 @@ async function main() {
|
|
|
1851
1458
|
// E area: a resumed session continues the script at its durable
|
|
1852
1459
|
// position — never restarts it (fauxSkip).
|
|
1853
1460
|
const routeLine = arg !== undefined ? enterRouted(id) : null;
|
|
1854
|
-
agent = await
|
|
1461
|
+
agent = await createCodingAgent(id, input, modelFlag);
|
|
1855
1462
|
applyConfigMode();
|
|
1856
1463
|
sayRouteLine(routeLine);
|
|
1857
1464
|
faux = currentFaux;
|
|
@@ -1873,7 +1480,7 @@ async function main() {
|
|
|
1873
1480
|
const prompt = process.argv[4];
|
|
1874
1481
|
dock.enter();
|
|
1875
1482
|
const routeLine = arg !== undefined ? enterRouted(arg) : null;
|
|
1876
|
-
agent = await
|
|
1483
|
+
agent = await createCodingAgent(arg, input, modelFlag);
|
|
1877
1484
|
applyConfigMode();
|
|
1878
1485
|
let id = arg;
|
|
1879
1486
|
if (id === undefined) {
|
|
@@ -1907,7 +1514,7 @@ async function main() {
|
|
|
1907
1514
|
faux = currentFaux;
|
|
1908
1515
|
// E area: the durable script position is computed from the
|
|
1909
1516
|
// session id, and on the picker path the id did not exist when
|
|
1910
|
-
//
|
|
1517
|
+
// createCodingAgent ran. Re-arm the scripted adapter at the PICKED
|
|
1911
1518
|
// session's position so a picked resume continues its script
|
|
1912
1519
|
// exactly where `kiso resume <id>` would have.
|
|
1913
1520
|
if (faux && arg === undefined)
|
|
@@ -1921,14 +1528,14 @@ async function main() {
|
|
|
1921
1528
|
case "sessions": {
|
|
1922
1529
|
// R-I-p2 audit (the argument-consistency mandate): the
|
|
1923
1530
|
// read-only listing NEVER writes through the input, but the
|
|
1924
|
-
// trust gate lives inside
|
|
1531
|
+
// trust gate lives inside createCodingAgent and ASKS through it — on
|
|
1925
1532
|
// a TTY with a first-discovery .kiso, the undefined input
|
|
1926
1533
|
// crashed identically to the bare command (finding R-I-p-2,
|
|
1927
1534
|
// "reading 'question'" on the dock-less branch). The input
|
|
1928
1535
|
// exists so the gate's ask can be answered; the listing
|
|
1929
1536
|
// itself never touches it.
|
|
1930
1537
|
if (pruneEmpty !== undefined) {
|
|
1931
|
-
// DC-60: before
|
|
1538
|
+
// DC-60: before createCodingAgent — the scan only reads, and nothing
|
|
1932
1539
|
// needs an agent to move a file to the Trash
|
|
1933
1540
|
const { empty, inUse } = findEmptySessions(listingFolders().map((f) => f.dir));
|
|
1934
1541
|
const n = (k, w) => `${k} ${w}${k === 1 ? "" : "s"}`;
|
|
@@ -1947,13 +1554,13 @@ async function main() {
|
|
|
1947
1554
|
break;
|
|
1948
1555
|
}
|
|
1949
1556
|
if (reverseManifest !== undefined) {
|
|
1950
|
-
// before
|
|
1557
|
+
// before createCodingAgent: its folder preparation would otherwise run
|
|
1951
1558
|
// the very move this undoes
|
|
1952
1559
|
const { restored, left } = reverseMigration(kisoHome(), reverseManifest);
|
|
1953
1560
|
console.log(`moved ${restored} session${restored === 1 ? "" : "s"} back to ${join(kisoHome(), "sessions")}; one folder per project is off until ${join(kisoHome(), "projects", ".migration-reversed")} is removed${left > 0 ? ` — ${left} created since the move stay in their project folders` : ""}`);
|
|
1954
1561
|
break;
|
|
1955
1562
|
}
|
|
1956
|
-
agent = await
|
|
1563
|
+
agent = await createCodingAgent(undefined, input, modelFlag);
|
|
1957
1564
|
// TUI2-R2 ③ — the same projection the picker renders, printed.
|
|
1958
1565
|
// The PIPE keeps today's bytes exactly: `kiso sessions` is
|
|
1959
1566
|
// something scripts read, and a badge column is a TTY-render
|
|
@@ -2047,7 +1654,7 @@ async function main() {
|
|
|
2047
1654
|
if (cred.type === "api-key")
|
|
2048
1655
|
lines.push(` ${id.padEnd(10)} api-key ${maskSecret(cred.key)} saved ${new Date(cred.savedAt).toISOString().slice(0, 10)}`);
|
|
2049
1656
|
else
|
|
2050
|
-
lines.push(` ${id.padEnd(10)} oauth ${cred.accountId ?? ""} expires ${new Date(cred.expires).toISOString()}${cred.expires < Date.now() ? " (expired)" : ""}`);
|
|
1657
|
+
lines.push(` ${id.padEnd(10)} oauth ${cred.accountId ?? ""} expires ${new Date(cred.expires).toISOString()}${cred.refreshRejectedAt !== undefined ? ` (renewal refused — run kiso login ${id})` : cred.expires < Date.now() ? " (expired — renews on use)" : ""}`);
|
|
2051
1658
|
}
|
|
2052
1659
|
const envs = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY"].filter((k) => process.env[k] !== undefined);
|
|
2053
1660
|
lines.push(`env vars set: ${envs.length ? envs.join(", ") : "none"} (a stored credential owns its provider; env applies only when nothing is stored)`);
|
|
@@ -2161,7 +1768,7 @@ async function main() {
|
|
|
2161
1768
|
// through the undefined input: "Cannot read properties of
|
|
2162
1769
|
// undefined" at the ask (panelAsk with the dock, question on
|
|
2163
1770
|
// the dock-less fallback).
|
|
2164
|
-
agent = await
|
|
1771
|
+
agent = await createCodingAgent(id, input, modelFlag);
|
|
2165
1772
|
// finding E4-1's faux resolution rides chatLoop (currentFaux).
|
|
2166
1773
|
faux = currentFaux;
|
|
2167
1774
|
// CX-1 F9 (audit F9): the bare entry resolves autoCompact from
|
|
@@ -2198,7 +1805,7 @@ async function main() {
|
|
|
2198
1805
|
rmSync(p, { recursive: true, force: true });
|
|
2199
1806
|
}
|
|
2200
1807
|
catch {
|
|
2201
|
-
// best-effort —
|
|
1808
|
+
// best-effort — a survivor is removed by a later startup's sweep (temp-sweep.ts) once this process is gone
|
|
2202
1809
|
}
|
|
2203
1810
|
}
|
|
2204
1811
|
}
|