@astrosheep/square 0.3.53 → 0.3.55

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "square",
3
- "version": "0.3.53",
3
+ "version": "0.3.55",
4
4
  "description": "Native Claude Code turn-boundary delivery for Square participants",
5
5
  "author": {
6
6
  "name": "Square"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "square",
3
- "version": "0.3.53",
3
+ "version": "0.3.55",
4
4
  "description": "Shared Square activity with reliable participant attention at Codex boundaries.",
5
5
  "author": {
6
6
  "name": "Square"
@@ -25,10 +25,13 @@ export function renderAttentionPreview(attention) {
25
25
  to: attention.recipient,
26
26
  kind: attentionKind,
27
27
  };
28
+ const entries = Object.entries(attributes);
29
+ const [lastKey, lastValue] = entries[entries.length - 1];
28
30
  return [
29
31
  '<square-activity',
30
- ...Object.entries(attributes).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`),
31
- '>',
32
+ // The opening tag must never emit a standalone `>` line: Markdown renders it as a blockquote.
33
+ ...entries.slice(0, -1).map(([key, value]) => ` ${key}="${escapeAttribute(value)}"`),
34
+ ` ${lastKey}="${escapeAttribute(lastValue)}">`,
32
35
  previewAttentionBody(attention.body),
33
36
  '</square-activity>',
34
37
  ...(attentionBodyIsClipped(attention.body)
@@ -29,9 +29,23 @@ export function renderPiInbox(inbox) {
29
29
  return renderPendingAtBoundary(pendingInbox(inbox));
30
30
  }
31
31
 
32
+ const NOTIFY_BODY_MAX = 80;
33
+
34
+ export function summarizePendingForNotify(pending) {
35
+ const lines = pending.flatMap((membership) => membership.notifications.map((note) => {
36
+ const verb = note.route === 'bell' ? 'rang the bell for' : note.route === 'mention' ? 'walked over to' : 'paid attention to';
37
+ const body = note.body.replace(/\s+/g, ' ').trim();
38
+ const clipped = body.length > NOTIFY_BODY_MAX ? `${body.slice(0, NOTIFY_BODY_MAX).trimEnd()}…` : body;
39
+ return `${note.actor} ${verb} ${membership.name}${clipped ? ` — ${clipped}` : ''}`;
40
+ }));
41
+ if (lines.length === 0) return undefined;
42
+ return lines.length === 1 ? `■ square · ${lines[0]}` : `■ square · ${lines[0]} (+${lines.length - 1} more)`;
43
+ }
44
+
32
45
  export default function squarePiExtension(pi) {
33
46
  let sessionId;
34
47
  let sessionCwd;
48
+ let ui;
35
49
  let watcher;
36
50
  let watcherAbort;
37
51
  let generation = 0;
@@ -185,10 +199,14 @@ export default function squarePiExtension(pi) {
185
199
  sessionId,
186
200
  async (content) => {
187
201
  if (signal.aborted || currentRunSignal?.aborted) throw new Error('Pi notification delivery cancelled');
202
+ // The full activity stays out of the TUI stream (display: false) but still
203
+ // reaches the model; a brief notify tells the human what just landed.
204
+ const summary = summarizePendingForNotify(pending);
205
+ if (summary) ui?.notify?.(summary, 'info');
188
206
  const landing = waitForLanding(content, signal, 'steer');
189
207
  try {
190
208
  Promise.resolve(pi.sendMessage(
191
- { customType: 'square', content, display: true },
209
+ { customType: 'square', content, display: false },
192
210
  { deliverAs: 'steer', triggerTurn: true },
193
211
  )).catch((error) => landing.ack.settle(error));
194
212
  } catch (error) {
@@ -240,6 +258,7 @@ export default function squarePiExtension(pi) {
240
258
  turnIndex = 0;
241
259
  activeTurn = undefined;
242
260
  currentRunSignal = undefined;
261
+ ui = ctx?.ui;
243
262
  sessionId = ctx.sessionManager.getSessionId();
244
263
  sessionCwd = ctx.cwd || process.cwd();
245
264
  const token = generation;
@@ -327,6 +346,7 @@ export default function squarePiExtension(pi) {
327
346
  generation += 1;
328
347
  failAcks(new Error('Pi session ended'));
329
348
  stopWatcher();
349
+ ui = undefined;
330
350
  if (sessionId && sessionCwd) void automaticSessionEnd('pi', sessionId, sessionCwd, sessionEnv(sessionId)).catch(() => undefined);
331
351
  sessionId = undefined;
332
352
  sessionCwd = undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrosheep/square",
3
- "version": "0.3.53",
3
+ "version": "0.3.55",
4
4
  "description": "A shared public square where agents join, catch activity, express, and step out when done.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,8 +18,9 @@
18
18
  "clean": "node --input-type=module -e \"import fs from 'node:fs'; fs.rmSync('dist',{recursive:true,force:true})\"",
19
19
  "build": "npm run clean && tsc && node --input-type=module -e \"import fs from 'node:fs'; fs.chmodSync('dist/square.js',0o755)\"",
20
20
  "verify-release": "node test/release.test.js",
21
- "release": "npm version patch && npm publish && git push --follow-tags",
22
- "prepublishOnly": "npm run build && npm run verify-release",
21
+ "sync-manifests": "node scripts/sync-manifests.mjs",
22
+ "release": "npm version patch && npm run sync-manifests -- --commit && npm publish && git push --follow-tags",
23
+ "prepublishOnly": "npm run sync-manifests && npm run build && npm run verify-release",
23
24
  "test": "npm run build && node --test test/*.test.js",
24
25
  "test:cli-process": "npm run build && node --test test/process/square-cli-render.test.js"
25
26
  },