pi-sdk-web 0.4.2 → 0.4.3
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 +6 -2
- package/dist/static/app.js +50 -3
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -433,6 +433,9 @@ export class PiWebServer {
|
|
|
433
433
|
if (!command)
|
|
434
434
|
throw new Error("Missing 'command'");
|
|
435
435
|
const excludeFromContext = data.excludeFromContext === true;
|
|
436
|
+
// Correlation id for streaming: Pi emits bash_execution_update
|
|
437
|
+
// events carrying this id while the command runs (onChunk).
|
|
438
|
+
const id = typeof data.id === "string" && data.id ? data.id : `bash-${Date.now()}`;
|
|
436
439
|
// Let extensions intercept/enhance the command (same as Pi RPC/TUI):
|
|
437
440
|
// user_bash handlers may provide a result or operations for execution.
|
|
438
441
|
const eventResult = await this.session.extensionRunner.emitUserBash({
|
|
@@ -443,14 +446,15 @@ export class PiWebServer {
|
|
|
443
446
|
});
|
|
444
447
|
if (eventResult?.result) {
|
|
445
448
|
this.session.recordBashResult(command, eventResult.result, { excludeFromContext });
|
|
446
|
-
this.broadcast({ type: "bash_result", command, data: eventResult.result });
|
|
449
|
+
this.broadcast({ type: "bash_result", id, command, data: eventResult.result });
|
|
447
450
|
break;
|
|
448
451
|
}
|
|
449
452
|
const result = await this.session.executeBash(command, undefined, {
|
|
450
453
|
excludeFromContext,
|
|
454
|
+
id,
|
|
451
455
|
operations: eventResult?.operations,
|
|
452
456
|
});
|
|
453
|
-
this.broadcast({ type: "bash_result", command, data: result });
|
|
457
|
+
this.broadcast({ type: "bash_result", id, command, data: result });
|
|
454
458
|
break;
|
|
455
459
|
}
|
|
456
460
|
case "cycle_model":
|
package/dist/static/app.js
CHANGED
|
@@ -213,6 +213,10 @@ class PiWebClient {
|
|
|
213
213
|
|
|
214
214
|
// Tool call rendering state: map toolCallId -> element
|
|
215
215
|
this.toolEls = new Map();
|
|
216
|
+
// Bash streaming blocks: map bash id -> element
|
|
217
|
+
this.bashEls = new Map();
|
|
218
|
+
this.pendingBashId = null;
|
|
219
|
+
this.pendingBashCommand = '';
|
|
216
220
|
// Tool execution timers: map toolCallId -> interval id
|
|
217
221
|
this.toolTimers = new Map();
|
|
218
222
|
|
|
@@ -913,6 +917,14 @@ class PiWebClient {
|
|
|
913
917
|
// Extension custom entries (e.g. magic-context /ctx-status) arrive live
|
|
914
918
|
this.renderEntry(ev.entry);
|
|
915
919
|
break;
|
|
920
|
+
case 'bash_execution_update':
|
|
921
|
+
// Streaming bash output (e.g. !! running a long-lived program).
|
|
922
|
+
// Append the delta to the matching tool block in real time; the
|
|
923
|
+
// final bash_result finalizes it (exit code, truncation info).
|
|
924
|
+
if (typeof ev.delta === 'string' && ev.delta.length > 0) {
|
|
925
|
+
this.appendBashChunk(ev.id, ev.delta);
|
|
926
|
+
}
|
|
927
|
+
break;
|
|
916
928
|
default:
|
|
917
929
|
break;
|
|
918
930
|
}
|
|
@@ -1310,11 +1322,39 @@ class PiWebClient {
|
|
|
1310
1322
|
this.toolEls.delete(ev.toolCallId);
|
|
1311
1323
|
}
|
|
1312
1324
|
|
|
1325
|
+
appendBashChunk(id, delta) {
|
|
1326
|
+
// Find or create the tool block for this bash run (keyed by the id the
|
|
1327
|
+
// client sent with the bash message, e.g. bash-<timestamp>).
|
|
1328
|
+
const key = id || this.pendingBashId;
|
|
1329
|
+
if (!key) return;
|
|
1330
|
+
let div = this.bashEls.get(key);
|
|
1331
|
+
if (!div) {
|
|
1332
|
+
div = this.createToolBlock('bash', { command: this.pendingBashCommand || '' }, key);
|
|
1333
|
+
div.className = 'tool-block pending';
|
|
1334
|
+
this.bashEls.set(key, div);
|
|
1335
|
+
}
|
|
1336
|
+
// Append the delta to the full text and re-apply the preview (respects
|
|
1337
|
+
// the collapsed/expanded state of the block).
|
|
1338
|
+
const full = (div.dataset.fullOutput || '') + delta;
|
|
1339
|
+
div.dataset.fullOutput = full;
|
|
1340
|
+
this.applyToolPreview(div);
|
|
1341
|
+
if (this.wasAtBottom()) this.scrollToBottom();
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1313
1344
|
renderBashResult(data) {
|
|
1314
|
-
const
|
|
1345
|
+
const id = data.id;
|
|
1315
1346
|
const result = data.data || {};
|
|
1347
|
+
let div = (id && this.bashEls.get(id)) || null;
|
|
1348
|
+
if (!div) {
|
|
1349
|
+
div = this.createToolBlock('bash', { command: data.command }, id || 'bash-' + Date.now());
|
|
1350
|
+
if (id) this.bashEls.set(id, div);
|
|
1351
|
+
}
|
|
1316
1352
|
const output = result.output || '';
|
|
1317
|
-
|
|
1353
|
+
// Streaming blocks have the full text already (appended incrementally);
|
|
1354
|
+
// for non-streaming runs set it now.
|
|
1355
|
+
if (!(div.dataset.fullOutput && div.dataset.fullOutput.length > 0)) {
|
|
1356
|
+
this.setToolOutput(div, output);
|
|
1357
|
+
}
|
|
1318
1358
|
|
|
1319
1359
|
const isError = result.exitCode !== undefined && result.exitCode !== 0;
|
|
1320
1360
|
div.className = isError ? 'tool-block error' : 'tool-block success';
|
|
@@ -1334,6 +1374,10 @@ class PiWebClient {
|
|
|
1334
1374
|
}
|
|
1335
1375
|
|
|
1336
1376
|
this.scrollToBottom();
|
|
1377
|
+
// Streaming done: drop the block from the live map (no more deltas).
|
|
1378
|
+
if (id) this.bashEls.delete(id);
|
|
1379
|
+
this.pendingBashId = null;
|
|
1380
|
+
this.pendingBashCommand = '';
|
|
1337
1381
|
}
|
|
1338
1382
|
|
|
1339
1383
|
resultText(result) {
|
|
@@ -1420,7 +1464,10 @@ class PiWebClient {
|
|
|
1420
1464
|
const isExcluded = text.startsWith('!!');
|
|
1421
1465
|
const command = (isExcluded ? text.slice(2) : text.slice(1)).trim();
|
|
1422
1466
|
if (command) {
|
|
1423
|
-
|
|
1467
|
+
const id = 'bash-' + Date.now();
|
|
1468
|
+
this.send({ type: 'bash', command: command, excludeFromContext: isExcluded, id: id });
|
|
1469
|
+
this.pendingBashId = id;
|
|
1470
|
+
this.pendingBashCommand = command;
|
|
1424
1471
|
}
|
|
1425
1472
|
} else if (text.startsWith('/')) {
|
|
1426
1473
|
// Skill commands (/skill:name args) go through prompt expansion in Pi -
|