pi-sdk-web 0.2.0 → 0.2.1

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 CHANGED
@@ -215,6 +215,11 @@ export class PiWebServer {
215
215
  // Initial state (state + history), mirroring the Python bridge
216
216
  this.sendJson(ws, { type: "state", data: this.buildState() });
217
217
  this.sendJson(ws, { type: "history", data: this.buildHistory() });
218
+ // Current extension statuses (setStatus may have fired before this client connected)
219
+ const extStatus = this.uiContext.getStatusSnapshot();
220
+ if (Object.keys(extStatus).length > 0) {
221
+ this.sendJson(ws, { type: "ext_status", data: extStatus });
222
+ }
218
223
  }
219
224
  sendJson(ws, obj) {
220
225
  if (ws.readyState === WebSocket.OPEN) {
@@ -36,6 +36,7 @@ class PiWebClient {
36
36
  this.modalMode = null; // 'model' | 'thinking'
37
37
  this.hasConnectedBefore = false;
38
38
  this.commandMenuIndex = -1;
39
+ this.extStatus = {};
39
40
 
40
41
  this.initThemeSwitch();
41
42
 
@@ -169,6 +170,9 @@ class PiWebClient {
169
170
  case 'pi_error':
170
171
  this.appendError(data.error);
171
172
  break;
173
+ case 'ext_status':
174
+ this.applyExtStatusSnapshot(data.data);
175
+ break;
172
176
  case 'extension_ui_request':
173
177
  this.handleExtensionUIRequest(data);
174
178
  break;
@@ -1350,8 +1354,36 @@ class PiWebClient {
1350
1354
  } else if (method === 'setWidget') {
1351
1355
  // Persistent widget panel (TUI: above/below editor). Not a popup.
1352
1356
  this.renderWidget(req);
1357
+ } else if (method === 'setStatus') {
1358
+ // Extension status text (e.g. magic-context "mc: 29.3K (4%) · idle")
1359
+ this.renderStatusItem(req);
1360
+ }
1361
+ // setTitle / set_editor_text are handled elsewhere or ignored
1362
+ }
1363
+
1364
+ renderStatusItem(req) {
1365
+ const el = document.getElementById('ext-status');
1366
+ if (!el) return;
1367
+ if (req.statusText === undefined || req.statusText === null) {
1368
+ delete this.extStatus[req.statusKey];
1369
+ } else {
1370
+ this.extStatus[req.statusKey] = req.statusText;
1353
1371
  }
1354
- // setStatus / setTitle / set_editor_text are handled elsewhere or ignored
1372
+ this.updateExtStatusDisplay();
1373
+ }
1374
+
1375
+ applyExtStatusSnapshot(snapshot) {
1376
+ if (!snapshot) return;
1377
+ this.extStatus = Object.assign({}, snapshot);
1378
+ this.updateExtStatusDisplay();
1379
+ }
1380
+
1381
+ updateExtStatusDisplay() {
1382
+ const el = document.getElementById('ext-status');
1383
+ if (!el) return;
1384
+ const entries = Object.entries(this.extStatus);
1385
+ el.textContent = entries.map(([k, v]) => `${k}: ${v}`).join(' · ');
1386
+ el.style.display = entries.length ? 'block' : 'none';
1355
1387
  }
1356
1388
 
1357
1389
  openExtensionSelect(req) {
@@ -35,6 +35,7 @@
35
35
  <div id="status"></div>
36
36
  <div id="footer">
37
37
  <div id="footer-line"></div>
38
+ <div id="ext-status" style="display:none"></div>
38
39
  <div id="footer-stats"></div>
39
40
  <div id="command-menu"></div>
40
41
  <div class="input-row">
@@ -599,6 +599,12 @@ body {
599
599
  margin-bottom: 4px;
600
600
  }
601
601
 
602
+ #ext-status {
603
+ color: var(--dim);
604
+ font-size: 12px;
605
+ margin-bottom: 4px;
606
+ }
607
+
602
608
  #footer-stats {
603
609
  display: flex;
604
610
  justify-content: space-between;
@@ -21,9 +21,15 @@ export class WebUIContext {
21
21
  pending = new Map();
22
22
  sink;
23
23
  identityTheme = createIdentityTheme();
24
+ /** Latest setStatus values per key, so late-connecting browsers get current state */
25
+ statusMap = new Map();
24
26
  constructor(sink) {
25
27
  this.sink = sink;
26
28
  }
29
+ /** Current extension status snapshot (key -> text) for new connections. */
30
+ getStatusSnapshot() {
31
+ return Object.fromEntries(this.statusMap);
32
+ }
27
33
  /** Handle a browser `extension_ui_response` message. */
28
34
  respond(id, response) {
29
35
  const pending = this.pending.get(id);
@@ -82,6 +88,12 @@ export class WebUIContext {
82
88
  this.sink({ type: "extension_ui_request", id: crypto.randomUUID(), method: "notify", message, notifyType: type });
83
89
  }
84
90
  setStatus(key, text) {
91
+ if (text === undefined || text === null) {
92
+ this.statusMap.delete(key);
93
+ }
94
+ else {
95
+ this.statusMap.set(key, text);
96
+ }
85
97
  this.sink({ type: "extension_ui_request", id: crypto.randomUUID(), method: "setStatus", statusKey: key, statusText: text });
86
98
  }
87
99
  setTitle(title) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-sdk-web",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Browser Web access for Pi (AI coding agent) via the Pi SDK - standalone module, zero modification to Pi itself",
5
5
  "type": "module",
6
6
  "bin": {