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,258 @@
|
|
|
1
|
+
// @cap-context(phase:11) Convention reader utility -- discovers existing project conventions for architecture mode
|
|
2
|
+
// @cap-decision Implemented as a standalone CJS module (not inline in the agent) so it can be tested independently
|
|
3
|
+
// @cap-ref(ref:ARCH-03) gsd-prototyper reads existing project conventions before generating skeleton
|
|
4
|
+
// @cap-constraint Zero external dependencies -- uses only Node.js built-ins (fs, path)
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
// @cap-feature(feature:F-013) Convention & Skeleton Generation — project convention discovery
|
|
9
|
+
// @cap-feature(feature:F-044) Audit and Right-Size Agent Behaviors for Opus 4.7 — minimal two-anchor probe
|
|
10
|
+
// @cap-decision(F-044/AC-3) Two-anchor probe replaces 6-7 file reads. CLAUDE.md + package.json are the
|
|
11
|
+
// highest-signal inputs for project context. Everything else (eslint config, tsconfig, naming
|
|
12
|
+
// convention, test pattern, build tool) can be inferred by Opus 4.7 from those two anchors plus a
|
|
13
|
+
// small handful of sample source files chosen on demand. The legacy readProjectConventions() is
|
|
14
|
+
// preserved for backwards compatibility -- see probeProjectAnchors() below for the right-sized API.
|
|
15
|
+
|
|
16
|
+
const fs = require('node:fs');
|
|
17
|
+
const path = require('node:path');
|
|
18
|
+
|
|
19
|
+
// @cap-api readProjectConventions(projectRoot) -- returns ConventionReport object describing discovered patterns
|
|
20
|
+
// @cap-pattern Convention reader returns a structured report that the agent prompt can serialize into context
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} ConventionReport
|
|
24
|
+
* @property {string} moduleType - 'esm' | 'cjs' | 'unknown'
|
|
25
|
+
* @property {string} namingConvention - 'kebab-case' | 'camelCase' | 'PascalCase' | 'snake_case' | 'unknown'
|
|
26
|
+
* @property {string} testPattern - 'colocated' | 'separate-dir' | 'unknown'
|
|
27
|
+
* @property {string|null} testRunner - detected test runner name or null
|
|
28
|
+
* @property {Object} pathAliases - e.g., { '@/*': ['src/*'] }
|
|
29
|
+
* @property {string|null} buildTool - detected build tool or null
|
|
30
|
+
* @property {string|null} linter - detected linter or null
|
|
31
|
+
* @property {string[]} existingDirs - list of existing directories (max depth 3)
|
|
32
|
+
* @property {Object} packageJson - parsed package.json or null
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Reads existing project conventions from config files and directory structure.
|
|
37
|
+
* Used by gsd-prototyper in architecture mode to match generated skeleton
|
|
38
|
+
* to the project's established patterns.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} projectRoot - absolute path to project root
|
|
41
|
+
* @returns {ConventionReport}
|
|
42
|
+
*/
|
|
43
|
+
function readProjectConventions(projectRoot) {
|
|
44
|
+
// @cap-todo(ref:AC-3) Implement full convention discovery: package.json parsing, tsconfig reading, directory pattern detection, linter config extraction
|
|
45
|
+
const report = {
|
|
46
|
+
moduleType: 'unknown',
|
|
47
|
+
namingConvention: 'unknown',
|
|
48
|
+
testPattern: 'unknown',
|
|
49
|
+
testRunner: null,
|
|
50
|
+
pathAliases: {},
|
|
51
|
+
buildTool: null,
|
|
52
|
+
linter: null,
|
|
53
|
+
existingDirs: [],
|
|
54
|
+
packageJson: null,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// --- package.json detection ---
|
|
58
|
+
// @cap-context Reads package.json for module type, naming conventions, and dependency-based framework detection
|
|
59
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
60
|
+
if (fs.existsSync(pkgPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
63
|
+
report.packageJson = pkg;
|
|
64
|
+
report.moduleType = pkg.type === 'module' ? 'esm' : 'cjs';
|
|
65
|
+
|
|
66
|
+
// @cap-decision Detect test runner from devDependencies keys rather than config files -- faster and covers most cases
|
|
67
|
+
if (pkg.devDependencies) {
|
|
68
|
+
if (pkg.devDependencies.vitest) report.testRunner = 'vitest';
|
|
69
|
+
else if (pkg.devDependencies.jest) report.testRunner = 'jest';
|
|
70
|
+
else if (pkg.devDependencies.mocha) report.testRunner = 'mocha';
|
|
71
|
+
else if (pkg.devDependencies.ava) report.testRunner = 'ava';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// @cap-decision Detect build tool from devDependencies -- covers esbuild, webpack, vite, rollup
|
|
75
|
+
if (pkg.devDependencies) {
|
|
76
|
+
if (pkg.devDependencies.esbuild) report.buildTool = 'esbuild';
|
|
77
|
+
else if (pkg.devDependencies.vite) report.buildTool = 'vite';
|
|
78
|
+
else if (pkg.devDependencies.webpack) report.buildTool = 'webpack';
|
|
79
|
+
else if (pkg.devDependencies.rollup) report.buildTool = 'rollup';
|
|
80
|
+
}
|
|
81
|
+
} catch (_e) {
|
|
82
|
+
// @cap-risk Malformed package.json silently ignored -- could produce incorrect convention report
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// --- tsconfig.json / jsconfig.json detection ---
|
|
87
|
+
// @cap-context Reads TypeScript/JavaScript config for path aliases and module resolution
|
|
88
|
+
const tsconfigPath = path.join(projectRoot, 'tsconfig.json');
|
|
89
|
+
const jsconfigPath = path.join(projectRoot, 'jsconfig.json');
|
|
90
|
+
const configPath = fs.existsSync(tsconfigPath) ? tsconfigPath : (fs.existsSync(jsconfigPath) ? jsconfigPath : null);
|
|
91
|
+
|
|
92
|
+
if (configPath) {
|
|
93
|
+
try {
|
|
94
|
+
// Strip JS-style comments (// and /* */) before parsing — handles JSONC tsconfig files
|
|
95
|
+
let raw = fs.readFileSync(configPath, 'utf8');
|
|
96
|
+
raw = raw.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
|
|
97
|
+
const config = JSON.parse(raw);
|
|
98
|
+
if (config.compilerOptions && config.compilerOptions.paths) {
|
|
99
|
+
report.pathAliases = config.compilerOptions.paths;
|
|
100
|
+
}
|
|
101
|
+
} catch (_e) {
|
|
102
|
+
// Malformed config silently ignored
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// --- Directory structure detection ---
|
|
107
|
+
// @cap-context Reads directory names to detect naming convention (kebab-case vs camelCase etc.)
|
|
108
|
+
report.existingDirs = discoverDirectories(projectRoot, 3);
|
|
109
|
+
report.namingConvention = detectNamingConvention(report.existingDirs);
|
|
110
|
+
|
|
111
|
+
// --- Test pattern detection ---
|
|
112
|
+
// @cap-decision Check for tests/ or __tests__/ directory first, then fall back to checking for colocated .test. files
|
|
113
|
+
const hasTestsDir = report.existingDirs.some(d => d === 'tests' || d === '__tests__' || d.endsWith('/tests') || d.endsWith('/__tests__'));
|
|
114
|
+
if (hasTestsDir) {
|
|
115
|
+
report.testPattern = 'separate-dir';
|
|
116
|
+
}
|
|
117
|
+
// @cap-todo Detect colocated test pattern by scanning for *.test.* files alongside source files
|
|
118
|
+
|
|
119
|
+
// --- Linter detection ---
|
|
120
|
+
// @cap-context Checks for linter config files to match code style in generated skeleton
|
|
121
|
+
const linterFiles = ['.eslintrc', '.eslintrc.js', '.eslintrc.json', '.eslintrc.cjs', 'biome.json', 'biome.jsonc'];
|
|
122
|
+
for (const f of linterFiles) {
|
|
123
|
+
if (fs.existsSync(path.join(projectRoot, f))) {
|
|
124
|
+
report.linter = f.includes('biome') ? 'biome' : 'eslint';
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return report;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Recursively discovers directories up to maxDepth.
|
|
134
|
+
* @param {string} dir
|
|
135
|
+
* @param {number} maxDepth
|
|
136
|
+
* @param {number} [currentDepth=0]
|
|
137
|
+
* @returns {string[]}
|
|
138
|
+
*/
|
|
139
|
+
function discoverDirectories(dir, maxDepth, currentDepth = 0) {
|
|
140
|
+
// @cap-constraint Uses readdirSync (not glob) per project zero-dep constraint
|
|
141
|
+
if (currentDepth >= maxDepth) return [];
|
|
142
|
+
|
|
143
|
+
const results = [];
|
|
144
|
+
try {
|
|
145
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
146
|
+
for (const entry of entries) {
|
|
147
|
+
if (!entry.isDirectory()) continue;
|
|
148
|
+
if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === '.planning') continue;
|
|
149
|
+
|
|
150
|
+
const fullPath = path.join(dir, entry.name);
|
|
151
|
+
const relativePath = path.relative(dir, fullPath);
|
|
152
|
+
results.push(relativePath);
|
|
153
|
+
const children = discoverDirectories(fullPath, maxDepth, currentDepth + 1);
|
|
154
|
+
results.push(...children.map(c => path.join(entry.name, c)));
|
|
155
|
+
}
|
|
156
|
+
} catch (_e) {
|
|
157
|
+
// Permission errors etc.
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return results;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Detects naming convention from directory names.
|
|
165
|
+
* @param {string[]} dirs
|
|
166
|
+
* @returns {string}
|
|
167
|
+
*/
|
|
168
|
+
function detectNamingConvention(dirs) {
|
|
169
|
+
// @cap-decision Simple heuristic: check if majority of directory names match a pattern
|
|
170
|
+
// @cap-risk Heuristic may misclassify projects with mixed naming -- returns 'unknown' when ambiguous
|
|
171
|
+
const leafNames = dirs.map(d => path.basename(d)).filter(n => n.length > 1);
|
|
172
|
+
if (leafNames.length === 0) return 'unknown';
|
|
173
|
+
|
|
174
|
+
const kebab = leafNames.filter(n => /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(n)).length;
|
|
175
|
+
const camel = leafNames.filter(n => /^[a-z][a-zA-Z0-9]+$/.test(n) && /[A-Z]/.test(n)).length;
|
|
176
|
+
const pascal = leafNames.filter(n => /^[A-Z][a-zA-Z0-9]+$/.test(n)).length;
|
|
177
|
+
const snake = leafNames.filter(n => /^[a-z][a-z0-9]*(_[a-z0-9]+)+$/.test(n)).length;
|
|
178
|
+
|
|
179
|
+
const max = Math.max(kebab, camel, pascal, snake);
|
|
180
|
+
if (max === 0) return 'unknown';
|
|
181
|
+
if (kebab === max) return 'kebab-case';
|
|
182
|
+
if (camel === max) return 'camelCase';
|
|
183
|
+
if (pascal === max) return 'PascalCase';
|
|
184
|
+
if (snake === max) return 'snake_case';
|
|
185
|
+
return 'unknown';
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// @cap-feature(feature:F-044) Two-anchor probe -- right-sized convention discovery for Opus 4.7
|
|
189
|
+
// @cap-todo(ac:F-044/AC-3) Replace 6-7 file reads with a single high-signal probe (CLAUDE.md + package.json)
|
|
190
|
+
// @cap-risk(F-044) Edge case: projects without CLAUDE.md or with non-JSON package.json get null fields.
|
|
191
|
+
// Mitigation: caller must handle null-valued anchors by either falling back to readProjectConventions()
|
|
192
|
+
// for the legacy multi-file probe or letting the agent infer conventions from sample source files.
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* @typedef {Object} ProjectAnchors
|
|
196
|
+
* @property {string|null} rawClaudeMd - raw contents of CLAUDE.md, or null if absent
|
|
197
|
+
* @property {string|null} rawPackageJson - raw contents of package.json (string, NOT parsed), or null if absent
|
|
198
|
+
* @property {Object|null} parsedPackageJson - parsed JSON of package.json, or null if absent or invalid
|
|
199
|
+
* @property {string} projectRoot - the absolute path probed
|
|
200
|
+
* @property {string[]} filesProbed - the relative paths actually read (for token-cost auditability)
|
|
201
|
+
*/
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Reads the two highest-signal anchor files for project context: CLAUDE.md and package.json.
|
|
205
|
+
*
|
|
206
|
+
* This replaces readProjectConventions() in the right-sized Opus 4.7 workflow. The agent
|
|
207
|
+
* infers the rest (linter, naming convention, test pattern, build tool) from these two
|
|
208
|
+
* anchors plus a small number of sample source files chosen on demand at the call site,
|
|
209
|
+
* rather than eagerly probing 6-7 config files up front.
|
|
210
|
+
*
|
|
211
|
+
* @param {string} projectRoot - absolute path to project root
|
|
212
|
+
* @returns {ProjectAnchors}
|
|
213
|
+
*/
|
|
214
|
+
function probeProjectAnchors(projectRoot) {
|
|
215
|
+
// @cap-todo(ac:F-044/AC-3) Implementation of the two-anchor probe -- exactly two file reads
|
|
216
|
+
const result = {
|
|
217
|
+
rawClaudeMd: null,
|
|
218
|
+
rawPackageJson: null,
|
|
219
|
+
parsedPackageJson: null,
|
|
220
|
+
projectRoot,
|
|
221
|
+
filesProbed: [],
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
// @cap-decision(F-044) Anchor 1: CLAUDE.md is the project's intent document. When present it
|
|
225
|
+
// captures conventions, tech stack, and constraints in one place -- higher signal than parsing
|
|
226
|
+
// .eslintrc + .prettierrc + tsconfig + biome.json individually.
|
|
227
|
+
const claudePath = path.join(projectRoot, 'CLAUDE.md');
|
|
228
|
+
if (fs.existsSync(claudePath)) {
|
|
229
|
+
try {
|
|
230
|
+
result.rawClaudeMd = fs.readFileSync(claudePath, 'utf8');
|
|
231
|
+
result.filesProbed.push('CLAUDE.md');
|
|
232
|
+
} catch (_e) {
|
|
233
|
+
// @cap-risk(F-044) Permission errors silently ignored -- caller treats null rawClaudeMd as "no project intent doc"
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// @cap-decision(F-044) Anchor 2: package.json is the deterministic structural anchor (module type,
|
|
238
|
+
// scripts, dependencies). We expose BOTH the raw string (for audit/log purposes) and the parsed
|
|
239
|
+
// object (for programmatic use) so consumers don't need to re-parse.
|
|
240
|
+
const pkgPath = path.join(projectRoot, 'package.json');
|
|
241
|
+
if (fs.existsSync(pkgPath)) {
|
|
242
|
+
try {
|
|
243
|
+
result.rawPackageJson = fs.readFileSync(pkgPath, 'utf8');
|
|
244
|
+
result.filesProbed.push('package.json');
|
|
245
|
+
try {
|
|
246
|
+
result.parsedPackageJson = JSON.parse(result.rawPackageJson);
|
|
247
|
+
} catch (_parseErr) {
|
|
248
|
+
// @cap-risk(F-044) Malformed package.json -- raw is preserved, parsed stays null. Caller must check.
|
|
249
|
+
}
|
|
250
|
+
} catch (_e) {
|
|
251
|
+
// Permission errors silently ignored
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
module.exports = { readProjectConventions, discoverDirectories, detectNamingConvention, probeProjectAnchors };
|