@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/square-api.js
CHANGED
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
import { SqliteSquare } from './sqlite-square.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { SquareError } from './model.js';
|
|
3
|
+
import { requireOwner } from './seats.js';
|
|
4
|
+
import { createDefaultWakeTransport } from './notifications.js';
|
|
5
|
+
export const Square = { at: async (input, control) => SqliteSquare.at({ ...input, wakeTransport: await resolveWakeTransport(input) }, control),
|
|
6
|
+
build: async (input, control) => SqliteSquare.build({ ...input, wakeTransport: await resolveWakeTransport(input) }, control), inMemory: SqliteSquare.inMemory };
|
|
7
|
+
const resolveWakeTransport = (input) => input.wakeTransport !== undefined
|
|
8
|
+
? Promise.resolve(input.wakeTransport)
|
|
9
|
+
: createDefaultWakeTransport(input.env ?? process.env).catch(() => undefined);
|
|
10
|
+
export { requireOwner, requireJoinName } from './seats.js';
|
|
4
11
|
export { squareLocation } from './square-location.js';
|
|
12
|
+
export async function selectOwnSeat(square, owner, name, options) {
|
|
13
|
+
if (owner === undefined && options?.optional && name === undefined)
|
|
14
|
+
return undefined;
|
|
15
|
+
const caller = requireOwner(owner);
|
|
16
|
+
if (name !== undefined)
|
|
17
|
+
return square.participant(name, { owner: caller });
|
|
18
|
+
const seats = (await square.seatsOf(caller)).filter(seat => seat.attachment === 'attached');
|
|
19
|
+
if (seats.length !== 1) {
|
|
20
|
+
if (options?.optional)
|
|
21
|
+
return undefined;
|
|
22
|
+
throw new SquareError('invalid_args', seats.length > 1
|
|
23
|
+
? 'Square needs an explicit participant name: this owner holds multiple names'
|
|
24
|
+
: 'Square needs one unambiguous participant name');
|
|
25
|
+
}
|
|
26
|
+
return square.participant(seats[0].name, { owner: caller });
|
|
27
|
+
}
|
|
5
28
|
export { ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
29
|
+
export { localUserOwner, harnessOwner, decodeHarnessOwner } from './owner.js';
|
|
6
30
|
export { squareClock, createSquareResourceOwner, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT, HELD_WAIT_BUDGET_MS, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT, diagnoseSquare, migrateSquare, discover, inbox } from './sqlite-square.js';
|
|
7
|
-
export const Square = {
|
|
8
|
-
async at(input, control) {
|
|
9
|
-
const captured = { ...input, cwd: input.cwd ?? process.cwd(), env: { ...(input.env ?? process.env) } };
|
|
10
|
-
const location = squareLocation(captured);
|
|
11
|
-
const selected = parseSquareLocation(location);
|
|
12
|
-
return selected.kind === 'local' ? SqliteSquare.at({ ...captured, path: location }, control)
|
|
13
|
-
: openStdioSquare(location, selected, captured, await backendConfiguration(captured), undefined, control);
|
|
14
|
-
},
|
|
15
|
-
async build(input, control) {
|
|
16
|
-
const captured = { ...input, cwd: input.cwd ?? process.cwd(), env: { ...(input.env ?? process.env) } };
|
|
17
|
-
const location = squareLocation(captured);
|
|
18
|
-
const selected = parseSquareLocation(location);
|
|
19
|
-
return selected.kind === 'local' ? SqliteSquare.build({ ...captured, path: location }, control)
|
|
20
|
-
: openStdioSquare(location, selected, captured, await backendConfiguration(captured), {
|
|
21
|
-
markdown: input.markdown, hardCap: input.hardCap, throttlePerMinute: input.throttlePerMinute,
|
|
22
|
-
template: input.template, force: input.force,
|
|
23
|
-
}, control);
|
|
24
|
-
},
|
|
25
|
-
inMemory(input) { return SqliteSquare.inMemory(input); },
|
|
26
|
-
};
|
package/dist/square-core.d.ts
CHANGED
|
@@ -59,9 +59,4 @@ export type Act = {
|
|
|
59
59
|
target: Participant;
|
|
60
60
|
at?: number;
|
|
61
61
|
};
|
|
62
|
-
export declare function audienceOf(say: {
|
|
63
|
-
body?: string;
|
|
64
|
-
mentions?: readonly Participant[];
|
|
65
|
-
reach?: Reach;
|
|
66
|
-
}): Audience;
|
|
67
62
|
export declare function audienceIncludes(audience: Audience, name: string): boolean;
|
package/dist/square-core.js
CHANGED
|
@@ -13,15 +13,6 @@ export function parseActivityId(value) {
|
|
|
13
13
|
const index = Number(value.slice(4));
|
|
14
14
|
return Number.isSafeInteger(index) ? index : undefined;
|
|
15
15
|
}
|
|
16
|
-
export function audienceOf(say) {
|
|
17
|
-
if (say.reach === 'bell')
|
|
18
|
-
return { kind: 'bell' };
|
|
19
|
-
const names = [];
|
|
20
|
-
for (const name of say.mentions ?? [])
|
|
21
|
-
if (!names.some((existing) => sameName(existing, name)))
|
|
22
|
-
names.push(name);
|
|
23
|
-
return { kind: 'mentions', names };
|
|
24
|
-
}
|
|
25
16
|
export function audienceIncludes(audience, name) {
|
|
26
17
|
return audience.kind === 'bell' || audience.names.some((mentioned) => sameName(mentioned, name));
|
|
27
18
|
}
|
package/dist/square-domain.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Seat, type StoredAct } from './model.js';
|
|
2
|
-
import type { ArtifactWriteAuthority, AttentionFact, LandedRecipient, ParticipantFact, SquareRead, SquareWrite } from './ports.js';
|
|
2
|
+
import type { ArtifactWriteAuthority, AttentionFact, LandedRecipient, ParticipantFact, SeatRef, SquareRead, SquareWrite } from './ports.js';
|
|
3
3
|
export interface LandingEffect {
|
|
4
4
|
readonly activity: StoredAct;
|
|
5
5
|
readonly participant?: ParticipantFact;
|
|
@@ -21,7 +21,7 @@ export interface LandingFacts {
|
|
|
21
21
|
/** The single landing transition, shared by both adapters and explicit rebuild. */
|
|
22
22
|
export declare function deriveLanding(activity: StoredAct, facts: LandingFacts): LandingEffect;
|
|
23
23
|
export declare function landingFacts(read: SquareRead, activity: StoredAct): LandingFacts;
|
|
24
|
-
export interface LandingWriter extends Pick<SquareWrite, 'markSeen' | 'putLease' | 'removeLease' | 'updateWakeAddress' | 'cancelThrough' | 'putDeliveryDeferral' | 'renewDeliveryDeferral' | 'releaseDeliveryDeferral' | 'claimDelivery' | 'prepareDelivery' | 'completeDelivery' | 'observeNativeDelivery'> {
|
|
24
|
+
export interface LandingWriter extends Pick<SquareWrite, 'markSeen' | 'putLease' | 'removeLease' | 'updateWakeAddress' | 'reattachSeat' | 'detachSeat' | 'cancelThrough' | 'putDeliveryDeferral' | 'renewDeliveryDeferral' | 'releaseDeliveryDeferral' | 'claimDelivery' | 'prepareDelivery' | 'completeDelivery' | 'observeNativeDelivery'> {
|
|
25
25
|
/** Artifact-private seat persistence used only by this gate's lifecycle transition. */
|
|
26
26
|
storeSeat(seat: Seat): boolean;
|
|
27
27
|
removeSeat(seat: import('./ports.js').SeatRef): boolean;
|
|
@@ -31,5 +31,7 @@ export interface SquareWriteGate {
|
|
|
31
31
|
readonly facts: SquareWrite;
|
|
32
32
|
complete(): void;
|
|
33
33
|
}
|
|
34
|
+
/** Read probes and writes share the same captured-coordinate and attachment fence. */
|
|
35
|
+
export declare function assertCurrentSeat(read: SquareRead, expected: SeatRef, allowDetached?: boolean): void;
|
|
34
36
|
/** The artifact transaction supplies one captured authority; every mutation checks it here. */
|
|
35
37
|
export declare function wrapSquareWrite(read: SquareRead, writes: LandingWriter, authority: ArtifactWriteAuthority): SquareWriteGate;
|
package/dist/square-domain.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SquareError, formatActivityId, parseActivityId,
|
|
1
|
+
import { SquareError, formatActivityId, parseActivityId, sameName, validateOwner, validateName } from './model.js';
|
|
2
2
|
/** The single landing transition, shared by both adapters and explicit rebuild. */
|
|
3
3
|
export function deriveLanding(activity, facts) {
|
|
4
4
|
const audience = [];
|
|
@@ -68,31 +68,38 @@ function validateGeneration(value) {
|
|
|
68
68
|
if (typeof value !== 'string' || parseActivityId(value) === undefined)
|
|
69
69
|
throw new SquareError('invalid_args', 'Artifact authority requires a valid join generation.');
|
|
70
70
|
}
|
|
71
|
+
/** Read probes and writes share the same captured-coordinate and attachment fence. */
|
|
72
|
+
export function assertCurrentSeat(read, expected, allowDetached = false) {
|
|
73
|
+
const current = read.seat(expected.participant);
|
|
74
|
+
if (current === undefined || current.owner !== expected.owner || current.generation !== expected.generation)
|
|
75
|
+
throw new SquareError('already_joined', 'This participant seat has been replaced.');
|
|
76
|
+
if (!allowDetached && current.attachment !== 'attached')
|
|
77
|
+
throw new SquareError('already_joined', 'This participant is away; join again before writing.', { reason: 'needs_seat', activityUnsent: true });
|
|
78
|
+
}
|
|
71
79
|
/** The artifact transaction supplies one captured authority; every mutation checks it here. */
|
|
72
80
|
export function wrapSquareWrite(read, writes, authority) {
|
|
73
81
|
if (authority === undefined || typeof authority !== 'object' || authority === null)
|
|
74
82
|
throw new SquareError('invalid_args', 'Artifact writes require an explicit authority.');
|
|
75
83
|
const { applyLanding, ...mutations } = writes;
|
|
76
|
-
const
|
|
77
|
-
|
|
84
|
+
const seated = authority.kind === 'participant' || authority.kind === 'host-cleanup';
|
|
85
|
+
const expectedName = seated ? authority.seat?.participant : authority.participant;
|
|
86
|
+
if (!['participant', 'host-cleanup', 'join', 'takeover'].includes(authority.kind) || typeof expectedName !== 'string')
|
|
78
87
|
throw new SquareError('invalid_args', 'Artifact write authority is malformed.');
|
|
79
88
|
validateName(expectedName);
|
|
80
|
-
if (
|
|
81
|
-
|
|
89
|
+
if (seated) {
|
|
90
|
+
validateOwner(authority.seat.owner);
|
|
82
91
|
validateGeneration(authority.seat.generation);
|
|
83
92
|
}
|
|
84
93
|
else {
|
|
85
|
-
|
|
94
|
+
validateOwner(authority.owner);
|
|
86
95
|
if (authority.kind === 'takeover')
|
|
87
96
|
validateGeneration(authority.expectedGeneration);
|
|
88
97
|
}
|
|
89
|
-
const assertSeat = (seat, expected = authority.kind === 'participant' ? authority.seat : undefined) => {
|
|
98
|
+
const assertSeat = (seat, expected = authority.kind === 'participant' ? authority.seat : undefined, allowDetached = false) => {
|
|
90
99
|
if (expected === undefined || !sameName(expected.participant, seat.participant)
|
|
91
|
-
|| seat.generation !== expected.generation ||
|
|
100
|
+
|| seat.generation !== expected.generation || seat.owner !== expected.owner)
|
|
92
101
|
throw new SquareError('already_joined', 'This write needs the current participant seat.');
|
|
93
|
-
|
|
94
|
-
if (current === undefined || !sameBody(current.body, expected.body) || current.generation !== expected.generation)
|
|
95
|
-
throw new SquareError('already_joined', 'This participant seat has been replaced.');
|
|
102
|
+
assertCurrentSeat(read, expected, allowDetached);
|
|
96
103
|
};
|
|
97
104
|
const assertParticipant = (name, generation) => {
|
|
98
105
|
if (authority.kind !== 'participant')
|
|
@@ -104,11 +111,14 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
104
111
|
if (authority.kind === 'participant') {
|
|
105
112
|
assertSeat(authority.seat);
|
|
106
113
|
}
|
|
114
|
+
else if (authority.kind === 'host-cleanup') {
|
|
115
|
+
// A late host cleanup is allowed to inspect a stale coordinate and return a no-op.
|
|
116
|
+
}
|
|
107
117
|
else if (authority.kind === 'join') {
|
|
108
118
|
const participant = read.participant(expectedName), seat = read.seat(expectedName);
|
|
109
119
|
if (participant?.joined) {
|
|
110
|
-
if (seat === undefined ||
|
|
111
|
-
throw new SquareError('already_joined', `${expectedName} is held by another
|
|
120
|
+
if (seat === undefined || seat.owner !== authority.owner)
|
|
121
|
+
throw new SquareError('already_joined', `${expectedName} is held by another owner; take it over explicitly`);
|
|
112
122
|
reconnectSeat = seat;
|
|
113
123
|
}
|
|
114
124
|
}
|
|
@@ -131,6 +141,11 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
131
141
|
if (activity.kind === 'join')
|
|
132
142
|
throw new SquareError('invalid_args', 'A participant seat can only be re-established by join.');
|
|
133
143
|
}
|
|
144
|
+
else if (authority.kind === 'host-cleanup') {
|
|
145
|
+
assertSeat(authority.seat, authority.seat, true);
|
|
146
|
+
if (activity.kind !== 'done')
|
|
147
|
+
throw new SquareError('invalid_args', 'Host cleanup may only end membership.');
|
|
148
|
+
}
|
|
134
149
|
else if (authority.kind === 'join') {
|
|
135
150
|
if (activity.kind !== 'join')
|
|
136
151
|
throw new SquareError('invalid_args', 'A new seat must be established by its join activity.');
|
|
@@ -157,27 +172,28 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
157
172
|
const stored = { ...activity, index };
|
|
158
173
|
applyLanding(deriveLanding(stored, landingFacts(read, stored)));
|
|
159
174
|
if (stored.kind === 'join') {
|
|
160
|
-
if (
|
|
161
|
-
throw new SquareError('invalid_args', '
|
|
175
|
+
if (seated)
|
|
176
|
+
throw new SquareError('invalid_args', 'Seat authority cannot establish another seat.');
|
|
162
177
|
const seat = {
|
|
163
178
|
participant: stored.actor,
|
|
164
|
-
|
|
179
|
+
owner: authority.owner,
|
|
165
180
|
generation: formatActivityId(stored.index),
|
|
181
|
+
attachment: 'attached',
|
|
166
182
|
...(authority.wakeAddress === undefined ? {} : { wakeAddress: authority.wakeAddress }),
|
|
167
183
|
};
|
|
168
184
|
mutations.storeSeat(seat);
|
|
169
185
|
const established = read.seat(seat.participant);
|
|
170
|
-
if (established === undefined ||
|
|
186
|
+
if (established === undefined || established.owner !== seat.owner || established.generation !== seat.generation)
|
|
171
187
|
throw new SquareError('invalid_args', 'The join activity did not establish its artifact seat.');
|
|
172
188
|
if (authority.kind === 'takeover')
|
|
173
189
|
takeoverPhase = 'joined';
|
|
174
190
|
}
|
|
175
|
-
else if (stored.kind === 'done' &&
|
|
191
|
+
else if (stored.kind === 'done' && seated) {
|
|
176
192
|
if (!mutations.removeSeat(authority.seat))
|
|
177
193
|
throw new SquareError('already_joined', 'The participant seat changed while it was being completed.');
|
|
178
194
|
}
|
|
179
195
|
else if (stored.kind === 'done' && authority.kind === 'takeover') {
|
|
180
|
-
if (captured === undefined || !mutations.removeSeat({ participant: expectedName,
|
|
196
|
+
if (captured === undefined || !mutations.removeSeat({ participant: expectedName, owner: captured.owner, generation: captured.generation }))
|
|
181
197
|
throw new SquareError('already_joined', 'The participant seat changed while takeover was completing it.');
|
|
182
198
|
takeoverPhase = 'done';
|
|
183
199
|
}
|
|
@@ -185,9 +201,28 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
185
201
|
return lastActivity;
|
|
186
202
|
},
|
|
187
203
|
updateWakeAddress(seat, wakeAddress) {
|
|
188
|
-
|
|
204
|
+
if (authority.kind !== 'join' && authority.kind !== 'participant')
|
|
205
|
+
throw new SquareError('already_joined', 'This write needs the current participant seat.');
|
|
206
|
+
assertSeat(seat, authority.kind === 'join' ? reconnectSeat : authority.seat);
|
|
189
207
|
return mutations.updateWakeAddress(seat, wakeAddress);
|
|
190
208
|
},
|
|
209
|
+
reattachSeat(seat, wakeAddress) {
|
|
210
|
+
if (authority.kind !== 'join')
|
|
211
|
+
throw new SquareError('already_joined', 'Reattachment requires a same-owner join.');
|
|
212
|
+
assertSeat(seat, reconnectSeat, true);
|
|
213
|
+
return mutations.reattachSeat(seat, wakeAddress);
|
|
214
|
+
},
|
|
215
|
+
detachSeat(seat) {
|
|
216
|
+
if (authority.kind !== 'host-cleanup')
|
|
217
|
+
throw new SquareError('already_joined', 'Detach requires captured host cleanup authority.');
|
|
218
|
+
const current = read.seat(seat.participant), expected = authority.seat;
|
|
219
|
+
if (!sameName(seat.participant, expected.participant) || seat.owner !== expected.owner || seat.generation !== expected.generation)
|
|
220
|
+
throw new SquareError('already_joined', 'Host cleanup does not match its captured seat.');
|
|
221
|
+
if (current === undefined || current.attachment !== 'attached' || current.owner !== expected.owner
|
|
222
|
+
|| current.generation !== expected.generation)
|
|
223
|
+
return false;
|
|
224
|
+
return mutations.detachSeat(seat);
|
|
225
|
+
},
|
|
191
226
|
cancelThrough(seat, through) {
|
|
192
227
|
assertSeat(seat);
|
|
193
228
|
if (!Number.isSafeInteger(through) || through < 0 || through > read.header().lastActIndex || read.activity(through) === undefined)
|
|
@@ -242,7 +277,7 @@ export function wrapSquareWrite(read, writes, authority) {
|
|
|
242
277
|
return;
|
|
243
278
|
const seat = read.seat(expectedName);
|
|
244
279
|
if (takeoverPhase !== 'joined' || lastActivity?.kind !== 'join' || seat === undefined
|
|
245
|
-
||
|
|
280
|
+
|| seat.owner !== authority.owner || seat.generation !== formatActivityId(lastActivity.index))
|
|
246
281
|
throw new SquareError('already_joined', 'Takeover did not complete its replacement join.');
|
|
247
282
|
},
|
|
248
283
|
};
|
package/dist/square-facade.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import type { SquareBackends } from './square-backend.js';
|
|
2
1
|
import type { DeliveryDeferral, MetadataMatch } from './delivery-deferral.js';
|
|
3
2
|
export type { DeliveryDeferral, MetadataMatch, MetadataScalar } from './delivery-deferral.js';
|
|
4
3
|
import type { ActivityId, Perception, Reach } from './square-core.js';
|
|
5
|
-
import type {
|
|
6
|
-
import type { WakeTransportPort,
|
|
4
|
+
import type { Owner, StoredAct, WakeAddress, ActivityMetadata, DirectedNotificationRoute } from './model.js';
|
|
5
|
+
import type { WakeTransportPort, SquareResourceOwner } from './ports.js';
|
|
7
6
|
export type { ActivityId, Perception, Reach } from './square-core.js';
|
|
8
|
-
export type {
|
|
7
|
+
export type { Owner, WakeAddress, ActivityMetadata, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
9
8
|
/** Indexed archive event, including read and historical actorless lifecycle records. */
|
|
10
9
|
export type ArchiveRecord = Readonly<StoredAct>;
|
|
11
10
|
export interface Activity {
|
|
@@ -22,6 +21,7 @@ export interface Activity {
|
|
|
22
21
|
}
|
|
23
22
|
export interface PerceivedActivity extends Activity {
|
|
24
23
|
readonly perception: Perception;
|
|
24
|
+
readonly via?: DirectedNotificationRoute;
|
|
25
25
|
}
|
|
26
26
|
/** Request extra facts for rendering, without changing operation semantics. */
|
|
27
27
|
export interface ObservationOptions {
|
|
@@ -39,12 +39,8 @@ export interface ExpressOptions extends ObservationOptions {
|
|
|
39
39
|
export interface ExpressInput extends ExpressOptions {
|
|
40
40
|
readonly body?: string;
|
|
41
41
|
}
|
|
42
|
-
export interface
|
|
42
|
+
export interface ExpressResult {
|
|
43
43
|
readonly activity: Activity;
|
|
44
|
-
readonly delivery?: DeliveryResult;
|
|
45
|
-
}
|
|
46
|
-
export interface ExpressResult extends ActivityResult {
|
|
47
|
-
readonly waited: boolean;
|
|
48
44
|
/** The replied-to author was not standing when the reply landed. */
|
|
49
45
|
readonly replyAuthorNotHere?: string;
|
|
50
46
|
/** Body @name tokens with no standing match at landing; never stored on the activity. */
|
|
@@ -61,8 +57,9 @@ export interface ListeningResult {
|
|
|
61
57
|
readonly listening: readonly string[];
|
|
62
58
|
readonly observation?: SquareObservation;
|
|
63
59
|
}
|
|
64
|
-
export interface LifecycleResult
|
|
65
|
-
readonly
|
|
60
|
+
export interface LifecycleResult {
|
|
61
|
+
readonly activity: Activity;
|
|
62
|
+
readonly observation?: SquareObservation;
|
|
66
63
|
}
|
|
67
64
|
export interface CatchOptions extends ObservationOptions {
|
|
68
65
|
readonly id?: ActivityId;
|
|
@@ -72,12 +69,11 @@ export interface CatchOptions extends ObservationOptions {
|
|
|
72
69
|
readonly limit?: number;
|
|
73
70
|
readonly replace?: boolean;
|
|
74
71
|
}
|
|
72
|
+
export type CatchReason = 'drained' | 'idle' | 'capped' | 'quorum' | 'replaced' | 'already-active';
|
|
75
73
|
export interface CatchResult {
|
|
76
74
|
readonly activities: readonly PerceivedActivity[];
|
|
77
|
-
readonly consumedThrough: ActivityId | null;
|
|
78
|
-
readonly idleExpired: boolean;
|
|
79
75
|
readonly remaining: number;
|
|
80
|
-
readonly
|
|
76
|
+
readonly reason: CatchReason;
|
|
81
77
|
/** Occasional participant-facing nudge; not part of any activity. */
|
|
82
78
|
readonly hint?: string;
|
|
83
79
|
readonly observation?: CatchObservation;
|
|
@@ -134,13 +130,6 @@ export interface HistoryResult {
|
|
|
134
130
|
readonly activities: readonly Activity[];
|
|
135
131
|
readonly observation?: HistoryObservation;
|
|
136
132
|
}
|
|
137
|
-
export interface ParticipantStatus {
|
|
138
|
-
readonly name: string;
|
|
139
|
-
readonly state: 'joined' | 'done';
|
|
140
|
-
readonly consumedThrough: ActivityId | null;
|
|
141
|
-
readonly watching: boolean;
|
|
142
|
-
readonly listening: readonly string[];
|
|
143
|
-
}
|
|
144
133
|
export interface SquareSnapshot {
|
|
145
134
|
readonly context: string;
|
|
146
135
|
readonly actCount: number;
|
|
@@ -150,16 +139,12 @@ export interface SquareSnapshot {
|
|
|
150
139
|
readonly by: string;
|
|
151
140
|
readonly reason?: string;
|
|
152
141
|
} | null;
|
|
153
|
-
readonly participants: readonly
|
|
142
|
+
readonly participants: readonly Pick<ParticipantSummary, 'name' | 'presence' | 'listening'>[];
|
|
154
143
|
delivered(name: string, id: ActivityId): boolean;
|
|
155
144
|
}
|
|
156
145
|
export interface OpenOptions {
|
|
157
146
|
readonly clock?: () => number;
|
|
158
|
-
readonly wakeTransport?: WakeTransportPort;
|
|
159
|
-
/** Explicit execution coordinate resolved by an adapter. */
|
|
160
|
-
readonly body?: Body;
|
|
161
|
-
/** Optional wake address attached to this body. */
|
|
162
|
-
readonly wakeAddress?: WakeAddress;
|
|
147
|
+
readonly wakeTransport?: WakeTransportPort | false;
|
|
163
148
|
}
|
|
164
149
|
export interface SquareLocation {
|
|
165
150
|
readonly path?: string;
|
|
@@ -167,8 +152,6 @@ export interface SquareLocation {
|
|
|
167
152
|
readonly env?: NodeJS.ProcessEnv;
|
|
168
153
|
}
|
|
169
154
|
export interface SquareAtInput extends SquareLocation, OpenOptions {
|
|
170
|
-
readonly backends?: SquareBackends;
|
|
171
|
-
readonly participant?: string;
|
|
172
155
|
/** A caller-owned connection; closing this Square never closes its owner. */
|
|
173
156
|
readonly resources?: SquareResourceOwner;
|
|
174
157
|
}
|
|
@@ -180,6 +163,8 @@ export interface SquareBuildInput extends SquareAtInput {
|
|
|
180
163
|
readonly force?: boolean;
|
|
181
164
|
}
|
|
182
165
|
export interface JoinOptions extends ObservationOptions {
|
|
166
|
+
readonly owner: Owner;
|
|
167
|
+
readonly wakeAddress?: WakeAddress;
|
|
183
168
|
readonly takeover?: boolean;
|
|
184
169
|
readonly last?: number;
|
|
185
170
|
}
|
|
@@ -187,8 +172,6 @@ export interface JoinResult {
|
|
|
187
172
|
readonly participant: Participant;
|
|
188
173
|
readonly activity: Activity | null;
|
|
189
174
|
readonly kind: 'joined' | 'reconnected' | 'taken-over';
|
|
190
|
-
/** Known joined-or-done participants, not the current standing count. */
|
|
191
|
-
readonly participantCount: number;
|
|
192
175
|
readonly observation?: JoinObservation;
|
|
193
176
|
}
|
|
194
177
|
export interface Participant {
|
|
@@ -200,7 +183,6 @@ export interface Participant {
|
|
|
200
183
|
unlisten(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
201
184
|
listening(options?: ObservationOptions, control?: OperationControl): Promise<ListeningResult>;
|
|
202
185
|
catch(options?: CatchOptions, control?: OperationControl): Promise<CatchResult>;
|
|
203
|
-
history(query?: HistoryQuery, control?: OperationControl): Promise<HistoryResult>;
|
|
204
186
|
hold(reason?: string, options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
205
187
|
resume(options?: ObservationOptions, control?: OperationControl): Promise<LifecycleResult>;
|
|
206
188
|
/** Leave without a message. Only an omitted or empty body is accepted. */
|
|
@@ -212,12 +194,15 @@ export interface Participant {
|
|
|
212
194
|
renewDeliveryDeferral(id: string, durationMs: number, control?: OperationControl): Promise<DeliveryDeferral | null>;
|
|
213
195
|
releaseDeliveryDeferral(id: string, control?: OperationControl): Promise<boolean>;
|
|
214
196
|
}
|
|
215
|
-
export
|
|
216
|
-
|
|
217
|
-
|
|
197
|
+
export interface HeldSeat {
|
|
198
|
+
readonly name: string;
|
|
199
|
+
readonly generation: ActivityId;
|
|
200
|
+
readonly attachment: 'attached' | 'detached';
|
|
201
|
+
}
|
|
202
|
+
export type ParticipantPresence = 'never-joined' | 'active' | 'watching' | 'away' | 'done';
|
|
218
203
|
export interface ParticipantSummary {
|
|
219
204
|
readonly name: string;
|
|
220
|
-
readonly
|
|
205
|
+
readonly deliveryAvailable: boolean;
|
|
221
206
|
readonly listening: readonly string[];
|
|
222
207
|
readonly activityCount: number;
|
|
223
208
|
readonly lastActiveAt?: number;
|
|
@@ -232,12 +217,11 @@ export interface StatusResult {
|
|
|
232
217
|
/** Present when a viewer resolves; an empty list means they listen to nobody. */
|
|
233
218
|
readonly listening?: readonly string[];
|
|
234
219
|
readonly hardCap: number | null;
|
|
235
|
-
readonly activeCount: number;
|
|
236
|
-
readonly doneCount: number;
|
|
237
220
|
readonly participants: readonly ParticipantSummary[];
|
|
238
221
|
readonly now: number;
|
|
239
222
|
readonly throttlePerMinute?: number;
|
|
240
|
-
|
|
223
|
+
/** Non-null whenever held; by is present with an actor and omitted only for historical actorless holds. */
|
|
224
|
+
readonly held: {
|
|
241
225
|
readonly by?: string;
|
|
242
226
|
readonly reason?: string;
|
|
243
227
|
readonly at?: number;
|
|
@@ -284,10 +268,8 @@ export interface RecoveryResult {
|
|
|
284
268
|
readonly participant?: string;
|
|
285
269
|
readonly standingCount?: number;
|
|
286
270
|
readonly held?: boolean;
|
|
287
|
-
readonly holdReason?: string;
|
|
288
271
|
readonly ownActivityCount?: number;
|
|
289
272
|
readonly hardCap?: number | null;
|
|
290
|
-
readonly roster?: readonly string[];
|
|
291
273
|
readonly activitySummaries?: readonly UnreadActivitySummary[];
|
|
292
274
|
}
|
|
293
275
|
export type StreamStart = {
|
|
@@ -295,69 +277,45 @@ export type StreamStart = {
|
|
|
295
277
|
readonly last: number;
|
|
296
278
|
} | {
|
|
297
279
|
readonly kind: 'after';
|
|
298
|
-
readonly after:
|
|
280
|
+
readonly after: ActivityId;
|
|
299
281
|
};
|
|
300
282
|
export interface StreamOptions {
|
|
301
283
|
readonly recipient?: string;
|
|
302
284
|
readonly start?: StreamStart;
|
|
303
285
|
}
|
|
304
|
-
export type StreamRecord =
|
|
305
|
-
readonly seq: number;
|
|
306
|
-
readonly square: string;
|
|
307
|
-
readonly route?: string;
|
|
308
|
-
};
|
|
309
|
-
export interface UnreadActivityPreview {
|
|
310
|
-
readonly number: number;
|
|
311
|
-
readonly act: Extract<ArchiveRecord, {
|
|
312
|
-
kind: 'say';
|
|
313
|
-
}>;
|
|
314
|
-
readonly perception: Perception;
|
|
315
|
-
}
|
|
286
|
+
export type StreamRecord = Activity | PerceivedActivity;
|
|
316
287
|
export interface UnreadActivitySummary {
|
|
317
288
|
readonly name: string;
|
|
318
289
|
readonly count: number;
|
|
319
290
|
readonly latestActivityAgeMs: number;
|
|
320
|
-
readonly
|
|
291
|
+
readonly preview: Extract<ArchiveRecord, {
|
|
292
|
+
kind: 'say';
|
|
293
|
+
}>;
|
|
321
294
|
}
|
|
322
295
|
export interface EntryPresentation {
|
|
323
296
|
readonly joinedBefore: boolean;
|
|
324
297
|
readonly scene: string;
|
|
325
298
|
readonly joinContext: string;
|
|
326
|
-
readonly recentActivities: readonly
|
|
327
|
-
readonly perceptions: Readonly<Record<number, Perception>>;
|
|
328
|
-
readonly sayNumbers: Readonly<Record<number, number>>;
|
|
329
|
-
}
|
|
330
|
-
export interface ListPresentation {
|
|
331
|
-
readonly context: readonly string[];
|
|
332
|
-
readonly participants: readonly string[];
|
|
333
|
-
readonly activities: number;
|
|
299
|
+
readonly recentActivities: readonly PerceivedActivity[];
|
|
334
300
|
}
|
|
335
301
|
export interface PresenceClassification {
|
|
336
302
|
readonly orderedHereNames: readonly string[];
|
|
337
303
|
readonly lingeringCount: number;
|
|
338
|
-
readonly classificationByName: Readonly<Record<string, 'here' | 'lingering' | 'done' | 'not-joined'>>;
|
|
304
|
+
readonly classificationByName: Readonly<Record<string, 'here' | 'lingering' | 'away' | 'done' | 'not-joined'>>;
|
|
339
305
|
}
|
|
340
306
|
export interface CatchPresence {
|
|
341
307
|
readonly participants: readonly ParticipantSummary[];
|
|
342
308
|
readonly now: number;
|
|
343
309
|
}
|
|
344
|
-
export interface StreamProjection {
|
|
345
|
-
readonly activities: readonly {
|
|
346
|
-
readonly activity: ArchiveRecord;
|
|
347
|
-
readonly route?: string;
|
|
348
|
-
}[];
|
|
349
|
-
readonly cursor: number;
|
|
350
|
-
readonly hasMore: boolean;
|
|
351
|
-
}
|
|
352
310
|
export interface SquareObservation {
|
|
353
311
|
readonly location: string;
|
|
354
312
|
readonly standingCount: number;
|
|
355
313
|
readonly held: boolean;
|
|
356
314
|
readonly now: number;
|
|
357
315
|
readonly participant?: string;
|
|
358
|
-
readonly automaticDeliveryAvailable: boolean;
|
|
359
316
|
}
|
|
360
317
|
export interface JoinObservation extends SquareObservation {
|
|
318
|
+
readonly deliveryAvailable: boolean;
|
|
361
319
|
readonly entry?: EntryPresentation;
|
|
362
320
|
/** The receipt succeeded, but optional recent-history/context enrichment was unavailable. */
|
|
363
321
|
readonly enrichmentUnavailable?: true;
|
|
@@ -366,19 +324,24 @@ export interface ExpressionObservation extends Pick<SquareObservation, 'standing
|
|
|
366
324
|
readonly ownActivityCount: number;
|
|
367
325
|
readonly hardCap: number | null;
|
|
368
326
|
}
|
|
327
|
+
export interface ExpressContext {
|
|
328
|
+
readonly activities: readonly {
|
|
329
|
+
readonly id: ActivityId;
|
|
330
|
+
readonly actor: string;
|
|
331
|
+
readonly preview: string;
|
|
332
|
+
readonly truncated: boolean;
|
|
333
|
+
}[];
|
|
334
|
+
/** Unread activities outside this preview, not a consumption cursor. */
|
|
335
|
+
readonly remaining: number;
|
|
336
|
+
}
|
|
369
337
|
export interface ExpressObservation extends SquareObservation, ExpressionObservation {
|
|
370
338
|
readonly participant: string;
|
|
371
|
-
readonly
|
|
372
|
-
readonly sayNumbers: Readonly<Record<number, number>>;
|
|
373
|
-
readonly perceptions: Readonly<Record<number, Perception>>;
|
|
339
|
+
readonly context: ExpressContext;
|
|
374
340
|
}
|
|
375
341
|
export interface CatchObservation extends SquareObservation, ExpressionObservation {
|
|
342
|
+
readonly deliveryAvailable: boolean;
|
|
376
343
|
readonly participant: string;
|
|
377
|
-
readonly sayNumbers: Readonly<Record<number, number>>;
|
|
378
344
|
readonly presence?: CatchPresence;
|
|
379
|
-
readonly stop?: CatchStopStatus;
|
|
380
|
-
readonly waitStarted?: boolean;
|
|
381
|
-
readonly replaced?: boolean;
|
|
382
345
|
readonly enrichmentUnavailable?: true;
|
|
383
346
|
}
|
|
384
347
|
export interface HistoryContinuation {
|
|
@@ -397,17 +360,12 @@ export interface HistoryObservation extends SquareObservation {
|
|
|
397
360
|
export interface ListenerObservation extends SquareObservation {
|
|
398
361
|
readonly participant: string;
|
|
399
362
|
readonly target: string;
|
|
400
|
-
readonly requestedTarget: string;
|
|
401
|
-
}
|
|
402
|
-
export interface LifecycleObservation extends SquareObservation {
|
|
403
|
-
readonly activity: ArchiveRecord;
|
|
404
363
|
}
|
|
405
|
-
export interface StatusObservation extends SquareObservation, PresenceClassification {
|
|
364
|
+
export interface StatusObservation extends Omit<SquareObservation, 'now' | 'held'>, PresenceClassification {
|
|
406
365
|
readonly knownParticipantCount: number;
|
|
407
|
-
readonly latestActNumber?: number;
|
|
408
366
|
readonly latestPerception?: Perception;
|
|
409
367
|
readonly joins: readonly {
|
|
410
|
-
readonly activity:
|
|
368
|
+
readonly activity: Activity;
|
|
411
369
|
readonly rejoined: boolean;
|
|
412
370
|
}[];
|
|
413
371
|
readonly joinCount: number;
|
package/dist/square-index.d.ts
CHANGED
|
@@ -1,24 +1,16 @@
|
|
|
1
1
|
import { type VersionObserver } from './file-changes.js';
|
|
2
|
-
import { type
|
|
3
|
-
/** A rebuildable discovery hint: the
|
|
4
|
-
* It is deliberately not a participant, generation, ownership, suppression, or evidence row. */
|
|
2
|
+
import { type Owner } from './model.js';
|
|
3
|
+
/** A rebuildable discovery hint: the owner that may have used an artifact and its path. */
|
|
5
4
|
export interface SquareIndexEntry {
|
|
6
5
|
readonly location: string;
|
|
7
|
-
readonly
|
|
6
|
+
readonly owner: Owner;
|
|
8
7
|
}
|
|
9
8
|
export interface SquareIndexQuery {
|
|
10
|
-
readonly
|
|
11
|
-
readonly channel?: string;
|
|
12
|
-
readonly session?: string;
|
|
13
|
-
readonly agent?: string;
|
|
9
|
+
readonly owner?: Owner;
|
|
14
10
|
}
|
|
15
|
-
/** The index is the only host-side Square state. Its path is test/configuration plumbing, not authority. */
|
|
16
11
|
export declare function squareIndexPath(env?: NodeJS.ProcessEnv): string;
|
|
17
|
-
/** Read and verify the disposable index. Paths are canonicalized on access and duplicates collapse. */
|
|
18
12
|
export declare function indexedSquareEntries(query?: SquareIndexQuery, env?: NodeJS.ProcessEnv): Promise<readonly SquareIndexEntry[]>;
|
|
19
13
|
export declare function indexedSquarePaths(query?: SquareIndexQuery, env?: NodeJS.ProcessEnv): Promise<readonly string[]>;
|
|
20
14
|
/** Best-effort discovery only: a busy index skips publication, never queues or delays artifact work. */
|
|
21
|
-
export declare function rememberSquarePath(location: string,
|
|
22
|
-
/** Index loss is tolerated by every caller; this observer is only a wake hint for rediscovery. */
|
|
15
|
+
export declare function rememberSquarePath(location: string, owner: Owner, index: string): Promise<boolean>;
|
|
23
16
|
export declare function observeSquareIndex(env?: NodeJS.ProcessEnv): Promise<VersionObserver<string>>;
|
|
24
|
-
export declare function bodyKey(body: Body): string;
|