@mmerterden/multi-agent-pipeline 20.8.1 → 20.8.2
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 +36 -0
- package/docs/facts.json +3 -3
- package/index.js +1 -0
- package/install/_codex-agents.mjs +1 -1
- package/install/_common.mjs +486 -53
- package/install/_mcp-register.mjs +173 -117
- package/install/claude.mjs +281 -220
- package/install/codex.mjs +7 -7
- package/install/copilot.mjs +13 -11
- package/install/index.mjs +92 -27
- package/install/templates/claude-hooks.json +9 -9
- package/manifest.json +75 -78
- package/package.json +4 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +28 -17
- package/pipeline/lib/confusables.json +79 -33
- package/pipeline/lib/extract-conventions.sh +3 -3
- package/pipeline/lib/json-file-lock.mjs +27 -7
- package/pipeline/lib/normalize-text.mjs +86 -17
- package/pipeline/lib/outbound-gate.mjs +13 -4
- package/pipeline/lib/redact.mjs +87 -14
- package/pipeline/multi-agent-refs/analysis/evidence.md +1 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +1 -1
- package/pipeline/multi-agent-refs/conventions-defaults.md +1 -1
- package/pipeline/multi-agent-refs/features/unattended-security.md +2 -2
- package/pipeline/scripts/agent-guard.py +150 -25
- package/pipeline/scripts/audit-log.sh +3 -4
- package/pipeline/scripts/autopilot-runner.mjs +14 -5
- package/pipeline/scripts/doctor.mjs +8 -2
- package/pipeline/scripts/log-metric.sh +9 -3
- package/pipeline/scripts/migrate-prefs.mjs +18 -4
- package/pipeline/scripts/pre-commit-check.sh +119 -31
- package/pipeline/scripts/scan-agent-config.sh +9 -9
- package/pipeline/scripts/unattended_policy.py +12 -3
- package/pipeline/scripts/uninstall.mjs +88 -1
- package/pipeline/scripts/usage-identity.mjs +1 -1
- package/pipeline/scripts/usage-register.mjs +1 -1
- package/pipeline/skills/.skill-manifest.json +11 -11
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +6 -3
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +43 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +31 -0
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-module-structure/modules/_TEMPLATE.yml +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +2 -1
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +14 -13
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +7 -7
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +105 -4
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +20 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +7 -8
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +20 -7
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-key-shots.py +4 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +15 -8
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +17 -9
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +39 -17
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +28 -7
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +5 -4
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +3 -2
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -2
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +4 -4
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +15 -6
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +8 -4
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +1 -1
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +25 -6
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/skill-creator/template.md +1 -1
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +3 -1
- package/pipeline/scripts/gen-ref-toc.mjs +0 -279
- package/pipeline/scripts/make-manifest.mjs +0 -199
- package/pipeline/scripts/scorecard-snapshot.mjs +0 -178
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,42 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [20.8.2] - 2026-09-27
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- The guard fold (`lib/normalize-text.mjs`, `scripts/agent-guard.py`) removes the whole Default_Ignorable_Code_Point set, read from `stripRanges` in `lib/confusables.json`: variation selectors, tag characters, the Mongolian free variation selectors and the musical formatting controls as well as the zero-width family. A commit trailer or a token carrying one of them is blocked.
|
|
24
|
+
- `lib/confusables.json` maps the compatibility letters and digits added after Unicode 13 whose NFKC form is ASCII (Outlined Latin, the modifier letters), so a Python whose `unicodedata` is older than Node's ICU folds them the same way. `test/normalize-parity.test.mjs` runs both folds over one shared sample file.
|
|
25
|
+
- `lib/normalize-text.mjs` loads its table fail-soft: without `confusables.json` it folds with NFKC only and prints one notice, so `lib/redact.mjs` and the log writers still redact. The outbound gate refuses to scan without the table.
|
|
26
|
+
- `lib/redact.mjs` matches credentials on the folded text and replaces the matching span of the original, so a token written with a look-alike letter or a non-breaking hyphen is redacted, and a line without a credential is written back byte for byte (Persian zero-width non-joiners, direction marks, joined emoji and soft hyphens included).
|
|
27
|
+
- The outbound gate skips the fold for pure-ASCII lines, and `pre-commit-check.sh` folds every non-ASCII file of a run in one node process, warning once per run when the fold is unavailable or fails.
|
|
28
|
+
- The `pre-commit-check.sh` identifier exemption for letters-only strings scores the letter pairs inside each segment against English: every pair carries log2 of its frequency in a 235k-word English word list relative to a uniform draw, rounded and clipped to -4..4, and the mean over the token must reach +0.25, with segments averaging 4+ letters and none longer than 24, and short all-caps acronyms not scored. Long CamelCase and snake_case identifiers built from words keep passing with an abbreviation inside (`Qr`, `Ffp`, `Otp`, `Cvv`, `Kg`, `Background`); fixed-seed random letters-only tokens are not exempt.
|
|
29
|
+
- `pre-commit-check.sh` returns at once in hook mode when the command does not spell `git`, with quotes and backslashes removed, and `agent-guard.py --git-subcommand` prints `commit` at its deadline so the scan runs rather than timing out. A commit whose command is a megabyte long is scanned inside the hook timeout.
|
|
30
|
+
- `agent-guard.py` tokenizes a segment longer than 16 KiB by whitespace with quotes and backslashes removed instead of with `shlex`, whose cost grows with the square of a token's length, and `unattended_policy.py` does the same. At the internal deadline, and on an internal error, a linear scan of the command still applies the force-push and attribution rules, attended and unattended. A force-push to a protected branch or an attribution trailer padded with a megabyte of text is blocked.
|
|
31
|
+
- `lib/redact.mjs` runs the rules on the raw text as well as on the folded copy and merges the spans, so a letter that folds to a word character next to a token (the Turkish dotless i, a ligature, a mathematical letter) no longer makes the whole line the replacement: only the token is. Where two rules match overlapping text, the one with the longer literal prefix names it, so an `sk-ant-` key is labelled `anthropic-key`.
|
|
32
|
+
- The unattended policy path-checks the toolkit's `output` (`ios_visual_diff`, `pass_build`) and `output_graph` (`ios_leaks`) parameters. `test/fixtures/toolkit-path-params.json`, generated by `test/fixtures/gen-toolkit-path-params.mjs` from the toolkit's tool schemas without starting it, lists every write parameter, and the unattended-guard test checks each one.
|
|
33
|
+
- `log-metric.sh` escapes `task_id`, `phase`, `event` and the detail keys with the same `json_escape` as `audit-log.sh`, and keeps a newline in a value as `\n` instead of dropping it, so a quote, backslash or newline in any field leaves one valid JSON line.
|
|
34
|
+
- The `outbound-gate.mjs` header documents exit 0 for an empty body and exit 2 for `--file` without a path, which is what the CLI does.
|
|
35
|
+
- `eval-guard-robustness.mjs` covers the new disguises on every guard, checks the redactor on every disguise, requires fullwidth tokens to be caught, adds Persian, Arabic and joined-emoji negatives, and removes its temporary directory.
|
|
36
|
+
- `check-rewrite-overlap.mjs` exits 2 on a path it cannot read, an empty or malformed `--max` or `--n`, and the `--flag=value` form.
|
|
37
|
+
- `package.json` `files` leaves out `gen-ref-toc.mjs`, `make-manifest.mjs` and `scorecard-snapshot.mjs`, and `smoke-consumer-smoke-surface.sh` holds the tarball's `pipeline/scripts/` to `isDevOnlyScript`.
|
|
38
|
+
- The `skill-creator` template states that the `metadata` block with `source` is required under `shared/external`, and optional elsewhere.
|
|
39
|
+
- `localization-reuse-map`: the key accessor type is an input (`--key-type`, repeatable or a comma list, or `keyType` in the mapping for `verify-map.py`; default `L10n`), and the language list is `--langs` or, for `all`, the languages present in the data, `en` first. `fetch-annotations.py`, `render-overlay.py`, `render-key-shots.py` and `publish-confluence.py` refuse `--token` with exit 2 and name the environment variable and keychain item to use; `publish-confluence.py` bounds each curl request with `--connect-timeout 15`, `--max-time 120` and a 150-second process timeout.
|
|
40
|
+
- `localization-reuse-map`: `resolve-new-values.py` and `resolve-legacy-values.py` default to `--langs all`, as the workflow already calls them, and the legacy-prefix examples use a neutral `App-`.
|
|
41
|
+
- `localization-reuse-map`: the default key accessor type is now `L10n`, and each project sets its own with `--key-type` or `keyType` in the mapping. When no chain of the configured type is found but Swift or Kotlin code has chains rooted at a common accessor name or ending in `.localized`, `scan-screen-keys.py` and `verify-map.py` print a `WARNING` naming those roots and the flag, and add `keyTypeWarning` to their JSON; the SKILL.md workflow sets the accessor before the scan and the gate. `verify-map.py` refuses a mapping `keyType` that is not a string or a list of strings with exit 2 instead of a traceback, and `format-and-output.md` documents the field and the `--langs all` defaults.
|
|
42
|
+
- Knowledge skills, checked against the iOS 26.4 SDK: notification grouping comes from the thread identifier and `summaryArgument` is not set (ignored since iOS 15); only four Apple Pay request types exclude each other and `applePayLaterAvailability` is separate; PencilKit `.version3` is the fountain-pen ink of iOS 17.5; RealityView placement uses anchors and raycasts go through `ARView`; the `StatefulRequest` list in `vision-framework` is complete; `permissionkit` names its non-`Sendable` types and `expirationDate`; `core-nfc` covers the iOS 26.4 session configuration; `cloudkit-sync` shows coordinated file access; `callkit-voip` no longer relies on `localizedName`.
|
|
43
|
+
- `extract-conventions.sh` recognises per-module DI registrars named `*DependencyRegistrar` as well as `*DependencyConfigurator` and reports them as "manual per-module registrar"; docs, templates and rule text describe these types by role.
|
|
44
|
+
- The 20.8.1 `localization-reuse-map` entry names one component mark; the code accepts three in the key column: `(owned by ...)`, `(bileşen ...)` and `(component ...)`.
|
|
45
|
+
- Install (Claude Code): `commands/multi-agent`, `multi-agent-refs`, `scripts`, `schemas`, `lib` and `templates` are each staged under `~/.claude/.pipeline-swap/` and swapped in by rename once all of them staged; the previous copies wait there until every swap succeeded, so no half-written or leftover copy ever sits inside `commands/`, where it would load as a command namespace. A copy or swap error leaves the previous install in place, prints one `install incomplete: ...` line and exits 1; `MULTI_AGENT_INSTALL_DEBUG=1` adds the stack trace. A leftover copy from an interrupted run is cleaned up or restored on the next install, one that cannot be deleted (a read-only subdirectory) is moved aside inside `.pipeline-swap/` with a note, and uninstall removes the directory.
|
|
46
|
+
- Install: a symlinked `rules/`, `agents/`, `commands/` or skills root that points outside the pipeline source is the user's; the install writes through it. Only a symlink into a pipeline checkout (a `--link` install) is replaced with a real directory. A pipeline-managed tree whose symlink points elsewhere is skipped with a warning. Applies to the Copilot CLI and Codex CLI installers too.
|
|
47
|
+
- Install (Claude Code): `~/.claude/.pipeline-manifest.json` records the hash of every co-owned file the installer writes (the top-level `commands/*.md`, `lib/`, `templates/`). A file is overwritten only when it is absent or unchanged since the last install; a file the user wrote or edited is kept and reported once. Files the source stops shipping are removed when unchanged, and other files in `lib/` and `templates/` are kept and reported once. The first install after one without a manifest adopts the files carrying shipped names.
|
|
48
|
+
- Uninstall (Claude Code) removes the manifest-listed files whose hash still matches, including the four top-level commands and `templates/`, keeps edited ones, and falls back to the shipped template names for an install without a manifest.
|
|
49
|
+
- Hook commands are written as `bash "$HOME/.claude/scripts/<script>.sh"`, so a HOME containing a space no longer makes the hook exit 126 and the guard stop. A re-install rewrites unquoted pipeline hook commands in place without duplicates; `install/templates/claude-hooks.json` uses the quoted form, `doctor` compares hook commands exactly, and `scan-agent-config.sh` and the autopilot runner accept the quoted and unquoted forms.
|
|
50
|
+
- `install.js --installed` installs the targets that already carry a version stamp (`~/.claude`, `~/.copilot`, `~/.codex` `.pipeline-version`), and Claude Code when none does. `/multi-agent:update` uses it instead of `--all`, so an update no longer installs Copilot CLI or Codex CLI (and registers their MCP server) on a machine that did not have them.
|
|
51
|
+
- `/multi-agent:update` keeps the values later steps need in `${TMPDIR:-/tmp}/multi-agent-update.env`, and every later shell block sources it: each block runs in a fresh shell, so `$CUR`, `$LATEST`, `$PKG`, `$REG` and `$UPD_DIR` were empty in steps 2, 3, 6 and 7.
|
|
52
|
+
- `migrate-prefs.mjs` writes `<file>.bak` before migrating and writes through a symlinked preferences file to its target; `usage-register.mjs` and `usage-identity.mjs` also write through the link. `writeJsonAtomicSync` and `updateJsonFileSync` take `followSymlink` (off by default).
|
|
53
|
+
- MCP registration adds first and reads the registered spec back only on "already exists": the same spec is left alone, a different one is replaced, and when the replacing add fails the previous spec is added back, so the host never ends up without the server. A spec that cannot be read back is left in place with the manual command.
|
|
54
|
+
|
|
19
55
|
## [20.8.1] - 2026-09-26
|
|
20
56
|
|
|
21
57
|
### Fixed
|
package/docs/facts.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "Generated by pipeline/scripts/gen-facts.mjs. Do not hand-edit: the site reads this, and a number edited here instead of at its source is the drift this file removes.",
|
|
3
|
-
"generatedAt": "2026-09-
|
|
4
|
-
"version": "20.8.
|
|
3
|
+
"generatedAt": "2026-09-27",
|
|
4
|
+
"version": "20.8.2",
|
|
5
5
|
"phaseSchema": 2,
|
|
6
6
|
"phases": [
|
|
7
7
|
{
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"media": 1
|
|
57
57
|
},
|
|
58
58
|
"pluginSkillCount": 245,
|
|
59
|
-
"toolkitVersion": "3.16.
|
|
59
|
+
"toolkitVersion": "3.16.1"
|
|
60
60
|
}
|
package/index.js
CHANGED
|
@@ -87,6 +87,7 @@ if (command === "--version" || command === "-v" || command === "version") {
|
|
|
87
87
|
npx @mmerterden/multi-agent-pipeline install --copilot Install for Copilot CLI
|
|
88
88
|
npx @mmerterden/multi-agent-pipeline install --codex Install for Codex CLI
|
|
89
89
|
npx @mmerterden/multi-agent-pipeline install --all Claude + Copilot + Codex
|
|
90
|
+
npx @mmerterden/multi-agent-pipeline install --installed Refresh only the targets already installed
|
|
90
91
|
npx @mmerterden/multi-agent-pipeline install --link Use symlinks (saves tokens, dev mode)
|
|
91
92
|
npx @mmerterden/multi-agent-pipeline install --dry-run Preview what would be written, write nothing
|
|
92
93
|
npx @mmerterden/multi-agent-pipeline install --index-only Ship only the skills index (dynamic skill loading)
|
|
@@ -144,7 +144,7 @@ export function installCodexAgents(agentsSrc, dest) {
|
|
|
144
144
|
|
|
145
145
|
// ensureRealDir only swaps a --link-era symlink for a real dir; it does not
|
|
146
146
|
// create a missing one. Both calls are needed.
|
|
147
|
-
ensureRealDir(dest);
|
|
147
|
+
dest = ensureRealDir(dest, { userOwned: true });
|
|
148
148
|
ensureDir(dest);
|
|
149
149
|
|
|
150
150
|
// `~/.codex/agents/` also holds user-authored agents, so never wipe the dir.
|