@pablozaiden/terminatui 0.6.3 → 0.7.1
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/package.json +3 -3
- package/src/core/application.ts +79 -6
- package/src/core/builder.ts +66 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pablozaiden/terminatui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Terminal UI and Command Line Application Framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"url": "https://github.com/PabloZaiden/terminatui",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"test": "bun test"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@opentui/core": "0.1.
|
|
25
|
-
"@opentui/react": "0.1.
|
|
24
|
+
"@opentui/core": "0.1.87",
|
|
25
|
+
"@opentui/react": "0.1.87",
|
|
26
26
|
"ink": "6.6.0",
|
|
27
27
|
"ink-select-input": "6.2.0",
|
|
28
28
|
"ink-text-input": "6.0.0",
|
package/src/core/application.ts
CHANGED
|
@@ -58,8 +58,11 @@ export interface ApplicationConfig {
|
|
|
58
58
|
version: string;
|
|
59
59
|
/** Optional commit hash for version display (shows "(dev)" if not set) */
|
|
60
60
|
commitHash?: string;
|
|
61
|
-
/**
|
|
62
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Commands to register.
|
|
63
|
+
* Can be omitted and registered later via `registerCommands()`.
|
|
64
|
+
*/
|
|
65
|
+
commands?: AnyCommand[];
|
|
63
66
|
/** Default command when no args provided (by name) */
|
|
64
67
|
defaultCommand?: string;
|
|
65
68
|
/** Logger configuration */
|
|
@@ -88,6 +91,7 @@ export interface ApplicationHooks {
|
|
|
88
91
|
*
|
|
89
92
|
* @example
|
|
90
93
|
* ```typescript
|
|
94
|
+
* // Option 1: Pass commands in constructor (original API, still works)
|
|
91
95
|
* const app = new Application({
|
|
92
96
|
* name: "myapp",
|
|
93
97
|
* version: "1.0.0",
|
|
@@ -97,6 +101,25 @@ export interface ApplicationHooks {
|
|
|
97
101
|
*
|
|
98
102
|
* await app.run();
|
|
99
103
|
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```typescript
|
|
107
|
+
* // Option 2: Register commands dynamically after construction
|
|
108
|
+
* const app = new Application({
|
|
109
|
+
* name: "myapp",
|
|
110
|
+
* version: "1.0.0",
|
|
111
|
+
* });
|
|
112
|
+
*
|
|
113
|
+
* // Access context before registering commands
|
|
114
|
+
* app.context.setService("db", await connectToDb());
|
|
115
|
+
*
|
|
116
|
+
* // Register commands that may depend on context
|
|
117
|
+
* app.registerCommands([
|
|
118
|
+
* new DynamicCommand(app.context),
|
|
119
|
+
* ]);
|
|
120
|
+
*
|
|
121
|
+
* await app.run();
|
|
122
|
+
* ```
|
|
100
123
|
*/
|
|
101
124
|
export class Application {
|
|
102
125
|
readonly name: string;
|
|
@@ -127,6 +150,7 @@ export class Application {
|
|
|
127
150
|
|
|
128
151
|
private readonly defaultCommandName?: string;
|
|
129
152
|
private hooks: ApplicationHooks = {};
|
|
153
|
+
private commandsRegistered = false;
|
|
130
154
|
|
|
131
155
|
constructor(config: ApplicationConfig) {
|
|
132
156
|
this.name = config.name;
|
|
@@ -146,15 +170,57 @@ export class Application {
|
|
|
146
170
|
|
|
147
171
|
context.logger.silly(`Application initialized: ${this.name} v${this.version}`);
|
|
148
172
|
|
|
149
|
-
// Create registry
|
|
173
|
+
// Create registry
|
|
150
174
|
this.registry = new CommandRegistry();
|
|
151
|
-
|
|
175
|
+
|
|
176
|
+
// If commands were provided in config (even empty array), register them now
|
|
177
|
+
// This maintains backward compatibility - passing commands: [] still registers built-ins
|
|
178
|
+
if (config.commands !== undefined) {
|
|
179
|
+
this.registerCommands(config.commands);
|
|
180
|
+
}
|
|
152
181
|
}
|
|
153
182
|
|
|
154
183
|
/**
|
|
155
|
-
* Register commands
|
|
184
|
+
* Register commands with the application.
|
|
185
|
+
*
|
|
186
|
+
* This method can be called after construction to register commands dynamically.
|
|
187
|
+
* This is useful when commands depend on context or other runtime information.
|
|
188
|
+
*
|
|
189
|
+
* @param commands Array of commands to register
|
|
190
|
+
* @throws If commands have already been registered
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const app = new Application({
|
|
195
|
+
* name: "myapp",
|
|
196
|
+
* version: "1.0.0",
|
|
197
|
+
* });
|
|
198
|
+
*
|
|
199
|
+
* // Access context to set up services
|
|
200
|
+
* app.context.setService("db", await connectToDb());
|
|
201
|
+
*
|
|
202
|
+
* // Register commands that depend on context
|
|
203
|
+
* app.registerCommands([
|
|
204
|
+
* new DbQueryCommand(),
|
|
205
|
+
* new DbMigrateCommand(),
|
|
206
|
+
* ]);
|
|
207
|
+
*
|
|
208
|
+
* await app.run();
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
registerCommands(commands: AnyCommand[]): void {
|
|
212
|
+
if (this.commandsRegistered) {
|
|
213
|
+
throw new Error("Commands have already been registered. registerCommands() can only be called once.");
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.commandsRegistered = true;
|
|
217
|
+
this.doRegisterCommands(commands);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Internal method to register commands and inject help subcommands.
|
|
156
222
|
*/
|
|
157
|
-
private
|
|
223
|
+
private doRegisterCommands(commands: AnyCommand[]): void {
|
|
158
224
|
this.assertNoReservedCommands(commands);
|
|
159
225
|
|
|
160
226
|
// Register version command at top level
|
|
@@ -244,6 +310,13 @@ export class Application {
|
|
|
244
310
|
* Useful for tests or manual programmatic invocation.
|
|
245
311
|
*/
|
|
246
312
|
async runFromArgs(argv: string[]): Promise<void> {
|
|
313
|
+
// Ensure commands have been registered before running
|
|
314
|
+
if (!this.commandsRegistered) {
|
|
315
|
+
throw new Error(
|
|
316
|
+
"No commands registered. Call registerCommands() before run(), or provide commands in the constructor config."
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
247
320
|
// configure logger
|
|
248
321
|
AppContext.current.logger.onLogEvent((event) => {
|
|
249
322
|
process.stderr.write(event.message + "\n");
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
export async function buildBinary(
|
|
6
|
+
rootDir: string,
|
|
7
|
+
entrypoint: string,
|
|
8
|
+
binaryName: string,
|
|
9
|
+
plugins : Bun.BunPlugin[] = []) {
|
|
10
|
+
|
|
11
|
+
// create a temp directory for output in the os temp directory
|
|
12
|
+
const outDir = fs.mkdtempSync(path.join(os.tmpdir(), `${binaryName}-build-`));
|
|
13
|
+
const finalOutDir = `${rootDir}/dist`;
|
|
14
|
+
|
|
15
|
+
// Parse --target argument (e.g., --target=linux-x64)
|
|
16
|
+
const targetArg = process.argv.find(arg => arg.startsWith('--target='));
|
|
17
|
+
const target = targetArg?.split('=')[1] as
|
|
18
|
+
| 'bun-linux-x64'
|
|
19
|
+
| 'bun-linux-arm64'
|
|
20
|
+
| 'bun-darwin-x64'
|
|
21
|
+
| 'bun-darwin-arm64'
|
|
22
|
+
| 'bun-windows-x64'
|
|
23
|
+
| undefined;
|
|
24
|
+
|
|
25
|
+
const isWindowsBinary = target?.startsWith('bun-windows') || (!target && os.platform() === 'win32');
|
|
26
|
+
const outfile = isWindowsBinary ? `${outDir}/${binaryName}.exe` : `${outDir}/${binaryName}`;
|
|
27
|
+
console.info('Building binary...');
|
|
28
|
+
if (target) {
|
|
29
|
+
console.info(`Target: ${target}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const result = await Bun.build({
|
|
33
|
+
entrypoints: [entrypoint],
|
|
34
|
+
compile: target
|
|
35
|
+
? { outfile, target }
|
|
36
|
+
: { outfile },
|
|
37
|
+
plugins: plugins,
|
|
38
|
+
minify: true,
|
|
39
|
+
sourcemap: true,
|
|
40
|
+
define: {
|
|
41
|
+
'process.env.NODE_ENV': JSON.stringify('production'),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (!result.success) {
|
|
46
|
+
console.error('Build failed:');
|
|
47
|
+
for (const log of result.logs) {
|
|
48
|
+
console.error(log);
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
console.info('Ensuring dist directory exists...');
|
|
55
|
+
fs.mkdirSync(finalOutDir, { recursive: true });
|
|
56
|
+
|
|
57
|
+
console.info('Copying built file to dist directory...');
|
|
58
|
+
const finalBinaryBaseName = target ? `${binaryName}-${target.replace('bun-', '')}` : binaryName;
|
|
59
|
+
const finalBinaryPath = `${finalOutDir}/${finalBinaryBaseName}${isWindowsBinary ? '.exe' : ''}`;
|
|
60
|
+
fs.copyFileSync(outfile, finalBinaryPath);
|
|
61
|
+
|
|
62
|
+
console.info('Cleaning up temporary files...');
|
|
63
|
+
fs.rmSync(outDir, { recursive: true, force: true });
|
|
64
|
+
|
|
65
|
+
console.info('Build completed:', finalBinaryPath);
|
|
66
|
+
}
|
package/src/index.ts
CHANGED