@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/notifications.js
CHANGED
|
@@ -3,29 +3,24 @@ import { randomUUID } from 'node:crypto';
|
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import {
|
|
7
|
-
import { deriveDeliveryModel, isDeliveryDelivered, leaseOwnsNotification, planActNotifications, } from './delivery.js';
|
|
6
|
+
import { leaseOwnsNotification, planActNotifications, } from './delivery.js';
|
|
8
7
|
import { sessionInbox } from './inbox.js';
|
|
9
8
|
import { hasPresentedAttention } from './presented.js';
|
|
10
|
-
import {
|
|
11
|
-
import { SLEEP_MS, matchesMentionTarget
|
|
12
|
-
import {
|
|
9
|
+
import { SquareError } from './model.js';
|
|
10
|
+
import { SLEEP_MS, matchesMentionTarget } from './runtime.js';
|
|
11
|
+
import { parseActivityId } from './square-core.js';
|
|
13
12
|
import { PaseoAdapter } from './paseo-delivery.js';
|
|
14
|
-
import { quoteShell } from './presentation.js';
|
|
13
|
+
import { participantIdentity, quoteShell } from './presentation.js';
|
|
15
14
|
import { lookupParticipant } from './registry.js';
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
15
|
+
import { openSquare } from './square-file-adapter.js';
|
|
16
|
+
import { closeOpenSquare } from './open-square.js';
|
|
17
|
+
import { entryPresentation, notificationDelivered, notificationForAct, pendingDeliveries, resolveParticipant } from './views.js';
|
|
18
|
+
import { claimNotificationLease, releaseNotificationLease, transitionNotificationLease } from './wakes.js';
|
|
18
19
|
import { nextWakeAttemptNumber, recordRecoveredUnknown, recordWakeAttempt, } from './wake-attempts.js';
|
|
19
|
-
import {
|
|
20
|
+
import { wakeEvidence, wakeIsEligible } from './wake-evidence.js';
|
|
20
21
|
import { WakePort } from './wake-port.js';
|
|
21
22
|
const NOTIFY_LEASE_MS = 5 * 60 * 1000;
|
|
22
23
|
export { planActNotifications, matchesMentionTarget };
|
|
23
|
-
function known(doc, name) {
|
|
24
|
-
const value = resolveRosterName(doc, name);
|
|
25
|
-
if (value === undefined)
|
|
26
|
-
throw new SquareError('invalid_args', `Unknown participant "${name}". Expected one of: ${rosterNames(doc).join(', ')}.`);
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
24
|
export { notificationMessageId } from './delivery.js';
|
|
30
25
|
export function wakeGraceMs(env = process.env) {
|
|
31
26
|
const value = Number.parseInt(env.SQUARE_NOTIFY_DELIVERY_WAIT_MS ?? '5000', 10);
|
|
@@ -43,7 +38,7 @@ function renderWakePayload(request) {
|
|
|
43
38
|
: request.squarePath;
|
|
44
39
|
return [
|
|
45
40
|
'<system-reminder source="square">',
|
|
46
|
-
`${request.route === 'bell' ? 'Bell' : 'Mention'} from
|
|
41
|
+
`${request.route === 'bell' ? 'Bell' : 'Mention'} from ${participantIdentity(request.actor)} in \`${display}\``,
|
|
47
42
|
'The native adapter will present it at the next boundary. If no native wake is available, pull from the square yourself.',
|
|
48
43
|
`\`${catchCommand(request.squarePath, request.recipient)}\``,
|
|
49
44
|
'</system-reminder>',
|
|
@@ -52,7 +47,7 @@ function renderWakePayload(request) {
|
|
|
52
47
|
async function waitForCatch(route, request, body) {
|
|
53
48
|
const binding = lookupParticipant(request.squarePath, request.recipient)
|
|
54
49
|
.find((item) => item.ownerId === route.ownerId);
|
|
55
|
-
const activeCatch = binding && sessionInbox(binding.sessionId)
|
|
50
|
+
const activeCatch = binding && (await sessionInbox(binding.sessionId))
|
|
56
51
|
.find((item) => item.name === request.recipient)?.catchLease;
|
|
57
52
|
if (!activeCatch || !leaseOwnsNotification(activeCatch, {
|
|
58
53
|
actor: request.actor,
|
|
@@ -62,12 +57,11 @@ async function waitForCatch(route, request, body) {
|
|
|
62
57
|
return false;
|
|
63
58
|
const deadline = Date.now() + 180_000;
|
|
64
59
|
while (Date.now() < deadline) {
|
|
65
|
-
|
|
66
|
-
if (isDeliveryDelivered(doc, request.recipient, request.actIndex))
|
|
60
|
+
if (await hasDeliveredNotification(request.squarePath, request.recipient, request.actIndex))
|
|
67
61
|
return true;
|
|
68
62
|
const currentBinding = lookupParticipant(request.squarePath, request.recipient)
|
|
69
63
|
.find((item) => item.ownerId === route.ownerId);
|
|
70
|
-
const lease = currentBinding && sessionInbox(currentBinding.sessionId)
|
|
64
|
+
const lease = currentBinding && (await sessionInbox(currentBinding.sessionId))
|
|
71
65
|
.find((item) => item.name === request.recipient)?.catchLease;
|
|
72
66
|
if (!lease || lease.expiresAt <= Date.now())
|
|
73
67
|
return false;
|
|
@@ -83,58 +77,45 @@ function notificationIndex(ref) {
|
|
|
83
77
|
throw new Error(`Invalid act ref: ${ref}`);
|
|
84
78
|
return index;
|
|
85
79
|
}
|
|
86
|
-
export function hasDeliveredNotification(squarePath, name, ref) {
|
|
87
|
-
const
|
|
88
|
-
|
|
80
|
+
export async function hasDeliveredNotification(squarePath, name, ref) {
|
|
81
|
+
const square = await openSquare(squarePath);
|
|
82
|
+
try {
|
|
83
|
+
const recipient = (await resolveParticipant(square, name)).name;
|
|
84
|
+
return notificationDelivered(square, recipient, notificationIndex(ref));
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
await closeOpenSquare(square);
|
|
88
|
+
}
|
|
89
89
|
}
|
|
90
|
-
export function hasAttentionNotification(squarePath, name, ref, env = process.env) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
export async function hasAttentionNotification(squarePath, name, ref, env = process.env) {
|
|
91
|
+
const square = await openSquare(squarePath);
|
|
92
|
+
try {
|
|
93
|
+
const recipient = (await resolveParticipant(square, name)).name;
|
|
94
|
+
const index = notificationIndex(ref);
|
|
95
|
+
return await notificationDelivered(square, recipient, index) || hasPresentedAttention(squarePath, recipient, index, env);
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
await closeOpenSquare(square);
|
|
99
|
+
}
|
|
95
100
|
}
|
|
96
101
|
export async function waitForDeliveredNotification(squarePath, name, ref, opts = {}) {
|
|
97
102
|
const deadline = Date.now() + (opts.timeoutMs ?? 30000);
|
|
98
103
|
while (Date.now() <= deadline) {
|
|
99
|
-
if (hasDeliveredNotification(squarePath, name, ref))
|
|
104
|
+
if (await hasDeliveredNotification(squarePath, name, ref))
|
|
100
105
|
return true;
|
|
101
106
|
await sleep(Math.min(SLEEP_MS, Math.max(1, deadline - Date.now())));
|
|
102
107
|
}
|
|
103
108
|
return false;
|
|
104
109
|
}
|
|
105
|
-
function
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
async function claimNotifyLease(squarePath, recipient, actIndex) {
|
|
109
|
-
const at = Date.now();
|
|
110
|
-
const committed = await execute(squarePath, {
|
|
111
|
-
type: 'claim-notify',
|
|
112
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
113
|
-
leaseId: randomUUID(),
|
|
114
|
-
at,
|
|
115
|
-
expiresAt: at + NOTIFY_LEASE_MS,
|
|
116
|
-
});
|
|
117
|
-
return committed.result;
|
|
110
|
+
async function claimNotifyLease(square, recipient, actIndex) {
|
|
111
|
+
const leaseId = randomUUID();
|
|
112
|
+
return claimNotificationLease(square, recipient, actIndex, leaseId, NOTIFY_LEASE_MS);
|
|
118
113
|
}
|
|
119
|
-
async function transitionNotifyLease(
|
|
120
|
-
|
|
121
|
-
const committed = await execute(squarePath, {
|
|
122
|
-
type: 'transition-notify',
|
|
123
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
124
|
-
leaseId,
|
|
125
|
-
expiresAt: at + NOTIFY_LEASE_MS,
|
|
126
|
-
phase,
|
|
127
|
-
...(routeKind === undefined ? {} : { routeKind }),
|
|
128
|
-
...(attemptN === undefined ? {} : { attemptN }),
|
|
129
|
-
});
|
|
130
|
-
return committed.result.updated;
|
|
114
|
+
async function transitionNotifyLease(square, recipient, actIndex, leaseId, phase, routeKind, attemptN) {
|
|
115
|
+
return transitionNotificationLease(square, recipient, actIndex, leaseId, phase, NOTIFY_LEASE_MS, routeKind, attemptN);
|
|
131
116
|
}
|
|
132
|
-
function releaseNotifyLease(
|
|
133
|
-
|
|
134
|
-
type: 'release-notify',
|
|
135
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
136
|
-
leaseId,
|
|
137
|
-
});
|
|
117
|
+
async function releaseNotifyLease(square, recipient, actIndex, leaseId) {
|
|
118
|
+
await releaseNotificationLease(square, recipient, actIndex, leaseId);
|
|
138
119
|
}
|
|
139
120
|
async function processNotification(squarePath, notification, opts) {
|
|
140
121
|
const env = opts.env ?? process.env;
|
|
@@ -145,23 +126,27 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
145
126
|
recipient: notification.recipient,
|
|
146
127
|
};
|
|
147
128
|
const initialAt = now();
|
|
148
|
-
if (!wakeIsEligible(wakeEvidence(squarePath, notification.recipient, notification.item.index, initialAt, env)))
|
|
129
|
+
if (!wakeIsEligible(await wakeEvidence(squarePath, notification.recipient, notification.item.index, initialAt, env)))
|
|
149
130
|
return;
|
|
150
|
-
const
|
|
151
|
-
|
|
131
|
+
const square = await openSquare(squarePath, { clock: now });
|
|
132
|
+
const claim = await claimNotifyLease(square, notification.recipient, notification.item.index);
|
|
133
|
+
if (claim.type === 'busy' || claim.type === 'delivered') {
|
|
134
|
+
await closeOpenSquare(square);
|
|
152
135
|
return;
|
|
136
|
+
}
|
|
153
137
|
if (claim.type === 'ambiguous') {
|
|
154
138
|
const recovered = recordRecoveredUnknown(attention, claim.lease, env);
|
|
155
139
|
if (recovered !== undefined) {
|
|
156
|
-
await releaseNotifyLease(
|
|
140
|
+
await releaseNotifyLease(square, notification.recipient, notification.item.index, claim.lease.leaseId);
|
|
157
141
|
}
|
|
142
|
+
await closeOpenSquare(square);
|
|
158
143
|
return;
|
|
159
144
|
}
|
|
160
145
|
const { leaseId } = claim;
|
|
161
146
|
let releaseLease = true;
|
|
162
147
|
try {
|
|
163
148
|
const dispatchAt = now();
|
|
164
|
-
const evidence = wakeEvidence(squarePath, notification.recipient, notification.item.index, dispatchAt, env);
|
|
149
|
+
const evidence = await wakeEvidence(squarePath, notification.recipient, notification.item.index, dispatchAt, env);
|
|
165
150
|
if (!wakeIsEligible(evidence))
|
|
166
151
|
return;
|
|
167
152
|
const port = new WakePort(opts.adapters ?? [new PaseoAdapter()]);
|
|
@@ -178,22 +163,21 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
178
163
|
if (await waitForCatch(route, request, notification.item.body))
|
|
179
164
|
return false;
|
|
180
165
|
const currentAt = now();
|
|
181
|
-
|
|
182
|
-
if (!isCurrentlyJoined(latest.acts, notification.recipient))
|
|
166
|
+
if (!(await entryPresentation(square, notification.recipient)).joined)
|
|
183
167
|
return false;
|
|
184
|
-
const current = wakeEvidence(squarePath, notification.recipient, notification.item.index, currentAt, env);
|
|
168
|
+
const current = await wakeEvidence(squarePath, notification.recipient, notification.item.index, currentAt, env);
|
|
185
169
|
if (!wakeIsEligible(current))
|
|
186
170
|
return false;
|
|
187
171
|
if (!current.attemptableRoutes.some((candidate) => candidate.ownerId === route.ownerId && candidate.kind === route.kind && candidate.sessionId === route.sessionId))
|
|
188
172
|
return false;
|
|
189
|
-
const dispatching = await transitionNotifyLease(
|
|
173
|
+
const dispatching = await transitionNotifyLease(square, notification.recipient, notification.item.index, leaseId, 'dispatching', route.kind, attemptN);
|
|
190
174
|
if (dispatching)
|
|
191
175
|
releaseLease = false;
|
|
192
176
|
return dispatching;
|
|
193
177
|
},
|
|
194
178
|
record: async (route, attemptN, outcome) => {
|
|
195
179
|
if (outcome.outcome === 'failed') {
|
|
196
|
-
await transitionNotifyLease(
|
|
180
|
+
await transitionNotifyLease(square, notification.recipient, notification.item.index, leaseId, 'claimed');
|
|
197
181
|
releaseLease = true;
|
|
198
182
|
}
|
|
199
183
|
recordWakeAttempt({
|
|
@@ -213,47 +197,47 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
213
197
|
}
|
|
214
198
|
finally {
|
|
215
199
|
if (releaseLease) {
|
|
216
|
-
await releaseNotifyLease(
|
|
200
|
+
await releaseNotifyLease(square, notification.recipient, notification.item.index, leaseId);
|
|
217
201
|
}
|
|
202
|
+
await closeOpenSquare(square);
|
|
218
203
|
}
|
|
219
204
|
}
|
|
220
205
|
export async function processActNotificationsOnce(squarePath, actIndex, opts = {}) {
|
|
221
|
-
const
|
|
222
|
-
const
|
|
223
|
-
if (item === undefined)
|
|
224
|
-
return;
|
|
225
|
-
const notifications = planActNotifications(doc, item);
|
|
206
|
+
const square = await openSquare(squarePath);
|
|
207
|
+
const notifications = await notificationForAct(square, actIndex).finally(() => closeOpenSquare(square));
|
|
226
208
|
await Promise.all(notifications.map((notification) => processNotification(squarePath, notification, opts)));
|
|
227
209
|
}
|
|
228
210
|
function launchWorker(workerPath, args) {
|
|
229
211
|
const child = spawn(process.execPath, [workerPath, ...args], { detached: true, stdio: 'ignore', env: process.env });
|
|
230
212
|
child.unref();
|
|
231
213
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
214
|
+
export function wakeNotifierForSquare(squarePath, env = process.env) {
|
|
215
|
+
return {
|
|
216
|
+
wake(recipients, activity) {
|
|
217
|
+
if (env.SQUARE_DISABLE_PASEO_WAKE === '1' || recipients.length === 0)
|
|
218
|
+
return;
|
|
219
|
+
const actIndex = parseActivityId(activity.id);
|
|
220
|
+
if (actIndex === undefined)
|
|
221
|
+
return;
|
|
222
|
+
launchWorker(fileURLToPath(new URL('./cmd/notify-once.js', import.meta.url)), ['--location', squarePath, '--act-index', String(actIndex)]);
|
|
223
|
+
},
|
|
224
|
+
};
|
|
241
225
|
}
|
|
242
226
|
/** Reconsider old pending attention at a bounded action boundary using the existing worker. */
|
|
243
|
-
export function sweepPendingNotifications(squarePath, opts = {}) {
|
|
227
|
+
export async function sweepPendingNotifications(squarePath, opts = {}) {
|
|
244
228
|
const env = opts.env ?? process.env;
|
|
245
229
|
if (env.SQUARE_DISABLE_PASEO_WAKE === '1')
|
|
246
230
|
return [];
|
|
247
231
|
const now = opts.now ?? Date.now();
|
|
248
232
|
const limit = opts.limit ?? 8;
|
|
249
|
-
const
|
|
250
|
-
const
|
|
233
|
+
const square = await openSquare(squarePath, { clock: () => now });
|
|
234
|
+
const pending = await pendingDeliveries(square).finally(() => closeOpenSquare(square));
|
|
251
235
|
const indexes = new Set();
|
|
252
|
-
for (const
|
|
253
|
-
for (const note of
|
|
236
|
+
for (const delivery of pending) {
|
|
237
|
+
for (const note of delivery.notifications) {
|
|
254
238
|
if (now - note.item.at <= wakeGraceMs(env))
|
|
255
239
|
continue;
|
|
256
|
-
if (!wakeIsEligible(wakeEvidence(squarePath, recipient, note.item.index, now, env)))
|
|
240
|
+
if (!wakeIsEligible(await wakeEvidence(squarePath, delivery.recipient, note.item.index, now, env)))
|
|
257
241
|
continue;
|
|
258
242
|
indexes.add(note.item.index);
|
|
259
243
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { StateCell } from './state-cell.js';
|
|
2
|
+
import type { WakeNotifier } from './square-facade.js';
|
|
3
|
+
/** Private binding assembled by storage and consumed by the four concerns. */
|
|
4
|
+
export interface OpenSquare {
|
|
5
|
+
readonly cell: StateCell;
|
|
6
|
+
readonly clock: () => number;
|
|
7
|
+
readonly notifier?: WakeNotifier;
|
|
8
|
+
readonly location: string;
|
|
9
|
+
}
|
|
10
|
+
/** Package-private lifecycle boundary for bound squares. */
|
|
11
|
+
export declare function closeOpenSquare(square: OpenSquare): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function participantIdentity(name: string): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { DaemonClient } from '@getpaseo/client/internal/daemon-client';
|
|
2
|
+
export type PaseoDaemonTarget = {
|
|
3
|
+
type: 'tcp';
|
|
4
|
+
url: string;
|
|
5
|
+
password?: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'ipc';
|
|
8
|
+
url: string;
|
|
9
|
+
socketPath: string;
|
|
10
|
+
password?: string;
|
|
11
|
+
};
|
|
12
|
+
/** Match the host precedence used by the Paseo CLI for local daemon connections. */
|
|
13
|
+
export declare function paseoDaemonHosts(env?: NodeJS.ProcessEnv): string[];
|
|
14
|
+
export declare function resolvePaseoDaemonTarget(host: string, env?: NodeJS.ProcessEnv): PaseoDaemonTarget;
|
|
15
|
+
export declare function connectPaseoDaemon(env?: NodeJS.ProcessEnv, connectTimeoutMs?: number): Promise<DaemonClient>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type WakeAdapter, type WakeDispatchResult } from './delivery.js';
|
|
2
|
+
import { discoverPaseoAgents, waitForPaseoWakeBoundary } from './paseo-state.js';
|
|
3
|
+
import { sendPaseoWake } from './wake-sink.js';
|
|
4
|
+
export interface PaseoAdapterOptions {
|
|
5
|
+
discover?: typeof discoverPaseoAgents;
|
|
6
|
+
waitForBoundary?: typeof waitForPaseoWakeBoundary;
|
|
7
|
+
sendWake?: typeof sendPaseoWake;
|
|
8
|
+
}
|
|
9
|
+
export declare class PaseoAdapter implements WakeAdapter {
|
|
10
|
+
private readonly opts;
|
|
11
|
+
readonly kind: "paseo";
|
|
12
|
+
constructor(opts?: PaseoAdapterOptions);
|
|
13
|
+
dispatch(address: Readonly<Record<string, string>>, payload: string, beforeSend: () => Promise<boolean>): Promise<WakeDispatchResult>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface PaseoAgent {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
status: string;
|
|
5
|
+
cwd?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function discoverPaseoAgents(timeoutMs?: number): {
|
|
8
|
+
agents: PaseoAgent[];
|
|
9
|
+
error?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare function waitForPaseoWakeBoundary(agent: Pick<PaseoAgent, 'id' | 'status'>): Promise<boolean>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type PaseoToolStatus = 'running' | 'completed' | 'failed';
|
|
2
|
+
export interface PaseoToolCallSnapshot {
|
|
3
|
+
callId: string;
|
|
4
|
+
status: PaseoToolStatus;
|
|
5
|
+
}
|
|
6
|
+
export interface PaseoTimelineSnapshot {
|
|
7
|
+
agentStatus: string;
|
|
8
|
+
toolCalls: PaseoToolCallSnapshot[];
|
|
9
|
+
}
|
|
10
|
+
export interface WaitForPaseoToolBoundaryOptions {
|
|
11
|
+
pollIntervalMs?: number;
|
|
12
|
+
timeoutMs?: number;
|
|
13
|
+
readSnapshot?: (agentId: string) => Promise<PaseoTimelineSnapshot>;
|
|
14
|
+
delay?: (ms: number) => Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function waitForPaseoToolBoundary(agentId: string, opts?: WaitForPaseoToolBoundaryOptions): Promise<boolean>;
|
package/dist/presence.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { extractMentions, formatActivityId, perceive } from './square-core.js';
|
|
2
|
+
import { ackPeerDelta, deliveryDelta, filteredRoomChanges, matchesFeedFilter, peerPublicActs } from './activity-feed.js';
|
|
3
|
+
import { markDeliveredNotifications } from './delivery.js';
|
|
4
|
+
import { SquareError } from './model.js';
|
|
5
|
+
import { resolveKnownName } from './decisions.js';
|
|
6
|
+
import { readCursor } from './runtime.js';
|
|
7
|
+
function expose(activity, viewer) {
|
|
8
|
+
if (activity.kind === 'read' || activity.actor === undefined)
|
|
9
|
+
throw new Error(`Cannot expose stored activity ${formatActivityId(activity.index)}`);
|
|
10
|
+
const perception = perceive(activity, viewer);
|
|
11
|
+
const result = { id: formatActivityId(activity.index), at: activity.at, kind: activity.kind, actor: activity.actor, mentions: activity.kind === 'say' ? extractMentions(activity.body) : [], ...('body' in activity && activity.body !== undefined ? { body: activity.body } : {}), ...(activity.kind === 'say' && activity.reply !== undefined ? { reply: formatActivityId(activity.reply) } : {}) };
|
|
12
|
+
if (perception === 'full' || !('body' in result))
|
|
13
|
+
return { ...result, perception };
|
|
14
|
+
const { body: _body, ...withoutBody } = result;
|
|
15
|
+
return { ...withoutBody, perception };
|
|
16
|
+
}
|
|
17
|
+
export async function catchUp(square, name, options = {}) {
|
|
18
|
+
const idle = options.idle ?? 0;
|
|
19
|
+
if (!Number.isFinite(idle) || idle < 0)
|
|
20
|
+
throw new SquareError('invalid_args', 'Catch idle duration must be a non-negative number');
|
|
21
|
+
const deadline = Date.now() + idle;
|
|
22
|
+
while (true) {
|
|
23
|
+
const attempt = await square.cell.transact((state, version) => {
|
|
24
|
+
const at = square.clock();
|
|
25
|
+
const viewer = resolveKnownName(state, name);
|
|
26
|
+
const delta = deliveryDelta(state, viewer);
|
|
27
|
+
const filter = { ...(options.from === undefined ? {} : { participants: [...options.from] }), ...(options.mention === true ? { mention: viewer } : {}) };
|
|
28
|
+
const delivered = [...peerPublicActs(delta, viewer).filter((activity) => matchesFeedFilter(activity, filter)), ...filteredRoomChanges(delta, viewer, filter)]
|
|
29
|
+
.filter((activity, index, activities) => activities.findIndex((candidate) => candidate.index === activity.index) === index)
|
|
30
|
+
.sort((left, right) => left.index - right.index);
|
|
31
|
+
const cursorChanged = ackPeerDelta(state, viewer, delta, at);
|
|
32
|
+
const receiptsChanged = markDeliveredNotifications(state, viewer, delivered, at);
|
|
33
|
+
const cursor = readCursor(state, viewer);
|
|
34
|
+
return { ...(cursorChanged || receiptsChanged ? { state } : {}), result: { version, caught: { activities: delivered.map((activity) => expose(activity, viewer)), consumedThrough: cursor < 0 ? null : formatActivityId(cursor), idleExpired: false } } };
|
|
35
|
+
});
|
|
36
|
+
if (attempt.caught.activities.length > 0 || idle === 0)
|
|
37
|
+
return attempt.caught;
|
|
38
|
+
const remaining = deadline - Date.now();
|
|
39
|
+
if (remaining <= 0 || !await square.cell.changed(attempt.version, remaining))
|
|
40
|
+
return { ...attempt.caught, idleExpired: true };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { type StoredAct, type SquareState, type PublicAct, type RoomChangeAct } from './model.js';
|
|
2
|
+
export { participantIdentity } from './participant-identity.js';
|
|
3
|
+
import type { UnreadActivitySummary, ParticipantStatus } from './decisions.js';
|
|
4
|
+
export type WatchStatus = 'stale' | 'empty-now' | 'quorum' | 'capped';
|
|
5
|
+
interface HeaderOptions {
|
|
6
|
+
participantCount?: number;
|
|
7
|
+
held?: boolean;
|
|
8
|
+
}
|
|
9
|
+
interface ParticipantOutputOptions {
|
|
10
|
+
squarePath: string;
|
|
11
|
+
name: string;
|
|
12
|
+
participantCount?: number;
|
|
13
|
+
held?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface ActivityLimitOptions extends ParticipantOutputOptions {
|
|
16
|
+
count?: number;
|
|
17
|
+
hardCap?: number;
|
|
18
|
+
draftPath?: string;
|
|
19
|
+
}
|
|
20
|
+
interface ActivityBlockedOptions extends ParticipantOutputOptions {
|
|
21
|
+
forceCommand: string;
|
|
22
|
+
activitySummaries: UnreadActivitySummary[];
|
|
23
|
+
unreadRoomChanges: RoomChangeAct[];
|
|
24
|
+
draftPath?: string;
|
|
25
|
+
}
|
|
26
|
+
interface ExpressWaitingOptions {
|
|
27
|
+
reason: 'throttled' | 'held';
|
|
28
|
+
delayMs?: number;
|
|
29
|
+
}
|
|
30
|
+
interface ExpressNoWaitOptions extends ParticipantOutputOptions {
|
|
31
|
+
reason: 'throttled' | 'held';
|
|
32
|
+
delayMs?: number;
|
|
33
|
+
holdReason?: string;
|
|
34
|
+
draftPath?: string;
|
|
35
|
+
}
|
|
36
|
+
interface WatchStatusOptions extends ParticipantOutputOptions {
|
|
37
|
+
status: WatchStatus;
|
|
38
|
+
idleMs?: number;
|
|
39
|
+
presence?: {
|
|
40
|
+
participants: ParticipantStatus[];
|
|
41
|
+
now: number;
|
|
42
|
+
};
|
|
43
|
+
showCatchHint?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export declare function displayPath(squarePath: string, cwd?: string): string;
|
|
46
|
+
export declare function withPathOutput(squarePath: string, body?: string, opts?: HeaderOptions): string;
|
|
47
|
+
export declare function quoteShell(value: string): string;
|
|
48
|
+
export declare function commandPrefix(squarePath: string): string;
|
|
49
|
+
export declare function participantCommandPrefix(squarePath: string, name: string): string;
|
|
50
|
+
export declare function renderPresenceLines(participants: ParticipantStatus[], now: number, limit?: number): string[];
|
|
51
|
+
export declare function expressHintLine(ownActivityCount: number): string | undefined;
|
|
52
|
+
export declare function truncateChars(body: string, maxChars: number): {
|
|
53
|
+
text: string;
|
|
54
|
+
remaining: number;
|
|
55
|
+
};
|
|
56
|
+
export declare function previewActivityBody(body: string): string;
|
|
57
|
+
export declare function renderRoomChangeText(event: RoomChangeAct): string;
|
|
58
|
+
export declare function renderEventCli(event: StoredAct, opts?: {
|
|
59
|
+
now?: number;
|
|
60
|
+
preview?: number;
|
|
61
|
+
actNumber?: number;
|
|
62
|
+
mention?: string;
|
|
63
|
+
}): string;
|
|
64
|
+
export declare function renderAmbientEvent(event: StoredAct, viewer: string, opts?: {
|
|
65
|
+
now?: number;
|
|
66
|
+
preview?: number;
|
|
67
|
+
actNumber?: number;
|
|
68
|
+
mention?: string;
|
|
69
|
+
}): string;
|
|
70
|
+
export declare function renderPendingFeed(history: StoredAct[], publicItems: PublicAct[], roomChanges: RoomChangeAct[], viewer?: string): string;
|
|
71
|
+
export declare function renderActivityBlocked(opts: ActivityBlockedOptions): string;
|
|
72
|
+
export declare function renderExpressWaiting(opts: ExpressWaitingOptions): string;
|
|
73
|
+
export declare function renderExpressNoWait(opts: ExpressNoWaitOptions): string;
|
|
74
|
+
export declare function renderPublicTail(events: StoredAct[], lastN: number | null | undefined, now?: number, viewer?: string): string;
|
|
75
|
+
export declare function renderActivitiesView(squareState: SquareState, visible: StoredAct[], lastN: number | null | undefined, full: boolean | undefined, squarePath: string, viewer?: string, mode?: 'ambient' | 'archive'): string;
|
|
76
|
+
export declare function renderGrepActivitiesView(visible: StoredAct[], totalMatches: number, full: boolean | undefined, squarePath: string, pattern: string, fixed?: boolean): string;
|
|
77
|
+
export declare function renderActivityLimit(opts: ActivityLimitOptions): string;
|
|
78
|
+
export declare function renderWatchAlreadyActive(opts: ParticipantOutputOptions): string;
|
|
79
|
+
export declare function renderWatchForceTakeover(_opts: ParticipantOutputOptions): string;
|
|
80
|
+
export declare function renderWatchReplaced(_opts: ParticipantOutputOptions): string;
|
|
81
|
+
export declare function renderWatchStatus(opts: WatchStatusOptions): string;
|
|
82
|
+
export declare function renderDoctorClean(): string;
|
|
83
|
+
export declare function renderDoctorUnfixable(reason: string): string;
|
|
84
|
+
export declare function renderWatchOutput(history: StoredAct[], publicItems: PublicAct[], roomChanges: RoomChangeAct[], opts: {
|
|
85
|
+
squarePath: string;
|
|
86
|
+
stalePartial?: boolean;
|
|
87
|
+
idleMs?: number;
|
|
88
|
+
mention?: string;
|
|
89
|
+
viewer: string;
|
|
90
|
+
showCatchHint?: boolean;
|
|
91
|
+
}): string;
|