@mmerterden/multi-agent-pipeline 11.4.0 → 12.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.
- package/CHANGELOG.md +172 -0
- package/README.md +1 -0
- package/docs/adr/0007-multi-tool-adapter-framework.md +2 -2
- package/index.js +9 -2
- package/install/_common.mjs +107 -5
- package/install/_telemetry.mjs +5 -23
- package/install/claude.mjs +95 -11
- package/install/copilot.mjs +75 -6
- package/install/index.mjs +34 -1
- package/package.json +4 -10
- package/pipeline/commands/multi-agent/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/analysis/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/channels/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/dev/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +2 -1
- package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/finish/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +29 -3
- package/pipeline/commands/multi-agent/help/SKILL.md +3 -2
- package/pipeline/commands/multi-agent/issue/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/jira/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/kill/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/language/SKILL.md +20 -1
- package/pipeline/commands/multi-agent/local/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/log/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/purge/SKILL.md +27 -24
- package/pipeline/commands/multi-agent/refactor/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/resume/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/review/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/search/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/stack/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/status/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +20 -2
- package/pipeline/commands/multi-agent/test/SKILL.md +1 -0
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +87 -0
- package/pipeline/commands/multi-agent/update/SKILL.md +1 -0
- package/pipeline/lib/account-resolver.sh +61 -23
- package/pipeline/lib/channels-multi-repo.sh +7 -2
- package/pipeline/lib/count-lib.sh +27 -0
- package/pipeline/lib/credential-store.sh +23 -6
- package/pipeline/lib/extract-conventions.sh +27 -21
- package/pipeline/lib/fetch-confluence.sh +25 -13
- package/pipeline/lib/fetch-crashlytics.sh +30 -8
- package/pipeline/lib/fetch-fortify.sh +11 -2
- package/pipeline/lib/fetch-swagger.sh +18 -7
- package/pipeline/lib/figma-mcp-refresh.sh +26 -11
- package/pipeline/lib/figma-screenshot.sh +11 -2
- package/pipeline/lib/issue-fetcher.sh +31 -6
- package/pipeline/lib/multi-repo-pipeline.sh +84 -20
- package/pipeline/lib/plan-todos.sh +12 -3
- package/pipeline/lib/post-pr-review.sh +5 -3
- package/pipeline/lib/repo-cache.sh +53 -9
- package/pipeline/lib/review-watch.sh +26 -6
- package/pipeline/lib/shadow-git.sh +45 -4
- package/pipeline/lib/vercel-deploy.sh +10 -1
- package/pipeline/multi-agent-refs/cross-cli-contract.md +5 -5
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +12 -1
- package/pipeline/scripts/audit-log-rotate.sh +38 -10
- package/pipeline/scripts/check-md-links.mjs +34 -9
- package/pipeline/scripts/diff-risk-score.mjs +4 -1
- package/pipeline/scripts/evidence-gate.mjs +10 -1
- package/pipeline/scripts/fixtures/install-layout.tsv +6 -4
- package/pipeline/scripts/fixtures/pack-expected-count.txt +1 -0
- package/pipeline/scripts/gc-tmp.sh +67 -8
- package/pipeline/scripts/gc-worktrees.sh +140 -0
- package/pipeline/scripts/keychain-save.sh +13 -9
- package/pipeline/scripts/lint-skills.mjs +40 -2
- package/pipeline/scripts/localize-commands.mjs +130 -0
- package/pipeline/scripts/migrate-prefs.mjs +26 -7
- package/pipeline/scripts/phase-tracker.sh +71 -0
- package/pipeline/scripts/pre-commit-check.sh +39 -0
- package/pipeline/scripts/prune-logs.sh +100 -15
- package/pipeline/scripts/purge.sh +235 -0
- package/pipeline/scripts/scan-skills.sh +217 -127
- package/pipeline/scripts/smoke-bitbucket-contract.sh +21 -5
- package/pipeline/scripts/smoke-description-tr.sh +82 -0
- package/pipeline/scripts/smoke-fetchers-offline.sh +382 -0
- package/pipeline/scripts/smoke-gc-tmp.sh +50 -4
- package/pipeline/scripts/smoke-gc-worktrees.sh +125 -0
- package/pipeline/scripts/smoke-install-layout.sh +11 -3
- package/pipeline/scripts/smoke-lib-scripts.sh +54 -1
- package/pipeline/scripts/smoke-pack-contents.sh +140 -0
- package/pipeline/scripts/smoke-plugin-validate.sh +64 -0
- package/pipeline/scripts/smoke-prune-logs.sh +57 -7
- package/pipeline/scripts/smoke-purge.sh +138 -0
- package/pipeline/scripts/smoke-shadow-git.sh +48 -1
- package/pipeline/scripts/smoke-skill-authoring.sh +1 -1
- package/pipeline/scripts/smoke-update-check.sh +13 -0
- package/pipeline/scripts/smoke-workflow-audit.sh +69 -0
- package/pipeline/scripts/test-gap-scan.mjs +12 -1
- package/pipeline/scripts/triage-memory.mjs +10 -1
- package/pipeline/scripts/uninstall.mjs +146 -42
- package/pipeline/scripts/update-check.sh +9 -0
- package/pipeline/scripts/update-issue-progress.sh +60 -41
- package/pipeline/scripts/write-state.mjs +14 -4
- package/pipeline/skills/.skill-manifest.json +7 -7
- package/pipeline/skills/.skills-index.json +9 -9
- package/pipeline/skills/shared/README.md +19 -10
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +1 -0
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +74 -0
- package/pipeline/skills/skills-index.md +1 -1
- package/pipeline/commands/multi-agent/delete/SKILL.md +0 -67
- package/pipeline/skills/shared/core/multi-agent-delete/SKILL.md +0 -66
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Run parallel review on a branch's diff or a Pull Request: 2 models on Claude Code (Fable + Sonnet), 3 models on Copilot CLI (GPT + Opus + Sonnet). On PR input, posts per-finding inline comments and sets approve/needs-work review state."
|
|
3
|
+
description-tr: "Bir branch diff'i veya Pull Request üzerinde paralel review koşar: Claude Code'da 2 model (Fable + Sonnet), Copilot CLI'da 3 model (GPT + Opus + Sonnet). PR girdisinde bulgu başına inline yorum atar ve approve/needs-work durumunu işaretler."
|
|
3
4
|
argument-hint: "[#N | repo#N | PR-URL | branch] - optional: PR by number/URL, repo+number, or local branch. Supports GitHub and Bitbucket Server URLs. If omitted (interactive), open GitHub + Bitbucket PRs are listed for multi-select; autopilot falls back to the current branch."
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Assess whether a GitHub issue is ready for multi-agent development: fetch it, grade scope / acceptance criteria / repro / design / API / stack readiness, then (after confirm) post the gaps as an issue comment. Read-only on code."
|
|
3
|
+
description-tr: "Bir GitHub issue'sunun multi-agent geliştirmeye hazır olup olmadığını değerlendirir: getirir; kapsam / kabul kriterleri / repro / tasarım / API / stack hazırlığını puanlar, sonra (onay sonrası) eksikleri issue yorumu olarak gönderir. Kodda salt-okunur."
|
|
3
4
|
argument-hint: "[#N | repo#N | GitHub issue URL] - optional; with no argument, pick from open issues"
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Assess whether a Jira issue is ready for multi-agent development: fetch it, grade scope / acceptance criteria / repro / design / API / stack readiness, then (after confirm) post the gaps as a Jira comment. Read-only on code."
|
|
3
|
+
description-tr: "Bir Jira issue'sunun multi-agent geliştirmeye hazır olup olmadığını değerlendirir: getirir; kapsam / kabul kriterleri / repro / tasarım / API / stack hazırlığını puanlar, sonra (onay sonrası) eksikleri Jira yorumu olarak gönderir. Kodda salt-okunur."
|
|
3
4
|
argument-hint: "[JIRA-KEY | Jira URL] - optional; with no argument, pick from your open Jira issues"
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Skill security scan: walks local skill directories against a tiered pattern catalog."
|
|
3
|
+
description-tr: "Skill güvenlik taraması: yerel skill dizinlerini kademeli desen kataloğuna göre tarar."
|
|
3
4
|
allowed-tools: Bash, Read
|
|
4
5
|
argument-hint: "[--strict] [--threshold critical|high|medium|low] [--json] [--root PATH]"
|
|
5
6
|
---
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Log search across every agent-log.md with smart ranking and filters. Optional --semantic flag queries the per-repo triage corpus."
|
|
3
|
+
description-tr: "Tüm agent-log.md dosyalarında akıllı sıralama ve filtrelerle log araması. İsteğe bağlı --semantic bayrağı repo bazlı triyaj korpusunu sorgular."
|
|
3
4
|
allowed-tools: Bash, Read
|
|
4
5
|
argument-hint: "\"query\" [--project NAME] [--since 7d] [--phase N] [--semantic] [--json|--tsv]"
|
|
5
6
|
---
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "First-run setup wizard: keychain token discovery, Git Identity onboarding, and pipeline preparation."
|
|
3
|
+
description-tr: "İlk kurulum sihirbazı: keychain token keşfi, Git Identity kaydı ve pipeline hazırlığı."
|
|
3
4
|
allowed-tools: Bash, Read, Write, AskUserQuestion, WebFetch
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "Select the active stack for this repo by enabling the matching marketplace plugin(s) in .claude/settings.json (ios/android/mobile/backend/frontend/fullstack/all)."
|
|
3
|
+
description-tr: "Bu repo için aktif stack'i seçer: eşleşen marketplace plugin'lerini .claude/settings.json'da etkinleştirir (ios/android/mobile/backend/frontend/fullstack/all)."
|
|
3
4
|
allowed-tools: Bash, Read, Edit, Write
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "One-shot sync of the entire multi-agent ecosystem: Claude Code, Copilot CLI, pipeline repo, and website."
|
|
3
|
+
description-tr: "Tüm multi-agent ekosisteminin tek atımlık senkronu: Claude Code, Copilot CLI, pipeline repo ve website."
|
|
3
4
|
argument-hint: "[release] [--platform=<macos|linux|windows>]"
|
|
4
5
|
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, WebFetch
|
|
5
6
|
---
|
|
@@ -130,6 +131,23 @@ If nothing is stale → report "All targets up to date" and stop.
|
|
|
130
131
|
~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
|
|
131
132
|
&& { echo "ABORT: corporate reference leaked into pipeline/commands"; exit 1; } || true
|
|
132
133
|
```
|
|
134
|
+
- **Localized picker descriptions are an installed-tree artifact.** When
|
|
135
|
+
`outputLanguage=tr`, the installed `description:` values are Turkish and a
|
|
136
|
+
`description-en:` sidecar holds the English original (see
|
|
137
|
+
`localize-commands.mjs`). The repo must ALWAYS receive the English form:
|
|
138
|
+
after copying commands into `pipeline/commands/`, normalize the copy and
|
|
139
|
+
verify no sidecar or Turkish description leaked:
|
|
140
|
+
```bash
|
|
141
|
+
# normalize: restore English descriptions, strip description-en sidecars
|
|
142
|
+
node ~/multi-agent-pipeline/pipeline/scripts/localize-commands.mjs restore \
|
|
143
|
+
--dir ~/multi-agent-pipeline/pipeline/commands/multi-agent
|
|
144
|
+
# backstop: no sidecar may survive into the repo
|
|
145
|
+
grep -rl "^description-en:" ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
|
|
146
|
+
&& { echo "ABORT: description-en sidecar leaked into pipeline/commands"; exit 1; } || true
|
|
147
|
+
# backstop: repo description lines must be English (Turkish-diacritics proxy)
|
|
148
|
+
grep -rn '^description:.*[çğıöşüÇĞİÖŞÜ]' ~/multi-agent-pipeline/pipeline/commands/ 2>/dev/null \
|
|
149
|
+
&& { echo "ABORT: localized description leaked into pipeline/commands"; exit 1; } || true
|
|
150
|
+
```
|
|
133
151
|
|
|
134
152
|
6. **Cross-platform smoke gate** (final step of the REPO sync, before push):
|
|
135
153
|
```bash
|
|
@@ -242,11 +260,11 @@ This runs on the Claude <-> Copilot axis — the two CLIs the pipeline supports
|
|
|
242
260
|
**38 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
|
|
243
261
|
|
|
244
262
|
```
|
|
245
|
-
analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira,
|
|
263
|
+
analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, dev,
|
|
246
264
|
dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, garbage-collect,
|
|
247
265
|
help, issue, jira, kill, language, local,
|
|
248
266
|
local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review, review-issue, review-jira,
|
|
249
|
-
scan, search, setup, stack, status, sync, test, update
|
|
267
|
+
scan, search, setup, stack, status, sync, test, uninstall, update
|
|
250
268
|
```
|
|
251
269
|
|
|
252
270
|
**NOT synced**: `$HOME/.claude/multi-agent-refs/*` - lazy-load references, Claude Code specific
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: "UI Bug Hunter - iOS Simulator (simctl) + Android Emulator (adb). Auto-detects platform. Screenshot + tap + analyze on the booted device. The Phase 5 Manual Test flow lives at /multi-agent:manual-test."
|
|
3
|
+
description-tr: "UI Bug Hunter - iOS Simulator (simctl) + Android Emulator (adb). Platformu otomatik algılar. Açık cihazda screenshot + tap + analiz. Faz 5 Manuel Test akışı /multi-agent:manual-test'te."
|
|
3
4
|
argument-hint: '[scenario] - e.g. "dark mode" | "accessibility" | "dynamic type" | "screenshot tr" | "store-ready" | (empty = full sweep)'
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Uninstall the pipeline from Claude Code + Copilot CLI. Keychain access tokens are always left untouched; --all-data also clears pipeline settings and logs. Asks for double confirmation."
|
|
3
|
+
description-tr: "Pipeline'ı Claude Code + Copilot CLI'dan kaldırır. Keychain erişim token'larına asla dokunulmaz; --all-data ayrıca pipeline ayarlarını ve loglarını da siler. Çift onay ister."
|
|
4
|
+
argument-hint: "[--dry-run] [--all-data] [--claude] [--copilot] [--target=<path>]"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# multi-agent uninstall - Token-Preserving Uninstall
|
|
8
|
+
|
|
9
|
+
Uninstalls the pipeline itself from the system. **This is different from `:purge`:**
|
|
10
|
+
|
|
11
|
+
| Command | What it removes |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `:purge` | Active tasks' worktrees / branches / logs / state (development data) |
|
|
14
|
+
| `:uninstall` | The pipeline itself: skills, commands, agents, scripts - from every CLI |
|
|
15
|
+
|
|
16
|
+
## Two modes
|
|
17
|
+
|
|
18
|
+
| Mode | Flag | Removes | Keeps |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| **Standard** (default) | (none) | distributed files: commands, skills, agents, scripts, refs, schemas, lib | tokens, `CLAUDE.md`, `rules/`, `multi-agent-preferences.json`, all logs |
|
|
21
|
+
| **Full cleanup** | `--all-data` | standard PLUS `multi-agent-preferences.json` + `~/.claude/logs/multi-agent/` (task logs, state, metrics, audit) | tokens, `CLAUDE.md`, `rules/` (user-owned) |
|
|
22
|
+
|
|
23
|
+
Tokens in the OS credential store are NEVER removed by either mode.
|
|
24
|
+
|
|
25
|
+
## Never deleted (either mode)
|
|
26
|
+
|
|
27
|
+
- **Keychain / Credential Manager / libsecret** personal access tokens (GitHub, Jira, Bitbucket, Confluence, Telegram, Vercel, Firebase, etc.)
|
|
28
|
+
- `~/.claude/CLAUDE.md` (user customisations)
|
|
29
|
+
- `~/.claude/rules/` (user-owned; installed write-if-missing, never overwritten)
|
|
30
|
+
- User content OUTSIDE the `<!-- multi-agent-pipeline:begin/end -->` markers (`copilot-instructions.md`)
|
|
31
|
+
|
|
32
|
+
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
|
+
|
|
34
|
+
## Steps
|
|
35
|
+
|
|
36
|
+
1. **Determine scope** - parse `$ARGUMENTS`:
|
|
37
|
+
- No target flag: every installed target (default)
|
|
38
|
+
- `--claude / --copilot`: selective
|
|
39
|
+
- `--all-data`: full cleanup (also removes settings + logs)
|
|
40
|
+
- `--target=<path>`: adapter target (default: cwd)
|
|
41
|
+
- `--dry-run`: report only, delete nothing
|
|
42
|
+
|
|
43
|
+
2. **Ask the cleanup depth** (skip if the user already passed `--all-data` or `--dry-run`) - native `AskUserQuestion` picker in `outputLanguage`:
|
|
44
|
+
- `question`: "How much should uninstall remove? Tokens are preserved either way."
|
|
45
|
+
- `header`: "Scope" · `options`:
|
|
46
|
+
`{ label: "Standard", description: "Remove pipeline files; keep settings + logs" }`,
|
|
47
|
+
`{ label: "Full cleanup", description: "Also remove settings + all task logs/state/metrics" }`
|
|
48
|
+
- **Full cleanup** adds `--all-data` to the flag set below.
|
|
49
|
+
|
|
50
|
+
3. **Show a preview** (run the script with `--dry-run`, carrying the chosen flags):
|
|
51
|
+
```bash
|
|
52
|
+
node "$HOME/.claude/scripts/uninstall.mjs" --dry-run --yes <flags>
|
|
53
|
+
```
|
|
54
|
+
Show the output raw to the user. In full-cleanup mode the preview lists the extra settings + log removals.
|
|
55
|
+
|
|
56
|
+
4. **First confirmation** - native `AskUserQuestion` picker (no typed y/N):
|
|
57
|
+
- `question`: "Remove the pipeline from the listed targets? Tokens are NOT touched." (`outputLanguage`)
|
|
58
|
+
- `header`: "Uninstall" · `options`: `{ label: "Continue", description: "Proceed to the final confirmation" }`, `{ label: "Cancel", description: "Keep everything installed" }`
|
|
59
|
+
- **Cancel** → exit.
|
|
60
|
+
|
|
61
|
+
5. **Second confirmation** (paranoia gate, same pattern as `:purge`) - a second `AskUserQuestion` picker:
|
|
62
|
+
- `question`: full cleanup -> "This also erases settings + all logs and is irreversible. Proceed?"; standard -> "This is irreversible. Permanently remove the pipeline files now?" (`outputLanguage`)
|
|
63
|
+
- `header`: "Confirm" · `options`: `{ label: "Remove permanently", description: "Run the uninstall; tokens are preserved" }`, `{ label: "Cancel", description: "Abort, change nothing" }`
|
|
64
|
+
- Anything other than **Remove permanently** → cancel.
|
|
65
|
+
|
|
66
|
+
6. **Remove** - run the real script with `--yes` (and `--all-data` if full cleanup was chosen):
|
|
67
|
+
```bash
|
|
68
|
+
node "$HOME/.claude/scripts/uninstall.mjs" --yes <flags>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
7. **Confirm**:
|
|
72
|
+
```
|
|
73
|
+
✓ multi-agent-pipeline removed.
|
|
74
|
+
ℹ Personal access tokens preserved in Keychain.
|
|
75
|
+
```
|
|
76
|
+
Remind the user how to inspect the tokens (cross-platform - same command on every backend):
|
|
77
|
+
- `~/.claude/lib/credential-store.sh get "<service>"`
|
|
78
|
+
|
|
79
|
+
8. **Reinstall** (if the user wants to):
|
|
80
|
+
```bash
|
|
81
|
+
npx @mmerterden/multi-agent-pipeline install
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Notes
|
|
85
|
+
|
|
86
|
+
- This command does NOT remove the *installed copy* of the npm package. It only removes the distributed files. `npm uninstall -g @mmerterden/multi-agent-pipeline` is a separate step.
|
|
87
|
+
- `--dry-run` is always safe - zero side effects.
|
|
@@ -63,10 +63,23 @@ except Exception:
|
|
|
63
63
|
|
|
64
64
|
# 1. Pull every credential entry that looks like one of our token services.
|
|
65
65
|
# Includes token entries AND username entries (BB needs the user keychain key).
|
|
66
|
-
# Uses cross-platform credential-store wrapper (macOS/Windows/Linux backends)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
# Uses cross-platform credential-store wrapper (macOS/Windows/Linux backends),
|
|
67
|
+
# located via the shared resolver (repo checkout or either install tree) -
|
|
68
|
+
# never a hardcoded path. A missing helper degrades to an empty inventory.
|
|
69
|
+
# A pre-set CRED_STORE (tests, custom installs) is honored as-is.
|
|
70
|
+
if [ -z "${CRED_STORE:-}" ]; then
|
|
71
|
+
# shellcheck disable=SC1090,SC1091
|
|
72
|
+
. "$(cd "$(dirname "$0")" && pwd)/credential-store-resolver.sh" 2>/dev/null \
|
|
73
|
+
|| . "$HOME/.claude/lib/credential-store-resolver.sh" 2>/dev/null \
|
|
74
|
+
|| . "$HOME/.copilot/lib/credential-store-resolver.sh" 2>/dev/null \
|
|
75
|
+
|| true
|
|
76
|
+
fi
|
|
77
|
+
services=""
|
|
78
|
+
if [ -n "${CRED_STORE:-}" ]; then
|
|
79
|
+
services=$("$CRED_STORE" list 2>/dev/null \
|
|
80
|
+
| grep -E '_(Github|Jira|Bitbucket|Confluence)_[A-Za-z]+_(Token|Json|Username)$|_Github_Auth_Token$|_Github_Access_Token$|_Jira_Access_Token$|_Bitbucket_Access_Token$|_Bitbucket_Username$|_Confluence_Access_Token$' \
|
|
81
|
+
|| true)
|
|
82
|
+
fi
|
|
70
83
|
|
|
71
84
|
# 2. Compute unique prefixes (everything before the provider segment).
|
|
72
85
|
prefixes=$(printf '%s\n' "$services" \
|
|
@@ -114,14 +127,6 @@ emit_accounts() {
|
|
|
114
127
|
[ $match -eq 0 ] && continue
|
|
115
128
|
fi
|
|
116
129
|
|
|
117
|
-
# Provider list
|
|
118
|
-
local prov_json=""
|
|
119
|
-
[ -n "$gh_token" ] && prov_json="${prov_json}\"github\","
|
|
120
|
-
[ -n "$jira_token" ] && prov_json="${prov_json}\"jira\","
|
|
121
|
-
[ -n "$bb_token" ] && prov_json="${prov_json}\"bitbucket\","
|
|
122
|
-
[ -n "$conf_token" ] && prov_json="${prov_json}\"confluence\","
|
|
123
|
-
prov_json="${prov_json%,}"
|
|
124
|
-
|
|
125
130
|
# Work-account heuristic: bitbucket+jira together indicates corporate.
|
|
126
131
|
local is_work="false"
|
|
127
132
|
if [ -n "$bb_token" ] && [ -n "$jira_token" ]; then
|
|
@@ -134,18 +139,18 @@ emit_accounts() {
|
|
|
134
139
|
|
|
135
140
|
# Hosts: per-account override (prefs.global.accounts[].jiraHost) wins; falls
|
|
136
141
|
# back to global.hosts.{jira,bitbucket}; otherwise null. No hardcoded values.
|
|
137
|
-
local jira_host="
|
|
142
|
+
local jira_host="" bb_host=""
|
|
138
143
|
local per_jira per_bb
|
|
139
144
|
per_jira=$(account_host_override "$short_id" "jiraHost")
|
|
140
145
|
per_bb=$(account_host_override "$short_id" "bitbucketHost")
|
|
141
146
|
if [ -n "$jira_token" ]; then
|
|
142
|
-
if [ -n "$per_jira" ]; then jira_host="
|
|
143
|
-
elif [ -n "$prefs_jira_host" ]; then jira_host="
|
|
147
|
+
if [ -n "$per_jira" ]; then jira_host="$per_jira"
|
|
148
|
+
elif [ -n "$prefs_jira_host" ]; then jira_host="$prefs_jira_host"
|
|
144
149
|
fi
|
|
145
150
|
fi
|
|
146
151
|
if [ -n "$bb_token" ]; then
|
|
147
|
-
if [ -n "$per_bb" ]; then bb_host="
|
|
148
|
-
elif [ -n "$prefs_bb_host" ]; then bb_host="
|
|
152
|
+
if [ -n "$per_bb" ]; then bb_host="$per_bb"
|
|
153
|
+
elif [ -n "$prefs_bb_host" ]; then bb_host="$prefs_bb_host"
|
|
149
154
|
fi
|
|
150
155
|
fi
|
|
151
156
|
|
|
@@ -185,12 +190,45 @@ emit_accounts() {
|
|
|
185
190
|
[ $first -eq 0 ] && printf ','
|
|
186
191
|
first=0
|
|
187
192
|
|
|
188
|
-
printf
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
# Build the entry with python3 from env vars - printf-interpolated JSON
|
|
194
|
+
# has zero escaping, so a quote or backslash in a keychain service name
|
|
195
|
+
# would corrupt the whole array. Values cross into python via the
|
|
196
|
+
# environment, never via string interpolation.
|
|
197
|
+
ACC_ID="$short_id" ACC_LABEL="$label" ACC_PREFIX="$prefix" \
|
|
198
|
+
ACC_GH_TOKEN="$gh_token" ACC_JIRA_TOKEN="$jira_token" \
|
|
199
|
+
ACC_BB_TOKEN="$bb_token" ACC_CONF_TOKEN="$conf_token" \
|
|
200
|
+
ACC_BB_USER_KEY="$bb_user_key" ACC_GH_USER="$gh_user" \
|
|
201
|
+
ACC_JIRA_HOST="$jira_host" ACC_BB_HOST="$bb_host" ACC_IS_WORK="$is_work" \
|
|
202
|
+
python3 - <<'PY'
|
|
203
|
+
import json, os
|
|
204
|
+
|
|
205
|
+
def env(name):
|
|
206
|
+
return os.environ.get(name, "")
|
|
207
|
+
|
|
208
|
+
providers = []
|
|
209
|
+
if env("ACC_GH_TOKEN"): providers.append("github")
|
|
210
|
+
if env("ACC_JIRA_TOKEN"): providers.append("jira")
|
|
211
|
+
if env("ACC_BB_TOKEN"): providers.append("bitbucket")
|
|
212
|
+
if env("ACC_CONF_TOKEN"): providers.append("confluence")
|
|
213
|
+
|
|
214
|
+
print(json.dumps({
|
|
215
|
+
"id": env("ACC_ID"),
|
|
216
|
+
"label": env("ACC_LABEL"),
|
|
217
|
+
"prefix": env("ACC_PREFIX"),
|
|
218
|
+
"providers": providers,
|
|
219
|
+
"tokens": {
|
|
220
|
+
"github": env("ACC_GH_TOKEN"),
|
|
221
|
+
"jira": env("ACC_JIRA_TOKEN"),
|
|
222
|
+
"bitbucket": env("ACC_BB_TOKEN"),
|
|
223
|
+
"confluence": env("ACC_CONF_TOKEN"),
|
|
224
|
+
},
|
|
225
|
+
"userKeys": {"bitbucket": env("ACC_BB_USER_KEY")},
|
|
226
|
+
"users": {"github": env("ACC_GH_USER")},
|
|
227
|
+
"jiraHost": env("ACC_JIRA_HOST") or None,
|
|
228
|
+
"bitbucketHost": env("ACC_BB_HOST") or None,
|
|
229
|
+
"isWork": env("ACC_IS_WORK") == "true",
|
|
230
|
+
}, ensure_ascii=False), end="")
|
|
231
|
+
PY
|
|
194
232
|
done <<< "$prefixes"
|
|
195
233
|
printf ']'
|
|
196
234
|
}
|
|
@@ -26,6 +26,11 @@ STATE="${2:-}"
|
|
|
26
26
|
}
|
|
27
27
|
[ ! -f "$STATE" ] && { echo "ERR: state file not found: $STATE" >&2; exit 2; }
|
|
28
28
|
|
|
29
|
+
# count_matches: single-line numeric grep -c (the bare `grep -c || echo 0`
|
|
30
|
+
# idiom emits "0" twice on zero matches and breaks the -le comparisons below).
|
|
31
|
+
# shellcheck source=count-lib.sh disable=SC1091
|
|
32
|
+
. "$(cd "$(dirname "$0")" && pwd)/count-lib.sh"
|
|
33
|
+
|
|
29
34
|
# --- Helpers ----------------------------------------------------------------
|
|
30
35
|
# Extract the targets array from agent-state.json. Output: TSV with columns
|
|
31
36
|
# repoName, prUrl, isPrimary (1/0). One target per row.
|
|
@@ -156,7 +161,7 @@ do_render_jira() {
|
|
|
156
161
|
local urls
|
|
157
162
|
urls=$(all_pr_urls | tr ' ' '\n' | grep -v '^$' || true)
|
|
158
163
|
local count
|
|
159
|
-
count=$(printf '%s\n' "$urls" |
|
|
164
|
+
count=$(printf '%s\n' "$urls" | count_matches .)
|
|
160
165
|
|
|
161
166
|
if [ "$count" -le 1 ]; then
|
|
162
167
|
cat "$body_file"
|
|
@@ -179,7 +184,7 @@ do_render_conf() {
|
|
|
179
184
|
local urls
|
|
180
185
|
urls=$(all_pr_urls | tr ' ' '\n' | grep -v '^$' || true)
|
|
181
186
|
local count
|
|
182
|
-
count=$(printf '%s\n' "$urls" |
|
|
187
|
+
count=$(printf '%s\n' "$urls" | count_matches .)
|
|
183
188
|
|
|
184
189
|
if [ "$count" -le 1 ]; then
|
|
185
190
|
cat "$body_file"
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# count-lib.sh - shared counting helper for pipeline shell scripts.
|
|
3
|
+
#
|
|
4
|
+
# Why: `grep -c` prints "0" AND exits 1 when nothing matches, so the common
|
|
5
|
+
# idiom `$(grep -c pattern file || echo 0)` emits TWO lines ("0" plus the
|
|
6
|
+
# fallback "0"). That breaks arithmetic (`$((x + 0\n0))` is a syntax error)
|
|
7
|
+
# and numeric comparisons (`[ "0\n0" -le 1 ]` silently evaluates false).
|
|
8
|
+
#
|
|
9
|
+
# count_matches guarantees single-line numeric output in every case:
|
|
10
|
+
# - match count when grep succeeds
|
|
11
|
+
# - "0" when nothing matches or grep itself errors (missing file, ...)
|
|
12
|
+
#
|
|
13
|
+
# Usage (same arguments as grep -c, file or stdin):
|
|
14
|
+
# n=$(count_matches -E 'pattern' "$file")
|
|
15
|
+
# n=$(printf '%s\n' "$blob" | count_matches .)
|
|
16
|
+
#
|
|
17
|
+
# Source from a sibling script:
|
|
18
|
+
# . "$(cd "$(dirname "$0")" && pwd)/count-lib.sh"
|
|
19
|
+
|
|
20
|
+
count_matches() {
|
|
21
|
+
local n
|
|
22
|
+
n=$(grep -c "$@" 2>/dev/null) || true
|
|
23
|
+
case "$n" in
|
|
24
|
+
'' | *[!0-9]*) n=0 ;;
|
|
25
|
+
esac
|
|
26
|
+
printf '%s\n' "$n"
|
|
27
|
+
}
|
|
@@ -8,6 +8,9 @@
|
|
|
8
8
|
# Subcommands:
|
|
9
9
|
# get <key> Read secret value to stdout (empty + exit 1 if missing)
|
|
10
10
|
# set <key> <value> Store secret (overwrites if exists)
|
|
11
|
+
# set <key> - Same, but read the secret from stdin. Preferred:
|
|
12
|
+
# keeps the secret off this script's argv (visible to
|
|
13
|
+
# ps). A literal "-" value cannot be stored this way.
|
|
11
14
|
# delete <key> Remove secret
|
|
12
15
|
# list List all keys (one per line)
|
|
13
16
|
# platform Print detected platform: macos | windows | linux | unknown
|
|
@@ -124,7 +127,11 @@ if (\$c) { \$c.GetNetworkCredential().Password }
|
|
|
124
127
|
|
|
125
128
|
do_set() {
|
|
126
129
|
local key="${1:-}" val="${2:-}"
|
|
127
|
-
[ -z "$key" ] && { echo "usage: $0 set <key> <value
|
|
130
|
+
[ -z "$key" ] && { echo "usage: $0 set <key> <value|->" >&2; exit 3; }
|
|
131
|
+
# "-" means: read the secret from stdin (keeps it off argv).
|
|
132
|
+
if [ "$val" = "-" ]; then
|
|
133
|
+
val=$(cat)
|
|
134
|
+
fi
|
|
128
135
|
if delegate_to_python; then
|
|
129
136
|
# Pass the value via stdin to keep it out of process listings / shell history.
|
|
130
137
|
printf '%s' "$val" | python3 "$KEYCHAIN_PY" set "$key" -
|
|
@@ -132,7 +139,15 @@ do_set() {
|
|
|
132
139
|
fi
|
|
133
140
|
case "$PLATFORM" in
|
|
134
141
|
macos)
|
|
135
|
-
security
|
|
142
|
+
# `security -i` reads the add command from stdin, so the secret never
|
|
143
|
+
# lands on the `security` argv (visible to ps). printf is a bash
|
|
144
|
+
# builtin, so no argv exposure there either. Double quotes/backslashes
|
|
145
|
+
# are escaped for security's interactive tokenizer.
|
|
146
|
+
local key_sec val_sec
|
|
147
|
+
key_sec=${key//\\/\\\\}; key_sec=${key_sec//\"/\\\"}
|
|
148
|
+
val_sec=${val//\\/\\\\}; val_sec=${val_sec//\"/\\\"}
|
|
149
|
+
printf 'add-generic-password -U -s "%s" -a "%s" -w "%s"\n' \
|
|
150
|
+
"$key_sec" "${USER:-claude}" "$val_sec" | security -i >/dev/null 2>&1
|
|
136
151
|
;;
|
|
137
152
|
linux)
|
|
138
153
|
require_cmd secret-tool "Install libsecret-tools (see doctor)."
|
|
@@ -140,11 +155,13 @@ do_set() {
|
|
|
140
155
|
;;
|
|
141
156
|
windows)
|
|
142
157
|
# Escape single quotes for PowerShell single-quoted strings ('' = literal ').
|
|
143
|
-
local key_esc="${key//\'/\'\'}"
|
|
144
|
-
#
|
|
145
|
-
|
|
158
|
+
local key_esc="${key//\'/\'\'}"
|
|
159
|
+
# The secret is piped via stdin ([Console]::In) so it never appears on
|
|
160
|
+
# the PowerShell argv (visible to process listings).
|
|
161
|
+
printf '%s' "$val" | ps_run "
|
|
146
162
|
\$ErrorActionPreference='Stop'
|
|
147
|
-
\$
|
|
163
|
+
\$raw = [Console]::In.ReadToEnd()
|
|
164
|
+
\$pwd = ConvertTo-SecureString \$raw -AsPlainText -Force
|
|
148
165
|
New-StoredCredential -Target '$key_esc' -UserName '${USER:-${USERNAME:-claude}}' -SecurePassword \$pwd -Persist LocalMachine | Out-Null
|
|
149
166
|
" >/dev/null
|
|
150
167
|
;;
|
|
@@ -40,6 +40,12 @@ if ! command -v jq >/dev/null 2>&1; then
|
|
|
40
40
|
exit 1
|
|
41
41
|
fi
|
|
42
42
|
|
|
43
|
+
# count_matches: single-line numeric grep -c. The bare `grep -c || echo 0`
|
|
44
|
+
# idiom emits "0" twice on zero matches, which turns the $((...)) counter
|
|
45
|
+
# arithmetic below into a silent syntax error that zeroes the bucket.
|
|
46
|
+
# shellcheck source=count-lib.sh disable=SC1091
|
|
47
|
+
. "$(cd "$(dirname "$0")" && pwd)/count-lib.sh"
|
|
48
|
+
|
|
43
49
|
# ---- global timing budget -----------------------------------------------------
|
|
44
50
|
SCRIPT_START_EPOCH=$(date +%s)
|
|
45
51
|
GLOBAL_BUDGET_SEC=180
|
|
@@ -672,16 +678,16 @@ bucket_test_method_naming() {
|
|
|
672
678
|
[ -z "$f" ] && continue
|
|
673
679
|
case "$PLATFORM" in
|
|
674
680
|
ios|android)
|
|
675
|
-
underscore_count=$((underscore_count + $(
|
|
676
|
-
underscore_count=$((underscore_count + $(
|
|
677
|
-
camel_count=$((camel_count + $(
|
|
678
|
-
backtick_count=$((backtick_count + $(
|
|
681
|
+
underscore_count=$((underscore_count + $(count_matches -E 'func +test[A-Za-z0-9]+_[A-Za-z0-9_]+' "$f")))
|
|
682
|
+
underscore_count=$((underscore_count + $(count_matches -E 'fun +[A-Za-z0-9]+_[A-Za-z0-9_]+_[A-Za-z0-9_]+ *\(' "$f")))
|
|
683
|
+
camel_count=$((camel_count + $(count_matches -E 'func +test[A-Z][A-Za-z0-9]+ *\(' "$f")))
|
|
684
|
+
backtick_count=$((backtick_count + $(count_matches -E '`[^`]*`\s*\(' "$f")))
|
|
679
685
|
;;
|
|
680
686
|
backend)
|
|
681
|
-
underscore_count=$((underscore_count + $(
|
|
687
|
+
underscore_count=$((underscore_count + $(count_matches -E '^def +test_[a-z0-9_]+' "$f")))
|
|
682
688
|
;;
|
|
683
689
|
frontend)
|
|
684
|
-
it_count=$((it_count + $(
|
|
690
|
+
it_count=$((it_count + $(count_matches -E "(it|test)\\(['\"\`]" "$f")))
|
|
685
691
|
;;
|
|
686
692
|
esac
|
|
687
693
|
done <<< "$test_files"
|
|
@@ -745,9 +751,9 @@ bucket_accessibility_identifier() {
|
|
|
745
751
|
if [ -z "$sample_ids" ]; then empty_bucket; return; fi
|
|
746
752
|
|
|
747
753
|
local dot_count snake_count camel_count
|
|
748
|
-
dot_count=$(printf '%s\n' "$sample_ids" |
|
|
749
|
-
snake_count=$(printf '%s\n' "$sample_ids" |
|
|
750
|
-
camel_count=$(printf '%s\n' "$sample_ids" |
|
|
754
|
+
dot_count=$(printf '%s\n' "$sample_ids" | count_matches -E '"[a-z]+(\.[a-zA-Z]+)+')
|
|
755
|
+
snake_count=$(printf '%s\n' "$sample_ids" | count_matches -E '"[a-z]+_[a-z_]+')
|
|
756
|
+
camel_count=$(printf '%s\n' "$sample_ids" | count_matches -E '"[a-z]+[A-Z][a-zA-Z]+')
|
|
751
757
|
dot_count=${dot_count:-0}; snake_count=${snake_count:-0}; camel_count=${camel_count:-0}
|
|
752
758
|
|
|
753
759
|
local evidence_json
|
|
@@ -772,9 +778,9 @@ bucket_accessibility_identifier() {
|
|
|
772
778
|
done | head -30 || true)
|
|
773
779
|
if [ -z "$ids" ]; then empty_bucket; return; fi
|
|
774
780
|
local snake_count kebab_count camel_count
|
|
775
|
-
snake_count=$(printf '%s\n' "$ids" |
|
|
776
|
-
kebab_count=$(printf '%s\n' "$ids" |
|
|
777
|
-
camel_count=$(printf '%s\n' "$ids" |
|
|
781
|
+
snake_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+_[a-z_]+')
|
|
782
|
+
kebab_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+-[a-z\-]+')
|
|
783
|
+
camel_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+[A-Z][a-zA-Z]+')
|
|
778
784
|
snake_count=${snake_count:-0}; kebab_count=${kebab_count:-0}; camel_count=${camel_count:-0}
|
|
779
785
|
if [ "$snake_count" -ge "$kebab_count" ] && [ "$snake_count" -ge "$camel_count" ] && [ "$snake_count" -gt 0 ]; then
|
|
780
786
|
emit_bucket "snake_case testTag" "checkin_continue_button" "$(confidence_for "$snake_count")" "[]" '["kebab","camelCase"]'
|
|
@@ -797,8 +803,8 @@ bucket_accessibility_identifier() {
|
|
|
797
803
|
done | head -50 || true)
|
|
798
804
|
if [ -z "$op_ids" ]; then empty_bucket; return; fi
|
|
799
805
|
local camel_count snake_count
|
|
800
|
-
camel_count=$(printf '%s\n' "$op_ids" |
|
|
801
|
-
snake_count=$(printf '%s\n' "$op_ids" |
|
|
806
|
+
camel_count=$(printf '%s\n' "$op_ids" | count_matches -E '[a-z]+[A-Z][A-Za-z]+')
|
|
807
|
+
snake_count=$(printf '%s\n' "$op_ids" | count_matches -E '[a-z]+_[a-z_]+')
|
|
802
808
|
camel_count=${camel_count:-0}; snake_count=${snake_count:-0}
|
|
803
809
|
if [ "$camel_count" -ge "$snake_count" ] && [ "$camel_count" -gt 0 ]; then
|
|
804
810
|
emit_bucket "camelCase operationId" "createFoo" "$(confidence_for "$camel_count")" "[]" '["snake_case"]'
|
|
@@ -817,9 +823,9 @@ bucket_accessibility_identifier() {
|
|
|
817
823
|
done | head -30 || true)
|
|
818
824
|
if [ -z "$ids" ]; then empty_bucket; return; fi
|
|
819
825
|
local kebab_count camel_count snake_count
|
|
820
|
-
kebab_count=$(printf '%s\n' "$ids" |
|
|
821
|
-
camel_count=$(printf '%s\n' "$ids" |
|
|
822
|
-
snake_count=$(printf '%s\n' "$ids" |
|
|
826
|
+
kebab_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+-[a-z\-]+')
|
|
827
|
+
camel_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+[A-Z][a-zA-Z]+')
|
|
828
|
+
snake_count=$(printf '%s\n' "$ids" | count_matches -E '"[a-z]+_[a-z_]+')
|
|
823
829
|
kebab_count=${kebab_count:-0}; camel_count=${camel_count:-0}; snake_count=${snake_count:-0}
|
|
824
830
|
if [ "$kebab_count" -ge "$camel_count" ] && [ "$kebab_count" -ge "$snake_count" ] && [ "$kebab_count" -gt 0 ]; then
|
|
825
831
|
emit_bucket "kebab-case data-testid" 'data-testid="checkin-continue-button"' "$(confidence_for "$kebab_count")" "[]" '["camelCase","snake"]'
|
|
@@ -879,9 +885,9 @@ bucket_localization_key() {
|
|
|
879
885
|
if [ -z "$keys" ]; then empty_bucket; return; fi
|
|
880
886
|
|
|
881
887
|
local dot_count snake_count camel_count
|
|
882
|
-
dot_count=$(printf '%s\n' "$keys" |
|
|
883
|
-
snake_count=$(printf '%s\n' "$keys" |
|
|
884
|
-
camel_count=$(printf '%s\n' "$keys" |
|
|
888
|
+
dot_count=$(printf '%s\n' "$keys" | count_matches -E '^[A-Za-z][A-Za-z0-9]*(\.[A-Za-z][A-Za-z0-9]*)+')
|
|
889
|
+
snake_count=$(printf '%s\n' "$keys" | count_matches -E '^[a-z][a-z0-9]*(_[a-z0-9]+)+')
|
|
890
|
+
camel_count=$(printf '%s\n' "$keys" | count_matches -E '^[a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*')
|
|
885
891
|
dot_count=${dot_count:-0}; snake_count=${snake_count:-0}; camel_count=${camel_count:-0}
|
|
886
892
|
|
|
887
893
|
if [ "$dot_count" -ge "$snake_count" ] && [ "$dot_count" -ge "$camel_count" ] && [ "$dot_count" -gt 0 ]; then
|
|
@@ -907,7 +913,7 @@ bucket_di_registration() {
|
|
|
907
913
|
local resolver_count factory_count manual_count swinject_count
|
|
908
914
|
manual_count=0; resolver_count=0; factory_count=0; swinject_count=0
|
|
909
915
|
if [ -n "$configurators" ]; then
|
|
910
|
-
manual_count=$(printf '%s\n' "$configurators" |
|
|
916
|
+
manual_count=$(printf '%s\n' "$configurators" | count_matches 'DependencyConfigurator')
|
|
911
917
|
fi
|
|
912
918
|
files=$(run_find -type f -name '*.swift' 2>/dev/null || true)
|
|
913
919
|
if [ -n "$files" ]; then
|