roguelike-cli 1.2.0 → 1.2.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/LICENSE +21 -0
- package/README.md +227 -139
- package/dist/interactive/commands.js +122 -0
- package/dist/interactive/startup.js +1 -1
- package/package.json +1 -1
- package/src/interactive/commands.ts +138 -0
- package/src/interactive/startup.ts +1 -1
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
|
@@ -13,196 +13,284 @@
|
|
|
13
13
|
' '
|
|
14
14
|
|
|
15
15
|
╔═════════════════════════╗
|
|
16
|
-
║
|
|
16
|
+
║ Roguelike CLI ║
|
|
17
17
|
╚═════════════════════════╝
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
## What is this?
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**A new format for notes, schemas, and todo lists — where every task is a folder.**
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
npm i -g roguelike-cli
|
|
26
|
-
```
|
|
24
|
+
Instead of flat text files, your tasks become a **file system tree**. Nested tasks = nested folders. You can:
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
- **Navigate** your todos like directories (`cd`, `ls`, `tree`)
|
|
27
|
+
- **Attach files** directly to tasks (just put them in the folder)
|
|
28
|
+
- **Track dependencies** and blockers between tasks
|
|
29
|
+
- **Generate beautiful visualizations** — trees, block diagrams, and dungeon maps
|
|
30
|
+
- Let **AI help** you structure complex projects
|
|
31
|
+
|
|
32
|
+
## Why folders?
|
|
29
33
|
|
|
30
|
-
```
|
|
31
|
-
|
|
34
|
+
```
|
|
35
|
+
project/
|
|
36
|
+
├── phase-1-research/
|
|
37
|
+
│ ├── market-analysis/
|
|
38
|
+
│ │ └── competitors.xlsx <- attach files directly
|
|
39
|
+
│ └── user-interviews/
|
|
40
|
+
├── phase-2-development/
|
|
41
|
+
│ ├── backend-api/
|
|
42
|
+
│ ├── frontend-ui/
|
|
43
|
+
│ └── database-schema/
|
|
44
|
+
└── phase-3-launch/
|
|
45
|
+
├── marketing/
|
|
46
|
+
└── deployment/
|
|
32
47
|
```
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
- Storage path for your notes
|
|
36
|
-
- AI provider (Claude, GPT, Gemini, Grok)
|
|
37
|
-
- API key
|
|
49
|
+
Your file manager becomes your task manager. Git tracks your progress. AI generates the structure.
|
|
38
50
|
|
|
39
|
-
##
|
|
51
|
+
## Install
|
|
40
52
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| `tree -A` | Show tree with files |
|
|
46
|
-
| `tree --depth=N` | Limit tree depth |
|
|
47
|
-
| `cd <node>` | Navigate into a node |
|
|
48
|
-
| `cd ..` | Go back to parent |
|
|
49
|
-
| `..` | Same as cd .. |
|
|
50
|
-
| `pwd` | Show current path |
|
|
51
|
-
| `open` | Open current folder in Finder |
|
|
52
|
-
| `open <folder>` | Open specific folder in Finder |
|
|
53
|
-
| `mkdir <name>` | Create new folder |
|
|
54
|
-
| `cp <src> <dest>` | Copy file or folder |
|
|
55
|
-
| `mv <src> <dest>` | Move/rename file or folder |
|
|
56
|
-
| `rm <name>` | Delete file |
|
|
57
|
-
| `rm -rf <name>` | Delete folder recursively |
|
|
58
|
-
| `config` | Show configuration |
|
|
59
|
-
| `config:apiKey=<key>` | Set API key |
|
|
60
|
-
| `init` | Run setup wizard |
|
|
61
|
-
| `help` | Show examples |
|
|
62
|
-
| `clean` | Show items to delete |
|
|
63
|
-
| `clean --yes` | Delete all items in current folder |
|
|
64
|
-
| `exit` / `quit` | Exit the program |
|
|
53
|
+
```bash
|
|
54
|
+
npm i -g roguelike-cli
|
|
55
|
+
rlc
|
|
56
|
+
```
|
|
65
57
|
|
|
66
58
|
## Workflow
|
|
67
59
|
|
|
68
|
-
1. Type description (e.g., `todo: deploy app`)
|
|
69
|
-
2. AI generates schema preview
|
|
70
|
-
3. Refine with more instructions if needed
|
|
71
|
-
4. Type `save` to save or `cancel` to discard
|
|
72
|
-
|
|
73
|
-
**Todo** creates folder structure, **Schema** saves as `.rlc.schema` file.
|
|
74
|
-
|
|
75
|
-
## Clipboard
|
|
76
|
-
|
|
77
|
-
Add `| pbcopy` (macOS), `| copy` or `| clip` (Windows) to any command:
|
|
78
|
-
|
|
79
60
|
```
|
|
80
|
-
>
|
|
81
|
-
|
|
82
|
-
|
|
61
|
+
> todo launch my startup
|
|
62
|
+
|
|
63
|
+
├── Research
|
|
64
|
+
│ ├── Market analysis
|
|
65
|
+
│ ├── Competitor research
|
|
66
|
+
│ └── User interviews
|
|
67
|
+
├── Development
|
|
68
|
+
│ ├── MVP features
|
|
69
|
+
│ ├── Backend API
|
|
70
|
+
│ └── Frontend UI
|
|
71
|
+
├── Launch
|
|
72
|
+
│ ├── Marketing campaign
|
|
73
|
+
│ └── Press release
|
|
74
|
+
└── Growth
|
|
75
|
+
├── Metrics tracking
|
|
76
|
+
└── User feedback
|
|
77
|
+
|
|
78
|
+
[Type "save" to create folder launch-my-startup/]
|
|
79
|
+
> save
|
|
80
|
+
Created todo folder: launch-my-startup/
|
|
81
|
+
|
|
82
|
+
> cd launch-my-startup
|
|
83
|
+
> tree
|
|
84
|
+
├── research/
|
|
85
|
+
│ ├── market-analysis/
|
|
86
|
+
│ ├── competitor-research/
|
|
87
|
+
│ └── user-interviews/
|
|
88
|
+
├── development/
|
|
89
|
+
│ ├── mvp-features/
|
|
90
|
+
│ ├── backend-api/
|
|
91
|
+
│ └── frontend-ui/
|
|
92
|
+
├── launch/
|
|
93
|
+
│ ├── marketing-campaign/
|
|
94
|
+
│ └── press-release/
|
|
95
|
+
└── growth/
|
|
96
|
+
├── metrics-tracking/
|
|
97
|
+
└── user-feedback/
|
|
83
98
|
```
|
|
84
99
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
### Todo List
|
|
100
|
+
Now you can `cd development/backend-api` and drop your actual code files there!
|
|
88
101
|
|
|
89
|
-
|
|
90
|
-
> todo opening company in delaware
|
|
102
|
+
## Visualizations
|
|
91
103
|
|
|
92
|
-
|
|
93
|
-
├── file incorporation papers
|
|
94
|
-
├── get EIN number
|
|
95
|
-
└── Branch: legal
|
|
96
|
-
└── open business bank account
|
|
104
|
+
### Tree View (default)
|
|
97
105
|
|
|
98
|
-
|
|
106
|
+
```
|
|
107
|
+
├── Phase 1: Setup
|
|
108
|
+
│ ├── Create repository
|
|
109
|
+
│ ├── Setup CI/CD
|
|
110
|
+
│ └── Configure environment
|
|
111
|
+
├── Phase 2: Development
|
|
112
|
+
│ ├── Backend API
|
|
113
|
+
│ └── Frontend UI
|
|
114
|
+
└── Phase 3: Deploy
|
|
99
115
|
```
|
|
100
116
|
|
|
101
|
-
###
|
|
117
|
+
### Block Diagram (for architecture)
|
|
102
118
|
|
|
103
119
|
```
|
|
104
|
-
>
|
|
120
|
+
> schema kubernetes cluster
|
|
105
121
|
|
|
106
122
|
┌─────────────────────────────────────────────────────────────┐
|
|
107
|
-
│
|
|
123
|
+
│ Kubernetes Cluster │
|
|
108
124
|
│ │
|
|
109
|
-
│
|
|
110
|
-
│ │
|
|
111
|
-
│ │
|
|
112
|
-
│
|
|
113
|
-
│
|
|
114
|
-
│
|
|
115
|
-
│
|
|
116
|
-
│
|
|
117
|
-
│
|
|
118
|
-
│
|
|
119
|
-
│
|
|
125
|
+
│ ┌──────────────┐ ┌──────────────┐ │
|
|
126
|
+
│ │ postgres │ │ redis │ │
|
|
127
|
+
│ │ │ │ │ │
|
|
128
|
+
│ │ primary-pod │ │ cache-pod-1 │ │
|
|
129
|
+
│ │ replica-pod │ │ cache-pod-2 │ │
|
|
130
|
+
│ └──────┬───────┘ └──────┬───────┘ │
|
|
131
|
+
│ └──────────┬───────────┘ │
|
|
132
|
+
│ ▼ │
|
|
133
|
+
│ ┌───────────────┐ │
|
|
134
|
+
│ │ worker-nodes │ │
|
|
135
|
+
│ └───────────────┘ │
|
|
120
136
|
└─────────────────────────────────────────────────────────────┘
|
|
121
137
|
```
|
|
122
138
|
|
|
123
|
-
###
|
|
139
|
+
### Dungeon Map View
|
|
124
140
|
|
|
125
|
-
|
|
126
|
-
> architecture production redis web application
|
|
141
|
+
Visualize your project as a dungeon map. Each room is a task, corridors show dependencies.
|
|
127
142
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
```
|
|
144
|
+
> map
|
|
145
|
+
|
|
146
|
+
████████████████████████████████████████
|
|
147
|
+
█ █ █
|
|
148
|
+
█ [Research] █ [Development] █
|
|
149
|
+
█ * Market █ * Backend █
|
|
150
|
+
█ * Users ──────+───* Frontend █
|
|
151
|
+
█ █ * Database █
|
|
152
|
+
█████████+███████████████████+██████████
|
|
153
|
+
│ │
|
|
154
|
+
█████████+███████████████████+██████████
|
|
155
|
+
█ █ █
|
|
156
|
+
█ [Launch] █ [Growth] █
|
|
157
|
+
█ * Marketing █ * Metrics █
|
|
158
|
+
█ * Press ──────+───* Feedback █
|
|
159
|
+
█ @ BOSS: Ship it! █ █
|
|
160
|
+
█ █ █
|
|
161
|
+
████████████████████████████████████████
|
|
162
|
+
|
|
163
|
+
Legend: * Task @ Milestone + Door █ Wall
|
|
139
164
|
```
|
|
140
165
|
|
|
141
|
-
|
|
166
|
+
## Gamification (Roadmap)
|
|
142
167
|
|
|
143
|
-
|
|
144
|
-
|
|
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
|
|
145
173
|
|
|
146
|
-
|
|
147
|
-
│ Kubernetes cluster with clusters postgres │
|
|
148
|
-
│ │
|
|
149
|
-
│ ┌──────────────┐ ┌──────────────┐ │
|
|
150
|
-
│ │ postgres │ │ redis │ │
|
|
151
|
-
│ │ │ │ │ │
|
|
152
|
-
│ │ primary-pod │ │ cache-pod-1 │ │
|
|
153
|
-
│ │ replica-pod-1│ │ cache-pod-2 │ │
|
|
154
|
-
│ │ replica-pod-2│ │ │ │
|
|
155
|
-
│ └──────┬───────┘ └──────┬───────┘ │
|
|
156
|
-
│ │ │ │
|
|
157
|
-
│ └──────────┬───────────┘ │
|
|
158
|
-
│ │ │
|
|
159
|
-
│ ┌───────▼────────┐ │
|
|
160
|
-
│ │ worker-zones │ │
|
|
161
|
-
│ │ zone-1 │ │
|
|
162
|
-
│ │ zone-2 │ │
|
|
163
|
-
│ └────────────────┘ │
|
|
164
|
-
└─────────────────────────────────────────────────────────────┘
|
|
165
|
-
```
|
|
174
|
+
## Commands
|
|
166
175
|
|
|
167
|
-
|
|
176
|
+
| Command | Description |
|
|
177
|
+
|---------|-------------|
|
|
178
|
+
| `ls` | List tasks and files |
|
|
179
|
+
| `tree` | Show task tree |
|
|
180
|
+
| `tree -A` | Include files |
|
|
181
|
+
| `map` | Dungeon map view |
|
|
182
|
+
| `cd <task>` | Enter task |
|
|
183
|
+
| `..` | Go back |
|
|
184
|
+
| `mkdir <name>` | Create task |
|
|
185
|
+
| `open` | Open in Finder |
|
|
186
|
+
| `cp`, `mv`, `rm` | File operations |
|
|
187
|
+
| `config` | Settings |
|
|
188
|
+
| `help` | Examples |
|
|
189
|
+
| `v`, `version` | Show version |
|
|
190
|
+
|
|
191
|
+
## AI Integration
|
|
192
|
+
|
|
193
|
+
Just describe what you need:
|
|
168
194
|
|
|
169
195
|
```
|
|
170
196
|
> todo bake cookies
|
|
171
197
|
|
|
172
198
|
├── Prep
|
|
173
199
|
│ ├── Gather ingredients
|
|
174
|
-
│ └── Preheat oven
|
|
200
|
+
│ └── Preheat oven
|
|
175
201
|
├── Mix
|
|
176
202
|
│ ├── Cream butter + sugar
|
|
177
|
-
│
|
|
178
|
-
|
|
179
|
-
├── Bake
|
|
180
|
-
│ ├── Shape cookies
|
|
181
|
-
│ └── Bake 8-10 min
|
|
203
|
+
│ └── Add flour
|
|
204
|
+
├── Bake (8-10 min)
|
|
182
205
|
└── Cool & store
|
|
206
|
+
|
|
207
|
+
> add deadline tomorrow for Bake
|
|
208
|
+
> add blocker "buy flour" for Mix
|
|
209
|
+
> shorter
|
|
210
|
+
> more detailed
|
|
211
|
+
> save
|
|
183
212
|
```
|
|
184
213
|
|
|
185
|
-
|
|
214
|
+
AI understands context and refines until you're happy.
|
|
186
215
|
|
|
216
|
+
## Examples
|
|
217
|
+
|
|
218
|
+
### Software Project
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
> todo build saas app
|
|
222
|
+
|
|
223
|
+
├── Planning
|
|
224
|
+
│ ├── Define MVP scope
|
|
225
|
+
│ ├── Create wireframes
|
|
226
|
+
│ └── Tech stack decision
|
|
227
|
+
├── Backend
|
|
228
|
+
│ ├── Database schema
|
|
229
|
+
│ ├── API endpoints
|
|
230
|
+
│ ├── Authentication
|
|
231
|
+
│ └── Payment integration
|
|
232
|
+
├── Frontend
|
|
233
|
+
│ ├── Components library
|
|
234
|
+
│ ├── Pages
|
|
235
|
+
│ └── State management
|
|
236
|
+
├── DevOps
|
|
237
|
+
│ ├── CI/CD pipeline
|
|
238
|
+
│ ├── Staging environment
|
|
239
|
+
│ └── Production deployment
|
|
240
|
+
└── Launch
|
|
241
|
+
├── Beta testing
|
|
242
|
+
├── Marketing site
|
|
243
|
+
└── Product Hunt launch
|
|
187
244
|
```
|
|
188
|
-
> todo launch startup
|
|
189
245
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
│ ├──
|
|
197
|
-
│
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
│ ├──
|
|
201
|
-
│
|
|
202
|
-
└──
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
246
|
+
### Life Goals
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
> todo learn japanese
|
|
250
|
+
|
|
251
|
+
├── Basics (Month 1-2)
|
|
252
|
+
│ ├── Hiragana
|
|
253
|
+
│ ├── Katakana
|
|
254
|
+
│ └── Basic grammar
|
|
255
|
+
├── Foundation (Month 3-6)
|
|
256
|
+
│ ├── Kanji (500)
|
|
257
|
+
│ ├── Vocabulary (2000 words)
|
|
258
|
+
│ └── Genki textbook
|
|
259
|
+
├── Intermediate (Month 6-12)
|
|
260
|
+
│ ├── JLPT N4 prep
|
|
261
|
+
│ ├── Reading practice
|
|
262
|
+
│ └── Conversation partner
|
|
263
|
+
└── Advanced
|
|
264
|
+
├── JLPT N3
|
|
265
|
+
├── Watch anime without subs
|
|
266
|
+
└── Visit Japan
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Infrastructure
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
> schema cloud infrastructure
|
|
273
|
+
|
|
274
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
275
|
+
│ Production │
|
|
276
|
+
│ │
|
|
277
|
+
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|
278
|
+
│ │ Load Balancer │ │ CDN │ │
|
|
279
|
+
│ └────────┬─────────┘ └──────────────────┘ │
|
|
280
|
+
│ │ │
|
|
281
|
+
│ ┌────────▼────────┐ ┌────────────┐ ┌────────────────┐ │
|
|
282
|
+
│ │ App Servers │ │ Redis │ │ PostgreSQL │ │
|
|
283
|
+
│ │ (3 replicas) │──│ Cache │ │ (Primary + │ │
|
|
284
|
+
│ └─────────────────┘ └────────────┘ │ Replica) │ │
|
|
285
|
+
│ └────────────────┘ │
|
|
286
|
+
└─────────────────────────────────────────────────────────────┘
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Clipboard
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
> tree | pbcopy # macOS
|
|
293
|
+
> tree | clip # Windows
|
|
206
294
|
```
|
|
207
295
|
|
|
208
296
|
## Website
|
|
@@ -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
|
@@ -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
|