@karthikrajkumar.kannan/get-things-done 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.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +237 -0
  3. package/agents/backward/gtd-accuracy-verifier.md +198 -0
  4. package/agents/backward/gtd-api-doc-writer.md +130 -0
  5. package/agents/backward/gtd-api-extractor.md +128 -0
  6. package/agents/backward/gtd-architecture-analyzer.md +144 -0
  7. package/agents/backward/gtd-capacity-writer.md +123 -0
  8. package/agents/backward/gtd-codebase-mapper.md +274 -0
  9. package/agents/backward/gtd-completeness-auditor.md +129 -0
  10. package/agents/backward/gtd-data-flow-tracer.md +104 -0
  11. package/agents/backward/gtd-dependency-analyzer.md +98 -0
  12. package/agents/backward/gtd-diagram-generator.md +152 -0
  13. package/agents/backward/gtd-hld-writer.md +123 -0
  14. package/agents/backward/gtd-lld-writer.md +126 -0
  15. package/agents/backward/gtd-pattern-detector.md +111 -0
  16. package/agents/backward/gtd-performance-profiler.md +93 -0
  17. package/agents/backward/gtd-runbook-writer.md +126 -0
  18. package/agents/backward/gtd-security-scanner.md +106 -0
  19. package/agents/backward/gtd-sysdesign-writer.md +137 -0
  20. package/agents/backward/gtd-tdd-writer.md +125 -0
  21. package/agents/forward/gtd-code-reviewer.md +130 -0
  22. package/agents/forward/gtd-debugger.md +133 -0
  23. package/agents/forward/gtd-deployer.md +110 -0
  24. package/agents/forward/gtd-executor.md +110 -0
  25. package/agents/forward/gtd-phase-researcher.md +114 -0
  26. package/agents/forward/gtd-plan-checker.md +132 -0
  27. package/agents/forward/gtd-planner.md +136 -0
  28. package/agents/forward/gtd-project-researcher.md +106 -0
  29. package/agents/forward/gtd-research-synthesizer.md +99 -0
  30. package/agents/forward/gtd-roadmapper.md +126 -0
  31. package/agents/forward/gtd-test-runner.md +119 -0
  32. package/agents/forward/gtd-verifier.md +115 -0
  33. package/agents/sync/gtd-alignment-auditor.md +222 -0
  34. package/agents/sync/gtd-drift-detector.md +222 -0
  35. package/agents/sync/gtd-reconciliation-planner.md +194 -0
  36. package/bin/gtd-tools.cjs +89 -0
  37. package/bin/install.js +164 -0
  38. package/commands/gtd/backward/analyze.md +42 -0
  39. package/commands/gtd/backward/create-all.md +32 -0
  40. package/commands/gtd/backward/create-api-docs.md +33 -0
  41. package/commands/gtd/backward/create-capacity.md +33 -0
  42. package/commands/gtd/backward/create-hld.md +33 -0
  43. package/commands/gtd/backward/create-lld.md +33 -0
  44. package/commands/gtd/backward/create-runbook.md +33 -0
  45. package/commands/gtd/backward/create-sysdesign.md +33 -0
  46. package/commands/gtd/backward/create-tdd.md +33 -0
  47. package/commands/gtd/backward/diff.md +22 -0
  48. package/commands/gtd/backward/doc-status.md +24 -0
  49. package/commands/gtd/backward/review-docs.md +22 -0
  50. package/commands/gtd/backward/scan.md +32 -0
  51. package/commands/gtd/backward/update-docs.md +30 -0
  52. package/commands/gtd/backward/verify-docs.md +28 -0
  53. package/commands/gtd/forward/add-phase.md +28 -0
  54. package/commands/gtd/forward/autonomous.md +28 -0
  55. package/commands/gtd/forward/code-review.md +28 -0
  56. package/commands/gtd/forward/complete-milestone.md +28 -0
  57. package/commands/gtd/forward/debug.md +28 -0
  58. package/commands/gtd/forward/discuss-phase.md +29 -0
  59. package/commands/gtd/forward/execute-phase.md +28 -0
  60. package/commands/gtd/forward/fast.md +28 -0
  61. package/commands/gtd/forward/new-milestone.md +28 -0
  62. package/commands/gtd/forward/new-project.md +29 -0
  63. package/commands/gtd/forward/next.md +28 -0
  64. package/commands/gtd/forward/plan-phase.md +29 -0
  65. package/commands/gtd/forward/progress.md +28 -0
  66. package/commands/gtd/forward/quick.md +28 -0
  67. package/commands/gtd/forward/ship.md +28 -0
  68. package/commands/gtd/forward/verify-work.md +28 -0
  69. package/commands/gtd/sync/audit.md +27 -0
  70. package/commands/gtd/sync/drift.md +27 -0
  71. package/commands/gtd/sync/reconcile.md +27 -0
  72. package/commands/gtd/sync/sync.md +27 -0
  73. package/commands/gtd/utility/health.md +53 -0
  74. package/commands/gtd/utility/help.md +61 -0
  75. package/commands/gtd/utility/map-codebase.md +27 -0
  76. package/commands/gtd/utility/settings.md +65 -0
  77. package/commands/gtd/utility/status.md +57 -0
  78. package/contexts/analysis.md +26 -0
  79. package/contexts/execution.md +35 -0
  80. package/contexts/planning.md +33 -0
  81. package/contexts/research.md +26 -0
  82. package/contexts/review.md +27 -0
  83. package/contexts/writing.md +29 -0
  84. package/hooks/gtd-check-update.js +37 -0
  85. package/hooks/gtd-context-monitor.js +32 -0
  86. package/hooks/gtd-prompt-guard.js +35 -0
  87. package/hooks/gtd-statusline.js +32 -0
  88. package/lib/agent-skills.cjs +130 -0
  89. package/lib/analysis.cjs +242 -0
  90. package/lib/config.cjs +255 -0
  91. package/lib/deploy.cjs +222 -0
  92. package/lib/diff-engine.cjs +245 -0
  93. package/lib/docs.cjs +243 -0
  94. package/lib/drift-engine.cjs +202 -0
  95. package/lib/file-ops.cjs +106 -0
  96. package/lib/frontmatter.cjs +100 -0
  97. package/lib/git.cjs +137 -0
  98. package/lib/init.cjs +370 -0
  99. package/lib/installer-core.cjs +197 -0
  100. package/lib/installers/augment.cjs +62 -0
  101. package/lib/installers/claude.cjs +89 -0
  102. package/lib/installers/cline.cjs +96 -0
  103. package/lib/installers/codex.cjs +63 -0
  104. package/lib/installers/copilot.cjs +62 -0
  105. package/lib/installers/cursor.cjs +62 -0
  106. package/lib/installers/gemini.cjs +62 -0
  107. package/lib/installers/opencode.cjs +62 -0
  108. package/lib/installers/windsurf.cjs +62 -0
  109. package/lib/phase.cjs +206 -0
  110. package/lib/roadmap.cjs +156 -0
  111. package/lib/scale-adapter.cjs +192 -0
  112. package/lib/security.cjs +243 -0
  113. package/lib/state.cjs +320 -0
  114. package/lib/template.cjs +218 -0
  115. package/lib/test-runner.cjs +202 -0
  116. package/package.json +76 -0
  117. package/references/agent-contracts.md +157 -0
  118. package/references/analysis-patterns.md +138 -0
  119. package/references/context-budget.md +148 -0
  120. package/references/diagram-conventions.md +88 -0
  121. package/references/document-standards.md +60 -0
  122. package/references/framework-signatures.md +609 -0
  123. package/references/gate-prompts.md +239 -0
  124. package/references/language-analyzers.md +227 -0
  125. package/references/planning-config.md +125 -0
  126. package/references/questioning.md +142 -0
  127. package/references/verification-patterns.md +67 -0
  128. package/templates/backward/api-docs/standard.md +42 -0
  129. package/templates/backward/capacity/standard.md +50 -0
  130. package/templates/backward/formats/compliance-guide.md +45 -0
  131. package/templates/backward/hld/standard.md +62 -0
  132. package/templates/backward/lld/standard.md +63 -0
  133. package/templates/backward/runbook/standard.md +50 -0
  134. package/templates/backward/system-design/standard.md +64 -0
  135. package/templates/backward/tdd/compliance.md +146 -0
  136. package/templates/backward/tdd/enterprise.md +134 -0
  137. package/templates/backward/tdd/standard.md +88 -0
  138. package/templates/backward/tdd/startup.md +51 -0
  139. package/templates/forward/context.md +65 -0
  140. package/templates/forward/phase-prompt.md +109 -0
  141. package/templates/forward/project.md +71 -0
  142. package/templates/forward/requirements.md +74 -0
  143. package/templates/forward/research/ARCHITECTURE.md +118 -0
  144. package/templates/forward/research/FEATURES.md +95 -0
  145. package/templates/forward/research/PITFALLS.md +106 -0
  146. package/templates/forward/research/STACK.md +80 -0
  147. package/templates/forward/research/SUMMARY.md +86 -0
  148. package/templates/forward/roadmap.md +72 -0
  149. package/workflows/backward/analyze-codebase.md +123 -0
  150. package/workflows/backward/create-all.md +53 -0
  151. package/workflows/backward/generate-document.md +182 -0
  152. package/workflows/backward/incremental-update.md +71 -0
  153. package/workflows/backward/review-document.md +102 -0
  154. package/workflows/backward/scan-codebase.md +111 -0
  155. package/workflows/backward/verify-document.md +79 -0
  156. package/workflows/forward/add-phase.md +29 -0
  157. package/workflows/forward/autonomous.md +62 -0
  158. package/workflows/forward/code-review.md +78 -0
  159. package/workflows/forward/complete-milestone.md +45 -0
  160. package/workflows/forward/debug.md +78 -0
  161. package/workflows/forward/deploy-local.md +51 -0
  162. package/workflows/forward/discuss-phase.md +89 -0
  163. package/workflows/forward/execute-phase.md +138 -0
  164. package/workflows/forward/fast.md +64 -0
  165. package/workflows/forward/new-milestone.md +61 -0
  166. package/workflows/forward/new-project.md +126 -0
  167. package/workflows/forward/next.md +49 -0
  168. package/workflows/forward/plan-phase.md +100 -0
  169. package/workflows/forward/progress.md +37 -0
  170. package/workflows/forward/quick.md +65 -0
  171. package/workflows/forward/ship.md +40 -0
  172. package/workflows/forward/test-phase.md +47 -0
  173. package/workflows/forward/verify-work.md +52 -0
  174. package/workflows/sync/audit.md +110 -0
  175. package/workflows/sync/detect-drift.md +122 -0
  176. package/workflows/sync/reconcile.md +113 -0
  177. package/workflows/sync/sync.md +150 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * GTD Template Engine — Variable substitution, conditionals, file includes.
3
+ *
4
+ * Template syntax:
5
+ * {{variable_name}} — Replaced with context value
6
+ * {{#section_name}} ... {{/section_name}} — Conditional section (included if truthy)
7
+ * {{^section_name}} ... {{/section_name}} — Inverted section (included if falsy)
8
+ * {{@file:path}} — Inline file content
9
+ *
10
+ * @module lib/template
11
+ */
12
+
13
+ 'use strict';
14
+
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ // Resolve templates directory relative to package root
19
+ const TEMPLATES_DIR = path.resolve(__dirname, '..', 'templates');
20
+
21
+ /**
22
+ * Fill a template with variables.
23
+ *
24
+ * @param {string} templateContent - Raw template string
25
+ * @param {object} variables - Key-value pairs for substitution
26
+ * @returns {string} Filled template
27
+ */
28
+ function fill(templateContent, variables) {
29
+ let result = templateContent;
30
+
31
+ // 1. Process conditional sections: {{#flag}} ... {{/flag}}
32
+ result = result.replace(
33
+ /\{\{#(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g,
34
+ (_match, key, content) => {
35
+ return variables[key] ? content : '';
36
+ },
37
+ );
38
+
39
+ // 2. Process inverted sections: {{^flag}} ... {{/flag}}
40
+ result = result.replace(
41
+ /\{\{\^(\w+)\}\}([\s\S]*?)\{\{\/\1\}\}/g,
42
+ (_match, key, content) => {
43
+ return !variables[key] ? content : '';
44
+ },
45
+ );
46
+
47
+ // 3. Process file includes: {{@file:path}}
48
+ result = result.replace(/\{\{@file:(.*?)\}\}/g, (_match, filePath) => {
49
+ try {
50
+ const resolved = path.isAbsolute(filePath)
51
+ ? filePath
52
+ : path.resolve(process.cwd(), filePath);
53
+ return fs.readFileSync(resolved, 'utf8');
54
+ } catch (_) {
55
+ return `<!-- File not found: ${filePath} -->`;
56
+ }
57
+ });
58
+
59
+ // 4. Process variable substitution: {{variable_name}}
60
+ result = result.replace(/\{\{(\w[\w.]*)\}\}/g, (_match, key) => {
61
+ const value = getNestedValue(variables, key);
62
+ if (value === undefined || value === null) return _match; // Preserve unresolved
63
+ return String(value);
64
+ });
65
+
66
+ return result;
67
+ }
68
+
69
+ /**
70
+ * Load and fill a template by type and format.
71
+ *
72
+ * @param {string} type - Template type ('tdd', 'hld', 'lld', etc.)
73
+ * @param {string} [format='standard'] - Format variant ('standard', 'enterprise', 'startup', 'compliance')
74
+ * @param {object} variables - Variables for substitution
75
+ * @returns {string} Filled template
76
+ */
77
+ function loadAndFill(type, format, variables) {
78
+ const templatePath = resolveTemplate(type, format);
79
+ const content = fs.readFileSync(templatePath, 'utf8');
80
+ return fill(content, variables);
81
+ }
82
+
83
+ /**
84
+ * Resolve a template file path by type and format.
85
+ * Resolution chain: format-specific → standard → default
86
+ *
87
+ * @param {string} type - Template type
88
+ * @param {string} [format='standard'] - Format variant
89
+ * @returns {string} Absolute path to template file
90
+ * @throws {Error} If no template found
91
+ */
92
+ function resolveTemplate(type, format) {
93
+ const formatName = format || 'standard';
94
+
95
+ // Check backward templates first, then forward
96
+ const candidates = [
97
+ path.join(TEMPLATES_DIR, 'backward', type, `${formatName}.md`),
98
+ path.join(TEMPLATES_DIR, 'backward', type, 'standard.md'),
99
+ path.join(TEMPLATES_DIR, 'backward', type, 'default.md'),
100
+ path.join(TEMPLATES_DIR, 'forward', type, `${formatName}.md`),
101
+ path.join(TEMPLATES_DIR, 'forward', type, 'standard.md'),
102
+ path.join(TEMPLATES_DIR, type, `${formatName}.md`),
103
+ path.join(TEMPLATES_DIR, type, 'standard.md'),
104
+ ];
105
+
106
+ for (const candidate of candidates) {
107
+ if (fs.existsSync(candidate)) return candidate;
108
+ }
109
+
110
+ throw new Error(
111
+ `Template not found for type="${type}", format="${formatName}". ` +
112
+ `Searched: ${candidates.map((c) => path.relative(TEMPLATES_DIR, c)).join(', ')}`,
113
+ );
114
+ }
115
+
116
+ /**
117
+ * List all available template types and their formats.
118
+ *
119
+ * @returns {Array<{type: string, formats: string[]}>}
120
+ */
121
+ function listTemplates() {
122
+ const result = [];
123
+
124
+ for (const subdir of ['backward', 'forward']) {
125
+ const dir = path.join(TEMPLATES_DIR, subdir);
126
+ if (!fs.existsSync(dir)) continue;
127
+
128
+ for (const typeDir of fs.readdirSync(dir, { withFileTypes: true })) {
129
+ if (!typeDir.isDirectory()) continue;
130
+
131
+ const typePath = path.join(dir, typeDir.name);
132
+ const formats = fs.readdirSync(typePath)
133
+ .filter((f) => f.endsWith('.md'))
134
+ .map((f) => f.replace('.md', ''));
135
+
136
+ if (formats.length > 0) {
137
+ result.push({ type: typeDir.name, category: subdir, formats });
138
+ }
139
+ }
140
+ }
141
+
142
+ return result;
143
+ }
144
+
145
+ /**
146
+ * Validate a template for syntax errors.
147
+ *
148
+ * @param {string} content - Template content
149
+ * @returns {{ valid: boolean, errors: string[] }}
150
+ */
151
+ function validateTemplate(content) {
152
+ const errors = [];
153
+
154
+ // Check for unclosed conditional sections
155
+ const opens = content.match(/\{\{#(\w+)\}\}/g) || [];
156
+ const closes = content.match(/\{\{\/(\w+)\}\}/g) || [];
157
+
158
+ const openNames = opens.map((m) => m.match(/\{\{#(\w+)\}\}/)[1]);
159
+ const closeNames = closes.map((m) => m.match(/\{\{\/(\w+)\}\}/)[1]);
160
+
161
+ for (const name of openNames) {
162
+ if (!closeNames.includes(name)) {
163
+ errors.push(`Unclosed section: {{#${name}}} has no matching {{/${name}}}`);
164
+ }
165
+ }
166
+
167
+ for (const name of closeNames) {
168
+ if (!openNames.includes(name)) {
169
+ errors.push(`Orphaned close: {{/${name}}} has no matching {{#${name}}}`);
170
+ }
171
+ }
172
+
173
+ return { valid: errors.length === 0, errors };
174
+ }
175
+
176
+ // --- Utility ---
177
+
178
+ function getNestedValue(obj, dotPath) {
179
+ const keys = dotPath.split('.');
180
+ let current = obj;
181
+ for (const key of keys) {
182
+ if (current === null || current === undefined || typeof current !== 'object') {
183
+ return undefined;
184
+ }
185
+ current = current[key];
186
+ }
187
+ return current;
188
+ }
189
+
190
+ // CLI handler
191
+ function run(args) {
192
+ const subcommand = args[0];
193
+
194
+ if (subcommand === 'list') {
195
+ process.stdout.write(JSON.stringify(listTemplates(), null, 2));
196
+ } else if (subcommand === 'resolve' && args[1]) {
197
+ try {
198
+ const resolved = resolveTemplate(args[1], args[2]);
199
+ process.stdout.write(resolved);
200
+ } catch (err) {
201
+ process.stderr.write(err.message + '\n');
202
+ process.exit(1);
203
+ }
204
+ } else {
205
+ process.stderr.write('Usage: gtd-tools.cjs template <list|resolve> [type] [format]\n');
206
+ process.exit(1);
207
+ }
208
+ }
209
+
210
+ module.exports = {
211
+ fill,
212
+ loadAndFill,
213
+ resolveTemplate,
214
+ listTemplates,
215
+ validateTemplate,
216
+ TEMPLATES_DIR,
217
+ run,
218
+ };
@@ -0,0 +1,202 @@
1
+ /**
2
+ * GTD Test Runner Module — Test framework detection, discovery, and execution.
3
+ * @module lib/test-runner
4
+ */
5
+
6
+ 'use strict';
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+ const { fileExists } = require('./file-ops.cjs');
11
+
12
+ /**
13
+ * Test framework detection rules.
14
+ */
15
+ const TEST_FRAMEWORKS = [
16
+ {
17
+ name: 'vitest',
18
+ detect: (root) => {
19
+ const pkg = loadPkg(root);
20
+ return (pkg?.devDependencies?.vitest || pkg?.dependencies?.vitest) ? true : false;
21
+ },
22
+ runCmd: 'npx vitest run',
23
+ coverageCmd: 'npx vitest run --coverage',
24
+ filePattern: '**/*.test.{ts,js,tsx,jsx}',
25
+ configFiles: ['vitest.config.ts', 'vitest.config.js'],
26
+ },
27
+ {
28
+ name: 'jest',
29
+ detect: (root) => {
30
+ const pkg = loadPkg(root);
31
+ return (pkg?.devDependencies?.jest || pkg?.dependencies?.jest) ? true : false;
32
+ },
33
+ runCmd: 'npx jest',
34
+ coverageCmd: 'npx jest --coverage',
35
+ filePattern: '**/*.test.{ts,js,tsx,jsx}',
36
+ configFiles: ['jest.config.ts', 'jest.config.js'],
37
+ },
38
+ {
39
+ name: 'pytest',
40
+ detect: (root) =>
41
+ fileExists(path.join(root, 'pytest.ini')) ||
42
+ fileExists(path.join(root, 'pyproject.toml')) ||
43
+ fileExists(path.join(root, 'conftest.py')) ||
44
+ fs.existsSync(path.join(root, 'tests')) && hasFiles(path.join(root, 'tests'), 'test_*.py'),
45
+ runCmd: 'pytest',
46
+ coverageCmd: 'pytest --cov',
47
+ filePattern: '**/test_*.py',
48
+ configFiles: ['pytest.ini', 'pyproject.toml', 'setup.cfg'],
49
+ },
50
+ {
51
+ name: 'go-test',
52
+ detect: (root) =>
53
+ fileExists(path.join(root, 'go.mod')) &&
54
+ hasFiles(root, '*_test.go'),
55
+ runCmd: 'go test ./...',
56
+ coverageCmd: 'go test ./... -cover',
57
+ filePattern: '**/*_test.go',
58
+ configFiles: [],
59
+ },
60
+ {
61
+ name: 'cargo-test',
62
+ detect: (root) => fileExists(path.join(root, 'Cargo.toml')),
63
+ runCmd: 'cargo test',
64
+ coverageCmd: 'cargo tarpaulin',
65
+ filePattern: '**/tests/**/*.rs',
66
+ configFiles: ['Cargo.toml'],
67
+ },
68
+ {
69
+ name: 'rspec',
70
+ detect: (root) =>
71
+ fileExists(path.join(root, 'Gemfile')) &&
72
+ fs.existsSync(path.join(root, 'spec')),
73
+ runCmd: 'bundle exec rspec',
74
+ coverageCmd: 'bundle exec rspec',
75
+ filePattern: 'spec/**/*_spec.rb',
76
+ configFiles: ['.rspec', 'spec/spec_helper.rb'],
77
+ },
78
+ ];
79
+
80
+ /**
81
+ * Detect the test framework for a project.
82
+ * @param {string} projectRoot - Project root directory
83
+ * @returns {{ name: string, runCmd: string, coverageCmd: string, filePattern: string }|null}
84
+ */
85
+ function detectTestFramework(projectRoot) {
86
+ for (const fw of TEST_FRAMEWORKS) {
87
+ if (fw.detect(projectRoot)) {
88
+ return {
89
+ name: fw.name,
90
+ runCmd: fw.runCmd,
91
+ coverageCmd: fw.coverageCmd,
92
+ filePattern: fw.filePattern,
93
+ };
94
+ }
95
+ }
96
+ return null;
97
+ }
98
+
99
+ /**
100
+ * Count test files in a project.
101
+ * @param {string} projectRoot - Project root directory
102
+ * @param {string} [pattern] - Glob pattern for test files
103
+ * @returns {number}
104
+ */
105
+ function countTestFiles(projectRoot, pattern) {
106
+ const fw = detectTestFramework(projectRoot);
107
+ if (!fw && !pattern) return 0;
108
+
109
+ const searchPattern = pattern || fw.filePattern;
110
+ let count = 0;
111
+
112
+ function walk(dir) {
113
+ if (!fs.existsSync(dir)) return;
114
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
115
+ if (entry.name === 'node_modules' || entry.name === '.git' || entry.name === 'dist') continue;
116
+ const full = path.join(dir, entry.name);
117
+ if (entry.isDirectory()) {
118
+ walk(full);
119
+ } else if (matchesTestPattern(entry.name, searchPattern)) {
120
+ count++;
121
+ }
122
+ }
123
+ }
124
+
125
+ walk(projectRoot);
126
+ return count;
127
+ }
128
+
129
+ /**
130
+ * Get test infrastructure summary.
131
+ * @param {string} projectRoot - Project root directory
132
+ * @returns {{ framework: string|null, testFiles: number, hasConfig: boolean, runCmd: string|null }}
133
+ */
134
+ function getTestSummary(projectRoot) {
135
+ const fw = detectTestFramework(projectRoot);
136
+ if (!fw) {
137
+ return { framework: null, testFiles: 0, hasConfig: false, runCmd: null };
138
+ }
139
+
140
+ const testFiles = countTestFiles(projectRoot, fw.filePattern);
141
+ const hasConfig = fw.configFiles
142
+ ? fw.configFiles.some((cf) => fileExists(path.join(projectRoot, cf)))
143
+ : false;
144
+
145
+ return {
146
+ framework: fw.name,
147
+ testFiles,
148
+ hasConfig,
149
+ runCmd: fw.runCmd,
150
+ coverageCmd: fw.coverageCmd,
151
+ };
152
+ }
153
+
154
+ // --- Helpers ---
155
+
156
+ function loadPkg(dir) {
157
+ try {
158
+ return JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf8'));
159
+ } catch (_) {
160
+ return null;
161
+ }
162
+ }
163
+
164
+ function hasFiles(dir, pattern) {
165
+ try {
166
+ return fs.readdirSync(dir).some((f) => matchesTestPattern(f, pattern));
167
+ } catch (_) {
168
+ return false;
169
+ }
170
+ }
171
+
172
+ function matchesTestPattern(filename, pattern) {
173
+ // Simple pattern matching: *.test.js, test_*.py, *_test.go
174
+ if (pattern.includes('test_*.py')) return filename.startsWith('test_') && filename.endsWith('.py');
175
+ if (pattern.includes('*_test.go')) return filename.endsWith('_test.go');
176
+ if (pattern.includes('*_spec.rb')) return filename.endsWith('_spec.rb');
177
+ if (pattern.includes('*.test.')) return filename.includes('.test.');
178
+ return false;
179
+ }
180
+
181
+ // CLI handler
182
+ function run(args) {
183
+ const projectRoot = process.cwd();
184
+ const subcommand = args[0] || 'detect';
185
+
186
+ if (subcommand === 'detect') {
187
+ process.stdout.write(JSON.stringify(getTestSummary(projectRoot), null, 2));
188
+ } else if (subcommand === 'count') {
189
+ process.stdout.write(JSON.stringify(countTestFiles(projectRoot)));
190
+ } else {
191
+ process.stderr.write('Usage: gtd-tools.cjs test <detect|count>\n');
192
+ process.exit(1);
193
+ }
194
+ }
195
+
196
+ module.exports = {
197
+ TEST_FRAMEWORKS,
198
+ detectTestFramework,
199
+ countTestFiles,
200
+ getTestSummary,
201
+ run,
202
+ };
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "@karthikrajkumar.kannan/get-things-done",
3
+ "version": "1.0.0",
4
+ "description": "Bidirectional spec-driven agentic framework — Forward (idea to code to deploy), Backward (code to docs), Sync (drift detection and reconciliation). The first framework that goes both ways.",
5
+ "keywords": [
6
+ "ai",
7
+ "agentic",
8
+ "spec-driven",
9
+ "documentation",
10
+ "code-generation",
11
+ "claude",
12
+ "claude-code",
13
+ "llm",
14
+ "technical-design",
15
+ "reverse-engineering",
16
+ "drift-detection",
17
+ "bidirectional",
18
+ "gemini",
19
+ "copilot",
20
+ "cursor",
21
+ "windsurf",
22
+ "codex"
23
+ ],
24
+ "author": "GTD Contributors",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/get-things-done/get-things-done"
29
+ },
30
+ "bin": {
31
+ "get-things-done": "./bin/install.js"
32
+ },
33
+ "main": "./bin/gtd-tools.cjs",
34
+ "files": [
35
+ "bin/",
36
+ "lib/",
37
+ "agents/",
38
+ "commands/",
39
+ "workflows/",
40
+ "references/",
41
+ "templates/",
42
+ "contexts/",
43
+ "hooks/"
44
+ ],
45
+ "engines": {
46
+ "node": ">=20.0.0"
47
+ },
48
+ "scripts": {
49
+ "test": "vitest run",
50
+ "test:watch": "vitest watch",
51
+ "test:coverage": "vitest run --coverage",
52
+ "lint": "eslint .",
53
+ "lint:fix": "eslint . --fix",
54
+ "format": "prettier --write .",
55
+ "format:check": "prettier --check .",
56
+ "quality": "npm run lint && npm run format:check && npm run test",
57
+ "prepare": "husky"
58
+ },
59
+ "devDependencies": {
60
+ "vitest": "^3.1.0",
61
+ "@vitest/coverage-v8": "^3.1.0",
62
+ "eslint": "^9.0.0",
63
+ "prettier": "^3.5.0",
64
+ "husky": "^9.1.0",
65
+ "lint-staged": "^15.4.0"
66
+ },
67
+ "lint-staged": {
68
+ "*.{js,cjs,ts}": [
69
+ "eslint --fix",
70
+ "prettier --write"
71
+ ],
72
+ "*.{md,json,yml,yaml}": [
73
+ "prettier --write"
74
+ ]
75
+ }
76
+ }
@@ -0,0 +1,157 @@
1
+ # Agent Contracts
2
+
3
+ > Formal interface definitions between orchestrators and agents in the forward pipeline.
4
+
5
+ ---
6
+
7
+ ## Contract Overview
8
+
9
+ Every agent interaction follows this lifecycle:
10
+
11
+ ```
12
+ Orchestrator --> [Spawn] --> Agent
13
+ Orchestrator --> [Context Bundle] --> Agent
14
+ Agent --> [File Artifacts] --> Orchestrator
15
+ Agent --> [Status Signal] --> Orchestrator
16
+ ```
17
+
18
+ ---
19
+
20
+ ## Spawn Protocol
21
+
22
+ ### How Orchestrators Spawn Agents
23
+
24
+ | Field | Required | Description |
25
+ |-------|----------|-------------|
26
+ | `agent_type` | Yes | One of: `research`, `planning`, `execution`, `gate` |
27
+ | `agent_id` | Yes | Unique identifier, format: `{{agent_type}}-{{sequence}}` |
28
+ | `task_description` | Yes | One-line description of what the agent must do |
29
+ | `context_files` | Yes | List of file paths the agent must read before starting |
30
+ | `output_files` | Yes | List of file paths the agent must produce |
31
+ | `timeout_ms` | No | Override default timeout (see defaults below) |
32
+ | `max_retries` | No | Override default retry count |
33
+
34
+ ### Example Spawn
35
+
36
+ ```json
37
+ {
38
+ "agent_type": "research",
39
+ "agent_id": "research-1",
40
+ "task_description": "Analyze technology stack options for a React + Node.js SaaS app",
41
+ "context_files": [
42
+ "PROJECT.md",
43
+ "REQUIREMENTS.md"
44
+ ],
45
+ "output_files": [
46
+ "research/STACK.md"
47
+ ],
48
+ "timeout_ms": 120000,
49
+ "max_retries": 1
50
+ }
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Context Bundle
56
+
57
+ What the agent receives when spawned.
58
+
59
+ | Agent Type | Always Receives | Conditionally Receives |
60
+ |-----------|----------------|----------------------|
61
+ | Research | PROJECT.md, REQUIREMENTS.md | Prior research outputs (if re-running) |
62
+ | Planning | PROJECT.md, REQUIREMENTS.md, research/* | User feedback (if revision) |
63
+ | Execution | PROJECT.md, phase CONTEXT.md, phase PROMPT.md | Prior phase artifacts |
64
+ | Gate | Phase output files, REQUIREMENTS.md | ROADMAP.md (for cross-phase gates) |
65
+
66
+ ### Context Size Rules
67
+
68
+ - Total context bundle must fit within the agent's allocated token budget
69
+ - If context exceeds budget, orchestrator must summarize or truncate
70
+ - Priority order for truncation: research files > context files > requirements > project
71
+
72
+ ---
73
+
74
+ ## Result Protocol
75
+
76
+ ### How Agents Return Results
77
+
78
+ Agents communicate results through file artifacts, not return values.
79
+
80
+ | Signal | Mechanism | Description |
81
+ |--------|-----------|-------------|
82
+ | Success | All `output_files` exist and are non-empty | Agent completed its task |
83
+ | Partial | Some `output_files` exist | Agent completed partially |
84
+ | Failure | No `output_files` created OR error marker file | Agent could not complete |
85
+ | Escalation | `ESCALATION.md` file created | Agent needs human decision |
86
+
87
+ ### Result File Requirements
88
+
89
+ - Every output file must have a YAML-style header with `agent_id` and `timestamp`
90
+ - Files must be valid Markdown
91
+ - Files must not exceed 500 lines (split into multiple files if needed)
92
+ - Agent must not modify files outside its `output_files` list
93
+
94
+ ---
95
+
96
+ ## Timeout Handling
97
+
98
+ | Agent Type | Default Timeout | Max Timeout | On Timeout |
99
+ |-----------|----------------|-------------|------------|
100
+ | Research | 120s | 300s | Retry once, then mark partial |
101
+ | Planning | 180s | 300s | Retry once, then escalate |
102
+ | Execution | 300s | 600s | Retry once, then pause pipeline |
103
+ | Gate | 60s | 120s | Auto-fail the gate |
104
+
105
+ ### Timeout Behavior
106
+
107
+ 1. Orchestrator sends a soft cancellation signal at `timeout - 30s`
108
+ 2. Agent should wrap up and write partial results
109
+ 3. At timeout, orchestrator force-terminates the agent
110
+ 4. Partial output files (if any) are preserved
111
+ 5. Retry uses the same context bundle plus partial output as additional context
112
+
113
+ ---
114
+
115
+ ## Retry Policy
116
+
117
+ | Condition | Retry | Max Retries | Backoff |
118
+ |-----------|-------|-------------|---------|
119
+ | Timeout | Yes | 1 | None (immediate) |
120
+ | Output file missing | Yes | 1 | None |
121
+ | Output file empty | Yes | 1 | None |
122
+ | Agent error (crash) | Yes | 2 | 5s between retries |
123
+ | Escalation signal | No | - | Route to user |
124
+ | Gate failure | No | - | Route to revision |
125
+
126
+ ### Retry Context
127
+
128
+ On retry, the agent receives the original context bundle plus:
129
+ - `_retry_reason`: Why the previous attempt failed
130
+ - `_partial_output`: Any files the previous attempt produced
131
+ - `_attempt_number`: Current attempt (1-indexed)
132
+
133
+ ---
134
+
135
+ ## Inter-Agent Communication
136
+
137
+ Agents do NOT communicate directly. All coordination flows through the orchestrator.
138
+
139
+ | Allowed | Not Allowed |
140
+ |---------|-------------|
141
+ | Agent writes to its output files | Agent reads another agent's in-progress files |
142
+ | Agent reads files listed in context_files | Agent spawns sub-agents |
143
+ | Agent creates ESCALATION.md | Agent modifies orchestrator state |
144
+ | Agent logs to its designated log path | Agent writes to shared directories |
145
+
146
+ ---
147
+
148
+ ## Escalation Protocol
149
+
150
+ When an agent encounters a decision it cannot make:
151
+
152
+ 1. Create `ESCALATION.md` in the phase directory
153
+ 2. Include: question, options, recommendation, impact of each option
154
+ 3. Set status to `escalated`
155
+ 4. Orchestrator pauses the pipeline and presents to user
156
+ 5. User decision is recorded in CONTEXT.md
157
+ 6. Agent is re-spawned with the decision in context