@wrongstack/tui 1.0.27 → 1.0.28
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/app-key-handler.d.ts +33 -2
- package/dist/auth-panel-model.d.ts +7 -0
- package/dist/index.js +56 -6
- package/package.json +7 -7
|
@@ -1,8 +1,39 @@
|
|
|
1
1
|
import { type KeyEvent } from './components/input.js';
|
|
2
2
|
import type { AppKeyHandlerOptions } from './key-handler-context.js';
|
|
3
3
|
export type { AppKeyHandlerOptions } from './key-handler-context.js';
|
|
4
|
-
/**
|
|
5
|
-
export
|
|
4
|
+
/** One delivered input event, as the host passes it to `handleKey`. */
|
|
5
|
+
export interface NextStepsTakeoverEvent {
|
|
6
|
+
/** Text payload of the event — empty for special keys and pointer reports. */
|
|
7
|
+
input: string;
|
|
8
|
+
key: KeyEvent;
|
|
9
|
+
/**
|
|
10
|
+
* Current composer buffer. The armed submit clears the composer when it
|
|
11
|
+
* fires, so text sitting here is what makes ANY event a takeover.
|
|
12
|
+
*/
|
|
13
|
+
draft: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* True when this event means the user has taken control of an armed automatic
|
|
17
|
+
* turn, i.e. the armed next-steps submit must be cancelled.
|
|
18
|
+
*
|
|
19
|
+
* Pointer reports are NOT keyboard activity: the input layer emits mouse
|
|
20
|
+
* press/release/wheel/move as `KeyEvent`s carrying `mouse` (see
|
|
21
|
+
* `components/input.tsx`, which builds them as `EMPTY_KEY` + `mouse`). Treating
|
|
22
|
+
* them as input made a plain click, a wheel scroll, or a drag through the
|
|
23
|
+
* transcript look like typing and silently killed the armed countdown, so the
|
|
24
|
+
* automatic turn never advanced.
|
|
25
|
+
*
|
|
26
|
+
* The same reasoning covers keyboard navigation: `PgUp`/`PgDn`, the caret
|
|
27
|
+
* keys, and the Ctrl+U/Ctrl+D paging chord move through the transcript exactly
|
|
28
|
+
* like the wheel does, so on an empty composer they leave the countdown armed
|
|
29
|
+
* too. Everything that can put text in the composer — typing, editing, pasting,
|
|
30
|
+
* ↑/↓ history recall, Tab accepting the suggestion, Enter — still cancels, and
|
|
31
|
+
* so does any event at all once the composer holds text, because the armed
|
|
32
|
+
* submit calls `clearDraft()` when it fires.
|
|
33
|
+
*/
|
|
34
|
+
export declare function shouldStopNextStepsAutoSubmit(event: NextStepsTakeoverEvent): boolean;
|
|
35
|
+
/** Cancel an armed automatic turn when this event is a real user takeover. */
|
|
36
|
+
export declare function stopNextStepsAutoSubmitOnKey(cancel: () => void, event: NextStepsTakeoverEvent): void;
|
|
6
37
|
/** Creates the terminal key host around focused overlay/input routers. */
|
|
7
38
|
export declare function createAppKeyHandler(options: AppKeyHandlerOptions): (input: string, key: KeyEvent) => Promise<void>;
|
|
8
39
|
//# sourceMappingURL=app-key-handler.d.ts.map
|
|
@@ -42,6 +42,13 @@ export interface AuthOAuthStrategyRow {
|
|
|
42
42
|
providerId: string;
|
|
43
43
|
label: string;
|
|
44
44
|
description?: string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Extended guidance, one entry per paragraph (mirrors
|
|
47
|
+
* `ProviderAuthStrategyMetadata.notes`). Unlike `description` this may be
|
|
48
|
+
* several sentences, so the oauth view renders it wrapped in the
|
|
49
|
+
* focused-strategy detail area, not inline on the row.
|
|
50
|
+
*/
|
|
51
|
+
notes?: readonly string[] | undefined;
|
|
45
52
|
}
|
|
46
53
|
/** Strategy ids are runtime-extensible. */
|
|
47
54
|
export type AuthOAuthKind = string;
|
package/dist/index.js
CHANGED
|
@@ -42278,7 +42278,7 @@ function KanbanPanel({
|
|
|
42278
42278
|
setPrompt({ ...prompt, buffer: prompt.buffer.slice(0, -1) });
|
|
42279
42279
|
return;
|
|
42280
42280
|
}
|
|
42281
|
-
if (input && !key2.ctrl && !key2.meta && input >= " ") {
|
|
42281
|
+
if (input && !key2.ctrl && !key2.meta && input >= " " && !isLeakedMouseInput(input)) {
|
|
42282
42282
|
setPrompt({ ...prompt, buffer: `${prompt.buffer}${input}` });
|
|
42283
42283
|
}
|
|
42284
42284
|
return;
|
|
@@ -47456,6 +47456,23 @@ function keySummary(keyRow) {
|
|
|
47456
47456
|
const created = keyRow.createdAt ? ` ${keyRow.createdAt.slice(0, 10)}` : "";
|
|
47457
47457
|
return `${keyRow.masked}${method}${created}`;
|
|
47458
47458
|
}
|
|
47459
|
+
var MAX_OAUTH_NOTE_LINES = 8;
|
|
47460
|
+
function wrapNoteText(text, width) {
|
|
47461
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
47462
|
+
if (words.length === 0) return [];
|
|
47463
|
+
const lines = [];
|
|
47464
|
+
let cur = words[0] ?? "";
|
|
47465
|
+
for (const word of words.slice(1)) {
|
|
47466
|
+
if (cur.length + 1 + word.length <= width) {
|
|
47467
|
+
cur += ` ${word}`;
|
|
47468
|
+
continue;
|
|
47469
|
+
}
|
|
47470
|
+
lines.push(cur);
|
|
47471
|
+
cur = word.length > width ? word.slice(0, width) : word;
|
|
47472
|
+
}
|
|
47473
|
+
lines.push(cur);
|
|
47474
|
+
return lines;
|
|
47475
|
+
}
|
|
47459
47476
|
function renderRow(row, focused, i) {
|
|
47460
47477
|
const marker = focused ? "\u203A" : " ";
|
|
47461
47478
|
const rowColor = focused ? UI_COLORS.focused : void 0;
|
|
@@ -47646,7 +47663,21 @@ function AuthPanel({ panel, maxRows, columns }) {
|
|
|
47646
47663
|
const size = useTerminalSize();
|
|
47647
47664
|
const budget = maxRows ?? Math.max(8, size.rows - 7);
|
|
47648
47665
|
const compact2 = budget < 14;
|
|
47649
|
-
const
|
|
47666
|
+
const noteWidth = Math.max(20, (columns ?? size.columns) - 4);
|
|
47667
|
+
const oauthFocus = panel.view === "oauth" ? panel.oauthStrategies?.[panel.selected] : void 0;
|
|
47668
|
+
const oauthNoteLines = !compact2 && oauthFocus?.notes ? oauthFocus.notes.flatMap(
|
|
47669
|
+
(note, i) => (
|
|
47670
|
+
// Blank separator between paragraphs; a space (not '') so Ink
|
|
47671
|
+
// emits the row and the reserve below matches the render.
|
|
47672
|
+
(i > 0 ? [" "] : []).concat(wrapNoteText(note, noteWidth))
|
|
47673
|
+
)
|
|
47674
|
+
).slice(
|
|
47675
|
+
0,
|
|
47676
|
+
// 8 keeps at least one list row visible on any non-compact
|
|
47677
|
+
// budget: total = 8 border/title/legend/warning + N + 1 list.
|
|
47678
|
+
Math.min(MAX_OAUTH_NOTE_LINES, Math.max(0, budget - 8))
|
|
47679
|
+
) : [];
|
|
47680
|
+
const extraRows = (panel.hint ? 1 : 0) + (panel.confirm ? compact2 ? 1 : 2 : 0) + (panel.input ? compact2 ? 1 : 2 : 0) + (panel.view === "catalog" ? compact2 ? 1 : 2 : 0) + (!compact2 && panel.view === "provider" ? 2 : 0) + (!compact2 && panel.view === "oauth" ? 3 + oauthNoteLines.length : 0) + (!compact2 && panel.view === "list" && panel.providers.length === 0 ? 2 : 0) + (!compact2 && panel.view === "catalog" && panel.busy ? 2 : 0);
|
|
47650
47681
|
const maxVisible = Math.max(
|
|
47651
47682
|
1,
|
|
47652
47683
|
budget - 4 - extraRows - (panel.view === "flow" ? compact2 ? 0 : 1 : 2)
|
|
@@ -47698,6 +47729,7 @@ function AuthPanel({ panel, maxRows, columns }) {
|
|
|
47698
47729
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Text2, { color: UI_COLORS.warning, wrap: "truncate-end", children: "\u26A0 Subscription tokens used outside official clients may violate provider Terms \u2014" }),
|
|
47699
47730
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Text2, { color: UI_COLORS.warning, wrap: "truncate-end", children: "your account could be rate-limited or banned. An API key is the sanctioned path." })
|
|
47700
47731
|
] }) : null,
|
|
47732
|
+
oauthNoteLines.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Box2, { flexDirection: "column", children: oauthNoteLines.map((line, ni) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Text2, { dimColor: true, wrap: "truncate-end", children: line }, `on-${ni}`)) }) : null,
|
|
47701
47733
|
panel.view === "catalog" ? /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Box2, { marginTop: compact2 ? 0 : 1, children: /* @__PURE__ */ (0, import_jsx_runtime37.jsxs)(Text2, { wrap: "truncate-end", children: [
|
|
47702
47734
|
/* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Text2, { dimColor: true, children: "filter: " }),
|
|
47703
47735
|
panel.filter.length > 0 ? panel.filter : /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(Text2, { dimColor: true, children: "(type to search)" }),
|
|
@@ -48670,6 +48702,7 @@ function isClearConfirmation(value) {
|
|
|
48670
48702
|
return value === "YES";
|
|
48671
48703
|
}
|
|
48672
48704
|
function clearConfirmationKeyResult(value, input, key2) {
|
|
48705
|
+
if (input && isLeakedMouseInput(input)) return { decision: null, value };
|
|
48673
48706
|
if (key2.escape) return { decision: false, value };
|
|
48674
48707
|
if (key2.ctrl || key2.meta) return { decision: null, value };
|
|
48675
48708
|
if (key2.return) {
|
|
@@ -54856,6 +54889,7 @@ function RefineCountdownPanel({
|
|
|
54856
54889
|
}, []);
|
|
54857
54890
|
use_input_default((input, key2) => {
|
|
54858
54891
|
if (resolvedRef.current) return;
|
|
54892
|
+
if (input && isLeakedMouseInput(input)) return;
|
|
54859
54893
|
resolvedRef.current = true;
|
|
54860
54894
|
const isBackspace = key2.backspace || key2.delete || input === "\x7F" || input === "\b";
|
|
54861
54895
|
if (key2.escape || isBackspace) onDecision("cancel");
|
|
@@ -85646,8 +85680,19 @@ async function routePointerEvents(ctx, input, key2) {
|
|
|
85646
85680
|
}
|
|
85647
85681
|
|
|
85648
85682
|
// src/app-key-handler.ts
|
|
85649
|
-
function
|
|
85650
|
-
|
|
85683
|
+
function isComposerEmptyNavigation(input, key2) {
|
|
85684
|
+
if (key2.pageUp || key2.pageDown || key2.home || key2.end) return true;
|
|
85685
|
+
if (key2.leftArrow || key2.rightArrow) return true;
|
|
85686
|
+
return key2.ctrl && (input === "u" || input === "d");
|
|
85687
|
+
}
|
|
85688
|
+
function shouldStopNextStepsAutoSubmit(event) {
|
|
85689
|
+
const { input, key: key2, draft } = event;
|
|
85690
|
+
if (draft !== "") return true;
|
|
85691
|
+
if (key2.mouse) return false;
|
|
85692
|
+
return !isComposerEmptyNavigation(input, key2);
|
|
85693
|
+
}
|
|
85694
|
+
function stopNextStepsAutoSubmitOnKey(cancel, event) {
|
|
85695
|
+
if (shouldStopNextStepsAutoSubmit(event)) cancel();
|
|
85651
85696
|
}
|
|
85652
85697
|
function createAppKeyHandler(options) {
|
|
85653
85698
|
const {
|
|
@@ -85660,7 +85705,8 @@ function createAppKeyHandler(options) {
|
|
|
85660
85705
|
terminalColumns,
|
|
85661
85706
|
terminalRows,
|
|
85662
85707
|
mainColumnWidth,
|
|
85663
|
-
cancelNextStepsCountdown
|
|
85708
|
+
cancelNextStepsCountdown,
|
|
85709
|
+
draftRef
|
|
85664
85710
|
} = options;
|
|
85665
85711
|
const stdout = { columns: terminalColumns, rows: terminalRows };
|
|
85666
85712
|
const historyWidth = mainColumnWidth > 0 ? mainColumnWidth : stdout?.columns ?? 80;
|
|
@@ -85679,7 +85725,11 @@ function createAppKeyHandler(options) {
|
|
|
85679
85725
|
);
|
|
85680
85726
|
const handleKey = async (input, key2) => {
|
|
85681
85727
|
if (!key2.escape) ctx.lastEscAtRef.current = 0;
|
|
85682
|
-
stopNextStepsAutoSubmitOnKey(cancelNextStepsCountdown
|
|
85728
|
+
stopNextStepsAutoSubmitOnKey(cancelNextStepsCountdown, {
|
|
85729
|
+
input,
|
|
85730
|
+
key: key2,
|
|
85731
|
+
draft: draftRef.current.buffer
|
|
85732
|
+
});
|
|
85683
85733
|
if (routeCtrlCEscalation(ctx, input, key2)) return;
|
|
85684
85734
|
if (routeModalOverlay(ctx, input, key2)) {
|
|
85685
85735
|
ctx.lastEscAtRef.current = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/tui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.28",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack terminal UI: Ink-based interactive renderer with history, pickers, and slash menus.",
|
|
6
6
|
"repository": {
|
|
@@ -26,12 +26,12 @@
|
|
|
26
26
|
"!dist/**/*.map"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@wrongstack/core": "1.0.
|
|
30
|
-
"@wrongstack/kanban": "1.0.
|
|
31
|
-
"@wrongstack/runtime": "1.0.
|
|
32
|
-
"@wrongstack/sage": "1.0.
|
|
33
|
-
"@wrongstack/sdd": "1.0.
|
|
34
|
-
"@wrongstack/tools": "1.0.
|
|
29
|
+
"@wrongstack/core": "1.0.28",
|
|
30
|
+
"@wrongstack/kanban": "1.0.28",
|
|
31
|
+
"@wrongstack/runtime": "1.0.28",
|
|
32
|
+
"@wrongstack/sage": "1.0.28",
|
|
33
|
+
"@wrongstack/sdd": "1.0.28",
|
|
34
|
+
"@wrongstack/tools": "1.0.28",
|
|
35
35
|
"string-width": "8.2.2",
|
|
36
36
|
"wrap-ansi": "^10.0.1"
|
|
37
37
|
},
|