@astrosheep/square 0.4.3 → 0.4.5
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-store.d.ts +1 -1
- package/dist/artifact-store.js +32 -15
- package/dist/artifact.d.ts +1 -4
- package/dist/artifact.js +0 -28
- package/dist/attention-presentation.js +1 -1
- package/dist/boundary-presentation.js +2 -2
- package/dist/claude-boundary-state.d.ts +6 -6
- package/dist/claude-boundary-state.js +13 -13
- package/dist/claude-hook.js +26 -25
- package/dist/claude-mcp-context.d.ts +2 -2
- package/dist/claude-mcp-context.js +6 -6
- package/dist/cli/context.js +3 -6
- package/dist/cli/json.js +1 -1
- package/dist/cli/mcp-server-command.js +3 -3
- package/dist/cli/observation-commands.d.ts +2 -2
- package/dist/cli/observation-commands.js +23 -51
- package/dist/cli/perceive-presentation.d.ts +3 -0
- package/dist/cli/{catch-presentation.js → perceive-presentation.js} +3 -3
- package/dist/cli/registry.js +2 -2
- package/dist/codex-address.d.ts +3 -0
- package/dist/codex-address.js +7 -0
- package/dist/codex-hook.d.ts +2 -2
- package/dist/codex-hook.js +29 -39
- package/dist/codex-queue.d.ts +3 -3
- package/dist/codex-queue.js +9 -15
- package/dist/codex-watch.d.ts +6 -1
- package/dist/codex-watch.js +38 -42
- package/dist/delivery-ledger-sqlite.d.ts +25 -20
- package/dist/delivery-ledger-sqlite.js +76 -61
- package/dist/delivery-ledger.d.ts +24 -19
- package/dist/delivery-ledger.js +150 -81
- package/dist/delivery-lifetime.d.ts +2 -2
- package/dist/delivery-lifetime.js +6 -18
- package/dist/help.js +12 -12
- package/dist/hints.d.ts +2 -2
- package/dist/hints.js +7 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.d.ts +2 -2
- package/dist/list.js +4 -3
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +8 -32
- package/dist/neutral.d.ts +5 -5
- package/dist/notifications.js +12 -6
- package/dist/operation-presentation.d.ts +8 -3
- package/dist/operation-presentation.js +50 -12
- package/dist/packages/agent-delivery/src/codex.d.ts +4 -0
- package/dist/packages/agent-delivery/src/codex.js +18 -13
- package/dist/packages/agent-delivery/src/file-lock.js +4 -1
- package/dist/perceive-decisions.d.ts +28 -0
- package/dist/{catch-decisions.js → perceive-decisions.js} +24 -24
- package/dist/{catch-selection.d.ts → perceive-selection.d.ts} +2 -2
- package/dist/{catch-selection.js → perceive-selection.js} +3 -3
- package/dist/plugins/opencode/index.js +4 -4
- package/dist/plugins/opencode-shared/delivery.d.ts +6 -6
- package/dist/plugins/opencode-shared/delivery.js +27 -21
- package/dist/plugins/opencode-v1/runtime.js +3 -3
- package/dist/ports.d.ts +0 -4
- package/dist/presentation.d.ts +1 -1
- package/dist/presentation.js +13 -13
- package/dist/session-lifecycle.d.ts +2 -2
- package/dist/session-lifecycle.js +11 -11
- package/dist/sqlite-square.d.ts +2 -4
- package/dist/sqlite-square.js +47 -54
- package/dist/sqlite-transaction.d.ts +2 -0
- package/dist/sqlite-transaction.js +25 -3
- package/dist/square-api.d.ts +1 -1
- package/dist/square-api.js +1 -1
- package/dist/square-domain.js +1 -1
- package/dist/square-facade.d.ts +15 -13
- package/dist/square-location.js +1 -1
- package/dist/square-posting.d.ts +5 -5
- package/dist/square-posting.js +39 -38
- package/dist/square-tools.d.ts +15 -4
- package/dist/square-tools.js +35 -17
- package/dist/views.d.ts +7 -3
- package/dist/views.js +6 -3
- package/guides/architect.md +2 -2
- package/guides/change-waits.md +1 -1
- package/guides/claude-native.md +2 -2
- package/guides/codex-delivery.md +91 -57
- package/guides/delivery-primitives.md +26 -10
- package/guides/mcp.md +4 -2
- package/guides/operation-cancellation.md +11 -3
- package/guides/pi-native-delivery.md +1 -1
- package/guides/pi-tools.md +11 -6
- package/guides/receive-primitive.md +3 -3
- package/guides/square-api.md +15 -8
- package/package.json +2 -2
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/hooks.json +2 -2
- package/plugins/claude/skills/square/SKILL.md +10 -10
- package/plugins/codex/.codex-plugin/plugin.json +2 -2
- package/plugins/codex/hooks/hooks.json +1 -7
- package/plugins/opencode/index.ts +4 -4
- package/plugins/opencode-shared/delivery.ts +27 -21
- package/plugins/opencode-v1/runtime.ts +3 -3
- package/plugins/pi/square-pi.js +18 -12
- package/skills/square/SKILL.md +10 -10
- package/dist/catch-decisions.d.ts +0 -28
- package/dist/cli/catch-presentation.d.ts +0 -3
- package/dist/codex-boundary-state.d.ts +0 -2
- package/dist/codex-boundary-state.js +0 -6
- package/guides/mcp-connection-lifetime.md +0 -22
|
@@ -3,8 +3,11 @@ function abort(signal) {
|
|
|
3
3
|
if (signal?.aborted)
|
|
4
4
|
throw signal.reason ?? new Error('SQLite operation aborted');
|
|
5
5
|
}
|
|
6
|
-
function
|
|
7
|
-
|
|
6
|
+
function isSqliteBusy(error) {
|
|
7
|
+
const code = error?.code;
|
|
8
|
+
return typeof code === 'string' && /^SQLITE_BUSY(?:_|$)/.test(code)
|
|
9
|
+
|| typeof error?.errcode === 'number' && (error.errcode & 0xff) === 5
|
|
10
|
+
|| error instanceof Error && /database is locked|database is busy|SQLITE_BUSY/i.test(error.message);
|
|
8
11
|
}
|
|
9
12
|
/** Yield rather than blocking the process while another connection owns SQLite. */
|
|
10
13
|
export async function retrySqliteBusy(operation, signal, retryMs = 25) {
|
|
@@ -14,7 +17,7 @@ export async function retrySqliteBusy(operation, signal, retryMs = 25) {
|
|
|
14
17
|
return operation();
|
|
15
18
|
}
|
|
16
19
|
catch (error) {
|
|
17
|
-
if (!
|
|
20
|
+
if (!isSqliteBusy(error))
|
|
18
21
|
throw error;
|
|
19
22
|
try {
|
|
20
23
|
await sleep(typeof retryMs === 'function' ? retryMs() : retryMs, undefined, { signal });
|
|
@@ -26,6 +29,25 @@ export async function retrySqliteBusy(operation, signal, retryMs = 25) {
|
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
}
|
|
32
|
+
/** Cancel a queued caller promptly without releasing its place in the connection's serial chain. */
|
|
33
|
+
export async function awaitSqliteQueue(result, signal, started) {
|
|
34
|
+
if (!signal)
|
|
35
|
+
return result;
|
|
36
|
+
let onAbort;
|
|
37
|
+
try {
|
|
38
|
+
return await Promise.race([result, new Promise((_, reject) => {
|
|
39
|
+
onAbort = () => { if (!started())
|
|
40
|
+
reject(signal.reason ?? new Error('SQLite operation aborted')); };
|
|
41
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
42
|
+
if (signal.aborted)
|
|
43
|
+
onAbort();
|
|
44
|
+
})]);
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
if (onAbort)
|
|
48
|
+
signal.removeEventListener('abort', onAbort);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
29
51
|
/** Acquisition may retry; COMMIT retries retain the callback's result and transaction. */
|
|
30
52
|
export async function inSqliteTransaction(db, write, validate, change, signal) {
|
|
31
53
|
let begun = false, backoffMs = 25;
|
package/dist/square-api.d.ts
CHANGED
|
@@ -16,4 +16,4 @@ export declare function selectOwnSeat(square: Pick<SqliteSquare, 'participant' |
|
|
|
16
16
|
}): Promise<Participant | undefined>;
|
|
17
17
|
export { ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
18
18
|
export { localUserOwner, harnessOwner, decodeHarnessOwner } from './owner.js';
|
|
19
|
-
export { squareClock,
|
|
19
|
+
export { squareClock, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, PERCEIVE_DEFAULT_LIMIT, PERCEIVE_MAX_LIMIT, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT, diagnoseSquare, discover, inbox } from './sqlite-square.js';
|
package/dist/square-api.js
CHANGED
|
@@ -24,4 +24,4 @@ export async function selectOwnSeat(square, owner, name, options) {
|
|
|
24
24
|
}
|
|
25
25
|
export { ACTIVITY_METADATA_MAX_BYTES } from './model.js';
|
|
26
26
|
export { localUserOwner, harnessOwner, decodeHarnessOwner } from './owner.js';
|
|
27
|
-
export { squareClock,
|
|
27
|
+
export { squareClock, formatActivityId, parseActivityId, MAX_IDENTITY_SET_SIZE, PERCEIVE_DEFAULT_LIMIT, PERCEIVE_MAX_LIMIT, HISTORY_DEFAULT_LIMIT, HISTORY_MAX_LIMIT, DEFAULT_LIST_DEPTH, MAX_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT, diagnoseSquare, discover, inbox } from './sqlite-square.js';
|
package/dist/square-domain.js
CHANGED
|
@@ -2,7 +2,7 @@ import { SquareError, nameKey, sameName, validateOwner, validateName } from './m
|
|
|
2
2
|
import { newEndpointGeneration, validateEndpointGeneration } from './message.js';
|
|
3
3
|
import { resolveAudience } from './attention.js';
|
|
4
4
|
import { freshWatchLease } from './runtime.js';
|
|
5
|
-
import { leaseOwnsNotification } from './
|
|
5
|
+
import { leaseOwnsNotification } from './perceive-selection.js';
|
|
6
6
|
export function deriveLanding(activity, facts) {
|
|
7
7
|
const audience = activity.kind === 'say' ? resolveAudience({
|
|
8
8
|
actor: activity.actor, recipients: facts.standing.map(item => item.name), mentions: activity.mentions,
|
package/dist/square-facade.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ import type { MetadataMatch } from './delivery-deferral.js';
|
|
|
2
2
|
export type { MetadataMatch, MetadataScalar } from './delivery-deferral.js';
|
|
3
3
|
import type { ActivityId, Perception, Reach } from './square-core.js';
|
|
4
4
|
import type { Owner, HydratedAct, WakeAddress, ActivityMetadata, DirectedNotificationRoute } from './model.js';
|
|
5
|
-
import type { SquareResourceOwner } from './ports.js';
|
|
6
5
|
import type { OperationControl } from './neutral.js';
|
|
7
6
|
export interface ActivitySearch {
|
|
8
7
|
readonly text: string;
|
|
@@ -17,7 +16,7 @@ export interface HeldSeat {
|
|
|
17
16
|
readonly name: string;
|
|
18
17
|
readonly generation: string;
|
|
19
18
|
}
|
|
20
|
-
export type {
|
|
19
|
+
export type { PerceiveWaitStart, OperationProgress, OperationControl, OperationFailureDetail, OperationError } from './neutral.js';
|
|
21
20
|
export type { ActivityId, Perception, Reach } from './square-core.js';
|
|
22
21
|
export type { Owner, WakeAddress, ActivityMetadata, JsonValue, DirectedNotificationRoute } from './model.js';
|
|
23
22
|
/** Indexed archive event, including read bookkeeping and a say's linked content. */
|
|
@@ -76,7 +75,7 @@ export interface LifecycleResult {
|
|
|
76
75
|
readonly activity: Activity;
|
|
77
76
|
readonly observation?: SquareObservation;
|
|
78
77
|
}
|
|
79
|
-
export interface
|
|
78
|
+
export interface PerceiveOptions extends ObservationOptions {
|
|
80
79
|
readonly id?: ActivityId;
|
|
81
80
|
readonly idle?: number;
|
|
82
81
|
readonly from?: readonly string[];
|
|
@@ -105,14 +104,14 @@ export interface PendingResult {
|
|
|
105
104
|
/** Matching unconsumed activities outside this page. */
|
|
106
105
|
readonly remaining: number;
|
|
107
106
|
}
|
|
108
|
-
export type
|
|
109
|
-
export interface
|
|
107
|
+
export type PerceiveReason = 'drained' | 'idle' | 'capped' | 'quorum' | 'replaced' | 'already-active';
|
|
108
|
+
export interface PerceiveResult {
|
|
110
109
|
readonly activities: readonly PerceivedActivity[];
|
|
111
110
|
readonly remaining: number;
|
|
112
|
-
readonly reason:
|
|
111
|
+
readonly reason: PerceiveReason;
|
|
113
112
|
/** Occasional participant-facing nudge; not part of any activity. */
|
|
114
113
|
readonly hint?: string;
|
|
115
|
-
readonly observation?:
|
|
114
|
+
readonly observation?: PerceiveObservation;
|
|
116
115
|
}
|
|
117
116
|
export interface HistoryQuery extends ActivityQuery, ObservationOptions {
|
|
118
117
|
/** Ten by default; null explicitly reads the full archive. */
|
|
@@ -136,8 +135,6 @@ export interface SquareLocation {
|
|
|
136
135
|
readonly env?: NodeJS.ProcessEnv;
|
|
137
136
|
}
|
|
138
137
|
export interface SquareAtInput extends SquareLocation, OpenOptions {
|
|
139
|
-
/** A caller-owned connection; closing this Square never closes its owner. */
|
|
140
|
-
readonly resources?: SquareResourceOwner;
|
|
141
138
|
}
|
|
142
139
|
export interface SquareBuildInput extends SquareAtInput {
|
|
143
140
|
readonly markdown: string;
|
|
@@ -167,7 +164,7 @@ export interface Participant {
|
|
|
167
164
|
ignore(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
168
165
|
unlisten(target: string, options?: ObservationOptions, control?: OperationControl): Promise<ListenerChangeResult>;
|
|
169
166
|
listening(options?: ObservationOptions, control?: OperationControl): Promise<ListeningResult>;
|
|
170
|
-
|
|
167
|
+
perceive(options?: PerceiveOptions, control?: OperationControl): Promise<PerceiveResult>;
|
|
171
168
|
pending(options?: PendingOptions, control?: OperationControl): Promise<PendingResult>;
|
|
172
169
|
/** Local custody only: ledger-only detach/delete is observed on privileged reconciliation. */
|
|
173
170
|
ack(ids: readonly ActivityId[], control?: OperationControl): Promise<AckResult>;
|
|
@@ -204,11 +201,16 @@ export interface ParticipantsResult {
|
|
|
204
201
|
readonly observation?: ParticipantsObservation;
|
|
205
202
|
}
|
|
206
203
|
export interface DiscoveryOptions {
|
|
204
|
+
readonly owner?: Owner;
|
|
207
205
|
readonly depth?: number;
|
|
208
206
|
readonly limit?: number;
|
|
209
207
|
readonly after?: string;
|
|
210
208
|
}
|
|
211
209
|
export interface SquareListItem {
|
|
210
|
+
readonly joined?: readonly {
|
|
211
|
+
readonly name: string;
|
|
212
|
+
readonly pending: number;
|
|
213
|
+
}[];
|
|
212
214
|
readonly path: string;
|
|
213
215
|
readonly lastActiveAt: number;
|
|
214
216
|
readonly context: readonly string[];
|
|
@@ -272,7 +274,7 @@ export interface PresenceClassification {
|
|
|
272
274
|
readonly lingeringCount: number;
|
|
273
275
|
readonly classificationByName: Readonly<Record<string, 'here' | 'lingering' | 'away' | 'done' | 'not-joined'>>;
|
|
274
276
|
}
|
|
275
|
-
export interface
|
|
277
|
+
export interface PerceivePresence {
|
|
276
278
|
readonly participants: readonly ParticipantSummary[];
|
|
277
279
|
readonly now: number;
|
|
278
280
|
}
|
|
@@ -306,10 +308,10 @@ export interface ExpressObservation extends SquareObservation, ExpressionObserva
|
|
|
306
308
|
readonly participant: string;
|
|
307
309
|
readonly context: ExpressContext;
|
|
308
310
|
}
|
|
309
|
-
export interface
|
|
311
|
+
export interface PerceiveObservation extends SquareObservation, ExpressionObservation {
|
|
310
312
|
readonly deliveryAvailable: boolean;
|
|
311
313
|
readonly participant: string;
|
|
312
|
-
readonly presence?:
|
|
314
|
+
readonly presence?: PerceivePresence;
|
|
313
315
|
readonly enrichmentUnavailable?: true;
|
|
314
316
|
}
|
|
315
317
|
export interface HistoryContinuation {
|
package/dist/square-location.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { SquareError } from './neutral.js';
|
|
3
3
|
export function squareLocation(input) {
|
|
4
|
-
const selected = input.path
|
|
4
|
+
const selected = input.path;
|
|
5
5
|
if (selected === undefined || selected.trim() === '')
|
|
6
6
|
throw new SquareError('invalid_args', 'Square needs a location');
|
|
7
7
|
// Windows roots include drive-relative prefixes such as D:.
|
package/dist/square-posting.d.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { DeliveryLedger, type DeliveryRoute, type DeliverySession } from './deli
|
|
|
2
2
|
import { type Seat } from './model.js';
|
|
3
3
|
import type { SquareArtifactPort } from './ports.js';
|
|
4
4
|
/** Local producer custody and current host attachment are different observations. */
|
|
5
|
-
export declare function deliverySessionsForSeats(ledger: DeliveryLedger, seats: readonly Seat[]): Promise<ReadonlyMap<string, DeliverySession | undefined>>;
|
|
5
|
+
export declare function deliverySessionsForSeats(ledger: DeliveryLedger, seats: readonly Seat[], signal?: AbortSignal): Promise<ReadonlyMap<string, DeliverySession | undefined>>;
|
|
6
6
|
/** Read-only host observations for status; callers fence them against the captured World seats. */
|
|
7
|
-
export declare function readSquareSessions(seats: readonly Seat[], env: NodeJS.ProcessEnv): Promise<ReadonlyMap<string, DeliverySession | undefined>>;
|
|
7
|
+
export declare function readSquareSessions(seats: readonly Seat[], env: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<ReadonlyMap<string, DeliverySession | undefined>>;
|
|
8
8
|
/** A first producer join may register an absent owner, never resume or revive one. */
|
|
9
|
-
export declare function ensureInitialDeliverySession(owner: Seat['owner'], env: NodeJS.ProcessEnv, route?: DeliveryRoute): Promise<boolean>;
|
|
9
|
+
export declare function ensureInitialDeliverySession(owner: Seat['owner'], env: NodeJS.ProcessEnv, route?: DeliveryRoute, signal?: AbortSignal): Promise<boolean>;
|
|
10
10
|
/** Called only by privileged mutations. Sandbox lease/ACK/selection never enters here. */
|
|
11
|
-
export declare function reconcileSquareDelivery(artifact: SquareArtifactPort, location: string, env: NodeJS.ProcessEnv, clock: () => number): Promise<void>;
|
|
11
|
+
export declare function reconcileSquareDelivery(artifact: SquareArtifactPort, location: string, env: NodeJS.ProcessEnv, clock: () => number, signal?: AbortSignal): Promise<void>;
|
|
12
12
|
/** One export path for Square activities and Square-owned notices. No transaction spans I/O. */
|
|
13
|
-
export declare function flushSquarePosts(artifact: SquareArtifactPort, location: string, env: NodeJS.ProcessEnv, clock: () => number): Promise<void>;
|
|
13
|
+
export declare function flushSquarePosts(artifact: SquareArtifactPort, location: string, env: NodeJS.ProcessEnv, clock: () => number, signal?: AbortSignal): Promise<void>;
|
package/dist/square-posting.js
CHANGED
|
@@ -7,8 +7,8 @@ import { coreDone } from './decisions.js';
|
|
|
7
7
|
import { activityMetadataHasContent } from './model.js';
|
|
8
8
|
import { formatActivityId } from './square-core.js';
|
|
9
9
|
import { squarePostKey } from './square-post.js';
|
|
10
|
-
const openLedger = (env) => DeliveryLedger.open({
|
|
11
|
-
location: deliveryLedgerLocation(env),
|
|
10
|
+
const openLedger = (env, signal) => DeliveryLedger.open({
|
|
11
|
+
location: deliveryLedgerLocation(env), signal,
|
|
12
12
|
});
|
|
13
13
|
function renderPost(location, post) {
|
|
14
14
|
if (post.kind === 'notice')
|
|
@@ -19,35 +19,35 @@ function renderPost(location, post) {
|
|
|
19
19
|
return { text: projected.text, full: projected.isFull };
|
|
20
20
|
}
|
|
21
21
|
/** Local producer custody and current host attachment are different observations. */
|
|
22
|
-
export async function deliverySessionsForSeats(ledger, seats) {
|
|
22
|
+
export async function deliverySessionsForSeats(ledger, seats, signal) {
|
|
23
23
|
const owners = [...new Set(seats.map(seat => seat.owner))];
|
|
24
|
-
return new Map(await Promise.all(owners.map(async (owner) => [owner, await ledger.session(owner)])));
|
|
24
|
+
return new Map(await Promise.all(owners.map(async (owner) => [owner, await ledger.session(owner, signal)])));
|
|
25
25
|
}
|
|
26
26
|
/** Read-only host observations for status; callers fence them against the captured World seats. */
|
|
27
|
-
export async function readSquareSessions(seats, env) {
|
|
27
|
+
export async function readSquareSessions(seats, env, signal) {
|
|
28
28
|
if (!seats.length)
|
|
29
29
|
return new Map();
|
|
30
|
-
const ledger = await openLedger(env);
|
|
30
|
+
const ledger = await openLedger(env, signal);
|
|
31
31
|
try {
|
|
32
|
-
return await deliverySessionsForSeats(ledger, seats);
|
|
32
|
+
return await deliverySessionsForSeats(ledger, seats, signal);
|
|
33
33
|
}
|
|
34
34
|
finally {
|
|
35
35
|
await ledger.close();
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
/** A first producer join may register an absent owner, never resume or revive one. */
|
|
39
|
-
export async function ensureInitialDeliverySession(owner, env, route) {
|
|
40
|
-
const ledger = await openLedger(env);
|
|
39
|
+
export async function ensureInitialDeliverySession(owner, env, route, signal) {
|
|
40
|
+
const ledger = await openLedger(env, signal);
|
|
41
41
|
try {
|
|
42
|
-
const current = await ledger.session(owner);
|
|
42
|
+
const current = await ledger.session(owner, signal);
|
|
43
43
|
if (!current) {
|
|
44
|
-
return !!await ledger.attach({ owner, expectedGeneration: null, routes: route ? [route] : [] });
|
|
44
|
+
return !!await ledger.attach({ owner, expectedGeneration: null, routes: route ? [route] : [] }, signal);
|
|
45
45
|
}
|
|
46
46
|
if (current.state !== 'attached')
|
|
47
47
|
return false;
|
|
48
48
|
if (route)
|
|
49
|
-
return ledger.updateRoutes({ owner, generation: current.generation,
|
|
50
|
-
routes: [...current.routes.filter(candidate => candidate.kind !== route.kind), route] });
|
|
49
|
+
return await ledger.updateRoutes({ owner, generation: current.generation,
|
|
50
|
+
routes: [...current.routes.filter(candidate => candidate.kind !== route.kind), route] }, signal);
|
|
51
51
|
return true;
|
|
52
52
|
}
|
|
53
53
|
finally {
|
|
@@ -55,14 +55,14 @@ export async function ensureInitialDeliverySession(owner, env, route) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
/** Called only by privileged mutations. Sandbox lease/ACK/selection never enters here. */
|
|
58
|
-
export async function reconcileSquareDelivery(artifact, location, env, clock) {
|
|
58
|
+
export async function reconcileSquareDelivery(artifact, location, env, clock, signal) {
|
|
59
59
|
const snapshot = (await artifact.read(facts => ({ seats: facts.roster().filter(person => person.joined)
|
|
60
|
-
.flatMap(person => { const seat = facts.seat(person.name); return seat ? [seat] : []; }), posts: facts.postedPosts() }))).value;
|
|
60
|
+
.flatMap(person => { const seat = facts.seat(person.name); return seat ? [seat] : []; }), posts: facts.postedPosts() }), signal)).value;
|
|
61
61
|
if (!snapshot.seats.length && !snapshot.posts.length)
|
|
62
62
|
return;
|
|
63
|
-
const ledger = await openLedger(env);
|
|
63
|
+
const ledger = await openLedger(env, signal);
|
|
64
64
|
try {
|
|
65
|
-
const sessions = await deliverySessionsForSeats(ledger, snapshot.seats);
|
|
65
|
+
const sessions = await deliverySessionsForSeats(ledger, snapshot.seats, signal);
|
|
66
66
|
for (const seat of snapshot.seats) {
|
|
67
67
|
const session = sessions.get(seat.owner);
|
|
68
68
|
if (!session)
|
|
@@ -72,71 +72,72 @@ export async function reconcileSquareDelivery(artifact, location, env, clock) {
|
|
|
72
72
|
const current = facts.seat(seat.participant);
|
|
73
73
|
if (current?.owner === seat.owner && current.generation === seat.generation && facts.participant(seat.participant)?.joined)
|
|
74
74
|
facts.land(coreDone(facts, seat.participant, '', clock()));
|
|
75
|
-
});
|
|
75
|
+
}, signal);
|
|
76
76
|
}
|
|
77
77
|
else if (seat.attachment !== session.state) {
|
|
78
78
|
const attachment = session.state;
|
|
79
|
-
await artifact.transactAs({ kind: 'producer' }, facts => facts.setSeatAttachment(seat, attachment));
|
|
79
|
+
await artifact.transactAs({ kind: 'producer' }, facts => facts.setSeatAttachment(seat, attachment), signal);
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
// A full receipt is monotonic external presentation evidence, never inferred from silence.
|
|
83
83
|
const receipts = new Map();
|
|
84
84
|
for (const owner of new Set(snapshot.posts.map(post => post.owner))) {
|
|
85
85
|
const keys = snapshot.posts.filter(post => post.owner === owner).map(post => squarePostKey(location, post));
|
|
86
|
-
receipts.set(owner, new Map((await ledger.receipts(owner, { keys })).map(receipt => [receipt.key, receipt.at])));
|
|
86
|
+
receipts.set(owner, new Map((await ledger.receipts(owner, { keys }, signal)).map(receipt => [receipt.key, receipt.at])));
|
|
87
87
|
}
|
|
88
88
|
for (const post of snapshot.posts) {
|
|
89
89
|
const cardKey = squarePostKey(location, post);
|
|
90
90
|
const receipt = receipts.get(post.owner)?.get(cardKey);
|
|
91
91
|
if (receipt !== undefined && post.full === true && !post.consumed)
|
|
92
|
-
await artifact.transactAs({ kind: 'producer' }, facts => facts.foldReceipt(post, receipt));
|
|
92
|
+
await artifact.transactAs({ kind: 'producer' }, facts => facts.foldReceipt(post, receipt), signal);
|
|
93
93
|
}
|
|
94
|
-
await suppressWithdrawn(artifact, ledger, location);
|
|
94
|
+
await suppressWithdrawn(artifact, ledger, location, signal);
|
|
95
95
|
}
|
|
96
96
|
finally {
|
|
97
97
|
await ledger.close();
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
async function suppressWithdrawn(artifact, ledger, location) {
|
|
100
|
+
async function suppressWithdrawn(artifact, ledger, location, signal) {
|
|
101
101
|
const posts = (await artifact.read(facts => facts.postedPosts().filter(post => {
|
|
102
102
|
const seat = facts.seat(post.recipient);
|
|
103
103
|
return post.consumed || !seat || seat.owner !== post.owner || seat.generation !== post.generation;
|
|
104
|
-
}))).value;
|
|
104
|
+
}), signal)).value;
|
|
105
105
|
// Departure withdraws only the captured notification, never producer read history or held effects.
|
|
106
106
|
for (const post of posts)
|
|
107
|
-
await ledger.suppress({ owner: post.owner, key: squarePostKey(location, post), scope: 'exact' });
|
|
107
|
+
await ledger.suppress({ owner: post.owner, key: squarePostKey(location, post), scope: 'exact' }, signal);
|
|
108
108
|
}
|
|
109
109
|
/** One export path for Square activities and Square-owned notices. No transaction spans I/O. */
|
|
110
|
-
export async function flushSquarePosts(artifact, location, env, clock) {
|
|
110
|
+
export async function flushSquarePosts(artifact, location, env, clock, signal) {
|
|
111
|
+
signal ??= AbortSignal.timeout(5000);
|
|
111
112
|
// Delivery enrichment cannot turn a committed producer mutation into a retry of that mutation.
|
|
112
113
|
let lifetime;
|
|
113
114
|
try {
|
|
114
|
-
const snapshot = (await artifact.read(facts => ({ pending: facts.pendingPosts(), posted: facts.postedPosts() }))).value;
|
|
115
|
+
const snapshot = (await artifact.read(facts => ({ pending: facts.pendingPosts(), posted: facts.postedPosts() }), signal)).value;
|
|
115
116
|
if (!snapshot.pending.length && !snapshot.posted.length)
|
|
116
117
|
return;
|
|
117
|
-
const ledger = await openLedger(env);
|
|
118
|
+
const ledger = await openLedger(env, signal);
|
|
118
119
|
lifetime = retainDeliveryLedger(ledger);
|
|
119
120
|
for (const post of snapshot.pending) {
|
|
120
|
-
const session = await ledger.session(post.owner);
|
|
121
|
+
const session = await ledger.session(post.owner, signal);
|
|
121
122
|
if (session?.state !== 'attached')
|
|
122
123
|
continue;
|
|
123
124
|
const rendered = renderPost(location, post), token = randomUUID();
|
|
124
|
-
const owned = (await artifact.transactAs({ kind: 'producer' }, facts => facts.acquirePost({ ...post, full: rendered.full }, token, process.pid, clock(), Date.now()))).value;
|
|
125
|
+
const owned = (await artifact.transactAs({ kind: 'producer' }, facts => facts.acquirePost({ ...post, full: rendered.full }, token, process.pid, clock(), Date.now()), signal)).value;
|
|
125
126
|
if (!owned)
|
|
126
127
|
continue;
|
|
127
128
|
let posted = false, knownUnsent = true;
|
|
128
129
|
try {
|
|
129
130
|
// This check is not custody across the await; the ledger independently fences delivery.
|
|
130
|
-
const current = await ledger.session(post.owner);
|
|
131
|
+
const current = await ledger.session(post.owner, signal);
|
|
131
132
|
if (current?.state !== 'attached' || current.generation !== session.generation
|
|
132
|
-
|| !(await artifact.read(facts => facts.ownsPost(token, Date.now()))).value)
|
|
133
|
+
|| !(await artifact.read(facts => facts.ownsPost(token, Date.now()), signal)).value)
|
|
133
134
|
continue;
|
|
134
135
|
knownUnsent = false;
|
|
135
136
|
const result = await ledger.post({ owner: post.owner, key: squarePostKey(location, post), text: rendered.text,
|
|
136
137
|
...(post.kind === 'activity' ? { details: { kind: 'presentation', origin: displayAttentionPath(location),
|
|
137
138
|
ref: formatActivityId(post.index), author: post.from, body: post.body ?? '',
|
|
138
139
|
...(post.route === 'bell' ? { badge: '🔔' } : {}) } } : {}),
|
|
139
|
-
});
|
|
140
|
+
}, signal);
|
|
140
141
|
posted = ['posted', 'duplicate', 'suppressed'].includes(result.status);
|
|
141
142
|
knownUnsent = !posted;
|
|
142
143
|
if (result.status === 'conflict')
|
|
@@ -147,20 +148,20 @@ export async function flushSquarePosts(artifact, location, env, clock) {
|
|
|
147
148
|
await artifact.settleAs({ kind: 'producer' }, facts => facts.settlePost(token, rendered.full, disposition));
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
|
-
await suppressWithdrawn(artifact, ledger, location);
|
|
151
|
+
await suppressWithdrawn(artifact, ledger, location, signal);
|
|
151
152
|
const posts = (await artifact.read(facts => facts.postedPosts().filter(post => {
|
|
152
153
|
const seat = facts.seat(post.recipient);
|
|
153
154
|
return !post.consumed && seat?.owner === post.owner && seat.generation === post.generation;
|
|
154
|
-
}))).value;
|
|
155
|
+
}), signal)).value;
|
|
155
156
|
for (const owner of new Set(posts.map(post => post.owner))) {
|
|
156
|
-
const session = await ledger.session(owner);
|
|
157
|
+
const session = await ledger.session(owner, signal);
|
|
157
158
|
if (session?.state !== 'attached')
|
|
158
159
|
continue;
|
|
159
|
-
const pendingKeys = new Set((await ledger.pending(owner, { generation: session.generation })).map(card => card.key));
|
|
160
|
+
const pendingKeys = new Set((await ledger.pending(owner, { generation: session.generation }, signal)).map(card => card.key));
|
|
160
161
|
for (const post of posts.filter(post => post.owner === owner)) {
|
|
161
162
|
const key = squarePostKey(location, post);
|
|
162
163
|
if (pendingKeys.has(key))
|
|
163
|
-
await dispatchPostedCard(ledger, owner, key, lifetime.track, env);
|
|
164
|
+
await dispatchPostedCard(ledger, owner, key, lifetime.track, env, signal);
|
|
164
165
|
}
|
|
165
166
|
}
|
|
166
167
|
}
|
package/dist/square-tools.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod/v4';
|
|
2
2
|
import { type Square } from './square-api.js';
|
|
3
|
-
import type { Owner, WakeAddress, OperationControl } from './square-facade.js';
|
|
3
|
+
import type { Owner, WakeAddress, OperationControl, DiscoveryOptions, DiscoveryResult } from './square-facade.js';
|
|
4
4
|
export interface ToolIdentity {
|
|
5
5
|
readonly owner?: Owner;
|
|
6
6
|
readonly wakeAddress?: WakeAddress;
|
|
@@ -19,20 +19,31 @@ export declare class SquareExpressDrafts {
|
|
|
19
19
|
interface ToolBinding {
|
|
20
20
|
identity: ToolIdentity;
|
|
21
21
|
open(location: string | undefined, control: OperationControl): Promise<Square>;
|
|
22
|
+
discover(options: DiscoveryOptions, control: OperationControl): Promise<{
|
|
23
|
+
result: DiscoveryResult;
|
|
24
|
+
now: number;
|
|
25
|
+
}>;
|
|
22
26
|
}
|
|
23
|
-
export declare function createSquareToolRunner(): (tool: ToolDefinition, args: JsonObject, control: OperationControl, bind: () => Promise<ToolBinding> | ToolBinding
|
|
27
|
+
export declare function createSquareToolRunner(): (tool: ToolDefinition, args: JsonObject, control: OperationControl, bind: () => Promise<ToolBinding> | ToolBinding) => Promise<{
|
|
24
28
|
text: string;
|
|
25
29
|
isError?: true;
|
|
26
30
|
}>;
|
|
27
|
-
interface
|
|
31
|
+
interface SingleSquareToolDefinition {
|
|
28
32
|
name: string;
|
|
29
33
|
description: string;
|
|
30
34
|
inputSchema: z.ZodObject<z.ZodRawShape>;
|
|
31
35
|
/** Human text identical to what the CLI prints; domain receipts stay inside the adapter. */
|
|
32
36
|
run(square: Square, args: JsonObject, control: OperationControl, identity: ToolIdentity): Promise<string>;
|
|
33
37
|
}
|
|
38
|
+
interface DiscoveryToolDefinition {
|
|
39
|
+
name: 'list';
|
|
40
|
+
description: string;
|
|
41
|
+
inputSchema: z.ZodObject<z.ZodRawShape>;
|
|
42
|
+
runDiscovery(args: JsonObject, control: OperationControl, binding: ToolBinding): Promise<string>;
|
|
43
|
+
}
|
|
44
|
+
type ToolDefinition = SingleSquareToolDefinition | DiscoveryToolDefinition;
|
|
34
45
|
export declare function squareToolsEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
35
|
-
export declare const SQUARE_TOOL_INSTRUCTIONS = "Join once. Then express to speak, and
|
|
46
|
+
export declare const SQUARE_TOOL_INSTRUCTIONS = "List nearby squares and your joined names with list. Pass location for a single square. Join once. Then express to speak, and perceive to take in what reached you. History looks back without taking anything in.";
|
|
36
47
|
export declare const SQUARE_TOOLS: readonly ToolDefinition[];
|
|
37
48
|
export declare function squareToolFailure(error: unknown, signal?: AbortSignal): JsonObject;
|
|
38
49
|
/** Readable failure text with the same recovery commands the CLI offers, never raw JSON. */
|
package/dist/square-tools.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
import { z } from 'zod/v4';
|
|
3
3
|
import { isSquareError, SquareError } from './model.js';
|
|
4
|
-
import { requireOwner, requireJoinName, selectOwnSeat,
|
|
5
|
-
import {
|
|
4
|
+
import { requireOwner, requireJoinName, selectOwnSeat, PERCEIVE_DEFAULT_LIMIT, DEFAULT_LIST_DEPTH, DEFAULT_LIST_LIMIT, MAX_LIST_DEPTH, MAX_LIST_LIMIT } from './square-api.js';
|
|
5
|
+
import { renderPerceiveOutcome, renderExpression, renderFailureLines, renderHistoryResult, renderJoinResult, renderLifecycleResult, renderListenerChange, renderStatusResult, renderSquareList, } from './operation-presentation.js';
|
|
6
6
|
/** Process-local recovery: FIFO 64, fixed two-hour TTL, consumed only by a successful express. */
|
|
7
7
|
const EXPRESS_DRAFT_TTL_MS = 2 * 60 * 60 * 1000;
|
|
8
8
|
const EXPRESS_DRAFT_LIMIT = 64;
|
|
@@ -33,7 +33,8 @@ export class SquareExpressDrafts {
|
|
|
33
33
|
const effect = failure.operation?.expressEffect;
|
|
34
34
|
// After an attempt, only an admission or argument refusal proves that retrying cannot duplicate an activity.
|
|
35
35
|
const unsent = !expressAttempted || effect === 'unsent' || (effect === undefined && failure.code === 'invalid_args');
|
|
36
|
-
if (!unsent || effect === 'landed' || effect === 'unknown' || typeof args.body !== 'string' || args.draft !== undefined
|
|
36
|
+
if (!unsent || effect === 'landed' || effect === 'unknown' || typeof args.body !== 'string' || args.draft !== undefined
|
|
37
|
+
|| typeof args.location !== 'string' || !args.location.trim())
|
|
37
38
|
return undefined;
|
|
38
39
|
this.purgeExpired();
|
|
39
40
|
if (token !== undefined && this.drafts.has(token))
|
|
@@ -47,7 +48,7 @@ export class SquareExpressDrafts {
|
|
|
47
48
|
}
|
|
48
49
|
export function createSquareToolRunner() {
|
|
49
50
|
const drafts = new SquareExpressDrafts();
|
|
50
|
-
return async (tool, args, control, bind
|
|
51
|
+
return async (tool, args, control, bind) => {
|
|
51
52
|
let toolArgs = args;
|
|
52
53
|
let owner;
|
|
53
54
|
let token;
|
|
@@ -56,6 +57,8 @@ export function createSquareToolRunner() {
|
|
|
56
57
|
try {
|
|
57
58
|
const binding = await bind();
|
|
58
59
|
owner = binding.identity.owner;
|
|
60
|
+
if ('runDiscovery' in tool)
|
|
61
|
+
return { text: await tool.runDiscovery(toolArgs, control, binding) };
|
|
59
62
|
if (tool.name === 'express') {
|
|
60
63
|
const resolved = drafts.resolve(toolArgs, owner);
|
|
61
64
|
toolArgs = resolved.args;
|
|
@@ -77,14 +80,15 @@ export function createSquareToolRunner() {
|
|
|
77
80
|
const failure = squareToolFailure(error, control.signal);
|
|
78
81
|
const draft = tool.name === 'express' ? drafts.retain(toolArgs, owner, token, failure, attempted) : undefined;
|
|
79
82
|
return { isError: true, text: squareToolFailureText(failure, {
|
|
80
|
-
location: square?.location ?? toolArgs.location
|
|
83
|
+
location: square?.location ?? toolArgs.location,
|
|
81
84
|
participant: typeof toolArgs.as === 'string' ? toolArgs.as : undefined,
|
|
82
85
|
draft,
|
|
83
86
|
}) };
|
|
84
87
|
}
|
|
85
88
|
};
|
|
86
89
|
}
|
|
87
|
-
const location = z.string().
|
|
90
|
+
const location = z.string().describe('Which square: a .square file path. Relative paths start from the working directory.');
|
|
91
|
+
const expressLocation = z.string().optional().describe('Which square: a .square file path. Relative paths start from the working directory. Required unless retrying with a draft token.');
|
|
88
92
|
const participant = z.string().optional().describe('Your name in the square. Leave it out if you hold exactly one name here.');
|
|
89
93
|
const activityId = z.string().regex(/^act\/(0|[1-9][0-9]*)$/);
|
|
90
94
|
const stringArray = z.array(z.string());
|
|
@@ -93,7 +97,7 @@ function rendering(render) {
|
|
|
93
97
|
return (result, args) => render(result, args);
|
|
94
98
|
}
|
|
95
99
|
function tool(name, description, shape, run, render) {
|
|
96
|
-
const inputSchema = z.object({ ...shape, location }).strict();
|
|
100
|
+
const inputSchema = z.object({ ...shape, location: name === 'express' ? expressLocation : location }).strict();
|
|
97
101
|
return { name, description, inputSchema,
|
|
98
102
|
run: async (square, args, control, identity) => {
|
|
99
103
|
const { location: _location, ...operationArgs } = inputSchema.parse(args);
|
|
@@ -109,7 +113,7 @@ export function squareToolsEnabled(env = process.env) {
|
|
|
109
113
|
return false;
|
|
110
114
|
throw new SquareError('invalid_args', 'Invalid SQUARE_TOOLS: expected 0, 1, true, false, or none.');
|
|
111
115
|
}
|
|
112
|
-
export const SQUARE_TOOL_INSTRUCTIONS = 'Join once. Then express to speak, and
|
|
116
|
+
export const SQUARE_TOOL_INSTRUCTIONS = 'List nearby squares and your joined names with list. Pass location for a single square. Join once. Then express to speak, and perceive to take in what reached you. History looks back without taking anything in.';
|
|
113
117
|
function historyToolQuery({ grep, fixed, before, after, ...query }) {
|
|
114
118
|
if (grep !== undefined && fixed !== undefined)
|
|
115
119
|
throw new SquareError('invalid_args', 'Use grep or fixed, not both.');
|
|
@@ -121,8 +125,22 @@ function historyToolQuery({ grep, fixed, before, after, ...query }) {
|
|
|
121
125
|
};
|
|
122
126
|
}
|
|
123
127
|
const target = z.string().describe('The participant to turn toward or away from.');
|
|
128
|
+
const listSchema = z.object({
|
|
129
|
+
depth: z.number().int().min(0).max(MAX_LIST_DEPTH).optional().describe('How many directory levels to explore (default 4).'),
|
|
130
|
+
limit: z.number().int().min(1).max(MAX_LIST_LIMIT).optional().describe('How many squares per page (default 20).'),
|
|
131
|
+
after: z.string().min(1).optional().describe('Continue after this relative square path.'),
|
|
132
|
+
}).strict();
|
|
124
133
|
export const SQUARE_TOOLS = [
|
|
125
|
-
|
|
134
|
+
{
|
|
135
|
+
name: 'list', description: 'Find nearby squares, including your joined names and what is waiting for them. Start here to choose a location.',
|
|
136
|
+
inputSchema: listSchema,
|
|
137
|
+
async runDiscovery(args, control, binding) {
|
|
138
|
+
const options = listSchema.parse(args);
|
|
139
|
+
const { result, now } = await binding.discover({ ...options, owner: binding.identity.owner }, control);
|
|
140
|
+
return renderSquareList(result, { now, depth: options.depth ?? DEFAULT_LIST_DEPTH, limit: options.limit ?? DEFAULT_LIST_LIMIT });
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
tool('join', 'Step into the square under your name. Do this once before you speak or perceive. You arrive seeing what was said most recently.', {
|
|
126
144
|
as: z.string().optional().describe('Your name in the square. Give it explicitly when joining.'), takeover: z.boolean().optional().describe('Claim this name even though another session holds it now. That session loses it.'),
|
|
127
145
|
}, (square, { as, takeover }, control, identity) => square.join(requireJoinName(as), { ...identity, owner: requireOwner(identity.owner), takeover, observe: true }, control), rendering((result) => renderJoinResult(result))),
|
|
128
146
|
tool('express', 'Speak or act in the square. Plain words, half-formed ideas and *actions* all belong here. Mention or reply to someone to be heard by them; ring the bell to be heard by everyone. Said to no one in particular, your words reach those who listen to you.', {
|
|
@@ -133,7 +151,7 @@ export const SQUARE_TOOLS = [
|
|
|
133
151
|
reach: z.enum(['bell']).optional().describe('"bell" calls everyone in the square. Cannot be used with mentions.'),
|
|
134
152
|
reply: activityId.optional().describe('The activity you are answering, like act/12. Its author hears you if still here.'),
|
|
135
153
|
noMention: z.boolean().optional().describe('Leave @names in the body as plain text. Mentions and reply still reach people.'),
|
|
136
|
-
force: z.boolean().optional().describe('Speak now, even if something reached you that you have not
|
|
154
|
+
force: z.boolean().optional().describe('Speak now, even if something reached you that you have not perceived yet.'),
|
|
137
155
|
noWait: z.boolean().optional().describe('If you are speaking too fast, return at once instead of waiting.'),
|
|
138
156
|
}, async (square, { body, draft, as, ...options }, control, identity) => {
|
|
139
157
|
if (draft !== undefined)
|
|
@@ -142,20 +160,20 @@ export const SQUARE_TOOLS = [
|
|
|
142
160
|
throw new SquareError('invalid_args', 'Express needs a body or a draft token.');
|
|
143
161
|
return (await selectOwnSeat(square, identity.owner, as)).express(body, { ...options, observe: true }, control);
|
|
144
162
|
}, rendering((result) => renderExpression(result.observation?.location ?? '', result))),
|
|
145
|
-
tool('
|
|
163
|
+
tool('perceive', 'Take in what reached you since you last looked: mentions, replies, bells, and words from those you listen to. What you perceive no longer waits for you; history lets you look back.', {
|
|
146
164
|
as: participant,
|
|
147
|
-
id: activityId.optional().describe('Take in this activity in full, like act/12, even if you
|
|
165
|
+
id: activityId.optional().describe('Take in this activity in full, like act/12, even if you perceived it before. Do not combine with idle, from, mention or limit.'),
|
|
148
166
|
idle: z.number().finite().min(0).optional().describe('When nothing is waiting, wait until something arrives or until it has been quiet this many milliseconds. Leave it out to return at once.'),
|
|
149
167
|
from: stringArray.optional().describe('Only what these participants said.'),
|
|
150
168
|
mention: z.boolean().optional().describe('Only what was addressed to you, and bells.'),
|
|
151
169
|
limit: z.number().int().min(1).optional().describe('At most this many at once (default 10, up to 100). The rest keeps waiting.'),
|
|
152
|
-
}, async (square, { as, ...options }, control, identity) => (await selectOwnSeat(square, identity.owner, as)).
|
|
170
|
+
}, async (square, { as, ...options }, control, identity) => (await selectOwnSeat(square, identity.owner, as)).perceive({ ...options, observe: true }, control), rendering((result, args) => {
|
|
153
171
|
// The CLI always spells the default cap in its continuation, so the tool does too.
|
|
154
172
|
const options = args;
|
|
155
|
-
const renderOptions = options.id === undefined ? { ...options, limit: options.limit ??
|
|
156
|
-
return
|
|
173
|
+
const renderOptions = options.id === undefined ? { ...options, limit: options.limit ?? PERCEIVE_DEFAULT_LIMIT } : options;
|
|
174
|
+
return renderPerceiveOutcome(result.observation?.location ?? '', result, renderOptions).stdout;
|
|
157
175
|
})),
|
|
158
|
-
tool('history', 'Look back at what was said. Reading here takes nothing in: whatever waits for
|
|
176
|
+
tool('history', 'Look back at what was said. Reading here takes nothing in: whatever waits for perceive keeps waiting. Page with before or after.', {
|
|
159
177
|
limit: z.number().int().min(1).optional().describe('How many per page (default 10, up to 100).'),
|
|
160
178
|
order: z.enum(['asc', 'desc']).optional().describe('"asc" for oldest first (default), "desc" for newest first.'),
|
|
161
179
|
before: activityId.optional().describe('The page just before this activity, like act/12.'),
|
|
@@ -199,7 +217,7 @@ export function squareToolFailureText(failure, context = {}) {
|
|
|
199
217
|
if (context.draft !== undefined) {
|
|
200
218
|
lines.push(`· draft kept in memory: ${context.draft}`);
|
|
201
219
|
lines.push(report.code === 'behind'
|
|
202
|
-
? '·
|
|
220
|
+
? '· perceive the pending activity, then retry express with only:'
|
|
203
221
|
: '· correct the problem above, then retry express with only:', `{ "draft": "${context.draft}" }`);
|
|
204
222
|
}
|
|
205
223
|
return lines.join('\n');
|
package/dist/views.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type ActivityId } from './square-core.js';
|
|
2
2
|
import { type HydratedAct } from './model.js';
|
|
3
3
|
import type { ActivityFilter, SquareRead } from './ports.js';
|
|
4
|
-
import type { Activity, ArchiveRecord, PerceivedActivity, HistoryQuery, HistoryContinuation, ParticipantsResult, EntryPresentation, StatusResult, SquareObservation,
|
|
4
|
+
import type { Activity, ArchiveRecord, PerceivedActivity, HistoryQuery, HistoryContinuation, ParticipantsResult, EntryPresentation, StatusResult, SquareObservation, PerceivePresence, Owner } from './square-facade.js';
|
|
5
5
|
export declare const HISTORY_DEFAULT_LIMIT = 10;
|
|
6
6
|
export declare const HISTORY_MAX_LIMIT = 100;
|
|
7
7
|
export declare const NON_READ: readonly ["join", "done", "say", "listen", "ignore", "unlisten"];
|
|
@@ -27,13 +27,17 @@ export declare function recoveryObservation(facts: SquareRead, name: string, now
|
|
|
27
27
|
export declare function entryPresentation(facts: SquareRead, name: string, lastN?: number | null): EntryPresentation;
|
|
28
28
|
type ParticipantQueryContext = Pick<SquareObservation, 'location' | 'now'>;
|
|
29
29
|
export declare function queryParticipants(facts: SquareRead, context: ParticipantQueryContext, observe?: boolean): ParticipantsResult;
|
|
30
|
-
export declare function listPresentation(facts: SquareRead): {
|
|
30
|
+
export declare function listPresentation(facts: SquareRead, owner?: Owner): {
|
|
31
|
+
joined?: {
|
|
32
|
+
name: string;
|
|
33
|
+
pending: number;
|
|
34
|
+
}[] | undefined;
|
|
31
35
|
context: readonly string[];
|
|
32
36
|
participants: string[];
|
|
33
37
|
activities: number;
|
|
34
38
|
};
|
|
35
39
|
export declare function queryStatus(facts: SquareRead, context: ParticipantQueryContext, viewer?: string, observe?: boolean): StatusResult;
|
|
36
|
-
export declare function
|
|
40
|
+
export declare function perceivePresence(facts: SquareRead, now: number): PerceivePresence;
|
|
37
41
|
export declare function streamProjection(facts: SquareRead, cursor: number, recipient?: string): {
|
|
38
42
|
activities: Activity[];
|
|
39
43
|
cursor: number;
|