@vincemakes/kiso-tui-cells 0.6.0 → 0.8.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/approval-panel.d.ts +61 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +7 -0
- package/dist/render.d.ts +17 -6
- package/dist/render.js +1 -1
- package/dist/strings.d.ts +107 -0
- package/dist/strings.js +157 -0
- package/package.json +5 -1
package/dist/approval-panel.d.ts
CHANGED
|
@@ -27,6 +27,54 @@
|
|
|
27
27
|
export type PanelFlavor = "approval" | "simple";
|
|
28
28
|
export type PanelPhase = "options" | "rule" | "amend";
|
|
29
29
|
export type PanelSel = 0 | 1 | 2 | 3;
|
|
30
|
+
/** One option of a question: the label the human picks, plus an
|
|
31
|
+
* optional one-line description (the model's own words). */
|
|
32
|
+
export interface AskOption {
|
|
33
|
+
readonly label: string;
|
|
34
|
+
readonly description?: string;
|
|
35
|
+
}
|
|
36
|
+
/** One question: 2-4 options, single- or multi-select, and an optional
|
|
37
|
+
* ≤12-cell header (the panel's title when present — the schema caps
|
|
38
|
+
* it so the title never fights the counter for the row). */
|
|
39
|
+
export interface AskQuestion {
|
|
40
|
+
readonly question: string;
|
|
41
|
+
readonly header?: string;
|
|
42
|
+
readonly options: readonly AskOption[];
|
|
43
|
+
readonly multiSelect?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** The whole ask_user call: 1-4 questions, walked in order. */
|
|
46
|
+
export interface AskSpec {
|
|
47
|
+
readonly questions: readonly AskQuestion[];
|
|
48
|
+
}
|
|
49
|
+
/** One answered question — the three shapes the tool_result carries:
|
|
50
|
+
* a single choice, a multi-select list, or the typed-in answer. */
|
|
51
|
+
export type AskAnswer = {
|
|
52
|
+
readonly q: string;
|
|
53
|
+
readonly choice: string;
|
|
54
|
+
} | {
|
|
55
|
+
readonly q: string;
|
|
56
|
+
readonly choices: readonly string[];
|
|
57
|
+
} | {
|
|
58
|
+
readonly q: string;
|
|
59
|
+
readonly custom: string;
|
|
60
|
+
};
|
|
61
|
+
/** The ask's outcome: every question answered, or the decline — an
|
|
62
|
+
* HONEST recorded outcome that names what was skipped, never silence. */
|
|
63
|
+
export type AskResult = {
|
|
64
|
+
readonly answers: readonly AskAnswer[];
|
|
65
|
+
} | {
|
|
66
|
+
readonly declined: readonly string[];
|
|
67
|
+
};
|
|
68
|
+
/** The ask panel's runtime state — the editor owns and advances it,
|
|
69
|
+
* the compositor reads it. `picks` and `custom` are per question, so
|
|
70
|
+
* a walk back (←) shows what was already chosen. */
|
|
71
|
+
export interface AskRuntime {
|
|
72
|
+
readonly qIndex: number;
|
|
73
|
+
readonly cursor: number;
|
|
74
|
+
readonly picks: readonly (readonly number[])[];
|
|
75
|
+
readonly custom: readonly (string | null)[];
|
|
76
|
+
readonly phase: "options" | "custom";
|
|
77
|
+
}
|
|
30
78
|
/** The ALWAYS-verbose args (the panel's body): the untruncated diff
|
|
31
79
|
* (edit/write), or the full text (shell = the command line, other =
|
|
32
80
|
* the pretty-printed JSON). The CLI composes them UNTRUNCATED — the
|
|
@@ -64,6 +112,10 @@ export interface PanelView {
|
|
|
64
112
|
/** The fallback question — the y/n text for the dock-less path
|
|
65
113
|
* (a TTY without a dock, or a pipe). */
|
|
66
114
|
readonly fallbackQuestion: string;
|
|
115
|
+
/** KC3.5: the questions, when this view is an ASK. Present = the
|
|
116
|
+
* panel renders the ask block and the editor routes the ask keys;
|
|
117
|
+
* absent = the approval/simple panel, unchanged. */
|
|
118
|
+
readonly ask?: AskSpec;
|
|
67
119
|
}
|
|
68
120
|
export type PanelVerdict = {
|
|
69
121
|
readonly action: "allow";
|
|
@@ -76,6 +128,13 @@ export type PanelVerdict = {
|
|
|
76
128
|
readonly reason: string;
|
|
77
129
|
} | {
|
|
78
130
|
readonly action: "cancel";
|
|
131
|
+
}
|
|
132
|
+
/** KC3.5: the ask's own verdict — the answers (or the decline) the
|
|
133
|
+
* cli hands back to the tool. Only ask views ever produce it, so
|
|
134
|
+
* the approval path's switch is untouched. */
|
|
135
|
+
| {
|
|
136
|
+
readonly action: "answers";
|
|
137
|
+
readonly result: AskResult;
|
|
79
138
|
};
|
|
80
139
|
/** The bound panel state the compositor reads — the editor owns the
|
|
81
140
|
* phase/selection state machine and the key routing; the compositor
|
|
@@ -84,6 +143,8 @@ export interface PanelState {
|
|
|
84
143
|
readonly view: PanelView;
|
|
85
144
|
readonly phase: PanelPhase;
|
|
86
145
|
readonly sel: PanelSel;
|
|
146
|
+
/** KC3.5: the ask's walk — present exactly when `view.ask` is. */
|
|
147
|
+
readonly ask?: AskRuntime;
|
|
87
148
|
}
|
|
88
149
|
/** The block's rows — EXACTLY the preview's frame shape, the gutter at
|
|
89
150
|
* the left edge (the preview's two-space mock indent is its own
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,7 @@ export { SPINNER, foldLine, visibleWidth, bodySpacing, Container, cellComponent,
|
|
|
10
10
|
export { editFileDiff, truncateDiff, writeFileDiff, type DiffLine, type DiffResult } from "./diff.js";
|
|
11
11
|
export { pendingQueueRows } from "./components.js";
|
|
12
12
|
export { charWidth, displayWidth, leadWidth, widthOf } from "./width.js";
|
|
13
|
-
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, type PanelArgs, type PanelFlavor, type PanelPhase, type PanelSel, type PanelState, type PanelVerdict, type PanelView, } from "./approval-panel.js";
|
|
13
|
+
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, type PanelArgs, type PanelFlavor, type PanelPhase, type PanelSel, type PanelState, type PanelVerdict, type PanelView, type AskAnswer, type AskOption, type AskQuestion, type AskResult, type AskRuntime, type AskSpec, } from "./approval-panel.js";
|
|
14
|
+
export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, type TrustArtifact, } from "./strings.js";
|
|
15
|
+
export { extensionsBannerText, helpRows, unansweredAskView, type BannerExtension } from "./strings.js";
|
|
14
16
|
export { bannerLines, COLOR_OFF, COLOR_ON, colorInlineCode, escapeTerminal, foldResult, foldThinking, kUnit, palette, relativeTime, renderResumeList, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, type Palette, type ResumeMeta, } from "./render.js";
|
package/dist/index.js
CHANGED
|
@@ -18,4 +18,11 @@ export { charWidth, displayWidth, leadWidth, widthOf } from "./width.js";
|
|
|
18
18
|
// approval is pending. Types + the row/lead/status renderers; the
|
|
19
19
|
// verdict mapping lives in the cli, never here.
|
|
20
20
|
export { panelAffordance, panelBlockRows, panelLead, panelLeadPlain, panelLeadWidth, panelStatus, } from "./approval-panel.js";
|
|
21
|
+
// KC3 slice 1 (the extraction): the human-facing strings the CLI's
|
|
22
|
+
// trust-ui.ts used to build inline — the prompt, the project-trust
|
|
23
|
+
// listing/view/note, the uncertain execution's view. The flow stays in
|
|
24
|
+
// the cli; what the human reads is presentation.
|
|
25
|
+
export { interactivePrompt, projectTrustRows, projectTrustView, projectUntrustedNote, uncertainView, } from "./strings.js";
|
|
26
|
+
// KC3.5: the interrupted-ask copy and the extracted /help table.
|
|
27
|
+
export { extensionsBannerText, helpRows, unansweredAskView } from "./strings.js";
|
|
21
28
|
export { bannerLines, COLOR_OFF, COLOR_ON, colorInlineCode, escapeTerminal, foldResult, foldThinking, kUnit, palette, relativeTime, renderResumeList, renderTerminalGap, renderToolSummary, TAGLINE, toolTarget, truncateRow, } from "./render.js";
|
package/dist/render.d.ts
CHANGED
|
@@ -11,12 +11,23 @@
|
|
|
11
11
|
* RETIRED — the identity accents (the you> prompt, the banner tagline,
|
|
12
12
|
* ✓ marks, slash-command names, the input brick) are bright-white BOLD
|
|
13
13
|
* (SGR 1); the user message is the SGR-7 chip (the 2026-08-09 ruling
|
|
14
|
-
* retired the ▍ rail);
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
14
|
+
* retired the ▍ rail); red for errors, dim for metadata, green for the
|
|
15
|
+
* diff additions. NO_COLOR set, or a non-TTY output → every code is
|
|
16
|
+
* empty, so pipes and CI carry ZERO ANSI (the existing byte-level e2e
|
|
17
|
+
* assertions guard it). Everything not listed is plain.
|
|
18
|
+
*
|
|
19
|
+
* KC3 §2 — THE MONO DISCIPLINE (the owner's 2026-08-17 ruling, a
|
|
20
|
+
* DECLARED SUPERSESSION under ADR-0051 Amendment 3). The interface's
|
|
21
|
+
* body is carried by shades of black and white; green ✓, yellow warn
|
|
22
|
+
* and red error are the ONLY functional exceptions. v5 had already
|
|
23
|
+
* taken the identity accents to bold; `code` was the one chromatic
|
|
24
|
+
* entry left — the light BLUE 38;5;110 — and it becomes the light GRAY
|
|
25
|
+
* 38;5;252. A tint still says "this span is code", which is the job it
|
|
26
|
+
* was hired for; saying it in a hue was never the job.
|
|
27
|
+
*
|
|
28
|
+
* The functional colors are deliberately NOT moved and not
|
|
29
|
+
* approximated: red stays SGR 31, green stays SGR 32. A reader who has
|
|
30
|
+
* learned that colour means something must keep being right.
|
|
20
31
|
*/
|
|
21
32
|
export interface Palette {
|
|
22
33
|
readonly bold: string;
|
package/dist/render.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* dependencies (the tui-cells package has none).
|
|
7
7
|
*/
|
|
8
8
|
import { charWidth, displayWidth } from "./width.js";
|
|
9
|
-
export const COLOR_ON = { bold: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", code: "\x1b[38;5;
|
|
9
|
+
export const COLOR_ON = { bold: "\x1b[1m", dim: "\x1b[2m", red: "\x1b[31m", green: "\x1b[32m", code: "\x1b[38;5;252m", rv: "\x1b[7m", rvEnd: "\x1b[27m", reset: "\x1b[0m" };
|
|
10
10
|
export const COLOR_OFF = { bold: "", dim: "", red: "", green: "", code: "", rv: "", rvEnd: "", reset: "" };
|
|
11
11
|
export function palette() {
|
|
12
12
|
return process.env.NO_COLOR === undefined && process.stdout.isTTY ? COLOR_ON : COLOR_OFF;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tui-cells — the human-facing STRINGS (KC3 slice 1, the ADR-0041
|
|
3
|
+
* escape hatch: extraction, never a raise): the readline prompt, the
|
|
4
|
+
* project-trust listing rows and its panel view, the uncertain
|
|
5
|
+
* execution's panel view, and the non-TTY not-trusted note. All five
|
|
6
|
+
* were built inline in the CLI's trust-ui.ts before the move.
|
|
7
|
+
*
|
|
8
|
+
* The split is the one the ADR names. The FLOW stays in the CLI: who is
|
|
9
|
+
* asked, when the ask happens, whether a TTY exists, and what a verdict
|
|
10
|
+
* MEANS (granted loads, refused is sticky, a cancel records nothing) is
|
|
11
|
+
* trust-ui.ts's and is untouched by this move. What the human READS is
|
|
12
|
+
* presentation, and presentation belongs to the terminal layer — the
|
|
13
|
+
* same reasoning that moved the status rows here in KC2 §5.
|
|
14
|
+
*
|
|
15
|
+
* Pure by construction: every function is (data) → bytes. No node
|
|
16
|
+
* builtins, no I/O, no clock — the package's zero-dependency promise is
|
|
17
|
+
* why the caller passes paths and counts in rather than having them
|
|
18
|
+
* looked up here.
|
|
19
|
+
*/
|
|
20
|
+
import type { PanelView } from "./approval-panel.js";
|
|
21
|
+
/** v2a: the interactive prompt — the identity accent. readline owns the
|
|
22
|
+
* echo of what the user types; we own the prompt's color. (v2c: the
|
|
23
|
+
* readline prompt keeps "you> " — the brick ▌ is the dock's row only;
|
|
24
|
+
* pipe bytes must not change.) */
|
|
25
|
+
export declare function interactivePrompt(): string;
|
|
26
|
+
/** E3 (ADR-0037) — one discovered project artifact: the relative path
|
|
27
|
+
* and its content digest. Structural on purpose — the runtime's
|
|
28
|
+
* ProjectArtifacts satisfies it without this package importing the
|
|
29
|
+
* runtime (it imports nothing). */
|
|
30
|
+
export interface TrustArtifact {
|
|
31
|
+
readonly path: string;
|
|
32
|
+
readonly digest: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* E3 — the artifact listing: `<path> (<digest6>)`, one row per file.
|
|
36
|
+
*
|
|
37
|
+
* The two callers differ by exactly the INDENT and nothing else: the
|
|
38
|
+
* scrollback record indents two (its rows sit under the root's own
|
|
39
|
+
* line), the panel's args do not (the block's frame supplies the
|
|
40
|
+
* inset). Before the move the two rows were written out separately, two
|
|
41
|
+
* template literals that had to agree by hand; the parameter keeps the
|
|
42
|
+
* one real difference visible while making the rest provably identical.
|
|
43
|
+
*/
|
|
44
|
+
export declare function projectTrustRows(files: readonly TrustArtifact[], indent?: string): string[];
|
|
45
|
+
/** E3 — the trust gate's panel: the SIMPLE flavor (1 Yes / 3 No — no
|
|
46
|
+
* "don't ask again" rule exists for a project), the root as the title,
|
|
47
|
+
* the artifact listing as the always-verbose args, and the question as
|
|
48
|
+
* the rule override. The same rows the scrollback records — the panel
|
|
49
|
+
* is a bounded block, the record is not. */
|
|
50
|
+
export declare function projectTrustView(root: string, files: readonly TrustArtifact[]): PanelView;
|
|
51
|
+
/** E3 — the non-TTY note: artifacts were found and deliberately NOT
|
|
52
|
+
* loaded, with the one path back (run once interactively). Printed to
|
|
53
|
+
* stderr by the caller; never silent. */
|
|
54
|
+
export declare function projectUntrustedNote(count: number, root: string): string;
|
|
55
|
+
/** rounds 8/10 — the uncertain execution's panel: the SIMPLE flavor
|
|
56
|
+
* again, with the options re-labelled in the rule line (1 rerun · 3
|
|
57
|
+
* abandon). The tool name is escaped for the dock-less fallback
|
|
58
|
+
* question because it reaches the terminal as raw text there; the
|
|
59
|
+
* panel's own rows are escaped by the panel renderer. */
|
|
60
|
+
export declare function uncertainView(name: string, executionId: string): PanelView;
|
|
61
|
+
/**
|
|
62
|
+
* KC3.5 — the SAME uncertainty gate, said honestly for an ask_user call.
|
|
63
|
+
*
|
|
64
|
+
* "Did the interrupted execution apply?" is the right question for a
|
|
65
|
+
* side effect and the wrong one for a question: nothing applied, the
|
|
66
|
+
* human simply never answered. The COPY special-cases ask_user; the
|
|
67
|
+
* mechanism does not — the verdict still maps to the runtime's own
|
|
68
|
+
* rerun/abandoned resolution, whose error-fill text is untouched.
|
|
69
|
+
*
|
|
70
|
+
* (The round's ① probe pinned why this surface exists at all: the
|
|
71
|
+
* shipped recovery blocks on a started-unreported execution regardless
|
|
72
|
+
* of idempotency, so an interrupted ask meets this gate on the way
|
|
73
|
+
* back. Re-asking is safe — that is what "1 re-ask" says out loud.)
|
|
74
|
+
*/
|
|
75
|
+
export declare function unansweredAskView(executionId: string): PanelView;
|
|
76
|
+
/** An extension as the banner names it — the live `connecting` flag is
|
|
77
|
+
* the MCP bridge's in-flight state ("mcp (connecting…)"). Structural on
|
|
78
|
+
* purpose: the runtime's KisoExtension satisfies it without this
|
|
79
|
+
* package importing the runtime. */
|
|
80
|
+
export interface BannerExtension {
|
|
81
|
+
readonly name: string;
|
|
82
|
+
readonly connecting?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* KC3.5 slice ⓪ (the extraction) — the `[N extensions: …]` banner text:
|
|
86
|
+
* the built-in column, then the user-level names, then the project-level
|
|
87
|
+
* ones marked `project:`.
|
|
88
|
+
*
|
|
89
|
+
* A pure function of three name lists, so what the banner SAYS is
|
|
90
|
+
* testable without a terminal — which matters this round, because the
|
|
91
|
+
* count is where the ask's TTY gate becomes visible: an interactive
|
|
92
|
+
* session reads `built-in: mcp, skills, subagent, ask` and a piped one
|
|
93
|
+
* reads `built-in: mcp, skills, subagent`, from this one composition.
|
|
94
|
+
*/
|
|
95
|
+
export declare function extensionsBannerText(builtIn: readonly BannerExtension[], user: readonly BannerExtension[], project: readonly BannerExtension[]): string;
|
|
96
|
+
/**
|
|
97
|
+
* KC3.5 slice ⓪ (the extraction) — the /help command table.
|
|
98
|
+
*
|
|
99
|
+
* The rows were eight bodyLog calls in the CLI's dispatcher; they are
|
|
100
|
+
* presentation, and presentation belongs here (the KC3 §1 pattern —
|
|
101
|
+
* the FLOW, which is "print these on the chain, then re-prompt", stays
|
|
102
|
+
* in dispatch.ts). The last row carries its own newline exactly as it
|
|
103
|
+
* did inline: bodyLog splits on \n, so `exit` and `keys` land as two
|
|
104
|
+
* rows from one call — the shape the KC1/KC2/KC3 gestures were added
|
|
105
|
+
* to, unchanged.
|
|
106
|
+
*/
|
|
107
|
+
export declare function helpRows(): string[];
|
package/dist/strings.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tui-cells — the human-facing STRINGS (KC3 slice 1, the ADR-0041
|
|
3
|
+
* escape hatch: extraction, never a raise): the readline prompt, the
|
|
4
|
+
* project-trust listing rows and its panel view, the uncertain
|
|
5
|
+
* execution's panel view, and the non-TTY not-trusted note. All five
|
|
6
|
+
* were built inline in the CLI's trust-ui.ts before the move.
|
|
7
|
+
*
|
|
8
|
+
* The split is the one the ADR names. The FLOW stays in the CLI: who is
|
|
9
|
+
* asked, when the ask happens, whether a TTY exists, and what a verdict
|
|
10
|
+
* MEANS (granted loads, refused is sticky, a cancel records nothing) is
|
|
11
|
+
* trust-ui.ts's and is untouched by this move. What the human READS is
|
|
12
|
+
* presentation, and presentation belongs to the terminal layer — the
|
|
13
|
+
* same reasoning that moved the status rows here in KC2 §5.
|
|
14
|
+
*
|
|
15
|
+
* Pure by construction: every function is (data) → bytes. No node
|
|
16
|
+
* builtins, no I/O, no clock — the package's zero-dependency promise is
|
|
17
|
+
* why the caller passes paths and counts in rather than having them
|
|
18
|
+
* looked up here.
|
|
19
|
+
*/
|
|
20
|
+
import { escapeTerminal, palette } from "./render.js";
|
|
21
|
+
/** v2a: the interactive prompt — the identity accent. readline owns the
|
|
22
|
+
* echo of what the user types; we own the prompt's color. (v2c: the
|
|
23
|
+
* readline prompt keeps "you> " — the brick ▌ is the dock's row only;
|
|
24
|
+
* pipe bytes must not change.) */
|
|
25
|
+
export function interactivePrompt() {
|
|
26
|
+
const p = palette();
|
|
27
|
+
return `${p.bold}you> ${p.reset}`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* E3 — the artifact listing: `<path> (<digest6>)`, one row per file.
|
|
31
|
+
*
|
|
32
|
+
* The two callers differ by exactly the INDENT and nothing else: the
|
|
33
|
+
* scrollback record indents two (its rows sit under the root's own
|
|
34
|
+
* line), the panel's args do not (the block's frame supplies the
|
|
35
|
+
* inset). Before the move the two rows were written out separately, two
|
|
36
|
+
* template literals that had to agree by hand; the parameter keeps the
|
|
37
|
+
* one real difference visible while making the rest provably identical.
|
|
38
|
+
*/
|
|
39
|
+
export function projectTrustRows(files, indent = "") {
|
|
40
|
+
return files.map((f) => `${indent}${f.path} (${f.digest.slice(0, 6)})`);
|
|
41
|
+
}
|
|
42
|
+
/** E3 — the trust gate's panel: the SIMPLE flavor (1 Yes / 3 No — no
|
|
43
|
+
* "don't ask again" rule exists for a project), the root as the title,
|
|
44
|
+
* the artifact listing as the always-verbose args, and the question as
|
|
45
|
+
* the rule override. The same rows the scrollback records — the panel
|
|
46
|
+
* is a bounded block, the record is not. */
|
|
47
|
+
export function projectTrustView(root, files) {
|
|
48
|
+
return {
|
|
49
|
+
flavor: "simple",
|
|
50
|
+
name: "project trust",
|
|
51
|
+
title: root,
|
|
52
|
+
speaker: "kiso",
|
|
53
|
+
statusText: "▸ project trust",
|
|
54
|
+
args: { kind: "text", lines: projectTrustRows(files) },
|
|
55
|
+
ruleOverride: "trust this project's .kiso?",
|
|
56
|
+
fallbackQuestion: `trust this project's .kiso? (y/n) `,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** E3 — the non-TTY note: artifacts were found and deliberately NOT
|
|
60
|
+
* loaded, with the one path back (run once interactively). Printed to
|
|
61
|
+
* stderr by the caller; never silent. */
|
|
62
|
+
export function projectUntrustedNote(count, root) {
|
|
63
|
+
return `[project .kiso] found ${count} artifact(s) in ${root} — not trusted, not loaded (run kiso interactively once to decide)`;
|
|
64
|
+
}
|
|
65
|
+
/** rounds 8/10 — the uncertain execution's panel: the SIMPLE flavor
|
|
66
|
+
* again, with the options re-labelled in the rule line (1 rerun · 3
|
|
67
|
+
* abandon). The tool name is escaped for the dock-less fallback
|
|
68
|
+
* question because it reaches the terminal as raw text there; the
|
|
69
|
+
* panel's own rows are escaped by the panel renderer. */
|
|
70
|
+
export function uncertainView(name, executionId) {
|
|
71
|
+
return {
|
|
72
|
+
flavor: "simple",
|
|
73
|
+
name: "uncertain execution",
|
|
74
|
+
title: `${name} (${executionId})`,
|
|
75
|
+
speaker: "kiso",
|
|
76
|
+
statusText: "▸ uncertain execution",
|
|
77
|
+
args: { kind: "text", lines: [executionId] },
|
|
78
|
+
ruleOverride: "did the interrupted execution apply? — 1 rerun · 3 abandon",
|
|
79
|
+
fallbackQuestion: `⚠ interrupted execution: ${escapeTerminal(name)} (${executionId}) — did it apply? (y)es / (n)o `,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* KC3.5 — the SAME uncertainty gate, said honestly for an ask_user call.
|
|
84
|
+
*
|
|
85
|
+
* "Did the interrupted execution apply?" is the right question for a
|
|
86
|
+
* side effect and the wrong one for a question: nothing applied, the
|
|
87
|
+
* human simply never answered. The COPY special-cases ask_user; the
|
|
88
|
+
* mechanism does not — the verdict still maps to the runtime's own
|
|
89
|
+
* rerun/abandoned resolution, whose error-fill text is untouched.
|
|
90
|
+
*
|
|
91
|
+
* (The round's ① probe pinned why this surface exists at all: the
|
|
92
|
+
* shipped recovery blocks on a started-unreported execution regardless
|
|
93
|
+
* of idempotency, so an interrupted ask meets this gate on the way
|
|
94
|
+
* back. Re-asking is safe — that is what "1 re-ask" says out loud.)
|
|
95
|
+
*/
|
|
96
|
+
export function unansweredAskView(executionId) {
|
|
97
|
+
return {
|
|
98
|
+
flavor: "simple",
|
|
99
|
+
name: "unanswered question",
|
|
100
|
+
title: `ask_user (${executionId})`,
|
|
101
|
+
speaker: "kiso",
|
|
102
|
+
statusText: "▸ unanswered question",
|
|
103
|
+
args: { kind: "text", lines: [executionId] },
|
|
104
|
+
ruleOverride: "an unanswered question was interrupted — ask it again? — 1 re-ask · 3 drop",
|
|
105
|
+
fallbackQuestion: `⚠ an unanswered question was interrupted (${executionId}) — ask it again? (y)es / (n)o `,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* KC3.5 slice ⓪ (the extraction) — the `[N extensions: …]` banner text:
|
|
110
|
+
* the built-in column, then the user-level names, then the project-level
|
|
111
|
+
* ones marked `project:`.
|
|
112
|
+
*
|
|
113
|
+
* A pure function of three name lists, so what the banner SAYS is
|
|
114
|
+
* testable without a terminal — which matters this round, because the
|
|
115
|
+
* count is where the ask's TTY gate becomes visible: an interactive
|
|
116
|
+
* session reads `built-in: mcp, skills, subagent, ask` and a piped one
|
|
117
|
+
* reads `built-in: mcp, skills, subagent`, from this one composition.
|
|
118
|
+
*/
|
|
119
|
+
export function extensionsBannerText(builtIn, user, project) {
|
|
120
|
+
const total = builtIn.length + user.length + project.length;
|
|
121
|
+
if (total === 0)
|
|
122
|
+
return "";
|
|
123
|
+
const label = (e) => (e.connecting === true ? `${e.name} (connecting…)` : e.name);
|
|
124
|
+
const parts = [];
|
|
125
|
+
if (builtIn.length > 0)
|
|
126
|
+
parts.push(`built-in: ${builtIn.map(label).join(", ")}`);
|
|
127
|
+
if (user.length > 0)
|
|
128
|
+
parts.push(user.map(label).join(", "));
|
|
129
|
+
if (project.length > 0)
|
|
130
|
+
parts.push(`project: ${project.map(label).join(", ")}`);
|
|
131
|
+
return ` · [${total} extension${total === 1 ? "" : "s"}: ${parts.join(" · ")}]`;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* KC3.5 slice ⓪ (the extraction) — the /help command table.
|
|
135
|
+
*
|
|
136
|
+
* The rows were eight bodyLog calls in the CLI's dispatcher; they are
|
|
137
|
+
* presentation, and presentation belongs here (the KC3 §1 pattern —
|
|
138
|
+
* the FLOW, which is "print these on the chain, then re-prompt", stays
|
|
139
|
+
* in dispatch.ts). The last row carries its own newline exactly as it
|
|
140
|
+
* did inline: bodyLog splits on \n, so `exit` and `keys` land as two
|
|
141
|
+
* rows from one call — the shape the KC1/KC2/KC3 gestures were added
|
|
142
|
+
* to, unchanged.
|
|
143
|
+
*/
|
|
144
|
+
export function helpRows() {
|
|
145
|
+
const p = palette();
|
|
146
|
+
const cmd = (name, desc) => `${p.bold}${name}${p.reset} ${desc}`;
|
|
147
|
+
return [
|
|
148
|
+
cmd("/help", "print this list of commands"),
|
|
149
|
+
cmd("/think", "show the last full thinking block"),
|
|
150
|
+
cmd("/last", "show the most recent tool call's input and output"),
|
|
151
|
+
cmd("/status", "show session id, event count, and context estimate"),
|
|
152
|
+
cmd("/mode", "show the approval tier; /mode <name> switches (manual/default/accept-edits/plan/bypass)"),
|
|
153
|
+
cmd("/model", "list model profiles; /model <name|provider/model> switches"),
|
|
154
|
+
cmd("/compact", "summarize the older conversation to free context"),
|
|
155
|
+
`${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 · 1-4 answers an ask")}`,
|
|
156
|
+
];
|
|
157
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincemakes/kiso-tui-cells",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "kiso tui-cells — the components cell renderer (components, diff, width, the render slice). Zero runtime dependencies: input is data, output is bytes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"./render": {
|
|
29
29
|
"types": "./dist/render.d.ts",
|
|
30
30
|
"default": "./dist/render.js"
|
|
31
|
+
},
|
|
32
|
+
"./strings": {
|
|
33
|
+
"types": "./dist/strings.d.ts",
|
|
34
|
+
"default": "./dist/strings.js"
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
"files": [
|