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.
- package/CHANGELOG.md +57 -0
- package/README.md +16 -11
- package/bin/install.js +127 -11
- package/manifest.json +20 -1
- package/package.json +4 -3
- package/src/agents/a11y-architect.md +141 -0
- package/src/agents/code-architect.md +71 -0
- package/src/agents/code-explorer.md +69 -0
- package/src/agents/code-simplifier.md +47 -0
- package/src/agents/comment-analyzer.md +45 -0
- package/src/agents/csharp-reviewer.md +101 -0
- package/src/agents/dart-build-resolver.md +201 -0
- package/src/agents/django-build-resolver.md +252 -0
- package/src/agents/django-reviewer.md +169 -0
- package/src/agents/fastapi-reviewer.md +79 -0
- package/src/agents/fsharp-reviewer.md +109 -0
- package/src/agents/pr-test-analyzer.md +45 -0
- package/src/agents/silent-failure-hunter.md +50 -0
- package/src/agents/swift-build-resolver.md +170 -0
- package/src/agents/swift-reviewer.md +116 -0
- package/src/agents/type-design-analyzer.md +41 -0
- package/src/available-rules/README.md +3 -1
- package/src/available-rules/dart/coding-style.md +159 -0
- package/src/available-rules/dart/hooks.md +66 -0
- package/src/available-rules/dart/patterns.md +261 -0
- package/src/available-rules/dart/security.md +135 -0
- package/src/available-rules/dart/testing.md +215 -0
- package/src/available-rules/web/coding-style.md +105 -0
- package/src/available-rules/web/design-quality.md +72 -0
- package/src/available-rules/web/hooks.md +129 -0
- package/src/available-rules/web/patterns.md +88 -0
- package/src/available-rules/web/performance.md +73 -0
- package/src/available-rules/web/security.md +66 -0
- package/src/available-rules/web/testing.md +64 -0
- package/src/commands/ccp/ai-integration-phase.md +36 -0
- package/src/commands/ccp/audit-fix.md +33 -0
- package/src/commands/ccp/code-review-fix.md +52 -0
- package/src/commands/ccp/cost-report.md +107 -0
- package/src/commands/ccp/eval-review.md +32 -0
- package/src/commands/ccp/extract_learnings.md +22 -0
- package/src/commands/ccp/import.md +37 -0
- package/src/commands/ccp/ingest-docs.md +42 -0
- package/src/commands/ccp/intel.md +179 -0
- package/src/commands/ccp/mvp-phase.md +45 -0
- package/src/commands/ccp/plan-prd.md +160 -0
- package/src/commands/ccp/plan-review-convergence.md +58 -0
- package/src/commands/ccp/pr-ecc.md +184 -0
- package/src/commands/ccp/scan.md +26 -0
- package/src/commands/ccp/security-scan.md +74 -0
- package/src/commands/ccp/sketch-wrap-up.md +31 -0
- package/src/commands/ccp/sketch.md +54 -0
- package/src/commands/ccp/spec-phase.md +62 -0
- package/src/commands/ccp/spike-wrap-up.md +31 -0
- package/src/commands/ccp/spike.md +51 -0
- package/src/commands/ccp/ultraplan-phase.md +33 -0
- package/src/hooks/ccp-bash-hook-dispatcher.js +96 -0
- package/src/hooks/ccp-context-monitor.js +23 -0
- package/src/hooks/ccp-doc-file-warning.js +93 -0
- package/src/hooks/ccp-pre-bash-dispatcher.js +24 -0
- package/src/hooks/ccp-read-injection-scanner.js +152 -0
- package/src/hooks/ccp-write-gateguard.js +868 -0
- package/src/hooks/kit-check-update.js +59 -7
- package/src/hooks/run-with-flags-shell.sh +1 -0
- package/src/hooks/run-with-flags.js +48 -1
- package/src/hooks/session-end.js +88 -1
- package/src/lib/hook-flags.js +14 -0
- package/src/lib/project-detect.js +0 -2
- package/src/lib/shell-substitution.js +499 -0
- package/src/pilot/references/agent-contracts.md +79 -0
- package/src/pilot/references/ai-evals.md +156 -0
- package/src/pilot/references/ai-frameworks.md +186 -0
- package/src/pilot/references/doc-conflict-engine.md +91 -0
- package/src/pilot/references/execute-mvp-tdd.md +81 -0
- package/src/pilot/references/gate-prompts.md +100 -0
- package/src/pilot/references/gates.md +70 -0
- package/src/pilot/references/mandatory-initial-read.md +2 -0
- package/src/pilot/references/mvp-concepts.md +49 -0
- package/src/pilot/references/planner-graphify-auto-update.md +67 -0
- package/src/pilot/references/planner-human-verify-mode.md +57 -0
- package/src/pilot/references/planner-mvp-mode.md +53 -0
- package/src/pilot/references/project-skills-discovery.md +19 -0
- package/src/pilot/references/revision-loop.md +97 -0
- package/src/pilot/references/skeleton-template.md +48 -0
- package/src/pilot/references/sketch-interactivity.md +41 -0
- package/src/pilot/references/sketch-theme-system.md +94 -0
- package/src/pilot/references/sketch-tooling.md +45 -0
- package/src/pilot/references/sketch-variant-patterns.md +81 -0
- package/src/pilot/references/spidr-splitting.md +69 -0
- package/src/pilot/references/thinking-models-debug.md +44 -0
- package/src/pilot/references/thinking-models-execution.md +50 -0
- package/src/pilot/references/thinking-models-planning.md +62 -0
- package/src/pilot/references/thinking-models-research.md +50 -0
- package/src/pilot/references/thinking-models-verification.md +55 -0
- package/src/pilot/references/user-story-template.md +58 -0
- package/src/pilot/references/verify-mvp-mode.md +85 -0
- package/src/pilot/references/worktree-path-safety.md +89 -0
- package/src/pilot/templates/AI-SPEC.md +246 -0
- package/src/pilot/templates/spec.md +307 -0
- package/src/pilot/workflows/ai-integration-phase.md +284 -0
- package/src/pilot/workflows/audit-fix.md +175 -0
- package/src/pilot/workflows/code-review-fix.md +497 -0
- package/src/pilot/workflows/eval-review.md +155 -0
- package/src/pilot/workflows/extract_learnings.md +242 -0
- package/src/pilot/workflows/help.md +5 -0
- package/src/pilot/workflows/import.md +246 -0
- package/src/pilot/workflows/ingest-docs.md +328 -0
- package/src/pilot/workflows/mvp-phase.md +199 -0
- package/src/pilot/workflows/plan-review-convergence.md +329 -0
- package/src/pilot/workflows/scan.md +102 -0
- package/src/pilot/workflows/sketch-wrap-up.md +285 -0
- package/src/pilot/workflows/sketch.md +360 -0
- package/src/pilot/workflows/spec-phase.md +262 -0
- package/src/pilot/workflows/spike-wrap-up.md +306 -0
- package/src/pilot/workflows/spike.md +452 -0
- package/src/pilot/workflows/ultraplan-phase.md +189 -0
- package/src/skills/accessibility/SKILL.md +146 -0
- package/src/skills/agent-architecture-audit/SKILL.md +256 -0
- package/src/skills/agent-eval/SKILL.md +145 -0
- package/src/skills/agent-harness-design/SKILL.md +73 -0
- package/src/skills/agent-introspection-debugging/SKILL.md +153 -0
- package/src/skills/android-clean-architecture/SKILL.md +339 -0
- package/src/skills/angular-developer/SKILL.md +154 -0
- package/src/skills/angular-developer/references/angular-animations.md +160 -0
- package/src/skills/angular-developer/references/angular-aria.md +410 -0
- package/src/skills/angular-developer/references/cli.md +86 -0
- package/src/skills/angular-developer/references/component-harnesses.md +59 -0
- package/src/skills/angular-developer/references/component-styling.md +91 -0
- package/src/skills/angular-developer/references/components.md +117 -0
- package/src/skills/angular-developer/references/creating-services.md +97 -0
- package/src/skills/angular-developer/references/data-resolvers.md +69 -0
- package/src/skills/angular-developer/references/define-routes.md +67 -0
- package/src/skills/angular-developer/references/defining-providers.md +72 -0
- package/src/skills/angular-developer/references/di-fundamentals.md +120 -0
- package/src/skills/angular-developer/references/e2e-testing.md +56 -0
- package/src/skills/angular-developer/references/effects.md +83 -0
- package/src/skills/angular-developer/references/hierarchical-injectors.md +43 -0
- package/src/skills/angular-developer/references/host-elements.md +80 -0
- package/src/skills/angular-developer/references/injection-context.md +63 -0
- package/src/skills/angular-developer/references/inputs.md +101 -0
- package/src/skills/angular-developer/references/linked-signal.md +59 -0
- package/src/skills/angular-developer/references/loading-strategies.md +61 -0
- package/src/skills/angular-developer/references/mcp.md +108 -0
- package/src/skills/angular-developer/references/navigate-to-routes.md +69 -0
- package/src/skills/angular-developer/references/outputs.md +86 -0
- package/src/skills/angular-developer/references/reactive-forms.md +122 -0
- package/src/skills/angular-developer/references/rendering-strategies.md +44 -0
- package/src/skills/angular-developer/references/resource.md +77 -0
- package/src/skills/angular-developer/references/route-animations.md +56 -0
- package/src/skills/angular-developer/references/route-guards.md +52 -0
- package/src/skills/angular-developer/references/router-lifecycle.md +45 -0
- package/src/skills/angular-developer/references/router-testing.md +87 -0
- package/src/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
- package/src/skills/angular-developer/references/signal-forms.md +795 -0
- package/src/skills/angular-developer/references/signals-overview.md +94 -0
- package/src/skills/angular-developer/references/tailwind-css.md +69 -0
- package/src/skills/angular-developer/references/template-driven-forms.md +114 -0
- package/src/skills/angular-developer/references/testing-fundamentals.md +65 -0
- package/src/skills/api-connector-builder/SKILL.md +120 -0
- package/src/skills/code-tour/SKILL.md +236 -0
- package/src/skills/compose-multiplatform-patterns/SKILL.md +299 -0
- package/src/skills/csharp-testing/SKILL.md +321 -0
- package/src/skills/dart-flutter-patterns/SKILL.md +563 -0
- package/src/skills/dashboard-builder/SKILL.md +108 -0
- package/src/skills/dotnet-patterns/SKILL.md +321 -0
- package/src/skills/error-handling/SKILL.md +376 -0
- package/src/skills/fastapi-patterns/SKILL.md +327 -0
- package/src/skills/flox-environments/SKILL.md +496 -0
- package/src/skills/frontend-design/SKILL.md +145 -0
- package/src/skills/frontend-slides/SKILL.md +184 -0
- package/src/skills/frontend-slides/STYLE_PRESETS.md +330 -0
- package/src/skills/fsharp-testing/SKILL.md +280 -0
- package/src/skills/gateguard/SKILL.md +121 -0
- package/src/skills/github-ops/SKILL.md +144 -0
- package/src/skills/hookify-rules/SKILL.md +128 -0
- package/src/skills/ios-icon-gen/SKILL.md +157 -0
- package/src/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
- package/src/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
- package/src/skills/knowledge-ops/SKILL.md +154 -0
- package/src/skills/liquid-glass-design/SKILL.md +279 -0
- package/src/skills/make-interfaces-feel-better/SKILL.md +151 -0
- package/src/skills/mysql-patterns/SKILL.md +412 -0
- package/src/skills/nestjs-patterns/SKILL.md +230 -0
- package/src/skills/plan-orchestrate/SKILL.md +220 -0
- package/src/skills/prisma-patterns/SKILL.md +371 -0
- package/src/skills/production-audit/SKILL.md +206 -0
- package/src/skills/security-bounty-hunter/SKILL.md +99 -0
- package/src/skills/security-scan/references/agentshield-policy-exception/candidate-playbook.md +49 -0
- package/src/skills/security-scan/references/agentshield-policy-exception/report.json +35 -0
- package/src/skills/security-scan/references/agentshield-policy-exception/scenario.json +62 -0
- package/src/skills/security-scan/references/agentshield-policy-exception/trace.json +45 -0
- package/src/skills/security-scan/references/agentshield-policy-exception/verifier-result.json +35 -0
- package/src/skills/swift-actor-persistence/SKILL.md +143 -0
- package/src/skills/swift-protocol-di-testing/SKILL.md +190 -0
- package/src/skills/swiftui-patterns/SKILL.md +259 -0
- package/src/skills/terminal-ops/SKILL.md +109 -0
- package/src/skills/ui-demo/SKILL.md +465 -0
- package/src/skills/vite-patterns/SKILL.md +449 -0
- 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.
|