instar 1.2.45 → 1.2.47
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/dist/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +54 -1
- package/dist/commands/server.js.map +1 -1
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +6 -1
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/middleware.d.ts +9 -3
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +14 -5
- package/dist/server/middleware.js.map +1 -1
- package/dist/tunnel/TunnelManager.d.ts +43 -0
- package/dist/tunnel/TunnelManager.d.ts.map +1 -1
- package/dist/tunnel/TunnelManager.js +79 -0
- package/dist/tunnel/TunnelManager.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +3 -3
- package/upgrades/1.2.46.md +99 -0
- package/upgrades/1.2.47.md +36 -0
- package/upgrades/side-effects/codex-telegram-default-framework.md +106 -0
- package/upgrades/side-effects/tunnel-credential-rotation.md +88 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
<!-- patch = bug fix, no new capability, no breaking change -->
|
|
5
|
+
|
|
6
|
+
## What Changed
|
|
7
|
+
|
|
8
|
+
**fix(framework): Telegram spawn path now honors the agent's configured framework (codex-cli agents stop spawning Claude sessions).**
|
|
9
|
+
|
|
10
|
+
A follow-on to the framework-spawn-portability fix (v1.2.31). That fix
|
|
11
|
+
made the fresh-spawn path (`spawnInteractiveSession`'s internal
|
|
12
|
+
resolution) read the agent's resolved `config.sessions.framework`. But
|
|
13
|
+
there are TWO paths that pick a framework, and the **Telegram message
|
|
14
|
+
path** was missed.
|
|
15
|
+
|
|
16
|
+
When a Telegram message arrives, `spawnSessionForTopic` resolves the
|
|
17
|
+
framework via `resolveTopicFramework(topicId)`, which returns the
|
|
18
|
+
module-level `_defaultFramework` for any topic without an explicit
|
|
19
|
+
per-topic override (i.e. every fresh topic). `_defaultFramework` was
|
|
20
|
+
initialized in `startServer` as:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
const framework = frameworkFromEnv() ?? 'claude-code';
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
— sourced ONLY from the `INSTAR_FRAMEWORK` environment variable. The
|
|
27
|
+
setup wizard sets `enabledFrameworks: ['codex-cli']` in config, NOT the
|
|
28
|
+
env var, so for a codex-cli-only agent that didn't export
|
|
29
|
+
`INSTAR_FRAMEWORK` (the common case), `frameworkFromEnv()` returned
|
|
30
|
+
undefined and `_defaultFramework` fell back to `'claude-code'`. Worse,
|
|
31
|
+
`spawnSessionForTopic` passes its resolved framework as the per-call
|
|
32
|
+
`options.framework` to `spawnInteractiveSession` — and per-call wins
|
|
33
|
+
over `config.framework`. So even though v1.2.31 correctly resolved
|
|
34
|
+
`config.framework` to `codex-cli`, the Telegram path's wrong default
|
|
35
|
+
overrode it and spawned a Claude session on every message.
|
|
36
|
+
|
|
37
|
+
The fix: derive `_defaultFramework` from the agent's resolved runtime
|
|
38
|
+
framework first, falling back to the env var only when that's unset:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const framework = config.sessions?.framework ?? frameworkFromEnv() ?? 'claude-code';
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`config.sessions.framework` is the single resolved source
|
|
45
|
+
(`resolveConfiguredFramework(sessions.framework, INSTAR_FRAMEWORK,
|
|
46
|
+
enabledFrameworks)` from `Config.load`), so both the fresh-spawn path
|
|
47
|
+
and the Telegram path now agree. A codex-cli-only agent spawns Codex
|
|
48
|
+
sessions whether the session is created directly via the API or
|
|
49
|
+
triggered by a Telegram message.
|
|
50
|
+
|
|
51
|
+
No migration needed — the fix is a server-startup derivation. Deployed
|
|
52
|
+
codex-cli agents get the correct behavior the moment they update and
|
|
53
|
+
restart cleanly. (Note: a clean restart IS required — an agent running
|
|
54
|
+
an older server process keeps the old `_defaultFramework` in memory
|
|
55
|
+
until restarted, even after its files update.)
|
|
56
|
+
|
|
57
|
+
## Evidence
|
|
58
|
+
|
|
59
|
+
The original failure: a codex-cli-only agent ("codey") with
|
|
60
|
+
`enabledFrameworks: ['codex-cli']` and no `INSTAR_FRAMEWORK` env spawned
|
|
61
|
+
a Claude Code (Opus 4.7) session every time it answered a Telegram
|
|
62
|
+
message — including in brand-new topics. A direct `/sessions/create`
|
|
63
|
+
API spawn correctly produced Codex, which masked the bug (the API path
|
|
64
|
+
doesn't pass the Telegram default).
|
|
65
|
+
|
|
66
|
+
Regression coverage in `tests/unit/framework-spawn-portability.test.ts`
|
|
67
|
+
(2 new assertions):
|
|
68
|
+
|
|
69
|
+
1. `server.ts` derives `_defaultFramework` from `config.sessions?.framework`
|
|
70
|
+
ahead of the `frameworkFromEnv()` fallback.
|
|
71
|
+
2. The pre-fix env-only derivation (`const framework = frameworkFromEnv()
|
|
72
|
+
?? 'claude-code';`) no longer appears in `server.ts`.
|
|
73
|
+
|
|
74
|
+
These join the existing 10 framework-spawn-portability tests (precedence
|
|
75
|
+
of `resolveConfiguredFramework`, the spawn-path source assertions, and
|
|
76
|
+
the `Config.load` wiring) — 12 tests total, all passing. `tsc --noEmit`
|
|
77
|
+
clean, lint clean.
|
|
78
|
+
|
|
79
|
+
Empirical confirmation against a live codex-cli agent (message it, watch
|
|
80
|
+
the spawned session run `codex --model gpt-5.3-codex` instead of
|
|
81
|
+
`claude`) is performed as part of the rollout, per the bug-fix evidence
|
|
82
|
+
bar — no "fixed" claim without reproducing the corrected behavior.
|
|
83
|
+
|
|
84
|
+
## What to Tell Your User
|
|
85
|
+
|
|
86
|
+
If you set up an agent to run on Codex, it will now correctly run on
|
|
87
|
+
Codex when it answers your messages — not just when a session is
|
|
88
|
+
created some other way. Before this fix, a Codex-only agent could still
|
|
89
|
+
quietly start up on Claude whenever you messaged it, because the
|
|
90
|
+
message-handling path was reading the wrong setting. You don't need to
|
|
91
|
+
do anything beyond letting your agent update and restart; the Codex
|
|
92
|
+
choice you made at setup is now respected on every path.
|
|
93
|
+
|
|
94
|
+
## Summary of New Capabilities
|
|
95
|
+
|
|
96
|
+
| Capability | How to Use |
|
|
97
|
+
|-----------|-----------|
|
|
98
|
+
| Telegram message path honors configured framework | Automatic — codex-cli agents spawn Codex on incoming messages |
|
|
99
|
+
| Single framework source of truth across both spawn paths | Automatic — derived from your install-time framework choice |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Upgrade Guide — vNEXT
|
|
2
|
+
|
|
3
|
+
<!-- bump: patch -->
|
|
4
|
+
|
|
5
|
+
## What Changed
|
|
6
|
+
|
|
7
|
+
PR 7 of the tunnel-failure-resilience chain. This is the security cleanup that makes the backup-tunnel feature safe to use: whenever a backup relay episode ends, the agent now rotates your dashboard PIN and access token.
|
|
8
|
+
|
|
9
|
+
**Why it matters.** While a backup relay is active, your dashboard traffic — including the PIN and any private view links — briefly passes through a third-party operator's machines. PIN rotation alone is not enough: the private view links are signed with your access token, so a copied link would keep working forever unless the token itself changes. This release rotates both. The moment the backup ends, the old PIN stops working and every previously-shared private view link becomes invalid.
|
|
10
|
+
|
|
11
|
+
**Where it triggers.** Every terminal exit from a backup relay episode rotates: an operator stop/shutdown while the relay was up, and — most importantly — boot-recovery. If the agent died mid-relay-episode, a flag persisted to disk causes rotation to run on the next boot **before the server accepts any API traffic**, so a relay operator who saw the old credentials can't use them against the freshly-started server.
|
|
12
|
+
|
|
13
|
+
**How it takes effect immediately.** The auth layer now reads the token live on every request instead of capturing it once at startup. So rotation invalidates the old token and old signed URLs instantly, with no restart. Existing behavior is unchanged when no rotation happens.
|
|
14
|
+
|
|
15
|
+
## What to Tell Your User
|
|
16
|
+
|
|
17
|
+
- If a backup tunnel was ever used, you'll get a private message with a fresh dashboard PIN once it's no longer needed. Any open dashboard tab will ask you to sign in again with the new PIN.
|
|
18
|
+
- Any private view link you shared while the backup was active will stop working — that's deliberate, so the backup operator can't reuse it.
|
|
19
|
+
- If nothing ever falls back to a backup, you'll never see any of this; normal operation is unchanged.
|
|
20
|
+
|
|
21
|
+
## Summary of New Capabilities
|
|
22
|
+
|
|
23
|
+
| Capability | How to Use |
|
|
24
|
+
|-----------|-----------|
|
|
25
|
+
| Credential rotation on relay-episode end | Automatic — fires on stop/shutdown and boot-recovery whenever a backup relay was in use; new PIN arrives in the owner DM |
|
|
26
|
+
| Live auth-token resolution | Automatic — the server now honors a rotated token immediately, no restart |
|
|
27
|
+
|
|
28
|
+
## Evidence
|
|
29
|
+
|
|
30
|
+
- Spec: `specs/dev-infrastructure/tunnel-failure-resilience.md` Part 6. Side-effects: `upgrades/side-effects/tunnel-credential-rotation.md`.
|
|
31
|
+
- Tests: `tests/unit/auth-middleware-live-token.test.ts` (5) asserts both sides of the rotation boundary — the old bearer token AND an old HMAC-signed view URL are rejected the instant the live token changes, and a URL signed with the new token works. `tests/unit/tunnel-credential-rotation.test.ts` (6) asserts the lifecycle: relay-active→idle rotates, a non-relay stop does not, a thrown rotator leaves the pending flag set for retry, and a fresh manager restores the flag and rotates on boot-recovery.
|
|
32
|
+
- No regression: 75 auth + tunnel tests pass, including the existing string-form auth-middleware suites (the refactor is backward compatible).
|
|
33
|
+
|
|
34
|
+
## Rollback
|
|
35
|
+
|
|
36
|
+
The middleware change is backward compatible (it still accepts a plain string). Revert = restore the string argument at the AgentServer auth callsite, drop the manager rotation methods and the `stop()` trigger, and remove the server.ts rotator closure + boot-recovery call. No config schema or persistent-state migration — a rotated PIN/token is just a new value.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Side-effects review — Telegram default-framework fix (codex agents)
|
|
2
|
+
|
|
3
|
+
**Scope**: Follow-on to framework-spawn-portability (v1.2.31). The
|
|
4
|
+
original fix corrected the fresh-spawn path
|
|
5
|
+
(`spawnInteractiveSession`'s internal framework resolution) but missed
|
|
6
|
+
the Telegram message path (`spawnSessionForTopic` →
|
|
7
|
+
`resolveTopicFramework` → `_defaultFramework`). `_defaultFramework` was
|
|
8
|
+
sourced from `frameworkFromEnv()` only, so a codex-cli-only agent
|
|
9
|
+
without the `INSTAR_FRAMEWORK` env var defaulted to claude-code and
|
|
10
|
+
spawned Claude on every Telegram message — and because the Telegram
|
|
11
|
+
path passes its framework as the per-call `options.framework`
|
|
12
|
+
(highest precedence), it overrode the correct `config.framework`.
|
|
13
|
+
Governed by the existing converged + approved spec
|
|
14
|
+
`specs/dev-infrastructure/framework-spawn-portability.md`.
|
|
15
|
+
|
|
16
|
+
**Files touched**:
|
|
17
|
+
- `src/commands/server.ts` — one line in `startServer`:
|
|
18
|
+
`const framework = frameworkFromEnv() ?? 'claude-code';`
|
|
19
|
+
→
|
|
20
|
+
`const framework = config.sessions?.framework ?? frameworkFromEnv() ?? 'claude-code';`
|
|
21
|
+
plus an explanatory comment. `config.sessions.framework` is the
|
|
22
|
+
resolved runtime framework (`resolveConfiguredFramework` output from
|
|
23
|
+
`Config.load`, line 635), so the Telegram default now matches the
|
|
24
|
+
fresh-spawn path.
|
|
25
|
+
- `tests/unit/framework-spawn-portability.test.ts` — 2 new source-grep
|
|
26
|
+
assertions (derivation reads `config.sessions?.framework`; the
|
|
27
|
+
env-only derivation is gone).
|
|
28
|
+
|
|
29
|
+
**Under-block**: None. The change makes a previously-ignored config
|
|
30
|
+
field authoritative for the Telegram default. There is no path where a
|
|
31
|
+
framework that *should* spawn is now suppressed: per-topic overrides
|
|
32
|
+
(`_topicFrameworksStore` / `_topicFrameworks`) still win over the
|
|
33
|
+
default (they're checked first in `resolveTopicFramework`), and the
|
|
34
|
+
`INSTAR_FRAMEWORK` env still applies as a fallback when
|
|
35
|
+
`config.sessions.framework` is somehow unset.
|
|
36
|
+
|
|
37
|
+
**Over-block**: None. A claude-code agent (config.sessions.framework =
|
|
38
|
+
'claude-code') still resolves to claude-code. A codex-cli agent now
|
|
39
|
+
correctly resolves to codex-cli instead of silently falling back to
|
|
40
|
+
claude-code. The only behavior change is the bug being fixed.
|
|
41
|
+
|
|
42
|
+
**Level-of-abstraction fit**: The Telegram default now reads the same
|
|
43
|
+
single resolved value (`config.sessions.framework`) that the
|
|
44
|
+
SessionManager's internal resolution reads. One source of truth, both
|
|
45
|
+
spawn paths. `resolveTopicFramework`'s precedence (per-topic store >
|
|
46
|
+
per-topic config map > default) is unchanged — only the *default's*
|
|
47
|
+
source is corrected.
|
|
48
|
+
|
|
49
|
+
**Signal vs authority**: Compliant. `config.sessions.framework`,
|
|
50
|
+
`INSTAR_FRAMEWORK`, and per-topic overrides are all SIGNALS;
|
|
51
|
+
`resolveConfiguredFramework` (in Config.load) is the single AUTHORITY
|
|
52
|
+
that resolves the agent-level framework, and `resolveTopicFramework`
|
|
53
|
+
layers per-topic overrides on top. No new authority introduced.
|
|
54
|
+
|
|
55
|
+
**Interactions**:
|
|
56
|
+
- `resolveTopicFramework` callers (the Telegram spawn path) now get the
|
|
57
|
+
correct default. The per-topic `/route` override path is unaffected
|
|
58
|
+
(it sets `_topicFrameworksStore`, checked before the default).
|
|
59
|
+
- `spawnSessionForTopic` passes `framework` as `options.framework` to
|
|
60
|
+
`spawnInteractiveSession`. With the fix, that value is now correct
|
|
61
|
+
for codex-cli agents, so the per-call override and the internal
|
|
62
|
+
`config.framework` resolution agree (no conflict).
|
|
63
|
+
- `resolvedFramework` (used a few lines later to pick the
|
|
64
|
+
IntelligenceProvider for relationships/shared intelligence) now also
|
|
65
|
+
reflects the configured framework — correct: a codex-cli agent's
|
|
66
|
+
shared intelligence provider should match its framework.
|
|
67
|
+
|
|
68
|
+
**External surfaces**: None. No new API endpoint, no new config field
|
|
69
|
+
(the `INSTAR_FRAMEWORK` env and `enabledFrameworks` config already
|
|
70
|
+
existed), no CLI change.
|
|
71
|
+
|
|
72
|
+
**Migration parity**: No agent-installed file change. The fix is a
|
|
73
|
+
server-startup derivation; deployed codex-cli agents get correct
|
|
74
|
+
behavior on their next update + clean restart. IMPORTANT operational
|
|
75
|
+
note (documented in NEXT.md): an agent running an older server process
|
|
76
|
+
keeps the stale `_defaultFramework` in memory until restarted, even
|
|
77
|
+
after its files update. This is the version-skew pattern — "updated"
|
|
78
|
+
≠ "running the update". The codey incident that surfaced this bug was
|
|
79
|
+
partly this: the fix-bearing files were present but a long-running
|
|
80
|
+
process still served the old default.
|
|
81
|
+
|
|
82
|
+
**Rollback cost**: Trivial. Revert one line in server.ts + the 2 test
|
|
83
|
+
assertions.
|
|
84
|
+
|
|
85
|
+
**Tests**:
|
|
86
|
+
- 12/12 `framework-spawn-portability.test.ts` (10 existing + 2 new).
|
|
87
|
+
- `tsc --noEmit` clean. `npm run lint` clean.
|
|
88
|
+
- Empirical end-to-end confirmation (live codex-cli agent spawns
|
|
89
|
+
`codex --model gpt-5.3-codex` on a Telegram message, not `claude`)
|
|
90
|
+
is performed during rollout per the bug-fix evidence bar.
|
|
91
|
+
|
|
92
|
+
**Decision-point inventory**:
|
|
93
|
+
1. Derive `_defaultFramework` from `config.sessions.framework` (vs.
|
|
94
|
+
adding yet another env read or a new config field) — reuses the
|
|
95
|
+
single resolved value the rest of the system already trusts. No new
|
|
96
|
+
knob.
|
|
97
|
+
2. Keep `frameworkFromEnv()` + `'claude-code'` as fallbacks (vs.
|
|
98
|
+
removing them) — defense-in-depth: if `config.sessions.framework`
|
|
99
|
+
is ever unset (older Config.load, or a hand-edited config), the env
|
|
100
|
+
var and historical default still apply. The fix only re-orders
|
|
101
|
+
precedence to put the resolved config value first.
|
|
102
|
+
3. Regression test via source-grep (vs. spinning up a full server) —
|
|
103
|
+
`_defaultFramework` is module-private state set inside the large
|
|
104
|
+
`startServer`; a source-grep assertion that the derivation reads
|
|
105
|
+
`config.sessions?.framework` is the proportionate guard, matching
|
|
106
|
+
the existing framework-spawn-portability spawn-path assertions.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Side-effects review — credential rotation (PR 7 of tunnel-failure-resilience chain)
|
|
2
|
+
|
|
3
|
+
**Scope (PR 7 of the chain):** Make `authToken` + `dashboardPin`
|
|
4
|
+
rotation real on every terminal exit from `relay-active`, plus
|
|
5
|
+
boot-recovery. The `rotationPending` flag (set on relay-active entry in
|
|
6
|
+
PR 5, persisted to `tunnel.json`) is now consumed: rotating the
|
|
7
|
+
authToken invalidates every previously-signed view URL and the dashboard
|
|
8
|
+
session — the documented UX cost of having briefly routed private
|
|
9
|
+
traffic through a third-party relay. Spec Part 6.
|
|
10
|
+
|
|
11
|
+
**Files touched:**
|
|
12
|
+
- `src/server/middleware.ts` — `authMiddleware` accepts `string | (() =>
|
|
13
|
+
string | undefined)` and resolves the token **per request**, so a
|
|
14
|
+
runtime rotation takes effect immediately (no restart). Backward
|
|
15
|
+
compatible: the string form is byte-identical to before.
|
|
16
|
+
- `src/server/AgentServer.ts` — wires the live getter
|
|
17
|
+
`authMiddleware(() => this.config.authToken, …)`. `this.config` is set
|
|
18
|
+
in the constructor and never reassigned, so the getter always reads the
|
|
19
|
+
shared, mutable config object.
|
|
20
|
+
- `src/tunnel/TunnelManager.ts` — `setCredentialRotator(fn)`,
|
|
21
|
+
`runCredentialRotation(reason)` (gated on `rotationPending`,
|
|
22
|
+
clears-only-after-success), `recoverPendingRotation()` (boot path), and
|
|
23
|
+
a rotation trigger at the end of `stop()`.
|
|
24
|
+
- `src/commands/server.ts` — the rotator closure (regen PIN + authToken →
|
|
25
|
+
`liveConfig.set` + mutate the in-memory `config` → owner DM with the new
|
|
26
|
+
PIN), wired right after tunnel construction; boot-recovery awaited
|
|
27
|
+
**before** `server.start()`.
|
|
28
|
+
- Tests: `tests/unit/tunnel-credential-rotation.test.ts` (6),
|
|
29
|
+
`tests/unit/auth-middleware-live-token.test.ts` (5).
|
|
30
|
+
|
|
31
|
+
**Over-block:** None. The middleware resolves `string → itself`, so all
|
|
32
|
+
existing string callers and the 75 auth/tunnel tests are unchanged.
|
|
33
|
+
|
|
34
|
+
**Under-block:** The getter returning `undefined` means "open" (the
|
|
35
|
+
documented test/dev passthrough), same as the old `authToken === undefined`
|
|
36
|
+
behavior. In production `authToken` is always set (init generates it;
|
|
37
|
+
rotation always assigns a fresh non-empty UUID). The rotator does
|
|
38
|
+
`config.authToken = newToken` as a single synchronous assignment after
|
|
39
|
+
the `liveConfig.set` calls — there is no window where the live token is
|
|
40
|
+
`undefined`; a concurrent in-flight request reads either the old or the
|
|
41
|
+
new token, never empty. The instant the assignment lands, the old bearer
|
|
42
|
+
token and old signed URLs are rejected (asserted by the rotation tests).
|
|
43
|
+
|
|
44
|
+
**Level-of-abstraction fit:** The manager owns the WHEN (lifecycle
|
|
45
|
+
triggers + the `rotationPending` invariant); the injected closure owns
|
|
46
|
+
the WHAT (regenerate/persist/notify). The manager never imports config or
|
|
47
|
+
messaging. Mirrors the PR 6 `attachTelegram` seam.
|
|
48
|
+
|
|
49
|
+
**Signal vs authority:** `rotationPending` is the single-writer
|
|
50
|
+
authoritative marker owned by `TunnelLifecycle`. `runCredentialRotation`
|
|
51
|
+
clears it **only after** the rotator resolves; a thrown rotator leaves it
|
|
52
|
+
set so the next `stop()` or next boot retries (tested). No abstraction
|
|
53
|
+
treats a low-context signal as authority.
|
|
54
|
+
|
|
55
|
+
**Interactions:**
|
|
56
|
+
- Boot-recovery runs before `server.start()` (verified ordering:
|
|
57
|
+
rotator wired at tunnel-construction ~L4846 → boot-recovery at L7305 →
|
|
58
|
+
listen inside `server.start()`). The owner DM uses `sendToOwnerDM`
|
|
59
|
+
(private chat), so it does not depend on the Dashboard topic being
|
|
60
|
+
ensured yet.
|
|
61
|
+
- The startup `dashboardPin` auto-gen (`if (!config.dashboardPin)`) runs
|
|
62
|
+
after boot-recovery, so a boot-recovery rotation is not clobbered.
|
|
63
|
+
- `signViewPath` (routes.ts) and `verifyViewSignature` (middleware) both
|
|
64
|
+
read the live token, so post-rotation: new view URLs are signed with
|
|
65
|
+
the new token and old shared URLs fail verification — the intended
|
|
66
|
+
invalidation (tested).
|
|
67
|
+
- The 6-digit PIN keeps the existing `Math.random` generator (a
|
|
68
|
+
convenience factor, not the primary secret); `authToken` is
|
|
69
|
+
`randomUUID()` and is the HMAC key. No change to the secret model.
|
|
70
|
+
|
|
71
|
+
**Migration parity:** No agent-installed files change. The rotation is
|
|
72
|
+
runtime behavior in `server.ts` (every agent runs the new server after
|
|
73
|
+
update) and an internal middleware refactor; no new config field, no
|
|
74
|
+
CLAUDE.md/hook change (those land in PR 9). `rotationPending` already
|
|
75
|
+
existed in the persisted schema since PR 5.
|
|
76
|
+
|
|
77
|
+
**Tier-2/Tier-3 note:** PR 7 adds no HTTP route — per spec Part 8 the
|
|
78
|
+
HTTP-assertable "feature is alive" surface is the `/tunnel` route in
|
|
79
|
+
PR 9. PR 7's security guarantee is covered by the live-token middleware
|
|
80
|
+
unit tests (both sides of the boundary + view-URL invalidation) and the
|
|
81
|
+
manager rotation-lifecycle tests; the boot-recovery wiring is verified at
|
|
82
|
+
the `server.ts` call site.
|
|
83
|
+
|
|
84
|
+
**Rollback cost:** Low. The middleware change is backward compatible;
|
|
85
|
+
revert = restore the string arg at the AgentServer callsite, drop the
|
|
86
|
+
manager rotation methods + `stop()` trigger, and remove the server.ts
|
|
87
|
+
rotator closure + boot-recovery call. No schema or persistent-state
|
|
88
|
+
migration (rotated PIN/token are just new values).
|