pi-sdk-web 0.3.4 → 0.3.6
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 +20 -1
- package/dist/static/app.js +33 -1
- package/dist/static/style.css +34 -0
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { execFileSync } from "node:child_process";
|
|
12
12
|
import { existsSync, readFileSync } from "node:fs";
|
|
13
|
-
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { readFile, unlink } from "node:fs/promises";
|
|
14
14
|
import { createServer } from "node:http";
|
|
15
15
|
import { dirname, join, resolve, sep } from "node:path";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
@@ -399,6 +399,10 @@ export class PiWebServer {
|
|
|
399
399
|
case "get_stats":
|
|
400
400
|
this.broadcastStats();
|
|
401
401
|
break;
|
|
402
|
+
case "get_state":
|
|
403
|
+
// Used by the sidebar Tools refresh button
|
|
404
|
+
this.broadcastState();
|
|
405
|
+
break;
|
|
402
406
|
case "bash": {
|
|
403
407
|
const command = typeof data.command === "string" ? data.command : "";
|
|
404
408
|
if (!command)
|
|
@@ -563,6 +567,21 @@ export class PiWebServer {
|
|
|
563
567
|
await this.resumeSession(path);
|
|
564
568
|
break;
|
|
565
569
|
}
|
|
570
|
+
case "delete_session": {
|
|
571
|
+
const path = typeof data.path === "string" && data.path ? data.path : "";
|
|
572
|
+
if (!path)
|
|
573
|
+
throw new Error("Missing 'path'");
|
|
574
|
+
// Safety: only allow deleting known session files (never arbitrary paths)
|
|
575
|
+
const known = (await listSessions()).some((s) => s.path === path);
|
|
576
|
+
if (!known)
|
|
577
|
+
throw new Error("Not a known session file");
|
|
578
|
+
// Align with TUI: cannot delete the currently active session
|
|
579
|
+
if (this.session.sessionFile === path) {
|
|
580
|
+
throw new Error("Cannot delete the currently active session");
|
|
581
|
+
}
|
|
582
|
+
await unlink(path);
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
566
585
|
default:
|
|
567
586
|
throw new Error(`Unsupported command: ${cmdType}`);
|
|
568
587
|
}
|
package/dist/static/app.js
CHANGED
|
@@ -279,6 +279,15 @@ class PiWebClient {
|
|
|
279
279
|
const header = document.createElement('div');
|
|
280
280
|
header.className = 'resources-header';
|
|
281
281
|
header.textContent = 'Tools (click to expand)';
|
|
282
|
+
const refreshBtn = document.createElement('span');
|
|
283
|
+
refreshBtn.className = 'tools-refresh';
|
|
284
|
+
refreshBtn.title = 'Refresh tools list';
|
|
285
|
+
refreshBtn.textContent = '⟳';
|
|
286
|
+
refreshBtn.addEventListener('click', (e) => {
|
|
287
|
+
e.stopPropagation();
|
|
288
|
+
this.send({ type: 'get_state' });
|
|
289
|
+
});
|
|
290
|
+
header.appendChild(refreshBtn);
|
|
282
291
|
|
|
283
292
|
const body = document.createElement('div');
|
|
284
293
|
body.className = 'resources-body';
|
|
@@ -291,7 +300,7 @@ class PiWebClient {
|
|
|
291
300
|
const expanded = div.dataset.expanded === 'true';
|
|
292
301
|
div.dataset.expanded = expanded ? 'false' : 'true';
|
|
293
302
|
body.style.display = expanded ? 'none' : 'block';
|
|
294
|
-
header.textContent = expanded ? 'Tools (click to expand)' : 'Tools (click to collapse)';
|
|
303
|
+
header.firstChild.textContent = expanded ? 'Tools (click to expand)' : 'Tools (click to collapse)';
|
|
295
304
|
});
|
|
296
305
|
this.loadedResourcesEl.appendChild(div);
|
|
297
306
|
}
|
|
@@ -1621,12 +1630,35 @@ class PiWebClient {
|
|
|
1621
1630
|
this.modalList.innerHTML = '<div class="modal-message">No other sessions available</div>';
|
|
1622
1631
|
return;
|
|
1623
1632
|
}
|
|
1633
|
+
this.resumeSessions = sessions;
|
|
1624
1634
|
this.renderModalItems(
|
|
1625
1635
|
sessions.map((s) => ({ name: s.name || s.id, desc: s.cwd, value: s.path })),
|
|
1626
1636
|
(item) => {
|
|
1627
1637
|
this.send({ type: 'resume', path: item.value });
|
|
1628
1638
|
},
|
|
1629
1639
|
);
|
|
1640
|
+
// Add delete buttons to each item (stopPropagation so clicks don't resume)
|
|
1641
|
+
this.modalList.querySelectorAll('.modal-item').forEach((el, i) => {
|
|
1642
|
+
const session = sessions[i];
|
|
1643
|
+
el.classList.add('resume-item');
|
|
1644
|
+
const del = document.createElement('span');
|
|
1645
|
+
del.className = 'resume-delete';
|
|
1646
|
+
del.title = 'Delete this session';
|
|
1647
|
+
del.textContent = '🗑';
|
|
1648
|
+
del.addEventListener('click', (e) => {
|
|
1649
|
+
e.stopPropagation();
|
|
1650
|
+
this.deleteSession(session);
|
|
1651
|
+
});
|
|
1652
|
+
el.appendChild(del);
|
|
1653
|
+
});
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
deleteSession(session) {
|
|
1657
|
+
const label = session.name || session.id;
|
|
1658
|
+
if (!window.confirm(`Delete session "${label}"?\nThis cannot be undone.`)) return;
|
|
1659
|
+
this.send({ type: 'delete_session', path: session.path });
|
|
1660
|
+
// Refresh the list after delete (errors surface via toast/error message)
|
|
1661
|
+
setTimeout(() => this.send({ type: 'get_sessions' }), 300);
|
|
1630
1662
|
}
|
|
1631
1663
|
|
|
1632
1664
|
// ------------------------------------------------------------------
|
package/dist/static/style.css
CHANGED
|
@@ -171,6 +171,17 @@ body {
|
|
|
171
171
|
color: var(--dim);
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
.tools-refresh {
|
|
175
|
+
float: right;
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
color: var(--accent);
|
|
178
|
+
padding: 0 4px;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.tools-refresh:hover {
|
|
182
|
+
text-decoration: underline;
|
|
183
|
+
}
|
|
184
|
+
|
|
174
185
|
.resources-body {
|
|
175
186
|
margin-top: 6px;
|
|
176
187
|
color: var(--muted);
|
|
@@ -699,6 +710,29 @@ body {
|
|
|
699
710
|
font-size: 13px;
|
|
700
711
|
}
|
|
701
712
|
|
|
713
|
+
/* Resume picker items: delete icon pushed to the right, away from the path */
|
|
714
|
+
.modal-item.resume-item {
|
|
715
|
+
display: flex;
|
|
716
|
+
align-items: baseline;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.modal-item.resume-item .resume-delete {
|
|
720
|
+
margin-left: auto;
|
|
721
|
+
padding-left: 16px;
|
|
722
|
+
cursor: pointer;
|
|
723
|
+
opacity: 0.6;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.modal-item.resume-item .resume-delete:hover {
|
|
727
|
+
opacity: 1;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.modal-item.resume-item .modal-item-desc {
|
|
731
|
+
overflow: hidden;
|
|
732
|
+
text-overflow: ellipsis;
|
|
733
|
+
white-space: nowrap;
|
|
734
|
+
}
|
|
735
|
+
|
|
702
736
|
.modal-item:hover {
|
|
703
737
|
background: var(--accent-hover);
|
|
704
738
|
}
|