@astrosheep/square 0.3.86 → 0.3.87
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/artifact.d.ts +6 -1
- package/dist/artifact.js +79 -10
- package/dist/boundary-presentation.d.ts +5 -4
- package/dist/boundary-presentation.js +21 -25
- package/dist/catch-decisions.js +2 -1
- package/dist/claude-delivery-status.d.ts +8 -2
- package/dist/claude-delivery-status.js +26 -10
- package/dist/claude-delivery.d.ts +8 -4
- package/dist/claude-delivery.js +114 -104
- package/dist/claude-mcp-context.js +2 -2
- package/dist/claude-mod.js +119 -105
- package/dist/cli/context.d.ts +3 -1
- package/dist/cli/context.js +25 -1
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +14 -10
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.js +1 -0
- package/dist/cli/registry.js +0 -2
- package/dist/cli/square-commands.d.ts +4 -2
- package/dist/cli/square-commands.js +21 -6
- package/dist/codex-hook.d.ts +3 -3
- package/dist/codex-hook.js +4 -4
- package/dist/codex-queue.d.ts +5 -6
- package/dist/codex-queue.js +9 -5
- package/dist/decisions.d.ts +3 -2
- package/dist/decisions.js +18 -6
- package/dist/delivery-health.d.ts +32 -2
- package/dist/delivery-health.js +108 -45
- package/dist/delivery-operations.d.ts +1 -2
- package/dist/delivery-operations.js +155 -196
- package/dist/delivery.d.ts +14 -23
- package/dist/delivery.js +48 -18
- package/dist/file-lock.d.ts +8 -1
- package/dist/file-lock.js +2 -0
- package/dist/help.js +8 -11
- package/dist/inbox.d.ts +35 -9
- package/dist/inbox.js +228 -144
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -3
- package/dist/list.js +9 -4
- package/dist/mcp.js +12 -1
- package/dist/model.d.ts +39 -5
- package/dist/model.js +84 -0
- package/dist/notifications.d.ts +8 -6
- package/dist/notifications.js +56 -143
- package/dist/operation-presentation.js +3 -4
- package/dist/participant-identity.d.ts +0 -3
- package/dist/participant-identity.js +0 -31
- package/dist/paseo-delivery.d.ts +5 -6
- package/dist/paseo-delivery.js +13 -8
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/delivery.d.ts +8 -3
- package/dist/plugins/opencode/delivery.js +187 -132
- package/dist/plugins/opencode/index.js +12 -38
- package/dist/ports.d.ts +112 -40
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +51 -35
- package/dist/presentation.js +8 -3
- package/dist/seats.d.ts +7 -0
- package/dist/seats.js +27 -0
- package/dist/session-lifecycle.d.ts +2 -2
- package/dist/session-lifecycle.js +10 -12
- package/dist/sqlite-square.d.ts +20 -9
- package/dist/sqlite-square.js +471 -339
- package/dist/square-api.d.ts +1 -0
- package/dist/square-api.js +3 -4
- package/dist/square-core.d.ts +3 -2
- package/dist/square-domain.d.ts +12 -5
- package/dist/square-domain.js +163 -7
- package/dist/square-facade.d.ts +14 -10
- package/dist/square-index.d.ts +24 -0
- package/dist/square-index.js +131 -0
- package/dist/square-legacy-framing.d.ts +9 -0
- package/dist/square-legacy-framing.js +56 -0
- package/dist/square-migration-host-ledger.d.ts +26 -0
- package/dist/square-migration-host-ledger.js +168 -0
- package/dist/square-migration.d.ts +5 -5
- package/dist/square-migration.js +373 -71
- package/dist/square-sqlite.d.ts +9 -9
- package/dist/square-sqlite.js +329 -79
- package/dist/square-stdio.d.ts +1 -1
- package/dist/square-stdio.js +12 -7
- package/dist/square-tools.js +29 -2
- package/dist/stdio-server.js +4 -2
- package/dist/stream.d.ts +3 -2
- package/dist/stream.js +9 -10
- package/dist/views.d.ts +9 -14
- package/dist/views.js +50 -70
- package/dist/wakes.d.ts +6 -5
- package/dist/wakes.js +20 -17
- package/guides/application-facade-delivery-evidence.md +1 -1
- package/guides/claude-native.md +9 -9
- package/guides/mcp.md +1 -1
- package/guides/migration.md +107 -67
- package/guides/row-storage-design.md +1 -1
- package/guides/square-api.md +61 -28
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/register.js +1 -1
- package/plugins/claude/skills/square/SKILL.md +1 -1
- package/plugins/claude/types.d.ts +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +170 -118
- package/plugins/opencode/index.ts +12 -30
- package/plugins/pi/square-pi.js +55 -17
- package/skills/square/SKILL.md +1 -1
- package/dist/cli/ledger-command.d.ts +0 -12
- package/dist/cli/ledger-command.js +0 -72
- package/dist/host-ledger-file-adapter.d.ts +0 -47
- package/dist/host-ledger-file-adapter.js +0 -384
- package/dist/host-ledger-migration.d.ts +0 -27
- package/dist/host-ledger-migration.js +0 -264
- package/dist/host-ledger-root.d.ts +0 -2
- package/dist/host-ledger-root.js +0 -9
- package/dist/host-ledger-sqlite.d.ts +0 -65
- package/dist/host-ledger-sqlite.js +0 -368
- package/dist/host-ledger.d.ts +0 -195
- package/dist/host-ledger.js +0 -1
- package/dist/ledger-maintenance.d.ts +0 -30
- package/dist/ledger-maintenance.js +0 -110
- package/dist/open-square.d.ts +0 -38
- package/dist/open-square.js +0 -81
- package/dist/participant-host.d.ts +0 -23
- package/dist/participant-host.js +0 -92
- package/dist/registry.d.ts +0 -55
- package/dist/registry.js +0 -123
- package/dist/routes.d.ts +0 -39
- package/dist/routes.js +0 -99
- package/dist/square-actions.d.ts +0 -56
- package/dist/square-actions.js +0 -353
- package/dist/square-projections.d.ts +0 -31
- package/dist/square-projections.js +0 -64
- package/dist/wake-attempts.d.ts +0 -10
- package/dist/wake-attempts.js +0 -39
- package/dist/wake-eligibility.d.ts +0 -53
- package/dist/wake-eligibility.js +0 -123
- package/dist/wake-evidence.d.ts +0 -33
- package/dist/wake-evidence.js +0 -32
- package/guides/host-ledger.md +0 -58
- package/guides/indexed-host-ledger-performance.md +0 -39
package/dist/square-stdio.js
CHANGED
|
@@ -3,9 +3,10 @@ import path from 'node:path';
|
|
|
3
3
|
import { createInterface } from 'node:readline';
|
|
4
4
|
import { SquareError } from './model.js';
|
|
5
5
|
import { harnessSessionSources } from './participant-identity.js';
|
|
6
|
+
import { requireJoinName } from './seats.js';
|
|
6
7
|
export const STDIO_PROTOCOL_VERSION = 1;
|
|
7
8
|
export const STDIO_MAX_FRAME_BYTES = 8 * 1024 * 1024;
|
|
8
|
-
export const identityVariables = [...harnessSessionSources.flatMap(source => [source.variable, ...(source.childVariable ? [source.childVariable] : [])])
|
|
9
|
+
export const identityVariables = [...harnessSessionSources.flatMap(source => [source.variable, ...(source.childVariable ? [source.childVariable] : [])])];
|
|
9
10
|
export function wireIdentity(env) {
|
|
10
11
|
return Object.fromEntries(identityVariables.map(key => [key, env[key] ?? '']));
|
|
11
12
|
}
|
|
@@ -162,7 +163,11 @@ class StdioSquare {
|
|
|
162
163
|
participantHandle(name) {
|
|
163
164
|
return {
|
|
164
165
|
name,
|
|
165
|
-
express: (
|
|
166
|
+
express: ((bodyOrInput, optionsOrControl, control) => {
|
|
167
|
+
if (typeof bodyOrInput === 'object' && bodyOrInput !== null)
|
|
168
|
+
return this.call('express', [bodyOrInput, undefined], optionsOrControl, name);
|
|
169
|
+
return this.call('express', [bodyOrInput, optionsOrControl], control, name);
|
|
170
|
+
}),
|
|
166
171
|
catch: (options, control) => this.call('catch', [options], control, name),
|
|
167
172
|
listen: (target, options, control) => this.call('listen', [target, options], control, name),
|
|
168
173
|
ignore: (target, options, control) => this.call('ignore', [target, options], control, name),
|
|
@@ -176,6 +181,7 @@ class StdioSquare {
|
|
|
176
181
|
}
|
|
177
182
|
async participant(name) { return this.participantHandle(await this.call('participant', [name])); }
|
|
178
183
|
async join(...[name, options, control]) {
|
|
184
|
+
requireJoinName(name);
|
|
179
185
|
const result = await this.call('join', [name, options], control);
|
|
180
186
|
return { ...result, participant: this.participantHandle(result.participant) };
|
|
181
187
|
}
|
|
@@ -187,14 +193,13 @@ class StdioSquare {
|
|
|
187
193
|
stream() { unsupported('stream'); }
|
|
188
194
|
recognize() { return Promise.reject(new SquareError('invalid_args', 'stdio does not support host recognition; select a participant explicitly')); }
|
|
189
195
|
implicitJoin() { unsupported('host implicit join'); }
|
|
190
|
-
doneOwnedSession() { unsupported('host session cleanup'); }
|
|
191
196
|
endOwnedSession() { unsupported('host session cleanup'); }
|
|
192
|
-
|
|
197
|
+
cancelDeliveries() { unsupported('host delivery cancellation'); }
|
|
193
198
|
close() { return this.connection.close(); }
|
|
194
199
|
}
|
|
195
200
|
export async function openStdioSquare(location, selected, input, backends, build, control) {
|
|
196
|
-
if (input.clock || input.
|
|
197
|
-
unsupported('client clock
|
|
201
|
+
if (input.clock || input.wakeTransport)
|
|
202
|
+
unsupported('client clock or wakeTransport injection');
|
|
198
203
|
if (control?.signal?.aborted)
|
|
199
204
|
throw control.signal.reason ?? new Error('Operation cancelled');
|
|
200
205
|
const backend = Object.hasOwn(backends, selected.backend) ? backends[selected.backend] : undefined;
|
|
@@ -205,7 +210,7 @@ export async function openStdioSquare(location, selected, input, backends, build
|
|
|
205
210
|
const connection = new Connection(command, backend.args ?? [], path.resolve(cwd, backend.cwd ?? '.'), { ...(input.env ?? process.env), ...backend.env });
|
|
206
211
|
try {
|
|
207
212
|
const result = await connection.request('square/open', { version: STDIO_PROTOCOL_VERSION, key: selected.key, location,
|
|
208
|
-
identity: wireIdentity(input.env ?? process.env), participant: input.participant, build }, control);
|
|
213
|
+
identity: wireIdentity(input.env ?? process.env), body: input.body, participant: input.participant, build }, control);
|
|
209
214
|
if (result.version !== STDIO_PROTOCOL_VERSION || typeof result.handle !== 'string')
|
|
210
215
|
throw new SquareError('unavailable', 'Backend protocol version mismatch');
|
|
211
216
|
return new StdioSquare(location, connection, result.handle);
|
package/dist/square-tools.js
CHANGED
|
@@ -14,11 +14,38 @@ function observation(control) {
|
|
|
14
14
|
function rendering(render) {
|
|
15
15
|
return (result, args) => render(result, args);
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Tool receipts are the one machine surface without activity metadata: a receipt copy drops every
|
|
19
|
+
* property named `metadata` while domain activities keep theirs for SDK, CLI, stdio and stream readers.
|
|
20
|
+
*/
|
|
21
|
+
function withoutActivityMetadata(value) {
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return value.map(withoutActivityMetadata);
|
|
24
|
+
if (value === null || typeof value !== 'object')
|
|
25
|
+
return value;
|
|
26
|
+
const prototype = Object.getPrototypeOf(value);
|
|
27
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
28
|
+
return value;
|
|
29
|
+
return Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'metadata')
|
|
30
|
+
.map(([key, item]) => [key, withoutActivityMetadata(item)]));
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Human text renders from the unfiltered receipt, so metadata-only says keep the placeholder the
|
|
34
|
+
* CLI prints and every other sentence stays identical. Machines only ever receive the filtered copy.
|
|
35
|
+
*/
|
|
36
|
+
const renderingReceipts = new WeakMap();
|
|
37
|
+
function renderingReceipt(receipt) {
|
|
38
|
+
return (renderingReceipts.get(receipt) ?? receipt);
|
|
39
|
+
}
|
|
17
40
|
function tool(name, description, shape, run, render) {
|
|
18
41
|
const inputSchema = z.object({ ...shape, location }).strict();
|
|
19
|
-
return { name, description, inputSchema, render
|
|
42
|
+
return { name, description, inputSchema, render: (receipt, args) => render(renderingReceipt(receipt), args),
|
|
43
|
+
run: async (square, args, control) => {
|
|
20
44
|
const { location: _location, ...operationArgs } = inputSchema.parse(args);
|
|
21
|
-
|
|
45
|
+
const receipt = await run(square, operationArgs, control);
|
|
46
|
+
const filtered = withoutActivityMetadata(receipt);
|
|
47
|
+
renderingReceipts.set(filtered, receipt);
|
|
48
|
+
return filtered;
|
|
22
49
|
} };
|
|
23
50
|
}
|
|
24
51
|
export const SQUARE_TOOL_INSTRUCTIONS = 'The catch tool consumes activities. Use history with act/<index> cursors for read-only archive access.';
|
package/dist/stdio-server.js
CHANGED
|
@@ -4,7 +4,7 @@ import fs from 'node:fs/promises';
|
|
|
4
4
|
import { createInterface } from 'node:readline';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
6
|
import { SqliteSquare } from './sqlite-square.js';
|
|
7
|
-
import { SquareError } from './model.js';
|
|
7
|
+
import { SquareError, validateBody } from './model.js';
|
|
8
8
|
import { canonicalPath } from './canonical-path.js';
|
|
9
9
|
import { STDIO_PROTOCOL_VERSION, STDIO_MAX_FRAME_BYTES, encodeError, identityVariables } from './square-stdio.js';
|
|
10
10
|
import { parseSquareLocation } from './square-location.js';
|
|
@@ -71,7 +71,9 @@ export async function runSquareStdioServer(root) {
|
|
|
71
71
|
throw new SquareError('invalid_args', 'Invalid operation identity');
|
|
72
72
|
env[key] = value ?? '';
|
|
73
73
|
}
|
|
74
|
-
const input = { path: target, env, participant: params.participant };
|
|
74
|
+
const input = { path: target, env, body: params.body, participant: params.participant };
|
|
75
|
+
if (params.body !== undefined)
|
|
76
|
+
validateBody(params.body);
|
|
75
77
|
square = params.build === undefined ? await SqliteSquare.at(input, control, false)
|
|
76
78
|
: await SqliteSquare.build({ ...params.build, ...input }, control, false);
|
|
77
79
|
location = parsed.uri;
|
package/dist/stream.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SquareArtifactPort } from './ports.js';
|
|
2
|
+
import type { OperationControl, StreamOptions, StreamRecord } from './square-facade.js';
|
|
2
3
|
/** Pull-based observation; return interrupts an outstanding pull before awaiting its cleanup. */
|
|
3
|
-
export declare function streamSquare(squarePath: string, options?: StreamOptions, control?: OperationControl,
|
|
4
|
+
export declare function streamSquare(squarePath: string, options?: StreamOptions, control?: OperationControl, borrowed?: SquareArtifactPort): AsyncIterable<StreamRecord>;
|
package/dist/stream.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import { SquareError } from './model.js';
|
|
3
|
-
import { observeSquareRevision } from './artifact.js';
|
|
4
|
-
import { openSquare, closeOpenSquare } from './open-square.js';
|
|
3
|
+
import { createArtifactPort, observeSquareRevision } from './artifact.js';
|
|
5
4
|
import { streamProjection, streamTailProjection } from './views.js';
|
|
6
5
|
/** Pull-based observation; return interrupts an outstanding pull before awaiting its cleanup. */
|
|
7
|
-
export function streamSquare(squarePath, options = {}, control,
|
|
6
|
+
export function streamSquare(squarePath, options = {}, control, borrowed) {
|
|
8
7
|
return {
|
|
9
8
|
[Symbol.asyncIterator]() {
|
|
10
9
|
const disposal = new AbortController();
|
|
11
10
|
const signal = control?.signal === undefined ? disposal.signal : AbortSignal.any([control.signal, disposal.signal]);
|
|
12
|
-
const iterationControl = { ...control, signal };
|
|
13
11
|
const records = observe();
|
|
14
12
|
return {
|
|
15
13
|
next: () => records.next(),
|
|
@@ -43,19 +41,20 @@ export function streamSquare(squarePath, options = {}, control, openOptions = {}
|
|
|
43
41
|
let projection;
|
|
44
42
|
try {
|
|
45
43
|
baseline = await observer.read(signal);
|
|
46
|
-
const
|
|
44
|
+
const artifact = borrowed ?? createArtifactPort(squarePath, undefined, signal);
|
|
47
45
|
try {
|
|
48
|
-
projection = initial === undefined
|
|
49
|
-
?
|
|
50
|
-
:
|
|
46
|
+
projection = (await artifact.read(facts => initial === undefined
|
|
47
|
+
? streamProjection(facts, cursor, options.recipient)
|
|
48
|
+
: streamTailProjection(facts, initial.last, options.recipient), signal)).value;
|
|
51
49
|
}
|
|
52
50
|
finally {
|
|
53
|
-
|
|
51
|
+
if (borrowed === undefined)
|
|
52
|
+
await artifact.close();
|
|
54
53
|
}
|
|
55
54
|
}
|
|
56
55
|
catch (error) {
|
|
57
56
|
signal.throwIfAborted();
|
|
58
|
-
if (error instanceof SquareError && error.code === 'invalid_args')
|
|
57
|
+
if (borrowed !== undefined || error instanceof SquareError && error.code === 'invalid_args')
|
|
59
58
|
throw error;
|
|
60
59
|
// Repair/replacement is a hint, not a reason to scan history on a timer.
|
|
61
60
|
await observer.hinted(generation, Infinity, signal);
|
package/dist/views.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type ActivityId } from './square-core.js';
|
|
2
2
|
import { type StoredAct } from './model.js';
|
|
3
|
-
import type { OpenSquare } from './open-square.js';
|
|
4
3
|
import type { ActivityFilter, SquareRead } from './ports.js';
|
|
5
|
-
import type { Activity, ArchiveRecord, HistoryQuery, HistoryContinuation,
|
|
4
|
+
import type { Activity, ArchiveRecord, HistoryQuery, HistoryContinuation, ParticipantsResult, SquareSnapshot, EntryPresentation, ListPresentation, StatusResult, SquareObservation, CatchPresence, StreamProjection } from './square-facade.js';
|
|
6
5
|
export type { EntryPresentation, ListPresentation, CatchPresence, StreamProjection } from './square-facade.js';
|
|
7
6
|
export declare const HISTORY_DEFAULT_LIMIT = 10;
|
|
8
7
|
export declare const HISTORY_MAX_LIMIT = 100;
|
|
@@ -18,12 +17,8 @@ export declare function selectHistory(facts: SquareRead, query: HistoryQuery, li
|
|
|
18
17
|
totalMatches: number;
|
|
19
18
|
};
|
|
20
19
|
export declare function publicActivities(activities: readonly ArchiveRecord[]): Activity[];
|
|
21
|
-
export declare function
|
|
22
|
-
|
|
23
|
-
}>;
|
|
24
|
-
export declare function currentParticipant(square: OpenSquare, name: string, control?: OperationControl): Promise<string | undefined>;
|
|
25
|
-
export declare function snapshot(square: OpenSquare, control?: OperationControl): Promise<SquareSnapshot>;
|
|
26
|
-
export declare function recoveryObservation(square: OpenSquare, name: string, control?: OperationControl): Promise<{
|
|
20
|
+
export declare function snapshot(facts: SquareRead, now: number): SquareSnapshot;
|
|
21
|
+
export declare function recoveryObservation(facts: SquareRead, name: string, now: number): {
|
|
27
22
|
ownActivityCount: number;
|
|
28
23
|
hardCap: import("./model.js").HardCap;
|
|
29
24
|
holdReason?: string | undefined;
|
|
@@ -32,12 +27,12 @@ export declare function recoveryObservation(square: OpenSquare, name: string, co
|
|
|
32
27
|
activitySummaries: import("./square-facade.js").UnreadActivitySummary[];
|
|
33
28
|
standingCount: number;
|
|
34
29
|
held: boolean;
|
|
35
|
-
}
|
|
36
|
-
export declare function entryPresentation(
|
|
30
|
+
};
|
|
31
|
+
export declare function entryPresentation(facts: SquareRead, name: string, lastN?: number | null): EntryPresentation;
|
|
37
32
|
type ParticipantQueryContext = Pick<SquareObservation, 'location' | 'now' | 'automaticDeliveryAvailable'>;
|
|
38
33
|
export declare function queryParticipants(facts: SquareRead, context: ParticipantQueryContext, observe?: boolean): ParticipantsResult;
|
|
39
|
-
export declare function listPresentation(
|
|
34
|
+
export declare function listPresentation(facts: SquareRead): ListPresentation;
|
|
40
35
|
export declare function queryStatus(facts: SquareRead, context: ParticipantQueryContext, viewer?: string, observe?: boolean): StatusResult;
|
|
41
|
-
export declare function catchPresence(
|
|
42
|
-
export declare function streamProjection(
|
|
43
|
-
export declare function streamTailProjection(
|
|
36
|
+
export declare function catchPresence(facts: SquareRead, now: number): CatchPresence;
|
|
37
|
+
export declare function streamProjection(facts: SquareRead, cursor: number, recipient?: string): StreamProjection;
|
|
38
|
+
export declare function streamTailProjection(facts: SquareRead, last?: number, recipient?: string): StreamProjection;
|
package/dist/views.js
CHANGED
|
@@ -18,6 +18,7 @@ export function toPublicActivity(stored) {
|
|
|
18
18
|
return { id: formatActivityId(stored.index), at: stored.at, kind: stored.kind, actor: stored.actor,
|
|
19
19
|
...(stored.kind === 'say' && stored.reach !== undefined ? { reach: stored.reach } : {}),
|
|
20
20
|
...('body' in stored && stored.body !== undefined ? { body: stored.body } : {}),
|
|
21
|
+
...(stored.kind === 'say' && stored.metadata !== undefined ? { metadata: stored.metadata } : {}),
|
|
21
22
|
mentions: stored.kind === 'say' ? stored.mentions ?? [] : [], ...('target' in stored ? { target: stored.target } : {}),
|
|
22
23
|
...(stored.kind === 'say' && stored.reply !== undefined ? { reply: formatActivityId(stored.reply) } : {}) };
|
|
23
24
|
}
|
|
@@ -104,46 +105,34 @@ export function selectHistory(facts, query, limit, kinds, presentation = true) {
|
|
|
104
105
|
export function publicActivities(activities) {
|
|
105
106
|
return activities.flatMap((activity) => activity.kind === 'read' || activity.actor === undefined ? [] : [toPublicActivity(activity)]);
|
|
106
107
|
}
|
|
107
|
-
export async function resolveParticipant(square, name, control) {
|
|
108
|
-
return (await square.artifact.read((facts) => ({ name: resolveKnownName(facts, name) }), control?.signal)).value;
|
|
109
|
-
}
|
|
110
|
-
export async function currentParticipant(square, name, control) {
|
|
111
|
-
return (await square.artifact.read((facts) => { const p = facts.participant(name); return p?.joined ? p.name : undefined; }, control?.signal)).value;
|
|
112
|
-
}
|
|
113
108
|
function statuses(facts, now) {
|
|
114
109
|
return coreParticipants(facts, now).filter((p) => p.state !== 'not joined').map((p) => {
|
|
115
110
|
const cursor = readCursor(facts, p.name);
|
|
116
111
|
return { name: p.name, state: p.state === 'done' ? 'done' : 'joined', consumedThrough: cursor < 0 ? null : formatActivityId(cursor), watching: p.presence === 'watching', listening: p.listening };
|
|
117
112
|
});
|
|
118
113
|
}
|
|
119
|
-
export
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
},
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
return { joinedBefore: facts.activityCount({ kinds: ['join'], actors: [name] }) > 1,
|
|
142
|
-
scene: header.warmup.join('\n').trim(),
|
|
143
|
-
joinContext: (header.preamble.at(-1) === '---' ? header.preamble.slice(0, -1) : header.preamble).join('\n').trim(), recentActivities,
|
|
144
|
-
perceptions: Object.fromEntries(recentActivities.map((a) => [a.index, perceiveActivity(facts, a, name)])),
|
|
145
|
-
sayNumbers: facts.sayOrdinals(recentActivities.map((a) => a.index)) };
|
|
146
|
-
}, control?.signal)).value;
|
|
114
|
+
export function snapshot(facts, now) {
|
|
115
|
+
const header = facts.header(), hold = facts.hold();
|
|
116
|
+
const names = new Map(facts.roster().map((p) => [nameKey(p.name), p.name]));
|
|
117
|
+
const receipts = new Set(facts.receiptAssignments().map((r) => JSON.stringify([r.owner, r.index])));
|
|
118
|
+
return { context: [...header.preamble, ...header.warmup].join('\n'), actCount: facts.activityCount({ kinds: NON_READ }), hardCap: header.hardCap,
|
|
119
|
+
...(header.throttlePerMinute === undefined ? {} : { throttlePerMinute: header.throttlePerMinute }),
|
|
120
|
+
held: hold.active && hold.actor !== undefined ? { by: hold.actor, ...(hold.reason === undefined ? {} : { reason: hold.reason }) } : null,
|
|
121
|
+
participants: statuses(facts, now), delivered(name, id) { return receipts.has(JSON.stringify([names.get(nameKey(name)) ?? name, parseRequiredActivityId(id)])); } };
|
|
122
|
+
}
|
|
123
|
+
export function recoveryObservation(facts, name, now) {
|
|
124
|
+
const known = resolveKnownName(facts, name), hold = facts.hold();
|
|
125
|
+
return { participant: known, roster: rosterNames(facts), activitySummaries: unreadActivitySummaries(facts, known, now), standingCount: inSquareCount(facts), held: hold.active,
|
|
126
|
+
...(hold.reason === undefined ? {} : { holdReason: hold.reason }), ownActivityCount: facts.participant(known).sayCount, hardCap: facts.header().hardCap };
|
|
127
|
+
}
|
|
128
|
+
export function entryPresentation(facts, name, lastN = HISTORY_DEFAULT_LIMIT) {
|
|
129
|
+
const header = facts.header();
|
|
130
|
+
const recentActivities = selectHistory(facts, {}, lastN, ['say', 'done']).activities;
|
|
131
|
+
return { joinedBefore: facts.activityCount({ kinds: ['join'], actors: [name] }) > 1,
|
|
132
|
+
scene: header.warmup.join('\n').trim(),
|
|
133
|
+
joinContext: (header.preamble.at(-1) === '---' ? header.preamble.slice(0, -1) : header.preamble).join('\n').trim(), recentActivities,
|
|
134
|
+
perceptions: Object.fromEntries(recentActivities.map((a) => [a.index, perceiveActivity(facts, a, name)])),
|
|
135
|
+
sayNumbers: facts.sayOrdinals(recentActivities.map((a) => a.index)) };
|
|
147
136
|
}
|
|
148
137
|
function classifyPresence(participants, now) {
|
|
149
138
|
const here = participants.filter((participant) => participant.state === 'active' && (participant.presence === 'watching'
|
|
@@ -159,14 +148,12 @@ export function queryParticipants(facts, context, observe = false) {
|
|
|
159
148
|
return { participants, ...(!observe ? {} : { observation: { ...context, ...classifyPresence(participants, context.now),
|
|
160
149
|
standingCount: inSquareCount(facts), held: facts.hold().active } }) };
|
|
161
150
|
}
|
|
162
|
-
export
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }) };
|
|
169
|
-
}, control?.signal)).value;
|
|
151
|
+
export function listPresentation(facts) {
|
|
152
|
+
const participants = facts.roster().filter((p) => p.joined).map((p) => {
|
|
153
|
+
const receiptAt = facts.receiptFacts(p.name, p.lastJoinIndex ?? -1).latestAt;
|
|
154
|
+
return { name: p.name, lastActiveAt: receiptAt === undefined ? p.lastActiveAt : Math.max(p.lastActiveAt ?? -Infinity, receiptAt) };
|
|
155
|
+
}).sort(compareParticipantActivity).map((p) => p.name);
|
|
156
|
+
return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }) };
|
|
170
157
|
}
|
|
171
158
|
export function queryStatus(facts, context, viewer = '', observe = false) {
|
|
172
159
|
const participants = coreParticipants(facts, context.now);
|
|
@@ -204,33 +191,26 @@ export function queryStatus(facts, context, viewer = '', observe = false) {
|
|
|
204
191
|
},
|
|
205
192
|
};
|
|
206
193
|
}
|
|
207
|
-
export
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|| (participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= PRESENCE_WINDOW_MS));
|
|
212
|
-
return { participants, now };
|
|
213
|
-
}, control?.signal)).value;
|
|
214
|
-
}
|
|
215
|
-
export async function streamProjection(square, cursor, recipient, control) {
|
|
216
|
-
return (await square.artifact.read((facts) => {
|
|
217
|
-
const page = facts.activityHeads({ afterIndex: cursor }, { edge: 'oldest', limit: PAGE_SIZE });
|
|
218
|
-
const heads = page.items.flatMap((head) => {
|
|
219
|
-
const route = recipient === undefined ? undefined : facts.directedAt(recipient, head.index)?.route;
|
|
220
|
-
return recipient !== undefined && route === undefined ? [] : [{ index: head.index, route }];
|
|
221
|
-
});
|
|
222
|
-
return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => {
|
|
223
|
-
const route = heads.find((h) => h.index === activity.index).route;
|
|
224
|
-
return { activity, ...(route === undefined ? {} : { route }) };
|
|
225
|
-
}), cursor: page.items.at(-1)?.index ?? cursor, hasMore: page.hasMore };
|
|
226
|
-
}, control?.signal)).value;
|
|
194
|
+
export function catchPresence(facts, now) {
|
|
195
|
+
const participants = coreParticipants(facts, now).filter((participant) => participant.state === 'done' || participant.presence === 'watching'
|
|
196
|
+
|| (participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= PRESENCE_WINDOW_MS));
|
|
197
|
+
return { participants, now };
|
|
227
198
|
}
|
|
228
|
-
export
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
199
|
+
export function streamProjection(facts, cursor, recipient) {
|
|
200
|
+
const page = facts.activityHeads({ afterIndex: cursor }, { edge: 'oldest', limit: PAGE_SIZE });
|
|
201
|
+
const heads = page.items.flatMap((head) => {
|
|
202
|
+
const route = recipient === undefined ? undefined : facts.directedAt(recipient, head.index)?.route;
|
|
203
|
+
return recipient !== undefined && route === undefined ? [] : [{ index: head.index, route }];
|
|
204
|
+
});
|
|
205
|
+
return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => {
|
|
206
|
+
const route = heads.find((h) => h.index === activity.index).route;
|
|
207
|
+
return { activity, ...(route === undefined ? {} : { route }) };
|
|
208
|
+
}), cursor: page.items.at(-1)?.index ?? cursor, hasMore: page.hasMore };
|
|
209
|
+
}
|
|
210
|
+
export function streamTailProjection(facts, last = HISTORY_DEFAULT_LIMIT, recipient) {
|
|
211
|
+
if (!Number.isSafeInteger(last) || last < 0 || last > PAGE_SIZE)
|
|
212
|
+
throw new SquareError('invalid_args', `Invalid stream tail: expected a non-negative safe integer no greater than ${PAGE_SIZE}.`);
|
|
213
|
+
const heads = last === 0 ? [] : recipient === undefined ? facts.activityHeads({}, { edge: 'newest', limit: last }).items : facts.directed(recipient, {}, { edge: 'newest', limit: last }).items;
|
|
214
|
+
return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => ({ activity,
|
|
215
|
+
...(recipient === undefined ? {} : { route: facts.directedAt(recipient, activity.index).route }) })), cursor: facts.header().lastActIndex, hasMore: false };
|
|
236
216
|
}
|
package/dist/wakes.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type WatchLease, type WatchOptions } from './model.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { SquareArtifactPort } from './ports.js';
|
|
3
|
+
import type { Seat } from './model.js';
|
|
3
4
|
export type WatchLeaseStart = {
|
|
4
5
|
readonly type: 'started';
|
|
5
6
|
readonly leaseId: string;
|
|
@@ -21,7 +22,7 @@ export type WatchLeasePulse = {
|
|
|
21
22
|
readonly type: 'sleep';
|
|
22
23
|
readonly heartbeatAt?: number;
|
|
23
24
|
};
|
|
24
|
-
export declare function acquireWatchLease(
|
|
25
|
-
export declare function pulseWatchLease(
|
|
26
|
-
export declare function releaseWatchLease(
|
|
27
|
-
export declare function ownsWatchLease(
|
|
25
|
+
export declare function acquireWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, options: WatchOptions, signal?: AbortSignal): Promise<WatchLeaseStart>;
|
|
26
|
+
export declare function pulseWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, options: WatchOptions, heartbeatDue: boolean, signal?: AbortSignal): Promise<WatchLeasePulse>;
|
|
27
|
+
export declare function releaseWatchLease(artifact: SquareArtifactPort, seat: Seat, leaseId: string): Promise<void>;
|
|
28
|
+
export declare function ownsWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, signal?: AbortSignal): Promise<boolean>;
|
package/dist/wakes.js
CHANGED
|
@@ -4,23 +4,21 @@ function newLease(leaseId, at, options) {
|
|
|
4
4
|
const filter = { ...(options.participants === undefined ? {} : { participants: [...options.participants] }), ...(options.mention === undefined ? {} : { mention: options.mention }) };
|
|
5
5
|
return { leaseId, heartbeatAt: at, expiresAt: at + WATCH_STALE_MS, ...(Object.keys(filter).length === 0 ? {} : { filter }) };
|
|
6
6
|
}
|
|
7
|
-
export async function acquireWatchLease(
|
|
8
|
-
const
|
|
9
|
-
const { value } = await
|
|
10
|
-
const known = resolveKnownName(facts, name);
|
|
11
|
-
const existing = freshWatchLease(facts, known, at);
|
|
7
|
+
export async function acquireWatchLease(artifact, seat, at, leaseId, options, signal) {
|
|
8
|
+
const name = seat.participant;
|
|
9
|
+
const { value } = await artifact.transactAs({ kind: 'participant', seat }, facts => {
|
|
10
|
+
const known = resolveKnownName(facts, name), existing = freshWatchLease(facts, known, at);
|
|
12
11
|
if (existing !== undefined && !options.replace)
|
|
13
12
|
return { type: 'active', lease: existing };
|
|
14
|
-
facts.putLease(known, newLease(leaseId, at, options));
|
|
13
|
+
facts.putLease(known, newLease(leaseId, at, options), seat.generation);
|
|
15
14
|
return { type: 'started', leaseId, replaced: existing !== undefined, heartbeatAt: at };
|
|
16
15
|
}, signal);
|
|
17
16
|
return value;
|
|
18
17
|
}
|
|
19
|
-
export async function pulseWatchLease(
|
|
20
|
-
const
|
|
21
|
-
const { value } = await
|
|
22
|
-
const known = resolveKnownName(facts, name);
|
|
23
|
-
const lease = freshWatchLease(facts, known, at);
|
|
18
|
+
export async function pulseWatchLease(artifact, seat, at, leaseId, options, heartbeatDue, signal) {
|
|
19
|
+
const name = seat.participant;
|
|
20
|
+
const { value } = await artifact.transactAs({ kind: 'participant', seat }, facts => {
|
|
21
|
+
const known = resolveKnownName(facts, name), lease = freshWatchLease(facts, known, at);
|
|
24
22
|
if (lease?.leaseId !== leaseId)
|
|
25
23
|
return { type: 'replaced' };
|
|
26
24
|
const held = facts.hold().active;
|
|
@@ -30,15 +28,20 @@ export async function pulseWatchLease(square, name, leaseId, options, heartbeatD
|
|
|
30
28
|
const type = held ? 'held' : 'sleep';
|
|
31
29
|
if (!heartbeatDue)
|
|
32
30
|
return { type };
|
|
33
|
-
facts.putLease(known, newLease(leaseId, at, options));
|
|
31
|
+
facts.putLease(known, newLease(leaseId, at, options), seat.generation);
|
|
34
32
|
return { type, heartbeatAt: at };
|
|
35
33
|
}, signal);
|
|
36
34
|
return value;
|
|
37
35
|
}
|
|
38
|
-
export async function releaseWatchLease(
|
|
39
|
-
|
|
40
|
-
await square.artifact.transact((facts) => facts.removeLease(resolveKnownName(facts, name), leaseId));
|
|
36
|
+
export async function releaseWatchLease(artifact, seat, leaseId) {
|
|
37
|
+
await artifact.transactAs({ kind: 'participant', seat }, facts => facts.removeLease(seat.participant, leaseId, seat.generation));
|
|
41
38
|
}
|
|
42
|
-
export async function ownsWatchLease(
|
|
43
|
-
|
|
39
|
+
export async function ownsWatchLease(artifact, seat, at, leaseId, signal) {
|
|
40
|
+
const name = seat.participant;
|
|
41
|
+
return (await artifact.read(facts => {
|
|
42
|
+
const current = facts.seat(name);
|
|
43
|
+
if (current === undefined || current.generation !== seat.generation)
|
|
44
|
+
return false;
|
|
45
|
+
return freshWatchLease(facts, resolveKnownName(facts, name), at)?.leaseId === leaseId;
|
|
46
|
+
}, signal)).value;
|
|
44
47
|
}
|
|
@@ -181,7 +181,7 @@ These are deliverer closures, not a reviewer verdict. Rows distinguish behavior
|
|
|
181
181
|
| Packed owner orchestration hides effects/count integrity | History, lifecycle branches, maintenance/discovery/recovery, catch conflict and SDK recognize are expanded into readable steps. Remaining one-line SDK delegates are supported simple resource calls, not packed async policy. Inspect implementation diff; all new source is included in count. |
|
|
182
182
|
| Invalid reply / done repair regressions | Typed `invalid_reply` covers malformed and valid-but-absent IDs; typed reach/done reasons stay domain facts, CLI owns glyphs/flags. Express-recovery tests execute printed repaired commands, preserving raw drafts, body candidates and other recipients. Unknown/landed effects offer reconciliation, never replay. |
|
|
183
183
|
| Failing application clock prevents draft creation | `executeExpression` uses `saveActivityDraft`'s transport-local `Date.now` default, never the failed owner clock. Focused `express-recovery` fixture supplies a throwing clock and landed error plus throwing recovery; exact CRLF raw is already saved at recovery invocation, landed ID remains in history reconciliation, and no replay is offered. |
|
|
184
|
-
| Captured default wake stops at adapter or executable selection | Amended `
|
|
184
|
+
| Captured default wake stops at adapter or executable selection | Amended `createDefaultWakeTransport(env)` builds `CodexQueueTransport({env})`; semantic state time belongs to Square operations and never controls external I/O deadlines; queue executable comes from explicit bin, else supplied env, never later ambient env. Boundary test uses a real isolated fake executable and captured child environment/queue destination after global mutation; injected port wins. No real native delivery. |
|
|
185
185
|
| Force-build ignores cancellation under lock | Amended build/create signal reaches existing lock retries and transaction boundaries; abort checked before public link, cleanup signal-free, no postcommit rejection. Real exclusive-lock fixture cancels, unlocks, and proves unchanged snapshot/no delayed rebuild/no temporary artifact. Separate published-link fixture aborts after commit and still gets the build result. |
|
|
186
186
|
| Removed helper tests / package contract | Obsolete consumers moved to actual application/renderer boundaries, not production stubs. Full suite includes packed ESM root import + TypeScript consumer + unsupported deep-import denial, native import migration, ownership/storage/migration and receipts. |
|
|
187
187
|
|
package/guides/claude-native.md
CHANGED
|
@@ -21,14 +21,14 @@ An absent/broken endpoint is unavailable; it does not consume Square activity.
|
|
|
21
21
|
|
|
22
22
|
## Native-first routing and policy holds
|
|
23
23
|
|
|
24
|
-
Native delivery is preferred, including under Paseo.
|
|
25
|
-
native queue
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
Native delivery is preferred, including under Paseo. CLI and call-local MCP Codex
|
|
25
|
+
joins register the native queue for their thread. Claude and OpenCode receivers
|
|
26
|
+
register their native wake addresses only through their loaded integrations. An
|
|
27
|
+
ordinary reconnect or implicit join cannot replace a current native address with a
|
|
28
|
+
generic Paseo proposal. Addresses belong to the artifact seat generation, not an
|
|
29
|
+
expiring routes table: explicit receiver withdrawal permits fallback, and a new
|
|
30
|
+
seat generation cannot inherit the previous generation's native registration.
|
|
31
|
+
Participant expressions do not publish replacement addresses.
|
|
32
32
|
|
|
33
33
|
This is route preference, not permission to bypass receiver policy. Claude can
|
|
34
34
|
legitimately hold an unsolicited peer message with `no-mode-asserted`, especially
|
|
@@ -47,7 +47,7 @@ Neither a release nor a drop is a queue receipt, proof of consumption or retry
|
|
|
47
47
|
authorization.
|
|
48
48
|
|
|
49
49
|
`square harness doctor delivery` shows native custody separately from pending
|
|
50
|
-
attention, including after the activity is seen
|
|
50
|
+
attention for current seat generations, including after the activity is seen. Paseo
|
|
51
51
|
presents the `peer_message_hold` state in its own timeline. Acceptance means normal
|
|
52
52
|
delivery when the receiver allows it, or a visible reason without bypass/replay when
|
|
53
53
|
policy holds it.
|
package/guides/mcp.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Square provides a stdio MCP server through `square mcp-server`.
|
|
4
4
|
|
|
5
|
-
Set `SQUARE_LOCATION` to the default `.square` artifact path
|
|
5
|
+
Set `SQUARE_LOCATION` to the default `.square` artifact path; calls may override it with `location`. Relative paths use the server's startup working directory. Join with an explicit `as` name. Later calls may omit `as` only when the artifact recognizes exactly one current name held by the call's exact Body (`channel`, `session`, optional `agent`); zero or multiple matches refuse and require explicit selection. An explicit name selects a voice but never grants custody. Request metadata supplies the live Codex (`threadId`) or OpenCode (`ai.opencode/sessionID`) coordinate when present; otherwise a reliable startup coordinate is required for participant writes. Read-only calls do not need a Body.
|
|
6
6
|
|
|
7
7
|
The server exposes `join`, `express`, `catch`, `history`, `listen`, `ignore`, `listening`, `hold`, `resume`, `done`, `status`, and `participants`. `catch` consumes activities. `history` is read-only and accepts stable `act/<index>` cursors. Tool results include JSON `structuredContent` and a text representation of the same data. Square failures are returned as tool errors with a structured `{ error: { code, message, facts? } }` value.
|
|
8
8
|
|