roguelike-cli 1.2.1 → 1.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Creative Ventures
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -26,7 +26,7 @@ Instead of flat text files, your tasks become a **file system tree**. Nested tas
26
26
  - **Navigate** your todos like directories (`cd`, `ls`, `tree`)
27
27
  - **Attach files** directly to tasks (just put them in the folder)
28
28
  - **Track dependencies** and blockers between tasks
29
- - **Generate beautiful visualizations** — trees, block diagrams, and even **dungeon maps**
29
+ - **Generate beautiful visualizations** — trees, block diagrams, and dungeon maps
30
30
  - Let **AI help** you structure complex projects
31
31
 
32
32
  ## Why folders?
@@ -35,7 +35,7 @@ Instead of flat text files, your tasks become a **file system tree**. Nested tas
35
35
  project/
36
36
  ├── phase-1-research/
37
37
  │ ├── market-analysis/
38
- │ │ └── competitors.xlsx attach files directly!
38
+ │ │ └── competitors.xlsx <- attach files directly
39
39
  │ └── user-interviews/
40
40
  ├── phase-2-development/
41
41
  │ ├── backend-api/
@@ -136,9 +136,9 @@ Now you can `cd development/backend-api` and drop your actual code files there!
136
136
  └─────────────────────────────────────────────────────────────┘
137
137
  ```
138
138
 
139
- ### Dungeon Map View (roguelike style) 🎮
139
+ ### Dungeon Map View
140
140
 
141
- Visualize your project as a dungeon map! Each room is a task, corridors show dependencies.
141
+ Visualize your project as a dungeon map. Each room is a task, corridors show dependencies.
142
142
 
143
143
  ```
144
144
  > map
@@ -146,32 +146,30 @@ Visualize your project as a dungeon map! Each room is a task, corridors show dep
146
146
  ████████████████████████████████████████
147
147
  █ █ █
148
148
  █ [Research] █ [Development] █
149
- Market █ Backend █
150
- Users ──────+───♦ Frontend █
151
- █ █ Database █
149
+ * Market █ * Backend █
150
+ * Users ──────+───* Frontend █
151
+ █ █ * Database █
152
152
  █████████+███████████████████+██████████
153
153
  │ │
154
154
  █████████+███████████████████+██████████
155
155
  █ █ █
156
156
  █ [Launch] █ [Growth] █
157
- Marketing █ Metrics █
158
- Press ──────+───♦ Feedback █
159
- BOSS: Ship it! █ █
157
+ * Marketing █ * Metrics █
158
+ * Press ──────+───* Feedback █
159
+ @ BOSS: Ship it! █ █
160
160
  █ █ █
161
161
  ████████████████████████████████████████
162
162
 
163
- Legend: Task Milestone + Door/Dependency █ Wall
163
+ Legend: * Task @ Milestone + Door █ Wall
164
164
  ```
165
165
 
166
- *Coming soon: Interactive dungeon exploration, XP for completed tasks, achievements!*
167
-
168
166
  ## Gamification (Roadmap)
169
167
 
170
- - 🎯 **XP System** — Earn experience for completing tasks
171
- - 🏆 **Achievements** — "First Blood", "100 Tasks", "Deep Nesting"
172
- - 🗡️ **Boss Tasks** — Major milestones as boss fights
173
- - 🗺️ **Dungeon Maps** — Explore your project as a roguelike dungeon
174
- - 📊 **Stats** — Track velocity, streaks, completion rates
168
+ - **XP System** — Earn experience for completing tasks
169
+ - **Achievements** — "First Blood", "100 Tasks", "Deep Nesting"
170
+ - **Boss Tasks** — Major milestones as boss fights
171
+ - **Dungeon Maps** — Explore your project as a roguelike dungeon
172
+ - **Stats** — Track velocity, streaks, completion rates
175
173
 
176
174
  ## Commands
177
175
 
@@ -180,6 +178,7 @@ Legend: ♦ Task ♣ Milestone + Door/Dependency █ Wall
180
178
  | `ls` | List tasks and files |
181
179
  | `tree` | Show task tree |
182
180
  | `tree -A` | Include files |
181
+ | `map` | Dungeon map view |
183
182
  | `cd <task>` | Enter task |
184
183
  | `..` | Go back |
185
184
  | `mkdir <name>` | Create task |
@@ -187,6 +186,7 @@ Legend: ♦ Task ♣ Milestone + Door/Dependency █ Wall
187
186
  | `cp`, `mv`, `rm` | File operations |
188
187
  | `config` | Settings |
189
188
  | `help` | Examples |
189
+ | `v`, `version` | Show version |
190
190
 
191
191
  ## AI Integration
192
192
 
@@ -297,12 +297,6 @@ AI understands context and refines until you're happy.
297
297
 
298
298
  **https://www.rlc.rocks**
299
299
 
300
- ## Inspired by
301
-
302
- - [roguelike](https://www.npmjs.com/package/roguelike) — 2D dungeon map generator
303
- - Unix philosophy — everything is a file
304
- - GTD methodology — capture, organize, do
305
-
306
300
  ## License
307
301
 
308
302
  MIT
@@ -91,7 +91,7 @@ async function initCommand() {
91
91
  const existingConfig = await (0, config_1.initConfig)();
92
92
  const oldStoragePath = existingConfig?.storagePath;
93
93
  // 1. Root directory
94
- const defaultRoot = path.join(os.homedir(), '.rlc', 'notes');
94
+ const defaultRoot = path.join(os.homedir(), '.rlc', 'workspace');
95
95
  const rootDirAnswer = await question(`Root directory for notes [${defaultRoot}]: `);
96
96
  const rootDir = rootDirAnswer.trim() || defaultRoot;
97
97
  // Check if we need to migrate data
@@ -41,7 +41,7 @@ const fs = __importStar(require("fs"));
41
41
  const path = __importStar(require("path"));
42
42
  const os = __importStar(require("os"));
43
43
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
44
- const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'notes');
44
+ const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
45
45
  async function initConfig() {
46
46
  const configDir = path.dirname(CONFIG_FILE);
47
47
  if (!fs.existsSync(configDir)) {
@@ -93,6 +93,116 @@ function createFoldersFromTree(rootPath, treeContent) {
93
93
  stack.push({ path: folderPath, indent });
94
94
  }
95
95
  }
96
+ // Generate dungeon map visualization from folder structure
97
+ function generateDungeonMap(dirPath) {
98
+ if (!fs.existsSync(dirPath)) {
99
+ return 'Directory does not exist.';
100
+ }
101
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
102
+ const folders = entries.filter(e => e.isDirectory() && !e.name.startsWith('.'));
103
+ if (folders.length === 0) {
104
+ return 'No rooms to display. Create some tasks first.';
105
+ }
106
+ const lines = [];
107
+ const roomWidth = 20;
108
+ const roomsPerRow = 2;
109
+ const wall = '█';
110
+ const door = '+';
111
+ const task = '*';
112
+ const milestone = '@';
113
+ // Group folders into rows of 2
114
+ const rows = [];
115
+ for (let i = 0; i < folders.length; i += roomsPerRow) {
116
+ rows.push(folders.slice(i, i + roomsPerRow));
117
+ }
118
+ // Top border
119
+ lines.push(' ' + wall.repeat(roomWidth * roomsPerRow + 3));
120
+ rows.forEach((row, rowIndex) => {
121
+ // Room content
122
+ for (let line = 0; line < 6; line++) {
123
+ let rowStr = ' ' + wall;
124
+ row.forEach((folder, colIndex) => {
125
+ const name = folder.name.replace(/-/g, ' ');
126
+ const displayName = name.length > roomWidth - 4
127
+ ? name.substring(0, roomWidth - 7) + '...'
128
+ : name;
129
+ // Get sub-items
130
+ const subPath = path.join(dirPath, folder.name);
131
+ const subEntries = fs.existsSync(subPath)
132
+ ? fs.readdirSync(subPath, { withFileTypes: true })
133
+ .filter(e => e.isDirectory() && !e.name.startsWith('.'))
134
+ : [];
135
+ if (line === 0) {
136
+ // Empty line
137
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
138
+ }
139
+ else if (line === 1) {
140
+ // Room name
141
+ const title = `[${displayName}]`;
142
+ const padding = roomWidth - title.length - 1;
143
+ rowStr += ' ' + title + ' '.repeat(Math.max(0, padding - 1)) + wall;
144
+ }
145
+ else if (line >= 2 && line <= 4) {
146
+ // Sub-items
147
+ const itemIndex = line - 2;
148
+ if (itemIndex < subEntries.length) {
149
+ const subName = subEntries[itemIndex].name.replace(/-/g, ' ');
150
+ const shortName = subName.length > roomWidth - 6
151
+ ? subName.substring(0, roomWidth - 9) + '...'
152
+ : subName;
153
+ const marker = subName.toLowerCase().includes('boss') ||
154
+ subName.toLowerCase().includes('launch') ||
155
+ subName.toLowerCase().includes('deploy')
156
+ ? milestone : task;
157
+ const itemStr = `${marker} ${shortName}`;
158
+ const itemPadding = roomWidth - itemStr.length - 1;
159
+ rowStr += ' ' + itemStr + ' '.repeat(Math.max(0, itemPadding - 1)) + wall;
160
+ }
161
+ else {
162
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
163
+ }
164
+ }
165
+ else {
166
+ // Empty line
167
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
168
+ }
169
+ // Add door between rooms
170
+ if (colIndex < row.length - 1 && line === 3) {
171
+ rowStr = rowStr.slice(0, -1) + door + door + door;
172
+ }
173
+ else if (colIndex < row.length - 1) {
174
+ rowStr = rowStr.slice(0, -1) + wall;
175
+ }
176
+ });
177
+ // Fill empty space if odd number of rooms
178
+ if (row.length < roomsPerRow) {
179
+ rowStr += ' '.repeat(roomWidth) + wall;
180
+ }
181
+ lines.push(rowStr);
182
+ }
183
+ // Bottom border with doors to next row
184
+ if (rowIndex < rows.length - 1) {
185
+ let borderStr = ' ' + wall.repeat(Math.floor(roomWidth / 2)) + door;
186
+ borderStr += wall.repeat(roomWidth - 1) + door;
187
+ borderStr += wall.repeat(Math.floor(roomWidth / 2) + 1);
188
+ lines.push(borderStr);
189
+ // Corridor
190
+ let corridorStr = ' ' + ' '.repeat(Math.floor(roomWidth / 2)) + '│';
191
+ corridorStr += ' '.repeat(roomWidth - 1) + '│';
192
+ lines.push(corridorStr);
193
+ borderStr = ' ' + wall.repeat(Math.floor(roomWidth / 2)) + door;
194
+ borderStr += wall.repeat(roomWidth - 1) + door;
195
+ borderStr += wall.repeat(Math.floor(roomWidth / 2) + 1);
196
+ lines.push(borderStr);
197
+ }
198
+ });
199
+ // Bottom border
200
+ lines.push(' ' + wall.repeat(roomWidth * roomsPerRow + 3));
201
+ // Legend
202
+ lines.push('');
203
+ lines.push(`Legend: ${task} Task ${milestone} Milestone ${door} Door ${wall} Wall`);
204
+ return lines.join('\n');
205
+ }
96
206
  // Global session state
97
207
  exports.sessionState = {
98
208
  pending: null,
@@ -168,6 +278,16 @@ async function processCommand(input, currentPath, config, signal) {
168
278
  }
169
279
  return result;
170
280
  };
281
+ // Version command
282
+ if (command === 'v' || command === 'version') {
283
+ const pkg = require('../../package.json');
284
+ return wrapResult({ output: `Roguelike CLI v${pkg.version}` });
285
+ }
286
+ // Map command - dungeon visualization
287
+ if (command === 'map') {
288
+ const dungeonMap = generateDungeonMap(currentPath);
289
+ return wrapResult({ output: dungeonMap });
290
+ }
171
291
  if (command === 'ls') {
172
292
  if (!fs.existsSync(currentPath)) {
173
293
  return wrapResult({ output: 'Directory does not exist.' });
@@ -432,6 +552,7 @@ Storage: ${config.storagePath}
432
552
  tree - Show directory tree structure
433
553
  tree -A - Show tree with files
434
554
  tree --depth=N - Limit tree depth (e.g., --depth=2)
555
+ map - Dungeon map visualization
435
556
  cd <node> - Navigate into a node
436
557
  cd .. - Go back to parent
437
558
  pwd - Show current path
@@ -444,6 +565,7 @@ Storage: ${config.storagePath}
444
565
  rm -rf <name> - Delete folder recursively
445
566
  config - Show configuration
446
567
  config:apiKey=<key> - Set API key
568
+ v, version - Show version
447
569
  <description> - Create schema/todo (AI generates preview)
448
570
  save - Save pending schema to disk
449
571
  cancel - Discard pending schema
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roguelike-cli",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "AI-powered interactive terminal for creating schemas and todo lists",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -62,7 +62,7 @@ export async function initCommand(): Promise<void> {
62
62
  const oldStoragePath = existingConfig?.storagePath;
63
63
 
64
64
  // 1. Root directory
65
- const defaultRoot = path.join(os.homedir(), '.rlc', 'notes');
65
+ const defaultRoot = path.join(os.homedir(), '.rlc', 'workspace');
66
66
  const rootDirAnswer = await question(`Root directory for notes [${defaultRoot}]: `);
67
67
  const rootDir = rootDirAnswer.trim() || defaultRoot;
68
68
 
@@ -12,7 +12,7 @@ export interface Config {
12
12
  }
13
13
 
14
14
  const CONFIG_FILE = path.join(os.homedir(), '.rlc', 'config.json');
15
- const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'notes');
15
+ const DEFAULT_STORAGE = path.join(os.homedir(), '.rlc', 'workspace');
16
16
 
17
17
  export async function initConfig(): Promise<Config | null> {
18
18
  const configDir = path.dirname(CONFIG_FILE);
@@ -69,6 +69,130 @@ function createFoldersFromTree(rootPath: string, treeContent: string): void {
69
69
  }
70
70
  }
71
71
 
72
+ // Generate dungeon map visualization from folder structure
73
+ function generateDungeonMap(dirPath: string): string {
74
+ if (!fs.existsSync(dirPath)) {
75
+ return 'Directory does not exist.';
76
+ }
77
+
78
+ const entries = fs.readdirSync(dirPath, { withFileTypes: true });
79
+ const folders = entries.filter(e => e.isDirectory() && !e.name.startsWith('.'));
80
+
81
+ if (folders.length === 0) {
82
+ return 'No rooms to display. Create some tasks first.';
83
+ }
84
+
85
+ const lines: string[] = [];
86
+ const roomWidth = 20;
87
+ const roomsPerRow = 2;
88
+ const wall = '█';
89
+ const door = '+';
90
+ const task = '*';
91
+ const milestone = '@';
92
+
93
+ // Group folders into rows of 2
94
+ const rows: typeof folders[] = [];
95
+ for (let i = 0; i < folders.length; i += roomsPerRow) {
96
+ rows.push(folders.slice(i, i + roomsPerRow));
97
+ }
98
+
99
+ // Top border
100
+ lines.push(' ' + wall.repeat(roomWidth * roomsPerRow + 3));
101
+
102
+ rows.forEach((row, rowIndex) => {
103
+ // Room content
104
+ for (let line = 0; line < 6; line++) {
105
+ let rowStr = ' ' + wall;
106
+
107
+ row.forEach((folder, colIndex) => {
108
+ const name = folder.name.replace(/-/g, ' ');
109
+ const displayName = name.length > roomWidth - 4
110
+ ? name.substring(0, roomWidth - 7) + '...'
111
+ : name;
112
+
113
+ // Get sub-items
114
+ const subPath = path.join(dirPath, folder.name);
115
+ const subEntries = fs.existsSync(subPath)
116
+ ? fs.readdirSync(subPath, { withFileTypes: true })
117
+ .filter(e => e.isDirectory() && !e.name.startsWith('.'))
118
+ : [];
119
+
120
+ if (line === 0) {
121
+ // Empty line
122
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
123
+ } else if (line === 1) {
124
+ // Room name
125
+ const title = `[${displayName}]`;
126
+ const padding = roomWidth - title.length - 1;
127
+ rowStr += ' ' + title + ' '.repeat(Math.max(0, padding - 1)) + wall;
128
+ } else if (line >= 2 && line <= 4) {
129
+ // Sub-items
130
+ const itemIndex = line - 2;
131
+ if (itemIndex < subEntries.length) {
132
+ const subName = subEntries[itemIndex].name.replace(/-/g, ' ');
133
+ const shortName = subName.length > roomWidth - 6
134
+ ? subName.substring(0, roomWidth - 9) + '...'
135
+ : subName;
136
+ const marker = subName.toLowerCase().includes('boss') ||
137
+ subName.toLowerCase().includes('launch') ||
138
+ subName.toLowerCase().includes('deploy')
139
+ ? milestone : task;
140
+ const itemStr = `${marker} ${shortName}`;
141
+ const itemPadding = roomWidth - itemStr.length - 1;
142
+ rowStr += ' ' + itemStr + ' '.repeat(Math.max(0, itemPadding - 1)) + wall;
143
+ } else {
144
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
145
+ }
146
+ } else {
147
+ // Empty line
148
+ rowStr += ' '.repeat(roomWidth - 1) + wall;
149
+ }
150
+
151
+ // Add door between rooms
152
+ if (colIndex < row.length - 1 && line === 3) {
153
+ rowStr = rowStr.slice(0, -1) + door + door + door;
154
+ } else if (colIndex < row.length - 1) {
155
+ rowStr = rowStr.slice(0, -1) + wall;
156
+ }
157
+ });
158
+
159
+ // Fill empty space if odd number of rooms
160
+ if (row.length < roomsPerRow) {
161
+ rowStr += ' '.repeat(roomWidth) + wall;
162
+ }
163
+
164
+ lines.push(rowStr);
165
+ }
166
+
167
+ // Bottom border with doors to next row
168
+ if (rowIndex < rows.length - 1) {
169
+ let borderStr = ' ' + wall.repeat(Math.floor(roomWidth / 2)) + door;
170
+ borderStr += wall.repeat(roomWidth - 1) + door;
171
+ borderStr += wall.repeat(Math.floor(roomWidth / 2) + 1);
172
+ lines.push(borderStr);
173
+
174
+ // Corridor
175
+ let corridorStr = ' ' + ' '.repeat(Math.floor(roomWidth / 2)) + '│';
176
+ corridorStr += ' '.repeat(roomWidth - 1) + '│';
177
+ lines.push(corridorStr);
178
+
179
+ borderStr = ' ' + wall.repeat(Math.floor(roomWidth / 2)) + door;
180
+ borderStr += wall.repeat(roomWidth - 1) + door;
181
+ borderStr += wall.repeat(Math.floor(roomWidth / 2) + 1);
182
+ lines.push(borderStr);
183
+ }
184
+ });
185
+
186
+ // Bottom border
187
+ lines.push(' ' + wall.repeat(roomWidth * roomsPerRow + 3));
188
+
189
+ // Legend
190
+ lines.push('');
191
+ lines.push(`Legend: ${task} Task ${milestone} Milestone ${door} Door ${wall} Wall`);
192
+
193
+ return lines.join('\n');
194
+ }
195
+
72
196
  export interface CommandResult {
73
197
  output?: string;
74
198
  newPath?: string;
@@ -181,6 +305,18 @@ export async function processCommand(
181
305
  return result;
182
306
  };
183
307
 
308
+ // Version command
309
+ if (command === 'v' || command === 'version') {
310
+ const pkg = require('../../package.json');
311
+ return wrapResult({ output: `Roguelike CLI v${pkg.version}` });
312
+ }
313
+
314
+ // Map command - dungeon visualization
315
+ if (command === 'map') {
316
+ const dungeonMap = generateDungeonMap(currentPath);
317
+ return wrapResult({ output: dungeonMap });
318
+ }
319
+
184
320
  if (command === 'ls') {
185
321
  if (!fs.existsSync(currentPath)) {
186
322
  return wrapResult({ output: 'Directory does not exist.' });
@@ -491,6 +627,7 @@ Storage: ${config.storagePath}
491
627
  tree - Show directory tree structure
492
628
  tree -A - Show tree with files
493
629
  tree --depth=N - Limit tree depth (e.g., --depth=2)
630
+ map - Dungeon map visualization
494
631
  cd <node> - Navigate into a node
495
632
  cd .. - Go back to parent
496
633
  pwd - Show current path
@@ -503,6 +640,7 @@ Storage: ${config.storagePath}
503
640
  rm -rf <name> - Delete folder recursively
504
641
  config - Show configuration
505
642
  config:apiKey=<key> - Set API key
643
+ v, version - Show version
506
644
  <description> - Create schema/todo (AI generates preview)
507
645
  save - Save pending schema to disk
508
646
  cancel - Discard pending schema