@astrosheep/square 0.3.68 → 0.3.69
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/extensions/square-pi.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
1
3
|
import { presentPendingAtBoundary, renderPendingAtBoundary } from '../dist/boundary-presentation.js';
|
|
2
4
|
import { automaticSessionEnd, automaticSessionStart } from '../dist/automatic-session.js';
|
|
3
5
|
import { sessionInbox, observeSessionPending } from '../dist/inbox.js';
|
|
@@ -25,31 +27,66 @@ export function renderPiInbox(inbox) {
|
|
|
25
27
|
return renderPendingAtBoundary(pendingInbox(inbox));
|
|
26
28
|
}
|
|
27
29
|
|
|
28
|
-
const NOTIFY_BODY_MAX = 80;
|
|
29
|
-
|
|
30
30
|
function framePiMessage(content) {
|
|
31
31
|
return `\n${content.replace(/^\n+/, '').replace(/\n+$/, '')}\n`;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
/** Renderer-only facts for the collapsed card; Pi never sends `details` to the model. */
|
|
35
|
+
export function pendingCardDetails(pending) {
|
|
36
|
+
const items = pending.flatMap((membership) => membership.notifications.map((note) => ({
|
|
37
|
+
square: path.basename(membership.squarePath, '.square'),
|
|
38
|
+
description: renderAttentionDescription({ actor: note.actor, recipient: membership.name, route: note.route }),
|
|
39
|
+
})));
|
|
40
|
+
return items.length === 0 ? undefined : { items };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Conservative terminal width: anything outside ASCII counts as two columns, so a
|
|
44
|
+
// truncated line never exceeds the viewport (Pi stops the TUI when a line overflows).
|
|
45
|
+
const columnsOf = (char) => (char.charCodeAt(0) < 0x80 ? 1 : 2);
|
|
46
|
+
const widthOf = (text) => Array.from(text).reduce((sum, char) => sum + columnsOf(char), 0);
|
|
47
|
+
|
|
48
|
+
function fitColumns(text, columns) {
|
|
49
|
+
if (widthOf(text) <= columns) return text;
|
|
50
|
+
let used = 1; // the ellipsis
|
|
51
|
+
let out = '';
|
|
52
|
+
for (const char of text) {
|
|
53
|
+
if (used + columnsOf(char) > columns) break;
|
|
54
|
+
used += columnsOf(char);
|
|
55
|
+
out += char;
|
|
56
|
+
}
|
|
57
|
+
return `${out}…`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Collapsed: one line naming who reached you and where. Expanded: Pi's default card,
|
|
62
|
+
* which shows the exact content the model received.
|
|
63
|
+
*/
|
|
64
|
+
export function renderSquareCard(message, { expanded, outputPad = 1 }, theme) {
|
|
65
|
+
const items = message.details?.items;
|
|
66
|
+
if (expanded || !Array.isArray(items) || items.length === 0) return undefined;
|
|
67
|
+
const [first] = items;
|
|
68
|
+
const tail = ` · ${first.square}${items.length > 1 ? ` +${items.length - 1}` : ''}`;
|
|
69
|
+
return {
|
|
70
|
+
invalidate() {},
|
|
71
|
+
render(width) {
|
|
72
|
+
const room = Math.max(1, width - outputPad * 2 - 2);
|
|
73
|
+
// Style only an untruncated line, so escape codes never count toward or get cut by the width.
|
|
74
|
+
const line = widthOf(first.description + tail) <= room
|
|
75
|
+
? `${first.description}${theme.fg('dim', tail)}`
|
|
76
|
+
: fitColumns(first.description + tail, room);
|
|
77
|
+
return [`${' '.repeat(outputPad)}${theme.fg('customMessageLabel', '■')} ${line}`];
|
|
78
|
+
},
|
|
79
|
+
};
|
|
43
80
|
}
|
|
44
81
|
|
|
45
82
|
export default function squarePiExtension(pi) {
|
|
83
|
+
pi.registerMessageRenderer?.('square', renderSquareCard);
|
|
46
84
|
pi.registerFlag('agent-delivery-socket', { type: 'string', description: 'Explicit private local delivery socket' });
|
|
47
85
|
createPiReceiver(pi, {
|
|
48
86
|
get endpoint() { return pi.getFlag('agent-delivery-socket'); },
|
|
49
87
|
});
|
|
50
88
|
let sessionId;
|
|
51
89
|
let sessionCwd;
|
|
52
|
-
let ui;
|
|
53
90
|
let watcher;
|
|
54
91
|
let watcherAbort;
|
|
55
92
|
let generation = 0;
|
|
@@ -199,15 +236,13 @@ export default function squarePiExtension(pi) {
|
|
|
199
236
|
boundSessionId,
|
|
200
237
|
async (content) => {
|
|
201
238
|
if (signal.aborted || currentRunSignal?.aborted) throw new Error('Pi notification delivery cancelled');
|
|
202
|
-
//
|
|
203
|
-
//
|
|
204
|
-
const summary = summarizePendingForNotify(pending);
|
|
205
|
-
if (summary) ui?.notify?.(summary, 'info');
|
|
239
|
+
// One card for the human: collapsed it names who reached you, expanded it
|
|
240
|
+
// shows the same content the model receives.
|
|
206
241
|
const messageContent = framePiMessage(content);
|
|
207
242
|
const landing = waitForLanding(messageContent, signal, 'steer');
|
|
208
243
|
try {
|
|
209
244
|
sendPiMessage(pi,
|
|
210
|
-
{ customType: 'square', content: messageContent, display:
|
|
245
|
+
{ customType: 'square', content: messageContent, display: true, details: pendingCardDetails(pending) },
|
|
211
246
|
{ deliverAs: 'steer', triggerTurn: true },
|
|
212
247
|
);
|
|
213
248
|
} catch (error) {
|
|
@@ -261,7 +296,6 @@ export default function squarePiExtension(pi) {
|
|
|
261
296
|
turnIndex = 0;
|
|
262
297
|
activeTurn = undefined;
|
|
263
298
|
currentRunSignal = undefined;
|
|
264
|
-
ui = ctx?.ui;
|
|
265
299
|
sessionId = ctx.sessionManager.getSessionId();
|
|
266
300
|
sessionCwd = ctx.cwd || process.cwd();
|
|
267
301
|
const token = generation;
|
|
@@ -354,7 +388,6 @@ export default function squarePiExtension(pi) {
|
|
|
354
388
|
generation += 1;
|
|
355
389
|
failAcks(new Error('Pi session ended'));
|
|
356
390
|
const stopped = stopWatcher();
|
|
357
|
-
ui = undefined;
|
|
358
391
|
const endedId = sessionId;
|
|
359
392
|
const endedCwd = sessionCwd;
|
|
360
393
|
const endedEnv = sessionEnv(endedId);
|