@vincemakes/kiso-code 0.6.0 → 0.7.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/dispatch.js CHANGED
@@ -30,7 +30,9 @@ export function dispatch(line, ctx) {
30
30
  // KC1: the composer's keys ride the SAME bodyLog call (it splits
31
31
  // on \n) — the help gains a row, the cli source does not.
32
32
  // KC2: the redirect joins the same row for the same reason.
33
- bodyLog(`${cmd("exit", "leave the session")}\n${cmd("keys", "enter sends · ctrl+J newline (shift+enter where encoded) · esc stops the run · alt+⏎ stops it and sends this instead")}`);
33
+ // KC3: and so does the @ picker the row is where a gesture is
34
+ // taught, and the row costs nothing.
35
+ bodyLog(`${cmd("exit", "leave the session")}\n${cmd("keys", "enter sends · ctrl+J newline (shift+enter where encoded) · esc stops the run · alt+⏎ stops it and sends this instead · @ files")}`);
34
36
  ctx.input.prompt();
35
37
  });
36
38
  return;
package/dist/index.js CHANGED
@@ -26,14 +26,14 @@ import { readFileSync, realpathSync, rmSync } from "node:fs";
26
26
  import { createInterface } from "node:readline";
27
27
  import { fileURLToPath } from "node:url";
28
28
  import { join } from "node:path";
29
- import { Body, Editor, bannerLines, escapeTerminal, palette, renderSessionLine } from "@vincemakes/kiso-tui";
29
+ import { Body, Editor, bannerLines, escapeTerminal, interactivePrompt, palette, renderSessionLine } from "@vincemakes/kiso-tui";
30
30
  import { createAgent, disposeExtensions, loadExtensions, loadProjectExtensions, SessionStore, } from "@vincemakes/kiso-runtime";
31
31
  import { createFauxProvider } from "@vincemakes/kiso-evals";
32
32
  import { createCodingTools } from "@vincemakes/kiso-tools-node";
33
33
  import { MODES, modeExtensions, modeFromEnv, modeSystemPrompt, setMode } from "./mode.js";
34
34
  import { builtInLayer } from "./builtin.js";
35
- 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";
36
- import { interactivePrompt, resolveProjectTrust } from "./trust-ui.js";
35
+ import { atFiles, 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";
36
+ import { resolveProjectTrust } from "./trust-ui.js";
37
37
  import { isFirstRun, scaffoldFirstRun } from "./first-run.js";
38
38
  import { fauxSkip, readFauxScript } from "./faux-glue.js";
39
39
  import { autoCompactFromEnv, chat, contextWindowTokens } from "./chat.js";
@@ -196,6 +196,8 @@ function makeLineInput() {
196
196
  // pipe bytes do not change)
197
197
  dock.bindInput(() => editor.dockState(), "› ");
198
198
  dock.bindMenu(() => editor.menuState()); // v3 §04: the slash-command menu
199
+ editor.bindAtItems(atFiles); // KC3 §5: the file source — listed per OPEN
200
+ dock.bindAt(() => editor.atState()); // KC3 §4: the picker's band
199
201
  dock.bindApproval(() => editor.panelState()); // W21: the panel's bound state
200
202
  return editorInput(editor);
201
203
  }
package/dist/state.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * creates the mutable ones (setBody / setAgentModel / setExtensionLists);
6
6
  * the moved modules read and mutate at call time.
7
7
  */
8
- import { Dock, type Body, type PanelVerdict, type PanelView } from "@vincemakes/kiso-tui";
8
+ import { Dock, type AtItem, type Body, type PanelVerdict, type PanelView } from "@vincemakes/kiso-tui";
9
9
  import type { KisoExtension } from "@vincemakes/kiso-runtime";
10
10
  /** finding #11: KISO_HOME is the ONE root — every default path derives from
11
11
  * it (sessions, trust, extensions, mcp config, skills). The dedicated
@@ -15,6 +15,30 @@ export declare function kisoHome(): string;
15
15
  export declare function sessionsDir(): string;
16
16
  /** E1: the extension scan directory — KISO_EXTENSIONS_DIR overrides. */
17
17
  export declare function extensionsDir(): string;
18
+ /**
19
+ * KC3 §5 — the @ picker's file source. Computed PER OPEN: no index, no
20
+ * daemon, no watcher, nothing to invalidate and nothing to go stale.
21
+ * (The editor snapshots the result for the life of one open, so this
22
+ * runs once per `@`, not once per keystroke.)
23
+ *
24
+ * In a git repo, git IS the answer. `ls-files -c -o --exclude-standard`
25
+ * is the tracked files AND the untracked ones that are not ignored, in
26
+ * ONE process: the same set the user's own tooling calls "the project",
27
+ * with every .gitignore in the tree already honoured — and honoured by
28
+ * git rather than by a reimplementation of git's rules. stderr is
29
+ * discarded because "not a git repository" must never land in a live
30
+ * TUI frame.
31
+ *
32
+ * Outside a repo — or with no git on PATH — the bounded walk stands
33
+ * in: it prunes AT_SKIP before descending and stops at AT_CAP + 1
34
+ * entries, the extra entry being what lets the panel's counter SAY it
35
+ * truncated instead of showing the first two thousand files as though
36
+ * they were all of them.
37
+ *
38
+ * Paths are forward-slashed on both branches (git's own format), so
39
+ * the fuzzy filter sees one alphabet whichever branch ran.
40
+ */
41
+ export declare function atFiles(): readonly AtItem[];
18
42
  /**
19
43
  * v2c — the interactive input source. TTYs use the raw-mode Editor (the
20
44
  * self-drawn input row — width-aware, the CJK-drift root cause retired,
package/dist/state.js CHANGED
@@ -5,11 +5,12 @@
5
5
  * creates the mutable ones (setBody / setAgentModel / setExtensionLists);
6
6
  * the moved modules read and mutate at call time.
7
7
  */
8
- import { readFileSync } from "node:fs";
8
+ import { execFileSync } from "node:child_process";
9
+ import { readdirSync, readFileSync } from "node:fs";
9
10
  import { homedir } from "node:os";
10
11
  import { dirname, join } from "node:path";
11
12
  import { fileURLToPath } from "node:url";
12
- import { Dock } from "@vincemakes/kiso-tui";
13
+ import { AT_CAP, AT_SKIP, Dock } from "@vincemakes/kiso-tui";
13
14
  /** finding #11: KISO_HOME is the ONE root — every default path derives from
14
15
  * it (sessions, trust, extensions, mcp config, skills). The dedicated
15
16
  * env vars (KISO_EXTENSIONS_DIR / KISO_MCP_CONFIG / KISO_SKILLS_DIR)
@@ -24,6 +25,62 @@ export function sessionsDir() {
24
25
  export function extensionsDir() {
25
26
  return process.env.KISO_EXTENSIONS_DIR ?? join(kisoHome(), "extensions");
26
27
  }
28
+ /**
29
+ * KC3 §5 — the @ picker's file source. Computed PER OPEN: no index, no
30
+ * daemon, no watcher, nothing to invalidate and nothing to go stale.
31
+ * (The editor snapshots the result for the life of one open, so this
32
+ * runs once per `@`, not once per keystroke.)
33
+ *
34
+ * In a git repo, git IS the answer. `ls-files -c -o --exclude-standard`
35
+ * is the tracked files AND the untracked ones that are not ignored, in
36
+ * ONE process: the same set the user's own tooling calls "the project",
37
+ * with every .gitignore in the tree already honoured — and honoured by
38
+ * git rather than by a reimplementation of git's rules. stderr is
39
+ * discarded because "not a git repository" must never land in a live
40
+ * TUI frame.
41
+ *
42
+ * Outside a repo — or with no git on PATH — the bounded walk stands
43
+ * in: it prunes AT_SKIP before descending and stops at AT_CAP + 1
44
+ * entries, the extra entry being what lets the panel's counter SAY it
45
+ * truncated instead of showing the first two thousand files as though
46
+ * they were all of them.
47
+ *
48
+ * Paths are forward-slashed on both branches (git's own format), so
49
+ * the fuzzy filter sees one alphabet whichever branch ran.
50
+ */
51
+ export function atFiles() {
52
+ let paths;
53
+ try {
54
+ paths = execFileSync("git", ["ls-files", "-c", "-o", "--exclude-standard"], { cwd: process.cwd(), encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 1 << 24 }).split("\n").filter((p) => p !== "");
55
+ }
56
+ catch {
57
+ paths = atWalk(process.cwd(), "", []);
58
+ }
59
+ return paths.slice(0, AT_CAP + 1).map((path) => ({ path }));
60
+ }
61
+ /** The fallback walk. `prefix` carries the repo-relative directory so
62
+ * the result needs no path arithmetic afterwards. An unreadable
63
+ * directory contributes nothing and ends nothing — the recursion's own
64
+ * try catches it at that level, so one locked subtree cannot stop a
65
+ * file picker from opening. */
66
+ function atWalk(dir, prefix, out) {
67
+ try {
68
+ for (const e of readdirSync(dir, { withFileTypes: true })) {
69
+ if (out.length > AT_CAP)
70
+ break;
71
+ if (AT_SKIP.has(e.name))
72
+ continue;
73
+ if (e.isDirectory())
74
+ atWalk(`${dir}/${e.name}`, `${prefix}${e.name}/`, out);
75
+ else if (e.isFile())
76
+ out.push(`${prefix}${e.name}`);
77
+ }
78
+ }
79
+ catch {
80
+ // unreadable — skipped
81
+ }
82
+ return out;
83
+ }
27
84
  /** v2b: the bottom-anchored UI — docked only on a color TTY; pipes and
28
85
  * NO_COLOR stay the v2a line mode byte-for-byte. Created at load, like
29
86
  * the pre-split module-scope const. */
@@ -9,11 +9,6 @@ import { type PanelVerdict, type PanelView } from "@vincemakes/kiso-tui";
9
9
  import { type ProjectArtifacts } from "@vincemakes/kiso-runtime";
10
10
  import type { AgentSession } from "@vincemakes/kiso-runtime";
11
11
  import { type LineInput } from "./state.js";
12
- /** v2a: the interactive prompt — blue, the identity accent. readline owns
13
- * the echo of what the user types; we own the prompt's color. (v2c: the
14
- * readline prompt keeps "you> " — the brick ▌ is the dock's row only;
15
- * pipe bytes must not change.) */
16
- export declare function interactivePrompt(): string;
17
12
  /**
18
13
  * W21 — ask the human with the approval panel: the bounded block that
19
14
  * replaces the running tool's live window while the approval is pending.
package/dist/trust-ui.js CHANGED
@@ -9,19 +9,11 @@ import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, symlinkS
9
9
  import { homedir, tmpdir } from "node:os";
10
10
  import { join } from "node:path";
11
11
  import { pathToFileURL } from "node:url";
12
- import { escapeTerminal, palette } from "@vincemakes/kiso-tui";
12
+ import { projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView } from "@vincemakes/kiso-tui";
13
13
  import { projectArtifacts, recordTrust, trustFor } from "@vincemakes/kiso-runtime";
14
14
  import { bodyLog, currentAgentExtensions, dock, extensionsDir, kisoHome, mergedTempPaths } from "./state.js";
15
15
  import { loadUserConfig, resolveProjectTrustPolicy } from "./config.js";
16
16
  import { getMode } from "./mode.js";
17
- /** v2a: the interactive prompt — blue, the identity accent. readline owns
18
- * the echo of what the user types; we own the prompt's color. (v2c: the
19
- * readline prompt keeps "you> " — the brick ▌ is the dock's row only;
20
- * pipe bytes must not change.) */
21
- export function interactivePrompt() {
22
- const p = palette();
23
- return `${p.bold}you> ${p.reset}`;
24
- }
25
17
  /**
26
18
  * W21 — ask the human with the approval panel: the bounded block that
27
19
  * replaces the running tool's live window while the approval is pending.
@@ -192,7 +184,7 @@ export async function resolveProjectTrust(input) {
192
184
  // First discovery — list every artifact (file name + digest short
193
185
  // prefix) and ask the human ONCE.
194
186
  if (!process.stdin.isTTY) {
195
- console.error(`[project .kiso] found ${artifacts.files.length} artifact(s) in ${artifacts.root} — not trusted, not loaded (run kiso interactively once to decide)`);
187
+ console.error(projectUntrustedNote(artifacts.files.length, artifacts.root));
196
188
  return null;
197
189
  }
198
190
  // v2c: the shared input (the editor on a TTY) reads the answer.
@@ -201,19 +193,9 @@ export async function resolveProjectTrust(input) {
201
193
  // the bodyLog below records, verbatim — the listing still lands in
202
194
  // the scrollback; the panel is a bounded block, the record is not).
203
195
  bodyLog(`[project .kiso] ${artifacts.root}`);
204
- for (const f of artifacts.files) {
205
- bodyLog(` ${f.path} (${f.digest.slice(0, 6)})`);
206
- }
207
- const verdict = await askPanel(input, {
208
- flavor: "simple",
209
- name: "project trust",
210
- title: artifacts.root,
211
- speaker: "kiso",
212
- statusText: "▸ project trust",
213
- args: { kind: "text", lines: artifacts.files.map((f) => `${f.path} (${f.digest.slice(0, 6)})`) },
214
- ruleOverride: "trust this project's .kiso?",
215
- fallbackQuestion: `trust this project's .kiso? (y/n) `,
216
- });
196
+ for (const row of projectTrustRows(artifacts.files, " "))
197
+ bodyLog(row);
198
+ const verdict = await askPanel(input, projectTrustView(artifacts.root, artifacts.files));
217
199
  // A cancel is a "no" HERE — refused is sticky, the project does not
218
200
  // load (re-evaluate by deleting the trust line or changing a file).
219
201
  // The non-TTY branch above returned WITHOUT a record so an interactive
@@ -317,16 +299,7 @@ function readdirSyncSafe(dir) {
317
299
  * the body is the single stdout writer, never a stray console.log. */
318
300
  export async function resolveUncertains(session, input, isCancelled) {
319
301
  for (const uncertain of session.uncertainExecutions()) {
320
- const verdict = await askPanel(input, {
321
- flavor: "simple",
322
- name: "uncertain execution",
323
- title: `${uncertain.name} (${uncertain.executionId})`,
324
- speaker: "kiso",
325
- statusText: "▸ uncertain execution",
326
- args: { kind: "text", lines: [uncertain.executionId] },
327
- ruleOverride: "did the interrupted execution apply? — 1 rerun · 3 abandon",
328
- fallbackQuestion: `⚠ interrupted execution: ${escapeTerminal(uncertain.name)} (${uncertain.executionId}) — did it apply? (y)es / (n)o `,
329
- });
302
+ const verdict = await askPanel(input, uncertainView(uncertain.name, uncertain.executionId));
330
303
  if (isCancelled() || verdict.action === "cancel") {
331
304
  // round 10: a cancellation NEVER records a verdict — the execution
332
305
  // stays uncertain and durable; no rerun/abandoned is fabricated.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vincemakes/kiso-code",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "kiso CLI — the durable coding agent that survives kill -9: kiso chat / kiso resume / kiso sessions.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -18,18 +18,18 @@
18
18
  "test": "vitest run"
19
19
  },
20
20
  "dependencies": {
21
- "@vincemakes/kiso-core": "0.6.0",
22
- "@vincemakes/kiso-evals": "0.6.0",
23
- "@vincemakes/kiso-mcp-ext": "0.6.0",
24
- "@vincemakes/kiso-provider-anthropic": "0.6.0",
25
- "@vincemakes/kiso-provider-openai": "0.6.0",
26
- "@vincemakes/kiso-runtime": "0.6.0",
27
- "@vincemakes/kiso-skills-ext": "0.6.0",
28
- "@vincemakes/kiso-subagent-ext": "0.6.0",
29
- "@vincemakes/kiso-task-ext": "0.6.0",
30
- "@vincemakes/kiso-tools-node": "0.6.0",
31
- "@vincemakes/kiso-tui": "0.6.0",
32
- "@vincemakes/kiso-tui-cells": "0.6.0"
21
+ "@vincemakes/kiso-core": "0.7.0",
22
+ "@vincemakes/kiso-evals": "0.7.0",
23
+ "@vincemakes/kiso-mcp-ext": "0.7.0",
24
+ "@vincemakes/kiso-provider-anthropic": "0.7.0",
25
+ "@vincemakes/kiso-provider-openai": "0.7.0",
26
+ "@vincemakes/kiso-runtime": "0.7.0",
27
+ "@vincemakes/kiso-skills-ext": "0.7.0",
28
+ "@vincemakes/kiso-subagent-ext": "0.7.0",
29
+ "@vincemakes/kiso-task-ext": "0.7.0",
30
+ "@vincemakes/kiso-tools-node": "0.7.0",
31
+ "@vincemakes/kiso-tui": "0.7.0",
32
+ "@vincemakes/kiso-tui-cells": "0.7.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@types/node": "^26.1.2",