roguelike-cli 1.3.2 → 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 +71 -80
- package/dist/commands/init.js +4 -4
- package/dist/config/config.js +12 -2
- package/dist/interactive/commands.js +50 -61
- package/dist/interactive/startup.js +6 -5
- package/package.json +1 -1
- package/src/commands/init.ts +4 -4
- package/src/config/config.ts +12 -1
- package/src/interactive/commands.ts +50 -62
- package/src/interactive/startup.ts +6 -5
package/README.md
CHANGED
|
@@ -24,11 +24,7 @@
|
|
|
24
24
|
- **RPG Engine** — Tasks are quests. Completing them earns XP, unlocks achievements, and levels you up.
|
|
25
25
|
- **AI Game Master** — Integrated AI helps decompose complex tasks and generates structured plans.
|
|
26
26
|
- **Local-First** — Your data stays on your machine in simple folders and JSON files.
|
|
27
|
-
- **
|
|
28
|
-
|
|
29
|
-
## Why Roguelike CLI?
|
|
30
|
-
|
|
31
|
-
Most task managers are boring. We make deep work addictive by applying proven RPG mechanics to your daily workflow.
|
|
27
|
+
- **Customizable Rules** — Choose adventure style: Fantasy, Space Opera, Star Wars, Cyberpunk, and more.
|
|
32
28
|
|
|
33
29
|
## Install
|
|
34
30
|
|
|
@@ -37,27 +33,6 @@ npm i -g roguelike-cli
|
|
|
37
33
|
rlc
|
|
38
34
|
```
|
|
39
35
|
|
|
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
|
-
|
|
61
36
|
## Quick Start
|
|
62
37
|
|
|
63
38
|
```
|
|
@@ -88,41 +63,33 @@ Created: launch-my-startup/
|
|
|
88
63
|
[x] Boss Slayer: Defeat a boss
|
|
89
64
|
```
|
|
90
65
|
|
|
91
|
-
##
|
|
66
|
+
## Folder Structure
|
|
92
67
|
|
|
93
|
-
|
|
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.
|
|
94
69
|
|
|
95
70
|
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
config -t=<theme> Set theme
|
|
109
|
-
config -r="<rules>" Set custom rules
|
|
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/
|
|
110
83
|
```
|
|
111
84
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
| Setting | Default |
|
|
115
|
-
|---------|---------|
|
|
116
|
-
| Provider | Claude Sonnet 4.5 |
|
|
117
|
-
| Storage | `~/.rlc/workspace` |
|
|
118
|
-
| Theme | Default (no theme) |
|
|
85
|
+
Navigate with `cd`, view with `tree`, open in Finder with `open`. It's just folders.
|
|
119
86
|
|
|
120
|
-
##
|
|
87
|
+
## Rules
|
|
121
88
|
|
|
122
|
-
|
|
89
|
+
Rules change how the AI speaks. Set during `init` or with `config -R="<rules>"`.
|
|
123
90
|
|
|
124
|
-
|
|
|
125
|
-
|
|
91
|
+
| Preset | Style |
|
|
92
|
+
|--------|-------|
|
|
126
93
|
| `default` | Standard task manager language |
|
|
127
94
|
| `fantasy` | Quests, dungeons, dragons, loot |
|
|
128
95
|
| `space` | Missions, starships, commanders |
|
|
@@ -134,11 +101,38 @@ Themes change how the AI speaks. Set with `config -t=<theme>` or during `init`.
|
|
|
134
101
|
### Custom Rules
|
|
135
102
|
|
|
136
103
|
```
|
|
137
|
-
> config -
|
|
104
|
+
> config -R="Speak like a medieval knight. Tasks are 'duties'. Use 'huzzah' for success."
|
|
138
105
|
```
|
|
139
106
|
|
|
140
107
|
Or select "Custom" during `init` to enter your own rules.
|
|
141
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)
|
|
134
|
+
```
|
|
135
|
+
|
|
142
136
|
## Commands
|
|
143
137
|
|
|
144
138
|
### Navigation
|
|
@@ -158,7 +152,7 @@ Or select "Custom" during `init` to enter your own rules.
|
|
|
158
152
|
|---------|-------------|
|
|
159
153
|
| `done` | Complete task (earns XP) |
|
|
160
154
|
| `undo` | Undo last done |
|
|
161
|
-
| `
|
|
155
|
+
| `dl <date>` | Set deadline (dl +3d, dl Jan 15) |
|
|
162
156
|
| `boss` | Toggle boss (3x XP) |
|
|
163
157
|
| `block [node]` | Block by task |
|
|
164
158
|
| `unblock` | Remove block |
|
|
@@ -186,18 +180,24 @@ Or select "Custom" during `init` to enter your own rules.
|
|
|
186
180
|
|---------|-------------|
|
|
187
181
|
| `init` | Setup wizard |
|
|
188
182
|
| `config` | View settings |
|
|
189
|
-
| `config -
|
|
190
|
-
| `config -
|
|
191
|
-
| `config -
|
|
192
|
-
|
|
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) |
|
|
193
193
|
|
|
194
194
|
## Deadlines
|
|
195
195
|
|
|
196
196
|
```
|
|
197
|
-
>
|
|
198
|
-
>
|
|
199
|
-
>
|
|
200
|
-
> deadline Jan 15
|
|
197
|
+
> dl today # Due today
|
|
198
|
+
> dl tomorrow # Due tomorrow
|
|
199
|
+
> dl +3d # In 3 days
|
|
200
|
+
> deadline Jan 15 # Specific date
|
|
201
201
|
```
|
|
202
202
|
|
|
203
203
|
Tree shows deadlines:
|
|
@@ -228,25 +228,16 @@ Tree shows deadlines:
|
|
|
228
228
|
| Speedrunner | Same-day completion |
|
|
229
229
|
| Streak Master | 7 day streak |
|
|
230
230
|
|
|
231
|
-
##
|
|
232
|
-
|
|
233
|
-
```
|
|
234
|
-
> map
|
|
235
|
-
|
|
236
|
-
###########################################
|
|
237
|
-
# # #
|
|
238
|
-
# [Research] # [Development] #
|
|
239
|
-
# x Analysis +---* Backend #
|
|
240
|
-
# x Interviews # @ Deploy BOSS #
|
|
241
|
-
# # #
|
|
242
|
-
##########+###########+###################
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Clipboard
|
|
231
|
+
## Supported Models
|
|
246
232
|
|
|
247
233
|
```
|
|
248
|
-
|
|
249
|
-
|
|
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
|
|
250
241
|
```
|
|
251
242
|
|
|
252
243
|
## Website
|
package/dist/commands/init.js
CHANGED
|
@@ -128,7 +128,7 @@ async function initCommand(existingRl) {
|
|
|
128
128
|
const apiKeyInput = await question(rl, keyPrompt);
|
|
129
129
|
const apiKey = apiKeyInput.trim() || existingApiKey;
|
|
130
130
|
if (!apiKey) {
|
|
131
|
-
console.log('Warning: API key not set. You can set it later with: config -
|
|
131
|
+
console.log('Warning: API key not set. You can set it later with: config -K=<key>');
|
|
132
132
|
}
|
|
133
133
|
else if (apiKeyInput.trim()) {
|
|
134
134
|
console.log('API key saved');
|
|
@@ -136,8 +136,8 @@ async function initCommand(existingRl) {
|
|
|
136
136
|
else {
|
|
137
137
|
console.log('Using existing API key');
|
|
138
138
|
}
|
|
139
|
-
// 4.
|
|
140
|
-
console.log('\nSelect AI
|
|
139
|
+
// 4. Rules preset selection
|
|
140
|
+
console.log('\nSelect AI Rules (affects language style):');
|
|
141
141
|
const presetKeys = Object.keys(config_1.RULES_PRESETS);
|
|
142
142
|
presetKeys.forEach((key, index) => {
|
|
143
143
|
console.log(` ${index + 1}. ${config_1.RULES_PRESETS[key].name}`);
|
|
@@ -190,7 +190,7 @@ async function initCommand(existingRl) {
|
|
|
190
190
|
console.log(`Root directory: ${rootDir}`);
|
|
191
191
|
console.log(`AI Provider: ${selectedProvider.name}`);
|
|
192
192
|
console.log(`Model: ${selectedProvider.model}`);
|
|
193
|
-
console.log(`
|
|
193
|
+
console.log(`Rules: ${config_1.RULES_PRESETS[selectedPreset]?.name || 'Custom'}\n`);
|
|
194
194
|
}
|
|
195
195
|
finally {
|
|
196
196
|
if (shouldCloseRl) {
|
package/dist/config/config.js
CHANGED
|
@@ -33,7 +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
|
+
exports.RULES_PRESETS = exports.SUPPORTED_MODELS = void 0;
|
|
37
37
|
exports.initConfig = initConfig;
|
|
38
38
|
exports.saveConfig = saveConfig;
|
|
39
39
|
exports.getConfig = getConfig;
|
|
@@ -41,7 +41,17 @@ exports.updateConfig = updateConfig;
|
|
|
41
41
|
const fs = __importStar(require("fs"));
|
|
42
42
|
const path = __importStar(require("path"));
|
|
43
43
|
const os = __importStar(require("os"));
|
|
44
|
-
//
|
|
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
|
|
45
55
|
exports.RULES_PRESETS = {
|
|
46
56
|
default: {
|
|
47
57
|
name: 'Default (No theme)',
|
|
@@ -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
|
|
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,64 +931,52 @@ async function processCommand(input, currentPath, config, signal, rl) {
|
|
|
931
931
|
return wrapResult({ output: currentPath });
|
|
932
932
|
}
|
|
933
933
|
if (command === 'config') {
|
|
934
|
-
const { updateConfig,
|
|
935
|
-
// Check for flags
|
|
936
|
-
const keyFlag = parts.find(p => p.startsWith('-
|
|
937
|
-
const modelFlag = parts.find(p => p.startsWith('-
|
|
938
|
-
const rulesFlag = parts.find(p => p.startsWith('-
|
|
939
|
-
const themeFlag = parts.find(p => p.startsWith('-t=') || p.startsWith('--theme='));
|
|
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='));
|
|
940
939
|
if (keyFlag) {
|
|
941
940
|
const value = keyFlag.split('=').slice(1).join('=');
|
|
941
|
+
if (!value) {
|
|
942
|
+
return wrapResult({ output: 'Error: API key cannot be empty' });
|
|
943
|
+
}
|
|
942
944
|
updateConfig({ apiKey: value });
|
|
943
945
|
return wrapResult({ output: 'API key updated.' });
|
|
944
946
|
}
|
|
945
947
|
if (modelFlag) {
|
|
946
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
|
+
}
|
|
947
954
|
updateConfig({ model: value });
|
|
948
955
|
return wrapResult({ output: `Model updated: ${value}` });
|
|
949
956
|
}
|
|
950
957
|
if (rulesFlag) {
|
|
951
958
|
const value = rulesFlag.split('=').slice(1).join('=');
|
|
952
959
|
updateConfig({ rules: value, rulesPreset: 'custom' });
|
|
953
|
-
return wrapResult({ output: '
|
|
954
|
-
}
|
|
955
|
-
if (themeFlag) {
|
|
956
|
-
const value = themeFlag.split('=').slice(1).join('=').toLowerCase();
|
|
957
|
-
if (RULES_PRESETS[value]) {
|
|
958
|
-
updateConfig({
|
|
959
|
-
rules: RULES_PRESETS[value].rules,
|
|
960
|
-
rulesPreset: value
|
|
961
|
-
});
|
|
962
|
-
return wrapResult({ output: `Theme updated: ${RULES_PRESETS[value].name}` });
|
|
963
|
-
}
|
|
964
|
-
else {
|
|
965
|
-
const themes = Object.keys(RULES_PRESETS).join(', ');
|
|
966
|
-
return wrapResult({ output: `Unknown theme. Available: ${themes}` });
|
|
967
|
-
}
|
|
960
|
+
return wrapResult({ output: 'Rules updated.' });
|
|
968
961
|
}
|
|
969
962
|
// Show config
|
|
970
963
|
const maskedKey = config.apiKey
|
|
971
964
|
? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
|
|
972
965
|
: '(not set)';
|
|
973
|
-
const themeName = config.rulesPreset
|
|
974
|
-
? (RULES_PRESETS[config.rulesPreset]?.name || 'Custom')
|
|
975
|
-
: 'Default';
|
|
976
966
|
const rulesPreview = config.rules
|
|
977
|
-
? (config.rules.length >
|
|
978
|
-
: '(
|
|
967
|
+
? (config.rules.length > 60 ? config.rules.substring(0, 60) + '...' : config.rules)
|
|
968
|
+
: '(default)';
|
|
979
969
|
const output = `
|
|
980
970
|
Provider: ${config.aiProvider}
|
|
981
971
|
Model: ${config.model || '(default)'}
|
|
982
972
|
API Key: ${maskedKey}
|
|
983
973
|
Storage: ${config.storagePath}
|
|
984
|
-
Theme: ${themeName}
|
|
985
974
|
Rules: ${rulesPreview}
|
|
986
975
|
|
|
987
976
|
Set with flags:
|
|
988
|
-
config -
|
|
989
|
-
config -
|
|
990
|
-
config -
|
|
991
|
-
config -r="<rules>" Set custom rules
|
|
977
|
+
config -K=<key> or --key=<key>
|
|
978
|
+
config -M=<model> or --model=<model>
|
|
979
|
+
config -R="<rules>" or --rules="<rules>"
|
|
992
980
|
`.trim();
|
|
993
981
|
return wrapResult({ output });
|
|
994
982
|
}
|
|
@@ -1001,49 +989,50 @@ Navigation:
|
|
|
1001
989
|
ls List tasks and files
|
|
1002
990
|
tree [-A] [--depth=N] Show task tree
|
|
1003
991
|
cd <task> Navigate into task
|
|
1004
|
-
|
|
1005
|
-
pwd
|
|
1006
|
-
open Open
|
|
992
|
+
.., ... Go up 1 or 2 levels
|
|
993
|
+
pwd Current path
|
|
994
|
+
open Open in Finder
|
|
1007
995
|
|
|
1008
|
-
|
|
1009
|
-
mkdir <name> Create
|
|
1010
|
-
done Complete
|
|
996
|
+
Tasks:
|
|
997
|
+
mkdir <name> Create task
|
|
998
|
+
done Complete (earns XP)
|
|
1011
999
|
undo Undo last done
|
|
1012
|
-
|
|
1013
|
-
boss Toggle boss
|
|
1014
|
-
block [node] Block by task
|
|
1000
|
+
dl <date> Set deadline (dl +3d, dl Jan 15)
|
|
1001
|
+
boss Toggle boss (3x XP)
|
|
1002
|
+
block [node] Block by task
|
|
1015
1003
|
unblock Remove block
|
|
1016
1004
|
status Task details
|
|
1017
|
-
check
|
|
1005
|
+
check Deadline alerts
|
|
1018
1006
|
|
|
1019
1007
|
Gamification:
|
|
1020
1008
|
stats XP, level, streaks
|
|
1021
1009
|
achievements Achievement list
|
|
1022
|
-
map
|
|
1010
|
+
map Dungeon map
|
|
1011
|
+
map --ai AI-generated map
|
|
1023
1012
|
|
|
1024
|
-
|
|
1013
|
+
Rules (AI style presets):
|
|
1014
|
+
Set via init or config -R="<rules>"
|
|
1015
|
+
Presets: fantasy, space, starwars, western, cyberpunk, pirate
|
|
1016
|
+
|
|
1017
|
+
Config:
|
|
1025
1018
|
init Setup wizard
|
|
1026
1019
|
config Show settings
|
|
1027
|
-
config -
|
|
1028
|
-
config -
|
|
1029
|
-
config -
|
|
1030
|
-
config -r="<rules>" Custom AI rules
|
|
1031
|
-
|
|
1032
|
-
Themes:
|
|
1033
|
-
default, fantasy, space, starwars, western, cyberpunk, pirate
|
|
1020
|
+
config -K=<key> or --key=<key>
|
|
1021
|
+
config -M=<model> or --model=<model>
|
|
1022
|
+
config -R="<rules>" or --rules="<rules>"
|
|
1034
1023
|
|
|
1035
|
-
|
|
1036
|
-
cp, mv, rm [-rf] Standard
|
|
1037
|
-
clean --yes Clear
|
|
1024
|
+
Files:
|
|
1025
|
+
cp, mv, rm [-rf] Standard operations
|
|
1026
|
+
clean --yes Clear folder
|
|
1038
1027
|
|
|
1039
|
-
AI
|
|
1040
|
-
<description>
|
|
1041
|
-
save Save to folders
|
|
1028
|
+
AI:
|
|
1029
|
+
<description> Generate preview
|
|
1030
|
+
save Save to folders
|
|
1042
1031
|
cancel Discard
|
|
1043
1032
|
|
|
1044
1033
|
Clipboard:
|
|
1045
|
-
<cmd> | pbcopy
|
|
1046
|
-
<cmd> | clip
|
|
1034
|
+
<cmd> | pbcopy macOS
|
|
1035
|
+
<cmd> | clip Windows
|
|
1047
1036
|
|
|
1048
1037
|
www.rlc.rocks
|
|
1049
1038
|
`.trim()
|
|
@@ -19,16 +19,17 @@ const ASCII_ART = [
|
|
|
19
19
|
'║ Roguelike CLI ║',
|
|
20
20
|
'╚═════════════════════════╝',
|
|
21
21
|
'',
|
|
22
|
-
' Tasks: done, undo,
|
|
23
|
-
' Stats: stats, achievements, map
|
|
24
|
-
' Config: init, config -t=<theme>',
|
|
22
|
+
' Tasks: done, undo, dl <date>, boss, block',
|
|
23
|
+
' Stats: stats, achievements, map --ai',
|
|
25
24
|
'',
|
|
26
|
-
'
|
|
25
|
+
' Rules: fantasy, space, starwars, cyberpunk',
|
|
26
|
+
' Config: init, config -R="<rules>"',
|
|
27
27
|
'',
|
|
28
28
|
' TAB autocomplete, | pbcopy to copy',
|
|
29
29
|
' <description> -> refine -> save',
|
|
30
30
|
'',
|
|
31
|
-
' help - commands
|
|
31
|
+
' help - commands',
|
|
32
|
+
' www.rlc.rocks',
|
|
32
33
|
'',
|
|
33
34
|
' Ready...',
|
|
34
35
|
'',
|
package/package.json
CHANGED
package/src/commands/init.ts
CHANGED
|
@@ -110,15 +110,15 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
|
|
|
110
110
|
const apiKey = apiKeyInput.trim() || existingApiKey;
|
|
111
111
|
|
|
112
112
|
if (!apiKey) {
|
|
113
|
-
console.log('Warning: API key not set. You can set it later with: config -
|
|
113
|
+
console.log('Warning: API key not set. You can set it later with: config -K=<key>');
|
|
114
114
|
} else if (apiKeyInput.trim()) {
|
|
115
115
|
console.log('API key saved');
|
|
116
116
|
} else {
|
|
117
117
|
console.log('Using existing API key');
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
// 4.
|
|
121
|
-
console.log('\nSelect AI
|
|
120
|
+
// 4. Rules preset selection
|
|
121
|
+
console.log('\nSelect AI Rules (affects language style):');
|
|
122
122
|
const presetKeys = Object.keys(RULES_PRESETS);
|
|
123
123
|
presetKeys.forEach((key, index) => {
|
|
124
124
|
console.log(` ${index + 1}. ${RULES_PRESETS[key].name}`);
|
|
@@ -177,7 +177,7 @@ export async function initCommand(existingRl?: readline.Interface): Promise<void
|
|
|
177
177
|
console.log(`Root directory: ${rootDir}`);
|
|
178
178
|
console.log(`AI Provider: ${selectedProvider.name}`);
|
|
179
179
|
console.log(`Model: ${selectedProvider.model}`);
|
|
180
|
-
console.log(`
|
|
180
|
+
console.log(`Rules: ${RULES_PRESETS[selectedPreset]?.name || 'Custom'}\n`);
|
|
181
181
|
} finally {
|
|
182
182
|
if (shouldCloseRl) {
|
|
183
183
|
rl.close();
|
package/src/config/config.ts
CHANGED
|
@@ -13,7 +13,18 @@ export interface Config {
|
|
|
13
13
|
rulesPreset?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
//
|
|
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
|
|
17
28
|
export const RULES_PRESETS: Record<string, { name: string; rules: string }> = {
|
|
18
29
|
default: {
|
|
19
30
|
name: 'Default (No theme)',
|
|
@@ -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
|
|
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,22 +1107,29 @@ export async function processCommand(
|
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
1109
|
if (command === 'config') {
|
|
1110
|
-
const { updateConfig,
|
|
1110
|
+
const { updateConfig, SUPPORTED_MODELS } = await import('../config/config');
|
|
1111
1111
|
|
|
1112
|
-
// Check for flags
|
|
1113
|
-
const keyFlag = parts.find(p => p.startsWith('-
|
|
1114
|
-
const modelFlag = parts.find(p => p.startsWith('-
|
|
1115
|
-
const rulesFlag = parts.find(p => p.startsWith('-
|
|
1116
|
-
const themeFlag = parts.find(p => p.startsWith('-t=') || p.startsWith('--theme='));
|
|
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='));
|
|
1117
1116
|
|
|
1118
1117
|
if (keyFlag) {
|
|
1119
1118
|
const value = keyFlag.split('=').slice(1).join('=');
|
|
1119
|
+
if (!value) {
|
|
1120
|
+
return wrapResult({ output: 'Error: API key cannot be empty' });
|
|
1121
|
+
}
|
|
1120
1122
|
updateConfig({ apiKey: value });
|
|
1121
1123
|
return wrapResult({ output: 'API key updated.' });
|
|
1122
1124
|
}
|
|
1123
1125
|
|
|
1124
1126
|
if (modelFlag) {
|
|
1125
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
|
+
}
|
|
1126
1133
|
updateConfig({ model: value });
|
|
1127
1134
|
return wrapResult({ output: `Model updated: ${value}` });
|
|
1128
1135
|
}
|
|
@@ -1130,21 +1137,7 @@ export async function processCommand(
|
|
|
1130
1137
|
if (rulesFlag) {
|
|
1131
1138
|
const value = rulesFlag.split('=').slice(1).join('=');
|
|
1132
1139
|
updateConfig({ rules: value, rulesPreset: 'custom' });
|
|
1133
|
-
return wrapResult({ output: '
|
|
1134
|
-
}
|
|
1135
|
-
|
|
1136
|
-
if (themeFlag) {
|
|
1137
|
-
const value = themeFlag.split('=').slice(1).join('=').toLowerCase();
|
|
1138
|
-
if (RULES_PRESETS[value]) {
|
|
1139
|
-
updateConfig({
|
|
1140
|
-
rules: RULES_PRESETS[value].rules,
|
|
1141
|
-
rulesPreset: value
|
|
1142
|
-
});
|
|
1143
|
-
return wrapResult({ output: `Theme updated: ${RULES_PRESETS[value].name}` });
|
|
1144
|
-
} else {
|
|
1145
|
-
const themes = Object.keys(RULES_PRESETS).join(', ');
|
|
1146
|
-
return wrapResult({ output: `Unknown theme. Available: ${themes}` });
|
|
1147
|
-
}
|
|
1140
|
+
return wrapResult({ output: 'Rules updated.' });
|
|
1148
1141
|
}
|
|
1149
1142
|
|
|
1150
1143
|
// Show config
|
|
@@ -1152,27 +1145,21 @@ export async function processCommand(
|
|
|
1152
1145
|
? config.apiKey.slice(0, 8) + '...' + config.apiKey.slice(-4)
|
|
1153
1146
|
: '(not set)';
|
|
1154
1147
|
|
|
1155
|
-
const themeName = config.rulesPreset
|
|
1156
|
-
? (RULES_PRESETS[config.rulesPreset]?.name || 'Custom')
|
|
1157
|
-
: 'Default';
|
|
1158
|
-
|
|
1159
1148
|
const rulesPreview = config.rules
|
|
1160
|
-
? (config.rules.length >
|
|
1161
|
-
: '(
|
|
1149
|
+
? (config.rules.length > 60 ? config.rules.substring(0, 60) + '...' : config.rules)
|
|
1150
|
+
: '(default)';
|
|
1162
1151
|
|
|
1163
1152
|
const output = `
|
|
1164
1153
|
Provider: ${config.aiProvider}
|
|
1165
1154
|
Model: ${config.model || '(default)'}
|
|
1166
1155
|
API Key: ${maskedKey}
|
|
1167
1156
|
Storage: ${config.storagePath}
|
|
1168
|
-
Theme: ${themeName}
|
|
1169
1157
|
Rules: ${rulesPreview}
|
|
1170
1158
|
|
|
1171
1159
|
Set with flags:
|
|
1172
|
-
config -
|
|
1173
|
-
config -
|
|
1174
|
-
config -
|
|
1175
|
-
config -r="<rules>" Set custom rules
|
|
1160
|
+
config -K=<key> or --key=<key>
|
|
1161
|
+
config -M=<model> or --model=<model>
|
|
1162
|
+
config -R="<rules>" or --rules="<rules>"
|
|
1176
1163
|
`.trim();
|
|
1177
1164
|
|
|
1178
1165
|
return wrapResult({ output });
|
|
@@ -1187,49 +1174,50 @@ Navigation:
|
|
|
1187
1174
|
ls List tasks and files
|
|
1188
1175
|
tree [-A] [--depth=N] Show task tree
|
|
1189
1176
|
cd <task> Navigate into task
|
|
1190
|
-
|
|
1191
|
-
pwd
|
|
1192
|
-
open Open
|
|
1177
|
+
.., ... Go up 1 or 2 levels
|
|
1178
|
+
pwd Current path
|
|
1179
|
+
open Open in Finder
|
|
1193
1180
|
|
|
1194
|
-
|
|
1195
|
-
mkdir <name> Create
|
|
1196
|
-
done Complete
|
|
1181
|
+
Tasks:
|
|
1182
|
+
mkdir <name> Create task
|
|
1183
|
+
done Complete (earns XP)
|
|
1197
1184
|
undo Undo last done
|
|
1198
|
-
|
|
1199
|
-
boss Toggle boss
|
|
1200
|
-
block [node] Block by task
|
|
1185
|
+
dl <date> Set deadline (dl +3d, dl Jan 15)
|
|
1186
|
+
boss Toggle boss (3x XP)
|
|
1187
|
+
block [node] Block by task
|
|
1201
1188
|
unblock Remove block
|
|
1202
1189
|
status Task details
|
|
1203
|
-
check
|
|
1190
|
+
check Deadline alerts
|
|
1204
1191
|
|
|
1205
1192
|
Gamification:
|
|
1206
1193
|
stats XP, level, streaks
|
|
1207
1194
|
achievements Achievement list
|
|
1208
|
-
map
|
|
1195
|
+
map Dungeon map
|
|
1196
|
+
map --ai AI-generated map
|
|
1209
1197
|
|
|
1210
|
-
|
|
1198
|
+
Rules (AI style presets):
|
|
1199
|
+
Set via init or config -R="<rules>"
|
|
1200
|
+
Presets: fantasy, space, starwars, western, cyberpunk, pirate
|
|
1201
|
+
|
|
1202
|
+
Config:
|
|
1211
1203
|
init Setup wizard
|
|
1212
1204
|
config Show settings
|
|
1213
|
-
config -
|
|
1214
|
-
config -
|
|
1215
|
-
config -
|
|
1216
|
-
config -r="<rules>" Custom AI rules
|
|
1217
|
-
|
|
1218
|
-
Themes:
|
|
1219
|
-
default, fantasy, space, starwars, western, cyberpunk, pirate
|
|
1205
|
+
config -K=<key> or --key=<key>
|
|
1206
|
+
config -M=<model> or --model=<model>
|
|
1207
|
+
config -R="<rules>" or --rules="<rules>"
|
|
1220
1208
|
|
|
1221
|
-
|
|
1222
|
-
cp, mv, rm [-rf] Standard
|
|
1223
|
-
clean --yes Clear
|
|
1209
|
+
Files:
|
|
1210
|
+
cp, mv, rm [-rf] Standard operations
|
|
1211
|
+
clean --yes Clear folder
|
|
1224
1212
|
|
|
1225
|
-
AI
|
|
1226
|
-
<description>
|
|
1227
|
-
save Save to folders
|
|
1213
|
+
AI:
|
|
1214
|
+
<description> Generate preview
|
|
1215
|
+
save Save to folders
|
|
1228
1216
|
cancel Discard
|
|
1229
1217
|
|
|
1230
1218
|
Clipboard:
|
|
1231
|
-
<cmd> | pbcopy
|
|
1232
|
-
<cmd> | clip
|
|
1219
|
+
<cmd> | pbcopy macOS
|
|
1220
|
+
<cmd> | clip Windows
|
|
1233
1221
|
|
|
1234
1222
|
www.rlc.rocks
|
|
1235
1223
|
`.trim()
|
|
@@ -17,16 +17,17 @@ const ASCII_ART = [
|
|
|
17
17
|
'║ Roguelike CLI ║',
|
|
18
18
|
'╚═════════════════════════╝',
|
|
19
19
|
'',
|
|
20
|
-
' Tasks: done, undo,
|
|
21
|
-
' Stats: stats, achievements, map
|
|
22
|
-
' Config: init, config -t=<theme>',
|
|
20
|
+
' Tasks: done, undo, dl <date>, boss, block',
|
|
21
|
+
' Stats: stats, achievements, map --ai',
|
|
23
22
|
'',
|
|
24
|
-
'
|
|
23
|
+
' Rules: fantasy, space, starwars, cyberpunk',
|
|
24
|
+
' Config: init, config -R="<rules>"',
|
|
25
25
|
'',
|
|
26
26
|
' TAB autocomplete, | pbcopy to copy',
|
|
27
27
|
' <description> -> refine -> save',
|
|
28
28
|
'',
|
|
29
|
-
' help - commands
|
|
29
|
+
' help - commands',
|
|
30
|
+
' www.rlc.rocks',
|
|
30
31
|
'',
|
|
31
32
|
' Ready...',
|
|
32
33
|
'',
|