@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/paseo-delivery.js
CHANGED
|
@@ -17,28 +17,30 @@ function diagnostic(phase, address, code) {
|
|
|
17
17
|
}
|
|
18
18
|
export class PaseoWakeTransport {
|
|
19
19
|
opts;
|
|
20
|
+
discovering;
|
|
20
21
|
constructor(opts = {}) {
|
|
21
22
|
this.opts = opts;
|
|
22
23
|
}
|
|
24
|
+
/** Coalesce overlapping inventory reads only; a later send must rediscover current status. */
|
|
25
|
+
discover(timeoutMs) {
|
|
26
|
+
return this.discovering ??= Promise.resolve().then(() => (this.opts.discover ?? discoverPaseoAgents)(timeoutMs))
|
|
27
|
+
.finally(() => { this.discovering = undefined; });
|
|
28
|
+
}
|
|
23
29
|
async attempt(request, timeoutMs, beforeSend) {
|
|
24
30
|
const address = request.route.address;
|
|
25
31
|
const deadline = Date.now() + timeoutMs;
|
|
26
32
|
const remainingMs = () => Math.max(0, deadline - Date.now());
|
|
27
33
|
const budgetUnavailable = () => ({
|
|
28
34
|
outcome: 'failed',
|
|
29
|
-
unavailable: true,
|
|
30
35
|
signature: 'dispatch_budget_exhausted',
|
|
31
36
|
message: 'The wake dispatch budget elapsed before Paseo accepted the wake.',
|
|
32
|
-
retainRoute: true,
|
|
33
37
|
});
|
|
34
38
|
const agentId = address.agentId?.trim();
|
|
35
39
|
if (!agentId) {
|
|
36
40
|
return {
|
|
37
41
|
outcome: 'failed',
|
|
38
|
-
unavailable: true,
|
|
39
42
|
signature: 'invalid_address',
|
|
40
43
|
message: 'Paseo route has no agent id.',
|
|
41
|
-
routeStale: true,
|
|
42
44
|
diagnostic: diagnostic('selection', address, 'invalid_address'),
|
|
43
45
|
};
|
|
44
46
|
}
|
|
@@ -49,30 +51,25 @@ export class PaseoWakeTransport {
|
|
|
49
51
|
let remaining = remainingMs();
|
|
50
52
|
if (remaining === 0)
|
|
51
53
|
return budgetUnavailable();
|
|
52
|
-
const discovery =
|
|
54
|
+
const discovery = await this.discover(remaining);
|
|
53
55
|
if (discovery.error && discovery.agents.length === 0) {
|
|
54
56
|
return {
|
|
55
57
|
outcome: 'failed',
|
|
56
|
-
unavailable: true,
|
|
57
58
|
// A credential or authorization refusal is proven; anything else may be transient.
|
|
58
59
|
signature: /password|auth|unauthori[sz]ed/i.test(discovery.error) ? 'discovery_rejected'
|
|
59
60
|
: /DAEMON_NOT_RUNNING|ECONNREFUSED|ENOENT|not found.*executable|ETIMEDOUT|timed out|timeout/i.test(discovery.error)
|
|
60
61
|
? 'discovery_transient' : 'discovery_rejected',
|
|
61
62
|
message: `Paseo unavailable: ${discovery.error}`,
|
|
62
63
|
diagnostic: diagnostic('discovery', address, 'unavailable'),
|
|
63
|
-
retainRoute: true,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
const agent = discovery.agents.find((candidate) => candidate.id === agentId);
|
|
67
67
|
if (agent === undefined || agent.status !== 'idle') {
|
|
68
68
|
return {
|
|
69
69
|
outcome: 'failed',
|
|
70
|
-
unavailable: true,
|
|
71
70
|
signature: agent === undefined ? 'address_not_found' : 'agent_not_idle',
|
|
72
71
|
message: agent === undefined ? 'The registered Paseo agent was not found.' : 'The registered Paseo agent is not idle.',
|
|
73
72
|
diagnostic: diagnostic('selection', address, agent === undefined ? 'not_found' : 'not_idle'),
|
|
74
|
-
...(agent === undefined ? {} : { retainRoute: true }),
|
|
75
|
-
...(agent === undefined ? { routeStale: true } : {}),
|
|
76
73
|
};
|
|
77
74
|
}
|
|
78
75
|
remaining = remainingMs();
|
|
@@ -81,11 +78,9 @@ export class PaseoWakeTransport {
|
|
|
81
78
|
if (!(await (this.opts.waitForBoundary ?? waitForPaseoWakeBoundary)(agent, remaining))) {
|
|
82
79
|
return {
|
|
83
80
|
outcome: 'failed',
|
|
84
|
-
unavailable: true,
|
|
85
81
|
signature: 'boundary_unavailable',
|
|
86
82
|
message: 'Paseo did not reach the current tool boundary before the wake timeout.',
|
|
87
83
|
diagnostic: diagnostic('boundary', address, 'unavailable'),
|
|
88
|
-
retainRoute: true,
|
|
89
84
|
};
|
|
90
85
|
}
|
|
91
86
|
if (!(await beforeSend()))
|
package/dist/paseo-state.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ export interface PaseoAgent {
|
|
|
7
7
|
export declare function discoverPaseoAgents(timeoutMs?: number, opts?: {
|
|
8
8
|
args?: string[];
|
|
9
9
|
bin?: string;
|
|
10
|
-
}): {
|
|
10
|
+
}): Promise<{
|
|
11
11
|
agents: PaseoAgent[];
|
|
12
12
|
error?: string;
|
|
13
|
-
}
|
|
13
|
+
}>;
|
|
14
14
|
export declare function waitForPaseoWakeBoundary(agent: Pick<PaseoAgent, 'id' | 'status'>, timeoutMs?: number): Promise<boolean>;
|
package/dist/paseo-state.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
2
3
|
import { waitForPaseoToolBoundary } from './paseo-timeline.js';
|
|
3
|
-
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export async function discoverPaseoAgents(timeoutMs = 5000, opts = {}) {
|
|
4
6
|
try {
|
|
5
|
-
const raw =
|
|
7
|
+
const { stdout: raw } = await execFileAsync(opts.bin ?? process.env.SQUARE_PASEO_BIN ?? 'paseo', [...(opts.args ?? []), 'ls', '--global', '--json'], {
|
|
6
8
|
encoding: 'utf8',
|
|
7
9
|
timeout: timeoutMs,
|
|
8
|
-
|
|
10
|
+
maxBuffer: 1024 * 1024,
|
|
9
11
|
});
|
|
10
12
|
const parsed = JSON.parse(raw);
|
|
11
13
|
const agents = Array.isArray(parsed) ? parsed : parsed?.agents;
|
|
@@ -3,39 +3,48 @@ import { createArtifactPort } from '../../artifact.js';
|
|
|
3
3
|
import { deliverPending } from '../../delivery-operations.js';
|
|
4
4
|
import { nativePendingPreview, observeSessionPending, projectSessionSeats } from '../../inbox.js';
|
|
5
5
|
import { automaticWakeEligible, presentationBlocksWake } from '../../delivery.js';
|
|
6
|
-
import {
|
|
6
|
+
import { harnessOwner, decodeHarnessOwner } from '../../owner.js';
|
|
7
7
|
import { formatActivityId, parseActivityId } from '../../square-core.js';
|
|
8
8
|
import { indexedSquareEntries } from '../../square-index.js';
|
|
9
9
|
import { asSeatRef } from '../../seats.js';
|
|
10
|
+
import { restoreSessionSeats } from '../../session-lifecycle.js';
|
|
10
11
|
import { presentPending } from '../../presentation-operations.js';
|
|
11
12
|
import { createNativeInputId, sendNativeText } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
12
13
|
const routeKind = 'opencode-server';
|
|
13
|
-
const
|
|
14
|
+
const ownerFor = (sessionId) => harnessOwner({ channel: 'opencode', session: sessionId });
|
|
14
15
|
const payloadHash = (payload) => createHash('sha256').update(payload).digest('hex');
|
|
15
|
-
function preview(facts, location,
|
|
16
|
+
function preview(facts, location, captured, index) {
|
|
17
|
+
const seat = facts.seat(captured.participant);
|
|
18
|
+
if (seat === undefined || seat.attachment !== 'attached' || seat.generation !== captured.generation || seat.owner !== captured.owner)
|
|
19
|
+
return undefined;
|
|
20
|
+
const wake = seat.wakeAddress;
|
|
21
|
+
if (wake?.kind !== routeKind)
|
|
22
|
+
return undefined;
|
|
16
23
|
return nativePendingPreview(facts, {
|
|
17
|
-
location, routeKind,
|
|
18
|
-
actIndex: index, address:
|
|
24
|
+
location, routeKind, generation: seat.generation, participant: seat.participant,
|
|
25
|
+
actIndex: index, address: wake.address, now: Date.now(),
|
|
19
26
|
});
|
|
20
27
|
}
|
|
21
28
|
export async function indexedOpenCodeSessions(env) {
|
|
22
|
-
return [...new Set((await indexedSquareEntries({
|
|
29
|
+
return [...new Set((await indexedSquareEntries({}, env)).flatMap((entry) => {
|
|
30
|
+
const coordinate = decodeHarnessOwner(entry.owner);
|
|
31
|
+
return coordinate?.channel === 'opencode' ? [coordinate.session] : [];
|
|
32
|
+
}))];
|
|
23
33
|
}
|
|
24
34
|
export async function discoverOpenCodeSeats(sessionId, env, signal) {
|
|
25
|
-
return projectSessionSeats({
|
|
35
|
+
return projectSessionSeats({ owner: ownerFor(sessionId), env }, signal);
|
|
26
36
|
}
|
|
27
37
|
function sameSeat(left, right) {
|
|
28
|
-
return left !== undefined && left.generation === right.generation &&
|
|
38
|
+
return left !== undefined && left.attachment === 'attached' && left.generation === right.generation && left.owner === right.owner;
|
|
29
39
|
}
|
|
30
40
|
function createOpenCodeWakeTransport(target, lifetime) {
|
|
31
41
|
return {
|
|
32
42
|
probe: async (route) => !lifetime.aborted && route.kind === routeKind
|
|
33
|
-
&& route.
|
|
43
|
+
&& route.address.sessionId === target.sessionId,
|
|
34
44
|
async attempt(request, timeoutMs, beforeSend) {
|
|
35
45
|
const index = parseActivityId(request.activity);
|
|
36
46
|
const artifact = request.artifact;
|
|
37
47
|
if (artifact === undefined || request.claimToken === undefined || index === undefined
|
|
38
|
-
|| !sameBody(request.seat.body, bodyFor(target.sessionId))
|
|
39
48
|
|| request.route.kind !== routeKind || request.route.address.sessionId !== target.sessionId) {
|
|
40
49
|
return { outcome: 'not-capable', diagnostic: 'OpenCode attention has no matching artifact claim or session.' };
|
|
41
50
|
}
|
|
@@ -61,7 +70,7 @@ function createOpenCodeWakeTransport(target, lifetime) {
|
|
|
61
70
|
if (result.state === 'accepted')
|
|
62
71
|
return { outcome: 'accepted' };
|
|
63
72
|
if (result.state === 'unavailable')
|
|
64
|
-
return { outcome: 'failed',
|
|
73
|
+
return { outcome: 'failed', signature: result.code };
|
|
65
74
|
return { outcome: 'unknown', signature: result.code };
|
|
66
75
|
},
|
|
67
76
|
};
|
|
@@ -126,7 +135,7 @@ export async function observeOpenCodeContext(sessionId, messages, env, signal) {
|
|
|
126
135
|
}
|
|
127
136
|
/** The native receiver owns no claims outside the artifact; HOME is used only for discovery. */
|
|
128
137
|
export async function receiveOpenCodePending(target, env, signal) {
|
|
129
|
-
const observer = await observeSessionPending(
|
|
138
|
+
const observer = await observeSessionPending(ownerFor(target.sessionId), env);
|
|
130
139
|
const transport = createOpenCodeWakeTransport(target, signal);
|
|
131
140
|
let waiting;
|
|
132
141
|
try {
|
|
@@ -181,7 +190,8 @@ export async function receiveOpenCodePending(target, env, signal) {
|
|
|
181
190
|
}
|
|
182
191
|
/** Publish the native address into current artifact seats; the legacy route projection is not read. */
|
|
183
192
|
export async function publishOpenCodeAddress(sessionId, env, signal) {
|
|
184
|
-
|
|
193
|
+
await restoreSessionSeats(ownerFor(sessionId), env, { kind: routeKind, address: { sessionId } }, signal);
|
|
194
|
+
const seats = (await discoverOpenCodeSeats(sessionId, env, signal)).filter(({ seat }) => seat.attachment === 'attached');
|
|
185
195
|
for (const { location, seat } of seats) {
|
|
186
196
|
if (signal.aborted)
|
|
187
197
|
return false;
|
|
@@ -199,6 +209,8 @@ export async function cancelOpenCodeDeliveries(sessionId, env, signal) {
|
|
|
199
209
|
for (const { location, seat } of await discoverOpenCodeSeats(sessionId, env, signal)) {
|
|
200
210
|
if (signal.aborted)
|
|
201
211
|
return;
|
|
212
|
+
if (seat.attachment !== 'attached')
|
|
213
|
+
continue;
|
|
202
214
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
203
215
|
try {
|
|
204
216
|
const { value: through } = await artifact.read((facts) => facts.header().lastActIndex, signal);
|
|
@@ -215,9 +227,9 @@ export async function endOpenCodeSession(sessionId, env, signal) {
|
|
|
215
227
|
if (signal.aborted)
|
|
216
228
|
return;
|
|
217
229
|
const { Square } = await import('../../square-api.js');
|
|
218
|
-
const square = await Square.at({ path: location, env
|
|
230
|
+
const square = await Square.at({ path: location, env });
|
|
219
231
|
try {
|
|
220
|
-
await square.
|
|
232
|
+
await square.endHeld(seat.participant, { owner: seat.owner, generation: seat.generation });
|
|
221
233
|
}
|
|
222
234
|
finally {
|
|
223
235
|
await square.close();
|
package/dist/ports.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Act, ActivityId,
|
|
1
|
+
import type { Act, ActivityId, Owner, HardCap, Seat, StoredAct, WakeAddress, WakeRoute, WatchLease } from './model.js';
|
|
2
2
|
import type { MetadataMatch, DeliveryDeferralFact } from './delivery-deferral.js';
|
|
3
3
|
export type ActivityIndex = number;
|
|
4
4
|
export interface SquareHeader {
|
|
@@ -85,22 +85,22 @@ export interface ReceiptAssignment {
|
|
|
85
85
|
readonly owner: string;
|
|
86
86
|
readonly index: ActivityIndex;
|
|
87
87
|
}
|
|
88
|
-
export type
|
|
89
|
-
readonly [key: string]: JsonValue;
|
|
90
|
-
};
|
|
91
|
-
export type SeatRef = Omit<Seat, 'wakeAddress'>;
|
|
88
|
+
export type SeatRef = Pick<Seat, 'participant' | 'owner' | 'generation'>;
|
|
92
89
|
export type ArtifactWriteAuthority = {
|
|
93
90
|
readonly kind: 'participant';
|
|
94
91
|
readonly seat: SeatRef;
|
|
92
|
+
} | {
|
|
93
|
+
readonly kind: 'host-cleanup';
|
|
94
|
+
readonly seat: SeatRef;
|
|
95
95
|
} | {
|
|
96
96
|
readonly kind: 'join';
|
|
97
97
|
readonly participant: string;
|
|
98
|
-
readonly
|
|
98
|
+
readonly owner: Owner;
|
|
99
99
|
readonly wakeAddress?: WakeAddress;
|
|
100
100
|
} | {
|
|
101
101
|
readonly kind: 'takeover';
|
|
102
102
|
readonly participant: string;
|
|
103
|
-
readonly
|
|
103
|
+
readonly owner: Owner;
|
|
104
104
|
readonly expectedGeneration: ActivityId;
|
|
105
105
|
readonly wakeAddress?: WakeAddress;
|
|
106
106
|
};
|
|
@@ -168,9 +168,7 @@ export interface DeliveryCompletion {
|
|
|
168
168
|
/** Domain facts exist only during a synchronous artifact callback. Values are detached. */
|
|
169
169
|
export interface SquareRead {
|
|
170
170
|
seat(requestedName: string): Seat | undefined;
|
|
171
|
-
|
|
172
|
-
/** Latest completed coordinates only; never participant write authority. */
|
|
173
|
-
completedSeatsForBody(body: Body): readonly Seat[];
|
|
171
|
+
seatsForOwner(owner: Owner): readonly Seat[];
|
|
174
172
|
deliveryEvidence(participant: string, generation: ActivityId, activity?: ActivityId): readonly DeliveryEvidence[];
|
|
175
173
|
deliveryByToken(claimToken: string): DeliveryEvidence | undefined;
|
|
176
174
|
cancelledThrough(participant: string, generation: ActivityId): number | undefined;
|
|
@@ -219,6 +217,10 @@ export interface SquareWrite extends SquareRead {
|
|
|
219
217
|
readonly at: number;
|
|
220
218
|
}): StoredAct;
|
|
221
219
|
updateWakeAddress(seat: SeatRef, wakeAddress?: WakeAddress): boolean;
|
|
220
|
+
/** Join authority only; preserves membership and its establishing generation. */
|
|
221
|
+
reattachSeat(seat: SeatRef, wakeAddress?: WakeAddress): boolean;
|
|
222
|
+
/** Host-cleanup authority only; stale/already-detached coordinates are a no-op. */
|
|
223
|
+
detachSeat(seat: SeatRef): boolean;
|
|
222
224
|
cancelThrough(seat: SeatRef, through: ActivityIndex): boolean;
|
|
223
225
|
claimDelivery(input: DeliveryClaimInput): DeliveryClaimResult;
|
|
224
226
|
prepareDelivery(input: DeliveryPreparation): boolean;
|
|
@@ -245,7 +247,7 @@ export interface SquareCommitResult<R> extends SquareReadResult<R> {
|
|
|
245
247
|
/** Atomic artifact access; no framing, SQL or lazy transaction capability escapes. */
|
|
246
248
|
export interface SquareArtifactPort {
|
|
247
249
|
read<R>(select: (facts: SquareRead) => R, signal?: AbortSignal): Promise<SquareReadResult<R>>;
|
|
248
|
-
/** Participant/domain writes must carry an explicit
|
|
250
|
+
/** Participant/domain writes must carry an explicit owner; no owner-less mutation path exists. */
|
|
249
251
|
transactAs<R>(authority: ArtifactWriteAuthority, change: (facts: SquareWrite) => R, signal?: AbortSignal): Promise<SquareCommitResult<R>>;
|
|
250
252
|
/** Bounded cleanup/evidence settlement on this same connection after custody was acquired.
|
|
251
253
|
* Independent of request/lifetime cancellation; explicit close and authority fences still apply. */
|
|
@@ -295,28 +297,14 @@ export interface WakeRequest {
|
|
|
295
297
|
export interface PresentationSinkPort {
|
|
296
298
|
present(activity: StoredAct): void | Promise<void>;
|
|
297
299
|
}
|
|
298
|
-
/** Read-only presentation evidence projection for diagnostics and migration callers. */
|
|
299
|
-
export interface PresentationEvidenceProjection {
|
|
300
|
-
readonly location: string;
|
|
301
|
-
readonly participant: string;
|
|
302
|
-
readonly sessionId: string;
|
|
303
|
-
readonly activity: string;
|
|
304
|
-
readonly outcome: string;
|
|
305
|
-
readonly at?: number;
|
|
306
|
-
}
|
|
307
300
|
export type WakeOutcome = {
|
|
308
301
|
readonly outcome: 'accepted';
|
|
309
302
|
readonly signature?: string;
|
|
310
|
-
readonly attemptN?: number;
|
|
311
303
|
} | {
|
|
312
304
|
readonly outcome: 'failed';
|
|
313
305
|
readonly message?: string;
|
|
314
306
|
readonly signature?: string;
|
|
315
307
|
readonly diagnostic?: unknown;
|
|
316
|
-
readonly attemptN?: number;
|
|
317
|
-
readonly unavailable?: boolean;
|
|
318
|
-
readonly retainRoute?: boolean;
|
|
319
|
-
readonly routeStale?: boolean;
|
|
320
308
|
} | {
|
|
321
309
|
readonly outcome: 'not-capable';
|
|
322
310
|
readonly diagnostic?: string;
|
|
@@ -325,15 +313,7 @@ export type WakeOutcome = {
|
|
|
325
313
|
readonly signature?: string;
|
|
326
314
|
readonly message?: string;
|
|
327
315
|
readonly diagnostic?: unknown;
|
|
328
|
-
readonly attemptN?: number;
|
|
329
316
|
};
|
|
330
|
-
export interface DeliveryResult {
|
|
331
|
-
readonly attempted: number;
|
|
332
|
-
readonly accepted: number;
|
|
333
|
-
readonly failed: number;
|
|
334
|
-
readonly unknown: number;
|
|
335
|
-
readonly notCapable: number;
|
|
336
|
-
}
|
|
337
317
|
export interface DeliverPendingInput {
|
|
338
318
|
readonly artifact: SquareArtifactPort;
|
|
339
319
|
readonly transport: WakeTransportPort;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { formatActivityId, parseActivityId } from './square-core.js';
|
|
3
|
-
import { isSquareError
|
|
3
|
+
import { isSquareError } from './model.js';
|
|
4
4
|
import { pendingHead, sameJoin } from './delivery.js';
|
|
5
5
|
import { deliveryDeferralExpiry } from './delivery-deferral.js';
|
|
6
6
|
import { asSeatRef } from './seats.js';
|
|
@@ -12,8 +12,8 @@ export async function preparePendingPresentation(input) {
|
|
|
12
12
|
const initial = await input.artifact.read((facts) => {
|
|
13
13
|
const participant = facts.participant(input.participant);
|
|
14
14
|
const seat = facts.seat(input.participant);
|
|
15
|
-
if (!participant?.joined || seat === undefined || input.generation !== undefined && input.generation !== seat.generation
|
|
16
|
-
|| input.seat !== undefined && (input.seat.generation !== seat.generation ||
|
|
15
|
+
if (!participant?.joined || seat === undefined || seat.attachment !== 'attached' || input.generation !== undefined && input.generation !== seat.generation
|
|
16
|
+
|| input.seat !== undefined && (input.seat.generation !== seat.generation || input.seat.owner !== seat.owner)
|
|
17
17
|
|| input.current?.(facts) === false || !pendingHead(facts, participant.name, index)
|
|
18
18
|
|| deliveryDeferralExpiry(facts, seat, index, input.now ?? Date.now()) !== undefined)
|
|
19
19
|
return undefined;
|
|
@@ -26,7 +26,7 @@ export async function preparePendingPresentation(input) {
|
|
|
26
26
|
const ref = asSeatRef(seat);
|
|
27
27
|
const owns = (facts) => {
|
|
28
28
|
const current = facts.seat(seat.participant);
|
|
29
|
-
return current !== undefined &&
|
|
29
|
+
return current !== undefined && current.attachment === 'attached' && current.owner === seat.owner && current.generation === seat.generation
|
|
30
30
|
&& sameJoin(facts, participant);
|
|
31
31
|
};
|
|
32
32
|
const claimToken = randomUUID();
|
package/dist/presentation.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type StoredAct, type RoomChangeAct } from './model.js';
|
|
|
2
2
|
export { participantIdentity } from './participant-identity.js';
|
|
3
3
|
import { type Perception } from './square-core.js';
|
|
4
4
|
import type { Activity, UnreadActivitySummary, ParticipantSummary } from './square-facade.js';
|
|
5
|
-
export type WatchStatus = '
|
|
5
|
+
export type WatchStatus = 'idle' | 'drained' | 'quorum' | 'capped';
|
|
6
6
|
interface HeaderOptions {
|
|
7
7
|
participantCount?: number;
|
|
8
8
|
held?: boolean;
|
|
@@ -10,6 +10,7 @@ interface HeaderOptions {
|
|
|
10
10
|
plain?: boolean;
|
|
11
11
|
}
|
|
12
12
|
interface ParticipantOutputOptions {
|
|
13
|
+
owner?: string;
|
|
13
14
|
squarePath: string;
|
|
14
15
|
name: string;
|
|
15
16
|
participantCount?: number;
|
|
@@ -60,11 +61,11 @@ export declare function formatRefusal(squarePath: string, bodyLines: string[], o
|
|
|
60
61
|
export declare function refusalText(error: unknown): string;
|
|
61
62
|
export declare function quoteShell(value: string): string;
|
|
62
63
|
export declare function commandPrefix(squarePath: string): string;
|
|
63
|
-
export declare function participantCommandPrefix(squarePath: string, name: string): string;
|
|
64
|
+
export declare function participantCommandPrefix(squarePath: string, name: string, owner?: string): string;
|
|
64
65
|
/** Blocked actions end with a full copy-pasteable recovery command. */
|
|
65
|
-
export declare function joinRecoveryCommand(squarePath: string, name: string): string;
|
|
66
|
+
export declare function joinRecoveryCommand(squarePath: string, name: string, owner?: string): string;
|
|
66
67
|
/** Taking a name is an explicit recovery choice, never an automatic retry. */
|
|
67
|
-
export declare function takeoverRecoveryLines(squarePath: string, name: string): string[];
|
|
68
|
+
export declare function takeoverRecoveryLines(squarePath: string, name: string, owner?: string): string[];
|
|
68
69
|
export declare function participantsRecoveryCommand(squarePath: string): string;
|
|
69
70
|
export declare function renderPresenceLines(recent: readonly ParticipantSummary[], now: number, limit?: number): string[];
|
|
70
71
|
export declare function truncateChars(body: string, maxChars: number): {
|
|
@@ -81,14 +82,12 @@ interface RenderedEvent {
|
|
|
81
82
|
export declare function renderEventCli(event: StoredAct | Activity, opts?: {
|
|
82
83
|
now?: number;
|
|
83
84
|
preview?: number;
|
|
84
|
-
actNumber?: number;
|
|
85
85
|
mention?: string;
|
|
86
86
|
}): string;
|
|
87
87
|
export declare function renderAmbientEventFacts(event: StoredAct | Activity, viewer: string, opts?: {
|
|
88
88
|
now?: number;
|
|
89
89
|
preview?: number;
|
|
90
90
|
presencePreview?: number;
|
|
91
|
-
actNumber?: number;
|
|
92
91
|
mention?: string;
|
|
93
92
|
perception?: Perception;
|
|
94
93
|
}): RenderedEvent;
|
|
@@ -96,11 +95,9 @@ export declare function renderAmbientEvent(event: StoredAct | Activity, viewer:
|
|
|
96
95
|
now?: number;
|
|
97
96
|
preview?: number;
|
|
98
97
|
presencePreview?: number;
|
|
99
|
-
actNumber?: number;
|
|
100
98
|
mention?: string;
|
|
101
99
|
perception?: Perception;
|
|
102
100
|
}): string;
|
|
103
|
-
export declare function renderPendingFeed(publicItems: readonly StoredAct[], sayNumbers: Readonly<Record<number, number>>, perceptions: Readonly<Record<number, Perception>>, viewer: string): string;
|
|
104
101
|
export declare function renderActivityBlocked(opts: ActivityBlockedOptions): string;
|
|
105
102
|
/** An indeterminate or already-committed send only points to inspection, never resend. */
|
|
106
103
|
export declare function renderActivityUncertain(opts: ParticipantOutputOptions & {
|
package/dist/presentation.js
CHANGED
|
@@ -50,18 +50,18 @@ export function quoteShell(value) {
|
|
|
50
50
|
export function commandPrefix(squarePath) {
|
|
51
51
|
return `square --location ${quoteShell(squarePath)}`;
|
|
52
52
|
}
|
|
53
|
-
export function participantCommandPrefix(squarePath, name) {
|
|
54
|
-
return `square --location ${quoteShell(/^[A-Za-z][A-Za-z0-9+.-]*:/.test(squarePath) ? squarePath : path.resolve(squarePath))} --as ${quoteShell(name)}`;
|
|
53
|
+
export function participantCommandPrefix(squarePath, name, owner) {
|
|
54
|
+
return `square --location ${quoteShell(/^[A-Za-z][A-Za-z0-9+.-]*:/.test(squarePath) ? squarePath : path.resolve(squarePath))} --as ${quoteShell(name)}${owner === undefined ? '' : ` --owner ${quoteShell(owner)}`}`;
|
|
55
55
|
}
|
|
56
56
|
/** Blocked actions end with a full copy-pasteable recovery command. */
|
|
57
|
-
export function joinRecoveryCommand(squarePath, name) {
|
|
58
|
-
return `${participantCommandPrefix(squarePath, name)} join`;
|
|
57
|
+
export function joinRecoveryCommand(squarePath, name, owner) {
|
|
58
|
+
return `${participantCommandPrefix(squarePath, name, owner)} join`;
|
|
59
59
|
}
|
|
60
60
|
/** Taking a name is an explicit recovery choice, never an automatic retry. */
|
|
61
|
-
export function takeoverRecoveryLines(squarePath, name) {
|
|
61
|
+
export function takeoverRecoveryLines(squarePath, name, owner) {
|
|
62
62
|
return [
|
|
63
63
|
'If this is your name to reclaim, --kick banishes the one standing here so you can step in:',
|
|
64
|
-
`${participantCommandPrefix(squarePath, name)} join --kick`,
|
|
64
|
+
`${participantCommandPrefix(squarePath, name, owner)} join --kick`,
|
|
65
65
|
];
|
|
66
66
|
}
|
|
67
67
|
export function participantsRecoveryCommand(squarePath) {
|
|
@@ -79,13 +79,14 @@ export function renderPresenceLines(recent, now, limit = 5) {
|
|
|
79
79
|
if (shown.length === 0)
|
|
80
80
|
return [style('dim', ' ○ nobody nearby')];
|
|
81
81
|
const lines = shown.map((p) => {
|
|
82
|
-
const glyph = p.
|
|
83
|
-
const text = p.
|
|
82
|
+
const glyph = p.presence === 'done' || p.presence === 'away' ? '○' : p.presence === 'watching' ? '◎' : p.lastActiveAt !== undefined ? '●' : '○';
|
|
83
|
+
const text = p.presence === 'done'
|
|
84
84
|
? (p.lastActiveAt === undefined ? 'stepped out of the square' : `stepped out of the square · ${formatRelativeTime(p.lastActiveAt, now)}`)
|
|
85
|
-
: p.presence === '
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
: p.
|
|
85
|
+
: p.presence === 'away' ? 'is away'
|
|
86
|
+
: p.presence === 'watching'
|
|
87
|
+
? (p.lastActiveAt === undefined ? 'is nearby · catching' : `is nearby · catching · ${formatRelativeTime(p.lastActiveAt, now)}`)
|
|
88
|
+
: p.lastActiveAt === undefined ? 'is nearby · quiet'
|
|
89
|
+
: p.activityCount > 0 ? `is nearby · ${formatRelativeTime(p.lastActiveAt, now)}` : `is nearby · quiet · ${formatRelativeTime(p.lastActiveAt, now)}`;
|
|
89
90
|
return ` ${glyph === '○' ? style('dim', glyph) : glyph} ${participantIdentity(p.name)}${style('dim', ` ${text}`)}`;
|
|
90
91
|
});
|
|
91
92
|
const remaining = recent.length - shown.length;
|
|
@@ -229,37 +230,26 @@ function draftSavedLines(draftPath) {
|
|
|
229
230
|
function withDraftInput(command, draftPath) {
|
|
230
231
|
return draftPath === undefined ? command : `${command} < ${quoteShell(draftPath)}`;
|
|
231
232
|
}
|
|
232
|
-
function renderUnreadSummary(
|
|
233
|
-
const visibleSummaries =
|
|
234
|
-
const remainingSummaries =
|
|
233
|
+
function renderUnreadSummary(activitySummaries) {
|
|
234
|
+
const visibleSummaries = activitySummaries.slice(0, MAX_IDENTITY_SET_SIZE);
|
|
235
|
+
const remainingSummaries = activitySummaries.length - visibleSummaries.length;
|
|
235
236
|
return [
|
|
236
|
-
...visibleSummaries.
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const compact = (preview.act.body ?? '').replace(/\s+/g, ' ').trim();
|
|
245
|
-
const bodyPreview = compact === ''
|
|
246
|
-
? { text: preview.act.metadata === undefined ? '(empty)' : '(structured activity)', remaining: 0 }
|
|
247
|
-
: truncateChars(compact, UNREAD_PREVIEW_CHARS);
|
|
248
|
-
const bodyText = bodyPreview.remaining === 0 ? bodyPreview.text : `${bodyPreview.text}${style('dim', `… (+${bodyPreview.remaining} chars)`)}`;
|
|
249
|
-
return style('dim', ` · ${participantIdentity(item.name)} spoke — ${formatAge(item.latestActivityAgeMs)} ago · "${bodyText}"`);
|
|
250
|
-
}),
|
|
251
|
-
]),
|
|
237
|
+
...visibleSummaries.map((item) => {
|
|
238
|
+
const compact = (item.preview.body ?? '').replace(/\s+/g, ' ').trim();
|
|
239
|
+
const bodyPreview = compact === ''
|
|
240
|
+
? { text: item.preview.metadata === undefined ? '(empty)' : '(structured activity)', remaining: 0 }
|
|
241
|
+
: truncateChars(compact, UNREAD_PREVIEW_CHARS);
|
|
242
|
+
const bodyText = bodyPreview.remaining === 0 ? bodyPreview.text : `${bodyPreview.text}${style('dim', `… (+${bodyPreview.remaining} chars)`)}`;
|
|
243
|
+
return style('dim', ` · ${participantIdentity(item.name)} spoke — ${formatAge(item.latestActivityAgeMs)} ago · "${bodyText}"`);
|
|
244
|
+
}),
|
|
252
245
|
...(remainingSummaries === 0 ? [] : [style('dim', ` · ${remainingSummaries} more participants have unread activity`)]),
|
|
253
246
|
];
|
|
254
247
|
}
|
|
255
|
-
export function renderPendingFeed(publicItems, sayNumbers, perceptions, viewer) {
|
|
256
|
-
return publicItems.map((act) => renderAmbientEvent(act, viewer, { actNumber: sayNumbers[act.index], perception: perceptions[act.index] })).filter(Boolean).join('\n\n');
|
|
257
|
-
}
|
|
258
248
|
export function renderActivityBlocked(opts) {
|
|
259
|
-
const readNowCommand = `${participantCommandPrefix(opts.squarePath, opts.name)} catch`;
|
|
249
|
+
const readNowCommand = `${participantCommandPrefix(opts.squarePath, opts.name, opts.owner)} catch`;
|
|
260
250
|
return withPathOutput(opts.squarePath, [
|
|
261
251
|
`${style('blocked', '✕')} your activity hasn't landed — someone spoke while you were away`,
|
|
262
|
-
...renderUnreadSummary(
|
|
252
|
+
...renderUnreadSummary(opts.activitySummaries),
|
|
263
253
|
...draftSavedLines(opts.draftPath),
|
|
264
254
|
`${readNowCommand}`,
|
|
265
255
|
' · take it in, then retry:',
|
|
@@ -373,7 +363,7 @@ export function renderGrepActivitiesView(visible, totalMatches, noTruncate, squa
|
|
|
373
363
|
export function renderActivityLimit(opts) {
|
|
374
364
|
// The cap wording lives inside the count: the speaker is simply spent.
|
|
375
365
|
const spoken = opts.count !== undefined && opts.hardCap !== undefined ? ` — ${opts.count}/${opts.hardCap} spoken` : '';
|
|
376
|
-
const doneCommand = `${participantCommandPrefix(opts.squarePath, opts.name)} done`;
|
|
366
|
+
const doneCommand = `${participantCommandPrefix(opts.squarePath, opts.name, opts.owner)} done`;
|
|
377
367
|
return withPathOutput(opts.squarePath, [
|
|
378
368
|
`${style('blocked', '✕')} you’ve reached your speaking cap${spoken}`,
|
|
379
369
|
...draftSavedLines(opts.draftPath),
|
|
@@ -386,7 +376,7 @@ export function renderWatchAlreadyActive(opts) {
|
|
|
386
376
|
`${style('blocked', '✕')} you are already catching`,
|
|
387
377
|
` · an active catch is already running for ${participantIdentity(opts.name)}`,
|
|
388
378
|
' · --replace lets a new catch take over',
|
|
389
|
-
`${participantCommandPrefix(opts.squarePath, opts.name)} catch --idle 30m --replace`,
|
|
379
|
+
`${participantCommandPrefix(opts.squarePath, opts.name, opts.owner)} catch --idle 30m --replace`,
|
|
390
380
|
].join('\n');
|
|
391
381
|
}
|
|
392
382
|
export function renderWatchForceTakeover(_opts) {
|
|
@@ -406,9 +396,9 @@ export function renderWatchStatus(opts) {
|
|
|
406
396
|
? ['', 'around the square', ...renderPresenceLines(others, opts.presence.now)]
|
|
407
397
|
: [];
|
|
408
398
|
switch (opts.status) {
|
|
409
|
-
case '
|
|
410
|
-
case '
|
|
411
|
-
const prefix = participantCommandPrefix(opts.squarePath, opts.name);
|
|
399
|
+
case 'idle':
|
|
400
|
+
case 'drained': {
|
|
401
|
+
const prefix = participantCommandPrefix(opts.squarePath, opts.name, opts.owner);
|
|
412
402
|
// Quiet graduates with the idle length; an empty catch has no idle budget to report.
|
|
413
403
|
const idleMs = opts.idleMs;
|
|
414
404
|
const quiet = idleMs !== undefined && idleMs >= 60 * 60 * 1000
|
|
@@ -425,12 +415,12 @@ export function renderWatchStatus(opts) {
|
|
|
425
415
|
].join('\n');
|
|
426
416
|
}
|
|
427
417
|
case 'quorum':
|
|
428
|
-
return [`${style('release', '✓')} everyone else has left — the square is yours alone`, `${participantCommandPrefix(opts.squarePath, opts.name)} done`].join('\n');
|
|
418
|
+
return [`${style('release', '✓')} everyone else has left — the square is yours alone`, `${participantCommandPrefix(opts.squarePath, opts.name, opts.owner)} done`].join('\n');
|
|
429
419
|
case 'capped': {
|
|
430
420
|
const spoken = opts.hardCap === undefined || opts.hardCap === null
|
|
431
421
|
? ''
|
|
432
422
|
: ` — ${opts.ownActivityCount ?? 0}/${opts.hardCap} spoken`;
|
|
433
|
-
return [`${style('blocked', '✕')} you’ve reached your speaking cap${spoken}`, `${participantCommandPrefix(opts.squarePath, opts.name)} done`].join('\n');
|
|
423
|
+
return [`${style('blocked', '✕')} you’ve reached your speaking cap${spoken}`, `${participantCommandPrefix(opts.squarePath, opts.name, opts.owner)} done`].join('\n');
|
|
434
424
|
}
|
|
435
425
|
}
|
|
436
426
|
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,18 +1,12 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import { type StoredAct, type WatchLease } from './model.js';
|
|
1
|
+
import { type WatchLease } from './model.js';
|
|
3
2
|
import type { ParticipantCounts, ParticipantFact, SquareRead } from './ports.js';
|
|
4
3
|
export declare const WATCH_HEARTBEAT_MS: number;
|
|
5
|
-
export declare const SLEEP_MS: number;
|
|
6
|
-
export declare const STALE_MS: number;
|
|
7
4
|
export declare const WATCH_STALE_MS: number;
|
|
8
5
|
export declare const THROTTLE_WINDOW_MS: number;
|
|
9
6
|
export declare const UNREAD_BLOCK_GRACE_MS: number;
|
|
10
7
|
export declare const HELD_WAIT_BUDGET_MS: number;
|
|
11
8
|
export declare const FACT_PAGE_SIZE = 100;
|
|
12
|
-
export declare function nowMs(): number;
|
|
13
|
-
export declare function rosterNames(facts: SquareRead): string[];
|
|
14
9
|
export declare function inSquareCount(facts: SquareRead): number;
|
|
15
|
-
export declare function actId(actOrIndex: StoredAct | number): ActivityId;
|
|
16
10
|
export declare function terminalStatusFor(current: ParticipantFact | undefined, hardCap: number | null, counts: ParticipantCounts): 'capped' | 'quorum' | undefined;
|
|
17
11
|
export declare function watchTerminalStatus(facts: SquareRead, name: string): 'capped' | 'quorum' | undefined;
|
|
18
12
|
/** A continuous prefix stops at the first unseen historical audience edge after join. */
|
package/dist/runtime.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { formatActivityId } from './square-core.js';
|
|
2
1
|
import { SquareError } from './model.js';
|
|
3
2
|
function parseIntegerEnv(name, fallback) {
|
|
4
3
|
const raw = process.env[name];
|
|
@@ -10,25 +9,12 @@ function parseIntegerEnv(name, fallback) {
|
|
|
10
9
|
return value;
|
|
11
10
|
}
|
|
12
11
|
export const WATCH_HEARTBEAT_MS = parseIntegerEnv('SQUARE_WATCH_HEARTBEAT_MS', 60000);
|
|
13
|
-
export const SLEEP_MS = parseIntegerEnv('SQUARE_WATCH_POLL_MS', 10000);
|
|
14
|
-
export const STALE_MS = parseIntegerEnv('SQUARE_WATCH_QUIET_MS', 300000);
|
|
15
12
|
export const WATCH_STALE_MS = parseIntegerEnv('SQUARE_WATCH_STALE_MS', 180000);
|
|
16
13
|
export const THROTTLE_WINDOW_MS = parseIntegerEnv('SQUARE_THROTTLE_WINDOW_MS', 60000);
|
|
17
14
|
export const UNREAD_BLOCK_GRACE_MS = parseIntegerEnv('SQUARE_UNREAD_BLOCK_GRACE_MS', 90000);
|
|
18
15
|
export const HELD_WAIT_BUDGET_MS = parseIntegerEnv('SQUARE_HELD_WAIT_BUDGET_MS', 10 * 60 * 1000);
|
|
19
16
|
export const FACT_PAGE_SIZE = 100;
|
|
20
|
-
export function nowMs() {
|
|
21
|
-
const override = process.env.SQUARE_NOW_MS;
|
|
22
|
-
if (override === undefined)
|
|
23
|
-
return Date.now();
|
|
24
|
-
const value = parseInt(override, 10);
|
|
25
|
-
if (!Number.isFinite(value))
|
|
26
|
-
throw new SquareError('invalid_args', 'Invalid SQUARE_NOW_MS: expected integer milliseconds.');
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
export function rosterNames(facts) { return facts.roster().map((participant) => participant.name); }
|
|
30
17
|
export function inSquareCount(facts) { return facts.participantCounts().joined; }
|
|
31
|
-
export function actId(actOrIndex) { return formatActivityId(typeof actOrIndex === 'number' ? actOrIndex : actOrIndex.index); }
|
|
32
18
|
export function terminalStatusFor(current, hardCap, counts) {
|
|
33
19
|
if (hardCap !== null && (current?.sayCount ?? 0) >= hardCap)
|
|
34
20
|
return 'capped';
|
package/dist/seats.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Owner, type Seat } from './model.js';
|
|
2
2
|
import type { ArtifactWriteAuthority, SeatRef } from './ports.js';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function requireOwner(owner: Owner | undefined): Owner;
|
|
4
4
|
export declare function requireJoinName(name: string | undefined): string;
|
|
5
5
|
export declare function asSeatRef(seat: Seat): SeatRef;
|
|
6
6
|
export declare function participantAuthority(seat: Seat): ArtifactWriteAuthority;
|
|
7
|
-
export declare function requireSeat(seat: Seat | undefined, body: Body | undefined, participant: string): Seat;
|