codeep 2.14.0 → 2.16.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/README.md +47 -27
- package/dist/acp/commands.js +22 -1
- package/dist/acp/server.js +13 -2
- package/dist/acp/session.js +22 -1
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.js +2 -2
- package/dist/config/providers.js +35 -24
- package/dist/renderer/App.d.ts +77 -30
- package/dist/renderer/App.js +429 -659
- package/dist/renderer/agentExecution.d.ts +1 -0
- package/dist/renderer/agentExecution.js +3 -2
- package/dist/renderer/commands/helpers.d.ts +251 -0
- package/dist/renderer/commands/helpers.js +450 -0
- package/dist/renderer/commands/registry.js +7 -1
- package/dist/renderer/commands.d.ts +4 -0
- package/dist/renderer/commands.js +363 -318
- package/dist/renderer/components/ActionFormatting.d.ts +17 -0
- package/dist/renderer/components/ActionFormatting.js +67 -0
- package/dist/renderer/components/Autocomplete.d.ts +58 -0
- package/dist/renderer/components/Autocomplete.js +75 -0
- package/dist/renderer/components/Intro.d.ts +9 -0
- package/dist/renderer/components/Intro.js +5 -15
- package/dist/renderer/components/MessageFormatter.d.ts +96 -0
- package/dist/renderer/components/MessageFormatter.js +375 -0
- package/dist/renderer/components/Permission.d.ts +4 -0
- package/dist/renderer/components/Permission.js +1 -1
- package/dist/renderer/components/Status.d.ts +4 -0
- package/dist/renderer/components/Status.js +2 -3
- package/dist/renderer/components/WelcomeFormatter.d.ts +19 -0
- package/dist/renderer/components/WelcomeFormatter.js +79 -0
- package/dist/renderer/components/uiConstants.d.ts +8 -0
- package/dist/renderer/components/uiConstants.js +24 -0
- package/dist/renderer/inputParsing.d.ts +22 -0
- package/dist/renderer/inputParsing.js +28 -0
- package/dist/renderer/layout.d.ts +219 -0
- package/dist/renderer/layout.js +338 -0
- package/dist/renderer/main.d.ts +2 -1
- package/dist/renderer/main.js +79 -11
- package/dist/renderer/ollamaHint.d.ts +12 -0
- package/dist/renderer/ollamaHint.js +29 -0
- package/dist/utils/agentChat.js +23 -1
- package/dist/utils/codeepCloud.d.ts +54 -0
- package/dist/utils/codeepCloud.js +95 -0
- package/dist/utils/diffPreview.d.ts +31 -0
- package/dist/utils/diffPreview.js +102 -0
- package/dist/utils/export.d.ts +12 -0
- package/dist/utils/export.js +3 -3
- package/dist/utils/git.d.ts +28 -0
- package/dist/utils/git.js +111 -1
- package/dist/utils/hooks.d.ts +26 -0
- package/dist/utils/hooks.js +69 -1
- package/dist/utils/keychain.js +45 -29
- package/dist/utils/logger.d.ts +12 -0
- package/dist/utils/logger.js +1 -1
- package/dist/utils/mcpConfig.d.ts +26 -0
- package/dist/utils/mcpConfig.js +109 -4
- package/dist/utils/mentions.d.ts +195 -0
- package/dist/utils/mentions.js +672 -0
- package/dist/utils/skillBundles.d.ts +14 -0
- package/dist/utils/skillBundles.js +3 -3
- package/dist/utils/skillBundlesCloud.d.ts +7 -0
- package/dist/utils/skillBundlesCloud.js +1 -1
- package/dist/utils/tokenTracker.js +21 -5
- package/dist/utils/toolParsing.d.ts +11 -0
- package/dist/utils/toolParsing.js +6 -0
- package/dist/utils/webFetch.d.ts +101 -0
- package/dist/utils/webFetch.js +375 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour per action kind. Falls back to plain white for unknown kinds so
|
|
3
|
+
* a new tool type degrades gracefully (visible, just uncoloured) instead
|
|
4
|
+
* of throwing.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getActionColor(type: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Shorten a file path for single-line display. Paths with 3+ segments
|
|
9
|
+
* keep their last two (parent dir + filename); longer paths get a leading
|
|
10
|
+
* `...`. The result is capped to `maxLen`, truncating from the left.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatActionTarget(target: string, maxLen: number): string;
|
|
13
|
+
/**
|
|
14
|
+
* Present-tense label for an action kind. Falls back to the raw `type`
|
|
15
|
+
* for unknown kinds.
|
|
16
|
+
*/
|
|
17
|
+
export declare function getActionLabel(type: string): string;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Action display helpers for the agent progress panel.
|
|
3
|
+
*
|
|
4
|
+
* Pure functions extracted from `App.ts` so they can be unit-tested in
|
|
5
|
+
* isolation. `getActionColor` / `getActionLabel` map an action `type`
|
|
6
|
+
* (read/write/edit/delete/command/...) to its colour and present-tense
|
|
7
|
+
* label; `formatActionTarget` shortens a file path to fit a column.
|
|
8
|
+
*/
|
|
9
|
+
import { fg } from '../ansi.js';
|
|
10
|
+
/**
|
|
11
|
+
* Colour per action kind. Falls back to plain white for unknown kinds so
|
|
12
|
+
* a new tool type degrades gracefully (visible, just uncoloured) instead
|
|
13
|
+
* of throwing.
|
|
14
|
+
*/
|
|
15
|
+
export function getActionColor(type) {
|
|
16
|
+
const colors = {
|
|
17
|
+
'read': fg.blue,
|
|
18
|
+
'write': fg.green,
|
|
19
|
+
'edit': fg.yellow,
|
|
20
|
+
'delete': fg.red,
|
|
21
|
+
'command': fg.magenta,
|
|
22
|
+
'search': fg.cyan,
|
|
23
|
+
'list': fg.white,
|
|
24
|
+
'mkdir': fg.blue,
|
|
25
|
+
'fetch': fg.cyan,
|
|
26
|
+
};
|
|
27
|
+
return colors[type] || fg.white;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Shorten a file path for single-line display. Paths with 3+ segments
|
|
31
|
+
* keep their last two (parent dir + filename); longer paths get a leading
|
|
32
|
+
* `...`. The result is capped to `maxLen`, truncating from the left.
|
|
33
|
+
*/
|
|
34
|
+
export function formatActionTarget(target, maxLen) {
|
|
35
|
+
if (target.includes('/')) {
|
|
36
|
+
const parts = target.split('/');
|
|
37
|
+
const filename = parts[parts.length - 1];
|
|
38
|
+
if (parts.length > 2) {
|
|
39
|
+
const short = `.../${parts[parts.length - 2]}/${filename}`;
|
|
40
|
+
if (short.length <= maxLen)
|
|
41
|
+
return short;
|
|
42
|
+
// Still too long: keep the filename and RE-ADD the `...` marker —
|
|
43
|
+
// a bare slice from the right would cut the marker mid-way and the
|
|
44
|
+
// result would no longer signal that it was truncated.
|
|
45
|
+
return '...' + short.slice(-(maxLen - 3));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return target.length > maxLen ? '...' + target.slice(-(maxLen - 3)) : target;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Present-tense label for an action kind. Falls back to the raw `type`
|
|
52
|
+
* for unknown kinds.
|
|
53
|
+
*/
|
|
54
|
+
export function getActionLabel(type) {
|
|
55
|
+
const labels = {
|
|
56
|
+
'read': 'Reading',
|
|
57
|
+
'write': 'Creating',
|
|
58
|
+
'edit': 'Editing',
|
|
59
|
+
'delete': 'Deleting',
|
|
60
|
+
'command': 'Running',
|
|
61
|
+
'search': 'Searching',
|
|
62
|
+
'list': 'Listing',
|
|
63
|
+
'mkdir': 'Creating dir',
|
|
64
|
+
'fetch': 'Fetching',
|
|
65
|
+
};
|
|
66
|
+
return labels[type] || type;
|
|
67
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocomplete logic for the `/`-command picker.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `App.ts` so the filter rule (prefix match, 8-item cap,
|
|
5
|
+
* only triggered for command-shaped input) can be unit-tested without
|
|
6
|
+
* the editor / render machinery.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Result of filtering a command list for the autocomplete dropdown.
|
|
10
|
+
* `null` means "autocomplete shouldn't be open" (the input isn't a
|
|
11
|
+
* command prefix, or there are no matches).
|
|
12
|
+
*/
|
|
13
|
+
export interface AutocompleteResult {
|
|
14
|
+
items: string[];
|
|
15
|
+
/** Always 0 on a fresh filter — the caller may move it via arrow keys. */
|
|
16
|
+
index: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Filter `commands` to those that start with the typed prefix and the
|
|
20
|
+
* dropdown should appear.
|
|
21
|
+
*
|
|
22
|
+
* Rules:
|
|
23
|
+
* - Input must start with `/` (a slash command).
|
|
24
|
+
* - Input must not contain a space (the user is still typing the
|
|
25
|
+
* command name, not an argument).
|
|
26
|
+
* - Match case-insensitively on the text after the `/`.
|
|
27
|
+
* - Cap at 8 results so the dropdown never grows past the panel.
|
|
28
|
+
*
|
|
29
|
+
* @param value The raw editor value (e.g. `/h`, `/lo`, `/hel world`).
|
|
30
|
+
* @param commands The full command-name list (from `COMMAND_DESCRIPTIONS`).
|
|
31
|
+
* @returns Match list, or `null` when the dropdown should be hidden.
|
|
32
|
+
*/
|
|
33
|
+
export declare function filterCommands(value: string, commands: string[]): AutocompleteResult | null;
|
|
34
|
+
/**
|
|
35
|
+
* The position and query of an in-progress `@mention`, or `null` when
|
|
36
|
+
* the cursor isn't inside a mention being typed.
|
|
37
|
+
*
|
|
38
|
+
* A mention is "in progress" when, scanning backwards from `cursorPos`:
|
|
39
|
+
* 1. We find an `@`.
|
|
40
|
+
* 2. Between `@` and the cursor there are only "path characters"
|
|
41
|
+
* (letters, digits, `/`, `.`, `_`, `-`, `\`) and no whitespace.
|
|
42
|
+
* 3. The `@` itself is at the start of the string OR preceded by a
|
|
43
|
+
* boundary char (space, `(`, `[`, …) — so `user@host` doesn't
|
|
44
|
+
* count. Mirrors `extractMentions` in `utils/mentions.ts`.
|
|
45
|
+
*/
|
|
46
|
+
export interface MentionQuery {
|
|
47
|
+
/** Start index of the `@` in the source string. */
|
|
48
|
+
atStart: number;
|
|
49
|
+
/** The text typed so far after the `@` (may be empty). */
|
|
50
|
+
query: string;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Detect whether the cursor sits inside an `@mention` being typed, and
|
|
54
|
+
* if so, return the query text (everything after `@`). Pure — no FS.
|
|
55
|
+
*
|
|
56
|
+
* Used by the autocomplete layer to know when to show the file picker.
|
|
57
|
+
*/
|
|
58
|
+
export declare function detectMentionQuery(text: string, cursorPos: number): MentionQuery | null;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autocomplete logic for the `/`-command picker.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `App.ts` so the filter rule (prefix match, 8-item cap,
|
|
5
|
+
* only triggered for command-shaped input) can be unit-tested without
|
|
6
|
+
* the editor / render machinery.
|
|
7
|
+
*/
|
|
8
|
+
import { MENTION_BOUNDARY } from '../../utils/mentions.js';
|
|
9
|
+
/**
|
|
10
|
+
* Filter `commands` to those that start with the typed prefix and the
|
|
11
|
+
* dropdown should appear.
|
|
12
|
+
*
|
|
13
|
+
* Rules:
|
|
14
|
+
* - Input must start with `/` (a slash command).
|
|
15
|
+
* - Input must not contain a space (the user is still typing the
|
|
16
|
+
* command name, not an argument).
|
|
17
|
+
* - Match case-insensitively on the text after the `/`.
|
|
18
|
+
* - Cap at 8 results so the dropdown never grows past the panel.
|
|
19
|
+
*
|
|
20
|
+
* @param value The raw editor value (e.g. `/h`, `/lo`, `/hel world`).
|
|
21
|
+
* @param commands The full command-name list (from `COMMAND_DESCRIPTIONS`).
|
|
22
|
+
* @returns Match list, or `null` when the dropdown should be hidden.
|
|
23
|
+
*/
|
|
24
|
+
export function filterCommands(value, commands) {
|
|
25
|
+
// Only show autocomplete while typing a command name.
|
|
26
|
+
if (!value.startsWith('/') || value.includes(' ')) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const query = value.slice(1).toLowerCase();
|
|
30
|
+
if (query.length === 0) {
|
|
31
|
+
// Empty query after the slash — the original App.ts code required
|
|
32
|
+
// `query.length > 0`, so an empty `/` keeps the dropdown closed.
|
|
33
|
+
return { items: [], index: 0 };
|
|
34
|
+
}
|
|
35
|
+
const items = commands
|
|
36
|
+
.filter((cmd) => cmd.startsWith(query))
|
|
37
|
+
.slice(0, 8);
|
|
38
|
+
if (items.length === 0)
|
|
39
|
+
return { items: [], index: 0 };
|
|
40
|
+
return { items, index: 0 };
|
|
41
|
+
}
|
|
42
|
+
const PATH_CHAR = /[A-Za-z0-9._\/\\-]/;
|
|
43
|
+
/**
|
|
44
|
+
* Detect whether the cursor sits inside an `@mention` being typed, and
|
|
45
|
+
* if so, return the query text (everything after `@`). Pure — no FS.
|
|
46
|
+
*
|
|
47
|
+
* Used by the autocomplete layer to know when to show the file picker.
|
|
48
|
+
*/
|
|
49
|
+
export function detectMentionQuery(text, cursorPos) {
|
|
50
|
+
if (cursorPos < 1 || cursorPos > text.length)
|
|
51
|
+
return null;
|
|
52
|
+
// Scan backwards from the cursor, collecting path chars until we hit `@`.
|
|
53
|
+
let i = cursorPos - 1;
|
|
54
|
+
let query = '';
|
|
55
|
+
while (i >= 0) {
|
|
56
|
+
const ch = text[i];
|
|
57
|
+
if (ch === '@') {
|
|
58
|
+
// Found the `@`. Check the preceding char is a boundary (or start).
|
|
59
|
+
// Boundary set mirrors `extractMentions` in `utils/mentions.ts`.
|
|
60
|
+
const before = i > 0 ? text[i - 1] : '';
|
|
61
|
+
// Keep in lockstep with `MENTION_RE`'s lookbehind in utils/mentions.ts.
|
|
62
|
+
// If this set is looser, the picker offers a completion the expander
|
|
63
|
+
// then refuses to treat as a mention and the file is never attached.
|
|
64
|
+
if (before === '' || MENTION_BOUNDARY.test(before)) {
|
|
65
|
+
return { atStart: i, query };
|
|
66
|
+
}
|
|
67
|
+
return null; // `@` not at a boundary → email/handle, not a mention.
|
|
68
|
+
}
|
|
69
|
+
if (!PATH_CHAR.test(ch))
|
|
70
|
+
return null; // hit a non-path char before `@`.
|
|
71
|
+
query = ch + query;
|
|
72
|
+
i--;
|
|
73
|
+
}
|
|
74
|
+
return null; // no `@` found before the cursor.
|
|
75
|
+
}
|
|
@@ -2,10 +2,19 @@
|
|
|
2
2
|
* Intro animation component - matches Ink version style
|
|
3
3
|
*/
|
|
4
4
|
import { Screen } from '../Screen';
|
|
5
|
+
export declare const GLITCH_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%&*<>?/;:[]=";
|
|
5
6
|
/**
|
|
6
7
|
* Show intro animation with decrypt effect
|
|
7
8
|
*/
|
|
8
9
|
export declare function showIntro(screen: Screen, duration?: number): Promise<void>;
|
|
10
|
+
/**
|
|
11
|
+
* Generate noise line (random glitch characters)
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateNoiseLine(original: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Get partially decrypted line based on progress
|
|
16
|
+
*/
|
|
17
|
+
export declare function getDecryptedLine(original: string, progress: number): string;
|
|
9
18
|
/**
|
|
10
19
|
* Quick version without animation (for fast startup)
|
|
11
20
|
*/
|
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Intro animation component - matches Ink version style
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
const LOGO = [
|
|
7
|
-
' ██████╗ ██████╗ ██████╗ ███████╗███████╗██████╗ ',
|
|
8
|
-
'██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗',
|
|
9
|
-
'██║ ██║ ██║██║ ██║█████╗ █████╗ ██████╔╝',
|
|
10
|
-
'██║ ██║ ██║██║ ██║██╔══╝ ██╔══╝ ██╔═══╝ ',
|
|
11
|
-
'╚██████╗╚██████╔╝██████╔╝███████╗███████╗██║ ',
|
|
12
|
-
' ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚══════╝╚═╝ ',
|
|
13
|
-
];
|
|
4
|
+
import { style } from '../ansi.js';
|
|
5
|
+
import { PRIMARY_COLOR, LOGO_LINES as LOGO } from './uiConstants.js';
|
|
14
6
|
const TAGLINE = 'Deep into Code.';
|
|
15
|
-
const GLITCH_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%&*<>?/;:[]=';
|
|
16
|
-
// Primary color: #f02a30 (Codeep red)
|
|
17
|
-
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
7
|
+
export const GLITCH_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@#$%&*<>?/;:[]=';
|
|
18
8
|
/**
|
|
19
9
|
* Show intro animation with decrypt effect
|
|
20
10
|
*/
|
|
@@ -68,7 +58,7 @@ export async function showIntro(screen, duration = 1500) {
|
|
|
68
58
|
/**
|
|
69
59
|
* Generate noise line (random glitch characters)
|
|
70
60
|
*/
|
|
71
|
-
function generateNoiseLine(original) {
|
|
61
|
+
export function generateNoiseLine(original) {
|
|
72
62
|
let result = '';
|
|
73
63
|
for (const char of original) {
|
|
74
64
|
if (char === ' ' && Math.random() > 0.1) {
|
|
@@ -83,7 +73,7 @@ function generateNoiseLine(original) {
|
|
|
83
73
|
/**
|
|
84
74
|
* Get partially decrypted line based on progress
|
|
85
75
|
*/
|
|
86
|
-
function getDecryptedLine(original, progress) {
|
|
76
|
+
export function getDecryptedLine(original, progress) {
|
|
87
77
|
let result = '';
|
|
88
78
|
for (let i = 0; i < original.length; i++) {
|
|
89
79
|
const char = original[i];
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message formatting utilities — extracted from `App.ts`.
|
|
3
|
+
*
|
|
4
|
+
* These are pure (or near-pure) functions that turn a chat message
|
|
5
|
+
* (`role` + raw `content`) into the array of styled lines the custom
|
|
6
|
+
* screen renderer paints. Extracting them:
|
|
7
|
+
*
|
|
8
|
+
* - shrinks `App.ts` (the 3.2k-LoC render-loop host) by ~600 LoC,
|
|
9
|
+
* - makes the formatter unit-testable in isolation (no App state),
|
|
10
|
+
* - lets the quick-chat / ACP surfaces reuse the same rendering if
|
|
11
|
+
* they ever need to paint formatted assistant output.
|
|
12
|
+
*
|
|
13
|
+
* Convention: a `RenderedLine` carries the already-ANSI-styled `text`
|
|
14
|
+
* plus a `raw` flag — when true, the screen writer must NOT apply the
|
|
15
|
+
* per-message default style (the line has its own colours baked in).
|
|
16
|
+
* This is how code blocks and headings keep their syntax-highlight
|
|
17
|
+
* palette instead of being washed by the body colour.
|
|
18
|
+
*/
|
|
19
|
+
export interface RenderedLine {
|
|
20
|
+
text: string;
|
|
21
|
+
style: string;
|
|
22
|
+
raw?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Mutable counter passed by reference into `formatMessage` so the caller
|
|
26
|
+
* (App, during a render pass) can keep a running code-block index across
|
|
27
|
+
* messages — that index is what `/copy [n]` refers to.
|
|
28
|
+
*
|
|
29
|
+
* Modelled as an object (not a return value) because `formatMessage`
|
|
30
|
+
* appends to an output array AND increments the counter; returning both
|
|
31
|
+
* would force every caller to thread a tuple through, and the render
|
|
32
|
+
* loop already mutates `this.codeBlockCounter` in place.
|
|
33
|
+
*/
|
|
34
|
+
export interface BlockCounter {
|
|
35
|
+
current: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Apply inline markdown formatting (bold, italic, inline code, strikethrough)
|
|
39
|
+
* to a single line. Returns the styled string plus a flag telling the caller
|
|
40
|
+
* whether any formatting was applied — the caller uses that to decide whether
|
|
41
|
+
* to mark the line `raw` (so the renderer doesn't double-apply the body colour).
|
|
42
|
+
*/
|
|
43
|
+
export declare function applyInlineMarkdown(text: string): {
|
|
44
|
+
formatted: string;
|
|
45
|
+
hasFormatting: boolean;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Word-wrap `text` to `maxWidth` columns. Words wider than `maxWidth`
|
|
49
|
+
* (typically long file paths with no spaces) are hard-broken across lines.
|
|
50
|
+
*
|
|
51
|
+
* Note: this is NOT the `wordWrap` exported from `ansi.ts` — that one
|
|
52
|
+
* lets over-width words overflow. This chat-flavoured variant slices
|
|
53
|
+
* them so a 200-char path doesn't blow out the right margin.
|
|
54
|
+
*/
|
|
55
|
+
export declare function wordWrap(text: string, maxWidth: number): string[];
|
|
56
|
+
/**
|
|
57
|
+
* Format a chunk of prose (text between code fences) into styled lines.
|
|
58
|
+
*
|
|
59
|
+
* Recognises, per line:
|
|
60
|
+
* - ATX headings (`#` … `######`)
|
|
61
|
+
* - horizontal rules (`---`, `***`, `___`)
|
|
62
|
+
* - blockquotes (`> …`, nestable)
|
|
63
|
+
* - bullet/numbered list items (`-`, `*`, `1.`)
|
|
64
|
+
* - plain text, with inline markdown + word-wrap
|
|
65
|
+
*
|
|
66
|
+
* `firstPrefix` / `firstStyle` apply only to the first output line — the
|
|
67
|
+
* caller uses that to attach the role indicator (▌ for user, ▸ for system);
|
|
68
|
+
* continuation lines get a blank/generic prefix so wrapped paragraphs stay
|
|
69
|
+
* visually grouped under the same marker.
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatTextLines(text: string, maxWidth: number, firstPrefix: string, firstStyle: string, rawPrefix?: boolean): RenderedLine[];
|
|
72
|
+
/**
|
|
73
|
+
* Format a fenced code block: language label + block number on the first
|
|
74
|
+
* line, then each source line indented and syntax-highlighted via
|
|
75
|
+
* `highlightCode`. A trailing blank line separates the block from the
|
|
76
|
+
* next paragraph.
|
|
77
|
+
*
|
|
78
|
+
* `blockNum` is the 1-based index used by `/copy [n]`; omitted when the
|
|
79
|
+
* caller is rendering a non-chat context (e.g. a paste preview).
|
|
80
|
+
*/
|
|
81
|
+
export declare function formatCodeBlock(code: string, lang: string, maxWidth: number, blockNum?: number): RenderedLine[];
|
|
82
|
+
/**
|
|
83
|
+
* Format a full chat message (role + content) into styled lines.
|
|
84
|
+
*
|
|
85
|
+
* Walks the content looking for `` ``` ``-fenced code blocks; anything
|
|
86
|
+
* outside a fence goes through `formatTextLines` (headings, lists, inline
|
|
87
|
+
* markdown), fenced regions go through `formatCodeBlock`. The fenced-block
|
|
88
|
+
* regex is non-greedy and stops at the first closing fence, so streaming
|
|
89
|
+
* input with an as-yet-unclosed fence still renders correctly (the open
|
|
90
|
+
* tail is treated as plain text until the closer arrives).
|
|
91
|
+
*
|
|
92
|
+
* `counter` is incremented once per fenced block encountered — callers
|
|
93
|
+
* thread the same `BlockCounter` across consecutive `formatMessage`
|
|
94
|
+
* calls so block numbers are stable across a whole render pass.
|
|
95
|
+
*/
|
|
96
|
+
export declare function formatMessage(role: 'user' | 'assistant' | 'system', content: string, maxWidth: number, counter: BlockCounter): RenderedLine[];
|