roguelike-cli 1.3.0 → 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,22 +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) |
159
+ | `done` | Complete task (earns XP) |
160
+ | `undo` | Undo last done |
98
161
  | `deadline <date>` | Set deadline |
99
- | `boss` | Toggle boss status (3x XP) |
100
- | `block [reason]` | Mark as blocked |
101
- | `unblock` | Remove blocked status |
102
- | `status` | Show task details |
162
+ | `boss` | Toggle boss (3x XP) |
163
+ | `block [node]` | Block by task |
164
+ | `unblock` | Remove block |
165
+ | `check` | Show deadlines |
103
166
 
104
167
  ### Gamification
105
168
 
@@ -107,77 +170,63 @@ You are now level 2!
107
170
  |---------|-------------|
108
171
  | `stats` | XP, level, streaks |
109
172
  | `achievements` | Achievement list |
110
- | `map` | Dungeon map view |
111
- | `map --ai` | AI-generated dungeon |
173
+ | `map` | Dungeon map |
174
+ | `map --ai` | AI-generated map |
112
175
 
113
176
  ### File Operations
114
177
 
115
178
  | Command | Description |
116
179
  |---------|-------------|
117
180
  | `mkdir <name>` | Create task |
118
- | `cp <src> <dst>` | Copy |
119
- | `mv <src> <dst>` | Move/rename |
120
- | `rm <name>` | Delete file |
121
- | `rm -rf <name>` | Delete folder |
181
+ | `cp`, `mv`, `rm` | Standard ops |
122
182
 
123
- ### AI Generation
183
+ ### Configuration
124
184
 
125
185
  | Command | Description |
126
186
  |---------|-------------|
127
- | `<description>` | AI generates preview |
128
- | `save` | Save pending schema |
129
- | `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 |
130
193
 
131
194
  ## Deadlines
132
195
 
133
196
  ```
134
197
  > deadline today # Due today
135
198
  > deadline tomorrow # Due tomorrow
136
- > deadline +3d # Due in 3 days
137
- > deadline Jan 15 # Due on date
199
+ > deadline +3d # In 3 days
200
+ > deadline Jan 15 # Specific date
138
201
  ```
139
202
 
140
203
  Tree shows deadlines:
141
-
142
204
  ```
143
- ├── Backend API/ [BOSS] [3d left]
205
+ ├── Backend/ [BOSS] [3d left]
144
206
  │ ├── Database/ [DONE]
145
- │ └── Endpoints/ [OVERDUE 2d]
207
+ │ └── API/ [OVERDUE 2d]
146
208
  └── Frontend/ [tomorrow]
147
209
  ```
148
210
 
149
211
  ## XP System
150
212
 
151
- - Base XP: 10 per task
152
- - Depth bonus: +5 XP per nesting level
153
- - Boss multiplier: 3x XP
154
-
155
- | Level | XP Required |
156
- |-------|-------------|
157
- | 1 | 0 |
158
- | 2 | 100 |
159
- | 3 | 150 |
160
- | 5 | 337 |
161
- | 10 | 3,844 |
213
+ | Factor | XP |
214
+ |--------|-----|
215
+ | Base task | 10 |
216
+ | Per depth level | +5 |
217
+ | Boss multiplier | 3x |
162
218
 
163
219
  ## Achievements
164
220
 
165
- | Achievement | Description |
166
- |-------------|-------------|
221
+ | Achievement | How to unlock |
222
+ |-------------|---------------|
167
223
  | First Blood | Complete first task |
168
224
  | Getting Started | Complete 10 tasks |
169
- | Productive | Complete 50 tasks |
170
225
  | Centurion | Complete 100 tasks |
171
- | Deep Diver | Complete task at depth 5+ |
172
- | Boss Slayer | Complete a boss task |
173
- | Boss Hunter | Defeat 5 bosses |
174
- | Speedrunner | Complete task same day |
175
- | On a Roll | 3 day streak |
226
+ | Deep Diver | Task at depth 5+ |
227
+ | Boss Slayer | Complete a boss |
228
+ | Speedrunner | Same-day completion |
176
229
  | Streak Master | 7 day streak |
177
- | Unstoppable | 30 day streak |
178
- | Adventurer | Reach level 5 |
179
- | Veteran | Reach level 10 |
180
- | Legend | Reach level 25 |
181
230
 
182
231
  ## Dungeon Map
183
232
 
@@ -185,42 +234,12 @@ Tree shows deadlines:
185
234
  > map
186
235
 
187
236
  ###########################################
188
- # # #
189
- # [Research] # [Development] #
190
- # * Market +---* Backend #
191
- # x Users # @ Deploy BOSS #
192
- # # #
193
- ##########+############+##################
194
- | |
195
- ##########+############+##################
196
- # #
197
- # [Launch] #
198
- # * Marketing #
199
- # @ SHIP IT! [BOSS] #
200
- # #
201
- ###########################################
202
-
203
- Legend: * Task x Done @ Boss ! Blocked + Door
204
- ```
205
-
206
- Use `map --ai` for creative AI-generated layouts.
207
-
208
- ## Block Diagrams
209
-
210
- ```
211
- > schema kubernetes cluster
212
-
213
- ┌─────────────────────────────────────────────────────────────┐
214
- │ Kubernetes Cluster │
215
- │ │
216
- │ ┌──────────────────┐ ┌──────────────────┐ │
217
- │ │ Control Plane │ │ Worker Nodes │ │
218
- │ └────────┬─────────┘ └────────┬─────────┘ │
219
- │ └──────────┬───────────────┘ │
220
- │ ┌──────────────────┐│┌──────────────────┐ │
221
- │ │ PostgreSQL │││ Redis │ │
222
- │ └──────────────────┘│└──────────────────┘ │
223
- └─────────────────────────────────────────────────────────────┘
237
+ # # #
238
+ # [Research] # [Development] #
239
+ # x Analysis +---* Backend #
240
+ # x Interviews # @ Deploy BOSS #
241
+ # # #
242
+ ##########+###########+###################
224
243
  ```
225
244
 
226
245
  ## Clipboard
@@ -228,15 +247,6 @@ Use `map --ai` for creative AI-generated layouts.
228
247
  ```
229
248
  > tree | pbcopy # macOS
230
249
  > tree | clip # Windows
231
- > ls | copy # Alternative
232
- ```
233
-
234
- ## Configuration
235
-
236
- ```
237
- > init # Setup wizard
238
- > config # Show settings
239
- > config:apiKey=sk-... # Set API key
240
250
  ```
241
251
 
242
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() {