@imix-js/taproot 0.2.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 (124) hide show
  1. package/README.md +88 -0
  2. package/dist/adapters/index.d.ts +20 -0
  3. package/dist/adapters/index.js +452 -0
  4. package/dist/adapters/index.js.map +1 -0
  5. package/dist/cli.d.ts +2 -0
  6. package/dist/cli.js +40 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/commands/acceptance-check.d.ts +26 -0
  9. package/dist/commands/acceptance-check.js +213 -0
  10. package/dist/commands/acceptance-check.js.map +1 -0
  11. package/dist/commands/check-orphans.d.ts +8 -0
  12. package/dist/commands/check-orphans.js +157 -0
  13. package/dist/commands/check-orphans.js.map +1 -0
  14. package/dist/commands/commithook.d.ts +15 -0
  15. package/dist/commands/commithook.js +389 -0
  16. package/dist/commands/commithook.js.map +1 -0
  17. package/dist/commands/coverage.d.ts +41 -0
  18. package/dist/commands/coverage.js +390 -0
  19. package/dist/commands/coverage.js.map +1 -0
  20. package/dist/commands/dod.d.ts +13 -0
  21. package/dist/commands/dod.js +141 -0
  22. package/dist/commands/dod.js.map +1 -0
  23. package/dist/commands/init.d.ts +14 -0
  24. package/dist/commands/init.js +378 -0
  25. package/dist/commands/init.js.map +1 -0
  26. package/dist/commands/link-commits.d.ts +12 -0
  27. package/dist/commands/link-commits.js +126 -0
  28. package/dist/commands/link-commits.js.map +1 -0
  29. package/dist/commands/overview.d.ts +6 -0
  30. package/dist/commands/overview.js +192 -0
  31. package/dist/commands/overview.js.map +1 -0
  32. package/dist/commands/plan.d.ts +23 -0
  33. package/dist/commands/plan.js +167 -0
  34. package/dist/commands/plan.js.map +1 -0
  35. package/dist/commands/sync-check.d.ts +8 -0
  36. package/dist/commands/sync-check.js +118 -0
  37. package/dist/commands/sync-check.js.map +1 -0
  38. package/dist/commands/update.d.ts +7 -0
  39. package/dist/commands/update.js +309 -0
  40. package/dist/commands/update.js.map +1 -0
  41. package/dist/commands/validate-format.d.ts +8 -0
  42. package/dist/commands/validate-format.js +93 -0
  43. package/dist/commands/validate-format.js.map +1 -0
  44. package/dist/commands/validate-structure.d.ts +8 -0
  45. package/dist/commands/validate-structure.js +29 -0
  46. package/dist/commands/validate-structure.js.map +1 -0
  47. package/dist/core/config.d.ts +6 -0
  48. package/dist/core/config.js +86 -0
  49. package/dist/core/config.js.map +1 -0
  50. package/dist/core/configuration.d.ts +7 -0
  51. package/dist/core/configuration.js +112 -0
  52. package/dist/core/configuration.js.map +1 -0
  53. package/dist/core/dod-runner.d.ts +20 -0
  54. package/dist/core/dod-runner.js +233 -0
  55. package/dist/core/dod-runner.js.map +1 -0
  56. package/dist/core/dor-runner.d.ts +18 -0
  57. package/dist/core/dor-runner.js +156 -0
  58. package/dist/core/dor-runner.js.map +1 -0
  59. package/dist/core/fs-walker.d.ts +5 -0
  60. package/dist/core/fs-walker.js +74 -0
  61. package/dist/core/fs-walker.js.map +1 -0
  62. package/dist/core/git.d.ts +24 -0
  63. package/dist/core/git.js +76 -0
  64. package/dist/core/git.js.map +1 -0
  65. package/dist/core/impl-reader.d.ts +8 -0
  66. package/dist/core/impl-reader.js +39 -0
  67. package/dist/core/impl-reader.js.map +1 -0
  68. package/dist/core/language.d.ts +39 -0
  69. package/dist/core/language.js +159 -0
  70. package/dist/core/language.js.map +1 -0
  71. package/dist/core/markdown-parser.d.ts +3 -0
  72. package/dist/core/markdown-parser.js +37 -0
  73. package/dist/core/markdown-parser.js.map +1 -0
  74. package/dist/core/reporter.d.ts +3 -0
  75. package/dist/core/reporter.js +33 -0
  76. package/dist/core/reporter.js.map +1 -0
  77. package/dist/templates/index.d.ts +4 -0
  78. package/dist/templates/index.js +126 -0
  79. package/dist/templates/index.js.map +1 -0
  80. package/dist/validators/format-rules.d.ts +10 -0
  81. package/dist/validators/format-rules.js +238 -0
  82. package/dist/validators/format-rules.js.map +1 -0
  83. package/dist/validators/structure-rules.d.ts +10 -0
  84. package/dist/validators/structure-rules.js +94 -0
  85. package/dist/validators/structure-rules.js.map +1 -0
  86. package/dist/validators/types.d.ts +68 -0
  87. package/dist/validators/types.js +2 -0
  88. package/dist/validators/types.js.map +1 -0
  89. package/docs/agents.md +88 -0
  90. package/docs/architecture.md +53 -0
  91. package/docs/cli.md +226 -0
  92. package/docs/concepts.md +268 -0
  93. package/docs/configuration.md +255 -0
  94. package/docs/demo.svg +111 -0
  95. package/docs/patterns.md +118 -0
  96. package/docs/security.md +95 -0
  97. package/docs/workflows.md +151 -0
  98. package/languages/de.json +20 -0
  99. package/languages/en.json +20 -0
  100. package/languages/es.json +20 -0
  101. package/languages/fr.json +20 -0
  102. package/languages/ja.json +20 -0
  103. package/languages/pt.json +20 -0
  104. package/package.json +54 -0
  105. package/skills/analyse-change.md +101 -0
  106. package/skills/behaviour.md +179 -0
  107. package/skills/bug.md +70 -0
  108. package/skills/commit.md +99 -0
  109. package/skills/decompose.md +101 -0
  110. package/skills/discover.md +392 -0
  111. package/skills/grill-me.md +65 -0
  112. package/skills/guide.md +118 -0
  113. package/skills/implement.md +149 -0
  114. package/skills/ineed.md +147 -0
  115. package/skills/intent.md +104 -0
  116. package/skills/plan.md +63 -0
  117. package/skills/promote.md +69 -0
  118. package/skills/refine.md +78 -0
  119. package/skills/research.md +122 -0
  120. package/skills/review-all.md +92 -0
  121. package/skills/review.md +80 -0
  122. package/skills/status.md +103 -0
  123. package/skills/sweep.md +89 -0
  124. package/skills/trace.md +151 -0
@@ -0,0 +1,112 @@
1
+ /**
2
+ * CONFIGURATION.md generator.
3
+ *
4
+ * Produces the content installed at .taproot/CONFIGURATION.md — the primary
5
+ * discoverability surface for agents completing configuration tasks.
6
+ */
7
+ import { supportedLanguages } from './language.js';
8
+ export function buildConfigurationMd() {
9
+ const langs = supportedLanguages().join(', ');
10
+ return `# Taproot Configuration Reference
11
+
12
+ Edit \`.taproot/settings.yaml\` to configure taproot.
13
+
14
+ **After changing \`language\` or \`vocabulary\`:** run \`taproot update\` to regenerate skill files and adapters.
15
+ **After changing \`definitionOfDone\` or \`definitionOfReady\`:** no \`taproot update\` needed — these are read at runtime.
16
+
17
+ ---
18
+
19
+ ## language
20
+
21
+ Language pack for section headers, Gherkin keywords, and status values in skill files.
22
+
23
+ \`\`\`yaml
24
+ language: de
25
+ \`\`\`
26
+
27
+ **Supported values:** ${langs}
28
+
29
+ **Default:** English (omit the field)
30
+
31
+ **Requires \`taproot update\`:** yes — skill files and adapter descriptions are regenerated with translated terminology.
32
+
33
+ ---
34
+
35
+ ## vocabulary
36
+
37
+ Domain-specific term substitutions applied to all skill file output. Use this to replace taproot's default terminology with words native to your project's domain.
38
+
39
+ \`\`\`yaml
40
+ vocabulary:
41
+ feature: story
42
+ behaviour: acceptance criterion
43
+ intent: epic
44
+ \`\`\`
45
+
46
+ **Format:** a YAML map of \`original: replacement\` string pairs. Keys are matched case-insensitively on whole words. Declaration order governs overlap — declare longer keys before their prefixes.
47
+
48
+ **Default:** no substitutions (omit the field)
49
+
50
+ **Requires \`taproot update\`:** yes — skill files are regenerated with the substituted terminology.
51
+
52
+ ---
53
+
54
+ ## definitionOfDone
55
+
56
+ Shell commands run as gates before implementation commits. Each command must exit 0 for the commit to proceed.
57
+
58
+ \`\`\`yaml
59
+ definitionOfDone:
60
+ - condition: tests-passing
61
+ run: npm test
62
+ - condition: lint-clean
63
+ run: npm run lint
64
+ \`\`\`
65
+
66
+ **Format:** a list of objects with \`condition\` (name shown in output) and \`run\` (shell command).
67
+
68
+ **Default:** baseline checks only (validate-format, validate-structure, tests-passing)
69
+
70
+ **Requires \`taproot update\`:** no — read at runtime by \`taproot dod\`.
71
+
72
+ ---
73
+
74
+ ## definitionOfReady
75
+
76
+ Shell commands run as gates before declaration commits (new impl.md). Each command must exit 0 for the commit to proceed.
77
+
78
+ \`\`\`yaml
79
+ definitionOfReady:
80
+ - condition: spec-reviewed
81
+ run: echo "Spec reviewed"
82
+ \`\`\`
83
+
84
+ **Format:** same as \`definitionOfDone\`.
85
+
86
+ **Default:** baseline checks only
87
+
88
+ **Requires \`taproot update\`:** no — read at runtime by the pre-commit hook.
89
+
90
+ ---
91
+
92
+ ## Full example
93
+
94
+ \`\`\`yaml
95
+ version: 1
96
+ language: de
97
+ vocabulary:
98
+ feature: story
99
+ behaviour: acceptance criterion
100
+ definitionOfDone:
101
+ - condition: tests-passing
102
+ run: npm test
103
+ - condition: lint-clean
104
+ run: npm run lint
105
+ \`\`\`
106
+
107
+ ---
108
+
109
+ *Generated by taproot. Run \`taproot update\` to refresh this file after upgrading.*
110
+ `;
111
+ }
112
+ //# sourceMappingURL=configuration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configuration.js","sourceRoot":"","sources":["../../src/core/configuration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,UAAU,oBAAoB;IAClC,MAAM,KAAK,GAAG,kBAAkB,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE9C,OAAO;;;;;;;;;;;;;;;;;wBAiBe,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmF5B,CAAC;AACF,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { DodConditionEntry } from '../validators/types.js';
2
+ export interface DodResult {
3
+ name: string;
4
+ passed: boolean;
5
+ output: string;
6
+ correction: string;
7
+ }
8
+ export interface DodReport {
9
+ configured: boolean;
10
+ results: DodResult[];
11
+ allPassed: boolean;
12
+ usecaseCascade?: string;
13
+ }
14
+ /** Read agent-check resolutions recorded in impl.md's ## DoD Resolutions section.
15
+ * Returns an empty set if impl.md has been modified after the resolutions were written
16
+ * (indicating more implementation work happened since the agent resolved the checks). */
17
+ export declare function readResolutions(implPath: string, cwd: string): Set<string>;
18
+ export declare function runDodChecks(conditions: DodConditionEntry[] | undefined, cwd: string, options?: {
19
+ implPath?: string;
20
+ }): DodReport;
@@ -0,0 +1,233 @@
1
+ import { existsSync, readFileSync, statSync } from 'fs';
2
+ import { join, dirname, resolve } from 'path';
3
+ import { spawnSync } from 'child_process';
4
+ import { parseMarkdown } from './markdown-parser.js';
5
+ import { validateFormat } from '../validators/format-rules.js';
6
+ import { loadConfig } from './config.js';
7
+ const BUILTINS = {
8
+ 'tests-passing': {
9
+ run: 'npm test',
10
+ correction: 'Fix failing tests and re-run.',
11
+ },
12
+ 'linter-clean': {
13
+ run: 'npm run lint',
14
+ correction: 'Fix lint errors reported above and re-run.',
15
+ },
16
+ 'commit-conventions': {
17
+ run: 'npm run check:commits',
18
+ correction: 'Ensure your commits follow the project commit convention.',
19
+ },
20
+ };
21
+ const TIMEOUT_MS = 30_000;
22
+ function resolveCondition(entry) {
23
+ if (typeof entry === 'object' && 'document-current' in entry) {
24
+ const description = entry['document-current'];
25
+ return {
26
+ name: 'document-current',
27
+ correction: description,
28
+ agentCheck: true,
29
+ description,
30
+ };
31
+ }
32
+ if (typeof entry === 'object' && 'check-if-affected' in entry) {
33
+ const target = entry['check-if-affected'];
34
+ return {
35
+ name: `check-if-affected: ${target}`,
36
+ agentCheck: true,
37
+ description: target,
38
+ correction: `Review whether this change requires updating ${target} and apply updates if needed.`,
39
+ };
40
+ }
41
+ if (typeof entry === 'object' && 'check-if-affected-by' in entry) {
42
+ const behaviourPath = entry['check-if-affected-by'];
43
+ return {
44
+ name: `check-if-affected-by: ${behaviourPath}`,
45
+ agentCheck: true,
46
+ description: behaviourPath,
47
+ correction: `Read the behaviour spec at ${behaviourPath}/usecase.md. Determine whether it applies to this implementation and verify compliance. If it applies, ensure this implementation satisfies it; if not, record why it does not apply.`,
48
+ };
49
+ }
50
+ if (typeof entry === 'object' && 'check' in entry) {
51
+ const question = entry['check'];
52
+ return {
53
+ name: `check: ${question}`,
54
+ agentCheck: true,
55
+ description: question,
56
+ correction: question,
57
+ };
58
+ }
59
+ if (typeof entry === 'string') {
60
+ const builtin = BUILTINS[entry];
61
+ if (!builtin) {
62
+ return {
63
+ name: entry,
64
+ run: entry,
65
+ correction: `Unknown built-in condition "${entry}". Use a known built-in or specify a "run:" command.`,
66
+ };
67
+ }
68
+ return { name: entry, run: builtin.run, correction: builtin.correction };
69
+ }
70
+ return {
71
+ name: entry.name ?? entry.run,
72
+ run: entry.run,
73
+ correction: entry.correction ?? 'Fix the issue reported above, then re-run.',
74
+ };
75
+ }
76
+ function runCondition(name, command, cwd, correction) {
77
+ let result;
78
+ try {
79
+ result = spawnSync(command, {
80
+ shell: true,
81
+ cwd,
82
+ encoding: 'utf-8',
83
+ timeout: TIMEOUT_MS,
84
+ });
85
+ }
86
+ catch (err) {
87
+ return {
88
+ name,
89
+ passed: false,
90
+ output: err.message,
91
+ correction: 'Ensure the command exists and is executable from the project root.',
92
+ };
93
+ }
94
+ if (result.error) {
95
+ const isTimeout = result.error.message.includes('ETIMEDOUT') || result.error.message.includes('timeout');
96
+ return {
97
+ name,
98
+ passed: false,
99
+ output: result.error.message,
100
+ correction: isTimeout
101
+ ? 'Check for hanging processes or increase the timeout.'
102
+ : 'Ensure the command exists and is executable from the project root.',
103
+ };
104
+ }
105
+ const output = [result.stdout ?? '', result.stderr ?? ''].filter(Boolean).join('\n').trim();
106
+ const passed = result.status === 0;
107
+ // Exit code 127 = shell "command not found"
108
+ if (result.status === 127) {
109
+ return {
110
+ name,
111
+ passed: false,
112
+ output,
113
+ correction: 'Ensure the command exists and is executable from the project root.',
114
+ };
115
+ }
116
+ return { name, passed, output, correction: passed ? '' : correction };
117
+ }
118
+ /** Run the always-on DoD baseline: usecase.md exists, state=specified, format-valid. */
119
+ function runDodBaseline(implPath, cwd) {
120
+ const absImpl = resolve(cwd, implPath);
121
+ const behaviourDir = dirname(dirname(absImpl));
122
+ const usecasePath = join(behaviourDir, 'usecase.md');
123
+ const results = [];
124
+ if (!existsSync(usecasePath)) {
125
+ results.push({
126
+ name: 'baseline-usecase-exists',
127
+ passed: false,
128
+ output: `No usecase.md at ${usecasePath}`,
129
+ correction: 'The behaviour spec this implementation references is missing. Restore it before marking complete.',
130
+ });
131
+ return results; // cannot check further without usecase
132
+ }
133
+ const content = readFileSync(usecasePath, 'utf-8');
134
+ const parsed = parseMarkdown(usecasePath, content);
135
+ // state: specified or more advanced (implemented/tested) — must not have regressed to proposed/deprecated
136
+ const statusSection = parsed.sections.get('status');
137
+ const stateMatch = statusSection?.rawBody.match(/\*\*State:\*\*\s*(\S+)/);
138
+ const state = stateMatch?.[1] ?? 'unknown';
139
+ const acceptedStates = new Set(['specified', 'implemented', 'tested']);
140
+ const isReady = acceptedStates.has(state);
141
+ results.push({
142
+ name: 'baseline-state-specified',
143
+ passed: isReady,
144
+ output: isReady ? '' : `usecase.md state is '${state}'`,
145
+ correction: "Restore usecase.md to 'specified' (or more advanced) before marking implementation complete.",
146
+ });
147
+ // validate-format
148
+ const { config } = loadConfig(cwd);
149
+ const violations = validateFormat(parsed, 'behaviour', config).filter(v => v.type === 'error');
150
+ const formatPassed = violations.length === 0;
151
+ results.push({
152
+ name: 'baseline-validate-format',
153
+ passed: formatPassed,
154
+ output: formatPassed ? '' : violations.map(v => v.message).join('\n'),
155
+ correction: 'Fix format violations in usecase.md and re-run.',
156
+ });
157
+ return results;
158
+ }
159
+ // Buffer to account for the time between Date.now() and the writeFileSync mtime.
160
+ // Resolutions written within this window of impl.md's mtime are considered current.
161
+ const RESOLUTION_STALE_BUFFER_MS = 2_000;
162
+ /** Read agent-check resolutions recorded in impl.md's ## DoD Resolutions section.
163
+ * Returns an empty set if impl.md has been modified after the resolutions were written
164
+ * (indicating more implementation work happened since the agent resolved the checks). */
165
+ export function readResolutions(implPath, cwd) {
166
+ const absPath = resolve(cwd, implPath);
167
+ if (!existsSync(absPath))
168
+ return new Set();
169
+ const content = readFileSync(absPath, 'utf-8');
170
+ const parsed = parseMarkdown(absPath, content);
171
+ const section = parsed.sections.get('dod resolutions');
172
+ if (!section)
173
+ return new Set();
174
+ const entries = [];
175
+ for (const line of section.rawBody.split('\n')) {
176
+ const m = line.match(/^-\s+condition:\s+(.+?)\s+\|.*\|\s+resolved:\s+(.+)$/);
177
+ if (m) {
178
+ const ts = Date.parse(m[2].trim());
179
+ if (!isNaN(ts))
180
+ entries.push({ condition: m[1].trim(), timestampMs: ts });
181
+ }
182
+ }
183
+ if (entries.length === 0)
184
+ return new Set();
185
+ // If impl.md is already complete, resolutions are always valid — DoD already passed.
186
+ // Only check staleness for in-progress impls, where the developer may have changed
187
+ // implementation code after the agent recorded resolutions.
188
+ const isComplete = /\*\*State:\*\*\s*complete/.test(content);
189
+ if (!isComplete) {
190
+ const implMtimeMs = statSync(absPath).mtimeMs;
191
+ const latestResolutionMs = Math.max(...entries.map(e => e.timestampMs));
192
+ if (implMtimeMs > latestResolutionMs + RESOLUTION_STALE_BUFFER_MS) {
193
+ return new Set(); // stale — impl.md changed after resolutions were recorded
194
+ }
195
+ }
196
+ return new Set(entries.map(e => e.condition));
197
+ }
198
+ export function runDodChecks(conditions, cwd, options) {
199
+ const results = [];
200
+ // Always run baseline when implPath is provided
201
+ if (options?.implPath) {
202
+ results.push(...runDodBaseline(options.implPath, cwd));
203
+ }
204
+ if (!conditions || conditions.length === 0) {
205
+ const configured = results.length > 0;
206
+ return { configured, results, allPassed: results.every(r => r.passed) };
207
+ }
208
+ // Read any agent-check resolutions recorded in impl.md
209
+ const resolvedChecks = options?.implPath
210
+ ? readResolutions(options.implPath, cwd)
211
+ : new Set();
212
+ for (const entry of conditions) {
213
+ const resolved = resolveCondition(entry);
214
+ if (resolved.agentCheck) {
215
+ const isResolved = resolvedChecks.has(resolved.name);
216
+ results.push({
217
+ name: resolved.name,
218
+ passed: isResolved,
219
+ output: isResolved ? '' : `Agent check required: ${resolved.description}`,
220
+ correction: resolved.correction,
221
+ });
222
+ }
223
+ else {
224
+ results.push(runCondition(resolved.name, resolved.run, cwd, resolved.correction));
225
+ }
226
+ }
227
+ return {
228
+ configured: true,
229
+ results,
230
+ allPassed: results.every(r => r.passed),
231
+ };
232
+ }
233
+ //# sourceMappingURL=dod-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dod-runner.js","sourceRoot":"","sources":["../../src/core/dod-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Read agent-check resolutions from impl.md's ## DoR Resolutions section. */
2
+ export declare function readDorResolutions(implMdPath: string, cwd: string): Set<string>;
3
+ export interface DorResult {
4
+ name: string;
5
+ passed: boolean;
6
+ output: string;
7
+ correction: string;
8
+ }
9
+ export interface DorReport {
10
+ results: DorResult[];
11
+ allPassed: boolean;
12
+ }
13
+ /** Resolve the parent usecase.md from an impl.md path.
14
+ * impl.md lives at taproot/<intent>/<behaviour>/<impl>/impl.md
15
+ * usecase.md lives at taproot/<intent>/<behaviour>/usecase.md
16
+ */
17
+ export declare function resolveUsecasePath(implMdPath: string, cwd: string): string;
18
+ export declare function runDorChecks(implMdPath: string, cwd: string): DorReport;
@@ -0,0 +1,156 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { join, dirname, resolve } from 'path';
3
+ import { spawnSync } from 'child_process';
4
+ import { parseMarkdown } from './markdown-parser.js';
5
+ import { loadConfig } from './config.js';
6
+ import { loadLanguagePack } from './language.js';
7
+ /** Resolve an English section key to its localised lowercase equivalent via the pack. */
8
+ function localizedSectionKey(englishKey, pack) {
9
+ if (!pack)
10
+ return englishKey;
11
+ const packKey = Object.keys(pack).find(k => k.toLowerCase() === englishKey);
12
+ if (!packKey)
13
+ return englishKey;
14
+ return pack[packKey].toLowerCase();
15
+ }
16
+ /** Read agent-check resolutions from impl.md's ## DoR Resolutions section. */
17
+ export function readDorResolutions(implMdPath, cwd) {
18
+ const absPath = resolve(cwd, implMdPath);
19
+ if (!existsSync(absPath))
20
+ return new Set();
21
+ const content = readFileSync(absPath, 'utf-8');
22
+ const parsed = parseMarkdown(absPath, content);
23
+ const section = parsed.sections.get('dor resolutions');
24
+ if (!section)
25
+ return new Set();
26
+ const conditions = new Set();
27
+ for (const line of section.rawBody.split('\n')) {
28
+ const m = line.match(/^-\s+condition:\s+(.+?)\s+\|/);
29
+ if (m)
30
+ conditions.add(m[1].trim());
31
+ }
32
+ return conditions;
33
+ }
34
+ /** Resolve the parent usecase.md from an impl.md path.
35
+ * impl.md lives at taproot/<intent>/<behaviour>/<impl>/impl.md
36
+ * usecase.md lives at taproot/<intent>/<behaviour>/usecase.md
37
+ */
38
+ export function resolveUsecasePath(implMdPath, cwd) {
39
+ const absImpl = resolve(cwd, implMdPath);
40
+ const implDir = dirname(absImpl); // <impl>/
41
+ const behaviourDir = dirname(implDir); // <behaviour>/
42
+ return join(behaviourDir, 'usecase.md');
43
+ }
44
+ export function runDorChecks(implMdPath, cwd) {
45
+ const results = [];
46
+ const usecasePath = resolveUsecasePath(implMdPath, cwd);
47
+ // 1. usecase.md exists
48
+ if (!existsSync(usecasePath)) {
49
+ results.push({
50
+ name: 'usecase-exists',
51
+ passed: false,
52
+ output: `No usecase.md found at ${usecasePath}`,
53
+ correction: 'Create a behaviour spec with /tr-behaviour before committing an impl.md',
54
+ });
55
+ return { results, allPassed: false };
56
+ }
57
+ const content = readFileSync(usecasePath, 'utf-8');
58
+ const parsed = parseMarkdown(usecasePath, content);
59
+ // 2. state: specified
60
+ const statusSection = parsed.sections.get('status');
61
+ const stateMatch = statusSection?.rawBody.match(/\*\*State:\*\*\s*(\S+)/);
62
+ const state = stateMatch?.[1] ?? 'unknown';
63
+ const isSpecified = state === 'specified';
64
+ results.push({
65
+ name: 'state-specified',
66
+ passed: isSpecified,
67
+ output: isSpecified ? '' : `usecase.md state is '${state}'`,
68
+ correction: "Bring the spec to 'specified' (run /tr-review then /tr-refine) before starting implementation",
69
+ });
70
+ // 3. Required sections (localised via language pack)
71
+ const { config } = loadConfig(cwd);
72
+ const pack = config.language ? loadLanguagePack(config.language) : null;
73
+ const required = [
74
+ ['actor', 'Actor'],
75
+ ['preconditions', 'Preconditions'],
76
+ ['main flow', 'Main Flow'],
77
+ ['postconditions', 'Postconditions'],
78
+ ];
79
+ for (const [englishKey, label] of required) {
80
+ const key = localizedSectionKey(englishKey, pack);
81
+ const present = parsed.sections.has(key);
82
+ results.push({
83
+ name: `section-${key.replace(' ', '-')}`,
84
+ passed: present,
85
+ output: present ? '' : `Missing ## ${label} section`,
86
+ correction: `Add a ## ${label} section to usecase.md`,
87
+ });
88
+ }
89
+ // 4. Flow (Mermaid diagram)
90
+ const hasFlow = parsed.sections.has('flow');
91
+ results.push({
92
+ name: 'flow-diagram',
93
+ passed: hasFlow,
94
+ output: hasFlow ? '' : 'Missing ## Flow section with Mermaid diagram',
95
+ correction: 'Add a ## Flow section with a mermaid diagram to usecase.md',
96
+ });
97
+ // 5. Related behaviours
98
+ const hasRelated = parsed.sections.has('related');
99
+ results.push({
100
+ name: 'related-behaviours',
101
+ passed: hasRelated,
102
+ output: hasRelated ? '' : 'Missing ## Related section',
103
+ correction: 'Add a ## Related section documenting related behaviours to usecase.md',
104
+ });
105
+ // 6. Configured definitionOfReady conditions
106
+ const dorConditions = config.definitionOfReady;
107
+ if (dorConditions && dorConditions.length > 0) {
108
+ const resolvedChecks = readDorResolutions(implMdPath, cwd);
109
+ for (const entry of dorConditions) {
110
+ if (typeof entry === 'object' && 'check' in entry) {
111
+ const question = entry['check'];
112
+ const name = `check: ${question}`;
113
+ const isResolved = resolvedChecks.has(name);
114
+ results.push({
115
+ name,
116
+ passed: isResolved,
117
+ output: isResolved ? '' : `Agent check required: ${question}`,
118
+ correction: `Reason about the question and record a resolution in impl.md under ## DoR Resolutions: "- condition: ${name} | note: <reasoning> | resolved: <ISO-timestamp>"`,
119
+ });
120
+ }
121
+ else if (typeof entry === 'object' && ('document-current' in entry || 'check-if-affected' in entry || 'check-if-affected-by' in entry)) {
122
+ // Other agent-check types — treat as unresolvable shell-side, report as agent check
123
+ const key = 'document-current' in entry ? 'document-current' : 'check-if-affected' in entry ? 'check-if-affected' : 'check-if-affected-by';
124
+ const value = entry[key];
125
+ const name = `${key}: ${value}`;
126
+ const isResolved = resolvedChecks.has(name);
127
+ results.push({
128
+ name,
129
+ passed: isResolved,
130
+ output: isResolved ? '' : `Agent check required: ${value}`,
131
+ correction: `Resolve this agent check and record it in impl.md under ## DoR Resolutions.`,
132
+ });
133
+ }
134
+ else if (typeof entry === 'string') {
135
+ const r = spawnSync(entry, { shell: true, cwd, encoding: 'utf-8', timeout: 30_000 });
136
+ results.push({
137
+ name: entry,
138
+ passed: r.status === 0,
139
+ output: [r.stdout, r.stderr].filter(Boolean).join('\n').trim(),
140
+ correction: 'Fix the issue reported above, then re-commit',
141
+ });
142
+ }
143
+ else if ('run' in entry) {
144
+ const r = spawnSync(entry.run, { shell: true, cwd, encoding: 'utf-8', timeout: 30_000 });
145
+ results.push({
146
+ name: entry.name ?? entry.run,
147
+ passed: r.status === 0,
148
+ output: [r.stdout, r.stderr].filter(Boolean).join('\n').trim(),
149
+ correction: entry.correction ?? 'Fix the issue reported above, then re-commit',
150
+ });
151
+ }
152
+ }
153
+ }
154
+ return { results, allPassed: results.every(r => r.passed) };
155
+ }
156
+ //# sourceMappingURL=dor-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dor-runner.js","sourceRoot":"","sources":["../../src/core/dor-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { FolderNode } from '../validators/types.js';
2
+ export declare function walkHierarchy(rootPath: string, options?: {
3
+ excludeDirs?: Set<string>;
4
+ }): FolderNode;
5
+ export declare function flattenTree(root: FolderNode): FolderNode[];
@@ -0,0 +1,74 @@
1
+ import { readdirSync, statSync } from 'fs';
2
+ import { join, relative, basename } from 'path';
3
+ const MARKER_FILES = {
4
+ 'intent.md': 'intent',
5
+ 'usecase.md': 'behaviour',
6
+ 'impl.md': 'impl',
7
+ };
8
+ const DEFAULT_EXCLUDE = new Set(['_brainstorms', 'skills', '.git', 'node_modules', 'dist']);
9
+ export function walkHierarchy(rootPath, options = {}) {
10
+ const excludeDirs = options.excludeDirs ?? DEFAULT_EXCLUDE;
11
+ return walkDir(rootPath, rootPath, null, 0, excludeDirs);
12
+ }
13
+ function walkDir(dirPath, rootPath, parent, depth, excludeDirs) {
14
+ let entries;
15
+ try {
16
+ entries = readdirSync(dirPath);
17
+ }
18
+ catch {
19
+ entries = [];
20
+ }
21
+ const markerFiles = [];
22
+ const subdirs = [];
23
+ for (const entry of entries) {
24
+ if (MARKER_FILES[entry]) {
25
+ markerFiles.push(entry);
26
+ }
27
+ try {
28
+ const fullPath = join(dirPath, entry);
29
+ if (statSync(fullPath).isDirectory() && !excludeDirs.has(entry)) {
30
+ subdirs.push(entry);
31
+ }
32
+ }
33
+ catch {
34
+ // skip unreadable entries
35
+ }
36
+ }
37
+ const node = {
38
+ absolutePath: dirPath,
39
+ relativePath: relative(rootPath, dirPath) || '.',
40
+ name: basename(dirPath),
41
+ marker: null,
42
+ markerFiles,
43
+ children: [],
44
+ parent,
45
+ depth,
46
+ hasDescendantWithMarker: false,
47
+ };
48
+ // Determine marker (first found wins; duplicates are reported as violations)
49
+ if (markerFiles.length > 0) {
50
+ node.marker = MARKER_FILES[markerFiles[0] ?? ''] ?? null;
51
+ }
52
+ // Recurse into subdirectories (post-order: children first)
53
+ for (const subdir of subdirs.sort()) {
54
+ const child = walkDir(join(dirPath, subdir), rootPath, node, depth + 1, excludeDirs);
55
+ node.children.push(child);
56
+ if (child.marker !== null || child.hasDescendantWithMarker) {
57
+ node.hasDescendantWithMarker = true;
58
+ }
59
+ }
60
+ return node;
61
+ }
62
+ export function flattenTree(root) {
63
+ const result = [];
64
+ const stack = [root];
65
+ while (stack.length > 0) {
66
+ const node = stack.pop();
67
+ result.push(node);
68
+ for (const child of [...node.children].reverse()) {
69
+ stack.push(child);
70
+ }
71
+ }
72
+ return result;
73
+ }
74
+ //# sourceMappingURL=fs-walker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-walker.js","sourceRoot":"","sources":["../../src/core/fs-walker.ts"],"names":[],"mappings":"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"}