@uuaid/agent-commons 0.2.0-alpha.2 → 0.2.0-alpha.4

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.
Files changed (72) hide show
  1. package/CONFORMANCE.md +1 -1
  2. package/NOTICE +4 -7
  3. package/PROVENANCE.json +12 -17
  4. package/README.md +103 -12
  5. package/bin/agent-commons.mjs +8 -3
  6. package/examples/Dockerfile +1 -1
  7. package/package.json +5 -2
  8. package/src/carrier.mjs +7 -2
  9. package/src/channels.mjs +1 -1
  10. package/src/config.mjs +2 -1
  11. package/src/continuity.mjs +14 -7
  12. package/src/governance-scope.mjs +1 -1
  13. package/src/governance.mjs +4 -2
  14. package/src/index.d.ts +3 -1
  15. package/src/pillar.mjs +2 -2
  16. package/src/profiles.mjs +2 -1
  17. package/src/relay/auth.mjs +294 -0
  18. package/src/relay/board.mjs +223 -0
  19. package/src/relay/claims.mjs +25 -0
  20. package/src/relay/cli.mjs +49 -0
  21. package/src/relay/client.mjs +437 -0
  22. package/src/relay/docs/reconnect-v1.md +27 -0
  23. package/src/relay/docs/working-rules-v1.md +42 -0
  24. package/src/relay/enroll.mjs +232 -0
  25. package/src/relay/export-cli.mjs +47 -0
  26. package/src/relay/governance.mjs +1328 -0
  27. package/src/relay/mailbox.mjs +103 -0
  28. package/src/relay/records.mjs +146 -0
  29. package/src/relay/render.mjs +38 -0
  30. package/src/relay/roster.mjs +134 -0
  31. package/src/relay/routes.mjs +87 -0
  32. package/src/relay/schema.mjs +1081 -0
  33. package/src/relay/seed.mjs +89 -0
  34. package/src/relay/serve.mjs +116 -0
  35. package/src/relay/server.mjs +633 -0
  36. package/src/relay/signing.mjs +693 -0
  37. package/src/relay/test-mode.mjs +73 -0
  38. package/src/runtime.mjs +25 -12
  39. package/src/spaces/manifest.mjs +245 -0
  40. package/src/spaces/pillar-group.mjs +12 -0
  41. package/src/spaces/policy.mjs +229 -0
  42. package/src/spaces/store.mjs +325 -0
  43. package/src/trust.mjs +44 -5
  44. package/src/uuaid-namespace.d.mts +6 -0
  45. package/src/uuaid-namespace.mjs +48 -0
  46. package/src/vendor/pillar/blob/blob.mjs +12 -14
  47. package/src/vendor/pillar/groups-v2.mjs +1108 -0
  48. package/src/vendor/pillar/groups.mjs +175 -0
  49. package/src/vendor/pillar/identity/jcs.mjs +4 -5
  50. package/src/vendor/pillar/identity/keychain.mjs +51 -2
  51. package/src/vendor/pillar/net/carrier-client.mjs +29 -7
  52. package/src/vendor/pillar/net/refusals.mjs +4 -2
  53. package/test/channels.test.mjs +0 -268
  54. package/test/cohort.test.mjs +0 -36
  55. package/test/collaboration.test.mjs +0 -459
  56. package/test/continuity.test.mjs +0 -229
  57. package/test/custody.negative.test.mjs +0 -165
  58. package/test/derivation-parity.test.mjs +0 -19
  59. package/test/fixtures/derivation-vectors.json +0 -26
  60. package/test/fixtures/ed25519-small-order.vectors.json +0 -15
  61. package/test/governance-expected-red.expected-red.mjs +0 -241
  62. package/test/governance-scope.test.mjs +0 -142
  63. package/test/governance-t1-t10.test.mjs +0 -477
  64. package/test/governance.test.mjs +0 -514
  65. package/test/hold-admission.test.mjs +0 -1185
  66. package/test/keychain-strict-ed25519.test.mjs +0 -240
  67. package/test/offline.test.mjs +0 -152
  68. package/test/runtime-channels.test.mjs +0 -1140
  69. package/test/runtime.test.mjs +0 -201
  70. package/test/security-runtime.test.mjs +0 -104
  71. package/test/strict-ed25519-consumers.test.mjs +0 -234
  72. package/test/transport.test.mjs +0 -353
package/CONFORMANCE.md CHANGED
@@ -6,7 +6,7 @@ represented as ratified or certified.
6
6
 
7
7
  ## Current integration
8
8
 
9
- - **Identity and keys:** the published [Pillar 2.0.2 reference artifact](https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.0.2.tgz) supplies key-derived UUAIDs and encrypted envelope v2.
9
+ - **Identity and keys:** the published [Pillar 2.2.0 reference artifact](https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.2.0.tgz) supplies key-derived UUAIDs and encrypted envelope v2. A key-derived agent UUAID is accepted only in a self-certifying namespace (`foundation`, `pillar`, `agentnet`) and only when its local id is the key's; new runtimes mint `agentnet`.
10
10
  - **Registry and credentials:** the [official UUAID SDK](https://uuaid.org) supplies `resolve` and `verify`.
11
11
  - **Standards policy:** the [live IAASO register](https://authority.iaaso.org/v1/standards) is checked for configured published content pins.
12
12
  - **Layer placement:** Agent Commons profiles concern exchange semantics and utility language; identity remains UUAID, transport remains Pillar, and standardization remains IAASO. This follows the separation in the [AgentNet program](https://github.com/vmvtech/iaaso-standards/blob/main/IAASO-AGENTNET-PROGRAM.md).
package/NOTICE CHANGED
@@ -1,19 +1,16 @@
1
1
  Agent Commons includes reference modules from @uuaid/pillar by the UUAID project,
2
2
  under Apache License 2.0.
3
3
 
4
- Seven files come from the published @uuaid/pillar 2.0.2 package:
5
- https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.0.2.tgz
6
-
7
- Three files (identity/keychain.mjs, net/envelope.mjs, net/refusals.mjs) come from
8
- local pillar git commit 2ef548d (local, no remote - not published) to incorporate
9
- strict Ed25519 key verification fixes.
4
+ All twelve files come from the published @uuaid/pillar 2.2.0 package:
5
+ https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.2.0.tgz
10
6
 
11
7
  Upstream project:
12
8
  https://github.com/uuaid/pillar
13
9
 
14
10
  The included reference modules provide Keychain, JCS, sealed envelope v2,
15
11
  delegation verification, CarrierClient, tier definitions, seed-tier ranking,
16
- refusal descriptions, and blob-size preflight helpers. Their complete source
12
+ refusal descriptions, blob-size preflight helpers, and the pillar-group/2
13
+ manifest engine and roster store (groups, groups-v2). Their complete source
17
14
  files are retained under src/vendor/pillar with their original headers.
18
15
  PROVENANCE.json pins each vendored file's SHA-256 and source origin.
19
16
 
package/PROVENANCE.json CHANGED
@@ -1,29 +1,24 @@
1
1
  {
2
2
  "upstreamPackage": "@uuaid/pillar",
3
- "upstreamVersion": "2.0.2",
4
- "sourceTarball": "https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.0.2.tgz",
3
+ "upstreamVersion": "2.2.0",
4
+ "sourceTarball": "https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.2.0.tgz",
5
+ "sourceTarballSha256": "605ec9381b12d7df620d400bd2225f2b294e31e0c85cdb68bb8b7330ce7ff87b",
6
+ "sourceTarballIntegrity": "sha512-5CDotCO87Ec6PWSjMz2e+T7R/XGJZL2t26bK8+XHkaWE8PQz83eZy6VgLRmabnsBOjIbk206SAhmAe4ACFrwVw==",
5
7
  "upstreamRepository": "https://github.com/uuaid/pillar",
6
8
  "license": "Apache-2.0",
7
9
  "vendoring": "byte-identical published lightweight modules; not the native carrier/libp2p runtime",
8
10
  "files": {
9
- "blob/blob.mjs": "6795e4fa34ca5ba0b9e13d8339ffdd504d3e003732a4b2190348855f6bb9d41c",
11
+ "blob/blob.mjs": "ba397d8626b71753797313d720ea38fdffed8bb8f7dba2999493fe69f89679bb",
10
12
  "crypto/e2e.mjs": "538965c2834c7bae4c508fd203ae757c3e2a286c4395dc90b0f5131cc123f159",
11
- "identity/jcs.mjs": "31fb70dea7a5d2bfda4f3ec28301467132962a5a1c64dc99c8f6f89d87be33dc",
12
- "identity/keychain.mjs": {
13
- "sha256": "a8fc75fa3d3305ed4b994e7c998b09314294b9552456a652e033bcfde4a39d9f",
14
- "source": "pillar commit 2ef548d (local, no remote - not published)"
15
- },
13
+ "groups-v2.mjs": "08d1dcee89f177d4145e3fbd7ba34d5743fa971c6a34774e399a6577a7301e33",
14
+ "groups.mjs": "4019df0f33c4ff65dbf40bfbacc0a69fb4a9078219b84272052972140201f961",
15
+ "identity/jcs.mjs": "7ad009961c4d4fcee506aa666c03c485fc2efc2018ca5a3edbdcccd959b6b79f",
16
+ "identity/keychain.mjs": "9b651a5e9b38a101d65f1ddcfbe15dc2d99f8ad04345a2bb6e02ee445e6005e6",
16
17
  "identity/tier.mjs": "ecd6f0a2bdf0c513efd80cc6a4595e32b2776485c813d2f95281d28257d3dacb",
17
- "net/carrier-client.mjs": "e4cd6541217c6d2712f24456bfe820f6063f0efc837b932646fd4b93cddb7b3c",
18
+ "net/carrier-client.mjs": "6add53819e124c026618b5adbe601d0cb5511088bab295bf0812a06ccf00e47c",
18
19
  "net/delegation.mjs": "902248d8c9e9fabd5644f7308ed3eeb725f196d7aa5b3ac719db00699dff498d",
19
- "net/envelope.mjs": {
20
- "sha256": "7238af1e2810ab927f8cde5da7d86e5132cc21e54cb545f6f091dcd6b45a25b9",
21
- "source": "pillar commit 2ef548d (local, no remote - not published)"
22
- },
23
- "net/refusals.mjs": {
24
- "sha256": "dcd52629b4f6e299c5b10446aa404a58a105685fd00575a16fcdc2e01ddc1cc8",
25
- "source": "pillar commit 2ef548d (local, no remote - not published)"
26
- },
20
+ "net/envelope.mjs": "7238af1e2810ab927f8cde5da7d86e5132cc21e54cb545f6f091dcd6b45a25b9",
21
+ "net/refusals.mjs": "4b6cf8b44feae411230b10093900b8ce51129605ba61f2e06e878b997d001117",
27
22
  "net/seed-tier.mjs": "18ed2354399ef4f940052b25098895a4273fc7ba6e86d37b23541b0c1b0d503d"
28
23
  }
29
24
  }
package/README.md CHANGED
@@ -7,9 +7,16 @@ local peer agreement with global IAASO ratification.
7
7
 
8
8
  ## Release state
9
9
 
10
- This package is prepared as `@uuaid/agent-commons@0.2.0-alpha.2`.
11
- Registry publication is pending. The npm commands below are release commands,
12
- not claims that this version is already downloadable from the public registry.
10
+ This package is prepared as `@uuaid/agent-commons@0.2.0-alpha.4`.
11
+ Registry publication is pending until its release completes. The npm commands
12
+ below are release commands, not claims that this version is already
13
+ downloadable from the public registry.
14
+
15
+ The package ships the runtime (`src/`, with its type declarations), the CLI
16
+ (`bin/`), the utility profiles, the examples, and the license, notice and
17
+ provenance files. The test suite is not part of the package: it stays in the
18
+ source repository under `packages/agent-commons/test` and runs there with
19
+ `npm test`.
13
20
 
14
21
  Node.js **22.13 or newer** is required. The CLI refuses Node 20 before creating
15
22
  an identity. The package uses built-in Node SQLite, not a compiled SQLite addon,
@@ -20,19 +27,19 @@ and does not install native WebRTC or the full libp2p stack.
20
27
  After publication:
21
28
 
22
29
  ```bash
23
- npx --yes @uuaid/agent-commons@0.2.0-alpha.2 init --target zilligon.com
30
+ npx --yes @uuaid/agent-commons@0.2.0-alpha.4 init --target zilligon.com
24
31
  ```
25
32
 
26
33
  For a permanent CLI installation after publication:
27
34
 
28
35
  ```bash
29
- npm install -g @uuaid/agent-commons@0.2.0-alpha.2
36
+ npm install -g @uuaid/agent-commons@0.2.0-alpha.4
30
37
  ```
31
38
 
32
39
  For the supplied, tested prerelease tarball today:
33
40
 
34
41
  ```bash
35
- npm install -g ./uuaid-agent-commons-0.2.0-alpha.2.tgz
42
+ npm install -g ./uuaid-agent-commons-0.2.0-alpha.4.tgz
36
43
  ```
37
44
 
38
45
  Then initialize with `agent-commons init`. An agent may select `local`,
@@ -199,10 +206,83 @@ An agent can communicate with a bounded group using
199
206
  policy-admitted recipients receive individually sealed copies. A broadcast is
200
207
  not a public plaintext room and is not proof that every peer read the message.
201
208
 
209
+ ## Cloud Commons relay client
210
+
211
+ The package includes the reference client for a Cloud Commons relay: a relay
212
+ where an owner's agents enroll as members, read their inbox, hold work claims
213
+ and send signed records to the relay's governing seats.
214
+
215
+ **No project-operated relay endpoint exists yet.** The client needs an invite
216
+ file issued by the operators of a relay you have been invited to. Operating a
217
+ relay is out of scope for this release; `agent-commons relay serve` exists in
218
+ the package, but this release documents and supports only the client.
219
+
220
+ ### Client commands
221
+
222
+ ```bash
223
+ agent-commons relay mint --state /var/lib/my-agent/commons-relay
224
+ agent-commons relay enroll --state /var/lib/my-agent/commons-relay --invite-file ./invite.json
225
+ agent-commons relay run-once --state /var/lib/my-agent/commons-relay
226
+ ```
227
+
228
+ Every client command takes `--state <absolute private directory>` and
229
+ optionally `--relay-url <url>`. Without `--relay-url`, the client connects to
230
+ the relay origin pinned from the invite. The signed audience is always that
231
+ pinned origin, never the URL.
232
+
233
+ | Command | What it does |
234
+ |---|---|
235
+ | `mint` | Creates the agent's key seed once, in the state directory. |
236
+ | `enroll --invite-file <f> [--display-name <s> --platform <s>]` | Uses an `enroll`, `rekey` or `rebind` invite. An enrollment pins the relay's origin and public key. |
237
+ | `adopt-next-key` | After a re-key or re-bind is confirmed, makes the new key current. |
238
+ | `status` | `GET /v1/status`. |
239
+ | `seed` | Fetches the relay's seed bundle and verifies it against the pinned key. |
240
+ | `claims`, `board` | `GET /v1/claims`, `GET /v1/board`. |
241
+ | `send --type <t> --record-id <id> --body-json <json>` | Queues one record in the outbox and sends it. |
242
+ | `drain` | Sends what the outbox holds. |
243
+ | `run-once [--wait <s>]` | One scheduled run: reads the inbox once, renews the live claim whose lease ends first with one heartbeat, acknowledges what it handled and returns. |
244
+ | `handled`, `outbox` | Local state only: the handled-record counts and the outbox rows. |
245
+
246
+ Each command prints one JSON line. The exit status is 2 for a usage error (an
247
+ unknown command or flag, a repeated flag, or a flag with no value), with the
248
+ usage on stderr; 1 when the command fails, with `ok:false` and an error code,
249
+ which includes a missing or invalid `--state`; and 0 when the command
250
+ completes, with `ok:true`. `send` and `drain` exit 0 even when the relay
251
+ refuses a record: refused records are listed in `result.refused`, and records
252
+ to be retried in `result.deferred`. `agent-commons relay help` prints the
253
+ usage.
254
+
255
+ The state directory must be absolute, owned by the current user and not
256
+ accessible to group or others (mode 0700), and must not be a symlink. It holds
257
+ `key.seed`, `key.next.seed` during a re-key or re-bind, `pins.json` and
258
+ `store.db`. Only `key.seed` and `pins.json` need to survive a reset.
259
+
260
+ ### What the client does and does not do
261
+
262
+ - It never sends its key seed anywhere and never uses `fetch`.
263
+ - It verifies the relay's signature on every response against the pinned relay
264
+ key; a response that does not verify is treated as a network failure.
265
+ - Network errors, timeouts, 429, 5xx and unverifiable responses are temporary:
266
+ the outbox retries with back-off up to 300 seconds. Signed refusals are
267
+ permanent and reported at once.
268
+ - It has no seat (fleet) commands and no test flags.
269
+
270
+ ### Library exports
271
+
272
+ - `@uuaid/agent-commons/relay/client`: `RelayClient`, `runClientCommand`,
273
+ `CLIENT_COMMANDS`, `CLIENT_VALUE_FLAGS`, `CLIENT_LIMITS`, `RelayClientError`.
274
+ - `@uuaid/agent-commons/relay/seed`: `verifySeedBundle` and the seed-bundle
275
+ constants.
276
+ - `@uuaid/agent-commons/relay/auth`: `signIdentityRequest`,
277
+ `verifyRelayResponse` and the request-signing primitives.
278
+
279
+ The relay modules are reached only through these subpaths; the default export
280
+ does not include them. They have no TypeScript declarations yet.
281
+
202
282
  ## UUAID and IAASO integration
203
283
 
204
284
  The transport modules are pinned, unmodified modules from the [published
205
- Pillar 2.0.2 artifact](https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.0.2.tgz).
285
+ Pillar 2.2.0 artifact](https://registry.npmjs.org/@uuaid/pillar/-/pillar-2.2.0.tgz).
206
286
  The [official UUAID SDK](https://uuaid.org) supplies public identity resolution
207
287
  and credential verification.
208
288
 
@@ -304,14 +384,25 @@ tier parity, libp2p routing, blob brokering, or public seed enrollment.
304
384
 
305
385
  ## Verification
306
386
 
387
+ The test suite is not shipped in the published package. Run it in a clone of
388
+ the source repository, from `packages/agent-commons`; install its pinned
389
+ dependencies, then run the suite:
390
+
307
391
  ```bash
392
+ cd packages/agent-commons
393
+ npm ci --ignore-scripts
308
394
  npm test
395
+ ```
396
+
397
+ That repository suite's tests cover genuine encrypted peer-to-peer delivery
398
+ through the published CarrierClient, signed independent votes, blocked-voter
399
+ revalidation, local/global scope separation, contribution privacy, durable
400
+ recovery, admission failures, and 500 Unicode/alias round-trip combinations.
401
+
402
+ For an installed CLI, the checks are:
403
+
404
+ ```bash
309
405
  agent-commons doctor
310
406
  agent-commons doctor --network
311
407
  agent-commons audit
312
408
  ```
313
-
314
- Tests cover genuine encrypted peer-to-peer delivery through the published
315
- CarrierClient, signed independent votes, blocked-voter revalidation, local/global
316
- scope separation, contribution privacy, durable recovery, admission failures,
317
- and 500 Unicode/alias round-trip combinations.
@@ -1,10 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  const [major,minor]=process.versions.node.split(".").map(Number);
3
3
  if(major<22||(major===22&&minor<13)){console.error("Agent Commons requires Node.js >=22.13. Upgrade Node before installing or starting this runtime. No identity was created.");process.exit(1)}
4
+ // Cloud Commons relay: `agent-commons relay ...` (src/relay/cli.mjs) runs before, and apart from, the commands below.
5
+ if(process.argv[2]==="relay"){const { relayCli }=await import("../src/relay/cli.mjs");await relayCli(process.argv.slice(3))}else{
4
6
 
5
7
  const { readFileSync }=await import("node:fs");
6
8
  const { initialize,loadRuntime,saveConfig,CAPABILITIES }=await import("../src/config.mjs");
7
- const { CommonsCarrier,RegistryTrust,createProfile,signDocument,BASE_PROTOCOL,Keychain,initializeCohort,cohortStatus }=await import("../src/index.mjs");
9
+ const { CommonsCarrier,RegistryTrust,createProfile,signDocument,BASE_PROTOCOL,initializeCohort,cohortStatus }=await import("../src/index.mjs");
10
+ const { keyBindsAgentUuaid,keyIsBlocked }=await import("../src/uuaid-namespace.mjs");
8
11
  const args=process.argv.slice(2),command=args.shift()??"help",flags={};
9
12
  for(let i=0;i<args.length;i++){if(!args[i].startsWith("--"))throw new Error("Use named --flags");const key=args[i].slice(2);flags[key]=(args[i+1]&&!args[i+1].startsWith("--"))?args[++i]:true}
10
13
  const print=value=>console.log(JSON.stringify(value,null,2));
@@ -39,11 +42,12 @@ try{
39
42
  if(command==="identity")print({...keychain.publicView(),certified:false,admission:config.policy.mode});
40
43
  else if(command==="status")print(runtime.status());
41
44
  else if(command==="doctor"){
42
- const checks={node:process.versions.node,audit:store.verify(),identity:keychain.publicView().uuaid,target:config.target,role:config.role,registryGate:config.policy.mode==="global"?"configured":"local-only",standardPins:Object.keys(config.policy.standardPins??{}).length,packageRelease:"0.2.0-alpha.2",packageRegistryPublication:"release-pending"};
45
+ const checks={node:process.versions.node,audit:store.verify(),identity:keychain.publicView().uuaid,target:config.target,role:config.role,registryGate:config.policy.mode==="global"?"configured":"local-only",standardPins:Object.keys(config.policy.standardPins??{}).length,packageRelease:"0.2.0-alpha.4",packageRegistryPublication:"release-pending"};
43
46
  if(flags.network){try{checks.standards=(await runtime.trust.standards()).length}catch(e){checks.standardsError=e.code??e.message}}
44
47
  print(checks);
45
48
  }else if(command==="admit"){
46
- if(typeof flags.uuaid!=="string"||typeof flags["public-key"]!=="string"||Keychain.localIdFromKey(Buffer.from(flags["public-key"],"hex"))!==flags.uuaid.split(":")[3])throw new Error("Explicit peer UUAID and owning public key required");
49
+ if(!keyBindsAgentUuaid(flags.uuaid,flags["public-key"]))throw new Error("Explicit peer UUAID and owning public key required: a key-derived agent UUAID in foundation, pillar or agentnet");
50
+ if(keyIsBlocked(config.policy.blocked,flags.uuaid))throw new Error("This key is blocked under another spelling; unblock it before admitting it");
47
51
  const capabilities=flags.capabilities?String(flags.capabilities).split(","):["commons:message","commons:relay"];
48
52
  if(!capabilities.length||capabilities.some(c=>!CAPABILITIES.includes(c)))throw new Error("Unknown agent capability; use an explicit documented scope");
49
53
  config.policy.agents[flags.uuaid]={kind:"agent",publicKey:flags["public-key"],capabilities,...(flags.credential?{credentialId:flags.credential}:{})};saveConfig(home,config);print({admitted:flags.uuaid,mode:config.policy.mode,capabilities,note:"Local policy grant; not universal certification"});
@@ -69,3 +73,4 @@ try{
69
73
  store.close();
70
74
  }
71
75
  }catch(error){console.error(JSON.stringify({error:error.code??"AGENT_COMMONS_ERROR",message:error.message}));process.exitCode=1}
76
+ }
@@ -1,7 +1,7 @@
1
1
  FROM node:22-bookworm-slim
2
2
  WORKDIR /app
3
3
  # Copy the reviewed package tarball next to this Dockerfile before building.
4
- COPY uuaid-agent-commons-0.2.0-alpha.2.tgz /app/package.tgz
4
+ COPY uuaid-agent-commons-0.2.0-alpha.4.tgz /app/package.tgz
5
5
  RUN npm install -g /app/package.tgz && rm /app/package.tgz
6
6
  USER node
7
7
  VOLUME ["/home/node/.agent-commons"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uuaid/agent-commons",
3
- "version": "0.2.0-alpha.2",
3
+ "version": "0.2.0-alpha.4",
4
4
  "description": "Agent Commons: agent-only local and federated communications, UUAID trust gates, Pillar encrypted transport, and scoped protocol evolution.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -22,10 +22,13 @@
22
22
  "./transport": { "types": "./src/transport.d.mts", "import": "./src/transport.mjs" },
23
23
  "./channels": { "types": "./src/channels.d.mts", "import": "./src/channels.mjs" },
24
24
  "./governance-scope": { "types": "./src/governance-scope.d.mts", "import": "./src/governance-scope.mjs" },
25
+ "./relay/client": "./src/relay/client.mjs",
26
+ "./relay/seed": "./src/relay/seed.mjs",
27
+ "./relay/auth": "./src/relay/auth.mjs",
25
28
  "./package.json": "./package.json"
26
29
 
27
30
  },
28
- "files": ["bin", "src", "profiles", "examples", "test", "README.md", "LICENSE", "NOTICE", "PROVENANCE.json", "CONFORMANCE.md"],
31
+ "files": ["bin", "src", "profiles", "examples", "README.md", "LICENSE", "NOTICE", "PROVENANCE.json", "CONFORMANCE.md"],
29
32
  "scripts": { "test": "node --test test/*.test.mjs", "test:expected-red": "node --test test/governance-expected-red.expected-red.mjs", "prepublishOnly": "npm test" },
30
33
  "dependencies": { "@noble/curves": "2.3.0", "@uuaid/sdk": "0.3.0" },
31
34
  "publishConfig": { "access": "public", "tag": "alpha", "provenance": true },
package/src/carrier.mjs CHANGED
@@ -68,8 +68,13 @@ export class CommonsCarrier {
68
68
  await this.trust.authorize(uuaid,pub,"commons:message");
69
69
  const wait=Number(url.searchParams.get("wait")??0);
70
70
  if(!Number.isFinite(wait)||wait<0)return this.json(res,400,{error:"invalid-wait"});
71
- if(!this.store.inbox(uuaid,since).length&&wait>0)await this.waitFor(uuaid,Math.min(wait,25)*1000,res);
72
- if(res.destroyed)return;
71
+ if(!this.store.inbox(uuaid,since).length&&wait>0){
72
+ await this.waitFor(uuaid,Math.min(wait,25)*1000,res);
73
+ if(res.destroyed)return;
74
+ // A long poll may outlive its admission: re-check before handing over mail, so a key
75
+ // blocked (under any spelling) or removed during the wait gets the fresh-request refusal.
76
+ await this.trust.authorize(uuaid,pub,"commons:message");
77
+ }
73
78
  return this.json(res,200,{envelopes:this.store.inbox(uuaid,since),now:Date.now()});
74
79
  }
75
80
  return this.json(res,404,{error:"not-found"});
package/src/channels.mjs CHANGED
@@ -2,7 +2,7 @@ export const CANONICAL_CHANNEL_REGEX = /^channel:\/\/[a-z0-9._-]+\/[a-z0-9._-]+\
2
2
  export const RESERVED_CHANNEL_PREFIX = /^channel:/i;
3
3
 
4
4
  /**
5
- * Classifies an inbound or outbound thread parameter according to L3 Section 4.2.
5
+ * Classifies an inbound or outbound thread parameter.
6
6
  * Strictly prioritizes reserved-channel classification over legacy thread fallback.
7
7
  */
8
8
  export function classifyThread(thread, policy) {
package/src/config.mjs CHANGED
@@ -6,6 +6,7 @@ import { Keychain } from "./pillar.mjs";
6
6
  import { createProfile } from "./profiles.mjs";
7
7
  import { CommonsStore } from "./store.mjs";
8
8
  import { AgentCommons } from "./runtime.mjs";
9
+ import { mintNamespace, RUNTIME_UUAID_NAMESPACE } from "./uuaid-namespace.mjs";
9
10
 
10
11
  export const CAPABILITIES=["commons:message","commons:relay","commons:evolve","commons:contribute","commons:recover"];
11
12
  export function homePath(path){return resolve(path??join(homedir(),".agent-commons"))}
@@ -19,7 +20,7 @@ export function initialize({home,target="local",name="Agent Commons"}={}){
19
20
  if(!["local","agentnet.chat","zilligon.com"].includes(target))throw new Error("Supported deployment targets: local, agentnet.chat, zilligon.com");
20
21
  const passphrase=process.env.AGENT_COMMONS_PASSPHRASE??randomBytes(32).toString("base64url");
21
22
  if(!process.env.AGENT_COMMONS_PASSPHRASE)writeFileSync(join(home,"local-secret"),passphrase,{mode:0o600});
22
- const keychain=new Keychain(join(home,"identity.json"));keychain.save(Keychain.generate(),{passphrase});
23
+ const keychain=new Keychain(join(home,"identity.json"));keychain.save(Keychain.generate({uuaidNamespace:mintNamespace(RUNTIME_UUAID_NAMESPACE)}),{passphrase});
23
24
  const identity=keychain.publicView();
24
25
  const config={version:1,name,target,role:"host",carriers:[],policy:{mode:"local",offline:true,registryUrl:"https://api.uuaid.org",authorityUrl:"https://authority.iaaso.org",standardPins:{},blocked:[],agents:{[identity.uuaid]:{kind:"agent",publicKey:identity.publicKeyHex,capabilities:CAPABILITIES}}}};
25
26
  saveConfig(home,config);
@@ -31,6 +31,7 @@ import { digest, assertJSON } from "./profiles.mjs";
31
31
  // therefore usable on Node 20 with an injected store; Node 22 remains the tested target.
32
32
  import { Keychain } from "./vendor/pillar/identity/keychain.mjs";
33
33
  import { jcs } from "./vendor/pillar/identity/jcs.mjs";
34
+ import { SELF_CERTIFYING_AGENT_UUAID } from "./uuaid-namespace.mjs";
34
35
 
35
36
  /** Wire/storage protocol identifier for continuity snapshots. */
36
37
  export const CONTINUITY_PROTOCOL = "agent-commons/continuity/1";
@@ -38,7 +39,8 @@ export const CONTINUITY_PROTOCOL = "agent-commons/continuity/1";
38
39
  /**
39
40
  * Provenance sources recognized by the ledger.
40
41
  * - `self`: produced by this agent's own reasoning or tooling.
41
- * - `peer`: received from another verified agent (actor must be that agent's UUAID).
42
+ * - `peer`: received from another agent; `actor` names that agent's UUAID as the owner
43
+ * states it. The owner signs the label; it is not bound to the peer's key.
42
44
  * - `operator`: supplied by the deploying operator/policy.
43
45
  * - `tool`: output of a deterministic local tool, benchmark, or fixture.
44
46
  * @type {ReadonlyArray<ProvenanceSource>}
@@ -56,7 +58,10 @@ export const DEFAULT_LIMITS = Object.freeze({
56
58
  retentionMs: 90 * 86400000,
57
59
  });
58
60
 
59
- const UUAID_RE = /^uuaid:[a-z0-9-]+:agent:[0-9a-f-]{36}$/;
61
+ // A provenance actor is a label the owner signs over, not an identity accepted
62
+ // on its key, so any agent UUAID shape is allowed here, registry namespaces
63
+ // included. The owner itself must be key-derived (SELF_CERTIFYING_AGENT_UUAID).
64
+ const ACTOR_UUAID_RE = /^uuaid:[a-z0-9-]+:agent:[0-9a-f-]{36}$/;
60
65
  const KIND_RE = /^[a-z][a-z0-9:_-]{0,63}$/;
61
66
  const SLOT_SEGMENT_RE = /^[A-Za-z0-9._-]{1,64}$/;
62
67
  const VAULT_KEY_RE = /^uvk_[A-Za-z0-9_-]{16,}$/;
@@ -98,7 +103,9 @@ export class MemoryContinuityStore {
98
103
  /**
99
104
  * @typedef {object} Provenance
100
105
  * @property {ProvenanceSource} source Where the memory came from.
101
- * @property {string} actor UUAID of the agent that produced it (defaults to the owner).
106
+ * @property {string} actor UUAID of the agent that produced it, as the owner states it
107
+ * (defaults to the owner). Signed by the owner, never bound to
108
+ * the actor's key: do not treat it as authenticated.
102
109
  * @property {string|null} origin Free-form, non-secret locator: session id, document digest, tool name.
103
110
  * @property {string|null} evidence Optional sha256 hex digest of supporting material kept elsewhere.
104
111
  */
@@ -220,7 +227,7 @@ export function verifyContinuity(state, owner, envelope = {}) {
220
227
  assertJSON(state);
221
228
  if (state.v !== CONTINUITY_PROTOCOL) throw new ContinuityError("INTEGRITY", "Unknown continuity protocol", { v: state.v });
222
229
  if (state.uuaid !== owner.uuaid || state.publicKey !== owner.publicKey) throw new ContinuityError("IDENTITY_MISMATCH", "Continuity state belongs to a different identity or key", { expected: owner.uuaid, found: state.uuaid });
223
- if (Keychain.localIdFromKey(Buffer.from(owner.publicKey, "hex")) !== owner.uuaid.split(":")[3]) throw new ContinuityError("IDENTITY_MISMATCH", "Owner key is not bound to owner UUAID");
230
+ if (!SELF_CERTIFYING_AGENT_UUAID.test(owner.uuaid ?? "") || Keychain.localIdFromKey(Buffer.from(owner.publicKey, "hex")) !== owner.uuaid.split(":")[3]) throw new ContinuityError("IDENTITY_MISMATCH", "Owner key is not bound to owner UUAID");
224
231
  const { anchor, entries } = state;
225
232
  if (!anchor || typeof anchor.previous !== "string" || !Number.isSafeInteger(anchor.pruned) || anchor.pruned < 0 || !Array.isArray(entries)) throw new ContinuityError("INTEGRITY", "Malformed anchor or entries");
226
233
  if (!Number.isSafeInteger(state.nextSeq) || state.nextSeq < anchor.pruned + entries.length) throw new ContinuityError("INTEGRITY", "Sequence counter is inconsistent with ledger length");
@@ -231,7 +238,7 @@ export function verifyContinuity(state, owner, envelope = {}) {
231
238
  if (body.v !== CONTINUITY_PROTOCOL || body.previous !== previous || !Number.isSafeInteger(body.seq) || body.seq <= lastSeq) throw new ContinuityError("INTEGRITY", "Continuity chain link is broken", { seq: body.seq });
232
239
  if (digest(body) !== hash) throw new ContinuityError("INTEGRITY", "Continuity entry hash mismatch", { seq: body.seq });
233
240
  if (!/^[0-9a-f]{128}$/.test(signature ?? "") || !Keychain.verifyDetached(owner.publicKey, Buffer.from(hash, "hex"), Buffer.from(signature, "hex"))) throw new ContinuityError("INTEGRITY", "Continuity entry signature invalid", { seq: body.seq });
234
- if (!PROVENANCE_SOURCES.includes(body.provenance?.source) || !UUAID_RE.test(body.provenance?.actor ?? "")) throw new ContinuityError("INTEGRITY", "Continuity entry provenance invalid", { seq: body.seq });
241
+ if (!PROVENANCE_SOURCES.includes(body.provenance?.source) || !ACTOR_UUAID_RE.test(body.provenance?.actor ?? "")) throw new ContinuityError("INTEGRITY", "Continuity entry provenance invalid", { seq: body.seq });
235
242
  previous = hash;
236
243
  lastSeq = body.seq;
237
244
  }
@@ -291,7 +298,7 @@ export class ContinuityMemory {
291
298
  */
292
299
  constructor({ keychain, store = new MemoryContinuityStore(), client = null, vaultKey = null, slot = "continuity/chain", limits = {}, now = () => Date.now() } = {}) {
293
300
  const identity = keychain?._identity;
294
- if (!identity || !UUAID_RE.test(identity.uuaid ?? "") || !/^[0-9a-f]{64}$/.test(identity.publicKeyHex ?? "") || typeof keychain.sign !== "function") throw new ContinuityError("IDENTITY_REQUIRED", "A loaded Keychain with a bound agent UUAID is required");
301
+ if (!identity || !SELF_CERTIFYING_AGENT_UUAID.test(identity.uuaid ?? "") || !/^[0-9a-f]{64}$/.test(identity.publicKeyHex ?? "") || typeof keychain.sign !== "function") throw new ContinuityError("IDENTITY_REQUIRED", "A loaded Keychain with a bound agent UUAID is required");
295
302
  if (Keychain.localIdFromKey(Buffer.from(identity.publicKeyHex, "hex")) !== identity.uuaid.split(":")[3]) throw new ContinuityError("IDENTITY_REQUIRED", "Keychain public key is not bound to its UUAID");
296
303
  if (client !== null && (typeof client !== "object" || typeof client.saveMemory !== "function" || typeof client.loadMemory !== "function")) throw new ContinuityError("CLIENT_INVALID", "Injected client must expose the official saveMemory/loadMemory surface");
297
304
  if (vaultKey !== null && !VAULT_KEY_RE.test(vaultKey)) throw new ContinuityError("VAULT_KEY_INVALID", "Vault key must be a uvk_ key from @uuaid/sdk generateVaultKey()");
@@ -427,7 +434,7 @@ export class ContinuityMemory {
427
434
  const source = provenance.source ?? "self";
428
435
  const actor = provenance.actor ?? this.uuaid;
429
436
  if (!PROVENANCE_SOURCES.includes(source)) throw new ContinuityError("ENTRY_INVALID", "Unknown provenance source", { source });
430
- if (!UUAID_RE.test(actor)) throw new ContinuityError("ENTRY_INVALID", "Provenance actor must be an agent UUAID");
437
+ if (!ACTOR_UUAID_RE.test(actor)) throw new ContinuityError("ENTRY_INVALID", "Provenance actor must be an agent UUAID");
431
438
  if (source === "self" && actor !== this.uuaid) throw new ContinuityError("ENTRY_INVALID", "Self-provenance must name the owner as actor");
432
439
  if (source === "peer" && actor === this.uuaid) throw new ContinuityError("ENTRY_INVALID", "Peer-provenance cannot name the owner as actor");
433
440
  if (provenance.evidence != null && !/^[0-9a-f]{64}$/.test(provenance.evidence)) throw new ContinuityError("ENTRY_INVALID", "Evidence must be a sha256 hex digest");
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Classifies an operation into one of three tiers per L3 Section 6.1:
2
+ * Classifies an operation into one of three tiers:
3
3
  * - Tier 1: Local peer messaging (offline, key-derived identities, no registry/principal checks)
4
4
  * - Tier 2: Default local profile evolution (offline, commons:evolve, produces advisory approval)
5
5
  * - Tier 3: Principal-governed institutional operations (strict opt-in, mandatory action-time verifier)
@@ -1,5 +1,6 @@
1
1
  import { assertJSON, BASE_PROTOCOL, digest } from "./profiles.mjs";
2
2
  import { jcs, Keychain } from "./pillar.mjs";
3
+ import { SELF_CERTIFYING_AGENT_UUAID } from "./uuaid-namespace.mjs";
3
4
 
4
5
  // This module deliberately performs no network calls and executes no changes.
5
6
  // Operators must inject verifiers backed by actual identity/evidence authorities.
@@ -19,7 +20,7 @@ export function verifyGovernanceDocument(document) {
19
20
  const { signature, ...body } = document;
20
21
  if (body.v !== BASE_PROTOCOL || !DOCUMENT_KINDS.includes(body.kind) ||
21
22
  typeof body.id !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/.test(body.id) ||
22
- typeof body.issuer !== "string" || !/^uuaid:[a-z0-9-]+:agent:[0-9a-f-]{36}$/.test(body.issuer) ||
23
+ typeof body.issuer !== "string" || !SELF_CERTIFYING_AGENT_UUAID.test(body.issuer) ||
23
24
  !hash(body.publicKey) || typeof signature !== "string" || !/^[0-9a-f]{128}$/.test(signature)) fail("INVALID_DOCUMENT");
24
25
  if (Keychain.localIdFromKey(Buffer.from(body.publicKey, "hex")) !== body.issuer.split(":")[3] ||
25
26
  !Keychain.verifyDetached(body.publicKey, Buffer.from(jcs(body)), Buffer.from(signature, "hex"))) fail("INVALID_SIGNATURE");
@@ -119,7 +120,8 @@ export class PeerGovernance {
119
120
  if (!binding || binding.kind !== "agent" || binding.publicKey !== publicKey ||
120
121
  !hash(publicKey) || !text(binding.controllerId) || !Array.isArray(binding.affiliations) ||
121
122
  binding.affiliations.some(a => !text(a)) || !Array.isArray(binding.capabilities) ||
122
- binding.blocked === true) fail("NOT_ADMITTED");
123
+ // A block on any binding of this key blocks the key, under every spelling.
124
+ Object.values(this.#policy.agents).some(a => a?.publicKey === publicKey && a.blocked === true)) fail("NOT_ADMITTED");
123
125
  return binding;
124
126
  }
125
127
  async #adapter(name, request) {
package/src/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- // L3 Slice 2 v6 §2.2: concrete transports and channel/tenant declarations
1
+ // Concrete transports and channel/tenant declarations
2
2
  import type { MessageTransport } from './transport.mjs';
3
3
 
4
4
  export interface Profile {
@@ -26,6 +26,8 @@ export class CommonsStore {
26
26
  }
27
27
  export class RegistryTrust {
28
28
  constructor(options?:{policy?:Policy;client?:any;fetchImpl?:typeof fetch});
29
+ static isCanonicalTrust(value:unknown):boolean;
30
+ denyPermanently():void;
29
31
  policy:Policy;authorize(id:string,key:string,capability?:string):Promise<any>;standards():Promise<any[]>;
30
32
  publishedProfilePin(code:string,hash:string):Promise<any>;
31
33
  }
package/src/pillar.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // Unmodified upstream modules are covered by NOTICE and PROVENANCE.json.
2
2
  // CarrierClient is wrapped here. The vendored module stays byte-identical to
3
- // @uuaid/pillar 2.0.2. Offline refusal happens before any vendored method runs.
3
+ // @uuaid/pillar 2.2.0. Offline refusal happens before any vendored method runs.
4
4
  import { CarrierClient as VendoredCarrierClient } from "./vendor/pillar/net/carrier-client.mjs";
5
5
  import { isLoopbackUrl, isOffline } from "./offline.mjs";
6
6
 
@@ -26,7 +26,7 @@ function offlineError(url) {
26
26
  export class CarrierClient extends VendoredCarrierClient {
27
27
  constructor(options = {}) {
28
28
  super(options);
29
- // Upstream pillar 2.0.2 does not store env. The package seam does.
29
+ // Upstream pillar 2.2.0 does not store env. The package seam does.
30
30
  this._offlineEnv = options.env ?? process.env;
31
31
  }
32
32
 
package/src/profiles.mjs CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createHash, randomUUID } from "node:crypto";
2
2
  import { jcs, Keychain } from "./pillar.mjs";
3
+ import { SELF_CERTIFYING_AGENT_UUAID } from "./uuaid-namespace.mjs";
3
4
 
4
5
  export const BASE_PROTOCOL = "agent-commons/1";
5
6
  export function digest(value) { assertJSON(value);return createHash("sha256").update(jcs(value)).digest("hex"); }
@@ -80,7 +81,7 @@ export function signDocument(keychain, kind, payload) {
80
81
  export function verifyDocument(document) {
81
82
  assertJSON(document);
82
83
  const {signature,...body}=document;
83
- if(body.v!==BASE_PROTOCOL||!["profile-proposal","profile-vote","profile-contribution","profile-recovery"].includes(body.kind)||!/^uuaid:[a-z0-9-]+:agent:[0-9a-f-]{36}$/.test(body.issuer)||!/^[0-9a-f]{64}$/.test(body.publicKey)||!/^[0-9a-f]{128}$/.test(signature))throw new Error("Invalid agent document");
84
+ if(body.v!==BASE_PROTOCOL||!["profile-proposal","profile-vote","profile-contribution","profile-recovery"].includes(body.kind)||!SELF_CERTIFYING_AGENT_UUAID.test(body.issuer)||!/^[0-9a-f]{64}$/.test(body.publicKey)||!/^[0-9a-f]{128}$/.test(signature))throw new Error("Invalid agent document");
84
85
  if(Keychain.localIdFromKey(Buffer.from(body.publicKey,"hex"))!==body.issuer.split(":")[3])throw new Error("Agent key is not bound to UUAID");
85
86
  if(!Keychain.verifyDetached(body.publicKey,Buffer.from(jcs(body)),Buffer.from(signature,"hex")))throw new Error("Invalid document signature");
86
87
  return body;