threewzrd 1.0.2 → 1.0.4

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/dist/cli.js CHANGED
@@ -3,6 +3,7 @@ import { Command } from 'commander';
3
3
  import { homedir } from 'os';
4
4
  import { startCommand } from './commands/start.js';
5
5
  import { configCommand } from './commands/config.js';
6
+ import { modelCommand } from './commands/model.js';
6
7
  // Safely get current working directory, fallback to home
7
8
  function safeGetCwd() {
8
9
  try {
@@ -22,6 +23,7 @@ program
22
23
  .command('start')
23
24
  .description('Start the wizard REPL')
24
25
  .option('-d, --directory <path>', 'Working directory for the wizard', safeGetCwd())
26
+ .option('-m, --model <model>', 'Model to use (sonnet, opus, haiku, opus-4.5, opus-4.6)')
25
27
  .action(startCommand);
26
28
  program
27
29
  .command('config')
@@ -30,4 +32,8 @@ program
30
32
  .option('-d, --delete', 'Delete saved API key')
31
33
  .option('-p, --path', 'Show config file path')
32
34
  .action(configCommand);
35
+ program
36
+ .command('model [name]')
37
+ .description('View or set the default model')
38
+ .action(modelCommand);
33
39
  program.parse();
@@ -0,0 +1 @@
1
+ export declare function modelCommand(name?: string): Promise<void>;
@@ -0,0 +1,62 @@
1
+ import { homedir } from 'os';
2
+ import { join } from 'path';
3
+ import { mkdir, writeFile, readFile } from 'fs/promises';
4
+ import chalk from 'chalk';
5
+ import { MODEL_MAP, DEFAULT_MODEL } from '../core/types.js';
6
+ const CONFIG_DIR = join(homedir(), '.threewzrd');
7
+ const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
8
+ const VALID_MODELS = ['sonnet', 'opus', 'haiku', 'opus-4.5', 'opus-4.6'];
9
+ async function loadConfig() {
10
+ try {
11
+ const content = await readFile(CONFIG_PATH, 'utf-8');
12
+ return JSON.parse(content);
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ }
18
+ async function saveConfig(config) {
19
+ await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
20
+ await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
21
+ }
22
+ export async function modelCommand(name) {
23
+ console.log();
24
+ if (!name) {
25
+ // Show current model
26
+ const config = await loadConfig();
27
+ const currentModel = config.model || DEFAULT_MODEL;
28
+ console.log(chalk.cyan(' Model Configuration'));
29
+ console.log(chalk.gray(' ─────────────────────────────────────────'));
30
+ console.log();
31
+ console.log(chalk.gray(' Current default: ') + chalk.green(currentModel));
32
+ console.log(chalk.gray(' Model ID: ') + chalk.gray(MODEL_MAP[currentModel]));
33
+ console.log();
34
+ console.log(chalk.gray(' Available models:'));
35
+ for (const model of VALID_MODELS) {
36
+ const marker = model === currentModel ? chalk.green(' (default)') : '';
37
+ console.log(chalk.gray(' - ') + chalk.white(model) + marker);
38
+ }
39
+ console.log();
40
+ console.log(chalk.gray(' To change: ') + chalk.cyan('threewzrd model <name>'));
41
+ console.log();
42
+ return;
43
+ }
44
+ // Set model
45
+ const modelName = name.toLowerCase();
46
+ if (!VALID_MODELS.includes(modelName)) {
47
+ console.log(chalk.red(` Unknown model: ${name}`));
48
+ console.log();
49
+ console.log(chalk.gray(' Valid models:'));
50
+ for (const model of VALID_MODELS) {
51
+ console.log(chalk.gray(' - ') + chalk.white(model));
52
+ }
53
+ console.log();
54
+ return;
55
+ }
56
+ const config = await loadConfig();
57
+ config.model = modelName;
58
+ await saveConfig(config);
59
+ console.log(chalk.green(` Default model set to: ${modelName}`));
60
+ console.log(chalk.gray(` Model ID: ${MODEL_MAP[modelName]}`));
61
+ console.log();
62
+ }
@@ -1,5 +1,6 @@
1
1
  interface StartOptions {
2
2
  directory: string;
3
+ model?: string;
3
4
  }
4
5
  export declare function startCommand(options: StartOptions): Promise<void>;
5
6
  export {};
@@ -1,10 +1,25 @@
1
1
  import dotenv from 'dotenv';
2
2
  import { homedir } from 'os';
3
3
  import { join } from 'path';
4
- import { mkdir, writeFile } from 'fs/promises';
4
+ import { mkdir, writeFile, readFile } from 'fs/promises';
5
5
  import * as readline from 'readline';
6
6
  import chalk from 'chalk';
7
7
  import { ThreeJsWizard } from '../core/ThreeJsWizard.js';
8
+ const VALID_MODELS = ['sonnet', 'opus', 'haiku', 'opus-4.5', 'opus-4.6'];
9
+ async function getConfiguredModel() {
10
+ try {
11
+ const configPath = join(homedir(), '.threewzrd', 'config.json');
12
+ const content = await readFile(configPath, 'utf-8');
13
+ const config = JSON.parse(content);
14
+ if (config.model && VALID_MODELS.includes(config.model)) {
15
+ return config.model;
16
+ }
17
+ }
18
+ catch {
19
+ // No config file or invalid config
20
+ }
21
+ return undefined;
22
+ }
8
23
  function loadEnvFiles(workingDir) {
9
24
  // Load from multiple locations (later ones don't override earlier)
10
25
  // 1. Current working directory
@@ -128,8 +143,23 @@ export async function startCommand(options) {
128
143
  await saveApiKey(apiKey);
129
144
  }
130
145
  }
146
+ // Determine which model to use (CLI flag > config > default)
147
+ let model;
148
+ if (options.model) {
149
+ if (VALID_MODELS.includes(options.model)) {
150
+ model = options.model;
151
+ }
152
+ else {
153
+ console.error(chalk.red(`Invalid model: ${options.model}`));
154
+ console.error(chalk.gray(`Valid models: ${VALID_MODELS.join(', ')}`));
155
+ process.exit(1);
156
+ }
157
+ }
158
+ else {
159
+ model = await getConfiguredModel();
160
+ }
131
161
  // Create and start the wizard
132
- const wizard = new ThreeJsWizard();
162
+ const wizard = new ThreeJsWizard({ model });
133
163
  // Handle graceful shutdown
134
164
  process.on('SIGINT', () => {
135
165
  console.log('\nShutting down...');
@@ -1,5 +1,5 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
- import { MODEL_MAP } from './types.js';
2
+ import { MODEL_MAP, DEFAULT_MODEL } from './types.js';
3
3
  import { toolDefinitions } from '../tools/definitions.js';
4
4
  import { ToolExecutor } from '../tools/ToolExecutor.js';
5
5
  import { THREEJS_SYSTEM_PROMPT } from '../prompts/system.js';
@@ -10,7 +10,7 @@ const MAX_RETRIES = 3;
10
10
  const RETRY_DELAY_MS = 5000; // 5 seconds base delay
11
11
  export class AgentEngine {
12
12
  client;
13
- model = 'sonnet';
13
+ model = DEFAULT_MODEL;
14
14
  conversationHistory = [];
15
15
  toolExecutor;
16
16
  ui;
@@ -1,3 +1,7 @@
1
+ import { ModelId } from './types.js';
2
+ export interface WizardOptions {
3
+ model?: ModelId;
4
+ }
1
5
  export declare class ThreeJsWizard {
2
6
  private ui;
3
7
  private engine;
@@ -5,7 +9,7 @@ export declare class ThreeJsWizard {
5
9
  private workingDirectory;
6
10
  private isRunning;
7
11
  private hasOnboarded;
8
- constructor();
12
+ constructor(options?: WizardOptions);
9
13
  start(): Promise<void>;
10
14
  private handleCommand;
11
15
  stop(): void;
@@ -9,11 +9,14 @@ export class ThreeJsWizard {
9
9
  workingDirectory;
10
10
  isRunning = false;
11
11
  hasOnboarded = false;
12
- constructor() {
12
+ constructor(options) {
13
13
  this.workingDirectory = process.cwd();
14
14
  this.ui = new TerminalUI();
15
15
  this.engine = new AgentEngine(this.ui, this.workingDirectory);
16
16
  this.projectManager = new ProjectManager(this.workingDirectory);
17
+ if (options?.model) {
18
+ this.engine.setModel(options.model);
19
+ }
17
20
  }
18
21
  async start() {
19
22
  this.isRunning = true;
@@ -100,16 +103,16 @@ export class ThreeJsWizard {
100
103
  case 'model':
101
104
  if (args.length === 0) {
102
105
  this.ui.printInfo(`Current model: ${this.engine.getModel()}`);
103
- this.ui.printInfo('Available models: sonnet, opus, haiku');
106
+ this.ui.printInfo('Available models: sonnet, opus, haiku, opus-4.5, opus-4.6');
104
107
  }
105
108
  else {
106
109
  const modelName = args[0].toLowerCase();
107
- if (['sonnet', 'opus', 'haiku'].includes(modelName)) {
110
+ if (['sonnet', 'opus', 'haiku', 'opus-4.5', 'opus-4.6'].includes(modelName)) {
108
111
  this.engine.setModel(modelName);
109
112
  this.ui.printModelSwitch(modelName);
110
113
  }
111
114
  else {
112
- this.ui.printError(`Unknown model: ${modelName}. Use: sonnet, opus, or haiku`);
115
+ this.ui.printError(`Unknown model: ${modelName}. Use: sonnet, opus, haiku, opus-4.5, or opus-4.6`);
113
116
  }
114
117
  }
115
118
  break;
@@ -1,6 +1,7 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
- export type ModelId = 'sonnet' | 'opus' | 'haiku';
2
+ export type ModelId = 'sonnet' | 'opus' | 'haiku' | 'opus-4.5' | 'opus-4.6';
3
3
  export declare const MODEL_MAP: Record<ModelId, string>;
4
+ export declare const DEFAULT_MODEL: ModelId;
4
5
  export type ProjectLanguage = 'javascript' | 'typescript';
5
6
  export type ProjectTarget = 'browser' | 'mobile' | 'desktop';
6
7
  export interface ProjectPreferences {
@@ -2,4 +2,7 @@ export const MODEL_MAP = {
2
2
  sonnet: 'claude-sonnet-4-20250514',
3
3
  opus: 'claude-opus-4-20250514',
4
4
  haiku: 'claude-haiku-4-20250514',
5
+ 'opus-4.5': 'claude-opus-4-5-20251101',
6
+ 'opus-4.6': 'claude-opus-4-6-20260201',
5
7
  };
8
+ export const DEFAULT_MODEL = 'opus-4.5';
@@ -110,6 +110,8 @@ export class TerminalUI {
110
110
  sonnet: 'Claude Sonnet 4',
111
111
  opus: 'Claude Opus 4',
112
112
  haiku: 'Claude Haiku 4',
113
+ 'opus-4.5': 'Claude Opus 4.5',
114
+ 'opus-4.6': 'Claude Opus 4.6',
113
115
  };
114
116
  console.log(chalk.green(`Switched to ${modelNames[model]}`));
115
117
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "threewzrd",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "AI-powered CLI for generating Three.js projects from natural language",
5
5
  "main": "dist/cli.js",
6
6
  "bin": {