toolcraft-openapi 0.0.151 → 0.0.153

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.
Files changed (55) hide show
  1. package/dist/composition.json +2 -2
  2. package/node_modules/toolcraft-design/README.md +30 -0
  3. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.d.ts +1 -0
  4. package/node_modules/toolcraft-design/dist/dashboard/terminal-width.js +18 -1
  5. package/node_modules/toolcraft-design/dist/explorer/actions.d.ts +1 -1
  6. package/node_modules/toolcraft-design/dist/explorer/actions.js +22 -4
  7. package/node_modules/toolcraft-design/dist/explorer/filter.js +1 -1
  8. package/node_modules/toolcraft-design/dist/explorer/index.d.ts +2 -4
  9. package/node_modules/toolcraft-design/dist/explorer/index.js +1 -2
  10. package/node_modules/toolcraft-design/dist/explorer/jobs.d.ts +2 -2
  11. package/node_modules/toolcraft-design/dist/explorer/jobs.js +3 -5
  12. package/node_modules/toolcraft-design/dist/explorer/keymap.d.ts +13 -3
  13. package/node_modules/toolcraft-design/dist/explorer/keymap.js +89 -348
  14. package/node_modules/toolcraft-design/dist/explorer/layout.d.ts +1 -0
  15. package/node_modules/toolcraft-design/dist/explorer/layout.js +14 -4
  16. package/node_modules/toolcraft-design/dist/explorer/reducer.js +58 -9
  17. package/node_modules/toolcraft-design/dist/explorer/render/detail.d.ts +1 -1
  18. package/node_modules/toolcraft-design/dist/explorer/render/detail.js +43 -7
  19. package/node_modules/toolcraft-design/dist/explorer/render/footer.d.ts +1 -1
  20. package/node_modules/toolcraft-design/dist/explorer/render/footer.js +6 -3
  21. package/node_modules/toolcraft-design/dist/explorer/render/header.d.ts +1 -1
  22. package/node_modules/toolcraft-design/dist/explorer/render/header.js +6 -2
  23. package/node_modules/toolcraft-design/dist/explorer/render/index.d.ts +1 -1
  24. package/node_modules/toolcraft-design/dist/explorer/render/index.js +2 -1
  25. package/node_modules/toolcraft-design/dist/explorer/render/list.d.ts +16 -2
  26. package/node_modules/toolcraft-design/dist/explorer/render/list.js +13 -34
  27. package/node_modules/toolcraft-design/dist/explorer/render/modal.d.ts +1 -1
  28. package/node_modules/toolcraft-design/dist/explorer/render/pane.d.ts +5 -2
  29. package/node_modules/toolcraft-design/dist/explorer/render/pane.js +9 -6
  30. package/node_modules/toolcraft-design/dist/explorer/render/test-fixtures.js +2 -3
  31. package/node_modules/toolcraft-design/dist/explorer/runtime.js +68 -63
  32. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.d.ts +23 -37
  33. package/node_modules/toolcraft-design/dist/explorer/runtime.test-helpers.js +32 -83
  34. package/node_modules/toolcraft-design/dist/explorer/state.d.ts +47 -5
  35. package/node_modules/toolcraft-design/dist/explorer/state.js +56 -12
  36. package/node_modules/toolcraft-design/dist/index.d.ts +8 -2
  37. package/node_modules/toolcraft-design/dist/index.js +5 -1
  38. package/node_modules/toolcraft-design/dist/screen/ansi-text.d.ts +2 -0
  39. package/node_modules/toolcraft-design/dist/screen/ansi-text.js +35 -0
  40. package/node_modules/toolcraft-design/dist/screen/screen.d.ts +40 -0
  41. package/node_modules/toolcraft-design/dist/screen/screen.js +122 -0
  42. package/node_modules/toolcraft-design/dist/screen/style.d.ts +16 -0
  43. package/node_modules/toolcraft-design/dist/screen/style.js +55 -0
  44. package/node_modules/toolcraft-design/dist/terminal/driver.d.ts +33 -0
  45. package/node_modules/toolcraft-design/dist/terminal/driver.js +61 -0
  46. package/node_modules/toolcraft-design/dist/terminal/input.d.ts +25 -0
  47. package/node_modules/toolcraft-design/dist/terminal/input.js +181 -0
  48. package/node_modules/toolcraft-design/dist/terminal/output.d.ts +8 -0
  49. package/node_modules/toolcraft-design/dist/terminal/output.js +42 -0
  50. package/node_modules/toolcraft-schema/package.json +1 -1
  51. package/package.json +3 -3
  52. package/node_modules/toolcraft-design/dist/explorer/two-pane.d.ts +0 -102
  53. package/node_modules/toolcraft-design/dist/explorer/two-pane.js +0 -510
  54. package/node_modules/toolcraft-design/dist/run-two-pane-explorer.d.ts +0 -2
  55. package/node_modules/toolcraft-design/dist/run-two-pane-explorer.js +0 -1
@@ -0,0 +1,181 @@
1
+ const ESC = 0x1b;
2
+ const PASTE_START = Buffer.from("\u001b[200~");
3
+ const PASTE_END = Buffer.from("\u001b[201~");
4
+ export function createInputParser(options = {}) {
5
+ const escTimeoutMs = options.escTimeoutMs ?? 50;
6
+ let pending = Buffer.alloc(0);
7
+ let paste = false;
8
+ let timer;
9
+ let escapeReady = false;
10
+ const clearEscapeTimer = () => {
11
+ if (timer !== undefined)
12
+ clearTimeout(timer);
13
+ timer = undefined;
14
+ escapeReady = false;
15
+ };
16
+ const armEscapeTimer = () => {
17
+ if (timer !== undefined)
18
+ return;
19
+ timer = setTimeout(() => {
20
+ timer = undefined;
21
+ if (options.onEvent !== undefined && pending.length === 1 && pending[0] === ESC) {
22
+ pending = pending.subarray(1);
23
+ options.onEvent(key("escape"));
24
+ }
25
+ else {
26
+ escapeReady = true;
27
+ }
28
+ }, escTimeoutMs);
29
+ };
30
+ const parse = () => {
31
+ const events = [];
32
+ while (pending.length > 0) {
33
+ if (paste) {
34
+ const end = pending.indexOf(PASTE_END);
35
+ if (end < 0)
36
+ break;
37
+ events.push({ type: "paste", text: pending.subarray(0, end).toString("utf8") });
38
+ pending = pending.subarray(end + PASTE_END.length);
39
+ paste = false;
40
+ continue;
41
+ }
42
+ if (pending[0] === ESC) {
43
+ if (pending.length === 1) {
44
+ if (escapeReady) {
45
+ pending = pending.subarray(1);
46
+ escapeReady = false;
47
+ events.push(key("escape"));
48
+ }
49
+ else {
50
+ armEscapeTimer();
51
+ }
52
+ break;
53
+ }
54
+ clearEscapeTimer();
55
+ if (pending.subarray(0, PASTE_START.length).equals(PASTE_START)) {
56
+ pending = pending.subarray(PASTE_START.length);
57
+ paste = true;
58
+ continue;
59
+ }
60
+ if (pending[1] === 0x5b) {
61
+ const final = findCsiFinal(pending);
62
+ if (final < 0)
63
+ break;
64
+ const sequence = pending.subarray(0, final + 1).toString("ascii");
65
+ pending = pending.subarray(final + 1);
66
+ const event = parseCsi(sequence);
67
+ if (event !== undefined)
68
+ events.push(event);
69
+ continue;
70
+ }
71
+ if (pending[1] === 0x4f) {
72
+ if (pending.length < 3)
73
+ break;
74
+ const name = navigationName(String.fromCharCode(pending[2]));
75
+ pending = pending.subarray(3);
76
+ if (name !== undefined)
77
+ events.push(key(name));
78
+ continue;
79
+ }
80
+ if (pending[1] === 0x03) {
81
+ pending = pending.subarray(1);
82
+ events.push(key("escape"));
83
+ continue;
84
+ }
85
+ const decoded = decodeFirstCharacter(pending.subarray(1));
86
+ if (decoded === undefined)
87
+ break;
88
+ pending = pending.subarray(1 + decoded.bytes);
89
+ events.push(character(decoded.ch, true));
90
+ continue;
91
+ }
92
+ const byte = pending[0];
93
+ if (byte < 0x20 || byte === 0x7f) {
94
+ pending = pending.subarray(1);
95
+ events.push(control(byte));
96
+ continue;
97
+ }
98
+ const decoded = decodeFirstCharacter(pending);
99
+ if (decoded === undefined)
100
+ break;
101
+ pending = pending.subarray(decoded.bytes);
102
+ events.push(character(decoded.ch, false));
103
+ }
104
+ return events;
105
+ };
106
+ return {
107
+ feed(chunk) {
108
+ if (chunk.length > 0) {
109
+ if (pending.length === 1 && pending[0] === ESC)
110
+ clearEscapeTimer();
111
+ pending = pending.length === 0 ? Buffer.from(chunk) : Buffer.concat([pending, chunk]);
112
+ }
113
+ return parse();
114
+ },
115
+ flush() {
116
+ return parse();
117
+ },
118
+ destroy() {
119
+ clearEscapeTimer();
120
+ pending = Buffer.alloc(0);
121
+ }
122
+ };
123
+ }
124
+ function findCsiFinal(input) {
125
+ for (let index = 2; index < input.length; index += 1) {
126
+ const byte = input[index];
127
+ if (byte >= 0x40 && byte <= 0x7e)
128
+ return index;
129
+ }
130
+ return -1;
131
+ }
132
+ function parseCsi(sequence) {
133
+ if (sequence.startsWith("\u001b[<") && (sequence.endsWith("M") || sequence.endsWith("m"))) {
134
+ const fields = sequence.slice(3, -1).split(";");
135
+ if ((fields[0] === "64" || fields[0] === "65") && fields.length === 3) {
136
+ return {
137
+ type: "wheel",
138
+ direction: fields[0] === "64" ? "up" : "down",
139
+ x: Number(fields[1]) - 1,
140
+ y: Number(fields[2]) - 1
141
+ };
142
+ }
143
+ }
144
+ const final = sequence.at(-1);
145
+ const name = navigationName(final) ?? ({ "5": "pageup", "6": "pagedown" }[sequence.slice(2, -1)]);
146
+ if (name === undefined)
147
+ return undefined;
148
+ const modifier = sequence.includes(";5") ? { ctrl: true } : {};
149
+ return key(name, modifier);
150
+ }
151
+ function navigationName(final) {
152
+ return { A: "up", B: "down", C: "right", D: "left", H: "home", F: "end" }[final];
153
+ }
154
+ function control(byte) {
155
+ if (byte === 0x0d || byte === 0x0a)
156
+ return key("enter");
157
+ if (byte === 0x09)
158
+ return key("tab");
159
+ if (byte === 0x7f || byte === 0x08)
160
+ return key("backspace");
161
+ if (byte === 0x20)
162
+ return character(" ", false);
163
+ if (byte >= 1 && byte <= 26)
164
+ return key(String.fromCharCode(96 + byte), { ctrl: true });
165
+ return key(`control-${byte}`);
166
+ }
167
+ function character(ch, alt) {
168
+ return { type: "key", name: ch, ch, ctrl: false, alt, shift: ch.toLocaleUpperCase() === ch && ch.toLocaleLowerCase() !== ch };
169
+ }
170
+ function key(name, flags = {}) {
171
+ return { type: "key", name, ctrl: flags.ctrl ?? false, alt: flags.alt ?? false, shift: flags.shift ?? false };
172
+ }
173
+ function decodeFirstCharacter(input) {
174
+ if (input.length === 0)
175
+ return undefined;
176
+ const first = input[0];
177
+ const bytes = first < 0x80 ? 1 : first < 0xe0 ? 2 : first < 0xf0 ? 3 : 4;
178
+ if (input.length < bytes)
179
+ return undefined;
180
+ return { ch: input.subarray(0, bytes).toString("utf8"), bytes };
181
+ }
@@ -0,0 +1,8 @@
1
+ export interface FrameWriter {
2
+ open(): void;
3
+ close(): void;
4
+ writeFrame(ansi: string): void;
5
+ }
6
+ export declare function createFrameWriter(stream: {
7
+ write(value: string): boolean;
8
+ }): FrameWriter;
@@ -0,0 +1,42 @@
1
+ const OPEN = "\u001b[?1049h\u001b[?25l\u001b[?2004h\u001b[?1000h\u001b[?1006h\u001b[?7l";
2
+ const CLOSE = "\u001b[0m\u001b[?7h\u001b[?1006l\u001b[?1000l\u001b[?2004l\u001b[?25h\u001b[?1049l";
3
+ export function createFrameWriter(stream) {
4
+ let opened = false;
5
+ const interrupt = () => terminateWith("SIGINT");
6
+ const terminate = () => terminateWith("SIGTERM");
7
+ const fatal = (error) => {
8
+ close();
9
+ throw error;
10
+ };
11
+ function terminateWith(signal) {
12
+ close();
13
+ process.kill(process.pid, signal);
14
+ }
15
+ function open() {
16
+ if (opened)
17
+ return;
18
+ opened = true;
19
+ stream.write(OPEN);
20
+ process.once("SIGINT", interrupt);
21
+ process.once("SIGTERM", terminate);
22
+ process.once("uncaughtException", fatal);
23
+ }
24
+ function close() {
25
+ if (!opened)
26
+ return;
27
+ opened = false;
28
+ process.removeListener("SIGINT", interrupt);
29
+ process.removeListener("SIGTERM", terminate);
30
+ process.removeListener("uncaughtException", fatal);
31
+ stream.write(CLOSE);
32
+ }
33
+ return {
34
+ open,
35
+ close,
36
+ writeFrame(ansi) {
37
+ if (!opened || ansi.length === 0)
38
+ return;
39
+ stream.write(`\u001b[?2026h${ansi}\u001b[?2026l`);
40
+ }
41
+ };
42
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.151",
3
+ "version": "0.0.153",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-openapi",
3
- "version": "0.0.151",
3
+ "version": "0.0.153",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "toolcraft-openapi-generate": "dist/bin/generate.js"
31
31
  },
32
32
  "dependencies": {
33
- "toolcraft": "0.0.151",
33
+ "toolcraft": "0.0.153",
34
34
  "auth-store": "^0.0.1",
35
35
  "fast-string-width": "^3.0.2",
36
36
  "fast-wrap-ansi": "^0.2.0",
@@ -46,7 +46,7 @@
46
46
  "directory": "packages/toolcraft-openapi"
47
47
  },
48
48
  "optionalDependencies": {
49
- "toolcraft-schema": "0.0.151",
49
+ "toolcraft-schema": "0.0.153",
50
50
  "toolcraft-design": "*",
51
51
  "@poe-code/frontmatter": "*"
52
52
  },
@@ -1,102 +0,0 @@
1
- import { ScreenBuffer } from "../dashboard/buffer.js";
2
- import { type TerminalDriver } from "../dashboard/terminal.js";
3
- import type { Tone } from "./state.js";
4
- export interface TwoPaneRow {
5
- id: string;
6
- title: string;
7
- subtitle?: string;
8
- badge?: {
9
- text: string;
10
- tone?: Tone;
11
- };
12
- }
13
- export interface TwoPaneDefinition {
14
- id: string;
15
- title: string;
16
- rows: () => Promise<TwoPaneRow[]>;
17
- emptyHint?: string;
18
- }
19
- export interface TwoPaneActionContext<R> {
20
- activePane: TwoPanePaneState;
21
- inactivePane: TwoPanePaneState;
22
- row: TwoPaneRow;
23
- rows: TwoPaneRow[];
24
- refresh: () => Promise<void>;
25
- suspendAnd: <T>(fn: () => Promise<T>) => Promise<T>;
26
- toast: (message: string, tone?: Tone) => void;
27
- exit: (result?: R | null) => void;
28
- }
29
- export interface TwoPaneAction<R> {
30
- id: string;
31
- label: string;
32
- key: string | string[];
33
- handler: (ctx: TwoPaneActionContext<R>) => void | Promise<void>;
34
- }
35
- export interface TwoPaneExplorerConfig<R> {
36
- title: string;
37
- panes: [TwoPaneDefinition, TwoPaneDefinition];
38
- actions: TwoPaneAction<R>[];
39
- refresh?: () => void | Promise<void>;
40
- trace?: (record: TwoPaneTraceRecord) => void | Promise<void>;
41
- }
42
- export interface TwoPaneTraceRecord {
43
- event: string;
44
- [key: string]: unknown;
45
- }
46
- export interface TwoPanePaneState {
47
- id: string;
48
- title: string;
49
- rows: TwoPaneRow[];
50
- cursor: number;
51
- selected: Set<string>;
52
- filter: string;
53
- emptyHint: string;
54
- }
55
- export interface TwoPaneExplorerState {
56
- title: string;
57
- panes: [TwoPanePaneState, TwoPanePaneState];
58
- activePaneIndex: 0 | 1;
59
- filterFocused: boolean;
60
- toast: {
61
- message: string;
62
- tone: Tone;
63
- } | null;
64
- size: {
65
- cols: number;
66
- rows: number;
67
- };
68
- }
69
- export declare function runTwoPaneExplorer<R = void>(config: TwoPaneExplorerConfig<R>): Promise<R | null>;
70
- export declare class TwoPaneExplorerRuntime<R> {
71
- private readonly config;
72
- private readonly driver;
73
- private state;
74
- private unsubscribeKeypress;
75
- private unsubscribeResize;
76
- private toastTimer;
77
- private stopped;
78
- private rowsRequestToken;
79
- private settle;
80
- constructor(config: TwoPaneExplorerConfig<R>, driver: TerminalDriver);
81
- run(): Promise<R | null>;
82
- private startTerminal;
83
- private subscribeKeypress;
84
- private pauseKeypress;
85
- private loadRows;
86
- private refresh;
87
- private dispatchKey;
88
- private dispatchFilterKey;
89
- private moveCursor;
90
- private setCursor;
91
- private toggleSelection;
92
- private runAction;
93
- private suspendAnd;
94
- private showToast;
95
- private activePane;
96
- private inactivePane;
97
- private render;
98
- private exit;
99
- private fail;
100
- private trace;
101
- }
102
- export declare function renderTwoPaneExplorer<R>(state: TwoPaneExplorerState, actions: TwoPaneAction<R>[], screen: ScreenBuffer): void;