@mmerterden/multi-agent-pipeline 15.4.0 → 15.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.
package/CHANGELOG.md CHANGED
@@ -16,6 +16,15 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [15.5.0] - 2026-08-18
20
+
21
+ ### Added
22
+ - **`sharedUtilities` census bucket** - the bind-don't-rebuild inventory: formatter families, validation rule types + per-module facades and design-token namespaces living outside screen slices, counted with samples; Phase 3 treats a non-empty bucket as binding.
23
+
24
+ ### Fixed
25
+ - **Smoke runs never touch the live dashboard** - run-smokes exports `MULTI_AGENT_SMOKE=1` and phase-tracker's live ping returns under it (test gates were leaving phantom "running" rows on the timeline).
26
+ - **Routing resolves the multi-agent-plugins toolkit first** - the public toolkit family is the pipeline's standard companion; a corporate variant is the fallback, not the default.
27
+
19
28
  ## [15.4.0] - 2026-08-18
20
29
 
21
30
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "15.4.0",
3
+ "version": "15.5.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",
@@ -1026,6 +1026,43 @@ bucket_di_registration() {
1026
1026
  # =============================================================================
1027
1027
  # Assemble final JSON
1028
1028
  # =============================================================================
1029
+
1030
+ # =============================================================================
1031
+ # C13 - sharedUtilities: the bind-don't-rebuild inventory
1032
+ # =============================================================================
1033
+ # What shared machinery already exists OUTSIDE screen slices - formatter families,
1034
+ # validation rule types + per-module rule facades, design-token namespaces. A dev
1035
+ # phase that sees a non-empty bucket binds these instead of hand-rolling a
1036
+ # duplicate; the counts say how settled each family is.
1037
+ bucket_shared_utilities() {
1038
+ local ext screens_seg
1039
+ case "$PLATFORM" in
1040
+ ios) ext='*.swift' ; screens_seg='/Screens/' ;;
1041
+ android) ext='*.kt' ; screens_seg='/screens/' ;;
1042
+ *) empty_bucket; return ;;
1043
+ esac
1044
+ local files
1045
+ files=$(run_find -type f -name "$ext" 2>/dev/null | grep -v "$screens_seg" | grep -viE '/tests?/|/generated/' || true)
1046
+ if [ -z "$files" ]; then empty_bucket; return; fi
1047
+ local fmt rules facades tokens
1048
+ fmt=$(printf '%s
1049
+ ' "$files" | grep -cE '(Formatter|Format)\.(swift|kt)$' || true)
1050
+ rules=$(printf '%s
1051
+ ' "$files" | grep -cE '[A-Za-z]Rule\.(swift|kt)$' || true)
1052
+ facades=$(printf '%s
1053
+ ' "$files"| grep -cE '(FormRules|ValidationRules)\.(swift|kt)$' || true)
1054
+ tokens=$(printf '%s
1055
+ ' "$files" | grep -cE '(Tokens?|Spacing|Radius|Typography)[A-Za-z]*\.(swift|kt)$' || true)
1056
+ fmt=${fmt:-0}; rules=${rules:-0}; facades=${facades:-0}; tokens=${tokens:-0}
1057
+ local total=$((fmt + rules + facades + tokens))
1058
+ if [ "$total" -eq 0 ]; then empty_bucket; return; fi
1059
+ local sample
1060
+ sample=$(printf '%s
1061
+ ' "$files" | grep -E '(Formatter|Format|Rule|FormRules|ValidationRules|Tokens?|Spacing|Radius|Typography)[A-Za-z]*\.(swift|kt)$' | head -5 | sed "s|^$REPO_PATH/||")
1062
+ emit_bucket "formatters:$fmt rules:$rules facades:$facades tokens:$tokens" "$(printf '%s
1063
+ ' "$sample" | head -1)" "$(confidence_for "$total")" "$(files_to_json "$sample")" "[]"
1064
+ }
1065
+
1029
1066
  folderStructure=$(run_bucket_with_timeout bucket_folder_structure)
1030
1067
  stateHolderNaming=$(run_bucket_with_timeout bucket_state_holder)
1031
1068
  viewNaming=$(run_bucket_with_timeout bucket_view_naming)
@@ -1038,6 +1075,7 @@ testMethodNaming=$(run_bucket_with_timeout bucket_test_method_naming)
1038
1075
  accessibilityIdentifier=$(run_bucket_with_timeout bucket_accessibility_identifier)
1039
1076
  localizationKey=$(run_bucket_with_timeout bucket_localization_key)
1040
1077
  diRegistration=$(run_bucket_with_timeout bucket_di_registration)
1078
+ sharedUtilities=$(run_bucket_with_timeout bucket_shared_utilities)
1041
1079
 
1042
1080
  jq -n \
1043
1081
  --argjson folderStructure "$folderStructure" \
@@ -1052,6 +1090,7 @@ jq -n \
1052
1090
  --argjson accessibilityIdentifier "$accessibilityIdentifier" \
1053
1091
  --argjson localizationKey "$localizationKey" \
1054
1092
  --argjson diRegistration "$diRegistration" \
1093
+ --argjson sharedUtilities "$sharedUtilities" \
1055
1094
  '{
1056
1095
  folderStructure: $folderStructure,
1057
1096
  stateHolderNaming: $stateHolderNaming,
@@ -1064,7 +1103,8 @@ jq -n \
1064
1103
  testMethodNaming: $testMethodNaming,
1065
1104
  accessibilityIdentifier: $accessibilityIdentifier,
1066
1105
  localizationKey: $localizationKey,
1067
- diRegistration: $diRegistration
1106
+ diRegistration: $diRegistration,
1107
+ sharedUtilities: $sharedUtilities
1068
1108
  }'
1069
1109
 
1070
1110
  exit 0
@@ -22,15 +22,15 @@ Platform comes from the same mapping component dispatch uses, so the two cannot
22
22
 
23
23
  | `state.platform` / detected stack | Toolkit candidates, first enabled wins |
24
24
  |---|---|
25
- | ios, swift | `ai-ios-engineering-toolkit`, then `ai-ios-toolkit` |
26
- | android, kotlin | `ai-android-engineering-toolkit`, then `ai-android-toolkit` |
25
+ | ios, swift | `ai-ios-toolkit`, then `ai-ios-engineering-toolkit` |
26
+ | android, kotlin | `ai-android-toolkit`, then `ai-android-engineering-toolkit` |
27
27
  | anything else | no toolkit - step is a recorded no-op |
28
28
 
29
- A row is an ORDERED candidate list, not one name: the corporate toolkit (where one exists)
30
- carries the project-specific doctrine and outranks its public derivation, so it resolves first.
31
- Probe the candidates in order against the enabled plugins and take the first hit. When none is
32
- enabled, the recorded no-op names every candidate probed - a repo that enabled a corporate
33
- toolkit the table did not know about must show up as a probe miss, never as silence.
29
+ A row is an ORDERED candidate list, not one name: the multi-agent-plugins toolkit is the
30
+ pipeline's standard companion and resolves first; a corporate variant is the fallback for a
31
+ repo that enables only it. Probe the candidates in order against the enabled plugins and take
32
+ the first hit. When none is enabled, the recorded no-op names every candidate probed - an
33
+ enabled toolkit the table did not know about must show up as a probe miss, never as silence.
34
34
 
35
35
  The toolkit is enabled per repo (`.claude/settings.local.json` / `~/.claude/settings.json` `enabledPlugins`). **Not enabled is not an error here**, unlike component dispatch: a backend or web repo legitimately has no toolkit, and halting would make the pipeline unusable outside mobile. Record the no-op and continue.
36
36
 
@@ -26,7 +26,7 @@ Pre-flight steps (run in order, abort on failure).
26
26
 
27
27
  5. **Standards binding citations**: read `analysis Section 21 References` table. For each row with `Rol: bağlayıcı / binding`, persist the source path into `state.dev.standardsBindings[]`. Phase 3 Dev tasks MUST cite at least one binding source per architectural decision (pre-existing Locked decision 8).
28
28
 
29
- 6. **Conventions handoff**: read `analysis Section 13.1 Concept Table` (Pass B output with footnotes). Persist concept-to-realization mapping into `state.dev.conventions[<concept>]`. Phase 3 implementation uses these names verbatim (e.g., if Section 13.1 says "State holder: PassengerFlightViewModel", Phase 3 names the class exactly `PassengerFlightViewModel`).
29
+ 6. **Conventions handoff**: read `analysis Section 13.1 Concept Table` (Pass B output with footnotes). Persist concept-to-realization mapping into `state.dev.conventions[<concept>]`. Phase 3 implementation uses these names verbatim, and a non-empty `sharedUtilities` bucket is binding: bind those formatters/rule-facades/tokens, never hand-roll a duplicate (e.g., if Section 13.1 says "State holder: PassengerFlightViewModel", Phase 3 names the class exactly `PassengerFlightViewModel`).
30
30
 
31
31
  7. **MCP forbidden**: calling `mcp__claude_ai_Figma__*` in Phase 3 is a violation. `smoke-no-mcp-in-dev-phases.sh` reads `state.telemetry.mcpCalls[]` after the run and fails if Phase 3 contributed an entry.
32
32
 
@@ -18,27 +18,61 @@
18
18
  "testMethodNaming",
19
19
  "accessibilityIdentifier",
20
20
  "localizationKey",
21
- "diRegistration"
21
+ "diRegistration",
22
+ "sharedUtilities"
22
23
  ],
23
24
  "properties": {
24
- "folderStructure": { "$ref": "#/$defs/conventionBucket" },
25
- "stateHolderNaming": { "$ref": "#/$defs/conventionBucket" },
26
- "viewNaming": { "$ref": "#/$defs/conventionBucket" },
27
- "navigatorNaming": { "$ref": "#/$defs/conventionBucket" },
28
- "useCaseNaming": { "$ref": "#/$defs/conventionBucket" },
29
- "repositoryNaming": { "$ref": "#/$defs/conventionBucket" },
30
- "dtoNaming": { "$ref": "#/$defs/conventionBucket" },
31
- "uiStateModel": { "$ref": "#/$defs/conventionBucket" },
32
- "testMethodNaming": { "$ref": "#/$defs/conventionBucket" },
33
- "accessibilityIdentifier": { "$ref": "#/$defs/conventionBucket" },
34
- "localizationKey": { "$ref": "#/$defs/conventionBucket" },
35
- "diRegistration": { "$ref": "#/$defs/conventionBucket" }
25
+ "folderStructure": {
26
+ "$ref": "#/$defs/conventionBucket"
27
+ },
28
+ "stateHolderNaming": {
29
+ "$ref": "#/$defs/conventionBucket"
30
+ },
31
+ "viewNaming": {
32
+ "$ref": "#/$defs/conventionBucket"
33
+ },
34
+ "navigatorNaming": {
35
+ "$ref": "#/$defs/conventionBucket"
36
+ },
37
+ "useCaseNaming": {
38
+ "$ref": "#/$defs/conventionBucket"
39
+ },
40
+ "repositoryNaming": {
41
+ "$ref": "#/$defs/conventionBucket"
42
+ },
43
+ "dtoNaming": {
44
+ "$ref": "#/$defs/conventionBucket"
45
+ },
46
+ "uiStateModel": {
47
+ "$ref": "#/$defs/conventionBucket"
48
+ },
49
+ "testMethodNaming": {
50
+ "$ref": "#/$defs/conventionBucket"
51
+ },
52
+ "accessibilityIdentifier": {
53
+ "$ref": "#/$defs/conventionBucket"
54
+ },
55
+ "localizationKey": {
56
+ "$ref": "#/$defs/conventionBucket"
57
+ },
58
+ "diRegistration": {
59
+ "$ref": "#/$defs/conventionBucket"
60
+ },
61
+ "sharedUtilities": {
62
+ "$ref": "#/$defs/conventionBucket"
63
+ }
36
64
  },
37
65
  "$defs": {
38
66
  "conventionBucket": {
39
67
  "type": "object",
40
68
  "additionalProperties": false,
41
- "required": ["pattern", "example", "confidence", "evidenceFiles", "alternativeCandidates"],
69
+ "required": [
70
+ "pattern",
71
+ "example",
72
+ "confidence",
73
+ "evidenceFiles",
74
+ "alternativeCandidates"
75
+ ],
42
76
  "properties": {
43
77
  "pattern": {
44
78
  "type": "string",
@@ -50,18 +84,27 @@
50
84
  },
51
85
  "confidence": {
52
86
  "type": "string",
53
- "enum": ["high", "medium", "low", "none"],
87
+ "enum": [
88
+ "high",
89
+ "medium",
90
+ "low",
91
+ "none"
92
+ ],
54
93
  "description": "high: 5+ examples; medium: 3-4; low: 1-2 or mixed; none: no evidence."
55
94
  },
56
95
  "evidenceFiles": {
57
96
  "type": "array",
58
- "items": { "type": "string" },
97
+ "items": {
98
+ "type": "string"
99
+ },
59
100
  "maxItems": 5,
60
101
  "description": "Repo-relative or absolute paths backing the detection (capped at 5)."
61
102
  },
62
103
  "alternativeCandidates": {
63
104
  "type": "array",
64
- "items": { "type": "string" },
105
+ "items": {
106
+ "type": "string"
107
+ },
65
108
  "description": "Competing patterns that were observed but lost the majority vote."
66
109
  }
67
110
  }
@@ -121,6 +121,9 @@ need_jq() {
121
121
  # the Phase 7 / halt emit that reads the real run status. The emitter no-ops
122
122
  # unless prefs.global.usageLog.enabled; detached so it never blocks a boundary.
123
123
  usage_live_ping() {
124
+ # Smoke runs exercise this script's state handling, never the live dashboard -
125
+ # a test gate must not leave phantom "running" rows on the timeline.
126
+ [ -n "${MULTI_AGENT_SMOKE:-}" ] && return 0
124
127
  local task="$1" phase="$2"
125
128
  local script="$HOME/.claude/scripts/usage-report.mjs"
126
129
  local prefs="$HOME/.claude/multi-agent-preferences.json"