ccdeck 3.29.1 → 3.29.3
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/web/assets/{BrowserWatchModal-C-TkzDPi.js → BrowserWatchModal-RXK8WXaU.js} +1 -1
- package/dist/web/assets/{UsageHistoryModal-FKBbTozZ.js → UsageHistoryModal-Dk5zag6g.js} +1 -1
- package/dist/web/assets/{index-7mOqoJ3Y.js → index-C7djiYSc.js} +7 -7
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/release-notes.json +2 -1
- package/src/server/deck-prefs.mjs +18 -0
- package/src/server/index.mjs +12 -2
package/dist/web/index.html
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
stored === "light" || (stored !== "dark" && light) ? "light" : "dark");
|
|
63
63
|
})();
|
|
64
64
|
</script>
|
|
65
|
-
<script type="module" crossorigin src="/assets/index-
|
|
65
|
+
<script type="module" crossorigin src="/assets/index-C7djiYSc.js"></script>
|
|
66
66
|
<link rel="stylesheet" crossorigin href="/assets/index-FeNTTJ0x.css">
|
|
67
67
|
</head>
|
|
68
68
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ccdeck",
|
|
3
|
-
"version": "3.29.
|
|
3
|
+
"version": "3.29.3",
|
|
4
4
|
"description": "Live dashboard for Claude Code and Codex — which agent is waiting on you, tool calls, token spend and every Claude Code subagent on one calm canvas. Run it with npx ccdeck.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/release-notes.json
CHANGED
|
@@ -285,6 +285,24 @@ function unreadablePrefs(path, why) {
|
|
|
285
285
|
return err;
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
/** The errors a filesystem raises for a place this user may not write — most
|
|
289
|
+
* often a settings folder a `sudo` run left owned by root (#1335). */
|
|
290
|
+
const NOT_WRITABLE = new Set(["EACCES", "EPERM", "EROFS"]);
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Why a settings write failed, as a reason the panel can name — or null when
|
|
294
|
+
* the failure is not one of the two a person can fix from outside the deck.
|
|
295
|
+
*
|
|
296
|
+
* A code, never the message: the message carries the absolute path, and a
|
|
297
|
+
* route's body is readable by a DNS-rebound page (see sendInternalError). The
|
|
298
|
+
* deck's log keeps the path for the person who has to go and look.
|
|
299
|
+
*/
|
|
300
|
+
export function prefsWriteRefusal(err) {
|
|
301
|
+
if (err?.code === "PREFS_UNREADABLE") return "prefs_unreadable";
|
|
302
|
+
if (NOT_WRITABLE.has(err?.code)) return "prefs_not_writable";
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
288
306
|
/**
|
|
289
307
|
* Read prefs.json, and say WHICH of four things happened — because three of
|
|
290
308
|
* them hand back the same object and only one of them means it.
|
package/src/server/index.mjs
CHANGED
|
@@ -37,7 +37,7 @@ import { createOutputWatch } from "./output-watch.mjs";
|
|
|
37
37
|
import { RECAP_MARK, foldRecapLine } from "./session-recap.mjs";
|
|
38
38
|
import { AWAY_BOOT_GRACE_MS, AWAY_RECHECK_MS, AWAY_TICK_MS, awayGate, awayUpdateStep } from "./auto-update.mjs";
|
|
39
39
|
import { createPresence } from "./presence.mjs";
|
|
40
|
-
import { DEFAULTS as PREF_DEFAULTS, cleanAlias, isAliasKey, lanEnabled, notificationsOn, notificationsVetoed, publicPrefs, readPrefs, updatePrefs, withAlias, withManualEntry, withShared, writePrefs } from "./deck-prefs.mjs";
|
|
40
|
+
import { DEFAULTS as PREF_DEFAULTS, cleanAlias, isAliasKey, lanEnabled, notificationsOn, notificationsVetoed, prefsWriteRefusal, publicPrefs, readPrefs, updatePrefs, withAlias, withManualEntry, withShared, writePrefs } from "./deck-prefs.mjs";
|
|
41
41
|
import { createEngine, defaultName } from "./lan-engine.mjs";
|
|
42
42
|
import { createTailnet, IDLE_MS as TAILNET_IDLE_MS } from "./tailscale.mjs";
|
|
43
43
|
import { portHolder } from "./port-holder.mjs";
|
|
@@ -3821,7 +3821,17 @@ async function handlePrefsWrite(req, res) {
|
|
|
3821
3821
|
let body = null;
|
|
3822
3822
|
try { body = JSON.parse(raw ?? ""); } catch { /* handled below */ }
|
|
3823
3823
|
if (!body || typeof body !== "object") return send(res, 400, { ok: false, reason: "bad_request" });
|
|
3824
|
-
|
|
3824
|
+
try {
|
|
3825
|
+
_prefs = await writePrefs(body);
|
|
3826
|
+
} catch (err) {
|
|
3827
|
+
// A settings file or folder this user cannot reach is the machine's to fix,
|
|
3828
|
+
// not the deck's, and `guard`'s bare 500 left the panel with nothing to say
|
|
3829
|
+
// about it (#1335). Anything else is still a bug and still goes to `guard`.
|
|
3830
|
+
const reason = prefsWriteRefusal(err);
|
|
3831
|
+
if (!reason) throw err;
|
|
3832
|
+
console.error(`${PRODUCT}: settings were not saved:`, err?.message ?? err);
|
|
3833
|
+
return send(res, 500, { ok: false, reason });
|
|
3834
|
+
}
|
|
3825
3835
|
// The engine reads its settings from here rather than holding its own copy,
|
|
3826
3836
|
// so turning the switch off in the panel really does stop the sockets rather
|
|
3827
3837
|
// than only changing what the panel says.
|