roguelike-cli 1.3.1 → 1.3.3

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,14 @@
17
17
  ╚═════════════════════════╝
18
18
  ```
19
19
 
20
- ## What is this?
21
-
22
- **A gamified task manager where every task is a folder and every project is a dungeon.**
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.
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.
25
21
 
26
22
  ## Features
27
23
 
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
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
+ - **Customizable Rules** Choose adventure style: Fantasy, Space Opera, Star Wars, Cyberpunk, and more.
35
28
 
36
29
  ## Install
37
30
 
@@ -43,36 +36,101 @@ rlc
43
36
  ## Quick Start
44
37
 
45
38
  ```
46
- > todo launch startup
39
+ > todo launch my startup
47
40
 
48
41
  ├── Research [BOSS]
49
42
  │ ├── Market analysis
50
- │ └── User interviews
43
+ │ └── User interviews [DUE: +7d]
51
44
  ├── Development
52
- │ ├── Backend API [DUE: +7d]
45
+ │ ├── Backend API [DUE: Jan 20]
53
46
  │ └── Frontend UI
54
47
  └── Launch [MILESTONE]
55
- └── Marketing campaign
56
48
 
57
- [Type "save" to create folder launch-startup/]
49
+ [Type "save" to create folders]
58
50
  > save
59
- Created todo folder: launch-startup/
51
+ Created: launch-my-startup/
60
52
 
61
- > cd launch-startup/research
53
+ > cd launch-my-startup/research
62
54
  > done
63
55
 
64
- === TASK COMPLETED ===
56
+ === QUEST COMPLETED ===
65
57
 
66
- Tasks completed: 3
67
- Bosses defeated: 1
68
58
  +45 XP
69
-
70
59
  *** LEVEL UP! ***
71
- You are now level 2!
72
60
 
73
61
  === NEW ACHIEVEMENTS ===
74
- [x] First Blood: Complete your first task
75
- [x] Boss Slayer: Complete a boss task
62
+ [x] First Blood: Complete your first quest
63
+ [x] Boss Slayer: Defeat a boss
64
+ ```
65
+
66
+ ## Folder Structure
67
+
68
+ Every task is a folder. You can drop files directly into task folders — designs, docs, code, anything. Your file manager becomes your task manager.
69
+
70
+ ```
71
+ my-startup/
72
+ ├── research/
73
+ │ ├── market-analysis/
74
+ │ │ └── competitors.xlsx <- attached file
75
+ │ └── user-interviews/
76
+ │ └── notes.md <- attached file
77
+ ├── development/
78
+ │ ├── backend-api/
79
+ │ │ └── spec.yaml <- attached file
80
+ │ └── frontend-ui/
81
+ └── launch/
82
+ └── marketing/
83
+ ```
84
+
85
+ Navigate with `cd`, view with `tree`, open in Finder with `open`. It's just folders.
86
+
87
+ ## Rules
88
+
89
+ Rules change how the AI speaks. Set during `init` or with `config -R="<rules>"`.
90
+
91
+ | Preset | Style |
92
+ |--------|-------|
93
+ | `default` | Standard task manager language |
94
+ | `fantasy` | Quests, dungeons, dragons, loot |
95
+ | `space` | Missions, starships, commanders |
96
+ | `starwars` | Jedi, Force, Rebel Alliance |
97
+ | `western` | Bounties, sheriffs, frontier |
98
+ | `cyberpunk` | Gigs, netrunners, corps |
99
+ | `pirate` | Plunder, treasure, seven seas |
100
+
101
+ ### Custom Rules
102
+
103
+ ```
104
+ > config -R="Speak like a medieval knight. Tasks are 'duties'. Use 'huzzah' for success."
105
+ ```
106
+
107
+ Or select "Custom" during `init` to enter your own rules.
108
+
109
+ ## Dungeon Map
110
+
111
+ ```
112
+ > map
113
+
114
+ #########################################
115
+ # # #
116
+ # [Research] # [Development] #
117
+ # x Analysis +---* Backend #
118
+ # x Interviews # * Frontend #
119
+ # # #
120
+ ##########+###########+#################
121
+ | |
122
+ ##########+###########+#################
123
+ # #
124
+ # [Launch] #
125
+ # * Marketing #
126
+ # @ SHIP IT! [BOSS] #
127
+ # #
128
+ #########################################
129
+
130
+ Legend: * Task x Done @ Boss + Door
131
+
132
+ > map --ai
133
+ (AI generates creative dungeon layout based on your tasks)
76
134
  ```
77
135
 
78
136
  ## Commands
@@ -84,24 +142,21 @@ You are now level 2!
84
142
  | `ls` | List tasks (shows status) |
85
143
  | `tree` | Task tree with deadlines |
86
144
  | `tree -A` | Include files |
87
- | `tree --depth=N` | Limit depth |
88
145
  | `cd <task>` | Enter task |
89
- | `..`, `...` | Go up 1 or 2 levels |
90
- | `pwd` | Current path |
146
+ | `..`, `...` | Go up levels |
91
147
  | `open` | Open in Finder |
92
148
 
93
149
  ### Task Management
94
150
 
95
151
  | Command | Description |
96
152
  |---------|-------------|
97
- | `done` | Complete task (recursive, earns XP) |
98
- | `undo` | Undo last done (restores XP) |
99
- | `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 |
153
+ | `done` | Complete task (earns XP) |
154
+ | `undo` | Undo last done |
155
+ | `dl <date>` | Set deadline (dl +3d, dl Jan 15) |
156
+ | `boss` | Toggle boss (3x XP) |
157
+ | `block [node]` | Block by task |
158
+ | `unblock` | Remove block |
159
+ | `check` | Show deadlines |
105
160
 
106
161
  ### Gamification
107
162
 
@@ -109,136 +164,80 @@ You are now level 2!
109
164
  |---------|-------------|
110
165
  | `stats` | XP, level, streaks |
111
166
  | `achievements` | Achievement list |
112
- | `map` | Dungeon map view |
113
- | `map --ai` | AI-generated dungeon |
167
+ | `map` | Dungeon map |
168
+ | `map --ai` | AI-generated map |
114
169
 
115
170
  ### File Operations
116
171
 
117
172
  | Command | Description |
118
173
  |---------|-------------|
119
174
  | `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 |
175
+ | `cp`, `mv`, `rm` | Standard ops |
124
176
 
125
- ### AI Generation
177
+ ### Configuration
126
178
 
127
179
  | Command | Description |
128
180
  |---------|-------------|
129
- | `<description>` | AI generates preview |
130
- | `save` | Save pending schema |
131
- | `cancel` | Discard |
181
+ | `init` | Setup wizard |
182
+ | `config` | View settings |
183
+ | `config -K=<key>` | or `--key=<key>` |
184
+ | `config -M=<model>` | or `--model=<model>` |
185
+ | `config -R="<rules>"` | or `--rules="<rules>"` |
186
+
187
+ ### Clipboard
188
+
189
+ | Command | Description |
190
+ |---------|-------------|
191
+ | `<cmd> \| pbcopy` | Copy to clipboard (macOS) |
192
+ | `<cmd> \| clip` | Copy to clipboard (Windows) |
132
193
 
133
194
  ## Deadlines
134
195
 
135
196
  ```
136
- > deadline today # Due today
137
- > deadline tomorrow # Due tomorrow
138
- > deadline +3d # Due in 3 days
139
- > deadline Jan 15 # Due on date
197
+ > dl today # Due today
198
+ > dl tomorrow # Due tomorrow
199
+ > dl +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
-
184
- ## Dungeon Map
185
-
186
- ```
187
- > map
188
-
189
- ###########################################
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
- └─────────────────────────────────────────────────────────────┘
226
- ```
227
-
228
- ## Clipboard
229
-
230
- ```
231
- > tree | pbcopy # macOS
232
- > tree | clip # Windows
233
- > ls | copy # Alternative
234
- ```
235
230
 
236
- ## Configuration
231
+ ## Supported Models
237
232
 
238
233
  ```
239
- > init # Setup wizard
240
- > config # Show settings
241
- > config:apiKey=sk-... # Set API key
234
+ claude-sonnet-4-20250514 (default)
235
+ claude-opus-4-20250514
236
+ gpt-4o
237
+ gpt-4-turbo
238
+ gemini-3-pro
239
+ gemini-2.0-flash
240
+ grok-beta
242
241
  ```
243
242
 
244
243
  ## 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. Rules preset selection
140
+ console.log('\nSelect AI Rules (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(`Rules: ${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 = exports.SUPPORTED_MODELS = void 0;
36
37
  exports.initConfig = initConfig;
37
38
  exports.saveConfig = saveConfig;
38
39
  exports.getConfig = getConfig;
@@ -40,6 +41,47 @@ 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
+ // Supported models for validation
45
+ exports.SUPPORTED_MODELS = [
46
+ 'claude-sonnet-4-20250514',
47
+ 'claude-opus-4-20250514',
48
+ 'gpt-4o',
49
+ 'gpt-4-turbo',
50
+ 'gemini-3-pro',
51
+ 'gemini-2.0-flash',
52
+ 'grok-beta',
53
+ ];
54
+ // Preset rules
55
+ exports.RULES_PRESETS = {
56
+ default: {
57
+ name: 'Default (No theme)',
58
+ rules: '',
59
+ },
60
+ fantasy: {
61
+ name: 'Fantasy RPG',
62
+ 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.',
63
+ },
64
+ space: {
65
+ name: 'Space Opera',
66
+ 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.',
67
+ },
68
+ starwars: {
69
+ name: 'Star Wars',
70
+ 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.',
71
+ },
72
+ western: {
73
+ name: 'Wild West',
74
+ 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.',
75
+ },
76
+ cyberpunk: {
77
+ name: 'Cyberpunk',
78
+ 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.',
79
+ },
80
+ pirate: {
81
+ name: 'Pirate',
82
+ 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!',
83
+ },
84
+ };
43
85
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
44
86
  const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
45
87
  async function initConfig() {
@@ -478,10 +478,10 @@ async function processCommand(input, currentPath, config, signal, rl) {
478
478
  output += '\n';
479
479
  return wrapResult({ output });
480
480
  }
481
- // Deadline command
482
- if (command === 'deadline') {
481
+ // Deadline command (dl as alias)
482
+ if (command === 'deadline' || command === 'dl') {
483
483
  if (parts.length < 2) {
484
- return wrapResult({ output: 'Usage: deadline <date>\nExamples: deadline today, deadline tomorrow, deadline +3d, deadline Jan 15' });
484
+ return wrapResult({ output: 'Usage: deadline <date> (or dl <date>)\nExamples: dl today, dl +3d, deadline Jan 15' });
485
485
  }
486
486
  const dateStr = parts.slice(1).join(' ');
487
487
  const deadline = parseDeadline(dateStr);
@@ -931,36 +931,55 @@ async function processCommand(input, currentPath, config, signal, rl) {
931
931
  return wrapResult({ output: currentPath });
932
932
  }
933
933
  if (command === 'config') {
934
+ const { updateConfig, SUPPORTED_MODELS } = await Promise.resolve().then(() => __importStar(require('../config/config')));
935
+ // Check for flags (uppercase short, lowercase long)
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
+ if (keyFlag) {
940
+ const value = keyFlag.split('=').slice(1).join('=');
941
+ if (!value) {
942
+ return wrapResult({ output: 'Error: API key cannot be empty' });
943
+ }
944
+ updateConfig({ apiKey: value });
945
+ return wrapResult({ output: 'API key updated.' });
946
+ }
947
+ if (modelFlag) {
948
+ const value = modelFlag.split('=').slice(1).join('=');
949
+ if (!SUPPORTED_MODELS.includes(value)) {
950
+ return wrapResult({
951
+ output: `Error: Unknown model "${value}"\n\nSupported models:\n ${SUPPORTED_MODELS.join('\n ')}`
952
+ });
953
+ }
954
+ updateConfig({ model: value });
955
+ return wrapResult({ output: `Model updated: ${value}` });
956
+ }
957
+ if (rulesFlag) {
958
+ const value = rulesFlag.split('=').slice(1).join('=');
959
+ updateConfig({ rules: value, rulesPreset: 'custom' });
960
+ return wrapResult({ output: 'Rules updated.' });
961
+ }
962
+ // Show config
934
963
  const maskedKey = config.apiKey
935
964
  ? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
936
965
  : '(not set)';
966
+ const rulesPreview = config.rules
967
+ ? (config.rules.length > 60 ? config.rules.substring(0, 60) + '...' : config.rules)
968
+ : '(default)';
937
969
  const output = `
938
970
  Provider: ${config.aiProvider}
939
971
  Model: ${config.model || '(default)'}
940
972
  API Key: ${maskedKey}
941
973
  Storage: ${config.storagePath}
974
+ Rules: ${rulesPreview}
975
+
976
+ Set with flags:
977
+ config -K=<key> or --key=<key>
978
+ config -M=<model> or --model=<model>
979
+ config -R="<rules>" or --rules="<rules>"
942
980
  `.trim();
943
981
  return wrapResult({ output });
944
982
  }
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
983
  if (command === 'help') {
965
984
  return wrapResult({
966
985
  output: `
@@ -968,59 +987,52 @@ Storage: ${config.storagePath}
968
987
 
969
988
  Navigation:
970
989
  ls List tasks and files
971
- tree Show task tree with status
972
- tree -A Include files
973
- tree --depth=N Limit tree depth
990
+ tree [-A] [--depth=N] Show task tree
974
991
  cd <task> Navigate into task
975
- cd .., ... Go back 1 or 2 levels
976
- pwd Show current path
977
- open Open folder in Finder
978
-
979
- Task Management:
980
- 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
992
+ .., ... Go up 1 or 2 levels
993
+ pwd Current path
994
+ open Open in Finder
989
995
 
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
996
+ Tasks:
997
+ mkdir <name> Create task
998
+ done Complete (earns XP)
999
+ undo Undo last done
1000
+ dl <date> Set deadline (dl +3d, dl Jan 15)
1001
+ boss Toggle boss (3x XP)
1002
+ block [node] Block by task
1003
+ unblock Remove block
1004
+ status Task details
1005
+ check Deadline alerts
995
1006
 
996
1007
  Gamification:
997
- stats Show XP, level, streaks
998
- achievements Show achievement list
999
- map Dungeon map view
1000
- map --ai AI-generated dungeon map
1008
+ stats XP, level, streaks
1009
+ achievements Achievement list
1010
+ map Dungeon map
1011
+ map --ai AI-generated map
1001
1012
 
1002
- Schema Generation:
1003
- <description> AI generates todo/schema preview
1004
- save Save pending schema
1005
- cancel Discard pending schema
1013
+ Rules (AI style presets):
1014
+ Set via init or config -R="<rules>"
1015
+ Presets: fantasy, space, starwars, western, cyberpunk, pirate
1006
1016
 
1007
- Utility:
1017
+ Config:
1008
1018
  init Setup wizard
1009
1019
  config Show settings
1010
- clean --yes Clear current folder
1011
- v, version Show version
1012
- help This help
1013
- exit, quit Exit
1020
+ config -K=<key> or --key=<key>
1021
+ config -M=<model> or --model=<model>
1022
+ config -R="<rules>" or --rules="<rules>"
1014
1023
 
1015
- Clipboard:
1016
- <cmd> | pbcopy Copy output (macOS)
1017
- <cmd> | clip Copy output (Windows)
1024
+ Files:
1025
+ cp, mv, rm [-rf] Standard operations
1026
+ clean --yes Clear folder
1027
+
1028
+ AI:
1029
+ <description> Generate preview
1030
+ save Save to folders
1031
+ cancel Discard
1018
1032
 
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
1033
+ Clipboard:
1034
+ <cmd> | pbcopy macOS
1035
+ <cmd> | clip Windows
1024
1036
 
1025
1037
  www.rlc.rocks
1026
1038
  `.trim()
@@ -19,15 +19,16 @@ const ASCII_ART = [
19
19
  '║ Roguelike CLI ║',
20
20
  '╚═════════════════════════╝',
21
21
  '',
22
- ' Navigation: ls, cd, tree, pwd, open',
23
- ' Tasks: done, undo, deadline, boss, block',
24
- ' Gamification: stats, achievements, map, check',
22
+ ' Tasks: done, undo, dl <date>, boss, block',
23
+ ' Stats: stats, achievements, map --ai',
25
24
  '',
26
- ' TAB to autocomplete, | pbcopy to copy',
27
- ' Workflow: <description> -> refine -> save',
25
+ ' Rules: fantasy, space, starwars, cyberpunk',
26
+ ' Config: init, config -R="<rules>"',
28
27
  '',
29
- ' help - all commands, init - setup',
28
+ ' TAB autocomplete, | pbcopy to copy',
29
+ ' <description> -> refine -> save',
30
30
  '',
31
+ ' help - commands',
31
32
  ' www.rlc.rocks',
32
33
  '',
33
34
  ' Ready...',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roguelike-cli",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
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. Rules preset selection
121
+ console.log('\nSelect AI Rules (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(`Rules: ${RULES_PRESETS[selectedPreset]?.name || 'Custom'}\n`);
145
181
  } finally {
146
182
  if (shouldCloseRl) {
147
183
  rl.close();
@@ -9,8 +9,53 @@ 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
+ // Supported models for validation
17
+ export const SUPPORTED_MODELS = [
18
+ 'claude-sonnet-4-20250514',
19
+ 'claude-opus-4-20250514',
20
+ 'gpt-4o',
21
+ 'gpt-4-turbo',
22
+ 'gemini-3-pro',
23
+ 'gemini-2.0-flash',
24
+ 'grok-beta',
25
+ ];
26
+
27
+ // Preset rules
28
+ export const RULES_PRESETS: Record<string, { name: string; rules: string }> = {
29
+ default: {
30
+ name: 'Default (No theme)',
31
+ rules: '',
32
+ },
33
+ fantasy: {
34
+ name: 'Fantasy RPG',
35
+ 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.',
36
+ },
37
+ space: {
38
+ name: 'Space Opera',
39
+ 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.',
40
+ },
41
+ starwars: {
42
+ name: 'Star Wars',
43
+ 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.',
44
+ },
45
+ western: {
46
+ name: 'Wild West',
47
+ 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.',
48
+ },
49
+ cyberpunk: {
50
+ name: 'Cyberpunk',
51
+ 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.',
52
+ },
53
+ pirate: {
54
+ name: 'Pirate',
55
+ 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!',
56
+ },
57
+ };
58
+
14
59
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
15
60
  const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
16
61
 
@@ -566,10 +566,10 @@ export async function processCommand(
566
566
  return wrapResult({ output });
567
567
  }
568
568
 
569
- // Deadline command
570
- if (command === 'deadline') {
569
+ // Deadline command (dl as alias)
570
+ if (command === 'deadline' || command === 'dl') {
571
571
  if (parts.length < 2) {
572
- return wrapResult({ output: 'Usage: deadline <date>\nExamples: deadline today, deadline tomorrow, deadline +3d, deadline Jan 15' });
572
+ return wrapResult({ output: 'Usage: deadline <date> (or dl <date>)\nExamples: dl today, dl +3d, deadline Jan 15' });
573
573
  }
574
574
 
575
575
  const dateStr = parts.slice(1).join(' ');
@@ -1107,44 +1107,64 @@ export async function processCommand(
1107
1107
  }
1108
1108
 
1109
1109
  if (command === 'config') {
1110
+ const { updateConfig, SUPPORTED_MODELS } = await import('../config/config');
1111
+
1112
+ // Check for flags (uppercase short, lowercase long)
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
+
1117
+ if (keyFlag) {
1118
+ const value = keyFlag.split('=').slice(1).join('=');
1119
+ if (!value) {
1120
+ return wrapResult({ output: 'Error: API key cannot be empty' });
1121
+ }
1122
+ updateConfig({ apiKey: value });
1123
+ return wrapResult({ output: 'API key updated.' });
1124
+ }
1125
+
1126
+ if (modelFlag) {
1127
+ const value = modelFlag.split('=').slice(1).join('=');
1128
+ if (!SUPPORTED_MODELS.includes(value)) {
1129
+ return wrapResult({
1130
+ output: `Error: Unknown model "${value}"\n\nSupported models:\n ${SUPPORTED_MODELS.join('\n ')}`
1131
+ });
1132
+ }
1133
+ updateConfig({ model: value });
1134
+ return wrapResult({ output: `Model updated: ${value}` });
1135
+ }
1136
+
1137
+ if (rulesFlag) {
1138
+ const value = rulesFlag.split('=').slice(1).join('=');
1139
+ updateConfig({ rules: value, rulesPreset: 'custom' });
1140
+ return wrapResult({ output: 'Rules updated.' });
1141
+ }
1142
+
1143
+ // Show config
1110
1144
  const maskedKey = config.apiKey
1111
1145
  ? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
1112
1146
  : '(not set)';
1113
1147
 
1148
+ const rulesPreview = config.rules
1149
+ ? (config.rules.length > 60 ? config.rules.substring(0, 60) + '...' : config.rules)
1150
+ : '(default)';
1151
+
1114
1152
  const output = `
1115
1153
  Provider: ${config.aiProvider}
1116
1154
  Model: ${config.model || '(default)'}
1117
1155
  API Key: ${maskedKey}
1118
1156
  Storage: ${config.storagePath}
1157
+ Rules: ${rulesPreview}
1158
+
1159
+ Set with flags:
1160
+ config -K=<key> or --key=<key>
1161
+ config -M=<model> or --model=<model>
1162
+ config -R="<rules>" or --rules="<rules>"
1119
1163
  `.trim();
1120
1164
 
1121
1165
  return wrapResult({ output });
1122
1166
  }
1123
1167
 
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
1168
  if (command === 'help') {
1149
1169
  return wrapResult({
1150
1170
  output: `
@@ -1152,59 +1172,52 @@ Storage: ${config.storagePath}
1152
1172
 
1153
1173
  Navigation:
1154
1174
  ls List tasks and files
1155
- tree Show task tree with status
1156
- tree -A Include files
1157
- tree --depth=N Limit tree depth
1175
+ tree [-A] [--depth=N] Show task tree
1158
1176
  cd <task> Navigate into task
1159
- cd .., ... Go back 1 or 2 levels
1160
- pwd Show current path
1161
- open Open folder in Finder
1162
-
1163
- Task Management:
1164
- 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
1177
+ .., ... Go up 1 or 2 levels
1178
+ pwd Current path
1179
+ open Open in Finder
1173
1180
 
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
1181
+ Tasks:
1182
+ mkdir <name> Create task
1183
+ done Complete (earns XP)
1184
+ undo Undo last done
1185
+ dl <date> Set deadline (dl +3d, dl Jan 15)
1186
+ boss Toggle boss (3x XP)
1187
+ block [node] Block by task
1188
+ unblock Remove block
1189
+ status Task details
1190
+ check Deadline alerts
1179
1191
 
1180
1192
  Gamification:
1181
- stats Show XP, level, streaks
1182
- achievements Show achievement list
1183
- map Dungeon map view
1184
- map --ai AI-generated dungeon map
1193
+ stats XP, level, streaks
1194
+ achievements Achievement list
1195
+ map Dungeon map
1196
+ map --ai AI-generated map
1185
1197
 
1186
- Schema Generation:
1187
- <description> AI generates todo/schema preview
1188
- save Save pending schema
1189
- cancel Discard pending schema
1198
+ Rules (AI style presets):
1199
+ Set via init or config -R="<rules>"
1200
+ Presets: fantasy, space, starwars, western, cyberpunk, pirate
1190
1201
 
1191
- Utility:
1202
+ Config:
1192
1203
  init Setup wizard
1193
1204
  config Show settings
1194
- clean --yes Clear current folder
1195
- v, version Show version
1196
- help This help
1197
- exit, quit Exit
1205
+ config -K=<key> or --key=<key>
1206
+ config -M=<model> or --model=<model>
1207
+ config -R="<rules>" or --rules="<rules>"
1198
1208
 
1199
- Clipboard:
1200
- <cmd> | pbcopy Copy output (macOS)
1201
- <cmd> | clip Copy output (Windows)
1209
+ Files:
1210
+ cp, mv, rm [-rf] Standard operations
1211
+ clean --yes Clear folder
1212
+
1213
+ AI:
1214
+ <description> Generate preview
1215
+ save Save to folders
1216
+ cancel Discard
1202
1217
 
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
1218
+ Clipboard:
1219
+ <cmd> | pbcopy macOS
1220
+ <cmd> | clip Windows
1208
1221
 
1209
1222
  www.rlc.rocks
1210
1223
  `.trim()
@@ -17,15 +17,16 @@ const ASCII_ART = [
17
17
  '║ Roguelike CLI ║',
18
18
  '╚═════════════════════════╝',
19
19
  '',
20
- ' Navigation: ls, cd, tree, pwd, open',
21
- ' Tasks: done, undo, deadline, boss, block',
22
- ' Gamification: stats, achievements, map, check',
20
+ ' Tasks: done, undo, dl <date>, boss, block',
21
+ ' Stats: stats, achievements, map --ai',
23
22
  '',
24
- ' TAB to autocomplete, | pbcopy to copy',
25
- ' Workflow: <description> -> refine -> save',
23
+ ' Rules: fantasy, space, starwars, cyberpunk',
24
+ ' Config: init, config -R="<rules>"',
26
25
  '',
27
- ' help - all commands, init - setup',
26
+ ' TAB autocomplete, | pbcopy to copy',
27
+ ' <description> -> refine -> save',
28
28
  '',
29
+ ' help - commands',
29
30
  ' www.rlc.rocks',
30
31
  '',
31
32
  ' Ready...',