@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.
@@ -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
- - **`riotplan_create`** - Create new plans with AI-generated steps
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
- - **`riotplan_validate`** - Validate plan structure
446
- - **`riotplan_generate`** - Generate plan content with AI
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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { q as createProgram } from "./cli-BNnX3BBS.js";
2
+ import { q as createProgram } from "./cli-gjREHy7E.js";
3
3
  const program = createProgram();
4
4
  program.parse();
5
5
  //# sourceMappingURL=bin.js.map
@@ -2352,7 +2352,8 @@ async function getPlanDir(planPath) {
2352
2352
  await readdir(standardDir);
2353
2353
  return standardDir;
2354
2354
  } catch {
2355
- return planPath;
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
- throw error;
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-BNnX3BBS.js.map
6600
+ //# sourceMappingURL=cli-gjREHy7E.js.map