@infinitedusky/indusk-mcp 1.22.0 → 1.23.1

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.
@@ -66,6 +66,8 @@ export function runEvaluatorBackground(opts) {
66
66
  "opus",
67
67
  "--permission-mode",
68
68
  "acceptEdits",
69
+ "--mcp-config",
70
+ ".mcp.json",
69
71
  "--allowed-tools",
70
72
  allowedTools.join(","),
71
73
  ];
@@ -188,6 +190,8 @@ async function runEvaluatorSyncInner(opts, projectGroup) {
188
190
  "opus",
189
191
  "--permission-mode",
190
192
  "acceptEdits",
193
+ "--mcp-config",
194
+ ".mcp.json",
191
195
  "--allowed-tools",
192
196
  allowedTools.join(","),
193
197
  ];
@@ -160,6 +160,10 @@ Output ONLY the JSON scorecard as before — no commentary.`;
160
160
  "json",
161
161
  "--resume",
162
162
  session.sessionId,
163
+ "--mcp-config",
164
+ ".mcp.json",
165
+ "--permission-mode",
166
+ "acceptEdits",
163
167
  "--allowed-tools",
164
168
  ALLOWED_TOOLS.join(","),
165
169
  ],
@@ -175,6 +179,8 @@ Output ONLY the JSON scorecard as before — no commentary.`;
175
179
  "opus",
176
180
  "--permission-mode",
177
181
  "acceptEdits",
182
+ "--mcp-config",
183
+ ".mcp.json",
178
184
  "--allowed-tools",
179
185
  ALLOWED_TOOLS.join(","),
180
186
  ],
@@ -1,10 +1,20 @@
1
1
  import { type Trajectory } from "./parser.js";
2
2
  export interface ValidationError {
3
- rule: "trajectory-presence" | "cross-reference-integrity" | "temporal-coherence" | "deferred-completeness";
3
+ rule: "trajectory-presence" | "cross-reference-integrity" | "temporal-coherence" | "deferred-completeness" | "rationale-completeness";
4
4
  message: string;
5
5
  /** The rough line number in the impl body, if known. */
6
6
  line?: number;
7
7
  }
8
+ export interface ValidateTrajectoryOptions {
9
+ /**
10
+ * When true, also enforce `### Trajectory Rationale` completeness — every
11
+ * trajectory T-ID must appear as a `- **TN**` entry in the subsection,
12
+ * and the subsection must not contain entries for IDs missing from the
13
+ * trajectory table. Mirrors the JS hook's `rationale: required` frontmatter
14
+ * check at apps/indusk-mcp/hooks/validate-impl-structure.js.
15
+ */
16
+ rationaleRequired?: boolean;
17
+ }
8
18
  /**
9
19
  * Rule 1: Every impl document must have a `## Test Trajectory` section.
10
20
  */
@@ -28,9 +38,30 @@ export declare function validateTemporalCoherence(trajectory: Trajectory): Valid
28
38
  */
29
39
  export declare function validateDeferredCompleteness(trajectory: Trajectory): ValidationError[];
30
40
  /**
31
- * Run all four trajectory validation rules against an impl body. The body
32
- * is the markdown content after the frontmatter pass the output of
33
- * `gray-matter` or equivalent. Returns combined errors; empty array means
34
- * the trajectory is valid.
41
+ * Rule 5: When the impl frontmatter sets `rationale: required`, every
42
+ * trajectory row whose `Writable at` is later than Phase 0 (the pre-plan
43
+ * baseline) must have an entry in the `### Trajectory Rationale` subsection.
44
+ *
45
+ * Phase 0 rows do NOT need a rationale — Phase 0 means "writable today
46
+ * against the current stack, before any plan implementation," which is
47
+ * the default and needs no justification. We only require rationale when
48
+ * a test will be authored after some plan code lands (Writable at: Phase 1+).
49
+ *
50
+ * If no row needs a rationale (every row is Phase 0), the subsection itself
51
+ * is optional. If any row is Phase 1+, the subsection must exist and contain
52
+ * an entry for every Phase 1+ row. Stale entries (entries for IDs not in the
53
+ * trajectory) are always flagged.
54
+ *
55
+ * Mirrors `validateRationaleCompleteness` in
56
+ * `.claude/hooks/validate-impl-structure.js`.
57
+ */
58
+ export declare function validateRationaleCompleteness(body: string, trajectory: Trajectory): ValidationError[];
59
+ /**
60
+ * Run all trajectory validation rules against an impl body. The body is the
61
+ * markdown content after the frontmatter — pass the output of `gray-matter`
62
+ * or equivalent. Returns combined errors; empty array means the trajectory
63
+ * is valid. Pass `{ rationaleRequired: true }` to additionally enforce
64
+ * `### Trajectory Rationale` completeness (mirrors the JS hook's check on
65
+ * `rationale: required` in frontmatter).
35
66
  */
36
- export declare function validateTrajectory(body: string): ValidationError[];
67
+ export declare function validateTrajectory(body: string, options?: ValidateTrajectoryOptions): ValidationError[];
@@ -184,19 +184,101 @@ export function validateDeferredCompleteness(trajectory) {
184
184
  return errors;
185
185
  }
186
186
  /**
187
- * Run all four trajectory validation rules against an impl body. The body
188
- * is the markdown content after the frontmatter pass the output of
189
- * `gray-matter` or equivalent. Returns combined errors; empty array means
190
- * the trajectory is valid.
187
+ * Rule 5: When the impl frontmatter sets `rationale: required`, every
188
+ * trajectory row whose `Writable at` is later than Phase 0 (the pre-plan
189
+ * baseline) must have an entry in the `### Trajectory Rationale` subsection.
190
+ *
191
+ * Phase 0 rows do NOT need a rationale — Phase 0 means "writable today
192
+ * against the current stack, before any plan implementation," which is
193
+ * the default and needs no justification. We only require rationale when
194
+ * a test will be authored after some plan code lands (Writable at: Phase 1+).
195
+ *
196
+ * If no row needs a rationale (every row is Phase 0), the subsection itself
197
+ * is optional. If any row is Phase 1+, the subsection must exist and contain
198
+ * an entry for every Phase 1+ row. Stale entries (entries for IDs not in the
199
+ * trajectory) are always flagged.
200
+ *
201
+ * Mirrors `validateRationaleCompleteness` in
202
+ * `.claude/hooks/validate-impl-structure.js`.
191
203
  */
192
- export function validateTrajectory(body) {
204
+ export function validateRationaleCompleteness(body, trajectory) {
205
+ const errors = [];
206
+ const rowsNeedingRationale = trajectory.rows.filter((r) => Number.isFinite(r.writableAt) && r.writableAt > 0);
207
+ const hasSubsection = /^###\s+Trajectory Rationale\b/m.test(body);
208
+ const rationaleIds = hasSubsection ? parseRationaleBlock(body) : new Set();
209
+ if (rowsNeedingRationale.length > 0 && !hasSubsection) {
210
+ errors.push({
211
+ rule: "rationale-completeness",
212
+ message: `\`rationale: required\` is set and ${rowsNeedingRationale.length} trajectory row(s) have \`Writable at\` later than Phase 0, but the impl is missing the \`### Trajectory Rationale\` subsection. Phase 0 rows don't need rationale; rows where authoring waits on plan code do — add an entry for ${rowsNeedingRationale.map((r) => r.id).join(", ")}.`,
213
+ });
214
+ // Even without the subsection, fall through to also check for stale entries
215
+ // (there are none in this case, but the structure is symmetric).
216
+ }
217
+ const missing = [];
218
+ for (const row of rowsNeedingRationale) {
219
+ if (!rationaleIds.has(row.id))
220
+ missing.push(row.id);
221
+ }
222
+ if (missing.length > 0 && hasSubsection) {
223
+ errors.push({
224
+ rule: "rationale-completeness",
225
+ message: `Trajectory rows with \`Writable at\` later than Phase 0 missing from \`### Trajectory Rationale\`: ${missing.join(", ")}. Every row whose authoring waits on plan code needs a \`- **TN** \`Writable at: Phase N\` — {reason}\` entry. Phase 0 rows (writable today against the current stack) do not need rationale.`,
226
+ });
227
+ }
228
+ const knownIds = new Set(trajectory.rows.map((r) => r.id));
229
+ const extra = [...rationaleIds].filter((id) => !knownIds.has(id));
230
+ if (extra.length > 0) {
231
+ errors.push({
232
+ rule: "rationale-completeness",
233
+ message: `\`### Trajectory Rationale\` contains entries for IDs not present in the trajectory table: ${extra.join(", ")}. Remove the stale entries or add the missing trajectory rows.`,
234
+ });
235
+ }
236
+ return errors;
237
+ }
238
+ /**
239
+ * Parse the `### Trajectory Rationale` subsection and return the set of
240
+ * T-IDs that appear as `- **TN**` entries. Stops at the next heading of
241
+ * depth 1-3.
242
+ */
243
+ function parseRationaleBlock(body) {
244
+ const lines = body.split("\n");
245
+ const ids = new Set();
246
+ let inRationale = false;
247
+ for (const line of lines) {
248
+ if (/^###\s+Trajectory Rationale\b/.test(line)) {
249
+ inRationale = true;
250
+ continue;
251
+ }
252
+ if (!inRationale)
253
+ continue;
254
+ if (/^#{1,3}\s+/.test(line) && !/^###\s+Trajectory Rationale\b/.test(line))
255
+ break;
256
+ const match = line.match(/^-\s+\*\*(T\d+)\*\*/);
257
+ if (match)
258
+ ids.add(match[1]);
259
+ }
260
+ return ids;
261
+ }
262
+ /**
263
+ * Run all trajectory validation rules against an impl body. The body is the
264
+ * markdown content after the frontmatter — pass the output of `gray-matter`
265
+ * or equivalent. Returns combined errors; empty array means the trajectory
266
+ * is valid. Pass `{ rationaleRequired: true }` to additionally enforce
267
+ * `### Trajectory Rationale` completeness (mirrors the JS hook's check on
268
+ * `rationale: required` in frontmatter).
269
+ */
270
+ export function validateTrajectory(body, options = {}) {
193
271
  const presenceErrors = validateTrajectoryPresence(body);
194
272
  if (presenceErrors.length > 0)
195
273
  return presenceErrors;
196
274
  const trajectory = parseTrajectory(body);
197
- return [
275
+ const errors = [
198
276
  ...validateCrossReferenceIntegrity(body, trajectory),
199
277
  ...validateTemporalCoherence(trajectory),
200
278
  ...validateDeferredCompleteness(trajectory),
201
279
  ];
280
+ if (options.rationaleRequired) {
281
+ errors.push(...validateRationaleCompleteness(body, trajectory));
282
+ }
283
+ return errors;
202
284
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infinitedusky/indusk-mcp",
3
- "version": "1.22.0",
3
+ "version": "1.23.1",
4
4
  "description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
5
5
  "type": "module",
6
6
  "files": [
@@ -24,7 +24,8 @@
24
24
  "dev": "tsx watch src/server/index.ts",
25
25
  "build": "tsc",
26
26
  "start": "node dist/server/index.js",
27
- "test": "vitest run"
27
+ "test": "vitest run",
28
+ "prepublishOnly": "pnpm build"
28
29
  },
29
30
  "dependencies": {
30
31
  "@modelcontextprotocol/sdk": "^1.12.1",