@dungle-scrubs/tallow 0.9.3 → 0.9.6
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/cli.js +7 -4
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/interactive-mode-patch.d.ts +24 -10
- package/dist/interactive-mode-patch.d.ts.map +1 -1
- package/dist/interactive-mode-patch.js +285 -148
- package/dist/interactive-mode-patch.js.map +1 -1
- package/dist/interactive-reset.d.ts +49 -0
- package/dist/interactive-reset.d.ts.map +1 -0
- package/dist/interactive-reset.js +40 -0
- package/dist/interactive-reset.js.map +1 -0
- package/dist/pi-tui-editor-patch.d.ts +10 -0
- package/dist/pi-tui-editor-patch.d.ts.map +1 -0
- package/dist/pi-tui-editor-patch.js +159 -0
- package/dist/pi-tui-editor-patch.js.map +1 -0
- package/dist/pi-tui-patch.d.ts +2 -0
- package/dist/pi-tui-patch.d.ts.map +1 -0
- package/dist/pi-tui-patch.js +563 -0
- package/dist/pi-tui-patch.js.map +1 -0
- package/dist/pi-tui-settings-list-patch.d.ts +11 -0
- package/dist/pi-tui-settings-list-patch.d.ts.map +1 -0
- package/dist/pi-tui-settings-list-patch.js +38 -0
- package/dist/pi-tui-settings-list-patch.js.map +1 -0
- package/dist/reset-diagnostics.d.ts +69 -0
- package/dist/reset-diagnostics.d.ts.map +1 -0
- package/dist/reset-diagnostics.js +41 -0
- package/dist/reset-diagnostics.js.map +1 -0
- package/dist/sdk.d.ts +5 -21
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +180 -149
- package/dist/sdk.js.map +1 -1
- package/dist/workspace-transition-interactive.d.ts +1 -0
- package/dist/workspace-transition-interactive.d.ts.map +1 -1
- package/dist/workspace-transition-interactive.js +7 -17
- package/dist/workspace-transition-interactive.js.map +1 -1
- package/extensions/__integration__/audit-findings.test.ts +6 -16
- package/extensions/__integration__/teams-runtime.test.ts +4 -1
- package/extensions/_icons/index.ts +2 -4
- package/extensions/_shared/__tests__/image-metadata.test.ts +33 -0
- package/extensions/_shared/__tests__/terminal-links.test.ts +18 -0
- package/extensions/_shared/image-metadata.ts +99 -0
- package/extensions/_shared/inline-preview.ts +1 -1
- package/extensions/_shared/pid-registry.ts +0 -1
- package/extensions/_shared/terminal-links.ts +22 -0
- package/extensions/ask-user-question-tool/index.ts +0 -3
- package/extensions/clear/__tests__/clear.test.ts +270 -3
- package/extensions/command-expansion/index.ts +1 -1
- package/extensions/context-files/index.ts +5 -1
- package/extensions/context-fork/__tests__/context-fork.test.ts +94 -1
- package/extensions/context-fork/extension.json +1 -1
- package/extensions/context-fork/index.ts +32 -0
- package/extensions/edit-tool-enhanced/index.ts +2 -1
- package/extensions/hooks/index.ts +33 -11
- package/extensions/loop/index.ts +14 -1
- package/extensions/lsp/index.ts +64 -13
- package/extensions/lsp/package.json +2 -2
- package/extensions/permissions/__tests__/permissions.test.ts +4 -4
- package/extensions/random-spinner/index.ts +7 -642
- package/extensions/read-tool-enhanced/index.ts +6 -8
- package/extensions/render-stabilizer/__tests__/render-stabilizer.test.ts +4 -5
- package/extensions/render-stabilizer/index.ts +6 -6
- package/extensions/show-system-prompt/__tests__/show-system-prompt.test.ts +1 -1
- package/extensions/slash-command-bridge/__tests__/slash-command-bridge.test.ts +26 -0
- package/extensions/slash-command-bridge/index.ts +14 -2
- package/extensions/subagent-tool/index.ts +1 -1
- package/extensions/subagent-tool/model-resolver.ts +274 -7
- package/extensions/tasks/__tests__/state-ui.test.ts +3 -3
- package/extensions/tasks/__tests__/widget-subagents.test.ts +2 -2
- package/extensions/tasks/commands/register-tasks-extension.ts +10 -10
- package/extensions/tasks/state/index.ts +1 -1
- package/extensions/tasks/ui/index.ts +2 -7
- package/extensions/teams-tool/tools/register-extension.ts +1 -3
- package/extensions/web-search-tool/index.ts +2 -1
- package/extensions/write-tool-enhanced/__tests__/write-tool-enhanced.test.ts +21 -6
- package/extensions/write-tool-enhanced/index.ts +2 -1
- package/node_modules/@mariozechner/pi-tui/README.md +56 -34
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts +18 -13
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js +182 -113
- package/node_modules/@mariozechner/pi-tui/dist/autocomplete.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js +3 -3
- package/node_modules/@mariozechner/pi-tui/dist/components/cancellable-loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts +45 -36
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js +489 -325
- package/node_modules/@mariozechner/pi-tui/dist/components/editor.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts +1 -99
- package/node_modules/@mariozechner/pi-tui/dist/components/image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js +17 -192
- package/node_modules/@mariozechner/pi-tui/dist/components/image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js +57 -60
- package/node_modules/@mariozechner/pi-tui/dist/components/input.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts +2 -69
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js +5 -102
- package/node_modules/@mariozechner/pi-tui/dist/components/loader.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js +111 -53
- package/node_modules/@mariozechner/pi-tui/dist/components/markdown.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts +19 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js +78 -67
- package/node_modules/@mariozechner/pi-tui/dist/components/select-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts +0 -2
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js +12 -23
- package/node_modules/@mariozechner/pi-tui/dist/components/settings-list.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts +8 -10
- package/node_modules/@mariozechner/pi-tui/dist/index.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/index.js +6 -9
- package/node_modules/@mariozechner/pi-tui/dist/index.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts +108 -238
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js +108 -365
- package/node_modules/@mariozechner/pi-tui/dist/keybindings.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts +33 -48
- package/node_modules/@mariozechner/pi-tui/dist/keys.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/keys.js +239 -155
- package/node_modules/@mariozechner/pi-tui/dist/keys.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts +14 -94
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js +44 -186
- package/node_modules/@mariozechner/pi-tui/dist/terminal-image.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts +13 -58
- package/node_modules/@mariozechner/pi-tui/dist/terminal.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js +78 -111
- package/node_modules/@mariozechner/pi-tui/dist/terminal.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts +24 -110
- package/node_modules/@mariozechner/pi-tui/dist/tui.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/tui.js +188 -435
- package/node_modules/@mariozechner/pi-tui/dist/tui.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts +0 -18
- package/node_modules/@mariozechner/pi-tui/dist/utils.d.ts.map +1 -1
- package/node_modules/@mariozechner/pi-tui/dist/utils.js +251 -119
- package/node_modules/@mariozechner/pi-tui/dist/utils.js.map +1 -1
- package/node_modules/@mariozechner/pi-tui/package.json +6 -6
- package/node_modules/@mariozechner/pi-tui/src/__tests__/__snapshots__/render.test.ts.snap +3 -40
- package/node_modules/@mariozechner/pi-tui/src/__tests__/image-component.test.ts +71 -81
- package/node_modules/@mariozechner/pi-tui/src/__tests__/render.test.ts +0 -33
- package/node_modules/@mariozechner/pi-tui/src/__tests__/terminal-image.test.ts +93 -334
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-render-scheduling.test.ts +1 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/utils.test.ts +11 -196
- package/node_modules/@mariozechner/pi-tui/src/autocomplete.ts +228 -142
- package/node_modules/@mariozechner/pi-tui/src/components/cancellable-loader.ts +3 -3
- package/node_modules/@mariozechner/pi-tui/src/components/editor.ts +624 -390
- package/node_modules/@mariozechner/pi-tui/src/components/image.ts +17 -227
- package/node_modules/@mariozechner/pi-tui/src/components/input.ts +71 -63
- package/node_modules/@mariozechner/pi-tui/src/components/loader.ts +5 -137
- package/node_modules/@mariozechner/pi-tui/src/components/markdown.ts +143 -52
- package/node_modules/@mariozechner/pi-tui/src/components/select-list.ts +136 -70
- package/node_modules/@mariozechner/pi-tui/src/components/settings-list.ts +11 -23
- package/node_modules/@mariozechner/pi-tui/src/index.ts +17 -36
- package/node_modules/@mariozechner/pi-tui/src/keybindings.ts +148 -421
- package/node_modules/@mariozechner/pi-tui/src/keys.ts +253 -181
- package/node_modules/@mariozechner/pi-tui/src/terminal-image.ts +51 -252
- package/node_modules/@mariozechner/pi-tui/src/terminal.ts +78 -133
- package/node_modules/@mariozechner/pi-tui/src/tui.ts +202 -478
- package/node_modules/@mariozechner/pi-tui/src/utils.ts +289 -125
- package/node_modules/@mariozechner/pi-tui/tsconfig.build.json +1 -0
- package/package.json +13 -13
- package/packages/tallow-tui/node_modules/@types/mime-types/README.md +8 -2
- package/packages/tallow-tui/node_modules/@types/mime-types/index.d.ts +6 -0
- package/packages/tallow-tui/node_modules/@types/mime-types/package.json +9 -3
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup-data.js +18 -0
- package/packages/tallow-tui/node_modules/get-east-asian-width/lookup.js +116 -384
- package/packages/tallow-tui/node_modules/get-east-asian-width/package.json +5 -4
- package/packages/tallow-tui/node_modules/get-east-asian-width/utilities.js +24 -0
- package/packages/tallow-tui/node_modules/marked/README.md +5 -4
- package/packages/tallow-tui/node_modules/marked/bin/main.js +10 -8
- package/packages/tallow-tui/node_modules/marked/bin/marked.js +2 -1
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.ts +156 -125
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js +67 -2179
- package/packages/tallow-tui/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js +67 -2201
- package/packages/tallow-tui/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/packages/tallow-tui/node_modules/marked/man/marked.1 +4 -2
- package/packages/tallow-tui/node_modules/marked/man/marked.1.md +2 -1
- package/packages/tallow-tui/node_modules/marked/package.json +26 -34
- package/runtime/model-metadata-overrides.ts +10 -1
- package/runtime/pid-schema.ts +26 -6
- package/skills/tallow-expert/SKILL.md +1 -3
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts +0 -32
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js +0 -46
- package/node_modules/@mariozechner/pi-tui/dist/border-styles.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts +0 -52
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js +0 -89
- package/node_modules/@mariozechner/pi-tui/dist/components/bordered-box.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts +0 -14
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.d.ts.map +0 -1
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js +0 -55
- package/node_modules/@mariozechner/pi-tui/dist/test-utils/capability-env.js.map +0 -1
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-change-listener.test.ts +0 -121
- package/node_modules/@mariozechner/pi-tui/src/__tests__/editor-ghost-text.test.ts +0 -112
- package/node_modules/@mariozechner/pi-tui/src/__tests__/mouse-events.test.ts +0 -134
- package/node_modules/@mariozechner/pi-tui/src/__tests__/settings-list.test.ts +0 -49
- package/node_modules/@mariozechner/pi-tui/src/__tests__/tui-diff-regression.test.ts +0 -555
- package/node_modules/@mariozechner/pi-tui/src/border-styles.ts +0 -60
- package/node_modules/@mariozechner/pi-tui/src/components/bordered-box.ts +0 -113
- package/node_modules/@mariozechner/pi-tui/src/test-utils/capability-env.ts +0 -56
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs +0 -2211
- package/packages/tallow-tui/node_modules/marked/lib/marked.cjs.map +0 -7
- package/packages/tallow-tui/node_modules/marked/lib/marked.d.cts +0 -728
- package/packages/tallow-tui/node_modules/marked/marked.min.js +0 -69
|
@@ -1,141 +1,36 @@
|
|
|
1
1
|
import type { TUI } from "../tui.js";
|
|
2
2
|
import { Text } from "./text.js";
|
|
3
3
|
|
|
4
|
-
/** Default braille spinner frames used when no custom frames are provided. */
|
|
5
|
-
const DEFAULT_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
6
|
-
|
|
7
|
-
/** Default animation interval in milliseconds. */
|
|
8
|
-
const DEFAULT_INTERVAL_MS = 80;
|
|
9
|
-
|
|
10
|
-
/** Optional configuration for the Loader's spinner appearance and timing. */
|
|
11
|
-
export interface LoaderOptions {
|
|
12
|
-
/** Spinner animation frames (defaults to braille dots). */
|
|
13
|
-
frames?: string[];
|
|
14
|
-
/** Animation interval in ms (default: 80). */
|
|
15
|
-
intervalMs?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/** Context passed to the message transform callback each tick. */
|
|
19
|
-
export interface MessageTransformContext {
|
|
20
|
-
/** The current message set on this Loader (from constructor or setMessage). */
|
|
21
|
-
message: string;
|
|
22
|
-
/** Monotonic tick counter — increments each animation frame for this instance. */
|
|
23
|
-
tick: number;
|
|
24
|
-
/** True if the message has not been changed via setMessage() since construction. */
|
|
25
|
-
isInitialMessage: boolean;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
4
|
/**
|
|
29
|
-
* Loader component that updates with
|
|
30
|
-
*
|
|
31
|
-
* @param ui - TUI instance for rendering
|
|
32
|
-
* @param spinnerColorFn - Color function applied to the spinner frame
|
|
33
|
-
* @param messageColorFn - Color function applied to the message text
|
|
34
|
-
* @param message - Text shown next to the spinner (default: "Loading...")
|
|
35
|
-
* @param options - Optional frames and interval override
|
|
5
|
+
* Loader component that updates every 80ms with spinning animation
|
|
36
6
|
*/
|
|
37
7
|
export class Loader extends Text {
|
|
38
|
-
private frames
|
|
39
|
-
private intervalMs: number;
|
|
8
|
+
private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
40
9
|
private currentFrame = 0;
|
|
41
10
|
private intervalId: NodeJS.Timeout | null = null;
|
|
42
|
-
private _transformIntervalId: NodeJS.Timeout | null = null;
|
|
43
11
|
private ui: TUI | null = null;
|
|
44
12
|
|
|
45
|
-
/** Per-instance tick counter for message transform animations. */
|
|
46
|
-
private _transformTick = 0;
|
|
47
|
-
|
|
48
|
-
/** Tracks whether setMessage() has been called since construction. */
|
|
49
|
-
private _messageChanged = false;
|
|
50
|
-
|
|
51
13
|
constructor(
|
|
52
14
|
ui: TUI,
|
|
53
15
|
private spinnerColorFn: (str: string) => string,
|
|
54
16
|
private messageColorFn: (str: string) => string,
|
|
55
|
-
private message: string = "Loading..."
|
|
56
|
-
options?: LoaderOptions
|
|
17
|
+
private message: string = "Loading..."
|
|
57
18
|
) {
|
|
58
19
|
super("", 1, 0);
|
|
59
|
-
this.frames = options?.frames ?? Loader.defaultFrames ?? DEFAULT_FRAMES;
|
|
60
|
-
this.intervalMs = options?.intervalMs ?? Loader.defaultIntervalMs ?? DEFAULT_INTERVAL_MS;
|
|
61
20
|
this.ui = ui;
|
|
62
21
|
this.start();
|
|
63
22
|
}
|
|
64
23
|
|
|
65
|
-
/**
|
|
66
|
-
* Global default spinner frames — set once, applies to all new Loader instances.
|
|
67
|
-
* Extensions can set this at session_start to override the braille default.
|
|
68
|
-
*/
|
|
69
|
-
static defaultFrames: string[] | undefined;
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Global default interval — set once, applies to all new Loader instances.
|
|
73
|
-
*/
|
|
74
|
-
static defaultIntervalMs: number | undefined;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Global message transform — called each tick to modify the displayed message.
|
|
78
|
-
* Extensions use this to animate or replace the loader text.
|
|
79
|
-
* Return the string to display. The transform is applied before messageColorFn.
|
|
80
|
-
*/
|
|
81
|
-
static defaultMessageTransform?: (ctx: MessageTransformContext) => string;
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Interval (ms) for the message transform tick — independent of the spinner frame rate.
|
|
85
|
-
* When set to a value faster than the spinner interval, a separate timer drives
|
|
86
|
-
* the transform tick and re-renders, giving animations higher
|
|
87
|
-
* frame rates without affecting the spinner animation speed.
|
|
88
|
-
*/
|
|
89
|
-
static defaultTransformIntervalMs: number | undefined;
|
|
90
|
-
|
|
91
|
-
/** Whether the loader is hidden (renders as empty space). */
|
|
92
|
-
private hidden = false;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Hide the loader — renders nothing but keeps the interval alive.
|
|
96
|
-
* Call show() to restore.
|
|
97
|
-
*/
|
|
98
|
-
hide() {
|
|
99
|
-
this.hidden = true;
|
|
100
|
-
this.setText("");
|
|
101
|
-
this.ui?.requestRender();
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Show the loader after a hide() call.
|
|
106
|
-
*/
|
|
107
|
-
show() {
|
|
108
|
-
this.hidden = false;
|
|
109
|
-
this.updateDisplay();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
24
|
render(width: number): string[] {
|
|
113
|
-
if (this.hidden) return [];
|
|
114
25
|
return ["", ...super.render(width)];
|
|
115
26
|
}
|
|
116
27
|
|
|
117
28
|
start() {
|
|
118
29
|
this.updateDisplay();
|
|
119
|
-
|
|
120
|
-
const transformMs = Loader.defaultTransformIntervalMs;
|
|
121
|
-
const hasFastTransform =
|
|
122
|
-
Loader.defaultMessageTransform != null &&
|
|
123
|
-
transformMs != null &&
|
|
124
|
-
transformMs < this.intervalMs;
|
|
125
|
-
|
|
126
30
|
this.intervalId = setInterval(() => {
|
|
127
31
|
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
128
|
-
this._transformTick++;
|
|
129
32
|
this.updateDisplay();
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
// Separate faster interval for message transform re-renders only.
|
|
133
|
-
// Does NOT advance _transformTick — just re-rolls random visuals.
|
|
134
|
-
if (hasFastTransform) {
|
|
135
|
-
this._transformIntervalId = setInterval(() => {
|
|
136
|
-
this.updateDisplay();
|
|
137
|
-
}, transformMs);
|
|
138
|
-
}
|
|
33
|
+
}, 80);
|
|
139
34
|
}
|
|
140
35
|
|
|
141
36
|
stop() {
|
|
@@ -143,43 +38,16 @@ export class Loader extends Text {
|
|
|
143
38
|
clearInterval(this.intervalId);
|
|
144
39
|
this.intervalId = null;
|
|
145
40
|
}
|
|
146
|
-
if (this._transformIntervalId) {
|
|
147
|
-
clearInterval(this._transformIntervalId);
|
|
148
|
-
this._transformIntervalId = null;
|
|
149
|
-
}
|
|
150
41
|
}
|
|
151
42
|
|
|
152
|
-
/** Sentinel value — pass to setWorkingMessage() to hide the loader. */
|
|
153
|
-
static readonly HIDE = "\u200B";
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Set the loader message. Pass Loader.HIDE to hide, any other string to show.
|
|
157
|
-
* @param message - Message text or Loader.HIDE sentinel
|
|
158
|
-
*/
|
|
159
43
|
setMessage(message: string) {
|
|
160
|
-
if (message === Loader.HIDE) {
|
|
161
|
-
this.hide();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (this.hidden) this.show();
|
|
165
|
-
this._messageChanged = true;
|
|
166
44
|
this.message = message;
|
|
167
45
|
this.updateDisplay();
|
|
168
46
|
}
|
|
169
47
|
|
|
170
48
|
private updateDisplay() {
|
|
171
49
|
const frame = this.frames[this.currentFrame];
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (Loader.defaultMessageTransform) {
|
|
175
|
-
displayMessage = Loader.defaultMessageTransform({
|
|
176
|
-
message: this.message,
|
|
177
|
-
tick: this._transformTick,
|
|
178
|
-
isInitialMessage: !this._messageChanged,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(displayMessage)}`);
|
|
50
|
+
this.setText(`${this.spinnerColorFn(frame)} ${this.messageColorFn(this.message)}`);
|
|
183
51
|
if (this.ui) {
|
|
184
52
|
this.ui.requestRender();
|
|
185
53
|
}
|
|
@@ -1,8 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { isImageLine } from "../terminal-image.js";
|
|
1
|
+
import { Marked, type Token, Tokenizer, type Tokens } from "marked";
|
|
2
|
+
import { getCapabilities, hyperlink, isImageLine } from "../terminal-image.js";
|
|
3
3
|
import type { Component } from "../tui.js";
|
|
4
4
|
import { applyBackgroundToLine, visibleWidth, wrapTextWithAnsi } from "../utils.js";
|
|
5
5
|
|
|
6
|
+
const STRICT_STRIKETHROUGH_REGEX = /^(~~)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/;
|
|
7
|
+
|
|
8
|
+
class StrictStrikethroughTokenizer extends Tokenizer {
|
|
9
|
+
override del(src: string): Tokens.Del | undefined {
|
|
10
|
+
const match = STRICT_STRIKETHROUGH_REGEX.exec(src);
|
|
11
|
+
if (!match) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const text = match[2];
|
|
16
|
+
return {
|
|
17
|
+
type: "del",
|
|
18
|
+
raw: match[0],
|
|
19
|
+
text,
|
|
20
|
+
tokens: this.lexer.inlineTokens(text),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const markdownParser = new Marked();
|
|
26
|
+
markdownParser.setOptions({
|
|
27
|
+
tokenizer: new StrictStrikethroughTokenizer(),
|
|
28
|
+
});
|
|
29
|
+
|
|
6
30
|
/**
|
|
7
31
|
* Default text styling for markdown content.
|
|
8
32
|
* Applied to all text unless overridden by markdown formatting.
|
|
@@ -112,7 +136,7 @@ export class Markdown implements Component {
|
|
|
112
136
|
const normalizedText = this.text.replace(/\t/g, " ");
|
|
113
137
|
|
|
114
138
|
// Parse markdown to HTML-like tokens
|
|
115
|
-
const tokens =
|
|
139
|
+
const tokens = markdownParser.lexer(normalizedText);
|
|
116
140
|
|
|
117
141
|
// Convert tokens to styled terminal output
|
|
118
142
|
const renderedLines: string[] = [];
|
|
@@ -260,31 +284,47 @@ export class Markdown implements Component {
|
|
|
260
284
|
};
|
|
261
285
|
}
|
|
262
286
|
|
|
263
|
-
private renderToken(
|
|
287
|
+
private renderToken(
|
|
288
|
+
token: Token,
|
|
289
|
+
width: number,
|
|
290
|
+
nextTokenType?: string,
|
|
291
|
+
styleContext?: InlineStyleContext
|
|
292
|
+
): string[] {
|
|
264
293
|
const lines: string[] = [];
|
|
265
294
|
|
|
266
295
|
switch (token.type) {
|
|
267
296
|
case "heading": {
|
|
268
297
|
const headingLevel = token.depth;
|
|
269
298
|
const headingPrefix = `${"#".repeat(headingLevel)} `;
|
|
270
|
-
|
|
271
|
-
|
|
299
|
+
|
|
300
|
+
// Build a heading-specific style context so inline tokens (codespan, bold, etc.)
|
|
301
|
+
// restore heading styling after their own ANSI resets instead of falling back to
|
|
302
|
+
// the default text style.
|
|
303
|
+
let headingStyleFn: (text: string) => string;
|
|
272
304
|
if (headingLevel === 1) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
styledHeading = this.theme.heading(this.theme.bold(headingText));
|
|
305
|
+
headingStyleFn = (text: string) =>
|
|
306
|
+
this.theme.heading(this.theme.bold(this.theme.underline(text)));
|
|
276
307
|
} else {
|
|
277
|
-
|
|
308
|
+
headingStyleFn = (text: string) => this.theme.heading(this.theme.bold(text));
|
|
278
309
|
}
|
|
310
|
+
|
|
311
|
+
const headingStyleContext: InlineStyleContext = {
|
|
312
|
+
applyText: headingStyleFn,
|
|
313
|
+
stylePrefix: this.getStylePrefix(headingStyleFn),
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const headingText = this.renderInlineTokens(token.tokens || [], headingStyleContext);
|
|
317
|
+
const styledHeading =
|
|
318
|
+
headingLevel >= 3 ? headingStyleFn(headingPrefix) + headingText : headingText;
|
|
279
319
|
lines.push(styledHeading);
|
|
280
|
-
if (nextTokenType !== "space") {
|
|
320
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
281
321
|
lines.push(""); // Add spacing after headings (unless space token follows)
|
|
282
322
|
}
|
|
283
323
|
break;
|
|
284
324
|
}
|
|
285
325
|
|
|
286
326
|
case "paragraph": {
|
|
287
|
-
const paragraphText = this.renderInlineTokens(token.tokens || []);
|
|
327
|
+
const paragraphText = this.renderInlineTokens(token.tokens || [], styleContext);
|
|
288
328
|
lines.push(paragraphText);
|
|
289
329
|
// Don't add spacing if next token is space or list
|
|
290
330
|
if (nextTokenType && nextTokenType !== "list" && nextTokenType !== "space") {
|
|
@@ -309,14 +349,14 @@ export class Markdown implements Component {
|
|
|
309
349
|
}
|
|
310
350
|
}
|
|
311
351
|
lines.push(this.theme.codeBlockBorder("```"));
|
|
312
|
-
if (nextTokenType !== "space") {
|
|
352
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
313
353
|
lines.push(""); // Add spacing after code blocks (unless space token follows)
|
|
314
354
|
}
|
|
315
355
|
break;
|
|
316
356
|
}
|
|
317
357
|
|
|
318
358
|
case "list": {
|
|
319
|
-
const listLines = this.renderList(token as any, 0);
|
|
359
|
+
const listLines = this.renderList(token as any, 0, styleContext);
|
|
320
360
|
lines.push(...listLines);
|
|
321
361
|
// Don't add spacing after lists if a space token follows
|
|
322
362
|
// (the space token will handle it)
|
|
@@ -324,31 +364,63 @@ export class Markdown implements Component {
|
|
|
324
364
|
}
|
|
325
365
|
|
|
326
366
|
case "table": {
|
|
327
|
-
const tableLines = this.renderTable(token as any, width);
|
|
367
|
+
const tableLines = this.renderTable(token as any, width, nextTokenType, styleContext);
|
|
328
368
|
lines.push(...tableLines);
|
|
329
369
|
break;
|
|
330
370
|
}
|
|
331
371
|
|
|
332
372
|
case "blockquote": {
|
|
333
373
|
const quoteStyle = (text: string) => this.theme.quote(this.theme.italic(text));
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
374
|
+
const quoteStylePrefix = this.getStylePrefix(quoteStyle);
|
|
375
|
+
const applyQuoteStyle = (line: string): string => {
|
|
376
|
+
if (!quoteStylePrefix) {
|
|
377
|
+
return quoteStyle(line);
|
|
378
|
+
}
|
|
379
|
+
const lineWithReappliedStyle = line.replace(/\x1b\[0m/g, `\x1b[0m${quoteStylePrefix}`);
|
|
380
|
+
return quoteStyle(lineWithReappliedStyle);
|
|
337
381
|
};
|
|
338
|
-
const quoteText = this.renderInlineTokens(token.tokens || [], quoteStyleContext);
|
|
339
|
-
const quoteLines = quoteText.split("\n");
|
|
340
382
|
|
|
341
383
|
// Calculate available width for quote content (subtract border "│ " = 2 chars)
|
|
342
384
|
const quoteContentWidth = Math.max(1, width - 2);
|
|
343
385
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
386
|
+
// Blockquotes contain block-level tokens (paragraph, list, code, etc.), so render
|
|
387
|
+
// children with renderToken() instead of renderInlineTokens().
|
|
388
|
+
// Default message style should not apply inside blockquotes.
|
|
389
|
+
const quoteInlineStyleContext: InlineStyleContext = {
|
|
390
|
+
applyText: (text: string) => text,
|
|
391
|
+
stylePrefix: quoteStylePrefix,
|
|
392
|
+
};
|
|
393
|
+
const quoteTokens = token.tokens || [];
|
|
394
|
+
const renderedQuoteLines: string[] = [];
|
|
395
|
+
for (let i = 0; i < quoteTokens.length; i++) {
|
|
396
|
+
const quoteToken = quoteTokens[i];
|
|
397
|
+
const nextQuoteToken = quoteTokens[i + 1];
|
|
398
|
+
renderedQuoteLines.push(
|
|
399
|
+
...this.renderToken(
|
|
400
|
+
quoteToken,
|
|
401
|
+
quoteContentWidth,
|
|
402
|
+
nextQuoteToken?.type,
|
|
403
|
+
quoteInlineStyleContext
|
|
404
|
+
)
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Avoid rendering an extra empty quote line before the outer blockquote spacing.
|
|
409
|
+
while (
|
|
410
|
+
renderedQuoteLines.length > 0 &&
|
|
411
|
+
renderedQuoteLines[renderedQuoteLines.length - 1] === ""
|
|
412
|
+
) {
|
|
413
|
+
renderedQuoteLines.pop();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
for (const quoteLine of renderedQuoteLines) {
|
|
417
|
+
const styledLine = applyQuoteStyle(quoteLine);
|
|
418
|
+
const wrappedLines = wrapTextWithAnsi(styledLine, quoteContentWidth);
|
|
347
419
|
for (const wrappedLine of wrappedLines) {
|
|
348
420
|
lines.push(this.theme.quoteBorder("│ ") + wrappedLine);
|
|
349
421
|
}
|
|
350
422
|
}
|
|
351
|
-
if (nextTokenType !== "space") {
|
|
423
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
352
424
|
lines.push(""); // Add spacing after blockquotes (unless space token follows)
|
|
353
425
|
}
|
|
354
426
|
break;
|
|
@@ -356,7 +428,7 @@ export class Markdown implements Component {
|
|
|
356
428
|
|
|
357
429
|
case "hr":
|
|
358
430
|
lines.push(this.theme.hr("─".repeat(Math.min(width, 80))));
|
|
359
|
-
if (nextTokenType !== "space") {
|
|
431
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
360
432
|
lines.push(""); // Add spacing after horizontal rules (unless space token follows)
|
|
361
433
|
}
|
|
362
434
|
break;
|
|
@@ -426,20 +498,24 @@ export class Markdown implements Component {
|
|
|
426
498
|
|
|
427
499
|
case "link": {
|
|
428
500
|
const linkText = this.renderInlineTokens(token.tokens || [], resolvedStyleContext);
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
? token.href.slice(7)
|
|
435
|
-
: token.href;
|
|
436
|
-
if (token.text === token.href || token.text === hrefForComparison) {
|
|
437
|
-
result += this.theme.link(this.theme.underline(linkText)) + stylePrefix;
|
|
501
|
+
const styledLink = this.theme.link(this.theme.underline(linkText));
|
|
502
|
+
if (getCapabilities().hyperlinks) {
|
|
503
|
+
// OSC 8: render as a clickable hyperlink. The URL is not printed inline,
|
|
504
|
+
// so we always show only the link text regardless of whether it matches href.
|
|
505
|
+
result += hyperlink(styledLink, token.href) + stylePrefix;
|
|
438
506
|
} else {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
507
|
+
// Fallback: print URL in parentheses when text differs from href.
|
|
508
|
+
// Compare raw token.text (not styled) against href for the equality check.
|
|
509
|
+
// For mailto: links strip the prefix (autolinked emails use text="foo@bar.com"
|
|
510
|
+
// but href="mailto:foo@bar.com").
|
|
511
|
+
const hrefForComparison = token.href.startsWith("mailto:")
|
|
512
|
+
? token.href.slice(7)
|
|
513
|
+
: token.href;
|
|
514
|
+
if (token.text === token.href || token.text === hrefForComparison) {
|
|
515
|
+
result += styledLink + stylePrefix;
|
|
516
|
+
} else {
|
|
517
|
+
result += styledLink + this.theme.linkUrl(` (${token.href})`) + stylePrefix;
|
|
518
|
+
}
|
|
443
519
|
}
|
|
444
520
|
break;
|
|
445
521
|
}
|
|
@@ -469,6 +545,10 @@ export class Markdown implements Component {
|
|
|
469
545
|
}
|
|
470
546
|
}
|
|
471
547
|
|
|
548
|
+
while (stylePrefix && result.endsWith(stylePrefix)) {
|
|
549
|
+
result = result.slice(0, -stylePrefix.length);
|
|
550
|
+
}
|
|
551
|
+
|
|
472
552
|
return result;
|
|
473
553
|
}
|
|
474
554
|
|
|
@@ -477,7 +557,8 @@ export class Markdown implements Component {
|
|
|
477
557
|
*/
|
|
478
558
|
private renderList(
|
|
479
559
|
token: Token & { items: any[]; ordered: boolean; start?: number },
|
|
480
|
-
depth: number
|
|
560
|
+
depth: number,
|
|
561
|
+
styleContext?: InlineStyleContext
|
|
481
562
|
): string[] {
|
|
482
563
|
const lines: string[] = [];
|
|
483
564
|
const indent = " ".repeat(depth);
|
|
@@ -489,7 +570,7 @@ export class Markdown implements Component {
|
|
|
489
570
|
const bullet = token.ordered ? `${startNumber + i}. ` : "- ";
|
|
490
571
|
|
|
491
572
|
// Process item tokens to handle nested lists
|
|
492
|
-
const itemLines = this.renderListItem(item.tokens || [], depth);
|
|
573
|
+
const itemLines = this.renderListItem(item.tokens || [], depth, styleContext);
|
|
493
574
|
|
|
494
575
|
if (itemLines.length > 0) {
|
|
495
576
|
// First line - check if it's a nested list
|
|
@@ -530,25 +611,29 @@ export class Markdown implements Component {
|
|
|
530
611
|
* Render list item tokens, handling nested lists
|
|
531
612
|
* Returns lines WITHOUT the parent indent (renderList will add it)
|
|
532
613
|
*/
|
|
533
|
-
private renderListItem(
|
|
614
|
+
private renderListItem(
|
|
615
|
+
tokens: Token[],
|
|
616
|
+
parentDepth: number,
|
|
617
|
+
styleContext?: InlineStyleContext
|
|
618
|
+
): string[] {
|
|
534
619
|
const lines: string[] = [];
|
|
535
620
|
|
|
536
621
|
for (const token of tokens) {
|
|
537
622
|
if (token.type === "list") {
|
|
538
623
|
// Nested list - render with one additional indent level
|
|
539
624
|
// These lines will have their own indent, so we just add them as-is
|
|
540
|
-
const nestedLines = this.renderList(token as any, parentDepth + 1);
|
|
625
|
+
const nestedLines = this.renderList(token as any, parentDepth + 1, styleContext);
|
|
541
626
|
lines.push(...nestedLines);
|
|
542
627
|
} else if (token.type === "text") {
|
|
543
628
|
// Text content (may have inline tokens)
|
|
544
629
|
const text =
|
|
545
630
|
token.tokens && token.tokens.length > 0
|
|
546
|
-
? this.renderInlineTokens(token.tokens)
|
|
631
|
+
? this.renderInlineTokens(token.tokens, styleContext)
|
|
547
632
|
: token.text || "";
|
|
548
633
|
lines.push(text);
|
|
549
634
|
} else if (token.type === "paragraph") {
|
|
550
635
|
// Paragraph in list item
|
|
551
|
-
const text = this.renderInlineTokens(token.tokens || []);
|
|
636
|
+
const text = this.renderInlineTokens(token.tokens || [], styleContext);
|
|
552
637
|
lines.push(text);
|
|
553
638
|
} else if (token.type === "code") {
|
|
554
639
|
// Code block in list item
|
|
@@ -568,7 +653,7 @@ export class Markdown implements Component {
|
|
|
568
653
|
lines.push(this.theme.codeBlockBorder("```"));
|
|
569
654
|
} else {
|
|
570
655
|
// Other token types - try to render as inline
|
|
571
|
-
const text = this.renderInlineTokens([token]);
|
|
656
|
+
const text = this.renderInlineTokens([token], styleContext);
|
|
572
657
|
if (text) {
|
|
573
658
|
lines.push(text);
|
|
574
659
|
}
|
|
@@ -609,7 +694,9 @@ export class Markdown implements Component {
|
|
|
609
694
|
*/
|
|
610
695
|
private renderTable(
|
|
611
696
|
token: Token & { header: any[]; rows: any[][]; raw?: string },
|
|
612
|
-
availableWidth: number
|
|
697
|
+
availableWidth: number,
|
|
698
|
+
nextTokenType?: string,
|
|
699
|
+
styleContext?: InlineStyleContext
|
|
613
700
|
): string[] {
|
|
614
701
|
const lines: string[] = [];
|
|
615
702
|
const numCols = token.header.length;
|
|
@@ -625,7 +712,9 @@ export class Markdown implements Component {
|
|
|
625
712
|
if (availableForCells < numCols) {
|
|
626
713
|
// Too narrow to render a stable table. Fall back to raw markdown.
|
|
627
714
|
const fallbackLines = token.raw ? wrapTextWithAnsi(token.raw, availableWidth) : [];
|
|
628
|
-
|
|
715
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
716
|
+
fallbackLines.push("");
|
|
717
|
+
}
|
|
629
718
|
return fallbackLines;
|
|
630
719
|
}
|
|
631
720
|
|
|
@@ -635,13 +724,13 @@ export class Markdown implements Component {
|
|
|
635
724
|
const naturalWidths: number[] = [];
|
|
636
725
|
const minWordWidths: number[] = [];
|
|
637
726
|
for (let i = 0; i < numCols; i++) {
|
|
638
|
-
const headerText = this.renderInlineTokens(token.header[i].tokens || []);
|
|
727
|
+
const headerText = this.renderInlineTokens(token.header[i].tokens || [], styleContext);
|
|
639
728
|
naturalWidths[i] = visibleWidth(headerText);
|
|
640
729
|
minWordWidths[i] = Math.max(1, this.getLongestWordWidth(headerText, maxUnbrokenWordWidth));
|
|
641
730
|
}
|
|
642
731
|
for (const row of token.rows) {
|
|
643
732
|
for (let i = 0; i < row.length; i++) {
|
|
644
|
-
const cellText = this.renderInlineTokens(row[i].tokens || []);
|
|
733
|
+
const cellText = this.renderInlineTokens(row[i].tokens || [], styleContext);
|
|
645
734
|
naturalWidths[i] = Math.max(naturalWidths[i] || 0, visibleWidth(cellText));
|
|
646
735
|
minWordWidths[i] = Math.max(
|
|
647
736
|
minWordWidths[i] || 1,
|
|
@@ -729,7 +818,7 @@ export class Markdown implements Component {
|
|
|
729
818
|
|
|
730
819
|
// Render header with wrapping
|
|
731
820
|
const headerCellLines: string[][] = token.header.map((cell, i) => {
|
|
732
|
-
const text = this.renderInlineTokens(cell.tokens || []);
|
|
821
|
+
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
|
733
822
|
return this.wrapCellText(text, columnWidths[i]);
|
|
734
823
|
});
|
|
735
824
|
const headerLineCount = Math.max(...headerCellLines.map((c) => c.length));
|
|
@@ -752,7 +841,7 @@ export class Markdown implements Component {
|
|
|
752
841
|
for (let rowIndex = 0; rowIndex < token.rows.length; rowIndex++) {
|
|
753
842
|
const row = token.rows[rowIndex];
|
|
754
843
|
const rowCellLines: string[][] = row.map((cell, i) => {
|
|
755
|
-
const text = this.renderInlineTokens(cell.tokens || []);
|
|
844
|
+
const text = this.renderInlineTokens(cell.tokens || [], styleContext);
|
|
756
845
|
return this.wrapCellText(text, columnWidths[i]);
|
|
757
846
|
});
|
|
758
847
|
const rowLineCount = Math.max(...rowCellLines.map((c) => c.length));
|
|
@@ -774,7 +863,9 @@ export class Markdown implements Component {
|
|
|
774
863
|
const bottomBorderCells = columnWidths.map((w) => "─".repeat(w));
|
|
775
864
|
lines.push(`└─${bottomBorderCells.join("─┴─")}─┘`);
|
|
776
865
|
|
|
777
|
-
|
|
866
|
+
if (nextTokenType && nextTokenType !== "space") {
|
|
867
|
+
lines.push(""); // Add spacing after table
|
|
868
|
+
}
|
|
778
869
|
return lines;
|
|
779
870
|
}
|
|
780
871
|
}
|