@zenera/cli 1.1.18 → 1.1.20
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/README.md +6 -0
- package/dist/banner.d.ts +8 -0
- package/dist/banner.js +10 -4
- package/dist/commands/cache.js +1 -0
- package/dist/commands/check.js +34 -2
- package/dist/commands/index.js +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/meta.js +1 -1
- package/dist/commands/open.js +1 -1
- package/dist/main.js +8 -1
- package/dist/meta.js +19 -7
- package/dist/scaffold.d.ts +37 -0
- package/dist/scaffold.js +67 -3
- package/dist/term.d.ts +16 -0
- package/dist/term.js +91 -1
- package/dist/tui/app.js +493 -186
- package/dist/tui/theme.d.ts +36 -7
- package/dist/tui/theme.js +66 -36
- package/dist/tui/wrap.d.ts +140 -33
- package/dist/tui/wrap.js +690 -44
- package/dist/validate.js +113 -20
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +35 -10
- package/templates/editor/.github/skills/zen-cli/references/check.md +0 -2
- package/templates/editor/.github/skills/zen-cli/references/projects.md +20 -8
- package/templates/editor/.github/skills/zen-memory/SKILL.md +77 -33
- package/templates/editor/.github/skills/zen-memory/scripts/check-instructions.sh +2 -1
- package/templates/editor/.vscode/agents.schema.json +611 -0
- package/templates/editor/.vscode/extensions.json +3 -0
- package/templates/editor/.vscode/settings.json +8 -0
- package/templates/project/agents/fork-instructions.md +151 -0
- package/templates/project/agents/memory-instructions.md +120 -8
- package/templates/project/agents/tools-instructions.md +8 -0
package/dist/tui/theme.d.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import { type Appearance } from '../term.ts';
|
|
2
|
+
export type { Appearance };
|
|
3
|
+
/**
|
|
4
|
+
* The roles a line can play in the transcript.
|
|
5
|
+
*
|
|
6
|
+
* `text` is what the agent said on its way somewhere — prose between one batch
|
|
7
|
+
* of calls and the next — and `agent` is the answer it finished on, which is
|
|
8
|
+
* the only one that gets a box. Reasoning is not among them: it is progress,
|
|
9
|
+
* and progress that has finished is worth no rows at all.
|
|
10
|
+
*/
|
|
11
|
+
export type Kind = 'you' | 'text' | 'agent' | 'tool' | 'note' | 'error';
|
|
4
12
|
export interface LineStyle {
|
|
5
13
|
/** `undefined` means the terminal's own foreground. */
|
|
6
14
|
readonly color?: string;
|
|
7
|
-
readonly dim?: boolean;
|
|
8
15
|
}
|
|
9
16
|
export interface Theme {
|
|
10
17
|
readonly appearance: Appearance;
|
|
@@ -13,13 +20,35 @@ export interface Theme {
|
|
|
13
20
|
readonly accent: string;
|
|
14
21
|
/** Read-only badge, busy label. */
|
|
15
22
|
readonly warn: string;
|
|
23
|
+
/**
|
|
24
|
+
* Box rules, clocks, the footer's numbers, the call rows. One step quieter
|
|
25
|
+
* than the prose and never two — stated as a grey because `dim` is a
|
|
26
|
+
* request the terminal is free to over-honour, and some do.
|
|
27
|
+
*/
|
|
28
|
+
readonly chrome: LineStyle;
|
|
16
29
|
/**
|
|
17
30
|
* Reasoning. It is not a tool call and it is not the answer, and drawn in
|
|
18
|
-
* the same
|
|
19
|
-
*
|
|
20
|
-
*
|
|
31
|
+
* the same grey as the rows around it there was nothing to say which — a
|
|
32
|
+
* wall of one weight reads as one thing. Its own hue is what separates the
|
|
33
|
+
* model's thinking from the work it went on to do.
|
|
21
34
|
*/
|
|
22
35
|
readonly thinking: LineStyle;
|
|
36
|
+
/**
|
|
37
|
+
* Inline code inside prose — `zen check`, `--theme`, a path.
|
|
38
|
+
*
|
|
39
|
+
* The one role added for markdown, and it is added because the alternative
|
|
40
|
+
* is worse: bold is already what `**strong**` means, and grey would say a
|
|
41
|
+
* command name matters less than the sentence around it when it is usually
|
|
42
|
+
* the only part worth copying. A hue says *this is literal* without
|
|
43
|
+
* ranking it.
|
|
44
|
+
*/
|
|
45
|
+
readonly code: LineStyle;
|
|
46
|
+
/**
|
|
47
|
+
* The three things a turn spends time on. One word in the footer says which,
|
|
48
|
+
* and it is read at a glance from across a desk — so the word changing is
|
|
49
|
+
* backed by the colour changing, not left to be spelled out.
|
|
50
|
+
*/
|
|
51
|
+
readonly phase: Record<'reasoning' | 'waiting' | 'working', string>;
|
|
23
52
|
/**
|
|
24
53
|
* Branch colours, cycled in order of first sight. A fan-out is the one
|
|
25
54
|
* place where colour carries information rather than decoration: eight
|
package/dist/tui/theme.js
CHANGED
|
@@ -13,47 +13,75 @@
|
|
|
13
13
|
// unreadable on dark and invisible on paper. What is left is the handful of
|
|
14
14
|
// accents that ANSI *does* let a light theme get wrong, so those swap.
|
|
15
15
|
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
16
|
+
// A second weight is spent on *chrome* and on the machinery: box rules,
|
|
17
|
+
// clocks, the footer's numbers, and the call rows that say how an answer was
|
|
18
|
+
// arrived at. What the agent actually said is drawn at full weight in the
|
|
19
|
+
// terminal's own foreground, so a transcript read top to bottom reads as prose
|
|
20
|
+
// with the work annotated beside it — not as one undifferentiated wall.
|
|
20
21
|
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
//
|
|
22
|
+
// That weight used to be SGR 2 (`dim`), and it was the third version of the
|
|
23
|
+
// same bug. `dim` is not a colour, it is an instruction, and how far it is
|
|
24
|
+
// obeyed is the terminal's business: iTerm2 takes a step, Apple Terminal
|
|
25
|
+
// blends most of the way to the background. On Terminal.app the entire margin
|
|
26
|
+
// — every rule, every call row, every number — went out with it.
|
|
27
|
+
//
|
|
28
|
+
// So there is exactly one ramp here, `chrome`, and it is a stated grey rather
|
|
29
|
+
// than an attribute. It is the only number in the file, and it buys the one
|
|
30
|
+
// thing deference cannot: a floor under the quiet half of the screen.
|
|
31
|
+
// Everything else is still named by role and still defers to the user's own
|
|
32
|
+
// scheme — no brand, no second hue, no 256-colour palette.
|
|
24
33
|
// ---------------------------------------------------------------------------
|
|
34
|
+
import { appearance, CHROME } from "../term.js";
|
|
35
|
+
// The two greys, shared with every one-shot command so a `zen check` table and
|
|
36
|
+
// a TUI call row are the same weight. Chalk steps them down for a 16-colour
|
|
37
|
+
// terminal, which is the only place the old `gray` problem is still reachable.
|
|
38
|
+
const DARK_CHROME = { color: `ansi256(${CHROME.dark})` };
|
|
39
|
+
const LIGHT_CHROME = { color: `ansi256(${CHROME.light})` };
|
|
25
40
|
const DARK = {
|
|
26
41
|
appearance: 'dark',
|
|
27
42
|
line: {
|
|
28
43
|
you: { color: 'cyan' },
|
|
44
|
+
text: {},
|
|
29
45
|
agent: {},
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
tool:
|
|
46
|
+
// A call is the machinery, not the work: the transcript is read for
|
|
47
|
+
// what the agent said, and the rows saying how it found out are a
|
|
48
|
+
// margin note beside that.
|
|
49
|
+
tool: DARK_CHROME,
|
|
34
50
|
note: { color: 'cyan' },
|
|
35
51
|
error: { color: 'red' },
|
|
36
52
|
},
|
|
37
53
|
accent: 'cyan',
|
|
38
54
|
warn: 'yellow',
|
|
39
|
-
|
|
55
|
+
chrome: DARK_CHROME,
|
|
56
|
+
// Bright: the gist is one line among many and plain `magenta` on black is
|
|
57
|
+
// the darkest of the six.
|
|
58
|
+
thinking: { color: 'magentaBright' },
|
|
59
|
+
// Green is the one hue with no other job here: it is not the accent, not
|
|
60
|
+
// the warning, and not the thinking.
|
|
61
|
+
code: { color: 'green' },
|
|
62
|
+
phase: { reasoning: 'magenta', waiting: 'yellow', working: 'cyan' },
|
|
40
63
|
lanes: ['cyan', 'green', 'yellow', 'blue', 'red', 'magenta'],
|
|
41
64
|
};
|
|
42
65
|
// On a light background `cyan` and `yellow` are barely darker than the paper.
|
|
43
|
-
//
|
|
44
|
-
// still legible.
|
|
66
|
+
// Grey and `blue`/`magenta` are the same information, still legible.
|
|
45
67
|
const LIGHT = {
|
|
46
68
|
appearance: 'light',
|
|
47
69
|
line: {
|
|
48
70
|
you: { color: 'blue' },
|
|
71
|
+
text: {},
|
|
49
72
|
agent: {},
|
|
50
|
-
tool:
|
|
73
|
+
tool: LIGHT_CHROME,
|
|
51
74
|
note: { color: 'blue' },
|
|
52
75
|
error: { color: 'red' },
|
|
53
76
|
},
|
|
54
77
|
accent: 'blue',
|
|
55
78
|
warn: 'magenta',
|
|
79
|
+
chrome: LIGHT_CHROME,
|
|
56
80
|
thinking: { color: 'magenta' },
|
|
81
|
+
code: { color: 'green' },
|
|
82
|
+
// No yellow: `waiting` takes blue and `working` green, which are the two
|
|
83
|
+
// that survive paper.
|
|
84
|
+
phase: { reasoning: 'magenta', waiting: 'blue', working: 'green' },
|
|
57
85
|
// No cyan or yellow: on paper they are barely darker than the paper.
|
|
58
86
|
lanes: ['blue', 'green', 'red', 'magenta'],
|
|
59
87
|
};
|
|
@@ -67,23 +95,17 @@ export async function resolveTheme(choice) {
|
|
|
67
95
|
if (asked !== 'auto') {
|
|
68
96
|
return THEMES[asked];
|
|
69
97
|
}
|
|
70
|
-
return THEMES[(await queryBackground()) ??
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* `COLORFGBG` is `fg;bg` or `fg;<something>;bg`; the background is the last
|
|
74
|
-
* field. Anything non-numeric (notably `default`) tells us nothing.
|
|
75
|
-
*/
|
|
76
|
-
function fromColorFgBg() {
|
|
77
|
-
const parts = process.env['COLORFGBG']?.split(';');
|
|
78
|
-
const bg = parts?.[parts.length - 1];
|
|
79
|
-
if (bg === undefined || !/^\d+$/.test(bg)) {
|
|
80
|
-
return undefined;
|
|
81
|
-
}
|
|
82
|
-
const n = Number(bg);
|
|
83
|
-
return n === 7 || n >= 9 ? 'light' : 'dark';
|
|
98
|
+
return THEMES[(await queryBackground()) ?? appearance()];
|
|
84
99
|
}
|
|
85
|
-
|
|
100
|
+
// The DA1 behind the colour query is what makes the answer conclusive. Every
|
|
101
|
+
// terminal replies to DA1, and none replies to it ahead of an OSC 11 it
|
|
102
|
+
// supports — so a DA1 arriving alone means "I do not do that", known in one
|
|
103
|
+
// round trip instead of guessed at the end of a timeout. What is left for the
|
|
104
|
+
// timeout is the terminal that answers neither, which is the only case worth
|
|
105
|
+
// waiting on and now the only one that does.
|
|
106
|
+
const QUERY = '\u001b]11;?\u0007\u001b[c';
|
|
86
107
|
const REPLY = /\u001b\]11;rgb:([\da-f]{1,4})\/([\da-f]{1,4})\/([\da-f]{1,4})/i;
|
|
108
|
+
const DA1 = /\u001b\[\?[\d;]*c/;
|
|
87
109
|
/**
|
|
88
110
|
* Ask the terminal for its background colour and read the answer off stdin.
|
|
89
111
|
*
|
|
@@ -93,7 +115,7 @@ const REPLY = /\u001b\]11;rgb:([\da-f]{1,4})\/([\da-f]{1,4})\/([\da-f]{1,4})/i;
|
|
|
93
115
|
* and nothing else. Anything the user typed in that window is put back, so
|
|
94
116
|
* the first keystroke of a fast start is not eaten by the handshake.
|
|
95
117
|
*/
|
|
96
|
-
async function queryBackground(timeoutMs =
|
|
118
|
+
async function queryBackground(timeoutMs = 300) {
|
|
97
119
|
const { stdin, stdout } = process;
|
|
98
120
|
if (!stdin.isTTY || !stdout.isTTY || typeof stdin.setRawMode !== 'function') {
|
|
99
121
|
return undefined;
|
|
@@ -102,6 +124,7 @@ async function queryBackground(timeoutMs = 120) {
|
|
|
102
124
|
let timer;
|
|
103
125
|
let settled = false;
|
|
104
126
|
let seen = '';
|
|
127
|
+
let found;
|
|
105
128
|
return await new Promise((resolve) => {
|
|
106
129
|
const finish = (result) => {
|
|
107
130
|
if (settled) {
|
|
@@ -114,26 +137,33 @@ async function queryBackground(timeoutMs = 120) {
|
|
|
114
137
|
if (!wasRaw) {
|
|
115
138
|
stdin.pause();
|
|
116
139
|
}
|
|
117
|
-
const typed = seen
|
|
140
|
+
const typed = seen
|
|
141
|
+
.replace(REPLY, '')
|
|
142
|
+
.replace(DA1, '')
|
|
143
|
+
.replace(/\u001b\\|\u0007/g, '');
|
|
118
144
|
if (typed) {
|
|
119
145
|
stdin.unshift(Buffer.from(typed, 'latin1'));
|
|
120
146
|
}
|
|
121
147
|
resolve(result);
|
|
122
148
|
};
|
|
149
|
+
// The DA1 is sent second and answered second, so it is the end of the
|
|
150
|
+
// conversation whether or not the colour came back. Settling on the
|
|
151
|
+
// colour alone leaves the DA1 in the pipe, and it surfaces a moment
|
|
152
|
+
// later as `[?64;1;2;...c` typed into the prompt.
|
|
123
153
|
const onData = (chunk) => {
|
|
124
154
|
seen += chunk.toString('latin1');
|
|
125
155
|
const m = REPLY.exec(seen);
|
|
126
156
|
if (m) {
|
|
127
|
-
|
|
157
|
+
found = appearanceOf(m[1], m[2], m[3]);
|
|
128
158
|
}
|
|
129
|
-
|
|
130
|
-
finish(
|
|
159
|
+
if (DA1.test(seen) || seen.length > 256) {
|
|
160
|
+
finish(found);
|
|
131
161
|
}
|
|
132
162
|
};
|
|
133
163
|
stdin.setRawMode(true);
|
|
134
164
|
stdin.resume();
|
|
135
165
|
stdin.on('data', onData);
|
|
136
|
-
timer = setTimeout(() => finish(
|
|
166
|
+
timer = setTimeout(() => finish(found), timeoutMs);
|
|
137
167
|
timer.unref?.();
|
|
138
168
|
stdout.write(QUERY);
|
|
139
169
|
});
|
package/dist/tui/wrap.d.ts
CHANGED
|
@@ -17,26 +17,33 @@ export declare function clip(text: string, width: number): string;
|
|
|
17
17
|
export declare function wrap(text: string, width: number): string[];
|
|
18
18
|
/** The three footer rows, its margin, the prompt, and a row in hand. */
|
|
19
19
|
export declare const CHROME_ROWS = 7;
|
|
20
|
-
/**
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* How much of the reasoning stream is worth showing.
|
|
22
|
+
*
|
|
23
|
+
* One row. A reasoning summary is not a document to be read while it arrives —
|
|
24
|
+
* it is the model saying what it is about to do, and the sentence that says so
|
|
25
|
+
* is the heading it writes for itself. Six rows of it pushed the answer and the
|
|
26
|
+
* work down the screen to make room for a paragraph nobody finishes reading,
|
|
27
|
+
* and the whole chain is in the trajectory either way.
|
|
28
|
+
*/
|
|
29
|
+
export declare const THINKING_ROWS = 1;
|
|
22
30
|
/** How much of the frame the work in flight may take. A branch is a box now,
|
|
23
|
-
* not a row, so a fan-out of two costs
|
|
24
|
-
export declare const ACTIVITY_ROWS =
|
|
25
|
-
/** The
|
|
26
|
-
export declare const
|
|
31
|
+
* not a row, so a fan-out of two costs twenty-two of these. */
|
|
32
|
+
export declare const ACTIVITY_ROWS = 24;
|
|
33
|
+
/** The width of the elapsed-time column every call row is drawn behind. */
|
|
34
|
+
export declare const TIME_COL = 5;
|
|
27
35
|
export interface Budget {
|
|
28
36
|
/** rows for the list of what is in flight */
|
|
29
37
|
activity: number;
|
|
30
|
-
/** rows for the
|
|
38
|
+
/** rows for the gist of what the model is reasoning about */
|
|
31
39
|
thinking: number;
|
|
32
40
|
/** rows for the answer as it arrives */
|
|
33
41
|
live: number;
|
|
34
42
|
/**
|
|
35
|
-
* What the three of them occupy together
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* reasoning block.
|
|
43
|
+
* What the three of them occupy together — a constant for a given terminal,
|
|
44
|
+
* whatever is happening inside it. The region grows to this and stops, and
|
|
45
|
+
* never shrinks back while the turn runs, which is what keeps the footer on
|
|
46
|
+
* one row instead of riding up and down on the work.
|
|
40
47
|
*/
|
|
41
48
|
total: number;
|
|
42
49
|
}
|
|
@@ -47,15 +54,22 @@ export interface Budget {
|
|
|
47
54
|
* arrives matters more than the machinery producing it. Reasoning yields to it
|
|
48
55
|
* in turn, because it is a progress indicator and the answer is the point.
|
|
49
56
|
*
|
|
50
|
-
* `thinking` is how many rows of reasoning are wanted
|
|
51
|
-
*
|
|
52
|
-
* settled and its tail is history rather than progress. The two rules are
|
|
53
|
-
* charged on top, so a block too cramped to be worth boxing is not drawn at all
|
|
54
|
-
* rather than drawn as a border with a line in it.
|
|
57
|
+
* `thinking` is how many rows of reasoning are wanted — one while the model is
|
|
58
|
+
* reasoning, none otherwise — and it never takes the answer's last row.
|
|
55
59
|
*/
|
|
56
60
|
export declare function budgetOf(rows: number, activity: number, thinking: number): Budget;
|
|
57
|
-
/** The rows a branch box may spend on its own calls and
|
|
58
|
-
export declare const BRANCH_ROWS =
|
|
61
|
+
/** The rows a branch box may spend on its own calls, prose and reasoning. */
|
|
62
|
+
export declare const BRANCH_ROWS = 9;
|
|
63
|
+
/**
|
|
64
|
+
* The fewest a box is worth drawing at.
|
|
65
|
+
*
|
|
66
|
+
* One row per branch fit more of them on screen and said nothing about any of
|
|
67
|
+
* them: a box holding a single call is a label, and the reason it is a box at
|
|
68
|
+
* all is that what a branch just did and said is why it is doing this. Below
|
|
69
|
+
* six rows there is no *what it just did* — so a fork too wide to give every
|
|
70
|
+
* branch six is cut to the ones that fit and counted, which is `fitActivity`.
|
|
71
|
+
*/
|
|
72
|
+
export declare const BRANCH_MIN = 6;
|
|
59
73
|
/** Rows a branch box spends on chrome: the title rule and the closing one. */
|
|
60
74
|
export declare const BOX_CHROME = 2;
|
|
61
75
|
/**
|
|
@@ -63,18 +77,27 @@ export declare const BOX_CHROME = 2;
|
|
|
63
77
|
* activity region has to divide between them.
|
|
64
78
|
*
|
|
65
79
|
* Every branch gets the same number, because they are the same kind of thing
|
|
66
|
-
* and a fan-out is read across, not down.
|
|
67
|
-
* complete rather than on being detailed: eight branches showing one call each
|
|
68
|
-
* is a picture of the fork, eight rows of one branch is not.
|
|
80
|
+
* and a fan-out is read across, not down.
|
|
69
81
|
*/
|
|
70
82
|
export declare function branchRows(count: number, allowance: number): number;
|
|
71
83
|
/**
|
|
72
|
-
* How wide
|
|
73
|
-
*
|
|
84
|
+
* How wide *prose* is drawn. A line spanning a 200-column terminal is
|
|
85
|
+
* measurably harder to read than one that stops, which is why every demo in
|
|
74
86
|
* `examples/sdk/` puts its answer in a box of bounded width — the terminal is the
|
|
75
87
|
* page, not the paragraph.
|
|
88
|
+
*
|
|
89
|
+
* `boxWidth` is what a whole answer is drawn at; this is the floor it starts from.
|
|
76
90
|
*/
|
|
77
91
|
export declare function answerWidth(columns: number): number;
|
|
92
|
+
/**
|
|
93
|
+
* How wide the box holding `text` has to be.
|
|
94
|
+
*
|
|
95
|
+
* Prose stops at the comfort width, but a fence and a table cannot be
|
|
96
|
+
* reflowed — fold a table row and the columns stop lining up, which is the one
|
|
97
|
+
* thing the table was for — so the box grows to hold the widest of them, as far
|
|
98
|
+
* as the terminal allows and no further.
|
|
99
|
+
*/
|
|
100
|
+
export declare function boxWidth(text: string, columns: number): number;
|
|
78
101
|
/**
|
|
79
102
|
* A tool payload as a person would read it, rather than as it was serialised.
|
|
80
103
|
*
|
|
@@ -87,18 +110,102 @@ export declare function answerWidth(columns: number): number;
|
|
|
87
110
|
* that got cut.
|
|
88
111
|
*/
|
|
89
112
|
export declare function readable(preview: string): string;
|
|
90
|
-
/**
|
|
91
|
-
export
|
|
92
|
-
|
|
113
|
+
/** Every field of a preview, first mention winning. */
|
|
114
|
+
export declare function fieldsOf(preview: string): Map<string, string>;
|
|
115
|
+
/** What a call is doing, and what it is doing it to. */
|
|
116
|
+
export interface CallView {
|
|
117
|
+
/** The verb, drawn first: what kind of thing this is. */
|
|
118
|
+
verb: string;
|
|
119
|
+
/** What identifies this call: a path, a command, a query. May be empty. */
|
|
120
|
+
subject: string;
|
|
121
|
+
}
|
|
122
|
+
export declare function describeCall(name: string, preview: string): CallView;
|
|
123
|
+
export declare function summarise(name: string, preview: string): string;
|
|
124
|
+
/**
|
|
125
|
+
* One line saying where the model has got to.
|
|
126
|
+
*
|
|
127
|
+
* Reasoning summaries arrive as markdown and are structured by their own bold
|
|
128
|
+
* headings — Gemini emits one every few sentences, and they are the shortest
|
|
129
|
+
* true account of the step. The last one is where the model is now. Failing
|
|
130
|
+
* that the raw text is clipped, which is a fragment, but a moving fragment is
|
|
131
|
+
* still proof that something is happening.
|
|
132
|
+
*/
|
|
133
|
+
export declare function gistOf(text: string, width: number): string;
|
|
134
|
+
/** A run of inline text and what it is. Style rides beside the text, never in it. */
|
|
135
|
+
export interface Span {
|
|
136
|
+
text: string;
|
|
137
|
+
bold?: boolean;
|
|
138
|
+
italic?: boolean;
|
|
139
|
+
/** an inline code span, taken verbatim and never scanned again */
|
|
140
|
+
code?: boolean;
|
|
141
|
+
/** where a link points, when its own text does not say */
|
|
142
|
+
href?: string;
|
|
143
|
+
}
|
|
144
|
+
export type BlockKind = 'paragraph' | 'heading' | 'item' | 'quote' | 'code' | 'table' | 'rule';
|
|
145
|
+
/** How a table column is set, when its rule row said. */
|
|
146
|
+
export type Align = 'left' | 'right' | 'center';
|
|
147
|
+
/**
|
|
148
|
+
* One block of an answer.
|
|
149
|
+
*
|
|
150
|
+
* `lines`, `cells` and `spans` are exclusive and say how the block may be
|
|
151
|
+
* drawn: `lines` is verbatim and must be cut rather than wrapped, `cells` is a
|
|
152
|
+
* grid to be laid out by `gridOf`, `spans` is prose and the renderer may do as
|
|
153
|
+
* it likes with it.
|
|
154
|
+
*/
|
|
155
|
+
export interface Block {
|
|
156
|
+
kind: BlockKind;
|
|
157
|
+
/** `heading`: its depth, 1–6. `item`: how deep it is nested. */
|
|
158
|
+
level?: number;
|
|
93
159
|
/** the fence's info string, when it had one */
|
|
94
160
|
title?: string;
|
|
95
|
-
|
|
161
|
+
/** what a list item is drawn behind — a bullet, or the number that was written */
|
|
162
|
+
marker?: string;
|
|
163
|
+
/** `code` only, whose indentation is its meaning */
|
|
164
|
+
lines?: string[];
|
|
165
|
+
/** `table` only: every row but the rule, as cells, with their markup resolved */
|
|
166
|
+
cells?: Span[][][];
|
|
167
|
+
/** `table` only: how each column is set, and that the first row is a header */
|
|
168
|
+
align?: Align[];
|
|
169
|
+
/** every other kind, with its inline markup resolved */
|
|
170
|
+
spans?: Span[];
|
|
96
171
|
}
|
|
97
172
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
173
|
+
* The inline markup of one block, resolved.
|
|
174
|
+
*
|
|
175
|
+
* Order is the correctness argument. Code is settled first and never entered
|
|
176
|
+
* again, which is why this is a scanner and not a chain of replaces: in
|
|
177
|
+
* "use `[a](b)` syntax" the brackets are prose, and no regex over the whole
|
|
178
|
+
* string can know that. Everything else recurses on the text between its own
|
|
179
|
+
* markers, so `**bold with `code` in it**` keeps both.
|
|
180
|
+
*/
|
|
181
|
+
export declare function inlineOf(text: string, style?: Omit<Span, 'text'>, depth?: number): Span[];
|
|
182
|
+
/**
|
|
183
|
+
* An answer, as the blocks it is made of.
|
|
184
|
+
*
|
|
185
|
+
* Read top down, one line at a time, because that is the order the text
|
|
186
|
+
* arrives in and a stream must be readable before it is finished. The two
|
|
187
|
+
* verbatim kinds win over everything: a pipe inside a fence is whatever the
|
|
188
|
+
* code says it is, and a `#` inside one is a comment, not a heading.
|
|
189
|
+
*/
|
|
190
|
+
export declare function blocksOf(text: string): Block[];
|
|
191
|
+
/**
|
|
192
|
+
* A table as its rows, each one a single run of spans.
|
|
193
|
+
*
|
|
194
|
+
* Columns are laid out here and nowhere else, so the drawn table and the plain
|
|
195
|
+
* one are the same table: a cell's width is the length of its text, which is
|
|
196
|
+
* what a `Span` measures whatever styling rides beside it. Nothing a model
|
|
197
|
+
* writes in a cell can move the cell after it.
|
|
198
|
+
*/
|
|
199
|
+
export declare function gridOf(block: Block): Span[][];
|
|
200
|
+
/**
|
|
201
|
+
* A block as the row or rows it reads as, with its markers resolved rather
|
|
202
|
+
* than shown, and nothing styled.
|
|
203
|
+
*
|
|
204
|
+
* This is what a sink that cannot style gets — the pre-answer stream, and the
|
|
205
|
+
* plain box `zen meta` draws — so that the text does not visibly change shape
|
|
206
|
+
* at the moment it settles.
|
|
102
207
|
*/
|
|
103
|
-
export declare function
|
|
208
|
+
export declare function textOf(block: Block, width?: number): string;
|
|
209
|
+
/** A whole answer with its markup resolved instead of shown. Still plain text. */
|
|
210
|
+
export declare function unmarked(text: string, width?: number): string;
|
|
104
211
|
//# sourceMappingURL=wrap.d.ts.map
|