@astrosheep/square 0.3.92 → 0.3.94
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/activity-feed.d.ts +3 -5
- package/dist/activity-feed.js +16 -14
- package/dist/artifact.js +2 -2
- package/dist/boundary-presentation.d.ts +2 -2
- package/dist/catch-decisions.d.ts +4 -6
- package/dist/catch-decisions.js +4 -4
- package/dist/claude-delivery-status.js +10 -4
- package/dist/claude-delivery.js +19 -11
- package/dist/claude-mod.js +24 -53
- package/dist/cli/context.d.ts +9 -4
- package/dist/cli/context.js +30 -25
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +26 -14
- package/dist/cli/json.d.ts +3 -0
- package/dist/cli/json.js +14 -0
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.d.ts +1 -3
- package/dist/cli/observation-commands.js +43 -56
- package/dist/cli/program.js +2 -2
- package/dist/cli/registry.js +6 -3
- package/dist/cli/square-commands.d.ts +1 -1
- package/dist/cli/square-commands.js +46 -54
- package/dist/codex-hook.d.ts +3 -2
- package/dist/codex-hook.js +13 -4
- package/dist/codex-queue.js +4 -4
- package/dist/decisions.d.ts +5 -11
- package/dist/decisions.js +9 -20
- package/dist/delivery-deferral.js +2 -2
- package/dist/delivery-health.d.ts +0 -1
- package/dist/delivery-health.js +1 -3
- package/dist/delivery-operations.d.ts +2 -2
- package/dist/delivery-operations.js +38 -38
- package/dist/delivery.d.ts +1 -1
- package/dist/delivery.js +1 -1
- package/dist/harness-links.d.ts +1 -10
- package/dist/harness-links.js +144 -109
- package/dist/harness.js +4 -13
- package/dist/help.js +12 -10
- package/dist/inbox.d.ts +9 -22
- package/dist/inbox.js +23 -27
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +23 -24
- package/dist/model.d.ts +8 -15
- package/dist/model.js +4 -7
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +6 -5
- package/dist/operation-presentation.d.ts +5 -4
- package/dist/operation-presentation.js +50 -45
- package/dist/owner.d.ts +11 -0
- package/dist/owner.js +32 -0
- package/dist/paseo-delivery.d.ts +4 -1
- package/dist/paseo-delivery.js +7 -12
- package/dist/paseo-state.d.ts +2 -2
- package/dist/paseo-state.js +6 -4
- package/dist/plugins/opencode/delivery.js +27 -15
- package/dist/ports.d.ts +13 -33
- package/dist/presentation-operations.js +4 -4
- package/dist/presentation.d.ts +5 -8
- package/dist/presentation.js +33 -43
- package/dist/runtime.d.ts +1 -7
- package/dist/runtime.js +0 -14
- package/dist/seats.d.ts +2 -3
- package/dist/seats.js +7 -15
- package/dist/session-lifecycle.d.ts +6 -2
- package/dist/session-lifecycle.js +39 -11
- package/dist/sqlite-square.d.ts +36 -22
- package/dist/sqlite-square.js +138 -161
- package/dist/square-api.d.ts +15 -10
- package/dist/square-api.js +26 -22
- package/dist/square-core.d.ts +0 -5
- package/dist/square-core.js +0 -9
- package/dist/square-domain.d.ts +4 -2
- package/dist/square-domain.js +56 -21
- package/dist/square-facade.d.ts +45 -87
- package/dist/square-index.d.ts +5 -13
- package/dist/square-index.js +13 -38
- package/dist/square-location.d.ts +1 -14
- package/dist/square-location.js +4 -69
- package/dist/square-migration-host-ledger.d.ts +2 -2
- package/dist/square-migration-host-ledger.js +6 -5
- package/dist/square-migration.d.ts +2 -1
- package/dist/square-migration.js +52 -30
- package/dist/square-sqlite.d.ts +6 -2
- package/dist/square-sqlite.js +54 -28
- package/dist/square-tools.d.ts +7 -10
- package/dist/square-tools.js +22 -54
- package/dist/stream.js +4 -5
- package/dist/views.d.ts +21 -10
- package/dist/views.js +38 -38
- package/dist/wakes.d.ts +1 -2
- package/dist/wakes.js +1 -1
- package/guides/application-facade-delivery-evidence.md +1 -1
- package/guides/claude-native.md +18 -9
- package/guides/codex-delivery.md +17 -6
- package/guides/mcp-connection-lifetime.md +1 -1
- package/guides/mcp.md +3 -3
- package/guides/migration.md +142 -151
- package/guides/operation-cancellation.md +1 -1
- package/guides/participant-ownership.md +78 -47
- package/guides/pi-tools.md +33 -4
- package/guides/primitive-history-consolidation.md +1 -1
- package/guides/row-storage-design.md +8 -8
- package/guides/square-api.md +244 -88
- package/package.json +2 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +27 -17
- package/plugins/paseo/client/palette.ts +18 -18
- package/plugins/paseo/client/square-message.tsx +17 -23
- package/plugins/pi/square-pi.js +17 -17
- package/dist/square-backend.d.ts +0 -13
- package/dist/square-backend.js +0 -1
- package/dist/square-stdio.d.ts +0 -22
- package/dist/square-stdio.js +0 -235
- package/dist/stdio-server.d.ts +0 -3
- package/dist/stdio-server.js +0 -212
- package/guides/backends.md +0 -193
package/dist/codex-queue.js
CHANGED
|
@@ -12,7 +12,7 @@ export class CodexQueueTransport {
|
|
|
12
12
|
const { address } = request.route;
|
|
13
13
|
const threadId = address.threadId?.trim();
|
|
14
14
|
if (!threadId) {
|
|
15
|
-
return { outcome: 'failed',
|
|
15
|
+
return { outcome: 'failed', signature: 'invalid_address', message: 'Codex route has no thread id.' };
|
|
16
16
|
}
|
|
17
17
|
const env = this.opts.env ?? process.env;
|
|
18
18
|
const payload = request.artifact === undefined ? undefined
|
|
@@ -28,15 +28,15 @@ export class CodexQueueTransport {
|
|
|
28
28
|
});
|
|
29
29
|
const remaining = deadline - Date.now();
|
|
30
30
|
if (remaining <= 0) {
|
|
31
|
-
return { outcome: 'failed',
|
|
31
|
+
return { outcome: 'failed', signature: 'dispatch_budget_exhausted', message: 'The wake dispatch budget elapsed before queueing.' };
|
|
32
32
|
}
|
|
33
33
|
await agent.queue(payload, { timeoutMs: remaining });
|
|
34
34
|
return { outcome: 'accepted' };
|
|
35
35
|
}
|
|
36
36
|
catch (error) {
|
|
37
37
|
if (error instanceof DeliveryError && error.code === 'session_inactive') {
|
|
38
|
-
return { outcome: 'failed',
|
|
39
|
-
message: 'The Codex thread has no current Stop boundary for queueing.'
|
|
38
|
+
return { outcome: 'failed', signature: 'boundary_not_stopped',
|
|
39
|
+
message: 'The Codex thread has no current Stop boundary for queueing.' };
|
|
40
40
|
}
|
|
41
41
|
const message = error instanceof Error ? error.message : String(error);
|
|
42
42
|
if (!(error instanceof DeliveryError) || error.maybeDelivered)
|
package/dist/decisions.d.ts
CHANGED
|
@@ -5,21 +5,14 @@ type TimedAct<K extends Act['kind'] = Act['kind']> = Extract<Act, {
|
|
|
5
5
|
}> & {
|
|
6
6
|
at: number;
|
|
7
7
|
};
|
|
8
|
-
import type { ExpressResult, ParticipantSummary
|
|
9
|
-
export type { ParticipantSummary as ParticipantStatus, ParticipantPresence as CorePresenceState, UnreadActivitySummary, UnreadActivityPreview } from './square-facade.js';
|
|
8
|
+
import type { ExpressResult, ParticipantSummary, UnreadActivitySummary } from './square-facade.js';
|
|
10
9
|
export declare function resolveKnownName(facts: SquareRead, name: string): string;
|
|
11
10
|
export interface DecideJoinResult {
|
|
12
11
|
joinedName: string;
|
|
13
12
|
addParticipant: boolean;
|
|
14
13
|
joinAct?: TimedAct<'join'>;
|
|
15
14
|
}
|
|
16
|
-
export interface DecideImplicitJoinResult {
|
|
17
|
-
joinedName: string;
|
|
18
|
-
state: 'joined' | 'active' | 'done';
|
|
19
|
-
joinAct?: TimedAct<'join'>;
|
|
20
|
-
}
|
|
21
15
|
export declare function decideJoin(facts: SquareRead, name: string, now: number): DecideJoinResult;
|
|
22
|
-
export declare function decideImplicitJoin(facts: SquareRead, name: string, now: number): DecideImplicitJoinResult;
|
|
23
16
|
export type ActDecision = ({
|
|
24
17
|
type: 'sent';
|
|
25
18
|
act: TimedAct;
|
|
@@ -40,7 +33,7 @@ export type ActDecision = ({
|
|
|
40
33
|
type: 'bell_quota';
|
|
41
34
|
nextAt: number;
|
|
42
35
|
};
|
|
43
|
-
/** Count the directed suffix
|
|
36
|
+
/** Count the directed suffix and hydrate only its last activity by index per spelling. */
|
|
44
37
|
export declare function unreadActivitySummaries(facts: SquareRead, name: string, now: number): UnreadActivitySummary[];
|
|
45
38
|
export declare function decideAct(facts: SquareRead, input: {
|
|
46
39
|
name: string;
|
|
@@ -61,5 +54,6 @@ export declare function coreUnlisten(facts: SquareRead, actor: string, target: s
|
|
|
61
54
|
export declare function coreListening(facts: SquareRead, actor: string): readonly string[];
|
|
62
55
|
export declare function coreHold(facts: SquareRead, actor: string, body: string, now: number): TimedAct<'hold'>;
|
|
63
56
|
export declare function coreResume(facts: SquareRead, actor: string, now: number): TimedAct<'resume'>;
|
|
64
|
-
export declare function compareParticipantActivity(a: Pick<
|
|
65
|
-
export declare function coreParticipants(facts: SquareRead, now: number):
|
|
57
|
+
export declare function compareParticipantActivity(a: Pick<ParticipantSummary, 'name' | 'lastActiveAt'>, b: Pick<ParticipantSummary, 'name' | 'lastActiveAt'>): number;
|
|
58
|
+
export declare function coreParticipants(facts: SquareRead, now: number): ParticipantSummary[];
|
|
59
|
+
export {};
|
package/dist/decisions.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SquareError, isSquareError, sameName,
|
|
1
|
+
import { SquareError, isSquareError, sameName, validateName, validateActivityMetadata, activityMetadataHasContent, } from './model.js';
|
|
2
2
|
import { participantIdentity } from './participant-identity.js';
|
|
3
3
|
import { UNREAD_BLOCK_GRACE_MS, freshWatchLease, readCursor, FACT_PAGE_SIZE, THROTTLE_WINDOW_MS } from './runtime.js';
|
|
4
4
|
import { formatActivityId, MAX_IDENTITY_SET_SIZE } from './square-core.js';
|
|
@@ -17,12 +17,6 @@ export function decideJoin(facts, name, now) {
|
|
|
17
17
|
return current?.joined ? { joinedName, addParticipant: false }
|
|
18
18
|
: { joinedName, addParticipant: current === undefined, joinAct: { kind: 'join', actor: joinedName, at: now } };
|
|
19
19
|
}
|
|
20
|
-
export function decideImplicitJoin(facts, name, now) {
|
|
21
|
-
validateName(name);
|
|
22
|
-
const current = facts.participant(name);
|
|
23
|
-
return current === undefined ? { joinedName: name, state: 'joined', joinAct: { kind: 'join', actor: name, at: now } }
|
|
24
|
-
: { joinedName: current.name, state: current.joined ? 'active' : 'done' };
|
|
25
|
-
}
|
|
26
20
|
function validateActivityName(name) {
|
|
27
21
|
try {
|
|
28
22
|
validateName(name);
|
|
@@ -54,34 +48,28 @@ function requireStanding(current) {
|
|
|
54
48
|
if (!current.joined)
|
|
55
49
|
throw new SquareError('not_joined', `${participantIdentity(current.name)} has not joined this square`);
|
|
56
50
|
}
|
|
57
|
-
/** Count the directed suffix
|
|
51
|
+
/** Count the directed suffix and hydrate only its last activity by index per spelling. */
|
|
58
52
|
export function unreadActivitySummaries(facts, name, now) {
|
|
59
53
|
let afterIndex = readCursor(facts, name);
|
|
60
|
-
const numbers = new Map();
|
|
61
54
|
const summaries = new Map();
|
|
62
55
|
while (true) {
|
|
63
56
|
const page = facts.directed(name, { afterIndex }, { edge: 'oldest', limit: FACT_PAGE_SIZE });
|
|
64
57
|
for (const item of page.items) {
|
|
65
|
-
const
|
|
66
|
-
const number = (numbers.get(key) ?? 0) + 1;
|
|
67
|
-
numbers.set(key, number);
|
|
68
|
-
const summary = summaries.get(item.actor) ?? { count: 0, latestAt: -Infinity, previews: [] };
|
|
58
|
+
const summary = summaries.get(item.actor) ?? { count: 0, latestAt: -Infinity, lastIndex: item.index };
|
|
69
59
|
summary.count++;
|
|
70
60
|
summary.latestAt = Math.max(summary.latestAt, item.at);
|
|
71
|
-
summary.
|
|
72
|
-
if (summary.previews.length > 3)
|
|
73
|
-
summary.previews.shift();
|
|
61
|
+
summary.lastIndex = item.index;
|
|
74
62
|
summaries.set(item.actor, summary);
|
|
75
63
|
}
|
|
76
64
|
if (!page.hasMore)
|
|
77
65
|
break;
|
|
78
66
|
afterIndex = page.items.at(-1).index;
|
|
79
67
|
}
|
|
80
|
-
const selected = facts.activities([...summaries.values()].
|
|
68
|
+
const selected = facts.activities([...summaries.values()].map((item) => item.lastIndex));
|
|
81
69
|
const byIndex = new Map(selected.map((item) => [item.index, item]));
|
|
82
70
|
return [...summaries].map(([name, summary]) => ({
|
|
83
71
|
name, count: summary.count, latestActivityAgeMs: Math.max(0, now - summary.latestAt),
|
|
84
|
-
|
|
72
|
+
preview: byIndex.get(summary.lastIndex),
|
|
85
73
|
})).sort((a, b) => a.latestActivityAgeMs - b.latestActivityAgeMs || a.name.localeCompare(b.name));
|
|
86
74
|
}
|
|
87
75
|
export function decideAct(facts, input) {
|
|
@@ -219,10 +207,11 @@ export function coreParticipants(facts, now) {
|
|
|
219
207
|
lastActiveAt = Math.max(lastActiveAt ?? -Infinity, seenAt);
|
|
220
208
|
}
|
|
221
209
|
return {
|
|
222
|
-
name: current.name,
|
|
210
|
+
name: current.name, deliveryAvailable: facts.seat(current.name)?.wakeAddress !== undefined,
|
|
223
211
|
listening: facts.attention(current.name).filter((item) => item.kind === 'listen').map((item) => item.target),
|
|
224
212
|
activityCount: current.sayCount, lastActiveAt,
|
|
225
|
-
presence: current.done ? 'done' : !current.joined ? 'never-joined' :
|
|
213
|
+
presence: current.done ? 'done' : !current.joined ? 'never-joined' : facts.seat(current.name)?.attachment === 'detached' ? 'away'
|
|
214
|
+
: freshWatchLease(facts, current.name, now) !== undefined ? 'watching' : 'active',
|
|
226
215
|
unreadActivityCount: current.joined ? facts.directedCount(current.name, { afterIndex: readCursor(facts, current.name) }) : 0,
|
|
227
216
|
pendingMentionCount: current.joined ? facts.directedCount(current.name, { afterIndex: current.lastJoinIndex ?? -1, unseenOnly: true }) : 0,
|
|
228
217
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SquareError
|
|
1
|
+
import { SquareError } from './model.js';
|
|
2
2
|
export const MAX_DELIVERY_DEFERRAL_MS = 24 * 60 * 60 * 1000;
|
|
3
3
|
export function validateMetadataMatch(value) {
|
|
4
4
|
const fail = () => { throw new SquareError('invalid_args', 'Invalid metadata match.'); };
|
|
@@ -69,7 +69,7 @@ export function matchingDeferrals(deferrals, metadata, now) {
|
|
|
69
69
|
}
|
|
70
70
|
export function deliveryDeferralExpiry(facts, captured, index, now) {
|
|
71
71
|
const seat = facts.seat(captured.participant);
|
|
72
|
-
if (seat === undefined || seat.generation !== captured.generation ||
|
|
72
|
+
if (seat === undefined || seat.generation !== captured.generation || seat.owner !== captured.owner)
|
|
73
73
|
return undefined;
|
|
74
74
|
const leases = facts.deliveryDeferrals(seat.participant, seat.generation);
|
|
75
75
|
if (!leases.some(lease => lease.expiresAt > now))
|
package/dist/delivery-health.js
CHANGED
|
@@ -38,7 +38,6 @@ export async function classifyDeliveryHealth(squarePath, opts) {
|
|
|
38
38
|
routeKind: attemptRow.route.kind,
|
|
39
39
|
outcome: attemptRow.outcome,
|
|
40
40
|
attemptN: attemptRow.attemptN,
|
|
41
|
-
session: seat.body.session,
|
|
42
41
|
...(attemptRow.signature === undefined ? {} : { signature: attemptRow.signature }),
|
|
43
42
|
...(attemptRow.message === undefined ? {} : { message: attemptRow.message }),
|
|
44
43
|
...(attemptRow.diagnostic === undefined ? {} : { diagnostic: attemptRow.diagnostic }),
|
|
@@ -128,7 +127,7 @@ function formatRelease(release, now) {
|
|
|
128
127
|
const diagnostic = release.diagnostic === undefined ? '' : ` · ${displayField(JSON.stringify(release.diagnostic))}`;
|
|
129
128
|
return ` · ${formatActivityId(release.attention.actIndex)} → ${displayField(participantIdentity(release.attention.recipient))} · ${route} · ${reason} · ${age}${message}${diagnostic}`;
|
|
130
129
|
}
|
|
131
|
-
function deliveryAttempt(squarePath, row
|
|
130
|
+
function deliveryAttempt(squarePath, row) {
|
|
132
131
|
if (row.route?.kind === undefined || row.outcome === 'released' || row.outcome === 'dispatching')
|
|
133
132
|
return undefined;
|
|
134
133
|
return {
|
|
@@ -137,7 +136,6 @@ function deliveryAttempt(squarePath, row, session) {
|
|
|
137
136
|
routeKind: row.route.kind,
|
|
138
137
|
outcome: row.outcome,
|
|
139
138
|
attemptN: row.attemptN,
|
|
140
|
-
...(session === undefined ? {} : { session }),
|
|
141
139
|
...(row.signature === undefined ? {} : { signature: row.signature }),
|
|
142
140
|
...(row.message === undefined ? {} : { message: row.message }),
|
|
143
141
|
...(row.diagnostic === undefined ? {} : { diagnostic: row.diagnostic }),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { SquareArtifactPort, DeliverPendingInput
|
|
2
|
-
export declare function deliverPending(input: DeliverPendingInput): Promise<
|
|
1
|
+
import type { SquareArtifactPort, DeliverPendingInput } from './ports.js';
|
|
2
|
+
export declare function deliverPending(input: DeliverPendingInput): Promise<void>;
|
|
3
3
|
export declare function sweepPending(input: {
|
|
4
4
|
readonly artifact: SquareArtifactPort;
|
|
5
5
|
readonly location: string;
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { formatActivityId, parseActivityId } from './square-core.js';
|
|
3
|
-
import { sameBody } from './model.js';
|
|
4
3
|
import { pendingHead, pendingHeads, pendingRecipients, presentationBlocksWake } from './delivery.js';
|
|
5
4
|
import { asSeatRef } from './seats.js';
|
|
6
|
-
import { canonicalPath } from './canonical-path.js';
|
|
7
5
|
import { freshWatchLease } from './runtime.js';
|
|
8
6
|
import { deliveryDeferralExpiry } from './delivery-deferral.js';
|
|
9
7
|
import { leaseOwnsNotification } from './delivery.js';
|
|
10
8
|
function routeFor(location, seat, now) {
|
|
11
|
-
if (seat.wakeAddress === undefined)
|
|
9
|
+
if (seat.attachment !== 'attached' || seat.wakeAddress === undefined)
|
|
12
10
|
return undefined;
|
|
13
11
|
return {
|
|
14
|
-
location, participant: seat.participant,
|
|
12
|
+
location, participant: seat.participant,
|
|
15
13
|
kind: seat.wakeAddress.kind, address: { ...seat.wakeAddress.address }, updatedAt: now,
|
|
16
14
|
};
|
|
17
15
|
}
|
|
@@ -19,8 +17,8 @@ async function currentness(artifact, request, now) {
|
|
|
19
17
|
const index = parseActivityId(request.activity);
|
|
20
18
|
const { value } = await artifact.read((facts) => {
|
|
21
19
|
const currentSeat = facts.seat(request.participant);
|
|
22
|
-
const seatCurrent = currentSeat !== undefined && currentSeat.generation === request.seat.generation
|
|
23
|
-
&&
|
|
20
|
+
const seatCurrent = currentSeat !== undefined && currentSeat.attachment === 'attached' && currentSeat.generation === request.seat.generation
|
|
21
|
+
&& currentSeat.owner === request.seat.owner
|
|
24
22
|
&& currentSeat.wakeAddress?.kind === request.route.kind
|
|
25
23
|
&& Object.keys(currentSeat.wakeAddress.address).length === Object.keys(request.route.address).length
|
|
26
24
|
&& Object.entries(currentSeat.wakeAddress.address).every(([key, val]) => request.route.address[key] === val);
|
|
@@ -59,7 +57,7 @@ async function candidates(artifact, requested, now = Date.now()) {
|
|
|
59
57
|
: pendingRecipients(facts, requested);
|
|
60
58
|
return heads.flatMap((head) => {
|
|
61
59
|
const seat = facts.seat(head.recipient);
|
|
62
|
-
return seat === undefined || deliveryDeferralExpiry(facts, seat, head.index, now) !== undefined ? [] : [{ seat, head }];
|
|
60
|
+
return seat === undefined || seat.attachment !== 'attached' || deliveryDeferralExpiry(facts, seat, head.index, now) !== undefined ? [] : [{ seat, head }];
|
|
63
61
|
});
|
|
64
62
|
});
|
|
65
63
|
return value;
|
|
@@ -81,19 +79,25 @@ function safeJson(value) {
|
|
|
81
79
|
return String(value);
|
|
82
80
|
}
|
|
83
81
|
export async function deliverPending(input) {
|
|
84
|
-
|
|
82
|
+
// The resource owner supplies its identity; delivery does not interpret it as a file.
|
|
83
|
+
const location = input.location;
|
|
85
84
|
const requested = input.activity === undefined ? undefined
|
|
86
85
|
: typeof input.activity === 'number' ? input.activity : parseActivityId(input.activity);
|
|
87
86
|
if (input.activity !== undefined && requested === undefined)
|
|
88
|
-
return
|
|
87
|
+
return;
|
|
89
88
|
const pending = await candidates(input.artifact, requested, input.now ?? Date.now());
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
// Preserve order within a receiving owner; unrelated receivers need not wait for each other.
|
|
90
|
+
const receivers = new Map();
|
|
91
|
+
for (const candidate of pending) {
|
|
92
|
+
const key = candidate.seat.owner;
|
|
93
|
+
const group = receivers.get(key) ?? [];
|
|
94
|
+
group.push(candidate);
|
|
95
|
+
receivers.set(key, group);
|
|
96
|
+
}
|
|
97
|
+
const dispatch = async ({ seat, head }) => {
|
|
92
98
|
const route = routeFor(location, seat, input.now ?? Date.now());
|
|
93
|
-
if (route === undefined)
|
|
94
|
-
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
99
|
+
if (route === undefined)
|
|
100
|
+
return;
|
|
97
101
|
const request = {
|
|
98
102
|
location, participant: seat.participant, activity: formatActivityId(head.index), actor: head.actor,
|
|
99
103
|
seat: asSeatRef(seat), route,
|
|
@@ -102,14 +106,11 @@ export async function deliverPending(input) {
|
|
|
102
106
|
if (input.transport.probe !== undefined) {
|
|
103
107
|
try {
|
|
104
108
|
const probe = await input.transport.probe(route);
|
|
105
|
-
if (probe === false || typeof probe === 'object' && probe.outcome === 'not-capable')
|
|
106
|
-
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
+
if (probe === false || typeof probe === 'object' && probe.outcome === 'not-capable')
|
|
110
|
+
return;
|
|
109
111
|
}
|
|
110
112
|
catch {
|
|
111
|
-
|
|
112
|
-
continue;
|
|
113
|
+
return;
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
const claimToken = randomUUID();
|
|
@@ -117,7 +118,7 @@ export async function deliverPending(input) {
|
|
|
117
118
|
const claim = await input.artifact.claimDelivery({ seat: request.seat, activity: request.activity, kind: 'wake',
|
|
118
119
|
route: seat.wakeAddress, at: input.now ?? Date.now(), leaseMs, claimToken }).catch(() => ({ status: 'stale' }));
|
|
119
120
|
if (claim.status !== 'acquired')
|
|
120
|
-
|
|
121
|
+
return;
|
|
121
122
|
const withClaim = { ...request, claimToken, attemptN: claim.attemptN };
|
|
122
123
|
let final;
|
|
123
124
|
let suppressed = false;
|
|
@@ -138,7 +139,7 @@ export async function deliverPending(input) {
|
|
|
138
139
|
catch { /* unverifiable */ }
|
|
139
140
|
if (!before?.current) {
|
|
140
141
|
await releaseClaim(input.artifact, request.seat, request.activity, claimToken, 'pre_send_revalidation_failed', before === undefined ? 'Square delivery state could not be verified.' : 'The notification is no longer current.', before);
|
|
141
|
-
|
|
142
|
+
return;
|
|
142
143
|
}
|
|
143
144
|
let outcome;
|
|
144
145
|
try {
|
|
@@ -149,32 +150,31 @@ export async function deliverPending(input) {
|
|
|
149
150
|
}
|
|
150
151
|
if (suppressed) {
|
|
151
152
|
await releaseClaim(input.artifact, request.seat, request.activity, claimToken, 'pre_send_revalidation_failed', 'The notification changed before the final send check.', final ?? { observationAvailable: false });
|
|
152
|
-
|
|
153
|
+
return;
|
|
153
154
|
}
|
|
154
155
|
if (outcome.outcome === 'not-capable') {
|
|
155
156
|
await releaseClaim(input.artifact, request.seat, request.activity, claimToken, 'transport_not_capable', undefined, outcome.diagnostic);
|
|
156
|
-
|
|
157
|
-
continue;
|
|
157
|
+
return;
|
|
158
158
|
}
|
|
159
|
-
attempted += 1;
|
|
160
159
|
const mapped = outcome.outcome === 'accepted' ? 'accepted'
|
|
161
160
|
: outcome.outcome === 'unknown' ? 'unknown' : 'failed';
|
|
162
|
-
|
|
161
|
+
await input.artifact.completeDelivery({ seat: request.seat, activity: request.activity, claimToken,
|
|
163
162
|
outcome: mapped, at: Date.now(),
|
|
164
163
|
...('signature' in outcome && outcome.signature !== undefined ? { signature: outcome.signature } : {}),
|
|
165
164
|
...('message' in outcome && outcome.message !== undefined ? { message: outcome.message } : {}),
|
|
166
165
|
...('diagnostic' in outcome && outcome.diagnostic !== undefined ? { diagnostic: safeJson(outcome.diagnostic) } : {}),
|
|
167
166
|
}).catch(() => false);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
167
|
+
};
|
|
168
|
+
const groups = receivers.values();
|
|
169
|
+
const settled = await Promise.allSettled(Array.from({ length: Math.min(4, receivers.size) }, async () => {
|
|
170
|
+
for (const group of groups)
|
|
171
|
+
for (const candidate of group)
|
|
172
|
+
await dispatch(candidate);
|
|
173
|
+
}));
|
|
174
|
+
// Even an unexpected failure must drain siblings before the caller closes its artifact.
|
|
175
|
+
for (const result of settled)
|
|
176
|
+
if (result.status === 'rejected')
|
|
177
|
+
throw result.reason;
|
|
178
178
|
}
|
|
179
179
|
export async function sweepPending(input) {
|
|
180
180
|
if (input.limit <= 0)
|
package/dist/delivery.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export declare function pendingPages(artifact: SquareArtifactPort, scan: Pending
|
|
|
40
40
|
at: number;
|
|
41
41
|
actor: string;
|
|
42
42
|
recipient: string;
|
|
43
|
-
route: "bell" | "
|
|
43
|
+
route: "bell" | "mention" | "reply" | "attention";
|
|
44
44
|
}[], void, unknown>;
|
|
45
45
|
/** A pass retains only its captured joins; routes and individual receipts are fresh. */
|
|
46
46
|
export declare function pendingFacts(facts: SquareRead, scan: PendingScan, heads: readonly DirectedHead[]): {
|
package/dist/delivery.js
CHANGED
|
@@ -8,7 +8,7 @@ export function wakePreview(facts, request) {
|
|
|
8
8
|
const head = index === undefined ? undefined : pendingHead(facts, request.participant, index);
|
|
9
9
|
const item = index === undefined ? undefined : facts.activity(index);
|
|
10
10
|
const seat = facts.seat(request.participant);
|
|
11
|
-
if (head === undefined || item?.kind !== 'say' || seat === undefined
|
|
11
|
+
if (head === undefined || item?.kind !== 'say' || seat === undefined || seat.attachment !== 'attached'
|
|
12
12
|
|| deliveryDeferralExpiry(facts, request.seat, item.index, Date.now()) !== undefined)
|
|
13
13
|
return undefined;
|
|
14
14
|
return renderSquareReminder([renderAttentionPreview({
|
package/dist/harness-links.d.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
export interface HarnessLink {
|
|
2
|
-
source: string;
|
|
3
|
-
target: string;
|
|
4
|
-
kind?: 'skill' | 'extension';
|
|
5
|
-
}
|
|
6
|
-
export declare function installHarnessLinks(links: HarnessLink[], force?: boolean): string[];
|
|
7
|
-
export declare function uninstallHarnessLinks(links: HarnessLink[]): string[];
|
|
8
|
-
export declare function doctorHarnessLinks(links: HarnessLink[]): string[];
|
|
9
1
|
export type OpenCodeCommandRunner = (homeDir: string, args: string[]) => {
|
|
10
2
|
status: number;
|
|
11
3
|
stdout: string;
|
|
@@ -13,6 +5,5 @@ export type OpenCodeCommandRunner = (homeDir: string, args: string[]) => {
|
|
|
13
5
|
};
|
|
14
6
|
export declare function installOpenCodePlugin(homeDir: string, force?: boolean, run?: OpenCodeCommandRunner): string[];
|
|
15
7
|
export declare function uninstallOpenCodePlugin(homeDir: string): string[];
|
|
16
|
-
/**
|
|
8
|
+
/** Config sources prove configuration, not that a running session loaded the plugin. */
|
|
17
9
|
export declare function verifyOpenCodeRuntime(homeDir: string, run?: OpenCodeCommandRunner): string;
|
|
18
|
-
export declare function skillLinks(homeDir?: string, parents?: Array<'.claude' | '.agents'>): HarnessLink[];
|