@marifold/tui 0.60.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/LICENSE +674 -0
- package/dist/core/appState.d.ts +158 -0
- package/dist/core/appState.d.ts.map +1 -0
- package/dist/core/appState.js +167 -0
- package/dist/core/appState.js.map +1 -0
- package/dist/core/commands.d.ts +70 -0
- package/dist/core/commands.d.ts.map +1 -0
- package/dist/core/commands.js +227 -0
- package/dist/core/commands.js.map +1 -0
- package/dist/core/displayPaths.d.ts +5 -0
- package/dist/core/displayPaths.d.ts.map +1 -0
- package/dist/core/displayPaths.js +14 -0
- package/dist/core/displayPaths.js.map +1 -0
- package/dist/core/eventView.d.ts +10 -0
- package/dist/core/eventView.d.ts.map +1 -0
- package/dist/core/eventView.js +77 -0
- package/dist/core/eventView.js.map +1 -0
- package/dist/core/inputGrammar.d.ts +29 -0
- package/dist/core/inputGrammar.d.ts.map +1 -0
- package/dist/core/inputGrammar.js +30 -0
- package/dist/core/inputGrammar.js.map +1 -0
- package/dist/core/skills.d.ts +2 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +2 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/transcriptWindow.d.ts.map +1 -0
- package/dist/core/transcriptWindow.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/runTui.d.ts +18 -0
- package/dist/runTui.d.ts.map +1 -0
- package/dist/runTui.js +146 -0
- package/dist/runTui.js.map +1 -0
- package/dist/ui/App.d.ts +23 -0
- package/dist/ui/App.d.ts.map +1 -0
- package/dist/ui/App.js +991 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/ApprovalModal.d.ts +12 -0
- package/dist/ui/ApprovalModal.d.ts.map +1 -0
- package/dist/ui/ApprovalModal.js +62 -0
- package/dist/ui/ApprovalModal.js.map +1 -0
- package/dist/ui/Header.d.ts +12 -0
- package/dist/ui/Header.d.ts.map +1 -0
- package/dist/ui/Header.js +15 -0
- package/dist/ui/Header.js.map +1 -0
- package/dist/ui/InfoPanel.d.ts +11 -0
- package/dist/ui/InfoPanel.d.ts.map +1 -0
- package/dist/ui/InfoPanel.js +16 -0
- package/dist/ui/InfoPanel.js.map +1 -0
- package/dist/ui/InputBox.d.ts +31 -0
- package/dist/ui/InputBox.d.ts.map +1 -0
- package/dist/ui/InputBox.js +410 -0
- package/dist/ui/InputBox.js.map +1 -0
- package/dist/ui/Markdown.d.ts +12 -0
- package/dist/ui/Markdown.d.ts.map +1 -0
- package/dist/ui/Markdown.js +111 -0
- package/dist/ui/Markdown.js.map +1 -0
- package/dist/ui/QuestionModal.d.ts +11 -0
- package/dist/ui/QuestionModal.d.ts.map +1 -0
- package/dist/ui/QuestionModal.js +211 -0
- package/dist/ui/QuestionModal.js.map +1 -0
- package/dist/ui/RunStatus.d.ts +17 -0
- package/dist/ui/RunStatus.d.ts.map +1 -0
- package/dist/ui/RunStatus.js +46 -0
- package/dist/ui/RunStatus.js.map +1 -0
- package/dist/ui/SelectList.d.ts +18 -0
- package/dist/ui/SelectList.d.ts.map +1 -0
- package/dist/ui/SelectList.js +54 -0
- package/dist/ui/SelectList.js.map +1 -0
- package/dist/ui/Spinner.d.ts +6 -0
- package/dist/ui/Spinner.d.ts.map +1 -0
- package/dist/ui/Spinner.js +14 -0
- package/dist/ui/Spinner.js.map +1 -0
- package/dist/ui/StatusLine.d.ts +6 -0
- package/dist/ui/StatusLine.d.ts.map +1 -0
- package/dist/ui/StatusLine.js +32 -0
- package/dist/ui/StatusLine.js.map +1 -0
- package/dist/ui/Transcript.d.ts +17 -0
- package/dist/ui/Transcript.d.ts.map +1 -0
- package/dist/ui/Transcript.js +58 -0
- package/dist/ui/Transcript.js.map +1 -0
- package/dist/ui/appHelpers.d.ts +16 -0
- package/dist/ui/appHelpers.d.ts.map +1 -0
- package/dist/ui/appHelpers.js +59 -0
- package/dist/ui/appHelpers.js.map +1 -0
- package/dist/ui/text.d.ts +7 -0
- package/dist/ui/text.d.ts.map +1 -0
- package/dist/ui/text.js +16 -0
- package/dist/ui/text.js.map +1 -0
- package/dist/ui/theme.d.ts +12 -0
- package/dist/ui/theme.d.ts.map +1 -0
- package/dist/ui/theme.js +12 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/useResizing.d.ts +14 -0
- package/dist/ui/useResizing.d.ts.map +1 -0
- package/dist/ui/useResizing.js +37 -0
- package/dist/ui/useResizing.js.map +1 -0
- package/dist/ui/useTerminalSize.d.ts +8 -0
- package/dist/ui/useTerminalSize.d.ts.map +1 -0
- package/dist/ui/useTerminalSize.js +23 -0
- package/dist/ui/useTerminalSize.js.map +1 -0
- package/package.json +32 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
/** Echo text for a skill turn: `$name arg1 arg2…` (or just `$name` with no args). */
|
|
3
|
+
export function skillInvocation(name, args) {
|
|
4
|
+
return args.length ? `$${name} ${args.join(' ')}` : `$${name}`;
|
|
5
|
+
}
|
|
6
|
+
/** Strip one pair of matching surrounding quotes/backticks from a path argument
|
|
7
|
+
* — users wrap or paste paths in `…`, "…", or '…'. */
|
|
8
|
+
export function unwrapPath(value) {
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
const first = trimmed[0];
|
|
11
|
+
if (trimmed.length >= 2 && (first === '`' || first === '"' || first === "'") && trimmed.endsWith(first)) {
|
|
12
|
+
return trimmed.slice(1, -1).trim();
|
|
13
|
+
}
|
|
14
|
+
return trimmed;
|
|
15
|
+
}
|
|
16
|
+
export function errorText(error) {
|
|
17
|
+
return error instanceof Error ? error.message : String(error);
|
|
18
|
+
}
|
|
19
|
+
/** A parenthetical run summary: elapsed time always, token count when the
|
|
20
|
+
* provider reported it, and cost only when a (cloud) provider reported one —
|
|
21
|
+
* e.g. `(9.1s, 919 tokens)`. */
|
|
22
|
+
export function runSummary(elapsedMs, usage) {
|
|
23
|
+
const parts = [`${(elapsedMs / 1000).toFixed(1)}s`];
|
|
24
|
+
const total = usage?.totalTokens ??
|
|
25
|
+
(usage?.inputTokens != null || usage?.outputTokens != null
|
|
26
|
+
? (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0)
|
|
27
|
+
: undefined);
|
|
28
|
+
if (total != null)
|
|
29
|
+
parts.push(`${total.toLocaleString()} tokens`);
|
|
30
|
+
// "on server": these are prompt tokens served from the provider's server-side
|
|
31
|
+
// prompt cache (not the local session store), so the label disambiguates.
|
|
32
|
+
if (usage?.cachedInputTokens != null && usage.cachedInputTokens > 0) {
|
|
33
|
+
parts.push(`${usage.cachedInputTokens.toLocaleString()} cached on server`);
|
|
34
|
+
}
|
|
35
|
+
if (usage?.reasoningTokens != null && usage.reasoningTokens > 0) {
|
|
36
|
+
parts.push(`${usage.reasoningTokens.toLocaleString()} reasoning`);
|
|
37
|
+
}
|
|
38
|
+
if (usage?.estimatedCostUSD != null && usage.estimatedCostUSD > 0) {
|
|
39
|
+
parts.push(`$${usage.estimatedCostUSD.toFixed(4)}`);
|
|
40
|
+
}
|
|
41
|
+
return `(${parts.join(', ')})`;
|
|
42
|
+
}
|
|
43
|
+
/** Copy text to the system clipboard via the platform's CLI utility. Used by
|
|
44
|
+
* /copy to grab a response's original (un-wrapped) text, since selecting from
|
|
45
|
+
* the terminal captures Ink's hard line wraps. */
|
|
46
|
+
export function copyToClipboard(text) {
|
|
47
|
+
const [command, args] = process.platform === 'darwin'
|
|
48
|
+
? ['pbcopy', []]
|
|
49
|
+
: process.platform === 'win32'
|
|
50
|
+
? ['clip', []]
|
|
51
|
+
: ['xclip', ['-selection', 'clipboard']];
|
|
52
|
+
return new Promise((resolve, reject) => {
|
|
53
|
+
const child = spawn(command, args, { stdio: ['pipe', 'ignore', 'ignore'] });
|
|
54
|
+
child.on('error', reject);
|
|
55
|
+
child.on('close', code => (code === 0 ? resolve() : reject(new Error(`${command} exited with code ${code}`))));
|
|
56
|
+
child.stdin.end(text);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=appHelpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appHelpers.js","sourceRoot":"","sources":["../../src/ui/appHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Flatten whitespace (newlines included) and clip to `max` columns with an
|
|
2
|
+
* ellipsis, so list rows and menus stay a single, non-wrapping line. Returns ''
|
|
3
|
+
* when there is no room. */
|
|
4
|
+
export declare function truncate(text: string, max: number): string;
|
|
5
|
+
/** Right-pad with spaces to `width` so adjacent columns line up. */
|
|
6
|
+
export declare function padTo(text: string, width: number): string;
|
|
7
|
+
//# sourceMappingURL=text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/ui/text.ts"],"names":[],"mappings":"AAAA;;4BAE4B;AAC5B,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK1D;AAED,oEAAoE;AACpE,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
package/dist/ui/text.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Flatten whitespace (newlines included) and clip to `max` columns with an
|
|
2
|
+
* ellipsis, so list rows and menus stay a single, non-wrapping line. Returns ''
|
|
3
|
+
* when there is no room. */
|
|
4
|
+
export function truncate(text, max) {
|
|
5
|
+
if (max <= 0)
|
|
6
|
+
return '';
|
|
7
|
+
const flat = text.replace(/\s+/g, ' ').trim();
|
|
8
|
+
if (flat.length <= max)
|
|
9
|
+
return flat;
|
|
10
|
+
return flat.slice(0, Math.max(0, max - 1)) + '…';
|
|
11
|
+
}
|
|
12
|
+
/** Right-pad with spaces to `width` so adjacent columns line up. */
|
|
13
|
+
export function padTo(text, width) {
|
|
14
|
+
return text.length >= width ? text : text + ' '.repeat(width - text.length);
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=text.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/ui/text.ts"],"names":[],"mappings":"AAAA;;4BAE4B;AAC5B,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,GAAW;IAChD,IAAI,GAAG,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACxB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9C,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AACnD,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,KAAa;IAC/C,OAAO,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Shared TUI palette. Hex values render on truecolor terminals; Ink falls
|
|
2
|
+
* back to the nearest ANSI color elsewhere. */
|
|
3
|
+
export declare const ACCENT = "#EAA221";
|
|
4
|
+
export declare const DIM_ACCENT = "#87744F";
|
|
5
|
+
export declare const DIM = "#999999";
|
|
6
|
+
/** Inline attachment tokens like `[image #1]`. */
|
|
7
|
+
export declare const ATTACHMENT = "#3FB950";
|
|
8
|
+
/** Submitted `/command` echoes in the transcript. */
|
|
9
|
+
export declare const COMMAND = "#A371F7";
|
|
10
|
+
/** Submitted `$skill` echoes in the transcript. */
|
|
11
|
+
export declare const SKILL = "#56B6C2";
|
|
12
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;+CAC+C;AAC/C,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,GAAG,YAAY,CAAC;AAC7B,kDAAkD;AAClD,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,qDAAqD;AACrD,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,mDAAmD;AACnD,eAAO,MAAM,KAAK,YAAY,CAAC"}
|
package/dist/ui/theme.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Shared TUI palette. Hex values render on truecolor terminals; Ink falls
|
|
2
|
+
* back to the nearest ANSI color elsewhere. */
|
|
3
|
+
export const ACCENT = '#EAA221';
|
|
4
|
+
export const DIM_ACCENT = '#87744F';
|
|
5
|
+
export const DIM = '#999999';
|
|
6
|
+
/** Inline attachment tokens like `[image #1]`. */
|
|
7
|
+
export const ATTACHMENT = '#3FB950';
|
|
8
|
+
/** Submitted `/command` echoes in the transcript. */
|
|
9
|
+
export const COMMAND = '#A371F7';
|
|
10
|
+
/** Submitted `$skill` echoes in the transcript. */
|
|
11
|
+
export const SKILL = '#56B6C2';
|
|
12
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/ui/theme.ts"],"names":[],"mappings":"AAAA;+CAC+C;AAC/C,MAAM,CAAC,MAAM,MAAM,GAAG,SAAS,CAAC;AAChC,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,MAAM,CAAC,MAAM,GAAG,GAAG,SAAS,CAAC;AAC7B,kDAAkD;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC;AACpC,qDAAqD;AACrD,MAAM,CAAC,MAAM,OAAO,GAAG,SAAS,CAAC;AACjC,mDAAmD;AACnD,MAAM,CAAC,MAAM,KAAK,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True while the terminal is actively being resized, flipping back to false
|
|
3
|
+
* after `quietMs` with no further resize events.
|
|
4
|
+
*
|
|
5
|
+
* Inline TUIs duplicate their input on resize because the terminal reflows the
|
|
6
|
+
* scrollback above (scrolling the viewport), and Ink's "move up N lines and
|
|
7
|
+
* erase" then targets the wrong rows — residue accumulates per resize tick. The
|
|
8
|
+
* fix is to collapse the live region to a single stable line during the resize
|
|
9
|
+
* burst: with nothing multi-line to mis-erase, the duplication can't build up,
|
|
10
|
+
* and the full input is redrawn cleanly once the size settles. Users don't type
|
|
11
|
+
* mid-resize, so the collapse is invisible in practice.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useResizing(quietMs?: number): boolean;
|
|
14
|
+
//# sourceMappingURL=useResizing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResizing.d.ts","sourceRoot":"","sources":["../../src/ui/useResizing.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,SAAM,GAAG,OAAO,CAkBlD"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { useStdout } from 'ink';
|
|
3
|
+
/**
|
|
4
|
+
* True while the terminal is actively being resized, flipping back to false
|
|
5
|
+
* after `quietMs` with no further resize events.
|
|
6
|
+
*
|
|
7
|
+
* Inline TUIs duplicate their input on resize because the terminal reflows the
|
|
8
|
+
* scrollback above (scrolling the viewport), and Ink's "move up N lines and
|
|
9
|
+
* erase" then targets the wrong rows — residue accumulates per resize tick. The
|
|
10
|
+
* fix is to collapse the live region to a single stable line during the resize
|
|
11
|
+
* burst: with nothing multi-line to mis-erase, the duplication can't build up,
|
|
12
|
+
* and the full input is redrawn cleanly once the size settles. Users don't type
|
|
13
|
+
* mid-resize, so the collapse is invisible in practice.
|
|
14
|
+
*/
|
|
15
|
+
export function useResizing(quietMs = 150) {
|
|
16
|
+
const { stdout } = useStdout();
|
|
17
|
+
const [resizing, setResizing] = useState(false);
|
|
18
|
+
const timer = useRef(null);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (!stdout)
|
|
21
|
+
return;
|
|
22
|
+
const onResize = () => {
|
|
23
|
+
setResizing(true);
|
|
24
|
+
if (timer.current)
|
|
25
|
+
clearTimeout(timer.current);
|
|
26
|
+
timer.current = setTimeout(() => setResizing(false), quietMs);
|
|
27
|
+
};
|
|
28
|
+
stdout.on('resize', onResize);
|
|
29
|
+
return () => {
|
|
30
|
+
stdout.off('resize', onResize);
|
|
31
|
+
if (timer.current)
|
|
32
|
+
clearTimeout(timer.current);
|
|
33
|
+
};
|
|
34
|
+
}, [stdout, quietMs]);
|
|
35
|
+
return resizing;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=useResizing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useResizing.js","sourceRoot":"","sources":["../../src/ui/useResizing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAAO,GAAG,GAAG;IACvC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAC;IACjE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,QAAQ,GAAG,GAAS,EAAE;YAC1B,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,IAAI,KAAK,CAAC,OAAO;gBAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/C,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC,CAAC;QACF,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9B,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,OAAO;gBAAE,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjD,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtB,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Terminal dimensions, kept current across resizes. The inline layout uses
|
|
2
|
+
* `rows` only to cap overlay (picker) height; Ink handles input/transcript
|
|
3
|
+
* wrapping itself. */
|
|
4
|
+
export declare function useTerminalSize(): {
|
|
5
|
+
columns: number;
|
|
6
|
+
rows: number;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=useTerminalSize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTerminalSize.d.ts","sourceRoot":"","sources":["../../src/ui/useTerminalSize.ts"],"names":[],"mappings":"AAGA;;sBAEsB;AACtB,wBAAgB,eAAe,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAgBnE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react';
|
|
2
|
+
import { useStdout } from 'ink';
|
|
3
|
+
/** Terminal dimensions, kept current across resizes. The inline layout uses
|
|
4
|
+
* `rows` only to cap overlay (picker) height; Ink handles input/transcript
|
|
5
|
+
* wrapping itself. */
|
|
6
|
+
export function useTerminalSize() {
|
|
7
|
+
const { stdout } = useStdout();
|
|
8
|
+
const [size, setSize] = useState(() => ({
|
|
9
|
+
columns: stdout?.columns ?? 80,
|
|
10
|
+
rows: stdout?.rows ?? 24,
|
|
11
|
+
}));
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!stdout)
|
|
14
|
+
return;
|
|
15
|
+
const onResize = () => setSize({ columns: stdout.columns ?? 80, rows: stdout.rows ?? 24 });
|
|
16
|
+
stdout.on('resize', onResize);
|
|
17
|
+
return () => {
|
|
18
|
+
stdout.off('resize', onResize);
|
|
19
|
+
};
|
|
20
|
+
}, [stdout]);
|
|
21
|
+
return size;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=useTerminalSize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useTerminalSize.js","sourceRoot":"","sources":["../../src/ui/useTerminalSize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAEhC;;sBAEsB;AACtB,MAAM,UAAU,eAAe;IAC7B,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC;QACtC,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,EAAE;QAC9B,IAAI,EAAE,MAAM,EAAE,IAAI,IAAI,EAAE;KACzB,CAAC,CAAC,CAAC;IACJ,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,QAAQ,GAAG,GAAS,EAAE,CAC1B,OAAO,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC9B,OAAO,GAAG,EAAE;YACV,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACjC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IACb,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marifold/tui",
|
|
3
|
+
"version": "0.60.0",
|
|
4
|
+
"description": "Ink-based terminal UI for Marifold",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"ink": "^7.1.1",
|
|
13
|
+
"react": "^19.2.8",
|
|
14
|
+
"@marifold/core": "0.60.0"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@types/node": "^24.13.3",
|
|
18
|
+
"@types/react": "^19.2.17",
|
|
19
|
+
"ink-testing-library": "^4.0.0",
|
|
20
|
+
"typescript": "^7.0.2",
|
|
21
|
+
"vitest": "^4.1.10"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24.0.0 <25"
|
|
25
|
+
},
|
|
26
|
+
"license": "GPL-3.0-only",
|
|
27
|
+
"scripts": {
|
|
28
|
+
"build": "tsc",
|
|
29
|
+
"typecheck": "tsc --noEmit",
|
|
30
|
+
"test": "vitest run --passWithNoTests"
|
|
31
|
+
}
|
|
32
|
+
}
|