threewzrd 1.0.5 → 1.0.6

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.
@@ -58,14 +58,17 @@ export class AgentEngine {
58
58
  }
59
59
  async runAgentLoop() {
60
60
  let continueLoop = true;
61
+ let turn = 1;
61
62
  while (continueLoop) {
62
- continueLoop = await this.runSingleTurn();
63
+ continueLoop = await this.runSingleTurn(turn);
64
+ turn++;
63
65
  }
64
66
  }
65
- async runSingleTurn(retryCount = 0) {
67
+ async runSingleTurn(turn, retryCount = 0) {
66
68
  try {
67
- // Show thinking indicator
68
- this.ui.startThinking('Thinking');
69
+ // Show thinking indicator with turn info
70
+ const thinkingMessage = turn === 1 ? 'Thinking' : 'Processing';
71
+ this.ui.startThinking(thinkingMessage, turn);
69
72
  // Create the API request with streaming
70
73
  const stream = this.client.messages.stream({
71
74
  model: MODEL_MAP[this.model],
@@ -110,8 +113,13 @@ export class AgentEngine {
110
113
  }
111
114
  // Execute all tool calls
112
115
  const toolResults = [];
113
- for (const toolUse of toolUseBlocks) {
116
+ const totalTools = toolUseBlocks.length;
117
+ for (let i = 0; i < toolUseBlocks.length; i++) {
118
+ const toolUse = toolUseBlocks[i];
119
+ const toolProgress = totalTools > 1 ? ` (${i + 1}/${totalTools})` : '';
120
+ this.ui.startThinking(`Executing ${toolUse.name}${toolProgress}`, turn);
114
121
  const result = await this.toolExecutor.execute(toolUse.name, toolUse.input);
122
+ this.ui.stopThinking();
115
123
  // Truncate large outputs to save tokens
116
124
  let output = result.success ? result.output : `Error: ${result.error}`;
117
125
  if (output.length > 2000) {
@@ -140,7 +148,7 @@ export class AgentEngine {
140
148
  const delay = RETRY_DELAY_MS * Math.pow(2, retryCount);
141
149
  this.ui.printWarning(`Rate limited. Retrying in ${delay / 1000}s...`);
142
150
  await this.sleep(delay);
143
- return this.runSingleTurn(retryCount + 1);
151
+ return this.runSingleTurn(turn, retryCount + 1);
144
152
  }
145
153
  this.ui.printError('Rate limit exceeded. Please wait a moment and try again.');
146
154
  return false;
@@ -9,6 +9,7 @@ export declare class ThreeJsWizard {
9
9
  private workingDirectory;
10
10
  private isRunning;
11
11
  private hasOnboarded;
12
+ private currentMode;
12
13
  constructor(options?: WizardOptions);
13
14
  start(): Promise<void>;
14
15
  private handleCommand;
@@ -9,6 +9,7 @@ export class ThreeJsWizard {
9
9
  workingDirectory;
10
10
  isRunning = false;
11
11
  hasOnboarded = false;
12
+ currentMode = 'single-shot';
12
13
  constructor(options) {
13
14
  this.workingDirectory = process.cwd();
14
15
  this.ui = new TerminalUI();
@@ -42,6 +43,7 @@ export class ThreeJsWizard {
42
43
  if (!this.hasOnboarded && isEmptyDir) {
43
44
  const preferences = await runOnboarding(this.ui);
44
45
  this.hasOnboarded = true;
46
+ this.currentMode = preferences.mode;
45
47
  // Process the initial project request
46
48
  const contextMessage = buildContextMessage(preferences);
47
49
  await this.engine.processMessage(contextMessage);
@@ -53,7 +55,8 @@ export class ThreeJsWizard {
53
55
  // Main REPL loop
54
56
  while (this.isRunning) {
55
57
  try {
56
- const input = await this.ui.prompt();
58
+ const { text: input, mode } = await this.ui.promptWithMode(this.currentMode);
59
+ this.currentMode = mode;
57
60
  if (!input) {
58
61
  continue;
59
62
  }
@@ -62,8 +65,13 @@ export class ThreeJsWizard {
62
65
  await this.handleCommand(input);
63
66
  continue;
64
67
  }
68
+ // Build message with mode context
69
+ const modePrefix = mode === 'planning'
70
+ ? '[PLANNING MODE] Output a detailed implementation plan before coding.\n\n'
71
+ : '';
72
+ const fullMessage = modePrefix + input;
65
73
  // Process user message through agent
66
- await this.engine.processMessage(input);
74
+ await this.engine.processMessage(fullMessage);
67
75
  // Track created files
68
76
  for (const file of this.engine.getCreatedFiles()) {
69
77
  this.projectManager.addFile(file);
@@ -4,10 +4,12 @@ export declare const MODEL_MAP: Record<ModelId, string>;
4
4
  export declare const DEFAULT_MODEL: ModelId;
5
5
  export type ProjectLanguage = 'javascript' | 'typescript';
6
6
  export type ProjectTarget = 'browser' | 'mobile' | 'desktop';
7
+ export type ExecutionMode = 'single-shot' | 'planning';
7
8
  export interface ProjectPreferences {
8
9
  language: ProjectLanguage;
9
10
  target: ProjectTarget;
10
11
  description: string;
12
+ mode: ExecutionMode;
11
13
  }
12
14
  export interface ProjectConfig {
13
15
  name: string;
@@ -1,6 +1,7 @@
1
1
  import * as fs from 'fs/promises';
2
2
  import * as path from 'path';
3
3
  import { spawn } from 'child_process';
4
+ import chalk from 'chalk';
4
5
  import { shouldValidate, validate } from './CodeValidator.js';
5
6
  // Whitelist of allowed commands for security
6
7
  const ALLOWED_COMMANDS = new Set([
@@ -232,6 +233,7 @@ export class ToolExecutor {
232
233
  try {
233
234
  // Validate input structure
234
235
  const validatedInput = this.validateWriteFileInput(input);
236
+ this.ui.startToolSpinner('write_file', `Writing ${validatedInput.path}`);
235
237
  // Validate path doesn't escape working directory
236
238
  const fullPath = this.validatePath(validatedInput.path);
237
239
  const dir = path.dirname(fullPath);
@@ -241,8 +243,7 @@ export class ToolExecutor {
241
243
  // If there are errors, don't write the file
242
244
  if (!validationResult.valid) {
243
245
  const errorDetails = validationResult.errors.join('\n - ');
244
- this.ui.printToolCall('write_file', `Writing: ${validatedInput.path}`);
245
- this.ui.printToolResult(false, 'Syntax validation failed');
246
+ this.ui.failToolSpinner('Syntax validation failed');
246
247
  return {
247
248
  success: false,
248
249
  output: '',
@@ -261,8 +262,7 @@ export class ToolExecutor {
261
262
  // Write the file
262
263
  await fs.writeFile(fullPath, validatedInput.content, 'utf-8');
263
264
  this.createdFiles.add(validatedInput.path);
264
- this.ui.printToolCall('write_file', `Writing: ${validatedInput.path}`);
265
- this.ui.printToolResult(true, '');
265
+ this.ui.succeedToolSpinner(`Wrote ${validatedInput.path}`);
266
266
  return {
267
267
  success: true,
268
268
  output: `Successfully wrote ${validatedInput.path}`,
@@ -270,9 +270,7 @@ export class ToolExecutor {
270
270
  }
271
271
  catch (error) {
272
272
  const errorMessage = error instanceof Error ? error.message : String(error);
273
- const displayPath = input?.path || 'unknown';
274
- this.ui.printToolCall('write_file', `Writing: ${displayPath}`);
275
- this.ui.printToolResult(false, errorMessage);
273
+ this.ui.failToolSpinner(`Failed to write: ${errorMessage}`);
276
274
  return {
277
275
  success: false,
278
276
  output: '',
@@ -284,11 +282,11 @@ export class ToolExecutor {
284
282
  try {
285
283
  // Validate input structure
286
284
  const validatedInput = this.validateReadFileInput(input);
285
+ this.ui.startToolSpinner('read_file', `Reading ${validatedInput.path}`);
287
286
  // Validate path doesn't escape working directory
288
287
  const fullPath = this.validatePath(validatedInput.path);
289
288
  const content = await fs.readFile(fullPath, 'utf-8');
290
- this.ui.printToolCall('read_file', `Reading: ${validatedInput.path}`);
291
- this.ui.printToolResult(true, '');
289
+ this.ui.succeedToolSpinner(`Read ${validatedInput.path}`);
292
290
  return {
293
291
  success: true,
294
292
  output: content,
@@ -296,9 +294,7 @@ export class ToolExecutor {
296
294
  }
297
295
  catch (error) {
298
296
  const errorMessage = error instanceof Error ? error.message : String(error);
299
- const displayPath = input?.path || 'unknown';
300
- this.ui.printToolCall('read_file', `Reading: ${displayPath}`);
301
- this.ui.printToolResult(false, errorMessage);
297
+ this.ui.failToolSpinner(`Failed to read: ${errorMessage}`);
302
298
  return {
303
299
  success: false,
304
300
  output: '',
@@ -318,17 +314,20 @@ export class ToolExecutor {
318
314
  if (validatedInput.cwd) {
319
315
  cwd = this.validatePath(validatedInput.cwd);
320
316
  }
321
- this.ui.printToolCall('run_command', `Command: ${validatedInput.command}`);
317
+ // Show command for user confirmation
318
+ console.log();
319
+ console.log(chalk.yellow(`[Command] `) + chalk.gray(validatedInput.command));
322
320
  // Ask for user confirmation before running any command
323
321
  const approved = await this.ui.confirm(`Run this command?`);
324
322
  if (!approved) {
325
- this.ui.printToolResult(false, 'User declined');
323
+ console.log(chalk.red(' Declined'));
326
324
  return {
327
325
  success: false,
328
326
  output: '',
329
327
  error: 'User declined to run this command',
330
328
  };
331
329
  }
330
+ this.ui.startToolSpinner('run_command', `Running: ${validatedInput.command}`);
332
331
  // For piped commands, use shell with pre-validated command string
333
332
  // For non-piped commands, use spawn without shell for security
334
333
  return new Promise((resolve) => {
@@ -355,14 +354,14 @@ export class ToolExecutor {
355
354
  child.on('close', (code) => {
356
355
  const output = stdout + (stderr ? `\nStderr: ${stderr}` : '');
357
356
  if (code === 0) {
358
- this.ui.printToolResult(true, '');
357
+ this.ui.succeedToolSpinner('Command completed');
359
358
  resolve({
360
359
  success: true,
361
360
  output: output || 'Command completed successfully',
362
361
  });
363
362
  }
364
363
  else {
365
- this.ui.printToolResult(false, `Exit code: ${code}`);
364
+ this.ui.failToolSpinner(`Exit code: ${code}`);
366
365
  resolve({
367
366
  success: false,
368
367
  output: '',
@@ -371,7 +370,7 @@ export class ToolExecutor {
371
370
  }
372
371
  });
373
372
  child.on('error', (error) => {
374
- this.ui.printToolResult(false, error.message);
373
+ this.ui.failToolSpinner(error.message);
375
374
  resolve({
376
375
  success: false,
377
376
  output: '',
@@ -382,9 +381,7 @@ export class ToolExecutor {
382
381
  }
383
382
  catch (error) {
384
383
  const errorMessage = error instanceof Error ? error.message : String(error);
385
- const displayCmd = input?.command || 'unknown';
386
- this.ui.printToolCall('run_command', `Command: ${displayCmd}`);
387
- this.ui.printToolResult(false, errorMessage);
384
+ this.ui.failToolSpinner(`Failed: ${errorMessage}`);
388
385
  return {
389
386
  success: false,
390
387
  output: '',
@@ -396,15 +393,16 @@ export class ToolExecutor {
396
393
  try {
397
394
  // Validate input structure
398
395
  const validatedInput = this.validateListFilesInput(input);
396
+ const displayPath = validatedInput.path || '.';
397
+ this.ui.startToolSpinner('list_files', `Listing ${displayPath}`);
399
398
  // Validate path doesn't escape working directory
400
399
  const targetPath = validatedInput.path
401
400
  ? this.validatePath(validatedInput.path)
402
401
  : this.workingDirectory;
403
- this.ui.printToolCall('list_files', `Listing: ${validatedInput.path || '.'}`);
404
402
  const files = await this.listFilesRecursive(targetPath, validatedInput.recursive ?? false);
405
403
  // Format output
406
404
  const relativePaths = files.map(f => path.relative(this.workingDirectory, f));
407
- this.ui.printToolResult(true, '');
405
+ this.ui.succeedToolSpinner(`Listed ${relativePaths.length} items`);
408
406
  return {
409
407
  success: true,
410
408
  output: relativePaths.length > 0
@@ -414,9 +412,7 @@ export class ToolExecutor {
414
412
  }
415
413
  catch (error) {
416
414
  const errorMessage = error instanceof Error ? error.message : String(error);
417
- const displayPath = input?.path || '.';
418
- this.ui.printToolCall('list_files', `Listing: ${displayPath}`);
419
- this.ui.printToolResult(false, errorMessage);
415
+ this.ui.failToolSpinner(`Failed to list: ${errorMessage}`);
420
416
  return {
421
417
  success: false,
422
418
  output: '',
@@ -1,4 +1,4 @@
1
- import { ModelId } from '../core/types.js';
1
+ import { ModelId, ExecutionMode } from '../core/types.js';
2
2
  export interface SelectOption {
3
3
  label: string;
4
4
  value: string;
@@ -7,9 +7,15 @@ export declare class TerminalUI {
7
7
  private rl;
8
8
  private isStreaming;
9
9
  private thinkingSpinner;
10
+ private toolSpinner;
10
11
  constructor();
11
- startThinking(message?: string): void;
12
+ startThinking(message?: string, turn?: number): void;
13
+ updateThinking(message: string, turn?: number): void;
12
14
  stopThinking(): void;
15
+ startToolSpinner(toolName: string, detail: string): void;
16
+ succeedToolSpinner(message?: string): void;
17
+ failToolSpinner(message: string): void;
18
+ stopToolSpinner(): void;
13
19
  confirm(message: string): Promise<boolean>;
14
20
  select(question: string, options: SelectOption[]): Promise<string>;
15
21
  printBanner(): void;
@@ -31,6 +37,11 @@ export declare class TerminalUI {
31
37
  streamText(text: string): void;
32
38
  endStreaming(): void;
33
39
  prompt(): Promise<string>;
40
+ promptWithMode(defaultMode?: ExecutionMode): Promise<{
41
+ text: string;
42
+ mode: ExecutionMode;
43
+ }>;
44
+ printModeInfo(mode: ExecutionMode): void;
34
45
  close(): void;
35
46
  clearScreen(): void;
36
47
  }
@@ -5,20 +5,28 @@ export class TerminalUI {
5
5
  rl;
6
6
  isStreaming = false;
7
7
  thinkingSpinner = null;
8
+ toolSpinner = null;
8
9
  constructor() {
9
10
  this.rl = readline.createInterface({
10
11
  input: process.stdin,
11
12
  output: process.stdout,
12
13
  });
13
14
  }
14
- // Thinking indicator
15
- startThinking(message = 'Thinking') {
15
+ // Thinking indicator with turn info
16
+ startThinking(message = 'Thinking', turn) {
17
+ const turnInfo = turn ? chalk.gray(` [Turn ${turn}]`) : '';
16
18
  this.thinkingSpinner = ora({
17
- text: chalk.cyan(message),
19
+ text: chalk.cyan(message) + turnInfo,
18
20
  spinner: 'dots',
19
21
  discardStdin: false, // Don't interfere with readline
20
22
  }).start();
21
23
  }
24
+ updateThinking(message, turn) {
25
+ if (this.thinkingSpinner) {
26
+ const turnInfo = turn ? chalk.gray(` [Turn ${turn}]`) : '';
27
+ this.thinkingSpinner.text = chalk.cyan(message) + turnInfo;
28
+ }
29
+ }
22
30
  stopThinking() {
23
31
  if (this.thinkingSpinner) {
24
32
  this.thinkingSpinner.stop();
@@ -29,6 +37,32 @@ export class TerminalUI {
29
37
  process.stdin.resume();
30
38
  }
31
39
  }
40
+ // Tool execution spinner
41
+ startToolSpinner(toolName, detail) {
42
+ this.toolSpinner = ora({
43
+ text: chalk.yellow(`${toolName}: `) + chalk.gray(detail),
44
+ spinner: 'dots',
45
+ discardStdin: false,
46
+ }).start();
47
+ }
48
+ succeedToolSpinner(message) {
49
+ if (this.toolSpinner) {
50
+ this.toolSpinner.succeed(message ? chalk.green(message) : undefined);
51
+ this.toolSpinner = null;
52
+ }
53
+ }
54
+ failToolSpinner(message) {
55
+ if (this.toolSpinner) {
56
+ this.toolSpinner.fail(chalk.red(message));
57
+ this.toolSpinner = null;
58
+ }
59
+ }
60
+ stopToolSpinner() {
61
+ if (this.toolSpinner) {
62
+ this.toolSpinner.stop();
63
+ this.toolSpinner = null;
64
+ }
65
+ }
32
66
  // Confirmation prompt for dangerous actions
33
67
  async confirm(message) {
34
68
  // Ensure any spinner is stopped
@@ -78,12 +112,18 @@ export class TerminalUI {
78
112
  console.log(chalk.gray(' lighting, animations, and more - just describe what'));
79
113
  console.log(chalk.gray(' you want in plain English.'));
80
114
  console.log();
115
+ console.log(chalk.gray(' Modes: ') + chalk.cyan('⚡ Quick') + chalk.gray(' | ') + chalk.magenta('📋 Plan') + chalk.gray(' (Tab to switch)'));
81
116
  console.log(chalk.gray(' Commands: ') + chalk.yellow('/help') + chalk.gray(' | ') + chalk.yellow('/clear') + chalk.gray(' | ') + chalk.yellow('/exit'));
82
117
  console.log();
83
118
  console.log(chalk.gray(' ─────────────────────────────────────────'));
84
119
  console.log();
85
120
  }
86
121
  printHelp() {
122
+ console.log();
123
+ console.log(chalk.yellow('Execution Modes:'));
124
+ console.log(chalk.cyan(' ⚡ Quick Mode') + chalk.gray(' - Direct implementation (default)'));
125
+ console.log(chalk.magenta(' 📋 Plan Mode') + chalk.gray(' - Detailed architecture plan first'));
126
+ console.log(chalk.gray(' Press Tab while typing to switch modes'));
87
127
  console.log();
88
128
  console.log(chalk.yellow('Commands:'));
89
129
  console.log(chalk.cyan(' /help') + chalk.gray(' - Show this help message'));
@@ -176,6 +216,100 @@ export class TerminalUI {
176
216
  });
177
217
  });
178
218
  }
219
+ // Mode-aware prompt with Tab toggle for execution mode
220
+ async promptWithMode(defaultMode = 'single-shot') {
221
+ let currentMode = defaultMode;
222
+ // Print mode indicator and instructions
223
+ const printModeBar = () => {
224
+ const singleShot = currentMode === 'single-shot'
225
+ ? chalk.bgCyan.black(' ⚡ Quick ')
226
+ : chalk.gray(' ⚡ Quick ');
227
+ const planning = currentMode === 'planning'
228
+ ? chalk.bgMagenta.white(' 📋 Plan ')
229
+ : chalk.gray(' 📋 Plan ');
230
+ // Clear line and reprint
231
+ process.stdout.write('\r\x1b[K');
232
+ process.stdout.write(` ${singleShot} ${planning} ${chalk.gray('Tab to switch')}\n`);
233
+ };
234
+ return new Promise((resolve) => {
235
+ printModeBar();
236
+ console.log();
237
+ // Close the existing readline interface to fully release stdin
238
+ this.rl.close();
239
+ // Store the current input
240
+ let inputBuffer = '';
241
+ // Set up raw mode for keypress detection
242
+ if (process.stdin.isTTY) {
243
+ process.stdin.setRawMode(true);
244
+ }
245
+ process.stdin.resume();
246
+ const promptPrefix = chalk.magenta(' › ');
247
+ process.stdout.write(promptPrefix);
248
+ const handleKeypress = (chunk) => {
249
+ const key = chunk.toString();
250
+ // Tab key - toggle mode
251
+ if (key === '\t') {
252
+ currentMode = currentMode === 'single-shot' ? 'planning' : 'single-shot';
253
+ // Move cursor up, clear the mode bar, reprint it, move back down
254
+ process.stdout.write('\x1b[2A'); // Move up 2 lines
255
+ printModeBar();
256
+ console.log();
257
+ process.stdout.write(promptPrefix + inputBuffer);
258
+ return;
259
+ }
260
+ // Enter key - submit
261
+ if (key === '\r' || key === '\n') {
262
+ process.stdout.write('\n');
263
+ cleanup();
264
+ resolve({ text: inputBuffer.trim(), mode: currentMode });
265
+ return;
266
+ }
267
+ // Ctrl+C - exit
268
+ if (key === '\x03') {
269
+ cleanup();
270
+ process.exit(0);
271
+ }
272
+ // Backspace
273
+ if (key === '\x7f' || key === '\b') {
274
+ if (inputBuffer.length > 0) {
275
+ inputBuffer = inputBuffer.slice(0, -1);
276
+ process.stdout.write('\b \b');
277
+ }
278
+ return;
279
+ }
280
+ // Escape sequences (arrow keys, etc.) - ignore for simplicity
281
+ if (key.startsWith('\x1b')) {
282
+ return;
283
+ }
284
+ // Regular character
285
+ if (key.length === 1 && key.charCodeAt(0) >= 32) {
286
+ inputBuffer += key;
287
+ process.stdout.write(key);
288
+ }
289
+ };
290
+ const cleanup = () => {
291
+ process.stdin.removeListener('data', handleKeypress);
292
+ if (process.stdin.isTTY) {
293
+ process.stdin.setRawMode(false);
294
+ }
295
+ // Recreate readline interface
296
+ this.rl = readline.createInterface({
297
+ input: process.stdin,
298
+ output: process.stdout,
299
+ });
300
+ };
301
+ process.stdin.on('data', handleKeypress);
302
+ });
303
+ }
304
+ printModeInfo(mode) {
305
+ if (mode === 'single-shot') {
306
+ console.log(chalk.cyan(' ⚡ Quick Mode: ') + chalk.gray('Direct implementation without formal planning'));
307
+ }
308
+ else {
309
+ console.log(chalk.magenta(' 📋 Plan Mode: ') + chalk.gray('Detailed architecture plan before implementation'));
310
+ }
311
+ console.log();
312
+ }
179
313
  close() {
180
314
  this.rl.close();
181
315
  }
@@ -12,27 +12,33 @@ export async function runOnboarding(ui) {
12
12
  { label: 'Mobile (React Native, etc.)', value: 'mobile' },
13
13
  { label: 'Desktop (Electron, etc.)', value: 'desktop' },
14
14
  ]);
15
- // Ask for project description
15
+ // Ask for project description with mode toggle
16
16
  console.log();
17
- console.log(chalk.cyan(' Now describe what you\'d like to build:'));
17
+ console.log(chalk.cyan(' Describe what you\'d like to build:'));
18
18
  console.log(chalk.gray(' (e.g., "A 3D solar system with orbiting planets")'));
19
19
  console.log();
20
- const description = await ui.prompt();
20
+ const { text: description, mode } = await ui.promptWithMode('single-shot');
21
21
  console.log();
22
+ ui.printModeInfo(mode);
22
23
  console.log(chalk.gray(' ─────────────────────────────────────────'));
23
24
  console.log();
24
25
  return {
25
26
  language,
26
27
  target,
27
28
  description,
29
+ mode,
28
30
  };
29
31
  }
30
32
  export function buildContextMessage(prefs) {
33
+ const modeInstruction = prefs.mode === 'planning'
34
+ ? `\n\nIMPORTANT: The user has requested Planning Mode. You MUST output a detailed implementation plan with Architecture Overview, Dependencies, File Structure, and Execution Steps BEFORE writing any code.`
35
+ : `\n\nThe user has requested Single-Shot Mode. Plan internally and proceed directly to implementation without outputting a formal plan.`;
31
36
  return `The user wants to create a Three.js project with these preferences:
32
37
  - Language: ${prefs.language}
33
38
  - Target platform: ${prefs.target}
39
+ - Execution mode: ${prefs.mode === 'planning' ? 'Planning Mode (detailed plan first)' : 'Single-Shot Mode (direct implementation)'}
34
40
 
35
- Their project description: ${prefs.description}
41
+ Their project description: ${prefs.description}${modeInstruction}
36
42
 
37
43
  Please create the project structure and initial files based on these requirements. Start by setting up the basic Three.js scene.`;
38
44
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threewzrd",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "description": "AI-powered CLI for generating Three.js projects from natural language",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {