claude-code-pilot 3.2.0 → 3.3.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/README.md +14 -9
  3. package/bin/install.js +124 -16
  4. package/manifest.json +18 -3
  5. package/package.json +3 -2
  6. package/src/agents/django-build-resolver.md +252 -0
  7. package/src/agents/django-reviewer.md +169 -0
  8. package/src/agents/fastapi-reviewer.md +79 -0
  9. package/src/agents/fsharp-reviewer.md +109 -0
  10. package/src/agents/swift-build-resolver.md +170 -0
  11. package/src/agents/swift-reviewer.md +116 -0
  12. package/src/commands/ccp/cost-report.md +107 -0
  13. package/src/commands/ccp/intel.md +3 -3
  14. package/src/commands/ccp/mvp-phase.md +45 -0
  15. package/src/commands/ccp/plan-prd.md +160 -0
  16. package/src/commands/ccp/pr-ecc.md +184 -0
  17. package/src/commands/ccp/security-scan.md +74 -0
  18. package/src/hooks/ccp-bash-hook-dispatcher.js +96 -0
  19. package/src/hooks/ccp-context-monitor.js +23 -0
  20. package/src/hooks/ccp-doc-file-warning.js +93 -0
  21. package/src/hooks/ccp-pre-bash-dispatcher.js +24 -0
  22. package/src/hooks/ccp-write-gateguard.js +868 -0
  23. package/src/lib/project-detect.js +0 -2
  24. package/src/lib/shell-substitution.js +499 -0
  25. package/src/pilot/references/execute-mvp-tdd.md +81 -0
  26. package/src/pilot/references/mvp-concepts.md +49 -0
  27. package/src/pilot/references/planner-graphify-auto-update.md +67 -0
  28. package/src/pilot/references/planner-human-verify-mode.md +57 -0
  29. package/src/pilot/references/planner-mvp-mode.md +53 -0
  30. package/src/pilot/references/skeleton-template.md +48 -0
  31. package/src/pilot/references/spidr-splitting.md +69 -0
  32. package/src/pilot/references/user-story-template.md +58 -0
  33. package/src/pilot/references/verify-mvp-mode.md +85 -0
  34. package/src/pilot/references/worktree-path-safety.md +89 -0
  35. package/src/pilot/workflows/help.md +5 -0
  36. package/src/pilot/workflows/mvp-phase.md +199 -0
  37. package/src/skills/agent-architecture-audit/SKILL.md +256 -0
  38. package/src/skills/agent-harness-design/SKILL.md +73 -0
  39. package/src/skills/angular-developer/SKILL.md +154 -0
  40. package/src/skills/angular-developer/references/angular-animations.md +160 -0
  41. package/src/skills/angular-developer/references/angular-aria.md +410 -0
  42. package/src/skills/angular-developer/references/cli.md +86 -0
  43. package/src/skills/angular-developer/references/component-harnesses.md +59 -0
  44. package/src/skills/angular-developer/references/component-styling.md +91 -0
  45. package/src/skills/angular-developer/references/components.md +117 -0
  46. package/src/skills/angular-developer/references/creating-services.md +97 -0
  47. package/src/skills/angular-developer/references/data-resolvers.md +69 -0
  48. package/src/skills/angular-developer/references/define-routes.md +67 -0
  49. package/src/skills/angular-developer/references/defining-providers.md +72 -0
  50. package/src/skills/angular-developer/references/di-fundamentals.md +120 -0
  51. package/src/skills/angular-developer/references/e2e-testing.md +56 -0
  52. package/src/skills/angular-developer/references/effects.md +83 -0
  53. package/src/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  54. package/src/skills/angular-developer/references/host-elements.md +80 -0
  55. package/src/skills/angular-developer/references/injection-context.md +63 -0
  56. package/src/skills/angular-developer/references/inputs.md +101 -0
  57. package/src/skills/angular-developer/references/linked-signal.md +59 -0
  58. package/src/skills/angular-developer/references/loading-strategies.md +61 -0
  59. package/src/skills/angular-developer/references/mcp.md +108 -0
  60. package/src/skills/angular-developer/references/navigate-to-routes.md +69 -0
  61. package/src/skills/angular-developer/references/outputs.md +86 -0
  62. package/src/skills/angular-developer/references/reactive-forms.md +122 -0
  63. package/src/skills/angular-developer/references/rendering-strategies.md +44 -0
  64. package/src/skills/angular-developer/references/resource.md +77 -0
  65. package/src/skills/angular-developer/references/route-animations.md +56 -0
  66. package/src/skills/angular-developer/references/route-guards.md +52 -0
  67. package/src/skills/angular-developer/references/router-lifecycle.md +45 -0
  68. package/src/skills/angular-developer/references/router-testing.md +87 -0
  69. package/src/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  70. package/src/skills/angular-developer/references/signal-forms.md +795 -0
  71. package/src/skills/angular-developer/references/signals-overview.md +94 -0
  72. package/src/skills/angular-developer/references/tailwind-css.md +69 -0
  73. package/src/skills/angular-developer/references/template-driven-forms.md +114 -0
  74. package/src/skills/angular-developer/references/testing-fundamentals.md +65 -0
  75. package/src/skills/error-handling/SKILL.md +376 -0
  76. package/src/skills/fastapi-patterns/SKILL.md +327 -0
  77. package/src/skills/flox-environments/SKILL.md +496 -0
  78. package/src/skills/fsharp-testing/SKILL.md +280 -0
  79. package/src/skills/ios-icon-gen/SKILL.md +157 -0
  80. package/src/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
  81. package/src/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
  82. package/src/skills/make-interfaces-feel-better/SKILL.md +151 -0
  83. package/src/skills/mysql-patterns/SKILL.md +412 -0
  84. package/src/skills/plan-orchestrate/SKILL.md +220 -0
  85. package/src/skills/prisma-patterns/SKILL.md +371 -0
  86. package/src/skills/production-audit/SKILL.md +206 -0
  87. package/src/skills/security-scan/references/agentshield-policy-exception/candidate-playbook.md +49 -0
  88. package/src/skills/security-scan/references/agentshield-policy-exception/report.json +35 -0
  89. package/src/skills/security-scan/references/agentshield-policy-exception/scenario.json +62 -0
  90. package/src/skills/security-scan/references/agentshield-policy-exception/trace.json +45 -0
  91. package/src/skills/security-scan/references/agentshield-policy-exception/verifier-result.json +35 -0
  92. package/src/skills/vite-patterns/SKILL.md +449 -0
  93. package/src/skills/windows-desktop-e2e/SKILL.md +887 -0
@@ -3,8 +3,6 @@
3
3
  *
4
4
  * Cross-platform (Windows, macOS, Linux) project type detection
5
5
  * by inspecting files in the working directory.
6
- *
7
- * Resolves: https://github.com/affaan-m/everything-claude-code/issues/293
8
6
  */
9
7
 
10
8
  const fs = require('fs');
@@ -0,0 +1,499 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Shell substitution / subshell / brace-group extractors.
5
+ *
6
+ * Ported into CCP (re-authored from ECC `744f4169`) as the sole non-stdlib
7
+ * dependency of the GateGuard fact-forcing hook (src/hooks/ccp-write-gateguard.js).
8
+ * Pure, stdlib-only logic — no requires, no I/O. Other PreToolUse hooks that need
9
+ * the same "scan inside `$(...)`, backticks, `(...)`, and `{ ...; }`" behavior can
10
+ * reuse it without duplicating the parser.
11
+ */
12
+
13
+ /**
14
+ * Extract executable command-substitution bodies from a shell line.
15
+ *
16
+ * Single quotes are literal, so substitutions inside them are ignored;
17
+ * double quotes still permit substitutions, so those bodies are scanned
18
+ * before quoted text is stripped. Returns each substitution body plus
19
+ * any nested substitutions discovered recursively.
20
+ *
21
+ * @param {string} input
22
+ * @returns {string[]}
23
+ */
24
+ function extractCommandSubstitutions(input) {
25
+ const source = String(input || '');
26
+ const substitutions = [];
27
+ let inSingle = false;
28
+ let inDouble = false;
29
+
30
+ for (let i = 0; i < source.length; i++) {
31
+ const ch = source[i];
32
+ const prev = source[i - 1];
33
+
34
+ if (ch === '\\' && !inSingle) {
35
+ i += 1;
36
+ continue;
37
+ }
38
+
39
+ if (ch === "'" && !inDouble && prev !== '\\') {
40
+ inSingle = !inSingle;
41
+ continue;
42
+ }
43
+
44
+ if (ch === '"' && !inSingle && prev !== '\\') {
45
+ inDouble = !inDouble;
46
+ continue;
47
+ }
48
+
49
+ if (inSingle) {
50
+ continue;
51
+ }
52
+
53
+ if (ch === '`') {
54
+ let body = '';
55
+ i += 1;
56
+ while (i < source.length) {
57
+ const inner = source[i];
58
+ if (inner === '\\') {
59
+ body += inner;
60
+ if (i + 1 < source.length) {
61
+ body += source[i + 1];
62
+ i += 2;
63
+ continue;
64
+ }
65
+ }
66
+ if (inner === '`') {
67
+ break;
68
+ }
69
+ body += inner;
70
+ i += 1;
71
+ }
72
+ if (body.trim()) {
73
+ substitutions.push(body);
74
+ substitutions.push(...extractCommandSubstitutions(body));
75
+ }
76
+ continue;
77
+ }
78
+
79
+ if (ch === '$' && source[i + 1] === '(') {
80
+ let depth = 1;
81
+ let body = '';
82
+ let bodyInSingle = false;
83
+ let bodyInDouble = false;
84
+ i += 2;
85
+ while (i < source.length && depth > 0) {
86
+ const inner = source[i];
87
+ const innerPrev = source[i - 1];
88
+ if (inner === '\\' && !bodyInSingle) {
89
+ body += inner;
90
+ if (i + 1 < source.length) {
91
+ body += source[i + 1];
92
+ i += 2;
93
+ continue;
94
+ }
95
+ }
96
+ if (inner === "'" && !bodyInDouble && innerPrev !== '\\') {
97
+ bodyInSingle = !bodyInSingle;
98
+ } else if (inner === '"' && !bodyInSingle && innerPrev !== '\\') {
99
+ bodyInDouble = !bodyInDouble;
100
+ } else if (!bodyInSingle && !bodyInDouble) {
101
+ if (inner === '(') {
102
+ depth += 1;
103
+ } else if (inner === ')') {
104
+ depth -= 1;
105
+ if (depth === 0) {
106
+ break;
107
+ }
108
+ }
109
+ }
110
+ body += inner;
111
+ i += 1;
112
+ }
113
+ if (body.trim()) {
114
+ substitutions.push(body);
115
+ substitutions.push(...extractCommandSubstitutions(body));
116
+ }
117
+ }
118
+ }
119
+
120
+ return substitutions;
121
+ }
122
+
123
+ /**
124
+ * Extract bodies of plain `(...)` subshell groups.
125
+ *
126
+ * Bash treats `(npm run dev)` as a subshell that executes its contents, but
127
+ * the regex-light segment splitters used by our PreToolUse hooks don't peer
128
+ * inside those parens. This helper finds top-level `(...)` groups (skipping
129
+ * `$(...)` command substitutions and backticks, which `extractCommandSubstitutions`
130
+ * already covers) and returns each body, recursing for nested groups.
131
+ *
132
+ * Quote semantics:
133
+ * - Single quotes are literal: `'( ... )'` is a string, not a subshell.
134
+ * - Double quotes are literal *for parens*: `"( ... )"` is a string too —
135
+ * bash only honors `$( )` inside double quotes, not bare `( )`.
136
+ *
137
+ * @param {string} input
138
+ * @returns {string[]}
139
+ */
140
+ function extractSubshellGroups(input) {
141
+ const source = String(input || '');
142
+ const groups = [];
143
+ let inSingle = false;
144
+ let inDouble = false;
145
+
146
+ for (let i = 0; i < source.length; i++) {
147
+ const ch = source[i];
148
+ const prev = source[i - 1];
149
+
150
+ if (ch === '\\' && !inSingle) {
151
+ i += 1;
152
+ continue;
153
+ }
154
+
155
+ if (ch === "'" && !inDouble && prev !== '\\') {
156
+ inSingle = !inSingle;
157
+ continue;
158
+ }
159
+
160
+ if (ch === '"' && !inSingle && prev !== '\\') {
161
+ inDouble = !inDouble;
162
+ continue;
163
+ }
164
+
165
+ if (inSingle || inDouble) {
166
+ continue;
167
+ }
168
+
169
+ if (ch === '$' && source[i + 1] === '(') {
170
+ let depth = 1;
171
+ let skipInSingle = false;
172
+ let skipInDouble = false;
173
+ i += 2;
174
+ while (i < source.length && depth > 0) {
175
+ const inner = source[i];
176
+ const innerPrev = source[i - 1];
177
+ if (inner === '\\' && !skipInSingle) {
178
+ i += 2;
179
+ continue;
180
+ }
181
+ if (inner === "'" && !skipInDouble && innerPrev !== '\\') {
182
+ skipInSingle = !skipInSingle;
183
+ } else if (inner === '"' && !skipInSingle && innerPrev !== '\\') {
184
+ skipInDouble = !skipInDouble;
185
+ } else if (!skipInSingle && !skipInDouble) {
186
+ if (inner === '(') depth += 1;
187
+ else if (inner === ')') depth -= 1;
188
+ }
189
+ i += 1;
190
+ }
191
+ i -= 1;
192
+ continue;
193
+ }
194
+
195
+ if (ch === '`') {
196
+ i += 1;
197
+ while (i < source.length && source[i] !== '`') {
198
+ if (source[i] === '\\' && i + 1 < source.length) {
199
+ i += 2;
200
+ continue;
201
+ }
202
+ i += 1;
203
+ }
204
+ continue;
205
+ }
206
+
207
+ if (ch === '(') {
208
+ let depth = 1;
209
+ let body = '';
210
+ let bodyInSingle = false;
211
+ let bodyInDouble = false;
212
+ i += 1;
213
+ while (i < source.length && depth > 0) {
214
+ const inner = source[i];
215
+ const innerPrev = source[i - 1];
216
+ if (inner === '\\' && !bodyInSingle) {
217
+ body += inner;
218
+ if (i + 1 < source.length) {
219
+ body += source[i + 1];
220
+ i += 2;
221
+ continue;
222
+ }
223
+ }
224
+ if (inner === "'" && !bodyInDouble && innerPrev !== '\\') {
225
+ bodyInSingle = !bodyInSingle;
226
+ } else if (inner === '"' && !bodyInSingle && innerPrev !== '\\') {
227
+ bodyInDouble = !bodyInDouble;
228
+ } else if (!bodyInSingle && !bodyInDouble) {
229
+ if (inner === '(') {
230
+ depth += 1;
231
+ } else if (inner === ')') {
232
+ depth -= 1;
233
+ if (depth === 0) {
234
+ break;
235
+ }
236
+ }
237
+ }
238
+ body += inner;
239
+ i += 1;
240
+ }
241
+ if (body.trim()) {
242
+ groups.push(body);
243
+ groups.push(...extractSubshellGroups(body));
244
+ }
245
+ }
246
+ }
247
+
248
+ return groups;
249
+ }
250
+
251
+ /**
252
+ * Extract bodies of `{ ...; }` brace groups.
253
+ *
254
+ * Bash brace groups run their body in the *current* shell (unlike `(...)`,
255
+ * which forks a subshell). Both forms group multiple commands, so for the
256
+ * purposes of destructive-bash and dev-server detection they are equivalent:
257
+ * a `rm -rf` or `npm run dev` inside `{ ...; }` still executes.
258
+ *
259
+ * Recognition rules match bash's own reserved-word semantics:
260
+ * - `{` is a reserved word only when followed by whitespace and preceded by
261
+ * the line start, whitespace, or a shell operator (`;`, `|`, `&`, `(`).
262
+ * So `{npm run dev}` is NOT a brace group (single token starting with `{`).
263
+ * - `}` closes the group only when preceded by `;` or whitespace.
264
+ * So `foo}` inside the body is not a closing brace.
265
+ * - Single quotes are literal; double quotes are also literal for `{`/`}`.
266
+ * - `$(...)`, backticks, and plain `(...)` spans are skipped so we don't
267
+ * double-extract bodies the sibling extractors already cover.
268
+ *
269
+ * @param {string} input
270
+ * @returns {string[]}
271
+ */
272
+ function extractBraceGroups(input) {
273
+ const source = String(input || '');
274
+ const groups = [];
275
+ let inSingle = false;
276
+ let inDouble = false;
277
+
278
+ for (let i = 0; i < source.length; i++) {
279
+ const ch = source[i];
280
+ const prev = source[i - 1];
281
+
282
+ if (ch === '\\' && !inSingle) {
283
+ i += 1;
284
+ continue;
285
+ }
286
+
287
+ if (ch === "'" && !inDouble && prev !== '\\') {
288
+ inSingle = !inSingle;
289
+ continue;
290
+ }
291
+
292
+ if (ch === '"' && !inSingle && prev !== '\\') {
293
+ inDouble = !inDouble;
294
+ continue;
295
+ }
296
+
297
+ if (inSingle || inDouble) {
298
+ continue;
299
+ }
300
+
301
+ if (ch === '$' && source[i + 1] === '(') {
302
+ let depth = 1;
303
+ let skipInSingle = false;
304
+ let skipInDouble = false;
305
+ i += 2;
306
+ while (i < source.length && depth > 0) {
307
+ const inner = source[i];
308
+ const innerPrev = source[i - 1];
309
+ if (inner === '\\' && !skipInSingle) {
310
+ i += 2;
311
+ continue;
312
+ }
313
+ if (inner === "'" && !skipInDouble && innerPrev !== '\\') {
314
+ skipInSingle = !skipInSingle;
315
+ } else if (inner === '"' && !skipInSingle && innerPrev !== '\\') {
316
+ skipInDouble = !skipInDouble;
317
+ } else if (!skipInSingle && !skipInDouble) {
318
+ if (inner === '(') depth += 1;
319
+ else if (inner === ')') depth -= 1;
320
+ }
321
+ i += 1;
322
+ }
323
+ i -= 1;
324
+ continue;
325
+ }
326
+
327
+ if (ch === '`') {
328
+ i += 1;
329
+ while (i < source.length && source[i] !== '`') {
330
+ if (source[i] === '\\' && i + 1 < source.length) {
331
+ i += 2;
332
+ continue;
333
+ }
334
+ i += 1;
335
+ }
336
+ continue;
337
+ }
338
+
339
+ if (ch === '(') {
340
+ let depth = 1;
341
+ let skipInSingle = false;
342
+ let skipInDouble = false;
343
+ i += 1;
344
+ while (i < source.length && depth > 0) {
345
+ const inner = source[i];
346
+ const innerPrev = source[i - 1];
347
+ if (inner === '\\' && !skipInSingle) {
348
+ i += 2;
349
+ continue;
350
+ }
351
+ if (inner === "'" && !skipInDouble && innerPrev !== '\\') {
352
+ skipInSingle = !skipInSingle;
353
+ } else if (inner === '"' && !skipInSingle && innerPrev !== '\\') {
354
+ skipInDouble = !skipInDouble;
355
+ } else if (!skipInSingle && !skipInDouble) {
356
+ if (inner === '(') depth += 1;
357
+ else if (inner === ')') depth -= 1;
358
+ }
359
+ i += 1;
360
+ }
361
+ i -= 1;
362
+ continue;
363
+ }
364
+
365
+ if (ch === '{' && /\s/.test(source[i + 1] || '')) {
366
+ const prevIsBoundary = i === 0 || /[\s;|&(]/.test(prev);
367
+ if (!prevIsBoundary) continue;
368
+
369
+ let depth = 1;
370
+ let body = '';
371
+ let bodyInSingle = false;
372
+ let bodyInDouble = false;
373
+ i += 1;
374
+ while (i < source.length && depth > 0) {
375
+ const inner = source[i];
376
+ const innerPrev = source[i - 1];
377
+ if (inner === '\\' && !bodyInSingle) {
378
+ body += inner;
379
+ if (i + 1 < source.length) {
380
+ body += source[i + 1];
381
+ i += 2;
382
+ continue;
383
+ }
384
+ }
385
+ if (inner === "'" && !bodyInDouble && innerPrev !== '\\') {
386
+ bodyInSingle = !bodyInSingle;
387
+ body += inner;
388
+ i += 1;
389
+ continue;
390
+ }
391
+ if (inner === '"' && !bodyInSingle && innerPrev !== '\\') {
392
+ bodyInDouble = !bodyInDouble;
393
+ body += inner;
394
+ i += 1;
395
+ continue;
396
+ }
397
+ if (bodyInSingle || bodyInDouble) {
398
+ body += inner;
399
+ i += 1;
400
+ continue;
401
+ }
402
+ // Skip $(...) spans — a quoted `}` or `}`-as-text inside a
403
+ // substitution body must not close the enclosing brace group.
404
+ if (inner === '$' && source[i + 1] === '(') {
405
+ body += inner + source[i + 1];
406
+ let subDepth = 1;
407
+ let subInSingle = false;
408
+ let subInDouble = false;
409
+ i += 2;
410
+ while (i < source.length && subDepth > 0) {
411
+ const c = source[i];
412
+ const p = source[i - 1];
413
+ body += c;
414
+ if (c === '\\' && !subInSingle && i + 1 < source.length) {
415
+ body += source[i + 1];
416
+ i += 2;
417
+ continue;
418
+ }
419
+ if (c === "'" && !subInDouble && p !== '\\') subInSingle = !subInSingle;
420
+ else if (c === '"' && !subInSingle && p !== '\\') subInDouble = !subInDouble;
421
+ else if (!subInSingle && !subInDouble) {
422
+ if (c === '(') subDepth += 1;
423
+ else if (c === ')') subDepth -= 1;
424
+ }
425
+ i += 1;
426
+ }
427
+ continue;
428
+ }
429
+ // Skip backtick spans for the same reason.
430
+ if (inner === '`') {
431
+ body += inner;
432
+ i += 1;
433
+ while (i < source.length && source[i] !== '`') {
434
+ if (source[i] === '\\' && i + 1 < source.length) {
435
+ body += source[i] + source[i + 1];
436
+ i += 2;
437
+ continue;
438
+ }
439
+ body += source[i];
440
+ i += 1;
441
+ }
442
+ if (i < source.length) {
443
+ body += source[i];
444
+ i += 1;
445
+ }
446
+ continue;
447
+ }
448
+ // Skip plain (...) subshell spans for the same reason.
449
+ if (inner === '(') {
450
+ body += inner;
451
+ let subDepth = 1;
452
+ let subInSingle = false;
453
+ let subInDouble = false;
454
+ i += 1;
455
+ while (i < source.length && subDepth > 0) {
456
+ const c = source[i];
457
+ const p = source[i - 1];
458
+ body += c;
459
+ if (c === '\\' && !subInSingle && i + 1 < source.length) {
460
+ body += source[i + 1];
461
+ i += 2;
462
+ continue;
463
+ }
464
+ if (c === "'" && !subInDouble && p !== '\\') subInSingle = !subInSingle;
465
+ else if (c === '"' && !subInSingle && p !== '\\') subInDouble = !subInDouble;
466
+ else if (!subInSingle && !subInDouble) {
467
+ if (c === '(') subDepth += 1;
468
+ else if (c === ')') subDepth -= 1;
469
+ }
470
+ i += 1;
471
+ }
472
+ continue;
473
+ }
474
+ if (inner === '{' && /\s/.test(source[i + 1] || '')) {
475
+ // Match the outer-scan boundary rule for nested `{` so
476
+ // tokens like `foo{` (no boundary, but followed by space
477
+ // via `foo{ bar`) cannot bump nested depth.
478
+ const nestedPrevIsBoundary = /[\s;|&(]/.test(innerPrev);
479
+ if (nestedPrevIsBoundary) depth += 1;
480
+ } else if (inner === '}' && (innerPrev === ';' || /\s/.test(innerPrev))) {
481
+ depth -= 1;
482
+ if (depth === 0) {
483
+ break;
484
+ }
485
+ }
486
+ body += inner;
487
+ i += 1;
488
+ }
489
+ if (body.trim()) {
490
+ groups.push(body);
491
+ groups.push(...extractBraceGroups(body));
492
+ }
493
+ }
494
+ }
495
+
496
+ return groups;
497
+ }
498
+
499
+ module.exports = { extractCommandSubstitutions, extractSubshellGroups, extractBraceGroups };
@@ -0,0 +1,81 @@
1
+ # Execute-Phase — MVP+TDD Gate (Runtime Enforcement)
2
+
3
+ > Loaded by `execute-phase` workflow and `ccp-executor` agent only when **both** `MVP_MODE=true` AND `TDD_MODE=true` for the phase. Defines the runtime gate that blocks behavior-adding tasks until a failing-test commit exists.
4
+
5
+ ## When this gate fires
6
+
7
+ - `MVP_MODE` is `true` (resolved from CLI flag → ROADMAP `**Mode:**` field → config; see `references/planner-mvp-mode.md`).
8
+ - `TDD_MODE` is `true` (resolved from `--tdd` flag → `workflow.tdd_mode` config).
9
+ - The current task being executed has `tdd="true"` in its `<task>` frontmatter (set by the planner per Phase 1).
10
+ - The task's `<behavior>` block lists at least one expected behavior.
11
+
12
+ If any of these is false, the gate is inactive — execution proceeds normally.
13
+
14
+ ## What the gate checks
15
+
16
+ For each task gated by MVP+TDD, the executor MUST verify (before running the implementation step):
17
+
18
+ 1. **A failing-test commit exists.** Search git log on the current branch for a commit matching `test({phase}-{plan})` whose subject mentions the same plan as the current task. The commit must touch a test file (`*.test.*`, `*.spec.*`, `tests/**`).
19
+ 2. **The test was actually red.** The commit message body or the executor's recent shell history must show the test failed when first run. Acceptable evidence:
20
+ - Commit message contains `RED:` prefix or `(RED)` tag
21
+ - Recent terminal output shows `FAIL` or non-zero exit on the new test before any implementation commit
22
+ 3. **No implementation commit yet.** No `feat({phase}-{plan})` commit may exist for the same plan ID before the failing-test commit.
23
+
24
+ If any check fails, the gate trips.
25
+
26
+ ## What "behavior-adding task" means
27
+
28
+ A task is behavior-adding when:
29
+ - Its frontmatter has `tdd="true"` AND
30
+ - Its `<behavior>` block names at least one user-visible outcome (not a config-only or doc-only task) AND
31
+ - Its `<files>` list includes at least one source file (not exclusively docs/tests/config files such as `*.md`, `*.json`, `*.test.*`, `*.spec.*`, `*.yml`, `*.yaml`, `*.toml`, `*.ini`, `.env*`)
32
+
33
+ Pure documentation, configuration, or test-only tasks are skipped by this gate even when both modes are active.
34
+
35
+ ## What happens when the gate trips
36
+
37
+ The executor MUST:
38
+
39
+ 1. Halt before running the task's implementation step.
40
+ 2. Emit a structured halt report:
41
+
42
+ ```
43
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
44
+ MVP+TDD GATE TRIPPED — Plan {plan_id}, Task {task_id}
45
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
46
+
47
+ Reason: {missing_red_commit | red_commit_not_failing | feat_before_test}
48
+
49
+ Behavior expected to be tested:
50
+ - {first behavior bullet}
51
+
52
+ Required next step:
53
+ 1. Write a failing test for the behavior above.
54
+ 2. Commit it as: test({phase}-{plan}): {short description}
55
+ 3. Re-run /ccp:execute-phase
56
+ ```
57
+
58
+ 3. Exit the current execution wave cleanly. Do NOT roll back any prior commits in the same wave.
59
+ 4. Update `STATE.md` with `last_gate_trip: {plan_id}/{task_id}` so the user can resume after writing the test.
60
+
61
+ ## Escalation: end-of-phase TDD review under MVP+TDD
62
+
63
+ The existing end-of-phase TDD review (in `workflows/execute-phase.md`'s `tdd_review_checkpoint` step) is normally **advisory** — it surfaces gate violations but does not block phase completion.
64
+
65
+ Under MVP+TDD, escalate this to **blocking**:
66
+ - If any TDD plan is missing a RED or GREEN commit, the executor MUST refuse to mark the phase complete.
67
+ - The user is shown the same review table, but the verdict line reads:
68
+ > "Phase blocked: {N} TDD plan(s) violate the RED→GREEN gate sequence under MVP+TDD. Resolve and re-run /ccp:execute-phase, or override with `/ccp:execute-phase {phase} --force-mvp-gate` to ship anyway."
69
+
70
+ The `--force-mvp-gate` flag is documented but not introduced by this plan — it is the escape hatch the spec mentions; if the user later builds it, the workflow already references the contract.
71
+
72
+ ## What this gate does NOT do
73
+
74
+ - It does not enforce REFACTOR commits. REFACTOR remains optional (per `references/tdd.md`).
75
+ - It does not check test quality (the test could be trivially passing). That's the planner's job.
76
+ - It does not run tests. The executor only inspects git log + file system. Running tests is the implementation step's job.
77
+ - It does not gate config-only or doc-only tasks (see "behavior-adding task" definition).
78
+
79
+ ## Compatibility with existing TDD discipline
80
+
81
+ This gate is additive to `references/tdd.md`. Tasks not under MVP+TDD continue to use the existing advisory TDD discipline (RED/GREEN/REFACTOR commits with end-of-phase review checkpoint). Only the runtime gate and the blocking escalation are new.
@@ -0,0 +1,49 @@
1
+ # MVP Concepts — index
2
+
3
+ Cross-reference for the six MVP-related reference files. Each file has a single, narrow purpose. This index exists so future readers (and agents resolving `@`-refs) can find the right file without grepping the directory.
4
+
5
+ Canonical domain terms for the concepts named below live in [CONTEXT.md](../../CONTEXT.md) under "Domain terms" — start there if you need a precise definition.
6
+
7
+ ## File map
8
+
9
+ | File | Purpose | Loaded by |
10
+ |---|---|---|
11
+ | `references/planner-mvp-mode.md` | **Rules.** Vertical-slice planning rules, slice ordering, Walking Skeleton constraints. | `ccp-planner` agent when `MVP_MODE=true` |
12
+ | `references/skeleton-template.md` | **Template.** Shape of `SKELETON.md` for new-project Phase 1 under `--mvp`. | `ccp-planner` agent when the Walking Skeleton gate fires |
13
+ | `references/user-story-template.md` | **Template.** Format and slot definitions for `As a / I want to / So that`. | `ccp:mvp-phase` workflow during interactive prompting; `ccp-planner` when emitting the `## Phase Goal` header |
14
+ | `references/spidr-splitting.md` | **Splitting discipline.** Five-axis decomposition (Spike, Paths, Interfaces, Data, Rules) for stories too large for one phase. | `ccp:mvp-phase` workflow when the user story exceeds size threshold |
15
+ | `references/execute-mvp-tdd.md` | **Gate.** MVP+TDD runtime gate semantics: when it fires, what it checks, halt-and-report protocol, end-of-phase blocking escalation, Behavior-Adding Task definition. | `ccp-executor` agent when `MVP_MODE=true && TDD_MODE=true` |
16
+ | `references/verify-mvp-mode.md` | **UAT framing.** Three-section UAT structure (user-flow → technical → coverage), anti-patterns, `User Flow Coverage` section in VERIFICATION.md. | `ccp-verifier` agent when the phase under verification has `mode: mvp` |
17
+
18
+ ## Concept-to-file map
19
+
20
+ If you're looking for the canonical statement of a concept, this is where to find it:
21
+
22
+ - **MVP Mode resolution chain** — `workflows/plan-phase.md` Step 1 (CLI flag → roadmap → config → false). Mirrored in `execute-phase.md` and `verify-work.md`.
23
+ - **`**Mode:** mvp` parser** — parsed by the planner workflow when MVP mode is active in ROADMAP.md. Workflows compare against the parser output, never re-parse.
24
+ - **User Story regex** — `/^As a .+, I want to .+, so that .+\.$/` — applied at runtime by `ccp-verifier` (the user-story-format guard) and `ccp:mvp-phase` (interactive validation).
25
+ - **Behavior-Adding Task predicate** — `references/execute-mvp-tdd.md` (the canonical three-check definition). Applied at runtime by `ccp-executor`.
26
+ - **Walking Skeleton gate condition** — `workflows/plan-phase.md` (Phase 1 + new project + `--mvp` + no prior summaries → emit `SKELETON.md`).
27
+ - **MVP+TDD Gate** (RED→GREEN enforcement) — `references/execute-mvp-tdd.md`.
28
+ - **MVP-mode UAT framing** (user-flow first, technical deferred) — `references/verify-mvp-mode.md`.
29
+ - **Per-phase mode authoring** — `workflows/mvp-phase.md` (writes `**Mode:** mvp` to ROADMAP.md after collecting the user story).
30
+ - **Project-wide mode prompt at init** — `workflows/new-project.md` (Vertical MVP vs Horizontal Layers question).
31
+
32
+ ## Interactions worth knowing
33
+
34
+ - **`--mvp` and `--prd <file>` together on Phase 1.** Both paths converge at the planner spawn. The PRD express path creates `CONTEXT.md` from the PRD file and continues to the research step; the Walking Skeleton gate fires independently when Phase 1 + new project + `--mvp`. The planner therefore receives both `WALKING_SKELETON=true` and PRD-derived context. This is intentional: the PRD informs what the skeleton should prove.
35
+ - **`MVP_MODE` is all-or-nothing per phase, not per task.** A phase is either MVP-mode or standard. Mixed-mode phases are not supported (PRD #2826 Q1).
36
+ - **`TDD_MODE` is independent of `MVP_MODE`.** TDD can be on without MVP, MVP can be on without TDD. Only the *intersection* (both true) activates the MVP+TDD Gate.
37
+ - **The `ccp-roadmapper` agent makes the MVP/standard decision once at project init** based on `PROJECT_MODE`. Per-phase opt-in/out happens later via `/ccp:mvp-phase` or `/ccp:edit-phase`.
38
+
39
+ ## Tests
40
+
41
+ Structural contract tests for each integration site live under `tests/`:
42
+
43
+ - `plan-phase-mvp-flag.test.cjs` — plan-phase MVP_MODE resolution chain
44
+ - `planner-mvp-mode.test.cjs` — ccp-planner agent MVP section
45
+ - `mvp-phase-command.test.cjs`, `mvp-phase-integration.test.cjs`, `mvp-phase-spidr.test.cjs` — `/ccp:mvp-phase`
46
+ - `execute-mvp-tdd-gate.test.cjs`, `executor-mvp-tdd-section.test.cjs` — MVP+TDD Gate
47
+ - `verifier-mvp-section.test.cjs`, `verify-mvp-uat.test.cjs` — verifier UAT framing
48
+ - `new-project-mvp-prompt.test.cjs` — mode prompt at init
49
+ - `progress-mvp-display.test.cjs`, `stats-mvp-display.test.cjs`, `graphify-mvp-viz.test.cjs` — discovery surfaces