@pablozaiden/terminatui 0.2.0 → 0.3.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.
Files changed (181) hide show
  1. package/README.md +64 -43
  2. package/package.json +11 -8
  3. package/src/__tests__/application.test.ts +87 -68
  4. package/src/__tests__/buildCliCommand.test.ts +99 -119
  5. package/src/__tests__/builtins.test.ts +27 -75
  6. package/src/__tests__/command.test.ts +100 -131
  7. package/src/__tests__/configOnChange.test.ts +63 -0
  8. package/src/__tests__/context.test.ts +1 -26
  9. package/src/__tests__/helpCore.test.ts +227 -0
  10. package/src/__tests__/parser.test.ts +98 -244
  11. package/src/__tests__/registry.test.ts +33 -160
  12. package/src/__tests__/schemaToFields.test.ts +75 -158
  13. package/src/builtins/help.ts +12 -4
  14. package/src/builtins/settings.ts +18 -32
  15. package/src/builtins/version.ts +3 -3
  16. package/src/cli/output/colors.ts +1 -1
  17. package/src/cli/parser.ts +26 -95
  18. package/src/core/application.ts +192 -110
  19. package/src/core/command.ts +26 -9
  20. package/src/core/context.ts +31 -20
  21. package/src/core/help.ts +24 -18
  22. package/src/core/knownCommands.ts +13 -0
  23. package/src/core/logger.ts +39 -42
  24. package/src/core/registry.ts +5 -12
  25. package/src/index.ts +22 -137
  26. package/src/tui/TuiApplication.tsx +63 -120
  27. package/src/tui/TuiRoot.tsx +135 -0
  28. package/src/tui/adapters/factory.ts +19 -0
  29. package/src/tui/adapters/ink/InkRenderer.tsx +139 -0
  30. package/src/tui/adapters/ink/components/Button.tsx +12 -0
  31. package/src/tui/adapters/ink/components/Code.tsx +6 -0
  32. package/src/tui/adapters/ink/components/CodeHighlight.tsx +6 -0
  33. package/src/tui/adapters/ink/components/Container.tsx +5 -0
  34. package/src/tui/adapters/ink/components/Field.tsx +12 -0
  35. package/src/tui/adapters/ink/components/Label.tsx +24 -0
  36. package/src/tui/adapters/ink/components/MenuButton.tsx +12 -0
  37. package/src/tui/adapters/ink/components/MenuItem.tsx +17 -0
  38. package/src/tui/adapters/ink/components/Overlay.tsx +5 -0
  39. package/src/tui/adapters/ink/components/Panel.tsx +15 -0
  40. package/src/tui/adapters/ink/components/ScrollView.tsx +5 -0
  41. package/src/tui/adapters/ink/components/Select.tsx +44 -0
  42. package/src/tui/adapters/ink/components/Spacer.tsx +15 -0
  43. package/src/tui/adapters/ink/components/Spinner.tsx +5 -0
  44. package/src/tui/adapters/ink/components/TextInput.tsx +22 -0
  45. package/src/tui/adapters/ink/components/Value.tsx +7 -0
  46. package/src/tui/adapters/ink/keyboard.ts +97 -0
  47. package/src/tui/adapters/ink/utils.ts +16 -0
  48. package/src/tui/adapters/opentui/OpenTuiRenderer.tsx +119 -0
  49. package/src/tui/adapters/opentui/components/Button.tsx +13 -0
  50. package/src/tui/adapters/opentui/components/Code.tsx +12 -0
  51. package/src/tui/adapters/opentui/components/CodeHighlight.tsx +24 -0
  52. package/src/tui/adapters/opentui/components/Container.tsx +56 -0
  53. package/src/tui/adapters/opentui/components/Field.tsx +18 -0
  54. package/src/tui/adapters/opentui/components/Label.tsx +15 -0
  55. package/src/tui/adapters/opentui/components/MenuButton.tsx +14 -0
  56. package/src/tui/adapters/opentui/components/MenuItem.tsx +29 -0
  57. package/src/tui/adapters/opentui/components/Overlay.tsx +21 -0
  58. package/src/tui/adapters/opentui/components/Panel.tsx +78 -0
  59. package/src/tui/adapters/opentui/components/ScrollView.tsx +85 -0
  60. package/src/tui/adapters/opentui/components/Select.tsx +59 -0
  61. package/src/tui/adapters/opentui/components/Spacer.tsx +5 -0
  62. package/src/tui/adapters/opentui/components/Spinner.tsx +12 -0
  63. package/src/tui/adapters/opentui/components/TextInput.tsx +13 -0
  64. package/src/tui/adapters/opentui/components/Value.tsx +13 -0
  65. package/src/tui/{hooks → adapters/opentui/hooks}/useSpinner.ts +2 -11
  66. package/src/tui/adapters/opentui/keyboard.ts +61 -0
  67. package/src/tui/adapters/types.ts +71 -0
  68. package/src/tui/components/ActionButton.tsx +0 -36
  69. package/src/tui/components/CommandSelector.tsx +45 -92
  70. package/src/tui/components/ConfigForm.tsx +68 -42
  71. package/src/tui/components/FieldRow.tsx +0 -30
  72. package/src/tui/components/Header.tsx +14 -13
  73. package/src/tui/components/JsonHighlight.tsx +10 -17
  74. package/src/tui/components/ModalBase.tsx +38 -0
  75. package/src/tui/components/ResultsPanel.tsx +27 -36
  76. package/src/tui/components/StatusBar.tsx +24 -39
  77. package/src/tui/components/logColors.ts +12 -0
  78. package/src/tui/context/ClipboardContext.tsx +87 -0
  79. package/src/tui/context/ExecutorContext.tsx +139 -0
  80. package/src/tui/context/KeyboardContext.tsx +85 -71
  81. package/src/tui/context/LogsContext.tsx +35 -0
  82. package/src/tui/context/NavigationContext.tsx +194 -0
  83. package/src/tui/context/RendererContext.tsx +20 -0
  84. package/src/tui/context/TuiAppContext.tsx +58 -0
  85. package/src/tui/hooks/useActiveKeyHandler.ts +75 -0
  86. package/src/tui/hooks/useBackHandler.ts +34 -0
  87. package/src/tui/hooks/useClipboard.ts +40 -25
  88. package/src/tui/hooks/useClipboardProvider.ts +42 -0
  89. package/src/tui/hooks/useGlobalKeyHandler.ts +54 -0
  90. package/src/tui/modals/CliModal.tsx +82 -0
  91. package/src/tui/modals/EditorModal.tsx +207 -0
  92. package/src/tui/modals/LogsModal.tsx +98 -0
  93. package/src/tui/registry.ts +102 -0
  94. package/src/tui/screens/CommandSelectScreen.tsx +162 -0
  95. package/src/tui/screens/ConfigScreen.tsx +165 -0
  96. package/src/tui/screens/ErrorScreen.tsx +58 -0
  97. package/src/tui/screens/ResultsScreen.tsx +68 -0
  98. package/src/tui/screens/RunningScreen.tsx +72 -0
  99. package/src/tui/screens/ScreenBase.ts +6 -0
  100. package/src/tui/semantic/Button.tsx +7 -0
  101. package/src/tui/semantic/Code.tsx +7 -0
  102. package/src/tui/semantic/CodeHighlight.tsx +7 -0
  103. package/src/tui/semantic/Container.tsx +7 -0
  104. package/src/tui/semantic/Field.tsx +7 -0
  105. package/src/tui/semantic/Label.tsx +7 -0
  106. package/src/tui/semantic/MenuButton.tsx +7 -0
  107. package/src/tui/semantic/MenuItem.tsx +7 -0
  108. package/src/tui/semantic/Overlay.tsx +7 -0
  109. package/src/tui/semantic/Panel.tsx +7 -0
  110. package/src/tui/semantic/ScrollView.tsx +9 -0
  111. package/src/tui/semantic/Select.tsx +7 -0
  112. package/src/tui/semantic/Spacer.tsx +7 -0
  113. package/src/tui/semantic/Spinner.tsx +7 -0
  114. package/src/tui/semantic/TextInput.tsx +7 -0
  115. package/src/tui/semantic/Value.tsx +7 -0
  116. package/src/tui/semantic/types.ts +195 -0
  117. package/src/tui/theme.ts +25 -14
  118. package/src/tui/utils/buildCliCommand.ts +1 -0
  119. package/src/tui/utils/getEnumKeys.ts +3 -0
  120. package/src/tui/utils/parameterPersistence.ts +1 -0
  121. package/src/types/command.ts +0 -60
  122. package/.devcontainer/devcontainer.json +0 -19
  123. package/.devcontainer/install-prerequisites.sh +0 -49
  124. package/.github/workflows/copilot-setup-steps.yml +0 -32
  125. package/.github/workflows/pull-request.yml +0 -27
  126. package/.github/workflows/release-npm-package.yml +0 -81
  127. package/AGENTS.md +0 -31
  128. package/bun.lock +0 -236
  129. package/examples/tui-app/commands/config/app/get.ts +0 -66
  130. package/examples/tui-app/commands/config/app/index.ts +0 -27
  131. package/examples/tui-app/commands/config/app/set.ts +0 -86
  132. package/examples/tui-app/commands/config/index.ts +0 -32
  133. package/examples/tui-app/commands/config/user/get.ts +0 -65
  134. package/examples/tui-app/commands/config/user/index.ts +0 -27
  135. package/examples/tui-app/commands/config/user/set.ts +0 -61
  136. package/examples/tui-app/commands/greet.ts +0 -76
  137. package/examples/tui-app/commands/index.ts +0 -4
  138. package/examples/tui-app/commands/math.ts +0 -115
  139. package/examples/tui-app/commands/status.ts +0 -77
  140. package/examples/tui-app/index.ts +0 -35
  141. package/guides/01-hello-world.md +0 -96
  142. package/guides/02-adding-options.md +0 -103
  143. package/guides/03-multiple-commands.md +0 -163
  144. package/guides/04-subcommands.md +0 -206
  145. package/guides/05-interactive-tui.md +0 -194
  146. package/guides/06-config-validation.md +0 -264
  147. package/guides/07-async-cancellation.md +0 -336
  148. package/guides/08-complete-application.md +0 -537
  149. package/guides/README.md +0 -74
  150. package/src/__tests__/colors.test.ts +0 -127
  151. package/src/__tests__/commandClass.test.ts +0 -130
  152. package/src/__tests__/help.test.ts +0 -412
  153. package/src/__tests__/registryNew.test.ts +0 -160
  154. package/src/__tests__/table.test.ts +0 -146
  155. package/src/__tests__/tui.test.ts +0 -26
  156. package/src/builtins/index.ts +0 -4
  157. package/src/cli/help.ts +0 -174
  158. package/src/cli/index.ts +0 -3
  159. package/src/cli/output/index.ts +0 -2
  160. package/src/cli/output/table.ts +0 -141
  161. package/src/commands/help.ts +0 -50
  162. package/src/commands/index.ts +0 -1
  163. package/src/components/index.ts +0 -147
  164. package/src/core/index.ts +0 -15
  165. package/src/hooks/index.ts +0 -131
  166. package/src/registry/commandRegistry.ts +0 -77
  167. package/src/registry/index.ts +0 -1
  168. package/src/tui/TuiApp.tsx +0 -619
  169. package/src/tui/app.ts +0 -29
  170. package/src/tui/components/CliModal.tsx +0 -81
  171. package/src/tui/components/EditorModal.tsx +0 -177
  172. package/src/tui/components/LogsPanel.tsx +0 -86
  173. package/src/tui/components/index.ts +0 -13
  174. package/src/tui/context/index.ts +0 -7
  175. package/src/tui/hooks/index.ts +0 -35
  176. package/src/tui/hooks/useKeyboardHandler.ts +0 -91
  177. package/src/tui/hooks/useLogStream.ts +0 -96
  178. package/src/tui/index.ts +0 -65
  179. package/src/tui/utils/index.ts +0 -13
  180. package/src/types/index.ts +0 -1
  181. package/tsconfig.json +0 -25
@@ -0,0 +1,7 @@
1
+ import type { LabelProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Label(props: LabelProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Label(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { MenuButtonProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function MenuButton(props: MenuButtonProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.MenuButton(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { MenuItemProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function MenuItem(props: MenuItemProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.MenuItem(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { OverlayProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Overlay(props: OverlayProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Overlay(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { PanelProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Panel(props: PanelProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Panel(props);
7
+ }
@@ -0,0 +1,9 @@
1
+ import type { ScrollViewProps, ScrollViewRef } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function ScrollView(props: ScrollViewProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.ScrollView(props);
7
+ }
8
+
9
+ export type { ScrollViewRef };
@@ -0,0 +1,7 @@
1
+ import type { SelectProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Select(props: SelectProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Select(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { SpacerProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Spacer(props: SpacerProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Spacer(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { SpinnerProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Spinner(props: SpinnerProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Spinner(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { TextInputProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function TextInput(props: TextInputProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.TextInput(props);
7
+ }
@@ -0,0 +1,7 @@
1
+ import type { ValueProps } from "./types.ts";
2
+ import { useRenderer } from "../context/RendererContext.tsx";
3
+
4
+ export function Value(props: ValueProps) {
5
+ const renderer = useRenderer();
6
+ return renderer.components.Value(props);
7
+ }
@@ -0,0 +1,195 @@
1
+ import type { ReactNode } from "react";
2
+
3
+ export type Align = "flex-start" | "center" | "flex-end" | "stretch";
4
+ export type Justify = "flex-start" | "center" | "flex-end" | "space-between" | "space-around" | "space-evenly";
5
+ export type FlexDirection = "row" | "column";
6
+
7
+ export interface Spacing {
8
+ top?: number;
9
+ right?: number;
10
+ bottom?: number;
11
+ left?: number;
12
+ }
13
+
14
+ export interface ThemeConfig {
15
+ colors: {
16
+ background: string;
17
+ panelBackground: string;
18
+ overlay: string;
19
+
20
+ text: string;
21
+ mutedText: string;
22
+ inverseText: string;
23
+
24
+ border: string;
25
+ focusBorder: string;
26
+
27
+ primary: string;
28
+ primaryText: string;
29
+
30
+ success: string;
31
+ warning: string;
32
+ error: string;
33
+
34
+ value: string;
35
+ code: string;
36
+
37
+ selectionBackground: string;
38
+ selectionText: string;
39
+ };
40
+ }
41
+
42
+ export type SemanticColor = keyof ThemeConfig["colors"];
43
+
44
+ export interface LayoutProps {
45
+ flex?: number;
46
+ width?: number | string;
47
+ height?: number | string;
48
+
49
+ flexDirection?: FlexDirection;
50
+ alignItems?: Align;
51
+ justifyContent?: Justify;
52
+
53
+ gap?: number;
54
+ padding?: number | Spacing;
55
+
56
+ /** When set, should prevent the node from shrinking in flex layouts. */
57
+ noShrink?: boolean;
58
+ }
59
+
60
+ export type PanelSurface = "panel" | "overlay";
61
+
62
+ export interface PanelProps extends LayoutProps {
63
+ title?: string;
64
+ focused?: boolean;
65
+ border?: boolean;
66
+ surface?: PanelSurface;
67
+
68
+ /** Renderer-level compact styling (e.g. no default padding). */
69
+ dense?: boolean;
70
+
71
+ children?: ReactNode;
72
+ }
73
+
74
+ export interface ContainerProps extends LayoutProps {
75
+ children?: ReactNode;
76
+ }
77
+
78
+ export interface ScrollViewRef {
79
+ scrollToTop: () => void;
80
+ scrollToBottom: () => void;
81
+ scrollToIndex: (index: number) => void;
82
+ }
83
+
84
+ export interface ScrollViewProps extends LayoutProps {
85
+ axis?: "vertical" | "horizontal" | "both";
86
+ stickyToEnd?: boolean;
87
+ focused?: boolean;
88
+ scrollRef?: (ref: ScrollViewRef | null) => void;
89
+ children?: ReactNode;
90
+ }
91
+
92
+ export interface OverlayProps {
93
+ zIndex?: number;
94
+ top?: number | string;
95
+ left?: number | string;
96
+ right?: number | string;
97
+ bottom?: number | string;
98
+ width?: number | string;
99
+ height?: number | string;
100
+ children?: ReactNode;
101
+ }
102
+
103
+ export interface SpacerProps {
104
+ size: number;
105
+ axis?: "horizontal" | "vertical";
106
+ }
107
+
108
+ export interface SpinnerProps {
109
+ active: boolean;
110
+ }
111
+
112
+ export interface LabelProps {
113
+ color?: SemanticColor;
114
+ bold?: boolean;
115
+ italic?: boolean;
116
+ wrap?: boolean;
117
+ children: ReactNode;
118
+ }
119
+
120
+ export interface ValueProps {
121
+ color?: SemanticColor;
122
+ truncate?: boolean;
123
+ children: ReactNode;
124
+ }
125
+
126
+ export interface CodeProps {
127
+ color?: SemanticColor;
128
+ children: string;
129
+ }
130
+
131
+ export type CodeTokenType =
132
+ | "punctuation"
133
+ | "string"
134
+ | "number"
135
+ | "boolean"
136
+ | "null"
137
+ | "key"
138
+ | "unknown";
139
+
140
+ export interface CodeToken {
141
+ type: CodeTokenType;
142
+ value: string;
143
+ }
144
+
145
+ export interface CodeHighlightProps {
146
+ tokens: CodeToken[];
147
+ }
148
+
149
+ export interface FieldProps {
150
+ label: string;
151
+ value: ReactNode;
152
+ selected?: boolean;
153
+ onActivate?: () => void;
154
+ }
155
+
156
+ export interface TextInputProps {
157
+ value: string;
158
+ placeholder?: string;
159
+ focused?: boolean;
160
+ onChange: (value: string) => void;
161
+ onSubmit?: () => void;
162
+ }
163
+
164
+ export interface SelectOption {
165
+ label: string;
166
+ value: string;
167
+ }
168
+
169
+ export interface SelectProps {
170
+ options: SelectOption[];
171
+ value: string;
172
+ focused?: boolean;
173
+ onChange: (value: string) => void;
174
+ onSubmit?: () => void;
175
+ }
176
+
177
+ export interface ButtonProps {
178
+ label: string;
179
+ selected?: boolean;
180
+ onActivate?: () => void;
181
+ }
182
+
183
+ export interface MenuButtonProps {
184
+ label: string;
185
+ selected?: boolean;
186
+ onActivate?: () => void;
187
+ }
188
+
189
+ export interface MenuItemProps {
190
+ label: string;
191
+ description?: string;
192
+ suffix?: string;
193
+ selected?: boolean;
194
+ onActivate?: () => void;
195
+ }
package/src/tui/theme.ts CHANGED
@@ -1,21 +1,32 @@
1
1
  /**
2
- * Default TUI theme colors.
2
+ * Default TUI theme.
3
+ *
4
+ * This is intentionally semantic: UI code should reference meanings
5
+ * (e.g. "error", "mutedText", "selectionBackground") rather than hardcoding colors.
3
6
  */
4
- export const Theme = {
5
- background: "#0b0c10",
7
+ export const SemanticColors = {
8
+ background: "#0f1117",
9
+ panelBackground: "#0f1117",
10
+ overlay: "#101218",
11
+
12
+ text: "#d6dde6",
13
+ mutedText: "#666666",
14
+ inverseText: "#0b0c10",
15
+
6
16
  border: "#2c2f36",
7
- borderFocused: "#5da9e9",
8
- borderSelected: "#61afef",
9
- label: "#c0cad6",
10
- value: "#98c379",
11
- actionButton: "#a0e8af",
12
- header: "#a8b3c1",
13
- statusText: "#d6dde6",
14
- overlay: "#0e1117",
15
- overlayTitle: "#e5c07b",
16
- error: "#f78888",
17
+ focusBorder: "#5da9e9",
18
+
19
+ primary: "#61afef",
20
+ primaryText: "#0b0c10",
21
+
17
22
  success: "#98c379",
18
23
  warning: "#f5c542",
24
+ error: "#f78888",
25
+
26
+ value: "#98c379",
27
+ code: "#c0cad6",
28
+
29
+ selectionBackground: "#61afef",
30
+ selectionText: "#0b0c10",
19
31
  } as const;
20
32
 
21
- export type ThemeColors = typeof Theme;
@@ -79,6 +79,7 @@ export function buildCliCommand<T extends OptionSchema>(
79
79
  }
80
80
  }
81
81
 
82
+ parts.push("--mode", "cli");
82
83
  return parts.join(" ");
83
84
  }
84
85
 
@@ -0,0 +1,3 @@
1
+ export function getEnumKeys<T extends Record<string, string | number>>(enumObj: T): string[] {
2
+ return Object.keys(enumObj).filter((key) => Number.isNaN(Number(key)));
3
+ }
@@ -47,6 +47,7 @@ export function loadPersistedParameters(
47
47
  return JSON.parse(content) as Record<string, unknown>;
48
48
  }
49
49
  } catch (error) {
50
+
50
51
  // Silently ignore errors - just return empty object
51
52
  console.error(`Failed to load persisted parameters: ${error}`);
52
53
  }
@@ -41,63 +41,3 @@ export type OptionValues<T extends OptionSchema> = {
41
41
  : unknown;
42
42
  };
43
43
 
44
- /**
45
- * Context passed to command executors
46
- */
47
- export interface CommandContext<T extends OptionSchema = OptionSchema> {
48
- options: OptionValues<T>;
49
- args: string[];
50
- commandPath: string[];
51
- }
52
-
53
- /**
54
- * Command executor function
55
- */
56
- export type CommandExecutor<T extends OptionSchema = OptionSchema> = (
57
- ctx: CommandContext<T>
58
- ) => void | Promise<void>;
59
-
60
- /**
61
- * Command definition
62
- */
63
- export interface Command<
64
- T extends OptionSchema = OptionSchema,
65
- R = void,
66
- > {
67
- name: string;
68
- description: string;
69
- aliases?: string[];
70
- hidden?: boolean;
71
- options?: T;
72
- subcommands?: Record<string, Command>;
73
- examples?: Array<{ command: string; description: string }>;
74
- execute: (ctx: CommandContext<T>) => R | Promise<R>;
75
- beforeExecute?: (ctx: CommandContext<T>) => void | Promise<void>;
76
- afterExecute?: (ctx: CommandContext<T>) => void | Promise<void>;
77
- }
78
-
79
- /**
80
- * TUI command with a render function
81
- */
82
- export interface TuiCommand<T extends OptionSchema = OptionSchema>
83
- extends Omit<Command<T>, "execute"> {
84
- render: (ctx: CommandContext<T>) => React.ReactNode;
85
- }
86
-
87
- /**
88
- * Define a CLI command
89
- */
90
- export function defineCommand<T extends OptionSchema = OptionSchema>(
91
- config: Command<T>
92
- ): Command<T> {
93
- return config;
94
- }
95
-
96
- /**
97
- * Define a TUI command
98
- */
99
- export function defineTuiCommand<T extends OptionSchema = OptionSchema>(
100
- config: TuiCommand<T>
101
- ): TuiCommand<T> {
102
- return config;
103
- }
@@ -1,19 +0,0 @@
1
- {
2
- "name": "Ubuntu",
3
- "image": "mcr.microsoft.com/devcontainers/base:noble",
4
- "features": {
5
- "ghcr.io/devcontainers/features/github-cli:1": {},
6
- "ghcr.io/devcontainers/features/azure-cli:latest": {},
7
- "ghcr.io/devcontainers/features/docker-outside-of-docker": {}
8
- },
9
- "postCreateCommand": "./.devcontainer/install-prerequisites.sh",
10
- "customizations": {
11
- "vscode": {
12
- "extensions": [
13
- "oven.bun-vscode",
14
- "ms-azuretools.vscode-docker",
15
- "SanjulaGanepola.github-local-actions"
16
- ]
17
- }
18
- }
19
- }
@@ -1,49 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- set -e
4
-
5
- # if bun is not installed, install it
6
- if ! command -v bun &> /dev/null
7
- then
8
- echo "Bun not found, installing..."
9
-
10
- curl -fsSL https://bun.com/install | bash
11
-
12
- # manual fix for missing package.json issue
13
- if [ ! -f "$HOME/.bun/install/global/package.json" ]; then
14
- echo "Creating missing package.json for bun global..."
15
- mkdir -p "$HOME/.bun/install/global"
16
- echo '{}' > "$HOME/.bun/install/global/package.json"
17
- fi
18
-
19
-
20
- # add bun to PATH
21
- export PATH="$HOME/.bun/bin:$PATH"
22
- fi
23
-
24
- # if there is no symlink for node, create it
25
- if ! command -v node &> /dev/null
26
- then
27
- # discover the bun binary location
28
- bunBinary=$(which bun)
29
- echo "Bun binary located at: $bunBinary"
30
- echo "Creating symlink for node to bun..."
31
- mkdir -p $HOME/.local/bin
32
- ln -sf "$bunBinary" "$HOME/.local/bin/node"
33
- fi
34
-
35
- export BUN_INSTALL_BIN=$HOME/.bun/bin
36
- export BUN_INSTALL_GLOBAL_DIR=$HOME/.bun/global
37
-
38
- # Ensure dirs exist and are owned by the current user
39
- mkdir -p "$BUN_INSTALL_BIN" "$BUN_INSTALL_GLOBAL_DIR"
40
- export PATH="$HOME/.bun/bin:$HOME/.bun/global/bin:${PATH}"
41
-
42
- # add the paths to bashrc and zshrc
43
- echo 'export PATH="$HOME/.bun/bin:$HOME/.bun/global/bin:${PATH}" ' >> $HOME/.bashrc
44
- echo 'export PATH="$HOME/.bun/bin:$HOME/.bun/global/bin:${PATH}" '>> $HOME/.zshrc
45
-
46
- # ensure $HOME/.local/bin is in PATH for current session and future shells
47
- export PATH="$HOME/.local/bin:$PATH"
48
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.bashrc"
49
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$HOME/.zshrc"
@@ -1,32 +0,0 @@
1
- name: "Copilot Setup Steps"
2
-
3
- on:
4
- workflow_dispatch:
5
- push:
6
- paths:
7
- - .github/workflows/copilot-setup-steps.yml
8
- pull_request:
9
- paths:
10
- - .github/workflows/copilot-setup-steps.yml
11
-
12
- jobs:
13
- # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
14
- copilot-setup-steps:
15
- runs-on: ubuntu-latest
16
-
17
- permissions:
18
- contents: read
19
-
20
- steps:
21
- - name: Checkout repository
22
- uses: actions/checkout@v6
23
-
24
- - name: Install prerequisites
25
- run: |
26
- chmod +x ./.devcontainer/install-prerequisites.sh
27
- ./.devcontainer/install-prerequisites.sh
28
- echo "$HOME/.bun/bin" >> $GITHUB_PATH
29
- echo "$HOME/.bun/global/bin" >> $GITHUB_PATH
30
-
31
- - name: Install dependencies
32
- run: bun install
@@ -1,27 +0,0 @@
1
- name: Pull Request
2
-
3
- on:
4
- pull_request:
5
- branches: [ "main" ]
6
-
7
- jobs:
8
- test:
9
- runs-on: ubuntu-latest
10
- environment: PR
11
-
12
- steps:
13
- - name: Checkout repository
14
- uses: actions/checkout@v6
15
-
16
- - name: Install prerequisites
17
- run: |
18
- chmod +x .devcontainer/install-prerequisites.sh
19
- ./.devcontainer/install-prerequisites.sh
20
- echo "$HOME/.bun/bin" >> $GITHUB_PATH
21
- echo "$HOME/.bun/global/bin" >> $GITHUB_PATH
22
-
23
- - name: Install dependencies
24
- run: bun install
25
-
26
- - name: Run tests
27
- run: bun test
@@ -1,81 +0,0 @@
1
- name: Release NPM Package
2
-
3
- on:
4
- release:
5
- types: [published]
6
- workflow_dispatch:
7
- inputs:
8
- tag:
9
- description: 'Release tag (e.g., v1.2.3)'
10
- required: true
11
-
12
- jobs:
13
- publish:
14
- name: Publish Package
15
- runs-on: ubuntu-latest
16
- permissions:
17
- contents: read
18
- id-token: write
19
- steps:
20
- - name: Determine release tag
21
- id: get_tag
22
- run: |
23
- echo "Event name: ${{ github.event_name }}"
24
- if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
25
- TAG="${{ github.event.inputs.tag }}"
26
- else
27
- TAG="${{ github.event.release.tag_name }}"
28
- fi
29
-
30
- # if the tag is empty, exit with error
31
- if [ -z "$TAG" ]; then
32
- echo "Error: Tag is empty"
33
- exit 1
34
- fi
35
-
36
- # Strip 'v' prefix if present
37
- VERSION="${TAG#v}"
38
-
39
- echo "Using tag: $TAG"
40
- echo "Using version: $VERSION"
41
-
42
- echo "tag=$TAG" >> $GITHUB_OUTPUT
43
- echo "version=$VERSION" >> $GITHUB_OUTPUT
44
-
45
- - name: Checkout repository
46
- uses: actions/checkout@v6
47
- with:
48
- ref: ${{ steps.get_tag.outputs.tag }}
49
-
50
- - name: Install bun
51
- run: |
52
- curl -fsSL https://bun.com/install | bash
53
- echo "$HOME/.bun/bin" >> $GITHUB_PATH
54
-
55
- - uses: actions/setup-node@v4
56
- with:
57
- node-version: '24'
58
- registry-url: 'https://registry.npmjs.org'
59
-
60
- - name: Set package version
61
- run: |
62
- VERSION="${{ steps.get_tag.outputs.version }}"
63
- jq --arg version "$VERSION" '.version = $version' package.json > package.json.tmp && mv package.json.tmp package.json
64
-
65
- - name: Verify package version
66
- run: |
67
- EXPECTED_VERSION="${{ steps.get_tag.outputs.version }}"
68
- ACTUAL_VERSION=$(jq -r '.version' package.json)
69
- if [ "$EXPECTED_VERSION" != "$ACTUAL_VERSION" ]; then
70
- echo "Error: Version mismatch. Expected $EXPECTED_VERSION, got $ACTUAL_VERSION"
71
- exit 1
72
- fi
73
- echo "Version verified: $ACTUAL_VERSION"
74
-
75
- - name: Install dependencies
76
- run: bun install
77
- - name: Build package
78
- run: bun run build
79
-
80
- - name: Publish Package
81
- run: npm publish --no-build
package/AGENTS.md DELETED
@@ -1,31 +0,0 @@
1
- Default to using Bun instead of Node.js.
2
-
3
- - Use `bun <file>` instead of `node <file>` or `ts-node <file>`
4
- - Use `bun test` instead of `jest` or `vitest`
5
- - Use `bun build <file.html|file.ts|file.css>` instead of `webpack` or `esbuild`
6
- - Use `bun install` instead of `npm install` or `yarn install` or `pnpm install`
7
- - Use `bun run <script>` instead of `npm run <script>` or `yarn run <script>` or `pnpm run <script>`
8
- - Use `bunx <package> <command>` instead of `npx <package> <command>`
9
- - Bun automatically loads .env, so don't use dotenv.
10
-
11
- ## APIs
12
-
13
- - Prefer `Bun.file` over `node:fs`'s readFile/writeFile
14
- - Bun.$`ls` instead of execa.
15
-
16
- ## Testing
17
-
18
- Always run `bun run build` before running tests, to make sure there are no build errors.
19
- Use `bun run test` to run all the tests.
20
-
21
- Always run `bun run test` when you think you are done making changes.
22
-
23
- ```ts#index.test.ts
24
- import { test, expect } from "bun:test";
25
-
26
- test("hello world", () => {
27
- expect(1).toBe(1);
28
- });
29
- ```
30
-
31
- For more information, read the Bun API docs in `node_modules/bun-types/docs/**.mdx`.