Add packages/mosaic registry schemas, validation, read-only CLI; pin pi 0.85.1 (#1499)

This commit is contained in:
2026-09-10 15:18:15 -05:00
parent 54c1231280
commit 557aba0f9e
17 changed files with 1134 additions and 151 deletions
+4
View File
@@ -1898,3 +1898,7 @@ Independent R1 SUPPORTED the Gate 7 reconciliation; Jason answered yes to all th
## 2026-09-10 — registry plan fully resolved ## 2026-09-10 — registry plan fully resolved
ms-grill-me rounds resolved gates 2/3/4/8/9/10 and the per-execution selection model; PI-REFRESH-ROCKO-1 established the 0.85.1 noninteractive refresh path read-only; owner Q15(a) selected pi auth check; GATE7-FINAL-FILBERT-1 APPROVED and corroborated the findings against the pinned 0.84.4 install. Committed 224147ec and 86e009dd (with intervening registration commits), pushed, remote identities verified. All ten gates carry owner rulings. Implementation awaits a separately chartered increment; pi pin moves to 0.85.1 within that increment. ms-grill-me rounds resolved gates 2/3/4/8/9/10 and the per-execution selection model; PI-REFRESH-ROCKO-1 established the 0.85.1 noninteractive refresh path read-only; owner Q15(a) selected pi auth check; GATE7-FINAL-FILBERT-1 APPROVED and corroborated the findings against the pinned 0.84.4 install. Committed 224147ec and 86e009dd (with intervening registration commits), pushed, remote identities verified. All ten gates carry owner rulings. Implementation awaits a separately chartered increment; pi pin moves to 0.85.1 within that increment.
## 2026-09-10 — #1499 increment 1 implemented (pre-review)
packages/mosaic added: provider/account/profile/selection/harness schemas with strict unknown-field and ID validation, allowInsecureTransport rule (plain-http custom endpoints only), fork-pin field, harness id==executable rule (gate 1), registry tree loader with cross-reference integrity, read-only validate/list CLI with secret-free projections. 15 package tests pass. Pi pin moved 0.84.4 -> 0.85.1 (package.json, lockfile regenerated, three fixture scripts updated). Suites after pin: config/auth/conductor/release green; task suite shows exactly the one pre-existing failure also present at stashed baseline (no agent identity on headless run); one earlier mock-adapter failure did not recur on rerun and is recorded as flaky-unreproduced. Implementation awaits independent review before commit/push consideration per charter; no materializer/refresh/credential paths exist in this code.
+611 -143
View File
@@ -1,24 +1,25 @@
{ {
"name": "mosaic-stack-dev-test", "name": "mosaic-stack-dev-test",
"version": "0.1.0", "version": "0.0.3",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "mosaic-stack-dev-test", "name": "mosaic-stack-dev-test",
"version": "0.1.0", "version": "0.0.3",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@earendil-works/pi-coding-agent": "0.84.4" "@earendil-works/pi-coding-agent": "0.85.1"
} }
}, },
"node_modules/@anthropic-ai/sdk": { "node_modules/@anthropic-ai/sdk": {
"version": "0.91.1", "version": "0.123.0",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.123.0.tgz",
"integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", "integrity": "sha512-Y9oX9mPNGZClHQOFqrWRk43Srcu/UHuPq3rfxxOq7JgW0gi+lJA2MAOK4Ul3k/+AUrwRWFJvd0tK3oC0Pw25dw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"json-schema-to-ts": "^3.1.1" "json-schema-to-ts": "^3.1.1",
"standardwebhooks": "^1.0.0"
}, },
"bin": { "bin": {
"anthropic-ai-sdk": "bin/cli" "anthropic-ai-sdk": "bin/cli"
@@ -107,9 +108,9 @@
} }
}, },
"node_modules/@aws-sdk/core": { "node_modules/@aws-sdk/core": {
"version": "3.977.9", "version": "3.978.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.9.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.0.tgz",
"integrity": "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA==", "integrity": "sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
@@ -126,12 +127,12 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-env": { "node_modules/@aws-sdk/credential-provider-env": {
"version": "3.972.70", "version": "3.972.71",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.70.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.71.tgz",
"integrity": "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw==", "integrity": "sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -142,12 +143,12 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-http": { "node_modules/@aws-sdk/credential-provider-http": {
"version": "3.972.72", "version": "3.972.73",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.72.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.73.tgz",
"integrity": "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w==", "integrity": "sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/fetch-http-handler": "^5.7.2", "@smithy/fetch-http-handler": "^5.7.2",
@@ -160,13 +161,13 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": {
"version": "4.12.0", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.0.tgz", "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz",
"integrity": "sha512-0mq1pHadfyXCYCqm2cNpbjNIT+fbaUpNxewZb/YNr2L0IrEVMOb8gM/Fl4K6XvHCW3uSNDFwPl/+iKm0bx9jYg==", "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.18.0",
"tslib": "^2.6.2" "tslib": "^2.6.2"
}, },
"engines": { "engines": {
@@ -174,19 +175,19 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-ini": { "node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.973.15", "version": "3.973.16",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.15.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.16.tgz",
"integrity": "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg==", "integrity": "sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-env": "^3.972.71",
"@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-http": "^3.972.73",
"@aws-sdk/credential-provider-login": "^3.972.77", "@aws-sdk/credential-provider-login": "^3.972.78",
"@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-process": "^3.972.71",
"@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-sso": "^3.973.15",
"@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/credential-provider-web-identity": "^3.972.77",
"@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/nested-clients": "^3.997.45",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/credential-provider-imds": "^4.4.16", "@smithy/credential-provider-imds": "^4.4.16",
@@ -198,13 +199,13 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-login": { "node_modules/@aws-sdk/credential-provider-login": {
"version": "3.972.77", "version": "3.972.78",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.77.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.78.tgz",
"integrity": "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ==", "integrity": "sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/nested-clients": "^3.997.45",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -215,17 +216,17 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-node": { "node_modules/@aws-sdk/credential-provider-node": {
"version": "3.972.82", "version": "3.972.83",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.82.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.83.tgz",
"integrity": "sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA==", "integrity": "sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-env": "^3.972.71",
"@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-http": "^3.972.73",
"@aws-sdk/credential-provider-ini": "^3.973.15", "@aws-sdk/credential-provider-ini": "^3.973.16",
"@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-process": "^3.972.71",
"@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-sso": "^3.973.15",
"@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/credential-provider-web-identity": "^3.972.77",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/credential-provider-imds": "^4.4.16", "@smithy/credential-provider-imds": "^4.4.16",
@@ -237,12 +238,12 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-process": { "node_modules/@aws-sdk/credential-provider-process": {
"version": "3.972.70", "version": "3.972.71",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.70.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.71.tgz",
"integrity": "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q==", "integrity": "sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -253,14 +254,14 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-sso": { "node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.973.14", "version": "3.973.15",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.14.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.15.tgz",
"integrity": "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA==", "integrity": "sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/nested-clients": "^3.997.45",
"@aws-sdk/token-providers": "3.1116.0", "@aws-sdk/token-providers": "3.1129.0",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -271,13 +272,13 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": {
"version": "3.1116.0", "version": "3.1129.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1116.0.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1129.0.tgz",
"integrity": "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q==", "integrity": "sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/nested-clients": "^3.997.45",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -288,13 +289,13 @@
} }
}, },
"node_modules/@aws-sdk/credential-provider-web-identity": { "node_modules/@aws-sdk/credential-provider-web-identity": {
"version": "3.972.76", "version": "3.972.77",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.76.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.77.tgz",
"integrity": "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA==", "integrity": "sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/nested-clients": "^3.997.45",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.17.2",
@@ -335,12 +336,12 @@
} }
}, },
"node_modules/@aws-sdk/middleware-websocket": { "node_modules/@aws-sdk/middleware-websocket": {
"version": "3.972.52", "version": "3.972.53",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.52.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.53.tgz",
"integrity": "sha512-vsPPM+nMbKJlUCFU+eoGZbdxdxDIAX9LbpjSXaR5Ufpmqgp8TdYQnoExhLu4T3umW/JIIPny1ydbhWidZZYokQ==", "integrity": "sha512-bIrDaMENQmYRBHntOiOheqkiw5+fhKW4Lqb+mS1uqF0VwvdWI22fW2HFgWrng66CmYd+4k8ePlpj38sEfTuMLQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/fetch-http-handler": "^5.7.2", "@smithy/fetch-http-handler": "^5.7.2",
@@ -353,12 +354,12 @@
} }
}, },
"node_modules/@aws-sdk/nested-clients": { "node_modules/@aws-sdk/nested-clients": {
"version": "3.997.44", "version": "3.997.45",
"resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.44.tgz", "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.45.tgz",
"integrity": "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw==", "integrity": "sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@aws-sdk/core": "^3.977.9", "@aws-sdk/core": "^3.978.0",
"@aws-sdk/signature-v4-multi-region": "^3.996.46", "@aws-sdk/signature-v4-multi-region": "^3.996.46",
"@aws-sdk/types": "^3.974.5", "@aws-sdk/types": "^3.974.5",
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
@@ -372,13 +373,13 @@
} }
}, },
"node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": {
"version": "4.12.0", "version": "4.12.1",
"resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.0.tgz", "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz",
"integrity": "sha512-0mq1pHadfyXCYCqm2cNpbjNIT+fbaUpNxewZb/YNr2L0IrEVMOb8gM/Fl4K6XvHCW3uSNDFwPl/+iKm0bx9jYg==", "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@smithy/core": "^3.33.3", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.18.0",
"tslib": "^2.6.2" "tslib": "^2.6.2"
}, },
"engines": { "engines": {
@@ -473,14 +474,27 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@earendil-works/pi-agent-core": { "node_modules/@earendil-works/chord": {
"version": "0.84.4", "version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.4.tgz", "resolved": "https://registry.npmjs.org/@earendil-works/chord/-/chord-0.85.1.tgz",
"integrity": "sha512-HyUnjaOXj6oN/6SNcr8A1J/ElRQA50FtIE0XUTSKAQVqmdlb9qdojOyUQwF/jULE5+yOEtGuVgi/N1RnBiNG+g==", "integrity": "sha512-VDlkEC3dhCzQ5fcyH1OhG19dq+6jCn+rqc/iXFivwDYGR5anwo2RCiXij9PpHhqNR5GuhhE+Er69Zi1Sn4eY6w==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@earendil-works/pi-ai": "^0.84.4", "esbuild": "0.28.1"
"@earendil-works/pi-telemetry": "^0.84.4", },
"engines": {
"node": ">=22.19.0"
}
},
"node_modules/@earendil-works/pi-agent-core": {
"version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.85.1.tgz",
"integrity": "sha512-hIXIP3eAWueAYiAl8aMvWCvvZ8Q5gT3Dip5bE5uJyIGh4+YlWRjtMLI4BaeoXoSs93zndjue61u1B/vhefLnuA==",
"license": "MIT",
"dependencies": {
"@earendil-works/chord": "^0.85.1",
"@earendil-works/pi-ai": "^0.85.1",
"@earendil-works/pi-telemetry": "^0.85.1",
"diff": "8.0.4", "diff": "8.0.4",
"ignore": "7.0.5", "ignore": "7.0.5",
"typebox": "1.3.7", "typebox": "1.3.7",
@@ -491,14 +505,14 @@
} }
}, },
"node_modules/@earendil-works/pi-ai": { "node_modules/@earendil-works/pi-ai": {
"version": "0.84.4", "version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.4.tgz", "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.85.1.tgz",
"integrity": "sha512-AClAZxf5+c4RRu44NJPS6wyQy+Nmq+Mzyyrdvm4ZVMNuixelO02RZX4G4Aq1F145Yzp43wnM5S+hLlSI7ypfVw==", "integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@anthropic-ai/sdk": "0.91.1", "@anthropic-ai/sdk": "0.123.0",
"@aws-sdk/client-bedrock-runtime": "3.1048.0", "@aws-sdk/client-bedrock-runtime": "3.1048.0",
"@earendil-works/pi-telemetry": "^0.84.4", "@earendil-works/pi-telemetry": "^0.85.1",
"@google/genai": "1.52.0", "@google/genai": "1.52.0",
"@smithy/node-http-handler": "4.7.3", "@smithy/node-http-handler": "4.7.3",
"http-proxy-agent": "7.0.2", "http-proxy-agent": "7.0.2",
@@ -514,29 +528,16 @@
"node": ">=22.19.0" "node": ">=22.19.0"
} }
}, },
"node_modules/@earendil-works/pi-client": {
"version": "0.84.4",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.4.tgz",
"integrity": "sha512-q398WY/3ZQHTizk7IKxApzqFV0xt4yM9LkSkwyqeLK5Bj5RwRjOWxESt26z4LgNp4O+8hqhqFPf/8fj4H5rE4A==",
"license": "MIT",
"dependencies": {
"@earendil-works/pi-protocol": "^0.84.4"
},
"engines": {
"node": ">=22.19.0"
}
},
"node_modules/@earendil-works/pi-coding-agent": { "node_modules/@earendil-works/pi-coding-agent": {
"version": "0.84.4", "version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.84.4.tgz", "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.85.1.tgz",
"integrity": "sha512-jmOlrqUmvhh/siNWFRXjYLJzhKFIHNsAQaysRwzQPQFnPAaV/vhqHsLH/MBsIISA1Rjj7WTUFR3nJrpXoLx39w==", "integrity": "sha512-FGRN+OHbWaefBPGaTggAdLjrIHW+s2PzLyglz/5dfLzb9of7uuXMXYC0fJIeZTw+shS32o2cuQ9jF7YSDuL/oQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@earendil-works/pi-agent-core": "^0.84.4", "@earendil-works/chord": "^0.85.1",
"@earendil-works/pi-ai": "^0.84.4", "@earendil-works/pi-agent-core": "^0.85.1",
"@earendil-works/pi-client": "^0.84.4", "@earendil-works/pi-ai": "^0.85.1",
"@earendil-works/pi-protocol": "^0.84.4", "@earendil-works/pi-tui": "^0.85.1",
"@earendil-works/pi-tui": "^0.84.4",
"@silvia-odwyer/photon-node": "0.3.4", "@silvia-odwyer/photon-node": "0.3.4",
"chalk": "5.6.2", "chalk": "5.6.2",
"cross-spawn": "7.0.6", "cross-spawn": "7.0.6",
@@ -563,31 +564,19 @@
"@mariozechner/clipboard": "0.3.9" "@mariozechner/clipboard": "0.3.9"
} }
}, },
"node_modules/@earendil-works/pi-protocol": {
"version": "0.84.4",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.4.tgz",
"integrity": "sha512-acyE9ozxkMiWiz/xyWpU0O9vwnYv0hyG889Vniv6Sg9c9zfsX+8MePnDNphBacY2Fvm1rxdsGmiVDSZl9yuDFA==",
"license": "MIT",
"dependencies": {
"typebox": "1.3.7"
},
"engines": {
"node": ">=22.19.0"
}
},
"node_modules/@earendil-works/pi-telemetry": { "node_modules/@earendil-works/pi-telemetry": {
"version": "0.84.4", "version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.4.tgz", "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.85.1.tgz",
"integrity": "sha512-8e2CuxM+ht+hedQXTZmi5JVl6/xDK9RpSDL2+MbITevKYQhMZ/z6lJOTFgox3HQyGxO8mOZEtYGVeQNaD4OzqA==", "integrity": "sha512-Bg/YN6kA7Swja/NQxka8xFdecb4E/auIEGF2G5A25EaQXhRnPj300/7/KpgsDDMYUzHTDAv4RyUxaQPJKW81Rw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=22.19.0" "node": ">=22.19.0"
} }
}, },
"node_modules/@earendil-works/pi-tui": { "node_modules/@earendil-works/pi-tui": {
"version": "0.84.4", "version": "0.85.1",
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.4.tgz", "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.85.1.tgz",
"integrity": "sha512-nPUnwDkLtupPXnZQYrCwPFcuTydCDqTY6ZbFqhsL4S4kVq0AT418kPa/6uXwtaCD+MjBNBltb7ScTYX65yeE1w==", "integrity": "sha512-OIzw9efInmO4WOBnD4TxcTdBjmzvYJpzslkgoUro946nEGoYWg5rwv1p4fDt3/JvMx9QybryUCUwlm7j8Dreig==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"get-east-asian-width": "1.6.0", "get-east-asian-width": "1.6.0",
@@ -597,6 +586,422 @@
"node": ">=22.19.0" "node": ">=22.19.0"
} }
}, },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz",
"integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"aix"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz",
"integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz",
"integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz",
"integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz",
"integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz",
"integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz",
"integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz",
"integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz",
"integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==",
"cpu": [
"arm"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz",
"integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz",
"integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz",
"integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==",
"cpu": [
"loong64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz",
"integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==",
"cpu": [
"mips64el"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz",
"integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==",
"cpu": [
"ppc64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz",
"integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==",
"cpu": [
"riscv64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz",
"integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==",
"cpu": [
"s390x"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz",
"integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz",
"integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz",
"integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz",
"integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz",
"integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/openharmony-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz",
"integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"openharmony"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz",
"integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz",
"integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==",
"cpu": [
"arm64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz",
"integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==",
"cpu": [
"ia32"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz",
"integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==",
"cpu": [
"x64"
],
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@google/genai": { "node_modules/@google/genai": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz",
@@ -906,13 +1311,13 @@
} }
}, },
"node_modules/@smithy/fetch-http-handler": { "node_modules/@smithy/fetch-http-handler": {
"version": "5.7.2", "version": "5.8.0",
"resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz",
"integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@smithy/core": "^3.33.2", "@smithy/core": "^3.33.3",
"@smithy/types": "^4.17.2", "@smithy/types": "^4.18.0",
"tslib": "^2.6.2" "tslib": "^2.6.2"
}, },
"engines": { "engines": {
@@ -960,9 +1365,9 @@
} }
}, },
"node_modules/@smithy/types": { "node_modules/@smithy/types": {
"version": "4.17.2", "version": "4.18.0",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.17.2.tgz", "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.18.0.tgz",
"integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", "integrity": "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"tslib": "^2.6.2" "tslib": "^2.6.2"
@@ -997,13 +1402,19 @@
"node": ">=14.0.0" "node": ">=14.0.0"
} }
}, },
"node_modules/@stablelib/base64": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz",
"integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==",
"license": "MIT"
},
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "26.4.1", "version": "22.20.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz",
"integrity": "sha512-k97ENvZWtvA6yqz5/FS6a7duDgOPEeOQOc2iKS/nY6mX6qJUKtLnWzQS+Xj6tXweyj6ZcTAK2Qecetnvi9nCLA==", "integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"undici-types": "~8.3.0" "undici-types": "~6.21.0"
} }
}, },
"node_modules/@types/retry": { "node_modules/@types/retry": {
@@ -1153,12 +1564,59 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"node_modules/esbuild": {
"version": "0.28.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz",
"integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.28.1",
"@esbuild/android-arm": "0.28.1",
"@esbuild/android-arm64": "0.28.1",
"@esbuild/android-x64": "0.28.1",
"@esbuild/darwin-arm64": "0.28.1",
"@esbuild/darwin-x64": "0.28.1",
"@esbuild/freebsd-arm64": "0.28.1",
"@esbuild/freebsd-x64": "0.28.1",
"@esbuild/linux-arm": "0.28.1",
"@esbuild/linux-arm64": "0.28.1",
"@esbuild/linux-ia32": "0.28.1",
"@esbuild/linux-loong64": "0.28.1",
"@esbuild/linux-mips64el": "0.28.1",
"@esbuild/linux-ppc64": "0.28.1",
"@esbuild/linux-riscv64": "0.28.1",
"@esbuild/linux-s390x": "0.28.1",
"@esbuild/linux-x64": "0.28.1",
"@esbuild/netbsd-arm64": "0.28.1",
"@esbuild/netbsd-x64": "0.28.1",
"@esbuild/openbsd-arm64": "0.28.1",
"@esbuild/openbsd-x64": "0.28.1",
"@esbuild/openharmony-arm64": "0.28.1",
"@esbuild/sunos-x64": "0.28.1",
"@esbuild/win32-arm64": "0.28.1",
"@esbuild/win32-ia32": "0.28.1",
"@esbuild/win32-x64": "0.28.1"
}
},
"node_modules/extend": { "node_modules/extend": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/fast-sha256": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz",
"integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==",
"license": "Unlicense"
},
"node_modules/fetch-blob": { "node_modules/fetch-blob": {
"version": "3.2.0", "version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
@@ -1632,6 +2090,16 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/standardwebhooks": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.1.1.tgz",
"integrity": "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==",
"license": "MIT",
"dependencies": {
"@stablelib/base64": "^1.0.0",
"fast-sha256": "^1.3.0"
}
},
"node_modules/ts-algebra": { "node_modules/ts-algebra": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz",
@@ -1660,9 +2128,9 @@
} }
}, },
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "8.3.0", "version": "6.21.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-8.3.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/web-streams-polyfill": { "node_modules/web-streams-polyfill": {
+1 -1
View File
@@ -5,6 +5,6 @@
"description": "Minimal Mosaic Stack container proof of concept: one Pi agent, four local contract files, one real model request returning MOSAIC_HELLO_OK.", "description": "Minimal Mosaic Stack container proof of concept: one Pi agent, four local contract files, one real model request returning MOSAIC_HELLO_OK.",
"license": "UNLICENSED", "license": "UNLICENSED",
"dependencies": { "dependencies": {
"@earendil-works/pi-coding-agent": "0.84.4" "@earendil-works/pi-coding-agent": "0.85.1"
} }
} }
+19
View File
@@ -0,0 +1,19 @@
{
"name": "@mosaic/registry",
"version": "0.1.0",
"private": true,
"description": "Mosaic auth/provider/harness registry schemas and validation (increment 1: schemas, validation, read-only CLI).",
"license": "UNLICENSED",
"type": "module",
"engines": { "node": ">=24" },
"bin": { "mosaic-registry": "src/cli/main.mjs" },
"exports": {
".": "./src/index.mjs",
"./ids.mjs": "./src/ids.mjs",
"./records.mjs": "./src/records.mjs",
"./registry.mjs": "./src/registry.mjs"
},
"scripts": {
"test": "node --test tests/"
}
}
+43
View File
@@ -0,0 +1,43 @@
import { loadRegistry } from "../registry.mjs";
// Read-only registry CLI: validate and list. No mutation commands (increment 1).
function usage() {
process.stdout.write(`usage: mosaic-registry <command> --registry-root <dir>
commands:
validate validate the registry tree; exit 0 valid, 1 invalid, 2 usage
list list providers, accounts, profiles (no credential fields ever)
`);
}
async function main(argv) {
const command = argv[0];
const rootIndex = argv.indexOf("--registry-root");
const root = rootIndex !== -1 ? argv[rootIndex + 1] : undefined;
if ((command !== "validate" && command !== "list") || !root) {
usage();
return 2;
}
const { entries, errors } = await loadRegistry(root);
if (command === "validate") {
if (errors.length > 0) {
for (const err of errors) process.stderr.write(`${err.path}: ${err.code}${err.detail ? `: ${err.detail}` : ""}\n`);
process.stderr.write(`${errors.length} validation error(s)\n`);
return 1;
}
process.stdout.write("valid\n");
return 0;
}
// list: strictly non-secret projection.
const providers = Object.keys(entries.providers).sort().map((id) => ({ id, kind: entries.providers[id].kind }));
const accounts = Object.keys(entries.accounts).sort().map((ref) => ({
ref,
name: entries.accounts[ref].name,
type: entries.accounts[ref].type,
}));
const profiles = Object.keys(entries.profiles).sort().map((id) => ({ id }));
process.stdout.write(`${JSON.stringify({ providers, accounts, profiles }, null, 2)}\n`);
return errors.length > 0 ? 1 : 0;
}
process.exitCode = await main(process.argv.slice(2));
+4
View File
@@ -0,0 +1,4 @@
import { validateProvider, validateAccount, validateSettingsProfile, validateSeatSelection, validateHarnessManifest, ValidationError } from "./records.mjs";
import { loadRegistry } from "./registry.mjs";
export { validateProvider, validateAccount, validateSettingsProfile, validateSeatSelection, validateHarnessManifest, ValidationError, loadRegistry };
+184
View File
@@ -0,0 +1,184 @@
// Registry record validation for the Mosaic auth/provider/harness domain.
// Increment 1 per docs/plans/2026-09-10_m20-increment1-charter.md: pure
// schema/reference validation, no I/O, no secrets, no materialization.
const ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
export class ValidationError extends Error {
constructor(path, code, detail) {
super(`${path}: ${code}${detail ? `: ${detail}` : ""}`);
this.name = "ValidationError";
this.path = path;
this.code = code;
this.detail = detail ?? "";
}
}
const fail = (errors, path, code, detail) => errors.push(new ValidationError(path, code, detail));
function isPlainObject(value) {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
// Rejects unknown fields: every record lists its allowed keys and a type map.
function checkShape(errors, path, value, allowed, requireAll) {
if (!isPlainObject(value)) {
fail(errors, path, "not-an-object");
return;
}
for (const key of Object.keys(value)) {
if (!(key in allowed)) fail(errors, `${path}.${key}`, "unknown-field");
}
for (const [key, type] of Object.entries(allowed)) {
if (!(key in value)) {
if (requireAll.includes(key)) fail(errors, `${path}.${key}`, "missing-field");
continue;
}
const v = value[key];
if (type === "id") {
if (typeof v !== "string" || !ID_PATTERN.test(v)) fail(errors, `${path}.${key}`, "invalid-id");
} else if (type === "string") {
if (typeof v !== "string" || v.length === 0) fail(errors, `${path}.${key}`, "invalid-string");
} else if (type === "accountRef[]") {
if (!Array.isArray(v) || v.length === 0 || v.some((e) => typeof e !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}\/[a-z0-9][a-z0-9._-]{0,63}$/.test(e))) {
fail(errors, `${path}.${key}`, "invalid-account-ref-list");
}
} else if (type === "string[]") {
if (!Array.isArray(v) || v.length === 0 || v.some((e) => typeof e !== "string" || !ID_PATTERN.test(e))) {
fail(errors, `${path}.${key}`, "invalid-id-list");
}
} else if (type === "record") {
if (!isPlainObject(v)) fail(errors, `${path}.${key}`, "not-an-object");
} else if (type === "timestamp") {
if (typeof v !== "string" || !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/.test(v)) {
fail(errors, `${path}.${key}`, "invalid-timestamp");
}
} else if (type === "boolean") {
if (typeof v !== "boolean") fail(errors, `${path}.${key}`, "invalid-boolean");
}
}
}
export function validateProvider(record) {
const errors = [];
checkShape(errors, "provider", record, {
providerVersion: "id",
id: "id",
kind: "string",
harnesses: "record",
credentialTypes: "string[]",
allowInsecureTransport: "boolean",
}, ["providerVersion", "id", "kind", "harnesses", "credentialTypes"]);
if (errors.length === 0) {
if (record.kind !== "native" && record.kind !== "custom-endpoint") {
fail(errors, "provider.kind", "unsupported-kind", record.kind);
}
for (const [harness, cfg] of Object.entries(record.harnesses)) {
if (!ID_PATTERN.test(harness)) fail(errors, `provider.harnesses.${harness}`, "invalid-id");
if (!isPlainObject(cfg)) fail(errors, `provider.harnesses.${harness}`, "not-an-object");
}
const harnessCfg = record.harnesses.pi;
if (record.kind === "custom-endpoint" && isPlainObject(harnessCfg)) {
const url = harnessCfg.baseUrl;
if (typeof url !== "string" || !/^https?:\/\//.test(url)) {
fail(errors, "provider.harnesses.pi.baseUrl", "invalid-url");
} else if (url.startsWith("http://") && record.allowInsecureTransport !== true) {
fail(errors, "provider.allowInsecureTransport", "insecure-transport-not-allowed");
}
if (!Array.isArray(harnessCfg.models) || harnessCfg.models.length === 0) {
fail(errors, "provider.harnesses.pi.models", "invalid-model-list");
}
} else if (record.kind === "native" && isPlainObject(harnessCfg) && harnessCfg.baseUrl === undefined && Array.isArray(harnessCfg.models) === false) {
// native: pi entry is providerId only; models/bases come from provider catalog
}
if (record.kind === "native" && record.allowInsecureTransport === true) {
fail(errors, "provider.allowInsecureTransport", "insecure-transport-unsupported-for-native");
}
}
return errors;
}
export function validateAccount(record, providerId) {
const errors = [];
checkShape(errors, "account", record, {
accountVersion: "id",
id: "id",
name: "string",
provider: "id",
type: "string",
createdAt: "timestamp",
}, ["accountVersion", "id", "name", "provider", "type", "createdAt"]);
if (errors.length === 0) {
if (providerId !== undefined && record.provider !== providerId) {
fail(errors, "account.provider", "provider-path-mismatch", `${record.provider} vs ${providerId}`);
}
if (record.type !== "oauth" && record.type !== "api_key" && record.type !== "none") {
fail(errors, "account.type", "unsupported-credential-type", record.type);
}
}
return errors;
}
export function validateSettingsProfile(record) {
const errors = [];
checkShape(errors, "profile", record, {
settingsVersion: "id",
id: "id",
allowedAccounts: "accountRef[]",
providers: "string[]",
defaultAccounts: "record",
models: "record",
}, ["settingsVersion", "id", "allowedAccounts"]);
if (errors.length === 0) {
for (const [provider, account] of Object.entries(record.defaultAccounts ?? {})) {
if (!ID_PATTERN.test(provider)) fail(errors, `profile.defaultAccounts.${provider}`, "invalid-id");
if (typeof account !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}\/[a-z0-9][a-z0-9._-]{0,63}$/.test(account)) {
fail(errors, `profile.defaultAccounts.${provider}`, "invalid-account-ref");
}
}
}
return errors;
}
export function validateSeatSelection(record) {
const errors = [];
checkShape(errors, "selection", record, {
selectionVersion: "id",
profile: "id",
accounts: "record",
updatedAt: "timestamp",
// Fork pin (gate 6): present only when this selection was pinned at fork time.
pinnedFromSession: "string",
}, ["selectionVersion", "profile"]);
if (errors.length === 0) {
for (const [provider, account] of Object.entries(record.accounts ?? {})) {
if (!ID_PATTERN.test(provider)) fail(errors, `selection.accounts.${provider}`, "invalid-id");
if (typeof account !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}\/[a-z0-9][a-z0-9._-]{0,63}$/.test(account)) {
fail(errors, `selection.accounts.${provider}`, "invalid-account-ref");
}
}
}
return errors;
}
export function validateHarnessManifest(record) {
const errors = [];
checkShape(errors, "harness", record, {
harnessVersion: "id",
id: "id",
executable: "string",
adapter: "string",
compatibleRange: "string",
executionMode: "string",
materializers: "string[]",
}, ["harnessVersion", "id", "executable", "adapter", "compatibleRange", "executionMode", "materializers"]);
if (errors.length === 0) {
if (record.id !== record.executable) {
fail(errors, "harness.executable", "id-executable-mismatch", "gate 1: canonical IDs are executable names");
}
if (record.executionMode !== "container" && record.executionMode !== "host") {
fail(errors, "harness.executionMode", "unsupported-mode", record.executionMode);
}
}
return errors;
}
+106
View File
@@ -0,0 +1,106 @@
// Registry tree loading and cross-record reference validation.
// Reads a supplied registry root; never writes, never touches credentials.
import { readFile, readdir, stat } from "node:fs/promises";
import { join } from "node:path";
import { validateProvider, validateAccount, validateSettingsProfile, validateSeatSelection, validateHarnessManifest } from "./records.mjs";
export async function loadRegistry(root) {
const entries = { providers: {}, accounts: {}, profiles: {}, selections: {}, harnesses: {} };
const errors = [];
const providersDir = join(root, "auth", "providers");
for (const file of await safeList(providersDir, errors)) {
if (!file.endsWith(".json")) continue;
const id = file.slice(0, -5);
const record = await readJson(join(providersDir, file), errors);
if (record === undefined) continue;
errors.push(...validateProvider(record));
if (record.id !== id) errors.push(new (await import("./records.mjs")).ValidationError(`providers/${file}`, "id-path-mismatch", `${record.id} vs ${id}`));
if (entries.providers[id]) errors.push(new (await import("./records.mjs")).ValidationError(`providers/${file}`, "duplicate-id", id));
entries.providers[id] = record;
}
const accountsDir = join(root, "auth", "accounts");
for (const provider of await safeList(accountsDir, errors)) {
for (const accountDir of await safeList(join(accountsDir, provider), errors)) {
// account.json sits in a per-account directory; credential.json is never read.
const record = await readJson(join(accountsDir, provider, accountDir, "account.json"), errors);
if (record === undefined) continue;
errors.push(...validateAccount(record, provider));
const accountRef = `${provider}/${accountDir}`;
if (record.id !== accountDir) errors.push(new (await import("./records.mjs")).ValidationError(`accounts/${provider}/${accountDir}`, "id-path-mismatch", `${record.id} vs ${accountDir}`));
if (entries.accounts[accountRef]) errors.push(new (await import("./records.mjs")).ValidationError(`accounts/${provider}/${accountDir}`, "duplicate-id", accountRef));
entries.accounts[accountRef] = record;
}
}
const settingsDir = join(root, "auth", "settings");
for (const file of await safeList(settingsDir, errors)) {
if (!file.endsWith(".json")) continue;
const record = await readJson(join(settingsDir, file), errors);
if (record === undefined) continue;
errors.push(...validateSettingsProfile(record));
if (record.id !== file.slice(0, -5)) errors.push(new (await import("./records.mjs")).ValidationError(`settings/${file}`, "id-path-mismatch"));
entries.profiles[file.slice(0, -5)] = record;
}
const harnessesDir = join(root, "harnesses");
for (const file of await safeList(harnessesDir, errors)) {
if (!file.endsWith(".json")) continue;
const record = await readJson(join(harnessesDir, file), errors);
if (record === undefined) continue;
errors.push(...validateHarnessManifest(record));
entries.harnesses[file.slice(0, -5)] = record;
}
// Cross-record reference integrity.
for (const [ref, account] of Object.entries(entries.accounts)) {
if (!entries.providers[account.provider]) {
errors.push(new (await import("./records.mjs")).ValidationError(`accounts/${ref}`, "missing-provider", account.provider));
}
}
for (const [pid, profile] of Object.entries(entries.profiles)) {
for (const ref of profile.allowedAccounts ?? []) {
if (!entries.accounts[ref]) errors.push(new (await import("./records.mjs")).ValidationError(`profiles/${pid}`, "missing-account", ref));
}
for (const provider of profile.providers ?? []) {
if (!entries.providers[provider]) errors.push(new (await import("./records.mjs")).ValidationError(`profiles/${pid}`, "missing-provider", provider));
}
for (const [provider, ref] of Object.entries(profile.defaultAccounts ?? {})) {
if (!entries.accounts[ref]) errors.push(new (await import("./records.mjs")).ValidationError(`profiles/${pid}`, "missing-default-account", ref));
else if (!ref.startsWith(`${provider}/`)) errors.push(new (await import("./records.mjs")).ValidationError(`profiles/${pid}`, "default-account-provider-mismatch", ref));
}
}
return { entries, errors };
}
async function safeList(dir, errors) {
try {
const s = await stat(dir);
if (!s.isDirectory()) throw new Error("not-a-directory");
return await readdir(dir);
} catch {
return [];
}
}
async function readJson(path, errors) {
try {
return JSON.parse(await readFile(path, "utf8"));
} catch (err) {
errors.push(new ValidationErrorCompat(path, "invalid-json", err.message));
return undefined;
}
}
class ValidationErrorCompat extends Error {
constructor(path, code, detail) {
super(`${path}: ${code}: ${detail}`);
this.name = "ValidationError";
this.path = path;
this.code = code;
this.detail = detail;
}
}
@@ -0,0 +1 @@
{"accountVersion":"1","id":"homelab-openai","name":"Homelab OpenAI","provider":"openai-codex","type":"oauth","createdAt":"2026-09-10T00:00:00Z"}
@@ -0,0 +1 @@
{"providerVersion":"1","id":"ollama-remote","kind":"custom-endpoint","allowInsecureTransport":true,"harnesses":{"pi":{"api":"openai-completions","baseUrl":"http://ollama.internal:11434/v1","models":["qwen2.5-coder:7b"]}},"credentialTypes":["none"]}
@@ -0,0 +1 @@
{"providerVersion":"1","id":"openai-codex","kind":"native","harnesses":{"pi":{"providerId":"openai-codex"}},"credentialTypes":["oauth","api_key"]}
@@ -0,0 +1 @@
{"settingsVersion":"1","id":"research-default","allowedAccounts":["openai-codex/homelab-openai"],"providers":["openai-codex","ollama-remote"],"defaultAccounts":{"openai-codex":"openai-codex/homelab-openai"},"models":{"ollama-remote":["qwen2.5-coder:7b"]}}
@@ -0,0 +1 @@
{"harnessVersion":"1","id":"pi","executable":"pi","adapter":"pi","compatibleRange":">=0.85.1 <0.86.0","executionMode":"container","materializers":["auth-json","models-json"]}
+149
View File
@@ -0,0 +1,149 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join, dirname, resolve } from "node:path";
import { spawnSync } from "node:child_process";
import { validateProvider, validateAccount, validateSettingsProfile, validateSeatSelection, validateHarnessManifest } from "../src/records.mjs";
const pkgRoot = resolve(import.meta.dirname, "..");
const cli = join(pkgRoot, "src", "cli", "main.mjs");
const validFixture = join(pkgRoot, "tests", "fixtures", "valid");
function makeRoot() {
const root = mkdtempSync(join(tmpdir(), "mosaic-registry-test-"));
return root;
}
function writeTree(root, files) {
for (const [name, content] of Object.entries(files)) {
const path = join(root, name);
mkdirSync(dirname(path), { recursive: true });
writeFileSync(path, typeof content === "string" ? content : JSON.stringify(content));
}
}
function runCli(root, command = "validate") {
return spawnSync(process.execPath, [cli, command, "--registry-root", root], { encoding: "utf8", timeout: 15000 });
}
const validTree = () => ({
"auth/providers/openai-codex.json": { providerVersion: "1", id: "openai-codex", kind: "native", harnesses: { pi: { providerId: "openai-codex" } }, credentialTypes: ["oauth", "api_key"] },
"auth/accounts/openai-codex/homelab/account.json": { accountVersion: "1", id: "homelab", name: "Homelab", provider: "openai-codex", type: "oauth", createdAt: "2026-09-10T00:00:00Z" },
"auth/settings/research.json": { settingsVersion: "1", id: "research", allowedAccounts: ["openai-codex/homelab"], providers: ["openai-codex"], defaultAccounts: { "openai-codex": "openai-codex/homelab" } },
"harnesses/pi.json": { harnessVersion: "1", id: "pi", executable: "pi", adapter: "pi", compatibleRange: ">=0.85.1 <0.86.0", executionMode: "container", materializers: ["auth-json"] },
});
test("valid fixture tree validates and lists without secrets", () => {
const r = runCli(validFixture);
assert.equal(r.status, 0, r.stderr);
assert.match(r.stdout, /^valid\n$/);
const l = runCli(validFixture, "list");
assert.equal(l.status, 0, l.stderr);
const listed = JSON.parse(l.stdout);
assert.equal(listed.providers.length, 2);
assert.equal(listed.accounts.length, 1);
assert.equal(listed.profiles.length, 1);
assert.ok(!JSON.stringify(listed).includes("credential"));
assert.ok(!JSON.stringify(listed).includes("token"));
});
test("unknown-field refuses", () => {
const errors = validateProvider({ providerVersion: "1", id: "p", kind: "native", harnesses: {}, credentialTypes: ["none"], extra: 1 });
assert.equal(errors[0].code, "unknown-field");
});
test("invalid-id refuses uppercase and traversal shapes", () => {
assert.ok(validateProvider({ providerVersion: "1", id: "BadID", kind: "native", harnesses: {}, credentialTypes: ["none"] }).some((e) => e.code === "invalid-id"));
assert.ok(validateAccount({ accountVersion: "1", id: "../escape", name: "x", provider: "p", type: "oauth", createdAt: "2026-09-10T00:00:00Z" }).some((e) => e.code === "invalid-id"));
});
test("plain-http baseUrl requires allowInsecureTransport", () => {
const base = { providerVersion: "1", id: "o", kind: "custom-endpoint", harnesses: { pi: { api: "openai-completions", baseUrl: "http://h:11434/v1", models: ["m"] } }, credentialTypes: ["none"] };
assert.ok(validateProvider(base).some((e) => e.code === "insecure-transport-not-allowed"));
assert.equal(validateProvider({ ...base, allowInsecureTransport: true }).length, 0);
const https = JSON.parse(JSON.stringify(base));
https.harnesses.pi.baseUrl = "https://h/v1";
assert.equal(validateProvider(https).length, 0);
});
test("native provider rejects allowInsecureTransport", () => {
assert.ok(validateProvider({ providerVersion: "1", id: "p", kind: "native", harnesses: {}, credentialTypes: ["none"], allowInsecureTransport: true }).some((e) => e.code === "insecure-transport-unsupported-for-native"));
});
test("unsupported credential type and kind refuse", () => {
assert.ok(validateAccount({ accountVersion: "1", id: "a", name: "x", provider: "p", type: "basic", createdAt: "2026-09-10T00:00:00Z" }).some((e) => e.code === "unsupported-credential-type"));
assert.ok(validateProvider({ providerVersion: "1", id: "p", kind: "weird", harnesses: {}, credentialTypes: ["none"] }).some((e) => e.code === "unsupported-kind"));
});
test("account provider-path mismatch refuses", () => {
assert.ok(validateAccount({ accountVersion: "1", id: "a", name: "x", provider: "other", type: "oauth", createdAt: "2026-09-10T00:00:00Z" }, "right").some((e) => e.code === "provider-path-mismatch"));
});
test("profile account refs must be provider/account shaped", () => {
const errors = validateSettingsProfile({ settingsVersion: "1", id: "s", allowedAccounts: ["justone"], providers: [], defaultAccounts: {} });
assert.ok(errors.some((e) => e.code === "invalid-account-ref-list"));
});
test("seat selection accepts fork pin field, validates account refs", () => {
assert.equal(validateSeatSelection({ selectionVersion: "1", profile: "research", accounts: { "openai-codex": "openai-codex/homelab" }, updatedAt: "2026-09-10T00:00:00Z", pinnedFromSession: "abc123" }).length, 0);
assert.ok(validateSeatSelection({ selectionVersion: "1", profile: "research", accounts: { "openai-codex": "nope" } }).some((e) => e.code === "invalid-account-ref"));
});
test("harness manifest id must equal executable (gate 1)", () => {
assert.ok(validateHarnessManifest({ harnessVersion: "1", id: "pi", executable: "claude", adapter: "x", compatibleRange: ">=1", executionMode: "container", materializers: ["m"] }).some((e) => e.code === "id-executable-mismatch"));
});
test("CLI validate: duplicate provider id across files refuses", () => {
const root = makeRoot();
try {
const tree = validTree();
tree["auth/providers/dup.json"] = { ...tree["auth/providers/openai-codex.json"] };
writeTree(root, tree);
const r = runCli(root);
assert.equal(r.status, 1);
assert.match(r.stderr, /duplicate-id|id-path-mismatch/);
} finally { rmSync(root, { recursive: true, force: true }); }
});
test("CLI validate: missing referenced provider/account refuse", () => {
const root = makeRoot();
try {
const tree = validTree();
delete tree["auth/providers/openai-codex.json"];
writeTree(root, tree);
const r = runCli(root);
assert.equal(r.status, 1);
assert.match(r.stderr, /missing-provider/);
} finally { rmSync(root, { recursive: true, force: true }); }
});
test("CLI validate: broken JSON refuses without secret echo", () => {
const root = makeRoot();
try {
const tree = validTree();
tree["auth/providers/openai-codex.json"] = "{ not json";
writeTree(root, tree);
const r = runCli(root);
assert.equal(r.status, 1);
assert.match(r.stderr, /invalid-json/);
} finally { rmSync(root, { recursive: true, force: true }); }
});
test("CLI usage errors exit 2", () => {
assert.equal(runCli(validFixture, "bogus").status, 2);
assert.equal(spawnSync(process.execPath, [cli, "validate"], { encoding: "utf8" }).status, 2);
});
test("credential.json sibling presence does not break validation and is never read", () => {
const root = makeRoot();
try {
const tree = validTree();
tree["auth/accounts/openai-codex/homelab/credential.json"] = { secretMarker: "FIXTURE-NOT-A-SECRET" };
writeTree(root, tree);
const r = runCli(root);
assert.equal(r.status, 0, r.stderr);
const l = runCli(root, "list");
assert.ok(!l.stdout.includes("FIXTURE-NOT-A-SECRET"));
} finally { rmSync(root, { recursive: true, force: true }); }
});
+1 -1
View File
@@ -36,7 +36,7 @@ CFG="MOSAIC_CONFIG=$SANDBOX/mock-config.json"
# release pointer so agent.sh's ensure stays on the no-op fast path # release pointer so agent.sh's ensure stays on the no-op fast path
REL="$(tr -d '[:space:]' < RELEASE)" REL="$(tr -d '[:space:]' < RELEASE)"
printf '{"pointerVersion":1,"release":"%s","imageTag":"mosaic-poc-agent:0.84.4-r%s","activatedAt":"2026-01-01T00:00:00Z"}\n' "$REL" "$REL" > "$SANDBOX/data/state/active.json" printf '{"pointerVersion":1,"release":"%s","imageTag":"mosaic-poc-agent:0.85.1-r%s","activatedAt":"2026-01-01T00:00:00Z"}\n' "$REL" "$REL" > "$SANDBOX/data/state/active.json"
# fixtures: a default-harness credential and two mosaic-managed accounts # fixtures: a default-harness credential and two mosaic-managed accounts
printf '{"anthropic":{"type":"oauth","access":"%s"},"zai":{"type":"api_key","key":"%s"}}' "$TOKEN" "$SECRET" > "$SANDBOX/pi/auth.json" printf '{"anthropic":{"type":"oauth","access":"%s"},"zai":{"type":"api_key","key":"%s"}}' "$TOKEN" "$SECRET" > "$SANDBOX/pi/auth.json"
+6 -5
View File
@@ -7,7 +7,7 @@ import { join, resolve } from 'node:path';
import { spawnSync } from 'node:child_process'; import { spawnSync } from 'node:child_process';
const source = resolve(import.meta.dirname, '..'); const source = resolve(import.meta.dirname, '..');
for (const agent of ['darkwing', 'dewey', 'filbert']) test(`${agent} launch context, resources, session recovery, and refusals`, () => { for (const agent of ['darkwing', 'dewey', 'filbert', 'sage']) test(`${agent} launch context, resources, session recovery, and refusals`, () => {
const root = mkdtempSync(join(tmpdir(), `${agent} launch `)); const root = mkdtempSync(join(tmpdir(), `${agent} launch `));
try { try {
for (const dir of ['agents', 'scripts', 'contracts', 'user', 'node_modules/.bin', 'extensions/goal']) { for (const dir of ['agents', 'scripts', 'contracts', 'user', 'node_modules/.bin', 'extensions/goal']) {
@@ -24,7 +24,7 @@ for (const agent of ['darkwing', 'dewey', 'filbert']) test(`${agent} launch cont
cpSync(join(source, 'scripts/agent-host-dev.sh'), join(root, 'scripts/agent-host-dev.sh')); cpSync(join(source, 'scripts/agent-host-dev.sh'), join(root, 'scripts/agent-host-dev.sh'));
cpSync(join(source, 'scripts/agent.sh'), join(root, 'scripts/agent.sh')); cpSync(join(source, 'scripts/agent.sh'), join(root, 'scripts/agent.sh'));
cpSync(join(source, 'skills'), join(root, 'skills'), { recursive: true }); cpSync(join(source, 'skills'), join(root, 'skills'), { recursive: true });
writeFileSync(join(root, 'package.json'), JSON.stringify({ dependencies: { '@earendil-works/pi-coding-agent': '0.84.4' } })); writeFileSync(join(root, 'package.json'), JSON.stringify({ dependencies: { '@earendil-works/pi-coding-agent': '0.85.1' } }));
for (const file of ['contracts/CONSTITUTION.md', 'contracts/STANDARDS.md', 'user/USER.md', 'AGENTS.md']) { for (const file of ['contracts/CONSTITUTION.md', 'contracts/STANDARDS.md', 'user/USER.md', 'AGENTS.md']) {
writeFileSync(join(root, file), `fixture ${file}\n`); writeFileSync(join(root, file), `fixture ${file}\n`);
} }
@@ -33,7 +33,7 @@ for (const agent of ['darkwing', 'dewey', 'filbert']) test(`${agent} launch cont
writeFileSync(join(root, 'scripts/sync-dev-extensions.sh'), '#!/bin/sh\nexit 0\n', { mode: 0o755 }); writeFileSync(join(root, 'scripts/sync-dev-extensions.sh'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
writeFileSync(join(root, 'node_modules/.bin/pi'), `#!/usr/bin/env node writeFileSync(join(root, 'node_modules/.bin/pi'), `#!/usr/bin/env node
const fs = require('node:fs'); const fs = require('node:fs');
if (process.argv[2] === '--version') { console.log('0.84.4'); process.exit(0); } if (process.argv[2] === '--version') { console.log('0.85.1'); process.exit(0); }
fs.writeFileSync('capture.json', JSON.stringify({args: process.argv.slice(2), agent: process.env.MOSAIC_AGENT_NAME, incarnation: process.env.MOSAIC_LAUNCH_INCARNATION})); fs.writeFileSync('capture.json', JSON.stringify({args: process.argv.slice(2), agent: process.env.MOSAIC_AGENT_NAME, incarnation: process.env.MOSAIC_LAUNCH_INCARNATION}));
`, { mode: 0o755 }); `, { mode: 0o755 });
const launch = (args = '', tty = true) => spawnSync(tty ? 'script' : 'bash', tty const launch = (args = '', tty = true) => spawnSync(tty ? 'script' : 'bash', tty
@@ -61,8 +61,9 @@ fs.writeFileSync('capture.json', JSON.stringify({args: process.argv.slice(2), ag
let captured = JSON.parse(readFileSync(join(root, 'capture.json'))); let captured = JSON.parse(readFileSync(join(root, 'capture.json')));
assert.equal(captured.incarnation, undefined); assert.equal(captured.incarnation, undefined);
assert.equal(captured.agent, agent); assert.equal(captured.agent, agent);
assert.equal(captured.args[captured.args.indexOf('--provider') + 1], agent === 'filbert' ? 'openai-codex' : 'test'); assert.equal(captured.args[captured.args.indexOf('--provider') + 1], agent === 'filbert' ? 'openai-codex' : agent === 'sage' ? 'zai' : 'test');
assert.equal(captured.args[captured.args.indexOf('--model') + 1], agent === 'filbert' ? 'gpt-6-astra' : 'test-model'); assert.equal(captured.args[captured.args.indexOf('--model') + 1], agent === 'filbert' ? 'gpt-6-astra' : agent === 'sage' ? 'glm-5.3' : 'test-model');
if (agent === 'sage') assert.equal(captured.args[captured.args.indexOf('--thinking') + 1], 'high');
if (agent === 'filbert') assert.equal(captured.args[captured.args.indexOf('--thinking') + 1], 'low'); if (agent === 'filbert') assert.equal(captured.args[captured.args.indexOf('--thinking') + 1], 'low');
assert.equal(captured.args[captured.args.indexOf('--session-dir') + 1], join(root, `.pi/state/${agent}/sessions`)); assert.equal(captured.args[captured.args.indexOf('--session-dir') + 1], join(root, `.pi/state/${agent}/sessions`));
assert.equal(captured.args.includes('--continue'), false); assert.equal(captured.args.includes('--continue'), false);
+1 -1
View File
@@ -220,7 +220,7 @@ EOF
EOF EOF
REL="$(tr -d '[:space:]' < RELEASE)" REL="$(tr -d '[:space:]' < RELEASE)"
mkdir -p "$SANDBOX/data/state" mkdir -p "$SANDBOX/data/state"
printf '{"pointerVersion":1,"release":"%s","imageTag":"mosaic-poc-agent:0.84.4-r%s","activatedAt":"2026-01-01T00:00:00Z"}\n' "$REL" "$REL" > "$SANDBOX/data/state/active.json" printf '{"pointerVersion":1,"release":"%s","imageTag":"mosaic-poc-agent:0.85.1-r%s","activatedAt":"2026-01-01T00:00:00Z"}\n' "$REL" "$REL" > "$SANDBOX/data/state/active.json"
scripts/skill.sh install ms-tools >/dev/null 2>&1 scripts/skill.sh install ms-tools >/dev/null 2>&1
scripts/skill.sh activate ms-tools >/dev/null 2>&1 scripts/skill.sh activate ms-tools >/dev/null 2>&1
env MOSAIC_CONFIG="$SANDBOX/mock-config.json" MOSAIC_MOCK_RESPONSE=MOCKED \ env MOSAIC_CONFIG="$SANDBOX/mock-config.json" MOSAIC_MOCK_RESPONSE=MOCKED \