@astrosheep/square 0.3.12 → 0.3.13
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/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/codex-plugin/hooks/hooks.json +9 -0
- package/dist/activity-feed.d.ts +14 -0
- package/dist/activity-feed.js +5 -5
- package/dist/activity.d.ts +9 -0
- package/dist/activity.js +111 -90
- package/dist/artifact.d.ts +20 -0
- package/dist/artifact.js +10 -29
- package/dist/automatic-session.d.ts +5 -0
- package/dist/automatic-session.js +86 -0
- package/dist/boundary-presentation.d.ts +5 -0
- package/dist/boundary-presentation.js +5 -4
- package/dist/claude-hook.d.ts +9 -0
- package/dist/claude-hook.js +35 -3
- package/dist/cli/context.d.ts +35 -0
- package/dist/cli/context.js +25 -30
- package/dist/cli/harness-command.d.ts +28 -0
- package/dist/cli/harness-command.js +29 -14
- package/dist/cli/maintenance-commands.d.ts +7 -0
- package/dist/cli/maintenance-commands.js +3 -3
- package/dist/cli/meta-commands.d.ts +5 -0
- package/dist/cli/observation-commands.d.ts +20 -0
- package/dist/cli/observation-commands.js +155 -128
- package/dist/cli/program.d.ts +2 -0
- package/dist/cli/program.js +2 -12
- package/dist/cli/registry.d.ts +9 -0
- package/dist/cli/registry.js +1 -2
- package/dist/cli/square-commands.d.ts +34 -0
- package/dist/cli/square-commands.js +81 -74
- package/dist/cmd/notify-once.d.ts +2 -0
- package/dist/codex-hook.d.ts +10 -0
- package/dist/codex-hook.js +35 -3
- package/dist/decisions.d.ts +92 -0
- package/dist/decisions.js +83 -77
- package/dist/delivery-health.d.ts +21 -0
- package/dist/delivery-health.js +40 -34
- package/dist/delivery.d.ts +81 -0
- package/dist/delivery.js +60 -22
- package/dist/file-lock.d.ts +6 -0
- package/dist/harness-claude.d.ts +19 -0
- package/dist/harness-claude.js +8 -3
- package/dist/harness-codex.d.ts +29 -0
- package/dist/harness-codex.js +2 -2
- package/dist/harness-links.d.ts +17 -0
- package/dist/harness-links.js +2 -2
- package/dist/harness-pi.d.ts +11 -0
- package/dist/harness-pi.js +2 -2
- package/dist/harness-stage.d.ts +6 -0
- package/dist/harness.d.ts +20 -0
- package/dist/harness.js +5 -3
- package/dist/help.d.ts +6 -0
- package/dist/help.js +6 -5
- package/dist/identity.d.ts +13 -0
- package/dist/inbox.d.ts +2 -0
- package/dist/inbox.js +15 -19
- package/dist/index.d.ts +13 -0
- package/dist/index.js +31 -69
- package/dist/landing.d.ts +10 -0
- package/dist/landing.js +95 -0
- package/dist/list.d.ts +1 -0
- package/dist/list.js +40 -18
- package/dist/model.d.ts +147 -0
- package/dist/model.js +12 -2
- package/dist/notifications.d.ts +30 -0
- package/dist/notifications.js +75 -91
- package/dist/open-square.d.ts +11 -0
- package/dist/open-square.js +4 -0
- package/dist/participant-identity.d.ts +1 -0
- package/dist/participant-identity.js +3 -0
- package/dist/paseo-connection.d.ts +15 -0
- package/dist/paseo-delivery.d.ts +14 -0
- package/dist/paseo-state.d.ts +11 -0
- package/dist/paseo-timeline.d.ts +16 -0
- package/dist/presence.d.ts +3 -0
- package/dist/presence.js +42 -0
- package/dist/presentation.d.ts +91 -0
- package/dist/presentation.js +33 -29
- package/dist/presented.d.ts +11 -0
- package/dist/registry.d.ts +58 -0
- package/dist/registry.js +36 -3
- package/dist/routes.d.ts +42 -0
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.js +42 -34
- package/dist/search.d.ts +11 -0
- package/dist/square-core.d.ts +111 -0
- package/dist/square-core.js +7 -0
- package/dist/square-facade.d.ts +86 -0
- package/dist/square-facade.js +1 -0
- package/dist/square-file-adapter.d.ts +18 -0
- package/dist/square-file-adapter.js +70 -0
- package/dist/square-storage.d.ts +20 -0
- package/dist/square-storage.js +171 -0
- package/dist/square-wiring.d.ts +19 -0
- package/dist/square-wiring.js +70 -0
- package/dist/square.d.ts +2 -0
- package/dist/state-cell.d.ts +14 -0
- package/dist/state-cell.js +1 -0
- package/dist/stream.d.ts +3 -0
- package/dist/stream.js +19 -23
- package/dist/time.d.ts +6 -0
- package/dist/views.d.ts +95 -0
- package/dist/views.js +81 -0
- package/dist/wake-attempts.d.ts +39 -0
- package/dist/wake-evidence.d.ts +12 -0
- package/dist/wake-evidence.js +7 -10
- package/dist/wake-port.d.ts +20 -0
- package/dist/wake-sink.d.ts +12 -0
- package/dist/wakes.d.ts +40 -0
- package/dist/wakes.js +62 -0
- package/dist/watch.d.ts +2 -0
- package/dist/watch.js +89 -210
- package/extensions/square-opencode.js +27 -1
- package/extensions/square-pi.js +13 -0
- package/package.json +5 -2
- package/skills/brainstorm/SKILL.md +26 -26
- package/skills/square/.claude-plugin/plugin.json +1 -1
- package/skills/square/SKILL.md +47 -29
- package/skills/square/hooks/hooks.json +9 -0
- package/skills/square-feedback/SKILL.md +2 -2
- package/dist/compact.js +0 -26
- package/dist/square-application.js +0 -193
package/dist/views.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { extractMentions, formatActivityId, parseActivityId, perceive } from './square-core.js';
|
|
2
|
+
import { deliveryDelta, peerPublicActs, peerRoomChanges } from './activity-feed.js';
|
|
3
|
+
import { coreActivities, coreParticipants, coreStatus, resolveKnownName } from './decisions.js';
|
|
4
|
+
import { deriveDeliveryModel, isDeliveryDelivered, planActNotifications } from './delivery.js';
|
|
5
|
+
import { SquareError, nameKey } from './model.js';
|
|
6
|
+
import { countSays, currentHold, foldedState, freshWatchLease, inSquareCount, isCurrentlyJoined, readCursor, resolveRosterName, rosterNames, watchTerminalStatus } from './runtime.js';
|
|
7
|
+
function expose(stored) {
|
|
8
|
+
if (stored.kind === 'read' || stored.actor === undefined)
|
|
9
|
+
throw new Error(`Cannot expose stored activity ${formatActivityId(stored.index)}`);
|
|
10
|
+
return { id: formatActivityId(stored.index), at: stored.at, kind: stored.kind, actor: stored.actor, ...('body' in stored && stored.body !== undefined ? { body: stored.body } : {}), mentions: stored.kind === 'say' ? extractMentions(stored.body) : [], ...(stored.kind === 'say' && stored.reply !== undefined ? { reply: formatActivityId(stored.reply) } : {}) };
|
|
11
|
+
}
|
|
12
|
+
function exposePerceived(stored, viewer) {
|
|
13
|
+
const perception = perceive(stored, viewer);
|
|
14
|
+
const activity = expose(stored);
|
|
15
|
+
if (perception === 'full' || activity.body === undefined)
|
|
16
|
+
return { ...activity, perception };
|
|
17
|
+
const { body: _body, ...withoutBody } = activity;
|
|
18
|
+
return { ...withoutBody, perception };
|
|
19
|
+
}
|
|
20
|
+
function parseRequiredActivityId(id) {
|
|
21
|
+
const index = parseActivityId(id);
|
|
22
|
+
if (index === undefined)
|
|
23
|
+
throw new SquareError('invalid_args', `Invalid activity id: ${id}`);
|
|
24
|
+
return index;
|
|
25
|
+
}
|
|
26
|
+
function historyOptions(query, viewer) {
|
|
27
|
+
return { ...(query.from === undefined ? {} : { participants: [...query.from] }), ...(query.grep === undefined ? {} : { grep: query.grep }), ...(query.mention === true && viewer !== undefined ? { mention: viewer } : {}), order: 'asc' };
|
|
28
|
+
}
|
|
29
|
+
function selectHistory(stored, query) {
|
|
30
|
+
let selected = stored.filter((activity) => activity.kind !== 'read');
|
|
31
|
+
if (query.all !== true && query.limit !== undefined) {
|
|
32
|
+
if (!Number.isSafeInteger(query.limit) || query.limit < 1)
|
|
33
|
+
throw new SquareError('invalid_args', 'History limit must be a positive integer');
|
|
34
|
+
selected = selected.slice(-query.limit);
|
|
35
|
+
}
|
|
36
|
+
return query.order === 'desc' ? selected.reverse() : selected;
|
|
37
|
+
}
|
|
38
|
+
function statuses(square, state) {
|
|
39
|
+
return coreStatus(state, square.clock()).participants.filter((participant) => participant.state !== 'not joined').map((participant) => ({ name: participant.name, state: participant.state === 'done' ? 'done' : 'joined', consumedThrough: readCursor(state, participant.name) < 0 ? null : formatActivityId(readCursor(state, participant.name)), watching: participant.presence === 'watching' }));
|
|
40
|
+
}
|
|
41
|
+
function anchors(state) {
|
|
42
|
+
const result = {};
|
|
43
|
+
for (const name of rosterNames(state)) {
|
|
44
|
+
const activity = state.acts.findLast((candidate) => candidate.index <= readCursor(state, name) && (candidate.kind === 'say' || candidate.kind === 'done'));
|
|
45
|
+
if (activity !== undefined)
|
|
46
|
+
result[activity.index] = [...(result[activity.index] ?? []), name];
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function sayNumbers(state) {
|
|
51
|
+
const counts = new Map();
|
|
52
|
+
const result = {};
|
|
53
|
+
for (const activity of state.acts)
|
|
54
|
+
if (activity.kind === 'say') {
|
|
55
|
+
const next = (counts.get(nameKey(activity.actor)) ?? 0) + 1;
|
|
56
|
+
counts.set(nameKey(activity.actor), next);
|
|
57
|
+
result[activity.index] = next;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
export async function history(square, query = {}) { const { state } = await square.cell.read(); return selectHistory(coreActivities(state, historyOptions(query)), query).map(expose); }
|
|
62
|
+
export async function participantHistory(square, name, query = {}) { const { state } = await square.cell.read(); const viewer = resolveKnownName(state, name); const effective = query.all === true || query.limit !== undefined ? query : { ...query, limit: 10 }; return selectHistory(coreActivities(state, historyOptions(effective, viewer)), effective).map((activity) => exposePerceived(activity, viewer)); }
|
|
63
|
+
export async function resolveParticipant(square, name) { const { state } = await square.cell.read(); return { name: resolveKnownName(state, name), roster: rosterNames(state) }; }
|
|
64
|
+
export async function participants(square) { const { state } = await square.cell.read(); return statuses(square, state); }
|
|
65
|
+
export async function snapshot(square) { const { state } = await square.cell.read(); const folded = foldedState(state); return { context: [...state.preamble, ...state.warmup].join('\n'), actCount: state.acts.filter((activity) => activity.kind !== 'read').length, hardCap: state.hardCap, ...(state.throttlePerMinute === undefined ? {} : { throttlePerMinute: state.throttlePerMinute }), held: folded.hold.active && folded.hold.actor !== undefined ? { by: folded.hold.actor, ...(folded.hold.reason === undefined ? {} : { reason: folded.hold.reason }) } : null, participants: statuses(square, state), delivered(name, id) { return isDeliveryDelivered(state, name, parseRequiredActivityId(id)); } }; }
|
|
66
|
+
export async function activityPresentation(square, name) { const { state } = await square.cell.read(); const known = resolveKnownName(state, name); const delta = deliveryDelta(state, known); const hold = currentHold(state.acts); return { name: known, roster: rosterNames(state), pendingPublic: peerPublicActs(delta, known), pendingRoomChanges: peerRoomChanges(delta, known), activities: state.acts, participantCount: inSquareCount(state), held: hold.active, ...(hold.reason === undefined ? {} : { holdReason: hold.reason }), ownActivityCount: countSays(state.acts, known), hardCap: state.hardCap }; }
|
|
67
|
+
export async function entryPresentation(square, name, lastN = 10) { const { state } = await square.cell.read(); const known = resolveRosterName(state, name) ?? name; const publicActivities = state.acts.filter((activity) => activity.kind === 'say' || activity.kind === 'done'); return { joined: isCurrentlyJoined(state.acts, known), scene: state.warmup.join('\n').trim(), context: state.preamble.join('\n').trim(), joinContext: (state.preamble.at(-1) === '---' ? state.preamble.slice(0, -1) : state.preamble).join('\n').trim(), recentActivities: lastN === null ? publicActivities : publicActivities.slice(-lastN), sayNumbers: sayNumbers(state), participantCount: inSquareCount(state) }; }
|
|
68
|
+
export async function historyPresentation(square, options) { const { state } = await square.cell.read(); return { activities: coreActivities(state, options).map((activity) => ({ ...activity, perception: options.viewer === undefined ? 'full' : perceive(activity, options.viewer) })), sayNumbers: sayNumbers(state), presenceAnchors: anchors(state), participantCount: inSquareCount(state) }; }
|
|
69
|
+
export async function participantsPresentation(square) { const { state } = await square.cell.read(); return coreParticipants(state, square.clock()); }
|
|
70
|
+
export async function listPresentation(square) { const { state } = await square.cell.read(); return { context: state.preamble, participants: foldedState(state).participants.filter((participant) => participant.joined).sort((left, right) => (right.lastActiveAt ?? -Infinity) - (left.lastActiveAt ?? -Infinity) || left.name.localeCompare(right.name)).map((participant) => participant.name), activities: state.acts.filter((activity) => activity.kind === 'say').length }; }
|
|
71
|
+
export async function statusPresentation(square) { const { state } = await square.cell.read(); const status = coreStatus(state, square.clock()); return { status, ...(status.latestAct?.kind === 'say' ? { latestActNumber: countSays(state.acts, status.latestAct.actor) } : {}) }; }
|
|
72
|
+
export async function eventPresentation(square, id) { const { state } = await square.cell.read(); const activity = state.acts.find((candidate) => candidate.index === parseRequiredActivityId(id)); if (activity === undefined)
|
|
73
|
+
throw new SquareError('invalid_args', `Unknown activity id: ${id}`); return { activity, participantCount: inSquareCount(state), held: currentHold(state.acts).active }; }
|
|
74
|
+
export async function watchPresentation(square, name) { const { state } = await square.cell.read(); const known = resolveKnownName(state, name); const now = square.clock(); const terminal = watchTerminalStatus(state, known); return { activities: state.acts, participantCount: inSquareCount(state), presence: { participants: coreParticipants(state, now), now }, ...(terminal === undefined ? {} : { terminalStatus: terminal }) }; }
|
|
75
|
+
export async function inboxProjection(square, name, ownerId) { const { state } = await square.cell.read(); const known = resolveRosterName(state, name); if (known === undefined || !isCurrentlyJoined(state.acts, known))
|
|
76
|
+
return { name, joined: false, notifications: [] }; const lease = freshWatchLease(state, known, square.clock()); return { name: known, joined: true, notifications: deriveDeliveryModel(state).pendingFor(known).map(({ item, route }) => ({ actIndex: item.index, actor: item.actor, at: item.at, route, body: item.body })), ...(lease?.ownerId === ownerId ? { catchLease: lease } : {}) }; }
|
|
77
|
+
export async function streamProjection(square, cursor, recipient) { const { state } = await square.cell.read(); return { activities: state.acts.filter((activity) => activity.index > cursor).flatMap((activity) => { if (recipient === undefined)
|
|
78
|
+
return [{ activity }]; const notification = planActNotifications(state, activity).find((candidate) => nameKey(candidate.recipient) === nameKey(recipient)); return notification === undefined ? [] : [{ activity, route: notification.route }]; }), cursor: Math.max(cursor, ...state.acts.map((activity) => activity.index)) }; }
|
|
79
|
+
export async function notificationForAct(square, actIndex) { const { state } = await square.cell.read(); const activity = state.acts.find((candidate) => candidate.index === actIndex); return activity === undefined ? [] : planActNotifications(state, activity); }
|
|
80
|
+
export async function pendingDeliveries(square) { const { state } = await square.cell.read(); return [...new Set(state.acts.filter((activity) => activity.kind === 'join').map((activity) => activity.actor))].filter((name) => isCurrentlyJoined(state.acts, name)).map((recipient) => ({ recipient, notifications: deriveDeliveryModel(state).pendingFor(recipient) })); }
|
|
81
|
+
export async function notificationDelivered(square, recipient, actIndex) { const { state } = await square.cell.read(); return isDeliveryDelivered(state, recipient, actIndex); }
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type NotifyLease, type WakeRoute, type WakeRouteKind } from './model.js';
|
|
2
|
+
export type WakeOutcome = 'accepted' | 'unknown' | 'failed';
|
|
3
|
+
export interface WakeAttention {
|
|
4
|
+
squarePath: string;
|
|
5
|
+
actIndex: number;
|
|
6
|
+
recipient: string;
|
|
7
|
+
}
|
|
8
|
+
export interface WakeAttempt {
|
|
9
|
+
at: number;
|
|
10
|
+
attention: WakeAttention;
|
|
11
|
+
routeKind: WakeRouteKind;
|
|
12
|
+
outcome: WakeOutcome;
|
|
13
|
+
signature?: string;
|
|
14
|
+
attemptN: number;
|
|
15
|
+
message?: string;
|
|
16
|
+
diagnostic?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export declare function wakeAttemptsPath(env?: NodeJS.ProcessEnv): string;
|
|
19
|
+
export declare function wakeAttentionKey(attention: WakeAttention): string;
|
|
20
|
+
export declare function readWakeAttempts(opts?: {
|
|
21
|
+
attention?: WakeAttention;
|
|
22
|
+
now?: number;
|
|
23
|
+
env?: NodeJS.ProcessEnv;
|
|
24
|
+
}): WakeAttempt[];
|
|
25
|
+
export declare function terminalWakeEvidence(attempts: readonly WakeAttempt[]): WakeAttempt | undefined;
|
|
26
|
+
export declare function terminalWakeAttempt(attention: WakeAttention, opts?: {
|
|
27
|
+
now?: number;
|
|
28
|
+
env?: NodeJS.ProcessEnv;
|
|
29
|
+
}): WakeAttempt | undefined;
|
|
30
|
+
export declare function isWakeRouteAttemptable(route: Pick<WakeRoute, 'kind' | 'updatedAt'>, attempts: readonly WakeAttempt[]): boolean;
|
|
31
|
+
export declare function hasAttemptableWakeRoute(routes: readonly Pick<WakeRoute, 'kind' | 'updatedAt'>[], attempts: readonly WakeAttempt[]): boolean;
|
|
32
|
+
export declare function nextWakeAttemptNumber(attention: WakeAttention, opts?: {
|
|
33
|
+
now?: number;
|
|
34
|
+
env?: NodeJS.ProcessEnv;
|
|
35
|
+
}): number;
|
|
36
|
+
export declare function recordWakeAttempt(attempt: Omit<WakeAttempt, 'at'> & {
|
|
37
|
+
at?: number;
|
|
38
|
+
}, env?: NodeJS.ProcessEnv): WakeAttempt;
|
|
39
|
+
export declare function recordRecoveredUnknown(attention: WakeAttention, lease: Pick<NotifyLease, 'attemptN' | 'routeKind'>, env?: NodeJS.ProcessEnv, at?: number): WakeAttempt | undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type WakeRoute } from './model.js';
|
|
2
|
+
import { type WakeAttempt } from './wake-attempts.js';
|
|
3
|
+
export interface WakeEvidence {
|
|
4
|
+
delivered: boolean;
|
|
5
|
+
presented: boolean;
|
|
6
|
+
attempts: WakeAttempt[];
|
|
7
|
+
terminal?: WakeAttempt;
|
|
8
|
+
attemptableRoutes: WakeRoute[];
|
|
9
|
+
}
|
|
10
|
+
/** Project every wake decision from the same primary evidence. */
|
|
11
|
+
export declare function wakeEvidence(squarePath: string, recipient: string, actIndex: number, now: number, env: NodeJS.ProcessEnv): Promise<WakeEvidence>;
|
|
12
|
+
export declare function wakeIsEligible(evidence: WakeEvidence): boolean;
|
package/dist/wake-evidence.js
CHANGED
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import { loadSquare } from './artifact.js';
|
|
2
|
-
import { isDeliveryDelivered } from './delivery.js';
|
|
3
1
|
import { hasPresentedAttention } from './presented.js';
|
|
4
2
|
import { lookupParticipant } from './registry.js';
|
|
5
|
-
import { isCurrentlyJoined } from './runtime.js';
|
|
6
3
|
import { readWakeRoutes } from './routes.js';
|
|
7
4
|
import { isWakeRouteAttemptable, readWakeAttempts, terminalWakeEvidence, } from './wake-attempts.js';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
5
|
+
import { openSquare } from './square-file-adapter.js';
|
|
6
|
+
import { closeOpenSquare } from './open-square.js';
|
|
7
|
+
import { notificationDelivered } from './views.js';
|
|
12
8
|
/** Project every wake decision from the same primary evidence. */
|
|
13
|
-
export function wakeEvidence(squarePath, recipient, actIndex, now, env) {
|
|
14
|
-
const
|
|
9
|
+
export async function wakeEvidence(squarePath, recipient, actIndex, now, env) {
|
|
10
|
+
const square = await openSquare(squarePath, { clock: () => now });
|
|
11
|
+
const delivered = await notificationDelivered(square, recipient, actIndex).finally(() => closeOpenSquare(square));
|
|
15
12
|
const owners = new Set(lookupParticipant(squarePath, recipient, now).map((binding) => binding.ownerId));
|
|
16
13
|
const attempts = readWakeAttempts({ attention: { squarePath, recipient, actIndex }, env, now });
|
|
17
14
|
const terminal = terminalWakeEvidence(attempts);
|
|
18
15
|
const routes = readWakeRoutes({ freshOnly: true, now, env })
|
|
19
16
|
.filter((route) => owners.has(route.ownerId));
|
|
20
17
|
return {
|
|
21
|
-
delivered
|
|
18
|
+
delivered,
|
|
22
19
|
presented: hasPresentedAttention(squarePath, recipient, actIndex, env, now),
|
|
23
20
|
attempts,
|
|
24
21
|
...(terminal === undefined ? {} : { terminal }),
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WakeAdapter, WakeDispatchResult } from './delivery.js';
|
|
2
|
+
import type { WakeRoute } from './model.js';
|
|
3
|
+
export interface WakePortHooks {
|
|
4
|
+
nextAttemptN(): number;
|
|
5
|
+
beforeSend(route: WakeRoute, attemptN: number): Promise<boolean>;
|
|
6
|
+
record(route: WakeRoute, attemptN: number, result: Exclude<WakeDispatchResult, {
|
|
7
|
+
outcome: 'cancelled';
|
|
8
|
+
}>): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export type WakePortResult = {
|
|
11
|
+
outcome: 'accepted' | 'unknown' | 'cancelled';
|
|
12
|
+
} | {
|
|
13
|
+
outcome: 'exhausted';
|
|
14
|
+
};
|
|
15
|
+
/** Select routes globally; adapters own only transport-specific live proof and dispatch. */
|
|
16
|
+
export declare class WakePort {
|
|
17
|
+
private readonly adapters;
|
|
18
|
+
constructor(adapters: WakeAdapter[]);
|
|
19
|
+
dispatch(routes: readonly WakeRoute[], payload: string, hooks: WakePortHooks): Promise<WakePortResult>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface PaseoWakeRequest {
|
|
2
|
+
agentId: string;
|
|
3
|
+
prompt: string;
|
|
4
|
+
}
|
|
5
|
+
export type PaseoWakeFailureKind = 'transient' | 'rejected' | 'unknown';
|
|
6
|
+
export declare class PaseoWakeSendError extends Error {
|
|
7
|
+
readonly kind: PaseoWakeFailureKind;
|
|
8
|
+
constructor(message: string, kind: PaseoWakeFailureKind);
|
|
9
|
+
}
|
|
10
|
+
export declare function sendPaseoWake({ agentId, prompt }: PaseoWakeRequest, opts?: {
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
}): void;
|
package/dist/wakes.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type NotifyLease, type WakeRouteKind, type WatchLease, type WatchOptions } from './model.js';
|
|
2
|
+
import type { OpenSquare } from './open-square.js';
|
|
3
|
+
export type WatchLeaseStart = {
|
|
4
|
+
readonly type: 'started';
|
|
5
|
+
readonly leaseId: string;
|
|
6
|
+
readonly replaced: boolean;
|
|
7
|
+
readonly heartbeatAt: number;
|
|
8
|
+
} | {
|
|
9
|
+
readonly type: 'active';
|
|
10
|
+
readonly lease: WatchLease;
|
|
11
|
+
};
|
|
12
|
+
export type WatchLeasePulse = {
|
|
13
|
+
readonly type: 'replaced';
|
|
14
|
+
} | {
|
|
15
|
+
readonly type: 'held';
|
|
16
|
+
} | {
|
|
17
|
+
readonly type: 'terminal';
|
|
18
|
+
readonly status: 'capped' | 'quorum';
|
|
19
|
+
} | {
|
|
20
|
+
readonly type: 'sleep';
|
|
21
|
+
readonly heartbeatAt?: number;
|
|
22
|
+
};
|
|
23
|
+
export type NotifyLeaseClaim = {
|
|
24
|
+
readonly type: 'delivered';
|
|
25
|
+
} | {
|
|
26
|
+
readonly type: 'busy';
|
|
27
|
+
} | {
|
|
28
|
+
readonly type: 'ambiguous';
|
|
29
|
+
readonly lease: NotifyLease;
|
|
30
|
+
} | {
|
|
31
|
+
readonly type: 'acquired';
|
|
32
|
+
readonly leaseId: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function acquireWatchLease(square: OpenSquare, name: string, leaseId: string, options: WatchOptions, ownerId?: string): Promise<WatchLeaseStart>;
|
|
35
|
+
export declare function pulseWatchLease(square: OpenSquare, name: string, leaseId: string, options: WatchOptions, heartbeatDue: boolean): Promise<WatchLeasePulse>;
|
|
36
|
+
export declare function releaseWatchLease(square: OpenSquare, name: string, leaseId: string | undefined): Promise<void>;
|
|
37
|
+
export declare function ownsWatchLease(square: OpenSquare, name: string, leaseId: string): Promise<boolean>;
|
|
38
|
+
export declare function claimNotificationLease(square: OpenSquare, recipient: string, actIndex: number, leaseId: string, leaseMs: number): Promise<NotifyLeaseClaim>;
|
|
39
|
+
export declare function transitionNotificationLease(square: OpenSquare, recipient: string, actIndex: number, leaseId: string, phase: NotifyLease['phase'], leaseMs: number, routeKind?: WakeRouteKind, attemptN?: number): Promise<boolean>;
|
|
40
|
+
export declare function releaseNotificationLease(square: OpenSquare, recipient: string, actIndex: number, leaseId: string): Promise<void>;
|
package/dist/wakes.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { formatActivityId } from './square-core.js';
|
|
2
|
+
import { isDeliveryDelivered } from './delivery.js';
|
|
3
|
+
import { nameKey } from './model.js';
|
|
4
|
+
import { resolveKnownName } from './decisions.js';
|
|
5
|
+
import { WATCH_STALE_MS, currentHold, freshWatchLease, removeWatchLease, touchPresenceCursor, watchTerminalStatus, writeWatchLease } from './runtime.js';
|
|
6
|
+
function filter(options) {
|
|
7
|
+
return { ...(options.participants === undefined ? {} : { participants: [...options.participants] }), ...(options.mention === undefined ? {} : { mention: options.mention }) };
|
|
8
|
+
}
|
|
9
|
+
function notificationKey(recipient, index) { return JSON.stringify([formatActivityId(index), nameKey(recipient)]); }
|
|
10
|
+
export async function acquireWatchLease(square, name, leaseId, options, ownerId) {
|
|
11
|
+
const at = square.clock();
|
|
12
|
+
return square.cell.transact((state) => {
|
|
13
|
+
const known = resolveKnownName(state, name);
|
|
14
|
+
const existing = freshWatchLease(state, known, at);
|
|
15
|
+
if (existing !== undefined && !options.replace)
|
|
16
|
+
return { result: { type: 'active', lease: existing } };
|
|
17
|
+
writeWatchLease(state, known, { leaseId, ...(ownerId === undefined ? {} : { ownerId }), heartbeatAt: at, expiresAt: at + WATCH_STALE_MS, ...(Object.keys(filter(options)).length === 0 ? {} : { filter: filter(options) }) });
|
|
18
|
+
touchPresenceCursor(state, known, at);
|
|
19
|
+
return { state, result: { type: 'started', leaseId, replaced: existing !== undefined, heartbeatAt: at } };
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export async function pulseWatchLease(square, name, leaseId, options, heartbeatDue) {
|
|
23
|
+
const at = square.clock();
|
|
24
|
+
return square.cell.transact((state) => {
|
|
25
|
+
const known = resolveKnownName(state, name);
|
|
26
|
+
const lease = freshWatchLease(state, known, at);
|
|
27
|
+
if (lease?.leaseId !== leaseId)
|
|
28
|
+
return { result: { type: 'replaced' } };
|
|
29
|
+
if (currentHold(state.acts).active)
|
|
30
|
+
return { result: { type: 'held' } };
|
|
31
|
+
const terminal = watchTerminalStatus(state, known);
|
|
32
|
+
if (terminal !== undefined)
|
|
33
|
+
return { result: { type: 'terminal', status: terminal } };
|
|
34
|
+
if (!heartbeatDue)
|
|
35
|
+
return { result: { type: 'sleep' } };
|
|
36
|
+
writeWatchLease(state, known, { leaseId, ...(lease.ownerId === undefined ? {} : { ownerId: lease.ownerId }), heartbeatAt: at, expiresAt: at + WATCH_STALE_MS, ...(Object.keys(filter(options)).length === 0 ? {} : { filter: filter(options) }) });
|
|
37
|
+
touchPresenceCursor(state, known, at);
|
|
38
|
+
return { state, result: { type: 'sleep', heartbeatAt: at } };
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
export async function releaseWatchLease(square, name, leaseId) {
|
|
42
|
+
if (leaseId === undefined)
|
|
43
|
+
return;
|
|
44
|
+
await square.cell.transact((state) => { const known = resolveKnownName(state, name); return removeWatchLease(state, known, leaseId) ? { state, result: undefined } : { result: undefined }; });
|
|
45
|
+
}
|
|
46
|
+
export async function ownsWatchLease(square, name, leaseId) { const { state } = await square.cell.read(); return freshWatchLease(state, resolveKnownName(state, name), square.clock())?.leaseId === leaseId; }
|
|
47
|
+
export async function claimNotificationLease(square, recipient, actIndex, leaseId, leaseMs) {
|
|
48
|
+
const at = square.clock();
|
|
49
|
+
const key = notificationKey(recipient, actIndex);
|
|
50
|
+
return square.cell.transact((state) => { const known = resolveKnownName(state, recipient); if (isDeliveryDelivered(state, known, actIndex))
|
|
51
|
+
return { result: { type: 'delivered' } }; const existing = state.runtime.notifyLeases[key]; if (existing !== undefined && existing.expiresAt > at)
|
|
52
|
+
return { result: { type: 'busy' } }; if (existing?.phase === 'dispatching')
|
|
53
|
+
return { result: { type: 'ambiguous', lease: existing } }; state.runtime.notifyLeases[key] = { leaseId, expiresAt: at + leaseMs, phase: 'claimed' }; return { state, result: { type: 'acquired', leaseId } }; });
|
|
54
|
+
}
|
|
55
|
+
export async function transitionNotificationLease(square, recipient, actIndex, leaseId, phase, leaseMs, routeKind, attemptN) {
|
|
56
|
+
const at = square.clock();
|
|
57
|
+
const key = notificationKey(recipient, actIndex);
|
|
58
|
+
return square.cell.transact((state) => { if (state.runtime.notifyLeases[key]?.leaseId !== leaseId)
|
|
59
|
+
return { result: false }; state.runtime.notifyLeases[key] = { leaseId, expiresAt: at + leaseMs, phase, ...(routeKind === undefined ? {} : { routeKind }), ...(attemptN === undefined ? {} : { attemptN }) }; return { state, result: true }; });
|
|
60
|
+
}
|
|
61
|
+
export async function releaseNotificationLease(square, recipient, actIndex, leaseId) { const key = notificationKey(recipient, actIndex); await square.cell.transact((state) => { if (state.runtime.notifyLeases[key]?.leaseId !== leaseId)
|
|
62
|
+
return { result: undefined }; delete state.runtime.notifyLeases[key]; return { state, result: undefined }; }); }
|
package/dist/watch.d.ts
ADDED