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