@mmerterden/multi-agent-pipeline 20.3.0 → 20.3.1
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,13 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [20.3.1] - 2026-09-25
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Registration and run reports reach the reporting site from installs whose `usageLog.endpoint` names its platform host: that host only redirects to the site's domain, and the usage clients never follow a redirect with a credential, so the endpoint is rewritten to the domain before any request.
|
|
24
|
+
- `usage-register.mjs` stores the issued token: it passes `-` so the credential store reads the value from stdin.
|
|
25
|
+
|
|
19
26
|
## [20.3.0] - 2026-09-25
|
|
20
27
|
|
|
21
28
|
### 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-09-25",
|
|
4
|
-
"version": "20.3.
|
|
4
|
+
"version": "20.3.1",
|
|
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.3.
|
|
4
|
-
"commit": "
|
|
5
|
-
"generatedAt": "2026-09-25T12:
|
|
3
|
+
"version": "20.3.1",
|
|
4
|
+
"commit": "04abc89922765fe8de6d8d722f08d0396d01450f",
|
|
5
|
+
"generatedAt": "2026-09-25T12:47:27.638Z",
|
|
6
6
|
"algorithm": "sha256",
|
|
7
|
-
"fileCount":
|
|
7
|
+
"fileCount": 1216,
|
|
8
8
|
"files": {
|
|
9
|
-
"CHANGELOG.md": "
|
|
9
|
+
"CHANGELOG.md": "a6dc8c4862792667cc8d8adadfd6c9b41c9c2f3aea6d45e8d100fd7134a40460",
|
|
10
10
|
"LICENSE": "8d8c51aaf1e1538b180c69965fa038db71be86798cc3e26a143bebfefe16a43e",
|
|
11
11
|
"README.md": "0613eebb0b38062bd94c44043595d1950b5c9b470874dd8e402c052fd20960cf",
|
|
12
12
|
"README.tr.md": "0c6b5e6943d6c3d3bf3a7ed99c705fb9a78d15d7722e6252f58404d3f6d3524d",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"docs/best-practices.md": "f8b75b0d38b5896a6a852bb30a1edddeb24dab8b5b7b1d9313290e1241c72024",
|
|
34
34
|
"docs/ecosystem.md": "cbd5f2e5609d7c80f87c03899d499d1a605b95bb53bf1f9bcdd74260051d56ba",
|
|
35
35
|
"docs/engineering.md": "550528cd47c7d2c921729c68d0782a00ac8e77a4bdfec479f6749f9c3235d188",
|
|
36
|
-
"docs/facts.json": "
|
|
36
|
+
"docs/facts.json": "6b3d8527857739bf04a8e3bb7b533d81681ab87ae1c0e381052c1696ec5d1b50",
|
|
37
37
|
"docs/features.md": "6c9f0efb00c683e6f611c440c87847b187f8b0eee59e9e812f3a241695bc2ae1",
|
|
38
38
|
"docs/performance.md": "bbf2f3922c25dcba0c1a9e69ef420e3871a729af5b35009a49b48a5d3c5cd151",
|
|
39
39
|
"docs/recovery-guide.md": "59a8f1b66b34cb9ff5507b3d54dac3b9915e184aa044d9c758d18cac818d510e",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"install/templates/multi-agent-autopilot-awake.plist.template": "ddd25c76c56fcbb38a89de8e35637372d70ace993d6bc487a88ca9cfb702fe1f",
|
|
62
62
|
"install/templates/multi-agent-autopilot.plist.template": "122c8a61cd927edd99375d6e3da40f1d42bcceed5b6641785c8b28bb930bc77e",
|
|
63
63
|
"install/unattended-profile-legacy.json": "f52e86b998956f09ad306b1735a6c10b58580d7082d8a55665a4c6bb15c3aa1f",
|
|
64
|
-
"package.json": "
|
|
64
|
+
"package.json": "1218189167652e06d6fe4f738d8fc7cad168e2d82f76cd99495823728517a881",
|
|
65
65
|
"pipeline/agents/android-architect.md": "baa5787b3a4c800dd065e27e05f44462927c9938c8bb676c80f18cb10e2b12c4",
|
|
66
66
|
"pipeline/agents/backend-architect.md": "a83bd7f8b0a5289a1ef9a9b59d60fc759b8db260606ff2df427cf5ade5db8530",
|
|
67
67
|
"pipeline/agents/bulk-reader.md": "0b9d415fab2c449d43329d759049af9401255d06b32d57a38c95e684837b19bf",
|
|
@@ -213,6 +213,7 @@
|
|
|
213
213
|
"pipeline/lib/unattended.mjs": "80f293edcd2bea550a687a62f41a4eb33e2bfe753c61040daf08921f5cc86e2c",
|
|
214
214
|
"pipeline/lib/unattended.sh": "6160d784bb36b9eaa71fcd097d5b34c093534ced02442bdf16778d66a794dac2",
|
|
215
215
|
"pipeline/lib/untrusted.mjs": "391f7093658386cac2ae2aabb21767cfc661e8bb04c7572aa2dc15b114bdc078",
|
|
216
|
+
"pipeline/lib/usage-endpoint.mjs": "9aed3a854e729f82563ca7614c9ab8dbb5af3b42fa0f7c10204b0094627b9906",
|
|
216
217
|
"pipeline/lib/user-facing.mjs": "08d8a1f4f12e36de88673d24167e244862f56671586a5ce26e73f52821996eed",
|
|
217
218
|
"pipeline/lib/user-facing.sh": "969038aa575a7075cbc8c2857b3e6bddfa5c8ea8a15811ad65c6660735539b76",
|
|
218
219
|
"pipeline/lib/vercel-deploy.sh": "7890a86f050611e7743e101303f1263527713019824a15aa4dddc09940bb0a65",
|
|
@@ -574,8 +575,8 @@
|
|
|
574
575
|
"pipeline/scripts/update-check.sh": "327a02306884093d2b93f395d2c297d5dc6b0c59757a740004bfafb13616fef0",
|
|
575
576
|
"pipeline/scripts/update-issue-progress.sh": "ccfef87743e91272e009e396ac07461d2784b2fa84a06c802a582526eeeb9ed9",
|
|
576
577
|
"pipeline/scripts/usage-identity.mjs": "3e2479bafc290f1acb253f5273339c87550f97d332818a26e5ac266d7ef289dc",
|
|
577
|
-
"pipeline/scripts/usage-register.mjs": "
|
|
578
|
-
"pipeline/scripts/usage-report.mjs": "
|
|
578
|
+
"pipeline/scripts/usage-register.mjs": "2844d2187226006d1a8b4e9b044d7591f4a5d3313cb24f9e388b36639022ce4c",
|
|
579
|
+
"pipeline/scripts/usage-report.mjs": "c3492168ee11d1c5cf9b9008bf13cfcb7debd1499f31d5bc805d9473debcaa0e",
|
|
579
580
|
"pipeline/scripts/validate-analysis-doc.mjs": "ae56b7578ef51e008a99f84eba9def3e0f1dd2bd87a3880f2083aa98b365f7a1",
|
|
580
581
|
"pipeline/scripts/validate-analysis.mjs": "d2dc9ccf45f6ca2702908761939edd830d18b3b273016a4b449f26fe285d5ea1",
|
|
581
582
|
"pipeline/scripts/validate-code-graph.mjs": "0ceac2f5b59f641334d54dc30bee5265361fb5fe1fc97e2f9791b546efe79941",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "20.3.
|
|
3
|
+
"version": "20.3.1",
|
|
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",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* usage-endpoint.mjs - the reporting endpoint a machine actually calls.
|
|
3
|
+
*
|
|
4
|
+
* The reporting site answers on its own domain; its platform host
|
|
5
|
+
* (mmerterden.vercel.app) only redirects there. The usage clients never follow
|
|
6
|
+
* a redirect with a credential attached, so an endpoint on the platform host,
|
|
7
|
+
* which earlier installs wrote into usageLog.endpoint, is rewritten to the
|
|
8
|
+
* site's domain before any request is made.
|
|
9
|
+
*
|
|
10
|
+
* @module pipeline/lib/usage-endpoint
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const SITE_HOST = "mmerterden.com";
|
|
14
|
+
const PLATFORM_HOSTS = new Set(["mmerterden.vercel.app"]);
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @param {string} endpoint
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function canonicalEndpoint(endpoint) {
|
|
21
|
+
if (!endpoint) return endpoint;
|
|
22
|
+
let u;
|
|
23
|
+
try {
|
|
24
|
+
u = new URL(endpoint);
|
|
25
|
+
} catch {
|
|
26
|
+
return endpoint;
|
|
27
|
+
}
|
|
28
|
+
if (u.protocol === "https:" && PLATFORM_HOSTS.has(u.hostname.toLowerCase())) {
|
|
29
|
+
u.hostname = SITE_HOST;
|
|
30
|
+
return u.toString();
|
|
31
|
+
}
|
|
32
|
+
return endpoint;
|
|
33
|
+
}
|
|
@@ -49,10 +49,12 @@ import { join } from "node:path";
|
|
|
49
49
|
import { homedir, hostname } from "node:os";
|
|
50
50
|
import { pathToFileURL } from "node:url";
|
|
51
51
|
import { hostCommand } from "../lib/user-facing.mjs";
|
|
52
|
+
import { canonicalEndpoint } from "../lib/usage-endpoint.mjs";
|
|
52
53
|
import { ghTokenFor, resolveReportingLogin } from "./usage-identity.mjs";
|
|
53
54
|
import { lockTimeoutFrom, updateJsonFileSync } from "../lib/json-file-lock.mjs";
|
|
54
55
|
|
|
55
56
|
const DEFAULT_ENDPOINT = "https://mmerterden.com/api/usage/ingest";
|
|
57
|
+
const BUILT_IN_HOSTS = ["mmerterden.com"];
|
|
56
58
|
const TIMEOUT_MS = 10000;
|
|
57
59
|
|
|
58
60
|
function readJson(file) {
|
|
@@ -118,7 +120,7 @@ export function decideRegistration(
|
|
|
118
120
|
|
|
119
121
|
/** The /register URL derived from whatever endpoint the prefs name. */
|
|
120
122
|
export function registerUrl(endpoint) {
|
|
121
|
-
const ep = (endpoint || DEFAULT_ENDPOINT).trim().replace(/\/+$/, "");
|
|
123
|
+
const ep = canonicalEndpoint((endpoint || DEFAULT_ENDPOINT).trim()).replace(/\/+$/, "");
|
|
122
124
|
return ep.endsWith("/ingest") ? `${ep.slice(0, -"/ingest".length)}/register` : `${ep}/register`;
|
|
123
125
|
}
|
|
124
126
|
|
|
@@ -132,7 +134,7 @@ function storedToken(prefs, credStore) {
|
|
|
132
134
|
|
|
133
135
|
/**
|
|
134
136
|
* May the gh token be sent to `url`? The token is a full GitHub credential, so
|
|
135
|
-
* it only goes over https to the
|
|
137
|
+
* it only goes over https to the reporting site's own hosts or a host the prefs
|
|
136
138
|
* name in `usageLog.trustedHosts`; http only to loopback (local development).
|
|
137
139
|
*/
|
|
138
140
|
export function registerUrlAllowed(url, trustedHosts = []) {
|
|
@@ -144,9 +146,7 @@ export function registerUrlAllowed(url, trustedHosts = []) {
|
|
|
144
146
|
}
|
|
145
147
|
if (u.protocol === "http:") return ["127.0.0.1", "localhost", "[::1]"].includes(u.hostname);
|
|
146
148
|
if (u.protocol !== "https:") return false;
|
|
147
|
-
const trusted = new Set(
|
|
148
|
-
[new URL(DEFAULT_ENDPOINT).hostname, ...trustedHosts].map((h) => String(h).toLowerCase()),
|
|
149
|
-
);
|
|
149
|
+
const trusted = new Set([...BUILT_IN_HOSTS, ...trustedHosts].map((h) => String(h).toLowerCase()));
|
|
150
150
|
return trusted.has(u.hostname.toLowerCase());
|
|
151
151
|
}
|
|
152
152
|
|
|
@@ -355,7 +355,7 @@ async function main(argv) {
|
|
|
355
355
|
|
|
356
356
|
const optedOut = prefs.global?.usageLog?.optOut === true;
|
|
357
357
|
const entry = `${process.env.USER || user}_Usage_Ingest_Token`;
|
|
358
|
-
const set = spawnSync("bash", [credStore, "set", entry], {
|
|
358
|
+
const set = spawnSync("bash", [credStore, "set", entry, "-"], {
|
|
359
359
|
input: token,
|
|
360
360
|
encoding: "utf8",
|
|
361
361
|
timeout: 10000,
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { readFileSync, existsSync, readdirSync, appendFileSync } from "fs";
|
|
31
|
+
import { canonicalEndpoint } from "../lib/usage-endpoint.mjs";
|
|
31
32
|
import { homedir, platform } from "os";
|
|
32
33
|
import { dirname, join } from "path";
|
|
33
34
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -721,7 +722,7 @@ async function main() {
|
|
|
721
722
|
const args = parseArgs(process.argv.slice(2));
|
|
722
723
|
if (process.env.MULTI_AGENT_SMOKE && !args.dryRun) return;
|
|
723
724
|
const prefs = resolvePrefs();
|
|
724
|
-
const endpoint = prefs.endpoint || ENDPOINT_DEFAULT;
|
|
725
|
+
const endpoint = canonicalEndpoint(prefs.endpoint || ENDPOINT_DEFAULT);
|
|
725
726
|
|
|
726
727
|
// Gate BEFORE touching the keychain: optOut is a hard block, and reading the
|
|
727
728
|
// secret for a disabled feature is both wasteful and can raise a macOS
|