@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,378 @@
1
+ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from 'fs';
2
+ import { resolve, join, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import yaml from 'js-yaml';
5
+ import { DEFAULT_CONFIG } from '../core/config.js';
6
+ import { substituteTokens, applyVocabulary, getStructuralKeys } from '../core/language.js';
7
+ import { intentTemplate, behaviourTemplate, implTemplate } from '../templates/index.js';
8
+ import { generateAdapters, ALL_AGENTS, AGENT_TIERS, getTierLabel } from '../adapters/index.js';
9
+ import checkbox from '@inquirer/checkbox';
10
+ import confirm from '@inquirer/confirm';
11
+ const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ // Bundled skills directory — two levels up from src/commands/ → package root → skills/
13
+ const BUNDLED_SKILLS_DIR = resolve(__dirname, '..', '..', 'skills');
14
+ // Bundled docs directory — two levels up from src/commands/ → package root → docs/
15
+ const BUNDLED_DOCS_DIR = resolve(__dirname, '..', '..', 'docs');
16
+ export const SKILL_FILES = [
17
+ 'analyse-change.md',
18
+ 'review.md',
19
+ 'review-all.md',
20
+ 'grill-me.md',
21
+ 'intent.md',
22
+ 'behaviour.md',
23
+ 'implement.md',
24
+ 'trace.md',
25
+ 'status.md',
26
+ 'refine.md',
27
+ 'promote.md',
28
+ 'decompose.md',
29
+ 'plan.md',
30
+ 'guide.md',
31
+ 'discover.md',
32
+ 'ineed.md',
33
+ 'research.md',
34
+ 'sweep.md',
35
+ 'commit.md',
36
+ 'bug.md',
37
+ ];
38
+ export function registerInit(program) {
39
+ program
40
+ .command('init')
41
+ .description('Initialize Taproot in the current project')
42
+ .option('--with-hooks', 'Install git pre-commit hooks')
43
+ .option('--with-ci <provider>', 'Generate CI workflow (github|gitlab)')
44
+ .option('--with-skills', 'Install canonical skill definitions into taproot/skills/')
45
+ .option('--agent <name>', `Generate agent adapter (${[...ALL_AGENTS, 'all'].join('|')})`)
46
+ .option('--path <path>', 'Directory to initialize in', process.cwd())
47
+ .action(async (options) => {
48
+ let agent = options.agent;
49
+ if (!agent) {
50
+ const AGENT_BASE_LABELS = {
51
+ claude: 'Claude Code',
52
+ cursor: 'Cursor',
53
+ copilot: 'GitHub Copilot',
54
+ windsurf: 'Windsurf',
55
+ gemini: 'Gemini CLI',
56
+ generic: 'Generic (any AI agent)',
57
+ };
58
+ const selected = await checkbox({
59
+ message: 'Which agent adapter(s) would you like to generate?',
60
+ choices: ALL_AGENTS.map((a) => ({
61
+ name: `${AGENT_BASE_LABELS[a]} (${getTierLabel(a)})`,
62
+ value: a,
63
+ })),
64
+ });
65
+ if (selected.length === ALL_AGENTS.length) {
66
+ agent = 'all';
67
+ }
68
+ else if (selected.length > 0) {
69
+ agent = selected;
70
+ }
71
+ }
72
+ let withHooks = options.withHooks;
73
+ if (!withHooks) {
74
+ withHooks = await confirm({
75
+ message: 'Install the pre-commit hook? (Strongly recommended — prevents implementation commits without traceability and requirement commits without quality checks)',
76
+ default: true,
77
+ });
78
+ }
79
+ const created = runInit({
80
+ cwd: options.path,
81
+ withHooks,
82
+ withCi: options.withCi,
83
+ withSkills: options.withSkills,
84
+ agent,
85
+ });
86
+ for (const msg of created) {
87
+ process.stdout.write(msg + '\n');
88
+ }
89
+ });
90
+ }
91
+ export function runInit(options) {
92
+ const cwd = options.cwd ?? process.cwd();
93
+ const messages = [];
94
+ if (!existsSync(join(cwd, '.git'))) {
95
+ throw new Error('No git repository found. Run `git init` first, then re-run `taproot init`.');
96
+ }
97
+ const configPath = join(cwd, '.taproot', 'settings.yaml');
98
+ const taprootDir = resolve(cwd, DEFAULT_CONFIG.root);
99
+ const skillsDir = join(cwd, '.taproot', 'skills');
100
+ // Create taproot/ directory
101
+ if (!existsSync(taprootDir)) {
102
+ mkdirSync(taprootDir, { recursive: true });
103
+ messages.push(`created ${DEFAULT_CONFIG.root}`);
104
+ }
105
+ else {
106
+ messages.push(`exists ${DEFAULT_CONFIG.root}`);
107
+ }
108
+ // Ensure .taproot/ directory exists
109
+ mkdirSync(join(cwd, '.taproot'), { recursive: true });
110
+ // Write .taproot/settings.yaml
111
+ if (!existsSync(configPath)) {
112
+ const configForYaml = {
113
+ version: DEFAULT_CONFIG.version,
114
+ root: DEFAULT_CONFIG.root,
115
+ commit_pattern: DEFAULT_CONFIG.commitPattern,
116
+ commit_trailer: DEFAULT_CONFIG.commitTrailer,
117
+ agents: DEFAULT_CONFIG.agents,
118
+ validation: {
119
+ require_dates: DEFAULT_CONFIG.validation.requireDates,
120
+ require_status: DEFAULT_CONFIG.validation.requireStatus,
121
+ allowed_intent_states: DEFAULT_CONFIG.validation.allowedIntentStates,
122
+ allowed_behaviour_states: DEFAULT_CONFIG.validation.allowedBehaviourStates,
123
+ allowed_impl_states: DEFAULT_CONFIG.validation.allowedImplStates,
124
+ },
125
+ };
126
+ writeFileSync(configPath, yaml.dump(configForYaml));
127
+ messages.push('created .taproot/settings.yaml');
128
+ }
129
+ else {
130
+ messages.push('exists .taproot/settings.yaml');
131
+ }
132
+ // Write CONVENTIONS.md
133
+ const conventionsPath = join(taprootDir, 'CONVENTIONS.md');
134
+ if (!existsSync(conventionsPath)) {
135
+ writeFileSync(conventionsPath, buildConventionsDoc());
136
+ messages.push(`created ${DEFAULT_CONFIG.root}CONVENTIONS.md`);
137
+ }
138
+ // Install skill definitions — always enabled when an adapter that references .taproot/skills/ is requested
139
+ const agentList = options.agent === 'all'
140
+ ? ALL_AGENTS
141
+ : Array.isArray(options.agent)
142
+ ? options.agent
143
+ : options.agent
144
+ ? [options.agent]
145
+ : [];
146
+ const needsSkills = options.withSkills || agentList.includes('claude') || agentList.includes('gemini');
147
+ if (needsSkills) {
148
+ messages.push(...installSkills(skillsDir));
149
+ messages.push(...installDocs(join(cwd, '.taproot', 'docs')));
150
+ }
151
+ // Git pre-commit hook
152
+ if (options.withHooks) {
153
+ const hookDir = join(cwd, '.git', 'hooks');
154
+ const hookPath = join(hookDir, 'pre-commit');
155
+ if (existsSync(join(cwd, '.git')) && !existsSync(hookPath)) {
156
+ mkdirSync(hookDir, { recursive: true });
157
+ writeFileSync(hookPath, '#!/bin/sh\ntaproot commithook\n', { mode: 0o755 });
158
+ messages.push('created .git/hooks/pre-commit');
159
+ }
160
+ }
161
+ else if (options.withHooks === false) {
162
+ messages.push('skipped .git/hooks/pre-commit — run `taproot init --with-hooks` to add it later');
163
+ }
164
+ // Agent adapters
165
+ if (options.agent) {
166
+ const results = generateAdapters(options.agent, cwd);
167
+ for (const result of results) {
168
+ for (const file of result.files) {
169
+ const rel = file.path.replace(cwd + '/', '').replace(cwd + '\\', '');
170
+ const verb = file.status === 'created' ? 'created' : file.status === 'updated' ? 'updated' : 'exists ';
171
+ messages.push(`${verb} ${rel}`);
172
+ }
173
+ const tier = AGENT_TIERS[result.agent];
174
+ messages.push(` ${getTierLabel(result.agent)}`);
175
+ if (tier === 3) {
176
+ messages.push(` Community-supported: adapter generated but not officially validated end-to-end. Feedback and fixes welcome.`);
177
+ }
178
+ }
179
+ }
180
+ // CI workflow
181
+ if (options.withCi === 'github') {
182
+ const workflowDir = join(cwd, '.github', 'workflows');
183
+ const workflowPath = join(workflowDir, 'taproot.yml');
184
+ if (!existsSync(workflowPath)) {
185
+ mkdirSync(workflowDir, { recursive: true });
186
+ writeFileSync(workflowPath, buildGithubWorkflow());
187
+ messages.push('created .github/workflows/taproot.yml');
188
+ }
189
+ else {
190
+ messages.push('exists .github/workflows/taproot.yml');
191
+ }
192
+ }
193
+ if (options.withCi === 'gitlab') {
194
+ const ciPath = join(cwd, '.gitlab-ci.yml');
195
+ if (!existsSync(ciPath)) {
196
+ writeFileSync(ciPath, buildGitlabCi());
197
+ messages.push('created .gitlab-ci.yml');
198
+ }
199
+ else {
200
+ // Append taproot job if not already present
201
+ const existing = readFileSync(ciPath, 'utf-8');
202
+ if (!existing.includes('taproot-validate')) {
203
+ writeFileSync(ciPath, existing.trimEnd() + '\n\n' + buildGitlabCiJob());
204
+ messages.push('updated .gitlab-ci.yml (appended taproot-validate job)');
205
+ }
206
+ else {
207
+ messages.push('exists .gitlab-ci.yml');
208
+ }
209
+ }
210
+ }
211
+ messages.push('');
212
+ messages.push('Taproot initialized. Run `taproot validate-structure` to verify.');
213
+ return messages;
214
+ }
215
+ export function installSkills(targetSkillsDir, force = false, pack, vocab) {
216
+ const messages = [];
217
+ if (!existsSync(BUNDLED_SKILLS_DIR)) {
218
+ messages.push(`warning Skills directory not found at ${BUNDLED_SKILLS_DIR} — skipping`);
219
+ return messages;
220
+ }
221
+ mkdirSync(targetSkillsDir, { recursive: true });
222
+ for (const filename of SKILL_FILES) {
223
+ const src = join(BUNDLED_SKILLS_DIR, filename);
224
+ const dest = join(targetSkillsDir, filename);
225
+ if (!existsSync(src)) {
226
+ messages.push(`warning Skill file not found: ${filename}`);
227
+ continue;
228
+ }
229
+ let content = readFileSync(src, 'utf-8');
230
+ if (pack) {
231
+ content = substituteTokens(content, pack);
232
+ }
233
+ if (vocab && Object.keys(vocab).length > 0) {
234
+ const structuralKeys = getStructuralKeys(pack ?? null);
235
+ const { result, warnings } = applyVocabulary(content, vocab, structuralKeys);
236
+ content = result;
237
+ for (const w of warnings) {
238
+ messages.push(`warning ${w}`);
239
+ }
240
+ }
241
+ if (!existsSync(dest)) {
242
+ writeFileSync(dest, content);
243
+ messages.push(`created .taproot/skills/${filename}`);
244
+ }
245
+ else if (force) {
246
+ writeFileSync(dest, content);
247
+ messages.push(`updated .taproot/skills/${filename}`);
248
+ }
249
+ else {
250
+ messages.push(`exists .taproot/skills/${filename}`);
251
+ }
252
+ }
253
+ return messages;
254
+ }
255
+ export function installDocs(targetDocsDir, force = false) {
256
+ const messages = [];
257
+ if (!existsSync(BUNDLED_DOCS_DIR)) {
258
+ messages.push(`warning Docs directory not found at ${BUNDLED_DOCS_DIR} — skipping`);
259
+ return messages;
260
+ }
261
+ mkdirSync(targetDocsDir, { recursive: true });
262
+ for (const filename of readdirSync(BUNDLED_DOCS_DIR).filter(f => f.endsWith('.md'))) {
263
+ const src = join(BUNDLED_DOCS_DIR, filename);
264
+ const dest = join(targetDocsDir, filename);
265
+ const content = readFileSync(src, 'utf-8');
266
+ if (!existsSync(dest)) {
267
+ writeFileSync(dest, content);
268
+ messages.push(`created .taproot/docs/${filename}`);
269
+ }
270
+ else if (force) {
271
+ writeFileSync(dest, content);
272
+ messages.push(`updated .taproot/docs/${filename}`);
273
+ }
274
+ else {
275
+ messages.push(`exists .taproot/docs/${filename}`);
276
+ }
277
+ }
278
+ return messages;
279
+ }
280
+ function buildConventionsDoc() {
281
+ const date = new Date().toISOString().slice(0, 10);
282
+ return `# Taproot Conventions
283
+
284
+ Auto-generated reference for document formats and commit conventions.
285
+
286
+ ## Document Formats
287
+
288
+ ### intent.md — Business Intent
289
+
290
+ \`\`\`markdown
291
+ ${intentTemplate(date)}\`\`\`
292
+
293
+ ### usecase.md — Behaviour (UseCase)
294
+
295
+ \`\`\`markdown
296
+ ${behaviourTemplate(date)}\`\`\`
297
+
298
+ ### impl.md — Implementation
299
+
300
+ \`\`\`markdown
301
+ ${implTemplate(date)}\`\`\`
302
+
303
+ ## Folder Naming
304
+
305
+ - Lowercase kebab-case: \`^[a-z0-9]+(-[a-z0-9]+)*\$\`
306
+ - Each folder is exactly one type (intent, behaviour, or implementation)
307
+ - Identified by its marker file: \`intent.md\`, \`usecase.md\`, or \`impl.md\`
308
+
309
+ ## Commit Convention
310
+
311
+ Link commits to implementations using the conventional tag format:
312
+
313
+ \`\`\`
314
+ taproot(<intent>/<behaviour>/<impl>): <message>
315
+ \`\`\`
316
+
317
+ Or use a commit trailer:
318
+
319
+ \`\`\`
320
+ Taproot: <intent>/<behaviour>/<impl>
321
+ \`\`\`
322
+
323
+ ## Folder Structure
324
+
325
+ \`\`\`
326
+ taproot/
327
+ ├── <intent-slug>/
328
+ │ ├── intent.md
329
+ │ └── <behaviour-slug>/
330
+ │ ├── usecase.md
331
+ │ └── <implementation-slug>/
332
+ │ └── impl.md
333
+ \`\`\`
334
+ `;
335
+ }
336
+ function buildGithubWorkflow() {
337
+ return `name: Taproot Validation
338
+
339
+ on:
340
+ pull_request:
341
+ push:
342
+ branches: [main, master]
343
+
344
+ jobs:
345
+ validate:
346
+ runs-on: ubuntu-latest
347
+ steps:
348
+ - uses: actions/checkout@v4
349
+ - uses: actions/setup-node@v4
350
+ with:
351
+ node-version: '20'
352
+ - run: npm install -g taproot
353
+ - run: taproot validate-structure
354
+ - run: taproot validate-format
355
+ - run: taproot check-orphans
356
+ `;
357
+ }
358
+ function buildGitlabCiJob() {
359
+ return `taproot-validate:
360
+ stage: test
361
+ image: node:20-alpine
362
+ script:
363
+ - npm install -g taproot
364
+ - taproot validate-structure
365
+ - taproot validate-format
366
+ - taproot check-orphans
367
+ rules:
368
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
369
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH`;
370
+ }
371
+ function buildGitlabCi() {
372
+ return `stages:
373
+ - test
374
+
375
+ ${buildGitlabCiJob()}
376
+ `;
377
+ }
378
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Command } from 'commander';
2
+ export interface LinkResult {
3
+ implPath: string;
4
+ addedHashes: string[];
5
+ }
6
+ export declare function registerLinkCommits(program: Command): void;
7
+ export declare function runLinkCommits(options: {
8
+ since?: string;
9
+ dryRun?: boolean;
10
+ path?: string;
11
+ cwd?: string;
12
+ }): Promise<LinkResult[]>;
@@ -0,0 +1,126 @@
1
+ import { readFileSync, writeFileSync } from 'fs';
2
+ import { join, relative, resolve } from 'path';
3
+ import { loadConfig } from '../core/config.js';
4
+ import { walkHierarchy, flattenTree } from '../core/fs-walker.js';
5
+ import { parseMarkdown } from '../core/markdown-parser.js';
6
+ import { parseImplData } from '../core/impl-reader.js';
7
+ import { gitLog, extractTaprootPath, isGitRepo, getRepoRoot } from '../core/git.js';
8
+ export function registerLinkCommits(program) {
9
+ program
10
+ .command('link-commits')
11
+ .description('Update impl.md files with commit references from git history')
12
+ .option('--since <date|hash>', 'Only scan commits after this date or hash')
13
+ .option('--dry-run', 'Preview changes without writing')
14
+ .option('--path <path>', 'Root path (overrides config)')
15
+ .action(async (options) => {
16
+ const results = await runLinkCommits({
17
+ since: options.since,
18
+ dryRun: options.dryRun ?? false,
19
+ path: options.path,
20
+ });
21
+ if (results.length === 0) {
22
+ process.stdout.write('No new commits to link.\n');
23
+ }
24
+ else {
25
+ for (const r of results) {
26
+ const verb = options.dryRun ? 'would add' : 'added';
27
+ process.stdout.write(`${r.implPath}: ${verb} ${r.addedHashes.join(', ')}\n`);
28
+ }
29
+ }
30
+ });
31
+ }
32
+ export async function runLinkCommits(options) {
33
+ const { config, configDir } = loadConfig(options.cwd);
34
+ const rootPath = options.path ? resolve(options.path) : config.root;
35
+ const cwd = options.cwd ?? process.cwd();
36
+ if (!isGitRepo(cwd)) {
37
+ throw new Error('Not inside a git repository. link-commits requires git.');
38
+ }
39
+ const repoRoot = getRepoRoot(cwd) ?? cwd;
40
+ // Build map: taproot-relative path → impl node
41
+ const tree = walkHierarchy(rootPath);
42
+ const implNodes = flattenTree(tree).filter((n) => n.marker === 'impl');
43
+ // Read existing commits for each impl
44
+ const implIndex = new Map();
45
+ for (const node of implNodes) {
46
+ const filePath = join(node.absolutePath, 'impl.md');
47
+ try {
48
+ const content = readFileSync(filePath, 'utf-8');
49
+ const doc = parseMarkdown(filePath, content);
50
+ const data = parseImplData(doc);
51
+ // Index by relative path from repo root (normalized, no trailing slash)
52
+ const relFromRoot = relative(repoRoot, node.absolutePath).replace(/\\/g, '/');
53
+ implIndex.set(relFromRoot, { node, existingHashes: new Set(data.commits) });
54
+ }
55
+ catch {
56
+ // skip unreadable impl.md
57
+ }
58
+ }
59
+ // Also index by relative path from taproot root for flexible matching
60
+ const implIndexFromTaproot = new Map(); // taproot-relative → repoRoot-relative
61
+ for (const node of implNodes) {
62
+ const relFromTaproot = node.relativePath.replace(/\\/g, '/');
63
+ const relFromRoot = relative(repoRoot, node.absolutePath).replace(/\\/g, '/');
64
+ implIndexFromTaproot.set(relFromTaproot, relFromRoot);
65
+ }
66
+ // Scan git log
67
+ const commits = gitLog({ since: options.since, cwd: repoRoot });
68
+ // Collect new commits per impl
69
+ const pendingAdditions = new Map(); // repoRoot-relative → new hashes
70
+ for (const commit of commits) {
71
+ const taprootPath = extractTaprootPath(commit, config.commitPattern, config.commitTrailer);
72
+ if (!taprootPath)
73
+ continue;
74
+ // Try matching as repoRoot-relative path first, then taproot-relative
75
+ let key = taprootPath;
76
+ if (!implIndex.has(key)) {
77
+ const mapped = implIndexFromTaproot.get(key);
78
+ if (mapped)
79
+ key = mapped;
80
+ }
81
+ const entry = implIndex.get(key);
82
+ if (!entry)
83
+ continue;
84
+ if (entry.existingHashes.has(commit.hash) || entry.existingHashes.has(commit.hash.slice(0, 7)))
85
+ continue;
86
+ const list = pendingAdditions.get(key) ?? [];
87
+ list.push(commit.hash);
88
+ pendingAdditions.set(key, list);
89
+ }
90
+ const results = [];
91
+ for (const [key, hashes] of pendingAdditions) {
92
+ const entry = implIndex.get(key);
93
+ if (!entry)
94
+ continue;
95
+ const filePath = join(entry.node.absolutePath, 'impl.md');
96
+ results.push({ implPath: filePath, addedHashes: hashes });
97
+ if (!options.dryRun) {
98
+ const content = readFileSync(filePath, 'utf-8');
99
+ const updated = appendCommitsToImplMd(content, hashes);
100
+ writeFileSync(filePath, updated, 'utf-8');
101
+ }
102
+ }
103
+ return results;
104
+ }
105
+ function appendCommitsToImplMd(content, hashes) {
106
+ const lines = content.split('\n');
107
+ const commitsHeading = lines.findIndex(l => /^##\s+Commits\s*$/.test(l));
108
+ if (commitsHeading === -1) {
109
+ // Append Commits section at end
110
+ const additions = hashes.map(h => `- \`${h}\` — (auto-linked by taproot link-commits)`);
111
+ return content.trimEnd() + '\n\n## Commits\n' + additions.join('\n') + '\n';
112
+ }
113
+ // Find last non-empty line in the Commits section (before next ## or EOF)
114
+ let insertAt = commitsHeading + 1;
115
+ for (let i = commitsHeading + 1; i < lines.length; i++) {
116
+ const line = lines[i] ?? '';
117
+ if (/^##\s/.test(line))
118
+ break;
119
+ if (line.trim())
120
+ insertAt = i + 1;
121
+ }
122
+ const newLines = hashes.map(h => `- \`${h}\` — (auto-linked by taproot link-commits)`);
123
+ lines.splice(insertAt, 0, ...newLines);
124
+ return lines.join('\n');
125
+ }
126
+ //# sourceMappingURL=link-commits.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link-commits.js","sourceRoot":"","sources":["../../src/commands/link-commits.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Command } from 'commander';
2
+ export declare function runOverview(options: {
3
+ taprootDir: string;
4
+ cwd?: string;
5
+ }): Promise<string[]>;
6
+ export declare function registerOverview(program: Command): void;