@alisio/alisio-code 0.1.0-alpha.15 → 0.1.0-alpha.17
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/tui/app.js +84 -13
- package/dist/tui/components.d.ts +71 -11
- package/dist/tui/components.js +465 -57
- package/dist/tui/state.d.ts +166 -1
- package/dist/tui/state.js +429 -12
- package/dist/tui/theme.d.ts +42 -1
- package/dist/tui/theme.js +516 -1
- package/package.json +4 -4
package/dist/tui/theme.js
CHANGED
|
@@ -17,8 +17,521 @@ export const style = {
|
|
|
17
17
|
userBg: sgr("48;5;236", 49),
|
|
18
18
|
};
|
|
19
19
|
export const levelColor = (level) => level === "ok" ? style.green : level === "warn" ? style.yellow : style.red;
|
|
20
|
+
const TS_KEYWORDS = new Set([
|
|
21
|
+
"abstract",
|
|
22
|
+
"as",
|
|
23
|
+
"async",
|
|
24
|
+
"await",
|
|
25
|
+
"break",
|
|
26
|
+
"case",
|
|
27
|
+
"catch",
|
|
28
|
+
"class",
|
|
29
|
+
"const",
|
|
30
|
+
"constructor",
|
|
31
|
+
"continue",
|
|
32
|
+
"debugger",
|
|
33
|
+
"declare",
|
|
34
|
+
"default",
|
|
35
|
+
"delete",
|
|
36
|
+
"do",
|
|
37
|
+
"else",
|
|
38
|
+
"enum",
|
|
39
|
+
"export",
|
|
40
|
+
"extends",
|
|
41
|
+
"false",
|
|
42
|
+
"finally",
|
|
43
|
+
"for",
|
|
44
|
+
"from",
|
|
45
|
+
"function",
|
|
46
|
+
"get",
|
|
47
|
+
"if",
|
|
48
|
+
"implements",
|
|
49
|
+
"import",
|
|
50
|
+
"in",
|
|
51
|
+
"instanceof",
|
|
52
|
+
"interface",
|
|
53
|
+
"is",
|
|
54
|
+
"keyof",
|
|
55
|
+
"let",
|
|
56
|
+
"namespace",
|
|
57
|
+
"new",
|
|
58
|
+
"never",
|
|
59
|
+
"null",
|
|
60
|
+
"of",
|
|
61
|
+
"override",
|
|
62
|
+
"private",
|
|
63
|
+
"protected",
|
|
64
|
+
"public",
|
|
65
|
+
"readonly",
|
|
66
|
+
"return",
|
|
67
|
+
"satisfies",
|
|
68
|
+
"set",
|
|
69
|
+
"static",
|
|
70
|
+
"super",
|
|
71
|
+
"switch",
|
|
72
|
+
"this",
|
|
73
|
+
"throw",
|
|
74
|
+
"true",
|
|
75
|
+
"try",
|
|
76
|
+
"type",
|
|
77
|
+
"typeof",
|
|
78
|
+
"unknown",
|
|
79
|
+
"using",
|
|
80
|
+
"var",
|
|
81
|
+
"void",
|
|
82
|
+
"while",
|
|
83
|
+
"with",
|
|
84
|
+
"yield",
|
|
85
|
+
]);
|
|
86
|
+
const PYTHON_KEYWORDS = new Set([
|
|
87
|
+
"and",
|
|
88
|
+
"as",
|
|
89
|
+
"assert",
|
|
90
|
+
"async",
|
|
91
|
+
"await",
|
|
92
|
+
"break",
|
|
93
|
+
"case",
|
|
94
|
+
"class",
|
|
95
|
+
"continue",
|
|
96
|
+
"def",
|
|
97
|
+
"del",
|
|
98
|
+
"elif",
|
|
99
|
+
"else",
|
|
100
|
+
"except",
|
|
101
|
+
"False",
|
|
102
|
+
"finally",
|
|
103
|
+
"for",
|
|
104
|
+
"from",
|
|
105
|
+
"global",
|
|
106
|
+
"if",
|
|
107
|
+
"import",
|
|
108
|
+
"in",
|
|
109
|
+
"is",
|
|
110
|
+
"lambda",
|
|
111
|
+
"match",
|
|
112
|
+
"None",
|
|
113
|
+
"nonlocal",
|
|
114
|
+
"not",
|
|
115
|
+
"or",
|
|
116
|
+
"pass",
|
|
117
|
+
"raise",
|
|
118
|
+
"return",
|
|
119
|
+
"True",
|
|
120
|
+
"try",
|
|
121
|
+
"while",
|
|
122
|
+
"with",
|
|
123
|
+
"yield",
|
|
124
|
+
]);
|
|
125
|
+
const SHELL_KEYWORDS = new Set([
|
|
126
|
+
"alias",
|
|
127
|
+
"break",
|
|
128
|
+
"case",
|
|
129
|
+
"continue",
|
|
130
|
+
"do",
|
|
131
|
+
"done",
|
|
132
|
+
"elif",
|
|
133
|
+
"else",
|
|
134
|
+
"esac",
|
|
135
|
+
"exit",
|
|
136
|
+
"export",
|
|
137
|
+
"fi",
|
|
138
|
+
"for",
|
|
139
|
+
"function",
|
|
140
|
+
"if",
|
|
141
|
+
"in",
|
|
142
|
+
"local",
|
|
143
|
+
"readonly",
|
|
144
|
+
"return",
|
|
145
|
+
"select",
|
|
146
|
+
"set",
|
|
147
|
+
"shift",
|
|
148
|
+
"source",
|
|
149
|
+
"then",
|
|
150
|
+
"time",
|
|
151
|
+
"true",
|
|
152
|
+
"false",
|
|
153
|
+
"until",
|
|
154
|
+
"while",
|
|
155
|
+
]);
|
|
156
|
+
const CSS_KEYWORDS = new Set([
|
|
157
|
+
"@charset",
|
|
158
|
+
"@font-face",
|
|
159
|
+
"@import",
|
|
160
|
+
"@keyframes",
|
|
161
|
+
"@layer",
|
|
162
|
+
"@media",
|
|
163
|
+
"@namespace",
|
|
164
|
+
"@page",
|
|
165
|
+
"@supports",
|
|
166
|
+
"important",
|
|
167
|
+
]);
|
|
168
|
+
/** Standalone words highlighted in HTML (tags themselves are matched structurally). */
|
|
169
|
+
const HTML_WORDS = new Set([]);
|
|
170
|
+
/** Rules used for TS/JS and as the fallback for unknown language tags. */
|
|
171
|
+
const TS_RULES = {
|
|
172
|
+
keywords: TS_KEYWORDS,
|
|
173
|
+
lineComment: "//",
|
|
174
|
+
blockComment: ["/*", "*/"],
|
|
175
|
+
strings: ['"', "'", "`"],
|
|
176
|
+
};
|
|
177
|
+
const LANG_RULES = {
|
|
178
|
+
ts: TS_RULES,
|
|
179
|
+
js: TS_RULES,
|
|
180
|
+
json: {
|
|
181
|
+
keywords: new Set(["true", "false", "null"]),
|
|
182
|
+
lineComment: "//",
|
|
183
|
+
blockComment: ["/*", "*/"],
|
|
184
|
+
strings: ['"', "'"],
|
|
185
|
+
keyString: true,
|
|
186
|
+
},
|
|
187
|
+
python: {
|
|
188
|
+
keywords: PYTHON_KEYWORDS,
|
|
189
|
+
lineComment: "#",
|
|
190
|
+
strings: ['"', "'"],
|
|
191
|
+
triple: ['"""', "'''"],
|
|
192
|
+
defNames: true,
|
|
193
|
+
decorators: true,
|
|
194
|
+
prefixedStrings: true,
|
|
195
|
+
},
|
|
196
|
+
bash: {
|
|
197
|
+
keywords: SHELL_KEYWORDS,
|
|
198
|
+
lineComment: "#",
|
|
199
|
+
strings: ['"', "'"],
|
|
200
|
+
dollarVars: true,
|
|
201
|
+
eqKey: true,
|
|
202
|
+
},
|
|
203
|
+
sh: {
|
|
204
|
+
keywords: SHELL_KEYWORDS,
|
|
205
|
+
lineComment: "#",
|
|
206
|
+
strings: ['"', "'"],
|
|
207
|
+
dollarVars: true,
|
|
208
|
+
eqKey: true,
|
|
209
|
+
},
|
|
210
|
+
yaml: {
|
|
211
|
+
keywords: new Set(["true", "false", "yes", "no", "on", "off", "null"]),
|
|
212
|
+
lineComment: "#",
|
|
213
|
+
strings: ['"', "'"],
|
|
214
|
+
colonKey: true,
|
|
215
|
+
},
|
|
216
|
+
css: {
|
|
217
|
+
keywords: CSS_KEYWORDS,
|
|
218
|
+
blockComment: ["/*", "*/"],
|
|
219
|
+
strings: ['"', "'"],
|
|
220
|
+
colonKey: true,
|
|
221
|
+
hexColors: true,
|
|
222
|
+
atWord: true,
|
|
223
|
+
},
|
|
224
|
+
html: {
|
|
225
|
+
keywords: HTML_WORDS,
|
|
226
|
+
blockComment: ["<!--", "-->"],
|
|
227
|
+
strings: ['"', "'"],
|
|
228
|
+
html: true,
|
|
229
|
+
eqKey: true,
|
|
230
|
+
hexColors: true,
|
|
231
|
+
},
|
|
232
|
+
md: { keywords: new Set(), strings: ["`"], headings: true },
|
|
233
|
+
};
|
|
234
|
+
const LANG_ALIASES = {
|
|
235
|
+
typescript: "ts",
|
|
236
|
+
tsx: "ts",
|
|
237
|
+
javascript: "js",
|
|
238
|
+
jsx: "js",
|
|
239
|
+
node: "js",
|
|
240
|
+
jsonc: "json",
|
|
241
|
+
json5: "json",
|
|
242
|
+
shell: "bash",
|
|
243
|
+
zsh: "bash",
|
|
244
|
+
python3: "python",
|
|
245
|
+
py: "python",
|
|
246
|
+
yml: "yaml",
|
|
247
|
+
markdown: "md",
|
|
248
|
+
};
|
|
249
|
+
/** Unknown or missing language tags fall back to TypeScript rules (closest to plain code). */
|
|
250
|
+
const rulesFor = (lang) => {
|
|
251
|
+
const base = (lang ?? "")
|
|
252
|
+
.trim()
|
|
253
|
+
.toLowerCase()
|
|
254
|
+
.split(/[\s.]+/)[0] ?? "";
|
|
255
|
+
return LANG_RULES[LANG_ALIASES[base] ?? base] ?? TS_RULES;
|
|
256
|
+
};
|
|
257
|
+
/** Strips ANSI escapes, OSC sequences and control characters; normalizes tabs. */
|
|
258
|
+
export function sanitizeCode(code) {
|
|
259
|
+
return code
|
|
260
|
+
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "")
|
|
261
|
+
.replace(/\x1b\[[0-9;?]*[ -/]*[@-~]/g, "")
|
|
262
|
+
.replace(/\x1b[()][0-9A-Za-z]/g, "")
|
|
263
|
+
.replace(/\x1b/g, "")
|
|
264
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000D\u000E-\u001F\u007F]/g, "")
|
|
265
|
+
.replace(/\t/g, " ");
|
|
266
|
+
}
|
|
267
|
+
function scanLine(line, rules, state) {
|
|
268
|
+
const out = [];
|
|
269
|
+
const len = line.length;
|
|
270
|
+
const push = (text, style) => {
|
|
271
|
+
if (text)
|
|
272
|
+
out.push({ text, style });
|
|
273
|
+
};
|
|
274
|
+
/** Finds the unescaped closing delimiter of a string starting at `from`. */
|
|
275
|
+
const scanString = (from, delimiter) => {
|
|
276
|
+
let j = from;
|
|
277
|
+
while (j < len) {
|
|
278
|
+
if (line[j] === "\\") {
|
|
279
|
+
j += 2;
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (line.startsWith(delimiter, j))
|
|
283
|
+
return { end: j + delimiter.length, closed: true };
|
|
284
|
+
j++;
|
|
285
|
+
}
|
|
286
|
+
return { end: len, closed: false };
|
|
287
|
+
};
|
|
288
|
+
let i = 0;
|
|
289
|
+
// Continue a multi-line string opened on a previous line.
|
|
290
|
+
if (state.inString) {
|
|
291
|
+
const end = line.indexOf(state.inString);
|
|
292
|
+
if (end < 0) {
|
|
293
|
+
push(line, "string");
|
|
294
|
+
return out;
|
|
295
|
+
}
|
|
296
|
+
push(line.slice(0, end + state.inString.length), "string");
|
|
297
|
+
i = end + state.inString.length;
|
|
298
|
+
state.inString = undefined;
|
|
299
|
+
}
|
|
300
|
+
// Continue a block comment opened on a previous line.
|
|
301
|
+
if (state.inComment) {
|
|
302
|
+
const end = line.indexOf(state.inComment);
|
|
303
|
+
if (end < 0) {
|
|
304
|
+
push(line, "comment");
|
|
305
|
+
return out;
|
|
306
|
+
}
|
|
307
|
+
push(line.slice(0, end + state.inComment.length), "comment");
|
|
308
|
+
i = end + state.inComment.length;
|
|
309
|
+
state.inComment = undefined;
|
|
310
|
+
}
|
|
311
|
+
while (i < len) {
|
|
312
|
+
const rem = line.slice(i);
|
|
313
|
+
// Markdown headings: color the `#` marker run (approximate; only at the start of a line).
|
|
314
|
+
if (rules.headings && /^#{1,6}[ \t]/.test(rem)) {
|
|
315
|
+
const m = /^#{1,6}/.exec(rem);
|
|
316
|
+
push(m?.[0] ?? "", "keyword");
|
|
317
|
+
push(rem.slice(m?.[0].length ?? 0), "plain");
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
const ws = /^ +/.exec(rem);
|
|
321
|
+
if (ws) {
|
|
322
|
+
push(ws[0], "plain");
|
|
323
|
+
i += ws[0].length;
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
if (rules.triple) {
|
|
327
|
+
const delim = rules.triple.find((d) => rem.startsWith(d));
|
|
328
|
+
if (delim) {
|
|
329
|
+
const end = line.indexOf(delim, i + delim.length);
|
|
330
|
+
if (end >= 0) {
|
|
331
|
+
push(line.slice(i, end + delim.length), "string");
|
|
332
|
+
i = end + delim.length;
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
push(line.slice(i), "string");
|
|
336
|
+
state.inString = delim;
|
|
337
|
+
i = len;
|
|
338
|
+
}
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
// Escape-aware quoted strings, with optional Python-style prefixes (`f"..."`, `r"..."`).
|
|
343
|
+
const anyQuote = () => {
|
|
344
|
+
for (const d of rules.strings) {
|
|
345
|
+
if (rem.startsWith(d)) {
|
|
346
|
+
const scan = scanString(i + d.length, d);
|
|
347
|
+
return { quote: d, from: i, closed: scan.closed, end: scan.end };
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (rules.prefixedStrings) {
|
|
351
|
+
const pm = /^(?:[fF][rR]?|[rR][fF]?|[bB]|[uU])(["'])/.exec(rem);
|
|
352
|
+
if (pm?.[1] && rules.strings.includes(pm[1])) {
|
|
353
|
+
const scan = scanString(i + pm[0].length, pm[1]);
|
|
354
|
+
return { quote: pm[1], from: i, closed: scan.closed, end: scan.end };
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return undefined;
|
|
358
|
+
};
|
|
359
|
+
const str = anyQuote();
|
|
360
|
+
if (str) {
|
|
361
|
+
const key = rules.keyString && /^\s*:/.test(line.slice(str.end));
|
|
362
|
+
push(line.slice(str.from, str.end), key ? "property" : "string");
|
|
363
|
+
i = str.end;
|
|
364
|
+
if (!str.closed && str.quote === "`")
|
|
365
|
+
state.inString = str.quote;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (rules.lineComment && rem.startsWith(rules.lineComment)) {
|
|
369
|
+
push(rem, "comment");
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
if (rules.blockComment && rem.startsWith(rules.blockComment[0])) {
|
|
373
|
+
const end = line.indexOf(rules.blockComment[1], i + rules.blockComment[0].length);
|
|
374
|
+
if (end >= 0) {
|
|
375
|
+
push(line.slice(i, end + rules.blockComment[1].length), "comment");
|
|
376
|
+
i = end + rules.blockComment[1].length;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
push(line.slice(i), "comment");
|
|
380
|
+
state.inComment = rules.blockComment[1];
|
|
381
|
+
i = len;
|
|
382
|
+
}
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
385
|
+
if (rules.dollarVars && rem.startsWith("$")) {
|
|
386
|
+
const m = /^\$(?:\{[^}]*\}|\d+|[A-Za-z_][\w]*)/.exec(rem);
|
|
387
|
+
if (m) {
|
|
388
|
+
push(m[0], "number");
|
|
389
|
+
i += m[0].length;
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (rules.decorators && rem.startsWith("@")) {
|
|
394
|
+
const m = /^@[A-Za-z_][\w]*/.exec(rem);
|
|
395
|
+
if (m) {
|
|
396
|
+
push("@", "plain");
|
|
397
|
+
push(m[0].slice(1), "function");
|
|
398
|
+
i += m[0].length;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (rules.atWord && rem.startsWith("@")) {
|
|
403
|
+
const m = /^@[A-Za-z-][\w-]*/.exec(rem);
|
|
404
|
+
if (m) {
|
|
405
|
+
push(m[0], "keyword");
|
|
406
|
+
i += m[0].length;
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (rules.html) {
|
|
411
|
+
const tag = /^<\/?[A-Za-z][\w-]*/.exec(rem);
|
|
412
|
+
if (tag && tag[0].length > 1) {
|
|
413
|
+
push(tag[0], "keyword");
|
|
414
|
+
i += tag[0].length;
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (rules.hexColors && rem.startsWith("#")) {
|
|
419
|
+
const m = /^#[0-9a-fA-F]{3,8}\b/.exec(rem);
|
|
420
|
+
if (m) {
|
|
421
|
+
push(m[0], "number");
|
|
422
|
+
i += m[0].length;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
const num = /^(?:0[xX][0-9a-fA-F]+|0[bB][01]+|\d[\d_]*(?:\.\d+)?(?:[eE][+-]?\d+)?)/.exec(rem);
|
|
427
|
+
if (num) {
|
|
428
|
+
push(num[0], "number");
|
|
429
|
+
i += num[0].length;
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
const word = /^[A-Za-z_$][\w$]*/.exec(rem);
|
|
433
|
+
if (word) {
|
|
434
|
+
const w = word[0];
|
|
435
|
+
const rest = line.slice(i + w.length);
|
|
436
|
+
const prevWord = out.at(-1)?.text;
|
|
437
|
+
if (rules.keywords.has(w))
|
|
438
|
+
push(w, "keyword");
|
|
439
|
+
else if (rules.defNames && (prevWord === "def" || prevWord === "class"))
|
|
440
|
+
push(w, "function");
|
|
441
|
+
else if (/^\(/.test(rest))
|
|
442
|
+
push(w, "function");
|
|
443
|
+
else if (rules.eqKey && /^=/.test(rest))
|
|
444
|
+
push(w, "property");
|
|
445
|
+
else if (rules.colonKey && /^:/.test(rest))
|
|
446
|
+
push(w, "property");
|
|
447
|
+
else
|
|
448
|
+
push(w, "plain");
|
|
449
|
+
i += w.length;
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
push(line[i] ?? "", "plain");
|
|
453
|
+
i++;
|
|
454
|
+
}
|
|
455
|
+
return out;
|
|
456
|
+
}
|
|
457
|
+
/** Tokenizes code into styled segments, maintaining multi-line string/comment state. */
|
|
458
|
+
export function tokenizeCode(code, lang) {
|
|
459
|
+
const rules = rulesFor(lang);
|
|
460
|
+
const state = {};
|
|
461
|
+
return sanitizeCode(code)
|
|
462
|
+
.split("\n")
|
|
463
|
+
.map((line) => scanLine(line, rules, state));
|
|
464
|
+
}
|
|
465
|
+
const TOKEN_PAINT = {
|
|
466
|
+
keyword: (t) => style.bold(style.magenta(t)),
|
|
467
|
+
string: (t) => style.green(t),
|
|
468
|
+
comment: (t) => style.gray(style.italic(t)),
|
|
469
|
+
number: (t) => style.yellow(t),
|
|
470
|
+
function: (t) => style.cyan(t),
|
|
471
|
+
property: (t) => style.brightCyan(t),
|
|
472
|
+
plain: (t) => t,
|
|
473
|
+
};
|
|
474
|
+
/**
|
|
475
|
+
* Per-line highlighting for markdown code blocks (pi-tui `MarkdownTheme.highlightCode`).
|
|
476
|
+
* Returns one styled (or plain, under NO_COLOR) line per source line; never emits ANSI for
|
|
477
|
+
* bytes that came from the input.
|
|
478
|
+
*/
|
|
479
|
+
export function highlightCode(code, lang) {
|
|
480
|
+
const lines = tokenizeCode(code, lang);
|
|
481
|
+
if (process.env.NO_COLOR !== undefined)
|
|
482
|
+
return lines.map((tokens) => tokens.map((t) => t.text).join(""));
|
|
483
|
+
return lines.map((tokens) => tokens.map((t) => (t.style === "plain" ? t.text : TOKEN_PAINT[t.style](t.text))).join(""));
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Normalizes table separator rows so models' sloppy ASCII art still renders as aligned tables:
|
|
487
|
+
* em/en/box dashes become plain `-` runs (marked's table tokenizer only accepts `-`), while
|
|
488
|
+
* alignment colons are preserved. Anything that is not an obvious separator row, including
|
|
489
|
+
* fenced or indented code, is left untouched. A bare `---` (horizontal rule / setext) has no
|
|
490
|
+
* `|` and is never touched.
|
|
491
|
+
*/
|
|
492
|
+
export function normalizeTableSeparators(markdown) {
|
|
493
|
+
const out = [];
|
|
494
|
+
let fence;
|
|
495
|
+
for (const line of markdown.split("\n")) {
|
|
496
|
+
const fenceMatch = /^ {0,3}(`{3,}|~{3,})/.exec(line);
|
|
497
|
+
if (fenceMatch) {
|
|
498
|
+
const marker = fenceMatch[1]?.[0] ?? "";
|
|
499
|
+
if (!fence)
|
|
500
|
+
fence = marker;
|
|
501
|
+
else if (fenceMatch[1]?.startsWith(fence))
|
|
502
|
+
fence = undefined;
|
|
503
|
+
out.push(line);
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
if (!fence && isTableSeparator(line)) {
|
|
507
|
+
out.push(line.replace(/(:)?[-—–─]+(:)?/g, (_m, left, right) => `${left ?? ""}---${right ?? ""}`));
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
out.push(line);
|
|
511
|
+
}
|
|
512
|
+
return out.join("\n");
|
|
513
|
+
}
|
|
514
|
+
function isTableSeparator(line) {
|
|
515
|
+
if (!line.includes("|") || /^ {4}/.test(line))
|
|
516
|
+
return false;
|
|
517
|
+
const cells = line.split("|");
|
|
518
|
+
let dashes = 0;
|
|
519
|
+
for (const cell of cells) {
|
|
520
|
+
const c = cell.trim();
|
|
521
|
+
if (c === "")
|
|
522
|
+
continue;
|
|
523
|
+
if (!/^:?[-—–─]+:?$/.test(c))
|
|
524
|
+
return false;
|
|
525
|
+
dashes++;
|
|
526
|
+
}
|
|
527
|
+
return dashes > 0;
|
|
528
|
+
}
|
|
529
|
+
/** Pre-parse hook for the Markdown component: normalizes table separators before marked parses. */
|
|
530
|
+
export const markdownTransform = (markdown, _availableWidth) => normalizeTableSeparators(markdown);
|
|
531
|
+
/** Subtle base tone for response body text; inline styles override it. */
|
|
532
|
+
export const markdownDefaultTextStyle = { color: (t) => style.gray(t) };
|
|
20
533
|
export const markdownTheme = {
|
|
21
|
-
heading: (t) => style.bold(style.
|
|
534
|
+
heading: (t) => style.bold(style.brightCyan(t)),
|
|
22
535
|
link: (t) => style.underline(style.blue(t)),
|
|
23
536
|
linkUrl: (t) => style.dim(t),
|
|
24
537
|
code: (t) => style.yellow(t),
|
|
@@ -32,6 +545,8 @@ export const markdownTheme = {
|
|
|
32
545
|
italic: (t) => style.italic(t),
|
|
33
546
|
strikethrough: (t) => style.strike(t),
|
|
34
547
|
underline: (t) => style.underline(t),
|
|
548
|
+
highlightCode,
|
|
549
|
+
codeBlockIndent: " ",
|
|
35
550
|
};
|
|
36
551
|
export const selectListTheme = {
|
|
37
552
|
selectedPrefix: (t) => style.cyan(t),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alisio/alisio-code",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.17",
|
|
4
4
|
"description": "Alisio: an extensible, provider-agnostic coding-agent harness for your terminal. TUI, OpenAI-compatible providers, permissioned local tools, context compaction, persistent memory and a typed plugin SDK.",
|
|
5
5
|
"author": "Gustavo Gutiérrez",
|
|
6
6
|
"license": "MIT",
|
|
@@ -45,14 +45,14 @@
|
|
|
45
45
|
"alisio": "./dist/main.js"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@alisio/core": "0.1.0-alpha.
|
|
48
|
+
"@alisio/core": "0.1.0-alpha.15",
|
|
49
49
|
"@alisio/plugin-deepseek": "0.1.0-alpha.10",
|
|
50
|
-
"@alisio/plugin-memory": "0.1.0-alpha.
|
|
50
|
+
"@alisio/plugin-memory": "0.1.0-alpha.8",
|
|
51
51
|
"@alisio/plugin-openai-compatible": "0.1.0-alpha.9",
|
|
52
52
|
"@alisio/plugin-opencode": "0.1.0-alpha.8",
|
|
53
53
|
"@alisio/plugin-opencode-go": "0.1.0-alpha.8",
|
|
54
54
|
"@alisio/plugin-subagents": "0.1.0-alpha.9",
|
|
55
|
-
"@alisio/sdk": "0.1.0-alpha.
|
|
55
|
+
"@alisio/sdk": "0.1.0-alpha.10",
|
|
56
56
|
"@earendil-works/pi-tui": "0.87.1",
|
|
57
57
|
"commander": "15.0.0"
|
|
58
58
|
},
|