pi-sdk-web 0.4.5 → 0.4.7
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/static/app.js +49 -4
- package/dist/static/style.css +57 -7
- package/package.json +1 -1
package/dist/static/app.js
CHANGED
|
@@ -786,7 +786,9 @@ class PiWebClient {
|
|
|
786
786
|
body.className = 'special-body body-text';
|
|
787
787
|
div.appendChild(labelEl);
|
|
788
788
|
div.appendChild(body);
|
|
789
|
-
|
|
789
|
+
// Click to expand/collapse, but NOT when the pointer was dragged (see
|
|
790
|
+
// bindExpandToggle - same drag-vs-click logic as tool blocks).
|
|
791
|
+
this.bindExpandToggle(div, (d) => this.toggleSpecial(d));
|
|
790
792
|
this.contentEl.appendChild(div);
|
|
791
793
|
return div;
|
|
792
794
|
}
|
|
@@ -1151,6 +1153,25 @@ class PiWebClient {
|
|
|
1151
1153
|
}
|
|
1152
1154
|
}
|
|
1153
1155
|
|
|
1156
|
+
/**
|
|
1157
|
+
* Add expand/collapse-on-click to a block, while preserving text selection.
|
|
1158
|
+
*
|
|
1159
|
+
* A drag that selects text ends with mouseup -> click; toggling then would
|
|
1160
|
+
* re-render the block and wipe the selection. Record the mousedown
|
|
1161
|
+
* position and skip the toggle when the pointer moved more than 3px
|
|
1162
|
+
* (anything beyond that is a drag, not a click - 3px tolerates hand tremor
|
|
1163
|
+
* on a plain click).
|
|
1164
|
+
*/
|
|
1165
|
+
bindExpandToggle(div, toggleFn) {
|
|
1166
|
+
let downX = 0, downY = 0;
|
|
1167
|
+
div.addEventListener('mousedown', (e) => { downX = e.clientX; downY = e.clientY; });
|
|
1168
|
+
div.addEventListener('click', (e) => {
|
|
1169
|
+
const dx = e.clientX - downX, dy = e.clientY - downY;
|
|
1170
|
+
if (dx * dx + dy * dy > 9) return; // dragged: preserve selection
|
|
1171
|
+
toggleFn(div);
|
|
1172
|
+
});
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1154
1175
|
createToolBlock(toolName, args, toolCallId) {
|
|
1155
1176
|
const div = document.createElement('div');
|
|
1156
1177
|
div.className = 'tool-block pending';
|
|
@@ -1203,8 +1224,9 @@ class PiWebClient {
|
|
|
1203
1224
|
div.appendChild(content);
|
|
1204
1225
|
div.appendChild(bottom);
|
|
1205
1226
|
|
|
1206
|
-
// Click to expand/collapse
|
|
1207
|
-
|
|
1227
|
+
// Click to expand/collapse, but NOT when the pointer was dragged (see
|
|
1228
|
+
// bindExpandToggle - a drag that selected text must preserve selection).
|
|
1229
|
+
this.bindExpandToggle(div, (d) => this.toggleToolExpand(d));
|
|
1208
1230
|
|
|
1209
1231
|
this.contentEl.appendChild(div);
|
|
1210
1232
|
return div;
|
|
@@ -1331,6 +1353,12 @@ class PiWebClient {
|
|
|
1331
1353
|
if (!div) {
|
|
1332
1354
|
div = this.createToolBlock('bash', { command: this.pendingBashCommand || '' }, key);
|
|
1333
1355
|
div.className = 'tool-block pending';
|
|
1356
|
+
// Running indicator (spinner + label) - makes it obvious the stream
|
|
1357
|
+
// is still live even when output is quiet; removed on bash_result.
|
|
1358
|
+
const run = document.createElement('span');
|
|
1359
|
+
run.className = 'bash-running';
|
|
1360
|
+
run.textContent = '⟳ running';
|
|
1361
|
+
div.querySelector('.tool-title')?.appendChild(run);
|
|
1334
1362
|
// Stop button in the title row (TUI Ctrl+C equivalent): abort_bash
|
|
1335
1363
|
// kills only this running bash. Removed when the block finalizes.
|
|
1336
1364
|
const stopBtn = document.createElement('button');
|
|
@@ -1351,7 +1379,14 @@ class PiWebClient {
|
|
|
1351
1379
|
const bashPending = document.getElementById('bash-pending');
|
|
1352
1380
|
if (bashPending) {
|
|
1353
1381
|
bashPending.appendChild(div);
|
|
1382
|
+
// Area-level status line at the TAIL (always visible even when the
|
|
1383
|
+
// block's own title scrolled out of view while output streams).
|
|
1384
|
+
const statusLine = document.createElement('div');
|
|
1385
|
+
statusLine.className = 'bash-stream-status';
|
|
1386
|
+
statusLine.textContent = '⟳ running…';
|
|
1387
|
+
bashPending.appendChild(statusLine);
|
|
1354
1388
|
bashPending.style.display = 'block';
|
|
1389
|
+
bashPending.scrollTop = bashPending.scrollHeight; // keep tail visible
|
|
1355
1390
|
} else {
|
|
1356
1391
|
this.contentEl.appendChild(div);
|
|
1357
1392
|
}
|
|
@@ -1362,6 +1397,12 @@ class PiWebClient {
|
|
|
1362
1397
|
const full = (div.dataset.fullOutput || '') + delta;
|
|
1363
1398
|
div.dataset.fullOutput = full;
|
|
1364
1399
|
this.applyToolPreview(div);
|
|
1400
|
+
// Keep the stream tail (and its running status line) visible inside the
|
|
1401
|
+
// pending area while output is coming in.
|
|
1402
|
+
const bashPending = document.getElementById('bash-pending');
|
|
1403
|
+
if (bashPending && bashPending.contains(div)) {
|
|
1404
|
+
bashPending.scrollTop = bashPending.scrollHeight;
|
|
1405
|
+
}
|
|
1365
1406
|
if (this.wasAtBottom()) this.scrollToBottom();
|
|
1366
1407
|
}
|
|
1367
1408
|
|
|
@@ -1384,12 +1425,16 @@ class PiWebClient {
|
|
|
1384
1425
|
const bashPending = document.getElementById('bash-pending');
|
|
1385
1426
|
if (bashPending && bashPending.contains(div)) {
|
|
1386
1427
|
this.contentEl.appendChild(div);
|
|
1428
|
+
// Remove the area-level running status line, then hide the empty area.
|
|
1429
|
+
bashPending.querySelectorAll('.bash-stream-status').forEach((el) => el.remove());
|
|
1387
1430
|
if (bashPending.children.length === 0) {
|
|
1388
1431
|
bashPending.style.display = 'none';
|
|
1389
1432
|
}
|
|
1390
1433
|
this.scrollToBottom();
|
|
1391
1434
|
}
|
|
1392
|
-
// Bash done: the stop button
|
|
1435
|
+
// Bash done: the running indicator and stop button are no longer
|
|
1436
|
+
// relevant.
|
|
1437
|
+
div.querySelector('.bash-running')?.remove();
|
|
1393
1438
|
div.querySelector('.bash-stop-btn')?.remove();
|
|
1394
1439
|
|
|
1395
1440
|
const isError = result.exitCode !== undefined && result.exitCode !== 0;
|
package/dist/static/style.css
CHANGED
|
@@ -63,6 +63,8 @@ body.theme-light {
|
|
|
63
63
|
box-sizing: border-box;
|
|
64
64
|
margin: 0;
|
|
65
65
|
padding: 0;
|
|
66
|
+
user-select: text;
|
|
67
|
+
-webkit-user-select: text;
|
|
66
68
|
}
|
|
67
69
|
|
|
68
70
|
html, body {
|
|
@@ -162,8 +164,7 @@ body {
|
|
|
162
164
|
border: 1px solid var(--border);
|
|
163
165
|
border-radius: 6px;
|
|
164
166
|
padding: 6px 10px;
|
|
165
|
-
cursor:
|
|
166
|
-
user-select: none;
|
|
167
|
+
cursor: text;
|
|
167
168
|
font-size: 12px;
|
|
168
169
|
}
|
|
169
170
|
|
|
@@ -268,8 +269,20 @@ body {
|
|
|
268
269
|
background: var(--tool-pending-bg);
|
|
269
270
|
margin: 4px 0;
|
|
270
271
|
font-size: 13px;
|
|
271
|
-
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.tool-block .tool-title,
|
|
275
|
+
.tool-block .tool-meta {
|
|
272
276
|
user-select: none;
|
|
277
|
+
cursor: pointer;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Tool args (the JSON parameter summary) and output are informative
|
|
281
|
+
content: selectable/copyable with a text cursor. */
|
|
282
|
+
.tool-block .tool-args,
|
|
283
|
+
.tool-block .tool-output {
|
|
284
|
+
user-select: text;
|
|
285
|
+
cursor: text;
|
|
273
286
|
}
|
|
274
287
|
|
|
275
288
|
.tool-block.success {
|
|
@@ -337,8 +350,6 @@ body {
|
|
|
337
350
|
margin: 4px 0;
|
|
338
351
|
padding: 6px 12px;
|
|
339
352
|
border-radius: 6px;
|
|
340
|
-
cursor: pointer;
|
|
341
|
-
user-select: none;
|
|
342
353
|
}
|
|
343
354
|
|
|
344
355
|
.special-block .special-label {
|
|
@@ -346,11 +357,15 @@ body {
|
|
|
346
357
|
font-weight: bold;
|
|
347
358
|
font-size: 12px;
|
|
348
359
|
margin-bottom: 4px;
|
|
360
|
+
user-select: none;
|
|
361
|
+
cursor: pointer;
|
|
349
362
|
}
|
|
350
363
|
|
|
351
364
|
.special-block .special-body {
|
|
352
365
|
color: var(--text);
|
|
353
366
|
font-size: 13px;
|
|
367
|
+
user-select: text;
|
|
368
|
+
cursor: text;
|
|
354
369
|
}
|
|
355
370
|
|
|
356
371
|
.special-block .special-body > *:first-child {
|
|
@@ -549,8 +564,11 @@ body {
|
|
|
549
564
|
pendingMessagesContainer). Moved into the message flow on completion. */
|
|
550
565
|
#bash-pending {
|
|
551
566
|
display: none;
|
|
552
|
-
padding:
|
|
553
|
-
|
|
567
|
+
padding: 8px 12px;
|
|
568
|
+
margin: 6px 8px 4px;
|
|
569
|
+
border: 1px solid var(--border);
|
|
570
|
+
border-radius: 6px;
|
|
571
|
+
background: var(--code-bg);
|
|
554
572
|
font-size: 13px;
|
|
555
573
|
/* ~10 lines of output visible; scrolling inside the block for more */
|
|
556
574
|
max-height: calc(10 * 1.5em);
|
|
@@ -569,6 +587,38 @@ body {
|
|
|
569
587
|
vertical-align: middle;
|
|
570
588
|
}
|
|
571
589
|
|
|
590
|
+
.bash-running {
|
|
591
|
+
margin-left: 8px;
|
|
592
|
+
font-size: 11px;
|
|
593
|
+
color: var(--accent);
|
|
594
|
+
vertical-align: middle;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
.bash-running::before {
|
|
598
|
+
content: '⟳';
|
|
599
|
+
display: inline-block;
|
|
600
|
+
margin-right: 4px;
|
|
601
|
+
animation: bash-spin 1s linear infinite;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
@keyframes bash-spin {
|
|
605
|
+
from { transform: rotate(0deg); }
|
|
606
|
+
to { transform: rotate(360deg); }
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
.bash-stream-status {
|
|
610
|
+
margin-top: 2px;
|
|
611
|
+
font-size: 11px;
|
|
612
|
+
color: var(--accent);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.bash-stream-status::before {
|
|
616
|
+
content: '⟳';
|
|
617
|
+
display: inline-block;
|
|
618
|
+
margin-right: 4px;
|
|
619
|
+
animation: bash-spin 1s linear infinite;
|
|
620
|
+
}
|
|
621
|
+
|
|
572
622
|
.bash-stop-btn:hover {
|
|
573
623
|
background: color-mix(in srgb, var(--error) 15%, transparent);
|
|
574
624
|
}
|