ma-agents 3.14.0 → 3.15.0-beta.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 (47) hide show
  1. package/lib/bmad-extension/.claude-plugin/marketplace.json.template +2 -1
  2. package/lib/bmad-extension/skills/bmad-knowledge/.gitkeep +0 -0
  3. package/lib/bmad-extension/skills/bmad-knowledge/SKILL.md +130 -0
  4. package/lib/bmad-extension/skills/bmad-knowledge/bmad-skill-manifest.yaml +3 -0
  5. package/lib/bmad-extension/skills/module-help.csv +1 -0
  6. package/lib/bmad-extension-plugin/.claude-plugin/marketplace.json +3 -2
  7. package/lib/bmad-extension-plugin/skills/bmad-knowledge/.gitkeep +0 -0
  8. package/lib/bmad-extension-plugin/skills/bmad-knowledge/SKILL.md +130 -0
  9. package/lib/bmad-extension-plugin/skills/bmad-knowledge/bmad-skill-manifest.yaml +3 -0
  10. package/lib/bmad-extension-plugin/skills/module-help.csv +1 -0
  11. package/lib/bmad.js +15 -0
  12. package/lib/installer.js +88 -0
  13. package/lib/knowledge-atlas/dist/atlas.cjs +14134 -0
  14. package/lib/knowledge-atlas/src/cli.ts +55 -0
  15. package/lib/knowledge-atlas/src/extract/entities.ts +420 -0
  16. package/lib/knowledge-atlas/src/extract/frontmatter.ts +84 -0
  17. package/lib/knowledge-atlas/src/extract/slug.ts +91 -0
  18. package/lib/knowledge-atlas/src/generate.ts +355 -0
  19. package/lib/knowledge-atlas/src/graph/build.ts +301 -0
  20. package/lib/knowledge-atlas/src/graph/reconcile.ts +340 -0
  21. package/lib/knowledge-atlas/src/index.ts +11 -0
  22. package/lib/knowledge-atlas/src/manifest/incremental.ts +146 -0
  23. package/lib/knowledge-atlas/src/manifest/persist.ts +112 -0
  24. package/lib/knowledge-atlas/src/render/backlinks.ts +160 -0
  25. package/lib/knowledge-atlas/src/render/design-system.ts +624 -0
  26. package/lib/knowledge-atlas/src/render/diagrams.ts +717 -0
  27. package/lib/knowledge-atlas/src/render/document.ts +333 -0
  28. package/lib/knowledge-atlas/src/render/force-graph-umd.ts +22 -0
  29. package/lib/knowledge-atlas/src/render/graph.ts +815 -0
  30. package/lib/knowledge-atlas/src/render/layout.ts +182 -0
  31. package/lib/knowledge-atlas/src/render/linkify.ts +464 -0
  32. package/lib/knowledge-atlas/src/render/orphan.ts +540 -0
  33. package/lib/knowledge-atlas/src/render/paths.ts +110 -0
  34. package/lib/knowledge-atlas/src/render/search.ts +343 -0
  35. package/lib/knowledge-atlas/src/render/site.ts +307 -0
  36. package/lib/knowledge-atlas/src/scan/hash.ts +49 -0
  37. package/lib/knowledge-atlas/src/scan/scanner.ts +239 -0
  38. package/lib/knowledge-atlas/src/types.ts +241 -0
  39. package/lib/knowledge-atlas/tsconfig.json +22 -0
  40. package/lib/templates/instruction-block-git.template.md +25 -25
  41. package/lib/templates/instruction-block-onprem.template.md +86 -86
  42. package/lib/templates/instruction-block-universal.template.md +29 -29
  43. package/package.json +16 -4
  44. package/scripts/build-atlas.js +253 -0
  45. package/skills/bmad-knowledge/SKILL.md +130 -0
  46. package/skills/bmad-knowledge/skill.json +7 -0
  47. package/skills/git-workflow-skill/skill.json +21 -21
@@ -110,7 +110,8 @@
110
110
  "./skills/prioritize-backlog",
111
111
  "./skills/project-context-expansion",
112
112
  "./skills/remove-from-sprint",
113
- "./skills/sprint-status-view"
113
+ "./skills/sprint-status-view",
114
+ "./skills/bmad-knowledge"
114
115
  ]
115
116
  }
116
117
  ]
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: bmad-knowledge
3
+ description: Generate a self-contained Knowledge Atlas HTML site from project planning and implementation artifacts
4
+ type: skill
5
+ triggers:
6
+ - "knowledge atlas"
7
+ - "generate knowledge site"
8
+ - "bmad-knowledge"
9
+ ---
10
+
11
+ # Knowledge Atlas Skill
12
+
13
+ Generate a self-contained, offline-ready Knowledge Atlas HTML site from the project's `_bmad-output` planning and implementation artifacts. No network access is required at generation or view time.
14
+
15
+ ## Prerequisites
16
+
17
+ - The project must have a `_bmad-output/` directory (created by BMAD install).
18
+ - `ma-agents` must be installed (globally via `npx ma-agents` or as a local dependency).
19
+ - Node.js >= 18 must be available.
20
+
21
+ ---
22
+
23
+ ## Workflow
24
+
25
+ ### Step 1 — Resolve the project root
26
+
27
+ The project root is the directory containing `_bmad-output/`. Locate it by walking up from the current working directory until `_bmad-output/` is found, or use the directory the agent is operating in.
28
+
29
+ ```
30
+ projectRoot = <directory containing _bmad-output/>
31
+ bmadOutputDir = <projectRoot>/_bmad-output
32
+ outputSite = <projectRoot>/_bmad-output/knowledge-site/index.html
33
+ ```
34
+
35
+ ### Step 2 — Locate the engine bundle
36
+
37
+ The Knowledge Atlas engine is a pre-bundled CJS file committed inside the `ma-agents` package. Resolve it in this order:
38
+
39
+ 1. **Installed package resolution (preferred):** Use Node.js module resolution to locate the bundle:
40
+ ```js
41
+ require.resolve('ma-agents/lib/knowledge-atlas/dist/atlas.cjs')
42
+ ```
43
+ This works when `ma-agents` is installed as a dependency or globally via `npx`.
44
+
45
+ 2. **Dev-local fallback:** If the skill is being run from within the `ma-agents` repo itself (e.g., during development), use a path relative to the skill file:
46
+ ```
47
+ <skill_dir>/../../../../lib/knowledge-atlas/dist/atlas.cjs
48
+ ```
49
+ where `<skill_dir>` is the directory containing this SKILL.md.
50
+
51
+ 3. If neither path resolves to an existing file, abort with:
52
+ ```
53
+ ERROR: Cannot locate atlas.cjs. Ensure ma-agents is installed:
54
+ npm install -g ma-agents
55
+ # or: npm install --save-dev ma-agents
56
+ ```
57
+
58
+ ### Step 3 — Run the engine
59
+
60
+ Execute the bundled engine as a Node.js subprocess. Pass `atlasPath` and
61
+ `projectRoot` as ARGUMENT-ARRAY elements (never interpolate them into a shell
62
+ string) so paths containing spaces, quotes, or shell metacharacters cannot be
63
+ misparsed or injected:
64
+
65
+ ```js
66
+ const { spawnSync } = require('node:child_process');
67
+ const res = spawnSync(process.execPath, [atlasPath, projectRoot], {
68
+ encoding: 'utf-8',
69
+ // No `shell: true` — args go directly to the OS exec, not a shell.
70
+ });
71
+ if (res.status !== 0) {
72
+ // Report res.stderr and abort.
73
+ throw new Error(`atlas.cjs failed (exit ${res.status}): ${res.stderr}`);
74
+ }
75
+ const indexHtmlPath = res.stdout.trim(); // engine prints the index.html path
76
+ ```
77
+
78
+ - The engine writes `_bmad-output/knowledge-site/index.html`.
79
+ - It prints the path to `stdout` on success.
80
+ - It exits with code 0 on success, non-zero on failure (error on stderr).
81
+ - It never modifies any source file — output is isolated to `_bmad-output/knowledge-site/`.
82
+
83
+ If the engine exits non-zero, report the stderr output and abort.
84
+
85
+ ### Step 4 — Open the generated site
86
+
87
+ After successful generation, open `_bmad-output/knowledge-site/index.html` using
88
+ the appropriate method for the current environment. Use `execFile`/`spawn` with
89
+ an ARGUMENT ARRAY — never build a shell command string with the path
90
+ interpolated, which would be an injection vector:
91
+
92
+ **VSCode detection** (open in the editor):
93
+ ```js
94
+ const { execFile } = require('node:child_process');
95
+ if (process.env.TERM_PROGRAM === 'vscode' || process.env.VSCODE_PID !== undefined) {
96
+ execFile('code', [indexHtmlPath]); // path is a discrete arg, not concatenated
97
+ }
98
+ ```
99
+
100
+ **System default browser** (for all other environments) — pass the path as an
101
+ arg-array element to the platform opener:
102
+ - **Windows:** `execFile('cmd', ['/c', 'start', '', indexHtmlPath])`
103
+ - **macOS:** `execFile('open', [indexHtmlPath])`
104
+ - **Linux:** `execFile('xdg-open', [indexHtmlPath])`
105
+
106
+ Report the output path to the user regardless of whether the browser opens:
107
+ ```
108
+ Knowledge Atlas generated: <projectRoot>/_bmad-output/knowledge-site/index.html
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Gitignore policy
114
+
115
+ The `_bmad-output/knowledge-site/` directory is automatically gitignored when BMAD installs into a project (via `ensureKnowledgeSiteIgnored`). If it is not already ignored, add the following line to `.gitignore`:
116
+
117
+ ```
118
+ _bmad-output/knowledge-site/
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Notes
124
+
125
+ - **Offline by construction:** The generated `index.html` is fully self-contained — no external URLs, no CDN links, no web fonts. It can be opened from a local filesystem in any browser.
126
+ - **Deterministic output:** Pin `SOURCE_DATE_EPOCH` (Unix seconds) to get byte-identical output across runs:
127
+ ```bash
128
+ SOURCE_DATE_EPOCH=1700000000 node atlas.cjs "<projectRoot>"
129
+ ```
130
+ - **No per-project install:** The engine (`atlas.cjs`) is pre-bundled in `ma-agents`. Consuming projects never run `npm install` for the Atlas engine.
@@ -0,0 +1,3 @@
1
+ type: skill
2
+ name: bmad-knowledge
3
+ module: ma-skills
@@ -60,3 +60,4 @@ ma-skills,4-implementation,Close Sprint,close-sprint,,skill:close-sprint,close-s
60
60
  ma-skills,4-implementation,Prioritize Backlog,prioritize-backlog,,skill:prioritize-backlog,prioritize-backlog,false,bmm-sm,,"Reprioritize backlog items using multiple criteria -- severity, business value, dependencies, type, age.",_bmad-output/implementation-artifacts,"backlog",
61
61
  ma-skills,4-implementation,Project Context Expansion,project-context-expansion,,skill:project-context-expansion,project-context-expansion,false,bmm-sm,,"Post-retrospective companion to update project-context.md with new rules.",_bmad-output,"project context",
62
62
  ma-skills,4-implementation,Requirements Quality Audit,sqa-requirements-quality,,skill:sqa-requirements-quality,sqa-requirements-quality,false,bmm-qa,,"Evaluate project requirements against 14 quality criteria — produces a per-requirement audit table, missing-elements section, and overall quality score.",_bmad-output,"quality report",
63
+ ma-skills,anytime,Knowledge Atlas,bmad-knowledge,,skill:bmad-knowledge,bmad-knowledge,false,bmm-sm,,"Generate a self-contained Knowledge Atlas HTML site from project planning and implementation artifacts.",_bmad-output/knowledge-site,"knowledge site",
@@ -37,7 +37,7 @@
37
37
  "name": "ma-skills",
38
38
  "source": "./",
39
39
  "description": "ma-agents extension module providing enterprise SDLC personas and operational workflow skills.",
40
- "version": "3.14.0",
40
+ "version": "3.15.0-beta.0",
41
41
  "author": {
42
42
  "name": "Alon Mayaffit"
43
43
  },
@@ -102,7 +102,8 @@
102
102
  "./skills/prioritize-backlog",
103
103
  "./skills/project-context-expansion",
104
104
  "./skills/remove-from-sprint",
105
- "./skills/sprint-status-view"
105
+ "./skills/sprint-status-view",
106
+ "./skills/bmad-knowledge"
106
107
  ]
107
108
  }
108
109
  ]
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: bmad-knowledge
3
+ description: Generate a self-contained Knowledge Atlas HTML site from project planning and implementation artifacts
4
+ type: skill
5
+ triggers:
6
+ - "knowledge atlas"
7
+ - "generate knowledge site"
8
+ - "bmad-knowledge"
9
+ ---
10
+
11
+ # Knowledge Atlas Skill
12
+
13
+ Generate a self-contained, offline-ready Knowledge Atlas HTML site from the project's `_bmad-output` planning and implementation artifacts. No network access is required at generation or view time.
14
+
15
+ ## Prerequisites
16
+
17
+ - The project must have a `_bmad-output/` directory (created by BMAD install).
18
+ - `ma-agents` must be installed (globally via `npx ma-agents` or as a local dependency).
19
+ - Node.js >= 18 must be available.
20
+
21
+ ---
22
+
23
+ ## Workflow
24
+
25
+ ### Step 1 — Resolve the project root
26
+
27
+ The project root is the directory containing `_bmad-output/`. Locate it by walking up from the current working directory until `_bmad-output/` is found, or use the directory the agent is operating in.
28
+
29
+ ```
30
+ projectRoot = <directory containing _bmad-output/>
31
+ bmadOutputDir = <projectRoot>/_bmad-output
32
+ outputSite = <projectRoot>/_bmad-output/knowledge-site/index.html
33
+ ```
34
+
35
+ ### Step 2 — Locate the engine bundle
36
+
37
+ The Knowledge Atlas engine is a pre-bundled CJS file committed inside the `ma-agents` package. Resolve it in this order:
38
+
39
+ 1. **Installed package resolution (preferred):** Use Node.js module resolution to locate the bundle:
40
+ ```js
41
+ require.resolve('ma-agents/lib/knowledge-atlas/dist/atlas.cjs')
42
+ ```
43
+ This works when `ma-agents` is installed as a dependency or globally via `npx`.
44
+
45
+ 2. **Dev-local fallback:** If the skill is being run from within the `ma-agents` repo itself (e.g., during development), use a path relative to the skill file:
46
+ ```
47
+ <skill_dir>/../../../../lib/knowledge-atlas/dist/atlas.cjs
48
+ ```
49
+ where `<skill_dir>` is the directory containing this SKILL.md.
50
+
51
+ 3. If neither path resolves to an existing file, abort with:
52
+ ```
53
+ ERROR: Cannot locate atlas.cjs. Ensure ma-agents is installed:
54
+ npm install -g ma-agents
55
+ # or: npm install --save-dev ma-agents
56
+ ```
57
+
58
+ ### Step 3 — Run the engine
59
+
60
+ Execute the bundled engine as a Node.js subprocess. Pass `atlasPath` and
61
+ `projectRoot` as ARGUMENT-ARRAY elements (never interpolate them into a shell
62
+ string) so paths containing spaces, quotes, or shell metacharacters cannot be
63
+ misparsed or injected:
64
+
65
+ ```js
66
+ const { spawnSync } = require('node:child_process');
67
+ const res = spawnSync(process.execPath, [atlasPath, projectRoot], {
68
+ encoding: 'utf-8',
69
+ // No `shell: true` — args go directly to the OS exec, not a shell.
70
+ });
71
+ if (res.status !== 0) {
72
+ // Report res.stderr and abort.
73
+ throw new Error(`atlas.cjs failed (exit ${res.status}): ${res.stderr}`);
74
+ }
75
+ const indexHtmlPath = res.stdout.trim(); // engine prints the index.html path
76
+ ```
77
+
78
+ - The engine writes `_bmad-output/knowledge-site/index.html`.
79
+ - It prints the path to `stdout` on success.
80
+ - It exits with code 0 on success, non-zero on failure (error on stderr).
81
+ - It never modifies any source file — output is isolated to `_bmad-output/knowledge-site/`.
82
+
83
+ If the engine exits non-zero, report the stderr output and abort.
84
+
85
+ ### Step 4 — Open the generated site
86
+
87
+ After successful generation, open `_bmad-output/knowledge-site/index.html` using
88
+ the appropriate method for the current environment. Use `execFile`/`spawn` with
89
+ an ARGUMENT ARRAY — never build a shell command string with the path
90
+ interpolated, which would be an injection vector:
91
+
92
+ **VSCode detection** (open in the editor):
93
+ ```js
94
+ const { execFile } = require('node:child_process');
95
+ if (process.env.TERM_PROGRAM === 'vscode' || process.env.VSCODE_PID !== undefined) {
96
+ execFile('code', [indexHtmlPath]); // path is a discrete arg, not concatenated
97
+ }
98
+ ```
99
+
100
+ **System default browser** (for all other environments) — pass the path as an
101
+ arg-array element to the platform opener:
102
+ - **Windows:** `execFile('cmd', ['/c', 'start', '', indexHtmlPath])`
103
+ - **macOS:** `execFile('open', [indexHtmlPath])`
104
+ - **Linux:** `execFile('xdg-open', [indexHtmlPath])`
105
+
106
+ Report the output path to the user regardless of whether the browser opens:
107
+ ```
108
+ Knowledge Atlas generated: <projectRoot>/_bmad-output/knowledge-site/index.html
109
+ ```
110
+
111
+ ---
112
+
113
+ ## Gitignore policy
114
+
115
+ The `_bmad-output/knowledge-site/` directory is automatically gitignored when BMAD installs into a project (via `ensureKnowledgeSiteIgnored`). If it is not already ignored, add the following line to `.gitignore`:
116
+
117
+ ```
118
+ _bmad-output/knowledge-site/
119
+ ```
120
+
121
+ ---
122
+
123
+ ## Notes
124
+
125
+ - **Offline by construction:** The generated `index.html` is fully self-contained — no external URLs, no CDN links, no web fonts. It can be opened from a local filesystem in any browser.
126
+ - **Deterministic output:** Pin `SOURCE_DATE_EPOCH` (Unix seconds) to get byte-identical output across runs:
127
+ ```bash
128
+ SOURCE_DATE_EPOCH=1700000000 node atlas.cjs "<projectRoot>"
129
+ ```
130
+ - **No per-project install:** The engine (`atlas.cjs`) is pre-bundled in `ma-agents`. Consuming projects never run `npm install` for the Atlas engine.
@@ -0,0 +1,3 @@
1
+ type: skill
2
+ name: bmad-knowledge
3
+ module: ma-skills
@@ -60,3 +60,4 @@ ma-skills,4-implementation,Close Sprint,close-sprint,,skill:close-sprint,close-s
60
60
  ma-skills,4-implementation,Prioritize Backlog,prioritize-backlog,,skill:prioritize-backlog,prioritize-backlog,false,bmm-sm,,"Reprioritize backlog items using multiple criteria -- severity, business value, dependencies, type, age.",_bmad-output/implementation-artifacts,"backlog",
61
61
  ma-skills,4-implementation,Project Context Expansion,project-context-expansion,,skill:project-context-expansion,project-context-expansion,false,bmm-sm,,"Post-retrospective companion to update project-context.md with new rules.",_bmad-output,"project context",
62
62
  ma-skills,4-implementation,Requirements Quality Audit,sqa-requirements-quality,,skill:sqa-requirements-quality,sqa-requirements-quality,false,bmm-qa,,"Evaluate project requirements against 14 quality criteria — produces a per-requirement audit table, missing-elements section, and overall quality score.",_bmad-output,"quality report",
63
+ ma-skills,anytime,Knowledge Atlas,bmad-knowledge,,skill:bmad-knowledge,bmad-knowledge,false,bmm-sm,,"Generate a self-contained Knowledge Atlas HTML site from project planning and implementation artifacts.",_bmad-output/knowledge-site,"knowledge site",
package/lib/bmad.js CHANGED
@@ -307,6 +307,21 @@ function ensurePluginStageGitignoredForProject(projectRoot) {
307
307
  );
308
308
  }
309
309
  }
310
+
311
+ // Story 29.1 — ensure the Knowledge Atlas site output directory is gitignored.
312
+ // `_bmad-output/knowledge-site/` is transient (regenerated on each skill run)
313
+ // and must not be committed. `_bmad-output/` itself remains tracked.
314
+ if (typeof installer.ensureKnowledgeSiteIgnored === 'function') {
315
+ try {
316
+ installer.ensureKnowledgeSiteIgnored(projectRoot);
317
+ } catch (err) {
318
+ console.warn(
319
+ chalk.yellow(
320
+ ` Warning: could not update ${path.join(projectRoot, '.gitignore')} with knowledge-site/ entry: ${err.message}`
321
+ )
322
+ );
323
+ }
324
+ }
310
325
  }
311
326
 
312
327
  /**
package/lib/installer.js CHANGED
@@ -487,6 +487,93 @@ function ensureBmadDirIgnored(projectRoot) {
487
487
  );
488
488
  }
489
489
 
490
+ // Story 29.1 — Knowledge Atlas site output is generated into
491
+ // `_bmad-output/knowledge-site/` on every skill invocation. This directory is
492
+ // transient (regenerated each run) and should never be committed. It is gitignored
493
+ // by the same append-only, idempotent policy as the plugin stage and _bmad/ tree.
494
+ //
495
+ // IMPORTANT: `_bmad-output/` itself is intentionally kept tracked (project knowledge
496
+ // artifacts live there). Only the nested `knowledge-site/` subdirectory is ignored.
497
+ const KNOWLEDGE_SITE_DIR_NAME = '_bmad-output/knowledge-site';
498
+ const KNOWLEDGE_SITE_PATTERNS = [
499
+ KNOWLEDGE_SITE_DIR_NAME, // _bmad-output/knowledge-site
500
+ `${KNOWLEDGE_SITE_DIR_NAME}/`, // _bmad-output/knowledge-site/
501
+ `/${KNOWLEDGE_SITE_DIR_NAME}`, // /_bmad-output/knowledge-site
502
+ `/${KNOWLEDGE_SITE_DIR_NAME}/`, // /_bmad-output/knowledge-site/
503
+ ];
504
+ const KNOWLEDGE_SITE_CANONICAL_ENTRY = `${KNOWLEDGE_SITE_DIR_NAME}/`;
505
+
506
+ /**
507
+ * Ensure `_bmad-output/knowledge-site/` is present in the target project's
508
+ * `.gitignore`. Mirrors the append-only, idempotent, EOL-preserving contract
509
+ * of `ensurePluginStageIgnored` and `ensureBmadDirIgnored`.
510
+ *
511
+ * - If `.gitignore` is absent, create it with the single canonical entry.
512
+ * - If any active (non-comment) line already matches any KNOWLEDGE_SITE_PATTERNS
513
+ * variant, do nothing (idempotent).
514
+ * - Otherwise, append `KNOWLEDGE_SITE_CANONICAL_ENTRY` preserving the file's
515
+ * existing EOL style.
516
+ *
517
+ * Non-fatal: EACCES / EROFS are swallowed by the caller in lib/bmad.js so an
518
+ * unwritable .gitignore never aborts the install. This function throws on other
519
+ * I/O errors so the caller can decide whether to swallow.
520
+ *
521
+ * Defensive: no-op on falsy / non-string projectRoot.
522
+ *
523
+ * @param {string} projectRoot - Absolute path to the target project root.
524
+ */
525
+ function ensureKnowledgeSiteIgnored(projectRoot) {
526
+ if (typeof projectRoot !== 'string' || projectRoot.length === 0) {
527
+ return;
528
+ }
529
+
530
+ const gitignorePath = path.join(projectRoot, '.gitignore');
531
+
532
+ let content = '';
533
+ let fileExists = true;
534
+ try {
535
+ content = fs.readFileSync(gitignorePath, 'utf-8');
536
+ } catch (err) {
537
+ if (err.code !== 'ENOENT') throw err;
538
+ fileExists = false;
539
+ }
540
+
541
+ if (fileExists) {
542
+ const alreadyPresent = content.split(/\r?\n/).some(rawLine => {
543
+ const line = rawLine.trim();
544
+ if (!line || line.startsWith('#')) return false; // skip blanks & comments
545
+ // Exact match on any canonical variant.
546
+ if (KNOWLEDGE_SITE_PATTERNS.includes(line)) return true;
547
+ // Broader coverage: if a parent entry (`_bmad-output` / `_bmad-output/`,
548
+ // optionally anchored with a leading slash) is already ignored, then the
549
+ // nested `knowledge-site/` is implicitly covered — appending our entry
550
+ // would be redundant. Match the directory form precisely so we never
551
+ // mistake an unrelated entry like `_bmad-output-archive` for a parent.
552
+ const normalized = line.replace(/^\//, '').replace(/\/$/, '');
553
+ if (normalized === '_bmad-output') return true;
554
+ return false;
555
+ });
556
+ if (alreadyPresent) return; // idempotent no-op
557
+ }
558
+
559
+ // Preserve the file's existing line-ending style; default to LF for new files.
560
+ const usesCrlf = fileExists && /\r\n/.test(content);
561
+ const eol = usesCrlf ? '\r\n' : '\n';
562
+
563
+ let next = content;
564
+ if (next && !next.endsWith('\n') && !next.endsWith('\r\n')) {
565
+ next += eol; // ensure the append lands on its own line
566
+ }
567
+ next += KNOWLEDGE_SITE_CANONICAL_ENTRY + eol;
568
+
569
+ fs.writeFileSync(gitignorePath, next, 'utf-8');
570
+ console.log(
571
+ chalk.green(
572
+ `${KNOWLEDGE_SITE_CANONICAL_ENTRY} added to .gitignore (Knowledge Atlas site output — regenerated on each run)`
573
+ )
574
+ );
575
+ }
576
+
490
577
  function ensureManifest(installPath, agentId, scope) {
491
578
  let manifest = readManifest(installPath);
492
579
  if (!manifest) {
@@ -2260,6 +2347,7 @@ module.exports = {
2260
2347
  ensureBmadOutputTracked,
2261
2348
  ensurePluginStageIgnored,
2262
2349
  ensureBmadDirIgnored,
2350
+ ensureKnowledgeSiteIgnored,
2263
2351
  reconcileAgentsSharedSkills,
2264
2352
  getAgentsSharedSkillAgentIds,
2265
2353
  generateSkillsManifest,