@mmerterden/multi-agent-pipeline 14.2.1 → 15.0.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 (184) hide show
  1. package/CHANGELOG.md +118 -6
  2. package/README.md +20 -9
  3. package/README.tr.md +150 -0
  4. package/docs/FIGMA_PIPELINE.md +3 -3
  5. package/docs/adr/0006-skills-core-external-split.md +1 -1
  6. package/docs/adr/0009-claude-stack-skills-plugin-only.md +31 -0
  7. package/docs/adr/README.md +1 -0
  8. package/docs/architecture.md +24 -9
  9. package/docs/ecosystem.md +237 -0
  10. package/docs/features.md +5 -5
  11. package/index.js +2 -0
  12. package/install/_codex-agents.mjs +11 -2
  13. package/install/_common.mjs +65 -1
  14. package/install/_dev-only-files.mjs +0 -1
  15. package/install/_platform-filter.mjs +73 -7
  16. package/install/_plugin-skills.mjs +33 -8
  17. package/install/claude.mjs +144 -59
  18. package/install/codex.mjs +37 -7
  19. package/install/copilot.mjs +36 -11
  20. package/install/index.mjs +6 -2
  21. package/install/templates/codex-instructions.md +1 -1
  22. package/install/templates/copilot-instructions.md +15 -12
  23. package/package.json +1 -2
  24. package/pipeline/commands/multi-agent/SKILL.md +4 -2
  25. package/pipeline/commands/multi-agent/analysis/SKILL.md +5 -5
  26. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +2 -2
  27. package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
  28. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +9 -9
  29. package/pipeline/commands/multi-agent/channels/SKILL.md +16 -5
  30. package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +186 -0
  31. package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -4
  32. package/pipeline/commands/multi-agent/dev/SKILL.md +10 -23
  33. package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +10 -2
  34. package/pipeline/commands/multi-agent/dev-local/SKILL.md +10 -24
  35. package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +10 -3
  36. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  37. package/pipeline/commands/multi-agent/help/SKILL.md +19 -4
  38. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +2 -2
  39. package/pipeline/commands/multi-agent/jira/SKILL.md +13 -2
  40. package/pipeline/commands/multi-agent/language/SKILL.md +1 -1
  41. package/pipeline/commands/multi-agent/local/SKILL.md +6 -2
  42. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +6 -2
  43. package/pipeline/commands/multi-agent/log/SKILL.md +7 -1
  44. package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +81 -0
  45. package/pipeline/commands/multi-agent/resume/SKILL.md +1 -1
  46. package/pipeline/commands/multi-agent/{ship → resume-local}/SKILL.md +13 -9
  47. package/pipeline/commands/multi-agent/setup/SKILL.md +5 -5
  48. package/pipeline/commands/multi-agent/stack/SKILL.md +55 -43
  49. package/pipeline/commands/multi-agent/store-ready/SKILL.md +3 -3
  50. package/pipeline/commands/multi-agent/sync/SKILL.md +18 -11
  51. package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +1 -1
  52. package/pipeline/commands/multi-agent/uninstall/SKILL.md +2 -0
  53. package/pipeline/commands/multi-agent/update/SKILL.md +1 -1
  54. package/pipeline/lib/extract-conventions.sh +44 -15
  55. package/pipeline/lib/fetch-figma-annotations.sh +8 -1
  56. package/pipeline/lib/fetch-fortify.sh +23 -8
  57. package/pipeline/lib/figma-screenshot.sh +11 -1
  58. package/pipeline/lib/issue-fetcher.sh +77 -10
  59. package/pipeline/lib/md2confluence-v3.py +16 -2
  60. package/pipeline/lib/parse-complaints.sh +306 -0
  61. package/pipeline/lib/plan-todos.sh +5 -2
  62. package/pipeline/lib/post-pr-review.sh +8 -6
  63. package/pipeline/lib/shadow-git.sh +50 -9
  64. package/pipeline/lib/submodule-detector.sh +8 -1
  65. package/pipeline/multi-agent-refs/_input-parser.md +1 -1
  66. package/pipeline/multi-agent-refs/channels/confluence.md +3 -0
  67. package/pipeline/multi-agent-refs/channels/issue-comment.md +2 -2
  68. package/pipeline/multi-agent-refs/channels/jira.md +13 -2
  69. package/pipeline/multi-agent-refs/channels/pr-review-actions.md +1 -1
  70. package/pipeline/multi-agent-refs/channels/pr.md +20 -0
  71. package/pipeline/multi-agent-refs/channels/wiki.md +4 -4
  72. package/pipeline/multi-agent-refs/complaint-analysis-template.md +99 -0
  73. package/pipeline/multi-agent-refs/component-dispatch.md +6 -6
  74. package/pipeline/multi-agent-refs/cross-cli-contract.md +16 -16
  75. package/pipeline/multi-agent-refs/features/external-context-injection.md +1 -1
  76. package/pipeline/multi-agent-refs/features/stack-skill-routing.md +5 -5
  77. package/pipeline/multi-agent-refs/features/worktree-finalize.md +1 -1
  78. package/pipeline/multi-agent-refs/generate-issue.md +3 -3
  79. package/pipeline/multi-agent-refs/issue-jira-triad.md +3 -3
  80. package/pipeline/multi-agent-refs/payload-contracts.md +67 -0
  81. package/pipeline/multi-agent-refs/phases/modes.md +20 -0
  82. package/pipeline/multi-agent-refs/phases/phase-0-init.md +2 -2
  83. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +7 -7
  84. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +5 -5
  85. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +3 -3
  86. package/pipeline/multi-agent-refs/phases/phase-4-review.md +12 -12
  87. package/pipeline/multi-agent-refs/phases/phase-5-test.md +1 -1
  88. package/pipeline/multi-agent-refs/phases/phase-6-commit.md +8 -40
  89. package/pipeline/multi-agent-refs/phases/phase-7-report.md +5 -3
  90. package/pipeline/multi-agent-refs/phases.md +6 -0
  91. package/pipeline/multi-agent-refs/rules.md +2 -0
  92. package/pipeline/multi-agent-refs/tracker-contract.md +1 -1
  93. package/pipeline/multi-agent-refs/wiki-capture.md +2 -2
  94. package/pipeline/preferences-template.json +13 -5
  95. package/pipeline/rules/figma-pipeline.md +2 -2
  96. package/pipeline/schemas/agent-state.schema.json +1 -1
  97. package/pipeline/schemas/complaint-analysis-spec.schema.json +216 -0
  98. package/pipeline/schemas/migrations/prefs-2.5.0-to-2.6.0.mjs +46 -0
  99. package/pipeline/schemas/prefs.schema.json +277 -67
  100. package/pipeline/schemas/token-budget.json +2 -2
  101. package/pipeline/scripts/_stack-routing.mjs +79 -0
  102. package/pipeline/scripts/audit-log-rotate.sh +14 -1
  103. package/pipeline/scripts/build-skills-index.mjs +11 -0
  104. package/pipeline/scripts/build-stack-plugins.mjs +35 -60
  105. package/pipeline/scripts/check-derived-drift.mjs +65 -29
  106. package/pipeline/scripts/diff-explain.mjs +41 -3
  107. package/pipeline/scripts/diff-risk-score.mjs +72 -8
  108. package/pipeline/scripts/gc-worktrees.sh +4 -1
  109. package/pipeline/scripts/gen-mode-dispatch.mjs +1 -1
  110. package/pipeline/scripts/gen-skills-index.mjs +1 -1
  111. package/pipeline/scripts/learning-curve.mjs +8 -2
  112. package/pipeline/scripts/match-skills.mjs +8 -2
  113. package/pipeline/scripts/migrate-prefs.mjs +28 -20
  114. package/pipeline/scripts/output-quality-check.sh +15 -4
  115. package/pipeline/scripts/phase-tracker.sh +33 -12
  116. package/pipeline/scripts/phase0-exit-gate.mjs +3 -2
  117. package/pipeline/scripts/pre-commit-check.sh +69 -22
  118. package/pipeline/scripts/render-agent-log-cost.sh +8 -3
  119. package/pipeline/scripts/render-cost-summary.sh +42 -22
  120. package/pipeline/scripts/render-work-summary.sh +47 -13
  121. package/pipeline/scripts/review-scope.mjs +1 -1
  122. package/pipeline/scripts/run-aggregator.mjs +43 -14
  123. package/pipeline/scripts/scan-agent-config.sh +1 -1
  124. package/pipeline/scripts/skill-conformance.mjs +165 -30
  125. package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
  126. package/pipeline/scripts/smoke-schema-validation.sh +5 -1
  127. package/pipeline/scripts/test-gap-rules/android.json +25 -0
  128. package/pipeline/scripts/test-gap-rules/ios.json +34 -0
  129. package/pipeline/scripts/test-gap-rules/node.json +29 -0
  130. package/pipeline/scripts/test-gap-rules/python.json +25 -0
  131. package/pipeline/scripts/test-gap-scan.mjs +45 -6
  132. package/pipeline/scripts/uninstall.mjs +196 -14
  133. package/pipeline/scripts/update-issue-progress.sh +12 -16
  134. package/pipeline/scripts/validate-complaint-doc.mjs +229 -0
  135. package/pipeline/scripts/validate-reviewer.mjs +9 -3
  136. package/pipeline/scripts/worktree-finalize.sh +23 -2
  137. package/pipeline/skills/.skill-manifest.json +156 -108
  138. package/pipeline/skills/.skills-index.json +459 -13
  139. package/pipeline/skills/shared/README.md +15 -11
  140. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
  141. package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -0
  142. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
  143. package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +49 -0
  144. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
  145. package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +4 -17
  146. package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +8 -0
  147. package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +5 -18
  148. package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +8 -0
  149. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -2
  150. package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +1 -1
  151. package/pipeline/skills/shared/core/multi-agent-local/SKILL.md +4 -0
  152. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +4 -0
  153. package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +83 -0
  154. package/pipeline/skills/shared/core/{multi-agent-ship → multi-agent-resume-local}/SKILL.md +10 -6
  155. package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +79 -22
  156. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +1 -1
  157. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -8
  158. package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +1 -1
  159. package/pipeline/skills/shared/external/ios-coding-standard/modules/_TEMPLATE.yml +2 -2
  160. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +368 -33
  161. package/pipeline/skills/shared/external/ios-coding-standard/references/swiftlint.draft.yml +1 -2
  162. package/pipeline/skills/shared/external/ios-coding-standard/scripts/check_structure.py +765 -0
  163. package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +75 -0
  164. package/pipeline/skills/shared/external/ios-module-structure/modules/_TEMPLATE.yml +131 -0
  165. package/pipeline/skills/shared/external/ios-module-structure/references/rules.yml +559 -0
  166. package/pipeline/skills/shared/external/ios-module-structure/scripts/check_structure.py +765 -0
  167. package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +302 -0
  168. package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +187 -0
  169. package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +156 -0
  170. package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +108 -0
  171. package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +176 -0
  172. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +865 -0
  173. package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +335 -0
  174. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +344 -0
  175. package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +130 -0
  176. package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +264 -0
  177. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +298 -0
  178. package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +529 -0
  179. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +187 -0
  180. package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +171 -0
  181. package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +184 -0
  182. package/pipeline/skills/shared/external/localization-reuse-map/scripts/snapshot-resources.sh +26 -0
  183. package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +173 -0
  184. package/pipeline/skills/skills-index.md +9 -5
@@ -14,7 +14,7 @@
14
14
  * @module install/claude
15
15
  */
16
16
 
17
- import { existsSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
17
+ import { existsSync, readFileSync, readdirSync, renameSync, rmSync } from "fs";
18
18
  import { join, dirname } from "path";
19
19
  import { execSync } from "child_process";
20
20
 
@@ -35,7 +35,7 @@ import {
35
35
  wipeDir,
36
36
  writeFile,
37
37
  } from "./_common.mjs";
38
- import { copyExternalSkillsFiltered } from "./_platform-filter.mjs";
38
+ import { EXTERNAL_SKILLS_MANIFEST } from "./_platform-filter.mjs";
39
39
  import { DEV_ONLY_SCRIPTS, countDevOnlyFiles } from "./_dev-only-files.mjs";
40
40
  import { registerMcpServer } from "./_mcp-register.mjs";
41
41
 
@@ -46,6 +46,16 @@ import { registerMcpServer } from "./_mcp-register.mjs";
46
46
  */
47
47
  export const LEGACY_PRE_COMMIT_MATCHER = "Bash(git commit:*)";
48
48
 
49
+ /**
50
+ * The only skills installed locally on Claude Code. Everything else reaches
51
+ * Claude Code through the marketplace plugins (`ai-<stack>-toolkit`), namespaced
52
+ * by the plugin loader. These two stay local by policy: they are pipeline-owned
53
+ * compliance catalogs that may carry audit rules not meant for the public
54
+ * marketplace, and `scripts/uninstall.mjs` (PIPELINE_CORE_SKILL_DIRS) already
55
+ * treats exactly this pair as pipeline-owned.
56
+ */
57
+ export const PIPELINE_LOCAL_SKILLS = ["apple-archive-compliance", "google-play-compliance"];
58
+
49
59
  /**
50
60
  * @param {{
51
61
  * home: string,
@@ -128,13 +138,16 @@ function installCommands(pipelineSrc, dest, useSymlinks) {
128
138
  //
129
139
  // Preserve local-only alias wrappers (frontmatter `local-only: true`) across
130
140
  // the wipe. They live ONLY under ~/.claude (never in pipeline/commands, and
131
- // never synced), so without this snapshot+restore they would be destroyed on
132
- // every install/update. Pipeline never ships these names, so restore is safe.
133
- const preservedWrappers = snapshotLocalOnlyWrappers(ownedCmdDir);
141
+ // never synced), so without this stash+restore they would be destroyed on
142
+ // every install/update. The stash is an on-disk rename, not an in-memory
143
+ // snapshot: the only copy of user-authored content stays on disk at every
144
+ // instant, so an install interrupted between wipe and restore loses nothing,
145
+ // and the next run adopts any leftover stash.
146
+ const wrapperStash = stashLocalOnlyWrappers(ownedCmdDir);
134
147
  wipeDir(ownedCmdDir);
135
148
 
136
149
  copyDir(commandsSrc, dest, { useSymlinks });
137
- const restored = restoreLocalOnlyWrappers(ownedCmdDir, preservedWrappers);
150
+ const restored = unstashLocalOnlyWrappers(ownedCmdDir, wrapperStash);
138
151
  console.log(` -> ${countFiles(commandsSrc)} files copied to ${dest}`);
139
152
  if (restored > 0) {
140
153
  console.log(` -> preserved ${restored} local-only alias wrapper(s)`);
@@ -163,36 +176,51 @@ function localizeCommandDescriptions(pipelineSrc, ownedCmdDir) {
163
176
  }
164
177
  }
165
178
 
166
- // Snapshot single-level command dirs whose SKILL.md declares `local-only: true`
167
- // (their files are read into memory) so installCommands can restore them after
168
- // the namespace wipe.
169
- function snapshotLocalOnlyWrappers(ownedCmdDir) {
170
- const out = [];
171
- if (!existsSync(ownedCmdDir)) return out;
179
+ // Move command dirs whose SKILL.md declares `local-only: true` into an on-disk
180
+ // stash beside the namespace, so installCommands can restore them after the
181
+ // namespace wipe. Returns the stash path.
182
+ function stashLocalOnlyWrappers(ownedCmdDir) {
183
+ const stashDir = join(dirname(ownedCmdDir), ".multi-agent-wrapper-stash");
184
+ if (isDryRun() || !existsSync(ownedCmdDir)) return stashDir;
172
185
  for (const name of readdirSync(ownedCmdDir)) {
173
186
  const dir = join(ownedCmdDir, name);
174
187
  const skill = join(dir, "SKILL.md");
175
188
  if (!existsSync(skill)) continue;
176
189
  if (!/^local-only:\s*true\s*$/m.test(readFileSync(skill, "utf-8"))) continue;
177
- const files = readdirSync(dir)
178
- .filter((f) => statSync(join(dir, f)).isFile())
179
- .map((f) => ({ rel: f, content: readFileSync(join(dir, f), "utf-8") }));
180
- out.push({ name, files });
190
+ ensureDir(stashDir);
191
+ const target = join(stashDir, name);
192
+ if (existsSync(target)) rmSync(target, { recursive: true, force: true });
193
+ renameSync(dir, target);
181
194
  }
182
- return out;
195
+ return stashDir;
183
196
  }
184
197
 
185
- // Restore snapshotted local-only wrappers, but never clobber a real command the
186
- // pipeline just installed under the same name. Returns the count restored.
187
- function restoreLocalOnlyWrappers(ownedCmdDir, preserved) {
198
+ // Restore stashed local-only wrappers (including any leftover from an earlier
199
+ // interrupted run), but never clobber a real command the pipeline just
200
+ // installed under the same name. Returns the count restored.
201
+ function unstashLocalOnlyWrappers(ownedCmdDir, stashDir) {
202
+ if (isDryRun() || !existsSync(stashDir)) return 0;
188
203
  let n = 0;
189
- for (const w of preserved) {
190
- const dir = join(ownedCmdDir, w.name);
191
- if (existsSync(dir)) continue; // pipeline shipped a real command with this name
192
- ensureDir(dir);
193
- for (const f of w.files) writeFileSync(join(dir, f.rel), f.content);
204
+ for (const name of readdirSync(stashDir)) {
205
+ const from = join(stashDir, name);
206
+ const to = join(ownedCmdDir, name);
207
+ if (existsSync(to)) {
208
+ // The pipeline now ships a real command under a name the user's wrapper
209
+ // was using, so the wrapper cannot be restored. Say whose content is
210
+ // being dropped: /multi-agent:save writes exactly these, and a release
211
+ // claiming a new name would otherwise delete a saved routine in silence.
212
+ console.log(
213
+ ` -> WARNING: dropped local-only wrapper '${name}' - this release ships a command ` +
214
+ `with that name. Re-save it under a different name if you still need it.`,
215
+ );
216
+ rmSync(from, { recursive: true, force: true });
217
+ continue;
218
+ }
219
+ ensureDir(ownedCmdDir);
220
+ renameSync(from, to);
194
221
  n++;
195
222
  }
223
+ rmSync(stashDir, { recursive: true, force: true });
196
224
  return n;
197
225
  }
198
226
 
@@ -327,7 +355,7 @@ function runPreDeployScans(pipelineSrc) {
327
355
  }
328
356
 
329
357
  function installSkills(opts) {
330
- const { pipelineSrc, dest, indexOnly, useSymlinks, platformFlag } = opts;
358
+ const { pipelineSrc, dest, indexOnly, useSymlinks } = opts;
331
359
  console.log(" [Claude Code] Installing skills...");
332
360
 
333
361
  // Same symlink guard as the other owned trees: never prune or copy through
@@ -343,40 +371,49 @@ function installSkills(opts) {
343
371
  }
344
372
 
345
373
  const sharedCoreSrc = join(pipelineSrc, "skills", "shared", "core");
346
- const sharedExternalSrc = join(pipelineSrc, "skills", "shared", "external");
347
374
 
348
375
  let claudeSkillCount = 0;
349
376
 
350
- if (existsSync(sharedCoreSrc)) {
351
- copyDir(sharedCoreSrc, dest, { useSymlinks });
352
- claudeSkillCount += countFiles(sharedCoreSrc);
377
+ // Claude Code no longer receives a local copy of the stack skills. The
378
+ // marketplace plugins (`ai-<stack>-toolkit`) are its only stack-skill source -
379
+ // a local copy duplicated ~110 skills against the enabled plugins (~10k
380
+ // tokens/session) and shadowed the plugin the moment it went stale. Only the
381
+ // two pipeline-owned compliance catalogs stay local (PIPELINE_LOCAL_SKILLS);
382
+ // they are deliberately not published to the marketplace.
383
+ ensureDir(dest);
384
+ for (const name of PIPELINE_LOCAL_SKILLS) {
385
+ const from = join(sharedCoreSrc, name);
386
+ if (!existsSync(from)) continue;
387
+ if (!useSymlinks) wipeDir(join(dest, name));
388
+ copyDir(from, join(dest, name), { useSymlinks });
389
+ claudeSkillCount += countFiles(from);
353
390
  }
354
391
 
355
- if (existsSync(sharedExternalSrc)) {
356
- const { copied, skipped } = copyExternalSkillsFiltered(sharedExternalSrc, dest, {
357
- platformFlag,
358
- useSymlinks,
359
- });
360
- claudeSkillCount += copied;
361
- if (skipped > 0) {
362
- console.log(
363
- ` -> --platform=${platformFlag} filter skipped ${skipped} external skill dir(s)`,
364
- );
365
- }
392
+ // Single-standard enforcement: Claude Code invokes pipeline commands via
393
+ // the `/multi-agent:*` slash-command namespace, so prune duplicate skill
394
+ // dirs left by older installs that copied shared/core wholesale. This used
395
+ // to live inside the external-copy branch; it must run unconditionally or
396
+ // the 51 multi-agent-* dirs return on the first install after a migration.
397
+ const pruned = pruneLegacyMultiAgentSkills(dest);
398
+ if (pruned > 0) {
399
+ console.log(
400
+ ` -> pruned ${pruned} legacy multi-agent-* skill dirs (slash commands cover these)`,
401
+ );
402
+ }
366
403
 
367
- // Single-standard enforcement: Claude Code invokes pipeline commands via
368
- // the `/multi-agent:*` slash-command namespace, so prune duplicate skill
369
- // dirs that come from the shared/external/ tree.
370
- const pruned = pruneLegacyMultiAgentSkills(dest);
371
- if (pruned > 0) {
372
- claudeSkillCount -= pruned;
373
- console.log(
374
- ` -> pruned ${pruned} legacy multi-agent-* skill dirs (slash commands cover these)`,
375
- );
376
- }
404
+ // Migration prune: an older install delivered the full external catalog here.
405
+ // Its manifest names exactly what was delivered, so removal is manifest-scoped -
406
+ // user-authored skills in the same directory are untouched. Without a manifest
407
+ // nothing is guessed; the stale copy then outlives this install and the user
408
+ // can clean it via uninstall --claude.
409
+ const migrated = pruneManifestDeliveredSkills(dest);
410
+ if (migrated > 0) {
411
+ console.log(
412
+ ` -> migration: removed ${migrated} stack skill dir(s) previously copied here (now plugin-only)`,
413
+ );
377
414
  }
378
415
 
379
- // Figma component skills moved to the ai-<platform>-engineering-toolkit marketplace
416
+ // Figma component skills moved to the ai-<platform>-toolkit marketplace
380
417
  // plugin and are no longer bundled here. Prune any stale copies left by a
381
418
  // pre-migration install so the installed tree stays consistent.
382
419
  for (const sub of ["figma-ios", "figma-android", "figma-common", "figma-to-component"]) {
@@ -410,21 +447,69 @@ function installSkills(opts) {
410
447
  console.log(` -> pruned ${orphans} stale flat skill file(s) from an older layout`);
411
448
  }
412
449
 
413
- console.log(` -> ${claudeSkillCount} skill files installed to ${dest}`);
450
+ console.log(` -> ${claudeSkillCount} skill files installed to ${dest} (stack skills: marketplace plugins)`);
414
451
 
415
- // Keep the shared skills index README in sync.
416
- const sharedReadmeSrc = join(pipelineSrc, "skills", "shared", "README.md");
417
- if (existsSync(sharedReadmeSrc)) {
418
- const claudeReadme = join(dest, "README.md");
452
+ // The shared skills README described the full local catalog; with the catalog
453
+ // gone it would document skills that are not here. Drop it, including copies
454
+ // an older install left behind.
455
+ const claudeReadme = join(dest, "README.md");
456
+ if (existsSync(claudeReadme) && !isDryRun()) {
419
457
  try {
420
- copyFile(sharedReadmeSrc, claudeReadme);
421
- console.log(` -> updated ${claudeReadme}`);
458
+ rmSync(claudeReadme);
459
+ console.log(` -> removed ${claudeReadme} (local catalog no longer installed)`);
422
460
  } catch {
423
461
  /* non-fatal */
424
462
  }
425
463
  }
426
464
  }
427
465
 
466
+ /**
467
+ * Remove the external stack skills an older install copied into `dest`, scoped
468
+ * strictly to the delivery manifest that install wrote. NOTICE files rode along
469
+ * with the external catalog, so they go with it.
470
+ *
471
+ * @param {string} dest - the installed skills directory
472
+ * @returns {number} directories removed
473
+ */
474
+ function pruneManifestDeliveredSkills(dest) {
475
+ const manifestPath = join(dest, EXTERNAL_SKILLS_MANIFEST);
476
+ if (!existsSync(manifestPath)) return 0;
477
+ if (isDryRun()) {
478
+ console.log(` [dry-run] would remove externally-delivered skills named in ${manifestPath}`);
479
+ return 0;
480
+ }
481
+ let removed = 0;
482
+ try {
483
+ const names = JSON.parse(readFileSync(manifestPath, "utf-8"));
484
+ for (const name of Array.isArray(names) ? names : []) {
485
+ // The two local compliance catalogs are never external-delivered, but a
486
+ // corrupted manifest must not be able to take them out.
487
+ if (PIPELINE_LOCAL_SKILLS.includes(name)) continue;
488
+ const dir = join(dest, name);
489
+ if (!existsSync(dir)) continue;
490
+ try {
491
+ rmSync(dir, { recursive: true, force: true });
492
+ removed++;
493
+ } catch {
494
+ /* non-fatal */
495
+ }
496
+ }
497
+ for (const entry of readdirSync(dest)) {
498
+ if (entry.startsWith("NOTICE-") && entry.endsWith(".md")) {
499
+ try {
500
+ rmSync(join(dest, entry));
501
+ } catch {
502
+ /* non-fatal */
503
+ }
504
+ }
505
+ }
506
+ rmSync(manifestPath, { force: true });
507
+ } catch {
508
+ /* unreadable manifest: leave everything in place rather than guess */
509
+ }
510
+ return removed;
511
+ }
512
+
428
513
  function ensureClaudeMd(home, pipelineSrc) {
429
514
  console.log(" [Claude Code] Checking CLAUDE.md template...");
430
515
  const CLAUDE_MD = join(home, ".claude", "CLAUDE.md");
package/install/codex.mjs CHANGED
@@ -10,7 +10,7 @@
10
10
  * name + description into a single prompt block and silently drops entries once
11
11
  * that block overflows - measured at install-design time, one 142-skill plugin
12
12
  * surfaced only 75 of its skills AND evicted an unrelated user skill. So the
13
- * pipeline contributes exactly one skill (`multi-agent`) and keeps its 42
13
+ * pipeline contributes exactly one skill (`multi-agent`) and keeps its
14
14
  * sub-command specs as reference files that cost nothing until read. Converting
15
15
  * them into peer skills would silently lose pipeline commands.
16
16
  *
@@ -34,7 +34,15 @@ import {
34
34
  import { DEV_ONLY_SCRIPTS, countDevOnlyFiles } from "./_dev-only-files.mjs";
35
35
  import { registerMcpServer } from "./_mcp-register.mjs";
36
36
  import { installCodexAgents } from "./_codex-agents.mjs";
37
- import { installAuthoredPluginSkills, pipelineOwnedSkillNames } from "./_plugin-skills.mjs";
37
+ import {
38
+ installAuthoredPluginSkills,
39
+ pipelineOwnedSkillNames,
40
+ pluginsToDeliver,
41
+ } from "./_plugin-skills.mjs";
42
+ import {
43
+ partitionExternalSkillsByPlugins,
44
+ writeExternalSkillsManifest,
45
+ } from "./_platform-filter.mjs";
38
46
  import { generateCodexInstructions } from "./_codex-instructions.mjs";
39
47
  import { mergeManagedBlock } from "./_managed-block.mjs";
40
48
 
@@ -230,7 +238,12 @@ function installRouterSkill(pipelineSrc, skillsDir) {
230
238
  const dest = join(skillsDir, "multi-agent");
231
239
  ensureDir(dest);
232
240
  writeFile(join(dest, "SKILL.md"), skill);
233
- console.log(` -> 1 router skill written to ${dest} (42 command specs stay as refs)`);
241
+
242
+ const commandsDir = join(pipelineSrc, "commands", "multi-agent");
243
+ const specCount = existsSync(commandsDir)
244
+ ? readdirSync(commandsDir, { withFileTypes: true }).filter((e) => e.isDirectory()).length
245
+ : 0;
246
+ console.log(` -> 1 router skill written to ${dest} (${specCount} command specs stay as refs)`);
234
247
  }
235
248
 
236
249
  /**
@@ -264,7 +277,7 @@ function pruneLegacyCommandSkills(skillsDir) {
264
277
  }
265
278
 
266
279
  /**
267
- * Install the reference tree: the shared `multi-agent-refs/` docs plus the 42
280
+ * Install the reference tree: the shared `multi-agent-refs/` docs plus every
268
281
  * sub-command specs, all path-rewritten. These are read on demand and never
269
282
  * enter the skills block.
270
283
  */
@@ -279,10 +292,10 @@ function installRefs(pipelineSrc, dest) {
279
292
  let count = 0;
280
293
  if (existsSync(refsSrc)) count += copyTreeRewritten(refsSrc, dest);
281
294
 
282
- // The 42 sub-command specs. Skip ONLY the top-level dispatcher SKILL.md -
295
+ // The sub-command specs. Skip ONLY the top-level dispatcher SKILL.md -
283
296
  // it already shipped as the router skill. The filter is on the path relative
284
297
  // to the copy root, not the basename: every sub-command spec is itself named
285
- // SKILL.md, so a basename filter would copy 42 empty directories and leave
298
+ // SKILL.md, so a basename filter would copy N empty directories and leave
286
299
  // the orchestrator with nothing to read.
287
300
  if (existsSync(commandsSrc)) {
288
301
  count += copyTreeRewritten(commandsSrc, join(dest, "commands"), (rel) => rel !== "SKILL.md");
@@ -389,7 +402,24 @@ function installSkillRefs(pipelineSrc, dest, home, platformFlag) {
389
402
  wipeDir(dest);
390
403
 
391
404
  let count = 0;
392
- if (existsSync(externalSrc)) count += copyTreeRewritten(externalSrc, dest);
405
+ if (existsSync(externalSrc)) {
406
+ // Active-stack filter (same contract as Copilot): Codex used to receive all
407
+ // 151 external skills regardless of stack - platformFlag only shaped the
408
+ // authored-plugin delivery below. The enabled-plugin set from
409
+ // ~/.claude/settings.json now bounds this copy too, so a Claude+Codex user
410
+ // sees one consistent stack surface across both hosts. The manifest makes
411
+ // the delivery inspectable; the wholesale wipeDir above already handles
412
+ // staleness on every install.
413
+ const { names: enabled, source: selectionSource } = pluginsToDeliver(home, platformFlag);
414
+ const { keep, skipped } = partitionExternalSkillsByPlugins(externalSrc, enabled);
415
+ for (const name of keep) {
416
+ count += copyTreeRewritten(join(externalSrc, name), join(dest, name));
417
+ }
418
+ writeExternalSkillsManifest(dest, keep);
419
+ console.log(
420
+ ` -> stack filter (${selectionSource}): ${keep.length} kept, ${skipped.length} skipped`,
421
+ );
422
+ }
393
423
 
394
424
  // `shared/core` also holds two skills that are NOT pipeline sub-commands:
395
425
  // apple-archive-compliance and google-play-compliance. Copying only `external`
@@ -24,11 +24,18 @@ import {
24
24
  wipeDir,
25
25
  writeFile,
26
26
  } from "./_common.mjs";
27
- import { copyExternalSkillsFiltered } from "./_platform-filter.mjs";
27
+ import {
28
+ partitionExternalSkillsByPlugins,
29
+ writeExternalSkillsManifest,
30
+ } from "./_platform-filter.mjs";
28
31
  import { DEV_ONLY_SCRIPTS, countDevOnlyFiles } from "./_dev-only-files.mjs";
29
32
  import { generateCopilotInstructions } from "./_copilot-instructions.mjs";
30
33
  import { legacyTrailingContent, mergeManagedBlock } from "./_managed-block.mjs";
31
- import { installAuthoredPluginSkills, pipelineOwnedSkillNames } from "./_plugin-skills.mjs";
34
+ import {
35
+ installAuthoredPluginSkills,
36
+ pipelineOwnedSkillNames,
37
+ pluginsToDeliver,
38
+ } from "./_plugin-skills.mjs";
32
39
  import { registerMcpServer } from "./_mcp-register.mjs";
33
40
 
34
41
  /**
@@ -357,16 +364,34 @@ function installSkills(opts) {
357
364
  }
358
365
 
359
366
  if (existsSync(sharedExternalSrc)) {
360
- const { copied, skipped } = copyExternalSkillsFiltered(sharedExternalSrc, dest, {
361
- platformFlag,
362
- useSymlinks,
363
- });
364
- copilotSkillCount += copied;
365
- if (skipped > 0) {
366
- console.log(
367
- ` -> --platform=${platformFlag} filter skipped ${skipped} external skill dir(s)`,
368
- );
367
+ // Active-stack filter: Copilot has no plugin loader, so its local copy is the
368
+ // only stack-skill source it has - but it should still carry the SAME stack
369
+ // set the enabled plugins serve on Claude Code, not the whole catalog. The
370
+ // enabled set comes from ~/.claude/settings.json (pluginsToDeliver); the
371
+ // --platform flag stays as the fallback for machines without one.
372
+ const { names: enabled, source: selectionSource } = pluginsToDeliver(home, platformFlag);
373
+ const { keep, skipped } = partitionExternalSkillsByPlugins(sharedExternalSrc, enabled);
374
+ ensureDir(dest);
375
+ for (const name of keep) {
376
+ const src = join(sharedExternalSrc, name);
377
+ const dst = join(dest, name);
378
+ if (!useSymlinks) wipeDir(dst);
379
+ copyDir(src, dst, { useSymlinks });
380
+ copilotSkillCount += countFiles(src);
381
+ }
382
+ // Stale prune: a skill delivered by a previous, wider stack selection must
383
+ // leave when the selection narrows, or the old stack lingers forever.
384
+ for (const name of skipped) {
385
+ const stale = join(dest, name);
386
+ if (!existsSync(stale) || isDryRun()) continue;
387
+ try {
388
+ rmSync(stale, { recursive: true, force: true });
389
+ } catch {
390
+ /* non-fatal */
391
+ }
369
392
  }
393
+ writeExternalSkillsManifest(dest, keep);
394
+ console.log(` -> stack filter (${selectionSource}): ${keep.length} kept, ${skipped.length} skipped`);
370
395
  }
371
396
 
372
397
  // The pre-migration figma-* skill copies are gone; the plugin owns component work
package/install/index.mjs CHANGED
@@ -187,7 +187,9 @@ function printSummary(opts) {
187
187
  // hand-registered entry became the only reason it worked on any given machine.
188
188
  console.log(" For UI testing, the dev-toolkit MCP server is registered automatically:");
189
189
  if (forClaude) {
190
- console.log(" Claude Code: claude mcp add --scope user dev-toolkit (user scope, all projects)");
190
+ console.log(
191
+ " Claude Code: claude mcp add --scope user dev-toolkit (user scope, all projects)",
192
+ );
191
193
  }
192
194
  if (forCopilot) {
193
195
  console.log(" Copilot CLI: copilot mcp add dev-toolkit");
@@ -195,7 +197,9 @@ function printSummary(opts) {
195
197
  if (forCodex) {
196
198
  console.log(" Codex CLI: codex mcp add dev-toolkit");
197
199
  }
198
- console.log(" Skipped only when the host CLI is not on PATH - the command to run is printed above.");
200
+ console.log(
201
+ " Skipped only when the host CLI is not on PATH - the command to run is printed above.",
202
+ );
199
203
  console.log("");
200
204
  console.log(" Uninstall everything: npx @mmerterden/multi-agent-pipeline uninstall");
201
205
  console.log(" (Personal access tokens in keychain are preserved.)");
@@ -62,7 +62,7 @@ failure this layout exists to prevent.
62
62
 
63
63
  Codex assembles every discovered skill's name + description into one prompt block
64
64
  and **silently drops entries when that block overflows**. The pipeline therefore
65
- contributes exactly **one** skill (`multi-agent`) and keeps its 42 sub-command
65
+ contributes exactly **one** skill (`multi-agent`) and keeps every sub-command
66
66
  specs as reference files that cost nothing until read. Do not convert those specs
67
67
  into peer skills: doing so evicts other skills, including ones from installed
68
68
  plugins, with no error surfaced.
@@ -33,17 +33,20 @@
33
33
  - **Fast + Local (multi-agent-dev-local)**: Dev on current branch - no worktree
34
34
  - **Fastest + Local (multi-agent-dev-local-autopilot)**: Dev + autopilot, no worktree
35
35
 
36
- ## Prompt Language (en/tr)
36
+ ## Language axes (en/tr)
37
37
 
38
- The pipeline honors `prefs.global.promptLanguage` (set via `/multi-agent:setup` or
39
- `/multi-agent:language en|tr`). This controls the language of **interactive prompts
40
- only** - e.g. the Phase 6 pre-commit local-checkout test prompt, Plan Approval Gate
41
- questions, multi-repo branch picker labels, and phase-banner.sh banners (when
42
- PHASE_LANG env is unset, it auto-reads prefs).
38
+ Two prefs, two jobs - the full matrix lives in `multi-agent-refs/rules.md`
39
+ "Language Application" and that file wins on any disagreement:
43
40
 
44
- Default: `en`. Supported: `en`, `tr`. Commit messages, PR bodies, Jira comments,
45
- and any external-facing payload **always stay in English** regardless of this
46
- setting - only the user-facing prompts change.
41
+ - `prefs.global.promptLanguage` is **locked to `en`**: every LLM-facing prompt,
42
+ spec file and instruction stays English.
43
+ - `prefs.global.outputLanguage` (set via `/multi-agent:setup` or
44
+ `/multi-agent:language en|tr`) drives what humans read: interactive prompts,
45
+ phase banners, AND the external payload **bodies** - PR description, Jira
46
+ comment, Confluence/Wiki pages all render in it.
47
+
48
+ Always English regardless of either pref: commit messages, branch names, PR
49
+ titles, code identifiers, file paths, and `AskUserQuestion` label/header.
47
50
 
48
51
  When writing TR prompts, use the same keyword/menu numbers as EN (e.g. `[1-4]`)
49
52
  so the user's input pattern stays language-agnostic.
@@ -242,7 +245,7 @@ Cost block reads `phase-tracker.sh tokens` accumulators × `cost-table.json` pri
242
245
 
243
246
  ## Stack Selection
244
247
 
245
- Stack skill sets ship as versioned plugins in the `multi-agent-plugins` marketplace. Selecting a stack enables the matching plugin(s) in the target repo's `.claude/settings.json` `enabledPlugins`; the `ai-common-engineering-toolkit` is always enabled alongside. There is no session-start auto-swap script. Select or change the stack with:
248
+ Stack skill sets ship as versioned plugins in the `multi-agent-plugins` marketplace. Selecting a stack enables the matching plugin(s) in the target repo's `.claude/settings.json` `enabledPlugins`; the `ai-common-toolkit` is always enabled alongside. There is no session-start auto-swap script. Select or change the stack with:
246
249
 
247
250
  ```bash
248
251
  multi-agent-stack [ios|android|mobile|backend|frontend|fullstack|all]
@@ -299,8 +302,8 @@ if [ "$(jq '.projects | length' "$STATE_FILE")" -ge 2 ]; then
299
302
  fi
300
303
  ```
301
304
 
302
- Full contract: `~/.copilot/skills/multi-agent/refs/multi-repo-integration-build.md`
303
- (or on GitHub: https://github.com/mmerterden/multi-agent-pipeline/blob/main/pipeline/multi-agent-refs/multi-repo-integration-build.md)
305
+ Full contract: https://github.com/mmerterden/multi-agent-pipeline/blob/main/pipeline/multi-agent-refs/multi-repo-integration-build.md
306
+ (the Copilot install ships no local refs tree, so the contract lives on GitHub only)
304
307
 
305
308
  ## Permissions Expectation
306
309
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "14.2.1",
3
+ "version": "15.0.0",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -89,7 +89,6 @@
89
89
  "!pipeline/scripts/sync-parity-check.sh",
90
90
  "!pipeline/scripts/benchmark-phase-0.sh",
91
91
  "!pipeline/scripts/fixtures/**",
92
- "!pipeline/scripts/test-gap-rules/**",
93
92
  "!pipeline/eval/**",
94
93
  "pipeline/scripts/smoke-schema-validation.sh",
95
94
  "pipeline/scripts/smoke-cross-cli-behavior.sh"
@@ -12,7 +12,7 @@ Parse the user input and route to the correct sub-command.
12
12
 
13
13
  **Input**: $ARGUMENTS
14
14
 
15
- > **Language (read FIRST)**: Before any status output, read `prefs.global.outputLanguage` from `$HOME/.claude/multi-agent-preferences.json` and render every conversational line in it. `AskUserQuestion` and external payloads stay English. Full contract: `$HOME/.claude/multi-agent-refs/rules.md` "Language Application".
15
+ > **Language (read FIRST)**: Before any status output, read `prefs.global.outputLanguage` from `$HOME/.claude/multi-agent-preferences.json` and render every conversational line in it. `AskUserQuestion` `label`/`header` stay English, but its `question` and option `description`s render in `outputLanguage`; external payload bodies follow `outputLanguage` too (identifiers, commit messages, branch names stay English). Full contract: `$HOME/.claude/multi-agent-refs/rules.md` "Language Application".
16
16
 
17
17
  ## Canonical Invocation (per CLI)
18
18
 
@@ -78,6 +78,7 @@ Lib scripts (`~/.claude/lib/`):
78
78
  | `review-jira [KEY\|url]` | Grade a Jira issue's readiness for the pipeline (scope / AC / repro / design / API / stack), then post the gaps as a Jira comment. Read-only on code. |
79
79
  | `review-issue [#N\|repo#N\|url]` | Grade a GitHub issue's readiness for the pipeline, then post the gaps as an issue comment. Read-only on code. |
80
80
  | `analysis ["<feature>"]` | Standalone feature-spec analizi: Figma / Swagger / Confluence / Jira / repo girdileri sabit 7-bölümlük şablona dökülür, humanizer'dan geçer, Local/Confluence/Jira hedef(ler)ine post edilir. Worktree veya commit yok. Dev'e zincirleme yok. |
81
+ | `complaint-analysis ["<run-name>"] [--file <path>] [<jira-id\|confluence-url> ...]` | Müşteri şikayeti triyajı: şikayetler (serbest metin / csv-xlsx-txt-json dosya / Jira issue / Confluence URL) redakte edilerek alınır, trxId/conversationId ile Graylog kanıtı çekilir, seçili client + BFF repolarında salt-okunur eşleştirme yapılır; verdict: client/bff (kök neden + citation + mevcut mimariyi referans alan fix planı + hazır dev prompt'u) veya core (core ekibine yönlendirme önerisi) veya insufficient-evidence. Rapor + Stop; worktree, commit, dev zinciri yok. |
81
82
  | `build-optimize` | iOS-only Xcode build performance wrapper. Vendored `xcode-build-orchestrator`'a dispatch eder; benchmark + compilation / project / SPM analyzer'lar + recommend-first plan `.build-benchmark/optimization-plan.md`. Non-iOS stack'lerde fail-fast. |
82
83
  | `channels [PR-url\|#N\|Jira-url\|Jira-id] [--channels pr,jira,confluence,wiki] [--content normal,test,auto-diff,note] [--message "..."]` | Post task report to multi-select channels (PR description, Jira comment, Confluence page, Wiki pages) with multi-select content sources. Humanizer pass per-channel. Bitbucket PR updates use reviewer-preserving PUT. Phase 7 delegates to this command; also invocable post-hoc for fixes made outside the pipeline. No worktree. |
83
84
  | `create-jira ["desc"] [figma-url] [swagger-url]` | Create a standards-compliant Jira issue: asks the type (**Task** / **Bug** / **Story**), mines the project's recent same-type issues for conventions (summary format, labels, priority, test-scenario style), detects the active sprint, drafts from a standard template with auto-sizing sections (Design Reference / API Contract / Screenshots appear only when their source is given), asks about unknown fields, then full draft preview + explicit approval before create. No worktree, no commits. |
@@ -120,6 +121,7 @@ This command uses lazy loading for token efficiency. Read the relevant sub-file
120
121
  | `review-jira` | `$HOME/.claude/commands/multi-agent/review-jira/SKILL.md` (loads `$HOME/.claude/multi-agent-refs/readiness-review.md`) |
121
122
  | `review-issue` | `$HOME/.claude/commands/multi-agent/review-issue/SKILL.md` (loads `$HOME/.claude/multi-agent-refs/readiness-review.md`) |
122
123
  | `analysis` | `$HOME/.claude/commands/multi-agent/analysis/SKILL.md` |
124
+ | `complaint-analysis` | `$HOME/.claude/commands/multi-agent/complaint-analysis/SKILL.md` |
123
125
  | `build-optimize` | `$HOME/.claude/commands/multi-agent/build-optimize/SKILL.md` |
124
126
  | `local` | `$HOME/.claude/commands/multi-agent/local/SKILL.md` |
125
127
  | `local-autopilot` | `$HOME/.claude/commands/multi-agent/local-autopilot/SKILL.md` |
@@ -207,7 +209,7 @@ When the user supplies an ID/URL/free-text:
207
209
  2. **Pick account** - always asked (autopilot picks default)
208
210
  3. **Fetch issue** - `lib/issue-fetcher.sh "$INPUT"` (Jira/GitHub fetch + maturity)
209
211
  4. **Repo picker** - only for `gh-num` (e.g. `316`) when repo is ambiguous, multi-select
210
- 5. **Maturity check** - blocker halts (autopilot too), warning prompt/log
212
+ 5. **Maturity check** - blocker halts (autopilot too), warning prompt/log. For a Jira input specifically, an empty own description with a non-empty parent surfaces as `description_empty_parent_available` (warning, not blocker) - ask the tailored parent-description question from `jira/SKILL.md`'s maturity section instead of the generic "Continue?" prompt.
211
213
  6. **Dev context** - always runs, empty submit allowed
212
214
  7. → Interactive Launcher → Phase 0
213
215
 
@@ -505,9 +505,9 @@ For each `platform` in `state.analysisSpec.platforms[]`:
505
505
 
506
506
  2. **Per-platform markdown render**: for each platform in `state.analysisSpec.platforms[]`, concatenate the per-platform spec into one markdown file. Tables in pipe-syntax. Numbering uses plain `## 1.`, `## 2.`, ... - omitted sections do **not** create gaps. Visible numbering is sequential 1..N over the rendered set.
507
507
 
508
- 3. **Humanizer pass (MANDATORY: actually invoke the `humanizer` skill on the rendered markdown - the punctuation grep alone does NOT satisfy this step)** (`technical-explanatory` tone for the scratch buffer; per-channel re-humanize happens in Phase 4 when actually emitting):
508
+ 3. **Humanizer pass (MANDATORY: actually invoke the `ai-common-toolkit:humanizer` skill on the rendered markdown - the punctuation grep alone does NOT satisfy this step)** (`technical-explanatory` tone for the scratch buffer; per-channel re-humanize happens in Phase 4 when actually emitting):
509
509
  ```
510
- humanizer skill input:
510
+ ai-common-toolkit:humanizer skill input:
511
511
  language: <tr|en>
512
512
  tone: technical-explanatory
513
513
  stripFancyPunctuation: true
@@ -543,7 +543,7 @@ options:
543
543
 
544
544
  Conditional follow-ups:
545
545
  - If `Confluence` selected: ask `header="Parent page"`, free-text via Other for the parent page key or URL. One Confluence page per platform is created under this parent, each titled `<Feature> - <Platform>`.
546
- - If `Jira` selected: if Step 5 Q4 produced Jira IDs, AskUserQuestion (single-select) to pick which one; otherwise ask via Other. Per Locked decision 9 + design choice "single description with platform separators", the chosen issue receives one combined description body holding all per-platform sections under `## Platform: <X>` headings.
546
+ - If `Jira` selected: if Step 5 Q4 produced Jira IDs, AskUserQuestion (single-select) to pick which one; otherwise ask via Other. Per Locked decision 9 + design choice "single description with platform separators", the chosen issue receives one combined description body holding all per-platform sections under `h2. Platform: <X>` separators (wiki markup - the description field does not render Markdown; conversion happens at dispatch, see Phase 4).
547
547
 
548
548
  Result: `state.analysisSpec.outputs.requested[]`.
549
549
 
@@ -565,7 +565,7 @@ Iterate `state.analysisSpec.outputs.requested`. For each target:
565
565
  |--------|--------|
566
566
  | Local | For each per-platform draft, `cp /tmp/analysis-<feature-slug>-<ts>/<feature>-<platform>.md` into `analysis/<feature>-<platform>.md` in the matching repo's working tree. When multiple repos exist for the same platform, the file is duplicated into each and the dispatch report lists every destination. **No commit.** |
567
567
  | Confluence | Re-humanize each per-platform draft with `formal-stakeholder` tone. One Confluence page per platform under the chosen parent, titled `<Feature> - <Platform>`. Cross-link siblings inside each page via `<ac:link><ri:page ri:content-title="<Feature> - <OtherPlatform>"/></ac:link>`. Markdown -> storage XML via `$HOME/.claude/multi-agent-refs/channels/confluence.md`. Re-emit on existing pages uses PUT with version bump. |
568
- | Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate per-platform drafts under `## Platform: iOS`, `## Platform: Android`, `## Platform: Backend`, `## Platform: Frontend` separators (in the order platforms were selected). PUT the chosen issue's description via `$HOME/.claude/multi-agent-refs/channels/jira.md`. |
568
+ | Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate per-platform drafts under `h2. Platform: iOS`, `h2. Platform: Android`, `h2. Platform: Backend`, `h2. Platform: Frontend` separators (in the order platforms were selected), then run the whole body through the markdown → Jira wiki conversion table in `$HOME/.claude/multi-agent-refs/channels/jira.md` - the `description` field renders wiki markup, so raw `##`/`**`/backticks arrive as literal text. Write with `PUT /rest/api/2/issue/{key}` body `{"fields": {"description": <converted body>}}` (`channels/jira.md` documents only the comment POST; the description update is this PUT). Same rawfile + `--data-binary` transport rules. |
569
569
 
570
570
  **Output capture**: fill `state.analysisSpec.outputs.localPaths[]` (one entry per per-platform-per-repo write), `outputs.confluencePageUrls[]` (one entry per platform), `outputs.jiraIssueKey` (single string).
571
571
 
@@ -662,7 +662,7 @@ When `phase == "cancelled_at_pass_b_preview"`:
662
662
  | `~/.claude/lib/extract-conventions.sh` | Phase 1c convention extractor (7 pattern groups, JSON output, confidence levels) |
663
663
  | `~/.claude/lib/figma-screenshot.sh` | Phase 2b Tier 2 Figma image downloader (REST API, section drill, 2x scale PNG, manifest.json) |
664
664
  | `~/.claude/lib/md2confluence-v3.py` | Phase 4 Confluence dispatch (multipart attachments, `<ac:image>` injection, mermaid macro + fallback, tooltip footnote macro, punctuation gate) |
665
- | `$HOME/.claude/skills/humanizer/SKILL.md` | Phase 3 tone pass |
665
+ | `ai-common-toolkit:humanizer` | Phase 3 tone pass |
666
666
  | 8-locale set (ar, de, en, es, fr, it, ru, tr) + localization-key naming (inline) | Section 10 localization generation |
667
667
  | `$HOME/.claude/multi-agent-refs/channels/confluence.md` | Phase 4 Confluence dispatch |
668
668
  | `$HOME/.claude/multi-agent-refs/channels/jira.md` | Phase 4 Jira dispatch |