ma-agents 3.17.0-beta.4 → 3.17.1

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.
package/README.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  A universal NPX tool to install AI coding agent skills. Write skills once, install them across Claude Code, Gemini, Copilot, Cline, Cursor, Kilocode, and Roo Code.
4
4
 
5
+ ## What's New in v3.17.1
6
+
7
+ - **ma-agents now show up in the Copilot agent picker** — the DevOps (Amit),
8
+ Cyber (Yael), SQA (Gadi), and SRE (Alex) personas now appear in the GitHub
9
+ Copilot agent-picker dropdown in VS Code alongside the core BMAD agents.
10
+ They installed correctly before but were missing the `customize.toml`
11
+ `[agent]` marker the installer uses to register a persona in the picker;
12
+ each now ships one.
13
+
5
14
  ## What's New in v3.17.0
6
15
 
7
16
  - **BMAD-METHOD v6.10.0** — bundled bmad-method updated to v6.10.0. The
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents Cyber agent (Yael).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Yael"
14
+ title = "Cyber Analyst"
15
+
16
+ icon = "🛡️"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Specialized Cyber Security Analyst focused on vulnerability assessment, threat modeling, and system hardening."
23
+ identity = "Cyber security expert with deep knowledge of OWASP Top 10, CWE/SANS Top 25, and industry-standard hardening guides (CIS, NIST). Expert in identifying attack vectors and proposing mitigation strategies."
24
+ communication_style = "Analytical, precise, and cautious. Focuses on risk assessment and practical security improvements. Uses professional security terminology naturally."
25
+
26
+ principles = [
27
+ "Security is a process, not a product.",
28
+ "Favor Defense in Depth.",
29
+ "Prioritize mitigations based on risk (Likelihood x Impact).",
30
+ "Ensure visibility and auditing are never overlooked.",
31
+ ]
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents DevOps agent (Amit).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Amit"
14
+ title = "DevOps Agent"
15
+
16
+ icon = "🏗️"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "DevOps Engineer specializing in CI/CD pipeline automation, Infrastructure as Code (Terraform, Ansible), and developer experience."
23
+ identity = "DevOps veteran with extensive experience in cloud-native technologies (AWS, GCP, Azure). Proponent of the \"shift-left\" philosophy and GitOps practices."
24
+ communication_style = "Collaborative, efficiency-minded, and tech-forward. Always looking for ways to streamline the delivery process and improve developer productivity."
25
+
26
+ principles = [
27
+ "Version control everything.",
28
+ "Immutable infrastructure is better.",
29
+ "Continuous improvement of the feedback loop.",
30
+ "Treat infrastructure as code, and code as infrastructure.",
31
+ ]
@@ -0,0 +1,32 @@
1
+ # Persona + agent metadata for the ma-agents SQA agent (Gadi).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Gadi"
14
+ title = "Software Quality Assurance & Standards Expert"
15
+
16
+ icon = "🔍"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Software Quality Assurance Engineer and Defense Standards Expert responsible for verifying project quality across all dimensions and producing rigorous, standards-compliant documentation."
23
+ identity = "Experienced quality professional with deep expertise in SQA auditing, IEEE/ISO/IEC standards compliance, and MIL-STD-498 documentation. Methodical, thorough, and evidence-driven."
24
+ communication_style = "Clear, precise, and structured for SQA work. Formal and authoritative for MIL-STD-498 documentation. Always presents findings as actionable reports with severity levels."
25
+
26
+ principles = [
27
+ "Quality is everyone's responsibility but the SQA auditor's job to verify.",
28
+ "Traceability from requirement to code is non-negotiable.",
29
+ "Process compliance prevents defects.",
30
+ "Evidence matters more than opinions.",
31
+ "Every section of a DID must fulfill its defined Data Item Description.",
32
+ ]
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents SRE agent (Alex).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Alex"
14
+ title = "SRE Agent"
15
+
16
+ icon = "🩺"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Site Reliability Engineer specializing in system availability, reliability, and performance optimization."
23
+ identity = "Seasoned SRE with expertise in Kubernetes, monitoring (Prometheus/Grafana), and incident management. Focuses on automation and reducing toil."
24
+ communication_style = "Calm, data-driven, and systematic. Prioritizes uptime and stability. Asks about SLOs and error budgets."
25
+
26
+ principles = [
27
+ "Automation over manual effort.",
28
+ "Monitor everything that matters.",
29
+ "Blame-free post-mortems.",
30
+ "Simplicity is a prerequisite for reliability.",
31
+ ]
@@ -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.17.0-beta.4",
40
+ "version": "3.17.1",
41
41
  "author": {
42
42
  "name": "Alon Mayaffit"
43
43
  },
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents Cyber agent (Yael).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Yael"
14
+ title = "Cyber Analyst"
15
+
16
+ icon = "🛡️"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Specialized Cyber Security Analyst focused on vulnerability assessment, threat modeling, and system hardening."
23
+ identity = "Cyber security expert with deep knowledge of OWASP Top 10, CWE/SANS Top 25, and industry-standard hardening guides (CIS, NIST). Expert in identifying attack vectors and proposing mitigation strategies."
24
+ communication_style = "Analytical, precise, and cautious. Focuses on risk assessment and practical security improvements. Uses professional security terminology naturally."
25
+
26
+ principles = [
27
+ "Security is a process, not a product.",
28
+ "Favor Defense in Depth.",
29
+ "Prioritize mitigations based on risk (Likelihood x Impact).",
30
+ "Ensure visibility and auditing are never overlooked.",
31
+ ]
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents DevOps agent (Amit).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Amit"
14
+ title = "DevOps Agent"
15
+
16
+ icon = "🏗️"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "DevOps Engineer specializing in CI/CD pipeline automation, Infrastructure as Code (Terraform, Ansible), and developer experience."
23
+ identity = "DevOps veteran with extensive experience in cloud-native technologies (AWS, GCP, Azure). Proponent of the \"shift-left\" philosophy and GitOps practices."
24
+ communication_style = "Collaborative, efficiency-minded, and tech-forward. Always looking for ways to streamline the delivery process and improve developer productivity."
25
+
26
+ principles = [
27
+ "Version control everything.",
28
+ "Immutable infrastructure is better.",
29
+ "Continuous improvement of the feedback loop.",
30
+ "Treat infrastructure as code, and code as infrastructure.",
31
+ ]
@@ -0,0 +1,32 @@
1
+ # Persona + agent metadata for the ma-agents SQA agent (Gadi).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Gadi"
14
+ title = "Software Quality Assurance & Standards Expert"
15
+
16
+ icon = "🔍"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Software Quality Assurance Engineer and Defense Standards Expert responsible for verifying project quality across all dimensions and producing rigorous, standards-compliant documentation."
23
+ identity = "Experienced quality professional with deep expertise in SQA auditing, IEEE/ISO/IEC standards compliance, and MIL-STD-498 documentation. Methodical, thorough, and evidence-driven."
24
+ communication_style = "Clear, precise, and structured for SQA work. Formal and authoritative for MIL-STD-498 documentation. Always presents findings as actionable reports with severity levels."
25
+
26
+ principles = [
27
+ "Quality is everyone's responsibility but the SQA auditor's job to verify.",
28
+ "Traceability from requirement to code is non-negotiable.",
29
+ "Process compliance prevents defects.",
30
+ "Evidence matters more than opinions.",
31
+ "Every section of a DID must fulfill its defined Data Item Description.",
32
+ ]
@@ -0,0 +1,31 @@
1
+ # Persona + agent metadata for the ma-agents SRE agent (Alex).
2
+ #
3
+ # The presence of this `[agent]` section is what marks the skill as an AGENT
4
+ # persona (not a plain skill) to BMAD's installer. Agent skills are emitted as
5
+ # entries in the GitHub Copilot agent picker (`.github/agents/<id>.agent.md`)
6
+ # and the equivalent surfaces for other IDEs; plain skills are not. Without this
7
+ # file the DevOps/Cyber/SQA/SRE personas install correctly but never appear in
8
+ # the Copilot agent-picker dropdown alongside the core BMAD agents.
9
+ #
10
+ # Keep this in sync with bmad-skill-manifest.yaml (the runtime persona source).
11
+
12
+ [agent]
13
+ name = "Alex"
14
+ title = "SRE Agent"
15
+
16
+ icon = "🩺"
17
+
18
+ persistent_facts = [
19
+ "file:{project-root}/**/project-context.md",
20
+ ]
21
+
22
+ role = "Site Reliability Engineer specializing in system availability, reliability, and performance optimization."
23
+ identity = "Seasoned SRE with expertise in Kubernetes, monitoring (Prometheus/Grafana), and incident management. Focuses on automation and reducing toil."
24
+ communication_style = "Calm, data-driven, and systematic. Prioritizes uptime and stability. Asks about SLOs and error budgets."
25
+
26
+ principles = [
27
+ "Automation over manual effort.",
28
+ "Monitor everything that matters.",
29
+ "Blame-free post-mortems.",
30
+ "Simplicity is a prerequisite for reliability.",
31
+ ]
package/lib/bmad.js CHANGED
@@ -2089,12 +2089,27 @@ function correctArtifactPath(value, outputFolder) {
2089
2089
  return `${prefix}${outputFolder}${suffix}`;
2090
2090
  }
2091
2091
 
2092
+ /**
2093
+ * Strip a leading `{project-root}/` token (and any interior `{project-root}`
2094
+ * fragments) from an artifact path value, returning the project-relative path.
2095
+ * Mirrors upstream's directory-creation stripping so the relative path we derive
2096
+ * matches the directory upstream actually created on disk.
2097
+ */
2098
+ function toProjectRelativePath(value) {
2099
+ if (typeof value !== 'string') return '';
2100
+ return value.replace(/^\{project-root\}\/?/, '').replaceAll('{project-root}', '');
2101
+ }
2102
+
2092
2103
  /**
2093
2104
  * Rewrite contaminated artifact paths inside `_bmad/config.toml`. Returns the
2094
2105
  * number of lines changed. Uses line-based editing (no TOML dependency) so we
2095
2106
  * preserve comments, ordering, and formatting exactly.
2107
+ *
2108
+ * When an `orphans` Set is supplied, the project-relative path of each rewritten
2109
+ * (contaminated) value is recorded so the caller can prune the empty directory
2110
+ * upstream physically created at that stale location.
2096
2111
  */
2097
- function normalizeTomlOutputFolders(tomlPath, outputFolder) {
2112
+ function normalizeTomlOutputFolders(tomlPath, outputFolder, orphans) {
2098
2113
  if (!fs.existsSync(tomlPath)) return 0;
2099
2114
  let raw;
2100
2115
  try {
@@ -2127,6 +2142,7 @@ function normalizeTomlOutputFolders(tomlPath, outputFolder) {
2127
2142
  if (corrected === null) continue;
2128
2143
  lines[i] = `${indent}${key}${eq}"${corrected}"${trailer}`;
2129
2144
  changed++;
2145
+ if (orphans) orphans.add(toProjectRelativePath(val));
2130
2146
  }
2131
2147
 
2132
2148
  if (changed > 0) {
@@ -2138,8 +2154,12 @@ function normalizeTomlOutputFolders(tomlPath, outputFolder) {
2138
2154
  /**
2139
2155
  * Rewrite contaminated artifact paths inside a per-module `_bmad/<mod>/config.yaml`.
2140
2156
  * Returns the number of keys changed. Uses js-yaml so we keep schema fidelity.
2157
+ *
2158
+ * When an `orphans` Set is supplied, the project-relative path of each rewritten
2159
+ * (contaminated) value is recorded so the caller can prune the empty directory
2160
+ * upstream physically created at that stale location.
2141
2161
  */
2142
- function normalizeYamlOutputFolders(yamlPath, outputFolder) {
2162
+ function normalizeYamlOutputFolders(yamlPath, outputFolder, orphans) {
2143
2163
  if (!fs.existsSync(yamlPath)) return 0;
2144
2164
  let raw;
2145
2165
  try {
@@ -2160,6 +2180,7 @@ function normalizeYamlOutputFolders(yamlPath, outputFolder) {
2160
2180
  if (typeof doc[key] !== 'string') continue;
2161
2181
  const corrected = correctArtifactPath(doc[key], outputFolder);
2162
2182
  if (corrected === null) continue;
2183
+ if (orphans) orphans.add(toProjectRelativePath(doc[key]));
2163
2184
  doc[key] = corrected;
2164
2185
  changed++;
2165
2186
  }
@@ -2182,11 +2203,103 @@ function normalizeYamlOutputFolders(yamlPath, outputFolder) {
2182
2203
  return changed;
2183
2204
  }
2184
2205
 
2206
+ /**
2207
+ * Return true when the subtree rooted at `dir` contains zero regular files
2208
+ * (only empty directories, at any depth). Anything that is not a directory —
2209
+ * a file, symlink, socket, etc. — makes the subtree non-empty and therefore
2210
+ * unsafe to remove. Missing/unreadable directories are reported non-empty so we
2211
+ * never delete something we could not inspect.
2212
+ */
2213
+ function dirIsFileless(dir) {
2214
+ let entries;
2215
+ try {
2216
+ entries = fs.readdirSync(dir, { withFileTypes: true });
2217
+ } catch {
2218
+ return false;
2219
+ }
2220
+ for (const entry of entries) {
2221
+ if (!entry.isDirectory()) return false; // a file or non-dir entry
2222
+ if (!dirIsFileless(path.join(dir, entry.name))) return false;
2223
+ }
2224
+ return true;
2225
+ }
2226
+
2227
+ /**
2228
+ * Bug 27.14 cleanup — remove the empty directories upstream physically created
2229
+ * at contaminated artifact locations before we repaired the config. Each entry
2230
+ * in `orphanRelPaths` is a project-relative path that WAS a contaminated
2231
+ * artifact value (e.g. `skills/planning-artifacts`).
2232
+ *
2233
+ * Safety rails:
2234
+ * - Only removes a directory whose entire subtree is fileless — user content
2235
+ * is never deleted.
2236
+ * - Never removes the canonical output folder, and never touches a path whose
2237
+ * top segment already equals it.
2238
+ * - Stays strictly inside `projectRoot`.
2239
+ * After removing an orphan, empty ancestor directories are pruned up to (but not
2240
+ * including) the project root, so the stray `skills/` container disappears once
2241
+ * its last orphaned child is gone.
2242
+ *
2243
+ * @returns {number} Number of orphaned directories removed (for tests/logging).
2244
+ */
2245
+ function pruneOrphanedArtifactDirs(projectRoot, outputFolder, orphanRelPaths) {
2246
+ const normalizedRoot = path.normalize(projectRoot);
2247
+ let removed = 0;
2248
+
2249
+ for (const rel of orphanRelPaths) {
2250
+ if (!rel) continue;
2251
+ const topSeg = rel.split(/[\\/]/).filter(Boolean)[0];
2252
+ // The stale segment must differ from the canonical output folder; if it
2253
+ // matches, the value was never really contaminated to a foreign folder.
2254
+ if (!topSeg || topSeg === outputFolder) continue;
2255
+
2256
+ const dir = path.normalize(path.join(projectRoot, rel));
2257
+ // Containment guard — must live strictly under the project root.
2258
+ if (dir === normalizedRoot || !dir.startsWith(normalizedRoot + path.sep)) continue;
2259
+ if (!fs.existsSync(dir)) continue;
2260
+ if (!dirIsFileless(dir)) continue; // never delete content
2261
+
2262
+ try {
2263
+ fs.rmSync(dir, { recursive: true, force: true });
2264
+ removed++;
2265
+ } catch {
2266
+ continue;
2267
+ }
2268
+
2269
+ // Prune now-empty ancestors up to — never including — the project root.
2270
+ // Only the canonical output folder is explicitly protected; every other
2271
+ // ancestor is fair game once it is completely empty.
2272
+ let parent = path.dirname(dir);
2273
+ while (parent !== normalizedRoot && parent.startsWith(normalizedRoot + path.sep)) {
2274
+ const isCanonicalTop =
2275
+ path.dirname(parent) === normalizedRoot && path.basename(parent) === outputFolder;
2276
+ if (isCanonicalTop) break;
2277
+ let contents;
2278
+ try {
2279
+ contents = fs.readdirSync(parent);
2280
+ } catch {
2281
+ break;
2282
+ }
2283
+ if (contents.length > 0) break;
2284
+ try {
2285
+ fs.rmdirSync(parent);
2286
+ } catch {
2287
+ break;
2288
+ }
2289
+ parent = path.dirname(parent);
2290
+ }
2291
+ }
2292
+
2293
+ return removed;
2294
+ }
2295
+
2185
2296
  /**
2186
2297
  * Bug 27.14 — post-install pass that re-points any contaminated module artifact
2187
2298
  * path at the canonical `[core] output_folder`. Reads the output folder from
2188
2299
  * `_bmad/config.toml` (the install-owned source of truth), then normalizes both
2189
- * `_bmad/config.toml` and every `_bmad/<mod>/config.yaml`.
2300
+ * `_bmad/config.toml` and every `_bmad/<mod>/config.yaml`. Finally prunes the
2301
+ * empty directories upstream created at the contaminated locations, so a clean
2302
+ * install is not littered with orphaned `skills/planning-artifacts`-style dirs.
2190
2303
  *
2191
2304
  * Idempotent and non-fatal: a second run finds nothing to change, and any I/O
2192
2305
  * error is logged and swallowed (config normalization must never abort an
@@ -2227,8 +2340,9 @@ function normalizeModuleOutputFolders(projectRoot) {
2227
2340
  if (!outputFolder) return 0; // nothing canonical to normalize against
2228
2341
 
2229
2342
  let total = 0;
2343
+ const orphans = new Set();
2230
2344
  try {
2231
- total += normalizeTomlOutputFolders(tomlPath, outputFolder);
2345
+ total += normalizeTomlOutputFolders(tomlPath, outputFolder, orphans);
2232
2346
 
2233
2347
  // Walk each `_bmad/<mod>/config.yaml`.
2234
2348
  const bmadDir = path.join(projectRoot, BMAD_DIR);
@@ -2241,7 +2355,7 @@ function normalizeModuleOutputFolders(projectRoot) {
2241
2355
  for (const entry of entries) {
2242
2356
  if (!entry.isDirectory()) continue;
2243
2357
  const cfg = path.join(bmadDir, entry.name, 'config.yaml');
2244
- total += normalizeYamlOutputFolders(cfg, outputFolder);
2358
+ total += normalizeYamlOutputFolders(cfg, outputFolder, orphans);
2245
2359
  }
2246
2360
  } catch (err) {
2247
2361
  console.warn(chalk.yellow(` Warning: output-folder normalization skipped: ${err.message}`));
@@ -2253,6 +2367,20 @@ function normalizeModuleOutputFolders(projectRoot) {
2253
2367
  ` Normalized ${total} module artifact path(s) to output folder "${outputFolder}/" (bug 27.14 work-around)`
2254
2368
  ));
2255
2369
  }
2370
+
2371
+ // Remove the empty directories upstream created at the contaminated
2372
+ // locations. Best-effort: never let cleanup failure abort the install.
2373
+ try {
2374
+ const pruned = pruneOrphanedArtifactDirs(projectRoot, outputFolder, orphans);
2375
+ if (pruned > 0) {
2376
+ console.log(chalk.green(
2377
+ ` Removed ${pruned} orphaned artifact director${pruned === 1 ? 'y' : 'ies'} left at contaminated path(s) (bug 27.14 work-around)`
2378
+ ));
2379
+ }
2380
+ } catch (err) {
2381
+ console.warn(chalk.yellow(` Warning: orphaned-directory cleanup skipped: ${err.message}`));
2382
+ }
2383
+
2256
2384
  return total;
2257
2385
  }
2258
2386
 
@@ -3290,6 +3418,8 @@ module.exports = {
3290
3418
  readCanonicalBmadConfig,
3291
3419
  normalizeModuleOutputFolders,
3292
3420
  correctArtifactPath,
3421
+ pruneOrphanedArtifactDirs,
3422
+ dirIsFileless,
3293
3423
  ensureCanonicalConfigLocation,
3294
3424
  CANONICAL_CONFIG_REL,
3295
3425
  LEGACY_MANIFEST_REL,
package/lib/diag.js CHANGED
@@ -1,86 +1,86 @@
1
- 'use strict';
2
-
3
- /**
4
- * Log-file-only diagnostics.
5
- *
6
- * When `--log` is active, bin/cli.js#setupLogging installs a sink that writes
7
- * to the log file descriptor. `diag()`/`diagError()` then emit structured
8
- * breadcrumbs to the LOG FILE ONLY — never to the user's console (the wizard's
9
- * user-facing output intentionally stays clean; e.g. a failed custom-marketplace
10
- * source shows a one-line message, not a raw stack — NFR71). Without a sink
11
- * (no `--log`), every call is a cheap no-op.
12
- *
13
- * This is how the swallowed root cause of a custom-marketplace failure (the
14
- * git/clone/resolve error behind a clean CustomMarketplaceError, the per-entry
15
- * module_definition that was missing, the FR238 zero-module trigger, etc.)
16
- * reaches the log for post-hoc diagnosis without leaking to the terminal.
17
- */
18
-
19
- let sink = null;
20
-
21
- /**
22
- * @param {((text: string) => void)|null} fn - writer for log-file output, or null to disable.
23
- */
24
- function setLogSink(fn) {
25
- sink = typeof fn === 'function' ? fn : null;
26
- }
27
-
28
- /** @returns {boolean} whether diagnostics are being captured. */
29
- function isActive() {
30
- return sink !== null;
31
- }
32
-
33
- function stamp() {
34
- // new Date() is available in the CLI runtime (this is not a workflow script).
35
- return new Date().toISOString();
36
- }
37
-
38
- function stringify(detail) {
39
- if (typeof detail === 'string') return detail;
40
- try {
41
- return JSON.stringify(detail);
42
- } catch {
43
- return String(detail);
44
- }
45
- }
46
-
47
- /**
48
- * Emit one diagnostic breadcrumb to the log file (no-op without a sink).
49
- * @param {string} label
50
- * @param {*} [detail] - string or JSON-serializable value.
51
- */
52
- function diag(label, detail) {
53
- if (!sink) return;
54
- let line = `[diag ${stamp()}] ${label}`;
55
- if (detail !== undefined) line += `: ${stringify(detail)}`;
56
- try {
57
- sink(line + '\n');
58
- } catch {
59
- /* never let diagnostics break the install */
60
- }
61
- }
62
-
63
- /**
64
- * Emit an error — including its `stack` AND any wrapped `cause` (message +
65
- * stack) — to the log file. This is the crucial bit for custom-marketplace
66
- * failures, whose user-facing message deliberately hides the upstream cause.
67
- * @param {string} label
68
- * @param {Error|*} err
69
- */
70
- function diagError(label, err) {
71
- if (!sink || !err) return;
72
- const parts = [`[diag ${stamp()}] ${label}: ${err.message || String(err)}`];
73
- if (err.stack) parts.push(` stack: ${err.stack}`);
74
- if (err.cause) {
75
- const c = err.cause;
76
- parts.push(` cause: ${(c && c.message) || String(c)}`);
77
- if (c && c.stack) parts.push(` cause.stack: ${c.stack}`);
78
- }
79
- try {
80
- sink(parts.join('\n') + '\n');
81
- } catch {
82
- /* never let diagnostics break the install */
83
- }
84
- }
85
-
86
- module.exports = { setLogSink, isActive, diag, diagError };
1
+ 'use strict';
2
+
3
+ /**
4
+ * Log-file-only diagnostics.
5
+ *
6
+ * When `--log` is active, bin/cli.js#setupLogging installs a sink that writes
7
+ * to the log file descriptor. `diag()`/`diagError()` then emit structured
8
+ * breadcrumbs to the LOG FILE ONLY — never to the user's console (the wizard's
9
+ * user-facing output intentionally stays clean; e.g. a failed custom-marketplace
10
+ * source shows a one-line message, not a raw stack — NFR71). Without a sink
11
+ * (no `--log`), every call is a cheap no-op.
12
+ *
13
+ * This is how the swallowed root cause of a custom-marketplace failure (the
14
+ * git/clone/resolve error behind a clean CustomMarketplaceError, the per-entry
15
+ * module_definition that was missing, the FR238 zero-module trigger, etc.)
16
+ * reaches the log for post-hoc diagnosis without leaking to the terminal.
17
+ */
18
+
19
+ let sink = null;
20
+
21
+ /**
22
+ * @param {((text: string) => void)|null} fn - writer for log-file output, or null to disable.
23
+ */
24
+ function setLogSink(fn) {
25
+ sink = typeof fn === 'function' ? fn : null;
26
+ }
27
+
28
+ /** @returns {boolean} whether diagnostics are being captured. */
29
+ function isActive() {
30
+ return sink !== null;
31
+ }
32
+
33
+ function stamp() {
34
+ // new Date() is available in the CLI runtime (this is not a workflow script).
35
+ return new Date().toISOString();
36
+ }
37
+
38
+ function stringify(detail) {
39
+ if (typeof detail === 'string') return detail;
40
+ try {
41
+ return JSON.stringify(detail);
42
+ } catch {
43
+ return String(detail);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Emit one diagnostic breadcrumb to the log file (no-op without a sink).
49
+ * @param {string} label
50
+ * @param {*} [detail] - string or JSON-serializable value.
51
+ */
52
+ function diag(label, detail) {
53
+ if (!sink) return;
54
+ let line = `[diag ${stamp()}] ${label}`;
55
+ if (detail !== undefined) line += `: ${stringify(detail)}`;
56
+ try {
57
+ sink(line + '\n');
58
+ } catch {
59
+ /* never let diagnostics break the install */
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Emit an error — including its `stack` AND any wrapped `cause` (message +
65
+ * stack) — to the log file. This is the crucial bit for custom-marketplace
66
+ * failures, whose user-facing message deliberately hides the upstream cause.
67
+ * @param {string} label
68
+ * @param {Error|*} err
69
+ */
70
+ function diagError(label, err) {
71
+ if (!sink || !err) return;
72
+ const parts = [`[diag ${stamp()}] ${label}: ${err.message || String(err)}`];
73
+ if (err.stack) parts.push(` stack: ${err.stack}`);
74
+ if (err.cause) {
75
+ const c = err.cause;
76
+ parts.push(` cause: ${(c && c.message) || String(c)}`);
77
+ if (c && c.stack) parts.push(` cause.stack: ${c.stack}`);
78
+ }
79
+ try {
80
+ sink(parts.join('\n') + '\n');
81
+ } catch {
82
+ /* never let diagnostics break the install */
83
+ }
84
+ }
85
+
86
+ module.exports = { setLogSink, isActive, diag, diagError };
@@ -1,25 +1,25 @@
1
- ## Git Workflow (ALL file-changing tasks)
2
-
3
- These rules apply to EVERY task that modifies a tracked file. There is no
4
- "small fix exemption" — a one-line edit follows the same workflow as a feature.
5
-
6
- - **Worktree first.** Before changing any file, create a fresh isolated worktree
7
- on a new feature branch: `git worktree add ../<project>-<branch> -b <branch>`.
8
- The scripted form is `skills/git-workflow-skill/scripts/start-feature.sh`. All
9
- file-writing happens inside that worktree — never in the main working tree.
10
- - **Never commit directly to the trunk.** Do NOT commit to `main`, `dev`,
11
- `master`, or whatever the trunk branch is. Commits land only on your feature
12
- branch inside the worktree.
13
- - **Conventional Commits.** Every commit message uses a Conventional Commits
14
- prefix. The allowed prefixes are: `feat`, `fix`, `chore`, `docs`, `refactor`,
15
- `test`, `ci`.
16
- - **PR is the only path into the trunk.** Integrate exclusively by opening a pull
17
- request with `gh pr create`. Never merge directly and never auto-merge a PR
18
- without explicit human approval.
19
- - **Self-review before opening the PR.** Run the `code-review` skill on your own
20
- changes and address its findings before you open the PR.
21
- - **Clean up after merge.** Once the PR is merged, remove the worktree with
22
- `git worktree remove` and delete the feature branch.
23
-
24
- Full procedure: see `skills/git-workflow-skill/SKILL.md`, and the helper scripts
25
- `scripts/start-feature.sh` / `scripts/finish-feature.sh`.
1
+ ## Git Workflow (ALL file-changing tasks)
2
+
3
+ These rules apply to EVERY task that modifies a tracked file. There is no
4
+ "small fix exemption" — a one-line edit follows the same workflow as a feature.
5
+
6
+ - **Worktree first.** Before changing any file, create a fresh isolated worktree
7
+ on a new feature branch: `git worktree add ../<project>-<branch> -b <branch>`.
8
+ The scripted form is `skills/git-workflow-skill/scripts/start-feature.sh`. All
9
+ file-writing happens inside that worktree — never in the main working tree.
10
+ - **Never commit directly to the trunk.** Do NOT commit to `main`, `dev`,
11
+ `master`, or whatever the trunk branch is. Commits land only on your feature
12
+ branch inside the worktree.
13
+ - **Conventional Commits.** Every commit message uses a Conventional Commits
14
+ prefix. The allowed prefixes are: `feat`, `fix`, `chore`, `docs`, `refactor`,
15
+ `test`, `ci`.
16
+ - **PR is the only path into the trunk.** Integrate exclusively by opening a pull
17
+ request with `gh pr create`. Never merge directly and never auto-merge a PR
18
+ without explicit human approval.
19
+ - **Self-review before opening the PR.** Run the `code-review` skill on your own
20
+ changes and address its findings before you open the PR.
21
+ - **Clean up after merge.** Once the PR is merged, remove the worktree with
22
+ `git worktree remove` and delete the feature branch.
23
+
24
+ Full procedure: see `skills/git-workflow-skill/SKILL.md`, and the helper scripts
25
+ `scripts/start-feature.sh` / `scripts/finish-feature.sh`.
@@ -1,86 +1,86 @@
1
- ## On-Prem / Local-LLM Guardrails
2
-
3
- These rules apply ONLY when this project is installed with `profile: on-prem`.
4
- They are appended to the universal block by the composer in `lib/installer.js`.
5
- Local LLMs (Nemotron, Qwen, DeepSeek, Llama-3, etc. served via vLLM, Ollama, or
6
- TGI) fail in patterns cloud LLMs rarely exhibit — the rules below pin those
7
- failure modes down explicitly. Keep these rules verbatim in every response
8
- context where tool use is possible.
9
-
10
- ### Reasoning mode: `/no_think` on planning-phase prompts
11
-
12
- Local reasoning-capable models (Nemotron-variants and similar) default to
13
- chain-of-thought reasoning that bloats planning-phase prompts with internal
14
- deliberation the operator does not need to read. Prepend the literal token
15
- `/no_think` as the first line of any planning-phase system prompt or user turn
16
- you compose. The token is consumed by the serving layer and suppresses the
17
- model's reasoning trace on that turn.
18
-
19
- - Planning-phase turns (PM, Architect, Tech Lead): begin the turn with
20
- `/no_think` on its own line. Reasoning-mode OFF.
21
- - Implementation-phase turns (Dev): omit `/no_think`. Reasoning-mode ON is
22
- desirable for stepwise code synthesis and debugging.
23
- - Review / QA turns: omit `/no_think` when the review benefits from explicit
24
- reasoning (root-cause analysis). Include `/no_think` for mechanical checks
25
- (lint, style, formatting).
26
-
27
- If the downstream serving layer does not recognize `/no_think`, it is a no-op
28
- text token — safe to include unconditionally on planning turns.
29
-
30
- ### No writes to `~/.claude/` or any user home directory
31
-
32
- Local LLMs frequently hallucinate paths under `~/.claude/`, `~/.cache/`,
33
- `~/Library/`, or `%APPDATA%` — imitating patterns learned from Claude Code and
34
- Cursor training data. These paths are OUTSIDE the project and cross-contaminate
35
- other projects on the same machine.
36
-
37
- - NEVER create, write, or modify files under `~/.claude/`, `~/.cache/`,
38
- `~/Library/`, `~/AppData/`, `%APPDATA%`, or any path that resolves outside
39
- the current project directory.
40
- - All project artifacts — code, configuration, logs, scratch notes, and agent
41
- state — MUST land under the current working directory (the project root) or
42
- an explicitly-named subdirectory thereof.
43
- - When a tool call appears to target a home-directory path, refuse the write
44
- and respond in text explaining the violation. Ask the user for an explicit
45
- in-project path before proceeding.
46
-
47
- ### No `str_replace_editor` or Claude Code-specific tools
48
-
49
- Local LLMs hallucinate Anthropic-proprietary tools — most commonly
50
- `str_replace_editor`, `text_editor_20241022`, and `computer_use_preview` — that
51
- do NOT exist outside the Anthropic API. Calling them against a local-LLM
52
- serving layer produces a tool-not-found error or, worse, a silent no-op.
53
-
54
- - Do NOT emit tool calls named `str_replace_editor`, `text_editor_*`,
55
- `computer_use_*`, or any other tool whose name includes `str_replace_editor`
56
- or matches Anthropic-specific tool schemas.
57
- - Use only tools enumerated in the active tool manifest (`MANIFEST.yaml`) or
58
- the IDE's native tool surface (Roo Code, Cline, OpenCode native tools).
59
- - When you want to edit a file, use the native file-write tool of the active
60
- agent — not `str_replace_editor`. If unsure what tool is available, list
61
- available tools or ask the user before emitting a tool call.
62
-
63
- ### Per-phase reasoning and sampling guidance
64
-
65
- Local LLMs require tighter sampling control than cloud LLMs. Use these defaults
66
- unless the serving layer overrides them.
67
-
68
- - **Planning phase (PM, Architect, Tech Lead):**
69
- - Reasoning: OFF (`/no_think` prepended).
70
- - Temperature: low (0.0 – 0.3). Planning artifacts should be deterministic
71
- and reproducible.
72
- - Top-p: 0.9 or unset. Top-k: unset.
73
- - Max tokens: generous (8k+) — planning documents are long.
74
- - **Implementation phase (Dev):**
75
- - Reasoning: ON (omit `/no_think`).
76
- - Temperature: moderate (0.3 – 0.6). Code synthesis benefits from controlled
77
- exploration but not creative rewriting.
78
- - Top-p: 0.95 or unset. Top-k: unset.
79
- - Max tokens: generous (8k+) — full-file rewrites are common.
80
- - **Review / QA phase:**
81
- - Reasoning: ON for root-cause analysis; OFF for mechanical checks.
82
- - Temperature: low (0.0 – 0.2). Reviews should be deterministic.
83
-
84
- If the serving layer applies its own sampler defaults, the per-phase guidance
85
- above is advisory — but the phase boundary and `/no_think` placement are
86
- load-bearing and MUST be honored on every turn.
1
+ ## On-Prem / Local-LLM Guardrails
2
+
3
+ These rules apply ONLY when this project is installed with `profile: on-prem`.
4
+ They are appended to the universal block by the composer in `lib/installer.js`.
5
+ Local LLMs (Nemotron, Qwen, DeepSeek, Llama-3, etc. served via vLLM, Ollama, or
6
+ TGI) fail in patterns cloud LLMs rarely exhibit — the rules below pin those
7
+ failure modes down explicitly. Keep these rules verbatim in every response
8
+ context where tool use is possible.
9
+
10
+ ### Reasoning mode: `/no_think` on planning-phase prompts
11
+
12
+ Local reasoning-capable models (Nemotron-variants and similar) default to
13
+ chain-of-thought reasoning that bloats planning-phase prompts with internal
14
+ deliberation the operator does not need to read. Prepend the literal token
15
+ `/no_think` as the first line of any planning-phase system prompt or user turn
16
+ you compose. The token is consumed by the serving layer and suppresses the
17
+ model's reasoning trace on that turn.
18
+
19
+ - Planning-phase turns (PM, Architect, Tech Lead): begin the turn with
20
+ `/no_think` on its own line. Reasoning-mode OFF.
21
+ - Implementation-phase turns (Dev): omit `/no_think`. Reasoning-mode ON is
22
+ desirable for stepwise code synthesis and debugging.
23
+ - Review / QA turns: omit `/no_think` when the review benefits from explicit
24
+ reasoning (root-cause analysis). Include `/no_think` for mechanical checks
25
+ (lint, style, formatting).
26
+
27
+ If the downstream serving layer does not recognize `/no_think`, it is a no-op
28
+ text token — safe to include unconditionally on planning turns.
29
+
30
+ ### No writes to `~/.claude/` or any user home directory
31
+
32
+ Local LLMs frequently hallucinate paths under `~/.claude/`, `~/.cache/`,
33
+ `~/Library/`, or `%APPDATA%` — imitating patterns learned from Claude Code and
34
+ Cursor training data. These paths are OUTSIDE the project and cross-contaminate
35
+ other projects on the same machine.
36
+
37
+ - NEVER create, write, or modify files under `~/.claude/`, `~/.cache/`,
38
+ `~/Library/`, `~/AppData/`, `%APPDATA%`, or any path that resolves outside
39
+ the current project directory.
40
+ - All project artifacts — code, configuration, logs, scratch notes, and agent
41
+ state — MUST land under the current working directory (the project root) or
42
+ an explicitly-named subdirectory thereof.
43
+ - When a tool call appears to target a home-directory path, refuse the write
44
+ and respond in text explaining the violation. Ask the user for an explicit
45
+ in-project path before proceeding.
46
+
47
+ ### No `str_replace_editor` or Claude Code-specific tools
48
+
49
+ Local LLMs hallucinate Anthropic-proprietary tools — most commonly
50
+ `str_replace_editor`, `text_editor_20241022`, and `computer_use_preview` — that
51
+ do NOT exist outside the Anthropic API. Calling them against a local-LLM
52
+ serving layer produces a tool-not-found error or, worse, a silent no-op.
53
+
54
+ - Do NOT emit tool calls named `str_replace_editor`, `text_editor_*`,
55
+ `computer_use_*`, or any other tool whose name includes `str_replace_editor`
56
+ or matches Anthropic-specific tool schemas.
57
+ - Use only tools enumerated in the active tool manifest (`MANIFEST.yaml`) or
58
+ the IDE's native tool surface (Roo Code, Cline, OpenCode native tools).
59
+ - When you want to edit a file, use the native file-write tool of the active
60
+ agent — not `str_replace_editor`. If unsure what tool is available, list
61
+ available tools or ask the user before emitting a tool call.
62
+
63
+ ### Per-phase reasoning and sampling guidance
64
+
65
+ Local LLMs require tighter sampling control than cloud LLMs. Use these defaults
66
+ unless the serving layer overrides them.
67
+
68
+ - **Planning phase (PM, Architect, Tech Lead):**
69
+ - Reasoning: OFF (`/no_think` prepended).
70
+ - Temperature: low (0.0 – 0.3). Planning artifacts should be deterministic
71
+ and reproducible.
72
+ - Top-p: 0.9 or unset. Top-k: unset.
73
+ - Max tokens: generous (8k+) — planning documents are long.
74
+ - **Implementation phase (Dev):**
75
+ - Reasoning: ON (omit `/no_think`).
76
+ - Temperature: moderate (0.3 – 0.6). Code synthesis benefits from controlled
77
+ exploration but not creative rewriting.
78
+ - Top-p: 0.95 or unset. Top-k: unset.
79
+ - Max tokens: generous (8k+) — full-file rewrites are common.
80
+ - **Review / QA phase:**
81
+ - Reasoning: ON for root-cause analysis; OFF for mechanical checks.
82
+ - Temperature: low (0.0 – 0.2). Reviews should be deterministic.
83
+
84
+ If the serving layer applies its own sampler defaults, the per-phase guidance
85
+ above is advisory — but the phase boundary and `/no_think` placement are
86
+ load-bearing and MUST be honored on every turn.
@@ -1,29 +1,29 @@
1
- # AI Agent Skills - Planning Instruction
2
-
3
- You have access to a library of skills in your skills directory. Before starting any task:
4
-
5
- 1. Read the skill manifest at {{MANIFEST_PATH}}
6
- 2. Based on the task description, select which skills are relevant
7
- 3. Read only the selected skill files
8
- 4. Then proceed with the task
9
-
10
- Always load skills marked with always_load: true.
11
- Do not load skills that are not relevant to the current task.
12
-
13
- ## Respond in TEXT vs. create FILES
14
-
15
- Choose your response medium deliberately. Defaulting to file creation when the user asked a question is a common failure mode — especially for coding agents running in web UIs.
16
-
17
- - **Create or modify FILES when the user's request contains file-action keywords:** `create`, `write`, `generate`, `build`, `implement` (and obvious synonyms such as `add`, `produce`, `refactor`, `fix`, `update <file>`). These signal a concrete artifact is expected.
18
- - **Respond in TEXT when the request contains text-response keywords:** `what do you think`, `how should we`, `discuss`, `opinion` (and obvious synonyms such as `explain`, `why`, `should I`, `compare`, `recommend`). These signal that a conversation is expected, not a deliverable.
19
- - **If unsure, respond in TEXT.** A text answer can always be followed by file creation on confirmation; an unwanted file cannot be cleanly undone.
20
- - **Never create `response.md`, `output.md`, or any similarly named scratch file as a reply.** A reply belongs in the chat transcript, not on disk.
21
- - **Confirm file paths before writing.** When you are about to create or modify a file whose path the user has not explicitly named, state the intended path in text and wait for confirmation, unless the path is unambiguous from the task context.
22
-
23
- ## BMAD phase discipline
24
-
25
- BMAD-METHOD organizes work into declared phases (analysis, planning, architecture, story-creation, implementation, review). Respect the currently declared phase.
26
-
27
- - **Do not skip ahead to implementation during planning.** If the project is in a planning phase — or the user has asked for requirements, architecture, or a story — produce planning artifacts, not code.
28
- - **Do not retroactively plan after you have already coded.** If implementation has already started, flag the gap instead of fabricating back-dated planning documents.
29
- - The declared phase is established by the active skill, the story status, or an explicit statement from the user. When none of these is available, ask before assuming.
1
+ # AI Agent Skills - Planning Instruction
2
+
3
+ You have access to a library of skills in your skills directory. Before starting any task:
4
+
5
+ 1. Read the skill manifest at {{MANIFEST_PATH}}
6
+ 2. Based on the task description, select which skills are relevant
7
+ 3. Read only the selected skill files
8
+ 4. Then proceed with the task
9
+
10
+ Always load skills marked with always_load: true.
11
+ Do not load skills that are not relevant to the current task.
12
+
13
+ ## Respond in TEXT vs. create FILES
14
+
15
+ Choose your response medium deliberately. Defaulting to file creation when the user asked a question is a common failure mode — especially for coding agents running in web UIs.
16
+
17
+ - **Create or modify FILES when the user's request contains file-action keywords:** `create`, `write`, `generate`, `build`, `implement` (and obvious synonyms such as `add`, `produce`, `refactor`, `fix`, `update <file>`). These signal a concrete artifact is expected.
18
+ - **Respond in TEXT when the request contains text-response keywords:** `what do you think`, `how should we`, `discuss`, `opinion` (and obvious synonyms such as `explain`, `why`, `should I`, `compare`, `recommend`). These signal that a conversation is expected, not a deliverable.
19
+ - **If unsure, respond in TEXT.** A text answer can always be followed by file creation on confirmation; an unwanted file cannot be cleanly undone.
20
+ - **Never create `response.md`, `output.md`, or any similarly named scratch file as a reply.** A reply belongs in the chat transcript, not on disk.
21
+ - **Confirm file paths before writing.** When you are about to create or modify a file whose path the user has not explicitly named, state the intended path in text and wait for confirmation, unless the path is unambiguous from the task context.
22
+
23
+ ## BMAD phase discipline
24
+
25
+ BMAD-METHOD organizes work into declared phases (analysis, planning, architecture, story-creation, implementation, review). Respect the currently declared phase.
26
+
27
+ - **Do not skip ahead to implementation during planning.** If the project is in a planning phase — or the user has asked for requirements, architecture, or a story — produce planning artifacts, not code.
28
+ - **Do not retroactively plan after you have already coded.** If implementation has already started, flag the gap instead of fabricating back-dated planning documents.
29
+ - The declared phase is established by the active skill, the story status, or an explicit statement from the user. When none of these is available, ask before assuming.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ma-agents",
3
- "version": "3.17.0-beta.4",
3
+ "version": "3.17.1",
4
4
  "description": "NPX tool to install skills for AI coding agents (Claude Code, Gemini, Copilot, Kilocode, Cline, Cursor, Roo Code)",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "start": "node bin/cli.js",
11
- "test": "node test/yes-flag.test.js && node test/skill-authoring.test.js && node test/skill-validation.test.js && node test/skill-mandatory.test.js && node test/skill-customize-agent.test.js && node test/create-agent.test.js && node test/generate-project-context.test.js && node test/build-bmad-args.test.js && node test/build-bmad-cache-reader.test.js && node test/bundle-filter-set-equality.test.js && node test/bmad-version-bump.test.js && node test/staging-6-10-0-regression.test.js && node test/uv-transition-resilience.test.js && node test/passthrough-reconciliation-6-9-0.test.js && node test/extension-module-restructure.test.js && node test/convert-agents-to-skills.test.js && node test/migration.test.js && node test/migration-validation.test.js && node test/story-15-5-workflow-skills.test.js && node test/repo-layout.test.js && node test/config-storage.test.js && node test/cross-repo-validation.test.js && node test/config-lost-on-update.test.js && node test/portable-paths.test.js && node test/cicd-remote-mode.test.js && node test/config-layout.test.js && node test/roo-code-agent.test.js && node test/roo-code-injection.test.js && node test/profile.test.js && node test/instruction-block.test.js && node test/instruction-injection.test.js && node test/agents-md.test.js && node test/instruction-block-git.test.js && node test/onprem-injection.test.js && node test/onprem-layer.test.js && node test/copilot-instructions-path.test.js && node test/roomodes.test.js && node test/clinerules.test.js && node test/cline-workflow-reconciliation.test.js && node test/reconfigure.test.js && node test/experimental-warning.test.js && node test/bmad-persona-phase-prefix.test.js && node test/f1a-on-prem-prefix-post-install.test.js && node test/retired-skills-migration.test.js && node test/rename-migration.test.js && node test/uninstall.test.js && node test/offline-recompile.test.js && node test/plugin-manifests.test.js && node test/demerzel-ml-removal-drift.test.js && node test/demerzel-deprecation-notice.test.js && node test/build-plugin.test.js && node test/config-path-migration.test.js && node test/gitignore-plugin-stage.test.js && node test/customizations-translation.test.js && node test/routing-parity.test.js && node test/bmad-extension.test.js && node test/integration-verification.test.js && node test/agent-scope.test.js && node test/obsolete-tool-dirs.test.js && node test/bmad-empty-tools-guard.test.js && node test/v68-pluginresolver-enumeration-passthrough.test.js && node test/agents.test.js && node test/installer.test.js && node test/bmad.test.js && node test/cli.test.js && node test/knowledge-atlas-smoke.test.js && node test/knowledge-atlas-manifest.test.js && node test/knowledge-atlas-render.test.js && node test/knowledge-atlas-graph.test.js && node test/knowledge-atlas-packaging.test.js && node test/knowledge-atlas-offline-safety.test.js && node test/knowledge-atlas-reconcile.test.js && node test/knowledge-atlas-determinism.test.js && node test/knowledge-atlas-degradation.test.js && node test/knowledge-atlas-realproject.test.js && node test/knowledge-atlas-link-integrity.test.js && node test/knowledge-atlas-config-scan.test.js && node test/knowledge-atlas-references.test.js && node test/agent-injection-strategy.test.js && node test/bmad-module-selection.test.js && node test/custom-marketplace-surface-drift.test.js && node test/custom-marketplace-wizard.test.js && node test/custom-marketplace-live-clone.test.js && node test/custom-marketplace-stage-install.test.js && node test/custom-marketplace-persist-reconcile.test.js && node test/demerzel-nondestructive-invariant.test.js && node test/fr243-custom-source-allowlist-nonleak.test.js && node test/custom-marketplace-registry.test.js && node test/diag.test.js",
11
+ "test": "node test/yes-flag.test.js && node test/skill-authoring.test.js && node test/skill-validation.test.js && node test/skill-mandatory.test.js && node test/skill-customize-agent.test.js && node test/create-agent.test.js && node test/generate-project-context.test.js && node test/build-bmad-args.test.js && node test/build-bmad-cache-reader.test.js && node test/bundle-filter-set-equality.test.js && node test/bmad-version-bump.test.js && node test/staging-6-10-0-regression.test.js && node test/uv-transition-resilience.test.js && node test/passthrough-reconciliation-6-9-0.test.js && node test/extension-module-restructure.test.js && node test/convert-agents-to-skills.test.js && node test/migration.test.js && node test/migration-validation.test.js && node test/story-15-5-workflow-skills.test.js && node test/repo-layout.test.js && node test/config-storage.test.js && node test/cross-repo-validation.test.js && node test/config-lost-on-update.test.js && node test/portable-paths.test.js && node test/cicd-remote-mode.test.js && node test/config-layout.test.js && node test/roo-code-agent.test.js && node test/roo-code-injection.test.js && node test/profile.test.js && node test/instruction-block.test.js && node test/instruction-injection.test.js && node test/agents-md.test.js && node test/instruction-block-git.test.js && node test/onprem-injection.test.js && node test/onprem-layer.test.js && node test/copilot-instructions-path.test.js && node test/ma-agent-persona-picker.test.js && node test/roomodes.test.js && node test/clinerules.test.js && node test/cline-workflow-reconciliation.test.js && node test/reconfigure.test.js && node test/experimental-warning.test.js && node test/bmad-persona-phase-prefix.test.js && node test/f1a-on-prem-prefix-post-install.test.js && node test/retired-skills-migration.test.js && node test/rename-migration.test.js && node test/uninstall.test.js && node test/offline-recompile.test.js && node test/plugin-manifests.test.js && node test/demerzel-ml-removal-drift.test.js && node test/demerzel-deprecation-notice.test.js && node test/build-plugin.test.js && node test/config-path-migration.test.js && node test/gitignore-plugin-stage.test.js && node test/customizations-translation.test.js && node test/routing-parity.test.js && node test/bmad-extension.test.js && node test/integration-verification.test.js && node test/agent-scope.test.js && node test/obsolete-tool-dirs.test.js && node test/bmad-empty-tools-guard.test.js && node test/v68-pluginresolver-enumeration-passthrough.test.js && node test/agents.test.js && node test/installer.test.js && node test/bmad.test.js && node test/cli.test.js && node test/knowledge-atlas-smoke.test.js && node test/knowledge-atlas-manifest.test.js && node test/knowledge-atlas-render.test.js && node test/knowledge-atlas-graph.test.js && node test/knowledge-atlas-packaging.test.js && node test/knowledge-atlas-offline-safety.test.js && node test/knowledge-atlas-reconcile.test.js && node test/knowledge-atlas-determinism.test.js && node test/knowledge-atlas-degradation.test.js && node test/knowledge-atlas-realproject.test.js && node test/knowledge-atlas-link-integrity.test.js && node test/knowledge-atlas-config-scan.test.js && node test/knowledge-atlas-references.test.js && node test/agent-injection-strategy.test.js && node test/bmad-module-selection.test.js && node test/custom-marketplace-surface-drift.test.js && node test/custom-marketplace-wizard.test.js && node test/custom-marketplace-live-clone.test.js && node test/custom-marketplace-stage-install.test.js && node test/custom-marketplace-persist-reconcile.test.js && node test/demerzel-nondestructive-invariant.test.js && node test/fr243-custom-source-allowlist-nonleak.test.js && node test/custom-marketplace-registry.test.js && node test/diag.test.js",
12
12
  "build:bmad-cache": "node scripts/build-bmad-cache.js",
13
13
  "build:plugin": "node scripts/build-plugin.js",
14
14
  "build:atlas": "node scripts/build-atlas.js",