@astrosheep/square 0.3.11 → 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 +112 -96
- package/dist/artifact.d.ts +20 -0
- package/dist/artifact.js +317 -648
- 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 +6 -5
- 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 +26 -31
- package/dist/cli/harness-command.d.ts +28 -0
- package/dist/cli/harness-command.js +30 -15
- package/dist/cli/maintenance-commands.d.ts +7 -0
- package/dist/cli/maintenance-commands.js +12 -69
- package/dist/cli/meta-commands.d.ts +5 -0
- package/dist/cli/observation-commands.d.ts +20 -0
- package/dist/cli/observation-commands.js +159 -139
- package/dist/cli/program.d.ts +2 -0
- package/dist/cli/program.js +3 -12
- package/dist/cli/registry.d.ts +9 -0
- package/dist/cli/registry.js +2 -4
- package/dist/cli/square-commands.d.ts +34 -0
- package/dist/cli/square-commands.js +90 -84
- 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 +93 -81
- package/dist/delivery-health.d.ts +21 -0
- package/dist/delivery-health.js +41 -34
- package/dist/delivery.d.ts +81 -0
- package/dist/delivery.js +71 -69
- 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 +12 -13
- 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 -67
- package/dist/landing.d.ts +10 -0
- package/dist/landing.js +95 -0
- package/dist/list.d.ts +1 -0
- package/dist/list.js +39 -61
- package/dist/model.d.ts +147 -0
- package/dist/model.js +12 -8
- package/dist/notifications.d.ts +30 -0
- package/dist/notifications.js +83 -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 +52 -63
- 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 +48 -55
- package/dist/search.d.ts +11 -0
- package/dist/square-core.d.ts +111 -0
- package/dist/square-core.js +63 -9
- 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-attempts.js +8 -4
- 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/guides/participant.md +7 -174
- package/package.json +5 -4
- package/skills/brainstorm/SKILL.md +30 -30
- package/skills/square/.claude-plugin/plugin.json +1 -1
- package/skills/square/SKILL.md +56 -29
- package/skills/square/hooks/hooks.json +9 -0
- package/skills/square-feedback/SKILL.md +9 -9
- package/dist/compact.js +0 -26
- package/dist/doctor.js +0 -36
- package/dist/square-application.js +0 -262
- package/template.md +0 -4
- package/templates/architect.md +0 -4
- package/templates/brainstorm.md +0 -4
package/dist/notifications.js
CHANGED
|
@@ -3,28 +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, isPendingNotification, 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
|
|
9
|
+
import { SquareError } from './model.js';
|
|
10
|
+
import { SLEEP_MS, matchesMentionTarget } from './runtime.js';
|
|
11
|
+
import { parseActivityId } from './square-core.js';
|
|
12
12
|
import { PaseoAdapter } from './paseo-delivery.js';
|
|
13
|
-
import { quoteShell } from './presentation.js';
|
|
13
|
+
import { participantIdentity, quoteShell } from './presentation.js';
|
|
14
14
|
import { lookupParticipant } from './registry.js';
|
|
15
|
-
import {
|
|
16
|
-
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';
|
|
17
19
|
import { nextWakeAttemptNumber, recordRecoveredUnknown, recordWakeAttempt, } from './wake-attempts.js';
|
|
18
|
-
import {
|
|
20
|
+
import { wakeEvidence, wakeIsEligible } from './wake-evidence.js';
|
|
19
21
|
import { WakePort } from './wake-port.js';
|
|
20
22
|
const NOTIFY_LEASE_MS = 5 * 60 * 1000;
|
|
21
23
|
export { planActNotifications, matchesMentionTarget };
|
|
22
|
-
function known(doc, name) {
|
|
23
|
-
const value = resolveRosterName(doc, name);
|
|
24
|
-
if (value === undefined)
|
|
25
|
-
throw new SquareError('invalid_args', `Unknown participant "${name}". Expected one of: ${rosterNames(doc).join(', ')}.`);
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
24
|
export { notificationMessageId } from './delivery.js';
|
|
29
25
|
export function wakeGraceMs(env = process.env) {
|
|
30
26
|
const value = Number.parseInt(env.SQUARE_NOTIFY_DELIVERY_WAIT_MS ?? '5000', 10);
|
|
@@ -42,7 +38,7 @@ function renderWakePayload(request) {
|
|
|
42
38
|
: request.squarePath;
|
|
43
39
|
return [
|
|
44
40
|
'<system-reminder source="square">',
|
|
45
|
-
`${request.route === 'bell' ? 'Bell' :
|
|
41
|
+
`${request.route === 'bell' ? 'Bell' : 'Mention'} from ${participantIdentity(request.actor)} in \`${display}\``,
|
|
46
42
|
'The native adapter will present it at the next boundary. If no native wake is available, pull from the square yourself.',
|
|
47
43
|
`\`${catchCommand(request.squarePath, request.recipient)}\``,
|
|
48
44
|
'</system-reminder>',
|
|
@@ -51,23 +47,21 @@ function renderWakePayload(request) {
|
|
|
51
47
|
async function waitForCatch(route, request, body) {
|
|
52
48
|
const binding = lookupParticipant(request.squarePath, request.recipient)
|
|
53
49
|
.find((item) => item.ownerId === route.ownerId);
|
|
54
|
-
const activeCatch = binding && sessionInbox(binding.sessionId)
|
|
50
|
+
const activeCatch = binding && (await sessionInbox(binding.sessionId))
|
|
55
51
|
.find((item) => item.name === request.recipient)?.catchLease;
|
|
56
52
|
if (!activeCatch || !leaseOwnsNotification(activeCatch, {
|
|
57
53
|
actor: request.actor,
|
|
58
54
|
body,
|
|
59
55
|
route: request.route,
|
|
60
|
-
recipient: request.recipient,
|
|
61
56
|
}))
|
|
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;
|
|
@@ -75,58 +69,53 @@ async function waitForCatch(route, request, body) {
|
|
|
75
69
|
}
|
|
76
70
|
return false;
|
|
77
71
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
72
|
+
function notificationIndex(ref) {
|
|
73
|
+
if (typeof ref === 'number')
|
|
74
|
+
return ref;
|
|
75
|
+
const index = parseActivityId(ref);
|
|
76
|
+
if (index === undefined)
|
|
77
|
+
throw new Error(`Invalid act ref: ${ref}`);
|
|
78
|
+
return index;
|
|
81
79
|
}
|
|
82
|
-
export function
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
+
}
|
|
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
|
+
}
|
|
87
100
|
}
|
|
88
101
|
export async function waitForDeliveredNotification(squarePath, name, ref, opts = {}) {
|
|
89
102
|
const deadline = Date.now() + (opts.timeoutMs ?? 30000);
|
|
90
103
|
while (Date.now() <= deadline) {
|
|
91
|
-
if (hasDeliveredNotification(squarePath, name, ref))
|
|
104
|
+
if (await hasDeliveredNotification(squarePath, name, ref))
|
|
92
105
|
return true;
|
|
93
106
|
await sleep(Math.min(SLEEP_MS, Math.max(1, deadline - Date.now())));
|
|
94
107
|
}
|
|
95
108
|
return false;
|
|
96
109
|
}
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
async function claimNotifyLease(squarePath, recipient, actIndex) {
|
|
101
|
-
const at = Date.now();
|
|
102
|
-
const committed = await execute(squarePath, {
|
|
103
|
-
type: 'claim-notify',
|
|
104
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
105
|
-
leaseId: randomUUID(),
|
|
106
|
-
at,
|
|
107
|
-
expiresAt: at + NOTIFY_LEASE_MS,
|
|
108
|
-
});
|
|
109
|
-
return committed.result;
|
|
110
|
+
async function claimNotifyLease(square, recipient, actIndex) {
|
|
111
|
+
const leaseId = randomUUID();
|
|
112
|
+
return claimNotificationLease(square, recipient, actIndex, leaseId, NOTIFY_LEASE_MS);
|
|
110
113
|
}
|
|
111
|
-
async function transitionNotifyLease(
|
|
112
|
-
|
|
113
|
-
const committed = await execute(squarePath, {
|
|
114
|
-
type: 'transition-notify',
|
|
115
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
116
|
-
leaseId,
|
|
117
|
-
expiresAt: at + NOTIFY_LEASE_MS,
|
|
118
|
-
phase,
|
|
119
|
-
...(routeKind === undefined ? {} : { routeKind }),
|
|
120
|
-
...(attemptN === undefined ? {} : { attemptN }),
|
|
121
|
-
});
|
|
122
|
-
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);
|
|
123
116
|
}
|
|
124
|
-
function releaseNotifyLease(
|
|
125
|
-
|
|
126
|
-
type: 'release-notify',
|
|
127
|
-
key: notifyLeaseKey(recipient, actIndex),
|
|
128
|
-
leaseId,
|
|
129
|
-
});
|
|
117
|
+
async function releaseNotifyLease(square, recipient, actIndex, leaseId) {
|
|
118
|
+
await releaseNotificationLease(square, recipient, actIndex, leaseId);
|
|
130
119
|
}
|
|
131
120
|
async function processNotification(squarePath, notification, opts) {
|
|
132
121
|
const env = opts.env ?? process.env;
|
|
@@ -137,23 +126,27 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
137
126
|
recipient: notification.recipient,
|
|
138
127
|
};
|
|
139
128
|
const initialAt = now();
|
|
140
|
-
if (!wakeIsEligible(wakeEvidence(squarePath, notification.recipient, notification.item.index, initialAt, env)))
|
|
129
|
+
if (!wakeIsEligible(await wakeEvidence(squarePath, notification.recipient, notification.item.index, initialAt, env)))
|
|
141
130
|
return;
|
|
142
|
-
const
|
|
143
|
-
|
|
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);
|
|
144
135
|
return;
|
|
136
|
+
}
|
|
145
137
|
if (claim.type === 'ambiguous') {
|
|
146
138
|
const recovered = recordRecoveredUnknown(attention, claim.lease, env);
|
|
147
139
|
if (recovered !== undefined) {
|
|
148
|
-
await releaseNotifyLease(
|
|
140
|
+
await releaseNotifyLease(square, notification.recipient, notification.item.index, claim.lease.leaseId);
|
|
149
141
|
}
|
|
142
|
+
await closeOpenSquare(square);
|
|
150
143
|
return;
|
|
151
144
|
}
|
|
152
145
|
const { leaseId } = claim;
|
|
153
146
|
let releaseLease = true;
|
|
154
147
|
try {
|
|
155
148
|
const dispatchAt = now();
|
|
156
|
-
const evidence = wakeEvidence(squarePath, notification.recipient, notification.item.index, dispatchAt, env);
|
|
149
|
+
const evidence = await wakeEvidence(squarePath, notification.recipient, notification.item.index, dispatchAt, env);
|
|
157
150
|
if (!wakeIsEligible(evidence))
|
|
158
151
|
return;
|
|
159
152
|
const port = new WakePort(opts.adapters ?? [new PaseoAdapter()]);
|
|
@@ -170,22 +163,21 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
170
163
|
if (await waitForCatch(route, request, notification.item.body))
|
|
171
164
|
return false;
|
|
172
165
|
const currentAt = now();
|
|
173
|
-
|
|
174
|
-
if (!isCurrentlyJoined(latest.acts, notification.recipient))
|
|
166
|
+
if (!(await entryPresentation(square, notification.recipient)).joined)
|
|
175
167
|
return false;
|
|
176
|
-
const current = wakeEvidence(squarePath, notification.recipient, notification.item.index, currentAt, env);
|
|
168
|
+
const current = await wakeEvidence(squarePath, notification.recipient, notification.item.index, currentAt, env);
|
|
177
169
|
if (!wakeIsEligible(current))
|
|
178
170
|
return false;
|
|
179
171
|
if (!current.attemptableRoutes.some((candidate) => candidate.ownerId === route.ownerId && candidate.kind === route.kind && candidate.sessionId === route.sessionId))
|
|
180
172
|
return false;
|
|
181
|
-
const dispatching = await transitionNotifyLease(
|
|
173
|
+
const dispatching = await transitionNotifyLease(square, notification.recipient, notification.item.index, leaseId, 'dispatching', route.kind, attemptN);
|
|
182
174
|
if (dispatching)
|
|
183
175
|
releaseLease = false;
|
|
184
176
|
return dispatching;
|
|
185
177
|
},
|
|
186
178
|
record: async (route, attemptN, outcome) => {
|
|
187
179
|
if (outcome.outcome === 'failed') {
|
|
188
|
-
await transitionNotifyLease(
|
|
180
|
+
await transitionNotifyLease(square, notification.recipient, notification.item.index, leaseId, 'claimed');
|
|
189
181
|
releaseLease = true;
|
|
190
182
|
}
|
|
191
183
|
recordWakeAttempt({
|
|
@@ -205,47 +197,47 @@ async function processNotification(squarePath, notification, opts) {
|
|
|
205
197
|
}
|
|
206
198
|
finally {
|
|
207
199
|
if (releaseLease) {
|
|
208
|
-
await releaseNotifyLease(
|
|
200
|
+
await releaseNotifyLease(square, notification.recipient, notification.item.index, leaseId);
|
|
209
201
|
}
|
|
202
|
+
await closeOpenSquare(square);
|
|
210
203
|
}
|
|
211
204
|
}
|
|
212
205
|
export async function processActNotificationsOnce(squarePath, actIndex, opts = {}) {
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
if (item === undefined)
|
|
216
|
-
return;
|
|
217
|
-
const notifications = planActNotifications(doc, item).filter(isPendingNotification);
|
|
206
|
+
const square = await openSquare(squarePath);
|
|
207
|
+
const notifications = await notificationForAct(square, actIndex).finally(() => closeOpenSquare(square));
|
|
218
208
|
await Promise.all(notifications.map((notification) => processNotification(squarePath, notification, opts)));
|
|
219
209
|
}
|
|
220
210
|
function launchWorker(workerPath, args) {
|
|
221
211
|
const child = spawn(process.execPath, [workerPath, ...args], { detached: true, stdio: 'ignore', env: process.env });
|
|
222
212
|
child.unref();
|
|
223
213
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
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
|
+
};
|
|
233
225
|
}
|
|
234
226
|
/** Reconsider old pending attention at a bounded action boundary using the existing worker. */
|
|
235
|
-
export function sweepPendingNotifications(squarePath, opts = {}) {
|
|
227
|
+
export async function sweepPendingNotifications(squarePath, opts = {}) {
|
|
236
228
|
const env = opts.env ?? process.env;
|
|
237
229
|
if (env.SQUARE_DISABLE_PASEO_WAKE === '1')
|
|
238
230
|
return [];
|
|
239
231
|
const now = opts.now ?? Date.now();
|
|
240
232
|
const limit = opts.limit ?? 8;
|
|
241
|
-
const
|
|
242
|
-
const
|
|
233
|
+
const square = await openSquare(squarePath, { clock: () => now });
|
|
234
|
+
const pending = await pendingDeliveries(square).finally(() => closeOpenSquare(square));
|
|
243
235
|
const indexes = new Set();
|
|
244
|
-
for (const
|
|
245
|
-
for (const note of
|
|
236
|
+
for (const delivery of pending) {
|
|
237
|
+
for (const note of delivery.notifications) {
|
|
246
238
|
if (now - note.item.at <= wakeGraceMs(env))
|
|
247
239
|
continue;
|
|
248
|
-
if (!wakeIsEligible(wakeEvidence(squarePath, recipient, note.item.index, now, env)))
|
|
240
|
+
if (!wakeIsEligible(await wakeEvidence(squarePath, delivery.recipient, note.item.index, now, env)))
|
|
249
241
|
continue;
|
|
250
242
|
indexes.add(note.item.index);
|
|
251
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;
|