@abelxiaoxing/cadence 2.0.6 → 2.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,14 +16,24 @@ Cadence needs Node `>=22.19.0` with npm and [Pi](https://www.npmjs.com/package/@
16
16
  ```sh
17
17
  npm install -g @abelxiaoxing/cadence
18
18
  cadence server install
19
- cadence token-link --workspace ~/cadence --reveal
20
19
  ```
21
20
 
22
21
  The global install puts `cadence` (and its alias `cadence-service`) on `PATH`.
23
22
  Cadence ships no install script, so npm 12 and Bun, which skip untrusted install scripts by default, change nothing.
24
23
  They may still report blocked scripts from the pinned Pi SDK's dependencies: `@google/genai`'s preinstall only echoes `no-op`, and `protobufjs`'s postinstall only warns about a dependent's version scheme, so neither needs approval.
25
24
  `cadence server install` registers and starts the background service for `~/cadence` on `http://127.0.0.1:17423`; `--workspace /absolute/project` selects another workspace.
26
- It also creates the research template `~/.pi/agent/cadence/.env` when missing; Pi's startup card names that path until it exists.
25
+ It prints the private link to open, `http://127.0.0.1:17423/?token=…`.
26
+ The port and that token live with the research settings in `~/.pi/agent/cadence/.env`.
27
+ Install creates that file from the research template when missing (your own 0600 file; Pi's startup card names the path until it exists), and adds either line when it is missing, never changing an existing one:
28
+
29
+ ```sh
30
+ CADENCE_PORT=17423
31
+ CADENCE_TOKEN=<random 43 characters>
32
+ ```
33
+
34
+ The token admits anyone who has it to the workspace, so keep the file and the link private; a token you choose needs at least 32 characters.
35
+ To change either, edit the line and run `cadence server restart`, which prints the new link; old links and browser cookies stop working.
36
+ A workspace that an earlier version started with a generated token switches to the file at that restart and keeps its history.
27
37
 
28
38
  | Platform | Service | Starts |
29
39
  | -------- | ------------------------------------------------------------------------------------------- | -------------------------------------------- |
@@ -116,7 +126,7 @@ For manual checks, `pi -e ./src/index.ts -e ./scripts/agent-panel-demo.ts` adds
116
126
 
117
127
  ### Browser
118
128
 
119
- Open the locally revealed token link.
129
+ Open the private link that `cadence server install` printed, or that `cadence token-link --reveal` reveals.
120
130
  Valid bootstrap redirects to a token-free URL and uses an HttpOnly SameSite cookie for subsequent HTTP/WebSocket access; no localStorage token copy.
121
131
  The browser can create/plan/Start/Cancel, run exact configured checks and record human review without a live Pi terminal.
122
132
  A token grants workspace access, not action consent.
@@ -363,6 +373,8 @@ Byte values are UTF-8/encoded bounds where specified; they are not targets to si
363
373
  | npm 12 or Bun skips untrusted install scripts by default | Ship none; `cadence server install` registers the service and creates the template |
364
374
  | Service manager that only signals (launchd, Windows login) | Orderly Stop first; an unconfirmed Stop changes nothing; no SIGTERM or `taskkill` |
365
375
  | Pi's TUI replaces an info status with the next one | The missing-service hint is its own warning notification |
376
+ | Token source the user edits (`CADENCE_TOKEN` in `.env`) | Read once before binding, never bound for the run: an edit cannot fence Stop |
377
+ | Saved port/token source differs from `.env` | Only when stopped, reselect just those under the reservation; running ones refuse |
366
378
 
367
379
  Good: current context → explicit grant → durable acceptance → genuine original native/storage settlement → exact retained dependency → real checks → human review.
368
380
  Base: a client leaves and another reattaches to the same accepted run without launching it again.
@@ -396,7 +408,8 @@ Regression owners:
396
408
  - `agent-panel`, `agent-panel-model`, `agent-panel-cadence`: panel keys/rendering and readonly owner observation that never starts, cancels or replays work.
397
409
  - `test/web/`: adapted pure/SSR tests separately from actual built-browser contexts, HTTPS, mixed clients, focus/viewports and complete downloads.
398
410
  - `package-*`, `distribution`, `service-package`, `independence`: exact tar/member/body/import/notice closure and nonactivating discovery.
399
- - `service-autostart`, `install-config`: explicit `cadence server` registration on systemd, launchd and the Windows Run key, definition escaping, restart/disable/mask/foreign handling, orderly Stop before every change and a package without install scripts.
411
+ - `service-autostart`, `install-config`: explicit `cadence server` registration on systemd, launchd and the Windows Run key, definition escaping, restart/disable/mask/foreign handling, orderly Stop before every change, the `.env` port and token lines and a package without install scripts.
412
+ - `service-cli`: real owners started from the `.env` port and token, reselection of a stopped workspace, edits while running and rotation of the token line.
400
413
  - `workspace-landing`: home-directory redirection to `~/cadence` across management, native attach and observation.
401
414
 
402
415
  Regenerate operator/service/native/browser outputs only through their canonical builders; `--check` variants compare new private output without overwriting canonical bytes.
@@ -405,6 +418,16 @@ Review the independently enumerated package member list and every emitted body,
405
418
  Keep public Pi peers external for the extension, the exact Undici/ws runtime edges, the exact optional SDK pins for the standalone owner and all upstream/font/vendor notices.
406
419
  Preserve original license bytes through their precise Git attributes; line-ending normalization must not invalidate audited source/notice hashes.
407
420
 
421
+ ### Release 2.0.7 acceptance snapshot
422
+
423
+ Full `verify` ran on the 2.0.7 release tree (`7973e23` plus the version bump), in the 2.0.3 environment below.
424
+ It passed 1945 root tests in 78 files (27 Windows-only controls skipped on Linux); `service-history-projection`'s multisegment archive test hit its 45s budget under shared load and passed alone (24 tests, 27s).
425
+ The 111 web tests, 5 real-browser scenarios and 132-member pack audit passed, and CI 40194654384 passed 12/12 on the candidate `7341cf6` (this commit before its snapshot).
426
+ `cadence server install|restart|uninstall` ran end to end in an isolated home, with a fake `systemctl` that runs the unit's own ExecStart and ExecStop.
427
+ The printed link entered the WebUI, and an earlier generated-token workspace was reselected to the `.env`.
428
+ An edit while running applied only at restart, and rotation changed only the `CADENCE_TOKEN` line.
429
+ Real systemd, launchd and Windows registration were not exercised for this release.
430
+
408
431
  ### Release 2.0.6 acceptance snapshot
409
432
 
410
433
  Full `verify` passed on the 2.0.6 release tree (`8d31512` plus the version bump): 1940 root tests in 78 files (27 Windows-only controls skipped on Linux), 111 web tests, 5 real-browser scenarios and the 132-member pack audit, in the 2.0.3 environment below.
@@ -23,6 +23,7 @@ Use a private0600 JSON file with actual absolute paths:
23
23
  }
24
24
  ```
25
25
 
26
+ `tokenSource` is `generated`, `environment` (`CADENCE_WEB_TOKEN`), `file` (the whole `tokenFile` is the token) or `config` (`tokenFile` names an `.env` whose [`CADENCE_PORT` and `CADENCE_TOKEN`](service-management.md#port-and-token) apply; its port must equal `http.port`).
26
27
  Explicitly start with `cadence-service start --workspace /absolute/project --config /absolute/private-config.json`.
27
28
  The host refuses arbitrary forwarding chains, alternate authorities and non-loopback binding.
28
29
  Native/management capability traffic remains direct loopback, separate from browser credentials.
@@ -47,14 +48,14 @@ Audit any additional proxy-generated forwarding headers against the exact backen
47
48
  HTTP and WebSocket upgrade must use the same authenticated route; no public backend bypass or insecure credential-bearing HTTP.
48
49
  This example does not install Caddy, provision DNS/certificates, change a firewall or deploy a service.
49
50
 
50
- Use `cadence-service token-link --workspace /absolute/project --reveal` to reveal a private entry link deliberately.
51
+ Use `cadence-service token-link --workspace /absolute/project --reveal` to reveal a private entry link deliberately; the background service prints its link at `cadence server install` and `restart`.
51
52
  Only root GET token entry accepts query credentials; subsequent private reads, exports and WS use the HttpOnly SameSite=Strict Secure cookie.
52
53
  Browser mutations/readonly POSTs require exact Origin and CSRF; access does not grant Start/check/review consent.
53
54
  A bad explicit token refuses even with an older cookie.
54
55
  Never put provider credentials in a browser or URL.
55
56
 
56
57
  `token-rotate` invalidates old links/cookies, pending grants, authenticated sockets and incomplete downloads without canceling admitted tasks.
57
- Environment-backed tokens require explicit Stop/restart with changed environment instead.
58
+ Environment-backed tokens require explicit Stop/restart with changed environment instead; an `.env` token's rotation rewrites only its `CADENCE_TOKEN` line.
58
59
  Links may already exist in clipboard/history or external logs; redirecting cannot retract disclosure.
59
60
  Use [management and recovery](service-management.md) for Stop, uncertainty and exact local resolution.
60
61
  Loopback HTTPS/viewport tests are not physical-device or second-machine deployment qualification.
@@ -16,7 +16,7 @@ cadence stop --workspace /absolute/project
16
16
 
17
17
  `cadence-service` is the same command, and the equivalent package-relative command is `node <cadence>/src/service-cli.mjs ...`.
18
18
  `--help` lists the finite interface.
19
- `start` also accepts `--foreground`, `--config`, `--agent-dir`, `--host` (loopback only), `--port`, `--token-file` and `--state-home`.
19
+ `start` also accepts `--foreground`, `--config`, `--agent-dir`, `--host` (loopback only), `--port`, `--token-file`, `--server-config` ([port and token](#port-and-token)) and `--state-home`.
20
20
  Defaults are loopback `127.0.0.1:17423`, normal Pi agent configuration, and detached service lifetime.
21
21
  An explicit port0 selects and persists a positive port once; restart uses the selected configuration, not a fallback endpoint.
22
22
  Missing/corrupt existing setup is preserved, not filled in or reset.
@@ -37,11 +37,11 @@ cadence server uninstall
37
37
 
38
38
  Only these explicit commands register, change or remove the service; no package install, update hook, `/cadence` or browser visit does.
39
39
  The package has no install script, so npm 12 and Bun skipping untrusted scripts by default changes nothing; the pinned Pi SDK's blocked `@google/genai` preinstall only echoes `no-op`, and its `protobufjs` postinstall only warns about version schemes.
40
- `install` also creates the research template `~/.pi/agent/cadence/.env` when it is missing, never overwriting it, whatever the service result.
41
- `install` works from any package location and runs `start --foreground --workspace` (Linux, macOS) or `start --workspace` (Windows) from that copy with the installing Node, without `--port`.
40
+ `install` also creates the research template `~/.pi/agent/cadence/.env` when it is missing, never overwriting it, whatever the service result, and adds its [port and token](#port-and-token) lines when they are missing.
41
+ `install` works from any package location and runs `start --foreground --workspace <workspace> --server-config <file>` (Linux, macOS) or the same without `--foreground` (Windows) from that copy with the installing Node, without `--port`.
42
42
  The workspace is `~/cadence` (created if missing), an existing absolute `--workspace`, or on later installs the one the definition already runs; a workspace containing the service's state home lands on `~/cadence` with a note.
43
- A new workspace selects `http://127.0.0.1:17423`; a port saved by an earlier start of that workspace still wins, and an occupied endpoint fails instead of falling back.
44
- Browser entry still requires the explicitly revealed token link; install prints the `token-link --reveal` command, never the token.
43
+ The `.env` [port and token](#port-and-token) select the endpoint (17423 by default) and the token; an occupied endpoint fails instead of falling back.
44
+ Install and restart print the private entry link once the owner answers; the JSON result on stdout never carries the token.
45
45
  `restart` rewrites an existing definition with the current Node and package paths, keeping its workspace and the user's disable choices, and starts it; run it after an npm upgrade, a Node change or a `models.json` edit.
46
46
  `stop` stops the owner orderly and keeps the registration for the next boot or login.
47
47
  `uninstall` stops it orderly and deletes only what Cadence generated; workspace, state home, history, linger and Pi sources stay.
@@ -58,6 +58,33 @@ It is a warning rather than part of the info card because Pi's TUI replaces one
58
58
  `/cadence` names the same command when it finds no owner.
59
59
  A machine without a supported user service manager and `CADENCE_AUTOSTART=0` keep both quiet; with `CADENCE_LINGER=0` they suggest `--no-linger`.
60
60
 
61
+ ### Port and token
62
+
63
+ The background service reads two lines of the research configuration `~/.pi/agent/cadence/.env`:
64
+
65
+ ```sh
66
+ CADENCE_PORT=17423
67
+ CADENCE_TOKEN=<at least 32 characters, no control or format characters>
68
+ ```
69
+
70
+ The file keeps the research skills' syntax (`KEY=value` lines, `#` comments, one optional pair of quotes), and each of these keys may appear only once.
71
+ `install` and `restart` create the file from the research template when it is missing, as your own 0600 file in a 0700 directory.
72
+ They append a missing `CADENCE_PORT` (17423) or `CADENCE_TOKEN` (random, 43 characters) under a comment, in the file's own line endings, and never change an existing line.
73
+ An unusable file (another owner, wider permissions, a symlink, a syntax error the research skills would also refuse, a duplicate key, a port outside 1-65535, a short token) makes them change nothing, naming only its path.
74
+ A project's `.pi/cadence/.env`, which the research skills prefer, is never read for the service.
75
+ `start --server-config <.env>` makes these lines authoritative.
76
+ The host reads them once before binding, like an environment token, so editing them while the owner runs changes nothing and can never fence access or the orderly Stop; the next start applies them, and `cadence server restart` does both.
77
+ A workspace whose token comes from the file follows it at every `start`, also without `--server-config`; a contradicting `--port`, `--token-file` or `CADENCE_WEB_TOKEN` refuses.
78
+ `CADENCE_WEB_TOKEN` stays the separate process-environment source; sourcing the `.env` in a shell sets `CADENCE_PORT` and `CADENCE_TOKEN`, which Cadence never reads from its environment.
79
+ The token never enters Cadence's state home, and status and diagnosis never print it.
80
+ `token-rotate` replaces only the `CADENCE_TOKEN` line's value with a new random token, keeping every other byte, and invalidates old links and cookies without stopping work.
81
+ It refuses without any effect when that token was edited since the start, so a pending edit is never overwritten.
82
+
83
+ A stopped workspace selected earlier with a generated, environment or file token, or another port, is reselected to the file at its next `start --server-config`.
84
+ Under the new owner reservation Cadence retires the previous token with a new access generation and replaces the selected port and token source; the history and every other selected setting stay.
85
+ A different agent directory, host or proxy still conflicts, and a running owner refuses until it has stopped.
86
+ An interrupted replacement keeps the reservation as a fence and is never repaired automatically, like any interrupted start.
87
+
61
88
  ### Linux systemd user unit
62
89
 
63
90
  `install` writes `~/.local/share/systemd/user/cadence.service`, enables it for `default.target` (also undoing a `disable`, never a `mask`) and starts it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abelxiaoxing/cadence",
3
- "version": "2.0.6",
3
+ "version": "2.0.7",
4
4
  "description": "Shared Pi task workspace: native terminal and WebUI, persistent service, checks and human review.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -518,6 +518,9 @@ export class ServiceCoordination {
518
518
  input: OwnerConfig,
519
519
  resolvedEndpoint: string = input.endpoint,
520
520
  initializeNew?: () => void,
521
+ /** Replaces a stopped selection's host policy and access (given its
522
+ * selected host-config snapshot); only then may the identity change. */
523
+ reselectExisting?: (hostConfig: FileSnapshot) => void,
521
524
  ): OwnerLease {
522
525
  const config = decodeOwnerConfig(input);
523
526
  const bound = endpoint(resolvedEndpoint);
@@ -537,7 +540,8 @@ export class ServiceCoordination {
537
540
  if (old?.value && old.value.phase !== "stopped")
538
541
  throw new ContractError("quarantine");
539
542
  if (this.store.inspectLock()) throw new ContractError("conflict");
540
- if (old && old.config.identity !== hash(encoded(config)))
543
+ const reselect = !!old && old.config.identity !== hash(encoded(config));
544
+ if (reselect && (!reselectExisting || !old?.hostConfig))
541
545
  throw new ContractError("conflict");
542
546
  // Reserve BEFORE root initialization/legacy acquisition. Any later failure
543
547
  // keeps the reservation and short lock as an explicit partial fence.
@@ -561,7 +565,26 @@ export class ServiceCoordination {
561
565
  }),
562
566
  REGISTRY_BYTES,
563
567
  );
564
- this.initialize(config);
568
+ if (old?.hostConfig && reselect && reselectExisting) {
569
+ // Host policy and access first, then the config and its manifest; the
570
+ // registration below takes the new identity. Failures keep the fence.
571
+ reselectExisting(old.hostConfig);
572
+ const saved = this.files.replace(
573
+ this.path("config.json"),
574
+ old.config,
575
+ encoded(config),
576
+ );
577
+ this.files.replace(
578
+ this.path("format.json"),
579
+ old.manifest,
580
+ encoded({
581
+ schema: "cadence-service-format/1",
582
+ root: this.store.root,
583
+ stateHome: this.stateHome,
584
+ configIdentity: saved.identity,
585
+ }),
586
+ );
587
+ } else this.initialize(config);
565
588
  // Called only for genuinely absent selected metadata, under the registry
566
589
  // reservation and before registration. Failures preserve the partial fence.
567
590
  if (!old) initializeNew?.();