@vincemakes/kiso-code 0.1.44 → 0.1.46
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/builtin.d.ts +2 -0
- package/dist/builtin.js +31 -0
- package/dist/first-run.d.ts +9 -0
- package/dist/first-run.js +37 -0
- package/dist/index.js +52 -30
- package/dist/state.d.ts +5 -1
- package/dist/state.js +6 -1
- package/package.json +6 -2
package/dist/builtin.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R-D 0.1.45 — the built-in layer: the four official extensions (mcp,
|
|
3
|
+
* skills, subagent, task), shipped in the cli package and registered by
|
|
4
|
+
* MODULE IMPORT — never a disk scan (the user layer's loadExtensions stays
|
|
5
|
+
* word-for-word untouched). The cascade, base → top: built-in → user
|
|
6
|
+
* (~/.kiso/extensions) → project (.kiso/extensions, trust-gated).
|
|
7
|
+
*
|
|
8
|
+
* - a user extension may SHADOW a built-in by name — the user's deliberate
|
|
9
|
+
* install wins (a built-in cannot be uninstalled), loudly, and the
|
|
10
|
+
* shadowed built-in leaves the loaded set and the banner;
|
|
11
|
+
* - the project layer may NOT shadow anything below — the same-name
|
|
12
|
+
* refusal the loader already applies to the user layer, spelled out
|
|
13
|
+
* for the built-in layer too.
|
|
14
|
+
*/
|
|
15
|
+
import createMcp from "@vincemakes/kiso-mcp-ext";
|
|
16
|
+
import createSkills from "@vincemakes/kiso-skills-ext";
|
|
17
|
+
import createSubagent from "@vincemakes/kiso-subagent-ext";
|
|
18
|
+
import createTask from "@vincemakes/kiso-task-ext";
|
|
19
|
+
export async function builtInLayer(user, project) {
|
|
20
|
+
const all = await Promise.all([createMcp(), createSkills(), createSubagent(), createTask()]);
|
|
21
|
+
const shadowed = all.filter((b) => user.some((u) => u.name === b.name));
|
|
22
|
+
for (const s of shadowed) {
|
|
23
|
+
console.error(`[extensions] user extension "${s.name}" shadows the built-in — the built-in is not loaded`);
|
|
24
|
+
}
|
|
25
|
+
for (const p of project) {
|
|
26
|
+
if (all.some((b) => b.name === p.name)) {
|
|
27
|
+
throw new Error(`[extensions] extension name "${p.name}" exists in both the built-in and the project-level extensions — refusing to shadow`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return all.filter((b) => !shadowed.includes(b));
|
|
31
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** First-run detection. Called only post-gate, so the verdict precedes
|
|
2
|
+
* even the first home READ. */
|
|
3
|
+
export declare function isFirstRun(): boolean;
|
|
4
|
+
/** Materialize the config surface (never clobbering a user's own config)
|
|
5
|
+
* and stamp the sentinel — the sequence's second home write. SILENT on
|
|
6
|
+
* purpose: every stream line must match a known cell format (the v2d
|
|
7
|
+
* lint), and the PTY grids pin the startup stream byte-for-byte — the
|
|
8
|
+
* first-run sequence is evidenced by the FILES, not an announcement. */
|
|
9
|
+
export declare function scaffoldFirstRun(): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* R-D 0.1.45 (deliverable B) — the first-run scaffold. A fresh install's
|
|
3
|
+
* FIRST startup materializes the config surface (the file the faux-mode
|
|
4
|
+
* notice names) and stamps the sentinel that ends first-run.
|
|
5
|
+
*
|
|
6
|
+
* Runs AFTER the E3 trust gate: pre-trust zero-read/write/scan is
|
|
7
|
+
* absolute — the trust question is the process's first home access of
|
|
8
|
+
* any kind, the trust record the first home write, the scaffold the
|
|
9
|
+
* second. First-run detection never precedes the verdict.
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { kisoHome } from "./state.js";
|
|
14
|
+
/** The sentinel: present = the home has seen the 0.1.45 first-run
|
|
15
|
+
* sequence (its config surface exists — no re-scaffold, no re-note). */
|
|
16
|
+
const SENTINEL = "first-run";
|
|
17
|
+
/** The minimal config surface — an empty models layer changes nothing
|
|
18
|
+
* (faux stays the default), but the file the notice points at exists. */
|
|
19
|
+
const CONFIG_SCAFFOLD = `${JSON.stringify({ models: {} }, null, 2)}\n`;
|
|
20
|
+
/** First-run detection. Called only post-gate, so the verdict precedes
|
|
21
|
+
* even the first home READ. */
|
|
22
|
+
export function isFirstRun() {
|
|
23
|
+
return !existsSync(join(kisoHome(), SENTINEL));
|
|
24
|
+
}
|
|
25
|
+
/** Materialize the config surface (never clobbering a user's own config)
|
|
26
|
+
* and stamp the sentinel — the sequence's second home write. SILENT on
|
|
27
|
+
* purpose: every stream line must match a known cell format (the v2d
|
|
28
|
+
* lint), and the PTY grids pin the startup stream byte-for-byte — the
|
|
29
|
+
* first-run sequence is evidenced by the FILES, not an announcement. */
|
|
30
|
+
export function scaffoldFirstRun() {
|
|
31
|
+
const home = kisoHome();
|
|
32
|
+
mkdirSync(home, { recursive: true });
|
|
33
|
+
const config = join(home, "config.json");
|
|
34
|
+
if (!existsSync(config))
|
|
35
|
+
writeFileSync(config, CONFIG_SCAFFOLD, "utf8");
|
|
36
|
+
writeFileSync(join(home, SENTINEL), "", "utf8");
|
|
37
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -22,8 +22,9 @@
|
|
|
22
22
|
* index.ts keeps the entry: banner, input sources, the A area prompt,
|
|
23
23
|
* makeAgent, and main.
|
|
24
24
|
*/
|
|
25
|
-
import { readFileSync, rmSync } from "node:fs";
|
|
25
|
+
import { readFileSync, realpathSync, rmSync } from "node:fs";
|
|
26
26
|
import { createInterface } from "node:readline";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
27
28
|
import { join } from "node:path";
|
|
28
29
|
import { Body, Editor, bannerLines, palette, renderSessionLine } from "@vincemakes/kiso-tui";
|
|
29
30
|
import { escapeTerminal } from "@vincemakes/kiso-tui";
|
|
@@ -31,8 +32,10 @@ import { createAgent, disposeExtensions, loadExtensions, loadProjectExtensions,
|
|
|
31
32
|
import { createFauxProvider } from "@vincemakes/kiso-evals";
|
|
32
33
|
import { createCodingTools } from "@vincemakes/kiso-tools-node";
|
|
33
34
|
import { MODES, modeExtensions, modeFromEnv, modeSystemPrompt, setMode } from "./mode.js";
|
|
34
|
-
import {
|
|
35
|
+
import { builtInLayer } from "./builtin.js";
|
|
36
|
+
import { body, bodyLog, builtInExtensions, currentFaux, dock, extensionsDir, loadedExtensions, mergedConfig, mergedTempPaths, projectExtensions, sessionsDir, setAgentModel, setBody, setConfigModels, setConfiguredWindow, setCurrentAgentExtensions, setCurrentFaux, setCurrentModelName, setExtensionLists, setMergedConfig, userExtensions, VERSION } from "./state.js";
|
|
35
37
|
import { interactivePrompt, resolveProjectTrust } from "./trust-ui.js";
|
|
38
|
+
import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
|
|
36
39
|
import { fauxSkip, readFauxScript } from "./faux-glue.js";
|
|
37
40
|
import { autoCompactFromEnv, chat, contextWindowTokens } from "./chat.js";
|
|
38
41
|
import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveAutoCompact, resolveContextWindow, resolveModel } from "./config.js";
|
|
@@ -188,17 +191,21 @@ function makeLineInput() {
|
|
|
188
191
|
}
|
|
189
192
|
return readlineInput(createInterface({ input: process.stdin, output: process.stdout }));
|
|
190
193
|
}
|
|
191
|
-
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
+
/** R-D 0.1.45: the `[N extensions: ...]` text — the built-in column, then
|
|
195
|
+
* the user-level names, then the project-level ones marked `project:`.
|
|
196
|
+
* The built-in column is the banner's truthful face of the built-in layer:
|
|
197
|
+
* a fresh install reads `[4 extensions: built-in: mcp, skills, subagent,
|
|
198
|
+
* task]` with zero disk setup. */
|
|
194
199
|
function bannerExtensionText() {
|
|
195
|
-
const total = userExtensions.length + projectExtensions.length;
|
|
200
|
+
const total = builtInExtensions.length + userExtensions.length + projectExtensions.length;
|
|
196
201
|
if (total === 0)
|
|
197
202
|
return "";
|
|
198
203
|
const parts = [];
|
|
199
204
|
// 0.1.26 (MCP lazy connection): an extension with a live `connecting` flag shows
|
|
200
205
|
// its in-flight state in the banner — "mcp (connecting…)".
|
|
201
206
|
const label = (e) => e.connecting === true ? `${e.name} (connecting…)` : e.name;
|
|
207
|
+
if (builtInExtensions.length > 0)
|
|
208
|
+
parts.push(`built-in: ${builtInExtensions.map(label).join(", ")}`);
|
|
202
209
|
if (userExtensions.length > 0)
|
|
203
210
|
parts.push(userExtensions.map(label).join(", "));
|
|
204
211
|
if (projectExtensions.length > 0)
|
|
@@ -290,22 +297,29 @@ export function composeSystemPrompt(cwd) {
|
|
|
290
297
|
const injected = readProjectInstructions(cwd);
|
|
291
298
|
return injected === "" ? SYSTEM_PROMPT : `${SYSTEM_PROMPT}\n${injected}`;
|
|
292
299
|
}
|
|
293
|
-
async function makeAgent(
|
|
294
|
-
const store = new SessionStore(sessionsDir());
|
|
300
|
+
async function makeAgent(sessionId, input, modelFlag) {
|
|
295
301
|
// E3: the project-level trust gate runs BEFORE any extension load (the
|
|
296
302
|
// mcp/skills merges must be in the env when the user-level extensions
|
|
297
303
|
// load). Untrusted project capability is never loaded — never silently.
|
|
298
304
|
const project = input !== undefined ? await resolveProjectTrust(input) : await resolveProjectTrust(undefined);
|
|
305
|
+
// R-D 0.1.45 (deliverable B): the first-run scaffold lands AFTER the
|
|
306
|
+
// verdict — pre-trust zero-read/write/scan is absolute. The sessions
|
|
307
|
+
// dir (SessionStore's constructor mkdirs) moved behind the gate too:
|
|
308
|
+
// the trust record is the first home write, the scaffold the second.
|
|
309
|
+
if (isFirstRun())
|
|
310
|
+
scaffoldFirstRun();
|
|
311
|
+
const store = new SessionStore(sessionsDir());
|
|
312
|
+
// E area: the durable script position — computed AFTER the verdict
|
|
313
|
+
// (fauxSkip's session-log read is a home read: pre-trust zero-read).
|
|
314
|
+
const fauxSkipTurns = sessionId === undefined ? 0 : fauxSkip(sessionId);
|
|
299
315
|
// E1: the startup extension scan — a broken extension fails the process
|
|
300
316
|
// LOUDLY here (loadExtensions throws), never silently.
|
|
301
317
|
const user = await loadExtensions(extensionsDir());
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
setExtensionLists(user, [], user);
|
|
308
|
-
}
|
|
318
|
+
const proj = project !== null ? await loadProjectExtensions(process.cwd(), user) : [];
|
|
319
|
+
// R-D 0.1.45: the built-in layer registers by module import (builtin.ts)
|
|
320
|
+
// — a user extension may shadow a built-in, a project one may not.
|
|
321
|
+
const builtIn = await builtInLayer(user, proj);
|
|
322
|
+
setExtensionLists(builtIn, user, proj, [...builtIn, ...user, ...proj]);
|
|
309
323
|
// merge round B — the config surface: user config + (trusted) project config,
|
|
310
324
|
// resolved with flags > env > project > user > default. The CLI never
|
|
311
325
|
// imports provider SDKs directly — the runtime's lazy provider
|
|
@@ -445,7 +459,7 @@ async function main() {
|
|
|
445
459
|
dock.enter();
|
|
446
460
|
// E area: a resumed session continues the script at its durable
|
|
447
461
|
// position — never restarts it (fauxSkip).
|
|
448
|
-
const agent = await makeAgent(
|
|
462
|
+
const agent = await makeAgent(id, input, modelFlag);
|
|
449
463
|
applyConfigMode();
|
|
450
464
|
const session = await agent.session({ id });
|
|
451
465
|
bodyLog(`session ${id}\n`);
|
|
@@ -463,7 +477,7 @@ async function main() {
|
|
|
463
477
|
// (argv = [node, script, resume, id, prompt?]).
|
|
464
478
|
const prompt = process.argv[4];
|
|
465
479
|
dock.enter();
|
|
466
|
-
const agent = await makeAgent(
|
|
480
|
+
const agent = await makeAgent(arg, input, modelFlag);
|
|
467
481
|
applyConfigMode();
|
|
468
482
|
const session = await agent.session({ id: arg });
|
|
469
483
|
faux = currentFaux;
|
|
@@ -471,7 +485,7 @@ async function main() {
|
|
|
471
485
|
break;
|
|
472
486
|
}
|
|
473
487
|
case "sessions": {
|
|
474
|
-
const agent = await makeAgent(
|
|
488
|
+
const agent = await makeAgent(undefined, undefined, modelFlag);
|
|
475
489
|
for (const meta of agent.sessions()) {
|
|
476
490
|
console.log(renderSessionLine(meta));
|
|
477
491
|
}
|
|
@@ -494,7 +508,7 @@ async function main() {
|
|
|
494
508
|
// chat — the first argument is the session id.
|
|
495
509
|
const id = command ?? new Date().toISOString().replace(/[:.]/g, "-").slice(0, 16);
|
|
496
510
|
dock.enter();
|
|
497
|
-
const agent = await makeAgent(
|
|
511
|
+
const agent = await makeAgent(id);
|
|
498
512
|
const session = await agent.session({ id });
|
|
499
513
|
bodyLog(`session ${id}\n`);
|
|
500
514
|
extensionsBanner(recentSessions(id, agent));
|
|
@@ -528,14 +542,22 @@ async function main() {
|
|
|
528
542
|
}
|
|
529
543
|
}
|
|
530
544
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
545
|
+
// R-D 0.1.45 (deliverable B): main runs ONLY as the entry — the CLI is
|
|
546
|
+
// import-clean. The unconditional module-scope run executed the full
|
|
547
|
+
// startup under the importing process's argv and REAL home whenever a
|
|
548
|
+
// test imported src/index.js for its functions (harmless before the
|
|
549
|
+
// first-run scaffold existed; the scaffold WRITES the home). The bin is
|
|
550
|
+
// a symlink, so argv[1] is realpathed before the comparison.
|
|
551
|
+
if (process.argv[1] !== undefined && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
552
|
+
main()
|
|
553
|
+
.then(() => process.exit(0))
|
|
554
|
+
.catch((err) => {
|
|
555
|
+
// round 10: top-level errors are terminal-escaped. v2a: the exit is EXPLICIT
|
|
556
|
+
// — natural drain is racy on a TTY (readline leaves the stdio handles
|
|
557
|
+
// active and the loop sometimes never drains). main's finally already
|
|
558
|
+
// ran (agent.close, dispose, temp cleanup) — nothing is skipped, no
|
|
559
|
+
// lock is left behind; the exit code is honest.
|
|
560
|
+
console.error(escapeTerminal(err instanceof Error ? err.message : String(err)));
|
|
561
|
+
process.exit(1);
|
|
562
|
+
});
|
|
563
|
+
}
|
package/dist/state.d.ts
CHANGED
|
@@ -87,13 +87,17 @@ export declare let currentModelName: string;
|
|
|
87
87
|
export declare function setCurrentModelName(value: string): void;
|
|
88
88
|
/** E1: the extensions loaded by makeAgent — their names feed the banner. */
|
|
89
89
|
export declare let loadedExtensions: readonly KisoExtension[];
|
|
90
|
+
/** R-D 0.1.45: the BUILT-IN layer — the four official extensions, shipped
|
|
91
|
+
* with the cli (module imports, never a disk scan; builtin.ts). The
|
|
92
|
+
* banner's marked column; a user extension may shadow a built-in. */
|
|
93
|
+
export declare let builtInExtensions: readonly KisoExtension[];
|
|
90
94
|
/** E1: the USER-level extensions alone — the banner's unmarked part (E3:
|
|
91
95
|
* loadedExtensions later includes the project-level ones too). */
|
|
92
96
|
export declare let userExtensions: readonly KisoExtension[];
|
|
93
97
|
/** E3: the PROJECT-level extensions (loaded after the trust gate) — the
|
|
94
98
|
* banner distinguishes them from the user-level ones. */
|
|
95
99
|
export declare let projectExtensions: readonly KisoExtension[];
|
|
96
|
-
export declare function setExtensionLists(user: readonly KisoExtension[], project: readonly KisoExtension[], loaded: readonly KisoExtension[]): void;
|
|
100
|
+
export declare function setExtensionLists(builtIn: readonly KisoExtension[], user: readonly KisoExtension[], project: readonly KisoExtension[], loaded: readonly KisoExtension[]): void;
|
|
97
101
|
/** W21: the CURRENT agent's extensions array — set by makeAgent, the
|
|
98
102
|
* don't-ask-again writer pushes the generated extension into it so a
|
|
99
103
|
* first-time rule joins the chain at the NEXT run (the run's policies
|
package/dist/state.js
CHANGED
|
@@ -78,13 +78,18 @@ export function setCurrentModelName(value) {
|
|
|
78
78
|
}
|
|
79
79
|
/** E1: the extensions loaded by makeAgent — their names feed the banner. */
|
|
80
80
|
export let loadedExtensions = [];
|
|
81
|
+
/** R-D 0.1.45: the BUILT-IN layer — the four official extensions, shipped
|
|
82
|
+
* with the cli (module imports, never a disk scan; builtin.ts). The
|
|
83
|
+
* banner's marked column; a user extension may shadow a built-in. */
|
|
84
|
+
export let builtInExtensions = [];
|
|
81
85
|
/** E1: the USER-level extensions alone — the banner's unmarked part (E3:
|
|
82
86
|
* loadedExtensions later includes the project-level ones too). */
|
|
83
87
|
export let userExtensions = [];
|
|
84
88
|
/** E3: the PROJECT-level extensions (loaded after the trust gate) — the
|
|
85
89
|
* banner distinguishes them from the user-level ones. */
|
|
86
90
|
export let projectExtensions = [];
|
|
87
|
-
export function setExtensionLists(user, project, loaded) {
|
|
91
|
+
export function setExtensionLists(builtIn, user, project, loaded) {
|
|
92
|
+
builtInExtensions = builtIn;
|
|
88
93
|
userExtensions = user;
|
|
89
94
|
projectExtensions = project;
|
|
90
95
|
loadedExtensions = loaded;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-code",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
4
4
|
"description": "kiso CLI — the coding-agent reference product: kiso chat / kiso resume / kiso sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,9 +20,13 @@
|
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"@vincemakes/kiso-core": "0.1.35",
|
|
22
22
|
"@vincemakes/kiso-evals": "0.1.36",
|
|
23
|
+
"@vincemakes/kiso-mcp-ext": "0.1.46",
|
|
23
24
|
"@vincemakes/kiso-provider-anthropic": "0.1.36",
|
|
24
25
|
"@vincemakes/kiso-provider-openai": "0.1.36",
|
|
25
|
-
"@vincemakes/kiso-runtime": "0.1.
|
|
26
|
+
"@vincemakes/kiso-runtime": "0.1.37",
|
|
27
|
+
"@vincemakes/kiso-skills-ext": "0.1.46",
|
|
28
|
+
"@vincemakes/kiso-subagent-ext": "0.1.46",
|
|
29
|
+
"@vincemakes/kiso-task-ext": "0.1.46",
|
|
26
30
|
"@vincemakes/kiso-tools-node": "0.1.36",
|
|
27
31
|
"@vincemakes/kiso-tui": "0.1.42",
|
|
28
32
|
"@vincemakes/kiso-tui-cells": "0.1.42"
|