@kjerneverk/riotplan 1.0.8 → 1.0.9-dev.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/BUG-FIX-STEP-ADD-DIRECTORY.md +76 -0
- package/MCP-ERROR-HANDLING-FIX.md +62 -0
- package/README.md +32 -3
- package/dist/bin.js +1 -1
- package/dist/{cli-BNnX3BBS.js → cli-gjREHy7E.js} +42 -6
- package/dist/cli-gjREHy7E.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +2 -2
- package/dist/mcp/prompts/shape_approach.md +17 -4
- package/dist/mcp-server.js +1523 -1083
- package/package.json +2 -2
- package/scripts/build-mcp.js +1 -0
- package/dist/cli-BNnX3BBS.js.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Bug Fix: riotplan_step_add Creates Files in Wrong Directory
|
|
2
|
+
|
|
3
|
+
## Issue
|
|
4
|
+
`riotplan_step_add` was creating step files directly in the plan root directory instead of in the `plan/` subdirectory when the `plan/` subdirectory didn't exist.
|
|
5
|
+
|
|
6
|
+
## Root Cause
|
|
7
|
+
The `getPlanDir()` helper function in `src/steps/operations.ts` would fall back to the plan root directory if the `plan/` subdirectory didn't exist, rather than creating it.
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
// OLD BEHAVIOR (BUGGY)
|
|
11
|
+
async function getPlanDir(planPath: string): Promise<string> {
|
|
12
|
+
const standardDir = join(planPath, PLAN_CONVENTIONS.standardDirs.plan);
|
|
13
|
+
try {
|
|
14
|
+
await readdir(standardDir);
|
|
15
|
+
return standardDir;
|
|
16
|
+
} catch {
|
|
17
|
+
return planPath; // ❌ Falls back to root instead of creating plan/
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Solution
|
|
23
|
+
Modified `getPlanDir()` to create the `plan/` subdirectory if it doesn't exist:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// NEW BEHAVIOR (FIXED)
|
|
27
|
+
async function getPlanDir(planPath: string): Promise<string> {
|
|
28
|
+
const standardDir = join(planPath, PLAN_CONVENTIONS.standardDirs.plan);
|
|
29
|
+
try {
|
|
30
|
+
await readdir(standardDir);
|
|
31
|
+
return standardDir;
|
|
32
|
+
} catch {
|
|
33
|
+
// Create plan/ subdirectory if it doesn't exist
|
|
34
|
+
await mkdir(standardDir, { recursive: true });
|
|
35
|
+
return standardDir; // ✅ Always returns plan/ subdirectory
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Files Changed
|
|
41
|
+
1. **src/steps/operations.ts**
|
|
42
|
+
- Added `mkdir` to imports from `node:fs/promises`
|
|
43
|
+
- Modified `getPlanDir()` to create `plan/` subdirectory if missing
|
|
44
|
+
- Updated function documentation
|
|
45
|
+
|
|
46
|
+
2. **tests/step-operations.test.ts**
|
|
47
|
+
- Added new test suite: "plan/ subdirectory creation"
|
|
48
|
+
- Test 1: Verifies `plan/` is created when it doesn't exist
|
|
49
|
+
- Test 2: Verifies existing `plan/` is used correctly
|
|
50
|
+
|
|
51
|
+
## Test Results
|
|
52
|
+
- All 666 tests pass (4 skipped)
|
|
53
|
+
- Coverage for `operations.ts`: 98.6% (improved from 97.2%)
|
|
54
|
+
- Overall coverage: 92.61% statements, 80.07% branches, 92.77% functions, 93.6% lines
|
|
55
|
+
|
|
56
|
+
## Impact
|
|
57
|
+
- ✅ New plans now have consistent structure
|
|
58
|
+
- ✅ Step files are always created in `plan/` subdirectory
|
|
59
|
+
- ✅ Matches existing plan conventions across the repository
|
|
60
|
+
- ✅ No breaking changes - existing plans continue to work
|
|
61
|
+
- ✅ Backward compatible - handles both scenarios correctly
|
|
62
|
+
|
|
63
|
+
## Verification
|
|
64
|
+
The fix was verified with:
|
|
65
|
+
1. Existing test suite (40 original tests)
|
|
66
|
+
2. New regression tests (2 additional tests)
|
|
67
|
+
3. Manual verification of plan structure consistency
|
|
68
|
+
|
|
69
|
+
## Related Files
|
|
70
|
+
All existing plans in the repository use the `plan/` subdirectory pattern:
|
|
71
|
+
- `mcp-integration/env-var-config-implementation/plan/`
|
|
72
|
+
- `done/config-discovery-locations/plan/`
|
|
73
|
+
- `done/config-format-support/plan/`
|
|
74
|
+
- `future/server-runtime-support/plan/`
|
|
75
|
+
|
|
76
|
+
This fix ensures all new plans follow the same convention.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# MCP Server Stdout Pollution Fix
|
|
2
|
+
|
|
3
|
+
## Issue
|
|
4
|
+
|
|
5
|
+
The RiotPlan MCP server was crashing with the error:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Unexpected token 'C', "Config fil"... is not valid JSON
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This was caused by stdout pollution corrupting the MCP JSON-RPC protocol stream.
|
|
12
|
+
|
|
13
|
+
## Root Cause
|
|
14
|
+
|
|
15
|
+
MCP uses stdio (stdin/stdout) for JSON-RPC communication. Any output to stdout - even from dependencies like CardiganTime - corrupts the protocol stream, causing the client to receive invalid JSON.
|
|
16
|
+
|
|
17
|
+
The error message `"Config fil"...` was actually the beginning of a log message like "Config file not found..." that was being written to stdout and mixing with the JSON-RPC messages.
|
|
18
|
+
|
|
19
|
+
## Solution
|
|
20
|
+
|
|
21
|
+
### Stdout Suppression
|
|
22
|
+
|
|
23
|
+
Redirected all stdout to stderr in MCP mode to prevent pollution of the JSON-RPC stream:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Suppress stdout to prevent pollution of MCP JSON-RPC stream
|
|
27
|
+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
28
|
+
process.stdout.write = (chunk: any, encoding?: any, callback?: any): boolean => {
|
|
29
|
+
// Redirect to stderr instead
|
|
30
|
+
return process.stderr.write(chunk, encoding, callback);
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This ensures:
|
|
35
|
+
- MCP JSON-RPC protocol remains clean on stdout
|
|
36
|
+
- All logs (from RiotPlan and dependencies) go to stderr
|
|
37
|
+
- No corruption of the protocol stream
|
|
38
|
+
|
|
39
|
+
### Enhanced Error Handling
|
|
40
|
+
|
|
41
|
+
Also improved error messages throughout:
|
|
42
|
+
|
|
43
|
+
1. **Better Config Error Messages** (`src/config/loader.ts`)
|
|
44
|
+
- Specific error handling for JSON parsing errors
|
|
45
|
+
- Specific error handling for validation errors
|
|
46
|
+
- Helpful troubleshooting tips
|
|
47
|
+
- Full error context
|
|
48
|
+
|
|
49
|
+
2. **Improved Server Error Handling** (`src/mcp/server.ts`)
|
|
50
|
+
- Centralized error logging with timestamps
|
|
51
|
+
- Try-catch wrapper around tool execution
|
|
52
|
+
- Global process error handlers
|
|
53
|
+
- Full stack traces in error responses
|
|
54
|
+
|
|
55
|
+
## Files Changed
|
|
56
|
+
|
|
57
|
+
- `src/mcp/server.ts` - Stdout suppression and error handling
|
|
58
|
+
- `src/config/loader.ts` - Enhanced error messages
|
|
59
|
+
|
|
60
|
+
## Testing
|
|
61
|
+
|
|
62
|
+
All 666 tests pass. The MCP server now properly isolates stdout for the JSON-RPC protocol.
|
package/README.md
CHANGED
|
@@ -434,16 +434,45 @@ Add to your Cursor MCP settings (`~/.cursor/mcp.json`):
|
|
|
434
434
|
|
|
435
435
|
**Zero-Config Experience:** If you don't set `RIOTPLAN_PLAN_DIRECTORY`, RiotPlan will automatically find your `plans/` directory by walking up from your workspace root. No configuration needed!
|
|
436
436
|
|
|
437
|
+
The MCP server includes enhanced error handling and logging for better reliability and debugging.
|
|
438
|
+
|
|
437
439
|
### MCP Tools
|
|
438
440
|
|
|
439
|
-
|
|
441
|
+
**Lifecycle Management:**
|
|
442
|
+
- **`riotplan_idea_create`** - Start exploring an idea (Idea stage)
|
|
443
|
+
- **`riotplan_shaping_start`** - Begin shaping approaches (Shaping stage)
|
|
444
|
+
- **`riotplan_build`** - Build plan from idea/shaping with AI generation (→ Built stage)
|
|
445
|
+
- **`riotplan_transition`** - Move between lifecycle stages manually
|
|
446
|
+
|
|
447
|
+
**Plan Management:**
|
|
448
|
+
- **`riotplan_create`** - Create new plan directory with AI-generated steps
|
|
440
449
|
- **`riotplan_status`** - Show plan status and progress
|
|
450
|
+
- **`riotplan_validate`** - Validate plan structure
|
|
451
|
+
- **`riotplan_generate`** - Generate plan content with AI
|
|
452
|
+
|
|
453
|
+
**Step Management:**
|
|
441
454
|
- **`riotplan_step_list`** - List all steps
|
|
442
455
|
- **`riotplan_step_start`** - Mark step as started
|
|
443
456
|
- **`riotplan_step_complete`** - Mark step as completed
|
|
444
457
|
- **`riotplan_step_add`** - Add new steps dynamically
|
|
445
|
-
|
|
446
|
-
|
|
458
|
+
|
|
459
|
+
**Idea Stage:**
|
|
460
|
+
- **`riotplan_idea_add_note`** - Add notes during exploration
|
|
461
|
+
- **`riotplan_idea_add_constraint`** - Document constraints
|
|
462
|
+
- **`riotplan_idea_add_question`** - Raise questions
|
|
463
|
+
- **`riotplan_idea_add_evidence`** - Attach supporting materials
|
|
464
|
+
- **`riotplan_idea_kill`** - Abandon idea with reason
|
|
465
|
+
|
|
466
|
+
**Shaping Stage:**
|
|
467
|
+
- **`riotplan_shaping_add_approach`** - Propose solution approaches
|
|
468
|
+
- **`riotplan_shaping_add_feedback`** - Add feedback on approaches
|
|
469
|
+
- **`riotplan_shaping_compare`** - Compare all approaches
|
|
470
|
+
- **`riotplan_shaping_select`** - Select best approach
|
|
471
|
+
|
|
472
|
+
**History & Checkpoints:**
|
|
473
|
+
- **`riotplan_checkpoint_create`** - Save state snapshots
|
|
474
|
+
- **`riotplan_checkpoint_restore`** - Restore previous state
|
|
475
|
+
- **`riotplan_history_show`** - View timeline of events
|
|
447
476
|
|
|
448
477
|
### MCP Resources
|
|
449
478
|
|
package/dist/bin.js
CHANGED
|
@@ -2352,7 +2352,8 @@ async function getPlanDir(planPath) {
|
|
|
2352
2352
|
await readdir(standardDir);
|
|
2353
2353
|
return standardDir;
|
|
2354
2354
|
} catch {
|
|
2355
|
-
|
|
2355
|
+
await mkdir(standardDir, { recursive: true });
|
|
2356
|
+
return standardDir;
|
|
2356
2357
|
}
|
|
2357
2358
|
}
|
|
2358
2359
|
function generateStepFilename(number, code) {
|
|
@@ -4400,10 +4401,12 @@ async function loadProvider(config) {
|
|
|
4400
4401
|
throw new Error(`Unknown provider: ${name}`);
|
|
4401
4402
|
}
|
|
4402
4403
|
} catch (error) {
|
|
4403
|
-
if (error instanceof Error && error.message.includes("Cannot find package")) {
|
|
4404
|
+
if (error instanceof Error && (error.message.includes("Cannot find package") || error.message.includes("Cannot find module"))) {
|
|
4404
4405
|
throw new Error(
|
|
4405
4406
|
`Provider '${name}' is not installed. Install it with:
|
|
4406
|
-
npm install @kjerneverk/execution-${name}
|
|
4407
|
+
npm install @kjerneverk/execution-${name}
|
|
4408
|
+
|
|
4409
|
+
Note: If you're using RiotPlan via MCP (e.g., in Cursor), consider using manual step creation with riotplan_step_add instead of riotplan_generate to avoid needing separate AI providers.`
|
|
4407
4410
|
);
|
|
4408
4411
|
}
|
|
4409
4412
|
throw error;
|
|
@@ -6185,8 +6188,11 @@ const RiotPlanConfigSchema = z.object({
|
|
|
6185
6188
|
const cardigantime = create({
|
|
6186
6189
|
defaults: {
|
|
6187
6190
|
configDirectory: process.cwd(),
|
|
6188
|
-
isRequired: false
|
|
6191
|
+
isRequired: false,
|
|
6189
6192
|
// Config file is optional
|
|
6193
|
+
pathResolution: {
|
|
6194
|
+
pathFields: ["planDirectory", "templateDirectory"]
|
|
6195
|
+
}
|
|
6190
6196
|
},
|
|
6191
6197
|
configShape: RiotPlanConfigSchema.shape,
|
|
6192
6198
|
features: ["config"]
|
|
@@ -6212,7 +6218,37 @@ async function loadConfig() {
|
|
|
6212
6218
|
if (error instanceof Error && error.message.includes("not found")) {
|
|
6213
6219
|
return null;
|
|
6214
6220
|
}
|
|
6215
|
-
|
|
6221
|
+
if (error instanceof Error) {
|
|
6222
|
+
if (error.message.includes("JSON") || error.message.includes("parse")) {
|
|
6223
|
+
throw new Error(
|
|
6224
|
+
`Failed to parse RiotPlan configuration file: ${error.message}
|
|
6225
|
+
|
|
6226
|
+
Please check that your config file (riotplan.config.* or .riotplan/config.*) contains valid JSON/YAML/JS.
|
|
6227
|
+
Common issues:
|
|
6228
|
+
- Missing quotes around strings
|
|
6229
|
+
- Trailing commas in JSON
|
|
6230
|
+
- Invalid YAML indentation
|
|
6231
|
+
|
|
6232
|
+
Original error: ${error.message}`
|
|
6233
|
+
);
|
|
6234
|
+
}
|
|
6235
|
+
if (error.message.includes("validation") || error.message.includes("schema")) {
|
|
6236
|
+
throw new Error(
|
|
6237
|
+
`RiotPlan configuration validation failed: ${error.message}
|
|
6238
|
+
|
|
6239
|
+
Valid configuration options:
|
|
6240
|
+
- planDirectory: string (path to plans directory)
|
|
6241
|
+
- defaultProvider: 'anthropic' | 'openai' | 'gemini'
|
|
6242
|
+
- defaultModel: string
|
|
6243
|
+
- templateDirectory: string (path to custom templates)
|
|
6244
|
+
|
|
6245
|
+
Original error: ${error.message}`
|
|
6246
|
+
);
|
|
6247
|
+
}
|
|
6248
|
+
}
|
|
6249
|
+
throw new Error(
|
|
6250
|
+
`Failed to load RiotPlan configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
6251
|
+
);
|
|
6216
6252
|
}
|
|
6217
6253
|
}
|
|
6218
6254
|
const walkUpCache = /* @__PURE__ */ new Map();
|
|
@@ -6561,4 +6597,4 @@ export {
|
|
|
6561
6597
|
getFeedback as y,
|
|
6562
6598
|
getReadySteps as z
|
|
6563
6599
|
};
|
|
6564
|
-
//# sourceMappingURL=cli-
|
|
6600
|
+
//# sourceMappingURL=cli-gjREHy7E.js.map
|