roguelike-cli 1.2.2 → 1.2.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.
@@ -37,34 +37,13 @@ exports.initCommand = initCommand;
37
37
  const fs = __importStar(require("fs"));
38
38
  const path = __importStar(require("path"));
39
39
  const os = __importStar(require("os"));
40
+ const readline = __importStar(require("readline"));
40
41
  const config_1 = require("../config/config");
41
- function question(query) {
42
+ function question(rl, query) {
42
43
  return new Promise((resolve) => {
43
- process.stdout.write(query);
44
- let input = '';
45
- const onData = (chunk) => {
46
- const str = chunk.toString();
47
- for (const char of str) {
48
- if (char === '\n' || char === '\r') {
49
- process.stdin.removeListener('data', onData);
50
- process.stdout.write('\n');
51
- resolve(input);
52
- return;
53
- }
54
- else if (char === '\x7f' || char === '\b') {
55
- // Backspace
56
- if (input.length > 0) {
57
- input = input.slice(0, -1);
58
- process.stdout.write('\b \b');
59
- }
60
- }
61
- else if (char >= ' ') {
62
- input += char;
63
- process.stdout.write(char);
64
- }
65
- }
66
- };
67
- process.stdin.on('data', onData);
44
+ rl.question(query, (answer) => {
45
+ resolve(answer);
46
+ });
68
47
  });
69
48
  }
70
49
  // Recursive copy function
@@ -83,93 +62,106 @@ function copyRecursive(src, dest) {
83
62
  fs.copyFileSync(src, dest);
84
63
  }
85
64
  }
86
- async function initCommand() {
87
- console.log('\n╔═══════════════════════════════════════╗');
88
- console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
89
- console.log('╚═══════════════════════════════════════╝\n');
90
- // Get existing config if any
91
- const existingConfig = await (0, config_1.initConfig)();
92
- const oldStoragePath = existingConfig?.storagePath;
93
- // 1. Root directory
94
- const defaultRoot = path.join(os.homedir(), '.rlc', 'notes');
95
- const rootDirAnswer = await question(`Root directory for notes [${defaultRoot}]: `);
96
- const rootDir = rootDirAnswer.trim() || defaultRoot;
97
- // Check if we need to migrate data
98
- if (oldStoragePath && oldStoragePath !== rootDir && fs.existsSync(oldStoragePath)) {
99
- const entries = fs.readdirSync(oldStoragePath);
100
- if (entries.length > 0) {
101
- const migrateAnswer = await question(`\nMigrate existing data from ${oldStoragePath}? [Y/n]: `);
102
- if (migrateAnswer.toLowerCase() !== 'n') {
103
- if (!fs.existsSync(rootDir)) {
104
- fs.mkdirSync(rootDir, { recursive: true });
105
- }
106
- console.log(`Migrating data...`);
107
- for (const entry of entries) {
108
- const srcPath = path.join(oldStoragePath, entry);
109
- const destPath = path.join(rootDir, entry);
110
- copyRecursive(srcPath, destPath);
65
+ async function initCommand(existingRl) {
66
+ // Create our own readline if not provided, or use existing one
67
+ const rl = existingRl || readline.createInterface({
68
+ input: process.stdin,
69
+ output: process.stdout,
70
+ });
71
+ const shouldCloseRl = !existingRl;
72
+ try {
73
+ console.log('\n╔═══════════════════════════════════════╗');
74
+ console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
75
+ console.log('╚═══════════════════════════════════════╝\n');
76
+ // Get existing config if any
77
+ const existingConfig = await (0, config_1.initConfig)();
78
+ const oldStoragePath = existingConfig?.storagePath;
79
+ // 1. Root directory
80
+ const defaultRoot = path.join(os.homedir(), '.rlc', 'workspace');
81
+ const rootDirAnswer = await question(rl, `Root directory [${defaultRoot}]: `);
82
+ const rootDir = rootDirAnswer.trim() || defaultRoot;
83
+ // Check if we need to migrate data
84
+ if (oldStoragePath && oldStoragePath !== rootDir && fs.existsSync(oldStoragePath)) {
85
+ const entries = fs.readdirSync(oldStoragePath);
86
+ if (entries.length > 0) {
87
+ const migrateAnswer = await question(rl, `\nMigrate existing data from ${oldStoragePath}? [Y/n]: `);
88
+ if (migrateAnswer.toLowerCase() !== 'n') {
89
+ if (!fs.existsSync(rootDir)) {
90
+ fs.mkdirSync(rootDir, { recursive: true });
91
+ }
92
+ console.log(`Migrating data...`);
93
+ for (const entry of entries) {
94
+ const srcPath = path.join(oldStoragePath, entry);
95
+ const destPath = path.join(rootDir, entry);
96
+ copyRecursive(srcPath, destPath);
97
+ }
98
+ console.log(`Migrated ${entries.length} items to ${rootDir}`);
111
99
  }
112
- console.log(`Migrated ${entries.length} items to ${rootDir}`);
113
100
  }
114
101
  }
102
+ if (!fs.existsSync(rootDir)) {
103
+ fs.mkdirSync(rootDir, { recursive: true });
104
+ console.log(`Created directory: ${rootDir}`);
105
+ }
106
+ // 2. AI Provider selection
107
+ console.log('\nSelect AI Provider:');
108
+ console.log(' 1. Claude Sonnet 4.5');
109
+ console.log(' 2. Claude Opus 4.5');
110
+ console.log(' 3. GPT-4o (latest)');
111
+ console.log(' 4. Gemini 3 Pro');
112
+ console.log(' 5. Grok (latest)');
113
+ const aiChoice = await question(rl, '\nEnter choice [1-5] (default: 1): ');
114
+ const aiProviders = [
115
+ { name: 'claude', model: 'claude-sonnet-4-20250514', apiUrl: 'https://api.anthropic.com' },
116
+ { name: 'claude-opus', model: 'claude-opus-4-20250514', apiUrl: 'https://api.anthropic.com' },
117
+ { name: 'openai', model: 'gpt-4o', apiUrl: 'https://api.openai.com' },
118
+ { name: 'gemini', model: 'gemini-3-pro', apiUrl: 'https://generativelanguage.googleapis.com' },
119
+ { name: 'grok', model: 'grok-beta', apiUrl: 'https://api.x.ai' },
120
+ ];
121
+ const selectedIndex = parseInt(aiChoice.trim()) - 1 || 0;
122
+ const selectedProvider = aiProviders[selectedIndex] || aiProviders[0];
123
+ console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
124
+ // 3. API Key - reuse existing if not provided
125
+ const existingApiKey = existingConfig?.apiKey || '';
126
+ const hasExistingKey = existingApiKey.length > 0;
127
+ const keyPrompt = hasExistingKey
128
+ ? `\nAPI key for ${selectedProvider.name} [Enter to keep existing]: `
129
+ : `\nEnter API key for ${selectedProvider.name}: `;
130
+ const apiKeyInput = await question(rl, keyPrompt);
131
+ const apiKey = apiKeyInput.trim() || existingApiKey;
132
+ if (!apiKey) {
133
+ console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
134
+ }
135
+ else if (apiKeyInput.trim()) {
136
+ console.log('API key saved');
137
+ }
138
+ else {
139
+ console.log('Using existing API key');
140
+ }
141
+ // Save config
142
+ const config = {
143
+ aiProvider: selectedProvider.name,
144
+ apiKey: apiKey,
145
+ apiUrl: selectedProvider.apiUrl,
146
+ storagePath: rootDir,
147
+ currentPath: rootDir,
148
+ model: selectedProvider.model,
149
+ };
150
+ (0, config_1.saveConfig)(config);
151
+ // Ensure storage directory exists
152
+ if (!fs.existsSync(rootDir)) {
153
+ fs.mkdirSync(rootDir, { recursive: true });
154
+ }
155
+ console.log('\n╔═══════════════════════════════════════╗');
156
+ console.log('║ INITIALIZATION COMPLETE ║');
157
+ console.log('╚═══════════════════════════════════════╝\n');
158
+ console.log(`Root directory: ${rootDir}`);
159
+ console.log(`AI Provider: ${selectedProvider.name}`);
160
+ console.log(`Model: ${selectedProvider.model}\n`);
115
161
  }
116
- if (!fs.existsSync(rootDir)) {
117
- fs.mkdirSync(rootDir, { recursive: true });
118
- console.log(`Created directory: ${rootDir}`);
119
- }
120
- // 2. AI Provider selection
121
- console.log('\nSelect AI Provider:');
122
- console.log(' 1. Claude Sonnet 4.5');
123
- console.log(' 2. Claude Opus 4.5');
124
- console.log(' 3. GPT-4o (latest)');
125
- console.log(' 4. Gemini 3 Pro');
126
- console.log(' 5. Grok (latest)');
127
- const aiChoice = await question('\nEnter choice [1-5] (default: 1): ');
128
- const aiProviders = [
129
- { name: 'claude', model: 'claude-sonnet-4-20250514', apiUrl: 'https://api.anthropic.com' },
130
- { name: 'claude-opus', model: 'claude-opus-4-20250514', apiUrl: 'https://api.anthropic.com' },
131
- { name: 'openai', model: 'gpt-4o', apiUrl: 'https://api.openai.com' },
132
- { name: 'gemini', model: 'gemini-3-pro', apiUrl: 'https://generativelanguage.googleapis.com' },
133
- { name: 'grok', model: 'grok-beta', apiUrl: 'https://api.x.ai' },
134
- ];
135
- const selectedIndex = parseInt(aiChoice.trim()) - 1 || 0;
136
- const selectedProvider = aiProviders[selectedIndex] || aiProviders[0];
137
- console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
138
- // 3. API Key - reuse existing if not provided
139
- const existingApiKey = existingConfig?.apiKey || '';
140
- const hasExistingKey = existingApiKey.length > 0;
141
- const keyPrompt = hasExistingKey
142
- ? `\nAPI key for ${selectedProvider.name} [press Enter to keep existing]: `
143
- : `\nEnter API key for ${selectedProvider.name}: `;
144
- const apiKeyInput = await question(keyPrompt);
145
- const apiKey = apiKeyInput.trim() || existingApiKey;
146
- if (!apiKey) {
147
- console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
148
- }
149
- else if (apiKeyInput.trim()) {
150
- console.log('API key saved');
151
- }
152
- else {
153
- console.log('Using existing API key');
154
- }
155
- // Save config
156
- const config = {
157
- aiProvider: selectedProvider.name,
158
- apiKey: apiKey,
159
- apiUrl: selectedProvider.apiUrl,
160
- storagePath: rootDir,
161
- currentPath: rootDir,
162
- model: selectedProvider.model,
163
- };
164
- (0, config_1.saveConfig)(config);
165
- // Ensure storage directory exists
166
- if (!fs.existsSync(rootDir)) {
167
- fs.mkdirSync(rootDir, { recursive: true });
162
+ finally {
163
+ if (shouldCloseRl) {
164
+ rl.close();
165
+ }
168
166
  }
169
- console.log('\n╔═══════════════════════════════════════╗');
170
- console.log('║ INITIALIZATION COMPLETE ║');
171
- console.log('╚═══════════════════════════════════════╝\n');
172
- console.log(`Root directory: ${rootDir}`);
173
- console.log(`AI Provider: ${selectedProvider.name}`);
174
- console.log(`Model: ${selectedProvider.model}\n`);
175
167
  }
@@ -41,7 +41,7 @@ const fs = __importStar(require("fs"));
41
41
  const path = __importStar(require("path"));
42
42
  const os = __importStar(require("os"));
43
43
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
44
- const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'notes');
44
+ const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
45
45
  async function initConfig() {
46
46
  const configDir = path.dirname(CONFIG_FILE);
47
47
  if (!fs.existsSync(configDir)) {
@@ -263,7 +263,7 @@ function copyRecursive(src, dest) {
263
263
  fs.copyFileSync(src, dest);
264
264
  }
265
265
  }
266
- async function processCommand(input, currentPath, config, signal) {
266
+ async function processCommand(input, currentPath, config, signal, rl) {
267
267
  // Check for clipboard pipe
268
268
  const clipboardPipe = /\s*\|\s*(pbcopy|copy|clip)\s*$/i;
269
269
  const shouldCopy = clipboardPipe.test(input);
@@ -460,7 +460,7 @@ async function processCommand(input, currentPath, config, signal) {
460
460
  }
461
461
  if (command === 'init') {
462
462
  const { initCommand } = await Promise.resolve().then(() => __importStar(require('../commands/init')));
463
- await initCommand();
463
+ await initCommand(rl);
464
464
  return { output: 'Initialization complete. You can now use rlc.\n', reloadConfig: true };
465
465
  }
466
466
  if (command === 'cd') {
@@ -136,7 +136,7 @@ async function startInteractive(initialConfig) {
136
136
  isProcessingCommand = true;
137
137
  const abortController = currentCommandAbortController;
138
138
  try {
139
- const result = await (0, commands_1.processCommand)(trimmed, state.currentPath, config, abortController.signal);
139
+ const result = await (0, commands_1.processCommand)(trimmed, state.currentPath, config, abortController.signal, rl);
140
140
  if (abortController.signal.aborted) {
141
141
  rl.prompt();
142
142
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roguelike-cli",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "AI-powered interactive terminal for creating schemas and todo lists",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -42,4 +42,3 @@
42
42
  "typescript": "^5.6.0"
43
43
  }
44
44
  }
45
-
@@ -1,36 +1,14 @@
1
1
  import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import * as os from 'os';
4
+ import * as readline from 'readline';
4
5
  import { Config, saveConfig, initConfig } from '../config/config';
5
6
 
6
- function question(query: string): Promise<string> {
7
+ function question(rl: readline.Interface, query: string): Promise<string> {
7
8
  return new Promise((resolve) => {
8
- process.stdout.write(query);
9
-
10
- let input = '';
11
- const onData = (chunk: Buffer) => {
12
- const str = chunk.toString();
13
-
14
- for (const char of str) {
15
- if (char === '\n' || char === '\r') {
16
- process.stdin.removeListener('data', onData);
17
- process.stdout.write('\n');
18
- resolve(input);
19
- return;
20
- } else if (char === '\x7f' || char === '\b') {
21
- // Backspace
22
- if (input.length > 0) {
23
- input = input.slice(0, -1);
24
- process.stdout.write('\b \b');
25
- }
26
- } else if (char >= ' ') {
27
- input += char;
28
- process.stdout.write(char);
29
- }
30
- }
31
- };
32
-
33
- process.stdin.on('data', onData);
9
+ rl.question(query, (answer) => {
10
+ resolve(answer);
11
+ });
34
12
  });
35
13
  }
36
14
 
@@ -52,108 +30,122 @@ function copyRecursive(src: string, dest: string): void {
52
30
  }
53
31
  }
54
32
 
55
- export async function initCommand(): Promise<void> {
56
- console.log('\n╔═══════════════════════════════════════╗');
57
- console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
58
- console.log('╚═══════════════════════════════════════╝\n');
59
-
60
- // Get existing config if any
61
- const existingConfig = await initConfig();
62
- const oldStoragePath = existingConfig?.storagePath;
63
-
64
- // 1. Root directory
65
- const defaultRoot = path.join(os.homedir(), '.rlc', 'notes');
66
- const rootDirAnswer = await question(`Root directory for notes [${defaultRoot}]: `);
67
- const rootDir = rootDirAnswer.trim() || defaultRoot;
68
-
69
- // Check if we need to migrate data
70
- if (oldStoragePath && oldStoragePath !== rootDir && fs.existsSync(oldStoragePath)) {
71
- const entries = fs.readdirSync(oldStoragePath);
72
- if (entries.length > 0) {
73
- const migrateAnswer = await question(`\nMigrate existing data from ${oldStoragePath}? [Y/n]: `);
74
- if (migrateAnswer.toLowerCase() !== 'n') {
75
- if (!fs.existsSync(rootDir)) {
76
- fs.mkdirSync(rootDir, { recursive: true });
77
- }
78
-
79
- console.log(`Migrating data...`);
80
- for (const entry of entries) {
81
- const srcPath = path.join(oldStoragePath, entry);
82
- const destPath = path.join(rootDir, entry);
83
- copyRecursive(srcPath, destPath);
33
+ export async function initCommand(existingRl?: readline.Interface): Promise<void> {
34
+ // Create our own readline if not provided, or use existing one
35
+ const rl = existingRl || readline.createInterface({
36
+ input: process.stdin,
37
+ output: process.stdout,
38
+ });
39
+
40
+ const shouldCloseRl = !existingRl;
41
+
42
+ try {
43
+ console.log('\n╔═══════════════════════════════════════╗');
44
+ console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
45
+ console.log('╚═══════════════════════════════════════╝\n');
46
+
47
+ // Get existing config if any
48
+ const existingConfig = await initConfig();
49
+ const oldStoragePath = existingConfig?.storagePath;
50
+
51
+ // 1. Root directory
52
+ const defaultRoot = path.join(os.homedir(), '.rlc', 'workspace');
53
+ const rootDirAnswer = await question(rl, `Root directory [${defaultRoot}]: `);
54
+ const rootDir = rootDirAnswer.trim() || defaultRoot;
55
+
56
+ // Check if we need to migrate data
57
+ if (oldStoragePath && oldStoragePath !== rootDir && fs.existsSync(oldStoragePath)) {
58
+ const entries = fs.readdirSync(oldStoragePath);
59
+ if (entries.length > 0) {
60
+ const migrateAnswer = await question(rl, `\nMigrate existing data from ${oldStoragePath}? [Y/n]: `);
61
+ if (migrateAnswer.toLowerCase() !== 'n') {
62
+ if (!fs.existsSync(rootDir)) {
63
+ fs.mkdirSync(rootDir, { recursive: true });
64
+ }
65
+
66
+ console.log(`Migrating data...`);
67
+ for (const entry of entries) {
68
+ const srcPath = path.join(oldStoragePath, entry);
69
+ const destPath = path.join(rootDir, entry);
70
+ copyRecursive(srcPath, destPath);
71
+ }
72
+ console.log(`Migrated ${entries.length} items to ${rootDir}`);
84
73
  }
85
- console.log(`Migrated ${entries.length} items to ${rootDir}`);
86
74
  }
87
75
  }
88
- }
89
76
 
90
- if (!fs.existsSync(rootDir)) {
91
- fs.mkdirSync(rootDir, { recursive: true });
92
- console.log(`Created directory: ${rootDir}`);
93
- }
77
+ if (!fs.existsSync(rootDir)) {
78
+ fs.mkdirSync(rootDir, { recursive: true });
79
+ console.log(`Created directory: ${rootDir}`);
80
+ }
94
81
 
95
- // 2. AI Provider selection
96
- console.log('\nSelect AI Provider:');
97
- console.log(' 1. Claude Sonnet 4.5');
98
- console.log(' 2. Claude Opus 4.5');
99
- console.log(' 3. GPT-4o (latest)');
100
- console.log(' 4. Gemini 3 Pro');
101
- console.log(' 5. Grok (latest)');
102
-
103
- const aiChoice = await question('\nEnter choice [1-5] (default: 1): ');
104
- const aiProviders = [
105
- { name: 'claude', model: 'claude-sonnet-4-20250514', apiUrl: 'https://api.anthropic.com' },
106
- { name: 'claude-opus', model: 'claude-opus-4-20250514', apiUrl: 'https://api.anthropic.com' },
107
- { name: 'openai', model: 'gpt-4o', apiUrl: 'https://api.openai.com' },
108
- { name: 'gemini', model: 'gemini-3-pro', apiUrl: 'https://generativelanguage.googleapis.com' },
109
- { name: 'grok', model: 'grok-beta', apiUrl: 'https://api.x.ai' },
110
- ];
111
-
112
- const selectedIndex = parseInt(aiChoice.trim()) - 1 || 0;
113
- const selectedProvider = aiProviders[selectedIndex] || aiProviders[0];
114
-
115
- console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
116
-
117
- // 3. API Key - reuse existing if not provided
118
- const existingApiKey = existingConfig?.apiKey || '';
119
- const hasExistingKey = existingApiKey.length > 0;
120
- const keyPrompt = hasExistingKey
121
- ? `\nAPI key for ${selectedProvider.name} [press Enter to keep existing]: `
122
- : `\nEnter API key for ${selectedProvider.name}: `;
123
-
124
- const apiKeyInput = await question(keyPrompt);
125
- const apiKey = apiKeyInput.trim() || existingApiKey;
126
-
127
- if (!apiKey) {
128
- console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
129
- } else if (apiKeyInput.trim()) {
130
- console.log('API key saved');
131
- } else {
132
- console.log('Using existing API key');
133
- }
82
+ // 2. AI Provider selection
83
+ console.log('\nSelect AI Provider:');
84
+ console.log(' 1. Claude Sonnet 4.5');
85
+ console.log(' 2. Claude Opus 4.5');
86
+ console.log(' 3. GPT-4o (latest)');
87
+ console.log(' 4. Gemini 3 Pro');
88
+ console.log(' 5. Grok (latest)');
89
+
90
+ const aiChoice = await question(rl, '\nEnter choice [1-5] (default: 1): ');
91
+ const aiProviders = [
92
+ { name: 'claude', model: 'claude-sonnet-4-20250514', apiUrl: 'https://api.anthropic.com' },
93
+ { name: 'claude-opus', model: 'claude-opus-4-20250514', apiUrl: 'https://api.anthropic.com' },
94
+ { name: 'openai', model: 'gpt-4o', apiUrl: 'https://api.openai.com' },
95
+ { name: 'gemini', model: 'gemini-3-pro', apiUrl: 'https://generativelanguage.googleapis.com' },
96
+ { name: 'grok', model: 'grok-beta', apiUrl: 'https://api.x.ai' },
97
+ ];
98
+
99
+ const selectedIndex = parseInt(aiChoice.trim()) - 1 || 0;
100
+ const selectedProvider = aiProviders[selectedIndex] || aiProviders[0];
101
+
102
+ console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
103
+
104
+ // 3. API Key - reuse existing if not provided
105
+ const existingApiKey = existingConfig?.apiKey || '';
106
+ const hasExistingKey = existingApiKey.length > 0;
107
+ const keyPrompt = hasExistingKey
108
+ ? `\nAPI key for ${selectedProvider.name} [Enter to keep existing]: `
109
+ : `\nEnter API key for ${selectedProvider.name}: `;
110
+
111
+ const apiKeyInput = await question(rl, keyPrompt);
112
+ const apiKey = apiKeyInput.trim() || existingApiKey;
113
+
114
+ if (!apiKey) {
115
+ console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
116
+ } else if (apiKeyInput.trim()) {
117
+ console.log('API key saved');
118
+ } else {
119
+ console.log('Using existing API key');
120
+ }
134
121
 
135
- // Save config
136
- const config: Config = {
137
- aiProvider: selectedProvider.name as any,
138
- apiKey: apiKey,
139
- apiUrl: selectedProvider.apiUrl,
140
- storagePath: rootDir,
141
- currentPath: rootDir,
142
- model: selectedProvider.model,
143
- };
144
-
145
- saveConfig(config);
146
-
147
- // Ensure storage directory exists
148
- if (!fs.existsSync(rootDir)) {
149
- fs.mkdirSync(rootDir, { recursive: true });
150
- }
122
+ // Save config
123
+ const config: Config = {
124
+ aiProvider: selectedProvider.name as any,
125
+ apiKey: apiKey,
126
+ apiUrl: selectedProvider.apiUrl,
127
+ storagePath: rootDir,
128
+ currentPath: rootDir,
129
+ model: selectedProvider.model,
130
+ };
151
131
 
152
- console.log('\n╔═══════════════════════════════════════╗');
153
- console.log('║ INITIALIZATION COMPLETE ║');
154
- console.log('╚═══════════════════════════════════════╝\n');
155
- console.log(`Root directory: ${rootDir}`);
156
- console.log(`AI Provider: ${selectedProvider.name}`);
157
- console.log(`Model: ${selectedProvider.model}\n`);
132
+ saveConfig(config);
133
+
134
+ // Ensure storage directory exists
135
+ if (!fs.existsSync(rootDir)) {
136
+ fs.mkdirSync(rootDir, { recursive: true });
137
+ }
138
+
139
+ console.log('\n╔═══════════════════════════════════════╗');
140
+ console.log('║ INITIALIZATION COMPLETE ║');
141
+ console.log('╚═══════════════════════════════════════╝\n');
142
+ console.log(`Root directory: ${rootDir}`);
143
+ console.log(`AI Provider: ${selectedProvider.name}`);
144
+ console.log(`Model: ${selectedProvider.model}\n`);
145
+ } finally {
146
+ if (shouldCloseRl) {
147
+ rl.close();
148
+ }
149
+ }
158
150
  }
159
151
 
@@ -12,7 +12,7 @@ export interface Config {
12
12
  }
13
13
 
14
14
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
15
- const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'notes');
15
+ const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
16
16
 
17
17
  export async function initConfig(): Promise<Config | null> {
18
18
  const configDir = path.dirname(CONFIG_FILE);
@@ -1,5 +1,6 @@
1
1
  import * as path from 'path';
2
2
  import * as fs from 'fs';
3
+ import * as readline from 'readline';
3
4
  import { execSync } from 'child_process';
4
5
  import { Config } from '../config/config';
5
6
  import { listSchemas, navigateToNode, getTree } from '../storage/storage';
@@ -286,7 +287,8 @@ export async function processCommand(
286
287
  input: string,
287
288
  currentPath: string,
288
289
  config: Config,
289
- signal?: AbortSignal
290
+ signal?: AbortSignal,
291
+ rl?: readline.Interface
290
292
  ): Promise<CommandResult> {
291
293
  // Check for clipboard pipe
292
294
  const clipboardPipe = /\s*\|\s*(pbcopy|copy|clip)\s*$/i;
@@ -518,7 +520,7 @@ export async function processCommand(
518
520
 
519
521
  if (command === 'init') {
520
522
  const { initCommand } = await import('../commands/init');
521
- await initCommand();
523
+ await initCommand(rl);
522
524
  return { output: 'Initialization complete. You can now use rlc.\n', reloadConfig: true };
523
525
  }
524
526
 
@@ -124,7 +124,7 @@ export async function startInteractive(initialConfig: Config): Promise<void> {
124
124
  const abortController = currentCommandAbortController;
125
125
 
126
126
  try {
127
- const result = await processCommand(trimmed, state.currentPath, config, abortController.signal);
127
+ const result = await processCommand(trimmed, state.currentPath, config, abortController.signal, rl);
128
128
 
129
129
  if (abortController.signal.aborted) {
130
130
  rl.prompt();