@mmerterden/multi-agent-pipeline 20.18.0 → 20.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,12 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [20.19.0] - 2026-10-09
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- `/multi-agent:update` ends with a note of what the update brought, in the user's language: every release between the installed and the new version (not only the last one, and not cut at 40 lines), grouped as new, fixed, changed and removed, plus each stack plugin the refresh moved and what its releases added. The note is written from `release-notes.mjs`, which reads the new release's CHANGELOG and each updated plugin's CHANGELOG and never fails the update; internal-only entries are left out and nothing is added that the CHANGELOGs do not say.
|
|
24
|
+
|
|
19
25
|
## [20.18.0] - 2026-10-09
|
|
20
26
|
|
|
21
27
|
### Added
|
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
3
|
"generatedAt": "2026-10-09",
|
|
4
|
-
"version": "20.
|
|
4
|
+
"version": "20.19.0",
|
|
5
5
|
"phaseSchema": 2,
|
|
6
6
|
"phases": [
|
|
7
7
|
{
|
package/manifest.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "20.
|
|
4
|
-
"commit": "
|
|
5
|
-
"generatedAt": "2026-10-
|
|
3
|
+
"version": "20.19.0",
|
|
4
|
+
"commit": "6db35d97282cfe57fab9bb66a0da8bc6696aca99",
|
|
5
|
+
"generatedAt": "2026-10-09T11:19:00.589Z",
|
|
6
6
|
"algorithm": "sha256",
|
|
7
|
-
"fileCount":
|
|
7
|
+
"fileCount": 1357,
|
|
8
8
|
"files": {
|
|
9
|
-
"CHANGELOG.md": "
|
|
9
|
+
"CHANGELOG.md": "273977981d9581cd702e05f063930ef2cff624a76b687472cf0fef545e7adad3",
|
|
10
10
|
"LICENSE": "8d8c51aaf1e1538b180c69965fa038db71be86798cc3e26a143bebfefe16a43e",
|
|
11
11
|
"README.md": "1336cf131fdc0dbab1dd8b90fcd5614bd19d27b92b4f91ab99c3108d61cb51e1",
|
|
12
12
|
"README.tr.md": "7979b32e6c72aedc3a6affe85f33b2840e72f056a836e8546566d259b236ff29",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"docs/best-practices.md": "f8b75b0d38b5896a6a852bb30a1edddeb24dab8b5b7b1d9313290e1241c72024",
|
|
34
34
|
"docs/ecosystem.md": "d504124f421748744599f6974ec71d52664affc47740665651cca5ddc17d0c71",
|
|
35
35
|
"docs/engineering.md": "550528cd47c7d2c921729c68d0782a00ac8e77a4bdfec479f6749f9c3235d188",
|
|
36
|
-
"docs/facts.json": "
|
|
36
|
+
"docs/facts.json": "80256de517e282de9b5a6e135a270d45a0590ab77ef579fafd171d644ce917b0",
|
|
37
37
|
"docs/features.md": "87ae163280fe05b36ff9f664b1bf9d98b697cc498731d47298751b439fa7a35c",
|
|
38
38
|
"docs/performance.md": "bbf2f3922c25dcba0c1a9e69ef420e3871a729af5b35009a49b48a5d3c5cd151",
|
|
39
39
|
"docs/recovery-guide.md": "59a8f1b66b34cb9ff5507b3d54dac3b9915e184aa044d9c758d18cac818d510e",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"install/templates/multi-agent-autopilot-awake.plist.template": "ddd25c76c56fcbb38a89de8e35637372d70ace993d6bc487a88ca9cfb702fe1f",
|
|
64
64
|
"install/templates/multi-agent-autopilot.plist.template": "122c8a61cd927edd99375d6e3da40f1d42bcceed5b6641785c8b28bb930bc77e",
|
|
65
65
|
"install/unattended-profile-legacy.json": "f52e86b998956f09ad306b1735a6c10b58580d7082d8a55665a4c6bb15c3aa1f",
|
|
66
|
-
"package.json": "
|
|
66
|
+
"package.json": "c45fc8e778927b72b074d2692f8fd895186b1adc1c752cfa2e18ff41c6822d49",
|
|
67
67
|
"pipeline/agents/android-architect.md": "11fb74543cb0ebcf9525ca6654fe95d53da7229e0bf4a1149b31fd9005abc453",
|
|
68
68
|
"pipeline/agents/backend-architect.md": "b02a606c301e4714131aed70ae6d16eeb77fbc819a001e2752cff2488d4246de",
|
|
69
69
|
"pipeline/agents/bulk-reader.md": "6597052cd7d205bac2b1c7633f5232fe1a40730664a913b8eb77efd5a786dc25",
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
"pipeline/commands/multi-agent/test/SKILL.md": "5a67be2b1ec0321e79f8b7f35be53676e349e55a4f8ca09a07f0de89dadac8c4",
|
|
143
143
|
"pipeline/commands/multi-agent/testflight-validation/SKILL.md": "38fa8d3d3c8340d025e100c53a70183cbad22665b7ddccbb6102c05986cce489",
|
|
144
144
|
"pipeline/commands/multi-agent/uninstall/SKILL.md": "b2124820a6e10cdd72be71df2183aad4f8bd8988ec90248c88599c1514f7d9ab",
|
|
145
|
-
"pipeline/commands/multi-agent/update/SKILL.md": "
|
|
145
|
+
"pipeline/commands/multi-agent/update/SKILL.md": "4b9ca40382eb2bd06f8b1a483d6232d1e9941d6e6288a21e83fa977482a1bae7",
|
|
146
146
|
"pipeline/commands/sim-test.md": "b09038b9511108c77fae5e0c11f8515b5c64eb8b63a77fe8c2ff5907ddd0313a",
|
|
147
147
|
"pipeline/contract/CHANGELOG.md": "0813f5737219bafad3eb4daf809b9754937fae8533e07caf3850e30b2685662b",
|
|
148
148
|
"pipeline/contract/README.md": "6239eb0877d70e70d63db74bae3499599b0425c80c71eceb6bb0a981523eaa89",
|
|
@@ -483,7 +483,7 @@
|
|
|
483
483
|
"pipeline/schemas/unattended-profile.json": "05bc095b6328ff77b7bee8b008becf9aa20f1dabeab3b0fc174b97cad421e23b",
|
|
484
484
|
"pipeline/schemas/unattended-profile.schema.json": "a9c0979f0d0742826e410fdbfe1ae1c4a56b05b4e638eec42d4c276d6f48f701",
|
|
485
485
|
"pipeline/schemas/worktrees.schema.json": "4e15c413c00811814eee734d86734ad9e1d34a37737f7df641b389ce5d8d134b",
|
|
486
|
-
"pipeline/scripts/README.md": "
|
|
486
|
+
"pipeline/scripts/README.md": "4cdf7054cddbe5cdcb08460f68782f2347a26c8c343d8ef8418714464672b36c",
|
|
487
487
|
"pipeline/scripts/_autopilot-config.mjs": "0f42d2791f1d71c4aad5a0735ca56fef1ed27d275b72f99d8ca8f95fcb8aa83a",
|
|
488
488
|
"pipeline/scripts/_autopilot-ops.mjs": "5e84d628482434c8f09dc69601c73ab70e928af15c2f068d998d2f61bd692d1a",
|
|
489
489
|
"pipeline/scripts/_autopilot-outcomes.mjs": "5b2423814d979ed5c657473290083b296f7245d40507c866e7931b2771001236",
|
|
@@ -617,6 +617,7 @@
|
|
|
617
617
|
"pipeline/scripts/prune-logs.sh": "c5587b33104c7253e07be8cce8249b50014c52dfdf232de637811ffdd88e95e4",
|
|
618
618
|
"pipeline/scripts/purge.sh": "95c60b272ae47209893dba9b17528538592bb5636da47940a02734cd9b4f0ce5",
|
|
619
619
|
"pipeline/scripts/record-phase.mjs": "041dc262e54f38b66299f45c44db7918812e599a773f5a3dc78cfd09ab5e155e",
|
|
620
|
+
"pipeline/scripts/release-notes.mjs": "05430926cf679534978bcc79c160a6787aaf04831b8b8489d8bbc9fa343a14af",
|
|
620
621
|
"pipeline/scripts/render-agent-log-cost.sh": "6c58c1f5754ff5754485a0c1b66f4cd713575d2e8ebb1630aedf2f87fe34ef4d",
|
|
621
622
|
"pipeline/scripts/render-cost-summary.sh": "ce9647332ab9a3e518af98f52a6fc70baab9fd3c09ec5f9e85bae2d67078a5e3",
|
|
622
623
|
"pipeline/scripts/render-work-summary.sh": "ee4db04ebc145cc2fc7fa9a533d42b7da4da191710ef67c883502ca83b2aa67c",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "20.
|
|
3
|
+
"version": "20.19.0",
|
|
4
4
|
"description": "6-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -100,9 +100,13 @@ and every later block that needs them starts by sourcing it.
|
|
|
100
100
|
|
|
101
101
|
4b. **Update the stack plugins** (catalog refresh, then every installed plugin in its own scope):
|
|
102
102
|
```bash
|
|
103
|
-
|
|
103
|
+
REFRESH_LOG="${TMPDIR:-/tmp}/multi-agent-plugin-refresh.log"
|
|
104
|
+
bash "$HOME/.claude/scripts/plugin-refresh.sh" {owner} > "$REFRESH_LOG" 2>&1
|
|
105
|
+
rc=$?
|
|
106
|
+
cat "$REFRESH_LOG"
|
|
107
|
+
echo "plugin-refresh exit: $rc"
|
|
104
108
|
```
|
|
105
|
-
A non-zero exit means a step failed and the CLI's own error is already on screen. Report it to the user; do not retry silently.
|
|
109
|
+
A non-zero exit means a step failed and the CLI's own error is already on screen. Report it to the user; do not retry silently. The log feeds step 6, which tells the user what each updated plugin brought.
|
|
106
110
|
|
|
107
111
|
4c. **Prune retired adapter files** (Cursor / Antigravity / Copilot Chat were removed in v10.7.0 - the pipeline targets Claude Code, Copilot CLI and Codex CLI):
|
|
108
112
|
```bash
|
|
@@ -139,19 +143,41 @@ and every later block that needs them starts by sourcing it.
|
|
|
139
143
|
or an SSH key on the personal account (the "Personal account" step in
|
|
140
144
|
`$HOME/.claude/multi-agent-refs/features/usage-reporting.md`).
|
|
141
145
|
|
|
142
|
-
6. **
|
|
146
|
+
6. **Tell the user what the update brought.** Read the notes, then write the summary yourself:
|
|
143
147
|
```bash
|
|
144
148
|
. "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
|
|
145
149
|
NEW=$(tr -d '[:space:]' < "$HOME/.claude/.pipeline-version" 2>/dev/null)
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
"$
|
|
150
|
+
NOTES="$UPD_DIR/package/pipeline/scripts/release-notes.mjs"
|
|
151
|
+
[ -f "$NOTES" ] || NOTES="$HOME/.claude/scripts/release-notes.mjs"
|
|
152
|
+
LOG="$UPD_DIR/package/CHANGELOG.md"
|
|
153
|
+
[ -f "$LOG" ] || LOG=/nonexistent
|
|
154
|
+
node "$NOTES" --changelog "$LOG" --from "$CUR" --to "$NEW" \
|
|
155
|
+
--plugins-dir "$HOME/.claude/plugins/marketplaces/multi-agent-plugins/plugins" \
|
|
156
|
+
--plugin-refresh-log "${TMPDIR:-/tmp}/multi-agent-plugin-refresh.log"
|
|
153
157
|
```
|
|
154
158
|
|
|
159
|
+
The JSON holds every release between the old and the new version (not only
|
|
160
|
+
the last one) and, for each plugin the refresh moved, that plugin's releases.
|
|
161
|
+
Turn it into a short note in `outputLanguage`, written for the person using
|
|
162
|
+
the pipeline, not for its maintainers:
|
|
163
|
+
|
|
164
|
+
- First line: `✓ Updated: v<CUR> → v<NEW>`, then one line per updated plugin
|
|
165
|
+
(`ai-ios-toolkit 0.20.0 → 0.21.0`).
|
|
166
|
+
- Then up to four groups, each only when it has entries: **New** (added),
|
|
167
|
+
**Fixed**, **Changed**, **Removed** (Turkish: Yeni, Düzeltilen, Değişen,
|
|
168
|
+
Kaldırılan). Put security entries first under Fixed.
|
|
169
|
+
- One plain sentence per item about what the user notices or can now do.
|
|
170
|
+
Merge items that say the same thing; leave out internal-only entries
|
|
171
|
+
(smoke tests, CI, refactors, budgets, docs) unless they change what a user
|
|
172
|
+
sees. At most about eight items per group; when more were dropped, say how
|
|
173
|
+
many and that the full list is in the CHANGELOG.
|
|
174
|
+
- Use only what the JSON says. Never invent a feature or a fix, and never
|
|
175
|
+
guess why something changed.
|
|
176
|
+
- Last line, when anything needs action: what to do (restart Claude Code for
|
|
177
|
+
plugin changes, run a command a release asks for).
|
|
178
|
+
|
|
179
|
+
With empty notes and no plugin updates, print only the version line.
|
|
180
|
+
|
|
155
181
|
7. **Smoke test (optional)** - the release tarball ships exactly two smokes for this purpose:
|
|
156
182
|
```bash
|
|
157
183
|
. "${TMPDIR:-/tmp}/multi-agent-update.env" || { echo "Run step 1 first."; exit 1; }
|
|
@@ -165,18 +191,19 @@ and every later block that needs them starts by sourcing it.
|
|
|
165
191
|
## Output
|
|
166
192
|
|
|
167
193
|
```
|
|
168
|
-
Current: v15.6.0 Latest: v15.
|
|
169
|
-
-> npm pack @{npm-scope}/multi-agent-pipeline@15.
|
|
194
|
+
Current: v15.6.0 Latest: v15.7.0
|
|
195
|
+
-> npm pack @{npm-scope}/multi-agent-pipeline@15.7.0
|
|
170
196
|
-> node install.js --installed (Claude Code; no Copilot CLI or Codex CLI stamp, not installed)
|
|
171
197
|
-> migrate-prefs.mjs (0 changes - already v2.6.0)
|
|
172
198
|
|
|
173
|
-
✓ Updated: v15.6.0 → v15.
|
|
199
|
+
✓ Updated: v15.6.0 → v15.7.0
|
|
200
|
+
ai-ios-toolkit 0.19.0 → 0.20.0
|
|
174
201
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
-
|
|
179
|
-
|
|
202
|
+
New
|
|
203
|
+
- iOS design review: critiques a screen against the HIG from screenshots.
|
|
204
|
+
Fixed
|
|
205
|
+
- The usage report reads the tracker as it is written.
|
|
206
|
+
Restart Claude Code to load the updated plugins.
|
|
180
207
|
|
|
181
208
|
Verification:
|
|
182
209
|
schema-validation: 27/27 pass
|
|
@@ -85,6 +85,7 @@ Shell scripts invoked during pipeline execution.
|
|
|
85
85
|
- `github-ssh-setup.sh` - first-run SSH key setup helper
|
|
86
86
|
- `update-check.sh` - cached registry read (`dist-tags.latest` + `dist-tags.required`); always exit 0
|
|
87
87
|
- `require-supported-version.sh` - turns the `force` signal into exit 3; fails open offline
|
|
88
|
+
- `release-notes.mjs` - every release between the installed and the new version, grouped by kind, plus each plugin the refresh moved; feeds the update summary
|
|
88
89
|
- `sync-parity-check.sh` - manual parity verification helper
|
|
89
90
|
|
|
90
91
|
## Node.js helpers (74 `.mjs` files)
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* release-notes.mjs - what an update brought, grouped so the user can be told.
|
|
4
|
+
*
|
|
5
|
+
* `/multi-agent:update` runs this from the release it just unpacked, against that
|
|
6
|
+
* release's CHANGELOG: every version after the one that was installed, up to the
|
|
7
|
+
* one now installed, with its bullets grouped by kind (added, changed, fixed,
|
|
8
|
+
* removed, ...). A jump across many releases is reported whole, not cut at a line
|
|
9
|
+
* count. The same is done for each stack plugin the plugin refresh moved, read
|
|
10
|
+
* from that plugin's CHANGELOG in the marketplace checkout.
|
|
11
|
+
*
|
|
12
|
+
* The output is data for the update step, which summarizes it for the user in
|
|
13
|
+
* their language. It never fails an update: a missing or unreadable CHANGELOG is
|
|
14
|
+
* empty notes and exit 0.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* release-notes.mjs --changelog <CHANGELOG.md> --from <old> --to <new>
|
|
18
|
+
* [--plugins-dir <marketplace>/plugins --plugin-refresh-log <file>]
|
|
19
|
+
*
|
|
20
|
+
* stdout: JSON `{ pipeline: Notes, plugins: [{ name, from, to, notes: Notes }] }`
|
|
21
|
+
* where Notes is `{ from, to, versions: [{ version, date, sections }], counts }`.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
import { pathToFileURL } from "node:url";
|
|
27
|
+
|
|
28
|
+
import { runMain } from "../lib/fatal.mjs";
|
|
29
|
+
|
|
30
|
+
const RELEASE_RE = /^## \[(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\](?:\s*-\s*(.+))?\s*$/;
|
|
31
|
+
const SECTION_RE = /^### (.+?)\s*$/;
|
|
32
|
+
|
|
33
|
+
function cmp(a, b) {
|
|
34
|
+
const [pa, qa = ""] = a.split("-");
|
|
35
|
+
const [pb, qb = ""] = b.split("-");
|
|
36
|
+
const x = pa.split(".").map(Number);
|
|
37
|
+
const y = pb.split(".").map(Number);
|
|
38
|
+
for (let i = 0; i < 3; i++) if (x[i] !== y[i]) return x[i] - y[i];
|
|
39
|
+
if (qa === qb) return 0;
|
|
40
|
+
if (!qa) return 1;
|
|
41
|
+
if (!qb) return -1;
|
|
42
|
+
return qa < qb ? -1 : 1;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Released versions in a Keep a Changelog file, newest first as written.
|
|
47
|
+
* `## [Unreleased]` is skipped; a bullet's wrapped lines are joined.
|
|
48
|
+
*
|
|
49
|
+
* @param {string} text
|
|
50
|
+
* @returns {{version: string, date: string|null, sections: Record<string, string[]>}[]}
|
|
51
|
+
*/
|
|
52
|
+
export function parseChangelog(text) {
|
|
53
|
+
const releases = [];
|
|
54
|
+
let release = null;
|
|
55
|
+
let section = null;
|
|
56
|
+
let bullet = null;
|
|
57
|
+
const flush = () => {
|
|
58
|
+
if (bullet !== null && release && section) release.sections[section].push(bullet.trim());
|
|
59
|
+
bullet = null;
|
|
60
|
+
};
|
|
61
|
+
for (const line of String(text || "").split("\n")) {
|
|
62
|
+
if (line.startsWith("## ")) {
|
|
63
|
+
flush();
|
|
64
|
+
const m = RELEASE_RE.exec(line);
|
|
65
|
+
release = m ? { version: m[1], date: m[2]?.trim() || null, sections: {} } : null;
|
|
66
|
+
if (release) releases.push(release);
|
|
67
|
+
section = null;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (!release) continue;
|
|
71
|
+
const s = SECTION_RE.exec(line);
|
|
72
|
+
if (s) {
|
|
73
|
+
flush();
|
|
74
|
+
section = s[1].toLowerCase();
|
|
75
|
+
release.sections[section] ||= [];
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!section) continue;
|
|
79
|
+
if (/^[-*] /.test(line)) {
|
|
80
|
+
flush();
|
|
81
|
+
bullet = line.slice(2);
|
|
82
|
+
} else if (bullet !== null && /^\s+\S/.test(line)) {
|
|
83
|
+
bullet += " " + line.trim();
|
|
84
|
+
} else if (!line.trim()) {
|
|
85
|
+
flush();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
flush();
|
|
89
|
+
return releases;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Releases after `from` up to and including `to`, newest first, with a count of
|
|
94
|
+
* bullets per section across all of them.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} text
|
|
97
|
+
* @param {{from: string, to: string}} range
|
|
98
|
+
*/
|
|
99
|
+
export function releaseNotes(text, { from, to }) {
|
|
100
|
+
const versions = parseChangelog(text)
|
|
101
|
+
.filter((r) => cmp(r.version, from) > 0 && cmp(r.version, to) <= 0)
|
|
102
|
+
.sort((a, b) => cmp(b.version, a.version));
|
|
103
|
+
const counts = {};
|
|
104
|
+
for (const v of versions) {
|
|
105
|
+
for (const [k, items] of Object.entries(v.sections))
|
|
106
|
+
counts[k] = (counts[k] || 0) + items.length;
|
|
107
|
+
}
|
|
108
|
+
return { from, to, versions, counts };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Plugins the refresh moved, from the CLI's own lines
|
|
113
|
+
* (`Plugin "<name>" updated from <a> to <b> for scope ...`). A plugin updated in
|
|
114
|
+
* several scopes is reported once, from the oldest version any of them had.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} output
|
|
117
|
+
* @returns {{name: string, from: string, to: string}[]}
|
|
118
|
+
*/
|
|
119
|
+
export function pluginUpdates(output) {
|
|
120
|
+
const byName = new Map();
|
|
121
|
+
const re = /Plugin "([^"]+)" updated from (\S+) to (\S+)/g;
|
|
122
|
+
for (const m of String(output || "").matchAll(re)) {
|
|
123
|
+
const [, name, from, to] = m;
|
|
124
|
+
const seen = byName.get(name);
|
|
125
|
+
if (!seen) byName.set(name, { name, from, to });
|
|
126
|
+
else {
|
|
127
|
+
if (cmp(from, seen.from) < 0) seen.from = from;
|
|
128
|
+
if (cmp(to, seen.to) > 0) seen.to = to;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [...byName.values()];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function read(path) {
|
|
135
|
+
try {
|
|
136
|
+
return existsSync(path) ? readFileSync(path, "utf8") : "";
|
|
137
|
+
} catch {
|
|
138
|
+
return "";
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function arg(argv, name) {
|
|
143
|
+
const i = argv.indexOf(name);
|
|
144
|
+
return i >= 0 ? argv[i + 1] : undefined;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function main(argv = process.argv.slice(2)) {
|
|
148
|
+
const from = arg(argv, "--from") || "0.0.0";
|
|
149
|
+
const to = arg(argv, "--to") || from;
|
|
150
|
+
const pipeline = releaseNotes(read(arg(argv, "--changelog") || ""), { from, to });
|
|
151
|
+
|
|
152
|
+
const pluginsDir = arg(argv, "--plugins-dir");
|
|
153
|
+
const refreshLog = arg(argv, "--plugin-refresh-log");
|
|
154
|
+
const plugins = [];
|
|
155
|
+
if (pluginsDir && refreshLog) {
|
|
156
|
+
for (const u of pluginUpdates(read(refreshLog))) {
|
|
157
|
+
const notes = releaseNotes(read(join(pluginsDir, u.name, "CHANGELOG.md")), u);
|
|
158
|
+
plugins.push({ ...u, notes });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
process.stdout.write(JSON.stringify({ pipeline, plugins }, null, 2) + "\n");
|
|
162
|
+
return 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (import.meta.url === pathToFileURL(process.argv[1] || "").href) {
|
|
166
|
+
runMain("release-notes", () => main());
|
|
167
|
+
}
|