pi-sync-system-theme 0.2.3 → 0.2.5
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 +1 -0
- package/index.ts +26 -25
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -118,6 +118,7 @@ export PI_SYSTEM_THEME_OSC11_ENABLED=0
|
|
|
118
118
|
- **SSH:** Works transparently — no special setup required
|
|
119
119
|
- **tmux:** Supported (including long-lived sessions where `SSH_*` env vars may be missing)
|
|
120
120
|
- **Ghostty `theme = auto`:** Fully supported. When Ghostty switches colors, the next poll detects it.
|
|
121
|
+
- **Session resume:** On `/resume`, the extension immediately re-checks appearance and reconciles the active theme.
|
|
121
122
|
|
|
122
123
|
## Migrating from pi-system-theme
|
|
123
124
|
|
package/index.ts
CHANGED
|
@@ -61,7 +61,7 @@ const DEFAULT_CONFIG: Config = {
|
|
|
61
61
|
const GLOBAL_CONFIG_PATH = path.join(os.homedir(), ".pi", "agent", "system-theme.json");
|
|
62
62
|
const DETECTION_TIMEOUT_MS = 1200;
|
|
63
63
|
const MIN_POLL_MS = 1000;
|
|
64
|
-
const OSC11_QUERY_TIMEOUT_MS =
|
|
64
|
+
const OSC11_QUERY_TIMEOUT_MS = 3200;
|
|
65
65
|
const OSC11_MIN_INTERVAL_MS = 15_000;
|
|
66
66
|
const OSC11_DISABLE_AFTER_FAILURES = 3;
|
|
67
67
|
const OSC11_DISABLE_COOLDOWN_MS = 60_000;
|
|
@@ -211,35 +211,23 @@ const OSC11_QUERY_SCRIPT = `
|
|
|
211
211
|
'use strict';
|
|
212
212
|
const fs = require('fs');
|
|
213
213
|
|
|
214
|
-
const O_NONBLOCK = fs.constants.O_NONBLOCK ?? 0;
|
|
215
214
|
let fd;
|
|
216
|
-
try { fd = fs.openSync('/dev/tty', fs.constants.O_RDWR | fs.constants.O_NOCTTY
|
|
215
|
+
try { fd = fs.openSync('/dev/tty', fs.constants.O_RDWR | fs.constants.O_NOCTTY); }
|
|
217
216
|
catch { process.exit(1); }
|
|
218
217
|
|
|
219
|
-
// Send OSC 11 query
|
|
220
|
-
try {
|
|
221
|
-
fs.writeSync(fd, '\x1b]11;?\x1b\\');
|
|
222
|
-
fs.writeSync(fd, '\x1b]11;?\x07');
|
|
223
|
-
}
|
|
218
|
+
// Send OSC 11 query (ST terminator)
|
|
219
|
+
try { fs.writeSync(fd, '\x1b]11;?\x1b\\'); }
|
|
224
220
|
catch { try { fs.closeSync(fd); } catch {} process.exit(1); }
|
|
225
221
|
|
|
226
222
|
const buf = Buffer.alloc(1024);
|
|
227
223
|
let response = '';
|
|
228
|
-
const deadline = Date.now() +
|
|
224
|
+
const deadline = Date.now() + 2500;
|
|
229
225
|
|
|
230
226
|
function tryRead() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
response += buf.toString('utf8', 0, n);
|
|
236
|
-
if (response.length > 8192) response = response.slice(-4096);
|
|
237
|
-
} catch (err) {
|
|
238
|
-
const code = err && err.code;
|
|
239
|
-
if (code === 'EAGAIN' || code === 'EWOULDBLOCK') return;
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
227
|
+
try {
|
|
228
|
+
const n = fs.readSync(fd, buf, 0, buf.length);
|
|
229
|
+
if (n > 0) response += buf.toString('utf8', 0, n);
|
|
230
|
+
} catch {}
|
|
243
231
|
}
|
|
244
232
|
|
|
245
233
|
function to8Bit(hex) {
|
|
@@ -251,7 +239,6 @@ function to8Bit(hex) {
|
|
|
251
239
|
|
|
252
240
|
function done() {
|
|
253
241
|
try { fs.closeSync(fd); } catch {}
|
|
254
|
-
// Keep parser permissive: tmux may wrap control sequences, but rgb payload remains stable.
|
|
255
242
|
const m = response.match(/rgb:([0-9a-fA-F]{2,8})\\/([0-9a-fA-F]{2,8})\\/([0-9a-fA-F]{2,8})/);
|
|
256
243
|
if (m) {
|
|
257
244
|
const r = to8Bit(m[1]);
|
|
@@ -266,7 +253,7 @@ function done() {
|
|
|
266
253
|
function poll() {
|
|
267
254
|
tryRead();
|
|
268
255
|
if (response.includes('rgb:') || Date.now() > deadline) return done();
|
|
269
|
-
setTimeout(poll,
|
|
256
|
+
setTimeout(poll, 20);
|
|
270
257
|
}
|
|
271
258
|
|
|
272
259
|
poll();
|
|
@@ -640,20 +627,34 @@ export default function systemThemeBridge(pi: ExtensionAPI): void {
|
|
|
640
627
|
|
|
641
628
|
// -- Lifecycle ------------------------------------------------------------
|
|
642
629
|
|
|
643
|
-
|
|
644
|
-
config = await loadConfig();
|
|
630
|
+
function resetOsc11State(): void {
|
|
645
631
|
osc11State.lastCheckedAt = 0;
|
|
646
632
|
osc11State.lastAppearance = null;
|
|
647
633
|
osc11State.failures = 0;
|
|
648
634
|
osc11State.disabledUntil = 0;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
async function applyOnSessionEnter(ctx: ExtensionContext): Promise<void> {
|
|
638
|
+
config = await loadConfig();
|
|
639
|
+
resetOsc11State();
|
|
649
640
|
|
|
650
641
|
if (!shouldAutoSync(ctx)) {
|
|
651
642
|
maybeWarnCustomTheme(ctx);
|
|
652
643
|
return;
|
|
653
644
|
}
|
|
654
645
|
|
|
646
|
+
// Force immediate theme reconciliation when entering a session
|
|
647
|
+
// (especially important after /resume from a differently-themed session).
|
|
655
648
|
await tick(ctx);
|
|
656
649
|
restartPolling(ctx);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
653
|
+
await applyOnSessionEnter(ctx);
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
pi.on("session_switch", async (_event, ctx) => {
|
|
657
|
+
await applyOnSessionEnter(ctx);
|
|
657
658
|
});
|
|
658
659
|
|
|
659
660
|
pi.on("session_shutdown", () => {
|