ma-agents 3.18.1-beta.0 → 3.18.1-beta.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.
@@ -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.18.1-beta.0",
40
+ "version": "3.18.1-beta.1",
41
41
  "author": {
42
42
  "name": "Alon Mayaffit"
43
43
  },
package/lib/bmad.js CHANGED
@@ -12,8 +12,9 @@ const { withExperimentalWarningSuppressed } = require('./warning-filter');
12
12
  * Build the env object passed to the bmad-method child spawn.
13
13
  * Extends parent env with GIT_TERMINAL_PROMPT=0 and a NODE_OPTIONS
14
14
  * value that silences the ExperimentalWarning about CJS require() of
15
- * an ES Module (Bug A). Callers that need a different NODE_OPTIONS
16
- * can merge after this call.
15
+ * an ES Module (Bug A) and preloads lib/fs-retry-preload.js, which makes
16
+ * the child's recursive deletes retry transient Windows locks (EBUSY).
17
+ * Callers that need a different NODE_OPTIONS can merge after this call.
17
18
  *
18
19
  * @param {NodeJS.ProcessEnv} [parentEnv=process.env]
19
20
  * @returns {NodeJS.ProcessEnv}
@@ -24,10 +25,26 @@ function buildChildSpawnEnv(parentEnv = process.env) {
24
25
  GIT_TERMINAL_PROMPT: '0',
25
26
  // Bug A — keep the bmad-method child as quiet about CJS-require-ESM
26
27
  // as the parent. Preserves any NODE_OPTIONS the user already set.
27
- NODE_OPTIONS: withExperimentalWarningSuppressed(parentEnv.NODE_OPTIONS),
28
+ NODE_OPTIONS: withFsRetryPreload(withExperimentalWarningSuppressed(parentEnv.NODE_OPTIONS)),
28
29
  };
29
30
  }
30
31
 
32
+ /**
33
+ * Append `--require "<lib/fs-retry-preload.js>"` to a NODE_OPTIONS value,
34
+ * unless it is already there. The path is written with forward slashes:
35
+ * inside a quoted NODE_OPTIONS value Node treats `\` as an escape
36
+ * character, and Windows accepts `/` as a separator.
37
+ *
38
+ * @param {string} nodeOptions - NODE_OPTIONS value to extend
39
+ * @returns {string}
40
+ */
41
+ function withFsRetryPreload(nodeOptions) {
42
+ const preload = path.join(__dirname, 'fs-retry-preload.js').replace(/\\/g, '/');
43
+ const current = (nodeOptions || '').trim();
44
+ if (current.includes(preload)) return current;
45
+ return `${current} --require "${preload}"`.trim();
46
+ }
47
+
31
48
  const BMAD_DIR = '_bmad';
32
49
  const CONFIG_DIR = path.join(BMAD_DIR, '_config', 'agents');
33
50
 
@@ -3866,4 +3883,7 @@ module.exports = {
3866
3883
  // Bug: external modules pinned to the bundled release (--pin)
3867
3884
  getBundledModulePins,
3868
3885
  cacheDiffersFromPin,
3886
+ // Bug: bmad-method's skill-dir cleanup fails on transient Windows locks
3887
+ buildChildSpawnEnv,
3888
+ withFsRetryPreload,
3869
3889
  };
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Preloaded into the bmad-method child process (`node --require`, via
5
+ * NODE_OPTIONS — see buildChildSpawnEnv in lib/bmad.js) to make its
6
+ * recursive deletes survive transient Windows file locks.
7
+ *
8
+ * Why this exists: right after copying skills into the IDE directories,
9
+ * bmad-method deletes the `_bmad/<module>/<skill>` copies
10
+ * (`Installer._cleanupSkillDirs`, via fs-extra `remove` → `fs.rm`). On
11
+ * Windows a just-written directory is routinely held for a moment by
12
+ * Defender real-time scanning, the Search indexer or an editor's file
13
+ * watcher, and `fs.rm` fails at once with EBUSY — aborting the whole
14
+ * install ("EBUSY: resource busy or locked, rmdir
15
+ * '...\_bmad\ma-skills\ma-agent-sqa'"). Node's `fs.rm` already retries
16
+ * EBUSY/EPERM/ENOTEMPTY/EMFILE/ENFILE with a linear backoff, but only when
17
+ * asked: `maxRetries` defaults to 0.
18
+ *
19
+ * This fills in `maxRetries`/`retryDelay` for recursive `rm` calls that did
20
+ * not set them, leaving every other call untouched. It must load before
21
+ * anything captures `fs.rm` — graceful-fs (used by fs-extra) clones the fs
22
+ * module when first required — which `--require` guarantees.
23
+ */
24
+
25
+ const fs = require('fs');
26
+
27
+ // Linear backoff: waits 100, 200, … 1500 ms — about 12 s in total before
28
+ // the original error is surfaced. Transient scanner/watcher locks clear in
29
+ // well under a second; a lock that outlives this is a real one.
30
+ const MAX_RETRIES = 15;
31
+ const RETRY_DELAY_MS = 100;
32
+
33
+ /**
34
+ * Return `options` with the retry defaults added when the call is a
35
+ * recursive rm that did not choose its own retry policy.
36
+ *
37
+ * @param {object|undefined} options - Options passed to fs.rm / rmSync
38
+ * @returns {object|undefined} Options to forward
39
+ */
40
+ function withRetries(options) {
41
+ if (!options || typeof options !== 'object' || !options.recursive) return options;
42
+ if (options.maxRetries !== undefined) return options;
43
+ return { ...options, maxRetries: MAX_RETRIES, retryDelay: options.retryDelay ?? RETRY_DELAY_MS };
44
+ }
45
+
46
+ // Each wrapper is installed only when the function exists, so an older Node
47
+ // without fs.rm is left exactly as it was.
48
+ if (typeof fs.rm === 'function') {
49
+ const originalRm = fs.rm;
50
+ fs.rm = function rm(target, options, callback) {
51
+ if (typeof options === 'function') return originalRm.call(this, target, options);
52
+ return originalRm.call(this, target, withRetries(options), callback);
53
+ };
54
+ }
55
+
56
+ if (typeof fs.rmSync === 'function') {
57
+ const originalRmSync = fs.rmSync;
58
+ fs.rmSync = function rmSync(target, options) {
59
+ return originalRmSync.call(this, target, withRetries(options));
60
+ };
61
+ }
62
+
63
+ if (fs.promises && typeof fs.promises.rm === 'function') {
64
+ const originalPromisesRm = fs.promises.rm;
65
+ fs.promises.rm = function rm(target, options) {
66
+ return originalPromisesRm.call(this, target, withRetries(options));
67
+ };
68
+ }
69
+
70
+ module.exports = { withRetries, MAX_RETRIES, RETRY_DELAY_MS };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ma-agents",
3
- "version": "3.18.1-beta.0",
3
+ "version": "3.18.1-beta.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/bundled-module-pins.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/project-layout-binding-spine.test.js && node test/project-layout-enum-single-source.test.js && node test/project-layout-config-generation.test.js && node test/project-layout-two-store-round-trip.test.js && node test/project-layout-two-store-wizard.test.js && node test/project-layout-staleness-guard.test.js && node test/project-layout-confluence-routing.test.js && node test/project-layout-confluence-page-tree.test.js && node test/project-layout-artifact-routing.test.js && node test/project-layout-confluence-configuration.test.js && node test/project-layout-confluence-publish-hook.test.js && node test/project-layout-legacy-single-store.test.js && node test/project-layout-bind.test.js && node test/global-install-scope.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/jira-identity-clause.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 && node test/release-gate-epic-31.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/bundled-module-pins.test.js && node test/bmad-child-fs-retry.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/project-layout-binding-spine.test.js && node test/project-layout-enum-single-source.test.js && node test/project-layout-config-generation.test.js && node test/project-layout-two-store-round-trip.test.js && node test/project-layout-two-store-wizard.test.js && node test/project-layout-staleness-guard.test.js && node test/project-layout-confluence-routing.test.js && node test/project-layout-confluence-page-tree.test.js && node test/project-layout-artifact-routing.test.js && node test/project-layout-confluence-configuration.test.js && node test/project-layout-confluence-publish-hook.test.js && node test/project-layout-legacy-single-store.test.js && node test/project-layout-bind.test.js && node test/global-install-scope.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/jira-identity-clause.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 && node test/release-gate-epic-31.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",