pi-sdk-web 0.3.12 → 0.3.13
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/server.js +10 -0
- package/dist/static/app.js +31 -8
- package/dist/static/index.html +1 -1
- package/dist/static/style.css +2 -2
- package/dist/ui-context.js +18 -14
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -418,6 +418,16 @@ export class PiWebServer {
|
|
|
418
418
|
// Used by the sidebar Tools refresh button
|
|
419
419
|
this.broadcastState();
|
|
420
420
|
break;
|
|
421
|
+
case "set_theme": {
|
|
422
|
+
// Browser theme switch (dark/light): swap the extension ANSI theme.
|
|
423
|
+
// CSS switches instantly on the client; the server theme only
|
|
424
|
+
// affects extension setStatus/setWidget generated after this point
|
|
425
|
+
// (same as TUI - status text is fixed at setStatus time).
|
|
426
|
+
const name = data.name === "light" ? "light" : "dark";
|
|
427
|
+
this.uiContext.setWebTheme(name);
|
|
428
|
+
this.broadcast({ type: "theme_set", data: { name } });
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
421
431
|
case "bash": {
|
|
422
432
|
const command = typeof data.command === "string" ? data.command : "";
|
|
423
433
|
if (!command)
|
package/dist/static/app.js
CHANGED
|
@@ -246,6 +246,10 @@ class PiWebClient {
|
|
|
246
246
|
return;
|
|
247
247
|
}
|
|
248
248
|
this.hasConnectedBefore = true;
|
|
249
|
+
// Sync the persisted theme to the server on first connection so
|
|
250
|
+
// extension ANSI colors match the CSS theme (server defaults to dark).
|
|
251
|
+
const stored = localStorage.getItem('piweb-theme') === 'bright' ? 'light' : (localStorage.getItem('piweb-theme') || 'light');
|
|
252
|
+
this.send({ type: 'set_theme', name: stored });
|
|
249
253
|
};
|
|
250
254
|
ws.onmessage = (ev) => this.handleMessage(ev.data);
|
|
251
255
|
ws.onclose = () => {
|
|
@@ -270,20 +274,33 @@ class PiWebClient {
|
|
|
270
274
|
// ------------------------------------------------------------------
|
|
271
275
|
|
|
272
276
|
initThemeSwitch() {
|
|
273
|
-
|
|
274
|
-
|
|
277
|
+
// Migrate the old 'bright' key to 'light' (renamed for TUI parity).
|
|
278
|
+
const stored = localStorage.getItem('piweb-theme') === 'bright' ? 'light' : (localStorage.getItem('piweb-theme') || 'light');
|
|
279
|
+
this.applyTheme(stored, true);
|
|
275
280
|
document.querySelectorAll('.theme-option').forEach((el) => {
|
|
276
|
-
el.addEventListener('click', () => this.applyTheme(el.dataset.theme));
|
|
281
|
+
el.addEventListener('click', () => this.applyTheme(el.dataset.theme, false));
|
|
277
282
|
});
|
|
278
283
|
}
|
|
279
284
|
|
|
280
|
-
applyTheme(theme) {
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
285
|
+
applyTheme(theme, initial) {
|
|
286
|
+
const light = theme === 'light';
|
|
287
|
+
const name = light ? 'light' : 'dark';
|
|
288
|
+
// CSS variables switch instantly (the "interface frame", like TUI's
|
|
289
|
+
// requestRender on theme change).
|
|
290
|
+
document.body.classList.toggle('theme-light', light);
|
|
291
|
+
localStorage.setItem('piweb-theme', name);
|
|
284
292
|
document.querySelectorAll('.theme-option').forEach((el) => {
|
|
285
|
-
el.classList.toggle('active', el.dataset.theme ===
|
|
293
|
+
el.classList.toggle('active', el.dataset.theme === name);
|
|
286
294
|
});
|
|
295
|
+
if (initial) return;
|
|
296
|
+
// Tell the server to swap the extension ANSI theme: extensions that
|
|
297
|
+
// setStatus/setWidget AFTER this point generate colors with the new
|
|
298
|
+
// theme. Already-rendered status text keeps its old colors until the
|
|
299
|
+
// extension updates it (same as TUI - status text is fixed at setStatus
|
|
300
|
+
// time; theme change only repaints the frame).
|
|
301
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
302
|
+
this.send({ type: 'set_theme', name: name });
|
|
303
|
+
}
|
|
287
304
|
}
|
|
288
305
|
|
|
289
306
|
send(obj) {
|
|
@@ -310,6 +327,12 @@ class PiWebClient {
|
|
|
310
327
|
case 'state':
|
|
311
328
|
this.renderState(data.data);
|
|
312
329
|
break;
|
|
330
|
+
case 'theme_set':
|
|
331
|
+
// Server acknowledged the theme switch. No reload needed: CSS
|
|
332
|
+
// variables already switched instantly and the server theme only
|
|
333
|
+
// affects extension setStatus/setWidget generated after this point
|
|
334
|
+
// (same as TUI).
|
|
335
|
+
break;
|
|
313
336
|
case 'history':
|
|
314
337
|
this.renderHistory(data.data);
|
|
315
338
|
break;
|
package/dist/static/index.html
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<span id="theme-switch">
|
|
15
15
|
<span class="theme-option" data-theme="dark">Dark</span>
|
|
16
16
|
<span class="theme-sep">|</span>
|
|
17
|
-
<span class="theme-option" data-theme="
|
|
17
|
+
<span class="theme-option" data-theme="light">Light</span>
|
|
18
18
|
</span>
|
|
19
19
|
<span id="msg-nav">
|
|
20
20
|
<span class="nav-btn" id="nav-prev" title="Jump to previous user message">↑</span>
|
package/dist/static/style.css
CHANGED
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
--table-head-bg: rgba(128, 128, 128, 0.1);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
/*
|
|
32
|
-
body.theme-
|
|
31
|
+
/* Light theme (colors aligned with Pi's light theme) */
|
|
32
|
+
body.theme-light {
|
|
33
33
|
--bg: #f5f5f5;
|
|
34
34
|
--text: #1f2328;
|
|
35
35
|
--dim: #767676;
|
package/dist/ui-context.js
CHANGED
|
@@ -3,23 +3,23 @@ import { readFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Load a Pi theme (dark.json/light.json colors) so extensions calling
|
|
7
|
+
* ui.theme.fg("accent", text) / .bg(...) get REAL ANSI escapes — identical
|
|
8
|
+
* to TUI (interactive-mode.ts returns the same Theme instance from
|
|
9
|
+
* ctx.ui.theme). The browser renders the escapes as colored spans (see
|
|
10
|
+
* app.js ansiToHtml), acting as the "terminal".
|
|
11
11
|
*
|
|
12
|
-
* The Theme class
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* The Theme class is exported by the Pi SDK and the theme JSONs ship in the
|
|
13
|
+
* package dist. Constructing the Theme directly keeps us independent of
|
|
14
|
+
* initTheme's global side effects and gives the same result.
|
|
15
15
|
*/
|
|
16
|
-
function createWebTheme() {
|
|
16
|
+
function createWebTheme(name = "dark") {
|
|
17
17
|
try {
|
|
18
18
|
const mainEntry = fileURLToPath(import.meta.resolve("@earendil-works/pi-coding-agent"));
|
|
19
|
-
const
|
|
19
|
+
const themeJson = JSON.parse(readFileSync(join(dirname(mainEntry), "modes", "interactive", "theme", `${name}.json`), "utf8"));
|
|
20
20
|
const fgColors = {};
|
|
21
21
|
const bgColors = {};
|
|
22
|
-
//
|
|
22
|
+
// theme colors refer to vars by name (e.g. "accent" -> "#8abeb7")
|
|
23
23
|
// or carry a literal hex. Split background keys from foreground keys by
|
|
24
24
|
// the explicit ThemeBg set (mirrors Pi's createTheme in theme.ts) rather
|
|
25
25
|
// than a "Bg" suffix: scrollbarThumb is a ThemeBg without that suffix.
|
|
@@ -33,8 +33,8 @@ function createWebTheme() {
|
|
|
33
33
|
"toolSuccessBg",
|
|
34
34
|
"toolErrorBg",
|
|
35
35
|
]);
|
|
36
|
-
for (const [key, value] of Object.entries(
|
|
37
|
-
const resolved = value.startsWith("#") ? value :
|
|
36
|
+
for (const [key, value] of Object.entries(themeJson.colors)) {
|
|
37
|
+
const resolved = value.startsWith("#") ? value : themeJson.vars[value] ?? value;
|
|
38
38
|
if (bgKeys.has(key)) {
|
|
39
39
|
bgColors[key] = resolved;
|
|
40
40
|
}
|
|
@@ -42,7 +42,7 @@ function createWebTheme() {
|
|
|
42
42
|
fgColors[key] = resolved;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
return new PiTheme(fgColors, bgColors, "truecolor", { name
|
|
45
|
+
return new PiTheme(fgColors, bgColors, "truecolor", { name });
|
|
46
46
|
}
|
|
47
47
|
catch {
|
|
48
48
|
// Last-resort identity: return the text argument unchanged (no ANSI).
|
|
@@ -202,6 +202,10 @@ export class WebUIContext {
|
|
|
202
202
|
setTheme() {
|
|
203
203
|
return { success: false, error: "Theme switching not supported in web mode" };
|
|
204
204
|
}
|
|
205
|
+
/** Switch the theme used for extension ANSI colors (dark/light). */
|
|
206
|
+
setWebTheme(name) {
|
|
207
|
+
this.webTheme = createWebTheme(name);
|
|
208
|
+
}
|
|
205
209
|
// ------------------------------------------------------------------
|
|
206
210
|
// Tool output expansion (web always shows expandable blocks)
|
|
207
211
|
// ------------------------------------------------------------------
|