clementine-agent 1.18.151 → 1.18.152

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.
@@ -2047,9 +2047,36 @@ export async function cmdDashboard(opts) {
2047
2047
  jsonParser(req, res, next);
2048
2048
  });
2049
2049
  // ── Dashboard authentication ────────────────────────────────────────
2050
- const dashboardToken = randomBytes(24).toString('hex');
2050
+ // 1.18.152 persist the token across restarts. Before this, every
2051
+ // dashboard startup (manual restart, auto-respawn, crash recovery)
2052
+ // generated a fresh random token, which invalidated every browser
2053
+ // bookmark, open tab, and printed URL. Auto-respawn (1.18.146) +
2054
+ // auto-open browser (1.18.147) made this acutely visible — users
2055
+ // would re-open the dashboard and find the URL they had bookmarked
2056
+ // 401'd, then a new browser window would open with a different token,
2057
+ // and any hook commands installed in projects would silently 401 too.
2058
+ //
2059
+ // Fix: read the existing token if `~/.clementine/.dashboard-token`
2060
+ // already exists; only generate-and-persist on first-ever startup.
2061
+ // To rotate tokens deliberately, the user deletes the file and
2062
+ // restarts. Local-machine threat model assumes the home dir is
2063
+ // trusted (see feedback_security_model.md) — a persistent token here
2064
+ // is the same security posture as `~/.ssh/id_rsa`.
2051
2065
  const tokenPath = path.join(BASE_DIR, '.dashboard-token');
2052
- writeFileSync(tokenPath, dashboardToken, { mode: 0o600 });
2066
+ let dashboardToken;
2067
+ try {
2068
+ const existing = readFileSync(tokenPath, 'utf-8').trim();
2069
+ // Strict format check — anything that doesn't look like a 48-hex-char
2070
+ // token (the format randomBytes(24).toString('hex') produces) gets
2071
+ // regenerated. Defends against truncated / corrupt files.
2072
+ if (!/^[a-f0-9]{48}$/.test(existing))
2073
+ throw new Error('invalid token format on disk');
2074
+ dashboardToken = existing;
2075
+ }
2076
+ catch {
2077
+ dashboardToken = randomBytes(24).toString('hex');
2078
+ writeFileSync(tokenPath, dashboardToken, { mode: 0o600 });
2079
+ }
2053
2080
  // ── Remote access + session management ─────────────────────────────
2054
2081
  const remoteConfig = loadRemoteConfig();
2055
2082
  const sessions = new Map();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.151",
3
+ "version": "1.18.152",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",