@agentuity/cli 0.1.14 → 0.1.15

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 (65) hide show
  1. package/dist/auth.d.ts.map +1 -1
  2. package/dist/auth.js +7 -6
  3. package/dist/auth.js.map +1 -1
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +54 -10
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cmd/ai/index.d.ts.map +1 -1
  8. package/dist/cmd/ai/index.js +6 -1
  9. package/dist/cmd/ai/index.js.map +1 -1
  10. package/dist/cmd/ai/opencode/index.d.ts +3 -0
  11. package/dist/cmd/ai/opencode/index.d.ts.map +1 -0
  12. package/dist/cmd/ai/opencode/index.js +27 -0
  13. package/dist/cmd/ai/opencode/index.js.map +1 -0
  14. package/dist/cmd/ai/opencode/install.d.ts +3 -0
  15. package/dist/cmd/ai/opencode/install.d.ts.map +1 -0
  16. package/dist/cmd/ai/opencode/install.js +102 -0
  17. package/dist/cmd/ai/opencode/install.js.map +1 -0
  18. package/dist/cmd/ai/opencode/run.d.ts +3 -0
  19. package/dist/cmd/ai/opencode/run.d.ts.map +1 -0
  20. package/dist/cmd/ai/opencode/run.js +88 -0
  21. package/dist/cmd/ai/opencode/run.js.map +1 -0
  22. package/dist/cmd/ai/opencode/uninstall.d.ts +3 -0
  23. package/dist/cmd/ai/opencode/uninstall.d.ts.map +1 -0
  24. package/dist/cmd/ai/opencode/uninstall.js +82 -0
  25. package/dist/cmd/ai/opencode/uninstall.js.map +1 -0
  26. package/dist/cmd/build/vite/beacon-plugin.d.ts.map +1 -1
  27. package/dist/cmd/build/vite/beacon-plugin.js.map +1 -1
  28. package/dist/cmd/build/vite/vite-builder.d.ts.map +1 -1
  29. package/dist/cmd/build/vite/vite-builder.js +1 -1
  30. package/dist/cmd/build/vite/vite-builder.js.map +1 -1
  31. package/dist/cmd/project/create.d.ts.map +1 -1
  32. package/dist/cmd/project/create.js +8 -2
  33. package/dist/cmd/project/create.js.map +1 -1
  34. package/dist/cmd/project/download.d.ts +3 -1
  35. package/dist/cmd/project/download.d.ts.map +1 -1
  36. package/dist/cmd/project/download.js +5 -0
  37. package/dist/cmd/project/download.js.map +1 -1
  38. package/dist/cmd/project/template-flow.d.ts +2 -0
  39. package/dist/cmd/project/template-flow.d.ts.map +1 -1
  40. package/dist/cmd/project/template-flow.js +32 -12
  41. package/dist/cmd/project/template-flow.js.map +1 -1
  42. package/dist/tui/prompt.d.ts.map +1 -1
  43. package/dist/tui/prompt.js +7 -1
  44. package/dist/tui/prompt.js.map +1 -1
  45. package/dist/tui.d.ts.map +1 -1
  46. package/dist/tui.js +74 -21
  47. package/dist/tui.js.map +1 -1
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js.map +1 -1
  50. package/package.json +7 -7
  51. package/src/auth.ts +7 -6
  52. package/src/cli.ts +70 -10
  53. package/src/cmd/ai/index.ts +6 -1
  54. package/src/cmd/ai/opencode/index.ts +28 -0
  55. package/src/cmd/ai/opencode/install.ts +120 -0
  56. package/src/cmd/ai/opencode/run.ts +103 -0
  57. package/src/cmd/ai/opencode/uninstall.ts +90 -0
  58. package/src/cmd/build/vite/beacon-plugin.ts +3 -1
  59. package/src/cmd/build/vite/vite-builder.ts +5 -1
  60. package/src/cmd/project/create.ts +9 -2
  61. package/src/cmd/project/download.ts +7 -1
  62. package/src/cmd/project/template-flow.ts +33 -12
  63. package/src/tui/prompt.ts +10 -3
  64. package/src/tui.ts +76 -22
  65. package/src/types.ts +1 -0
@@ -0,0 +1,120 @@
1
+ import { mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { createSubcommand, type CommandContext } from '../../../types';
5
+ import * as tui from '../../../tui';
6
+ import { getCommand } from '../../../command-prefix';
7
+
8
+ const OPENCODE_CONFIG_DIR = join(homedir(), '.config', 'opencode');
9
+ const OPENCODE_CONFIG_FILE = join(OPENCODE_CONFIG_DIR, 'opencode.json');
10
+
11
+ export const installSubcommand = createSubcommand({
12
+ name: 'install',
13
+ description: 'Install Agentuity Open Code plugin',
14
+ tags: ['fast'],
15
+ requires: { auth: true, apiClient: true, org: true },
16
+ examples: [
17
+ {
18
+ command: getCommand('ai opencode install'),
19
+ description: 'Install Agentuity Open Code plugin',
20
+ },
21
+ ],
22
+ async handler(ctx: CommandContext<{ auth: true; apiClient: true; org: true }>) {
23
+ const { options, orgId } = ctx;
24
+ const jsonMode = !!options?.json;
25
+
26
+ if (!jsonMode) {
27
+ tui.newline();
28
+ tui.output(tui.bold('Installing Agentuity Open Code plugin'));
29
+ tui.newline();
30
+ tui.success(`Using organization: ${orgId}`);
31
+ }
32
+
33
+ const pluginEntry = '@agentuity/opencode';
34
+
35
+ // Update Open Code config if needed
36
+ let openCodeUpdated = false;
37
+ if (!existsSync(OPENCODE_CONFIG_DIR)) {
38
+ mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true });
39
+ }
40
+
41
+ let openCodeConfig: { plugin?: string[]; $schema?: string } = {};
42
+ if (existsSync(OPENCODE_CONFIG_FILE)) {
43
+ try {
44
+ const content = readFileSync(OPENCODE_CONFIG_FILE, 'utf-8');
45
+ openCodeConfig = JSON.parse(content);
46
+ } catch {
47
+ openCodeConfig = {};
48
+ }
49
+ }
50
+
51
+ if (!openCodeConfig.plugin) {
52
+ openCodeConfig.plugin = [];
53
+ }
54
+
55
+ // Check if the exact plugin entry already exists
56
+ const hasExactEntry = openCodeConfig.plugin.includes(pluginEntry);
57
+
58
+ // Check if there's an existing entry that needs updating
59
+ const existingIndex = openCodeConfig.plugin.findIndex((p) => p === '@agentuity/opencode');
60
+
61
+ if (hasExactEntry) {
62
+ if (!jsonMode) {
63
+ tui.info('Open Code plugin already configured');
64
+ }
65
+ } else if (existingIndex >= 0) {
66
+ // Update existing entry to new value
67
+ openCodeConfig.plugin[existingIndex] = pluginEntry;
68
+ writeFileSync(OPENCODE_CONFIG_FILE, JSON.stringify(openCodeConfig, null, 2));
69
+ if (!jsonMode) {
70
+ tui.success(`Updated Open Code plugin to: ${pluginEntry}`);
71
+ }
72
+ openCodeUpdated = true;
73
+ } else {
74
+ // Add new entry
75
+ openCodeConfig.plugin.push(pluginEntry);
76
+ writeFileSync(OPENCODE_CONFIG_FILE, JSON.stringify(openCodeConfig, null, 2));
77
+ if (!jsonMode) {
78
+ tui.success(`Added ${pluginEntry} to Open Code config`);
79
+ }
80
+ openCodeUpdated = true;
81
+ }
82
+
83
+ // Summary (TUI only)
84
+ if (!jsonMode) {
85
+ tui.newline();
86
+ if (openCodeUpdated) {
87
+ tui.output(tui.bold('Agentuity Open Code plugin installed successfully!'));
88
+ } else {
89
+ tui.output(tui.bold('Agentuity Open Code plugin already installed'));
90
+ }
91
+
92
+ tui.newline();
93
+ tui.info('Next steps:');
94
+ tui.output(` ${tui.ICONS.bullet} Start Open Code to use Agentuity Coder agents`);
95
+ tui.output(
96
+ ` ${tui.ICONS.bullet} Run ${tui.bold(getCommand('ai opencode run "<task>"'))} to execute tasks`
97
+ );
98
+ tui.newline();
99
+
100
+ tui.output(tui.muted('Recommended MCP servers for Scout/Expert agents:'));
101
+ tui.output(tui.muted('Add to your opencode.json:'));
102
+ tui.newline();
103
+ tui.output(tui.muted(' "mcp": {'));
104
+ tui.output(
105
+ tui.muted(
106
+ ' "context7": { "type": "remote", "url": "https://mcp.context7.com/mcp" },'
107
+ )
108
+ );
109
+ tui.output(
110
+ tui.muted(' "grep_app": { "type": "remote", "url": "https://mcp.grep.app" }')
111
+ );
112
+ tui.output(tui.muted(' }'));
113
+ tui.newline();
114
+ }
115
+
116
+ return { success: true, orgId };
117
+ },
118
+ });
119
+
120
+ export default installSubcommand;
@@ -0,0 +1,103 @@
1
+ import { createSubcommand, type CommandContext } from '../../../types';
2
+ import * as tui from '../../../tui';
3
+ import { getCommand } from '../../../command-prefix';
4
+ import { z } from 'zod';
5
+
6
+ const RunArgsSchema = z.object({
7
+ task: z.string().describe('The task description to execute'),
8
+ });
9
+
10
+ const RunOptionsSchema = z.object({
11
+ sandbox: z.boolean().optional().describe('Run in a cloud sandbox environment'),
12
+ json: z.boolean().optional().describe('Output raw JSON events'),
13
+ });
14
+
15
+ export const runSubcommand = createSubcommand({
16
+ name: 'run',
17
+ description: 'Run a task with the Agentuity Coder agent team (non-interactive)',
18
+ tags: ['slow'],
19
+ requires: { auth: true },
20
+ schema: {
21
+ args: RunArgsSchema,
22
+ options: RunOptionsSchema,
23
+ },
24
+ examples: [
25
+ {
26
+ command: getCommand('ai opencode run "implement dark mode toggle"'),
27
+ description: 'Run a coding task',
28
+ },
29
+ {
30
+ command: getCommand('ai opencode run --sandbox "run the test suite"'),
31
+ description: 'Run in a cloud sandbox',
32
+ },
33
+ {
34
+ command: getCommand('ai opencode run --json "fix the bug"'),
35
+ description: 'Output raw JSON events',
36
+ },
37
+ ],
38
+ async handler(
39
+ ctx: CommandContext<{ auth: true }, undefined, typeof RunArgsSchema, typeof RunOptionsSchema>
40
+ ) {
41
+ const { logger, args, opts } = ctx;
42
+ const { task } = args;
43
+ const sandbox = opts?.sandbox;
44
+ const json = opts?.json;
45
+
46
+ if (!json) {
47
+ tui.newline();
48
+ tui.output(tui.bold('Agentuity Coder'));
49
+ tui.newline();
50
+ tui.output(`${tui.ICONS.arrow} Running task: ${task}`);
51
+ if (sandbox) {
52
+ tui.info('Sandbox mode enabled');
53
+ }
54
+ tui.newline();
55
+ }
56
+
57
+ const openCodeArgs = ['run', '--agent', 'Agentuity Coder Lead'];
58
+
59
+ if (json) {
60
+ openCodeArgs.push('--format', 'json');
61
+ }
62
+
63
+ // Build the task prompt with any mode prefixes
64
+ let taskPrompt = task;
65
+ if (sandbox) {
66
+ taskPrompt = `[SANDBOX MODE: Execute all code in an Agentuity cloud sandbox, not locally] ${taskPrompt}`;
67
+ }
68
+ if (json) {
69
+ taskPrompt = `[JSON OUTPUT: Your final response MUST be a valid JSON object with this structure: {"status": "success" | "failed" | "partial", "summary": "Brief description of what was done", "filesChanged": ["path/to/file.ts"], "errors": ["error message if any"], "payload": <any task-specific return data or null>}. Output ONLY the JSON, no other text.] ${taskPrompt}`;
70
+ }
71
+
72
+ openCodeArgs.push(taskPrompt);
73
+
74
+ logger.debug(`Spawning: opencode ${openCodeArgs.join(' ')}`);
75
+
76
+ const proc = Bun.spawn(['opencode', ...openCodeArgs], {
77
+ stdio: ['inherit', 'inherit', 'inherit'],
78
+ env: {
79
+ ...process.env,
80
+ AGENTUITY_CODER_MODE: 'non-interactive',
81
+ },
82
+ });
83
+
84
+ const exitCode = await proc.exited;
85
+
86
+ // In JSON mode, let opencode's output speak for itself - exit code indicates success
87
+ if (json) {
88
+ process.exit(exitCode);
89
+ }
90
+
91
+ if (exitCode === 0) {
92
+ tui.newline();
93
+ tui.success('Task completed');
94
+ } else {
95
+ tui.newline();
96
+ tui.error(`Task failed with exit code ${exitCode}`);
97
+ }
98
+
99
+ return { success: exitCode === 0, task, exitCode, sandbox: !!sandbox };
100
+ },
101
+ });
102
+
103
+ export default runSubcommand;
@@ -0,0 +1,90 @@
1
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ import { createSubcommand } from '../../../types';
5
+ import * as tui from '../../../tui';
6
+ import { getCommand } from '../../../command-prefix';
7
+
8
+ const OPENCODE_CONFIG_DIR = join(homedir(), '.config', 'opencode');
9
+ const OPENCODE_CONFIG_FILE = join(OPENCODE_CONFIG_DIR, 'opencode.json');
10
+
11
+ export const uninstallSubcommand = createSubcommand({
12
+ name: 'uninstall',
13
+ description: 'Uninstall Agentuity Open Code plugin',
14
+ tags: ['fast'],
15
+ examples: [
16
+ {
17
+ command: getCommand('ai opencode uninstall'),
18
+ description: 'Uninstall Agentuity Open Code plugin',
19
+ },
20
+ ],
21
+ async handler(ctx) {
22
+ const { options } = ctx;
23
+ const jsonMode = !!options?.json;
24
+
25
+ if (!jsonMode) {
26
+ tui.newline();
27
+ tui.output(tui.bold('Uninstalling Agentuity Open Code plugin'));
28
+ tui.newline();
29
+ }
30
+
31
+ let removedFromOpenCode = false;
32
+
33
+ // Remove from OpenCode config
34
+ if (!existsSync(OPENCODE_CONFIG_FILE)) {
35
+ if (!jsonMode) {
36
+ tui.info('Open Code config not found - nothing to uninstall');
37
+ }
38
+ } else {
39
+ try {
40
+ const content = readFileSync(OPENCODE_CONFIG_FILE, 'utf-8');
41
+ const openCodeConfig: { plugin?: string[]; $schema?: string } = JSON.parse(content);
42
+
43
+ if (!openCodeConfig.plugin || openCodeConfig.plugin.length === 0) {
44
+ if (!jsonMode) {
45
+ tui.info('No plugins configured in Open Code');
46
+ }
47
+ } else {
48
+ const originalLength = openCodeConfig.plugin.length;
49
+ openCodeConfig.plugin = openCodeConfig.plugin.filter(
50
+ (p) => p !== '@agentuity/opencode'
51
+ );
52
+
53
+ if (openCodeConfig.plugin.length < originalLength) {
54
+ writeFileSync(OPENCODE_CONFIG_FILE, JSON.stringify(openCodeConfig, null, 2));
55
+ if (!jsonMode) {
56
+ tui.success('Removed Agentuity Open Code plugin');
57
+ }
58
+ removedFromOpenCode = true;
59
+ } else {
60
+ if (!jsonMode) {
61
+ tui.info('Agentuity Open Code plugin not found');
62
+ }
63
+ }
64
+ }
65
+ } catch (error) {
66
+ if (!jsonMode) {
67
+ tui.warn(`Failed to parse Open Code config: ${error}`);
68
+ }
69
+ }
70
+ }
71
+
72
+ if (!jsonMode) {
73
+ tui.newline();
74
+
75
+ if (removedFromOpenCode) {
76
+ tui.output(tui.bold('Agentuity Open Code plugin uninstalled successfully'));
77
+ } else {
78
+ tui.output(tui.bold('Agentuity Open Code plugin was not installed'));
79
+ }
80
+
81
+ tui.newline();
82
+ tui.info(`To reinstall, run: ${tui.bold(getCommand('ai opencode install'))}`);
83
+ tui.newline();
84
+ }
85
+
86
+ return { success: true, removedFromOpenCode };
87
+ },
88
+ });
89
+
90
+ export default uninstallSubcommand;
@@ -104,7 +104,9 @@ export function beaconPlugin(options: BeaconPluginOptions): Plugin {
104
104
  source: beaconCode,
105
105
  });
106
106
  } catch (error) {
107
- this.error(`Failed to read beacon script: ${error instanceof Error ? error.message : String(error)}`);
107
+ this.error(
108
+ `Failed to read beacon script: ${error instanceof Error ? error.message : String(error)}`
109
+ );
108
110
  }
109
111
  },
110
112
 
@@ -142,7 +142,11 @@ export async function runViteBuild(options: ViteBuildOptions): Promise<void> {
142
142
  const htmlPath = join(rootDir, 'src', 'web', 'index.html');
143
143
 
144
144
  // Use workbench config passed from runAllBuilds
145
- const { workbenchEnabled = false, workbenchRoute = '/workbench', analyticsEnabled = false } = options;
145
+ const {
146
+ workbenchEnabled = false,
147
+ workbenchRoute = '/workbench',
148
+ analyticsEnabled = false,
149
+ } = options;
146
150
 
147
151
  // Load custom user plugins from agentuity.config.ts if it exists
148
152
  const clientOutDir = join(rootDir, '.agentuity/client');
@@ -6,6 +6,7 @@ import type { APIClient as APIClientType } from '../../api';
6
6
 
7
7
  const ProjectCreateResponseSchema = z.object({
8
8
  success: z.boolean().describe('Whether the operation succeeded'),
9
+ error: z.string().optional().describe('Error message if setup failed'),
9
10
  name: z.string().describe('Project name'),
10
11
  path: z.string().describe('Project directory path'),
11
12
  projectId: z.string().optional().describe('Project ID if registered'),
@@ -73,7 +74,7 @@ export const createProjectSubcommand = createSubcommand({
73
74
  },
74
75
 
75
76
  async handler(ctx) {
76
- const { logger, opts, auth, config, apiClient, region } = ctx;
77
+ const { logger, opts, auth, config, apiClient, region, options } = ctx;
77
78
 
78
79
  // Only get org if registering
79
80
  let orgId: string | undefined;
@@ -102,8 +103,14 @@ export const createProjectSubcommand = createSubcommand({
102
103
  region,
103
104
  });
104
105
 
106
+ // Exit with error code if setup failed and not in JSON mode
107
+ if (!result.success && !options.json) {
108
+ process.exitCode = 1;
109
+ }
110
+
105
111
  return {
106
- success: true,
112
+ success: result.success,
113
+ error: result.error,
107
114
  name: result.name,
108
115
  path: result.path,
109
116
  projectId: result.projectId,
@@ -328,8 +328,9 @@ export async function downloadTemplate(options: DownloadOptions): Promise<void>
328
328
  }
329
329
  }
330
330
 
331
- export async function setupProject(options: SetupOptions): Promise<void> {
331
+ export async function setupProject(options: SetupOptions): Promise<{ success: boolean }> {
332
332
  const { dest, projectName, dirName, noInstall, noBuild, logger } = options;
333
+ let hasError = false;
333
334
 
334
335
  // Replace {{PROJECT_NAME}} in files
335
336
  tui.info(`🔧 Setting up ${projectName}...`);
@@ -345,6 +346,7 @@ export async function setupProject(options: SetupOptions): Promise<void> {
345
346
  });
346
347
  if (exitCode !== 0) {
347
348
  logger.error('Failed to install dependencies');
349
+ hasError = true;
348
350
  }
349
351
  }
350
352
 
@@ -361,6 +363,7 @@ export async function setupProject(options: SetupOptions): Promise<void> {
361
363
  });
362
364
  if (exitCode !== 0) {
363
365
  logger.error('Template setup script failed');
366
+ hasError = true;
364
367
  }
365
368
  } finally {
366
369
  // Always delete the setup script after running (or attempting to run)
@@ -382,12 +385,15 @@ export async function setupProject(options: SetupOptions): Promise<void> {
382
385
  });
383
386
  if (exitCode !== 0) {
384
387
  logger.error('Failed to build project');
388
+ hasError = true;
385
389
  }
386
390
  }
387
391
 
388
392
  // Generate and write AGENTS.md files for the CLI and source folders
389
393
  // Always overwrite during project setup to ensure fresh content
390
394
  await writeAgentsDocs(dest);
395
+
396
+ return { success: !hasError };
391
397
  }
392
398
 
393
399
  export async function initGitRepo(dest: string): Promise<void> {
@@ -66,6 +66,8 @@ export interface CreateFlowResult {
66
66
  installed: boolean;
67
67
  built: boolean;
68
68
  domains?: string[];
69
+ success: boolean;
70
+ error?: string;
69
71
  }
70
72
 
71
73
  export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateFlowResult> {
@@ -249,7 +251,7 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
249
251
  });
250
252
 
251
253
  // Setup project (replace placeholders, install deps, build)
252
- await setupProject({
254
+ const setupResult = await setupProject({
253
255
  dest,
254
256
  projectName: projectName === '.' ? basename(dest) : projectName,
255
257
  dirName: dirName === '.' ? basename(dest) : dirName,
@@ -258,15 +260,24 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
258
260
  logger,
259
261
  });
260
262
 
261
- // Re-display template selection after spinners clear it (only if user actually selected)
262
- if (!skipPrompts && templates.length > 1) {
263
+ // If setup failed, skip resource prompts and registration - just show error and return
264
+ if (!setupResult.success) {
265
+ tui.warning('Project setup failed. Skipping resource configuration.');
266
+ return {
267
+ name: projectName,
268
+ path: dest,
269
+ template: selectedTemplate.id,
270
+ installed: !options.noInstall,
271
+ built: false,
272
+ success: false,
273
+ error: 'Project setup completed with errors',
274
+ };
275
+ }
276
+
277
+ // Add separator bar if we're going to show resource prompts
278
+ if (!skipPrompts && auth && apiClient && catalystClient && orgId && region) {
263
279
  const { symbols, tuiColors } = tui;
264
- console.log(`${tuiColors.completed(symbols.completed)} Select a template:`);
265
- console.log(`${tuiColors.secondary(symbols.bar)} ${tuiColors.muted(selectedTemplate.name)}`);
266
- // Only add bar if we're going to show resource prompts
267
- if (auth && apiClient && catalystClient && orgId && region) {
268
- console.log(tuiColors.secondary(symbols.bar));
269
- }
280
+ console.log(tuiColors.secondary(symbols.bar));
270
281
  }
271
282
 
272
283
  let _domains = domains;
@@ -597,7 +608,11 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
597
608
 
598
609
  // Show completion message
599
610
  if (!skipPrompts) {
600
- tui.success('✨ Project created successfully!\n');
611
+ if (setupResult.success) {
612
+ tui.success('✨ Project created successfully!\n');
613
+ } else {
614
+ tui.warning('Project created with errors (see above)\n');
615
+ }
601
616
 
602
617
  // Show next steps in a box with primary color for commands
603
618
  if (dirName !== '.') {
@@ -617,7 +632,11 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
617
632
  `${tui.tuiColors.muted('⭐️ Follow us:')} ${tui.link('https://github.com/agentuity/sdk')}`
618
633
  );
619
634
  } else {
620
- tui.success('✨ Project created successfully!');
635
+ if (setupResult.success) {
636
+ tui.success('✨ Project created successfully!');
637
+ } else {
638
+ tui.warning('Project created with errors');
639
+ }
621
640
  }
622
641
 
623
642
  playSound();
@@ -643,8 +662,10 @@ export async function runCreateFlow(options: CreateFlowOptions): Promise<CreateF
643
662
  path: dest,
644
663
  template: selectedTemplate.id,
645
664
  installed: !options.noInstall,
646
- built: !options.noBuild,
665
+ built: !options.noBuild && setupResult.success,
647
666
  domains: _domains,
667
+ success: setupResult.success,
668
+ error: setupResult.success ? undefined : 'Project setup completed with errors',
648
669
  };
649
670
  }
650
671
 
package/src/tui/prompt.ts CHANGED
@@ -166,9 +166,16 @@ export class PromptFlow {
166
166
  readline.moveCursor(process.stdout, 0, -linesToClear);
167
167
  readline.clearScreenDown(process.stdout);
168
168
 
169
- process.stdout.write(
170
- `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(value)}\n${colors.secondary(symbols.bar)}\n`
171
- );
169
+ // If value is empty, only show message and separator (no value line)
170
+ if (value === '') {
171
+ process.stdout.write(
172
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)}\n`
173
+ );
174
+ } else {
175
+ process.stdout.write(
176
+ `${colors.completed(symbols.completed)} ${message}\n${colors.secondary(symbols.bar)} ${colors.muted(value)}\n${colors.secondary(symbols.bar)}\n`
177
+ );
178
+ }
172
179
 
173
180
  this.states.push({
174
181
  type: 'completed',