roguelike-cli 1.3.1 → 1.3.2

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/README.md CHANGED
@@ -17,21 +17,18 @@
17
17
  ╚═════════════════════════╝
18
18
  ```
19
19
 
20
- ## What is this?
20
+ **Turn your backlog into a dungeon crawl.** Roguelike CLI is a terminal-based task manager that transforms productivity into an RPG experience. Complete quests, level up, and conquer your goals.
21
21
 
22
- **A gamified task manager where every task is a folder and every project is a dungeon.**
22
+ ## Features
23
23
 
24
- Instead of flat text files, your tasks become a **file system tree**. Nested tasks = nested folders. Complete tasks to earn XP, level up, and unlock achievements.
24
+ - **RPG Engine** Tasks are quests. Completing them earns XP, unlocks achievements, and levels you up.
25
+ - **AI Game Master** — Integrated AI helps decompose complex tasks and generates structured plans.
26
+ - **Local-First** — Your data stays on your machine in simple folders and JSON files.
27
+ - **Themeable** — Choose your adventure style: Fantasy, Space Opera, Star Wars, Cyberpunk, and more.
25
28
 
26
- ## Features
29
+ ## Why Roguelike CLI?
27
30
 
28
- - **Navigate** your todos like directories (`cd`, `ls`, `tree`)
29
- - **Track progress** with XP, levels, and streaks
30
- - **Earn achievements** for completing tasks
31
- - **Mark milestones** as boss fights (3x XP)
32
- - **Set deadlines** with human-readable dates
33
- - **Generate visualizations** - trees, block diagrams, dungeon maps
34
- - Let **AI help** you structure complex projects
31
+ Most task managers are boring. We make deep work addictive by applying proven RPG mechanics to your daily workflow.
35
32
 
36
33
  ## Install
37
34
 
@@ -40,40 +37,107 @@ npm i -g roguelike-cli
40
37
  rlc
41
38
  ```
42
39
 
40
+ ## Folder Structure
41
+
42
+ Every task is a folder. You can drop files directly into task folders — designs, docs, code, anything. Your file manager becomes your task manager.
43
+
44
+ ```
45
+ my-startup/
46
+ ├── research/
47
+ │ ├── market-analysis/
48
+ │ │ └── competitors.xlsx <- attached file
49
+ │ └── user-interviews/
50
+ │ └── notes.md <- attached file
51
+ ├── development/
52
+ │ ├── backend-api/
53
+ │ │ └── spec.yaml <- attached file
54
+ │ └── frontend-ui/
55
+ └── launch/
56
+ └── marketing/
57
+ ```
58
+
59
+ Navigate with `cd`, view with `tree`, open in Finder with `open`. It's just folders.
60
+
43
61
  ## Quick Start
44
62
 
45
63
  ```
46
- > todo launch startup
64
+ > todo launch my startup
47
65
 
48
66
  ├── Research [BOSS]
49
67
  │ ├── Market analysis
50
- │ └── User interviews
68
+ │ └── User interviews [DUE: +7d]
51
69
  ├── Development
52
- │ ├── Backend API [DUE: +7d]
70
+ │ ├── Backend API [DUE: Jan 20]
53
71
  │ └── Frontend UI
54
72
  └── Launch [MILESTONE]
55
- └── Marketing campaign
56
73
 
57
- [Type "save" to create folder launch-startup/]
74
+ [Type "save" to create folders]
58
75
  > save
59
- Created todo folder: launch-startup/
76
+ Created: launch-my-startup/
60
77
 
61
- > cd launch-startup/research
78
+ > cd launch-my-startup/research
62
79
  > done
63
80
 
64
- === TASK COMPLETED ===
81
+ === QUEST COMPLETED ===
65
82
 
66
- Tasks completed: 3
67
- Bosses defeated: 1
68
83
  +45 XP
69
-
70
84
  *** LEVEL UP! ***
71
- You are now level 2!
72
85
 
73
86
  === NEW ACHIEVEMENTS ===
74
- [x] First Blood: Complete your first task
75
- [x] Boss Slayer: Complete a boss task
87
+ [x] First Blood: Complete your first quest
88
+ [x] Boss Slayer: Defeat a boss
89
+ ```
90
+
91
+ ## Configuration
92
+
93
+ Run `init` to set up, or use `config` flags:
94
+
95
+ ```
96
+ > config
97
+
98
+ Provider: claude
99
+ Model: claude-sonnet-4-20250514
100
+ API Key: sk-ant-a...xxxx
101
+ Storage: /Users/you/.rlc/workspace
102
+ Theme: Fantasy RPG
103
+ Rules: Use fantasy RPG language...
104
+
105
+ Set with flags:
106
+ config -k=<key> Set API key
107
+ config -m=<model> Set model
108
+ config -t=<theme> Set theme
109
+ config -r="<rules>" Set custom rules
110
+ ```
111
+
112
+ ### Default Settings
113
+
114
+ | Setting | Default |
115
+ |---------|---------|
116
+ | Provider | Claude Sonnet 4.5 |
117
+ | Storage | `~/.rlc/workspace` |
118
+ | Theme | Default (no theme) |
119
+
120
+ ## Themes (Rules)
121
+
122
+ Themes change how the AI speaks. Set with `config -t=<theme>` or during `init`.
123
+
124
+ | Theme | Style |
125
+ |-------|-------|
126
+ | `default` | Standard task manager language |
127
+ | `fantasy` | Quests, dungeons, dragons, loot |
128
+ | `space` | Missions, starships, commanders |
129
+ | `starwars` | Jedi, Force, Rebel Alliance |
130
+ | `western` | Bounties, sheriffs, frontier |
131
+ | `cyberpunk` | Gigs, netrunners, corps |
132
+ | `pirate` | Plunder, treasure, seven seas |
133
+
134
+ ### Custom Rules
135
+
76
136
  ```
137
+ > config -r="Speak like a medieval knight. Tasks are 'duties'. Use 'huzzah' for success."
138
+ ```
139
+
140
+ Or select "Custom" during `init` to enter your own rules.
77
141
 
78
142
  ## Commands
79
143
 
@@ -84,24 +148,21 @@ You are now level 2!
84
148
  | `ls` | List tasks (shows status) |
85
149
  | `tree` | Task tree with deadlines |
86
150
  | `tree -A` | Include files |
87
- | `tree --depth=N` | Limit depth |
88
151
  | `cd <task>` | Enter task |
89
- | `..`, `...` | Go up 1 or 2 levels |
90
- | `pwd` | Current path |
152
+ | `..`, `...` | Go up levels |
91
153
  | `open` | Open in Finder |
92
154
 
93
155
  ### Task Management
94
156
 
95
157
  | Command | Description |
96
158
  |---------|-------------|
97
- | `done` | Complete task (recursive, earns XP) |
98
- | `undo` | Undo last done (restores XP) |
159
+ | `done` | Complete task (earns XP) |
160
+ | `undo` | Undo last done |
99
161
  | `deadline <date>` | Set deadline |
100
- | `boss` | Toggle boss status (3x XP) |
101
- | `block [node]` | Block by task or text reason |
102
- | `unblock` | Remove blocked status |
103
- | `status` | Show task details |
104
- | `check` | Show overdue/upcoming deadlines |
162
+ | `boss` | Toggle boss (3x XP) |
163
+ | `block [node]` | Block by task |
164
+ | `unblock` | Remove block |
165
+ | `check` | Show deadlines |
105
166
 
106
167
  ### Gamification
107
168
 
@@ -109,77 +170,63 @@ You are now level 2!
109
170
  |---------|-------------|
110
171
  | `stats` | XP, level, streaks |
111
172
  | `achievements` | Achievement list |
112
- | `map` | Dungeon map view |
113
- | `map --ai` | AI-generated dungeon |
173
+ | `map` | Dungeon map |
174
+ | `map --ai` | AI-generated map |
114
175
 
115
176
  ### File Operations
116
177
 
117
178
  | Command | Description |
118
179
  |---------|-------------|
119
180
  | `mkdir <name>` | Create task |
120
- | `cp <src> <dst>` | Copy |
121
- | `mv <src> <dst>` | Move/rename |
122
- | `rm <name>` | Delete file |
123
- | `rm -rf <name>` | Delete folder |
181
+ | `cp`, `mv`, `rm` | Standard ops |
124
182
 
125
- ### AI Generation
183
+ ### Configuration
126
184
 
127
185
  | Command | Description |
128
186
  |---------|-------------|
129
- | `<description>` | AI generates preview |
130
- | `save` | Save pending schema |
131
- | `cancel` | Discard |
187
+ | `init` | Setup wizard |
188
+ | `config` | View settings |
189
+ | `config -k=<key>` | Set API key |
190
+ | `config -m=<model>` | Set model |
191
+ | `config -t=<theme>` | Set theme |
192
+ | `config -r="<rules>"` | Custom rules |
132
193
 
133
194
  ## Deadlines
134
195
 
135
196
  ```
136
197
  > deadline today # Due today
137
198
  > deadline tomorrow # Due tomorrow
138
- > deadline +3d # Due in 3 days
139
- > deadline Jan 15 # Due on date
199
+ > deadline +3d # In 3 days
200
+ > deadline Jan 15 # Specific date
140
201
  ```
141
202
 
142
203
  Tree shows deadlines:
143
-
144
204
  ```
145
- ├── Backend API/ [BOSS] [3d left]
205
+ ├── Backend/ [BOSS] [3d left]
146
206
  │ ├── Database/ [DONE]
147
- │ └── Endpoints/ [OVERDUE 2d]
207
+ │ └── API/ [OVERDUE 2d]
148
208
  └── Frontend/ [tomorrow]
149
209
  ```
150
210
 
151
211
  ## XP System
152
212
 
153
- - Base XP: 10 per task
154
- - Depth bonus: +5 XP per nesting level
155
- - Boss multiplier: 3x XP
156
-
157
- | Level | XP Required |
158
- |-------|-------------|
159
- | 1 | 0 |
160
- | 2 | 100 |
161
- | 3 | 150 |
162
- | 5 | 337 |
163
- | 10 | 3,844 |
213
+ | Factor | XP |
214
+ |--------|-----|
215
+ | Base task | 10 |
216
+ | Per depth level | +5 |
217
+ | Boss multiplier | 3x |
164
218
 
165
219
  ## Achievements
166
220
 
167
- | Achievement | Description |
168
- |-------------|-------------|
221
+ | Achievement | How to unlock |
222
+ |-------------|---------------|
169
223
  | First Blood | Complete first task |
170
224
  | Getting Started | Complete 10 tasks |
171
- | Productive | Complete 50 tasks |
172
225
  | Centurion | Complete 100 tasks |
173
- | Deep Diver | Complete task at depth 5+ |
174
- | Boss Slayer | Complete a boss task |
175
- | Boss Hunter | Defeat 5 bosses |
176
- | Speedrunner | Complete task same day |
177
- | On a Roll | 3 day streak |
226
+ | Deep Diver | Task at depth 5+ |
227
+ | Boss Slayer | Complete a boss |
228
+ | Speedrunner | Same-day completion |
178
229
  | Streak Master | 7 day streak |
179
- | Unstoppable | 30 day streak |
180
- | Adventurer | Reach level 5 |
181
- | Veteran | Reach level 10 |
182
- | Legend | Reach level 25 |
183
230
 
184
231
  ## Dungeon Map
185
232
 
@@ -187,42 +234,12 @@ Tree shows deadlines:
187
234
  > map
188
235
 
189
236
  ###########################################
190
- # # #
191
- # [Research] # [Development] #
192
- # * Market +---* Backend #
193
- # x Users # @ Deploy BOSS #
194
- # # #
195
- ##########+############+##################
196
- | |
197
- ##########+############+##################
198
- # #
199
- # [Launch] #
200
- # * Marketing #
201
- # @ SHIP IT! [BOSS] #
202
- # #
203
- ###########################################
204
-
205
- Legend: * Task x Done @ Boss ! Blocked + Door
206
- ```
207
-
208
- Use `map --ai` for creative AI-generated layouts.
209
-
210
- ## Block Diagrams
211
-
212
- ```
213
- > schema kubernetes cluster
214
-
215
- ┌─────────────────────────────────────────────────────────────┐
216
- │ Kubernetes Cluster │
217
- │ │
218
- │ ┌──────────────────┐ ┌──────────────────┐ │
219
- │ │ Control Plane │ │ Worker Nodes │ │
220
- │ └────────┬─────────┘ └────────┬─────────┘ │
221
- │ └──────────┬───────────────┘ │
222
- │ ┌──────────────────┐│┌──────────────────┐ │
223
- │ │ PostgreSQL │││ Redis │ │
224
- │ └──────────────────┘│└──────────────────┘ │
225
- └─────────────────────────────────────────────────────────────┘
237
+ # # #
238
+ # [Research] # [Development] #
239
+ # x Analysis +---* Backend #
240
+ # x Interviews # @ Deploy BOSS #
241
+ # # #
242
+ ##########+###########+###################
226
243
  ```
227
244
 
228
245
  ## Clipboard
@@ -230,15 +247,6 @@ Use `map --ai` for creative AI-generated layouts.
230
247
  ```
231
248
  > tree | pbcopy # macOS
232
249
  > tree | clip # Windows
233
- > ls | copy # Alternative
234
- ```
235
-
236
- ## Configuration
237
-
238
- ```
239
- > init # Setup wizard
240
- > config # Show settings
241
- > config:apiKey=sk-... # Set API key
242
250
  ```
243
251
 
244
252
  ## Website
package/dist/ai/claude.js CHANGED
@@ -46,7 +46,7 @@ Create a creative, interesting dungeon layout for the given tasks.
46
46
  Output ONLY the ASCII map, no JSON wrapper.`;
47
47
  async function generateSchemaWithAI(input, config, signal, history) {
48
48
  if (!config.apiKey) {
49
- throw new Error('API key not set. Use config:apiKey=<key> to set it.');
49
+ throw new Error('API key not set. Use config -k=<key> to set it.');
50
50
  }
51
51
  const client = new sdk_1.default({
52
52
  apiKey: config.apiKey,
@@ -68,10 +68,15 @@ async function generateSchemaWithAI(input, config, signal, history) {
68
68
  });
69
69
  try {
70
70
  const model = config.model || 'claude-sonnet-4-20250514';
71
+ // Build system prompt with custom rules
72
+ let systemPrompt = SYSTEM_PROMPT;
73
+ if (config.rules) {
74
+ systemPrompt += '\n\nADDITIONAL STYLE RULES (apply to all responses):\n' + config.rules;
75
+ }
71
76
  const message = await client.messages.create({
72
77
  model: model,
73
78
  max_tokens: 2000,
74
- system: SYSTEM_PROMPT,
79
+ system: systemPrompt,
75
80
  messages: messages,
76
81
  });
77
82
  const content = message.content[0];
@@ -98,17 +103,22 @@ async function generateSchemaWithAI(input, config, signal, history) {
98
103
  }
99
104
  async function generateDungeonMapWithAI(treeContent, config, signal) {
100
105
  if (!config.apiKey) {
101
- throw new Error('API key not set. Use config:apiKey=<key> to set it.');
106
+ throw new Error('API key not set. Use config -k=<key> to set it.');
102
107
  }
103
108
  const client = new sdk_1.default({
104
109
  apiKey: config.apiKey,
105
110
  });
106
111
  try {
107
112
  const model = config.model || 'claude-sonnet-4-20250514';
113
+ // Build system prompt with custom rules
114
+ let systemPrompt = DUNGEON_MAP_PROMPT;
115
+ if (config.rules) {
116
+ systemPrompt += '\n\nADDITIONAL STYLE RULES:\n' + config.rules;
117
+ }
108
118
  const message = await client.messages.create({
109
119
  model: model,
110
120
  max_tokens: 2000,
111
- system: DUNGEON_MAP_PROMPT,
121
+ system: systemPrompt,
112
122
  messages: [{
113
123
  role: 'user',
114
124
  content: 'Generate a dungeon map for this task tree:\n\n' + treeContent
@@ -63,7 +63,6 @@ function copyRecursive(src, dest) {
63
63
  }
64
64
  }
65
65
  async function initCommand(existingRl) {
66
- // Create our own readline if not provided, or use existing one
67
66
  const rl = existingRl || readline.createInterface({
68
67
  input: process.stdin,
69
68
  output: process.stdout,
@@ -73,7 +72,6 @@ async function initCommand(existingRl) {
73
72
  console.log('\n╔═══════════════════════════════════════╗');
74
73
  console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
75
74
  console.log('╚═══════════════════════════════════════╝\n');
76
- // Get existing config if any
77
75
  const existingConfig = await (0, config_1.initConfig)();
78
76
  const oldStoragePath = existingConfig?.storagePath;
79
77
  // 1. Root directory
@@ -121,7 +119,7 @@ async function initCommand(existingRl) {
121
119
  const selectedIndex = parseInt(aiChoice.trim()) - 1 || 0;
122
120
  const selectedProvider = aiProviders[selectedIndex] || aiProviders[0];
123
121
  console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
124
- // 3. API Key - reuse existing if not provided
122
+ // 3. API Key
125
123
  const existingApiKey = existingConfig?.apiKey || '';
126
124
  const hasExistingKey = existingApiKey.length > 0;
127
125
  const keyPrompt = hasExistingKey
@@ -130,7 +128,7 @@ async function initCommand(existingRl) {
130
128
  const apiKeyInput = await question(rl, keyPrompt);
131
129
  const apiKey = apiKeyInput.trim() || existingApiKey;
132
130
  if (!apiKey) {
133
- console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
131
+ console.log('Warning: API key not set. You can set it later with: config -k <key>');
134
132
  }
135
133
  else if (apiKeyInput.trim()) {
136
134
  console.log('API key saved');
@@ -138,6 +136,39 @@ async function initCommand(existingRl) {
138
136
  else {
139
137
  console.log('Using existing API key');
140
138
  }
139
+ // 4. Theme/Rules selection
140
+ console.log('\nSelect AI Theme (affects language style):');
141
+ const presetKeys = Object.keys(config_1.RULES_PRESETS);
142
+ presetKeys.forEach((key, index) => {
143
+ console.log(` ${index + 1}. ${config_1.RULES_PRESETS[key].name}`);
144
+ });
145
+ console.log(` ${presetKeys.length + 1}. Custom (enter your own rules)`);
146
+ const existingPreset = existingConfig?.rulesPreset || 'default';
147
+ const defaultPresetIndex = presetKeys.indexOf(existingPreset) + 1 || 1;
148
+ const themeChoice = await question(rl, `\nEnter choice [1-${presetKeys.length + 1}] (default: ${defaultPresetIndex}): `);
149
+ const themeIndex = parseInt(themeChoice.trim()) - 1;
150
+ let selectedRules = '';
151
+ let selectedPreset = 'default';
152
+ if (themeIndex >= 0 && themeIndex < presetKeys.length) {
153
+ selectedPreset = presetKeys[themeIndex];
154
+ selectedRules = config_1.RULES_PRESETS[selectedPreset].rules;
155
+ console.log(`Selected: ${config_1.RULES_PRESETS[selectedPreset].name}`);
156
+ }
157
+ else if (themeIndex === presetKeys.length) {
158
+ // Custom rules
159
+ console.log('\nEnter your custom rules for AI (how it should speak, what terms to use):');
160
+ console.log('Example: "Use pirate language. Tasks are treasure hunts. Be playful."');
161
+ const customRules = await question(rl, '\nYour rules: ');
162
+ selectedRules = customRules.trim();
163
+ selectedPreset = 'custom';
164
+ console.log('Custom rules saved');
165
+ }
166
+ else {
167
+ // Default
168
+ selectedPreset = existingConfig?.rulesPreset || 'default';
169
+ selectedRules = existingConfig?.rules || '';
170
+ console.log(`Keeping: ${config_1.RULES_PRESETS[selectedPreset]?.name || 'Default'}`);
171
+ }
141
172
  // Save config
142
173
  const config = {
143
174
  aiProvider: selectedProvider.name,
@@ -146,9 +177,10 @@ async function initCommand(existingRl) {
146
177
  storagePath: rootDir,
147
178
  currentPath: rootDir,
148
179
  model: selectedProvider.model,
180
+ rules: selectedRules,
181
+ rulesPreset: selectedPreset,
149
182
  };
150
183
  (0, config_1.saveConfig)(config);
151
- // Ensure storage directory exists
152
184
  if (!fs.existsSync(rootDir)) {
153
185
  fs.mkdirSync(rootDir, { recursive: true });
154
186
  }
@@ -157,7 +189,8 @@ async function initCommand(existingRl) {
157
189
  console.log('╚═══════════════════════════════════════╝\n');
158
190
  console.log(`Root directory: ${rootDir}`);
159
191
  console.log(`AI Provider: ${selectedProvider.name}`);
160
- console.log(`Model: ${selectedProvider.model}\n`);
192
+ console.log(`Model: ${selectedProvider.model}`);
193
+ console.log(`Theme: ${config_1.RULES_PRESETS[selectedPreset]?.name || 'Custom'}\n`);
161
194
  }
162
195
  finally {
163
196
  if (shouldCloseRl) {
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.RULES_PRESETS = void 0;
36
37
  exports.initConfig = initConfig;
37
38
  exports.saveConfig = saveConfig;
38
39
  exports.getConfig = getConfig;
@@ -40,6 +41,37 @@ exports.updateConfig = updateConfig;
40
41
  const fs = __importStar(require("fs"));
41
42
  const path = __importStar(require("path"));
42
43
  const os = __importStar(require("os"));
44
+ // Preset rules for different themes
45
+ exports.RULES_PRESETS = {
46
+ default: {
47
+ name: 'Default (No theme)',
48
+ rules: '',
49
+ },
50
+ fantasy: {
51
+ name: 'Fantasy RPG',
52
+ rules: 'Use fantasy RPG language. Tasks are "quests", completing them is "slaying". Major milestones are "boss battles". Use terms like "adventurer", "dungeon", "loot", "guild". Add flavor text with swords, dragons, magic.',
53
+ },
54
+ space: {
55
+ name: 'Space Opera',
56
+ rules: 'Use sci-fi space language. Tasks are "missions", completing them is "mission accomplished". Major milestones are "final frontier". Use terms like "commander", "starship", "coordinates", "hyperdrive". Add flavor with stars, planets, aliens.',
57
+ },
58
+ starwars: {
59
+ name: 'Star Wars',
60
+ rules: 'Use Star Wars language. Tasks are "missions from the Rebel Alliance". Completing is "defeating the Empire". Milestones are "destroying the Death Star". Use "Jedi", "Force", "Padawan", "Master". May the Force be with you.',
61
+ },
62
+ western: {
63
+ name: 'Wild West',
64
+ rules: 'Use Wild West language. Tasks are "bounties", completing them is "collecting the reward". Milestones are "showdowns". Use terms like "sheriff", "outlaw", "saloon", "frontier", "partner". Add dusty trails and tumbleweeds.',
65
+ },
66
+ cyberpunk: {
67
+ name: 'Cyberpunk',
68
+ rules: 'Use cyberpunk language. Tasks are "gigs", completing them is "flatlined". Milestones are "megacorp takedowns". Use terms like "netrunner", "chrome", "corpo", "edgerunner", "eddies". Add neon and rain.',
69
+ },
70
+ pirate: {
71
+ name: 'Pirate',
72
+ rules: 'Use pirate language. Tasks are "plunder", completing them is "claiming the treasure". Milestones are "capturing the flagship". Use "captain", "crew", "booty", "seven seas", "landlubber". Arr matey!',
73
+ },
74
+ };
43
75
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
44
76
  const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
45
77
  async function initConfig() {
@@ -931,36 +931,67 @@ async function processCommand(input, currentPath, config, signal, rl) {
931
931
  return wrapResult({ output: currentPath });
932
932
  }
933
933
  if (command === 'config') {
934
+ const { updateConfig, RULES_PRESETS } = await Promise.resolve().then(() => __importStar(require('../config/config')));
935
+ // Check for flags
936
+ const keyFlag = parts.find(p => p.startsWith('-k=') || p.startsWith('--key='));
937
+ const modelFlag = parts.find(p => p.startsWith('-m=') || p.startsWith('--model='));
938
+ const rulesFlag = parts.find(p => p.startsWith('-r=') || p.startsWith('--rules='));
939
+ const themeFlag = parts.find(p => p.startsWith('-t=') || p.startsWith('--theme='));
940
+ if (keyFlag) {
941
+ const value = keyFlag.split('=').slice(1).join('=');
942
+ updateConfig({ apiKey: value });
943
+ return wrapResult({ output: 'API key updated.' });
944
+ }
945
+ if (modelFlag) {
946
+ const value = modelFlag.split('=').slice(1).join('=');
947
+ updateConfig({ model: value });
948
+ return wrapResult({ output: `Model updated: ${value}` });
949
+ }
950
+ if (rulesFlag) {
951
+ const value = rulesFlag.split('=').slice(1).join('=');
952
+ updateConfig({ rules: value, rulesPreset: 'custom' });
953
+ return wrapResult({ output: 'Custom rules updated.' });
954
+ }
955
+ if (themeFlag) {
956
+ const value = themeFlag.split('=').slice(1).join('=').toLowerCase();
957
+ if (RULES_PRESETS[value]) {
958
+ updateConfig({
959
+ rules: RULES_PRESETS[value].rules,
960
+ rulesPreset: value
961
+ });
962
+ return wrapResult({ output: `Theme updated: ${RULES_PRESETS[value].name}` });
963
+ }
964
+ else {
965
+ const themes = Object.keys(RULES_PRESETS).join(', ');
966
+ return wrapResult({ output: `Unknown theme. Available: ${themes}` });
967
+ }
968
+ }
969
+ // Show config
934
970
  const maskedKey = config.apiKey
935
971
  ? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
936
972
  : '(not set)';
973
+ const themeName = config.rulesPreset
974
+ ? (RULES_PRESETS[config.rulesPreset]?.name || 'Custom')
975
+ : 'Default';
976
+ const rulesPreview = config.rules
977
+ ? (config.rules.length > 50 ? config.rules.substring(0, 50) + '...' : config.rules)
978
+ : '(none)';
937
979
  const output = `
938
980
  Provider: ${config.aiProvider}
939
981
  Model: ${config.model || '(default)'}
940
982
  API Key: ${maskedKey}
941
983
  Storage: ${config.storagePath}
984
+ Theme: ${themeName}
985
+ Rules: ${rulesPreview}
986
+
987
+ Set with flags:
988
+ config -k=<key> Set API key
989
+ config -m=<model> Set model
990
+ config -t=<theme> Set theme (fantasy, space, starwars, western, cyberpunk, pirate)
991
+ config -r="<rules>" Set custom rules
942
992
  `.trim();
943
993
  return wrapResult({ output });
944
994
  }
945
- if (command.startsWith('config:')) {
946
- const configParts = input.split(':').slice(1).join(':').trim().split('=');
947
- if (configParts.length !== 2) {
948
- return { output: 'Usage: config:key=value' };
949
- }
950
- const key = configParts[0].trim();
951
- const value = configParts[1].trim();
952
- if (key === 'apiKey') {
953
- const { updateConfig } = await Promise.resolve().then(() => __importStar(require('../config/config')));
954
- updateConfig({ apiKey: value });
955
- return { output: 'API key updated.' };
956
- }
957
- if (key === 'storagePath') {
958
- const { updateConfig } = await Promise.resolve().then(() => __importStar(require('../config/config')));
959
- updateConfig({ storagePath: value, currentPath: value });
960
- return { output: `Storage path updated to: ${value}` };
961
- }
962
- return { output: `Unknown config key: ${key}` };
963
- }
964
995
  if (command === 'help') {
965
996
  return wrapResult({
966
997
  output: `
@@ -968,9 +999,7 @@ Storage: ${config.storagePath}
968
999
 
969
1000
  Navigation:
970
1001
  ls List tasks and files
971
- tree Show task tree with status
972
- tree -A Include files
973
- tree --depth=N Limit tree depth
1002
+ tree [-A] [--depth=N] Show task tree
974
1003
  cd <task> Navigate into task
975
1004
  cd .., ... Go back 1 or 2 levels
976
1005
  pwd Show current path
@@ -978,49 +1007,43 @@ Navigation:
978
1007
 
979
1008
  Task Management:
980
1009
  mkdir <name> Create new task
981
- done Mark current task as completed (recursive)
982
- undo Undo last done (restores XP)
983
- deadline <date> Set deadline (today, tomorrow, +3d, Jan 15)
984
- boss Toggle boss/milestone status (3x XP)
985
- block [node] Block by task (or text reason)
986
- unblock Remove blocked status
987
- status Show current task details
988
- check Show overdue/upcoming deadlines
989
-
990
- File Operations:
991
- cp <src> <dest> Copy file or folder
992
- mv <src> <dest> Move/rename
993
- rm <name> Delete file
994
- rm -rf <name> Delete folder
1010
+ done Complete task (earns XP)
1011
+ undo Undo last done
1012
+ deadline <date> Set deadline (today, +3d, Jan 15)
1013
+ boss Toggle boss status (3x XP)
1014
+ block [node] Block by task or text
1015
+ unblock Remove block
1016
+ status Task details
1017
+ check Upcoming deadlines
995
1018
 
996
1019
  Gamification:
997
- stats Show XP, level, streaks
998
- achievements Show achievement list
999
- map Dungeon map view
1000
- map --ai AI-generated dungeon map
1020
+ stats XP, level, streaks
1021
+ achievements Achievement list
1022
+ map [--ai] Dungeon map view
1001
1023
 
1002
- Schema Generation:
1003
- <description> AI generates todo/schema preview
1004
- save Save pending schema
1005
- cancel Discard pending schema
1006
-
1007
- Utility:
1024
+ Configuration:
1008
1025
  init Setup wizard
1009
1026
  config Show settings
1027
+ config -k=<key> Set API key
1028
+ config -m=<model> Set model
1029
+ config -t=<theme> Set theme (fantasy, space, starwars, etc)
1030
+ config -r="<rules>" Custom AI rules
1031
+
1032
+ Themes:
1033
+ default, fantasy, space, starwars, western, cyberpunk, pirate
1034
+
1035
+ File Operations:
1036
+ cp, mv, rm [-rf] Standard file operations
1010
1037
  clean --yes Clear current folder
1011
- v, version Show version
1012
- help This help
1013
- exit, quit Exit
1014
1038
 
1015
- Clipboard:
1016
- <cmd> | pbcopy Copy output (macOS)
1017
- <cmd> | clip Copy output (Windows)
1039
+ AI Generation:
1040
+ <description> AI generates preview
1041
+ save Save to folders/file
1042
+ cancel Discard
1018
1043
 
1019
- Examples:
1020
- block backend-api Block current task by sibling task
1021
- block "waiting for design" Block with text reason
1022
- deadline +3d Due in 3 days
1023
- check See all upcoming deadlines
1044
+ Clipboard:
1045
+ <cmd> | pbcopy Copy to clipboard (macOS)
1046
+ <cmd> | clip Copy to clipboard (Windows)
1024
1047
 
1025
1048
  www.rlc.rocks
1026
1049
  `.trim()
@@ -19,16 +19,16 @@ const ASCII_ART = [
19
19
  '║ Roguelike CLI ║',
20
20
  '╚═════════════════════════╝',
21
21
  '',
22
- ' Navigation: ls, cd, tree, pwd, open',
23
22
  ' Tasks: done, undo, deadline, boss, block',
24
- ' Gamification: stats, achievements, map, check',
23
+ ' Stats: stats, achievements, map, check',
24
+ ' Config: init, config -t=<theme>',
25
25
  '',
26
- ' TAB to autocomplete, | pbcopy to copy',
27
- ' Workflow: <description> -> refine -> save',
26
+ ' Themes: fantasy, space, starwars, cyberpunk',
28
27
  '',
29
- ' help - all commands, init - setup',
28
+ ' TAB autocomplete, | pbcopy to copy',
29
+ ' <description> -> refine -> save',
30
30
  '',
31
- ' www.rlc.rocks',
31
+ ' help - commands, www.rlc.rocks',
32
32
  '',
33
33
  ' Ready...',
34
34
  '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roguelike-cli",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "AI-powered interactive terminal for creating schemas and todo lists",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
package/src/ai/claude.ts CHANGED
@@ -60,7 +60,7 @@ export async function generateSchemaWithAI(
60
60
  history?: ConversationMessage[]
61
61
  ): Promise<GeneratedSchema | null> {
62
62
  if (!config.apiKey) {
63
- throw new Error('API key not set. Use config:apiKey=<key> to set it.');
63
+ throw new Error('API key not set. Use config -k=<key> to set it.');
64
64
  }
65
65
 
66
66
  const client = new Anthropic({
@@ -87,10 +87,17 @@ export async function generateSchemaWithAI(
87
87
 
88
88
  try {
89
89
  const model = config.model || 'claude-sonnet-4-20250514';
90
+
91
+ // Build system prompt with custom rules
92
+ let systemPrompt = SYSTEM_PROMPT;
93
+ if (config.rules) {
94
+ systemPrompt += '\n\nADDITIONAL STYLE RULES (apply to all responses):\n' + config.rules;
95
+ }
96
+
90
97
  const message = await client.messages.create({
91
98
  model: model,
92
99
  max_tokens: 2000,
93
- system: SYSTEM_PROMPT,
100
+ system: systemPrompt,
94
101
  messages: messages,
95
102
  });
96
103
 
@@ -126,7 +133,7 @@ export async function generateDungeonMapWithAI(
126
133
  signal?: AbortSignal
127
134
  ): Promise<string | null> {
128
135
  if (!config.apiKey) {
129
- throw new Error('API key not set. Use config:apiKey=<key> to set it.');
136
+ throw new Error('API key not set. Use config -k=<key> to set it.');
130
137
  }
131
138
 
132
139
  const client = new Anthropic({
@@ -135,10 +142,17 @@ export async function generateDungeonMapWithAI(
135
142
 
136
143
  try {
137
144
  const model = config.model || 'claude-sonnet-4-20250514';
145
+
146
+ // Build system prompt with custom rules
147
+ let systemPrompt = DUNGEON_MAP_PROMPT;
148
+ if (config.rules) {
149
+ systemPrompt += '\n\nADDITIONAL STYLE RULES:\n' + config.rules;
150
+ }
151
+
138
152
  const message = await client.messages.create({
139
153
  model: model,
140
154
  max_tokens: 2000,
141
- system: DUNGEON_MAP_PROMPT,
155
+ system: systemPrompt,
142
156
  messages: [{
143
157
  role: 'user',
144
158
  content: 'Generate a dungeon map for this task tree:\n\n' + treeContent
@@ -2,7 +2,7 @@ import * as fs from 'fs';
2
2
  import * as path from 'path';
3
3
  import * as os from 'os';
4
4
  import * as readline from 'readline';
5
- import { Config, saveConfig, initConfig } from '../config/config';
5
+ import { Config, saveConfig, initConfig, RULES_PRESETS } from '../config/config';
6
6
 
7
7
  function question(rl: readline.Interface, query: string): Promise<string> {
8
8
  return new Promise((resolve) => {
@@ -31,7 +31,6 @@ function copyRecursive(src: string, dest: string): void {
31
31
  }
32
32
 
33
33
  export async function initCommand(existingRl?: readline.Interface): Promise<void> {
34
- // Create our own readline if not provided, or use existing one
35
34
  const rl = existingRl || readline.createInterface({
36
35
  input: process.stdin,
37
36
  output: process.stdout,
@@ -44,7 +43,6 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
44
43
  console.log('║ ROGUELIKE CLI INITIALIZATION WIZARD ║');
45
44
  console.log('╚═══════════════════════════════════════╝\n');
46
45
 
47
- // Get existing config if any
48
46
  const existingConfig = await initConfig();
49
47
  const oldStoragePath = existingConfig?.storagePath;
50
48
 
@@ -101,7 +99,7 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
101
99
 
102
100
  console.log(`Selected: ${selectedProvider.name} (${selectedProvider.model})`);
103
101
 
104
- // 3. API Key - reuse existing if not provided
102
+ // 3. API Key
105
103
  const existingApiKey = existingConfig?.apiKey || '';
106
104
  const hasExistingKey = existingApiKey.length > 0;
107
105
  const keyPrompt = hasExistingKey
@@ -112,13 +110,49 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
112
110
  const apiKey = apiKeyInput.trim() || existingApiKey;
113
111
 
114
112
  if (!apiKey) {
115
- console.log('Warning: API key not set. You can set it later with config:apiKey=<key>');
113
+ console.log('Warning: API key not set. You can set it later with: config -k <key>');
116
114
  } else if (apiKeyInput.trim()) {
117
115
  console.log('API key saved');
118
116
  } else {
119
117
  console.log('Using existing API key');
120
118
  }
121
119
 
120
+ // 4. Theme/Rules selection
121
+ console.log('\nSelect AI Theme (affects language style):');
122
+ const presetKeys = Object.keys(RULES_PRESETS);
123
+ presetKeys.forEach((key, index) => {
124
+ console.log(` ${index + 1}. ${RULES_PRESETS[key].name}`);
125
+ });
126
+ console.log(` ${presetKeys.length + 1}. Custom (enter your own rules)`);
127
+
128
+ const existingPreset = existingConfig?.rulesPreset || 'default';
129
+ const defaultPresetIndex = presetKeys.indexOf(existingPreset) + 1 || 1;
130
+
131
+ const themeChoice = await question(rl, `\nEnter choice [1-${presetKeys.length + 1}] (default: ${defaultPresetIndex}): `);
132
+ const themeIndex = parseInt(themeChoice.trim()) - 1;
133
+
134
+ let selectedRules = '';
135
+ let selectedPreset = 'default';
136
+
137
+ if (themeIndex >= 0 && themeIndex < presetKeys.length) {
138
+ selectedPreset = presetKeys[themeIndex];
139
+ selectedRules = RULES_PRESETS[selectedPreset].rules;
140
+ console.log(`Selected: ${RULES_PRESETS[selectedPreset].name}`);
141
+ } else if (themeIndex === presetKeys.length) {
142
+ // Custom rules
143
+ console.log('\nEnter your custom rules for AI (how it should speak, what terms to use):');
144
+ console.log('Example: "Use pirate language. Tasks are treasure hunts. Be playful."');
145
+ const customRules = await question(rl, '\nYour rules: ');
146
+ selectedRules = customRules.trim();
147
+ selectedPreset = 'custom';
148
+ console.log('Custom rules saved');
149
+ } else {
150
+ // Default
151
+ selectedPreset = existingConfig?.rulesPreset || 'default';
152
+ selectedRules = existingConfig?.rules || '';
153
+ console.log(`Keeping: ${RULES_PRESETS[selectedPreset]?.name || 'Default'}`);
154
+ }
155
+
122
156
  // Save config
123
157
  const config: Config = {
124
158
  aiProvider: selectedProvider.name as any,
@@ -127,11 +161,12 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
127
161
  storagePath: rootDir,
128
162
  currentPath: rootDir,
129
163
  model: selectedProvider.model,
164
+ rules: selectedRules,
165
+ rulesPreset: selectedPreset,
130
166
  };
131
167
 
132
168
  saveConfig(config);
133
169
 
134
- // Ensure storage directory exists
135
170
  if (!fs.existsSync(rootDir)) {
136
171
  fs.mkdirSync(rootDir, { recursive: true });
137
172
  }
@@ -141,7 +176,8 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
141
176
  console.log('╚═══════════════════════════════════════╝\n');
142
177
  console.log(`Root directory: ${rootDir}`);
143
178
  console.log(`AI Provider: ${selectedProvider.name}`);
144
- console.log(`Model: ${selectedProvider.model}\n`);
179
+ console.log(`Model: ${selectedProvider.model}`);
180
+ console.log(`Theme: ${RULES_PRESETS[selectedPreset]?.name || 'Custom'}\n`);
145
181
  } finally {
146
182
  if (shouldCloseRl) {
147
183
  rl.close();
@@ -9,8 +9,42 @@ export interface Config {
9
9
  storagePath: string;
10
10
  currentPath: string;
11
11
  model?: string;
12
+ rules?: string;
13
+ rulesPreset?: string;
12
14
  }
13
15
 
16
+ // Preset rules for different themes
17
+ export const RULES_PRESETS: Record<string, { name: string; rules: string }> = {
18
+ default: {
19
+ name: 'Default (No theme)',
20
+ rules: '',
21
+ },
22
+ fantasy: {
23
+ name: 'Fantasy RPG',
24
+ rules: 'Use fantasy RPG language. Tasks are "quests", completing them is "slaying". Major milestones are "boss battles". Use terms like "adventurer", "dungeon", "loot", "guild". Add flavor text with swords, dragons, magic.',
25
+ },
26
+ space: {
27
+ name: 'Space Opera',
28
+ rules: 'Use sci-fi space language. Tasks are "missions", completing them is "mission accomplished". Major milestones are "final frontier". Use terms like "commander", "starship", "coordinates", "hyperdrive". Add flavor with stars, planets, aliens.',
29
+ },
30
+ starwars: {
31
+ name: 'Star Wars',
32
+ rules: 'Use Star Wars language. Tasks are "missions from the Rebel Alliance". Completing is "defeating the Empire". Milestones are "destroying the Death Star". Use "Jedi", "Force", "Padawan", "Master". May the Force be with you.',
33
+ },
34
+ western: {
35
+ name: 'Wild West',
36
+ rules: 'Use Wild West language. Tasks are "bounties", completing them is "collecting the reward". Milestones are "showdowns". Use terms like "sheriff", "outlaw", "saloon", "frontier", "partner". Add dusty trails and tumbleweeds.',
37
+ },
38
+ cyberpunk: {
39
+ name: 'Cyberpunk',
40
+ rules: 'Use cyberpunk language. Tasks are "gigs", completing them is "flatlined". Milestones are "megacorp takedowns". Use terms like "netrunner", "chrome", "corpo", "edgerunner", "eddies". Add neon and rain.',
41
+ },
42
+ pirate: {
43
+ name: 'Pirate',
44
+ rules: 'Use pirate language. Tasks are "plunder", completing them is "claiming the treasure". Milestones are "capturing the flagship". Use "captain", "crew", "booty", "seven seas", "landlubber". Arr matey!',
45
+ },
46
+ };
47
+
14
48
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
15
49
  const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
16
50
 
@@ -1107,44 +1107,77 @@ export async function processCommand(
1107
1107
  }
1108
1108
 
1109
1109
  if (command === 'config') {
1110
+ const { updateConfig, RULES_PRESETS } = await import('../config/config');
1111
+
1112
+ // Check for flags
1113
+ const keyFlag = parts.find(p => p.startsWith('-k=') || p.startsWith('--key='));
1114
+ const modelFlag = parts.find(p => p.startsWith('-m=') || p.startsWith('--model='));
1115
+ const rulesFlag = parts.find(p => p.startsWith('-r=') || p.startsWith('--rules='));
1116
+ const themeFlag = parts.find(p => p.startsWith('-t=') || p.startsWith('--theme='));
1117
+
1118
+ if (keyFlag) {
1119
+ const value = keyFlag.split('=').slice(1).join('=');
1120
+ updateConfig({ apiKey: value });
1121
+ return wrapResult({ output: 'API key updated.' });
1122
+ }
1123
+
1124
+ if (modelFlag) {
1125
+ const value = modelFlag.split('=').slice(1).join('=');
1126
+ updateConfig({ model: value });
1127
+ return wrapResult({ output: `Model updated: ${value}` });
1128
+ }
1129
+
1130
+ if (rulesFlag) {
1131
+ const value = rulesFlag.split('=').slice(1).join('=');
1132
+ updateConfig({ rules: value, rulesPreset: 'custom' });
1133
+ return wrapResult({ output: 'Custom rules updated.' });
1134
+ }
1135
+
1136
+ if (themeFlag) {
1137
+ const value = themeFlag.split('=').slice(1).join('=').toLowerCase();
1138
+ if (RULES_PRESETS[value]) {
1139
+ updateConfig({
1140
+ rules: RULES_PRESETS[value].rules,
1141
+ rulesPreset: value
1142
+ });
1143
+ return wrapResult({ output: `Theme updated: ${RULES_PRESETS[value].name}` });
1144
+ } else {
1145
+ const themes = Object.keys(RULES_PRESETS).join(', ');
1146
+ return wrapResult({ output: `Unknown theme. Available: ${themes}` });
1147
+ }
1148
+ }
1149
+
1150
+ // Show config
1110
1151
  const maskedKey = config.apiKey
1111
1152
  ? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
1112
1153
  : '(not set)';
1113
1154
 
1155
+ const themeName = config.rulesPreset
1156
+ ? (RULES_PRESETS[config.rulesPreset]?.name || 'Custom')
1157
+ : 'Default';
1158
+
1159
+ const rulesPreview = config.rules
1160
+ ? (config.rules.length > 50 ? config.rules.substring(0, 50) + '...' : config.rules)
1161
+ : '(none)';
1162
+
1114
1163
  const output = `
1115
1164
  Provider: ${config.aiProvider}
1116
1165
  Model: ${config.model || '(default)'}
1117
1166
  API Key: ${maskedKey}
1118
1167
  Storage: ${config.storagePath}
1168
+ Theme: ${themeName}
1169
+ Rules: ${rulesPreview}
1170
+
1171
+ Set with flags:
1172
+ config -k=<key> Set API key
1173
+ config -m=<model> Set model
1174
+ config -t=<theme> Set theme (fantasy, space, starwars, western, cyberpunk, pirate)
1175
+ config -r="<rules>" Set custom rules
1119
1176
  `.trim();
1120
1177
 
1121
1178
  return wrapResult({ output });
1122
1179
  }
1123
1180
 
1124
- if (command.startsWith('config:')) {
1125
- const configParts = input.split(':').slice(1).join(':').trim().split('=');
1126
- if (configParts.length !== 2) {
1127
- return { output: 'Usage: config:key=value' };
1128
- }
1129
-
1130
- const key = configParts[0].trim();
1131
- const value = configParts[1].trim();
1132
-
1133
- if (key === 'apiKey') {
1134
- const { updateConfig } = await import('../config/config');
1135
- updateConfig({ apiKey: value });
1136
- return { output: 'API key updated.' };
1137
- }
1138
-
1139
- if (key === 'storagePath') {
1140
- const { updateConfig } = await import('../config/config');
1141
- updateConfig({ storagePath: value, currentPath: value });
1142
- return { output: `Storage path updated to: ${value}` };
1143
- }
1144
-
1145
- return { output: `Unknown config key: ${key}` };
1146
- }
1147
-
1148
1181
  if (command === 'help') {
1149
1182
  return wrapResult({
1150
1183
  output: `
@@ -1152,9 +1185,7 @@ Storage: ${config.storagePath}
1152
1185
 
1153
1186
  Navigation:
1154
1187
  ls List tasks and files
1155
- tree Show task tree with status
1156
- tree -A Include files
1157
- tree --depth=N Limit tree depth
1188
+ tree [-A] [--depth=N] Show task tree
1158
1189
  cd <task> Navigate into task
1159
1190
  cd .., ... Go back 1 or 2 levels
1160
1191
  pwd Show current path
@@ -1162,49 +1193,43 @@ Navigation:
1162
1193
 
1163
1194
  Task Management:
1164
1195
  mkdir <name> Create new task
1165
- done Mark current task as completed (recursive)
1166
- undo Undo last done (restores XP)
1167
- deadline <date> Set deadline (today, tomorrow, +3d, Jan 15)
1168
- boss Toggle boss/milestone status (3x XP)
1169
- block [node] Block by task (or text reason)
1170
- unblock Remove blocked status
1171
- status Show current task details
1172
- check Show overdue/upcoming deadlines
1173
-
1174
- File Operations:
1175
- cp <src> <dest> Copy file or folder
1176
- mv <src> <dest> Move/rename
1177
- rm <name> Delete file
1178
- rm -rf <name> Delete folder
1196
+ done Complete task (earns XP)
1197
+ undo Undo last done
1198
+ deadline <date> Set deadline (today, +3d, Jan 15)
1199
+ boss Toggle boss status (3x XP)
1200
+ block [node] Block by task or text
1201
+ unblock Remove block
1202
+ status Task details
1203
+ check Upcoming deadlines
1179
1204
 
1180
1205
  Gamification:
1181
- stats Show XP, level, streaks
1182
- achievements Show achievement list
1183
- map Dungeon map view
1184
- map --ai AI-generated dungeon map
1206
+ stats XP, level, streaks
1207
+ achievements Achievement list
1208
+ map [--ai] Dungeon map view
1185
1209
 
1186
- Schema Generation:
1187
- <description> AI generates todo/schema preview
1188
- save Save pending schema
1189
- cancel Discard pending schema
1190
-
1191
- Utility:
1210
+ Configuration:
1192
1211
  init Setup wizard
1193
1212
  config Show settings
1213
+ config -k=<key> Set API key
1214
+ config -m=<model> Set model
1215
+ config -t=<theme> Set theme (fantasy, space, starwars, etc)
1216
+ config -r="<rules>" Custom AI rules
1217
+
1218
+ Themes:
1219
+ default, fantasy, space, starwars, western, cyberpunk, pirate
1220
+
1221
+ File Operations:
1222
+ cp, mv, rm [-rf] Standard file operations
1194
1223
  clean --yes Clear current folder
1195
- v, version Show version
1196
- help This help
1197
- exit, quit Exit
1198
1224
 
1199
- Clipboard:
1200
- <cmd> | pbcopy Copy output (macOS)
1201
- <cmd> | clip Copy output (Windows)
1225
+ AI Generation:
1226
+ <description> AI generates preview
1227
+ save Save to folders/file
1228
+ cancel Discard
1202
1229
 
1203
- Examples:
1204
- block backend-api Block current task by sibling task
1205
- block "waiting for design" Block with text reason
1206
- deadline +3d Due in 3 days
1207
- check See all upcoming deadlines
1230
+ Clipboard:
1231
+ <cmd> | pbcopy Copy to clipboard (macOS)
1232
+ <cmd> | clip Copy to clipboard (Windows)
1208
1233
 
1209
1234
  www.rlc.rocks
1210
1235
  `.trim()
@@ -17,16 +17,16 @@ const ASCII_ART = [
17
17
  '║ Roguelike CLI ║',
18
18
  '╚═════════════════════════╝',
19
19
  '',
20
- ' Navigation: ls, cd, tree, pwd, open',
21
20
  ' Tasks: done, undo, deadline, boss, block',
22
- ' Gamification: stats, achievements, map, check',
21
+ ' Stats: stats, achievements, map, check',
22
+ ' Config: init, config -t=<theme>',
23
23
  '',
24
- ' TAB to autocomplete, | pbcopy to copy',
25
- ' Workflow: <description> -> refine -> save',
24
+ ' Themes: fantasy, space, starwars, cyberpunk',
26
25
  '',
27
- ' help - all commands, init - setup',
26
+ ' TAB autocomplete, | pbcopy to copy',
27
+ ' <description> -> refine -> save',
28
28
  '',
29
- ' www.rlc.rocks',
29
+ ' help - commands, www.rlc.rocks',
30
30
  '',
31
31
  ' Ready...',
32
32
  '',