@ktpartners/dgs-platform 2.6.2
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 +38 -0
- package/README.md +851 -0
- package/agents/dgs-codebase-cross-analyzer.md +183 -0
- package/agents/dgs-codebase-mapper.md +782 -0
- package/agents/dgs-codebase-synthesizer.md +156 -0
- package/agents/dgs-debugger.md +1256 -0
- package/agents/dgs-executor.md +550 -0
- package/agents/dgs-integration-checker.md +481 -0
- package/agents/dgs-nyquist-auditor.md +178 -0
- package/agents/dgs-phase-researcher.md +563 -0
- package/agents/dgs-phase-verifier.md +450 -0
- package/agents/dgs-plan-checker.md +708 -0
- package/agents/dgs-planner.md +1324 -0
- package/agents/dgs-project-researcher.md +631 -0
- package/agents/dgs-research-synthesizer.md +249 -0
- package/agents/dgs-roadmapper.md +652 -0
- package/agents/dgs-verifier.md +607 -0
- package/bin/install.js +2073 -0
- package/commands/dgs/add-doc.md +45 -0
- package/commands/dgs/add-idea.md +38 -0
- package/commands/dgs/add-phase.md +43 -0
- package/commands/dgs/add-repo.md +54 -0
- package/commands/dgs/add-tests.md +41 -0
- package/commands/dgs/add-todo.md +47 -0
- package/commands/dgs/approve-spec.md +38 -0
- package/commands/dgs/audit-milestone.md +36 -0
- package/commands/dgs/audit-phase.md +37 -0
- package/commands/dgs/cancel-job.md +23 -0
- package/commands/dgs/capture-principle.md +143 -0
- package/commands/dgs/check-todos.md +45 -0
- package/commands/dgs/cleanup.md +18 -0
- package/commands/dgs/complete-milestone.md +136 -0
- package/commands/dgs/complete-project.md +70 -0
- package/commands/dgs/consolidate-ideas.md +50 -0
- package/commands/dgs/create-milestone-job.md +37 -0
- package/commands/dgs/debug.md +164 -0
- package/commands/dgs/develop-idea.md +53 -0
- package/commands/dgs/discuss-idea.md +41 -0
- package/commands/dgs/discuss-phase.md +83 -0
- package/commands/dgs/execute-phase.md +41 -0
- package/commands/dgs/fast.md +38 -0
- package/commands/dgs/find-related-ideas.md +43 -0
- package/commands/dgs/health.md +28 -0
- package/commands/dgs/help.md +22 -0
- package/commands/dgs/import-spec.md +36 -0
- package/commands/dgs/init-product.md +28 -0
- package/commands/dgs/insert-phase.md +32 -0
- package/commands/dgs/join-discord.md +18 -0
- package/commands/dgs/list-docs.md +40 -0
- package/commands/dgs/list-ideas.md +42 -0
- package/commands/dgs/list-jobs.md +22 -0
- package/commands/dgs/list-phase-assumptions.md +46 -0
- package/commands/dgs/list-projects.md +57 -0
- package/commands/dgs/list-specs.md +40 -0
- package/commands/dgs/map-codebase.md +92 -0
- package/commands/dgs/new-milestone.md +44 -0
- package/commands/dgs/new-project.md +42 -0
- package/commands/dgs/node-repair.md +26 -0
- package/commands/dgs/overlap-check.md +20 -0
- package/commands/dgs/pause-work.md +38 -0
- package/commands/dgs/plan-milestone-gaps.md +34 -0
- package/commands/dgs/plan-phase.md +44 -0
- package/commands/dgs/progress.md +24 -0
- package/commands/dgs/quick.md +41 -0
- package/commands/dgs/reactivate-project.md +70 -0
- package/commands/dgs/reapply-patches.md +110 -0
- package/commands/dgs/refine-spec.md +38 -0
- package/commands/dgs/reject-idea.md +43 -0
- package/commands/dgs/remove-doc.md +44 -0
- package/commands/dgs/remove-phase.md +31 -0
- package/commands/dgs/remove-repo.md +69 -0
- package/commands/dgs/research-idea.md +43 -0
- package/commands/dgs/research-phase.md +189 -0
- package/commands/dgs/restore-idea.md +45 -0
- package/commands/dgs/resume-work.md +40 -0
- package/commands/dgs/rollback-job.md +24 -0
- package/commands/dgs/run-job.md +35 -0
- package/commands/dgs/search.md +40 -0
- package/commands/dgs/set-profile.md +34 -0
- package/commands/dgs/settings.md +38 -0
- package/commands/dgs/switch-project.md +58 -0
- package/commands/dgs/undo-consolidation.md +42 -0
- package/commands/dgs/update-idea.md +44 -0
- package/commands/dgs/update.md +37 -0
- package/commands/dgs/validate-phase.md +35 -0
- package/commands/dgs/verify-work.md +39 -0
- package/commands/dgs/write-spec.md +49 -0
- package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-01-SUMMARY.md +84 -0
- package/deliver-great-systems/.planning/phases/09-backend-wiring-and-error-handling/09-02-SUMMARY.md +86 -0
- package/deliver-great-systems/.planning/phases/10-v1-to-v2-migration-flow/10-01-SUMMARY.md +85 -0
- package/deliver-great-systems/bin/dgs-tools.cjs +1444 -0
- package/deliver-great-systems/bin/lib/auto-test.cjs +1365 -0
- package/deliver-great-systems/bin/lib/commands.cjs +570 -0
- package/deliver-great-systems/bin/lib/config.cjs +417 -0
- package/deliver-great-systems/bin/lib/conflict-agent.cjs +1063 -0
- package/deliver-great-systems/bin/lib/conflict-agent.test.cjs +554 -0
- package/deliver-great-systems/bin/lib/context.cjs +929 -0
- package/deliver-great-systems/bin/lib/context.test.cjs +693 -0
- package/deliver-great-systems/bin/lib/core.cjs +744 -0
- package/deliver-great-systems/bin/lib/core.test.cjs +822 -0
- package/deliver-great-systems/bin/lib/docs.cjs +919 -0
- package/deliver-great-systems/bin/lib/docs.test.cjs +211 -0
- package/deliver-great-systems/bin/lib/execution.cjs +705 -0
- package/deliver-great-systems/bin/lib/execution.test.cjs +1472 -0
- package/deliver-great-systems/bin/lib/frontmatter.cjs +324 -0
- package/deliver-great-systems/bin/lib/ideas.cjs +1406 -0
- package/deliver-great-systems/bin/lib/ideas.test.cjs +1417 -0
- package/deliver-great-systems/bin/lib/identity.cjs +125 -0
- package/deliver-great-systems/bin/lib/init.cjs +1114 -0
- package/deliver-great-systems/bin/lib/init.test.cjs +1271 -0
- package/deliver-great-systems/bin/lib/jobs.cjs +2015 -0
- package/deliver-great-systems/bin/lib/jobs.test.cjs +2619 -0
- package/deliver-great-systems/bin/lib/merge-conflicts.cjs +654 -0
- package/deliver-great-systems/bin/lib/merge-conflicts.test.cjs +370 -0
- package/deliver-great-systems/bin/lib/migration.cjs +352 -0
- package/deliver-great-systems/bin/lib/migration.test.cjs +582 -0
- package/deliver-great-systems/bin/lib/milestone.cjs +243 -0
- package/deliver-great-systems/bin/lib/overlap.cjs +437 -0
- package/deliver-great-systems/bin/lib/overlap.test.cjs +747 -0
- package/deliver-great-systems/bin/lib/path-audit.test.cjs +384 -0
- package/deliver-great-systems/bin/lib/paths.cjs +144 -0
- package/deliver-great-systems/bin/lib/paths.test.cjs +486 -0
- package/deliver-great-systems/bin/lib/phase.cjs +910 -0
- package/deliver-great-systems/bin/lib/projects.cjs +691 -0
- package/deliver-great-systems/bin/lib/projects.test.cjs +871 -0
- package/deliver-great-systems/bin/lib/repos.cjs +1432 -0
- package/deliver-great-systems/bin/lib/repos.test.cjs +1882 -0
- package/deliver-great-systems/bin/lib/roadmap.cjs +305 -0
- package/deliver-great-systems/bin/lib/search.cjs +570 -0
- package/deliver-great-systems/bin/lib/specs.cjs +1303 -0
- package/deliver-great-systems/bin/lib/state.cjs +893 -0
- package/deliver-great-systems/bin/lib/template.cjs +228 -0
- package/deliver-great-systems/bin/lib/test-helpers.cjs +291 -0
- package/deliver-great-systems/bin/lib/verify.cjs +796 -0
- package/deliver-great-systems/references/checkpoints.md +776 -0
- package/deliver-great-systems/references/conflict-resolution.md +66 -0
- package/deliver-great-systems/references/context-tiers.md +166 -0
- package/deliver-great-systems/references/continuation-format.md +249 -0
- package/deliver-great-systems/references/decimal-phase-calculation.md +67 -0
- package/deliver-great-systems/references/git-integration.md +250 -0
- package/deliver-great-systems/references/git-planning-commit.md +40 -0
- package/deliver-great-systems/references/model-profile-resolution.md +36 -0
- package/deliver-great-systems/references/model-profiles.md +95 -0
- package/deliver-great-systems/references/phase-argument-parsing.md +61 -0
- package/deliver-great-systems/references/planning-config.md +224 -0
- package/deliver-great-systems/references/questioning.md +162 -0
- package/deliver-great-systems/references/spec-review-loop.md +177 -0
- package/deliver-great-systems/references/tdd.md +265 -0
- package/deliver-great-systems/references/ui-brand.md +160 -0
- package/deliver-great-systems/references/verification-patterns.md +612 -0
- package/deliver-great-systems/templates/DEBUG.md +166 -0
- package/deliver-great-systems/templates/UAT.md +251 -0
- package/deliver-great-systems/templates/VALIDATION.md +95 -0
- package/deliver-great-systems/templates/claude-md.md +74 -0
- package/deliver-great-systems/templates/codebase/architecture.md +257 -0
- package/deliver-great-systems/templates/codebase/concerns.md +312 -0
- package/deliver-great-systems/templates/codebase/conventions.md +309 -0
- package/deliver-great-systems/templates/codebase/integrations.md +282 -0
- package/deliver-great-systems/templates/codebase/stack.md +188 -0
- package/deliver-great-systems/templates/codebase/structure.md +287 -0
- package/deliver-great-systems/templates/codebase/testing.md +482 -0
- package/deliver-great-systems/templates/config.json +38 -0
- package/deliver-great-systems/templates/context.md +354 -0
- package/deliver-great-systems/templates/continue-here.md +80 -0
- package/deliver-great-systems/templates/debug-subagent-prompt.md +93 -0
- package/deliver-great-systems/templates/discovery.md +148 -0
- package/deliver-great-systems/templates/milestone-archive.md +125 -0
- package/deliver-great-systems/templates/milestone.md +117 -0
- package/deliver-great-systems/templates/phase-prompt.md +615 -0
- package/deliver-great-systems/templates/planner-subagent-prompt.md +119 -0
- package/deliver-great-systems/templates/project.md +186 -0
- package/deliver-great-systems/templates/requirements.md +233 -0
- package/deliver-great-systems/templates/research-project/ARCHITECTURE.md +206 -0
- package/deliver-great-systems/templates/research-project/FEATURES.md +149 -0
- package/deliver-great-systems/templates/research-project/PITFALLS.md +202 -0
- package/deliver-great-systems/templates/research-project/STACK.md +122 -0
- package/deliver-great-systems/templates/research-project/SUMMARY.md +172 -0
- package/deliver-great-systems/templates/research.md +554 -0
- package/deliver-great-systems/templates/retrospective.md +54 -0
- package/deliver-great-systems/templates/roadmap.md +204 -0
- package/deliver-great-systems/templates/state.md +178 -0
- package/deliver-great-systems/templates/summary-complex.md +59 -0
- package/deliver-great-systems/templates/summary-minimal.md +41 -0
- package/deliver-great-systems/templates/summary-standard.md +48 -0
- package/deliver-great-systems/templates/summary.md +253 -0
- package/deliver-great-systems/templates/user-setup.md +313 -0
- package/deliver-great-systems/templates/verification-report.md +324 -0
- package/deliver-great-systems/workflows/add-doc.md +151 -0
- package/deliver-great-systems/workflows/add-idea.md +96 -0
- package/deliver-great-systems/workflows/add-phase.md +120 -0
- package/deliver-great-systems/workflows/add-tests.md +359 -0
- package/deliver-great-systems/workflows/add-todo.md +162 -0
- package/deliver-great-systems/workflows/approve-spec.md +194 -0
- package/deliver-great-systems/workflows/audit-milestone.md +364 -0
- package/deliver-great-systems/workflows/audit-phase.md +462 -0
- package/deliver-great-systems/workflows/cancel-job.md +108 -0
- package/deliver-great-systems/workflows/check-todos.md +181 -0
- package/deliver-great-systems/workflows/cleanup.md +247 -0
- package/deliver-great-systems/workflows/codereview.md +526 -0
- package/deliver-great-systems/workflows/complete-milestone.md +1298 -0
- package/deliver-great-systems/workflows/consolidate-ideas.md +365 -0
- package/deliver-great-systems/workflows/create-milestone-job.md +177 -0
- package/deliver-great-systems/workflows/develop-idea.md +544 -0
- package/deliver-great-systems/workflows/diagnose-issues.md +231 -0
- package/deliver-great-systems/workflows/discovery-phase.md +301 -0
- package/deliver-great-systems/workflows/discuss-idea.md +263 -0
- package/deliver-great-systems/workflows/discuss-phase.md +733 -0
- package/deliver-great-systems/workflows/execute-phase.md +571 -0
- package/deliver-great-systems/workflows/execute-plan.md +592 -0
- package/deliver-great-systems/workflows/find-related-ideas.md +271 -0
- package/deliver-great-systems/workflows/health.md +173 -0
- package/deliver-great-systems/workflows/help.md +997 -0
- package/deliver-great-systems/workflows/import-spec.md +381 -0
- package/deliver-great-systems/workflows/init-product.md +767 -0
- package/deliver-great-systems/workflows/insert-phase.md +138 -0
- package/deliver-great-systems/workflows/list-docs.md +119 -0
- package/deliver-great-systems/workflows/list-ideas.md +154 -0
- package/deliver-great-systems/workflows/list-jobs.md +89 -0
- package/deliver-great-systems/workflows/list-phase-assumptions.md +192 -0
- package/deliver-great-systems/workflows/list-specs.md +101 -0
- package/deliver-great-systems/workflows/map-codebase.md +621 -0
- package/deliver-great-systems/workflows/new-milestone.md +591 -0
- package/deliver-great-systems/workflows/new-project.md +1113 -0
- package/deliver-great-systems/workflows/node-repair.md +94 -0
- package/deliver-great-systems/workflows/overlap-check.md +86 -0
- package/deliver-great-systems/workflows/pause-work.md +134 -0
- package/deliver-great-systems/workflows/plan-milestone-gaps.md +306 -0
- package/deliver-great-systems/workflows/plan-phase.md +698 -0
- package/deliver-great-systems/workflows/progress.md +386 -0
- package/deliver-great-systems/workflows/quick.md +845 -0
- package/deliver-great-systems/workflows/refine-spec.md +275 -0
- package/deliver-great-systems/workflows/reject-idea.md +109 -0
- package/deliver-great-systems/workflows/remove-doc.md +117 -0
- package/deliver-great-systems/workflows/remove-phase.md +163 -0
- package/deliver-great-systems/workflows/research-idea.md +325 -0
- package/deliver-great-systems/workflows/research-phase.md +81 -0
- package/deliver-great-systems/workflows/restore-idea.md +101 -0
- package/deliver-great-systems/workflows/resume-project.md +311 -0
- package/deliver-great-systems/workflows/rollback-job.md +130 -0
- package/deliver-great-systems/workflows/run-job.md +498 -0
- package/deliver-great-systems/workflows/search.md +130 -0
- package/deliver-great-systems/workflows/set-profile.md +83 -0
- package/deliver-great-systems/workflows/settings.md +470 -0
- package/deliver-great-systems/workflows/transition.md +563 -0
- package/deliver-great-systems/workflows/undo-consolidation.md +155 -0
- package/deliver-great-systems/workflows/update-idea.md +157 -0
- package/deliver-great-systems/workflows/update.md +242 -0
- package/deliver-great-systems/workflows/validate-phase.md +177 -0
- package/deliver-great-systems/workflows/verify-phase.md +253 -0
- package/deliver-great-systems/workflows/verify-work.md +671 -0
- package/deliver-great-systems/workflows/write-spec.md +450 -0
- package/hooks/dist/dgs-check-update.js +62 -0
- package/hooks/dist/dgs-context-monitor.js +141 -0
- package/hooks/dist/dgs-statusline.js +115 -0
- package/package.json +60 -0
- package/scripts/build-hooks.js +43 -0
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path audit test — comprehensive gating test for all file categories.
|
|
3
|
+
*
|
|
4
|
+
* This test suite:
|
|
5
|
+
* 1. GATES on ALL file categories (workflows, templates, agents, references)
|
|
6
|
+
* to prevent hardcoded .planning/ path constructions from creeping back in
|
|
7
|
+
* 2. GATES on library source files (path.join(cwd, '.planning') pattern)
|
|
8
|
+
* 3. Documents baselines for lib module raw string literals
|
|
9
|
+
*
|
|
10
|
+
* Allowlisted files (may legitimately reference .planning/):
|
|
11
|
+
* - workflows/init-product.md — creates and describes both layouts
|
|
12
|
+
* - workflows/help.md — user documentation explaining directory structure
|
|
13
|
+
*
|
|
14
|
+
* Allowlisted line patterns:
|
|
15
|
+
* - HTML comments: <!-- .planning/ ... -->
|
|
16
|
+
* - .gitignore example blocks containing .planning/
|
|
17
|
+
*
|
|
18
|
+
* Uses Node.js built-in test runner (node:test) and assert (node:assert/strict).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
const { describe, it } = require('node:test');
|
|
22
|
+
const assert = require('node:assert/strict');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
|
|
26
|
+
// Root of the deliver-great-systems package (two levels up from bin/lib/)
|
|
27
|
+
const DGS_ROOT = path.resolve(__dirname, '..', '..');
|
|
28
|
+
|
|
29
|
+
// Root of the overall repo (one level above deliver-great-systems/)
|
|
30
|
+
const REPO_ROOT = path.resolve(DGS_ROOT, '..');
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Comprehensive pattern: matches ANY .planning/ reference.
|
|
34
|
+
* Used for the broad gate tests across all file categories.
|
|
35
|
+
*/
|
|
36
|
+
const COMPREHENSIVE_PATTERN = /\.planning\//;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Project-scoped path pattern: matches .planning/ followed by a project-scoped
|
|
40
|
+
* filename or directory name. These are paths that would be WRONG in a v2
|
|
41
|
+
* multi-project install because they resolve to the root instead of
|
|
42
|
+
* .planning/<project>/<path>.
|
|
43
|
+
*/
|
|
44
|
+
const PROJECT_SCOPED_PATTERN = /\.planning\/(?:STATE|ROADMAP|PROJECT(?!S\.md)|REQUIREMENTS|phases|archive|quick|todos|debug|research)/;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Workflow files allowlisted from comprehensive .planning/ scanning.
|
|
48
|
+
* These files legitimately reference .planning/ for layout documentation.
|
|
49
|
+
*/
|
|
50
|
+
const ALLOWLISTED_WORKFLOW_FILES = [
|
|
51
|
+
'workflows/init-product.md', // Creates and describes both layouts
|
|
52
|
+
'workflows/help.md', // User documentation explaining directory structure
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Reference files allowlisted from comprehensive .planning/ scanning.
|
|
57
|
+
* These files have legitimate .planning/ references in example content.
|
|
58
|
+
*/
|
|
59
|
+
const ALLOWLISTED_REFERENCE_FILES = [
|
|
60
|
+
'references/planning-config.md', // Has .planning/ in .gitignore example block
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Product-level paths that are intentionally at .planning/ root and should
|
|
65
|
+
* NOT be flagged by the audit.
|
|
66
|
+
*/
|
|
67
|
+
const SAFE_PRODUCT_PATHS = [
|
|
68
|
+
'.planning/config.json',
|
|
69
|
+
'.planning/PROJECTS.md',
|
|
70
|
+
'.planning/REPOS.md',
|
|
71
|
+
'.planning/codebase',
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Recursively collect all .md files under a directory.
|
|
76
|
+
* @param {string} dir - Absolute path to scan
|
|
77
|
+
* @returns {string[]} Array of absolute file paths
|
|
78
|
+
*/
|
|
79
|
+
function collectMdFiles(dir) {
|
|
80
|
+
const results = [];
|
|
81
|
+
try {
|
|
82
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
83
|
+
for (const entry of entries) {
|
|
84
|
+
const fullPath = path.join(dir, entry.name);
|
|
85
|
+
if (entry.isDirectory()) {
|
|
86
|
+
results.push(...collectMdFiles(fullPath));
|
|
87
|
+
} else if (entry.name.endsWith('.md')) {
|
|
88
|
+
results.push(fullPath);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch {
|
|
92
|
+
// Directory may not exist
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Count lines matching the comprehensive .planning/ pattern in a set of files.
|
|
99
|
+
* Skips allowlisted files and allowlisted line patterns.
|
|
100
|
+
* @param {string[]} files - Array of absolute file paths
|
|
101
|
+
* @param {string[]} allowlistFiles - Basenames to skip entirely
|
|
102
|
+
* @returns {{ count: number, details: Array<{ file: string, line: number, text: string }> }}
|
|
103
|
+
*/
|
|
104
|
+
function countComprehensivePaths(files, allowlistFiles = []) {
|
|
105
|
+
let count = 0;
|
|
106
|
+
const details = [];
|
|
107
|
+
|
|
108
|
+
for (const filePath of files) {
|
|
109
|
+
// Skip allowlisted files
|
|
110
|
+
const relPath = path.relative(DGS_ROOT, filePath);
|
|
111
|
+
if (allowlistFiles.some(af => relPath === af || relPath.endsWith(af))) {
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
116
|
+
const lines = content.split('\n');
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < lines.length; i++) {
|
|
119
|
+
const line = lines[i];
|
|
120
|
+
// Skip HTML comment lines
|
|
121
|
+
if (line.trimStart().startsWith('<!--')) continue;
|
|
122
|
+
|
|
123
|
+
if (COMPREHENSIVE_PATTERN.test(line)) {
|
|
124
|
+
count++;
|
|
125
|
+
details.push({
|
|
126
|
+
file: relPath,
|
|
127
|
+
line: i + 1,
|
|
128
|
+
text: line.trim().substring(0, 120),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { count, details };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Count lines matching the project-scoped pattern in a set of files.
|
|
139
|
+
* Excludes HTML comment lines (starting with <!--).
|
|
140
|
+
* @param {string[]} files - Array of absolute file paths
|
|
141
|
+
* @returns {{ count: number, details: Array<{ file: string, line: number, text: string }> }}
|
|
142
|
+
*/
|
|
143
|
+
function countProjectScopedPaths(files) {
|
|
144
|
+
let count = 0;
|
|
145
|
+
const details = [];
|
|
146
|
+
|
|
147
|
+
for (const filePath of files) {
|
|
148
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
149
|
+
const lines = content.split('\n');
|
|
150
|
+
|
|
151
|
+
for (let i = 0; i < lines.length; i++) {
|
|
152
|
+
const line = lines[i];
|
|
153
|
+
// Skip HTML comment lines
|
|
154
|
+
if (line.trimStart().startsWith('<!--')) continue;
|
|
155
|
+
|
|
156
|
+
if (PROJECT_SCOPED_PATTERN.test(line)) {
|
|
157
|
+
count++;
|
|
158
|
+
details.push({
|
|
159
|
+
file: path.relative(DGS_ROOT, filePath),
|
|
160
|
+
line: i + 1,
|
|
161
|
+
text: line.trim().substring(0, 120),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return { count, details };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Format violations for assertion error messages.
|
|
172
|
+
*/
|
|
173
|
+
function formatViolations(details) {
|
|
174
|
+
return details.map(d => ` ${d.file}:${d.line}: ${d.text}`).join('\n');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ─── Comprehensive GATE Tests ───────────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
describe('path audit: comprehensive .planning/ reference scanning', () => {
|
|
180
|
+
|
|
181
|
+
it('GATE: zero hardcoded .planning/ in workflow files (except allowlisted)', () => {
|
|
182
|
+
const workflowDir = path.join(DGS_ROOT, 'workflows');
|
|
183
|
+
const allFiles = collectMdFiles(workflowDir);
|
|
184
|
+
const { count, details } = countComprehensivePaths(allFiles, ALLOWLISTED_WORKFLOW_FILES);
|
|
185
|
+
|
|
186
|
+
if (count > 0) {
|
|
187
|
+
assert.fail(
|
|
188
|
+
`Found ${count} hardcoded .planning/ reference(s) in workflow files:\n${formatViolations(details)}\n\n` +
|
|
189
|
+
'All workflow files (except init-product.md and help.md) must use ${variable} notation.\n' +
|
|
190
|
+
'Replace .planning/STATE.md with ${state_path}, .planning/ROADMAP.md with ${roadmap_path}, etc.'
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
assert.equal(count, 0, 'Non-allowlisted workflow files should have zero .planning/ references');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('GATE: zero hardcoded .planning/ in template files', () => {
|
|
198
|
+
const templateDir = path.join(DGS_ROOT, 'templates');
|
|
199
|
+
const allFiles = collectMdFiles(templateDir);
|
|
200
|
+
const { count, details } = countComprehensivePaths(allFiles);
|
|
201
|
+
|
|
202
|
+
if (count > 0) {
|
|
203
|
+
assert.fail(
|
|
204
|
+
`Found ${count} hardcoded .planning/ reference(s) in template files:\n${formatViolations(details)}\n\n` +
|
|
205
|
+
'Template files must use relative-from-planning-root paths (e.g., phases/XX-name/ not .planning/phases/XX-name/).\n' +
|
|
206
|
+
'For @ context references in prompt templates, use ${variable} notation.'
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
assert.equal(count, 0, 'Template files should have zero .planning/ references');
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it('GATE: zero hardcoded .planning/ in agent files', () => {
|
|
214
|
+
const agentDir = path.join(REPO_ROOT, 'agents');
|
|
215
|
+
const allFiles = collectMdFiles(agentDir);
|
|
216
|
+
const { count, details } = countComprehensivePaths(allFiles);
|
|
217
|
+
|
|
218
|
+
if (count > 0) {
|
|
219
|
+
// Adjust paths for repo-relative display
|
|
220
|
+
const repoDetails = details.map(d => ({
|
|
221
|
+
...d,
|
|
222
|
+
file: path.relative(REPO_ROOT, path.join(DGS_ROOT, d.file)),
|
|
223
|
+
}));
|
|
224
|
+
assert.fail(
|
|
225
|
+
`Found ${count} hardcoded .planning/ reference(s) in agent files:\n${formatViolations(repoDetails)}\n\n` +
|
|
226
|
+
'Agent files must use ${variable} notation resolved by orchestrators at runtime.\n' +
|
|
227
|
+
'Replace .planning/STATE.md with ${state_path}, .planning/phases/ with ${phase_dir}/, etc.'
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
assert.equal(count, 0, 'Agent files should have zero .planning/ references');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('GATE: zero hardcoded .planning/ in reference files (except allowlisted)', () => {
|
|
235
|
+
const refDir = path.join(DGS_ROOT, 'references');
|
|
236
|
+
const allFiles = collectMdFiles(refDir);
|
|
237
|
+
const { count, details } = countComprehensivePaths(allFiles, ALLOWLISTED_REFERENCE_FILES);
|
|
238
|
+
|
|
239
|
+
if (count > 0) {
|
|
240
|
+
assert.fail(
|
|
241
|
+
`Found ${count} hardcoded .planning/ reference(s) in reference files:\n${formatViolations(details)}\n\n` +
|
|
242
|
+
'Reference files (except planning-config.md) must use ${variable} notation.\n' +
|
|
243
|
+
'They inherit variable context from parent workflow init output via @ inclusion.'
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
assert.equal(count, 0, 'Non-allowlisted reference files should have zero .planning/ references');
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// ─── Library Source Gate Test ────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
it('GATE: zero hardcoded path.join(cwd, .planning) in library source files', () => {
|
|
253
|
+
const libDir = path.join(DGS_ROOT, 'bin', 'lib');
|
|
254
|
+
const files = fs.readdirSync(libDir)
|
|
255
|
+
.filter(f => f.endsWith('.cjs'))
|
|
256
|
+
.filter(f => !f.endsWith('.test.cjs'))
|
|
257
|
+
.filter(f => f !== 'test-helpers.cjs')
|
|
258
|
+
.filter(f => f !== 'migration.cjs') // v1 migration intentionally uses hardcoded .planning/ paths
|
|
259
|
+
.map(f => path.join(libDir, f));
|
|
260
|
+
|
|
261
|
+
const HARDCODED_PATTERN = /path\.join\(\s*cwd\s*,\s*['"]\.planning['"]/;
|
|
262
|
+
const violations = [];
|
|
263
|
+
|
|
264
|
+
for (const filePath of files) {
|
|
265
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
266
|
+
const lines = content.split('\n');
|
|
267
|
+
for (let i = 0; i < lines.length; i++) {
|
|
268
|
+
if (lines[i].trimStart().startsWith('//')) continue;
|
|
269
|
+
if (lines[i].trimStart().startsWith('*')) continue;
|
|
270
|
+
if (HARDCODED_PATTERN.test(lines[i])) {
|
|
271
|
+
violations.push(`${path.basename(filePath)}:${i + 1}: ${lines[i].trim()}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (violations.length > 0) {
|
|
277
|
+
assert.fail(`Found ${violations.length} hardcoded path.join(cwd, '.planning') references:\n${violations.join('\n')}`);
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// ─── Allowlist Verification ─────────────────────────────────────────────
|
|
282
|
+
|
|
283
|
+
it('allowlisted workflow files exist and are minimal', () => {
|
|
284
|
+
for (const af of ALLOWLISTED_WORKFLOW_FILES) {
|
|
285
|
+
const fullPath = path.join(DGS_ROOT, af);
|
|
286
|
+
assert.ok(fs.existsSync(fullPath), `Allowlisted file should exist: ${af}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Allowlist must stay minimal
|
|
290
|
+
assert.ok(
|
|
291
|
+
ALLOWLISTED_WORKFLOW_FILES.length <= 2,
|
|
292
|
+
`Workflow allowlist too large (${ALLOWLISTED_WORKFLOW_FILES.length}). ` +
|
|
293
|
+
'Only init-product.md and help.md should be allowlisted. Migrate others.'
|
|
294
|
+
);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('allowlisted reference files exist and are minimal', () => {
|
|
298
|
+
for (const af of ALLOWLISTED_REFERENCE_FILES) {
|
|
299
|
+
const fullPath = path.join(DGS_ROOT, af);
|
|
300
|
+
assert.ok(fs.existsSync(fullPath), `Allowlisted file should exist: ${af}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Allowlist must stay minimal
|
|
304
|
+
assert.ok(
|
|
305
|
+
ALLOWLISTED_REFERENCE_FILES.length <= 1,
|
|
306
|
+
`Reference allowlist too large (${ALLOWLISTED_REFERENCE_FILES.length}). ` +
|
|
307
|
+
'Only planning-config.md should be allowlisted.'
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('known safe paths are excluded from project-scoped audit', () => {
|
|
312
|
+
for (const safePath of SAFE_PRODUCT_PATHS) {
|
|
313
|
+
assert.equal(
|
|
314
|
+
PROJECT_SCOPED_PATTERN.test(safePath),
|
|
315
|
+
false,
|
|
316
|
+
safePath + ' should NOT match project-scoped pattern (it is product-level)'
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
assert.equal(SAFE_PRODUCT_PATHS.length, 4, 'Expected 4 known safe product-level paths');
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
// ─── Documentation Tests ───────────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
it('documents file counts across all categories', () => {
|
|
326
|
+
const workflowFiles = collectMdFiles(path.join(DGS_ROOT, 'workflows'));
|
|
327
|
+
const templateFiles = collectMdFiles(path.join(DGS_ROOT, 'templates'));
|
|
328
|
+
const agentFiles = collectMdFiles(path.join(REPO_ROOT, 'agents'));
|
|
329
|
+
const refFiles = collectMdFiles(path.join(DGS_ROOT, 'references'));
|
|
330
|
+
|
|
331
|
+
console.log(`Workflow files scanned: ${workflowFiles.length} (${ALLOWLISTED_WORKFLOW_FILES.length} allowlisted)`);
|
|
332
|
+
console.log(`Template files scanned: ${templateFiles.length} (0 allowlisted)`);
|
|
333
|
+
console.log(`Agent files scanned: ${agentFiles.length} (0 allowlisted)`);
|
|
334
|
+
console.log(`Reference files scanned: ${refFiles.length} (${ALLOWLISTED_REFERENCE_FILES.length} allowlisted)`);
|
|
335
|
+
console.log(`Total files gated: ${workflowFiles.length + templateFiles.length + agentFiles.length + refFiles.length}`);
|
|
336
|
+
|
|
337
|
+
assert.ok(workflowFiles.length > 0, 'Should find workflow files');
|
|
338
|
+
assert.ok(templateFiles.length > 0, 'Should find template files');
|
|
339
|
+
assert.ok(agentFiles.length > 0, 'Should find agent files');
|
|
340
|
+
assert.ok(refFiles.length > 0, 'Should find reference files');
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
it('documents current hardcoded path count in lib modules (non-test)', () => {
|
|
344
|
+
const libDir = path.join(DGS_ROOT, 'bin', 'lib');
|
|
345
|
+
let files;
|
|
346
|
+
try {
|
|
347
|
+
files = fs.readdirSync(libDir)
|
|
348
|
+
.filter(f => f.endsWith('.cjs'))
|
|
349
|
+
.filter(f => !f.endsWith('.test.cjs'))
|
|
350
|
+
.filter(f => f !== 'test-helpers.cjs')
|
|
351
|
+
.map(f => path.join(libDir, f));
|
|
352
|
+
} catch {
|
|
353
|
+
files = [];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// For lib modules, count raw string literals with .planning/ followed by
|
|
357
|
+
// project-scoped filenames (not inside path.join calls)
|
|
358
|
+
let count = 0;
|
|
359
|
+
const RAW_STRING_PATTERN = /['"`]\.planning\/(?:STATE|ROADMAP|PROJECT|REQUIREMENTS)\.md['"`]/;
|
|
360
|
+
|
|
361
|
+
for (const filePath of files) {
|
|
362
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
363
|
+
const lines = content.split('\n');
|
|
364
|
+
|
|
365
|
+
for (const line of lines) {
|
|
366
|
+
// Skip lines that use path.join (these are properly resolved)
|
|
367
|
+
if (line.includes('path.join')) continue;
|
|
368
|
+
// Skip comment-only lines
|
|
369
|
+
if (line.trimStart().startsWith('//')) continue;
|
|
370
|
+
if (line.trimStart().startsWith('*')) continue;
|
|
371
|
+
|
|
372
|
+
if (RAW_STRING_PATTERN.test(line)) {
|
|
373
|
+
count++;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
console.log('Lib module raw .planning/ string literals: ' + count);
|
|
379
|
+
console.log('Lib modules scanned: ' + files.length);
|
|
380
|
+
|
|
381
|
+
// Documentation test -- always passes, just records the count
|
|
382
|
+
assert.equal(typeof count, 'number');
|
|
383
|
+
});
|
|
384
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* paths.cjs — Planning root detection and path constants
|
|
3
|
+
*
|
|
4
|
+
* LEAF MODULE: Zero DGS imports. Uses only Node.js built-in fs and path.
|
|
5
|
+
* This module sits at the bottom of the dependency graph to prevent
|
|
6
|
+
* circular dependencies with core.cjs and config.cjs.
|
|
7
|
+
*
|
|
8
|
+
* Exports:
|
|
9
|
+
* getPlanningRoot(cwd) — Returns absolute path to planning root
|
|
10
|
+
* getPaths(cwd) — Returns frozen PATHS object with all standard paths
|
|
11
|
+
* initPaths(cwd) — Alias for getPaths (explicit cache population)
|
|
12
|
+
* resetPaths() — Clears the cwd-keyed cache (for test isolation)
|
|
13
|
+
*
|
|
14
|
+
* Detection cascade (getPlanningRoot):
|
|
15
|
+
* 1. .planning/dgs.config.json or .planning/config.json exists -> .planning/ layout
|
|
16
|
+
* 2. dgs.config.json at root with planningRoot: '.' -> root layout
|
|
17
|
+
* 3. dgs.config.json at root without planningRoot: '.' -> .planning/ layout
|
|
18
|
+
* 4. PROJECT.md at root AND no .planning/ directory -> root layout (auto-detect)
|
|
19
|
+
* 5. No signals -> .planning/ layout (default)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
|
|
25
|
+
const _cache = new Map();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The canonical directory name for the projects container.
|
|
29
|
+
* Single source of truth — all project path construction should reference
|
|
30
|
+
* this constant instead of using the string literal 'projects'.
|
|
31
|
+
*/
|
|
32
|
+
const PROJECTS_DIR = 'projects';
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Detect the planning root directory for the given cwd.
|
|
36
|
+
*
|
|
37
|
+
* @param {string} [cwd] - Working directory (defaults to process.cwd())
|
|
38
|
+
* @returns {string} Absolute path to the planning root
|
|
39
|
+
*/
|
|
40
|
+
function getPlanningRoot(cwd) {
|
|
41
|
+
const resolved = path.resolve(cwd || process.cwd());
|
|
42
|
+
const dotPlanning = path.join(resolved, '.planning');
|
|
43
|
+
|
|
44
|
+
// Step 1: .planning/ layout — config files inside .planning/
|
|
45
|
+
if (
|
|
46
|
+
fs.existsSync(path.join(dotPlanning, 'dgs.config.json')) ||
|
|
47
|
+
fs.existsSync(path.join(dotPlanning, 'config.json'))
|
|
48
|
+
) {
|
|
49
|
+
return dotPlanning;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Step 2: Root layout — dgs.config.json at repo root
|
|
53
|
+
const rootConfigPath = path.join(resolved, 'dgs.config.json');
|
|
54
|
+
if (fs.existsSync(rootConfigPath)) {
|
|
55
|
+
try {
|
|
56
|
+
const config = JSON.parse(fs.readFileSync(rootConfigPath, 'utf-8'));
|
|
57
|
+
if (config.planningRoot === '.') return resolved;
|
|
58
|
+
} catch {
|
|
59
|
+
// Malformed JSON — fall through to next check
|
|
60
|
+
}
|
|
61
|
+
// dgs.config.json exists but no planningRoot: '.' or malformed
|
|
62
|
+
// If malformed, we already fell through the try/catch
|
|
63
|
+
// If valid but no planningRoot: '.', return .planning/
|
|
64
|
+
// We need to distinguish: if we got here via catch, we should fall through
|
|
65
|
+
// If we got here via the normal flow (no planningRoot), return .planning/
|
|
66
|
+
return dotPlanning;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Step 3: Auto-detect root layout — PROJECT.md at root, no .planning/ dir
|
|
70
|
+
if (
|
|
71
|
+
fs.existsSync(path.join(resolved, 'PROJECT.md')) &&
|
|
72
|
+
!fs.existsSync(dotPlanning)
|
|
73
|
+
) {
|
|
74
|
+
return resolved;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Step 4: Default — .planning/
|
|
78
|
+
return dotPlanning;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Get the frozen PATHS object for the given cwd.
|
|
83
|
+
* Results are cached per resolved absolute cwd.
|
|
84
|
+
*
|
|
85
|
+
* @param {string} [cwd] - Working directory (defaults to process.cwd())
|
|
86
|
+
* @returns {Readonly<Object>} Frozen PATHS object with ROOT, PHASES, IDEAS, etc.
|
|
87
|
+
*/
|
|
88
|
+
function getPaths(cwd) {
|
|
89
|
+
const resolved = path.resolve(cwd || process.cwd());
|
|
90
|
+
if (_cache.has(resolved)) return _cache.get(resolved);
|
|
91
|
+
|
|
92
|
+
const root = getPlanningRoot(resolved);
|
|
93
|
+
const isRoot = (root === resolved);
|
|
94
|
+
|
|
95
|
+
const paths = Object.freeze({
|
|
96
|
+
ROOT: root,
|
|
97
|
+
PHASES: path.join(root, 'phases'),
|
|
98
|
+
IDEAS: path.join(root, 'ideas'),
|
|
99
|
+
SPECS: path.join(root, 'specs'),
|
|
100
|
+
JOBS: path.join(root, 'jobs'),
|
|
101
|
+
DOCS: path.join(root, 'docs'),
|
|
102
|
+
CODEBASE: path.join(root, 'codebase'),
|
|
103
|
+
MILESTONES: path.join(root, 'milestones'),
|
|
104
|
+
CONFIG: path.join(root, 'dgs.config.json'),
|
|
105
|
+
CONFIG_LEGACY: path.join(root, 'config.json'),
|
|
106
|
+
QUICK: path.join(root, 'quick'),
|
|
107
|
+
TODOS: path.join(root, 'todos'),
|
|
108
|
+
RESEARCH: path.join(root, 'research'),
|
|
109
|
+
DEBUG: path.join(root, 'debug'),
|
|
110
|
+
ARCHIVE: path.join(root, 'archive'),
|
|
111
|
+
PROJECTS: path.join(root, PROJECTS_DIR),
|
|
112
|
+
LAYOUT: isRoot ? 'root' : 'dotplanning',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
_cache.set(resolved, paths);
|
|
116
|
+
return paths;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Populate the cache for the given cwd and return the PATHS object.
|
|
121
|
+
* Alias for getPaths — provides explicit intent for test setup.
|
|
122
|
+
*
|
|
123
|
+
* @param {string} [cwd] - Working directory (defaults to process.cwd())
|
|
124
|
+
* @returns {Readonly<Object>} Frozen PATHS object
|
|
125
|
+
*/
|
|
126
|
+
function initPaths(cwd) {
|
|
127
|
+
return getPaths(cwd);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Clear all cached PATHS entries.
|
|
132
|
+
* Call in afterEach for test isolation between test cases.
|
|
133
|
+
*/
|
|
134
|
+
function resetPaths() {
|
|
135
|
+
_cache.clear();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
getPlanningRoot,
|
|
140
|
+
getPaths,
|
|
141
|
+
initPaths,
|
|
142
|
+
resetPaths,
|
|
143
|
+
PROJECTS_DIR,
|
|
144
|
+
};
|