@astrosheep/square 0.3.93 → 0.3.94
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activity-feed.d.ts +3 -5
- package/dist/activity-feed.js +16 -14
- package/dist/artifact.js +2 -2
- package/dist/boundary-presentation.d.ts +2 -2
- package/dist/catch-decisions.d.ts +4 -6
- package/dist/catch-decisions.js +4 -4
- package/dist/claude-delivery-status.js +10 -4
- package/dist/claude-delivery.js +19 -11
- package/dist/claude-mod.js +24 -53
- package/dist/cli/context.d.ts +9 -4
- package/dist/cli/context.js +30 -25
- package/dist/cli/express-presentation.d.ts +3 -1
- package/dist/cli/express-presentation.js +26 -14
- package/dist/cli/json.d.ts +3 -0
- package/dist/cli/json.js +14 -0
- package/dist/cli/mcp-server-command.js +2 -2
- package/dist/cli/observation-commands.d.ts +1 -3
- package/dist/cli/observation-commands.js +43 -56
- package/dist/cli/program.js +2 -2
- package/dist/cli/registry.js +6 -3
- package/dist/cli/square-commands.d.ts +1 -1
- package/dist/cli/square-commands.js +46 -54
- package/dist/codex-hook.d.ts +3 -2
- package/dist/codex-hook.js +13 -4
- package/dist/codex-queue.js +4 -4
- package/dist/decisions.d.ts +5 -11
- package/dist/decisions.js +9 -20
- package/dist/delivery-deferral.js +2 -2
- package/dist/delivery-health.d.ts +0 -1
- package/dist/delivery-health.js +1 -3
- package/dist/delivery-operations.d.ts +2 -2
- package/dist/delivery-operations.js +38 -38
- package/dist/delivery.d.ts +1 -1
- package/dist/delivery.js +1 -1
- package/dist/help.js +12 -10
- package/dist/inbox.d.ts +9 -22
- package/dist/inbox.js +23 -27
- package/dist/index.d.ts +1 -3
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +3 -0
- package/dist/mcp.js +23 -24
- package/dist/model.d.ts +8 -15
- package/dist/model.js +4 -7
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +6 -5
- package/dist/operation-presentation.d.ts +5 -4
- package/dist/operation-presentation.js +50 -45
- package/dist/owner.d.ts +11 -0
- package/dist/owner.js +32 -0
- package/dist/paseo-delivery.d.ts +4 -1
- package/dist/paseo-delivery.js +7 -12
- package/dist/paseo-state.d.ts +2 -2
- package/dist/paseo-state.js +6 -4
- package/dist/plugins/opencode/delivery.js +27 -15
- package/dist/ports.d.ts +13 -33
- package/dist/presentation-operations.js +4 -4
- package/dist/presentation.d.ts +5 -8
- package/dist/presentation.js +33 -43
- package/dist/runtime.d.ts +1 -7
- package/dist/runtime.js +0 -14
- package/dist/seats.d.ts +2 -3
- package/dist/seats.js +7 -15
- package/dist/session-lifecycle.d.ts +6 -2
- package/dist/session-lifecycle.js +39 -11
- package/dist/sqlite-square.d.ts +36 -22
- package/dist/sqlite-square.js +138 -161
- package/dist/square-api.d.ts +15 -10
- package/dist/square-api.js +26 -22
- package/dist/square-core.d.ts +0 -5
- package/dist/square-core.js +0 -9
- package/dist/square-domain.d.ts +4 -2
- package/dist/square-domain.js +56 -21
- package/dist/square-facade.d.ts +45 -87
- package/dist/square-index.d.ts +5 -13
- package/dist/square-index.js +13 -38
- package/dist/square-location.d.ts +1 -14
- package/dist/square-location.js +4 -70
- package/dist/square-migration-host-ledger.d.ts +2 -2
- package/dist/square-migration-host-ledger.js +6 -5
- package/dist/square-migration.d.ts +2 -1
- package/dist/square-migration.js +52 -30
- package/dist/square-sqlite.d.ts +6 -2
- package/dist/square-sqlite.js +54 -28
- package/dist/square-tools.d.ts +7 -10
- package/dist/square-tools.js +22 -54
- package/dist/stream.js +4 -5
- package/dist/views.d.ts +21 -10
- package/dist/views.js +38 -38
- package/dist/wakes.d.ts +1 -2
- package/dist/wakes.js +1 -1
- package/guides/application-facade-delivery-evidence.md +1 -1
- package/guides/claude-native.md +18 -9
- package/guides/codex-delivery.md +17 -6
- package/guides/mcp-connection-lifetime.md +1 -1
- package/guides/mcp.md +3 -3
- package/guides/migration.md +142 -151
- package/guides/operation-cancellation.md +1 -1
- package/guides/participant-ownership.md +78 -47
- package/guides/pi-tools.md +33 -4
- package/guides/primitive-history-consolidation.md +1 -1
- package/guides/row-storage-design.md +8 -8
- package/guides/square-api.md +244 -88
- package/package.json +1 -1
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +27 -17
- package/plugins/paseo/client/palette.ts +18 -18
- package/plugins/paseo/client/square-message.tsx +17 -23
- package/plugins/pi/square-pi.js +17 -17
- package/dist/square-backend.d.ts +0 -13
- package/dist/square-backend.js +0 -1
- package/dist/square-stdio.d.ts +0 -22
- package/dist/square-stdio.js +0 -235
- package/dist/stdio-server.d.ts +0 -3
- package/dist/stdio-server.js +0 -212
- package/guides/backends.md +0 -193
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
// Human-facing text for one settled operation. The CLI and the MCP transport both
|
|
2
2
|
// render through these functions, so a person sees the same square either way.
|
|
3
3
|
import { sameName } from './model.js';
|
|
4
|
-
import { formatActivityId
|
|
5
|
-
import { commandPrefix, joinRecoveryCommand, participantCommandPrefix, participantIdentity, participantsRecoveryCommand, quoteShell, renderAmbientEvent, renderAmbientEventFacts, renderEventCli, renderGrepActivitiesView,
|
|
4
|
+
import { formatActivityId } from './square-core.js';
|
|
5
|
+
import { commandPrefix, joinRecoveryCommand, participantCommandPrefix, participantIdentity, participantsRecoveryCommand, quoteShell, renderAmbientEvent, renderAmbientEventFacts, renderEventCli, renderGrepActivitiesView, renderPresenceAnchor, renderRoomChangeText, renderWatchAlreadyActive, renderWatchReplaced, renderWatchStatus, takeoverRecoveryLines, withPathOutput, } from './presentation.js';
|
|
6
6
|
import { formatRelativeTime, formatTimestamp } from './time.js';
|
|
7
7
|
import { style } from './tty-style.js';
|
|
8
8
|
export const PARTICIPANTS_DEFAULT_LIMIT = 20;
|
|
9
9
|
export const PARTICIPANTS_MAX_LIMIT = 100;
|
|
10
10
|
const STATUS_PARTICIPANT_PREVIEW_LIMIT = 10;
|
|
11
|
-
export function renderJoinResult(data) {
|
|
11
|
+
export function renderJoinResult(data, owner) {
|
|
12
12
|
const after = data.observation;
|
|
13
13
|
if (after === undefined)
|
|
14
14
|
return undefined;
|
|
15
15
|
const entry = after.entry;
|
|
16
16
|
const name = typeof data.participant === 'string' ? data.participant : data.participant.name;
|
|
17
17
|
const activities = (entry?.recentActivities ?? []).map((event) => renderAmbientEvent(event, name, {
|
|
18
|
-
now: after.now, preview: 200,
|
|
19
|
-
actNumber: event.kind === 'say' ? entry.sayNumbers[event.index] : undefined,
|
|
20
|
-
perception: entry.perceptions[event.index],
|
|
18
|
+
now: after.now, preview: 200, perception: event.perception,
|
|
21
19
|
})).filter(Boolean).join('\n\n');
|
|
22
|
-
const fallback = after.
|
|
23
|
-
'', `${participantCommandPrefix(after.location, name)} catch --idle 30m`,
|
|
20
|
+
const fallback = after.deliveryAvailable ? ['', '· when someone calls you, you’ll hear them here'] : [
|
|
21
|
+
'', `${participantCommandPrefix(after.location, name, owner)} catch --idle 30m`,
|
|
24
22
|
' · stay within earshot — keep this catch open for new activity',
|
|
25
23
|
];
|
|
26
24
|
const entryLine = data.kind === 'joined' ? '● you stepped into the square'
|
|
@@ -41,16 +39,18 @@ export function renderJoinResult(data) {
|
|
|
41
39
|
function isGestureOnly(body) {
|
|
42
40
|
return /\*[^*]*\*/.test(body) && body.replace(/\*[^*]*\*/g, '').trim() === '';
|
|
43
41
|
}
|
|
44
|
-
export function renderExpression(squarePath, data) {
|
|
42
|
+
export function renderExpression(squarePath, data, owner) {
|
|
45
43
|
const projection = data.observation;
|
|
46
44
|
if (projection === undefined)
|
|
47
45
|
return undefined;
|
|
48
46
|
const name = projection.participant;
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
:
|
|
47
|
+
const context = projection.context;
|
|
48
|
+
const pending = context.activities.length === 0 ? '' : '\n\n' + [
|
|
49
|
+
'Unread context · preview only, not consumed',
|
|
50
|
+
...context.activities.map(item => `· ${participantIdentity(item.actor)} · ${item.id}\n ${item.preview}${item.truncated ? '… (truncated)' : ''}`),
|
|
51
|
+
...(context.remaining === 0 ? [] : [`· ${context.remaining} more unread activities`]),
|
|
52
|
+
`${participantCommandPrefix(projection.location, name, owner)} catch`,
|
|
53
|
+
].join('\n');
|
|
54
54
|
const ownCount = projection.ownActivityCount;
|
|
55
55
|
const capCount = projection.hardCap === null ? '' : ` · ${ownCount}/${projection.hardCap}`;
|
|
56
56
|
const activity = data.activity;
|
|
@@ -65,7 +65,7 @@ export function renderExpression(squarePath, data) {
|
|
|
65
65
|
? `\n · ${data.unmatchedMentions.map((token) => `@${token} isn't standing here`).join('; ')} — ${activity.mentions.length === 0 && activity.reply === undefined ? 'activity landed bare' : 'left as literal text'}` : '';
|
|
66
66
|
return withPathOutput(projection.location ?? squarePath, confirmation + (data.hint ? `\n${style('dim', `· ${data.hint}`)}` : '') + replyNotice + unmatchedNotice + pending, { participantCount: projection.standingCount, held: projection.held });
|
|
67
67
|
}
|
|
68
|
-
function continuationCommand(squarePath, name, options) {
|
|
68
|
+
function continuationCommand(squarePath, name, options, owner) {
|
|
69
69
|
const args = ['--now'];
|
|
70
70
|
if (options.from?.length)
|
|
71
71
|
args.push('--from', options.from.join(','));
|
|
@@ -73,20 +73,20 @@ function continuationCommand(squarePath, name, options) {
|
|
|
73
73
|
args.push('--mention');
|
|
74
74
|
if (options.limit !== undefined)
|
|
75
75
|
args.push('--limit', String(options.limit));
|
|
76
|
-
return `${participantCommandPrefix(squarePath, name)} catch ${args.join(' ')}`;
|
|
76
|
+
return `${participantCommandPrefix(squarePath, name, owner)} catch ${args.join(' ')}`;
|
|
77
77
|
}
|
|
78
78
|
/** Render settled catch facts; no selection, terminal decisions, receipts or wait machinery. */
|
|
79
|
-
export function renderCatchOutcome(squarePath, data, options = {}) {
|
|
79
|
+
export function renderCatchOutcome(squarePath, data, options = {}, owner) {
|
|
80
80
|
const projection = data.observation;
|
|
81
81
|
if (projection === undefined)
|
|
82
82
|
return { stdout: '', exitCode: 0 };
|
|
83
83
|
const location = projection.location ?? squarePath;
|
|
84
84
|
const name = projection.participant;
|
|
85
|
-
const stop =
|
|
85
|
+
const stop = data.reason === 'drained' && data.activities.length > 0 ? undefined : data.reason;
|
|
86
86
|
const header = { participantCount: projection.standingCount, held: projection.held };
|
|
87
87
|
const statusOptions = {
|
|
88
|
-
squarePath: location, name, presence: projection.presence,
|
|
89
|
-
showCatchHint: !projection.
|
|
88
|
+
squarePath: location, name, owner, presence: projection.presence,
|
|
89
|
+
showCatchHint: !projection.deliveryAvailable,
|
|
90
90
|
ownActivityCount: projection.ownActivityCount, hardCap: projection.hardCap,
|
|
91
91
|
};
|
|
92
92
|
if (stop === 'already-active' || stop === 'replaced') {
|
|
@@ -97,17 +97,16 @@ export function renderCatchOutcome(squarePath, data, options = {}) {
|
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
99
|
const rendered = data.activities.map((activity) => renderAmbientEvent(activity, name, {
|
|
100
|
-
now: projection.now,
|
|
101
|
-
perception: activity.perception, mention: options.mention ? name : undefined,
|
|
100
|
+
now: projection.now, perception: activity.perception, mention: options.mention ? name : undefined,
|
|
102
101
|
})).filter(Boolean).join('\n\n');
|
|
103
102
|
const remaining = data.remaining === 0 ? ''
|
|
104
|
-
: `· ${data.remaining} matching ${data.remaining === 1 ? 'activity remains' : 'activities remain'}\n${continuationCommand(location, name, options)}`;
|
|
103
|
+
: `· ${data.remaining} matching ${data.remaining === 1 ? 'activity remains' : 'activities remain'}\n${continuationCommand(location, name, options, owner)}`;
|
|
105
104
|
const terminal = stop === undefined ? '' : renderWatchStatus({
|
|
106
105
|
...statusOptions, status: stop,
|
|
107
|
-
...(stop === '
|
|
106
|
+
...(stop === 'idle' && options.idle !== undefined ? { idleMs: options.idle } : {}),
|
|
108
107
|
});
|
|
109
|
-
const fallback = stop === undefined && !projection.
|
|
110
|
-
? `${participantCommandPrefix(location, name)} catch --idle 30m\n stay available for new activity` : '';
|
|
108
|
+
const fallback = stop === undefined && !projection.deliveryAvailable && data.remaining === 0
|
|
109
|
+
? `${participantCommandPrefix(location, name, owner)} catch --idle 30m\n stay available for new activity` : '';
|
|
111
110
|
const hint = data.hint === undefined ? '' : style('dim', `· ${data.hint}`);
|
|
112
111
|
return {
|
|
113
112
|
stdout: withPathOutput(location, [terminal, rendered, hint, remaining, fallback].filter(Boolean).join('\n\n'), header),
|
|
@@ -121,11 +120,7 @@ function renderHistoryProjection(projection, visible, noTruncate, squarePath) {
|
|
|
121
120
|
// Presence anchors collect into one closing line instead of interrupting the page.
|
|
122
121
|
const anchored = [];
|
|
123
122
|
for (const activity of shown) {
|
|
124
|
-
const
|
|
125
|
-
preview,
|
|
126
|
-
actNumber: activity.kind === 'say' ? projection.sayNumbers[activity.index] : undefined,
|
|
127
|
-
};
|
|
128
|
-
const rendered = renderEventCli(activity, options);
|
|
123
|
+
const rendered = renderEventCli(activity, { preview });
|
|
129
124
|
if (rendered !== '')
|
|
130
125
|
chunks.push(rendered);
|
|
131
126
|
for (const participant of projection.presenceAnchors[activity.index] ?? []) {
|
|
@@ -193,8 +188,8 @@ export function renderParticipantsResult(squarePath, data, limit = PARTICIPANTS_
|
|
|
193
188
|
const now = projection.now;
|
|
194
189
|
const participants = data.participants;
|
|
195
190
|
const lines = participants.slice(0, limit).map((participant) => {
|
|
196
|
-
const glyph = participant.
|
|
197
|
-
const state = participant.
|
|
191
|
+
const glyph = participant.presence === 'done' ? '○' : participant.presence === 'watching' ? '◎' : participant.activityCount > 0 && projection.classificationByName[participant.name] === 'here' ? '●' : '○';
|
|
192
|
+
const state = participant.presence === 'watching' ? 'catching' : participant.presence === 'never-joined' ? 'not joined' : participant.presence;
|
|
198
193
|
const last = participant.lastActiveAt === undefined ? '—' : formatRelativeTime(participant.lastActiveAt, now);
|
|
199
194
|
return ` ${glyph} ${participant.name}${style('dim', ` · ${state} · ${participant.activityCount} ${participant.activityCount === 1 ? 'activity' : 'activities'} · ${last}`)}`;
|
|
200
195
|
});
|
|
@@ -217,8 +212,9 @@ export function renderStatusResult(squarePath, data) {
|
|
|
217
212
|
const participantsByName = new Map(data.participants.map((participant) => [participant.name, participant]));
|
|
218
213
|
const orderedHere = presentation.orderedHereNames.map((name) => participantsByName.get(name));
|
|
219
214
|
const lingering = presentation.lingeringCount;
|
|
215
|
+
const away = data.participants.filter(participant => participant.presence === 'away');
|
|
220
216
|
const people = [];
|
|
221
|
-
if (
|
|
217
|
+
if (presentation.standingCount === 0) {
|
|
222
218
|
people.push(' ○ nobody in the square');
|
|
223
219
|
}
|
|
224
220
|
else {
|
|
@@ -243,7 +239,11 @@ export function renderStatusResult(squarePath, data) {
|
|
|
243
239
|
: 'caught up';
|
|
244
240
|
return ` ${glyph} ${participantIdentity(participant.name)}${style('dim', ` ${summary}${attention === '' ? '' : ` · ${attention}`}`)}`;
|
|
245
241
|
}));
|
|
246
|
-
|
|
242
|
+
people.push(...away.slice(0, STATUS_PARTICIPANT_PREVIEW_LIMIT).map(participant => ` ○ ${participantIdentity(participant.name)}${style('dim', ' · away')}`));
|
|
243
|
+
if (away.length > STATUS_PARTICIPANT_PREVIEW_LIMIT)
|
|
244
|
+
people.push(` ○ … ${away.length - STATUS_PARTICIPANT_PREVIEW_LIMIT} more away`);
|
|
245
|
+
const unshown = Math.max(0, orderedHere.length - STATUS_PARTICIPANT_PREVIEW_LIMIT)
|
|
246
|
+
+ Math.max(0, away.length - STATUS_PARTICIPANT_PREVIEW_LIMIT) + lingering;
|
|
247
247
|
if (orderedHere.length > STATUS_PARTICIPANT_PREVIEW_LIMIT) {
|
|
248
248
|
people.push(` ○ … ${orderedHere.length - STATUS_PARTICIPANT_PREVIEW_LIMIT} more here`);
|
|
249
249
|
}
|
|
@@ -256,16 +256,16 @@ export function renderStatusResult(squarePath, data) {
|
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
258
|
const cap = data.hardCap === null ? 'unlimited' : `${data.hardCap} each`;
|
|
259
|
-
const
|
|
260
|
-
const
|
|
261
|
-
|
|
259
|
+
const held = data.held;
|
|
260
|
+
const holdTime = held?.at === undefined ? 'just now' : formatRelativeTime(held.at, data.now);
|
|
261
|
+
const hold = held !== null
|
|
262
|
+
? `· ${held.by === undefined ? 'someone' : participantIdentity(held.by)} raised a hand${held.reason ? ` — ${held.reason}` : ''}${style('dim', ` · ${holdTime}`)}`
|
|
262
263
|
: undefined;
|
|
263
264
|
const visible = data.latestActivity === undefined
|
|
264
265
|
? { text: '', bodyClipped: false }
|
|
265
266
|
: renderAmbientEventFacts(data.latestActivity, presentation.viewer, {
|
|
266
267
|
now: data.now,
|
|
267
268
|
preview: 200,
|
|
268
|
-
actNumber: presentation.latestActNumber,
|
|
269
269
|
perception: presentation.latestPerception,
|
|
270
270
|
});
|
|
271
271
|
const latest = visible.text === ''
|
|
@@ -285,8 +285,9 @@ export function renderStatusResult(squarePath, data) {
|
|
|
285
285
|
}
|
|
286
286
|
const counts = [
|
|
287
287
|
`${orderedHere.length} here`,
|
|
288
|
+
...(away.length > 0 ? [`${away.length} away`] : []),
|
|
288
289
|
...(lingering > 0 ? [`${lingering} lingering`] : []),
|
|
289
|
-
`${data.
|
|
290
|
+
`${data.participants.filter((participant) => participant.presence === 'done').length} done`,
|
|
290
291
|
`cap ${cap}`,
|
|
291
292
|
`throttle ${data.throttlePerMinute === undefined ? 'none' : `${data.throttlePerMinute}/min`}`,
|
|
292
293
|
].join(' · ');
|
|
@@ -298,7 +299,7 @@ export function renderStatusResult(squarePath, data) {
|
|
|
298
299
|
...(data.listening.length === 0 ? [' ○ not turned toward anyone'] : data.listening.map((name) => ` · ${participantIdentity(name)}`)),
|
|
299
300
|
]),
|
|
300
301
|
].join('\n');
|
|
301
|
-
return withPathOutput(squarePath, output, { participantCount: presentation.standingCount, held:
|
|
302
|
+
return withPathOutput(squarePath, output, { participantCount: presentation.standingCount, held: data.held !== null });
|
|
302
303
|
}
|
|
303
304
|
export function renderListeningResult(squarePath, data) {
|
|
304
305
|
const projection = data.observation;
|
|
@@ -334,12 +335,12 @@ export function renderLifecycleResult(squarePath, verb, data) {
|
|
|
334
335
|
if (verb === 'done') {
|
|
335
336
|
return withPathOutput(projection.location ?? squarePath, `○ you stepped out — your footsteps fade · ${data.activity.id}`, header);
|
|
336
337
|
}
|
|
337
|
-
const line = `${renderRoomChangeText(
|
|
338
|
+
const line = `${renderRoomChangeText(data.activity)} · ${data.activity.id} · just now`;
|
|
338
339
|
return withPathOutput(projection.location ?? squarePath, verb === 'hold' ? `· ${line}` : `✓ ${line}`, header);
|
|
339
340
|
}
|
|
340
341
|
/** Refusal lines with the same recovery commands the CLI prints. */
|
|
341
342
|
export function renderFailureLines(failure, options = {}) {
|
|
342
|
-
const { squarePath, name } = options;
|
|
343
|
+
const { squarePath, name, owner } = options;
|
|
343
344
|
const facts = failure.facts;
|
|
344
345
|
const reason = facts?.reason;
|
|
345
346
|
const marked = reason === 'never_joined' || reason === 'not_standing';
|
|
@@ -350,13 +351,17 @@ export function renderFailureLines(failure, options = {}) {
|
|
|
350
351
|
else if (squarePath !== undefined)
|
|
351
352
|
lines.push(`${commandPrefix(squarePath)} migrate`);
|
|
352
353
|
}
|
|
354
|
+
else if (squarePath !== undefined && name !== undefined && reason === 'needs_seat') {
|
|
355
|
+
lines.splice(0, 1, `✕ ${failure.message}`);
|
|
356
|
+
lines.push(joinRecoveryCommand(squarePath, name, owner));
|
|
357
|
+
}
|
|
353
358
|
else if (squarePath !== undefined && name !== undefined && failure.code === 'already_joined') {
|
|
354
359
|
lines.splice(0, 1, `✕ ${participantIdentity(name)} shoos you out of the square`, ` · ${participantIdentity(name)} already stands here — another session holds the name`);
|
|
355
|
-
lines.push(...takeoverRecoveryLines(squarePath, name));
|
|
360
|
+
lines.push(...takeoverRecoveryLines(squarePath, name, owner));
|
|
356
361
|
}
|
|
357
362
|
else if (squarePath !== undefined && reason === 'never_joined') {
|
|
358
363
|
lines.push(failure.operation?.subject !== 'filter' && name !== undefined
|
|
359
|
-
? joinRecoveryCommand(squarePath, name) : participantsRecoveryCommand(squarePath));
|
|
364
|
+
? joinRecoveryCommand(squarePath, name, owner) : participantsRecoveryCommand(squarePath));
|
|
360
365
|
}
|
|
361
366
|
else if (squarePath !== undefined && reason === 'not_standing') {
|
|
362
367
|
lines.push(participantsRecoveryCommand(squarePath));
|
package/dist/owner.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Owner } from './model.js';
|
|
2
|
+
export type { Owner } from './model.js';
|
|
3
|
+
export interface HarnessCoordinate {
|
|
4
|
+
readonly channel: string;
|
|
5
|
+
readonly session: string;
|
|
6
|
+
readonly agent?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function harnessOwner(coordinate: HarnessCoordinate): Owner;
|
|
9
|
+
/** Decode only at harness adapter boundaries; core never consumes the coordinate. */
|
|
10
|
+
export declare function decodeHarnessOwner(owner: Owner): HarnessCoordinate | undefined;
|
|
11
|
+
export declare function localUserOwner(): Owner;
|
package/dist/owner.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import { validateOwner } from './model.js';
|
|
3
|
+
export function harnessOwner(coordinate) {
|
|
4
|
+
const channel = nonempty(coordinate.channel, 'channel');
|
|
5
|
+
const session = nonempty(coordinate.session, 'session');
|
|
6
|
+
const agent = coordinate.agent === undefined ? undefined : nonempty(coordinate.agent, 'agent');
|
|
7
|
+
return validateOwner([channel, session, ...(agent === undefined ? [] : ['agent', agent])].map(encodeURIComponent).join(':'));
|
|
8
|
+
}
|
|
9
|
+
/** Decode only at harness adapter boundaries; core never consumes the coordinate. */
|
|
10
|
+
export function decodeHarnessOwner(owner) {
|
|
11
|
+
const parts = owner.split(':');
|
|
12
|
+
if ((parts.length !== 2 && parts.length !== 4) || (parts.length === 4 && parts[2] !== 'agent'))
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
const [channel, session] = parts;
|
|
16
|
+
const decoded = { channel: decodeURIComponent(channel), session: decodeURIComponent(session) };
|
|
17
|
+
if (parts.length === 4)
|
|
18
|
+
return { ...decoded, agent: decodeURIComponent(parts[3]) };
|
|
19
|
+
return decoded;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function localUserOwner() {
|
|
26
|
+
return validateOwner(`user:${os.userInfo().username}@${os.hostname()}`);
|
|
27
|
+
}
|
|
28
|
+
function nonempty(value, label) {
|
|
29
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
30
|
+
throw new Error(`Harness ${label} must be non-empty.`);
|
|
31
|
+
return value;
|
|
32
|
+
}
|
package/dist/paseo-delivery.d.ts
CHANGED
|
@@ -2,12 +2,15 @@ import type { WakeRequest, WakeOutcome, WakeTransportPort } from './ports.js';
|
|
|
2
2
|
import { discoverPaseoAgents, waitForPaseoWakeBoundary } from './paseo-state.js';
|
|
3
3
|
import { sendPaseoWake } from './wake-sink.js';
|
|
4
4
|
export interface PaseoWakeTransportOptions {
|
|
5
|
-
discover?: typeof discoverPaseoAgents
|
|
5
|
+
discover?: (timeoutMs: number) => ReturnType<typeof discoverPaseoAgents> | Awaited<ReturnType<typeof discoverPaseoAgents>>;
|
|
6
6
|
waitForBoundary?: typeof waitForPaseoWakeBoundary;
|
|
7
7
|
sendWake?: typeof sendPaseoWake;
|
|
8
8
|
}
|
|
9
9
|
export declare class PaseoWakeTransport implements WakeTransportPort {
|
|
10
10
|
private readonly opts;
|
|
11
|
+
private discovering?;
|
|
11
12
|
constructor(opts?: PaseoWakeTransportOptions);
|
|
13
|
+
/** Coalesce overlapping inventory reads only; a later send must rediscover current status. */
|
|
14
|
+
private discover;
|
|
12
15
|
attempt(request: WakeRequest, timeoutMs: number, beforeSend: () => Promise<boolean>): Promise<WakeOutcome>;
|
|
13
16
|
}
|
package/dist/paseo-delivery.js
CHANGED
|
@@ -17,28 +17,30 @@ function diagnostic(phase, address, code) {
|
|
|
17
17
|
}
|
|
18
18
|
export class PaseoWakeTransport {
|
|
19
19
|
opts;
|
|
20
|
+
discovering;
|
|
20
21
|
constructor(opts = {}) {
|
|
21
22
|
this.opts = opts;
|
|
22
23
|
}
|
|
24
|
+
/** Coalesce overlapping inventory reads only; a later send must rediscover current status. */
|
|
25
|
+
discover(timeoutMs) {
|
|
26
|
+
return this.discovering ??= Promise.resolve().then(() => (this.opts.discover ?? discoverPaseoAgents)(timeoutMs))
|
|
27
|
+
.finally(() => { this.discovering = undefined; });
|
|
28
|
+
}
|
|
23
29
|
async attempt(request, timeoutMs, beforeSend) {
|
|
24
30
|
const address = request.route.address;
|
|
25
31
|
const deadline = Date.now() + timeoutMs;
|
|
26
32
|
const remainingMs = () => Math.max(0, deadline - Date.now());
|
|
27
33
|
const budgetUnavailable = () => ({
|
|
28
34
|
outcome: 'failed',
|
|
29
|
-
unavailable: true,
|
|
30
35
|
signature: 'dispatch_budget_exhausted',
|
|
31
36
|
message: 'The wake dispatch budget elapsed before Paseo accepted the wake.',
|
|
32
|
-
retainRoute: true,
|
|
33
37
|
});
|
|
34
38
|
const agentId = address.agentId?.trim();
|
|
35
39
|
if (!agentId) {
|
|
36
40
|
return {
|
|
37
41
|
outcome: 'failed',
|
|
38
|
-
unavailable: true,
|
|
39
42
|
signature: 'invalid_address',
|
|
40
43
|
message: 'Paseo route has no agent id.',
|
|
41
|
-
routeStale: true,
|
|
42
44
|
diagnostic: diagnostic('selection', address, 'invalid_address'),
|
|
43
45
|
};
|
|
44
46
|
}
|
|
@@ -49,30 +51,25 @@ export class PaseoWakeTransport {
|
|
|
49
51
|
let remaining = remainingMs();
|
|
50
52
|
if (remaining === 0)
|
|
51
53
|
return budgetUnavailable();
|
|
52
|
-
const discovery =
|
|
54
|
+
const discovery = await this.discover(remaining);
|
|
53
55
|
if (discovery.error && discovery.agents.length === 0) {
|
|
54
56
|
return {
|
|
55
57
|
outcome: 'failed',
|
|
56
|
-
unavailable: true,
|
|
57
58
|
// A credential or authorization refusal is proven; anything else may be transient.
|
|
58
59
|
signature: /password|auth|unauthori[sz]ed/i.test(discovery.error) ? 'discovery_rejected'
|
|
59
60
|
: /DAEMON_NOT_RUNNING|ECONNREFUSED|ENOENT|not found.*executable|ETIMEDOUT|timed out|timeout/i.test(discovery.error)
|
|
60
61
|
? 'discovery_transient' : 'discovery_rejected',
|
|
61
62
|
message: `Paseo unavailable: ${discovery.error}`,
|
|
62
63
|
diagnostic: diagnostic('discovery', address, 'unavailable'),
|
|
63
|
-
retainRoute: true,
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
const agent = discovery.agents.find((candidate) => candidate.id === agentId);
|
|
67
67
|
if (agent === undefined || agent.status !== 'idle') {
|
|
68
68
|
return {
|
|
69
69
|
outcome: 'failed',
|
|
70
|
-
unavailable: true,
|
|
71
70
|
signature: agent === undefined ? 'address_not_found' : 'agent_not_idle',
|
|
72
71
|
message: agent === undefined ? 'The registered Paseo agent was not found.' : 'The registered Paseo agent is not idle.',
|
|
73
72
|
diagnostic: diagnostic('selection', address, agent === undefined ? 'not_found' : 'not_idle'),
|
|
74
|
-
...(agent === undefined ? {} : { retainRoute: true }),
|
|
75
|
-
...(agent === undefined ? { routeStale: true } : {}),
|
|
76
73
|
};
|
|
77
74
|
}
|
|
78
75
|
remaining = remainingMs();
|
|
@@ -81,11 +78,9 @@ export class PaseoWakeTransport {
|
|
|
81
78
|
if (!(await (this.opts.waitForBoundary ?? waitForPaseoWakeBoundary)(agent, remaining))) {
|
|
82
79
|
return {
|
|
83
80
|
outcome: 'failed',
|
|
84
|
-
unavailable: true,
|
|
85
81
|
signature: 'boundary_unavailable',
|
|
86
82
|
message: 'Paseo did not reach the current tool boundary before the wake timeout.',
|
|
87
83
|
diagnostic: diagnostic('boundary', address, 'unavailable'),
|
|
88
|
-
retainRoute: true,
|
|
89
84
|
};
|
|
90
85
|
}
|
|
91
86
|
if (!(await beforeSend()))
|
package/dist/paseo-state.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ export interface PaseoAgent {
|
|
|
7
7
|
export declare function discoverPaseoAgents(timeoutMs?: number, opts?: {
|
|
8
8
|
args?: string[];
|
|
9
9
|
bin?: string;
|
|
10
|
-
}): {
|
|
10
|
+
}): Promise<{
|
|
11
11
|
agents: PaseoAgent[];
|
|
12
12
|
error?: string;
|
|
13
|
-
}
|
|
13
|
+
}>;
|
|
14
14
|
export declare function waitForPaseoWakeBoundary(agent: Pick<PaseoAgent, 'id' | 'status'>, timeoutMs?: number): Promise<boolean>;
|
package/dist/paseo-state.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
2
3
|
import { waitForPaseoToolBoundary } from './paseo-timeline.js';
|
|
3
|
-
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export async function discoverPaseoAgents(timeoutMs = 5000, opts = {}) {
|
|
4
6
|
try {
|
|
5
|
-
const raw =
|
|
7
|
+
const { stdout: raw } = await execFileAsync(opts.bin ?? process.env.SQUARE_PASEO_BIN ?? 'paseo', [...(opts.args ?? []), 'ls', '--global', '--json'], {
|
|
6
8
|
encoding: 'utf8',
|
|
7
9
|
timeout: timeoutMs,
|
|
8
|
-
|
|
10
|
+
maxBuffer: 1024 * 1024,
|
|
9
11
|
});
|
|
10
12
|
const parsed = JSON.parse(raw);
|
|
11
13
|
const agents = Array.isArray(parsed) ? parsed : parsed?.agents;
|
|
@@ -3,39 +3,48 @@ import { createArtifactPort } from '../../artifact.js';
|
|
|
3
3
|
import { deliverPending } from '../../delivery-operations.js';
|
|
4
4
|
import { nativePendingPreview, observeSessionPending, projectSessionSeats } from '../../inbox.js';
|
|
5
5
|
import { automaticWakeEligible, presentationBlocksWake } from '../../delivery.js';
|
|
6
|
-
import {
|
|
6
|
+
import { harnessOwner, decodeHarnessOwner } from '../../owner.js';
|
|
7
7
|
import { formatActivityId, parseActivityId } from '../../square-core.js';
|
|
8
8
|
import { indexedSquareEntries } from '../../square-index.js';
|
|
9
9
|
import { asSeatRef } from '../../seats.js';
|
|
10
|
+
import { restoreSessionSeats } from '../../session-lifecycle.js';
|
|
10
11
|
import { presentPending } from '../../presentation-operations.js';
|
|
11
12
|
import { createNativeInputId, sendNativeText } from '../../packages/agent-delivery/src/opencode-native.js';
|
|
12
13
|
const routeKind = 'opencode-server';
|
|
13
|
-
const
|
|
14
|
+
const ownerFor = (sessionId) => harnessOwner({ channel: 'opencode', session: sessionId });
|
|
14
15
|
const payloadHash = (payload) => createHash('sha256').update(payload).digest('hex');
|
|
15
|
-
function preview(facts, location,
|
|
16
|
+
function preview(facts, location, captured, index) {
|
|
17
|
+
const seat = facts.seat(captured.participant);
|
|
18
|
+
if (seat === undefined || seat.attachment !== 'attached' || seat.generation !== captured.generation || seat.owner !== captured.owner)
|
|
19
|
+
return undefined;
|
|
20
|
+
const wake = seat.wakeAddress;
|
|
21
|
+
if (wake?.kind !== routeKind)
|
|
22
|
+
return undefined;
|
|
16
23
|
return nativePendingPreview(facts, {
|
|
17
|
-
location, routeKind,
|
|
18
|
-
actIndex: index, address:
|
|
24
|
+
location, routeKind, generation: seat.generation, participant: seat.participant,
|
|
25
|
+
actIndex: index, address: wake.address, now: Date.now(),
|
|
19
26
|
});
|
|
20
27
|
}
|
|
21
28
|
export async function indexedOpenCodeSessions(env) {
|
|
22
|
-
return [...new Set((await indexedSquareEntries({
|
|
29
|
+
return [...new Set((await indexedSquareEntries({}, env)).flatMap((entry) => {
|
|
30
|
+
const coordinate = decodeHarnessOwner(entry.owner);
|
|
31
|
+
return coordinate?.channel === 'opencode' ? [coordinate.session] : [];
|
|
32
|
+
}))];
|
|
23
33
|
}
|
|
24
34
|
export async function discoverOpenCodeSeats(sessionId, env, signal) {
|
|
25
|
-
return projectSessionSeats({
|
|
35
|
+
return projectSessionSeats({ owner: ownerFor(sessionId), env }, signal);
|
|
26
36
|
}
|
|
27
37
|
function sameSeat(left, right) {
|
|
28
|
-
return left !== undefined && left.generation === right.generation &&
|
|
38
|
+
return left !== undefined && left.attachment === 'attached' && left.generation === right.generation && left.owner === right.owner;
|
|
29
39
|
}
|
|
30
40
|
function createOpenCodeWakeTransport(target, lifetime) {
|
|
31
41
|
return {
|
|
32
42
|
probe: async (route) => !lifetime.aborted && route.kind === routeKind
|
|
33
|
-
&& route.
|
|
43
|
+
&& route.address.sessionId === target.sessionId,
|
|
34
44
|
async attempt(request, timeoutMs, beforeSend) {
|
|
35
45
|
const index = parseActivityId(request.activity);
|
|
36
46
|
const artifact = request.artifact;
|
|
37
47
|
if (artifact === undefined || request.claimToken === undefined || index === undefined
|
|
38
|
-
|| !sameBody(request.seat.body, bodyFor(target.sessionId))
|
|
39
48
|
|| request.route.kind !== routeKind || request.route.address.sessionId !== target.sessionId) {
|
|
40
49
|
return { outcome: 'not-capable', diagnostic: 'OpenCode attention has no matching artifact claim or session.' };
|
|
41
50
|
}
|
|
@@ -61,7 +70,7 @@ function createOpenCodeWakeTransport(target, lifetime) {
|
|
|
61
70
|
if (result.state === 'accepted')
|
|
62
71
|
return { outcome: 'accepted' };
|
|
63
72
|
if (result.state === 'unavailable')
|
|
64
|
-
return { outcome: 'failed',
|
|
73
|
+
return { outcome: 'failed', signature: result.code };
|
|
65
74
|
return { outcome: 'unknown', signature: result.code };
|
|
66
75
|
},
|
|
67
76
|
};
|
|
@@ -126,7 +135,7 @@ export async function observeOpenCodeContext(sessionId, messages, env, signal) {
|
|
|
126
135
|
}
|
|
127
136
|
/** The native receiver owns no claims outside the artifact; HOME is used only for discovery. */
|
|
128
137
|
export async function receiveOpenCodePending(target, env, signal) {
|
|
129
|
-
const observer = await observeSessionPending(
|
|
138
|
+
const observer = await observeSessionPending(ownerFor(target.sessionId), env);
|
|
130
139
|
const transport = createOpenCodeWakeTransport(target, signal);
|
|
131
140
|
let waiting;
|
|
132
141
|
try {
|
|
@@ -181,7 +190,8 @@ export async function receiveOpenCodePending(target, env, signal) {
|
|
|
181
190
|
}
|
|
182
191
|
/** Publish the native address into current artifact seats; the legacy route projection is not read. */
|
|
183
192
|
export async function publishOpenCodeAddress(sessionId, env, signal) {
|
|
184
|
-
|
|
193
|
+
await restoreSessionSeats(ownerFor(sessionId), env, { kind: routeKind, address: { sessionId } }, signal);
|
|
194
|
+
const seats = (await discoverOpenCodeSeats(sessionId, env, signal)).filter(({ seat }) => seat.attachment === 'attached');
|
|
185
195
|
for (const { location, seat } of seats) {
|
|
186
196
|
if (signal.aborted)
|
|
187
197
|
return false;
|
|
@@ -199,6 +209,8 @@ export async function cancelOpenCodeDeliveries(sessionId, env, signal) {
|
|
|
199
209
|
for (const { location, seat } of await discoverOpenCodeSeats(sessionId, env, signal)) {
|
|
200
210
|
if (signal.aborted)
|
|
201
211
|
return;
|
|
212
|
+
if (seat.attachment !== 'attached')
|
|
213
|
+
continue;
|
|
202
214
|
const artifact = createArtifactPort(location, undefined, signal);
|
|
203
215
|
try {
|
|
204
216
|
const { value: through } = await artifact.read((facts) => facts.header().lastActIndex, signal);
|
|
@@ -215,9 +227,9 @@ export async function endOpenCodeSession(sessionId, env, signal) {
|
|
|
215
227
|
if (signal.aborted)
|
|
216
228
|
return;
|
|
217
229
|
const { Square } = await import('../../square-api.js');
|
|
218
|
-
const square = await Square.at({ path: location, env
|
|
230
|
+
const square = await Square.at({ path: location, env });
|
|
219
231
|
try {
|
|
220
|
-
await square.
|
|
232
|
+
await square.endHeld(seat.participant, { owner: seat.owner, generation: seat.generation });
|
|
221
233
|
}
|
|
222
234
|
finally {
|
|
223
235
|
await square.close();
|
package/dist/ports.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Act, ActivityId,
|
|
1
|
+
import type { Act, ActivityId, Owner, HardCap, Seat, StoredAct, WakeAddress, WakeRoute, WatchLease } from './model.js';
|
|
2
2
|
import type { MetadataMatch, DeliveryDeferralFact } from './delivery-deferral.js';
|
|
3
3
|
export type ActivityIndex = number;
|
|
4
4
|
export interface SquareHeader {
|
|
@@ -85,22 +85,22 @@ export interface ReceiptAssignment {
|
|
|
85
85
|
readonly owner: string;
|
|
86
86
|
readonly index: ActivityIndex;
|
|
87
87
|
}
|
|
88
|
-
export type
|
|
89
|
-
readonly [key: string]: JsonValue;
|
|
90
|
-
};
|
|
91
|
-
export type SeatRef = Omit<Seat, 'wakeAddress'>;
|
|
88
|
+
export type SeatRef = Pick<Seat, 'participant' | 'owner' | 'generation'>;
|
|
92
89
|
export type ArtifactWriteAuthority = {
|
|
93
90
|
readonly kind: 'participant';
|
|
94
91
|
readonly seat: SeatRef;
|
|
92
|
+
} | {
|
|
93
|
+
readonly kind: 'host-cleanup';
|
|
94
|
+
readonly seat: SeatRef;
|
|
95
95
|
} | {
|
|
96
96
|
readonly kind: 'join';
|
|
97
97
|
readonly participant: string;
|
|
98
|
-
readonly
|
|
98
|
+
readonly owner: Owner;
|
|
99
99
|
readonly wakeAddress?: WakeAddress;
|
|
100
100
|
} | {
|
|
101
101
|
readonly kind: 'takeover';
|
|
102
102
|
readonly participant: string;
|
|
103
|
-
readonly
|
|
103
|
+
readonly owner: Owner;
|
|
104
104
|
readonly expectedGeneration: ActivityId;
|
|
105
105
|
readonly wakeAddress?: WakeAddress;
|
|
106
106
|
};
|
|
@@ -168,9 +168,7 @@ export interface DeliveryCompletion {
|
|
|
168
168
|
/** Domain facts exist only during a synchronous artifact callback. Values are detached. */
|
|
169
169
|
export interface SquareRead {
|
|
170
170
|
seat(requestedName: string): Seat | undefined;
|
|
171
|
-
|
|
172
|
-
/** Latest completed coordinates only; never participant write authority. */
|
|
173
|
-
completedSeatsForBody(body: Body): readonly Seat[];
|
|
171
|
+
seatsForOwner(owner: Owner): readonly Seat[];
|
|
174
172
|
deliveryEvidence(participant: string, generation: ActivityId, activity?: ActivityId): readonly DeliveryEvidence[];
|
|
175
173
|
deliveryByToken(claimToken: string): DeliveryEvidence | undefined;
|
|
176
174
|
cancelledThrough(participant: string, generation: ActivityId): number | undefined;
|
|
@@ -219,6 +217,10 @@ export interface SquareWrite extends SquareRead {
|
|
|
219
217
|
readonly at: number;
|
|
220
218
|
}): StoredAct;
|
|
221
219
|
updateWakeAddress(seat: SeatRef, wakeAddress?: WakeAddress): boolean;
|
|
220
|
+
/** Join authority only; preserves membership and its establishing generation. */
|
|
221
|
+
reattachSeat(seat: SeatRef, wakeAddress?: WakeAddress): boolean;
|
|
222
|
+
/** Host-cleanup authority only; stale/already-detached coordinates are a no-op. */
|
|
223
|
+
detachSeat(seat: SeatRef): boolean;
|
|
222
224
|
cancelThrough(seat: SeatRef, through: ActivityIndex): boolean;
|
|
223
225
|
claimDelivery(input: DeliveryClaimInput): DeliveryClaimResult;
|
|
224
226
|
prepareDelivery(input: DeliveryPreparation): boolean;
|
|
@@ -245,7 +247,7 @@ export interface SquareCommitResult<R> extends SquareReadResult<R> {
|
|
|
245
247
|
/** Atomic artifact access; no framing, SQL or lazy transaction capability escapes. */
|
|
246
248
|
export interface SquareArtifactPort {
|
|
247
249
|
read<R>(select: (facts: SquareRead) => R, signal?: AbortSignal): Promise<SquareReadResult<R>>;
|
|
248
|
-
/** Participant/domain writes must carry an explicit
|
|
250
|
+
/** Participant/domain writes must carry an explicit owner; no owner-less mutation path exists. */
|
|
249
251
|
transactAs<R>(authority: ArtifactWriteAuthority, change: (facts: SquareWrite) => R, signal?: AbortSignal): Promise<SquareCommitResult<R>>;
|
|
250
252
|
/** Bounded cleanup/evidence settlement on this same connection after custody was acquired.
|
|
251
253
|
* Independent of request/lifetime cancellation; explicit close and authority fences still apply. */
|
|
@@ -295,28 +297,14 @@ export interface WakeRequest {
|
|
|
295
297
|
export interface PresentationSinkPort {
|
|
296
298
|
present(activity: StoredAct): void | Promise<void>;
|
|
297
299
|
}
|
|
298
|
-
/** Read-only presentation evidence projection for diagnostics and migration callers. */
|
|
299
|
-
export interface PresentationEvidenceProjection {
|
|
300
|
-
readonly location: string;
|
|
301
|
-
readonly participant: string;
|
|
302
|
-
readonly sessionId: string;
|
|
303
|
-
readonly activity: string;
|
|
304
|
-
readonly outcome: string;
|
|
305
|
-
readonly at?: number;
|
|
306
|
-
}
|
|
307
300
|
export type WakeOutcome = {
|
|
308
301
|
readonly outcome: 'accepted';
|
|
309
302
|
readonly signature?: string;
|
|
310
|
-
readonly attemptN?: number;
|
|
311
303
|
} | {
|
|
312
304
|
readonly outcome: 'failed';
|
|
313
305
|
readonly message?: string;
|
|
314
306
|
readonly signature?: string;
|
|
315
307
|
readonly diagnostic?: unknown;
|
|
316
|
-
readonly attemptN?: number;
|
|
317
|
-
readonly unavailable?: boolean;
|
|
318
|
-
readonly retainRoute?: boolean;
|
|
319
|
-
readonly routeStale?: boolean;
|
|
320
308
|
} | {
|
|
321
309
|
readonly outcome: 'not-capable';
|
|
322
310
|
readonly diagnostic?: string;
|
|
@@ -325,15 +313,7 @@ export type WakeOutcome = {
|
|
|
325
313
|
readonly signature?: string;
|
|
326
314
|
readonly message?: string;
|
|
327
315
|
readonly diagnostic?: unknown;
|
|
328
|
-
readonly attemptN?: number;
|
|
329
316
|
};
|
|
330
|
-
export interface DeliveryResult {
|
|
331
|
-
readonly attempted: number;
|
|
332
|
-
readonly accepted: number;
|
|
333
|
-
readonly failed: number;
|
|
334
|
-
readonly unknown: number;
|
|
335
|
-
readonly notCapable: number;
|
|
336
|
-
}
|
|
337
317
|
export interface DeliverPendingInput {
|
|
338
318
|
readonly artifact: SquareArtifactPort;
|
|
339
319
|
readonly transport: WakeTransportPort;
|