@mmerterden/multi-agent-pipeline 14.2.2 → 15.1.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 +186 -6
- package/README.md +19 -12
- package/README.tr.md +19 -12
- package/SECURITY.md +43 -0
- package/docs/FIGMA_PIPELINE.md +3 -3
- package/docs/adr/0006-skills-core-external-split.md +1 -1
- package/docs/adr/0007-multi-tool-adapter-framework.md +1 -1
- package/docs/adr/0009-claude-stack-skills-plugin-only.md +31 -0
- package/docs/adr/README.md +1 -0
- package/docs/architecture.md +13 -13
- package/docs/ecosystem.md +31 -31
- package/docs/features.md +5 -5
- package/index.js +6 -1
- package/install/_codex-agents.mjs +11 -2
- package/install/_common.mjs +109 -3
- package/install/_dev-only-files.mjs +0 -1
- package/install/_platform-filter.mjs +54 -113
- package/install/_plugin-skills.mjs +36 -36
- package/install/claude.mjs +251 -61
- package/install/codex.mjs +28 -6
- package/install/copilot.mjs +69 -9
- package/install/index.mjs +9 -3
- package/install/templates/codex-instructions.md +1 -1
- package/install/templates/copilot-instructions.md +3 -3
- package/package.json +2 -3
- package/pipeline/commands/multi-agent/SKILL.md +2 -0
- package/pipeline/commands/multi-agent/analysis/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/channels/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +186 -0
- package/pipeline/commands/multi-agent/dev/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/help/SKILL.md +19 -4
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/jira/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +81 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +36 -1
- package/pipeline/commands/multi-agent/resume/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/{ship → resume-local}/SKILL.md +8 -8
- package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/stack/SKILL.md +62 -40
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/sync/SKILL.md +18 -11
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +2 -0
- package/pipeline/commands/multi-agent/update/SKILL.md +4 -4
- package/pipeline/lib/issue-fetcher.sh +1 -1
- package/pipeline/lib/parse-complaints.sh +316 -0
- package/pipeline/multi-agent-refs/channels/wiki.md +3 -3
- package/pipeline/multi-agent-refs/complaint-analysis-template.md +99 -0
- package/pipeline/multi-agent-refs/component-dispatch.md +6 -6
- package/pipeline/multi-agent-refs/cross-cli-contract.md +16 -16
- package/pipeline/multi-agent-refs/features/external-context-injection.md +1 -1
- package/pipeline/multi-agent-refs/features/stack-skill-routing.md +5 -5
- package/pipeline/multi-agent-refs/generate-issue.md +1 -1
- package/pipeline/multi-agent-refs/phases/modes.md +1 -1
- package/pipeline/multi-agent-refs/phases/operations.md +7 -1
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +7 -7
- package/pipeline/multi-agent-refs/phases/phase-2-planning.md +5 -5
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +3 -3
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +12 -12
- package/pipeline/multi-agent-refs/phases/phase-5-test.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-7-report.md +6 -0
- package/pipeline/multi-agent-refs/tracker-contract.md +3 -2
- package/pipeline/multi-agent-refs/wiki-capture.md +2 -2
- package/pipeline/preferences-template.json +18 -5
- package/pipeline/rules/figma-pipeline.md +2 -2
- package/pipeline/schemas/agent-state.schema.json +1 -1
- package/pipeline/schemas/complaint-analysis-spec.schema.json +216 -0
- package/pipeline/schemas/migrations/prefs-2.5.0-to-2.6.0.mjs +46 -0
- package/pipeline/schemas/prefs.schema.json +296 -66
- package/pipeline/schemas/token-budget.json +2 -2
- package/pipeline/scripts/README.md +4 -3
- package/pipeline/scripts/_stack-routing.mjs +79 -0
- package/pipeline/scripts/audit-log-rotate.sh +4 -1
- package/pipeline/scripts/build-skills-index.mjs +11 -0
- package/pipeline/scripts/build-stack-plugins.mjs +28 -60
- package/pipeline/scripts/check-derived-drift.mjs +55 -28
- package/pipeline/scripts/gc-worktrees.sh +4 -1
- package/pipeline/scripts/gen-skills-index.mjs +1 -1
- package/pipeline/scripts/match-skills.mjs +12 -2
- package/pipeline/scripts/migrate-prefs.mjs +33 -21
- package/pipeline/scripts/phase-tracker.sh +32 -5
- package/pipeline/scripts/phase0-exit-gate.mjs +3 -2
- package/pipeline/scripts/run-aggregator.mjs +7 -2
- package/pipeline/scripts/scan-agent-config.sh +1 -1
- package/pipeline/scripts/skill-conformance.mjs +165 -30
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +1 -1
- package/pipeline/scripts/test-gap-rules/android.json +25 -0
- package/pipeline/scripts/test-gap-rules/ios.json +34 -0
- package/pipeline/scripts/test-gap-rules/node.json +29 -0
- package/pipeline/scripts/test-gap-rules/python.json +25 -0
- package/pipeline/scripts/uninstall.mjs +160 -11
- package/pipeline/scripts/usage-report.mjs +426 -0
- package/pipeline/scripts/validate-complaint-doc.mjs +250 -0
- package/pipeline/scripts/validate-reviewer.mjs +9 -3
- package/pipeline/skills/.skill-manifest.json +156 -108
- package/pipeline/skills/.skills-index.json +449 -12
- package/pipeline/skills/shared/README.md +14 -10
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +49 -0
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +83 -0
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +153 -90
- package/pipeline/skills/shared/core/{multi-agent-ship → multi-agent-resume-local}/SKILL.md +6 -6
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +89 -22
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +1 -1
- package/pipeline/skills/shared/external/ios-coding-standard/modules/_TEMPLATE.yml +2 -2
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +368 -33
- package/pipeline/skills/shared/external/ios-coding-standard/references/swiftlint.draft.yml +1 -2
- package/pipeline/skills/shared/external/ios-coding-standard/scripts/check_structure.py +765 -0
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +75 -0
- package/pipeline/skills/shared/external/ios-module-structure/modules/_TEMPLATE.yml +131 -0
- package/pipeline/skills/shared/external/ios-module-structure/references/rules.yml +559 -0
- package/pipeline/skills/shared/external/ios-module-structure/scripts/check_structure.py +765 -0
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +53 -10
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +4 -3
- package/pipeline/skills/skills-index.md +7 -4
|
@@ -59,8 +59,8 @@ Run every step automatically:
|
|
|
59
59
|
```
|
|
60
60
|
Step 1: PLATFORM Detect macOS / Linux / Windows (Git Bash / WSL); export PLATFORM env
|
|
61
61
|
Step 1.5: DETECT Compare timestamps, find stale targets
|
|
62
|
-
Step 2: COPILOT Claude Code -> Copilot CLI (instructions +
|
|
63
|
-
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill +
|
|
62
|
+
Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 51 sub-command skills)
|
|
63
|
+
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill + 51 specs as refs + 8 agent TOML)
|
|
64
64
|
Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
|
|
65
65
|
Step 3c: PLUGINS pipeline shared/external -> multi-agent-plugins marketplace (rebuild knowledge/,
|
|
66
66
|
bump changed plugins' patch version, commit + push the plugins repo)
|
|
@@ -127,13 +127,13 @@ If nothing is stale → report "All targets up to date" and stop.
|
|
|
127
127
|
- `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
|
|
128
128
|
- `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh`, `agent-guard.sh`, `agent-guard.py`, and `build-stack-plugins.mjs` (generic, synced)
|
|
129
129
|
- `~/.claude/settings.json`
|
|
130
|
-
- **Any `~/.claude/commands/multi-agent/*.md` whose frontmatter has `local-only: true`** - these are user/repo-specific alias wrappers that delegate to a private marketplace plugin (e.g. corporate `ai-ios-
|
|
130
|
+
- **Any `~/.claude/commands/multi-agent/*.md` whose frontmatter has `local-only: true`** - these are user/repo-specific alias wrappers that delegate to a private marketplace plugin (e.g. corporate `ai-ios-toolkit` skills exposed as `multi-agent:<name>`). Syncing them would leak the private plugin/skill names into the public pipeline. Filter before copy: skip every source file containing `local-only: true`, and after copy assert none reached `pipeline/commands/`.
|
|
131
131
|
```bash
|
|
132
132
|
# backstop: no local-only wrapper may exist in the synced target
|
|
133
133
|
grep -rl "^local-only: true" ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
|
|
134
134
|
&& { echo "ABORT: local-only wrapper leaked into pipeline/commands"; exit 1; } || true
|
|
135
135
|
# backstop: no corporate marketplace/skill reference in the synced tree
|
|
136
|
-
grep -rniE "ai-ios-engineering
|
|
136
|
+
grep -rniE "ai-ios(-engineering)?-toolkit:(create-ui-component|evolve-ui-component|fix-bug|branch-and-pr|backlog|code-connect|figma-utility|resource-utility|component-wiki|component-docs|figma-setup)" \
|
|
137
137
|
~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
|
|
138
138
|
&& { echo "ABORT: corporate reference leaked into pipeline/commands"; exit 1; } || true
|
|
139
139
|
```
|
|
@@ -176,7 +176,7 @@ If nothing is stale → report "All targets up to date" and stop.
|
|
|
176
176
|
Unlike the Copilot step, this one does **not** hand-copy files. The Codex tree is a
|
|
177
177
|
*transform* of the Claude tree, not a mirror of it, and the transform is real work:
|
|
178
178
|
|
|
179
|
-
- the
|
|
179
|
+
- the 51 sub-command specs become reference files, because Codex silently truncates
|
|
180
180
|
its skills block (see `cross-cli-contract.md` 2.6 for the measurement)
|
|
181
181
|
- every `$HOME/.claude/...` reference to a CLI-owned tree is retargeted, with
|
|
182
182
|
`agents/<persona>.md` becoming `.toml` and the dispatcher becoming the router skill
|
|
@@ -233,13 +233,20 @@ node "$HOME/multi-agent-pipeline/pipeline/scripts/build-stack-plugins.mjs" --dry
|
|
|
233
233
|
|
|
234
234
|
# 2. Apply: rebuild each stack plugin's knowledge/ from shared/external,
|
|
235
235
|
# regenerate plugin.json skills[], bump the patch version of any plugin
|
|
236
|
-
# whose skill set changed. Cross-stack skills -> ai-common-
|
|
236
|
+
# whose skill set changed. Cross-stack skills -> ai-common-toolkit;
|
|
237
237
|
# Apple/Xcode-only skills -> iOS plugin only.
|
|
238
238
|
node "$HOME/multi-agent-pipeline/pipeline/scripts/build-stack-plugins.mjs"
|
|
239
239
|
```
|
|
240
240
|
|
|
241
241
|
**Version-based management:** the generator bumps a plugin's `version` (patch) only when its skill set actually changed. Idempotent - a no-op run bumps nothing. Consumers pick up new versions via `/multi-agent:update` (which runs `claude marketplace update multi-agent-plugins`).
|
|
242
242
|
|
|
243
|
+
**Help + README freshness (mandatory when the generator reported any change):**
|
|
244
|
+
|
|
245
|
+
1. Every plugin ships a `tools/help` skill that renders its catalog LIVE from `plugin.json`, so it needs no per-skill edits - but verify each changed plugin still registers it (`grep -c "./skills/tools/help" plugins/<name>/.claude-plugin/plugin.json` = 1) and that a new plugin gets one before publish.
|
|
246
|
+
2. Plugin README tables sync through `python3 tools/bump.py <plugin> --set <version>`; run `python3 tools/bump.py --check` and treat DRIFT as a blocker.
|
|
247
|
+
3. `python3 tools/validate.py` must be clean (it also enforces the CHANGELOG heading for every bumped version - write the entry, do not backdate).
|
|
248
|
+
4. When the pipeline's command surface changed in the same sync (new/renamed `/multi-agent:*` commands), confirm `commands/multi-agent/help/SKILL.md` and both pipeline READMEs (`README.md`, `README.tr.md`) were updated in Step 3 before pushing here.
|
|
249
|
+
|
|
243
250
|
**Publish (only if the generator reported bumps):**
|
|
244
251
|
|
|
245
252
|
```bash
|
|
@@ -484,21 +491,21 @@ When invoked with the `release` argument:
|
|
|
484
491
|
> Codex takes the Step 2b path instead; see that section.
|
|
485
492
|
|
|
486
493
|
This runs on the Claude <-> Copilot axis. Codex is NOT synced here: it receives the
|
|
487
|
-
same
|
|
494
|
+
same 51 specs as reference files rather than as peer skills, via Step 2b - see
|
|
488
495
|
`cross-cli-contract.md` 2.6 for why the parity axis differs per host.
|
|
489
496
|
|
|
490
497
|
| Claude Code | Copilot CLI |
|
|
491
498
|
|-------------|-------------|
|
|
492
499
|
| `~/.claude/commands/multi-agent/{cmd}/SKILL.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
|
|
493
500
|
|
|
494
|
-
**
|
|
501
|
+
**51 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
|
|
495
502
|
|
|
496
503
|
```
|
|
497
|
-
analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, design-check, dev,
|
|
504
|
+
analysis, analysis-resolve, autopilot, build-optimize, channels, complaint-analysis, create-jira, design-check, dev,
|
|
498
505
|
dev-autopilot, dev-local, dev-local-autopilot, diff-explain, forget, garbage-collect,
|
|
499
506
|
help, ios-coding-standard, issue, jira, kill, language, local,
|
|
500
|
-
local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review, review-issue, review-jira,
|
|
501
|
-
routines, save, scan, search, setup,
|
|
507
|
+
local-autopilot, log, manual-test, prune-logs, prune-prompts, purge, refactor, resume, review, review-issue, review-jira,
|
|
508
|
+
routines, save, scan, search, setup, resume-local, stack, status, store-ready, sync, test, test-accessibility,
|
|
502
509
|
test-dark-mode, test-dynamic-type, test-screenshots, testflight-validation, uninstall, update
|
|
503
510
|
```
|
|
504
511
|
|
|
@@ -40,7 +40,7 @@ Unchanged from before the merge, on the iOS path:
|
|
|
40
40
|
|---|---|---|
|
|
41
41
|
| **1. Static** | `ios_app_store_audit` (18 rules, real ITMS codes) | an `.xcarchive` |
|
|
42
42
|
| **2. Authoritative** | `ios_testflight_validate` → `altool --validate-app` | an `.ipa` + credentials |
|
|
43
|
-
| **3. Policy** | `app-store-review` skill vs repo source | repo checkout |
|
|
43
|
+
| **3. Policy** | `ai-ios-toolkit:app-store-review` skill vs repo source | repo checkout |
|
|
44
44
|
|
|
45
45
|
A skipped gate is never folded into the pass count, and the run never uploads. The
|
|
46
46
|
report lands in `~/StoreChecks/ios-<repo>-<branch>-<timestamp>/report.md`.
|
|
@@ -28,6 +28,8 @@ Tokens in the OS credential store are NEVER removed by either mode.
|
|
|
28
28
|
- `~/.claude/CLAUDE.md` (user customisations)
|
|
29
29
|
- `~/.claude/rules/` (user-owned; installed write-if-missing, never overwritten)
|
|
30
30
|
- User content OUTSIDE the `<!-- multi-agent-pipeline:begin/end -->` markers (`copilot-instructions.md`)
|
|
31
|
+
- Local-only alias wrappers (`local-only: true` frontmatter) under `commands/multi-agent/` (user-authored, exist nowhere else)
|
|
32
|
+
- User-authored skill dirs and agent files (only pipeline-shipped names are removed)
|
|
31
33
|
|
|
32
34
|
Settings (`multi-agent-preferences.json`) and the log root (`~/.claude/logs/multi-agent/`) are kept by default and removed only when the user picks full cleanup (`--all-data`).
|
|
33
35
|
|
|
@@ -99,12 +99,12 @@ Update the pipeline in one command. Existing preferences are preserved; only ski
|
|
|
99
99
|
## Output
|
|
100
100
|
|
|
101
101
|
```
|
|
102
|
-
Current:
|
|
102
|
+
Current: v14.2.2
|
|
103
103
|
-> git pull origin main
|
|
104
|
-
-> node install.js --all (
|
|
105
|
-
-> migrate-prefs.mjs (0 changes - already v2.
|
|
104
|
+
-> node install.js --all (51 commands, 228 scripts, 205 skills)
|
|
105
|
+
-> migrate-prefs.mjs (0 changes - already v2.6.0)
|
|
106
106
|
|
|
107
|
-
✓ Updated:
|
|
107
|
+
✓ Updated: v14.2.2 → v15.0.0
|
|
108
108
|
|
|
109
109
|
Changes:
|
|
110
110
|
e3f883e fix(dev): Phase 6 must show local test prompt
|
|
@@ -402,7 +402,7 @@ sys.stdout.write((f.get("description") or "").replace("\x1f", " "))
|
|
|
402
402
|
gh-url)
|
|
403
403
|
OWNER=$(printf '%s' "$INPUT" | sed -E 's#https?://github.com/##; s#/.*##')
|
|
404
404
|
REPO=$(printf '%s' "$INPUT" | sed -E 's#https?://github.com/[^/]+/##; s#/.*##')
|
|
405
|
-
NUM=$(printf '%s' "$INPUT" | sed -E 's#.*/issues/##; s#[
|
|
405
|
+
NUM=$(printf '%s' "$INPUT" | sed -E 's#.*/issues/##; s#[/?#].*##')
|
|
406
406
|
raw=$(fetch_github "$OWNER" "$REPO" "$NUM") || raw=""
|
|
407
407
|
if [ -n "$raw" ]; then
|
|
408
408
|
# Single python3 pass - see jira-id branch for rationale on the
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
#
|
|
3
|
+
# parse-complaints.sh
|
|
4
|
+
# Normalize a batch of customer complaints into the uniform JSON list the
|
|
5
|
+
# /multi-agent:complaint-analysis command consumes. Accepts a file export
|
|
6
|
+
# (csv / xlsx / txt / json) or pasted free text on stdin, extracts any
|
|
7
|
+
# transaction / conversation ids embedded in the text, and redacts common
|
|
8
|
+
# PII shapes before anything leaves this script. The raw input is never
|
|
9
|
+
# copied into pipeline state - only the redacted view is.
|
|
10
|
+
#
|
|
11
|
+
# Input forms (exactly one source is required):
|
|
12
|
+
# ./parse-complaints.sh --file <path> [--format csv|xlsx|txt|json|auto]
|
|
13
|
+
# ./parse-complaints.sh --stdin [--format text]
|
|
14
|
+
#
|
|
15
|
+
# Options:
|
|
16
|
+
# --no-redact keep complaint text verbatim (debugging only; the skill
|
|
17
|
+
# never passes this flag)
|
|
18
|
+
#
|
|
19
|
+
# Column mapping (file formats, case-insensitive header match):
|
|
20
|
+
# trxId <- trxId | trx | transaction id / transaction_id / transactionId
|
|
21
|
+
# convId <- convId | conversationId | x-conversationId
|
|
22
|
+
# date <- date | created | createdAt | timestamp
|
|
23
|
+
# platformHint <- platform | channel | os | device
|
|
24
|
+
# text <- comment | complaint | text | description | message, else the
|
|
25
|
+
# longest text column
|
|
26
|
+
#
|
|
27
|
+
# Free-text mode splits on blank lines (or numbered bullets when the paste is
|
|
28
|
+
# one block) and pre-fills ids per block using the same label set as
|
|
29
|
+
# context-link-extractor.sh GRAYLOG_RE (x-conversationId | conversationId |
|
|
30
|
+
# convId | trxId | trx | transaction id).
|
|
31
|
+
#
|
|
32
|
+
# Redaction (default ON, applied after id extraction so ids survive):
|
|
33
|
+
# email -> [REDACTED:email]
|
|
34
|
+
# 13-19 digit card-like runs -> [REDACTED:card]
|
|
35
|
+
# 11 digit national-id-like numbers -> [REDACTED:national-id]
|
|
36
|
+
# 9+ digit phone-like runs -> [REDACTED:phone]
|
|
37
|
+
# 6-char PNR-like tokens (A-Z0-9 mix)-> [REDACTED:pnr]
|
|
38
|
+
#
|
|
39
|
+
# Output (stdout, single JSON object):
|
|
40
|
+
# {
|
|
41
|
+
# "parsedAt": "<ISO8601>",
|
|
42
|
+
# "source": "<path>"|"stdin",
|
|
43
|
+
# "format": "csv|xlsx|txt|json|text",
|
|
44
|
+
# "complaints": [
|
|
45
|
+
# { "id": "C-01", "text": "...", "trxId": "..."|null,
|
|
46
|
+
# "convId": "..."|null, "date": "..."|null,
|
|
47
|
+
# "platformHint": "..."|null }
|
|
48
|
+
# ],
|
|
49
|
+
# "redacted": <bool>, "degraded": <bool>, "degradeReason": "..."|null
|
|
50
|
+
# }
|
|
51
|
+
#
|
|
52
|
+
# Exit codes:
|
|
53
|
+
# 0 success
|
|
54
|
+
# 4 bad usage (no source, unknown flag, unreadable file)
|
|
55
|
+
# 5 format degrade (xlsx requested but openpyxl is not installed; the
|
|
56
|
+
# degraded JSON on stdout tells the user to export as CSV and re-run)
|
|
57
|
+
|
|
58
|
+
set -euo pipefail
|
|
59
|
+
|
|
60
|
+
FILE=""
|
|
61
|
+
USE_STDIN="false"
|
|
62
|
+
FORMAT="auto"
|
|
63
|
+
REDACT="true"
|
|
64
|
+
|
|
65
|
+
while [ $# -gt 0 ]; do
|
|
66
|
+
case "$1" in
|
|
67
|
+
--file)
|
|
68
|
+
[ $# -ge 2 ] || { echo "ERR: --file needs a value" >&2; exit 4; }
|
|
69
|
+
FILE="$2"; shift 2 ;;
|
|
70
|
+
--stdin) USE_STDIN="true"; shift ;;
|
|
71
|
+
--format)
|
|
72
|
+
[ $# -ge 2 ] || { echo "ERR: --format needs a value" >&2; exit 4; }
|
|
73
|
+
FORMAT="$2"; shift 2 ;;
|
|
74
|
+
--no-redact) REDACT="false"; shift ;;
|
|
75
|
+
-h|--help)
|
|
76
|
+
echo "usage: $0 --file <path> [--format csv|xlsx|txt|json|auto] [--no-redact] | --stdin [--format text]" >&2
|
|
77
|
+
exit 4 ;;
|
|
78
|
+
*)
|
|
79
|
+
echo "ERR: unexpected arg $1" >&2; exit 4 ;;
|
|
80
|
+
esac
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
if [ -z "$FILE" ] && [ "$USE_STDIN" != "true" ]; then
|
|
84
|
+
echo "ERR: no source (pass --file <path> or --stdin)" >&2
|
|
85
|
+
exit 4
|
|
86
|
+
fi
|
|
87
|
+
if [ -n "$FILE" ] && [ "$USE_STDIN" = "true" ]; then
|
|
88
|
+
echo "ERR: pass either --file or --stdin, not both" >&2
|
|
89
|
+
exit 4
|
|
90
|
+
fi
|
|
91
|
+
if [ -n "$FILE" ] && [ ! -r "$FILE" ]; then
|
|
92
|
+
echo "ERR: file not readable: $FILE" >&2
|
|
93
|
+
exit 4
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [ "$FORMAT" = "auto" ]; then
|
|
97
|
+
if [ "$USE_STDIN" = "true" ]; then
|
|
98
|
+
FORMAT="text"
|
|
99
|
+
else
|
|
100
|
+
case "$FILE" in
|
|
101
|
+
*.csv) FORMAT="csv" ;;
|
|
102
|
+
*.xlsx) FORMAT="xlsx" ;;
|
|
103
|
+
*.json) FORMAT="json" ;;
|
|
104
|
+
*.txt|*.md) FORMAT="txt" ;;
|
|
105
|
+
*)
|
|
106
|
+
echo "ERR: cannot infer format from extension; pass --format" >&2
|
|
107
|
+
exit 4 ;;
|
|
108
|
+
esac
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
case "$FORMAT" in
|
|
113
|
+
csv|xlsx|txt|json|text) : ;;
|
|
114
|
+
*) echo "ERR: unknown format $FORMAT" >&2; exit 4 ;;
|
|
115
|
+
esac
|
|
116
|
+
|
|
117
|
+
STDIN_PAYLOAD=""
|
|
118
|
+
if [ "$USE_STDIN" = "true" ]; then
|
|
119
|
+
STDIN_PAYLOAD=$(cat)
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
PC_FILE="$FILE" PC_FORMAT="$FORMAT" PC_REDACT="$REDACT" PC_STDIN="$STDIN_PAYLOAD" \
|
|
123
|
+
python3 - <<'PY'
|
|
124
|
+
import csv, datetime, io, json, os, re, sys
|
|
125
|
+
|
|
126
|
+
fmt = os.environ["PC_FORMAT"]
|
|
127
|
+
path = os.environ.get("PC_FILE") or ""
|
|
128
|
+
redact_on = os.environ.get("PC_REDACT") == "true"
|
|
129
|
+
|
|
130
|
+
# Same label set as context-link-extractor.sh GRAYLOG_RE.
|
|
131
|
+
ID_LABEL = re.compile(
|
|
132
|
+
r"(?P<label>x-conversationId|conversationId|convId|trxId|trx|transaction[ _-]?id)"
|
|
133
|
+
r"\s*[:=#]?\s*(?P<value>[A-Za-z0-9][A-Za-z0-9._-]{5,63})",
|
|
134
|
+
re.IGNORECASE,
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def extract_ids(text):
|
|
138
|
+
trx, conv = None, None
|
|
139
|
+
for m in ID_LABEL.finditer(text or ""):
|
|
140
|
+
label = m.group("label").lower()
|
|
141
|
+
value = m.group("value")
|
|
142
|
+
if "conv" in label:
|
|
143
|
+
conv = conv or value
|
|
144
|
+
else:
|
|
145
|
+
trx = trx or value
|
|
146
|
+
return trx, conv
|
|
147
|
+
|
|
148
|
+
# Order matters: card (13-19 digits, separators allowed) before national-id
|
|
149
|
+
# (exactly 11) before phone (9+); a 16-digit card must not survive as a
|
|
150
|
+
# "phone". PNR-like runs last so redacted placeholders are not re-matched.
|
|
151
|
+
REDACTIONS = [
|
|
152
|
+
(re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}"), "[REDACTED:email]"),
|
|
153
|
+
(re.compile(r"\b\d(?:[ -]?\d){12,18}\b"), "[REDACTED:card]"),
|
|
154
|
+
(re.compile(r"\b\d{11}\b"), "[REDACTED:national-id]"),
|
|
155
|
+
(re.compile(r"(?<![\w.-])\+?\d(?:[ ()-]?\d){8,14}\b"), "[REDACTED:phone]"),
|
|
156
|
+
(re.compile(r"\b(?=[A-Z0-9]{6}\b)(?=[A-Z0-9]*[A-Z])(?=[A-Z0-9]*\d)[A-Z0-9]{6}\b"), "[REDACTED:pnr]"),
|
|
157
|
+
# All-letter PNRs exist too, but a bare 6-letter uppercase word is far too
|
|
158
|
+
# common to redact blind - only take one that follows a PNR-ish keyword.
|
|
159
|
+
(
|
|
160
|
+
re.compile(r"\b(?P<kw>pnr|rezervasyon kodu|booking (?:ref|reference|code))(?P<sep>[^A-Za-z0-9\n]{0,3})[A-Z]{6}\b", re.IGNORECASE),
|
|
161
|
+
lambda m: m.group("kw") + m.group("sep") + "[REDACTED:pnr]",
|
|
162
|
+
),
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
def redact(text):
|
|
166
|
+
if not redact_on:
|
|
167
|
+
return text
|
|
168
|
+
for rx, repl in REDACTIONS:
|
|
169
|
+
text = rx.sub(repl, text)
|
|
170
|
+
return text
|
|
171
|
+
|
|
172
|
+
TEXT_KEYS = ("comment", "complaint", "text", "description", "message", "yorum", "sikayet")
|
|
173
|
+
TRX_KEYS = re.compile(r"^(trxid|trx|transaction[ _-]?id)$", re.IGNORECASE)
|
|
174
|
+
CONV_KEYS = re.compile(r"^(convid|conversationid|x-conversationid)$", re.IGNORECASE)
|
|
175
|
+
DATE_KEYS = re.compile(r"^(date|created|createdat|timestamp)$", re.IGNORECASE)
|
|
176
|
+
PLATFORM_KEYS = re.compile(r"^(platform|channel|os|device)$", re.IGNORECASE)
|
|
177
|
+
|
|
178
|
+
def row_to_complaint(row):
|
|
179
|
+
text_val, trx, conv, date, platform = None, None, None, None, None
|
|
180
|
+
longest = ""
|
|
181
|
+
for key, raw in row.items():
|
|
182
|
+
if key is None or raw is None:
|
|
183
|
+
continue
|
|
184
|
+
val = str(raw).strip()
|
|
185
|
+
if not val:
|
|
186
|
+
continue
|
|
187
|
+
k = str(key).strip()
|
|
188
|
+
if TRX_KEYS.match(k):
|
|
189
|
+
trx = val
|
|
190
|
+
elif CONV_KEYS.match(k):
|
|
191
|
+
conv = val
|
|
192
|
+
elif DATE_KEYS.match(k):
|
|
193
|
+
date = val
|
|
194
|
+
elif PLATFORM_KEYS.match(k):
|
|
195
|
+
platform = val
|
|
196
|
+
elif k.lower() in TEXT_KEYS:
|
|
197
|
+
text_val = val
|
|
198
|
+
elif len(val) > len(longest):
|
|
199
|
+
longest = val
|
|
200
|
+
text = text_val or longest
|
|
201
|
+
if not text:
|
|
202
|
+
return None
|
|
203
|
+
found_trx, found_conv = extract_ids(text)
|
|
204
|
+
return {
|
|
205
|
+
"text": text,
|
|
206
|
+
"trxId": trx or found_trx,
|
|
207
|
+
"convId": conv or found_conv,
|
|
208
|
+
"date": date,
|
|
209
|
+
"platformHint": platform,
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
def blocks_from_text(payload):
|
|
213
|
+
payload = payload.strip()
|
|
214
|
+
if not payload:
|
|
215
|
+
return []
|
|
216
|
+
blocks = [b.strip() for b in re.split(r"\n\s*\n", payload) if b.strip()]
|
|
217
|
+
if len(blocks) == 1 and re.search(r"^\s*(?:\d+[.)]|-)\s+", payload, re.MULTILINE):
|
|
218
|
+
blocks = [
|
|
219
|
+
b.strip()
|
|
220
|
+
for b in re.split(r"^\s*(?:\d+[.)]|-)\s+", payload, flags=re.MULTILINE)
|
|
221
|
+
if b.strip()
|
|
222
|
+
]
|
|
223
|
+
return blocks
|
|
224
|
+
|
|
225
|
+
degraded = False
|
|
226
|
+
degrade_reason = None
|
|
227
|
+
raw_complaints = []
|
|
228
|
+
|
|
229
|
+
if fmt == "text":
|
|
230
|
+
for block in blocks_from_text(os.environ.get("PC_STDIN") or ""):
|
|
231
|
+
trx, conv = extract_ids(block)
|
|
232
|
+
raw_complaints.append(
|
|
233
|
+
{"text": block, "trxId": trx, "convId": conv, "date": None, "platformHint": None}
|
|
234
|
+
)
|
|
235
|
+
elif fmt == "txt":
|
|
236
|
+
with open(path, encoding="utf-8-sig", errors="replace") as f:
|
|
237
|
+
payload = f.read()
|
|
238
|
+
for block in blocks_from_text(payload):
|
|
239
|
+
trx, conv = extract_ids(block)
|
|
240
|
+
raw_complaints.append(
|
|
241
|
+
{"text": block, "trxId": trx, "convId": conv, "date": None, "platformHint": None}
|
|
242
|
+
)
|
|
243
|
+
elif fmt == "csv":
|
|
244
|
+
with open(path, encoding="utf-8-sig", errors="replace", newline="") as f:
|
|
245
|
+
sample = f.read(4096)
|
|
246
|
+
f.seek(0)
|
|
247
|
+
try:
|
|
248
|
+
dialect = csv.Sniffer().sniff(sample, delimiters=",;\t")
|
|
249
|
+
except csv.Error:
|
|
250
|
+
dialect = csv.excel
|
|
251
|
+
for row in csv.DictReader(f, dialect=dialect):
|
|
252
|
+
c = row_to_complaint(row)
|
|
253
|
+
if c:
|
|
254
|
+
raw_complaints.append(c)
|
|
255
|
+
elif fmt == "json":
|
|
256
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
257
|
+
data = json.load(f)
|
|
258
|
+
if isinstance(data, dict):
|
|
259
|
+
data = data.get("complaints") or data.get("items") or []
|
|
260
|
+
if not isinstance(data, list):
|
|
261
|
+
data = []
|
|
262
|
+
for row in data:
|
|
263
|
+
if isinstance(row, str):
|
|
264
|
+
trx, conv = extract_ids(row)
|
|
265
|
+
raw_complaints.append(
|
|
266
|
+
{"text": row.strip(), "trxId": trx, "convId": conv, "date": None, "platformHint": None}
|
|
267
|
+
)
|
|
268
|
+
elif isinstance(row, dict):
|
|
269
|
+
c = row_to_complaint(row)
|
|
270
|
+
if c:
|
|
271
|
+
raw_complaints.append(c)
|
|
272
|
+
elif fmt == "xlsx":
|
|
273
|
+
try:
|
|
274
|
+
import openpyxl
|
|
275
|
+
except ImportError:
|
|
276
|
+
degraded = True
|
|
277
|
+
degrade_reason = "openpyxl not installed; export the sheet as CSV and re-run with --format csv"
|
|
278
|
+
if not degraded:
|
|
279
|
+
wb = openpyxl.load_workbook(path, read_only=True, data_only=True)
|
|
280
|
+
ws = wb.active
|
|
281
|
+
rows = ws.iter_rows(values_only=True)
|
|
282
|
+
header = next(rows, None)
|
|
283
|
+
if header:
|
|
284
|
+
keys = [str(h).strip() if h is not None else "" for h in header]
|
|
285
|
+
for values in rows:
|
|
286
|
+
row = {k: v for k, v in zip(keys, values) if k}
|
|
287
|
+
c = row_to_complaint(row)
|
|
288
|
+
if c:
|
|
289
|
+
raw_complaints.append(c)
|
|
290
|
+
wb.close()
|
|
291
|
+
|
|
292
|
+
complaints = []
|
|
293
|
+
for i, c in enumerate(raw_complaints, start=1):
|
|
294
|
+
complaints.append(
|
|
295
|
+
{
|
|
296
|
+
"id": "C-%02d" % i,
|
|
297
|
+
"text": redact(c["text"]),
|
|
298
|
+
"trxId": c["trxId"],
|
|
299
|
+
"convId": c["convId"],
|
|
300
|
+
"date": c["date"],
|
|
301
|
+
"platformHint": (c["platformHint"] or None) and str(c["platformHint"]).strip().lower(),
|
|
302
|
+
}
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
result = {
|
|
306
|
+
"parsedAt": datetime.datetime.utcnow().isoformat() + "Z",
|
|
307
|
+
"source": path or "stdin",
|
|
308
|
+
"format": fmt,
|
|
309
|
+
"complaints": complaints,
|
|
310
|
+
"redacted": redact_on,
|
|
311
|
+
"degraded": degraded,
|
|
312
|
+
"degradeReason": degrade_reason,
|
|
313
|
+
}
|
|
314
|
+
print(json.dumps(result, ensure_ascii=False))
|
|
315
|
+
sys.exit(5 if degraded else 0)
|
|
316
|
+
PY
|
|
@@ -34,9 +34,9 @@ The selected scope routes to a platform skill:
|
|
|
34
34
|
|
|
35
35
|
| Platform | Skill | Notes |
|
|
36
36
|
|---|---|---|
|
|
37
|
-
| iOS / SwiftUI | `ai-ios-
|
|
38
|
-
| Android / Compose | `ai-android-
|
|
39
|
-
| Generic | `ai-ios-
|
|
37
|
+
| iOS / SwiftUI | `ai-ios-toolkit:figma-component-wiki` | Reads `Configuration` + `+Modifiers` from the source, captures Figma screenshots via MCP / REST, runs Snapshot tests for iOS dark/light/RTL. |
|
|
38
|
+
| Android / Compose | `ai-android-toolkit:figma-component-wiki` | Reads Compose composables + previews, runs Paparazzi screenshots if available, otherwise generates from layout inspector. |
|
|
39
|
+
| Generic | `ai-ios-toolkit:figma-component-wiki` (fallback) | Used when `state.platform` is unknown (fallback path - typically a flag). |
|
|
40
40
|
|
|
41
41
|
Full per-skill contract: `$HOME/.claude/multi-agent-refs/wiki-capture.md`.
|
|
42
42
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Complaint-Analysis Report Template
|
|
2
|
+
|
|
3
|
+
Master layout for the report `/multi-agent:complaint-analysis` renders at Phase 4 and dispatches at Phase 5. Single-language body: every heading and prose block is written in `outputLanguage` (`tr` or `en`); the TR / EN heading pairs below show both forms, render ONE. Verdict tokens, Graylog excerpts, and field names in routing entries stay English (SKILL Locked 9). The deterministic gate over an emitted instance is `scripts/validate-complaint-doc.mjs` - keep this file and that validator in sync.
|
|
4
|
+
|
|
5
|
+
Numbering is fixed 1..8. Section 4 (routing) is rendered only when at least one `core` verdict exists; numbering still re-flows sequentially when it is omitted (same omission style as the analysis template).
|
|
6
|
+
|
|
7
|
+
## YAML front-matter (required keys)
|
|
8
|
+
|
|
9
|
+
```yaml
|
|
10
|
+
---
|
|
11
|
+
run_name: complaints-20260810
|
|
12
|
+
generated_at: <UTC ISO8601>
|
|
13
|
+
language: tr | en
|
|
14
|
+
complaint_count: <N>
|
|
15
|
+
repos: "<name>:<layer>, <name>:<layer>, ..."
|
|
16
|
+
verdict_counts: "client=<X> bff=<Y> core=<Z> insufficient=<W>"
|
|
17
|
+
graylog_degraded: true | false
|
|
18
|
+
---
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`run_name`, `generated_at`, `language`, `complaint_count`, `graylog_degraded` are validator-required; `repos` and `verdict_counts` are part of the template contract but advisory to the gate.
|
|
22
|
+
|
|
23
|
+
## 1. Özet / Summary
|
|
24
|
+
|
|
25
|
+
2-4 sentences: how many complaints, where they came from (source types only - never file contents), the verdict distribution, and whether Graylog was degraded for any of them. Follow with the count table:
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
| Verdict | Count |
|
|
29
|
+
|---|---|
|
|
30
|
+
| client | X |
|
|
31
|
+
| bff | Y |
|
|
32
|
+
| core | Z |
|
|
33
|
+
| insufficient-evidence | W |
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Then the coverage table - every selected repo appears, including the ones that came back clean, so "only the client layer needed a fix" is visible at a glance:
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
| Repo | Layer | Evidence hits | Verdicts attributed |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| <owner>/my-ios-app | ios | 3 | C-01 |
|
|
42
|
+
| <owner>/my-mobile-bff | mobile-bff | 0 | - (incelendi, temiz / checked, clean) |
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 2. Triage Tablosu / Triage Table
|
|
46
|
+
|
|
47
|
+
One row per complaint. Verdict tokens are the English enum: `client:ios`, `client:android`, `client:web`, `bff:mobile-bff`, `bff:web-bff`, `core`, `insufficient-evidence`. The validator requires every row in this section whose FIRST cell is a `C-NN` id to carry one of these tokens in a cell of its own (cell-exact; the Section 1 coverage table citing ids in its last column is exempt by scope).
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
| Id | Özet (redakte) | trx/conv | Verdict | Confidence | Routing |
|
|
51
|
+
|---|---|---|---|---|---|
|
|
52
|
+
| C-01 | <redacted excerpt <= 80 chars> | trx-9f3a | client:ios | high | - |
|
|
53
|
+
| C-02 | ... | conv-77aa | core | medium | payment-core |
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`Routing` column: the suspected core service for `core` rows, `-` otherwise.
|
|
57
|
+
|
|
58
|
+
## 3. Şikayet Detayları / Complaint Details
|
|
59
|
+
|
|
60
|
+
One `### C-NN` subsection per complaint:
|
|
61
|
+
|
|
62
|
+
- **Şikayet / Complaint**: the redacted text (full, not the excerpt).
|
|
63
|
+
- **Graylog**: status line (`ok: N messages` / `degraded: <reason>` / `skipped: user choice`), then up to 3 evidence lines, English, shape `timestamp source level message-excerpt`. Redact any PII the log itself carries before quoting.
|
|
64
|
+
- **Repo kanıtı / Repo evidence**: `file:line - signal (matchKind)` rows from the correlation phase; `-` when none.
|
|
65
|
+
- **Elenen katmanlar / Ruled out**: one line listing the repos/layers that were grepped for this complaint's signals and returned nothing (e.g. `mobile-bff, web-bff: sinyal yok`). This is what justifies a single-layer verdict.
|
|
66
|
+
- **Verdict + gerekçe / rationale**: the verdict token, confidence, and 1-3 sentences citing the evidence above (SKILL Locked 10: client/bff needs 1 Graylog + 1 repo citation; core needs the Graylog line naming the upstream).
|
|
67
|
+
- **Geliştirme planı / Fix plan** (client/bff only, SKILL Locked 13; validator-required for every client/bff verdict): 2-5 numbered steps grounded in the existing architecture - each step references a cited `file:line` or component, reuse-first, tests included. Never rendered for core / insufficient-evidence.
|
|
68
|
+
- **Dev prompt** (client/bff only): one fenced English block ready to paste into `/multi-agent:dev` or a Jira description - complaint summary, root cause, cited files, fix plan steps, acceptance check, and the `[C-NN]` id.
|
|
69
|
+
|
|
70
|
+
## 4. Core Yönlendirme Önerileri / Core Routing Recommendations
|
|
71
|
+
|
|
72
|
+
Rendered only when `core` verdicts exist. One `### C-NN` subsection per core verdict (the validator checks each core id appears here):
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
suspectedService: <Graylog source>
|
|
76
|
+
endpoint: <path or ->
|
|
77
|
+
errorCode: <code or ->
|
|
78
|
+
evidenceExcerpt: <short redacted EN excerpt>
|
|
79
|
+
suggestedQueue: <prefs.projects[*].routing.coreTeamLabel or ->
|
|
80
|
+
confidence: high | medium | low
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
No fix analysis, no code speculation about the core service (SKILL Locked 5). This block is what gets forwarded to the core team.
|
|
84
|
+
|
|
85
|
+
## 5. Açık Sorular / Open Questions
|
|
86
|
+
|
|
87
|
+
One bullet per `insufficient-evidence` verdict (what is missing: id, reproducible log, repo signal) plus any ambiguity worth a human decision (e.g. client-vs-bff attribution at low confidence).
|
|
88
|
+
|
|
89
|
+
## 6. Metodoloji / Methodology
|
|
90
|
+
|
|
91
|
+
Fixed short block: source types ingested, redaction applied (`parse-complaints.sh`), Graylog query window/limit actually used, repos + layers grepped, and a **degraded services** list (`graylog: <reason>` when any fetch degraded - a degraded payload is never silently dropped).
|
|
92
|
+
|
|
93
|
+
## 7. Referanslar / References
|
|
94
|
+
|
|
95
|
+
Input source names only - file basename + row count, Jira issue keys, Confluence page titles/URLs. Never inline the input contents. Then the repo list with layers.
|
|
96
|
+
|
|
97
|
+
## 8. (Footer)
|
|
98
|
+
|
|
99
|
+
One line: `Generated by /multi-agent:complaint-analysis - report only, no branches or commits.` (localized).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component Dispatch (Phase 3 short-circuit)
|
|
2
2
|
|
|
3
|
-
> **TLDR** - When `taskType === "component"` (Figma URL in task description or instruction-driven figma workflow), multi-agent Phase 3 **does not run the TDD loop**. It delegates the entire phase to the enabled `ai-<platform>-
|
|
3
|
+
> **TLDR** - When `taskType === "component"` (Figma URL in task description or instruction-driven figma workflow), multi-agent Phase 3 **does not run the TDD loop**. It delegates the entire phase to the enabled `ai-<platform>-toolkit` **marketplace plugin's** component skill (`create-component`, falling back to `create-ui-component`) via the Skill tool. Implementation lives in the plugin; multi-agent's job is classification, dispatch, and state report. The pipeline no longer bundles its own `figma-to-component` orchestrator - component skills live in one place, the plugin marketplace.
|
|
4
4
|
|
|
5
5
|
This doc is referenced from `$HOME/.claude/multi-agent-refs/phases/phase-3-dev.md`. Keeping it separate lets `phase-3-dev.md` remain tight (it's already the largest phase doc) and gives the orchestrator-report contract a stable URL for both Claude-side and Copilot-side implementations.
|
|
6
6
|
|
|
@@ -37,8 +37,8 @@ run produced entities and a mapper but left the screen half-wired.
|
|
|
37
37
|
|
|
38
38
|
| `state.componentScope` | Meaning | iOS skill | Android skill |
|
|
39
39
|
|---|---|---|---|
|
|
40
|
-
| `screen` (default when the frame is a full screen, or the task names a screen) | Full clean-architecture vertical: Entity → Repository → Mapper → UseCase → LocalizedText → AnalyticsTracking → CoordinatorEvent → ViewModel → Scene → Preview, then verify | `ai-ios-
|
|
41
|
-
| `component` | One reusable UI component (Configuration / View / +Modifiers / Code Connect) | `ai-ios-
|
|
40
|
+
| `screen` (default when the frame is a full screen, or the task names a screen) | Full clean-architecture vertical: Entity → Repository → Mapper → UseCase → LocalizedText → AnalyticsTracking → CoordinatorEvent → ViewModel → Scene → Preview, then verify | `ai-ios-toolkit:create-screen` | `ai-android-toolkit:create-screen` |
|
|
41
|
+
| `component` | One reusable UI component (Configuration / View / +Modifiers / Code Connect) | `ai-ios-toolkit:create-component` (fallback `create-ui-component`) | `ai-android-toolkit:create-component` (fallback `create-ui-component`) |
|
|
42
42
|
| `evolve` | Change an existing component | `evolve-component` (fallback `evolve-ui-component`) | same |
|
|
43
43
|
|
|
44
44
|
```
|
|
@@ -52,7 +52,7 @@ a single atom is `component`. When it cannot be decided, ask - do not default
|
|
|
52
52
|
omits the wiring.
|
|
53
53
|
|
|
54
54
|
**Pre-implementation validation is not optional on iOS.** Before the create skill
|
|
55
|
-
runs, dispatch `ai-ios-
|
|
55
|
+
runs, dispatch `ai-ios-toolkit:figma-validate` for the frame. It checks
|
|
56
56
|
registry presence, Code Connect strategy, **design token compliance**, dependency
|
|
57
57
|
readiness, atomic scope and already-implemented status in about ten seconds. Those
|
|
58
58
|
are precisely the checks whose absence produced guessed spacing and an unpublished
|
|
@@ -60,7 +60,7 @@ Code Connect binding. A `figma-validate` failure halts the dispatch.
|
|
|
60
60
|
|
|
61
61
|
**Dual-name resolution.** The public (`multi-agent-plugins`) and a corporate/private marketplace named the same skill differently - `create-component` vs `create-ui-component`. Dispatch tries `create-component` first; if it is not available in the current repo, tries `create-ui-component`. (Same dual-name rule applies when `taskType` maps to evolve → `evolve-component`/`evolve-ui-component`, or fix → `fix-bug`.)
|
|
62
62
|
|
|
63
|
-
If **neither** resolves, the platform's `ai-<platform>-
|
|
63
|
+
If **neither** resolves, the platform's `ai-<platform>-toolkit` plugin is not enabled in this repo. **Halt with a user-visible error**: "component task requires the ai-<platform>-toolkit plugin enabled in this repo (`.claude/settings.local.json`)." Do not silently fall back to TDD - a component task ran through the bugfix path would produce wrong artefacts.
|
|
64
64
|
|
|
65
65
|
## Dispatch call
|
|
66
66
|
|
|
@@ -119,7 +119,7 @@ Phase 4 runs in `--dev` as it does in the full pipeline, and its reviewer count
|
|
|
119
119
|
|
|
120
120
|
Component dispatch is **no longer byte-identical across CLIs** and that is by design (see `cross-cli-contract.md` section 1.1):
|
|
121
121
|
|
|
122
|
-
- **Claude Code**: dispatches to the enabled `ai-<platform>-
|
|
122
|
+
- **Claude Code**: dispatches to the enabled `ai-<platform>-toolkit` marketplace plugin via the Skill tool (this doc).
|
|
123
123
|
- **Copilot CLI**: has no plugin loader; it continues to use its standalone `~/.copilot/skills/figma-*` skill copies (frozen fallback). Copilot's resolution + progress lines follow those local skills.
|
|
124
124
|
|
|
125
125
|
What still MUST match across CLIs: the `taskType === "component"` classification, the `state.phases["3"].subphases[]` shape the dispatch layer writes, and `--dev` elision semantics. Figma-skill *inventory* parity is no longer enforced. `smoke-cross-cli-behavior.sh` asserts only the classification + state-shape axis for components.
|