@mmerterden/multi-agent-pipeline 11.4.0 → 11.5.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 (54) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/README.md +1 -0
  3. package/index.js +9 -2
  4. package/install/_common.mjs +107 -5
  5. package/install/_telemetry.mjs +5 -23
  6. package/install/claude.mjs +70 -10
  7. package/install/copilot.mjs +75 -6
  8. package/package.json +4 -10
  9. package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
  10. package/pipeline/lib/account-resolver.sh +61 -23
  11. package/pipeline/lib/channels-multi-repo.sh +7 -2
  12. package/pipeline/lib/count-lib.sh +27 -0
  13. package/pipeline/lib/credential-store.sh +23 -6
  14. package/pipeline/lib/extract-conventions.sh +27 -21
  15. package/pipeline/lib/fetch-confluence.sh +25 -13
  16. package/pipeline/lib/fetch-crashlytics.sh +30 -8
  17. package/pipeline/lib/fetch-fortify.sh +11 -2
  18. package/pipeline/lib/fetch-swagger.sh +18 -7
  19. package/pipeline/lib/figma-mcp-refresh.sh +26 -11
  20. package/pipeline/lib/figma-screenshot.sh +11 -2
  21. package/pipeline/lib/issue-fetcher.sh +31 -6
  22. package/pipeline/lib/multi-repo-pipeline.sh +84 -20
  23. package/pipeline/lib/plan-todos.sh +12 -3
  24. package/pipeline/lib/post-pr-review.sh +5 -3
  25. package/pipeline/lib/repo-cache.sh +53 -9
  26. package/pipeline/lib/review-watch.sh +26 -6
  27. package/pipeline/lib/shadow-git.sh +45 -4
  28. package/pipeline/lib/vercel-deploy.sh +10 -1
  29. package/pipeline/scripts/audit-log-rotate.sh +38 -10
  30. package/pipeline/scripts/check-md-links.mjs +34 -9
  31. package/pipeline/scripts/diff-risk-score.mjs +4 -1
  32. package/pipeline/scripts/evidence-gate.mjs +10 -1
  33. package/pipeline/scripts/fixtures/install-layout.tsv +4 -4
  34. package/pipeline/scripts/fixtures/pack-expected-count.txt +1 -0
  35. package/pipeline/scripts/keychain-save.sh +13 -9
  36. package/pipeline/scripts/lint-skills.mjs +40 -2
  37. package/pipeline/scripts/migrate-prefs.mjs +26 -7
  38. package/pipeline/scripts/phase-tracker.sh +71 -0
  39. package/pipeline/scripts/pre-commit-check.sh +39 -0
  40. package/pipeline/scripts/scan-skills.sh +217 -127
  41. package/pipeline/scripts/smoke-bitbucket-contract.sh +21 -5
  42. package/pipeline/scripts/smoke-fetchers-offline.sh +382 -0
  43. package/pipeline/scripts/smoke-install-layout.sh +11 -3
  44. package/pipeline/scripts/smoke-lib-scripts.sh +54 -1
  45. package/pipeline/scripts/smoke-pack-contents.sh +140 -0
  46. package/pipeline/scripts/smoke-plugin-validate.sh +64 -0
  47. package/pipeline/scripts/smoke-shadow-git.sh +48 -1
  48. package/pipeline/scripts/smoke-skill-authoring.sh +1 -1
  49. package/pipeline/scripts/smoke-workflow-audit.sh +69 -0
  50. package/pipeline/scripts/test-gap-scan.mjs +12 -1
  51. package/pipeline/scripts/triage-memory.mjs +10 -1
  52. package/pipeline/scripts/uninstall.mjs +105 -36
  53. package/pipeline/scripts/update-issue-progress.sh +60 -41
  54. package/pipeline/scripts/write-state.mjs +14 -4
@@ -130,6 +130,10 @@ function isLockStale(lockPath, staleMs) {
130
130
  }
131
131
  }
132
132
 
133
+ // Path whose lock this process currently holds (null when none). Lets the
134
+ // top-level error handler release our lock on unexpected failures.
135
+ let heldLockFor = null;
136
+
133
137
  /** @param {string} path */
134
138
  function releaseLock(path) {
135
139
  const lockPath = `${path}.lock`;
@@ -138,6 +142,7 @@ function releaseLock(path) {
138
142
  } catch {
139
143
  /* already gone - fine */
140
144
  }
145
+ if (heldLockFor === path) heldLockFor = null;
141
146
  }
142
147
 
143
148
  /**
@@ -178,6 +183,7 @@ async function main() {
178
183
 
179
184
  try {
180
185
  await acquireLock(path);
186
+ heldLockFor = path;
181
187
  } catch (err) {
182
188
  if (err.code === "LOCK_TIMEOUT") {
183
189
  console.error(err.message);
@@ -187,6 +193,10 @@ async function main() {
187
193
  process.exit(3);
188
194
  }
189
195
 
196
+ // process.exit() inside a try block skips `finally`, so every exit path in
197
+ // here must release OUR lock explicitly before exiting - otherwise a corrupt
198
+ // state file (or any I/O error) leaks agent-state.json.lock and blocks the
199
+ // next writer until the stale-lock window elapses.
190
200
  try {
191
201
  let next;
192
202
  if (replace) {
@@ -198,8 +208,7 @@ async function main() {
198
208
  try {
199
209
  current = JSON.parse(readFileSync(path, "utf-8"));
200
210
  } catch (err) {
201
- console.error(`write-state: existing state unreadable - ${err.message}`);
202
- process.exit(3);
211
+ throw new Error(`existing state unreadable - ${err.message}`, { cause: err });
203
212
  }
204
213
  }
205
214
  next = deepMerge(current, payload);
@@ -210,15 +219,16 @@ async function main() {
210
219
  renameSync(tmp, path); // atomic on POSIX
211
220
  } catch (err) {
212
221
  console.error(`write-state: ${err.message}`);
213
- process.exit(3);
214
- } finally {
215
222
  releaseLock(path);
223
+ process.exit(3);
216
224
  }
217
225
 
226
+ releaseLock(path);
218
227
  process.exit(0);
219
228
  }
220
229
 
221
230
  main().catch((err) => {
222
231
  console.error(`write-state: unhandled - ${err.message}`);
232
+ if (heldLockFor) releaseLock(heldLockFor);
223
233
  process.exit(3);
224
234
  });