@astrosheep/square 0.3.58 → 0.3.61
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/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity.js +16 -14
- package/dist/attention-presentation.js +19 -19
- package/dist/automatic-session.js +2 -2
- package/dist/catch-decisions.js +1 -1
- package/dist/cli/context.js +16 -16
- package/dist/cli/observation-commands.js +85 -45
- package/dist/cli/program.js +33 -9
- package/dist/cli/square-commands.js +21 -19
- package/dist/decisions.d.ts +2 -0
- package/dist/decisions.js +38 -31
- package/dist/list.js +12 -9
- package/dist/presentation.d.ts +7 -0
- package/dist/presentation.js +75 -67
- package/dist/registry.js +2 -2
- package/dist/runtime.d.ts +8 -0
- package/dist/runtime.js +37 -0
- package/dist/square-actions.js +4 -4
- package/dist/stream.js +1 -1
- package/dist/tty-style.d.ts +7 -0
- package/dist/tty-style.js +13 -0
- package/dist/views.js +6 -5
- package/dist/watch.js +24 -11
- package/extensions/square-pi.js +16 -6
- package/package.json +3 -3
package/dist/watch.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
2
2
|
import { isSquareError, } from './model.js';
|
|
3
|
-
import { SLEEP_MS, STALE_MS, WATCH_HEARTBEAT_MS, nowMs, } from './runtime.js';
|
|
3
|
+
import { SLEEP_MS, STALE_MS, WATCH_HEARTBEAT_MS, inSquareCount, nowMs, } from './runtime.js';
|
|
4
4
|
import { openSquare } from './square-file-adapter.js';
|
|
5
5
|
import { closeOpenSquare } from './open-square.js';
|
|
6
6
|
import { openParticipant } from './square-wiring.js';
|
|
7
7
|
import { resolveParticipant, watchPresentation } from './views.js';
|
|
8
8
|
import { acquireWatchLease, ownsWatchLease, pulseWatchLease, releaseWatchLease } from './wakes.js';
|
|
9
|
-
import { renderWatchForceTakeover, renderWatchAlreadyActive, renderWatchReplaceMissing, renderWatchOutput, renderWatchReplaced, renderWatchStatus, participantCommandPrefix, joinRecoveryCommand, participantsRecoveryCommand, withPathOutput, } from './presentation.js';
|
|
9
|
+
import { renderWatchForceTakeover, renderWatchAlreadyActive, renderWatchReplaceMissing, renderWatchOutput, renderWatchReplaced, renderWatchStatus, formatRefusal, participantCommandPrefix, joinRecoveryCommand, participantsRecoveryCommand, withPathOutput, } from './presentation.js';
|
|
10
10
|
import { hasAutomaticDeliveryIdentity } from './registry.js';
|
|
11
11
|
import { parseActivityId } from './square-core.js';
|
|
12
12
|
function watchStatusExitCode(status) {
|
|
@@ -37,7 +37,7 @@ function watchOutputResult(squarePath, presentation, name, caught, opts = {}) {
|
|
|
37
37
|
showCatchHint: !hasAutomaticDeliveryIdentity(),
|
|
38
38
|
perceptions,
|
|
39
39
|
}) + (caught.remaining > 0
|
|
40
|
-
? `\n○ ${caught.remaining} matching ${caught.remaining === 1 ? 'activity remains' : 'activities remain'}\n
|
|
40
|
+
? `\n○ ${caught.remaining} matching ${caught.remaining === 1 ? 'activity remains' : 'activities remain'}\n${catchContinuationCommand(squarePath, name, opts)}`
|
|
41
41
|
: ''),
|
|
42
42
|
remaining: caught.remaining,
|
|
43
43
|
...(opts.status ? { status: opts.status } : {}),
|
|
@@ -61,7 +61,7 @@ function writeWatchOutput(squarePath, name, presentation, stdout, remaining, sta
|
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
const fallback = showCatchHint && remaining === 0
|
|
64
|
-
?
|
|
64
|
+
? `${participantCommandPrefix(squarePath, name)} catch --idle 30m\n stay available for new activity`
|
|
65
65
|
: '';
|
|
66
66
|
process.stdout.write(withPathOutput(squarePath, [stdout.trimEnd(), fallback].filter(Boolean).join('\n\n').trimEnd(), headerOpts));
|
|
67
67
|
}
|
|
@@ -109,7 +109,7 @@ function installWatchInterruptHandler(square, squarePath, name, currentLeaseId)
|
|
|
109
109
|
const onInterrupt = () => {
|
|
110
110
|
void (async () => {
|
|
111
111
|
await endWatch(square, name, currentLeaseId());
|
|
112
|
-
process.stdout.write(withPathOutput(squarePath, '
|
|
112
|
+
process.stdout.write(withPathOutput(squarePath, '○ you step back — catch stopped'));
|
|
113
113
|
process.exit(130);
|
|
114
114
|
})().catch((error) => {
|
|
115
115
|
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
@@ -144,19 +144,30 @@ async function cmdWatchNow(squarePath, name, opts) {
|
|
|
144
144
|
await closeOpenSquare(square);
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
+
async function countParticipants(square) {
|
|
148
|
+
try {
|
|
149
|
+
return inSquareCount((await square.artifact.read()).state);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
147
155
|
/** `false` is reserved for a quiet --now; idle completion preserves its existing sweep boundary. */
|
|
148
156
|
export async function cmdWatch(squarePath, name, opts) {
|
|
149
157
|
let square;
|
|
158
|
+
let participantCount;
|
|
150
159
|
try {
|
|
151
160
|
square = await openSquare(squarePath, { clock: nowMs });
|
|
161
|
+
participantCount = inSquareCount((await square.artifact.read()).state);
|
|
152
162
|
name = (await resolveParticipant(square, name)).name;
|
|
153
163
|
}
|
|
154
164
|
catch (err) {
|
|
155
165
|
if (isSquareError(err)) {
|
|
156
|
-
|
|
166
|
+
const bodyLines = [err.message];
|
|
157
167
|
// The caller's own name has never joined; only a join admits it.
|
|
158
|
-
if (
|
|
159
|
-
|
|
168
|
+
if (/^✕ .* has never stepped into/.test(err.message))
|
|
169
|
+
bodyLines.push(joinRecoveryCommand(squarePath, name));
|
|
170
|
+
process.stderr.write(formatRefusal(squarePath, bodyLines, participantCount === undefined ? {} : { participantCount }));
|
|
160
171
|
process.exit(err.code === 'not_found' ? 1 : 2);
|
|
161
172
|
}
|
|
162
173
|
throw err;
|
|
@@ -169,12 +180,14 @@ export async function cmdWatch(squarePath, name, opts) {
|
|
|
169
180
|
}
|
|
170
181
|
}
|
|
171
182
|
catch (err) {
|
|
183
|
+
const participantCount = await countParticipants(square);
|
|
172
184
|
await closeOpenSquare(square).catch(() => undefined);
|
|
173
185
|
if (isSquareError(err)) {
|
|
174
|
-
|
|
186
|
+
const bodyLines = [err.message];
|
|
175
187
|
// A filter target is unknown, not the caller; the roster is the useful next read.
|
|
176
|
-
if (
|
|
177
|
-
|
|
188
|
+
if (/^✕ .*(has never stepped into|is not standing in this square)/.test(err.message))
|
|
189
|
+
bodyLines.push(participantsRecoveryCommand(squarePath));
|
|
190
|
+
process.stderr.write(formatRefusal(squarePath, bodyLines, participantCount === undefined ? {} : { participantCount }));
|
|
178
191
|
process.exit(err.code === 'not_found' ? 1 : 2);
|
|
179
192
|
}
|
|
180
193
|
throw err;
|
package/extensions/square-pi.js
CHANGED
|
@@ -31,12 +31,20 @@ export function renderPiInbox(inbox) {
|
|
|
31
31
|
|
|
32
32
|
const NOTIFY_BODY_MAX = 80;
|
|
33
33
|
|
|
34
|
+
function framePiMessage(content) {
|
|
35
|
+
return `\n${content.replace(/^\n+/, '').replace(/\n+$/, '')}\n`;
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
export function summarizePendingForNotify(pending) {
|
|
35
39
|
const lines = pending.flatMap((membership) => membership.notifications.map((note) => {
|
|
36
|
-
const verb = note.route === 'bell'
|
|
40
|
+
const verb = note.route === 'bell'
|
|
41
|
+
? 'rang the bell'
|
|
42
|
+
: note.route === 'mention'
|
|
43
|
+
? `called your name (${membership.name})`
|
|
44
|
+
: `spoke within your earshot (${membership.name})`;
|
|
37
45
|
const body = note.body.replace(/\s+/g, ' ').trim();
|
|
38
46
|
const clipped = body.length > NOTIFY_BODY_MAX ? `${body.slice(0, NOTIFY_BODY_MAX).trimEnd()}…` : body;
|
|
39
|
-
return `${note.actor} ${verb}
|
|
47
|
+
return `${note.actor} ${verb}${clipped ? ` — ${clipped}` : ''}`;
|
|
40
48
|
}));
|
|
41
49
|
if (lines.length === 0) return undefined;
|
|
42
50
|
return lines.length === 1 ? `■ square · ${lines[0]}` : `■ square · ${lines[0]} (+${lines.length - 1} more)`;
|
|
@@ -203,10 +211,11 @@ export default function squarePiExtension(pi) {
|
|
|
203
211
|
// reaches the model; a brief notify tells the human what just landed.
|
|
204
212
|
const summary = summarizePendingForNotify(pending);
|
|
205
213
|
if (summary) ui?.notify?.(summary, 'info');
|
|
206
|
-
const
|
|
214
|
+
const messageContent = framePiMessage(content);
|
|
215
|
+
const landing = waitForLanding(messageContent, signal, 'steer');
|
|
207
216
|
try {
|
|
208
217
|
Promise.resolve(pi.sendMessage(
|
|
209
|
-
{ customType: 'square', content, display: false },
|
|
218
|
+
{ customType: 'square', content: messageContent, display: false },
|
|
210
219
|
{ deliverAs: 'steer', triggerTurn: true },
|
|
211
220
|
)).catch((error) => landing.ack.settle(error));
|
|
212
221
|
} catch (error) {
|
|
@@ -266,10 +275,11 @@ export default function squarePiExtension(pi) {
|
|
|
266
275
|
const signal = watcherAbort.signal;
|
|
267
276
|
void automaticSessionStart('pi', sessionId, sessionCwd, sessionEnv(sessionId)).then((context) => {
|
|
268
277
|
if (context === undefined || sessionId === undefined || token !== generation) return;
|
|
269
|
-
const
|
|
278
|
+
const messageContent = framePiMessage(context);
|
|
279
|
+
const landing = waitForLanding(messageContent, signal, 'nextTurn');
|
|
270
280
|
try {
|
|
271
281
|
Promise.resolve(pi.sendMessage(
|
|
272
|
-
{ customType: 'square', content:
|
|
282
|
+
{ customType: 'square', content: messageContent, display: true },
|
|
273
283
|
{ deliverAs: 'nextTurn' },
|
|
274
284
|
)).catch((error) => landing.ack.settle(error));
|
|
275
285
|
} catch {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrosheep/square",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.61",
|
|
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": {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"sync-manifests": "node scripts/sync-manifests.mjs",
|
|
22
22
|
"release": "npm version patch && npm run sync-manifests -- --commit && npm publish && git push --follow-tags",
|
|
23
23
|
"prepublishOnly": "npm run sync-manifests && npm run build && npm run verify-release",
|
|
24
|
-
"test": "npm run build && node --test test/*.test.js",
|
|
25
|
-
"test:cli-process": "npm run build && node --test test/process/square-cli-render.test.js"
|
|
24
|
+
"test": "npm run build && node --import ./test/sandbox-env.js --test test/*.test.js",
|
|
25
|
+
"test:cli-process": "npm run build && node --import ./test/sandbox-env.js --test test/process/square-cli-render.test.js"
|
|
26
26
|
},
|
|
27
27
|
"keywords": [
|
|
28
28
|
"brainstorm",
|