cap-pro 1.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/.claude-plugin/README.md +26 -0
- package/.claude-plugin/marketplace.json +24 -0
- package/.claude-plugin/plugin.json +24 -0
- package/LICENSE +21 -0
- package/README.ja-JP.md +834 -0
- package/README.ko-KR.md +823 -0
- package/README.md +806 -0
- package/README.pt-BR.md +452 -0
- package/README.zh-CN.md +800 -0
- package/agents/cap-architect.md +269 -0
- package/agents/cap-brainstormer.md +207 -0
- package/agents/cap-curator.md +276 -0
- package/agents/cap-debugger.md +365 -0
- package/agents/cap-designer.md +246 -0
- package/agents/cap-historian.md +464 -0
- package/agents/cap-migrator.md +291 -0
- package/agents/cap-prototyper.md +197 -0
- package/agents/cap-validator.md +308 -0
- package/bin/install.js +5433 -0
- package/cap/bin/cap-tools.cjs +853 -0
- package/cap/bin/lib/arc-scanner.cjs +344 -0
- package/cap/bin/lib/cap-affinity-engine.cjs +862 -0
- package/cap/bin/lib/cap-anchor.cjs +228 -0
- package/cap/bin/lib/cap-annotation-writer.cjs +340 -0
- package/cap/bin/lib/cap-checkpoint.cjs +434 -0
- package/cap/bin/lib/cap-cluster-detect.cjs +945 -0
- package/cap/bin/lib/cap-cluster-display.cjs +52 -0
- package/cap/bin/lib/cap-cluster-format.cjs +245 -0
- package/cap/bin/lib/cap-cluster-helpers.cjs +295 -0
- package/cap/bin/lib/cap-cluster-io.cjs +212 -0
- package/cap/bin/lib/cap-completeness.cjs +540 -0
- package/cap/bin/lib/cap-deps.cjs +583 -0
- package/cap/bin/lib/cap-design-families.cjs +332 -0
- package/cap/bin/lib/cap-design.cjs +966 -0
- package/cap/bin/lib/cap-divergence-detector.cjs +400 -0
- package/cap/bin/lib/cap-doctor.cjs +752 -0
- package/cap/bin/lib/cap-feature-map-internals.cjs +19 -0
- package/cap/bin/lib/cap-feature-map-migrate.cjs +335 -0
- package/cap/bin/lib/cap-feature-map-monorepo.cjs +885 -0
- package/cap/bin/lib/cap-feature-map-shard.cjs +315 -0
- package/cap/bin/lib/cap-feature-map.cjs +1943 -0
- package/cap/bin/lib/cap-fitness-score.cjs +1075 -0
- package/cap/bin/lib/cap-impact-analysis.cjs +652 -0
- package/cap/bin/lib/cap-learn-review.cjs +1072 -0
- package/cap/bin/lib/cap-learning-signals.cjs +627 -0
- package/cap/bin/lib/cap-loader.cjs +227 -0
- package/cap/bin/lib/cap-logger.cjs +57 -0
- package/cap/bin/lib/cap-memory-bridge.cjs +764 -0
- package/cap/bin/lib/cap-memory-confidence.cjs +452 -0
- package/cap/bin/lib/cap-memory-dir.cjs +987 -0
- package/cap/bin/lib/cap-memory-engine.cjs +698 -0
- package/cap/bin/lib/cap-memory-extends.cjs +398 -0
- package/cap/bin/lib/cap-memory-graph.cjs +790 -0
- package/cap/bin/lib/cap-memory-migrate.cjs +2015 -0
- package/cap/bin/lib/cap-memory-pin.cjs +183 -0
- package/cap/bin/lib/cap-memory-platform.cjs +490 -0
- package/cap/bin/lib/cap-memory-prune.cjs +707 -0
- package/cap/bin/lib/cap-memory-schema.cjs +812 -0
- package/cap/bin/lib/cap-migrate-tags.cjs +309 -0
- package/cap/bin/lib/cap-migrate.cjs +540 -0
- package/cap/bin/lib/cap-pattern-apply.cjs +1203 -0
- package/cap/bin/lib/cap-pattern-pipeline.cjs +1034 -0
- package/cap/bin/lib/cap-plugin-manifest.cjs +80 -0
- package/cap/bin/lib/cap-realtime-affinity.cjs +399 -0
- package/cap/bin/lib/cap-reconcile.cjs +570 -0
- package/cap/bin/lib/cap-research-gate.cjs +218 -0
- package/cap/bin/lib/cap-scope-filter.cjs +402 -0
- package/cap/bin/lib/cap-semantic-pipeline.cjs +1038 -0
- package/cap/bin/lib/cap-session-extract.cjs +987 -0
- package/cap/bin/lib/cap-session.cjs +445 -0
- package/cap/bin/lib/cap-snapshot-linkage.cjs +963 -0
- package/cap/bin/lib/cap-stack-docs.cjs +646 -0
- package/cap/bin/lib/cap-tag-observer.cjs +371 -0
- package/cap/bin/lib/cap-tag-scanner.cjs +1766 -0
- package/cap/bin/lib/cap-telemetry.cjs +466 -0
- package/cap/bin/lib/cap-test-audit.cjs +1438 -0
- package/cap/bin/lib/cap-thread-migrator.cjs +307 -0
- package/cap/bin/lib/cap-thread-synthesis.cjs +545 -0
- package/cap/bin/lib/cap-thread-tracker.cjs +519 -0
- package/cap/bin/lib/cap-trace.cjs +399 -0
- package/cap/bin/lib/cap-trust-mode.cjs +336 -0
- package/cap/bin/lib/cap-ui-design-editor.cjs +642 -0
- package/cap/bin/lib/cap-ui-mind-map.cjs +712 -0
- package/cap/bin/lib/cap-ui-thread-nav.cjs +693 -0
- package/cap/bin/lib/cap-ui.cjs +1245 -0
- package/cap/bin/lib/cap-upgrade.cjs +1028 -0
- package/cap/bin/lib/cli/arg-helpers.cjs +49 -0
- package/cap/bin/lib/cli/frontmatter-router.cjs +31 -0
- package/cap/bin/lib/cli/init-router.cjs +68 -0
- package/cap/bin/lib/cli/phase-router.cjs +102 -0
- package/cap/bin/lib/cli/state-router.cjs +61 -0
- package/cap/bin/lib/cli/template-router.cjs +37 -0
- package/cap/bin/lib/cli/uat-router.cjs +29 -0
- package/cap/bin/lib/cli/validation-router.cjs +26 -0
- package/cap/bin/lib/cli/verification-router.cjs +31 -0
- package/cap/bin/lib/cli/workstream-router.cjs +39 -0
- package/cap/bin/lib/commands.cjs +961 -0
- package/cap/bin/lib/config.cjs +467 -0
- package/cap/bin/lib/convention-reader.cjs +258 -0
- package/cap/bin/lib/core.cjs +1241 -0
- package/cap/bin/lib/feature-aggregator.cjs +423 -0
- package/cap/bin/lib/frontmatter.cjs +337 -0
- package/cap/bin/lib/init.cjs +1443 -0
- package/cap/bin/lib/manifest-generator.cjs +383 -0
- package/cap/bin/lib/milestone.cjs +253 -0
- package/cap/bin/lib/model-profiles.cjs +69 -0
- package/cap/bin/lib/monorepo-context.cjs +226 -0
- package/cap/bin/lib/monorepo-migrator.cjs +509 -0
- package/cap/bin/lib/phase.cjs +889 -0
- package/cap/bin/lib/profile-output.cjs +989 -0
- package/cap/bin/lib/profile-pipeline.cjs +540 -0
- package/cap/bin/lib/roadmap.cjs +330 -0
- package/cap/bin/lib/security.cjs +394 -0
- package/cap/bin/lib/session-manager.cjs +292 -0
- package/cap/bin/lib/skeleton-generator.cjs +179 -0
- package/cap/bin/lib/state.cjs +1032 -0
- package/cap/bin/lib/template.cjs +231 -0
- package/cap/bin/lib/test-detector.cjs +62 -0
- package/cap/bin/lib/uat.cjs +283 -0
- package/cap/bin/lib/verify.cjs +889 -0
- package/cap/bin/lib/workspace-detector.cjs +371 -0
- package/cap/bin/lib/workstream.cjs +492 -0
- package/cap/commands/gsd/workstreams.md +63 -0
- package/cap/references/arc-standard.md +315 -0
- package/cap/references/cap-agent-architecture.md +101 -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/contract-test-templates.md +312 -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-profiles.md +174 -0
- package/cap/references/phase-numbering.md +126 -0
- package/cap/references/planning-config.md +202 -0
- package/cap/references/property-test-templates.md +316 -0
- package/cap/references/security-test-templates.md +347 -0
- package/cap/references/session-template.json +8 -0
- package/cap/references/tdd.md +263 -0
- package/cap/references/user-profiling.md +681 -0
- package/cap/references/verification-patterns.md +612 -0
- package/cap/templates/UAT.md +265 -0
- package/cap/templates/claude-md.md +175 -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/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/roadmap.md +202 -0
- package/cap/templates/state.md +176 -0
- package/cap/templates/summary.md +364 -0
- package/cap/templates/user-preferences.md +498 -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 +857 -0
- package/cap/workflows/plant-seed.md +169 -0
- package/cap/workflows/pr-branch.md +129 -0
- package/cap/workflows/profile-user.md +449 -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 +298 -0
- package/cap/workflows/ui-review.md +161 -0
- package/cap/workflows/update.md +323 -0
- package/cap/workflows/validate-phase.md +170 -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 +393 -0
- package/commands/cap/checkpoint.md +106 -0
- package/commands/cap/completeness.md +94 -0
- package/commands/cap/continue.md +72 -0
- package/commands/cap/debug.md +588 -0
- package/commands/cap/deps.md +169 -0
- package/commands/cap/design.md +479 -0
- package/commands/cap/init.md +354 -0
- package/commands/cap/iterate.md +249 -0
- package/commands/cap/learn.md +459 -0
- package/commands/cap/memory.md +275 -0
- package/commands/cap/migrate-feature-map.md +91 -0
- package/commands/cap/migrate-memory.md +108 -0
- package/commands/cap/migrate-tags.md +91 -0
- package/commands/cap/migrate.md +131 -0
- package/commands/cap/prototype.md +510 -0
- package/commands/cap/reconcile.md +121 -0
- package/commands/cap/review.md +360 -0
- package/commands/cap/save.md +72 -0
- package/commands/cap/scan.md +404 -0
- package/commands/cap/start.md +356 -0
- package/commands/cap/status.md +118 -0
- package/commands/cap/test-audit.md +262 -0
- package/commands/cap/test.md +394 -0
- package/commands/cap/trace.md +133 -0
- package/commands/cap/ui.md +167 -0
- package/hooks/dist/cap-check-update.js +115 -0
- package/hooks/dist/cap-context-monitor.js +185 -0
- package/hooks/dist/cap-learn-review-hook.js +114 -0
- package/hooks/dist/cap-learning-hook.js +192 -0
- package/hooks/dist/cap-memory.js +299 -0
- package/hooks/dist/cap-prompt-guard.js +97 -0
- package/hooks/dist/cap-statusline.js +157 -0
- package/hooks/dist/cap-tag-observer.js +115 -0
- package/hooks/dist/cap-version-check.js +112 -0
- package/hooks/dist/cap-workflow-guard.js +175 -0
- package/hooks/hooks.json +55 -0
- package/package.json +58 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +93 -0
- package/scripts/cap-removal-checklist.md +202 -0
- package/scripts/prompt-injection-scan.sh +199 -0
- package/scripts/run-tests.cjs +181 -0
- package/scripts/secret-scan.sh +227 -0
|
@@ -0,0 +1,404 @@
|
|
|
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] [--strict] [--include=<glob>] [--exclude=<glob>]"
|
|
5
|
+
allowed-tools:
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Bash
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<!-- @cap-context CAP v2.0 scan command (final pass) -- adds monorepo workspace traversal and cross-package file references to the base scan flow. -->
|
|
14
|
+
<!-- @cap-decision Monorepo detection is automatic -- checks package.json workspaces field and lerna.json. No --monorepo flag required (AC-80). -->
|
|
15
|
+
<!-- @cap-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
|
+
<!-- @cap-constraint Works seamlessly with normal single-repo projects -- monorepo features are additive, not blocking (AC-80). -->
|
|
17
|
+
<!-- @cap-feature(feature:F-085) Scope filter — gitignore-aware, plugin-mirror-aware, with --include/--exclude glob overrides. Shared with cap-migrate-tags via cap-scope-filter.cjs. -->
|
|
18
|
+
|
|
19
|
+
<!-- @cap-todo(ref:AC-78) /cap:scan shall traverse all packages in a monorepo -->
|
|
20
|
+
<!-- @cap-todo(ref:AC-79) Feature Map entries shall support cross-package file references -->
|
|
21
|
+
<!-- @cap-todo(ref:AC-80) CAP shall work seamlessly with normal single-repo projects with no monorepo-specific configuration required -->
|
|
22
|
+
<!-- @cap-feature(feature:F-046) Polylingual tag context detection: --strict flag fails the scan if any @cap-* token is found outside a recognized comment context. -->
|
|
23
|
+
<!-- @cap-todo(ac:F-046/AC-4) /cap:scan --strict invokes scanner.scanDirectoryWithContext with strict:true for CI enforcement. -->
|
|
24
|
+
|
|
25
|
+
<objective>
|
|
26
|
+
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.
|
|
27
|
+
|
|
28
|
+
**Monorepo support:**
|
|
29
|
+
- Automatically detects npm/yarn/pnpm workspaces from package.json `workspaces` field
|
|
30
|
+
- Detects Lerna monorepos from lerna.json
|
|
31
|
+
- Traverses all workspace packages independently
|
|
32
|
+
- File references use full paths from project root (e.g., `packages/core/src/auth.ts`)
|
|
33
|
+
|
|
34
|
+
**Polylingual context detection (F-046):**
|
|
35
|
+
- The scanner now classifies each `@cap-*` match against the file's comment syntax (per extension).
|
|
36
|
+
- Tokens found outside any recognized comment (e.g. inside a string literal) are NOT parsed as tags but are reported as warnings.
|
|
37
|
+
- Supported comment styles: `//`, `/* */` (JS/TS/Go/Rust/C/Java/CSS/SCSS), `#` (Python/Ruby/Shell/YAML/TOML), `"""`/`'''` (Python triple-quote), `=begin`/`=end` (Ruby), `///` (Rust doc), `<!-- -->` (HTML/Markdown), `--` (SQL).
|
|
38
|
+
|
|
39
|
+
**Scope filter (F-085):** the scan respects the project's top-level `.gitignore` and an opinionated default-exclude list. By default it skips:
|
|
40
|
+
|
|
41
|
+
- everything matched by `.gitignore` (typically `.claude/`, `node_modules/`, `dist/`, `coverage/`, build caches);
|
|
42
|
+
- agent worktrees under `.claude/worktrees/`;
|
|
43
|
+
- the plugin-self-mirror at `.claude/cap/` (detected when both `bin/` and `commands/` are present);
|
|
44
|
+
- test fixtures under `tests/fixtures/` and `**/fixtures/polyglot/` — fixtures are intentionally raw-tagged.
|
|
45
|
+
|
|
46
|
+
The same scope filter is shared with `cap:migrate-tags` so the two tools never disagree about which files are in scope.
|
|
47
|
+
|
|
48
|
+
**Arguments:**
|
|
49
|
+
- `--features NAME` -- scope scan to specific Feature Map entries (comma-separated)
|
|
50
|
+
- `--json` -- output raw scan results as JSON instead of formatted report
|
|
51
|
+
- `--strict` -- (F-046/AC-4) fail the scan with a non-zero exit code if ANY `@cap-*` token is found outside a recognized comment. Intended for CI enforcement.
|
|
52
|
+
- `--include=<glob>` -- restrict the scan to paths matching the pattern (additive, repeatable).
|
|
53
|
+
- `--exclude=<glob>` -- additionally skip paths matching the pattern (additive, repeatable).
|
|
54
|
+
</objective>
|
|
55
|
+
|
|
56
|
+
<context>
|
|
57
|
+
$ARGUMENTS
|
|
58
|
+
|
|
59
|
+
@FEATURE-MAP.md
|
|
60
|
+
</context>
|
|
61
|
+
|
|
62
|
+
<process>
|
|
63
|
+
|
|
64
|
+
## Step 0: Parse flags
|
|
65
|
+
|
|
66
|
+
Check `$ARGUMENTS` for:
|
|
67
|
+
- `--features NAME` -- if present, store as `feature_filter`
|
|
68
|
+
- `--json` -- if present, set `json_output = true`
|
|
69
|
+
- `--strict` -- if present, set `strict_mode = true` (F-046/AC-4)
|
|
70
|
+
|
|
71
|
+
## Step 0b: Check active app scoping
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
node -e "
|
|
75
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
76
|
+
const s = session.loadSession(process.cwd());
|
|
77
|
+
console.log(JSON.stringify({ activeApp: s.activeApp }));
|
|
78
|
+
"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Store as `app_scope`. If `app_scope.activeApp` is set, this scan will be scoped to the active app directory and its shared packages. The results will be written to the app's FEATURE-MAP.md (not root).
|
|
82
|
+
|
|
83
|
+
## Step 1: Detect monorepo configuration
|
|
84
|
+
|
|
85
|
+
<!-- @cap-decision Monorepo detection reads package.json workspaces and lerna.json. Supports npm, yarn, pnpm workspace patterns. Glob expansion uses Bash for simplicity. -->
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
node -e "
|
|
89
|
+
const fs = require('node:fs');
|
|
90
|
+
const path = require('node:path');
|
|
91
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
92
|
+
const lernaPath = path.join(process.cwd(), 'lerna.json');
|
|
93
|
+
const result = { isMonorepo: false, workspaces: [], packages: [] };
|
|
94
|
+
|
|
95
|
+
// Check package.json workspaces
|
|
96
|
+
if (fs.existsSync(pkgPath)) {
|
|
97
|
+
try {
|
|
98
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
99
|
+
if (pkg.workspaces) {
|
|
100
|
+
result.isMonorepo = true;
|
|
101
|
+
result.workspaces = Array.isArray(pkg.workspaces)
|
|
102
|
+
? pkg.workspaces
|
|
103
|
+
: (pkg.workspaces.packages || []);
|
|
104
|
+
}
|
|
105
|
+
} catch (_e) {}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check pnpm-workspace.yaml
|
|
109
|
+
const pnpmPath = path.join(process.cwd(), 'pnpm-workspace.yaml');
|
|
110
|
+
if (!result.isMonorepo && fs.existsSync(pnpmPath)) {
|
|
111
|
+
try {
|
|
112
|
+
const content = fs.readFileSync(pnpmPath, 'utf8');
|
|
113
|
+
const packagesMatch = content.match(/packages:\\s*\\n((?:\\s+-\\s*.+\\n?)*)/);
|
|
114
|
+
if (packagesMatch) {
|
|
115
|
+
result.isMonorepo = true;
|
|
116
|
+
result.workspaces = packagesMatch[1]
|
|
117
|
+
.split('\\n')
|
|
118
|
+
.map(line => line.replace(/^\\s*-\\s*['\"]?/, '').replace(/['\"]?\\s*$/, ''))
|
|
119
|
+
.filter(Boolean);
|
|
120
|
+
}
|
|
121
|
+
} catch (_e) {}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Check nx.json
|
|
125
|
+
const nxPath = path.join(process.cwd(), 'nx.json');
|
|
126
|
+
if (!result.isMonorepo && fs.existsSync(nxPath)) {
|
|
127
|
+
try {
|
|
128
|
+
const nx = JSON.parse(fs.readFileSync(nxPath, 'utf8'));
|
|
129
|
+
result.isMonorepo = true;
|
|
130
|
+
const layout = nx.workspaceLayout || {};
|
|
131
|
+
const patterns = [];
|
|
132
|
+
if (layout.appsDir) patterns.push(layout.appsDir + '/*');
|
|
133
|
+
if (layout.libsDir) patterns.push(layout.libsDir + '/*');
|
|
134
|
+
if (patterns.length === 0) {
|
|
135
|
+
for (const dir of ['apps', 'packages', 'libs']) {
|
|
136
|
+
if (fs.existsSync(path.join(process.cwd(), dir))) {
|
|
137
|
+
patterns.push(dir + '/*');
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
result.workspaces = patterns;
|
|
142
|
+
} catch (_e) {}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Check lerna.json
|
|
146
|
+
if (!result.isMonorepo && fs.existsSync(lernaPath)) {
|
|
147
|
+
try {
|
|
148
|
+
const lerna = JSON.parse(fs.readFileSync(lernaPath, 'utf8'));
|
|
149
|
+
result.isMonorepo = true;
|
|
150
|
+
result.workspaces = lerna.packages || ['packages/*'];
|
|
151
|
+
} catch (_e) {}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Resolve workspace globs to actual package directories
|
|
155
|
+
if (result.isMonorepo) {
|
|
156
|
+
for (const ws of result.workspaces) {
|
|
157
|
+
const wsBase = ws.replace('/*', '').replace('/**', '');
|
|
158
|
+
const wsDir = path.join(process.cwd(), wsBase);
|
|
159
|
+
if (fs.existsSync(wsDir) && fs.statSync(wsDir).isDirectory()) {
|
|
160
|
+
const entries = fs.readdirSync(wsDir, { withFileTypes: true });
|
|
161
|
+
for (const entry of entries) {
|
|
162
|
+
if (entry.isDirectory()) {
|
|
163
|
+
const pkgJsonPath = path.join(wsDir, entry.name, 'package.json');
|
|
164
|
+
if (fs.existsSync(pkgJsonPath)) {
|
|
165
|
+
result.packages.push(path.join(wsBase, entry.name));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log(JSON.stringify(result, null, 2));
|
|
174
|
+
"
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Store as `monorepo_info`. Log project type:
|
|
178
|
+
- Monorepo: "Detected monorepo with {N} workspace packages: {list}"
|
|
179
|
+
- Single repo: "Single repository project detected."
|
|
180
|
+
|
|
181
|
+
## Step 2: Run tag scanner (with monorepo and app-scoping awareness)
|
|
182
|
+
|
|
183
|
+
**If `app_scope.activeApp` is set (app-scoped scan):**
|
|
184
|
+
|
|
185
|
+
Scan only the active app directory and its referenced shared packages:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
node -e "
|
|
189
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
190
|
+
const projectRoot = process.cwd();
|
|
191
|
+
const appPath = process.argv[1];
|
|
192
|
+
const result = scanner.scanApp(projectRoot, appPath);
|
|
193
|
+
console.log(JSON.stringify({ tags: result.tags, scannedDirs: result.scannedDirs }, null, 2));
|
|
194
|
+
" '<ACTIVE_APP_PATH>'
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Log: "App-scoped scan: {activeApp} (+ {N} shared packages)"
|
|
198
|
+
|
|
199
|
+
**Else if monorepo detected (full monorepo scan):**
|
|
200
|
+
|
|
201
|
+
Scan each workspace package independently AND the root:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
node -e "
|
|
205
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
206
|
+
const fs = require('node:fs');
|
|
207
|
+
const path = require('node:path');
|
|
208
|
+
|
|
209
|
+
const monorepoInfo = JSON.parse(process.argv[1]);
|
|
210
|
+
const projectRoot = process.cwd();
|
|
211
|
+
|
|
212
|
+
if (monorepoInfo.isMonorepo) {
|
|
213
|
+
// Scan root first
|
|
214
|
+
const rootTags = scanner.scanDirectory(projectRoot, { projectRoot });
|
|
215
|
+
const allTags = [...rootTags];
|
|
216
|
+
|
|
217
|
+
// Scan each workspace package
|
|
218
|
+
for (const pkg of monorepoInfo.packages) {
|
|
219
|
+
const pkgDir = path.join(projectRoot, pkg);
|
|
220
|
+
if (fs.existsSync(pkgDir)) {
|
|
221
|
+
const pkgTags = scanner.scanDirectory(pkgDir, { projectRoot });
|
|
222
|
+
allTags.push(...pkgTags);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Deduplicate by file+line
|
|
227
|
+
const seen = new Set();
|
|
228
|
+
const deduped = allTags.filter(t => {
|
|
229
|
+
const key = t.file + ':' + t.line;
|
|
230
|
+
if (seen.has(key)) return false;
|
|
231
|
+
seen.add(key);
|
|
232
|
+
return true;
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
console.log(JSON.stringify(deduped, null, 2));
|
|
236
|
+
} else {
|
|
237
|
+
const tags = scanner.scanDirectory(projectRoot);
|
|
238
|
+
console.log(JSON.stringify(tags, null, 2));
|
|
239
|
+
}
|
|
240
|
+
" '<MONOREPO_INFO_JSON>'
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Else (single repo):**
|
|
244
|
+
|
|
245
|
+
Standard scan as before.
|
|
246
|
+
|
|
247
|
+
Store as `all_tags`.
|
|
248
|
+
|
|
249
|
+
## Step 2b: Polylingual context check (only when `--strict` is set)
|
|
250
|
+
|
|
251
|
+
<!-- @cap-decision When --strict is set, run the polylingual scanner in strict mode. It throws on any @cap-* token outside a recognized comment (string literal, code reference). Intended for CI enforcement (F-046/AC-4). -->
|
|
252
|
+
|
|
253
|
+
If `strict_mode === true`:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
node -e "
|
|
257
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
258
|
+
try {
|
|
259
|
+
const result = scanner.scanDirectoryWithContext(process.cwd(), { strict: true });
|
|
260
|
+
console.log(JSON.stringify({ ok: true, tags: result.tags.length, warnings: result.warnings.length }));
|
|
261
|
+
} catch (e) {
|
|
262
|
+
if (e.code === 'CAP_STRICT_TAG_VIOLATION') {
|
|
263
|
+
console.error(e.message);
|
|
264
|
+
process.exit(1);
|
|
265
|
+
}
|
|
266
|
+
throw e;
|
|
267
|
+
}
|
|
268
|
+
"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
If the command exits non-zero, surface the violation list to the user and abort the scan (do NOT proceed to enrichment). Otherwise continue to Step 3.
|
|
272
|
+
|
|
273
|
+
When `strict_mode === false` (default), the polylingual scan still runs but warnings are silently collected (available in `--json` output) and do not block the scan.
|
|
274
|
+
|
|
275
|
+
## Step 3: Group tags by feature and by package
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
node -e "
|
|
279
|
+
const tags = JSON.parse(process.argv[1]);
|
|
280
|
+
const groups = {};
|
|
281
|
+
const packageGroups = {};
|
|
282
|
+
|
|
283
|
+
for (const tag of tags) {
|
|
284
|
+
// Group by feature
|
|
285
|
+
const fid = (tag.metadata && tag.metadata.feature) || '(unassigned)';
|
|
286
|
+
if (!groups[fid]) groups[fid] = [];
|
|
287
|
+
groups[fid].push(tag);
|
|
288
|
+
|
|
289
|
+
// Group by package (first path segment if monorepo)
|
|
290
|
+
const parts = tag.file.split('/');
|
|
291
|
+
const pkg = parts.length > 2 && parts[0] === 'packages' ? parts[0] + '/' + parts[1] : '(root)';
|
|
292
|
+
if (!packageGroups[pkg]) packageGroups[pkg] = [];
|
|
293
|
+
packageGroups[pkg].push(tag);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
console.log(JSON.stringify({ byFeature: groups, byPackage: packageGroups }, null, 2));
|
|
297
|
+
" '<ALL_TAGS_JSON>'
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Step 4: Cross-reference and detect orphans
|
|
301
|
+
|
|
302
|
+
Same as base scan -- run orphan detection against FEATURE-MAP.md.
|
|
303
|
+
|
|
304
|
+
## Step 5: Auto-enrich Feature Map with cross-package file references
|
|
305
|
+
|
|
306
|
+
<!-- @cap-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. -->
|
|
307
|
+
|
|
308
|
+
**If app-scoped (activeApp set):** Enrich the app's FEATURE-MAP.md, not root.
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
node -e "
|
|
312
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
313
|
+
const activeApp = process.argv[1] === 'null' ? null : process.argv[1];
|
|
314
|
+
const tags = JSON.parse(process.argv[2]);
|
|
315
|
+
const updated = fm.enrichFromTags(process.cwd(), tags, activeApp);
|
|
316
|
+
console.log(JSON.stringify({
|
|
317
|
+
features_enriched: updated.features.filter(f => f.files.length > 0).length,
|
|
318
|
+
total_file_refs: updated.features.reduce((sum, f) => sum + f.files.length, 0),
|
|
319
|
+
cross_package_refs: updated.features.reduce((sum, f) =>
|
|
320
|
+
sum + f.files.filter(fp => fp.startsWith('packages/')).length, 0)
|
|
321
|
+
}));
|
|
322
|
+
" '<ACTIVE_APP_OR_NULL>' '<ALL_TAGS_JSON>'
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
**If not app-scoped (full scan):**
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
node -e "
|
|
329
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
330
|
+
const fm = require('./cap/bin/lib/cap-feature-map.cjs');
|
|
331
|
+
const tags = scanner.scanDirectory(process.cwd());
|
|
332
|
+
const updated = fm.enrichFromTags(process.cwd(), tags);
|
|
333
|
+
console.log(JSON.stringify({
|
|
334
|
+
features_enriched: updated.features.filter(f => f.files.length > 0).length,
|
|
335
|
+
total_file_refs: updated.features.reduce((sum, f) => sum + f.files.length, 0),
|
|
336
|
+
cross_package_refs: updated.features.reduce((sum, f) =>
|
|
337
|
+
sum + f.files.filter(fp => fp.startsWith('packages/')).length, 0)
|
|
338
|
+
}));
|
|
339
|
+
"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Step 5b: Record regret signals from @cap-decision regret:true tags (F-070/AC-3)
|
|
343
|
+
|
|
344
|
+
<!-- @cap-todo(ac:F-070/AC-3) Decision-Regret collector runs from /cap:scan, not from a hook (regret detection is retrospective and would blow F-070/AC-5's hook-overhead budget if scanned per Stop). -->
|
|
345
|
+
<!-- @cap-decision(F-070/D4) Trigger split — hooks fire override / memory-ref; tag-scanner enrichment fires regret. -->
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
node -e "
|
|
349
|
+
const scanner = require('./cap/bin/lib/cap-tag-scanner.cjs');
|
|
350
|
+
const learning = require('./cap/bin/lib/cap-learning-signals.cjs');
|
|
351
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
352
|
+
const tags = scanner.scanDirectory(process.cwd(), { projectRoot: process.cwd() });
|
|
353
|
+
let sessionId = null;
|
|
354
|
+
try { const s = session.loadSession(process.cwd()); sessionId = s && s.sessionId || null; } catch(_e){}
|
|
355
|
+
const result = learning.recordRegretsFromScan(process.cwd(), tags, { sessionId });
|
|
356
|
+
console.log(JSON.stringify(result));
|
|
357
|
+
"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Step 6: Output results
|
|
361
|
+
|
|
362
|
+
**Formatted report (default):**
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
cap:scan complete.
|
|
366
|
+
|
|
367
|
+
{If monorepo:}
|
|
368
|
+
Monorepo: {workspace_count} packages scanned
|
|
369
|
+
{For each package:}
|
|
370
|
+
- {package_name}: {tag_count} tags
|
|
371
|
+
|
|
372
|
+
Tags found: {total_tags}
|
|
373
|
+
@cap-feature: {count}
|
|
374
|
+
@cap-todo: {count}
|
|
375
|
+
@cap-risk: {count}
|
|
376
|
+
@cap-decision:{count}
|
|
377
|
+
|
|
378
|
+
Coverage: {files_with_tags} of {total_source_files} source files ({percentage}%)
|
|
379
|
+
|
|
380
|
+
Feature Map enrichment:
|
|
381
|
+
Features with file refs: {N}
|
|
382
|
+
Total file references: {N}
|
|
383
|
+
{If monorepo:} Cross-package refs: {N}
|
|
384
|
+
|
|
385
|
+
{Orphan section same as base scan}
|
|
386
|
+
|
|
387
|
+
Feature breakdown:
|
|
388
|
+
{For each feature group:}
|
|
389
|
+
{feature_id}: {count} tags ({type breakdown})
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
## Step 7: Update session
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
node -e "
|
|
396
|
+
const session = require('./cap/bin/lib/cap-session.cjs');
|
|
397
|
+
session.updateSession(process.cwd(), {
|
|
398
|
+
lastCommand: '/cap:scan',
|
|
399
|
+
lastCommandTimestamp: new Date().toISOString()
|
|
400
|
+
});
|
|
401
|
+
"
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
</process>
|