@vincemakes/kiso-code 0.1.29 → 0.1.30
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/chat.d.ts +5 -5
- package/dist/chat.js +22 -22
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/dispatch.d.ts +1 -1
- package/dist/dispatch.js +4 -4
- package/dist/faux-glue.d.ts +5 -5
- package/dist/faux-glue.js +6 -6
- package/dist/index.d.ts +4 -4
- package/dist/index.js +20 -20
- package/dist/mode.d.ts +1 -1
- package/dist/mode.js +1 -1
- package/dist/resume.d.ts +2 -2
- package/dist/resume.js +5 -5
- package/dist/state.d.ts +7 -7
- package/dist/state.js +7 -7
- package/dist/trust-ui.d.ts +2 -2
- package/dist/trust-ui.js +4 -4
- package/package.json +1 -1
package/dist/chat.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the interactive REPL (chat), the run consumer
|
|
3
3
|
* (consumeRun — the single renderer of a run's event stream), the
|
|
4
4
|
* approval-moment mini-diff, the status spinner, and the context
|
|
5
5
|
* estimates. All bodies moved verbatim from index.ts.
|
|
@@ -8,7 +8,7 @@ import { type RunUsage } from "@vincemakes/kiso-tui";
|
|
|
8
8
|
import type { AgentSession } from "@vincemakes/kiso-runtime";
|
|
9
9
|
import { type LineInput } from "./state.js";
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* The ergonomics batch C8 — the /compact auto-trigger, OPT-IN (default off: only an
|
|
12
12
|
* explicit KISO_AUTO_COMPACT=<ratio> enables it — the CLI never defaults
|
|
13
13
|
* it on). After every completed turn the ~ctx ratio is checked; at/over
|
|
14
14
|
* thresholdRatio the /compact full path runs (the same dispatch — same
|
|
@@ -21,14 +21,14 @@ export interface AutoCompact {
|
|
|
21
21
|
/** Parse KISO_AUTO_COMPACT — an invalid value is OFF, never a crash. */
|
|
22
22
|
export declare function autoCompactFromEnv(): AutoCompact | undefined;
|
|
23
23
|
/**
|
|
24
|
-
* C
|
|
25
|
-
* config window (
|
|
24
|
+
* C area: the model window in tokens — env (KISO_CONTEXT_WINDOW) beats the
|
|
25
|
+
* config window (merge round B), both beat the 200k default. The microcompact
|
|
26
26
|
* threshold is derived from it (50%), and the status line's ~ctx estimate
|
|
27
27
|
* is measured against it — one source of truth for the window.
|
|
28
28
|
*/
|
|
29
29
|
export declare function contextWindowTokens(): number;
|
|
30
30
|
/**
|
|
31
|
-
* B
|
|
31
|
+
* B area: approximate context ratio — chars/4 of the projected messages vs
|
|
32
32
|
* the model window. Marked ~ everywhere it is shown; no counting API.
|
|
33
33
|
*/
|
|
34
34
|
export declare function estimateCtxRatio(session: AgentSession): number;
|
package/dist/chat.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the interactive REPL (chat), the run consumer
|
|
3
3
|
* (consumeRun — the single renderer of a run's event stream), the
|
|
4
4
|
* approval-moment mini-diff, the status spinner, and the context
|
|
5
5
|
* estimates. All bodies moved verbatim from index.ts.
|
|
@@ -13,7 +13,7 @@ import { CANCELLED, agentModel, body, bodyLog, configuredWindow, dock } from "./
|
|
|
13
13
|
import { ask, pendingAsk, resolveUncertains } from "./trust-ui.js";
|
|
14
14
|
import { FauxExhaustionError, failOnFauxExhaustion } from "./faux-glue.js";
|
|
15
15
|
import { MODES, getMode, setMode } from "./mode.js";
|
|
16
|
-
/** B
|
|
16
|
+
/** B area: default context window for the ~ctx estimate (config overridable). */
|
|
17
17
|
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
|
18
18
|
/** Parse KISO_AUTO_COMPACT — an invalid value is OFF, never a crash. */
|
|
19
19
|
export function autoCompactFromEnv() {
|
|
@@ -26,8 +26,8 @@ export function autoCompactFromEnv() {
|
|
|
26
26
|
return { thresholdRatio: ratio };
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* C
|
|
30
|
-
* config window (
|
|
29
|
+
* C area: the model window in tokens — env (KISO_CONTEXT_WINDOW) beats the
|
|
30
|
+
* config window (merge round B), both beat the 200k default. The microcompact
|
|
31
31
|
* threshold is derived from it (50%), and the status line's ~ctx estimate
|
|
32
32
|
* is measured against it — one source of truth for the window.
|
|
33
33
|
*/
|
|
@@ -39,7 +39,7 @@ export function contextWindowTokens() {
|
|
|
39
39
|
return Number.isFinite(window) && window > 0 ? window : DEFAULT_CONTEXT_WINDOW;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* B
|
|
42
|
+
* B area: approximate context ratio — chars/4 of the projected messages vs
|
|
43
43
|
* the model window. Marked ~ everywhere it is shown; no counting API.
|
|
44
44
|
*/
|
|
45
45
|
export function estimateCtxRatio(session) {
|
|
@@ -94,13 +94,13 @@ function approvalDiff(name, input) {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
97
|
-
*
|
|
97
|
+
* The ergonomics batch C5 — the translation layer: the tui renders its OWN data shape
|
|
98
98
|
* (RenderInput, zero kiso-core imports); the CLI translates its Event
|
|
99
99
|
* stream here. Events without a render (stop, expired, resolved, …) → null,
|
|
100
100
|
* and the consumer skips them — the pipe bytes stay identical.
|
|
101
101
|
*/
|
|
102
102
|
/**
|
|
103
|
-
*
|
|
103
|
+
* round 6 (the todo round): translate a do-not-compact-tagged tool result whose
|
|
104
104
|
* content follows the todo echo contract (a [todo] header line + one
|
|
105
105
|
* `[pending|active|done] text` line per item) into the checklist cell's
|
|
106
106
|
* structured items. Null = not a checklist — the ordinary result cell
|
|
@@ -180,7 +180,7 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
180
180
|
try {
|
|
181
181
|
for await (const ev of run) {
|
|
182
182
|
last = ev;
|
|
183
|
-
// v2a (
|
|
183
|
+
// v2a (the double echo): the interactive echo was already rendered by the
|
|
184
184
|
// input source — rendering the event again is the double echo.
|
|
185
185
|
// v2b: DOCKED — the echo lives in the input row (H), NOT the body;
|
|
186
186
|
// the body render is the ONLY visible copy of the sent line.
|
|
@@ -219,7 +219,7 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
219
219
|
case "tool_result": {
|
|
220
220
|
const text = typeof ev.content === "string" ? ev.content : "";
|
|
221
221
|
body.toolResult(ev.callId, { content: text, isError: ev.isError });
|
|
222
|
-
//
|
|
222
|
+
// round 6 (the todo round): a result tagged do-not-compact whose content
|
|
223
223
|
// follows the checklist shape also renders as the durable
|
|
224
224
|
// checklist cell (the CLI translates Event → the tui's own
|
|
225
225
|
// shape; a non-matching parse falls back to the ordinary
|
|
@@ -240,7 +240,7 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
240
240
|
statusCb?.(usage, estimateCtxRatio(session));
|
|
241
241
|
break;
|
|
242
242
|
case "uncertain_pending":
|
|
243
|
-
//
|
|
243
|
+
// ruling #12 (ADR-0038): the ⚠ line is pure INFORMATION now — the
|
|
244
244
|
// approval chain guards retries, and the human question belongs
|
|
245
245
|
// only to the crash window's recovery flow (resolveUncertains).
|
|
246
246
|
body.notice(`⚠ ${escapeTerminal(ev.name)} FAILED — the side effect may have applied. ${escapeTerminal(ev.error)}`);
|
|
@@ -256,7 +256,7 @@ export async function consumeRun(session, run, input, turnNo, faux, liveInput, s
|
|
|
256
256
|
const decisionId = ev.decisionId;
|
|
257
257
|
const answer = await ask(input, `approve ${escapeTerminal(name)}? (y/n) `);
|
|
258
258
|
if (answer === CANCELLED) {
|
|
259
|
-
//
|
|
259
|
+
// round 10: a cancellation is a CONSERVATIVE denial, explicitly
|
|
260
260
|
// distinguished from the user typing "n".
|
|
261
261
|
body.notice("[approval cancelled — treated as a denial]");
|
|
262
262
|
await session.approve(decisionId, false);
|
|
@@ -329,17 +329,17 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
329
329
|
stopSpinner();
|
|
330
330
|
paintIdle();
|
|
331
331
|
currentRun = null;
|
|
332
|
-
//
|
|
332
|
+
// round 8: a faux script that ran out of declared turns exits
|
|
333
333
|
// loudly with a non-zero status — never a silent status 0.
|
|
334
|
-
//
|
|
334
|
+
// round 4 (adversarial): the exhaustion is a CONTROLLED rejection of
|
|
335
335
|
// this turn's promise — it propagates through the chain to
|
|
336
336
|
// chat to main's finally/catch, never an orphaned
|
|
337
337
|
// unhandled rejection from the IIFE.
|
|
338
338
|
failOnFauxExhaustion(last, faux, input);
|
|
339
|
-
//
|
|
339
|
+
// round 8: after EVERY turn the prompt is re-armed — the human
|
|
340
340
|
// never types blind after the first turn.
|
|
341
341
|
input.prompt();
|
|
342
|
-
//
|
|
342
|
+
// the ergonomics batch C8: the opt-in auto-compact — checked AFTER the
|
|
343
343
|
// turn ended (the run's terminal is in the log, the ratio
|
|
344
344
|
// is post-run).
|
|
345
345
|
await maybeAutoCompact();
|
|
@@ -362,7 +362,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
362
362
|
});
|
|
363
363
|
input.onSigint(() => {
|
|
364
364
|
if (currentRun) {
|
|
365
|
-
//
|
|
365
|
+
// round 8: Ctrl+C cancels BOTH the pending question (if one is
|
|
366
366
|
// awaiting a line) and the run — the run then writes its unique
|
|
367
367
|
// aborted terminal, which the consumer keeps consuming.
|
|
368
368
|
console.log("\n[aborting run]");
|
|
@@ -395,7 +395,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
395
395
|
currentRun.abort();
|
|
396
396
|
}
|
|
397
397
|
});
|
|
398
|
-
//
|
|
398
|
+
// round 5 (P1-11): the PERSISTENT line listener is installed BEFORE the
|
|
399
399
|
// startup recovery — a cancelled question's re-emitted "line" needs a
|
|
400
400
|
// listener from the very first instant, or the input is silently lost.
|
|
401
401
|
// Turns are SERIALIZED on a chain — piped lines arrive faster than
|
|
@@ -405,7 +405,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
405
405
|
const chainRef = { current: Promise.resolve() };
|
|
406
406
|
let replReady = false;
|
|
407
407
|
const queuedLines = [];
|
|
408
|
-
// B
|
|
408
|
+
// B area: user-turn counter for the status line. /last and /think read
|
|
409
409
|
// the body (the ToolCell / ThinkingCell final states).
|
|
410
410
|
let turnNo = 0;
|
|
411
411
|
// v2a: the last line THIS process's readline consumed — the double-echo
|
|
@@ -455,7 +455,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
455
455
|
submitTurn,
|
|
456
456
|
estimateCtx: () => estimateCtxRatio(session),
|
|
457
457
|
};
|
|
458
|
-
//
|
|
458
|
+
// the ergonomics batch C8: the auto-compact check — the /compact FULL path via the
|
|
459
459
|
// shared dispatch (same notices, same chain ordering, same mid-run
|
|
460
460
|
// refusal — the isRunning guard here only avoids the refusal's noise).
|
|
461
461
|
// The appended segment is NOT awaited here on purpose: from inside a
|
|
@@ -482,7 +482,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
482
482
|
// Recovery first: a session with a dangling pause or uncertain
|
|
483
483
|
// executions must resolve them BEFORE the REPL accepts new turns —
|
|
484
484
|
// otherwise the interrupted run dangles while a new one starts.
|
|
485
|
-
//
|
|
485
|
+
// round 8: the startup resume is bound to currentRun — Ctrl+C during it
|
|
486
486
|
// aborts the recovery, exactly like the interactive turns.
|
|
487
487
|
await resolveUncertains(session, input, () => cancelled);
|
|
488
488
|
if (!cancelled) {
|
|
@@ -492,7 +492,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
492
492
|
const last = await consumeRun(session, recoveryRun, input, turnNo, faux, liveInput, statusCb);
|
|
493
493
|
currentRun = null;
|
|
494
494
|
failOnFauxExhaustion(last, faux, input);
|
|
495
|
-
maybeAutoCompact(); //
|
|
495
|
+
maybeAutoCompact(); // the ergonomics batch C8: the recovery run ended too — same check (awaited by the exit re-await)
|
|
496
496
|
}
|
|
497
497
|
if (cancelled) {
|
|
498
498
|
input.close();
|
|
@@ -513,7 +513,7 @@ export async function chat(session, faux, input, autoCompact) {
|
|
|
513
513
|
input.prompt();
|
|
514
514
|
await input.closed;
|
|
515
515
|
await chainRef.current; // never exit while a turn is in flight
|
|
516
|
-
//
|
|
516
|
+
// the ergonomics batch C8: the auto-compact may have appended ITS segment inside the
|
|
517
517
|
// turn (the check runs at the turn's end, after the exit-await above
|
|
518
518
|
// already captured the chain) — re-await once so the summarize either
|
|
519
519
|
// runs before the exit or the chain is already settled. One level is
|
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
package/dist/dispatch.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the ONE dispatcher: slash commands, exit, and
|
|
3
3
|
* turns. The bodies moved verbatim from chat()'s closure; chat provides
|
|
4
4
|
* the context (the chain, the run state, the prompt arming).
|
|
5
5
|
*/
|
package/dist/dispatch.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the ONE dispatcher: slash commands, exit, and
|
|
3
3
|
* turns. The bodies moved verbatim from chat()'s closure; chat provides
|
|
4
4
|
* the context (the chain, the run state, the prompt arming).
|
|
5
5
|
*/
|
|
@@ -48,7 +48,7 @@ export function dispatch(line, ctx) {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
if (trimmed === "/last") {
|
|
51
|
-
// B
|
|
51
|
+
// B area/v2d: print the FULL input/output of the most recent tool
|
|
52
52
|
// call — the body holds it (the ToolCell's final state). Runs on
|
|
53
53
|
// the chain: after any in-flight turn completes.
|
|
54
54
|
ctx.chainRef.current = ctx.chainRef.current.then(async () => {
|
|
@@ -67,7 +67,7 @@ export function dispatch(line, ctx) {
|
|
|
67
67
|
return;
|
|
68
68
|
}
|
|
69
69
|
if (trimmed === "/status") {
|
|
70
|
-
// B
|
|
70
|
+
// B area: session id, durable event count, and the ~ context
|
|
71
71
|
// estimate — all read straight from the live session, nothing
|
|
72
72
|
// stored separately. Runs on the chain after any in-flight turn.
|
|
73
73
|
ctx.chainRef.current = ctx.chainRef.current.then(async () => {
|
|
@@ -104,7 +104,7 @@ export function dispatch(line, ctx) {
|
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
if (trimmed === "/model" || trimmed.startsWith("/model ")) {
|
|
107
|
-
//
|
|
107
|
+
// merge round B: /model lists the profiles (with availability — the
|
|
108
108
|
// config never stores keys, only apiKeyEnv NAMES; an unset env
|
|
109
109
|
// marks the profile unavailable, never a crash) and switches the
|
|
110
110
|
// session's adapter — the NEXT turn uses it (session.setAdapter),
|
package/dist/faux-glue.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the faux-mode glue: the durable script position
|
|
3
3
|
* (fauxSkip), the script sources (env override + the built-in demo), and
|
|
4
4
|
* the exhaustion guard. All bodies moved verbatim from index.ts.
|
|
5
5
|
*/
|
|
6
6
|
import type { FauxScript } from "@vincemakes/kiso-evals";
|
|
7
7
|
import { type LineInput } from "./state.js";
|
|
8
8
|
/**
|
|
9
|
-
* E
|
|
9
|
+
* E area: how many faux-script turns a session has already consumed. The faux
|
|
10
10
|
* provider's script counter is per-process, so a FRESH process that resumes
|
|
11
11
|
* a session would restart the script at turn 0 — re-issuing the first
|
|
12
12
|
* scripted call instead of continuing the trajectory. The session log is
|
|
@@ -18,7 +18,7 @@ import { type LineInput } from "./state.js";
|
|
|
18
18
|
*/
|
|
19
19
|
export declare function fauxSkip(id: string): number;
|
|
20
20
|
/**
|
|
21
|
-
* E
|
|
21
|
+
* E area: KISO_FAUX_SCRIPT=<path> overrides the demo script with a JSON
|
|
22
22
|
* FauxScript file — the kill -9 e2e drives the CLI through an exact
|
|
23
23
|
* multi-tool trajectory. Absent → the built-in demo script.
|
|
24
24
|
*/
|
|
@@ -27,10 +27,10 @@ export declare function readFauxScript(): FauxScript;
|
|
|
27
27
|
* The keyless demo script: tours the tools so `kiso chat` exercises them.
|
|
28
28
|
* FOUR turns: each user turn consumes two model rounds (call → result →
|
|
29
29
|
* summary), so at least two consecutive user turns work in one process
|
|
30
|
-
* (F
|
|
30
|
+
* (F group).
|
|
31
31
|
*/
|
|
32
32
|
export declare function fauxScript(): FauxScript;
|
|
33
|
-
/**
|
|
33
|
+
/** round 10: a faux-mode run whose scripted turns are exhausted must NOT print a
|
|
34
34
|
* provider error and exit 0 — the honest outcome is a loud message and a
|
|
35
35
|
* non-zero exit. Thrown as a CONTROLLED exception (never process.exit):
|
|
36
36
|
* the REPL closes, the error propagates through main's finally (so
|
package/dist/faux-glue.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the faux-mode glue: the durable script position
|
|
3
3
|
* (fauxSkip), the script sources (env override + the built-in demo), and
|
|
4
4
|
* the exhaustion guard. All bodies moved verbatim from index.ts.
|
|
5
5
|
*/
|
|
@@ -8,7 +8,7 @@ import { escapeTerminal } from "@vincemakes/kiso-tui";
|
|
|
8
8
|
import { SessionStore } from "@vincemakes/kiso-runtime";
|
|
9
9
|
import { sessionsDir } from "./state.js";
|
|
10
10
|
/**
|
|
11
|
-
* E
|
|
11
|
+
* E area: how many faux-script turns a session has already consumed. The faux
|
|
12
12
|
* provider's script counter is per-process, so a FRESH process that resumes
|
|
13
13
|
* a session would restart the script at turn 0 — re-issuing the first
|
|
14
14
|
* scripted call instead of continuing the trajectory. The session log is
|
|
@@ -28,7 +28,7 @@ export function fauxSkip(id) {
|
|
|
28
28
|
events.filter((e) => e.type === "tool_call_end" && !results.has(e.callId)).length);
|
|
29
29
|
}
|
|
30
30
|
/**
|
|
31
|
-
* E
|
|
31
|
+
* E area: KISO_FAUX_SCRIPT=<path> overrides the demo script with a JSON
|
|
32
32
|
* FauxScript file — the kill -9 e2e drives the CLI through an exact
|
|
33
33
|
* multi-tool trajectory. Absent → the built-in demo script.
|
|
34
34
|
*/
|
|
@@ -51,13 +51,13 @@ export function readFauxScript() {
|
|
|
51
51
|
* The keyless demo script: tours the tools so `kiso chat` exercises them.
|
|
52
52
|
* FOUR turns: each user turn consumes two model rounds (call → result →
|
|
53
53
|
* summary), so at least two consecutive user turns work in one process
|
|
54
|
-
* (F
|
|
54
|
+
* (F group).
|
|
55
55
|
*/
|
|
56
56
|
export function fauxScript() {
|
|
57
57
|
return [
|
|
58
58
|
{
|
|
59
59
|
events: [
|
|
60
|
-
//
|
|
60
|
+
// bootstrap P1: a multi-delta thinking block — renders as ONE
|
|
61
61
|
// streaming segment, not one line per token.
|
|
62
62
|
{ type: "thinking", text: "Let me think about" },
|
|
63
63
|
{ type: "thinking", text: " the workspace" },
|
|
@@ -88,7 +88,7 @@ export function fauxScript() {
|
|
|
88
88
|
},
|
|
89
89
|
];
|
|
90
90
|
}
|
|
91
|
-
/**
|
|
91
|
+
/** round 10: a faux-mode run whose scripted turns are exhausted must NOT print a
|
|
92
92
|
* provider error and exit 0 — the honest outcome is a loud message and a
|
|
93
93
|
* non-zero exit. Thrown as a CONTROLLED exception (never process.exit):
|
|
94
94
|
* the REPL closes, the error propagates through main's finally (so
|
package/dist/index.d.ts
CHANGED
|
@@ -15,21 +15,21 @@
|
|
|
15
15
|
* append-only JSONL. Write/edit/shell tools sit behind the approval policy:
|
|
16
16
|
* the run pauses, asks, and resumes — durably (ADR-0024).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* The ergonomics batch B4 (pure move): the interactive pieces live beside this file —
|
|
19
19
|
* chat.ts (the REPL + consumeRun), dispatch.ts (the slash dispatcher),
|
|
20
20
|
* resume.ts, trust-ui.ts (the question surface + E3 merges), faux-glue.ts
|
|
21
21
|
* (the scripted-model plumbing), state.ts (the shared process state).
|
|
22
|
-
* index.ts keeps the entry: banner, input sources, the A
|
|
22
|
+
* index.ts keeps the entry: banner, input sources, the A area prompt,
|
|
23
23
|
* makeAgent, and main.
|
|
24
24
|
*/
|
|
25
25
|
export { applyProjectMerges } from "./trust-ui.js";
|
|
26
26
|
/**
|
|
27
|
-
* A
|
|
27
|
+
* A area: read the FIRST present instruction file (AGENTS.md preferred) and
|
|
28
28
|
* return it as an injected section, or "" when none exists. Truncated at
|
|
29
29
|
* 8KB with an explicit note. Pure — read once per session, so the prompt
|
|
30
30
|
* is byte-stable for the session's lifetime.
|
|
31
31
|
*/
|
|
32
32
|
export declare function readProjectInstructions(cwd: string): string;
|
|
33
|
-
/** A
|
|
33
|
+
/** A area: the session's system prompt — the constant plus any project
|
|
34
34
|
* instructions found in the workspace. Deterministic per cwd. */
|
|
35
35
|
export declare function composeSystemPrompt(cwd: string): string;
|
package/dist/index.js
CHANGED
|
@@ -15,11 +15,11 @@
|
|
|
15
15
|
* append-only JSONL. Write/edit/shell tools sit behind the approval policy:
|
|
16
16
|
* the run pauses, asks, and resumes — durably (ADR-0024).
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* The ergonomics batch B4 (pure move): the interactive pieces live beside this file —
|
|
19
19
|
* chat.ts (the REPL + consumeRun), dispatch.ts (the slash dispatcher),
|
|
20
20
|
* resume.ts, trust-ui.ts (the question surface + E3 merges), faux-glue.ts
|
|
21
21
|
* (the scripted-model plumbing), state.ts (the shared process state).
|
|
22
|
-
* index.ts keeps the entry: banner, input sources, the A
|
|
22
|
+
* index.ts keeps the entry: banner, input sources, the A area prompt,
|
|
23
23
|
* makeAgent, and main.
|
|
24
24
|
*/
|
|
25
25
|
import { readFileSync, rmSync } from "node:fs";
|
|
@@ -38,9 +38,9 @@ import { autoCompactFromEnv, chat, contextWindowTokens } from "./chat.js";
|
|
|
38
38
|
import { loadProjectConfig, loadUserConfig, mergeConfigs, resolveAutoCompact, resolveContextWindow, resolveModel } from "./config.js";
|
|
39
39
|
import { resume } from "./resume.js";
|
|
40
40
|
// The moved exports stay reachable from this entry — the test imports
|
|
41
|
-
// (project-trust, coding-agent) never change (B4:
|
|
41
|
+
// (project-trust, coding-agent) never change (B4: zero assertion changes).
|
|
42
42
|
export { applyProjectMerges } from "./trust-ui.js";
|
|
43
|
-
/**
|
|
43
|
+
/** The banner: the block-letter logo (design fixed). TTY only — pipes, e2e
|
|
44
44
|
* drivers, and CI see byte-for-byte the old output; the extensions line
|
|
45
45
|
* merges into the third row on TTY and stays a standalone line off-TTY.
|
|
46
46
|
* v2a: the logo rows stay dim; the TAGLINE (row 2) is the blue identity
|
|
@@ -178,7 +178,7 @@ function bannerExtensionText() {
|
|
|
178
178
|
if (total === 0)
|
|
179
179
|
return "";
|
|
180
180
|
const parts = [];
|
|
181
|
-
// 0.1.26 (MCP
|
|
181
|
+
// 0.1.26 (MCP lazy connection): an extension with a live `connecting` flag shows
|
|
182
182
|
// its in-flight state in the banner — "mcp (connecting…)".
|
|
183
183
|
const label = (e) => e.connecting === true ? `${e.name} (connecting…)` : e.name;
|
|
184
184
|
if (userExtensions.length > 0)
|
|
@@ -200,8 +200,8 @@ function extensionsBanner() {
|
|
|
200
200
|
bodyLog(`${text}\n`);
|
|
201
201
|
}
|
|
202
202
|
/**
|
|
203
|
-
* A
|
|
204
|
-
* session's lifetime (D
|
|
203
|
+
* A area: the coding-agent system prompt — ONE constant, byte-stable for the
|
|
204
|
+
* session's lifetime (D area). Kept under ~80 lines; no template engine.
|
|
205
205
|
*/
|
|
206
206
|
const SYSTEM_PROMPT = `You are kiso, a coding agent. You work in a workspace
|
|
207
207
|
directory and change code with tools. Be concise: answer in a few lines
|
|
@@ -227,12 +227,12 @@ Tool discipline:
|
|
|
227
227
|
Workflow: understand the request, find the relevant code, make the
|
|
228
228
|
smallest change that works, then verify with a command (tests/build).
|
|
229
229
|
Report what you did in one or two lines per change.`;
|
|
230
|
-
/** The project-instructions file names, in priority order (A
|
|
230
|
+
/** The project-instructions file names, in priority order (A area). */
|
|
231
231
|
const INSTRUCTION_FILES = ["AGENTS.md", "CLAUDE.md"];
|
|
232
232
|
/** Hard cap for injected instructions — truncate and say so. */
|
|
233
233
|
const INSTRUCTION_MAX = 8 * 1024;
|
|
234
234
|
/**
|
|
235
|
-
* A
|
|
235
|
+
* A area: read the FIRST present instruction file (AGENTS.md preferred) and
|
|
236
236
|
* return it as an injected section, or "" when none exists. Truncated at
|
|
237
237
|
* 8KB with an explicit note. Pure — read once per session, so the prompt
|
|
238
238
|
* is byte-stable for the session's lifetime.
|
|
@@ -251,7 +251,7 @@ export function readProjectInstructions(cwd) {
|
|
|
251
251
|
}
|
|
252
252
|
return "";
|
|
253
253
|
}
|
|
254
|
-
/** A
|
|
254
|
+
/** A area: the session's system prompt — the constant plus any project
|
|
255
255
|
* instructions found in the workspace. Deterministic per cwd. */
|
|
256
256
|
export function composeSystemPrompt(cwd) {
|
|
257
257
|
const injected = readProjectInstructions(cwd);
|
|
@@ -273,7 +273,7 @@ async function makeAgent(fauxSkipTurns = 0, input, modelFlag) {
|
|
|
273
273
|
else {
|
|
274
274
|
setExtensionLists(user, [], user);
|
|
275
275
|
}
|
|
276
|
-
//
|
|
276
|
+
// merge round B — the config surface: user config + (trusted) project config,
|
|
277
277
|
// resolved with flags > env > project > user > default. The CLI never
|
|
278
278
|
// imports provider SDKs directly — the runtime's lazy provider
|
|
279
279
|
// resolution owns them (a config profile only ever NAMES an env var for
|
|
@@ -312,7 +312,7 @@ async function makeAgent(fauxSkipTurns = 0, input, modelFlag) {
|
|
|
312
312
|
const extra = modeSystemPrompt();
|
|
313
313
|
return extra === undefined ? sp : `${sp}\n\n${extra}`;
|
|
314
314
|
})(),
|
|
315
|
-
// C
|
|
315
|
+
// C area: microcompact is ON by default in the product — threshold =
|
|
316
316
|
// half the model window (KISO_CONTEXT_WINDOW override included;
|
|
317
317
|
// 200k window → 100k tokens). Long sessions compact old read/list/
|
|
318
318
|
// search/shell outputs instead of silently growing past the window.
|
|
@@ -337,7 +337,7 @@ async function main() {
|
|
|
337
337
|
// first makeAgent (the tier extensions read `current` live). The flag
|
|
338
338
|
// is stripped from the positional args, so it works in any position.
|
|
339
339
|
const args = process.argv.slice(2);
|
|
340
|
-
//
|
|
340
|
+
// merge round B: --model <profile|provider/model> — the top of the model
|
|
341
341
|
// precedence chain; the value flows into makeAgent's config resolution.
|
|
342
342
|
let modelFlag;
|
|
343
343
|
const modelArgIdx = args.indexOf("--model");
|
|
@@ -366,7 +366,7 @@ async function main() {
|
|
|
366
366
|
setMode(modeFromEnv() ?? loadUserConfig()?.mode ?? "default");
|
|
367
367
|
}
|
|
368
368
|
const [command, arg] = args;
|
|
369
|
-
//
|
|
369
|
+
// round 8: faux mode is the keyless demo script — an exhausted script must
|
|
370
370
|
// exit non-zero, never masquerade as a successful provider run. The
|
|
371
371
|
// verdict comes from makeAgent's config resolution now (a config
|
|
372
372
|
// profile can provide a real model with no OPENAI_* env).
|
|
@@ -387,7 +387,7 @@ async function main() {
|
|
|
387
387
|
onDock: () => dock.redraw(), // v2d-B: the freeze scrolls the dock up — re-pin it
|
|
388
388
|
}));
|
|
389
389
|
try {
|
|
390
|
-
//
|
|
390
|
+
// merge round B: the project config's mode applies AFTER the trust gate
|
|
391
391
|
// (its verdict decides whether the project config exists at all) —
|
|
392
392
|
// unless a higher layer (--mode flag / KISO_MODE) already decided.
|
|
393
393
|
const applyConfigMode = () => {
|
|
@@ -403,7 +403,7 @@ async function main() {
|
|
|
403
403
|
// v2b: the dock (TTY only) wraps the whole session — the
|
|
404
404
|
// trust question, the banner, the body, and the input line.
|
|
405
405
|
dock.enter();
|
|
406
|
-
// E
|
|
406
|
+
// E area: a resumed session continues the script at its durable
|
|
407
407
|
// position — never restarts it (fauxSkip).
|
|
408
408
|
const agent = await makeAgent(fauxSkip(id), input, modelFlag);
|
|
409
409
|
applyConfigMode();
|
|
@@ -450,7 +450,7 @@ async function main() {
|
|
|
450
450
|
}
|
|
451
451
|
case undefined:
|
|
452
452
|
default: {
|
|
453
|
-
// A
|
|
453
|
+
// A area: no subcommand (or any non-command first argument) IS
|
|
454
454
|
// chat — the first argument is the session id.
|
|
455
455
|
const id = command ?? new Date().toISOString().replace(/[:.]/g, "-").slice(0, 16);
|
|
456
456
|
dock.enter();
|
|
@@ -466,14 +466,14 @@ async function main() {
|
|
|
466
466
|
finally {
|
|
467
467
|
body.close(); // flush the pending frame, stop the heartbeat
|
|
468
468
|
input.close();
|
|
469
|
-
// E
|
|
469
|
+
// E group: every normal and abnormal exit releases the fds and writer
|
|
470
470
|
// locks — no lock file is left behind.
|
|
471
471
|
agent?.close();
|
|
472
472
|
// v2b: the dock tears down on EVERY exit path — CSI r resets the
|
|
473
473
|
// scroll region, the cursor lands at the input line, no broken
|
|
474
474
|
// terminal (kill -9 excepted; `reset` saves it).
|
|
475
475
|
dock.exit();
|
|
476
|
-
//
|
|
476
|
+
// finding #8 (P1): extension dispose runs on the same exit path — a
|
|
477
477
|
// dispose failure prints one line and NEVER changes the exit code.
|
|
478
478
|
await disposeExtensions(loadedExtensions);
|
|
479
479
|
// E3: the merged mcp/skills temp artifacts are best-effort removed on
|
|
@@ -491,7 +491,7 @@ async function main() {
|
|
|
491
491
|
main()
|
|
492
492
|
.then(() => process.exit(0))
|
|
493
493
|
.catch((err) => {
|
|
494
|
-
//
|
|
494
|
+
// round 10: top-level errors are terminal-escaped. v2a: the exit is EXPLICIT
|
|
495
495
|
// — natural drain is racy on a TTY (readline leaves the stdio handles
|
|
496
496
|
// active and the loop sometimes never drains). main's finally already
|
|
497
497
|
// ran (agent.close, dispose, temp cleanup) — nothing is skipped, no
|
package/dist/mode.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export declare const MODES: readonly Mode[];
|
|
|
15
15
|
export declare function getMode(): Mode;
|
|
16
16
|
export declare function setMode(m: Mode): void;
|
|
17
17
|
/** The startup mode from env: KISO_MODE, or undefined when unset (the
|
|
18
|
-
* config layer's mode then applies —
|
|
18
|
+
* config layer's mode then applies — merge round B; the --mode flag is
|
|
19
19
|
* applied by main before the first makeAgent and wins over everything). */
|
|
20
20
|
export declare function modeFromEnv(): Mode | undefined;
|
|
21
21
|
/** The five built-in mode tiers as chain extensions — named "mode:<tier>"
|
package/dist/mode.js
CHANGED
|
@@ -21,7 +21,7 @@ export function setMode(m) {
|
|
|
21
21
|
current = m;
|
|
22
22
|
}
|
|
23
23
|
/** The startup mode from env: KISO_MODE, or undefined when unset (the
|
|
24
|
-
* config layer's mode then applies —
|
|
24
|
+
* config layer's mode then applies — merge round B; the --mode flag is
|
|
25
25
|
* applied by main before the first makeAgent and wins over everything). */
|
|
26
26
|
export function modeFromEnv() {
|
|
27
27
|
const raw = process.env.KISO_MODE;
|
package/dist/resume.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — resume: the RECOVERY flow (Area 2/7). The body
|
|
3
3
|
* moved verbatim from index.ts.
|
|
4
4
|
*/
|
|
5
5
|
import type { AgentSession } from "@vincemakes/kiso-runtime";
|
|
@@ -8,7 +8,7 @@ import { type LineInput } from "./state.js";
|
|
|
8
8
|
* Resume = the RECOVERY flow (Area 2/7): uncertain executions are decided,
|
|
9
9
|
* the interrupted run is continued via session.resume() — never faked with
|
|
10
10
|
* a new prompt. An optional prompt afterwards starts a genuinely new turn.
|
|
11
|
-
* E
|
|
11
|
+
* E group: SIGINT aborts the run being resumed; every exit path closes the
|
|
12
12
|
* session store so no lock is left behind.
|
|
13
13
|
*/
|
|
14
14
|
export declare function resume(session: AgentSession, prompt: string | undefined, faux: boolean, input: LineInput): Promise<void>;
|
package/dist/resume.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — resume: the RECOVERY flow (Area 2/7). The body
|
|
3
3
|
* moved verbatim from index.ts.
|
|
4
4
|
*/
|
|
5
5
|
import { kUnit } from "@vincemakes/kiso-tui";
|
|
@@ -12,7 +12,7 @@ import { consumeRun, estimateCtxRatio, startStatusSpinner } from "./chat.js";
|
|
|
12
12
|
* Resume = the RECOVERY flow (Area 2/7): uncertain executions are decided,
|
|
13
13
|
* the interrupted run is continued via session.resume() — never faked with
|
|
14
14
|
* a new prompt. An optional prompt afterwards starts a genuinely new turn.
|
|
15
|
-
* E
|
|
15
|
+
* E group: SIGINT aborts the run being resumed; every exit path closes the
|
|
16
16
|
* session store so no lock is left behind.
|
|
17
17
|
*/
|
|
18
18
|
export async function resume(session, prompt, faux, input) {
|
|
@@ -59,15 +59,15 @@ export async function resume(session, prompt, faux, input) {
|
|
|
59
59
|
};
|
|
60
60
|
input.onSigint(() => {
|
|
61
61
|
if (currentRun) {
|
|
62
|
-
//
|
|
62
|
+
// round 8: Ctrl+C cancels the pending question AND the run.
|
|
63
63
|
console.log("\n[aborting run]");
|
|
64
64
|
pendingAsk?.();
|
|
65
65
|
currentRun.abort();
|
|
66
66
|
}
|
|
67
67
|
else if (!cancelled) {
|
|
68
|
-
//
|
|
68
|
+
// round 4 (adversarial): also unblock a pending startup question — the
|
|
69
69
|
// readline close alone would leave ask() hanging forever.
|
|
70
|
-
//
|
|
70
|
+
// round 5 (P2-2): the cancellation is recorded so the recovery is
|
|
71
71
|
// NOT started afterwards — Ctrl+C exits cleanly.
|
|
72
72
|
cancelled = true;
|
|
73
73
|
console.log("\n[exit requested]");
|
package/dist/state.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 — the CLI's shared process state. The module split (dispatch/
|
|
3
3
|
* chat/resume/trust-ui/faux-glue) is a PURE MOVE: every piece that more
|
|
4
4
|
* than one module touches lives here as a live ESM binding. index.ts
|
|
5
5
|
* creates the mutable ones (setBody / setAgentModel / setExtensionLists);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Dock, type Body } 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
|
|
12
12
|
* env vars (KISO_EXTENSIONS_DIR / KISO_MCP_CONFIG / KISO_SKILLS_DIR)
|
|
13
13
|
* still override their own path; nothing hard-codes ~/.kiso anymore. */
|
|
@@ -52,19 +52,19 @@ export declare function bodyLog(text: string): void;
|
|
|
52
52
|
/** The model name for the status bar — set by makeAgent. */
|
|
53
53
|
export declare let agentModel: string;
|
|
54
54
|
export declare function setAgentModel(value: string): void;
|
|
55
|
-
/**
|
|
55
|
+
/** merge round B: whether the agent runs on the faux provider (no real key) —
|
|
56
56
|
* set inside makeAgent, read by main for chat/resume's exhaustion check. */
|
|
57
57
|
export declare let currentFaux: boolean;
|
|
58
58
|
export declare function setCurrentFaux(value: boolean): void;
|
|
59
|
-
/**
|
|
59
|
+
/** merge round B: the merged config (user + trusted project) as resolved by the
|
|
60
60
|
* LAST makeAgent — /model and autoCompact resolve against it. */
|
|
61
61
|
export declare let mergedConfig: import("./config.js").KisoConfig;
|
|
62
62
|
export declare function setMergedConfig(value: import("./config.js").KisoConfig): void;
|
|
63
|
-
/**
|
|
63
|
+
/** merge round B: the resolved context window (env > config.contextWindow) —
|
|
64
64
|
* chat.ts's contextWindowTokens() consults it before the env. */
|
|
65
65
|
export declare let configuredWindow: number | undefined;
|
|
66
66
|
export declare function setConfiguredWindow(value: number | undefined): void;
|
|
67
|
-
/**
|
|
67
|
+
/** merge round B: the merged config (user + trusted project) + the current
|
|
68
68
|
* model's NAME — /model lists and switches against them. */
|
|
69
69
|
export declare let configModels: Readonly<Record<string, import("./config.js").ModelProfile>>;
|
|
70
70
|
export declare function setConfigModels(models: Readonly<Record<string, import("./config.js").ModelProfile>>): void;
|
|
@@ -85,7 +85,7 @@ export declare function setExtensionLists(user: readonly KisoExtension[], projec
|
|
|
85
85
|
export declare const mergedTempPaths: string[];
|
|
86
86
|
/** The CLI's own version — read from the package.json next to the build. */
|
|
87
87
|
export declare const VERSION: string;
|
|
88
|
-
/**
|
|
88
|
+
/** round 10: a question cancelled by Ctrl+C — NEVER the empty string, which is a
|
|
89
89
|
* real user answer (the empty line). The empty answer and the cancellation
|
|
90
90
|
* are distinct facts. */
|
|
91
91
|
export declare const CANCELLED: unique symbol;
|
package/dist/state.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 — the CLI's shared process state. The module split (dispatch/
|
|
3
3
|
* chat/resume/trust-ui/faux-glue) is a PURE MOVE: every piece that more
|
|
4
4
|
* than one module touches lives here as a live ESM binding. index.ts
|
|
5
5
|
* creates the mutable ones (setBody / setAgentModel / setExtensionLists);
|
|
@@ -10,7 +10,7 @@ import { homedir } from "node:os";
|
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
11
|
import { fileURLToPath } from "node:url";
|
|
12
12
|
import { Dock } from "@vincemakes/kiso-tui";
|
|
13
|
-
/**
|
|
13
|
+
/** finding #11: KISO_HOME is the ONE root — every default path derives from
|
|
14
14
|
* it (sessions, trust, extensions, mcp config, skills). The dedicated
|
|
15
15
|
* env vars (KISO_EXTENSIONS_DIR / KISO_MCP_CONFIG / KISO_SKILLS_DIR)
|
|
16
16
|
* still override their own path; nothing hard-codes ~/.kiso anymore. */
|
|
@@ -46,25 +46,25 @@ export let agentModel = "faux";
|
|
|
46
46
|
export function setAgentModel(value) {
|
|
47
47
|
agentModel = value;
|
|
48
48
|
}
|
|
49
|
-
/**
|
|
49
|
+
/** merge round B: whether the agent runs on the faux provider (no real key) —
|
|
50
50
|
* set inside makeAgent, read by main for chat/resume's exhaustion check. */
|
|
51
51
|
export let currentFaux = true;
|
|
52
52
|
export function setCurrentFaux(value) {
|
|
53
53
|
currentFaux = value;
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
55
|
+
/** merge round B: the merged config (user + trusted project) as resolved by the
|
|
56
56
|
* LAST makeAgent — /model and autoCompact resolve against it. */
|
|
57
57
|
export let mergedConfig = {};
|
|
58
58
|
export function setMergedConfig(value) {
|
|
59
59
|
mergedConfig = value;
|
|
60
60
|
}
|
|
61
|
-
/**
|
|
61
|
+
/** merge round B: the resolved context window (env > config.contextWindow) —
|
|
62
62
|
* chat.ts's contextWindowTokens() consults it before the env. */
|
|
63
63
|
export let configuredWindow;
|
|
64
64
|
export function setConfiguredWindow(value) {
|
|
65
65
|
configuredWindow = value;
|
|
66
66
|
}
|
|
67
|
-
/**
|
|
67
|
+
/** merge round B: the merged config (user + trusted project) + the current
|
|
68
68
|
* model's NAME — /model lists and switches against them. */
|
|
69
69
|
export let configModels = {};
|
|
70
70
|
export function setConfigModels(models) {
|
|
@@ -102,7 +102,7 @@ export const VERSION = (() => {
|
|
|
102
102
|
return "?";
|
|
103
103
|
}
|
|
104
104
|
})();
|
|
105
|
-
/**
|
|
105
|
+
/** round 10: a question cancelled by Ctrl+C — NEVER the empty string, which is a
|
|
106
106
|
* real user answer (the empty line). The empty answer and the cancellation
|
|
107
107
|
* are distinct facts. */
|
|
108
108
|
export const CANCELLED = Symbol("kiso-question-cancelled");
|
package/dist/trust-ui.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the human-facing question UI: the E3 project
|
|
3
3
|
* trust gate (ADR-0037), the mcp/skills env merges, the generic ask()
|
|
4
4
|
* (approvals, trust, uncertain resolutions), and the uncertain-execution
|
|
5
5
|
* decisions. All bodies moved verbatim from index.ts.
|
|
@@ -17,7 +17,7 @@ export declare function interactivePrompt(): string;
|
|
|
17
17
|
* forever: approvals auto-deny and uncertain executions auto-abandon, both
|
|
18
18
|
* printed loudly — never silently ignored, never hung (Area 7).
|
|
19
19
|
*
|
|
20
|
-
*
|
|
20
|
+
* rounds 8/10: the question is ABORTABLE — a pending rl.question is registered in
|
|
21
21
|
* `pendingAsk` and the SIGINT handler resolves it with the CANCELLED
|
|
22
22
|
* sentinel. The rl.question callback is NOT left dangling: an input that
|
|
23
23
|
* arrives after the cancellation is re-emitted as a fresh "line" — it
|
package/dist/trust-ui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* The ergonomics batch B4 (pure move) — the human-facing question UI: the E3 project
|
|
3
3
|
* trust gate (ADR-0037), the mcp/skills env merges, the generic ask()
|
|
4
4
|
* (approvals, trust, uncertain resolutions), and the uncertain-execution
|
|
5
5
|
* decisions. All bodies moved verbatim from index.ts.
|
|
@@ -24,7 +24,7 @@ export function interactivePrompt() {
|
|
|
24
24
|
* forever: approvals auto-deny and uncertain executions auto-abandon, both
|
|
25
25
|
* printed loudly — never silently ignored, never hung (Area 7).
|
|
26
26
|
*
|
|
27
|
-
*
|
|
27
|
+
* rounds 8/10: the question is ABORTABLE — a pending rl.question is registered in
|
|
28
28
|
* `pendingAsk` and the SIGINT handler resolves it with the CANCELLED
|
|
29
29
|
* sentinel. The rl.question callback is NOT left dangling: an input that
|
|
30
30
|
* arrives after the cancellation is re-emitted as a fresh "line" — it
|
|
@@ -91,7 +91,7 @@ export async function resolveProjectTrust(input) {
|
|
|
91
91
|
const artifacts = await projectArtifacts(process.cwd());
|
|
92
92
|
if (artifacts === null)
|
|
93
93
|
return null; // no .kiso artifacts — nothing to gate
|
|
94
|
-
//
|
|
94
|
+
// merge round B: projectTrust "never" (user config) — the gate auto-refuses:
|
|
95
95
|
// no ask, no record, nothing loads. There is deliberately no "always".
|
|
96
96
|
if (resolveProjectTrustPolicy(loadUserConfig() ?? {}) === "never") {
|
|
97
97
|
bodyLog(`[project .kiso] projectTrust: never — ${artifacts.root} not loaded`);
|
|
@@ -214,7 +214,7 @@ export async function resolveUncertains(session, input, isCancelled) {
|
|
|
214
214
|
for (const uncertain of session.uncertainExecutions()) {
|
|
215
215
|
const answer = await ask(input, `⚠ interrupted execution: ${escapeTerminal(uncertain.name)} (${uncertain.executionId}) — did it apply? (r)erun / (a)bandon: `);
|
|
216
216
|
if (isCancelled() || answer === CANCELLED) {
|
|
217
|
-
//
|
|
217
|
+
// round 10: a cancellation NEVER records a verdict — the execution
|
|
218
218
|
// stays uncertain and durable; no rerun/abandoned is fabricated.
|
|
219
219
|
return;
|
|
220
220
|
}
|