@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,24 @@
1
+ export interface GitCommit {
2
+ hash: string;
3
+ subject: string;
4
+ body: string;
5
+ date: string;
6
+ }
7
+ export declare function isGitRepo(cwd: string): boolean;
8
+ export declare function getRepoRoot(cwd: string): string | null;
9
+ export declare function gitLog(options: {
10
+ since?: string;
11
+ cwd: string;
12
+ }): GitCommit[];
13
+ export declare function commitExists(hash: string, cwd: string): boolean;
14
+ /** Returns the date of the last commit that touched this file, or null. */
15
+ export declare function fileLastCommitDate(filePath: string, cwd: string): Date | null;
16
+ /** Returns the filesystem mtime of a file, or null if it doesn't exist. */
17
+ export declare function fileMtime(filePath: string): Date | null;
18
+ /**
19
+ * Parse a commit looking for a taproot path reference.
20
+ * Supports:
21
+ * Subject: taproot(some/path): message
22
+ * Body trailer: Taproot: some/path
23
+ */
24
+ export declare function extractTaprootPath(commit: GitCommit, commitPattern: string, trailerKey: string): string | null;
@@ -0,0 +1,76 @@
1
+ import { spawnSync } from 'child_process';
2
+ import { statSync } from 'fs';
3
+ function git(args, cwd) {
4
+ const result = spawnSync('git', args, { cwd, encoding: 'utf-8' });
5
+ return {
6
+ stdout: result.stdout?.trim() ?? '',
7
+ ok: result.status === 0,
8
+ };
9
+ }
10
+ export function isGitRepo(cwd) {
11
+ return git(['rev-parse', '--git-dir'], cwd).ok;
12
+ }
13
+ export function getRepoRoot(cwd) {
14
+ const r = git(['rev-parse', '--show-toplevel'], cwd);
15
+ return r.ok ? r.stdout : null;
16
+ }
17
+ export function gitLog(options) {
18
+ const args = ['log', '--format=%H%x00%s%x00%b%x00%aI%x00---COMMIT---'];
19
+ if (options.since)
20
+ args.push(`--since=${options.since}`);
21
+ const { stdout, ok } = git(args, options.cwd);
22
+ if (!ok || !stdout)
23
+ return [];
24
+ return stdout
25
+ .split('---COMMIT---')
26
+ .map(s => s.trim())
27
+ .filter(Boolean)
28
+ .map(block => {
29
+ const parts = block.split('\x00');
30
+ return {
31
+ hash: (parts[0] ?? '').trim(),
32
+ subject: (parts[1] ?? '').trim(),
33
+ body: (parts[2] ?? '').trim(),
34
+ date: (parts[3] ?? '').trim(),
35
+ };
36
+ })
37
+ .filter(c => c.hash.length === 40);
38
+ }
39
+ export function commitExists(hash, cwd) {
40
+ return git(['cat-file', '-e', `${hash}^{commit}`], cwd).ok;
41
+ }
42
+ /** Returns the date of the last commit that touched this file, or null. */
43
+ export function fileLastCommitDate(filePath, cwd) {
44
+ const r = git(['log', '-1', '--format=%aI', '--', filePath], cwd);
45
+ if (!r.ok || !r.stdout)
46
+ return null;
47
+ const d = new Date(r.stdout);
48
+ return isNaN(d.getTime()) ? null : d;
49
+ }
50
+ /** Returns the filesystem mtime of a file, or null if it doesn't exist. */
51
+ export function fileMtime(filePath) {
52
+ try {
53
+ return statSync(filePath).mtime;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ /**
60
+ * Parse a commit looking for a taproot path reference.
61
+ * Supports:
62
+ * Subject: taproot(some/path): message
63
+ * Body trailer: Taproot: some/path
64
+ */
65
+ export function extractTaprootPath(commit, commitPattern, trailerKey) {
66
+ const subjectRegex = new RegExp(commitPattern);
67
+ const subjectMatch = subjectRegex.exec(commit.subject);
68
+ if (subjectMatch?.[1])
69
+ return subjectMatch[1].trim();
70
+ const trailerRegex = new RegExp(`^${trailerKey}:\\s*(.+)$`, 'm');
71
+ const trailerMatch = trailerRegex.exec(commit.body);
72
+ if (trailerMatch?.[1])
73
+ return trailerMatch[1].trim();
74
+ return null;
75
+ }
76
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../src/core/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { ParsedMarkdown } from '../validators/types.js';
2
+ export interface ImplData {
3
+ behaviourRef: string | null;
4
+ sourceFiles: string[];
5
+ commits: string[];
6
+ testFiles: string[];
7
+ }
8
+ export declare function parseImplData(doc: ParsedMarkdown): ImplData;
@@ -0,0 +1,39 @@
1
+ /** Returns true if a backtick-quoted token looks like a file path (contains '/' or ends with a dotted extension). */
2
+ function isFilePath(token) {
3
+ return token.includes('/') || /\.\w+$/.test(token);
4
+ }
5
+ /** Extract a backtick-quoted value from a list item line: `- \`value\` — ...` */
6
+ function extractBacktickValues(lines) {
7
+ const result = [];
8
+ for (const line of lines) {
9
+ const match = /`([^`]+)`/.exec(line);
10
+ if (match?.[1])
11
+ result.push(match[1]);
12
+ }
13
+ return result;
14
+ }
15
+ /** Extract file paths from a list of lines — skips backtick-quoted tokens that are not recognisable as file paths (e.g. function signatures, identifiers). */
16
+ function extractFilePaths(lines) {
17
+ return extractBacktickValues(lines).filter(isFilePath);
18
+ }
19
+ /** Extract commit hashes — 6-64 hex chars from backtick-quoted items */
20
+ function extractCommitHashes(lines) {
21
+ return extractBacktickValues(lines).filter(v => /^[0-9a-f]{6,64}$/i.test(v));
22
+ }
23
+ export function parseImplData(doc) {
24
+ const behaviourSection = doc.sections.get('behaviour');
25
+ const sourceSection = doc.sections.get('source files');
26
+ const commitsSection = doc.sections.get('commits');
27
+ const testsSection = doc.sections.get('tests');
28
+ // Behaviour ref: first non-empty line of the Behaviour section
29
+ const behaviourRef = behaviourSection?.bodyLines
30
+ .map(l => l.trim())
31
+ .find(l => l.length > 0) ?? null;
32
+ return {
33
+ behaviourRef,
34
+ sourceFiles: extractFilePaths(sourceSection?.bodyLines ?? []),
35
+ commits: extractCommitHashes(commitsSection?.bodyLines ?? []),
36
+ testFiles: extractFilePaths(testsSection?.bodyLines ?? []),
37
+ };
38
+ }
39
+ //# sourceMappingURL=impl-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"impl-reader.js","sourceRoot":"","sources":["../../src/core/impl-reader.ts"],"names":[],"mappings":"AASA,qHAAqH;AACrH,SAAS,UAAU,CAAC,KAAa;IAC/B,OAAO,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,iFAAiF;AACjF,SAAS,qBAAqB,CAAC,KAAe;IAC5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8JAA8J;AAC9J,SAAS,gBAAgB,CAAC,KAAe;IACvC,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AACzD,CAAC;AAED,wEAAwE;AACxE,SAAS,mBAAmB,CAAC,KAAe;IAC1C,OAAO,qBAAqB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAmB;IAC/C,MAAM,gBAAgB,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACvD,MAAM,cAAc,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAE/C,+DAA+D;IAC/D,MAAM,YAAY,GAAG,gBAAgB,EAAE,SAAS;SAC7C,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SAClB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;IAEnC,OAAO;QACL,YAAY;QACZ,WAAW,EAAE,gBAAgB,CAAC,aAAa,EAAE,SAAS,IAAI,EAAE,CAAC;QAC7D,OAAO,EAAE,mBAAmB,CAAC,cAAc,EAAE,SAAS,IAAI,EAAE,CAAC;QAC7D,SAAS,EAAE,gBAAgB,CAAC,YAAY,EAAE,SAAS,IAAI,EAAE,CAAC;KAC3D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { MarkerType } from '../validators/types.js';
2
+ export type LanguagePack = Record<string, string>;
3
+ /**
4
+ * Load a language pack by code. Returns null if unsupported or file not found.
5
+ * Falls back gracefully on missing keys — returns null only for wholly unknown codes.
6
+ */
7
+ export declare function loadLanguagePack(code: string): LanguagePack | null;
8
+ /** Returns the list of supported language codes. */
9
+ export declare function supportedLanguages(): string[];
10
+ /**
11
+ * Return the structural keyword keys for conflict detection.
12
+ * Uses the provided pack, or falls back to the English pack.
13
+ * Always returns a non-empty list so structural keywords are always protected.
14
+ */
15
+ export declare function getStructuralKeys(pack: LanguagePack | null): string[];
16
+ /**
17
+ * Substitute all language pack tokens in content.
18
+ * Single-pass, sorted by key length descending (longer keys matched first).
19
+ * Case-sensitive exact string replacement.
20
+ */
21
+ export declare function substituteTokens(content: string, pack: LanguagePack): string;
22
+ /**
23
+ * Apply domain vocabulary overrides to content.
24
+ * Runs after the language pack substitution pass.
25
+ *
26
+ * - Declaration-order: keys processed in the order they appear in the map
27
+ * - Single-pass via placeholder trick (same mechanism as substituteTokens)
28
+ * - Structural keys (those present in the language pack) are excluded with a warning
29
+ * - Returns the substituted content and any conflict warnings
30
+ */
31
+ export declare function applyVocabulary(content: string, vocab: Record<string, string>, structuralKeys: string[]): {
32
+ result: string;
33
+ warnings: string[];
34
+ };
35
+ /**
36
+ * Return required section keys for a given marker type, localised via the pack.
37
+ * impl.md sections are always English (excluded from localisation by design).
38
+ */
39
+ export declare function getLocalizedRequiredSections(markerType: MarkerType, pack: LanguagePack | null): string[];
@@ -0,0 +1,159 @@
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import { resolve, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ // Packs live at src/languages/ → compiled to dist/languages/ (two levels up from dist/core/)
6
+ const LANGUAGES_DIR = resolve(__dirname, '..', '..', 'languages');
7
+ const SUPPORTED_LANGUAGES = ['en', 'de', 'fr', 'es', 'ja', 'pt'];
8
+ /** English required section keys per marker type (lowercase, as stored in ParsedMarkdown.sections). */
9
+ const ENGLISH_REQUIRED_SECTIONS = {
10
+ intent: ['stakeholders', 'goal', 'success criteria', 'status'],
11
+ behaviour: ['actor', 'preconditions', 'main flow', 'postconditions', 'status'],
12
+ impl: ['behaviour', 'commits', 'tests', 'status'],
13
+ };
14
+ /**
15
+ * Load a language pack by code. Returns null if unsupported or file not found.
16
+ * Falls back gracefully on missing keys — returns null only for wholly unknown codes.
17
+ */
18
+ export function loadLanguagePack(code) {
19
+ if (!SUPPORTED_LANGUAGES.includes(code))
20
+ return null;
21
+ if (code === 'en')
22
+ return buildEnglishPack();
23
+ const packPath = resolve(LANGUAGES_DIR, `${code}.json`);
24
+ if (!existsSync(packPath))
25
+ return null;
26
+ try {
27
+ const raw = JSON.parse(readFileSync(packPath, 'utf-8'));
28
+ // Fill missing keys from English defaults with a warning
29
+ const english = buildEnglishPack();
30
+ const result = { ...english };
31
+ for (const [key, value] of Object.entries(raw)) {
32
+ if (typeof value === 'string' && value.length > 0) {
33
+ result[key] = value;
34
+ }
35
+ }
36
+ return result;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /** Returns the list of supported language codes. */
43
+ export function supportedLanguages() {
44
+ return [...SUPPORTED_LANGUAGES];
45
+ }
46
+ /**
47
+ * Return the structural keyword keys for conflict detection.
48
+ * Uses the provided pack, or falls back to the English pack.
49
+ * Always returns a non-empty list so structural keywords are always protected.
50
+ */
51
+ export function getStructuralKeys(pack) {
52
+ if (pack)
53
+ return Object.keys(pack);
54
+ const english = buildEnglishPack();
55
+ return Object.keys(english);
56
+ }
57
+ /**
58
+ * Substitute all language pack tokens in content.
59
+ * Single-pass, sorted by key length descending (longer keys matched first).
60
+ * Case-sensitive exact string replacement.
61
+ */
62
+ export function substituteTokens(content, pack) {
63
+ if (!pack || Object.keys(pack).length === 0)
64
+ return content;
65
+ // Sort entries by key length descending so "Main Flow" is matched before "Flow"
66
+ const entries = Object.entries(pack).sort((a, b) => b[0].length - a[0].length);
67
+ // Single-pass: replace each key with a placeholder, then swap placeholders for values
68
+ // This prevents double-substitution when a value contains another key
69
+ const placeholders = [];
70
+ let result = content;
71
+ for (let i = 0; i < entries.length; i++) {
72
+ const [key, value] = entries[i];
73
+ if (key === value)
74
+ continue; // English pack — no-op
75
+ const placeholder = `\x00TAPROOT_LANG_${i}\x00`;
76
+ placeholders.push([placeholder, value]);
77
+ result = result.split(key).join(placeholder);
78
+ }
79
+ for (const [placeholder, value] of placeholders) {
80
+ result = result.split(placeholder).join(value);
81
+ }
82
+ return result;
83
+ }
84
+ /**
85
+ * Apply domain vocabulary overrides to content.
86
+ * Runs after the language pack substitution pass.
87
+ *
88
+ * - Declaration-order: keys processed in the order they appear in the map
89
+ * - Single-pass via placeholder trick (same mechanism as substituteTokens)
90
+ * - Structural keys (those present in the language pack) are excluded with a warning
91
+ * - Returns the substituted content and any conflict warnings
92
+ */
93
+ export function applyVocabulary(content, vocab, structuralKeys) {
94
+ const warnings = [];
95
+ const structuralLower = new Set(structuralKeys.map(k => k.toLowerCase()));
96
+ // Filter entries: skip structural conflicts
97
+ const entries = [];
98
+ for (const [key, value] of Object.entries(vocab)) {
99
+ if (structuralLower.has(key.toLowerCase())) {
100
+ warnings.push(`Vocabulary override '${key}' conflicts with a structural keyword — structural keywords take precedence; override ignored`);
101
+ }
102
+ else {
103
+ entries.push([key, value]);
104
+ }
105
+ }
106
+ if (entries.length === 0)
107
+ return { result: content, warnings };
108
+ // Single-pass substitution in declaration order using placeholders
109
+ const placeholders = [];
110
+ let result = content;
111
+ for (let i = 0; i < entries.length; i++) {
112
+ const [key, value] = entries[i];
113
+ const placeholder = `\x00TAPROOT_VOCAB_${i}\x00`;
114
+ placeholders.push([placeholder, value]);
115
+ result = result.split(key).join(placeholder);
116
+ }
117
+ for (const [placeholder, value] of placeholders) {
118
+ result = result.split(placeholder).join(value);
119
+ }
120
+ return { result, warnings };
121
+ }
122
+ /**
123
+ * Return required section keys for a given marker type, localised via the pack.
124
+ * impl.md sections are always English (excluded from localisation by design).
125
+ */
126
+ export function getLocalizedRequiredSections(markerType, pack) {
127
+ const english = ENGLISH_REQUIRED_SECTIONS[markerType];
128
+ if (!pack || markerType === 'impl')
129
+ return english;
130
+ return english.map(key => {
131
+ // Find the matching pack entry: pack keys are Title Case, section keys are lowercase
132
+ const packKey = Object.keys(pack).find(k => k.toLowerCase() === key);
133
+ if (!packKey)
134
+ return key; // fallback to English
135
+ return pack[packKey].toLowerCase();
136
+ });
137
+ }
138
+ function buildEnglishPack() {
139
+ const packPath = resolve(LANGUAGES_DIR, 'en.json');
140
+ if (existsSync(packPath)) {
141
+ try {
142
+ return JSON.parse(readFileSync(packPath, 'utf-8'));
143
+ }
144
+ catch {
145
+ // fall through to hardcoded defaults
146
+ }
147
+ }
148
+ // Hardcoded fallback if en.json not found (should never happen in a valid install)
149
+ return {
150
+ Goal: 'Goal', Actor: 'Actor', Preconditions: 'Preconditions',
151
+ 'Main Flow': 'Main Flow', 'Alternate Flows': 'Alternate Flows',
152
+ Postconditions: 'Postconditions', 'Error Conditions': 'Error Conditions',
153
+ 'Acceptance Criteria': 'Acceptance Criteria', Status: 'Status',
154
+ Stakeholders: 'Stakeholders', 'Success Criteria': 'Success Criteria',
155
+ Given: 'Given', When: 'When', Then: 'Then',
156
+ specified: 'specified', implemented: 'implemented', complete: 'complete', active: 'active',
157
+ };
158
+ }
159
+ //# sourceMappingURL=language.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language.js","sourceRoot":"","sources":["../../src/core/language.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ParsedMarkdown } from '../validators/types.js';
2
+ export declare function parseMarkdown(filePath: string, content: string): ParsedMarkdown;
3
+ export declare function getSectionLine(doc: ParsedMarkdown, sectionKey: string): number | undefined;
@@ -0,0 +1,37 @@
1
+ export function parseMarkdown(filePath, content) {
2
+ const rawLines = content.split('\n');
3
+ const sections = new Map();
4
+ let currentHeading = null;
5
+ let currentStart = 0;
6
+ let currentBody = [];
7
+ const flushSection = (endIndex) => {
8
+ if (currentHeading === null)
9
+ return;
10
+ const rawBody = currentBody.join('\n').trim();
11
+ sections.set(currentHeading.toLowerCase(), {
12
+ heading: currentHeading,
13
+ startLine: currentStart,
14
+ bodyLines: currentBody,
15
+ rawBody,
16
+ });
17
+ };
18
+ for (let i = 0; i < rawLines.length; i++) {
19
+ const line = rawLines[i] ?? '';
20
+ const match = line.match(/^##\s+(.+)$/);
21
+ if (match) {
22
+ flushSection(i);
23
+ currentHeading = (match[1] ?? '').trim();
24
+ currentStart = i + 1; // 1-indexed line number of the heading itself
25
+ currentBody = [];
26
+ }
27
+ else if (currentHeading !== null) {
28
+ currentBody.push(line);
29
+ }
30
+ }
31
+ flushSection(rawLines.length);
32
+ return { filePath, sections, rawLines };
33
+ }
34
+ export function getSectionLine(doc, sectionKey) {
35
+ return doc.sections.get(sectionKey.toLowerCase())?.startLine;
36
+ }
37
+ //# sourceMappingURL=markdown-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown-parser.js","sourceRoot":"","sources":["../../src/core/markdown-parser.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IAC7D,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEnD,IAAI,cAAc,GAAkB,IAAI,CAAC;IACzC,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,WAAW,GAAa,EAAE,CAAC;IAE/B,MAAM,YAAY,GAAG,CAAC,QAAgB,EAAE,EAAE;QACxC,IAAI,cAAc,KAAK,IAAI;YAAE,OAAO;QACpC,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,QAAQ,CAAC,GAAG,CAAC,cAAc,CAAC,WAAW,EAAE,EAAE;YACzC,OAAO,EAAE,cAAc;YACvB,SAAS,EAAE,YAAY;YACvB,SAAS,EAAE,WAAW;YACtB,OAAO;SACR,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACxC,IAAI,KAAK,EAAE,CAAC;YACV,YAAY,CAAC,CAAC,CAAC,CAAC;YAChB,cAAc,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACzC,YAAY,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,8CAA8C;YACpE,WAAW,GAAG,EAAE,CAAC;QACnB,CAAC;aAAM,IAAI,cAAc,KAAK,IAAI,EAAE,CAAC;YACnC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IACD,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,GAAmB,EAAE,UAAkB;IACpE,OAAO,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,SAAS,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Violation } from '../validators/types.js';
2
+ export declare function renderViolations(violations: Violation[]): string;
3
+ export declare function exitCode(violations: Violation[]): number;
@@ -0,0 +1,33 @@
1
+ import chalk from 'chalk';
2
+ export function renderViolations(violations) {
3
+ if (violations.length === 0) {
4
+ return chalk.green('✓ No violations found.\n');
5
+ }
6
+ const byFile = new Map();
7
+ for (const v of violations) {
8
+ const list = byFile.get(v.filePath) ?? [];
9
+ list.push(v);
10
+ byFile.set(v.filePath, list);
11
+ }
12
+ const lines = [];
13
+ for (const [filePath, fileViolations] of byFile) {
14
+ lines.push('');
15
+ lines.push(chalk.underline(filePath));
16
+ for (const v of fileViolations) {
17
+ const location = v.line !== undefined ? `:${v.line}` : '';
18
+ const severity = v.type === 'error' ? chalk.red('error') : chalk.yellow('warning');
19
+ lines.push(` ${filePath}${location} ${severity} ${v.message} ${chalk.gray(v.code)}`);
20
+ }
21
+ }
22
+ const errors = violations.filter(v => v.type === 'error').length;
23
+ const warnings = violations.filter(v => v.type === 'warning').length;
24
+ lines.push('');
25
+ const summary = `${errors} error${errors !== 1 ? 's' : ''}, ${warnings} warning${warnings !== 1 ? 's' : ''}`;
26
+ lines.push(errors > 0 ? chalk.red(summary) : chalk.yellow(summary));
27
+ lines.push('');
28
+ return lines.join('\n');
29
+ }
30
+ export function exitCode(violations) {
31
+ return violations.some(v => v.type === 'error') ? 1 : 0;
32
+ }
33
+ //# sourceMappingURL=reporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reporter.js","sourceRoot":"","sources":["../../src/core/reporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,MAAM,UAAU,gBAAgB,CAAC,UAAuB;IACtD,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC1C,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACb,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC/B,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,QAAQ,EAAE,cAAc,CAAC,IAAI,MAAM,EAAE,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,cAAc,EAAE,CAAC;YAC/B,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACnF,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,GAAG,QAAQ,KAAK,QAAQ,KAAK,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3F,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IACjE,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,CAAC;IACrE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,MAAM,OAAO,GAAG,GAAG,MAAM,SAAS,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,WAAW,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC7G,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,UAAuB;IAC9C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function intentTemplate(date: string): string;
2
+ export declare function behaviourTemplate(date: string): string;
3
+ export declare function implTemplate(date: string, behaviourRef?: string): string;
4
+ export declare const SECTION_PLACEHOLDERS: Record<string, Record<string, string>>;
@@ -0,0 +1,126 @@
1
+ export function intentTemplate(date) {
2
+ return `# Intent: <Title>
3
+
4
+ ## Stakeholders
5
+ - <Role>: <Name or team> — <their interest in this intent>
6
+
7
+ ## Goal
8
+ <1-3 sentences describing the desired outcome from the stakeholder's perspective>
9
+
10
+ ## Success Criteria
11
+ - [ ] <Measurable criterion 1>
12
+ - [ ] <Measurable criterion 2>
13
+
14
+ ## Constraints
15
+ - <Constraint 1 (regulatory, technical, timeline, etc.)>
16
+
17
+ ## Status
18
+ - **State:** draft
19
+ - **Created:** ${date}
20
+ - **Last reviewed:** ${date}
21
+
22
+ ## Notes
23
+ <Free-form context, links to external docs, meeting notes, etc.>
24
+ `;
25
+ }
26
+ export function behaviourTemplate(date) {
27
+ return `# Behaviour: <Title>
28
+
29
+ ## Actor
30
+ <Who or what initiates this behaviour>
31
+
32
+ ## Preconditions
33
+ - <What must be true before this behaviour can occur>
34
+
35
+ ## Main Flow
36
+ 1. <Step 1>
37
+ 2. <Step 2>
38
+ 3. <Step 3>
39
+
40
+ ## Alternate Flows
41
+ ### <Alternate flow name>
42
+ - **Trigger:** <When does this alternate flow occur?>
43
+ - **Steps:**
44
+ 1. <Step>
45
+ 2. <Step>
46
+
47
+ ## Postconditions
48
+ - <What is true after successful completion>
49
+
50
+ ## Error Conditions
51
+ - <Error scenario>: <Expected system response>
52
+
53
+ ## Diagram
54
+ <!-- Optional: sequence, flowchart, or state diagram in Mermaid syntax -->
55
+ \`\`\`mermaid
56
+ sequenceDiagram
57
+ Actor->>System: <trigger>
58
+ System-->>Actor: <response>
59
+ \`\`\`
60
+
61
+ ## Status
62
+ - **State:** proposed
63
+ - **Created:** ${date}
64
+ - **Last reviewed:** ${date}
65
+
66
+ ## Notes
67
+ <Edge cases, open questions, links to related behaviours>
68
+ `;
69
+ }
70
+ export function implTemplate(date, behaviourRef = '../usecase.md') {
71
+ return `# Implementation: <Title>
72
+
73
+ ## Behaviour
74
+ ${behaviourRef}
75
+
76
+ ## Design Decisions
77
+ - <Decision 1: what was chosen and why>
78
+
79
+ ## Source Files
80
+ - \`<path/to/file.ts>\` — <brief description of what this file does for this implementation>
81
+
82
+ ## Commits
83
+ - \`<hash>\` — <one-line summary>
84
+
85
+ ## Tests
86
+ - \`<path/to/test-file.test.ts>\` — <what scenarios this test covers>
87
+
88
+ ## Status
89
+ - **State:** planned
90
+ - **Created:** ${date}
91
+ - **Last verified:** ${date}
92
+
93
+ ## Notes
94
+ <Technical debt, known limitations, future improvements>
95
+ `;
96
+ }
97
+ export const SECTION_PLACEHOLDERS = {
98
+ intent: {
99
+ 'stakeholders': '- <Role>: <Name or team> — <their interest in this intent>',
100
+ 'goal': '<1-3 sentences describing the desired outcome from the stakeholder\'s perspective>',
101
+ 'success criteria': '- [ ] <Measurable criterion 1>',
102
+ 'constraints': '- <Constraint 1>',
103
+ 'status': '- **State:** draft\n- **Created:** <YYYY-MM-DD>\n- **Last reviewed:** <YYYY-MM-DD>',
104
+ 'notes': '<Free-form context>',
105
+ },
106
+ behaviour: {
107
+ 'actor': '<Who or what initiates this behaviour>',
108
+ 'preconditions': '- <What must be true before this behaviour can occur>',
109
+ 'main flow': '1. <Step 1>\n2. <Step 2>',
110
+ 'alternate flows': '### <Alternate flow name>\n- **Trigger:** <When?>\n- **Steps:**\n 1. <Step>',
111
+ 'postconditions': '- <What is true after successful completion>',
112
+ 'error conditions': '- <Error scenario>: <Expected system response>',
113
+ 'status': '- **State:** proposed\n- **Created:** <YYYY-MM-DD>\n- **Last reviewed:** <YYYY-MM-DD>',
114
+ 'notes': '<Edge cases, open questions>',
115
+ },
116
+ impl: {
117
+ 'behaviour': '../usecase.md',
118
+ 'design decisions': '- <Decision 1: what was chosen and why>',
119
+ 'source files': '- `<path/to/file.ts>` — <description>',
120
+ 'commits': '- `<hash>` — <one-line summary>',
121
+ 'tests': '- `<path/to/test.ts>` — <what this covers>',
122
+ 'status': '- **State:** planned\n- **Created:** <YYYY-MM-DD>\n- **Last verified:** <YYYY-MM-DD>',
123
+ 'notes': '<Technical debt, known limitations>',
124
+ },
125
+ };
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO;;;;;;;;;;;;;;;;;iBAiBQ,IAAI;uBACE,IAAI;;;;CAI1B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoCQ,IAAI;uBACE,IAAI;;;;CAI1B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,eAAuB,eAAe;IAC/E,OAAO;;;EAGP,YAAY;;;;;;;;;;;;;;;;iBAgBG,IAAI;uBACE,IAAI;;;;CAI1B,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAA2C;IAC1E,MAAM,EAAE;QACN,cAAc,EAAE,4DAA4D;QAC5E,MAAM,EAAE,oFAAoF;QAC5F,kBAAkB,EAAE,gCAAgC;QACpD,aAAa,EAAE,kBAAkB;QACjC,QAAQ,EAAE,oFAAoF;QAC9F,OAAO,EAAE,qBAAqB;KAC/B;IACD,SAAS,EAAE;QACT,OAAO,EAAE,wCAAwC;QACjD,eAAe,EAAE,uDAAuD;QACxE,WAAW,EAAE,0BAA0B;QACvC,iBAAiB,EAAE,8EAA8E;QACjG,gBAAgB,EAAE,8CAA8C;QAChE,kBAAkB,EAAE,gDAAgD;QACpE,QAAQ,EAAE,uFAAuF;QACjG,OAAO,EAAE,8BAA8B;KACxC;IACD,IAAI,EAAE;QACJ,WAAW,EAAE,eAAe;QAC5B,kBAAkB,EAAE,yCAAyC;QAC7D,cAAc,EAAE,uCAAuC;QACvD,SAAS,EAAE,iCAAiC;QAC5C,OAAO,EAAE,4CAA4C;QACrD,QAAQ,EAAE,sFAAsF;QAChG,OAAO,EAAE,qCAAqC;KAC/C;CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { ParsedMarkdown, MarkerType, TaprootConfig, Violation, FolderNode } from './types.js';
2
+ import type { LanguagePack } from '../core/language.js';
3
+ export declare function checkRequiredSections(doc: ParsedMarkdown, markerType: MarkerType, pack?: LanguagePack | null): Violation[];
4
+ export declare function checkStatusValue(doc: ParsedMarkdown, markerType: MarkerType, config: TaprootConfig): Violation[];
5
+ export declare function checkDateFormat(doc: ParsedMarkdown, config: TaprootConfig): Violation[];
6
+ export declare function checkBehaviourReference(doc: ParsedMarkdown, implFilePath: string): Violation[];
7
+ export declare function checkDiagramSection(doc: ParsedMarkdown): Violation[];
8
+ export declare function checkLinkSection(doc: ParsedMarkdown, node: FolderNode): Violation[];
9
+ export declare function checkAcceptanceCriteria(doc: ParsedMarkdown, node: FolderNode, pack?: LanguagePack | null): Violation[];
10
+ export declare function validateFormat(doc: ParsedMarkdown, markerType: MarkerType, config: TaprootConfig, node?: FolderNode, pack?: LanguagePack | null): Violation[];