code-as-plan 2.0.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/LICENSE +21 -0
- package/README.ja-JP.md +834 -0
- package/README.ko-KR.md +823 -0
- package/README.md +1006 -0
- package/README.pt-BR.md +452 -0
- package/README.zh-CN.md +800 -0
- package/agents/cap-brainstormer.md +154 -0
- package/agents/cap-debugger.md +221 -0
- package/agents/cap-prototyper.md +170 -0
- package/agents/cap-reviewer.md +230 -0
- package/agents/cap-tester.md +193 -0
- package/bin/install.js +5002 -0
- package/cap/bin/gsd-tools.cjs +1141 -0
- package/cap/bin/lib/arc-scanner.cjs +341 -0
- package/cap/bin/lib/cap-feature-map.cjs +506 -0
- package/cap/bin/lib/cap-session.cjs +191 -0
- package/cap/bin/lib/cap-stack-docs.cjs +598 -0
- package/cap/bin/lib/cap-tag-scanner.cjs +458 -0
- package/cap/bin/lib/commands.cjs +959 -0
- package/cap/bin/lib/config.cjs +466 -0
- package/cap/bin/lib/convention-reader.cjs +180 -0
- package/cap/bin/lib/core.cjs +1230 -0
- package/cap/bin/lib/feature-aggregator.cjs +422 -0
- package/cap/bin/lib/frontmatter.cjs +336 -0
- package/cap/bin/lib/init.cjs +1442 -0
- package/cap/bin/lib/manifest-generator.cjs +381 -0
- package/cap/bin/lib/milestone.cjs +252 -0
- package/cap/bin/lib/model-profiles.cjs +68 -0
- package/cap/bin/lib/monorepo-context.cjs +224 -0
- package/cap/bin/lib/monorepo-migrator.cjs +507 -0
- package/cap/bin/lib/phase.cjs +888 -0
- package/cap/bin/lib/profile-output.cjs +952 -0
- package/cap/bin/lib/profile-pipeline.cjs +539 -0
- package/cap/bin/lib/roadmap.cjs +329 -0
- package/cap/bin/lib/security.cjs +382 -0
- package/cap/bin/lib/session-manager.cjs +290 -0
- package/cap/bin/lib/skeleton-generator.cjs +177 -0
- package/cap/bin/lib/state.cjs +1031 -0
- package/cap/bin/lib/template.cjs +222 -0
- package/cap/bin/lib/test-detector.cjs +61 -0
- package/cap/bin/lib/uat.cjs +282 -0
- package/cap/bin/lib/verify.cjs +888 -0
- package/cap/bin/lib/workspace-detector.cjs +369 -0
- package/cap/bin/lib/workstream.cjs +491 -0
- package/cap/commands/gsd/workstreams.md +63 -0
- package/cap/references/arc-standard.md +315 -0
- package/cap/references/cap-agent-architecture.md +102 -0
- package/cap/references/cap-gitignore-template +9 -0
- package/cap/references/cap-zero-deps.md +158 -0
- package/cap/references/checkpoints.md +778 -0
- package/cap/references/continuation-format.md +249 -0
- package/cap/references/decimal-phase-calculation.md +64 -0
- package/cap/references/feature-map-template.md +25 -0
- package/cap/references/git-integration.md +295 -0
- package/cap/references/git-planning-commit.md +38 -0
- package/cap/references/model-profile-resolution.md +36 -0
- package/cap/references/model-profiles.md +139 -0
- package/cap/references/phase-argument-parsing.md +61 -0
- package/cap/references/planning-config.md +202 -0
- package/cap/references/questioning.md +162 -0
- package/cap/references/session-template.json +8 -0
- package/cap/references/tdd.md +263 -0
- package/cap/references/ui-brand.md +160 -0
- package/cap/references/user-profiling.md +681 -0
- package/cap/references/verification-patterns.md +612 -0
- package/cap/references/workstream-flag.md +58 -0
- package/cap/templates/DEBUG.md +164 -0
- package/cap/templates/UAT.md +265 -0
- package/cap/templates/UI-SPEC.md +100 -0
- package/cap/templates/VALIDATION.md +76 -0
- package/cap/templates/claude-md.md +122 -0
- package/cap/templates/codebase/architecture.md +255 -0
- package/cap/templates/codebase/concerns.md +310 -0
- package/cap/templates/codebase/conventions.md +307 -0
- package/cap/templates/codebase/integrations.md +280 -0
- package/cap/templates/codebase/stack.md +186 -0
- package/cap/templates/codebase/structure.md +285 -0
- package/cap/templates/codebase/testing.md +480 -0
- package/cap/templates/config.json +44 -0
- package/cap/templates/context.md +352 -0
- package/cap/templates/continue-here.md +78 -0
- package/cap/templates/copilot-instructions.md +7 -0
- package/cap/templates/debug-subagent-prompt.md +91 -0
- package/cap/templates/dev-preferences.md +21 -0
- package/cap/templates/discovery.md +146 -0
- package/cap/templates/discussion-log.md +63 -0
- package/cap/templates/milestone-archive.md +123 -0
- package/cap/templates/milestone.md +115 -0
- package/cap/templates/phase-prompt.md +610 -0
- package/cap/templates/planner-subagent-prompt.md +117 -0
- package/cap/templates/project.md +186 -0
- package/cap/templates/requirements.md +231 -0
- package/cap/templates/research-project/ARCHITECTURE.md +204 -0
- package/cap/templates/research-project/FEATURES.md +147 -0
- package/cap/templates/research-project/PITFALLS.md +200 -0
- package/cap/templates/research-project/STACK.md +120 -0
- package/cap/templates/research-project/SUMMARY.md +170 -0
- package/cap/templates/research.md +552 -0
- package/cap/templates/retrospective.md +54 -0
- package/cap/templates/roadmap.md +202 -0
- package/cap/templates/state.md +176 -0
- package/cap/templates/summary-complex.md +59 -0
- package/cap/templates/summary-minimal.md +41 -0
- package/cap/templates/summary-standard.md +48 -0
- package/cap/templates/summary.md +248 -0
- package/cap/templates/user-profile.md +146 -0
- package/cap/templates/user-setup.md +311 -0
- package/cap/templates/verification-report.md +322 -0
- package/cap/workflows/add-phase.md +112 -0
- package/cap/workflows/add-tests.md +351 -0
- package/cap/workflows/add-todo.md +158 -0
- package/cap/workflows/audit-milestone.md +340 -0
- package/cap/workflows/audit-uat.md +109 -0
- package/cap/workflows/autonomous.md +891 -0
- package/cap/workflows/check-todos.md +177 -0
- package/cap/workflows/cleanup.md +152 -0
- package/cap/workflows/complete-milestone.md +767 -0
- package/cap/workflows/diagnose-issues.md +231 -0
- package/cap/workflows/discovery-phase.md +289 -0
- package/cap/workflows/discuss-phase-assumptions.md +653 -0
- package/cap/workflows/discuss-phase.md +1049 -0
- package/cap/workflows/do.md +104 -0
- package/cap/workflows/execute-phase.md +846 -0
- package/cap/workflows/execute-plan.md +514 -0
- package/cap/workflows/fast.md +105 -0
- package/cap/workflows/forensics.md +265 -0
- package/cap/workflows/health.md +181 -0
- package/cap/workflows/help.md +660 -0
- package/cap/workflows/insert-phase.md +130 -0
- package/cap/workflows/list-phase-assumptions.md +178 -0
- package/cap/workflows/list-workspaces.md +56 -0
- package/cap/workflows/manager.md +362 -0
- package/cap/workflows/map-codebase.md +377 -0
- package/cap/workflows/milestone-summary.md +223 -0
- package/cap/workflows/new-milestone.md +486 -0
- package/cap/workflows/new-project.md +1250 -0
- package/cap/workflows/new-workspace.md +237 -0
- package/cap/workflows/next.md +97 -0
- package/cap/workflows/node-repair.md +92 -0
- package/cap/workflows/note.md +156 -0
- package/cap/workflows/pause-work.md +176 -0
- package/cap/workflows/plan-milestone-gaps.md +273 -0
- package/cap/workflows/plan-phase.md +859 -0
- package/cap/workflows/plant-seed.md +169 -0
- package/cap/workflows/pr-branch.md +129 -0
- package/cap/workflows/profile-user.md +450 -0
- package/cap/workflows/progress.md +507 -0
- package/cap/workflows/quick.md +757 -0
- package/cap/workflows/remove-phase.md +155 -0
- package/cap/workflows/remove-workspace.md +90 -0
- package/cap/workflows/research-phase.md +82 -0
- package/cap/workflows/resume-project.md +326 -0
- package/cap/workflows/review.md +228 -0
- package/cap/workflows/session-report.md +146 -0
- package/cap/workflows/settings.md +283 -0
- package/cap/workflows/ship.md +228 -0
- package/cap/workflows/stats.md +60 -0
- package/cap/workflows/transition.md +671 -0
- package/cap/workflows/ui-phase.md +302 -0
- package/cap/workflows/ui-review.md +165 -0
- package/cap/workflows/update.md +323 -0
- package/cap/workflows/validate-phase.md +174 -0
- package/cap/workflows/verify-phase.md +254 -0
- package/cap/workflows/verify-work.md +637 -0
- package/commands/cap/annotate.md +165 -0
- package/commands/cap/brainstorm.md +238 -0
- package/commands/cap/debug.md +297 -0
- package/commands/cap/init.md +262 -0
- package/commands/cap/iterate.md +234 -0
- package/commands/cap/prototype.md +281 -0
- package/commands/cap/refresh-docs.md +37 -0
- package/commands/cap/review.md +272 -0
- package/commands/cap/scan.md +249 -0
- package/commands/cap/start.md +234 -0
- package/commands/cap/status.md +189 -0
- package/commands/cap/test.md +250 -0
- package/hooks/dist/gsd-check-update.js +114 -0
- package/hooks/dist/gsd-context-monitor.js +156 -0
- package/hooks/dist/gsd-prompt-guard.js +96 -0
- package/hooks/dist/gsd-statusline.js +119 -0
- package/hooks/dist/gsd-workflow-guard.js +94 -0
- package/package.json +51 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +82 -0
- package/scripts/cap-removal-checklist.md +202 -0
- package/scripts/prompt-injection-scan.sh +198 -0
- package/scripts/run-tests.cjs +29 -0
- package/scripts/secret-scan.sh +227 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cap:scan
|
|
3
|
+
description: "Scan codebase for @cap-feature and @cap-todo tags with monorepo support. Traverses all workspace packages, updates Feature Map, reports coverage gaps."
|
|
4
|
+
argument-hint: "[--features NAME] [--json] [--monorepo]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- @gsd-context CAP v2.0 scan command (final pass) -- adds monorepo workspace traversal and cross-package file references to the base scan flow. -->
|
|
14
|
+
<!-- @gsd-decision Monorepo detection is automatic -- checks package.json workspaces field and lerna.json. No --monorepo flag required (AC-80). -->
|
|
15
|
+
<!-- @gsd-decision Cross-package file references use full relative paths from project root (e.g., packages/core/src/auth.ts) to avoid ambiguity (AC-79). -->
|
|
16
|
+
<!-- @gsd-constraint Works seamlessly with normal single-repo projects -- monorepo features are additive, not blocking (AC-80). -->
|
|
17
|
+
|
|
18
|
+
<!-- @gsd-todo(ref:AC-78) /cap:scan shall traverse all packages in a monorepo -->
|
|
19
|
+
<!-- @gsd-todo(ref:AC-79) Feature Map entries shall support cross-package file references -->
|
|
20
|
+
<!-- @gsd-todo(ref:AC-80) CAP shall work seamlessly with normal single-repo projects with no monorepo-specific configuration required -->
|
|
21
|
+
|
|
22
|
+
<objective>
|
|
23
|
+
Scans the codebase for @cap-feature and @cap-todo tags. In monorepo projects, automatically detects and traverses all workspace packages. Cross-references against FEATURE-MAP.md, flags orphan tags, and auto-enriches Feature Map with discovered file references.
|
|
24
|
+
|
|
25
|
+
**Monorepo support:**
|
|
26
|
+
- Automatically detects npm/yarn/pnpm workspaces from package.json `workspaces` field
|
|
27
|
+
- Detects Lerna monorepos from lerna.json
|
|
28
|
+
- Traverses all workspace packages independently
|
|
29
|
+
- File references use full paths from project root (e.g., `packages/core/src/auth.ts`)
|
|
30
|
+
|
|
31
|
+
**Arguments:**
|
|
32
|
+
- `--features NAME` -- scope scan to specific Feature Map entries (comma-separated)
|
|
33
|
+
- `--json` -- output raw scan results as JSON instead of formatted report
|
|
34
|
+
</objective>
|
|
35
|
+
|
|
36
|
+
<context>
|
|
37
|
+
$ARGUMENTS
|
|
38
|
+
|
|
39
|
+
@FEATURE-MAP.md
|
|
40
|
+
</context>
|
|
41
|
+
|
|
42
|
+
<process>
|
|
43
|
+
|
|
44
|
+
## Step 0: Parse flags
|
|
45
|
+
|
|
46
|
+
Check `$ARGUMENTS` for:
|
|
47
|
+
- `--features NAME` -- if present, store as `feature_filter`
|
|
48
|
+
- `--json` -- if present, set `json_output = true`
|
|
49
|
+
|
|
50
|
+
## Step 1: Detect monorepo configuration
|
|
51
|
+
|
|
52
|
+
<!-- @gsd-decision Monorepo detection reads package.json workspaces and lerna.json. Supports npm, yarn, pnpm workspace patterns. Glob expansion uses Bash for simplicity. -->
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
node -e "
|
|
56
|
+
const fs = require('node:fs');
|
|
57
|
+
const path = require('node:path');
|
|
58
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
59
|
+
const lernaPath = path.join(process.cwd(), 'lerna.json');
|
|
60
|
+
const result = { isMonorepo: false, workspaces: [], packages: [] };
|
|
61
|
+
|
|
62
|
+
// Check package.json workspaces
|
|
63
|
+
if (fs.existsSync(pkgPath)) {
|
|
64
|
+
try {
|
|
65
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
66
|
+
if (pkg.workspaces) {
|
|
67
|
+
result.isMonorepo = true;
|
|
68
|
+
result.workspaces = Array.isArray(pkg.workspaces)
|
|
69
|
+
? pkg.workspaces
|
|
70
|
+
: (pkg.workspaces.packages || []);
|
|
71
|
+
}
|
|
72
|
+
} catch (_e) {}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Check lerna.json
|
|
76
|
+
if (!result.isMonorepo && fs.existsSync(lernaPath)) {
|
|
77
|
+
try {
|
|
78
|
+
const lerna = JSON.parse(fs.readFileSync(lernaPath, 'utf8'));
|
|
79
|
+
result.isMonorepo = true;
|
|
80
|
+
result.workspaces = lerna.packages || ['packages/*'];
|
|
81
|
+
} catch (_e) {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Resolve workspace globs to actual package directories
|
|
85
|
+
if (result.isMonorepo) {
|
|
86
|
+
for (const ws of result.workspaces) {
|
|
87
|
+
const wsBase = ws.replace('/*', '').replace('/**', '');
|
|
88
|
+
const wsDir = path.join(process.cwd(), wsBase);
|
|
89
|
+
if (fs.existsSync(wsDir) && fs.statSync(wsDir).isDirectory()) {
|
|
90
|
+
const entries = fs.readdirSync(wsDir, { withFileTypes: true });
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (entry.isDirectory()) {
|
|
93
|
+
const pkgJsonPath = path.join(wsDir, entry.name, 'package.json');
|
|
94
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
95
|
+
result.packages.push(path.join(wsBase, entry.name));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
console.log(JSON.stringify(result, null, 2));
|
|
104
|
+
"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Store as `monorepo_info`. Log project type:
|
|
108
|
+
- Monorepo: "Detected monorepo with {N} workspace packages: {list}"
|
|
109
|
+
- Single repo: "Single repository project detected."
|
|
110
|
+
|
|
111
|
+
## Step 2: Run tag scanner (with monorepo awareness)
|
|
112
|
+
|
|
113
|
+
If monorepo detected, scan each workspace package independently AND the root:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
node -e "
|
|
117
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
118
|
+
const fs = require('node:fs');
|
|
119
|
+
const path = require('node:path');
|
|
120
|
+
|
|
121
|
+
const monorepoInfo = JSON.parse(process.argv[1]);
|
|
122
|
+
const projectRoot = process.cwd();
|
|
123
|
+
|
|
124
|
+
if (monorepoInfo.isMonorepo) {
|
|
125
|
+
// Scan root first
|
|
126
|
+
const rootTags = scanner.scanDirectory(projectRoot, { projectRoot });
|
|
127
|
+
const allTags = [...rootTags];
|
|
128
|
+
|
|
129
|
+
// Scan each workspace package
|
|
130
|
+
for (const pkg of monorepoInfo.packages) {
|
|
131
|
+
const pkgDir = path.join(projectRoot, pkg);
|
|
132
|
+
if (fs.existsSync(pkgDir)) {
|
|
133
|
+
const pkgTags = scanner.scanDirectory(pkgDir, { projectRoot });
|
|
134
|
+
allTags.push(...pkgTags);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Deduplicate by file+line
|
|
139
|
+
const seen = new Set();
|
|
140
|
+
const deduped = allTags.filter(t => {
|
|
141
|
+
const key = t.file + ':' + t.line;
|
|
142
|
+
if (seen.has(key)) return false;
|
|
143
|
+
seen.add(key);
|
|
144
|
+
return true;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
console.log(JSON.stringify(deduped, null, 2));
|
|
148
|
+
} else {
|
|
149
|
+
const tags = scanner.scanDirectory(projectRoot);
|
|
150
|
+
console.log(JSON.stringify(tags, null, 2));
|
|
151
|
+
}
|
|
152
|
+
" '<MONOREPO_INFO_JSON>'
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Store as `all_tags`.
|
|
156
|
+
|
|
157
|
+
## Step 3: Group tags by feature and by package
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
node -e "
|
|
161
|
+
const tags = JSON.parse(process.argv[1]);
|
|
162
|
+
const groups = {};
|
|
163
|
+
const packageGroups = {};
|
|
164
|
+
|
|
165
|
+
for (const tag of tags) {
|
|
166
|
+
// Group by feature
|
|
167
|
+
const fid = (tag.metadata && tag.metadata.feature) || '(unassigned)';
|
|
168
|
+
if (!groups[fid]) groups[fid] = [];
|
|
169
|
+
groups[fid].push(tag);
|
|
170
|
+
|
|
171
|
+
// Group by package (first path segment if monorepo)
|
|
172
|
+
const parts = tag.file.split('/');
|
|
173
|
+
const pkg = parts.length > 2 && parts[0] === 'packages' ? parts[0] + '/' + parts[1] : '(root)';
|
|
174
|
+
if (!packageGroups[pkg]) packageGroups[pkg] = [];
|
|
175
|
+
packageGroups[pkg].push(tag);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
console.log(JSON.stringify({ byFeature: groups, byPackage: packageGroups }, null, 2));
|
|
179
|
+
" '<ALL_TAGS_JSON>'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Step 4: Cross-reference and detect orphans
|
|
183
|
+
|
|
184
|
+
Same as base scan -- run orphan detection against FEATURE-MAP.md.
|
|
185
|
+
|
|
186
|
+
## Step 5: Auto-enrich Feature Map with cross-package file references
|
|
187
|
+
|
|
188
|
+
<!-- @gsd-decision Cross-package file refs are stored as full relative paths from project root. This means packages/core/src/auth.ts, not just src/auth.ts. Feature Map readers can identify the package from the path prefix. -->
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
node -e "
|
|
192
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
193
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
194
|
+
const tags = scanner.scanDirectory(process.cwd());
|
|
195
|
+
const updated = fm.enrichFromTags(process.cwd(), tags);
|
|
196
|
+
console.log(JSON.stringify({
|
|
197
|
+
features_enriched: updated.features.filter(f => f.files.length > 0).length,
|
|
198
|
+
total_file_refs: updated.features.reduce((sum, f) => sum + f.files.length, 0),
|
|
199
|
+
cross_package_refs: updated.features.reduce((sum, f) =>
|
|
200
|
+
sum + f.files.filter(fp => fp.startsWith('packages/')).length, 0)
|
|
201
|
+
}));
|
|
202
|
+
"
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## Step 6: Output results
|
|
206
|
+
|
|
207
|
+
**Formatted report (default):**
|
|
208
|
+
|
|
209
|
+
```
|
|
210
|
+
cap:scan complete.
|
|
211
|
+
|
|
212
|
+
{If monorepo:}
|
|
213
|
+
Monorepo: {workspace_count} packages scanned
|
|
214
|
+
{For each package:}
|
|
215
|
+
- {package_name}: {tag_count} tags
|
|
216
|
+
|
|
217
|
+
Tags found: {total_tags}
|
|
218
|
+
@cap-feature: {count}
|
|
219
|
+
@cap-todo: {count}
|
|
220
|
+
@cap-risk: {count}
|
|
221
|
+
@cap-decision:{count}
|
|
222
|
+
|
|
223
|
+
Coverage: {files_with_tags} of {total_source_files} source files ({percentage}%)
|
|
224
|
+
|
|
225
|
+
Feature Map enrichment:
|
|
226
|
+
Features with file refs: {N}
|
|
227
|
+
Total file references: {N}
|
|
228
|
+
{If monorepo:} Cross-package refs: {N}
|
|
229
|
+
|
|
230
|
+
{Orphan section same as base scan}
|
|
231
|
+
|
|
232
|
+
Feature breakdown:
|
|
233
|
+
{For each feature group:}
|
|
234
|
+
{feature_id}: {count} tags ({type breakdown})
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Step 7: Update session
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
node -e "
|
|
241
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
242
|
+
session.updateSession(process.cwd(), {
|
|
243
|
+
lastCommand: '/cap:scan',
|
|
244
|
+
lastCommandTimestamp: new Date().toISOString()
|
|
245
|
+
});
|
|
246
|
+
"
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
</process>
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cap:start
|
|
3
|
+
description: Initialize a CAP session -- restore previous session state, detect project context, and get working immediately.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- AskUserQuestion
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
<!-- @gsd-context CAP v2.0 start command -- session initialization at the start of a new conversation. Restores .cap/SESSION.json state, detects workspace type, and presents current Feature Map status. -->
|
|
12
|
+
<!-- @gsd-decision Start reads SESSION.json to restore context from previous conversation. This is critical for cross-conversation continuity since Claude Code conversations are stateless. -->
|
|
13
|
+
<!-- @gsd-decision Start auto-runs /cap:init if .cap/ directory does not exist -- first-time users get bootstrapped automatically. -->
|
|
14
|
+
|
|
15
|
+
<objective>
|
|
16
|
+
Initialize a CAP session at the start of a new conversation:
|
|
17
|
+
1. Check if .cap/ exists -- if not, auto-initialize
|
|
18
|
+
2. Auto-detect project info from package.json and directory structure
|
|
19
|
+
3. Load .cap/SESSION.json for previous session state
|
|
20
|
+
4. List features from FEATURE-MAP.md for user selection
|
|
21
|
+
5. Present current status and suggest next action
|
|
22
|
+
|
|
23
|
+
No arguments needed -- always runs the same flow.
|
|
24
|
+
</objective>
|
|
25
|
+
|
|
26
|
+
<context>
|
|
27
|
+
$ARGUMENTS
|
|
28
|
+
|
|
29
|
+
@.cap/SESSION.json
|
|
30
|
+
@FEATURE-MAP.md
|
|
31
|
+
</context>
|
|
32
|
+
|
|
33
|
+
<process>
|
|
34
|
+
|
|
35
|
+
## Step 1: Check for .cap/ directory and auto-initialize
|
|
36
|
+
|
|
37
|
+
<!-- @gsd-todo(ref:AC-34) /cap:start shall initialize a session by setting the active feature in SESSION.json and restoring context from the Feature Map. -->
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
test -d .cap && echo "initialized" || echo "not_initialized"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**If not initialized:**
|
|
44
|
+
|
|
45
|
+
Log: "First run detected. Initializing .cap/ directory..."
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
node -e "
|
|
49
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
50
|
+
session.initCapDirectory(process.cwd());
|
|
51
|
+
console.log('initialized');
|
|
52
|
+
"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Check if FEATURE-MAP.md exists:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
test -f FEATURE-MAP.md && echo "exists" || echo "missing"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If FEATURE-MAP.md does not exist, generate the template:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
node -e "
|
|
65
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
66
|
+
const fs = require('node:fs');
|
|
67
|
+
const path = require('node:path');
|
|
68
|
+
const template = fm.generateTemplate();
|
|
69
|
+
fs.writeFileSync(path.join(process.cwd(), 'FEATURE-MAP.md'), template, 'utf8');
|
|
70
|
+
console.log('FEATURE-MAP.md created');
|
|
71
|
+
"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Log: "Created .cap/ directory and FEATURE-MAP.md"
|
|
75
|
+
|
|
76
|
+
## Step 2: Auto-detect project context
|
|
77
|
+
|
|
78
|
+
<!-- @gsd-todo(ref:AC-35) /cap:start shall auto-scope to the project by deriving project information from actual code (package.json, directory structure) rather than asking questions. -->
|
|
79
|
+
|
|
80
|
+
Detect project info from the filesystem -- no questions asked:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
node -e "
|
|
84
|
+
const fs = require('node:fs');
|
|
85
|
+
const path = require('node:path');
|
|
86
|
+
const cwd = process.cwd();
|
|
87
|
+
const info = { name: path.basename(cwd), language: 'unknown', framework: 'unknown', testFramework: 'unknown' };
|
|
88
|
+
|
|
89
|
+
// Read package.json if available
|
|
90
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
91
|
+
if (fs.existsSync(pkgPath)) {
|
|
92
|
+
try {
|
|
93
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
94
|
+
info.name = pkg.name || info.name;
|
|
95
|
+
info.language = 'javascript';
|
|
96
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
97
|
+
if (allDeps.typescript) info.language = 'typescript';
|
|
98
|
+
if (allDeps.react) info.framework = 'react';
|
|
99
|
+
if (allDeps.next) info.framework = 'next.js';
|
|
100
|
+
if (allDeps.express) info.framework = 'express';
|
|
101
|
+
if (allDeps.vitest) info.testFramework = 'vitest';
|
|
102
|
+
else if (allDeps.jest) info.testFramework = 'jest';
|
|
103
|
+
else if (pkg.scripts && pkg.scripts.test && pkg.scripts.test.includes('node --test')) info.testFramework = 'node:test';
|
|
104
|
+
} catch (e) {}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Check for Python
|
|
108
|
+
if (fs.existsSync(path.join(cwd, 'requirements.txt')) || fs.existsSync(path.join(cwd, 'pyproject.toml'))) {
|
|
109
|
+
info.language = 'python';
|
|
110
|
+
if (fs.existsSync(path.join(cwd, 'pyproject.toml'))) {
|
|
111
|
+
const content = fs.readFileSync(path.join(cwd, 'pyproject.toml'), 'utf8');
|
|
112
|
+
if (content.includes('django')) info.framework = 'django';
|
|
113
|
+
if (content.includes('fastapi')) info.framework = 'fastapi';
|
|
114
|
+
if (content.includes('pytest')) info.testFramework = 'pytest';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Check for Go
|
|
119
|
+
if (fs.existsSync(path.join(cwd, 'go.mod'))) {
|
|
120
|
+
info.language = 'go';
|
|
121
|
+
info.testFramework = 'go test';
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check for Rust
|
|
125
|
+
if (fs.existsSync(path.join(cwd, 'Cargo.toml'))) {
|
|
126
|
+
info.language = 'rust';
|
|
127
|
+
info.testFramework = 'cargo test';
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
console.log(JSON.stringify(info));
|
|
131
|
+
"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Store as `project_info`.
|
|
135
|
+
|
|
136
|
+
## Step 3: Load session state
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
node -e "
|
|
140
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
141
|
+
const s = session.loadSession(process.cwd());
|
|
142
|
+
console.log(JSON.stringify(s));
|
|
143
|
+
"
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Store as `session`.
|
|
147
|
+
|
|
148
|
+
## Step 4: Load Feature Map and present features
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
node -e "
|
|
152
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
153
|
+
const featureMap = fm.readFeatureMap(process.cwd());
|
|
154
|
+
const status = fm.getStatus(featureMap);
|
|
155
|
+
console.log(JSON.stringify({
|
|
156
|
+
features: featureMap.features.map(f => ({ id: f.id, title: f.title, state: f.state, acCount: f.acs.length })),
|
|
157
|
+
...status
|
|
158
|
+
}));
|
|
159
|
+
"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Store as `fm_data`.
|
|
163
|
+
|
|
164
|
+
## Step 5: Present session context and select active feature
|
|
165
|
+
|
|
166
|
+
Display session restoration:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
=== CAP Session Start ===
|
|
170
|
+
|
|
171
|
+
Project: {project_info.name} ({project_info.language} / {project_info.framework})
|
|
172
|
+
Test framework: {project_info.testFramework}
|
|
173
|
+
|
|
174
|
+
{If session.activeFeature:}
|
|
175
|
+
Previous session:
|
|
176
|
+
Active feature: {session.activeFeature}
|
|
177
|
+
Last step: {session.step}
|
|
178
|
+
Last command: {session.lastCommand}
|
|
179
|
+
|
|
180
|
+
{End if}
|
|
181
|
+
|
|
182
|
+
Features ({fm_data.totalFeatures} total):
|
|
183
|
+
planned: {count}
|
|
184
|
+
prototyped: {count}
|
|
185
|
+
tested: {count}
|
|
186
|
+
shipped: {count}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**If features exist, list them and ask user to select:**
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
Available features:
|
|
193
|
+
{For each feature:}
|
|
194
|
+
{feature.id}: {feature.title} [{feature.state}] ({feature.acCount} ACs)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
If `session.activeFeature` is set, offer to continue:
|
|
198
|
+
|
|
199
|
+
Use AskUserQuestion:
|
|
200
|
+
> "Continue working on {session.activeFeature} ({title})? Or enter a feature ID to switch (e.g., F-001). Type 'none' to work without a focused feature."
|
|
201
|
+
|
|
202
|
+
If no active feature:
|
|
203
|
+
|
|
204
|
+
Use AskUserQuestion:
|
|
205
|
+
> "Select a feature to focus on (enter feature ID, e.g., F-001), or type 'none' to skip."
|
|
206
|
+
|
|
207
|
+
**Process user response:**
|
|
208
|
+
- If a valid feature ID: set as active feature
|
|
209
|
+
- If `none` or `skip`: proceed without active feature
|
|
210
|
+
- If continuing previous: keep existing active feature
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
node -e "
|
|
214
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
215
|
+
session.startSession(process.cwd(), '{selected_feature_id}', 'start');
|
|
216
|
+
console.log('Session updated');
|
|
217
|
+
"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Step 6: Suggest next action
|
|
221
|
+
|
|
222
|
+
Based on current state, suggest:
|
|
223
|
+
|
|
224
|
+
- If no features: "No features found. Run /cap:brainstorm to discover features."
|
|
225
|
+
- If active feature is `planned`: "Run /cap:prototype to build initial code for {feature}."
|
|
226
|
+
- If active feature is `prototyped`: "Run /cap:iterate to refine, or /cap:test to write tests."
|
|
227
|
+
- If active feature is `tested`: "Run /cap:review to verify {feature}."
|
|
228
|
+
- If active feature is `shipped`: "All done with {feature}. Select a different feature or run /cap:brainstorm."
|
|
229
|
+
|
|
230
|
+
```
|
|
231
|
+
Session started. Suggested next: {action}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
</process>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cap:status
|
|
3
|
+
description: Show project status derived from Feature Map -- feature completion, test coverage, open risks, and next actions.
|
|
4
|
+
argument-hint: "[--features NAME] [--verbose]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Bash
|
|
8
|
+
- Glob
|
|
9
|
+
- Grep
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<!-- @gsd-context CAP v2.0 status command -- reads FEATURE-MAP.md and .cap/SESSION.json to present a compact project status dashboard. No agent spawning, no file writes. -->
|
|
13
|
+
<!-- @gsd-decision Status is read-only -- it presents information but never modifies Feature Map or session state. Safe to run at any time. -->
|
|
14
|
+
<!-- @gsd-decision Status derives from Feature Map, session state, AND live tag scan -- gives a complete picture without requiring a separate /cap:scan first. -->
|
|
15
|
+
|
|
16
|
+
<objective>
|
|
17
|
+
Presents a compact project status dashboard derived from FEATURE-MAP.md, SESSION.json, and a live tag count:
|
|
18
|
+
- Current session state (active feature, step, duration)
|
|
19
|
+
- Feature completion by state (planned, prototyped, tested, shipped)
|
|
20
|
+
- Tag coverage statistics (files with tags vs total source files)
|
|
21
|
+
|
|
22
|
+
**Arguments:**
|
|
23
|
+
- `--features NAME` -- show status for specific features only
|
|
24
|
+
- `--verbose` -- include per-AC breakdown
|
|
25
|
+
</objective>
|
|
26
|
+
|
|
27
|
+
<context>
|
|
28
|
+
$ARGUMENTS
|
|
29
|
+
|
|
30
|
+
@FEATURE-MAP.md
|
|
31
|
+
@.cap/SESSION.json
|
|
32
|
+
</context>
|
|
33
|
+
|
|
34
|
+
<process>
|
|
35
|
+
|
|
36
|
+
## Step 0: Parse flags
|
|
37
|
+
|
|
38
|
+
Check `$ARGUMENTS` for:
|
|
39
|
+
- `--features NAME` -- if present, store as `feature_filter` (comma-separated)
|
|
40
|
+
- `--verbose` -- if present, set `verbose = true`
|
|
41
|
+
|
|
42
|
+
## Step 1: Read session state
|
|
43
|
+
|
|
44
|
+
<!-- @gsd-todo(ref:AC-31) /cap:status shall display the current session state from SESSION.json (active feature, current step, session duration). -->
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
node -e "
|
|
48
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
49
|
+
const s = session.loadSession(process.cwd());
|
|
50
|
+
const duration = s.startedAt ? Math.round((Date.now() - new Date(s.startedAt).getTime()) / 60000) : null;
|
|
51
|
+
console.log(JSON.stringify({
|
|
52
|
+
activeFeature: s.activeFeature,
|
|
53
|
+
step: s.step,
|
|
54
|
+
startedAt: s.startedAt,
|
|
55
|
+
durationMinutes: duration,
|
|
56
|
+
lastCommand: s.lastCommand,
|
|
57
|
+
lastCommandTimestamp: s.lastCommandTimestamp,
|
|
58
|
+
activeDebugSession: s.activeDebugSession
|
|
59
|
+
}));
|
|
60
|
+
"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Store as `session_state`.
|
|
64
|
+
|
|
65
|
+
## Step 2: Read Feature Map status
|
|
66
|
+
|
|
67
|
+
<!-- @gsd-todo(ref:AC-32) /cap:status shall display a summary of FEATURE-MAP.md (count of features per state: planned, prototyped, tested, shipped). -->
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
node -e "
|
|
71
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
72
|
+
const featureMap = fm.readFeatureMap(process.cwd());
|
|
73
|
+
const status = fm.getStatus(featureMap);
|
|
74
|
+
const byState = { planned: 0, prototyped: 0, tested: 0, shipped: 0 };
|
|
75
|
+
for (const f of featureMap.features) {
|
|
76
|
+
byState[f.state] = (byState[f.state] || 0) + 1;
|
|
77
|
+
}
|
|
78
|
+
console.log(JSON.stringify({
|
|
79
|
+
...status,
|
|
80
|
+
byState,
|
|
81
|
+
features: featureMap.features.map(f => ({
|
|
82
|
+
id: f.id,
|
|
83
|
+
title: f.title,
|
|
84
|
+
state: f.state,
|
|
85
|
+
acCount: f.acs.length,
|
|
86
|
+
acsImplemented: f.acs.filter(a => a.status === 'implemented').length,
|
|
87
|
+
acsTested: f.acs.filter(a => a.status === 'tested').length,
|
|
88
|
+
acsReviewed: f.acs.filter(a => a.status === 'reviewed').length,
|
|
89
|
+
fileCount: f.files.length,
|
|
90
|
+
dependencies: f.dependencies
|
|
91
|
+
})),
|
|
92
|
+
lastScan: featureMap.lastScan
|
|
93
|
+
}));
|
|
94
|
+
"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Store as `fm_status`. If `feature_filter` is set, filter `fm_status.features` to matching IDs.
|
|
98
|
+
|
|
99
|
+
## Step 3: Compute tag coverage
|
|
100
|
+
|
|
101
|
+
<!-- @gsd-todo(ref:AC-33) /cap:status shall display tag coverage statistics (files with tags vs. total source files). -->
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
node -e "
|
|
105
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
106
|
+
const fs = require('node:fs');
|
|
107
|
+
const path = require('node:path');
|
|
108
|
+
const tags = scanner.scanDirectory(process.cwd());
|
|
109
|
+
const filesWithTags = new Set(tags.map(t => t.file));
|
|
110
|
+
let totalFiles = 0;
|
|
111
|
+
function walk(dir, exclude) {
|
|
112
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
113
|
+
for (const e of entries) {
|
|
114
|
+
if (e.isDirectory() && !exclude.includes(e.name)) walk(path.join(dir, e.name), exclude);
|
|
115
|
+
else if (e.isFile() && scanner.SUPPORTED_EXTENSIONS.includes(path.extname(e.name))) totalFiles++;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
walk(process.cwd(), scanner.DEFAULT_EXCLUDE);
|
|
119
|
+
const byType = {};
|
|
120
|
+
for (const t of tags) { byType[t.type] = (byType[t.type] || 0) + 1; }
|
|
121
|
+
console.log(JSON.stringify({ filesWithTags: filesWithTags.size, totalFiles, totalTags: tags.length, byType }));
|
|
122
|
+
"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Store as `tag_stats`.
|
|
126
|
+
|
|
127
|
+
## Step 4: Present formatted dashboard
|
|
128
|
+
|
|
129
|
+
Display:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
=== CAP Status ===
|
|
133
|
+
|
|
134
|
+
Session:
|
|
135
|
+
Active feature: {session_state.activeFeature or "none"}
|
|
136
|
+
Current step: {session_state.step or "none"}
|
|
137
|
+
Session duration: {session_state.durationMinutes} minutes {or "no active session"}
|
|
138
|
+
Last command: {session_state.lastCommand} ({session_state.lastCommandTimestamp})
|
|
139
|
+
|
|
140
|
+
Features ({fm_status.totalFeatures} total):
|
|
141
|
+
planned: {byState.planned}
|
|
142
|
+
prototyped: {byState.prototyped}
|
|
143
|
+
tested: {byState.tested}
|
|
144
|
+
shipped: {byState.shipped}
|
|
145
|
+
|
|
146
|
+
Acceptance Criteria:
|
|
147
|
+
Total: {fm_status.totalACs}
|
|
148
|
+
Implemented: {fm_status.implementedACs}
|
|
149
|
+
Tested: {fm_status.testedACs}
|
|
150
|
+
Reviewed: {fm_status.reviewedACs}
|
|
151
|
+
|
|
152
|
+
Tag Coverage:
|
|
153
|
+
Source files with @cap-* tags: {tag_stats.filesWithTags} of {tag_stats.totalFiles} ({percentage}%)
|
|
154
|
+
Total tags: {tag_stats.totalTags}
|
|
155
|
+
@cap-feature: {byType.feature or 0}
|
|
156
|
+
@cap-todo: {byType.todo or 0}
|
|
157
|
+
@cap-risk: {byType.risk or 0}
|
|
158
|
+
@cap-decision: {byType.decision or 0}
|
|
159
|
+
|
|
160
|
+
Last scan: {fm_status.lastScan or "never"}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**If `verbose` is true:**
|
|
164
|
+
|
|
165
|
+
For each feature in scope, display:
|
|
166
|
+
|
|
167
|
+
```
|
|
168
|
+
{feature.id}: {feature.title} [{feature.state}]
|
|
169
|
+
ACs: {feature.acCount} total, {feature.acsImplemented} implemented, {feature.acsTested} tested
|
|
170
|
+
Files: {feature.fileCount}
|
|
171
|
+
Dependencies: {feature.dependencies.join(', ') or 'none'}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Step 5: Suggest next action
|
|
175
|
+
|
|
176
|
+
Based on current state, suggest the most useful next command:
|
|
177
|
+
|
|
178
|
+
- If no features exist: "Run /cap:brainstorm to discover features."
|
|
179
|
+
- If all features are `planned`: "Run /cap:prototype to build initial scaffolds."
|
|
180
|
+
- If active feature is `prototyped`: "Run /cap:test to write tests for {activeFeature}."
|
|
181
|
+
- If active feature is `tested`: "Run /cap:review to verify {activeFeature}."
|
|
182
|
+
- If tag coverage < 50%: "Run /cap:scan or /cap:annotate to improve tag coverage."
|
|
183
|
+
- Otherwise: "Run /cap:iterate to continue development."
|
|
184
|
+
|
|
185
|
+
```
|
|
186
|
+
Suggested next: {action}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
</process>
|