claude-code-pilot 3.1.1 → 3.3.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.
Files changed (198) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/README.md +16 -11
  3. package/bin/install.js +127 -11
  4. package/manifest.json +20 -1
  5. package/package.json +4 -3
  6. package/src/agents/a11y-architect.md +141 -0
  7. package/src/agents/code-architect.md +71 -0
  8. package/src/agents/code-explorer.md +69 -0
  9. package/src/agents/code-simplifier.md +47 -0
  10. package/src/agents/comment-analyzer.md +45 -0
  11. package/src/agents/csharp-reviewer.md +101 -0
  12. package/src/agents/dart-build-resolver.md +201 -0
  13. package/src/agents/django-build-resolver.md +252 -0
  14. package/src/agents/django-reviewer.md +169 -0
  15. package/src/agents/fastapi-reviewer.md +79 -0
  16. package/src/agents/fsharp-reviewer.md +109 -0
  17. package/src/agents/pr-test-analyzer.md +45 -0
  18. package/src/agents/silent-failure-hunter.md +50 -0
  19. package/src/agents/swift-build-resolver.md +170 -0
  20. package/src/agents/swift-reviewer.md +116 -0
  21. package/src/agents/type-design-analyzer.md +41 -0
  22. package/src/available-rules/README.md +3 -1
  23. package/src/available-rules/dart/coding-style.md +159 -0
  24. package/src/available-rules/dart/hooks.md +66 -0
  25. package/src/available-rules/dart/patterns.md +261 -0
  26. package/src/available-rules/dart/security.md +135 -0
  27. package/src/available-rules/dart/testing.md +215 -0
  28. package/src/available-rules/web/coding-style.md +105 -0
  29. package/src/available-rules/web/design-quality.md +72 -0
  30. package/src/available-rules/web/hooks.md +129 -0
  31. package/src/available-rules/web/patterns.md +88 -0
  32. package/src/available-rules/web/performance.md +73 -0
  33. package/src/available-rules/web/security.md +66 -0
  34. package/src/available-rules/web/testing.md +64 -0
  35. package/src/commands/ccp/ai-integration-phase.md +36 -0
  36. package/src/commands/ccp/audit-fix.md +33 -0
  37. package/src/commands/ccp/code-review-fix.md +52 -0
  38. package/src/commands/ccp/cost-report.md +107 -0
  39. package/src/commands/ccp/eval-review.md +32 -0
  40. package/src/commands/ccp/extract_learnings.md +22 -0
  41. package/src/commands/ccp/import.md +37 -0
  42. package/src/commands/ccp/ingest-docs.md +42 -0
  43. package/src/commands/ccp/intel.md +179 -0
  44. package/src/commands/ccp/mvp-phase.md +45 -0
  45. package/src/commands/ccp/plan-prd.md +160 -0
  46. package/src/commands/ccp/plan-review-convergence.md +58 -0
  47. package/src/commands/ccp/pr-ecc.md +184 -0
  48. package/src/commands/ccp/scan.md +26 -0
  49. package/src/commands/ccp/security-scan.md +74 -0
  50. package/src/commands/ccp/sketch-wrap-up.md +31 -0
  51. package/src/commands/ccp/sketch.md +54 -0
  52. package/src/commands/ccp/spec-phase.md +62 -0
  53. package/src/commands/ccp/spike-wrap-up.md +31 -0
  54. package/src/commands/ccp/spike.md +51 -0
  55. package/src/commands/ccp/ultraplan-phase.md +33 -0
  56. package/src/hooks/ccp-bash-hook-dispatcher.js +96 -0
  57. package/src/hooks/ccp-context-monitor.js +23 -0
  58. package/src/hooks/ccp-doc-file-warning.js +93 -0
  59. package/src/hooks/ccp-pre-bash-dispatcher.js +24 -0
  60. package/src/hooks/ccp-read-injection-scanner.js +152 -0
  61. package/src/hooks/ccp-write-gateguard.js +868 -0
  62. package/src/hooks/kit-check-update.js +59 -7
  63. package/src/hooks/run-with-flags-shell.sh +1 -0
  64. package/src/hooks/run-with-flags.js +48 -1
  65. package/src/hooks/session-end.js +88 -1
  66. package/src/lib/hook-flags.js +14 -0
  67. package/src/lib/project-detect.js +0 -2
  68. package/src/lib/shell-substitution.js +499 -0
  69. package/src/pilot/references/agent-contracts.md +79 -0
  70. package/src/pilot/references/ai-evals.md +156 -0
  71. package/src/pilot/references/ai-frameworks.md +186 -0
  72. package/src/pilot/references/doc-conflict-engine.md +91 -0
  73. package/src/pilot/references/execute-mvp-tdd.md +81 -0
  74. package/src/pilot/references/gate-prompts.md +100 -0
  75. package/src/pilot/references/gates.md +70 -0
  76. package/src/pilot/references/mandatory-initial-read.md +2 -0
  77. package/src/pilot/references/mvp-concepts.md +49 -0
  78. package/src/pilot/references/planner-graphify-auto-update.md +67 -0
  79. package/src/pilot/references/planner-human-verify-mode.md +57 -0
  80. package/src/pilot/references/planner-mvp-mode.md +53 -0
  81. package/src/pilot/references/project-skills-discovery.md +19 -0
  82. package/src/pilot/references/revision-loop.md +97 -0
  83. package/src/pilot/references/skeleton-template.md +48 -0
  84. package/src/pilot/references/sketch-interactivity.md +41 -0
  85. package/src/pilot/references/sketch-theme-system.md +94 -0
  86. package/src/pilot/references/sketch-tooling.md +45 -0
  87. package/src/pilot/references/sketch-variant-patterns.md +81 -0
  88. package/src/pilot/references/spidr-splitting.md +69 -0
  89. package/src/pilot/references/thinking-models-debug.md +44 -0
  90. package/src/pilot/references/thinking-models-execution.md +50 -0
  91. package/src/pilot/references/thinking-models-planning.md +62 -0
  92. package/src/pilot/references/thinking-models-research.md +50 -0
  93. package/src/pilot/references/thinking-models-verification.md +55 -0
  94. package/src/pilot/references/user-story-template.md +58 -0
  95. package/src/pilot/references/verify-mvp-mode.md +85 -0
  96. package/src/pilot/references/worktree-path-safety.md +89 -0
  97. package/src/pilot/templates/AI-SPEC.md +246 -0
  98. package/src/pilot/templates/spec.md +307 -0
  99. package/src/pilot/workflows/ai-integration-phase.md +284 -0
  100. package/src/pilot/workflows/audit-fix.md +175 -0
  101. package/src/pilot/workflows/code-review-fix.md +497 -0
  102. package/src/pilot/workflows/eval-review.md +155 -0
  103. package/src/pilot/workflows/extract_learnings.md +242 -0
  104. package/src/pilot/workflows/help.md +5 -0
  105. package/src/pilot/workflows/import.md +246 -0
  106. package/src/pilot/workflows/ingest-docs.md +328 -0
  107. package/src/pilot/workflows/mvp-phase.md +199 -0
  108. package/src/pilot/workflows/plan-review-convergence.md +329 -0
  109. package/src/pilot/workflows/scan.md +102 -0
  110. package/src/pilot/workflows/sketch-wrap-up.md +285 -0
  111. package/src/pilot/workflows/sketch.md +360 -0
  112. package/src/pilot/workflows/spec-phase.md +262 -0
  113. package/src/pilot/workflows/spike-wrap-up.md +306 -0
  114. package/src/pilot/workflows/spike.md +452 -0
  115. package/src/pilot/workflows/ultraplan-phase.md +189 -0
  116. package/src/skills/accessibility/SKILL.md +146 -0
  117. package/src/skills/agent-architecture-audit/SKILL.md +256 -0
  118. package/src/skills/agent-eval/SKILL.md +145 -0
  119. package/src/skills/agent-harness-design/SKILL.md +73 -0
  120. package/src/skills/agent-introspection-debugging/SKILL.md +153 -0
  121. package/src/skills/android-clean-architecture/SKILL.md +339 -0
  122. package/src/skills/angular-developer/SKILL.md +154 -0
  123. package/src/skills/angular-developer/references/angular-animations.md +160 -0
  124. package/src/skills/angular-developer/references/angular-aria.md +410 -0
  125. package/src/skills/angular-developer/references/cli.md +86 -0
  126. package/src/skills/angular-developer/references/component-harnesses.md +59 -0
  127. package/src/skills/angular-developer/references/component-styling.md +91 -0
  128. package/src/skills/angular-developer/references/components.md +117 -0
  129. package/src/skills/angular-developer/references/creating-services.md +97 -0
  130. package/src/skills/angular-developer/references/data-resolvers.md +69 -0
  131. package/src/skills/angular-developer/references/define-routes.md +67 -0
  132. package/src/skills/angular-developer/references/defining-providers.md +72 -0
  133. package/src/skills/angular-developer/references/di-fundamentals.md +120 -0
  134. package/src/skills/angular-developer/references/e2e-testing.md +56 -0
  135. package/src/skills/angular-developer/references/effects.md +83 -0
  136. package/src/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  137. package/src/skills/angular-developer/references/host-elements.md +80 -0
  138. package/src/skills/angular-developer/references/injection-context.md +63 -0
  139. package/src/skills/angular-developer/references/inputs.md +101 -0
  140. package/src/skills/angular-developer/references/linked-signal.md +59 -0
  141. package/src/skills/angular-developer/references/loading-strategies.md +61 -0
  142. package/src/skills/angular-developer/references/mcp.md +108 -0
  143. package/src/skills/angular-developer/references/navigate-to-routes.md +69 -0
  144. package/src/skills/angular-developer/references/outputs.md +86 -0
  145. package/src/skills/angular-developer/references/reactive-forms.md +122 -0
  146. package/src/skills/angular-developer/references/rendering-strategies.md +44 -0
  147. package/src/skills/angular-developer/references/resource.md +77 -0
  148. package/src/skills/angular-developer/references/route-animations.md +56 -0
  149. package/src/skills/angular-developer/references/route-guards.md +52 -0
  150. package/src/skills/angular-developer/references/router-lifecycle.md +45 -0
  151. package/src/skills/angular-developer/references/router-testing.md +87 -0
  152. package/src/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  153. package/src/skills/angular-developer/references/signal-forms.md +795 -0
  154. package/src/skills/angular-developer/references/signals-overview.md +94 -0
  155. package/src/skills/angular-developer/references/tailwind-css.md +69 -0
  156. package/src/skills/angular-developer/references/template-driven-forms.md +114 -0
  157. package/src/skills/angular-developer/references/testing-fundamentals.md +65 -0
  158. package/src/skills/api-connector-builder/SKILL.md +120 -0
  159. package/src/skills/code-tour/SKILL.md +236 -0
  160. package/src/skills/compose-multiplatform-patterns/SKILL.md +299 -0
  161. package/src/skills/csharp-testing/SKILL.md +321 -0
  162. package/src/skills/dart-flutter-patterns/SKILL.md +563 -0
  163. package/src/skills/dashboard-builder/SKILL.md +108 -0
  164. package/src/skills/dotnet-patterns/SKILL.md +321 -0
  165. package/src/skills/error-handling/SKILL.md +376 -0
  166. package/src/skills/fastapi-patterns/SKILL.md +327 -0
  167. package/src/skills/flox-environments/SKILL.md +496 -0
  168. package/src/skills/frontend-design/SKILL.md +145 -0
  169. package/src/skills/frontend-slides/SKILL.md +184 -0
  170. package/src/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  171. package/src/skills/fsharp-testing/SKILL.md +280 -0
  172. package/src/skills/gateguard/SKILL.md +121 -0
  173. package/src/skills/github-ops/SKILL.md +144 -0
  174. package/src/skills/hookify-rules/SKILL.md +128 -0
  175. package/src/skills/ios-icon-gen/SKILL.md +157 -0
  176. package/src/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
  177. package/src/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
  178. package/src/skills/knowledge-ops/SKILL.md +154 -0
  179. package/src/skills/liquid-glass-design/SKILL.md +279 -0
  180. package/src/skills/make-interfaces-feel-better/SKILL.md +151 -0
  181. package/src/skills/mysql-patterns/SKILL.md +412 -0
  182. package/src/skills/nestjs-patterns/SKILL.md +230 -0
  183. package/src/skills/plan-orchestrate/SKILL.md +220 -0
  184. package/src/skills/prisma-patterns/SKILL.md +371 -0
  185. package/src/skills/production-audit/SKILL.md +206 -0
  186. package/src/skills/security-bounty-hunter/SKILL.md +99 -0
  187. package/src/skills/security-scan/references/agentshield-policy-exception/candidate-playbook.md +49 -0
  188. package/src/skills/security-scan/references/agentshield-policy-exception/report.json +35 -0
  189. package/src/skills/security-scan/references/agentshield-policy-exception/scenario.json +62 -0
  190. package/src/skills/security-scan/references/agentshield-policy-exception/trace.json +45 -0
  191. package/src/skills/security-scan/references/agentshield-policy-exception/verifier-result.json +35 -0
  192. package/src/skills/swift-actor-persistence/SKILL.md +143 -0
  193. package/src/skills/swift-protocol-di-testing/SKILL.md +190 -0
  194. package/src/skills/swiftui-patterns/SKILL.md +259 -0
  195. package/src/skills/terminal-ops/SKILL.md +109 -0
  196. package/src/skills/ui-demo/SKILL.md +465 -0
  197. package/src/skills/vite-patterns/SKILL.md +449 -0
  198. package/src/skills/windows-desktop-e2e/SKILL.md +887 -0
@@ -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,79 @@
1
+ # Agent Contracts
2
+
3
+ Completion markers and handoff schemas for all GSD agents. Workflows use these markers to detect agent completion and route accordingly.
4
+
5
+ This doc describes what IS, not what should be. Casing inconsistencies are documented as they appear in agent source files.
6
+
7
+ ---
8
+
9
+ ## Agent Registry
10
+
11
+ | Agent | Role | Completion Markers |
12
+ |-------|------|--------------------|
13
+ | gsd-planner | Plan creation | `## PLANNING COMPLETE` |
14
+ | gsd-executor | Plan execution | `## PLAN COMPLETE`, `## CHECKPOINT REACHED` |
15
+ | gsd-phase-researcher | Phase-scoped research | `## RESEARCH COMPLETE`, `## RESEARCH BLOCKED` |
16
+ | gsd-project-researcher | Project-wide research | `## RESEARCH COMPLETE`, `## RESEARCH BLOCKED` |
17
+ | gsd-plan-checker | Plan validation | `## VERIFICATION PASSED`, `## ISSUES FOUND` |
18
+ | gsd-research-synthesizer | Multi-research synthesis | `## SYNTHESIS COMPLETE`, `## SYNTHESIS BLOCKED` |
19
+ | gsd-debugger | Debug investigation | `## DEBUG COMPLETE`, `## ROOT CAUSE FOUND`, `## CHECKPOINT REACHED` |
20
+ | gsd-roadmapper | Roadmap creation/revision | `## ROADMAP CREATED`, `## ROADMAP REVISED`, `## ROADMAP BLOCKED` |
21
+ | gsd-ui-auditor | UI review | `## UI REVIEW COMPLETE` |
22
+ | gsd-ui-checker | UI validation | `## ISSUES FOUND` |
23
+ | gsd-ui-researcher | UI spec creation | `## UI-SPEC COMPLETE`, `## UI-SPEC BLOCKED` |
24
+ | gsd-verifier | Post-execution verification | `## Verification Complete` (title case) |
25
+ | gsd-integration-checker | Cross-phase integration check | `## Integration Check Complete` (title case) |
26
+ | gsd-nyquist-auditor | Sampling audit | `## PARTIAL`, `## ESCALATE` (non-standard) |
27
+ | gsd-security-auditor | Security audit | `## OPEN_THREATS`, `## ESCALATE` (non-standard) |
28
+ | gsd-codebase-mapper | Codebase analysis | No marker (writes docs directly) |
29
+ | gsd-assumptions-analyzer | Assumption extraction | No marker (returns `## Assumptions` sections) |
30
+ | gsd-doc-verifier | Doc validation | No marker (writes JSON to `.planning/tmp/`) |
31
+ | gsd-doc-writer | Doc generation | No marker (writes docs directly) |
32
+ | gsd-advisor-researcher | Advisory research | No marker (utility agent) |
33
+ | gsd-user-profiler | User profiling | No marker (returns JSON in analysis tags) |
34
+ | gsd-intel-updater | Codebase intelligence analysis | `## INTEL UPDATE COMPLETE`, `## INTEL UPDATE FAILED` |
35
+
36
+ ## Marker Rules
37
+
38
+ 1. **ALL-CAPS markers** (e.g., `## PLANNING COMPLETE`) are the standard convention
39
+ 2. **Title-case markers** (e.g., `## Verification Complete`) exist in gsd-verifier and gsd-integration-checker -- these are intentional as-is, not bugs
40
+ 3. **Non-standard markers** (e.g., `## PARTIAL`, `## ESCALATE`) in audit agents indicate partial results requiring orchestrator judgment
41
+ 4. **Agents without markers** either write artifacts directly to disk or return structured data (JSON/sections) that the caller parses
42
+ 5. Markers must appear as H2 headings (`## `) at the start of a line in the agent's final output
43
+
44
+ ## Key Handoff Contracts
45
+
46
+ ### Planner -> Executor (via PLAN.md)
47
+
48
+ | Field | Required | Description |
49
+ |-------|----------|-------------|
50
+ | Frontmatter | Yes | phase, plan, type, wave, depends_on, files_modified, autonomous, requirements |
51
+ | `<objective>` | Yes | What the plan achieves |
52
+ | `<tasks>` | Yes | Ordered task list with type, files, action, verify, acceptance_criteria |
53
+ | `<verification>` | Yes | Overall verification steps |
54
+ | `<success_criteria>` | Yes | Measurable completion criteria |
55
+
56
+ ### Executor -> Verifier (via SUMMARY.md)
57
+
58
+ | Field | Required | Description |
59
+ |-------|----------|-------------|
60
+ | Frontmatter | Yes | phase, plan, subsystem, tags, key-files, metrics |
61
+ | Commits table | Yes | Per-task commit hashes and descriptions |
62
+ | Deviations section | Yes | Auto-fixed issues or "None" |
63
+ | Self-Check | Yes | PASSED or FAILED with details |
64
+
65
+ ## Workflow Regex Patterns
66
+
67
+ Workflows match these markers to detect agent completion:
68
+
69
+ **plan-phase.md matches:**
70
+ - `## RESEARCH COMPLETE` / `## RESEARCH BLOCKED` (researcher output)
71
+ - `## PLANNING COMPLETE` (planner output)
72
+ - `## CHECKPOINT REACHED` (planner/executor pause)
73
+ - `## VERIFICATION PASSED` / `## ISSUES FOUND` (plan-checker output)
74
+
75
+ **execute-phase.md matches:**
76
+ - `## PHASE COMPLETE` (all plans in phase done)
77
+ - `## Self-Check: FAILED` (summary self-check)
78
+
79
+ > **NOTE:** `## PLAN COMPLETE` is the gsd-executor's completion marker but execute-phase.md does not regex-match it. Instead, it detects executor completion via spot-checks (SUMMARY.md existence, git commit state). This is intentional behavior, not a mismatch.