@astrosheep/square 0.3.62 → 0.3.64
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 +3 -2
- package/claude-plugin/hooks/hooks.json +1 -22
- package/claude-plugin/hooks/register.js +119 -0
- package/claude-plugin/types.d.ts +7 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity-feed.d.ts +1 -10
- package/dist/activity-feed.js +1 -27
- package/dist/activity.js +57 -25
- package/dist/artifact.js +12 -24
- package/dist/attention-presentation.js +1 -0
- package/dist/automatic-session.d.ts +3 -1
- package/dist/automatic-session.js +21 -34
- package/dist/boundary-presentation.js +4 -13
- package/dist/canonical-path.d.ts +11 -0
- package/dist/canonical-path.js +47 -0
- package/dist/catch-decisions.js +14 -10
- package/dist/catch-selection.d.ts +6 -0
- package/dist/catch-selection.js +14 -0
- package/dist/claude-delivery.d.ts +11 -0
- package/dist/claude-delivery.js +145 -0
- package/dist/claude-mod.d.ts +8 -0
- package/dist/claude-mod.js +164 -0
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +9 -21
- package/dist/cli/harness-command.d.ts +0 -1
- package/dist/cli/harness-command.js +0 -6
- package/dist/cli/observation-commands.d.ts +1 -1
- package/dist/cli/observation-commands.js +31 -58
- package/dist/cli/program.js +20 -18
- package/dist/cli/registry.js +2 -2
- package/dist/cli/square-commands.js +10 -6
- package/dist/codex-hook.js +9 -12
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +7 -5
- package/dist/decisions.d.ts +2 -6
- package/dist/decisions.js +16 -17
- package/dist/delivery-health.d.ts +1 -2
- package/dist/delivery-health.js +4 -5
- package/dist/delivery-operations.d.ts +2 -5
- package/dist/delivery-operations.js +77 -214
- package/dist/delivery.d.ts +25 -47
- package/dist/delivery.js +14 -46
- package/dist/diagnostic-redaction.js +7 -9
- package/dist/file-changes.d.ts +0 -1
- package/dist/file-changes.js +2 -19
- package/dist/harness-claude.js +8 -6
- package/dist/harness-codex.d.ts +0 -2
- package/dist/harness-codex.js +0 -2
- package/dist/harness-links.js +13 -17
- package/dist/harness.js +3 -7
- package/dist/help.js +4 -3
- package/dist/host-ledger-file-adapter.d.ts +17 -8
- package/dist/host-ledger-file-adapter.js +164 -80
- package/dist/host-ledger.d.ts +55 -50
- package/dist/inbox.d.ts +0 -3
- package/dist/inbox.js +13 -30
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.js +1 -4
- package/dist/mcp.js +18 -40
- package/dist/mention-parse.js +3 -9
- package/dist/model.d.ts +11 -2
- package/dist/model.js +1 -1
- package/dist/notifications.d.ts +3 -16
- package/dist/notifications.js +41 -122
- package/dist/opencode-delivery.d.ts +14 -0
- package/dist/opencode-delivery.js +171 -0
- package/dist/opencode.d.ts +39 -18
- package/dist/opencode.js +145 -40
- package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
- package/dist/packages/agent-delivery/src/claude-auth.js +70 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
- package/dist/packages/agent-delivery/src/claude-native.js +65 -0
- package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
- package/dist/packages/agent-delivery/src/claude.js +66 -0
- package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
- package/dist/packages/agent-delivery/src/deadline.js +41 -0
- package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
- package/dist/packages/agent-delivery/src/errors.js +41 -0
- package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
- package/dist/packages/agent-delivery/src/guards.js +6 -0
- package/dist/packages/agent-delivery/src/index.d.ts +83 -0
- package/dist/packages/agent-delivery/src/index.js +110 -0
- package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
- package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
- package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
- package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
- package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
- package/dist/packages/agent-delivery/src/opencode.js +127 -0
- package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
- package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
- package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
- package/dist/packages/agent-delivery/src/paseo.js +106 -0
- package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
- package/dist/packages/agent-delivery/src/pi-client.js +106 -0
- package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
- package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
- package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
- package/dist/packages/agent-delivery/src/pi-send.js +4 -0
- package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
- package/dist/packages/agent-delivery/src/pi.js +209 -0
- package/dist/packages/agent-delivery/src/types.d.ts +120 -0
- package/dist/participant-host.js +12 -13
- package/dist/participant-identity.d.ts +21 -0
- package/dist/participant-identity.js +32 -11
- package/dist/paseo-delivery.d.ts +2 -2
- package/dist/paseo-delivery.js +35 -27
- package/dist/paseo-timeline.js +25 -21
- package/dist/paseo.d.ts +2 -2
- package/dist/paseo.js +1 -2
- package/dist/ports.d.ts +7 -20
- package/dist/presentation-operations.js +16 -4
- package/dist/presentation.d.ts +19 -10
- package/dist/presentation.js +99 -177
- package/dist/registry.d.ts +15 -66
- package/dist/registry.js +45 -123
- package/dist/routes.d.ts +1 -28
- package/dist/routes.js +22 -104
- package/dist/runtime.d.ts +3 -9
- package/dist/runtime.js +14 -67
- package/dist/search.d.ts +0 -2
- package/dist/search.js +3 -10
- package/dist/square-actions.js +48 -72
- package/dist/square-application.js +25 -23
- package/dist/square-core.d.ts +3 -0
- package/dist/square-core.js +22 -5
- package/dist/square-facade.d.ts +2 -0
- package/dist/square-file-adapter.js +4 -7
- package/dist/square-projections.d.ts +40 -45
- package/dist/square-projections.js +43 -73
- package/dist/square-state.js +1 -4
- package/dist/square-storage.d.ts +5 -8
- package/dist/square-storage.js +13 -36
- package/dist/square-wiring.d.ts +0 -5
- package/dist/square-wiring.js +3 -21
- package/dist/stream.js +4 -6
- package/dist/time.js +2 -7
- package/dist/views.d.ts +4 -16
- package/dist/views.js +12 -19
- package/dist/wake-attempts.d.ts +2 -56
- package/dist/wake-attempts.js +15 -110
- package/dist/wake-eligibility.d.ts +43 -0
- package/dist/wake-eligibility.js +106 -0
- package/dist/wake-evidence.d.ts +32 -9
- package/dist/wake-evidence.js +29 -24
- package/dist/wake-sink.d.ts +13 -9
- package/dist/wake-sink.js +35 -54
- package/dist/watch.js +13 -21
- package/extensions/square-pi.js +10 -5
- package/guides/architect.md +77 -77
- package/guides/brainstorm.md +197 -197
- package/guides/claude-native.md +101 -0
- package/guides/host-ledger.md +3 -1
- package/guides/participant.md +14 -7
- package/guides/pi-native-delivery.md +43 -0
- package/package.json +4 -3
- package/dist/claude-hook.d.ts +0 -10
- package/dist/claude-hook.js +0 -60
- package/dist/paseo-connection.d.ts +0 -15
- package/dist/paseo-connection.js +0 -141
- package/dist/presence.d.ts +0 -2
- package/dist/presence.js +0 -24
- package/dist/presented.d.ts +0 -2
- package/dist/presented.js +0 -10
- package/dist/state-cell.d.ts +0 -14
- package/dist/wake-port.d.ts +0 -23
- package/dist/wake-port.js +0 -27
- /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runClaudeMod } from '../claude-mod.js';
|
|
2
2
|
import { runCodexHookAsync } from '../codex-hook.js';
|
|
3
3
|
import { sessionInbox } from '../inbox.js';
|
|
4
4
|
import { sweepPendingNotifications } from '../notifications.js';
|
|
5
5
|
import { cmdListSquares } from '../list.js';
|
|
6
6
|
import { nameKey, parseActivityId, sameName } from '../model.js';
|
|
7
|
-
import { commandPrefix, participantIdentity, renderGrepActivitiesView, renderEventCli,
|
|
7
|
+
import { commandPrefix, participantIdentity, renderGrepActivitiesView, renderEventCli, renderAmbientEventFacts, renderPresenceAnchor, truncateChars, withPathOutput, quoteShell, } from '../presentation.js';
|
|
8
8
|
import { actId, nowMs } from '../runtime.js';
|
|
9
9
|
import { style } from '../tty-style.js';
|
|
10
10
|
import { cmdStream, cmdStreamNdjson } from '../stream.js';
|
|
@@ -31,9 +31,6 @@ function inboxDisplay(value) {
|
|
|
31
31
|
const truncated = truncateChars(value, INBOX_DISPLAY_CHARS - 1);
|
|
32
32
|
return truncated.remaining === 0 ? truncated.text : `${truncated.text}…`;
|
|
33
33
|
}
|
|
34
|
-
function inboxLimitCommand(sessionId, json) {
|
|
35
|
-
return `square inbox --for-session ${quoteShell(sessionId)} --limit ${INBOX_MAX_LIMIT}${json ? ' --json' : ''}`;
|
|
36
|
-
}
|
|
37
34
|
export const listCommand = {
|
|
38
35
|
parse: (argv) => argv,
|
|
39
36
|
async execute(argv, context) {
|
|
@@ -305,37 +302,9 @@ function parseHistory(argv, context) {
|
|
|
305
302
|
continuationArgs: historyContinuationArgs(argv),
|
|
306
303
|
};
|
|
307
304
|
}
|
|
308
|
-
function
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
...(options.mention === undefined ? {} : { mention: options.mention }),
|
|
312
|
-
...(options.afterIndex === undefined ? {} : { after: actId(options.afterIndex) }),
|
|
313
|
-
...(options.beforeIndex === undefined ? {} : { before: actId(options.beforeIndex) }),
|
|
314
|
-
...(options.grep === undefined ? {} : { grep: options.grep }), ...(options.fixed === undefined ? {} : { fixed: options.fixed }),
|
|
315
|
-
order: 'asc',
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
function activityAsStored(activity) {
|
|
319
|
-
const index = parseActivityId(activity.id);
|
|
320
|
-
if (index === undefined)
|
|
321
|
-
throw new Error('Application returned a non-canonical activity id');
|
|
322
|
-
switch (activity.kind) {
|
|
323
|
-
case 'say': return { index, kind: 'say', actor: activity.actor, at: activity.at, body: activity.body ?? '', mentions: activity.mentions, ...(activity.reach === undefined ? {} : { reach: activity.reach }), ...(activity.reply === undefined ? {} : { reply: parseActivityId(activity.reply) ?? undefined }) };
|
|
324
|
-
case 'done': return { index, kind: 'done', actor: activity.actor, at: activity.at, body: activity.body ?? '' };
|
|
325
|
-
case 'hold': return { index, kind: 'hold', actor: activity.actor, at: activity.at, ...(activity.body === undefined ? {} : { body: activity.body }) };
|
|
326
|
-
case 'resume': return { index, kind: 'resume', actor: activity.actor, at: activity.at };
|
|
327
|
-
case 'join': return { index, kind: 'join', actor: activity.actor, at: activity.at };
|
|
328
|
-
case 'listen': return { index, kind: 'listen', actor: activity.actor, target: activity.target ?? '', at: activity.at };
|
|
329
|
-
case 'ignore': return { index, kind: 'ignore', actor: activity.actor, target: activity.target ?? '', at: activity.at };
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
function historyContinuationCommand(options, squarePath, direction, index) {
|
|
333
|
-
const args = [...(options.continuationArgs ?? []), direction, actId(index), '--limit', String(options.lastN ?? HISTORY_DEFAULT_LIMIT)];
|
|
334
|
-
return `${commandPrefix(squarePath)} history ${args.map((arg) => arg.startsWith('-') || /^act\/\d+$/.test(arg) || /^\d+$/.test(arg) ? arg : quoteShell(arg)).join(' ')}`;
|
|
335
|
-
}
|
|
336
|
-
function boundedHistoryCommand(options, squarePath) {
|
|
337
|
-
const args = [...(options.continuationArgs ?? []), '--limit', String(HISTORY_MAX_LIMIT)];
|
|
338
|
-
return `${commandPrefix(squarePath)} history ${args.map((arg) => arg.startsWith('-') || /^act\/\d+$/.test(arg) || /^\d+$/.test(arg) ? arg : quoteShell(arg)).join(' ')}`;
|
|
305
|
+
function historyContinuationCommand(options, squarePath, args) {
|
|
306
|
+
const full = [...(options.continuationArgs ?? []), ...args];
|
|
307
|
+
return `${commandPrefix(squarePath)} history ${full.map((arg) => arg.startsWith('-') || /^act\/\d+$/.test(arg) || /^\d+$/.test(arg) ? arg : quoteShell(arg)).join(' ')}`;
|
|
339
308
|
}
|
|
340
309
|
/** The archive-visible activity model: content plus the lifecycle moves that keep its story honest — a raised hand pairs with its lowering, and a departure pairs with the return. */
|
|
341
310
|
function isArchiveActivity(item) {
|
|
@@ -377,6 +346,8 @@ function renderHistoryProjection(projection, visible, noTruncate, squarePath) {
|
|
|
377
346
|
const shown = visible.filter(isArchiveActivity);
|
|
378
347
|
const preview = noTruncate || shown.length <= 1 ? undefined : 200;
|
|
379
348
|
const chunks = [];
|
|
349
|
+
// Presence anchors collect into one closing line instead of interrupting the page.
|
|
350
|
+
const anchored = [];
|
|
380
351
|
for (const activity of shown) {
|
|
381
352
|
const options = {
|
|
382
353
|
preview,
|
|
@@ -385,15 +356,18 @@ function renderHistoryProjection(projection, visible, noTruncate, squarePath) {
|
|
|
385
356
|
const rendered = renderEventCli(activity, options);
|
|
386
357
|
if (rendered !== '')
|
|
387
358
|
chunks.push(rendered);
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
359
|
+
for (const participant of projection.presenceAnchors[activity.index] ?? []) {
|
|
360
|
+
if (!anchored.some((existing) => sameName(existing, participant)))
|
|
361
|
+
anchored.push(participant);
|
|
362
|
+
}
|
|
391
363
|
}
|
|
392
364
|
if (chunks.length === 0)
|
|
393
365
|
return 'latest\n ○ no public activity in this view';
|
|
394
366
|
if (preview !== undefined && shown.some((activity) => activity.kind === 'say' && activity.body.length > preview)) {
|
|
395
367
|
chunks.push(`${commandPrefix(squarePath)} history --no-truncate`);
|
|
396
368
|
}
|
|
369
|
+
if (anchored.length > 0)
|
|
370
|
+
chunks.push(renderPresenceAnchor(anchored));
|
|
397
371
|
return chunks.join('\n\n');
|
|
398
372
|
}
|
|
399
373
|
export const historyCommand = {
|
|
@@ -403,15 +377,14 @@ export const historyCommand = {
|
|
|
403
377
|
const square = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
|
|
404
378
|
try {
|
|
405
379
|
// Keep the projection chronological; pagination chooses a stable edge,
|
|
406
|
-
// then --order only changes how the selected page is displayed.
|
|
380
|
+
// then --order only changes how the selected page is displayed. The
|
|
381
|
+
// plain archive hides `read` bookkeeping, while --at/-C/--since windows
|
|
382
|
+
// render the raw activity stream around their coordinates.
|
|
407
383
|
const projection = await historyPresentation(square, { ...options, order: 'asc' });
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
? await createSquareApplication({ cwd: context.cwd, env: { ...context.env, SQUARE_PARTICIPANT_NAME: undefined }, squarePath, clock: nowMs }).history(applicationHistoryQuery(options))
|
|
411
|
-
: undefined;
|
|
412
|
-
let events = applicationHistory === undefined ? [...projection.activities] : applicationHistory.map(activityAsStored);
|
|
384
|
+
const hideReadActs = options.atIndexes === undefined && options.beforeContext === undefined && options.afterContext === undefined && options.after === undefined;
|
|
385
|
+
let events = hideReadActs ? projection.activities.filter((activity) => activity.kind !== 'read') : [...projection.activities];
|
|
413
386
|
if (options.lastN === null && events.length > HISTORY_MAX_LIMIT) {
|
|
414
|
-
fail(`✕ history is capped at ${HISTORY_MAX_LIMIT} activities\n${
|
|
387
|
+
fail(`✕ history is capped at ${HISTORY_MAX_LIMIT} activities\n${historyContinuationCommand(options, squarePath, ['--limit', String(HISTORY_MAX_LIMIT)])}`);
|
|
415
388
|
}
|
|
416
389
|
const searching = options.grep !== undefined || options.fixed !== undefined;
|
|
417
390
|
const totalMatches = searching ? events.length : 0;
|
|
@@ -440,7 +413,7 @@ export const historyCommand = {
|
|
|
440
413
|
: allPublic.some((item) => item.index < (pageMin ?? Infinity)));
|
|
441
414
|
const cursorDirection = options.afterIndex !== undefined ? '--after' : '--before';
|
|
442
415
|
const cursorIndex = cursorDirection === '--after' ? Math.max(...publicEvents.map((item) => item.index)) : Math.min(...publicEvents.map((item) => item.index));
|
|
443
|
-
const continuation = hasMore ? `\n\n${historyContinuationCommand(options, squarePath, cursorDirection, cursorIndex)}` : '';
|
|
416
|
+
const continuation = hasMore ? `\n\n${historyContinuationCommand(options, squarePath, [cursorDirection, actId(cursorIndex), '--limit', String(options.lastN ?? HISTORY_DEFAULT_LIMIT)])}` : '';
|
|
444
417
|
return withPathOutput(squarePath, output + continuation, { participantCount: projection.participantCount });
|
|
445
418
|
}
|
|
446
419
|
finally {
|
|
@@ -522,10 +495,10 @@ export const statusCommand = {
|
|
|
522
495
|
? '◎'
|
|
523
496
|
: participant.activityCount > 0 ? '●' : '○';
|
|
524
497
|
const summary = participant.presence === 'watching'
|
|
525
|
-
? 'catching'
|
|
498
|
+
? 'is nearby · catching'
|
|
526
499
|
: participant.activityCount > 0
|
|
527
|
-
? formatRelativeTime(participant.lastActiveAt ?? result.now, result.now)
|
|
528
|
-
: `quiet · ${participant.lastActiveAt === undefined ? 'just now' : formatRelativeTime(participant.lastActiveAt, result.now)}`;
|
|
500
|
+
? `is nearby · ${formatRelativeTime(participant.lastActiveAt ?? result.now, result.now)}`
|
|
501
|
+
: `is nearby · quiet · ${participant.lastActiveAt === undefined ? 'just now' : formatRelativeTime(participant.lastActiveAt, result.now)}`;
|
|
529
502
|
const showAttention = context.name === undefined || sameName(participant.name, context.name);
|
|
530
503
|
const attention = !showAttention
|
|
531
504
|
? ''
|
|
@@ -534,7 +507,7 @@ export const statusCommand = {
|
|
|
534
507
|
: participant.unreadActivityCount > 0
|
|
535
508
|
? `${participant.unreadActivityCount} change${participant.unreadActivityCount === 1 ? '' : 's'} waiting`
|
|
536
509
|
: 'caught up';
|
|
537
|
-
return ` ${glyph} ${participantIdentity(participant.name)}${style('dim', `
|
|
510
|
+
return ` ${glyph} ${participantIdentity(participant.name)}${style('dim', ` ${summary}${attention === '' ? '' : ` · ${attention}`}`)}`;
|
|
538
511
|
}));
|
|
539
512
|
const unshown = Math.max(0, orderedHere.length - STATUS_PARTICIPANT_PREVIEW_LIMIT) + lingering;
|
|
540
513
|
if (orderedHere.length > STATUS_PARTICIPANT_PREVIEW_LIMIT) {
|
|
@@ -554,18 +527,18 @@ export const statusCommand = {
|
|
|
554
527
|
? `· ${result.holdActor === undefined ? 'someone' : participantIdentity(result.holdActor)} raised a hand${result.holdReason ? ` — ${result.holdReason}` : ''}${style('dim', ` · ${holdTime}`)}`
|
|
555
528
|
: undefined;
|
|
556
529
|
const visible = result.latestAct === undefined
|
|
557
|
-
? ''
|
|
558
|
-
:
|
|
530
|
+
? { text: '', bodyClipped: false }
|
|
531
|
+
: renderAmbientEventFacts(result.latestAct, context.name ?? '', {
|
|
559
532
|
now: result.now,
|
|
560
533
|
preview: 200,
|
|
561
534
|
actNumber: presentation.latestActNumber,
|
|
562
535
|
squareState: presentation.state,
|
|
563
536
|
});
|
|
564
|
-
const latest = visible === ''
|
|
537
|
+
const latest = visible.text === ''
|
|
565
538
|
? [result.latestAct === undefined
|
|
566
539
|
? ' ○ no public activity yet'
|
|
567
540
|
: ' · the latest words were meant for other ears']
|
|
568
|
-
: [` ${visible.replace(/\n/g, '\n ')}`];
|
|
541
|
+
: [` ${visible.text.replace(/\n/g, '\n ')}`];
|
|
569
542
|
// Presence events after the latest public act: otherwise the roster can say someone is
|
|
570
543
|
// here while the latest line shows them leaving, with nothing to reconcile the two.
|
|
571
544
|
const latestIndex = result.latestAct?.index ?? -1;
|
|
@@ -576,7 +549,7 @@ export const statusCommand = {
|
|
|
576
549
|
}
|
|
577
550
|
if (stepsIn.length > 3)
|
|
578
551
|
latest.push(style('dim', ` → … ${stepsIn.length - 3} more stepped in`));
|
|
579
|
-
if (visible.
|
|
552
|
+
if (visible.bodyClipped && result.latestAct !== undefined) {
|
|
580
553
|
latest.push(`${commandPrefix(squarePath)} history --at ${actId(result.latestAct)} -C 2 --no-truncate`);
|
|
581
554
|
}
|
|
582
555
|
const counts = [
|
|
@@ -624,7 +597,7 @@ export const inboxCommand = {
|
|
|
624
597
|
}
|
|
625
598
|
if (!sessionId)
|
|
626
599
|
fail('inbox requires --for-session <session-id>.');
|
|
627
|
-
const retry =
|
|
600
|
+
const retry = `square inbox --for-session ${quoteShell(sessionId)} --limit ${INBOX_MAX_LIMIT}${json ? ' --json' : ''}`;
|
|
628
601
|
if (duplicateLimit)
|
|
629
602
|
fail(`✕ inbox accepts one --limit\n${retry}`);
|
|
630
603
|
const limit = hasLimit
|
|
@@ -673,5 +646,5 @@ function hookCommand(runHook) {
|
|
|
673
646
|
present: (result) => process.stdout.write(result),
|
|
674
647
|
};
|
|
675
648
|
}
|
|
676
|
-
export const
|
|
649
|
+
export const claudeModCommand = hookCommand(runClaudeMod);
|
|
677
650
|
export const codexHookCommand = hookCommand(runCodexHookAsync);
|
package/dist/cli/program.js
CHANGED
|
@@ -1,46 +1,48 @@
|
|
|
1
1
|
import { helpRequest } from '../help.js';
|
|
2
2
|
import { isSquareError } from '../model.js';
|
|
3
|
-
import { formatRefusal, joinRecoveryCommand, participantsRecoveryCommand, takeoverRecoveryLines } from '../presentation.js';
|
|
3
|
+
import { commandPrefix, formatRefusal, joinRecoveryCommand, participantsRecoveryCommand, takeoverRecoveryLines } from '../presentation.js';
|
|
4
4
|
import { inSquareCount, nowMs } from '../runtime.js';
|
|
5
5
|
import { openSquare } from '../square-file-adapter.js';
|
|
6
6
|
import { closeOpenSquare } from '../open-square.js';
|
|
7
7
|
import { defaultContext, parseGlobalArgs } from './context.js';
|
|
8
8
|
import { executeRegisteredCommand, findCommand } from './registry.js';
|
|
9
|
-
async function participantCountFor(squarePath) {
|
|
10
|
-
try {
|
|
11
|
-
const square = await openSquare(squarePath, { clock: nowMs });
|
|
12
|
-
try {
|
|
13
|
-
return inSquareCount((await square.artifact.read()).state);
|
|
14
|
-
}
|
|
15
|
-
finally {
|
|
16
|
-
await closeOpenSquare(square);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
return undefined;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
9
|
async function handleSquareError(error, squarePath, name) {
|
|
24
10
|
if (isSquareError(error)) {
|
|
25
11
|
const existing = [error.message];
|
|
26
12
|
if (squarePath !== undefined && name !== undefined && error.code === 'already_joined') {
|
|
27
13
|
existing.push(...takeoverRecoveryLines(squarePath, name));
|
|
28
14
|
}
|
|
29
|
-
else if (squarePath !== undefined &&
|
|
15
|
+
else if (squarePath !== undefined && error.facts?.reason === 'never_joined') {
|
|
30
16
|
// The caller's name has never joined this square; only a join admits it.
|
|
31
17
|
if (name !== undefined)
|
|
32
18
|
existing.push(joinRecoveryCommand(squarePath, name));
|
|
33
19
|
else
|
|
34
20
|
existing.push(participantsRecoveryCommand(squarePath));
|
|
35
21
|
}
|
|
36
|
-
else if (squarePath !== undefined &&
|
|
22
|
+
else if (squarePath !== undefined && error.facts?.reason === 'not_standing') {
|
|
37
23
|
existing.push(participantsRecoveryCommand(squarePath));
|
|
38
24
|
}
|
|
25
|
+
else if (squarePath !== undefined && error.facts?.reason === 'not_addressed' && typeof error.facts.activityId === 'string') {
|
|
26
|
+
// An anchor only works for an activity the artifact actually holds.
|
|
27
|
+
existing.push(error.facts.activityExists === true
|
|
28
|
+
? `${commandPrefix(squarePath)} history --at ${error.facts.activityId} -C 2`
|
|
29
|
+
: `${commandPrefix(squarePath)} history --limit 10`);
|
|
30
|
+
}
|
|
39
31
|
if (squarePath === undefined) {
|
|
40
32
|
process.stderr.write(`${existing.join('\n')}\n`);
|
|
41
33
|
}
|
|
42
34
|
else {
|
|
43
|
-
|
|
35
|
+
let participantCount;
|
|
36
|
+
try {
|
|
37
|
+
const square = await openSquare(squarePath, { clock: nowMs });
|
|
38
|
+
try {
|
|
39
|
+
participantCount = inSquareCount((await square.artifact.read()).state);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
await closeOpenSquare(square);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch { /* the header count is best effort */ }
|
|
44
46
|
process.stderr.write(formatRefusal(squarePath, existing, participantCount === undefined ? {} : { participantCount }));
|
|
45
47
|
}
|
|
46
48
|
process.exit(error.code === 'not_found' ? 1 : 2);
|
package/dist/cli/registry.js
CHANGED
|
@@ -3,7 +3,7 @@ import { doctorCommand } from './maintenance-commands.js';
|
|
|
3
3
|
import { harnessCommand, installCommand, uninstallCommand } from './harness-command.js';
|
|
4
4
|
import { helpCommand, versionCommand } from './meta-commands.js';
|
|
5
5
|
import { mcpServerCommand } from './mcp-server-command.js';
|
|
6
|
-
import { catchCommand,
|
|
6
|
+
import { catchCommand, claudeModCommand, codexHookCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand, } from './observation-commands.js';
|
|
7
7
|
/** Every public command is an executable adapter, including aliases and utility commands. */
|
|
8
8
|
export const commandRegistry = [
|
|
9
9
|
{ names: ['build'], spec: buildCommand },
|
|
@@ -11,7 +11,7 @@ export const commandRegistry = [
|
|
|
11
11
|
{ names: ['join'], spec: joinCommand },
|
|
12
12
|
{ names: ['stream'], spec: streamCommand },
|
|
13
13
|
{ names: ['inbox'], spec: inboxCommand },
|
|
14
|
-
{ names: ['claude-
|
|
14
|
+
{ names: ['claude-mod'], spec: claudeModCommand },
|
|
15
15
|
{ names: ['codex-hook'], spec: codexHookCommand },
|
|
16
16
|
{ names: ['catch'], spec: catchCommand },
|
|
17
17
|
{ names: ['express'], spec: expressCommand },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { cmdActivity } from '../activity.js';
|
|
2
2
|
import { scanMentionCandidates } from '../mention-parse.js';
|
|
3
3
|
import { validateDoneBody } from '../decisions.js';
|
|
4
|
-
import { formatHardCap, } from '../model.js';
|
|
4
|
+
import { formatHardCap, sameName, } from '../model.js';
|
|
5
5
|
import { formatRefusal, participantCommandPrefix, participantIdentity, takeoverRecoveryLines, renderRoomChangeText, renderAmbientEvent, withPathOutput, } from '../presentation.js';
|
|
6
6
|
import { hostLedgerForEnv, hasAutomaticDeliveryIdentity, } from '../registry.js';
|
|
7
7
|
import { actId, nowMs } from '../runtime.js';
|
|
@@ -59,7 +59,7 @@ export const buildCommand = {
|
|
|
59
59
|
await createSquare(squarePath, intent.options, snippet);
|
|
60
60
|
const cap = intent.options.hardCap === null ? 'unlimited' : formatHardCap(intent.options.hardCap);
|
|
61
61
|
const throttle = intent.options.throttlePerMinute === undefined ? [] : [` · throttle ${intent.options.throttlePerMinute}/min`];
|
|
62
|
-
return withPathOutput(squarePath, ['
|
|
62
|
+
return withPathOutput(squarePath, ['· the square stands ready', ` · cap ${cap}`, ...throttle].join('\n'), { participantCount: 0 });
|
|
63
63
|
},
|
|
64
64
|
present: (result) => process.stdout.write(result),
|
|
65
65
|
};
|
|
@@ -130,11 +130,15 @@ export const joinCommand = {
|
|
|
130
130
|
: `✓ you banished the original ${participantIdentity(joinedName)} — the name is yours`;
|
|
131
131
|
const isRejoin = joinKind !== 'joined';
|
|
132
132
|
const reconnect = joinKind === 'reconnected';
|
|
133
|
+
// The long scene belongs to a name's first join here; a return reads its own line.
|
|
134
|
+
const joinedBefore = after.state.acts.filter((act) => act.kind === 'join' && sameName(act.actor, joinedName)).length > 1;
|
|
135
|
+
const rejoinScene = '*the flagstones are where you left them. so is your shadow.*';
|
|
136
|
+
const entryScene = joinKind !== 'joined' ? '' : joinedBefore ? rejoinScene : scene;
|
|
133
137
|
const output = [
|
|
134
138
|
entryLine,
|
|
135
139
|
'',
|
|
136
140
|
"· carved into the fountain's edge: every word here lands on a real ear — speak when someone needs it.",
|
|
137
|
-
...(reconnect ||
|
|
141
|
+
...(reconnect || entryScene === '' ? [] : ['', entryScene]),
|
|
138
142
|
...(isRejoin || contextText === '' ? [] : ['', style('dim', 'context'), contextText]),
|
|
139
143
|
...(isRejoin || activities === '' ? [] : ['', style('dim', 'recent activity'), activities]),
|
|
140
144
|
...fallback,
|
|
@@ -193,8 +197,8 @@ export const expressCommand = {
|
|
|
193
197
|
async execute(intent, context) {
|
|
194
198
|
const squarePath = requireSquarePath(context);
|
|
195
199
|
const body = await resolveBody(intent.activity);
|
|
196
|
-
if (intent.reach === undefined && !intent.noMention && intent.mentions.length === 0 && scanMentionCandidates(body).length === 0) {
|
|
197
|
-
fail(
|
|
200
|
+
if (intent.reach === undefined && !intent.noMention && intent.mentions.length === 0 && intent.reply === undefined && scanMentionCandidates(body).length === 0) {
|
|
201
|
+
fail("✕ express needs --mention <name>, --no-mention, --bell, or an @name in the body\n · --reply <activity-id> also reaches the author it answers\nsquare express --help");
|
|
198
202
|
}
|
|
199
203
|
await cmdActivity(squarePath, intent.name, body, (value) => value, {
|
|
200
204
|
force: intent.force,
|
|
@@ -304,7 +308,7 @@ export const doneCommand = {
|
|
|
304
308
|
const name = result.activity.actor;
|
|
305
309
|
const presentation = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
|
|
306
310
|
const participantCount = (await entryPresentation(presentation, name).finally(() => closeOpenSquare(presentation))).participantCount;
|
|
307
|
-
return withPathOutput(squarePath, `○
|
|
311
|
+
return withPathOutput(squarePath, `○ you stepped out — your footsteps fade · ${result.activity.id}`, { participantCount });
|
|
308
312
|
},
|
|
309
313
|
present: (result) => process.stdout.write(result),
|
|
310
314
|
};
|
package/dist/codex-hook.js
CHANGED
|
@@ -11,17 +11,6 @@ const CODEX_HOOK_EVENTS = {
|
|
|
11
11
|
Stop: 'Stop',
|
|
12
12
|
};
|
|
13
13
|
const defaultTrace = (line) => { process.stderr.write(`${line}\n`); };
|
|
14
|
-
/** Per-stage timings, emitted as each stage completes so a killed hook still leaves a trace. */
|
|
15
|
-
function stageTracer(trace) {
|
|
16
|
-
const startedAt = Date.now();
|
|
17
|
-
let mark = startedAt;
|
|
18
|
-
return (stage, extra = '') => {
|
|
19
|
-
const now = Date.now();
|
|
20
|
-
const durationMs = now - mark;
|
|
21
|
-
mark = now;
|
|
22
|
-
trace(`square-codex-hook: stage=${stage} durationMs=${durationMs} totalMs=${now - startedAt}${extra === '' ? '' : ` ${extra}`}`);
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
14
|
function hookBudgetMs(env) {
|
|
26
15
|
const configured = Number(env.SQUARE_CODEX_HOOK_BUDGET_MS ?? CODEX_HOOK_BUDGET_MS);
|
|
27
16
|
return Number.isFinite(configured) && configured > 0 ? configured : CODEX_HOOK_BUDGET_MS;
|
|
@@ -34,7 +23,15 @@ export async function codexHookResponse(input, lookup = sessionInbox, env = proc
|
|
|
34
23
|
const hookEventName = CODEX_HOOK_EVENTS[input.hook_event_name];
|
|
35
24
|
if (hookEventName === undefined)
|
|
36
25
|
return undefined;
|
|
37
|
-
|
|
26
|
+
// Per-stage timings, emitted as each stage completes so a killed hook still leaves a trace.
|
|
27
|
+
const startedAt = Date.now();
|
|
28
|
+
let mark = startedAt;
|
|
29
|
+
const stage = (name, extra = '') => {
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const durationMs = now - mark;
|
|
32
|
+
mark = now;
|
|
33
|
+
trace(`square-codex-hook: stage=${name} durationMs=${durationMs} totalMs=${now - startedAt}${extra === '' ? '' : ` ${extra}`}`);
|
|
34
|
+
};
|
|
38
35
|
const signal = AbortSignal.timeout(hookBudgetMs(env));
|
|
39
36
|
const sweepDeadline = Date.now() + Math.min(PRIVILEGED_HOOK_BUDGET_MS, hookBudgetMs(env));
|
|
40
37
|
const cwd = typeof input.cwd === 'string' ? input.cwd : process.cwd();
|
package/dist/codex-queue.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { WakeAdapter,
|
|
1
|
+
import type { WakeAdapter, WakeAdapterResult } from './delivery.js';
|
|
2
2
|
import { type WakeRoute } from './model.js';
|
|
3
3
|
export interface CodexQueueRequest {
|
|
4
4
|
threadId: string;
|
|
@@ -23,6 +23,6 @@ export declare class CodexQueueAdapter implements WakeAdapter {
|
|
|
23
23
|
private readonly opts;
|
|
24
24
|
readonly kind: "codex-queue";
|
|
25
25
|
constructor(opts?: CodexQueueAdapterOptions);
|
|
26
|
-
dispatch(address: Readonly<Record<string, string>>, payload: string, beforeSend: () => Promise<boolean>, timeoutMs?: number): Promise<
|
|
26
|
+
dispatch(address: Readonly<Record<string, string>>, payload: string, beforeSend: () => Promise<boolean>, timeoutMs?: number): Promise<WakeAdapterResult>;
|
|
27
27
|
}
|
|
28
28
|
export type { WakeRoute };
|
package/dist/codex-queue.js
CHANGED
|
@@ -38,22 +38,24 @@ export class CodexQueueAdapter {
|
|
|
38
38
|
const remainingMs = () => Math.max(0, deadline - Date.now());
|
|
39
39
|
const threadId = address.threadId?.trim();
|
|
40
40
|
if (!threadId) {
|
|
41
|
-
return { outcome: '
|
|
41
|
+
return { outcome: 'failed', unavailable: true, signature: 'invalid_address', message: 'Codex route has no thread id.', routeStale: true };
|
|
42
42
|
}
|
|
43
43
|
const env = this.opts.env ?? process.env;
|
|
44
44
|
if (!await codexQueueEligible(threadId, env)) {
|
|
45
45
|
return {
|
|
46
|
-
outcome: '
|
|
46
|
+
outcome: 'failed',
|
|
47
|
+
unavailable: true,
|
|
47
48
|
signature: 'boundary_not_stopped',
|
|
48
49
|
message: 'The Codex thread has not reached a current Stop boundary.',
|
|
49
50
|
retainRoute: true,
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
if (!(await beforeSend()))
|
|
53
|
-
return { outcome: '
|
|
54
|
+
return { outcome: 'gate-rejected' };
|
|
54
55
|
if (!await codexQueueEligible(threadId, env)) {
|
|
55
56
|
return {
|
|
56
|
-
outcome: '
|
|
57
|
+
outcome: 'failed',
|
|
58
|
+
unavailable: true,
|
|
57
59
|
signature: 'boundary_not_stopped',
|
|
58
60
|
message: 'The Codex thread left its Stop boundary before queueing.',
|
|
59
61
|
retainRoute: true,
|
|
@@ -61,7 +63,7 @@ export class CodexQueueAdapter {
|
|
|
61
63
|
}
|
|
62
64
|
const remaining = remainingMs();
|
|
63
65
|
if (remaining === 0) {
|
|
64
|
-
return { outcome: '
|
|
66
|
+
return { outcome: 'failed', unavailable: true, signature: 'dispatch_budget_exhausted', message: 'The wake dispatch budget elapsed before queueing.', retainRoute: true };
|
|
65
67
|
}
|
|
66
68
|
try {
|
|
67
69
|
(this.opts.sendQueue ?? sendCodexQueue)({ threadId, message: payload }, { env, timeoutMs: remaining });
|
package/dist/decisions.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { type ActivitiesOptions, type Act, type StoredAct, type SquareState, type Reach, type HardCap } from './model.js';
|
|
2
|
-
import { directedPeerSays, peerRoomChanges } from './activity-feed.js';
|
|
3
2
|
import { type Perception } from './square-core.js';
|
|
4
3
|
import { type DeliveryModel } from './delivery.js';
|
|
5
4
|
export interface UnreadActivitySummary {
|
|
@@ -36,14 +35,11 @@ export declare function decideImplicitJoin(squareState: SquareState, name: strin
|
|
|
36
35
|
export type ActDecision = {
|
|
37
36
|
type: 'sent';
|
|
38
37
|
act: Act;
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
pendingPublic: ReturnType<typeof directedPeerSays>;
|
|
42
|
-
pendingRoomChanges: ReturnType<typeof peerRoomChanges>;
|
|
38
|
+
/** The replied-to author was not standing, so the reply landed without reaching them. */
|
|
39
|
+
replyAuthorNotHere?: string;
|
|
43
40
|
} | {
|
|
44
41
|
type: 'blocked';
|
|
45
42
|
activitySummaries: UnreadActivitySummary[];
|
|
46
|
-
unreadRoomChanges: ReturnType<typeof peerRoomChanges>;
|
|
47
43
|
} | {
|
|
48
44
|
type: 'capped';
|
|
49
45
|
count: number;
|
package/dist/decisions.js
CHANGED
|
@@ -2,7 +2,7 @@ import { SquareError, sameName, validateName, } from './model.js';
|
|
|
2
2
|
import { participantIdentity } from './participant-identity.js';
|
|
3
3
|
import { UNREAD_BLOCK_GRACE_MS, actId, actStableIndex, foldedState, freshWatchLease, publicActs, resolveRosterName, rosterNames, THROTTLE_WINDOW_MS, } from './runtime.js';
|
|
4
4
|
import { actDelta, directedPeerSays } from './activity-feed.js';
|
|
5
|
-
import { formatActivityId, isIgnored, isListening, listeningTo, MAX_IDENTITY_SET_SIZE, validate } from './square-core.js';
|
|
5
|
+
import { actorOf, formatActivityId, isIgnored, isListening, listeningTo, MAX_IDENTITY_SET_SIZE, validate } from './square-core.js';
|
|
6
6
|
import { deriveDeliveryModel } from './delivery.js';
|
|
7
7
|
import { compileSearchPattern } from './search.js';
|
|
8
8
|
import { scanMentionCandidates, resolveNameAt } from './mention-parse.js';
|
|
@@ -10,13 +10,10 @@ export function resolveKnownName(squareState, name) {
|
|
|
10
10
|
validateName(name);
|
|
11
11
|
const known = resolveRosterName(squareState, name);
|
|
12
12
|
if (known === undefined) {
|
|
13
|
-
throw new SquareError('invalid_args', `✕ ${participantIdentity(name)} has never stepped into this square
|
|
13
|
+
throw new SquareError('invalid_args', `✕ ${participantIdentity(name)} has never stepped into this square`, { reason: 'never_joined' });
|
|
14
14
|
}
|
|
15
15
|
return known;
|
|
16
16
|
}
|
|
17
|
-
function participantState(state, name) {
|
|
18
|
-
return state.participants.find((participant) => sameName(participant.name, name));
|
|
19
|
-
}
|
|
20
17
|
export function decideJoin(squareState, name, now) {
|
|
21
18
|
validateName(name);
|
|
22
19
|
const knownName = resolveRosterName(squareState, name);
|
|
@@ -38,7 +35,7 @@ export function decideImplicitJoin(squareState, name, now) {
|
|
|
38
35
|
const knownName = resolveRosterName(squareState, name);
|
|
39
36
|
const joinedName = knownName ?? name;
|
|
40
37
|
if (knownName !== undefined) {
|
|
41
|
-
const current =
|
|
38
|
+
const current = foldedState(squareState).participants.find((participant) => sameName(participant.name, knownName));
|
|
42
39
|
return { joinedName, state: current?.joined === true ? 'active' : 'done' };
|
|
43
40
|
}
|
|
44
41
|
return {
|
|
@@ -116,7 +113,7 @@ export function decideAct(squareState, input) {
|
|
|
116
113
|
validateName(requested);
|
|
117
114
|
const resolved = joinedNames.find((candidate) => sameName(candidate, requested));
|
|
118
115
|
if (resolved === undefined) {
|
|
119
|
-
throw new SquareError('invalid_args', `✕ ${participantIdentity(requested)} is not standing in this square
|
|
116
|
+
throw new SquareError('invalid_args', `✕ ${participantIdentity(requested)} is not standing in this square`, { reason: 'not_standing' });
|
|
120
117
|
}
|
|
121
118
|
if (!mentionNames.some((existing) => sameName(existing, resolved))) {
|
|
122
119
|
if (mentionNames.length >= MAX_IDENTITY_SET_SIZE) {
|
|
@@ -156,11 +153,11 @@ export function decideAct(squareState, input) {
|
|
|
156
153
|
lines.push(`✕ ${notStanding.map((candidate) => participantIdentity(candidate.token)).join(', ')} ${notStanding.length === 1 ? 'is' : 'are'} not standing in this square`);
|
|
157
154
|
}
|
|
158
155
|
lines.push(' · wrap literal @text in backticks, or pass --no-mention to land bare');
|
|
159
|
-
throw new SquareError('invalid_args', lines.join('\n'));
|
|
156
|
+
throw new SquareError('invalid_args', lines.join('\n'), { reason: 'unmatched_mention' });
|
|
160
157
|
}
|
|
161
158
|
}
|
|
162
159
|
if (reach === 'bell' && mentionNames.length > 0) {
|
|
163
|
-
throw new SquareError('invalid_args', '
|
|
160
|
+
throw new SquareError('invalid_args', '✕ a bell cannot be combined with a mention — remove --mention or the @name in the body.', { reason: 'bell_mention_conflict' });
|
|
164
161
|
}
|
|
165
162
|
const reply = input.reply;
|
|
166
163
|
if (reply !== undefined) {
|
|
@@ -169,7 +166,14 @@ export function decideAct(squareState, input) {
|
|
|
169
166
|
throw new SquareError('invalid_args', `Unknown reply activity: ${label}`);
|
|
170
167
|
}
|
|
171
168
|
}
|
|
172
|
-
|
|
169
|
+
// A non-standing author never rejects the activity: the reply still lands and the
|
|
170
|
+
// speaker is told the notification did not reach them.
|
|
171
|
+
const repliedTo = reply === undefined ? undefined : squareState.acts.find((act) => act.index === reply);
|
|
172
|
+
const repliedToAuthor = repliedTo === undefined ? undefined : actorOf(repliedTo);
|
|
173
|
+
const replyAuthorNotHere = repliedToAuthor === undefined || sameName(repliedToAuthor, name)
|
|
174
|
+
|| state.participants.some((participant) => participant.joined && sameName(participant.name, repliedToAuthor))
|
|
175
|
+
? undefined
|
|
176
|
+
: repliedToAuthor;
|
|
173
177
|
const result = validate(state, {
|
|
174
178
|
kind: 'say', actor: name, at: now, body, mentions: mentionNames,
|
|
175
179
|
...(reach !== undefined ? { reach } : {}),
|
|
@@ -194,15 +198,13 @@ export function decideAct(squareState, input) {
|
|
|
194
198
|
const delivery = deriveDeliveryModel(squareState);
|
|
195
199
|
const delta = actDelta(squareState.acts, delivery.cursorFor(name));
|
|
196
200
|
const unreadPublic = directedPeerSays(squareState, delta, name, delivery);
|
|
197
|
-
const unreadRoomChanges = [];
|
|
198
201
|
const activitySummaries = unreadActivitySummaries(squareState, name, now);
|
|
199
202
|
const latestActivityAgeMs = activitySummaries[0]?.latestActivityAgeMs;
|
|
200
203
|
const hasUnread = unreadPublic.length > 0;
|
|
201
204
|
const hasFreshUnreadActivity = latestActivityAgeMs !== undefined && latestActivityAgeMs <= UNREAD_BLOCK_GRACE_MS;
|
|
202
205
|
if (!force && hasUnread && !hasFreshUnreadActivity) {
|
|
203
|
-
return { type: 'blocked', activitySummaries
|
|
206
|
+
return { type: 'blocked', activitySummaries };
|
|
204
207
|
}
|
|
205
|
-
const ownActCount = (current?.activityCount ?? 0) + 1;
|
|
206
208
|
return {
|
|
207
209
|
type: 'sent',
|
|
208
210
|
act: {
|
|
@@ -210,10 +212,7 @@ export function decideAct(squareState, input) {
|
|
|
210
212
|
...(reach !== undefined ? { reach } : {}),
|
|
211
213
|
...(reply !== undefined ? { reply } : {}),
|
|
212
214
|
},
|
|
213
|
-
|
|
214
|
-
ownActCount,
|
|
215
|
-
pendingPublic: unreadPublic,
|
|
216
|
-
pendingRoomChanges: unreadRoomChanges,
|
|
215
|
+
...(replyAuthorNotHere === undefined ? {} : { replyAuthorNotHere }),
|
|
217
216
|
};
|
|
218
217
|
}
|
|
219
218
|
export function validateDoneBody(body) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type DirectedNotificationRoute } from './delivery.js';
|
|
2
|
-
import {
|
|
3
|
-
import { type WakeReleaseDiagnostic } from './wake-attempts.js';
|
|
2
|
+
import type { WakeAttempt, WakeReleaseDiagnostic } from './wake-evidence.js';
|
|
4
3
|
export type DeliveryHealthKind = 'awaiting' | 'wake-accepted' | 'wake-unknown' | 'presented-not-delivered' | 'unreachable';
|
|
5
4
|
export interface DeliveryHealthItem {
|
|
6
5
|
squarePath: string;
|
package/dist/delivery-health.js
CHANGED
|
@@ -71,10 +71,6 @@ function displayField(value) {
|
|
|
71
71
|
const truncated = truncateChars(value, DISPLAY_FIELD_LIMIT - 1);
|
|
72
72
|
return truncated.remaining === 0 ? truncated.text : `${truncated.text}…`;
|
|
73
73
|
}
|
|
74
|
-
function formatItem(item) {
|
|
75
|
-
const evidence = item.attempt?.signature === undefined ? '' : ` · ${displayField(item.attempt.signature)}`;
|
|
76
|
-
return ` · ${formatActivityId(item.actIndex)} → ${displayField(participantIdentity(item.recipient))} from ${displayField(participantIdentity(item.actor))} · ${formatDuration(item.ageMs)}${evidence}`;
|
|
77
|
-
}
|
|
78
74
|
export function renderDeliveryHealth(items, releases = [], now = Date.now()) {
|
|
79
75
|
const out = items.length === 0 ? ['✓ no pending delivery attention'] : [`· delivery attention · ${items.length} pending`];
|
|
80
76
|
if (items.length > 0) {
|
|
@@ -85,7 +81,10 @@ export function renderDeliveryHealth(items, releases = [], now = Date.now()) {
|
|
|
85
81
|
continue;
|
|
86
82
|
out.push(`${ACTIONABLE.has(kind) ? '✕' : '○'} ${kind}: ${group.length}`);
|
|
87
83
|
const details = group.slice(0, DETAIL_LIMIT - displayed);
|
|
88
|
-
out.push(...details.map(
|
|
84
|
+
out.push(...details.map((item) => {
|
|
85
|
+
const evidence = item.attempt?.signature === undefined ? '' : ` · ${displayField(item.attempt.signature)}`;
|
|
86
|
+
return ` · ${formatActivityId(item.actIndex)} → ${displayField(participantIdentity(item.recipient))} from ${displayField(participantIdentity(item.actor))} · ${formatDuration(item.ageMs)}${evidence}`;
|
|
87
|
+
}));
|
|
89
88
|
displayed += details.length;
|
|
90
89
|
}
|
|
91
90
|
if (items.length > DETAIL_LIMIT)
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { HostLedgerPort,
|
|
1
|
+
import type { SquareState } from './model.js';
|
|
2
|
+
import type { HostLedgerPort, SquareArtifactPort, DeliverPendingInput, DeliveryResult } from './ports.js';
|
|
3
3
|
import { deriveDeliveryModel } from './delivery.js';
|
|
4
|
-
import { type WakeAttempt } from './square-projections.js';
|
|
5
|
-
export declare function observeSquare(input: ObserveSquareInput): Promise<SquareObservation>;
|
|
6
4
|
export declare function deliverPending(input: DeliverPendingInput): Promise<DeliveryResult>;
|
|
7
|
-
export declare function selectPendingWakeActivities(state: SquareState, routes: readonly PresenceRecord[], attempts: readonly WakeAttempt[], now: number, graceMs: number, limit: number, delivery?: import("./delivery.js").DeliveryModel, presentations?: readonly PresentationEvidenceProjection[]): number[];
|
|
8
5
|
export declare function sweepPending(input: {
|
|
9
6
|
readonly artifact: SquareArtifactPort;
|
|
10
7
|
readonly hostLedger: HostLedgerPort;
|