clementine-agent 1.18.151 → 1.18.153

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();
@@ -39458,9 +39485,15 @@ async function runWorkflow(name) {
39458
39485
  // the list so the migrated workflow disappears (its .md is renamed to
39459
39486
  // .md.migrated server-side and parseAllWorkflows stops picking it up).
39460
39487
  async function migrateWorkflowToSkill(name) {
39461
- if (!confirm('Migrate "' + name + '" into a skill folder?\n\n' +
39462
- '• A new skill will be created at vault/00-System/skills/<slug>/SKILL.md\n' +
39463
- '• The original workflow .md will be renamed to .md.migrated (kept for rollback)\n' +
39488
+ // 1.18.153 escape \\n through the outer template literal. Without the
39489
+ // double-backslash the served HTML gets literal newlines INSIDE a single-
39490
+ // quoted JS string, which the browser parser rejects as
39491
+ // "Uncaught SyntaxError: Invalid or unexpected token". That kills the
39492
+ // entire inline script block, so no API calls fire, no data renders,
39493
+ // dashboard appears completely broken even though the server is healthy.
39494
+ if (!confirm('Migrate "' + name + '" into a skill folder?\\n\\n' +
39495
+ '• A new skill will be created at vault/00-System/skills/<slug>/SKILL.md\\n' +
39496
+ '• The original workflow .md will be renamed to .md.migrated (kept for rollback)\\n' +
39464
39497
  '• The workflow stops firing; the skill is ready to schedule from the Skills tab')) return;
39465
39498
  try {
39466
39499
  var r = await apiFetch('/api/workflows/' + encodeURIComponent(name) + '/migrate-to-skill', {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.18.151",
3
+ "version": "1.18.153",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",