zas-agent 0.9.0 → 0.11.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.
Files changed (4) hide show
  1. package/CHANGELOG.md +54 -1
  2. package/README.md +102 -12
  3. package/dist/cli.js +3783 -2425
  4. package/package.json +6 -4
package/CHANGELOG.md CHANGED
@@ -7,6 +7,57 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.11.0] - 2026-10-12
11
+
12
+ ### Added
13
+
14
+ - Automatic npm release checks and separately staged updates, enabled by default.
15
+ Verified releases take effect on the next launch without interrupting transfers
16
+ or changing pairing data. Add `update`, `updates [on|off]`, the
17
+ `ZAS_AGENT_AUTO_UPDATE` override, and update information in `zas_status`.
18
+ Source checkouts stay on their working code; offline or failed checks keep the
19
+ current agent running.
20
+
21
+ ### Security
22
+
23
+ - Sanitize local filenames with the pinned web rules, enforce containment, and
24
+ publish downloads and Directo receives without overwriting competing files (#13).
25
+ - Migrate private keys and pairing secrets to Windows DPAPI, macOS Keychain or
26
+ Linux Secret Service, with an owner-only headless fallback. Check POSIX secret
27
+ permissions and report the storage backend in status (#14).
28
+ - Refuse unsafe HTTP bases and emulator credential mixing, revalidate saved
29
+ endpoints, and reject redirects on credential-bearing requests (#15).
30
+ - Update compatible production dependencies to pass the high-severity audit.
31
+ - Mirror zas.web `46d727a` shared codecs and vectors: reject invalid OPRF points,
32
+ read v2 envelopes while retaining v1 writes, and verify server-selected VOPRF
33
+ against configured public-key pins. CI checks pinned shared sources (#16).
34
+
35
+ ## [0.10.0] - 2026-09-28
36
+
37
+ ### Added
38
+
39
+ - Transfer telemetry. File and note sends, item downloads, and Directo sends
40
+ and receives (live and reliable delivery) report `transfer.started`,
41
+ `transfer.stage_started`, `transfer.slow` (after 30 s),
42
+ `transfer.phase_timing` and `transfer.finished`. Each report carries the
43
+ item category, the transport, byte counts, a size bucket, stage durations and
44
+ the outcome (success, failure or cancellation), joined by a random
45
+ per-attempt ID. No file name, content, path or channel name. The same
46
+ opt-out as `agent.tool_call` covers it. The telemetry notice names the new
47
+ fields.
48
+
49
+ - `plan_inactive`. A send, replace or Directo transfer in an organization
50
+ channel whose plan is inactive now says so, and names who can reactivate
51
+ it. It used to arrive as `upload_failed`, which told the agent to retry.
52
+
53
+ ### Changed
54
+
55
+ - Reports never delay or fail a tool call. The `agent.tool_call` report is
56
+ sent after the answer, on a later tick. Transfer events are queued, at most
57
+ 32 per batch, and sent in one request on a later tick. A report is one
58
+ request with a 2 s timeout and no retry. It is skipped when there is no
59
+ valid session, so it never starts or refreshes a sign-in.
60
+
10
61
  ## [0.9.0] - 2026-09-09
11
62
 
12
63
  ### Added
@@ -333,7 +384,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
333
384
  two separate identities that cannot read each other's keys.
334
385
  - Install snippets for Claude Code and Codex, printed by `zas-agent pair`.
335
386
 
336
- [Unreleased]: https://github.com/soke1556/zas-agent/compare/v0.9.0...HEAD
387
+ [Unreleased]: https://github.com/soke1556/zas-agent/compare/v0.11.0...HEAD
388
+ [0.11.0]: https://github.com/soke1556/zas-agent/compare/v0.10.0...v0.11.0
389
+ [0.10.0]: https://github.com/soke1556/zas-agent/compare/v0.9.0...v0.10.0
337
390
  [0.9.0]: https://github.com/soke1556/zas-agent/compare/v0.8.0...v0.9.0
338
391
  [0.8.0]: https://github.com/soke1556/zas-agent/compare/v0.7.0...v0.8.0
339
392
  [0.7.0]: https://github.com/soke1556/zas-agent/compare/v0.6.3...v0.7.0
package/README.md CHANGED
@@ -112,6 +112,40 @@ You can also start the flow from the coding agent with the `zas_pair` tool:
112
112
  the first call hands back the URL, a later call says whether the approval
113
113
  landed, and if the page shows a code, a call with `code` claims with it.
114
114
 
115
+ ## Updates
116
+
117
+ Automatic updates are on by default in published installations. While serving,
118
+ the agent checks npm's `latest` stable release in the background, at most once
119
+ per day. It installs newer releases in a separate directory and verifies that
120
+ the installed executable reports the expected version. The next agent launch
121
+ uses that release. Restart the MCP connection (or your coding agent) to apply it;
122
+ running transfers are never restarted by the updater. Pairing and channel grants
123
+ stay in place, and an offline or failed update leaves the current version usable.
124
+
125
+ ```sh
126
+ zas-agent updates # show the setting and any release ready to use
127
+ zas-agent updates off # disable automatic downloads and staged launch selection
128
+ zas-agent updates on # enable them again
129
+ zas-agent update # check and stage a release now
130
+ ```
131
+
132
+ Use `npx -y zas-agent@latest` in place of `zas-agent` if you have no global
133
+ installation. `zas_status` also reports the running version and staged update.
134
+ `ZAS_AGENT_AUTO_UPDATE=0` disables the built-in updater; `1` enables it, overriding
135
+ the saved setting. An explicit `update` command can still download a release while
136
+ updates are off, but it will not be selected until updates are enabled again.
137
+ For a pinned installation, use an exact version in the launch command and disable
138
+ automatic updates. The documented `npx ...@latest` command still asks npm for the
139
+ latest package even when the built-in updater is off.
140
+
141
+ Updates require npm and install the official `zas-agent` package from
142
+ `https://registry.npmjs.org`, including its normal dependency installation scripts
143
+ and npm integrity checks. No administrator access is needed. Staged packages live
144
+ under `~/.zas/agent/.updates` (or `ZAS_AGENT_HOME/.updates`); old installations are
145
+ retained and can be removed with the agent stopped. Source checkouts and prerelease
146
+ builds do not update themselves. Existing installations need to upgrade once to a
147
+ release containing this updater before these controls are available.
148
+
115
149
  ## Why you can trust it
116
150
 
117
151
  Every line here is a fact. The ones about this package you can check in this
@@ -159,8 +193,13 @@ The package refuses some of these on its own, before a request is made. The
159
193
  ones marked *(server-side)* are enforced by the Zas server.
160
194
 
161
195
  - **No channel you did not grant.** Not by name, not by id.
162
- - **No shared channel you merely joined, and no workspace channel.** Grants
163
- exist only on channels your account owns and that no organization manages
196
+ - **No shared channel you joined, unless its owner allows it.** You can grant
197
+ a channel you joined, but the grant stays `grant_pending` until that
198
+ channel's owner allows this agent in Zas. The plan also caps how many of
199
+ these channels one agent holds: 2 on Free *(server-side)*.
200
+ - **No workspace channel, unless the organization allows agents.** A channel
201
+ an organization manages, or one you created inside its workspace, can be
202
+ granted only while the organization is active and an admin turned agents on
164
203
  *(server-side)*.
165
204
  - **No reading unless the grant says so.** `read` is a separate switch from
166
205
  `send`; without it, `zas_list_items` and `zas_get_item` are refused.
@@ -196,10 +235,16 @@ string ever reaches a terminal.
196
235
  | Code | What it means |
197
236
  | --- | --- |
198
237
  | `not_paired` | This agent is not paired yet. |
238
+ | `unsafe_endpoint` | An endpoint or emulator configuration could expose credentials. |
239
+ | `identity_permissions` | A secret file is not private to its owner. |
240
+ | `secret_store_failed` | The OS secret store cannot save or open this profile. |
241
+ | `invalid_voprf_configuration` | The server-selected encryption key has no valid local pin. |
242
+ | `invalid_voprf_proof` | The encryption service response failed verification. |
199
243
  | `identity_corrupt` | The identity file on disk is damaged. |
200
244
  | `agent_revoked` | The owner revoked this agent. |
201
245
  | `agent_forbidden` | Only the account owner can do that. |
202
246
  | `grant_missing` | This agent has no access to that channel. |
247
+ | `grant_pending` | That channel belongs to somebody else, and its owner has not allowed this agent yet. |
203
248
  | `send_forbidden` | This agent cannot send to that channel. |
204
249
  | `read_forbidden` | This agent cannot read that channel. |
205
250
  | `direct_mode` | That channel is in Directo mode. |
@@ -215,6 +260,7 @@ string ever reaches a terminal.
215
260
  | `fallback_unavailable` | Reliable delivery is not available right now. |
216
261
  | `key_stale` | The channel key changed; the owner refreshes it by opening Zas. |
217
262
  | `quota_exceeded` | The account reached its storage limit. |
263
+ | `plan_inactive` | The organization's plan is inactive, so sending to its channels is paused; the owner or a billing admin reactivates it. |
218
264
  | `rate_limited` | Too many sends in a row. |
219
265
  | `file_too_big` | The file is over the plan limit. |
220
266
  | `duplicate` | That item is already in the channel. |
@@ -228,6 +274,12 @@ string ever reaches a terminal.
228
274
  | `write_failed` | The download destination could not be written. |
229
275
  | `pairing_expired` | The pairing expired; pair again. |
230
276
  | `pairing_cancelled` | The owner cancelled the pairing. |
277
+ | `claim_mismatch` | The code does not match. |
278
+ | `pairing_not_approved` | Nobody has approved this pairing yet. |
279
+ | `pairing_claimed` | This pairing was already claimed; pair again. |
280
+ | `agent_limit` | The account cannot take another agent; the owner deletes one from Settings → Agents. |
281
+ | `grant_limit` | The plan allows fewer channels per agent than this pairing grants. |
282
+ | `foreign_limit` | The plan allows this agent fewer channels of other people than this pairing asks for. |
231
283
  | `feature_disabled` | Agents are not enabled for this account yet. |
232
284
  | `upload_failed` | The upload failed. |
233
285
  | `oprf_failed` | Zas did not answer correctly while preparing the file. |
@@ -306,14 +358,16 @@ covers every profile on the machine; pairing again does not reset it.
306
358
 
307
359
  What one report carries, and nothing else: the tool that ran, whether it
308
360
  worked, the closed error code when it did not, which of four duration buckets
309
- it fell in, and the package version. No file name, no file contents, no path,
361
+ it fell in, and the package version. Item transfers also report item category,
362
+ transport, byte counts, stage durations, and success/failure/cancellation, joined
363
+ by a random per-attempt ID. No file name, no file contents, no path,
310
364
  no channel name, no error message, no stack.
311
365
 
312
366
  Where it goes: to Zas, never to an analytics service directly. This package
313
367
  holds no analytics token and opens no connection to a third party, so no
314
368
  address of yours reaches one. The report is attributed to the Zas account the
315
369
  agent is paired with, which the server reads from the session — the request
316
- carries no identifier of its own. Nothing is reported before pairing, because
370
+ carries no account or content identifier. Nothing is reported before pairing, because
317
371
  until then there is no account it could belong to.
318
372
 
319
373
  A report is never allowed to matter: it is sent after the answer, waited on
@@ -329,8 +383,8 @@ Codex agent side by side without either reading the other's keys:
329
383
  | macOS, Linux | `~/.zas/agent/<profile>/` |
330
384
  | Windows | `%USERPROFILE%\.zas\agent\<profile>\` |
331
385
 
332
- Four files in the profile directory, all written through a temporary file and
333
- renamed into place, so a crash mid-write cannot leave half a file behind:
386
+ Profile metadata is written through temporary files and renamed into place,
387
+ so a crash mid-write cannot leave half a file behind:
334
388
 
335
389
  - `identity.json` — the agent uid, the owner uid, the name, and the two key
336
390
  pairs. Back it up like a private key, or delete it and pair again.
@@ -349,11 +403,24 @@ One more file sits next to the profiles, in `~/.zas/agent/`:
349
403
  above was last printed. It belongs to the machine, not to a profile, so one
350
404
  decision covers every agent on it.
351
405
 
352
- On macOS and Linux the directory is created `0700` and every file `0600`. On
353
- Windows those bits have no effect: the files carry the permissions of the user
354
- profile they live in, and the package does not try to set any others.
355
-
356
- Deleting the directory makes this machine forget the agent. It does not revoke
406
+ Private keys, polling secrets and legacy pairing codes migrate out of the old
407
+ JSON files on the next start. The replacement metadata is committed only after
408
+ storage succeeds. Windows uses current-user DPAPI and an owner-only directory
409
+ ACL without inherited grants. macOS uses Keychain; Linux uses Secret Service
410
+ through `secret-tool` when a desktop session and that tool are available. A
411
+ locked or failing desktop store must be unlocked or repaired before retrying.
412
+ Headless Linux uses a `0600` file in a `0700` directory. POSIX secret reads reject
413
+ files owned by another user, symlinks, hard links, and group/world permissions;
414
+ the error includes the `chmod 600` repair command. `zas_status` reports the store.
415
+
416
+ Older agent versions cannot read the migrated secret references; keep the
417
+ updated agent installed after migration. OS-protected profiles are not portable backups. Pair a new profile on another
418
+ machine; do not copy its JSON files and expect them to sign in. OS protection
419
+ does not prevent a process already running as your user from using your keys.
420
+
421
+ Deleting the directory removes the local references. Keychain/Secret Service
422
+ entries may remain under service `red.zas.agent`; remove those with the OS
423
+ credential manager when discarding a profile. It does not revoke
357
424
  anything: the account side is closed from the web app, under
358
425
  Settings → Agents → Revoke.
359
426
 
@@ -386,12 +453,22 @@ agent: same keys, same channels, one row.
386
453
  | `ZAS_TOKEN_BASE` | `https://zas.red/anon-token` | The challenge and token routes. |
387
454
  | `ZAS_OPRF_BASE` | `https://zas.red/oprf` | The blind key-derivation service. |
388
455
  | `ZAS_FIREBASE_PROJECT` | `zas-me` | The project whose Firestore the read path queries. |
456
+ | `ZAS_ALLOW_INSECURE_DEV` | unset | `1` permits HTTP only on `localhost`, `127.0.0.1`, or `::1`. |
457
+ | `ZAS_VOPRF_PUBLIC_KEYS` | unset | Operator-provided JSON mapping key IDs to pinned base64 VOPRF public keys. Required when the server selects mode 1. |
389
458
  | `ZAS_FIREBASE_API_KEY` | the public web key | The key used to exchange a custom token for a session. |
390
459
 
391
460
  Only `--profile`, `ZAS_AGENT_HOME` and the two telemetry switches are worth
392
461
  setting by hand. The rest exist
393
462
  so the package can be pointed at a test deployment.
394
463
 
464
+ Saved API/token/OPRF bases are validated on every load. Non-loopback HTTP is
465
+ refused even with the dev flag. To run Firebase emulators, set both
466
+ `FIREBASE_AUTH_EMULATOR_HOST` and `FIRESTORE_EMULATOR_HOST` to loopback hosts,
467
+ all three Zas service bases to loopback, `ZAS_FIREBASE_PROJECT` to a `demo-*`
468
+ project, and `ZAS_ALLOW_INSECURE_DEV=1`. Production profiles cannot use these
469
+ emulators. Credential-bearing requests refuse redirects. Use a separate
470
+ profile for development; repair unsafe saved bases before loading an old one.
471
+
395
472
  ## Development
396
473
 
397
474
  ```
@@ -407,7 +484,7 @@ node dist/cli.js --version
407
484
  This repository is the public mirror of the `agent/` package of Zas's private
408
485
  monorepo. It is produced by `scripts/export-public.mjs`, which builds the
409
486
  package with esbuild and uses the build's own metafile to decide what to copy:
410
- `src/`, `test/`, the package files, and the nine `src/shared/*` modules the
487
+ `src/`, `test/`, the package files, and the `src/shared/*` modules the
411
488
  agent imports. Those shared modules are the client-side crypto and format code — the
412
489
  chunker, the manifest, the envelope, the key derivation — that the Zas web app
413
490
  also ships, which is why the encryption the agent performs is the encryption the
@@ -417,6 +494,19 @@ Pull requests are welcome against this repository. The maintainer applies
417
494
  accepted changes back into the monorepo, and the next export brings them here.
418
495
  See [CONTRIBUTING.md](CONTRIBUTING.md).
419
496
 
497
+ `shared-source.json` pins the shared modules and interoperability fixtures to
498
+ zas.web commit `46d727a870c64728b42b768950d55d7d7a575181`. CI runs
499
+ `npm run check:shared` to detect drift using upstream Git blob IDs. Maintainers
500
+ with the private checkout can verify the pin against the actual commit with
501
+ `npm run check:shared -- --source ../zas.web`. Apply these agent changes back
502
+ to the monorepo before the next export.
503
+
504
+ This release follows the web reader phase: legacy/v1 and authenticated v2
505
+ envelopes can be read; application writers still produce v1. VOPRF mode is
506
+ selected by `GET /v1/agents/me`; mode 1 requires a local public-key pin and a
507
+ valid batch proof, with no downgrade on failure. Enabling production v2 writes
508
+ and coordinating VOPRF adoption across clients remain separate rollout work.
509
+
420
510
  ## Security
421
511
 
422
512
  Please report vulnerabilities privately. [SECURITY.md](SECURITY.md) says how,