@astrosheep/square 0.3.69 → 0.3.71
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 +4 -5
- package/dist/activity-feed.js +14 -10
- package/dist/artifact.d.ts +26 -33
- package/dist/artifact.js +346 -317
- package/dist/attention-presentation.js +2 -9
- package/dist/automatic-session.js +6 -6
- package/dist/boundary-presentation.js +3 -3
- package/dist/catch-decisions.d.ts +19 -12
- package/dist/catch-decisions.js +32 -68
- package/dist/claude-delivery.js +7 -7
- package/dist/claude-mod.js +18 -7
- package/dist/cli/catch-presentation.d.ts +7 -0
- package/dist/cli/catch-presentation.js +55 -0
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +5 -23
- package/dist/cli/express-presentation.d.ts +10 -0
- package/dist/cli/express-presentation.js +196 -0
- package/dist/cli/maintenance-commands.d.ts +4 -0
- package/dist/cli/maintenance-commands.js +29 -6
- package/dist/cli/observation-commands.d.ts +7 -5
- package/dist/cli/observation-commands.js +275 -262
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +43 -56
- package/dist/cli/registry.js +2 -1
- package/dist/cli/square-commands.d.ts +3 -9
- package/dist/cli/square-commands.js +134 -255
- package/dist/codex-queue.js +4 -1
- package/dist/decisions.d.ts +26 -74
- package/dist/decisions.js +190 -335
- package/dist/delivery-health.js +13 -22
- package/dist/delivery-operations.d.ts +0 -11
- package/dist/delivery-operations.js +44 -33
- package/dist/delivery.d.ts +33 -32
- package/dist/delivery.js +70 -81
- package/dist/harness-claude.js +1 -1
- package/dist/harness-codex.js +1 -1
- package/dist/harness-pi.js +1 -1
- package/dist/help.js +6 -1
- package/dist/inbox.d.ts +27 -0
- package/dist/inbox.js +55 -18
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -1
- package/dist/list.d.ts +7 -1
- package/dist/list.js +49 -122
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +7 -37
- package/dist/model.d.ts +4 -44
- package/dist/model.js +1 -3
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +13 -7
- package/dist/open-square.d.ts +16 -2
- package/dist/open-square.js +40 -1
- package/dist/perception-projection.d.ts +6 -15
- package/dist/perception-projection.js +6 -26
- package/dist/{opencode-delivery.d.ts → plugins/opencode/delivery.d.ts} +1 -1
- package/dist/{opencode-delivery.js → plugins/opencode/delivery.js} +18 -18
- package/dist/{opencode.d.ts → plugins/opencode/index.d.ts} +2 -2
- package/dist/{opencode.js → plugins/opencode/index.js} +9 -9
- package/dist/ports.d.ts +156 -11
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +35 -44
- package/dist/presentation.d.ts +12 -19
- package/dist/presentation.js +33 -54
- package/dist/routes.d.ts +7 -14
- package/dist/routes.js +33 -62
- package/dist/runtime.d.ts +12 -39
- package/dist/runtime.js +33 -164
- package/dist/square-actions.d.ts +11 -21
- package/dist/square-actions.js +171 -271
- package/dist/square-application.d.ts +31 -55
- package/dist/square-application.js +637 -141
- package/dist/square-core.d.ts +3 -94
- package/dist/square-core.js +8 -353
- package/dist/square-domain.d.ts +24 -0
- package/dist/square-domain.js +77 -0
- package/dist/square-facade.d.ts +360 -9
- package/dist/square-migration.d.ts +24 -0
- package/dist/square-migration.js +211 -0
- package/dist/square-projections.d.ts +2 -42
- package/dist/square-projections.js +1 -37
- package/dist/square-sqlite.d.ts +59 -0
- package/dist/square-sqlite.js +702 -0
- package/dist/stream.d.ts +3 -10
- package/dist/stream.js +81 -52
- package/dist/views.d.ts +27 -95
- package/dist/views.js +217 -87
- package/dist/wake-eligibility.d.ts +15 -5
- package/dist/wake-eligibility.js +32 -16
- package/dist/wakes.d.ts +3 -3
- package/dist/wakes.js +31 -27
- package/guides/application-facade-delivery-evidence.md +200 -0
- package/guides/application-facade-design.md +95 -0
- package/guides/change-waits.md +4 -4
- package/guides/migration.md +77 -0
- package/guides/pi-native-delivery.md +1 -1
- package/guides/primitive-catch-consolidation.md +85 -0
- package/guides/primitive-history-consolidation.md +76 -0
- package/guides/primitive-status-consolidation.md +87 -0
- package/guides/primitive-storage-consolidation.md +128 -0
- package/guides/row-runtime-delivery-evidence.md +160 -0
- package/guides/row-storage-design.md +567 -0
- package/package.json +5 -7
- package/{claude-plugin → plugins/claude}/.claude-plugin/plugin.json +1 -1
- package/{codex-plugin → plugins/codex}/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +149 -0
- package/plugins/opencode/index.ts +136 -0
- package/plugins/paseo/OVERVIEW.md +14 -0
- package/plugins/paseo/README.md +54 -0
- package/plugins/paseo/client/square-message.tsx +106 -0
- package/plugins/paseo/client/transform.ts +24 -0
- package/plugins/paseo/index.client.tsx +19 -0
- package/plugins/paseo/package.json +19 -0
- package/plugins/paseo/paseo-plugin.json +7 -0
- package/plugins/paseo/shared/message.ts +29 -0
- package/{extensions → plugins/pi}/square-pi.js +8 -5
- package/dist/activity.d.ts +0 -14
- package/dist/activity.js +0 -248
- package/dist/square-file-adapter.d.ts +0 -26
- package/dist/square-file-adapter.js +0 -85
- package/dist/square-state.d.ts +0 -6
- package/dist/square-state.js +0 -138
- package/dist/square-storage.d.ts +0 -14
- package/dist/square-storage.js +0 -188
- package/dist/square-wiring.d.ts +0 -33
- package/dist/square-wiring.js +0 -109
- package/dist/watch.d.ts +0 -8
- package/dist/watch.js +0 -252
- /package/{claude-plugin → plugins/claude}/hooks/hooks.json +0 -0
- /package/{claude-plugin → plugins/claude}/hooks/register.js +0 -0
- /package/{claude-plugin → plugins/claude}/skills/square/SKILL.md +0 -0
- /package/{claude-plugin → plugins/claude}/types.d.ts +0 -0
- /package/{codex-plugin → plugins/codex}/hooks/hooks.json +0 -0
package/dist/open-square.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HostLedgerPort, SquareArtifactPort, WakeTransportPort } from './ports.js';
|
|
2
|
-
|
|
2
|
+
import type { OperationControl } from './square-facade.js';
|
|
3
|
+
/** Host-bound resource: artifact, captured environment, clock, ledger and transport. */
|
|
3
4
|
export interface OpenSquare {
|
|
4
5
|
readonly artifact: SquareArtifactPort;
|
|
5
6
|
readonly clock: () => number;
|
|
@@ -8,5 +9,18 @@ export interface OpenSquare {
|
|
|
8
9
|
readonly wakeTransport?: WakeTransportPort;
|
|
9
10
|
readonly env?: NodeJS.ProcessEnv;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
+
export interface SquareBuildOptions {
|
|
13
|
+
markdown: string;
|
|
14
|
+
hardCap?: number | null;
|
|
15
|
+
throttlePerMinute?: number;
|
|
16
|
+
clock?: () => number;
|
|
17
|
+
hostLedger?: HostLedgerPort;
|
|
18
|
+
wakeTransport?: WakeTransportPort;
|
|
19
|
+
env?: NodeJS.ProcessEnv;
|
|
20
|
+
/** One caller deadline propagated into artifact busy retries. */
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export declare function openSquare(squarePath: string, options?: Pick<SquareBuildOptions, 'clock' | 'hostLedger' | 'wakeTransport' | 'env' | 'signal'>, control?: OperationControl): Promise<OpenSquare>;
|
|
24
|
+
export declare function buildSquare(squarePath: string, options: SquareBuildOptions): Promise<OpenSquare>;
|
|
25
|
+
export declare function buildMemorySquare(options: SquareBuildOptions): OpenSquare;
|
|
12
26
|
export declare function closeOpenSquare(square: OpenSquare): Promise<void>;
|
package/dist/open-square.js
CHANGED
|
@@ -1,4 +1,43 @@
|
|
|
1
|
-
|
|
1
|
+
import { createArtifactPort, createSquare, prepareSquareBuild } from './artifact.js';
|
|
2
|
+
import { InternalSquareError, SquareError } from './model.js';
|
|
3
|
+
import { hostLedgerRoot } from './host-ledger-root.js';
|
|
4
|
+
import { createHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
5
|
+
export async function openSquare(squarePath, options = {}, control) {
|
|
6
|
+
const env = { ...(options.env ?? process.env) };
|
|
7
|
+
const artifact = createArtifactPort(squarePath, undefined, options.signal);
|
|
8
|
+
try {
|
|
9
|
+
await artifact.read(facts => facts.header(), control?.signal);
|
|
10
|
+
return {
|
|
11
|
+
artifact, clock: options.clock ?? Date.now, location: squarePath, env,
|
|
12
|
+
hostLedger: options.hostLedger ?? createHostLedgerPort({ rootPath: hostLedgerRoot(env) }),
|
|
13
|
+
wakeTransport: options.wakeTransport,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
await artifact.close();
|
|
18
|
+
if (error instanceof InternalSquareError && error.code === 'not_found')
|
|
19
|
+
throw new SquareError('unavailable', `Square is unavailable at ${squarePath}`);
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function buildSquare(squarePath, options) {
|
|
24
|
+
try {
|
|
25
|
+
await createSquare(squarePath, { ...options, force: false }, options.markdown, options.signal);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof InternalSquareError && error.code === 'conflict')
|
|
29
|
+
throw new SquareError('io', `Cannot build over an existing square at ${squarePath}`);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
return openSquare(squarePath, { ...options, signal: undefined });
|
|
33
|
+
}
|
|
34
|
+
export function buildMemorySquare(options) {
|
|
35
|
+
return {
|
|
36
|
+
artifact: createArtifactPort(':memory:', prepareSquareBuild(options, options.markdown)),
|
|
37
|
+
clock: options.clock ?? Date.now, location: 'memory',
|
|
38
|
+
hostLedger: options.hostLedger, wakeTransport: options.wakeTransport,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
2
41
|
export function closeOpenSquare(square) {
|
|
3
42
|
return square.artifact.close();
|
|
4
43
|
}
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { type
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
export interface PerceptionProjection {
|
|
8
|
-
directedTo(activity: StoredAct, name: string): boolean;
|
|
9
|
-
perceive(activity: StoredAct, name: string): Perception;
|
|
10
|
-
cursorFor(name: string): number;
|
|
11
|
-
isSeen(name: string, index: number): boolean;
|
|
12
|
-
readonly replayedActivityCount: number;
|
|
13
|
-
}
|
|
14
|
-
/** Build perception over one audience replay of a SquareState snapshot. */
|
|
15
|
-
export declare function derivePerceptionProjection(state: SquareState, landed?: LandedAudienceReplay): PerceptionProjection;
|
|
1
|
+
import type { Perception } from './square-core.js';
|
|
2
|
+
import { type StoredAct } from './model.js';
|
|
3
|
+
import type { SquareRead } from './ports.js';
|
|
4
|
+
export declare function directedTo(facts: SquareRead, activity: StoredAct, name: string): boolean;
|
|
5
|
+
/** Audience is settled at landing, never reconstructed from a partial history. */
|
|
6
|
+
export declare function perceiveActivity(facts: SquareRead, activity: StoredAct, name: string): Perception;
|
|
@@ -1,28 +1,8 @@
|
|
|
1
|
-
import { formatActivityId, replayLandedAudiences } from './square-core.js';
|
|
2
1
|
import { sameName } from './model.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function directedTo(activity, name) {
|
|
10
|
-
return activity.kind === 'say' && landed.includes(activity, name);
|
|
11
|
-
}
|
|
12
|
-
function perceive(activity, name) {
|
|
13
|
-
if (activity.kind !== 'say' || sameName(activity.actor, name))
|
|
14
|
-
return 'full';
|
|
15
|
-
return directedTo(activity, name) ? 'full' : 'presence';
|
|
16
|
-
}
|
|
17
|
-
function isSeen(name, index) {
|
|
18
|
-
const recipient = canonicalName(name);
|
|
19
|
-
return state.runtime.observations?.[recipient]?.[formatActivityId(index)]?.state === 'seen';
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
directedTo,
|
|
23
|
-
perceive,
|
|
24
|
-
cursorFor: (name) => readCursor(state, name, landed),
|
|
25
|
-
isSeen,
|
|
26
|
-
replayedActivityCount: landed.replayedActivityCount,
|
|
27
|
-
};
|
|
2
|
+
export function directedTo(facts, activity, name) {
|
|
3
|
+
return activity.kind === 'say' && facts.directedAt(name, activity.index) !== undefined;
|
|
4
|
+
}
|
|
5
|
+
/** Audience is settled at landing, never reconstructed from a partial history. */
|
|
6
|
+
export function perceiveActivity(facts, activity, name) {
|
|
7
|
+
return activity.kind !== 'say' || sameName(activity.actor, name) || directedTo(facts, activity, name) ? 'full' : 'presence';
|
|
28
8
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type OpenCodeNativeSession } from '
|
|
1
|
+
import { type OpenCodeNativeSession } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
2
2
|
export interface OpenCodeContextMessage {
|
|
3
3
|
readonly id?: string;
|
|
4
4
|
readonly role: string;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { nameKey } from '
|
|
2
|
-
import { observeSessionPending, sessionInbox } from '
|
|
3
|
-
import { hostLedgerForEnv } from '
|
|
4
|
-
import { openSquare } from '
|
|
5
|
-
import { closeOpenSquare } from '
|
|
6
|
-
import {
|
|
7
|
-
import { presentPending } from '
|
|
8
|
-
import { deliverPending } from '
|
|
9
|
-
import { createWakeTransport } from '
|
|
10
|
-
import { publishWakeRoute } from '
|
|
11
|
-
import { formatActivityId, parseActivityId } from '
|
|
12
|
-
import { createNativeInputId, sendNativeText } from '
|
|
1
|
+
import { nameKey } from '../../model.js';
|
|
2
|
+
import { nativePendingPreview, observeSessionPending, sessionInbox } from '../../inbox.js';
|
|
3
|
+
import { hostLedgerForEnv } from '../../registry.js';
|
|
4
|
+
import { openSquare } from '../../open-square.js';
|
|
5
|
+
import { closeOpenSquare } from '../../open-square.js';
|
|
6
|
+
import { presentationSuppressesWake, projectPresentationEvidence } from '../../square-projections.js';
|
|
7
|
+
import { presentPending } from '../../presentation-operations.js';
|
|
8
|
+
import { deliverPending } from '../../delivery-operations.js';
|
|
9
|
+
import { createWakeTransport } from '../../notifications.js';
|
|
10
|
+
import { publishWakeRoute } from '../../routes.js';
|
|
11
|
+
import { formatActivityId, parseActivityId } from '../../square-core.js';
|
|
12
|
+
import { createNativeInputId, sendNativeText } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
13
13
|
const routeKind = 'opencode-server';
|
|
14
14
|
const key = (location, participant, index) => `${location}\0${nameKey(participant)}\0${index}`;
|
|
15
15
|
/** The one native pending preview: the audience/catch/epoch fence before send and inside presentation. */
|
|
16
|
-
function preview(
|
|
17
|
-
return nativePendingPreview(
|
|
16
|
+
function preview(facts, owner, index) {
|
|
17
|
+
return nativePendingPreview(facts, { location: owner.location, routeKind, sessionId: owner.session, participant: owner.participant, actIndex: index, epoch: owner.epoch, address: { sessionId: owner.session }, cancelledThrough: owner.cancelledThrough, now: Date.now() });
|
|
18
18
|
}
|
|
19
19
|
function createOpenCodeWakeTransport(target, env, lifetime) {
|
|
20
20
|
const ledger = hostLedgerForEnv(env);
|
|
@@ -36,14 +36,14 @@ function createOpenCodeWakeTransport(target, env, lifetime) {
|
|
|
36
36
|
return undefined;
|
|
37
37
|
const square = await openSquare(owner.location, { hostLedger: ledger, env, signal });
|
|
38
38
|
try {
|
|
39
|
-
const prepared =
|
|
39
|
+
const { value: prepared } = await square.artifact.read((facts) => preview(facts, owner, index), signal);
|
|
40
40
|
if (!prepared)
|
|
41
41
|
return undefined;
|
|
42
42
|
const row = { location: owner.location, participant: owner.participant, session: target.sessionId,
|
|
43
43
|
activity: request.activity, kind: 'wake', outcome: 'dispatching', routeKind, attemptN: request.attemptN, claimToken: request.claimToken,
|
|
44
44
|
nativeDelivery: { harness: 'opencode', epoch: owner.epoch ?? 0, inputId: createNativeInputId(), payload: prepared.payload } };
|
|
45
45
|
if (!await ledger.prepareNativeWake(row) || !await (beforeSend?.() ?? Promise.resolve(true)) || signal.aborted
|
|
46
|
-
||
|
|
46
|
+
|| (await square.artifact.read((facts) => preview(facts, owner, index)?.payload, signal)).value !== prepared.payload)
|
|
47
47
|
return undefined;
|
|
48
48
|
return { sending: sendNativeText(target, prepared.payload, { inputId: row.nativeDelivery.inputId, delivery: 'steer',
|
|
49
49
|
timeoutMs: Math.max(1, deadline - Date.now()), signal }) };
|
|
@@ -82,7 +82,7 @@ export async function observeOpenCodeContext(sessionId, messages, env, signal) {
|
|
|
82
82
|
continue;
|
|
83
83
|
const square = await openSquare(row.location, { hostLedger: ledger, env, signal });
|
|
84
84
|
try {
|
|
85
|
-
const prepared =
|
|
85
|
+
const { value: prepared } = await square.artifact.read((facts) => preview(facts, owner, index), signal);
|
|
86
86
|
if (!prepared || prepared.payload !== row.nativeDelivery.payload)
|
|
87
87
|
continue;
|
|
88
88
|
const prior = await projectPresentationEvidence({ hostLedger: ledger, location: row.location, participant: row.participant, sessionId, activity: row.activity });
|
|
@@ -90,7 +90,7 @@ export async function observeOpenCodeContext(sessionId, messages, env, signal) {
|
|
|
90
90
|
continue;
|
|
91
91
|
await presentPending({ artifact: square.artifact, hostLedger: ledger, location: row.location, participant: row.participant, session: sessionId,
|
|
92
92
|
activity: row.activity, sink: { present() { } }, markSeen: !prepared.clipped, signal,
|
|
93
|
-
current: (
|
|
93
|
+
current: (facts) => !signal.aborted && preview(facts, owner, index)?.payload === row.nativeDelivery.payload });
|
|
94
94
|
}
|
|
95
95
|
finally {
|
|
96
96
|
await closeOpenSquare(square);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type OpenCodeSessionCapability } from '
|
|
2
|
-
import { type OpenCodeContextMessage } from './
|
|
1
|
+
import { type OpenCodeSessionCapability } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
2
|
+
import { type OpenCodeContextMessage } from './delivery.js';
|
|
3
3
|
interface OpenCodePluginContext {
|
|
4
4
|
readonly app: {
|
|
5
5
|
readonly version: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { automaticSessionStart, operationEnv } from '
|
|
2
|
-
import { hostLedgerForEnv } from '
|
|
3
|
-
import { canonicalPath } from '
|
|
4
|
-
import { openSquare } from '
|
|
5
|
-
import { closeOpenSquare } from '
|
|
6
|
-
import { Square } from '
|
|
7
|
-
import { connectNative } from '
|
|
8
|
-
import { observeOpenCodeContext, publishOpenCodeRoutes, receiveOpenCodePending } from './
|
|
1
|
+
import { automaticSessionStart, operationEnv } from '../../automatic-session.js';
|
|
2
|
+
import { hostLedgerForEnv } from '../../registry.js';
|
|
3
|
+
import { canonicalPath } from '../../canonical-path.js';
|
|
4
|
+
import { openSquare } from '../../open-square.js';
|
|
5
|
+
import { closeOpenSquare } from '../../open-square.js';
|
|
6
|
+
import { Square } from '../../square-application.js';
|
|
7
|
+
import { connectNative } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
8
|
+
import { observeOpenCodeContext, publishOpenCodeRoutes, receiveOpenCodePending } from './delivery.js';
|
|
9
9
|
/** Actual OpenCode 2.0.20 server plugin. Harness identity belongs to ctx, never process.env. */
|
|
10
10
|
export default {
|
|
11
11
|
id: 'square',
|
|
@@ -81,7 +81,7 @@ export default {
|
|
|
81
81
|
for (const owner of (await ledger.listPresence({ session: sessionId })).filter((binding) => binding.channel === 'opencode')) {
|
|
82
82
|
const square = await openSquare(owner.location, { hostLedger: ledger, env, signal: lifetime.signal });
|
|
83
83
|
try {
|
|
84
|
-
await ledger.suppressPresence(owner, (await square.artifact.read(
|
|
84
|
+
await ledger.suppressPresence(owner, (await square.artifact.read((facts) => facts.header().nextActIndex - 1, lifetime.signal)).value);
|
|
85
85
|
}
|
|
86
86
|
finally {
|
|
87
87
|
await closeOpenSquare(square);
|
package/dist/ports.d.ts
CHANGED
|
@@ -1,16 +1,161 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Act, HardCap, InboxNotification, StoredAct, WakeRoute, WakeRouteKind, WatchLease } from './model.js';
|
|
2
2
|
export type { ClaimResult, EvidenceClaim, EvidenceRelease, EvidenceGc, EvidenceLookup, EvidenceRecord, HostLedgerPort, PresenceKey, PresenceLookup, PresenceRecord, PresenceClaimResult, PresenceChannel, PresenceResult, } from './host-ledger.js';
|
|
3
3
|
import type { HostLedgerPort } from './host-ledger.js';
|
|
4
|
-
|
|
4
|
+
export type ActivityIndex = number;
|
|
5
|
+
export interface SquareHeader {
|
|
6
|
+
readonly revision: number;
|
|
7
|
+
readonly nextActIndex: number;
|
|
8
|
+
readonly lastActIndex: number;
|
|
9
|
+
readonly hardCap: HardCap;
|
|
10
|
+
readonly throttlePerMinute?: number;
|
|
11
|
+
readonly preamble: readonly string[];
|
|
12
|
+
readonly warmup: readonly string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ParticipantFact {
|
|
15
|
+
readonly name: string;
|
|
16
|
+
readonly firstIndex: number;
|
|
17
|
+
readonly joined: boolean;
|
|
18
|
+
readonly done: boolean;
|
|
19
|
+
readonly sayCount: number;
|
|
20
|
+
readonly lastActiveAt?: number;
|
|
21
|
+
readonly lastJoinIndex?: number;
|
|
22
|
+
}
|
|
23
|
+
export interface AttentionFact {
|
|
24
|
+
readonly listener: string;
|
|
25
|
+
readonly target: string;
|
|
26
|
+
readonly kind: 'listen' | 'ignore';
|
|
27
|
+
readonly sinceIndex: number;
|
|
28
|
+
}
|
|
29
|
+
export interface ActivityHead {
|
|
30
|
+
readonly index: ActivityIndex;
|
|
31
|
+
readonly at: number;
|
|
32
|
+
readonly kind: StoredAct['kind'];
|
|
33
|
+
readonly actor?: string;
|
|
34
|
+
readonly reach?: 'bell';
|
|
35
|
+
readonly reply?: ActivityIndex;
|
|
36
|
+
}
|
|
37
|
+
export interface ActivityFilter {
|
|
38
|
+
readonly afterIndex?: number;
|
|
39
|
+
readonly beforeIndex?: number;
|
|
40
|
+
readonly throughIndex?: number;
|
|
41
|
+
readonly indexes?: readonly ActivityIndex[];
|
|
42
|
+
readonly kinds?: readonly StoredAct['kind'][];
|
|
43
|
+
readonly actors?: readonly string[];
|
|
44
|
+
readonly actorMatch?: 'identity' | 'exact';
|
|
45
|
+
readonly actorRequired?: true;
|
|
46
|
+
readonly afterAt?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface IndexPage {
|
|
49
|
+
readonly edge: 'oldest' | 'newest';
|
|
50
|
+
readonly limit: number;
|
|
51
|
+
}
|
|
52
|
+
export interface FactPage<T> {
|
|
53
|
+
readonly items: readonly T[];
|
|
54
|
+
readonly hasMore: boolean;
|
|
55
|
+
}
|
|
56
|
+
export interface DirectedFilter {
|
|
57
|
+
readonly afterIndex?: number;
|
|
58
|
+
readonly beforeIndex?: number;
|
|
59
|
+
readonly throughIndex?: number;
|
|
60
|
+
readonly unseenOnly?: true;
|
|
61
|
+
readonly senders?: readonly string[];
|
|
62
|
+
readonly attentionOnly?: true;
|
|
63
|
+
}
|
|
64
|
+
export interface DirectedHead {
|
|
65
|
+
readonly index: ActivityIndex;
|
|
66
|
+
readonly at: number;
|
|
67
|
+
readonly actor: string;
|
|
68
|
+
readonly recipient: string;
|
|
69
|
+
readonly route: 'mention' | 'reply' | 'attention' | 'bell';
|
|
70
|
+
}
|
|
71
|
+
export interface LandedRecipient {
|
|
72
|
+
readonly recipient: string;
|
|
73
|
+
readonly route: DirectedHead['route'];
|
|
74
|
+
}
|
|
75
|
+
export interface ReceiptFacts {
|
|
76
|
+
readonly latestAt?: number;
|
|
77
|
+
readonly latestActorActivityIndex?: number;
|
|
78
|
+
}
|
|
79
|
+
export interface ReceiptAssignment {
|
|
80
|
+
readonly owner: string;
|
|
81
|
+
readonly index: ActivityIndex;
|
|
82
|
+
}
|
|
83
|
+
export type JsonValue = null | boolean | number | string | readonly JsonValue[] | {
|
|
84
|
+
readonly [key: string]: JsonValue;
|
|
85
|
+
};
|
|
86
|
+
export interface RouteFact {
|
|
87
|
+
readonly location: string;
|
|
88
|
+
readonly participant: string;
|
|
89
|
+
readonly sessionId: string;
|
|
90
|
+
readonly channel: string;
|
|
91
|
+
readonly kind: WakeRouteKind;
|
|
92
|
+
readonly address: Readonly<Record<string, string>>;
|
|
93
|
+
readonly updatedAt: number;
|
|
94
|
+
readonly epoch?: JsonValue;
|
|
95
|
+
readonly extra: Readonly<Record<string, JsonValue>>;
|
|
96
|
+
}
|
|
97
|
+
/** Domain facts exist only during a synchronous artifact callback. Values are detached. */
|
|
98
|
+
export interface SquareRead {
|
|
99
|
+
header(): SquareHeader;
|
|
100
|
+
participant(requestedName: string): ParticipantFact | undefined;
|
|
101
|
+
roster(): readonly ParticipantFact[];
|
|
102
|
+
attention(listener: string): readonly AttentionFact[];
|
|
103
|
+
incomingAttention(sender: string): readonly AttentionFact[];
|
|
104
|
+
hold(): {
|
|
105
|
+
readonly active: boolean;
|
|
106
|
+
readonly at?: number;
|
|
107
|
+
readonly reason?: string;
|
|
108
|
+
readonly actor?: string;
|
|
109
|
+
};
|
|
110
|
+
activity(index: ActivityIndex): StoredAct | undefined;
|
|
111
|
+
activityHeads(filter: ActivityFilter, page: IndexPage): FactPage<ActivityHead>;
|
|
112
|
+
activities(indexes: readonly ActivityIndex[]): readonly StoredAct[];
|
|
113
|
+
activityCount(filter: ActivityFilter): number;
|
|
114
|
+
contextIndexes(centers: readonly ActivityIndex[], before: number, after: number): readonly ActivityIndex[];
|
|
115
|
+
sayOrdinals(indexes: readonly ActivityIndex[]): Readonly<Record<number, number>>;
|
|
116
|
+
recentSayTimes(afterExclusive: number, takeLatest: number, actor?: string, bellOnly?: true): readonly number[];
|
|
117
|
+
audience(index: ActivityIndex): readonly LandedRecipient[];
|
|
118
|
+
directed(recipient: string, filter: DirectedFilter, page: IndexPage): FactPage<DirectedHead>;
|
|
119
|
+
directedAt(recipient: string, index: ActivityIndex): DirectedHead | undefined;
|
|
120
|
+
directedCount(recipient: string, filter: DirectedFilter): number;
|
|
121
|
+
pendingAudience(afterExclusive: number, throughInclusive: number, activityLimit: number): {
|
|
122
|
+
readonly groups: readonly {
|
|
123
|
+
readonly index: ActivityIndex;
|
|
124
|
+
readonly at: number;
|
|
125
|
+
readonly actor: string;
|
|
126
|
+
readonly recipients: readonly LandedRecipient[];
|
|
127
|
+
}[];
|
|
128
|
+
readonly hasMore: boolean;
|
|
129
|
+
};
|
|
130
|
+
receipt(requestedName: string, index: ActivityIndex): {
|
|
131
|
+
readonly at: number;
|
|
132
|
+
} | undefined;
|
|
133
|
+
receiptFacts(requestedName: string, afterIndex: number): ReceiptFacts;
|
|
134
|
+
receiptAssignments(): readonly ReceiptAssignment[];
|
|
135
|
+
lease(requestedName: string): WatchLease | undefined;
|
|
136
|
+
routes(): readonly RouteFact[];
|
|
137
|
+
}
|
|
138
|
+
export interface SquareWrite extends SquareRead {
|
|
139
|
+
land(activity: Act & {
|
|
140
|
+
readonly at: number;
|
|
141
|
+
}): StoredAct;
|
|
142
|
+
markSeen(requestedName: string, indexes: readonly ActivityIndex[], at: number): number;
|
|
143
|
+
putLease(requestedName: string, lease: WatchLease): boolean;
|
|
144
|
+
removeLease(requestedName: string, expectedLeaseId: string): boolean;
|
|
145
|
+
replaceRoutes(routes: readonly RouteFact[]): boolean;
|
|
146
|
+
}
|
|
147
|
+
export interface SquareReadResult<R> {
|
|
148
|
+
readonly value: R;
|
|
149
|
+
readonly version: number;
|
|
150
|
+
}
|
|
151
|
+
export interface SquareCommitResult<R> extends SquareReadResult<R> {
|
|
152
|
+
readonly changed: boolean;
|
|
153
|
+
}
|
|
154
|
+
/** Atomic artifact access; no framing, SQL or lazy transaction capability escapes. */
|
|
5
155
|
export interface SquareArtifactPort {
|
|
6
|
-
read(signal?: AbortSignal): Promise<
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}>;
|
|
10
|
-
transact<R>(fn: (state: SquareState, version: number) => {
|
|
11
|
-
state?: SquareState;
|
|
12
|
-
result: R;
|
|
13
|
-
}, signal?: AbortSignal): Promise<R>;
|
|
156
|
+
read<R>(select: (facts: SquareRead) => R, signal?: AbortSignal): Promise<SquareReadResult<R>>;
|
|
157
|
+
transact<R>(change: (facts: SquareWrite) => R, signal?: AbortSignal): Promise<SquareCommitResult<R>>;
|
|
158
|
+
revision(signal?: AbortSignal): Promise<number>;
|
|
14
159
|
changed(sinceVersion: number, timeoutMs: number, signal?: AbortSignal): Promise<boolean>;
|
|
15
160
|
close(): Promise<void>;
|
|
16
161
|
}
|
|
@@ -121,5 +266,5 @@ export interface PresentPendingInput {
|
|
|
121
266
|
/** Boundary previews that were clipped remain pending for a later full presentation. */
|
|
122
267
|
readonly markSeen?: boolean;
|
|
123
268
|
/** Receiver-specific fences checked inside the artifact observation transaction. */
|
|
124
|
-
readonly current?: (
|
|
269
|
+
readonly current?: (facts: SquareRead) => boolean;
|
|
125
270
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { PresentationResult, PresentPendingInput } from './ports.js';
|
|
2
|
-
/**
|
|
2
|
+
/** Presentation evidence is not a receipt; only the fenced receipt transaction marks seen. */
|
|
3
3
|
export declare function presentPending(input: PresentPendingInput): Promise<PresentationResult>;
|
|
@@ -1,65 +1,56 @@
|
|
|
1
1
|
import { formatActivityId, parseActivityId } from './square-core.js';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
/** Present one pending activity; artifact seen remains the authoritative receipt. */
|
|
2
|
+
import { pendingHead, sameJoin } from './delivery.js';
|
|
3
|
+
/** Presentation evidence is not a receipt; only the fenced receipt transaction marks seen. */
|
|
5
4
|
export async function presentPending(input) {
|
|
6
5
|
const index = typeof input.activity === 'number' ? input.activity : parseActivityId(input.activity);
|
|
7
6
|
if (index === undefined)
|
|
8
7
|
return { presented: false };
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
catch
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
const delivery = deriveDeliveryModel(before.state);
|
|
17
|
-
const item = before.state.acts.find((activity) => activity.index === index);
|
|
18
|
-
if (input.current?.(before.state) === false || item === undefined || delivery.isSeen(input.participant, index) || !delivery.pendingFor(input.participant).some((notification) => notification.item.index === index))
|
|
8
|
+
const before = await input.artifact.read((facts) => {
|
|
9
|
+
if (input.current?.(facts) === false || !pendingHead(facts, input.participant, index))
|
|
10
|
+
return undefined;
|
|
11
|
+
return { item: facts.activity(index), participant: facts.participant(input.participant) };
|
|
12
|
+
}, input.signal).catch(() => undefined);
|
|
13
|
+
if (before?.value === undefined)
|
|
19
14
|
return { presented: false };
|
|
15
|
+
const { item, participant } = before.value;
|
|
16
|
+
const current = (facts) => sameJoin(facts, participant) && input.current?.(facts) !== false
|
|
17
|
+
&& pendingHead(facts, participant.name, index) !== undefined;
|
|
18
|
+
const coordinate = { location: input.location, participant: input.participant, session: input.session, activity: formatActivityId(index), kind: 'presentation' };
|
|
20
19
|
let claimToken;
|
|
20
|
+
const release = async () => {
|
|
21
|
+
if (claimToken !== undefined)
|
|
22
|
+
await input.hostLedger.releaseEvidence({ ...coordinate, claimToken });
|
|
23
|
+
};
|
|
21
24
|
if (input.hostLedger !== undefined && input.session !== undefined) {
|
|
22
|
-
const claim = await input.hostLedger.claimEvidence({
|
|
25
|
+
const claim = await input.hostLedger.claimEvidence({ ...coordinate, leaseMs: input.timeoutMs ?? 5000 });
|
|
23
26
|
if (claim.status !== 'acquired')
|
|
24
27
|
return { presented: false };
|
|
25
28
|
claimToken = claim.claimToken;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
catch {
|
|
31
|
-
await input.hostLedger.releaseEvidence({ location: input.location, participant: input.participant, session: input.session, activity: formatActivityId(index), kind: 'presentation', claimToken }).catch(() => undefined);
|
|
32
|
-
return { presented: false };
|
|
33
|
-
}
|
|
34
|
-
if (input.current?.(current.state) === false || deriveDeliveryModel(current.state).isSeen(input.participant, index)) {
|
|
35
|
-
await input.hostLedger.releaseEvidence({ location: input.location, participant: input.participant, session: input.session, activity: formatActivityId(index), kind: 'presentation', claimToken }).catch(() => undefined);
|
|
29
|
+
const fresh = await input.artifact.read(current, input.signal).catch(() => undefined);
|
|
30
|
+
if (!fresh?.value) {
|
|
31
|
+
await release().catch(() => undefined);
|
|
36
32
|
return { presented: false };
|
|
37
33
|
}
|
|
38
|
-
try {
|
|
39
|
-
await input.sink.present(item);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
await input.hostLedger.appendEvidence({ location: input.location, participant: input.participant, session: input.session, activity: formatActivityId(index), kind: 'presentation', outcome: 'failed', message: error instanceof Error ? error.message : String(error), claimToken });
|
|
43
|
-
throw error;
|
|
44
|
-
}
|
|
45
34
|
}
|
|
46
|
-
|
|
35
|
+
try {
|
|
47
36
|
await input.sink.present(item);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (claimToken !== undefined)
|
|
40
|
+
await input.hostLedger.appendEvidence({ ...coordinate, outcome: 'failed', message: error instanceof Error ? error.message : String(error), claimToken });
|
|
41
|
+
throw error;
|
|
42
|
+
}
|
|
43
|
+
const { value: committed } = await input.artifact.transact((facts) => {
|
|
44
|
+
if (!current(facts))
|
|
45
|
+
return false;
|
|
46
|
+
return input.markSeen === false || facts.markSeen(participant.name, [index], input.now ?? Date.now()) > 0;
|
|
56
47
|
}, input.signal);
|
|
57
48
|
if (!committed) {
|
|
58
|
-
|
|
59
|
-
await input.hostLedger.releaseEvidence({ location: input.location, participant: input.participant, session: input.session, activity: formatActivityId(index), kind: 'presentation', claimToken });
|
|
49
|
+
await release();
|
|
60
50
|
return { presented: false };
|
|
61
51
|
}
|
|
62
|
-
if (
|
|
63
|
-
await input.hostLedger.appendEvidence({
|
|
52
|
+
if (claimToken !== undefined)
|
|
53
|
+
await input.hostLedger.appendEvidence({ ...coordinate, outcome: input.markSeen === false ? 'clipped' : 'presented',
|
|
54
|
+
...(input.markSeen === false ? { message: 'presentation clipped' } : {}), claimToken });
|
|
64
55
|
return { presented: true, activity: item };
|
|
65
56
|
}
|
package/dist/presentation.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type StoredAct, type
|
|
1
|
+
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
|
-
import type { UnreadActivitySummary,
|
|
4
|
+
import type { Activity, UnreadActivitySummary, ParticipantSummary } from './square-facade.js';
|
|
5
5
|
export type WatchStatus = 'stale' | 'empty-now' | 'quorum' | 'capped';
|
|
6
6
|
interface HeaderOptions {
|
|
7
7
|
participantCount?: number;
|
|
@@ -23,7 +23,7 @@ interface ActivityLimitOptions extends ParticipantOutputOptions {
|
|
|
23
23
|
interface ActivityBlockedOptions extends ParticipantOutputOptions {
|
|
24
24
|
retryCommand: string;
|
|
25
25
|
forceCommand: string;
|
|
26
|
-
activitySummaries: UnreadActivitySummary[];
|
|
26
|
+
activitySummaries: readonly UnreadActivitySummary[];
|
|
27
27
|
draftPath?: string;
|
|
28
28
|
}
|
|
29
29
|
interface ExpressWaitingOptions {
|
|
@@ -44,7 +44,7 @@ interface WatchStatusOptions extends ParticipantOutputOptions {
|
|
|
44
44
|
status: WatchStatus;
|
|
45
45
|
idleMs?: number;
|
|
46
46
|
presence?: {
|
|
47
|
-
participants:
|
|
47
|
+
participants: readonly ParticipantSummary[];
|
|
48
48
|
now: number;
|
|
49
49
|
};
|
|
50
50
|
showCatchHint?: boolean;
|
|
@@ -58,6 +58,7 @@ export declare function formatRefusal(squarePath: string, bodyLines: string[], o
|
|
|
58
58
|
participantCount?: number;
|
|
59
59
|
held?: boolean;
|
|
60
60
|
}): string;
|
|
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
64
|
export declare function participantCommandPrefix(squarePath: string, name: string): string;
|
|
@@ -66,44 +67,42 @@ export declare function joinRecoveryCommand(squarePath: string, name: string): s
|
|
|
66
67
|
/** Taking a name is an explicit recovery choice, never an automatic retry. */
|
|
67
68
|
export declare function takeoverRecoveryLines(squarePath: string, name: string): string[];
|
|
68
69
|
export declare function participantsRecoveryCommand(squarePath: string): string;
|
|
69
|
-
export declare function renderPresenceLines(
|
|
70
|
+
export declare function renderPresenceLines(recent: readonly ParticipantSummary[], now: number, limit?: number): string[];
|
|
70
71
|
export declare function expressHintLine(ownActivityCount: number): string | undefined;
|
|
71
72
|
export declare function truncateChars(body: string, maxChars: number): {
|
|
72
73
|
text: string;
|
|
73
74
|
remaining: number;
|
|
74
75
|
};
|
|
75
76
|
export declare function truncateExternalDiagnostic(diagnostic: string): string;
|
|
76
|
-
export declare function renderRoomChangeText(event: RoomChangeAct): string;
|
|
77
|
+
export declare function renderRoomChangeText(event: RoomChangeAct | Activity): string;
|
|
77
78
|
interface RenderedEvent {
|
|
78
79
|
text: string;
|
|
79
80
|
/** The rendered body was cut short by `preview`. */
|
|
80
81
|
bodyClipped: boolean;
|
|
81
82
|
}
|
|
82
|
-
export declare function renderEventCli(event: StoredAct, opts?: {
|
|
83
|
+
export declare function renderEventCli(event: StoredAct | Activity, opts?: {
|
|
83
84
|
now?: number;
|
|
84
85
|
preview?: number;
|
|
85
86
|
actNumber?: number;
|
|
86
87
|
mention?: string;
|
|
87
88
|
}): string;
|
|
88
|
-
export declare function renderAmbientEventFacts(event: StoredAct, viewer: string, opts?: {
|
|
89
|
+
export declare function renderAmbientEventFacts(event: StoredAct | Activity, viewer: string, opts?: {
|
|
89
90
|
now?: number;
|
|
90
91
|
preview?: number;
|
|
91
92
|
presencePreview?: number;
|
|
92
93
|
actNumber?: number;
|
|
93
94
|
mention?: string;
|
|
94
|
-
squareState?: SquareState;
|
|
95
95
|
perception?: Perception;
|
|
96
96
|
}): RenderedEvent;
|
|
97
|
-
export declare function renderAmbientEvent(event: StoredAct, viewer: string, opts?: {
|
|
97
|
+
export declare function renderAmbientEvent(event: StoredAct | Activity, viewer: string, opts?: {
|
|
98
98
|
now?: number;
|
|
99
99
|
preview?: number;
|
|
100
100
|
presencePreview?: number;
|
|
101
101
|
actNumber?: number;
|
|
102
102
|
mention?: string;
|
|
103
|
-
squareState?: SquareState;
|
|
104
103
|
perception?: Perception;
|
|
105
104
|
}): string;
|
|
106
|
-
export declare function renderPendingFeed(
|
|
105
|
+
export declare function renderPendingFeed(publicItems: readonly StoredAct[], sayNumbers: Readonly<Record<number, number>>, perceptions: Readonly<Record<number, Perception>>, viewer: string): string;
|
|
107
106
|
export declare function renderActivityBlocked(opts: ActivityBlockedOptions): string;
|
|
108
107
|
/** An indeterminate or already-committed send only points to inspection, never resend. */
|
|
109
108
|
export declare function renderActivityUncertain(opts: ParticipantOutputOptions & {
|
|
@@ -114,7 +113,7 @@ export declare function renderActivityUncertain(opts: ParticipantOutputOptions &
|
|
|
114
113
|
export declare function renderExpressWaiting(opts: ExpressWaitingOptions): string;
|
|
115
114
|
export declare function renderExpressNoWait(opts: ExpressNoWaitOptions): string;
|
|
116
115
|
export declare function renderPresenceAnchor(names: readonly string[]): string;
|
|
117
|
-
export declare function renderGrepActivitiesView(visible: StoredAct[], totalMatches: number, noTruncate: boolean | undefined, squarePath: string, pattern: string, fixed?: boolean, perception?: (act: StoredAct) => Perception): string;
|
|
116
|
+
export declare function renderGrepActivitiesView(visible: readonly StoredAct[], totalMatches: number, noTruncate: boolean | undefined, squarePath: string, pattern: string, fixed?: boolean, perception?: (act: StoredAct) => Perception): string;
|
|
118
117
|
export declare function renderActivityLimit(opts: ActivityLimitOptions): string;
|
|
119
118
|
export declare function renderWatchAlreadyActive(opts: ParticipantOutputOptions): string;
|
|
120
119
|
export declare function renderWatchForceTakeover(_opts: ParticipantOutputOptions): string;
|
|
@@ -123,9 +122,3 @@ export declare function renderWatchReplaced(_opts: ParticipantOutputOptions): st
|
|
|
123
122
|
export declare function renderWatchStatus(opts: WatchStatusOptions): string;
|
|
124
123
|
export declare function renderDoctorClean(): string;
|
|
125
124
|
export declare function renderDoctorUnfixable(reason: string): string;
|
|
126
|
-
export declare function renderWatchOutput(history: StoredAct[], publicItems: PublicAct[], opts: {
|
|
127
|
-
mention?: string;
|
|
128
|
-
viewer: string;
|
|
129
|
-
squareState?: SquareState;
|
|
130
|
-
perceptions?: ReadonlyMap<number, Perception>;
|
|
131
|
-
}): string;
|