@gravirei/reis 2.3.3 ā 2.4.0
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/CHANGELOG.md +75 -0
- package/bin/reis.js +58 -17
- package/lib/commands/checkpoint.js +4 -0
- package/lib/commands/cycle.js +3 -0
- package/lib/commands/debug.js +88 -25
- package/lib/commands/execute-plan.js +4 -0
- package/lib/commands/execute.js +149 -7
- package/lib/commands/help.js +25 -6
- package/lib/commands/kanban.js +105 -0
- package/lib/commands/plan.js +4 -1
- package/lib/commands/progress.js +4 -1
- package/lib/commands/resume.js +4 -1
- package/lib/commands/verify.js +112 -23
- package/lib/utils/config.js +6 -0
- package/lib/utils/cycle-orchestrator.js +151 -29
- package/lib/utils/cycle-state-manager.js +68 -1
- package/lib/utils/kanban-renderer.js +674 -0
- package/lib/utils/subagent-invoker.js +813 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,81 @@ All notable changes to REIS will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.4.0] - 2026-01-22
|
|
9
|
+
|
|
10
|
+
### Added - Kanban Board & Real Execution š
|
|
11
|
+
|
|
12
|
+
**Major Feature: Persistent Kanban Board**
|
|
13
|
+
|
|
14
|
+
A visual kanban board that displays automatically on workflow commands showing real-time cycle progress.
|
|
15
|
+
|
|
16
|
+
#### Kanban Board Features
|
|
17
|
+
|
|
18
|
+
- **Persistent Display** - Shows automatically on workflow commands (plan, execute, verify, debug, cycle, progress, resume, checkpoint)
|
|
19
|
+
- **4-Column Layout**:
|
|
20
|
+
- ALL PHASES - Shows all project phases (P1 P2 P3 P4...)
|
|
21
|
+
- IN PROGRESS - Current phase with wave/task breakdown
|
|
22
|
+
- CYCLE - Planning ā Execute ā Verify ā Debug stages with progress bars
|
|
23
|
+
- COMPLETED - List of completed cycles
|
|
24
|
+
- **Wave Execution Visualization**:
|
|
25
|
+
- Wave list with tree structure (Wave 1/3 ā, Wave 2/3 ā, Wave 3/3 ā)
|
|
26
|
+
- Task status under current wave (ā 2.1 ā, ā 2.4 ā)
|
|
27
|
+
- Parallel execution indicator (ā«“2 of 4 tasks)
|
|
28
|
+
- Running/Waiting task breakdown
|
|
29
|
+
- **Subagent Status** - Shows active subagent (planner, executor, verifier, debugger)
|
|
30
|
+
- **Centered Progress Bars** - `[ā ā ā ā ā 45% āāāāā]` format
|
|
31
|
+
- **3 Display Styles**: full, compact, minimal
|
|
32
|
+
- **Idle States**:
|
|
33
|
+
- "No active phase" + "Run: reis cycle" prompt
|
|
34
|
+
- "No cycles completed" for fresh projects
|
|
35
|
+
- "ā All phases done!" when complete
|
|
36
|
+
|
|
37
|
+
#### Kanban Command
|
|
38
|
+
|
|
39
|
+
- `reis kanban` - Show current settings
|
|
40
|
+
- `reis kanban enable/disable/toggle` - Control display
|
|
41
|
+
- `reis kanban style <full|compact|minimal>` - Change display style
|
|
42
|
+
- `--no-kanban` flag to hide for single command
|
|
43
|
+
|
|
44
|
+
**Major Feature: Real Subagent Execution (Priority 1)**
|
|
45
|
+
|
|
46
|
+
Transformed REIS from a "prompt printer" to an actual "execution system".
|
|
47
|
+
|
|
48
|
+
#### Subagent Invocation API
|
|
49
|
+
|
|
50
|
+
- **New Module** (`lib/utils/subagent-invoker.js`) - Core API for programmatic subagent invocation
|
|
51
|
+
- Classes: `SubagentDefinition`, `ExecutionContext`, `InvocationResult`, `SubagentInvoker`
|
|
52
|
+
- Functions: `loadSubagentDefinition()`, `listSubagents()`, `buildExecutionContext()`, `invoke()`, `invokeParallel()`
|
|
53
|
+
- Event-based execution with progress tracking
|
|
54
|
+
- Timeout and error handling
|
|
55
|
+
|
|
56
|
+
#### Cycle Orchestrator Completion
|
|
57
|
+
|
|
58
|
+
- Implemented 5 TODOs that were previously stubbed:
|
|
59
|
+
- Actually execute plans via `invokeSubagent('reis_executor', ...)`
|
|
60
|
+
- Actually run verification via `invokeSubagent('reis_verifier', ...)`
|
|
61
|
+
- Actually run debug analysis via `invokeSubagent('reis_debugger', ...)`
|
|
62
|
+
- Actually execute fix plans
|
|
63
|
+
- Append completion records to STATE.md
|
|
64
|
+
|
|
65
|
+
#### Command Updates
|
|
66
|
+
|
|
67
|
+
- `reis execute <phase>` - Now invokes reis_executor subagent (with `--dry-run` fallback)
|
|
68
|
+
- `reis verify` - Now invokes reis_verifier subagent
|
|
69
|
+
- `reis debug` - Now invokes reis_debugger subagent
|
|
70
|
+
- New options: `--dry-run`, `--verbose`, `--timeout <ms>`
|
|
71
|
+
|
|
72
|
+
### Fixed
|
|
73
|
+
|
|
74
|
+
- `reis whats-new` - Was showing "Command coming soon", now properly wired to implementation
|
|
75
|
+
- `reis docs` - Was showing "Command coming soon", now properly wired to implementation
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- Help modal updated with new command options and compact format
|
|
80
|
+
- Added hidden commands to help: `reis add`, `reis insert`, `reis remove`
|
|
81
|
+
- Updated column widths in kanban board for better readability
|
|
82
|
+
|
|
8
83
|
## [2.3.0] - 2026-01-22
|
|
9
84
|
|
|
10
85
|
### Added - Decision Trees Support š³
|
package/bin/reis.js
CHANGED
|
@@ -78,6 +78,7 @@ const configCmd = require('../lib/commands/config.js');
|
|
|
78
78
|
const cycleCmd = require('../lib/commands/cycle.js');
|
|
79
79
|
const decisionsCmd = require('../lib/commands/decisions.js');
|
|
80
80
|
const treeCmd = require('../lib/commands/tree.js');
|
|
81
|
+
const kanbanCmd = require('../lib/commands/kanban.js');
|
|
81
82
|
|
|
82
83
|
// Check for --help or -h flag before Commander parses
|
|
83
84
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
@@ -95,6 +96,9 @@ program
|
|
|
95
96
|
.description('REIS - Roadmap Execution & Implementation System')
|
|
96
97
|
.usage('<command> [options]');
|
|
97
98
|
|
|
99
|
+
// Global option for kanban
|
|
100
|
+
program.option('--no-kanban', 'Hide kanban board for this command');
|
|
101
|
+
|
|
98
102
|
// Getting Started Commands
|
|
99
103
|
program
|
|
100
104
|
.command('help')
|
|
@@ -130,7 +134,10 @@ program
|
|
|
130
134
|
program
|
|
131
135
|
.command('plan [phase]')
|
|
132
136
|
.description('Create detailed plan for a phase')
|
|
133
|
-
.action((phase) =>
|
|
137
|
+
.action((phase, options, command) => {
|
|
138
|
+
const globalOpts = command.parent?.opts() || {};
|
|
139
|
+
planCmd({ phase }, { noKanban: globalOpts.kanban === false });
|
|
140
|
+
});
|
|
134
141
|
|
|
135
142
|
program
|
|
136
143
|
.command('discuss [phase]')
|
|
@@ -150,7 +157,15 @@ program
|
|
|
150
157
|
program
|
|
151
158
|
.command('execute [phase]')
|
|
152
159
|
.description('Execute a phase')
|
|
153
|
-
.
|
|
160
|
+
.option('--dry-run', 'Show prompt without executing')
|
|
161
|
+
.option('-v, --verbose', 'Show detailed output')
|
|
162
|
+
.option('--no-commit', 'Skip auto-commit')
|
|
163
|
+
.option('--timeout <ms>', 'Execution timeout in milliseconds')
|
|
164
|
+
.action(async (phase, options, command) => {
|
|
165
|
+
const globalOpts = command.parent?.opts() || {};
|
|
166
|
+
const exitCode = await executeCmd({ phase }, { ...options, noKanban: globalOpts.kanban === false });
|
|
167
|
+
process.exit(exitCode);
|
|
168
|
+
});
|
|
154
169
|
|
|
155
170
|
program
|
|
156
171
|
.command('execute-plan <path>')
|
|
@@ -158,29 +173,37 @@ program
|
|
|
158
173
|
.option('--wave', 'Enable wave-based execution (v2.0 feature)')
|
|
159
174
|
.option('--dry-run', 'Show plan structure without executing')
|
|
160
175
|
.option('--interactive', 'Step-by-step execution with prompts between waves')
|
|
161
|
-
.action(async (
|
|
176
|
+
.action(async (planPath, options, command) => {
|
|
177
|
+
const globalOpts = command.parent?.opts() || {};
|
|
162
178
|
await executePlanCmd({
|
|
163
|
-
path,
|
|
179
|
+
path: planPath,
|
|
164
180
|
wave: options.wave,
|
|
165
181
|
dryRun: options.dryRun,
|
|
166
|
-
interactive: options.interactive
|
|
182
|
+
interactive: options.interactive,
|
|
183
|
+
noKanban: globalOpts.kanban === false
|
|
167
184
|
});
|
|
168
185
|
});
|
|
169
186
|
|
|
170
187
|
program
|
|
171
188
|
.command('verify <target>')
|
|
172
189
|
.description('Verify execution results against success criteria (uses reis_verifier subagent)')
|
|
190
|
+
.option('--dry-run', 'Show prompt without executing')
|
|
173
191
|
.option('-v, --verbose', 'Show detailed verification output')
|
|
174
192
|
.option('-s, --strict', 'Fail on warnings')
|
|
175
|
-
.
|
|
176
|
-
|
|
193
|
+
.option('--timeout <ms>', 'Verification timeout in milliseconds')
|
|
194
|
+
.action(async (target, options, command) => {
|
|
195
|
+
const globalOpts = command.parent?.opts() || {};
|
|
196
|
+
await verifyCmd(target, { ...options, noKanban: globalOpts.kanban === false });
|
|
177
197
|
});
|
|
178
198
|
|
|
179
199
|
// Progress Commands
|
|
180
200
|
program
|
|
181
201
|
.command('progress')
|
|
182
202
|
.description('Show current project progress')
|
|
183
|
-
.action(() =>
|
|
203
|
+
.action((options, command) => {
|
|
204
|
+
const globalOpts = command.parent?.opts() || {};
|
|
205
|
+
progressCmd({}, { noKanban: globalOpts.kanban === false });
|
|
206
|
+
});
|
|
184
207
|
|
|
185
208
|
program
|
|
186
209
|
.command('pause')
|
|
@@ -190,7 +213,10 @@ program
|
|
|
190
213
|
program
|
|
191
214
|
.command('resume')
|
|
192
215
|
.description('Resume paused work')
|
|
193
|
-
.action(() =>
|
|
216
|
+
.action((options, command) => {
|
|
217
|
+
const globalOpts = command.parent?.opts() || {};
|
|
218
|
+
resumeCmd({}, { noKanban: globalOpts.kanban === false });
|
|
219
|
+
});
|
|
194
220
|
|
|
195
221
|
// Checkpoint Management Commands
|
|
196
222
|
program
|
|
@@ -199,8 +225,9 @@ program
|
|
|
199
225
|
.option('-c, --commit', 'Force git commit')
|
|
200
226
|
.option('--no-commit', 'Skip git commit')
|
|
201
227
|
.option('-m, --message <message>', 'Custom commit message')
|
|
202
|
-
.action((subcommand, name, options) => {
|
|
203
|
-
|
|
228
|
+
.action((subcommand, name, options, command) => {
|
|
229
|
+
const globalOpts = command.parent?.opts() || {};
|
|
230
|
+
checkpointCmd({ subcommand, name, ...options, noKanban: globalOpts.kanban === false });
|
|
204
231
|
});
|
|
205
232
|
|
|
206
233
|
// Roadmap Management Commands
|
|
@@ -241,11 +268,14 @@ program
|
|
|
241
268
|
program
|
|
242
269
|
.command('debug [target]')
|
|
243
270
|
.description('Analyze failures and generate fix plans (uses reis_debugger subagent)')
|
|
271
|
+
.option('--dry-run', 'Show prompt without executing')
|
|
244
272
|
.option('-i, --input <path>', 'Path to DEBUG_INPUT.md or plan file')
|
|
245
273
|
.option('-f, --focus <area>', 'Focus analysis on specific area')
|
|
246
274
|
.option('-v, --verbose', 'Show detailed debug output')
|
|
247
|
-
.
|
|
248
|
-
|
|
275
|
+
.option('--timeout <ms>', 'Debug timeout in milliseconds')
|
|
276
|
+
.action(async (target, options, command) => {
|
|
277
|
+
const globalOpts = command.parent?.opts() || {};
|
|
278
|
+
await debugCmd(target, { ...options, noKanban: globalOpts.kanban === false });
|
|
249
279
|
});
|
|
250
280
|
|
|
251
281
|
program
|
|
@@ -256,8 +286,9 @@ program
|
|
|
256
286
|
.option('--resume', 'Resume interrupted cycle')
|
|
257
287
|
.option('--continue-on-fail', 'Continue even if verification fails')
|
|
258
288
|
.option('-v, --verbose', 'Detailed output')
|
|
259
|
-
.action(async (phaseOrPlan, options) => {
|
|
260
|
-
|
|
289
|
+
.action(async (phaseOrPlan, options, command) => {
|
|
290
|
+
const globalOpts = command.parent?.opts() || {};
|
|
291
|
+
await cycleCmd(phaseOrPlan, { ...options, noKanban: globalOpts.kanban === false });
|
|
261
292
|
});
|
|
262
293
|
|
|
263
294
|
program
|
|
@@ -310,7 +341,17 @@ program
|
|
|
310
341
|
await treeCmd(subcommand, args, options);
|
|
311
342
|
});
|
|
312
343
|
|
|
344
|
+
program
|
|
345
|
+
.command('kanban [subcommand] [value]')
|
|
346
|
+
.description('Manage kanban board settings')
|
|
347
|
+
.action((subcommand, value) => {
|
|
348
|
+
const args = [subcommand, value].filter(Boolean);
|
|
349
|
+
kanbanCmd(args, {});
|
|
350
|
+
});
|
|
351
|
+
|
|
313
352
|
const updateCmd = require('../lib/commands/update.js');
|
|
353
|
+
const whatsNewCmd = require('../lib/commands/whats-new.js');
|
|
354
|
+
const docsCmd = require('../lib/commands/docs.js');
|
|
314
355
|
|
|
315
356
|
program
|
|
316
357
|
.command('update')
|
|
@@ -323,14 +364,14 @@ program
|
|
|
323
364
|
.command('whats-new')
|
|
324
365
|
.description('Show what\'s new in latest version')
|
|
325
366
|
.action(() => {
|
|
326
|
-
|
|
367
|
+
whatsNewCmd({});
|
|
327
368
|
});
|
|
328
369
|
|
|
329
370
|
program
|
|
330
371
|
.command('docs')
|
|
331
372
|
.description('Open REIS documentation')
|
|
332
373
|
.action(() => {
|
|
333
|
-
|
|
374
|
+
docsCmd({});
|
|
334
375
|
});
|
|
335
376
|
|
|
336
377
|
program
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
const StateManager = require('../utils/state-manager');
|
|
7
7
|
const GitIntegration = require('../utils/git-integration');
|
|
8
8
|
const { loadConfig } = require('../utils/config');
|
|
9
|
+
const { showKanbanBoard } = require('../utils/kanban-renderer');
|
|
9
10
|
const fs = require('fs');
|
|
10
11
|
const path = require('path');
|
|
11
12
|
|
|
@@ -301,6 +302,9 @@ async function deleteCheckpoint(name, options = {}) {
|
|
|
301
302
|
* Main checkpoint command handler
|
|
302
303
|
*/
|
|
303
304
|
async function checkpoint(options = {}) {
|
|
305
|
+
// Show kanban board (unless disabled)
|
|
306
|
+
showKanbanBoard({ noKanban: options?.noKanban });
|
|
307
|
+
|
|
304
308
|
const subcommand = options.subcommand || 'list';
|
|
305
309
|
const name = options.name;
|
|
306
310
|
|
package/lib/commands/cycle.js
CHANGED
|
@@ -2,6 +2,7 @@ const chalk = require('chalk');
|
|
|
2
2
|
const { runCycle } = require('../utils/cycle-orchestrator');
|
|
3
3
|
const stateManager = require('../utils/cycle-state-manager');
|
|
4
4
|
const { showError, checkPlanningDir } = require('../utils/command-helpers');
|
|
5
|
+
const { showKanbanBoard } = require('../utils/kanban-renderer');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Cycle Command
|
|
@@ -14,6 +15,8 @@ const { showError, checkPlanningDir } = require('../utils/command-helpers');
|
|
|
14
15
|
* @param {Object} options - Command options
|
|
15
16
|
*/
|
|
16
17
|
async function cycle(phaseOrPlan, options = {}) {
|
|
18
|
+
// Show kanban board (unless disabled)
|
|
19
|
+
showKanbanBoard({ noKanban: options?.noKanban });
|
|
17
20
|
try {
|
|
18
21
|
// Show welcome banner
|
|
19
22
|
showBanner(phaseOrPlan, options);
|
package/lib/commands/debug.js
CHANGED
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const { showError, showSuccess, showInfo, checkPlanningDir } = require('../utils/command-helpers.js');
|
|
5
|
+
const { showKanbanBoard } = require('../utils/kanban-renderer');
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Debug command - Analyze verification failures and generate fix plans
|
|
@@ -9,6 +10,8 @@ const { showError, showSuccess, showInfo, checkPlanningDir } = require('../utils
|
|
|
9
10
|
* @param {Object} options - Command options
|
|
10
11
|
*/
|
|
11
12
|
async function debugCommand(target, options = {}) {
|
|
13
|
+
// Show kanban board (unless disabled)
|
|
14
|
+
showKanbanBoard({ noKanban: options?.noKanban });
|
|
12
15
|
console.log(chalk.blue('\nš REIS Debugger\n'));
|
|
13
16
|
|
|
14
17
|
// Validate REIS project
|
|
@@ -58,6 +61,13 @@ async function debugCommand(target, options = {}) {
|
|
|
58
61
|
process.exit(1);
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
// Handle dry-run case
|
|
65
|
+
if (result.dryRun) {
|
|
66
|
+
console.log(chalk.yellow('\nā ļø Dry run complete - no actual debugging performed'));
|
|
67
|
+
console.log(chalk.gray('Run without --dry-run to perform actual analysis'));
|
|
68
|
+
process.exit(0);
|
|
69
|
+
}
|
|
70
|
+
|
|
61
71
|
// 7. Display results
|
|
62
72
|
console.log(chalk.green('\nā
Analysis complete!\n'));
|
|
63
73
|
|
|
@@ -215,39 +225,92 @@ function buildDebuggerPrompt(debugInput, context, issueType, options) {
|
|
|
215
225
|
|
|
216
226
|
/**
|
|
217
227
|
* Invoke debugger subagent via Rovo Dev
|
|
228
|
+
* @param {string} prompt - Debug prompt
|
|
229
|
+
* @param {object} options - Command options
|
|
230
|
+
* @returns {Promise<object>} Debug results
|
|
218
231
|
*/
|
|
219
232
|
async function invokeDebugger(prompt, options) {
|
|
220
|
-
// TODO: Integrate with Rovo Dev API or CLI
|
|
221
|
-
// For now, output the prompt that would be sent to the subagent
|
|
222
|
-
|
|
223
|
-
console.log(chalk.yellow('ā ļø Note: Subagent invocation pending Rovo Dev integration'));
|
|
224
|
-
console.log(chalk.gray('The debugger prompt has been generated and would be sent to reis_debugger.'));
|
|
225
|
-
console.log();
|
|
226
|
-
console.log(chalk.cyan('Prompt Preview:'));
|
|
227
|
-
console.log(chalk.gray('ā'.repeat(80)));
|
|
228
|
-
console.log(prompt.substring(0, 500) + '...');
|
|
229
|
-
console.log(chalk.gray('ā'.repeat(80)));
|
|
230
|
-
console.log();
|
|
231
|
-
|
|
232
|
-
// Create debug output directory
|
|
233
233
|
const debugDir = path.join(process.cwd(), '.planning', 'debug');
|
|
234
|
+
|
|
235
|
+
// Ensure debug directory exists
|
|
234
236
|
if (!fs.existsSync(debugDir)) {
|
|
235
237
|
fs.mkdirSync(debugDir, { recursive: true });
|
|
236
238
|
}
|
|
237
|
-
|
|
238
|
-
// Save prompt for manual invocation
|
|
239
|
-
const promptPath = path.join(debugDir, 'DEBUGGER_PROMPT.txt');
|
|
240
|
-
fs.writeFileSync(promptPath, prompt, 'utf-8');
|
|
241
|
-
console.log(chalk.gray(`Prompt saved to: ${promptPath}`));
|
|
242
|
-
console.log();
|
|
243
239
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
240
|
+
// Dry run mode - show prompt only
|
|
241
|
+
if (options.dryRun) {
|
|
242
|
+
console.log(chalk.yellow('--dry-run mode: Showing prompt that would be sent\n'));
|
|
243
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
244
|
+
console.log(prompt.substring(0, 2000) + '...');
|
|
245
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
246
|
+
|
|
247
|
+
// Save prompt for reference
|
|
248
|
+
const promptPath = path.join(debugDir, 'DEBUGGER_PROMPT.txt');
|
|
249
|
+
fs.writeFileSync(promptPath, prompt, 'utf-8');
|
|
250
|
+
console.log(chalk.gray(`\nPrompt saved to: ${promptPath}`));
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
success: true,
|
|
254
|
+
dryRun: true,
|
|
255
|
+
outputs: {
|
|
256
|
+
report: path.join(debugDir, 'DEBUG_REPORT.md'),
|
|
257
|
+
fixPlan: path.join(debugDir, 'FIX_PLAN.md')
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Real execution mode
|
|
263
|
+
const { invokeSubagent, SubagentInvoker } = require('../utils/subagent-invoker');
|
|
264
|
+
|
|
265
|
+
const invoker = new SubagentInvoker({ verbose: options.verbose });
|
|
266
|
+
|
|
267
|
+
invoker.on('progress', (data) => {
|
|
268
|
+
console.log(chalk.gray(` ${data.message}`));
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
invoker.on('artifact', (data) => {
|
|
272
|
+
console.log(chalk.green(` ā Generated: ${data.path}`));
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
try {
|
|
276
|
+
const result = await invokeSubagent('reis_debugger', {
|
|
277
|
+
verbose: options.verbose,
|
|
278
|
+
timeout: options.timeout || 300000,
|
|
279
|
+
additionalContext: {
|
|
280
|
+
debugPrompt: prompt,
|
|
281
|
+
focusArea: options.focus || null
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// Determine output paths
|
|
286
|
+
let reportPath = path.join(debugDir, 'DEBUG_REPORT.md');
|
|
287
|
+
let fixPlanPath = path.join(debugDir, 'FIX_PLAN.md');
|
|
288
|
+
|
|
289
|
+
if (result.metadata) {
|
|
290
|
+
reportPath = result.metadata.reportPath || reportPath;
|
|
291
|
+
fixPlanPath = result.metadata.fixPlanPath || fixPlanPath;
|
|
249
292
|
}
|
|
250
|
-
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
success: result.success,
|
|
296
|
+
outputs: {
|
|
297
|
+
report: reportPath,
|
|
298
|
+
fixPlan: fixPlanPath
|
|
299
|
+
},
|
|
300
|
+
output: result.output,
|
|
301
|
+
error: result.error
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
} catch (error) {
|
|
305
|
+
return {
|
|
306
|
+
success: false,
|
|
307
|
+
error: error,
|
|
308
|
+
outputs: {
|
|
309
|
+
report: path.join(debugDir, 'DEBUG_REPORT.md'),
|
|
310
|
+
fixPlan: path.join(debugDir, 'FIX_PLAN.md')
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
}
|
|
251
314
|
}
|
|
252
315
|
|
|
253
316
|
/**
|
|
@@ -7,6 +7,7 @@ const { loadConfig } = require('../utils/config');
|
|
|
7
7
|
const { getGitStatus, commitWaveCompletion } = require('../utils/git-integration');
|
|
8
8
|
const { parseDecisionTrees } = require('../utils/decision-tree-parser');
|
|
9
9
|
const { renderDecisionTree } = require('../utils/visualizer');
|
|
10
|
+
const { showKanbanBoard } = require('../utils/kanban-renderer');
|
|
10
11
|
const chalk = require('chalk');
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -16,9 +17,12 @@ const chalk = require('chalk');
|
|
|
16
17
|
* @param {boolean} args.wave - Enable wave-based execution
|
|
17
18
|
* @param {boolean} args.dryRun - Show plan without executing
|
|
18
19
|
* @param {boolean} args.interactive - Step-by-step execution with prompts
|
|
20
|
+
* @param {boolean} args.noKanban - Hide kanban board
|
|
19
21
|
* @returns {Promise<number>} Exit code
|
|
20
22
|
*/
|
|
21
23
|
async function executePlan(args) {
|
|
24
|
+
// Show kanban board (unless disabled)
|
|
25
|
+
showKanbanBoard({ noKanban: args?.noKanban });
|
|
22
26
|
// Check if .planning/ exists
|
|
23
27
|
if (!checkPlanningDir()) {
|
|
24
28
|
showError('Not a REIS project. Run "reis new" or "reis map" first.');
|
package/lib/commands/execute.js
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
|
-
const
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const chalk = require('chalk');
|
|
4
|
+
const { showError, checkPlanningDir, validatePhaseNumber } = require('../utils/command-helpers');
|
|
5
|
+
const { invokeSubagent, SubagentInvoker, buildExecutionContext } = require('../utils/subagent-invoker');
|
|
6
|
+
const { showKanbanBoard } = require('../utils/kanban-renderer');
|
|
2
7
|
|
|
3
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Execute command - Runs reis_executor subagent
|
|
10
|
+
* @param {Object} args - Command arguments
|
|
11
|
+
* @param {Object} options - Command options
|
|
12
|
+
*/
|
|
13
|
+
async function execute(args, options = {}) {
|
|
14
|
+
// Show kanban board (unless disabled)
|
|
15
|
+
showKanbanBoard({ noKanban: options?.noKanban });
|
|
4
16
|
// Check if .planning/ exists
|
|
5
17
|
if (!checkPlanningDir()) {
|
|
6
18
|
showError('Not a REIS project. Run "reis new" or "reis map" first.');
|
|
@@ -14,15 +26,145 @@ module.exports = function execute(args) {
|
|
|
14
26
|
process.exit(1);
|
|
15
27
|
}
|
|
16
28
|
|
|
17
|
-
// Validate phase is a valid positive number
|
|
18
29
|
const validatedPhase = validatePhaseNumber(phase);
|
|
19
30
|
if (validatedPhase === null) {
|
|
20
31
|
process.exit(1);
|
|
21
32
|
}
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
// Find plan file(s) for this phase
|
|
35
|
+
const planPath = findPlanPath(validatedPhase);
|
|
36
|
+
if (!planPath) {
|
|
37
|
+
showError(`No plan found for phase ${validatedPhase}. Run "reis plan ${validatedPhase}" first.`);
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
console.log(chalk.blue(`\nāļø REIS Executor - Phase ${validatedPhase}\n`));
|
|
42
|
+
console.log(chalk.gray(`Plan: ${planPath}`));
|
|
43
|
+
|
|
44
|
+
// Dry run mode - just show what would happen
|
|
45
|
+
if (options.dryRun) {
|
|
46
|
+
console.log(chalk.yellow('\n--dry-run mode: Showing prompt that would be sent\n'));
|
|
47
|
+
const ctx = buildExecutionContext('reis_executor', { planPath });
|
|
48
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
49
|
+
console.log(ctx.buildPrompt().substring(0, 2000) + '...');
|
|
50
|
+
console.log(chalk.gray('ā'.repeat(60)));
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Real execution mode
|
|
55
|
+
console.log(chalk.blue('\nš Starting execution...\n'));
|
|
24
56
|
|
|
25
|
-
|
|
57
|
+
const invoker = new SubagentInvoker({ verbose: options.verbose });
|
|
26
58
|
|
|
27
|
-
|
|
28
|
-
|
|
59
|
+
// Set up progress display
|
|
60
|
+
invoker.on('start', () => {
|
|
61
|
+
console.log(chalk.gray(' Initializing executor...'));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
invoker.on('progress', (data) => {
|
|
65
|
+
console.log(chalk.gray(` ${data.message}`));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
invoker.on('artifact', (data) => {
|
|
69
|
+
console.log(chalk.green(` ā Created: ${data.path}`));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const result = await invokeSubagent('reis_executor', {
|
|
74
|
+
planPath,
|
|
75
|
+
verbose: options.verbose,
|
|
76
|
+
timeout: options.timeout || 600000,
|
|
77
|
+
additionalContext: {
|
|
78
|
+
phase: validatedPhase,
|
|
79
|
+
autoCommit: options.commit !== false
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if (result.success) {
|
|
84
|
+
console.log(chalk.green('\nā
Execution complete!\n'));
|
|
85
|
+
|
|
86
|
+
if (result.metadata?.artifacts?.length > 0) {
|
|
87
|
+
console.log(chalk.cyan('Artifacts created:'));
|
|
88
|
+
result.metadata.artifacts.forEach(a => {
|
|
89
|
+
console.log(chalk.gray(` - ${a}`));
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(chalk.blue('\nNext step: ') + chalk.cyan(`reis verify ${validatedPhase}`));
|
|
94
|
+
return 0;
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.red('\nā Execution failed\n'));
|
|
97
|
+
if (result.error) {
|
|
98
|
+
console.log(chalk.red(`Error: ${result.error.message}`));
|
|
99
|
+
}
|
|
100
|
+
console.log(chalk.yellow('\nTry: reis debug to analyze the failure'));
|
|
101
|
+
return 1;
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(chalk.red(`\nā Execution error: ${error.message}`));
|
|
105
|
+
if (options.verbose) {
|
|
106
|
+
console.error(error.stack);
|
|
107
|
+
}
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Find plan file for a phase
|
|
114
|
+
*/
|
|
115
|
+
function findPlanPath(phase) {
|
|
116
|
+
const planningDir = path.join(process.cwd(), '.planning');
|
|
117
|
+
|
|
118
|
+
// Try phase-N.PLAN.md
|
|
119
|
+
const directPath = path.join(planningDir, `phase-${phase}.PLAN.md`);
|
|
120
|
+
if (fs.existsSync(directPath)) {
|
|
121
|
+
return directPath;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Try phases/N-*/PLAN.md
|
|
125
|
+
const phasesDir = path.join(planningDir, 'phases');
|
|
126
|
+
if (fs.existsSync(phasesDir)) {
|
|
127
|
+
const dirs = fs.readdirSync(phasesDir).filter(d => d.startsWith(`${phase}-`));
|
|
128
|
+
if (dirs.length > 0) {
|
|
129
|
+
const phaseDir = path.join(phasesDir, dirs[0]);
|
|
130
|
+
const plans = fs.readdirSync(phaseDir).filter(f => f.endsWith('.PLAN.md'));
|
|
131
|
+
if (plans.length > 0) {
|
|
132
|
+
return path.join(phaseDir, plans[0]);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Try N-*/PLAN.md directly in .planning
|
|
138
|
+
const dirs = fs.readdirSync(planningDir).filter(d => d.startsWith(`${phase}-`));
|
|
139
|
+
if (dirs.length > 0) {
|
|
140
|
+
const phaseDir = path.join(planningDir, dirs[0]);
|
|
141
|
+
if (fs.statSync(phaseDir).isDirectory()) {
|
|
142
|
+
const plans = fs.readdirSync(phaseDir).filter(f => f.endsWith('.PLAN.md'));
|
|
143
|
+
if (plans.length > 0) {
|
|
144
|
+
return path.join(phaseDir, plans[0]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Try priority-*/phase-N-* pattern (for priority folders)
|
|
150
|
+
const priorityDirs = fs.readdirSync(planningDir).filter(d => d.startsWith('priority-'));
|
|
151
|
+
for (const priorityDir of priorityDirs) {
|
|
152
|
+
const priorityPath = path.join(planningDir, priorityDir);
|
|
153
|
+
if (fs.statSync(priorityPath).isDirectory()) {
|
|
154
|
+
const phaseDirs = fs.readdirSync(priorityPath).filter(d =>
|
|
155
|
+
d.startsWith(`phase-${phase}-`) || d.startsWith(`${phase}-`)
|
|
156
|
+
);
|
|
157
|
+
if (phaseDirs.length > 0) {
|
|
158
|
+
const phaseDir = path.join(priorityPath, phaseDirs[0]);
|
|
159
|
+
const plans = fs.readdirSync(phaseDir).filter(f => f.endsWith('.PLAN.md'));
|
|
160
|
+
if (plans.length > 0) {
|
|
161
|
+
return path.join(phaseDir, plans[0]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
module.exports = execute;
|