@awebai/claude-channel 1.1.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "aweb-channel",
3
3
  "description": "aweb agent coordination channel — receive mail, chat, tasks, and control signals from your agent team in real time.",
4
- "version": "1.1.0",
4
+ "version": "1.3.0",
5
5
  "author": {
6
6
  "name": "awebai"
7
7
  },
package/README.md CHANGED
@@ -49,5 +49,5 @@ The directory must already be connected to an aweb team workspace
49
49
  ## More info
50
50
 
51
51
  - [Channel documentation](https://github.com/awebai/aweb/blob/main/docs/channel.md)
52
- - [Agent guide](https://github.com/awebai/aweb/blob/main/docs/agent-guide.txt)
52
+ - [Agent guide](https://github.com/awebai/aweb/blob/main/docs/agent-guide.md)
53
53
  - [aweb.ai](https://aweb.ai)
package/dist/index.js CHANGED
@@ -25130,6 +25130,7 @@ async function loadSigningKey(path) {
25130
25130
  etc.sha512Sync = (...m) => sha512(etc.concatBytes(...m));
25131
25131
  async function resolveConfig(workdir) {
25132
25132
  const workspacePath = join(workdir, ".aw", "workspace.yaml");
25133
+ const teamsPath = join(workdir, ".aw", "teams.yaml");
25133
25134
  const identityPath = join(workdir, ".aw", "identity.yaml");
25134
25135
  const signingKeyPath = join(workdir, ".aw", "signing.key");
25135
25136
  const workspace = await readYAML(workspacePath);
@@ -25143,19 +25144,25 @@ async function resolveConfig(workdir) {
25143
25144
  "This workspace is on the legacy single-team shape (.aw/workspace.yaml has team_address but no memberships). Run aw workspace migrate-multi-team to convert, then retry."
25144
25145
  );
25145
25146
  }
25146
- const activeTeam = (workspace.active_team || "").trim();
25147
- const membership = (workspace.memberships || []).find((item) => (item.team_id || "").trim() === activeTeam);
25147
+ const teamState = await readYAML(teamsPath);
25148
+ if (!teamState) {
25149
+ throw new Error("worktree team state is missing .aw/teams.yaml; run `aw init` or `aw id team add` first");
25150
+ }
25151
+ const activeTeam = (teamState.active_team || "").trim();
25152
+ const teamMembership = (teamState.memberships || []).find((item) => (item.team_id || "").trim() === activeTeam);
25153
+ const workspaceMembership = (workspace.memberships || []).find((item) => (item.team_id || "").trim() === activeTeam);
25148
25154
  const teamID = activeTeam;
25149
- const alias = (membership?.alias || "").trim();
25150
- if (!baseURL || !teamID || !membership || !alias) {
25155
+ const alias = (teamMembership?.alias || "").trim();
25156
+ const certPath = (teamMembership?.cert_path || "").trim();
25157
+ if (!baseURL || !teamID || !teamMembership || !workspaceMembership || !alias || !certPath) {
25151
25158
  throw new Error("worktree workspace binding is missing aweb_url, active_team, or the active membership alias");
25152
25159
  }
25153
25160
  const signingKey = await loadSigningKey(signingKeyPath);
25154
- const certificate = await loadActiveTeamCertificate(workdir, teamID);
25161
+ const certificate = await loadConfiguredTeamCertificate(workdir, teamID, certPath);
25155
25162
  const identity = await readYAML(identityPath);
25156
25163
  const did = computeDIDKey(getPublicKey(signingKey));
25157
25164
  const stableID = (identity?.stable_id || "").trim() || (certificate.member_did_aw || "").trim();
25158
- const address = (identity?.address || "").trim() || (certificate.member_address || "").trim();
25165
+ const address = (certificate.member_address || "").trim() || (identity?.address || "").trim();
25159
25166
  if ((identity?.did || "").trim() && did !== identity?.did?.trim()) {
25160
25167
  throw new Error("identity.yaml did does not match .aw/signing.key");
25161
25168
  }
@@ -25163,10 +25170,10 @@ async function resolveConfig(workdir) {
25163
25170
  throw new Error("team certificate member_did_key does not match .aw/signing.key");
25164
25171
  }
25165
25172
  if ((certificate.team_id || "").trim() !== teamID) {
25166
- throw new Error(`workspace.yaml active_team does not match certificate for ${teamID}`);
25173
+ throw new Error(`team certificate does not match active team ${teamID}`);
25167
25174
  }
25168
25175
  if ((certificate.alias || "").trim() !== alias) {
25169
- throw new Error("workspace.yaml active membership alias does not match the team certificate");
25176
+ throw new Error("active membership alias does not match the team certificate");
25170
25177
  }
25171
25178
  return {
25172
25179
  baseURL,
@@ -25179,6 +25186,16 @@ async function resolveConfig(workdir) {
25179
25186
  teamCertificateHeader: encodeTeamCertificateHeader(certificate)
25180
25187
  };
25181
25188
  }
25189
+ async function loadConfiguredTeamCertificate(workdir, activeTeam, certPath) {
25190
+ try {
25191
+ return await loadTeamCertificate(join(workdir, ".aw", certPath));
25192
+ } catch (error2) {
25193
+ if (error2.code !== "ENOENT") {
25194
+ throw error2;
25195
+ }
25196
+ return loadActiveTeamCertificate(workdir, activeTeam);
25197
+ }
25198
+ }
25182
25199
  async function loadActiveTeamCertificate(workdir, activeTeam) {
25183
25200
  const certsDir = join(workdir, ".aw", "team-certs");
25184
25201
  let files;
@@ -26313,12 +26330,13 @@ var SenderTrustManager = class {
26313
26330
  }
26314
26331
  const trustAddress = this.canonicalTrustAddress(rawAddress);
26315
26332
  const meta3 = await this.resolveAgentMeta(rawAddress);
26316
- status = await this.checkStableIdentityRegistry(
26333
+ const registryCheck = await this.checkStableIdentityRegistry(
26317
26334
  status,
26318
26335
  (verificationAddress || rawAddress).trim(),
26319
26336
  fromDID,
26320
26337
  fromStableID
26321
26338
  );
26339
+ status = registryCheck.status;
26322
26340
  return this.checkTOFUPinWithMeta(
26323
26341
  store,
26324
26342
  status,
@@ -26328,7 +26346,8 @@ var SenderTrustManager = class {
26328
26346
  fromStableID,
26329
26347
  rotationAnnouncement,
26330
26348
  replacementAnnouncement,
26331
- meta3
26349
+ meta3,
26350
+ registryCheck.confirmedCurrentKey
26332
26351
  );
26333
26352
  }
26334
26353
  checkRecipientBinding(status, toDID) {
@@ -26339,18 +26358,21 @@ var SenderTrustManager = class {
26339
26358
  }
26340
26359
  async checkStableIdentityRegistry(status, trustAddress, fromDID, fromStableID) {
26341
26360
  if (status !== "verified" || !fromDID || !fromStableID?.startsWith("did:aw:")) {
26342
- return status;
26361
+ return { status, confirmedCurrentKey: false };
26343
26362
  }
26344
26363
  const registryResult = await this.registry.verifyStableIdentity(trustAddress, fromStableID);
26345
26364
  if (registryResult.outcome === "HARD_ERROR") {
26346
- return "identity_mismatch";
26365
+ return { status: "identity_mismatch", confirmedCurrentKey: false };
26347
26366
  }
26348
26367
  if (registryResult.outcome === "OK_VERIFIED" && registryResult.currentDidKey && registryResult.currentDidKey !== fromDID) {
26349
- return "identity_mismatch";
26368
+ return { status: "identity_mismatch", confirmedCurrentKey: false };
26350
26369
  }
26351
- return status;
26370
+ return {
26371
+ status,
26372
+ confirmedCurrentKey: registryResult.outcome === "OK_VERIFIED" && registryResult.currentDidKey === fromDID
26373
+ };
26352
26374
  }
26353
- checkTOFUPinWithMeta(store, status, rawAddress, trustAddress, fromDID, fromStableID, rotationAnnouncement, replacementAnnouncement, meta3) {
26375
+ checkTOFUPinWithMeta(store, status, rawAddress, trustAddress, fromDID, fromStableID, rotationAnnouncement, replacementAnnouncement, meta3, registryConfirmedCurrentKey) {
26354
26376
  if (!status || status !== "verified" && status !== "verified_custodial" || !fromDID || !trustAddress || !meta3.resolved) {
26355
26377
  return { status, stored: false };
26356
26378
  }
@@ -26395,6 +26417,13 @@ var SenderTrustManager = class {
26395
26417
  if (fromStableID) {
26396
26418
  const pin = store.pins.get(pinKey);
26397
26419
  if (pin?.did_key && pin.did_key !== fromDID) {
26420
+ if (registryConfirmedCurrentKey) {
26421
+ store.storePin(pinKey, trustAddress, "", "");
26422
+ const updated = store.pins.get(pinKey);
26423
+ updated.stable_id = fromStableID;
26424
+ updated.did_key = fromDID;
26425
+ return { status, stored: true };
26426
+ }
26398
26427
  if (!this.verifyRotationAnnouncement(rotationAnnouncement, fromDID, pin.did_key) && !this.verifyReplacementAnnouncement(trustAddress, replacementAnnouncement, fromDID, pin.did_key, meta3)) {
26399
26428
  return { status: "identity_mismatch", stored: false };
26400
26429
  }
@@ -26410,6 +26439,14 @@ var SenderTrustManager = class {
26410
26439
  }
26411
26440
  case "mismatch": {
26412
26441
  const pinnedKey = store.addresses.get(trustAddress) || "";
26442
+ if (registryConfirmedCurrentKey && fromStableID) {
26443
+ store.removeAddress(trustAddress);
26444
+ store.storePin(pinKey, trustAddress, "", "");
26445
+ const pin = store.pins.get(pinKey);
26446
+ pin.stable_id = fromStableID;
26447
+ pin.did_key = fromDID;
26448
+ return { status, stored: true };
26449
+ }
26413
26450
  if (fromStableID && pinnedKey === fromStableID) {
26414
26451
  const pin = store.pins.get(pinnedKey);
26415
26452
  if (pin?.did_key === fromDID) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awebai/claude-channel",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": "./dist/index.js",
@@ -79,4 +79,4 @@ Diagnose and fix the aweb channel setup for this project.
79
79
  ```
80
80
 
81
81
  Reference model: `docs/aweb-sot.md`, `docs/awid-sot.md`, and
82
- `docs/agent-guide.txt`.
82
+ `docs/agent-guide.md`.