@astrosheep/square 0.3.69 → 0.3.71
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/activity-feed.d.ts +4 -5
- package/dist/activity-feed.js +14 -10
- package/dist/artifact.d.ts +26 -33
- package/dist/artifact.js +346 -317
- package/dist/attention-presentation.js +2 -9
- package/dist/automatic-session.js +6 -6
- package/dist/boundary-presentation.js +3 -3
- package/dist/catch-decisions.d.ts +19 -12
- package/dist/catch-decisions.js +32 -68
- package/dist/claude-delivery.js +7 -7
- package/dist/claude-mod.js +18 -7
- package/dist/cli/catch-presentation.d.ts +7 -0
- package/dist/cli/catch-presentation.js +55 -0
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +5 -23
- package/dist/cli/express-presentation.d.ts +10 -0
- package/dist/cli/express-presentation.js +196 -0
- package/dist/cli/maintenance-commands.d.ts +4 -0
- package/dist/cli/maintenance-commands.js +29 -6
- package/dist/cli/observation-commands.d.ts +7 -5
- package/dist/cli/observation-commands.js +275 -262
- package/dist/cli/program.d.ts +1 -1
- package/dist/cli/program.js +43 -56
- package/dist/cli/registry.js +2 -1
- package/dist/cli/square-commands.d.ts +3 -9
- package/dist/cli/square-commands.js +134 -255
- package/dist/codex-queue.js +4 -1
- package/dist/decisions.d.ts +26 -74
- package/dist/decisions.js +190 -335
- package/dist/delivery-health.js +13 -22
- package/dist/delivery-operations.d.ts +0 -11
- package/dist/delivery-operations.js +44 -33
- package/dist/delivery.d.ts +33 -32
- package/dist/delivery.js +70 -81
- package/dist/harness-claude.js +1 -1
- package/dist/harness-codex.js +1 -1
- package/dist/harness-pi.js +1 -1
- package/dist/help.js +6 -1
- package/dist/inbox.d.ts +27 -0
- package/dist/inbox.js +55 -18
- package/dist/index.d.ts +2 -4
- package/dist/index.js +1 -1
- package/dist/list.d.ts +7 -1
- package/dist/list.js +49 -122
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +7 -37
- package/dist/model.d.ts +4 -44
- package/dist/model.js +1 -3
- package/dist/notifications.d.ts +1 -1
- package/dist/notifications.js +13 -7
- package/dist/open-square.d.ts +16 -2
- package/dist/open-square.js +40 -1
- package/dist/perception-projection.d.ts +6 -15
- package/dist/perception-projection.js +6 -26
- package/dist/{opencode-delivery.d.ts → plugins/opencode/delivery.d.ts} +1 -1
- package/dist/{opencode-delivery.js → plugins/opencode/delivery.js} +18 -18
- package/dist/{opencode.d.ts → plugins/opencode/index.d.ts} +2 -2
- package/dist/{opencode.js → plugins/opencode/index.js} +9 -9
- package/dist/ports.d.ts +156 -11
- package/dist/presentation-operations.d.ts +1 -1
- package/dist/presentation-operations.js +35 -44
- package/dist/presentation.d.ts +12 -19
- package/dist/presentation.js +33 -54
- package/dist/routes.d.ts +7 -14
- package/dist/routes.js +33 -62
- package/dist/runtime.d.ts +12 -39
- package/dist/runtime.js +33 -164
- package/dist/square-actions.d.ts +11 -21
- package/dist/square-actions.js +171 -271
- package/dist/square-application.d.ts +31 -55
- package/dist/square-application.js +637 -141
- package/dist/square-core.d.ts +3 -94
- package/dist/square-core.js +8 -353
- package/dist/square-domain.d.ts +24 -0
- package/dist/square-domain.js +77 -0
- package/dist/square-facade.d.ts +360 -9
- package/dist/square-migration.d.ts +24 -0
- package/dist/square-migration.js +211 -0
- package/dist/square-projections.d.ts +2 -42
- package/dist/square-projections.js +1 -37
- package/dist/square-sqlite.d.ts +59 -0
- package/dist/square-sqlite.js +702 -0
- package/dist/stream.d.ts +3 -10
- package/dist/stream.js +81 -52
- package/dist/views.d.ts +27 -95
- package/dist/views.js +217 -87
- package/dist/wake-eligibility.d.ts +15 -5
- package/dist/wake-eligibility.js +32 -16
- package/dist/wakes.d.ts +3 -3
- package/dist/wakes.js +31 -27
- package/guides/application-facade-delivery-evidence.md +200 -0
- package/guides/application-facade-design.md +95 -0
- package/guides/change-waits.md +4 -4
- package/guides/migration.md +77 -0
- package/guides/pi-native-delivery.md +1 -1
- package/guides/primitive-catch-consolidation.md +85 -0
- package/guides/primitive-history-consolidation.md +76 -0
- package/guides/primitive-status-consolidation.md +87 -0
- package/guides/primitive-storage-consolidation.md +128 -0
- package/guides/row-runtime-delivery-evidence.md +160 -0
- package/guides/row-storage-design.md +567 -0
- package/package.json +5 -7
- package/{claude-plugin → plugins/claude}/.claude-plugin/plugin.json +1 -1
- package/{codex-plugin → plugins/codex}/.codex-plugin/plugin.json +1 -1
- package/plugins/opencode/delivery.ts +149 -0
- package/plugins/opencode/index.ts +136 -0
- package/plugins/paseo/OVERVIEW.md +14 -0
- package/plugins/paseo/README.md +54 -0
- package/plugins/paseo/client/square-message.tsx +106 -0
- package/plugins/paseo/client/transform.ts +24 -0
- package/plugins/paseo/index.client.tsx +19 -0
- package/plugins/paseo/package.json +19 -0
- package/plugins/paseo/paseo-plugin.json +7 -0
- package/plugins/paseo/shared/message.ts +29 -0
- package/{extensions → plugins/pi}/square-pi.js +8 -5
- package/dist/activity.d.ts +0 -14
- package/dist/activity.js +0 -248
- package/dist/square-file-adapter.d.ts +0 -26
- package/dist/square-file-adapter.js +0 -85
- package/dist/square-state.d.ts +0 -6
- package/dist/square-state.js +0 -138
- package/dist/square-storage.d.ts +0 -14
- package/dist/square-storage.js +0 -188
- package/dist/square-wiring.d.ts +0 -33
- package/dist/square-wiring.js +0 -109
- package/dist/watch.d.ts +0 -8
- package/dist/watch.js +0 -252
- /package/{claude-plugin → plugins/claude}/hooks/hooks.json +0 -0
- /package/{claude-plugin → plugins/claude}/hooks/register.js +0 -0
- /package/{claude-plugin → plugins/claude}/skills/square/SKILL.md +0 -0
- /package/{claude-plugin → plugins/claude}/types.d.ts +0 -0
- /package/{codex-plugin → plugins/codex}/hooks/hooks.json +0 -0
package/dist/inbox.js
CHANGED
|
@@ -1,21 +1,55 @@
|
|
|
1
1
|
import { nameKey } from './model.js';
|
|
2
|
-
import {
|
|
2
|
+
import { createArtifactPort, observeSquareRevision } from './artifact.js';
|
|
3
3
|
import { hostLedgerForEnv } from './registry.js';
|
|
4
4
|
import { canonicalPath } from './canonical-path.js';
|
|
5
|
-
import { projectBoundaryEligibility,
|
|
6
|
-
import { WATCH_STALE_MS } from './runtime.js';
|
|
5
|
+
import { projectBoundaryEligibility, projectSessionBindings } from './square-projections.js';
|
|
6
|
+
import { freshWatchLease, WATCH_STALE_MS } from './runtime.js';
|
|
7
|
+
import { pendingHead, pendingNotifications, leaseOwnsNotification } from './delivery.js';
|
|
8
|
+
import { attentionBodyIsClipped, renderAttentionPreview } from './attention-presentation.js';
|
|
9
|
+
function bindingCoordinate(binding) {
|
|
10
|
+
return JSON.stringify([binding.location, nameKey(binding.participant), binding.sessionId, binding.channel, binding.epoch, binding.cancelledThrough ?? -1]);
|
|
11
|
+
}
|
|
7
12
|
function notificationKey(membership, actIndex) {
|
|
8
13
|
return membership.squarePath + '\0' + membership.name.toLocaleLowerCase() + '\0' + actIndex;
|
|
9
14
|
}
|
|
15
|
+
export function projectPresentation(facts, requested, now = Date.now()) {
|
|
16
|
+
const participant = facts.participant(requested.participant);
|
|
17
|
+
if (!participant?.joined)
|
|
18
|
+
return { binding: requested, joined: false, notifications: [] };
|
|
19
|
+
const binding = { ...requested, participant: participant.name };
|
|
20
|
+
const notifications = pendingNotifications(facts, participant.name).map(({ item, route }) => ({
|
|
21
|
+
actIndex: item.index, actor: item.actor, at: item.at, body: item.body, route,
|
|
22
|
+
}));
|
|
23
|
+
const catchLease = freshWatchLease(facts, participant.name, now);
|
|
24
|
+
return { binding, joined: true, notifications, ...(catchLease === undefined ? {} : { catchLease }) };
|
|
25
|
+
}
|
|
26
|
+
/** First matching ordered route, exact native epoch/address and catch ownership. */
|
|
27
|
+
export function nativePendingPreview(facts, input) {
|
|
28
|
+
const route = facts.routes().find((candidate) => candidate.kind === input.routeKind && candidate.sessionId === input.sessionId
|
|
29
|
+
&& candidate.epoch === input.epoch && nameKey(candidate.participant) === nameKey(input.participant)
|
|
30
|
+
&& (input.routeKind === 'claude-native' ? candidate.address.endpoint === input.address.endpoint : candidate.address.sessionId === input.address.sessionId));
|
|
31
|
+
if (!route || input.actIndex <= (input.cancelledThrough ?? -1))
|
|
32
|
+
return undefined;
|
|
33
|
+
const head = pendingHead(facts, input.participant, input.actIndex);
|
|
34
|
+
const lease = freshWatchLease(facts, input.participant, input.now);
|
|
35
|
+
if (!head || (lease !== undefined && leaseOwnsNotification(lease, head)))
|
|
36
|
+
return undefined;
|
|
37
|
+
const item = facts.activity(input.actIndex);
|
|
38
|
+
if (item?.kind !== 'say')
|
|
39
|
+
return undefined;
|
|
40
|
+
return { payload: renderAttentionPreview({ squarePath: input.location, recipient: input.participant, actIndex: item.index,
|
|
41
|
+
actor: item.actor, route: head.route, body: item.body }), clipped: attentionBodyIsClipped(item.body) };
|
|
42
|
+
}
|
|
10
43
|
async function readInboxMembership(binding, signal) {
|
|
11
|
-
const artifact =
|
|
44
|
+
const artifact = createArtifactPort(binding.location, undefined, signal);
|
|
12
45
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
notifications: [...projection.notifications],
|
|
18
|
-
|
|
46
|
+
return await artifact.read((facts) => {
|
|
47
|
+
const projection = projectPresentation(facts, binding);
|
|
48
|
+
if (!projection.joined)
|
|
49
|
+
return undefined;
|
|
50
|
+
return { name: projection.binding.participant, squarePath: projection.binding.location, notifications: [...projection.notifications],
|
|
51
|
+
...(projection.catchLease === undefined ? {} : { catchLease: projection.catchLease }) };
|
|
52
|
+
}, signal);
|
|
19
53
|
}
|
|
20
54
|
finally {
|
|
21
55
|
await artifact.close();
|
|
@@ -28,7 +62,7 @@ export async function sessionInbox(sessionId, env = process.env, signal) {
|
|
|
28
62
|
if (signal?.aborted)
|
|
29
63
|
throw signal.reason;
|
|
30
64
|
try {
|
|
31
|
-
const membership = await readInboxMembership(binding, signal);
|
|
65
|
+
const { value: membership } = await readInboxMembership(binding, signal);
|
|
32
66
|
if (membership !== undefined)
|
|
33
67
|
inbox.push(membership);
|
|
34
68
|
}
|
|
@@ -100,19 +134,18 @@ export async function observeSessionPending(sessionId, suppliedEnv = process.env
|
|
|
100
134
|
for (const file of paths) {
|
|
101
135
|
if (artifacts.has(file))
|
|
102
136
|
continue;
|
|
103
|
-
const observer = await
|
|
137
|
+
const observer = await observeSquareRevision(file);
|
|
104
138
|
if (signal.aborted) {
|
|
105
139
|
observer.close();
|
|
106
140
|
return [];
|
|
107
141
|
}
|
|
108
142
|
artifacts.set(file, { observer, inbox: new Map() });
|
|
109
143
|
}
|
|
144
|
+
const revisions = new Map();
|
|
110
145
|
for (const [file, entry] of artifacts) {
|
|
111
146
|
const source = await capture(entry.observer, 'artifact', signal);
|
|
112
147
|
sources.push(source);
|
|
113
|
-
|
|
114
|
-
entry.inbox.clear();
|
|
115
|
-
entry.revision = source.value;
|
|
148
|
+
revisions.set(file, source.value);
|
|
116
149
|
const names = new Set(bindings.filter((binding) => binding.location === file).map((binding) => nameKey(binding.participant)));
|
|
117
150
|
for (const name of entry.inbox.keys())
|
|
118
151
|
if (!names.has(name))
|
|
@@ -125,9 +158,13 @@ export async function observeSessionPending(sessionId, suppliedEnv = process.env
|
|
|
125
158
|
const entry = artifacts.get(binding.location);
|
|
126
159
|
const name = nameKey(binding.participant);
|
|
127
160
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
161
|
+
const coordinate = bindingCoordinate(binding);
|
|
162
|
+
const cached = entry.inbox.get(name);
|
|
163
|
+
if (cached?.version !== revisions.get(binding.location) || cached?.binding !== coordinate) {
|
|
164
|
+
const projection = await readInboxMembership(binding, signal);
|
|
165
|
+
entry.inbox.set(name, { ...projection, binding: coordinate });
|
|
166
|
+
}
|
|
167
|
+
const membership = entry.inbox.get(name)?.value;
|
|
131
168
|
if (membership === undefined)
|
|
132
169
|
continue;
|
|
133
170
|
const { catchLease, ...rest } = membership;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Square } from './square-
|
|
1
|
+
export { Square } from './square-application.js';
|
|
2
2
|
export { createSquareApplication } from './square-application.js';
|
|
3
3
|
export { SquareError } from './model.js';
|
|
4
4
|
export { squareAssignedParticipantName } from './registry.js';
|
|
@@ -6,6 +6,4 @@ export { createDefaultWakeTransport } from './notifications.js';
|
|
|
6
6
|
export { createHostLedgerPort, FileHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
7
7
|
export type { HostLedgerPort, PresenceRecord, EvidenceRecord } from './host-ledger.js';
|
|
8
8
|
export type { PresentationSinkPort } from './ports.js';
|
|
9
|
-
export type
|
|
10
|
-
export type { ActivityId } from './square-core.js';
|
|
11
|
-
export type { Activity, CatchOptions, CatchResult, ExpressOptions, ExpressResult, HistoryQuery, OperationControl, OperationProgress, ListenerChangeResult, OpenOptions, Participant, ParticipantStatus, PerceivedActivity, SquareAtInput, SquareBuildInput, SquareSnapshot, SquareSource, } from './square-facade.js';
|
|
9
|
+
export type * from './square-facade.js';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { Square } from './square-
|
|
1
|
+
export { Square } from './square-application.js';
|
|
2
2
|
export { createSquareApplication } from './square-application.js';
|
|
3
3
|
export { SquareError } from './model.js';
|
|
4
4
|
export { squareAssignedParticipantName } from './registry.js';
|
package/dist/list.d.ts
CHANGED
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import type { DiscoveryApplicationData, DiscoveryApplicationOptions, OpenOptions, OperationControl } from './square-facade.js';
|
|
2
|
+
export declare const DEFAULT_LIST_DEPTH = 4;
|
|
3
|
+
export declare const MAX_LIST_DEPTH = 16;
|
|
4
|
+
export declare const DEFAULT_LIST_LIMIT = 20;
|
|
5
|
+
export declare const MAX_LIST_LIMIT = 100;
|
|
6
|
+
/** Bounded deterministic discovery. Only the application calls this private operation. */
|
|
7
|
+
export declare function discoverSquares(root: string, options?: DiscoveryApplicationOptions, control?: OperationControl, openOptions?: OpenOptions): Promise<DiscoveryApplicationData>;
|
package/dist/list.js
CHANGED
|
@@ -1,46 +1,51 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { openSquare } from './open-square.js';
|
|
4
4
|
import { closeOpenSquare } from './open-square.js';
|
|
5
5
|
import { listPresentation } from './views.js';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const DEFAULT_LIST_LIMIT = 20;
|
|
12
|
-
const MAX_LIST_LIMIT = 100;
|
|
6
|
+
import { SquareError } from './model.js';
|
|
7
|
+
export const DEFAULT_LIST_DEPTH = 4;
|
|
8
|
+
export const MAX_LIST_DEPTH = 16;
|
|
9
|
+
export const DEFAULT_LIST_LIMIT = 20;
|
|
10
|
+
export const MAX_LIST_LIMIT = 100;
|
|
13
11
|
const LIST_DISCOVERY_BUDGET = 10_000;
|
|
14
|
-
const CONTEXT_PREVIEW_LINES = 2;
|
|
15
|
-
const PARTICIPANT_PREVIEW_COUNT = 3;
|
|
16
|
-
const DISPLAY_CHARACTER_LIMIT = 160;
|
|
17
12
|
const LIST_SKIP_DIRS = new Set(['.git', 'node_modules', 'dist']);
|
|
18
|
-
async function readSquareListItem(filePath, root) {
|
|
19
|
-
|
|
13
|
+
async function readSquareListItem(filePath, root, options, control) {
|
|
14
|
+
if (!filePath.endsWith('.square'))
|
|
15
|
+
return null;
|
|
20
16
|
try {
|
|
21
|
-
|
|
17
|
+
control?.signal?.throwIfAborted();
|
|
18
|
+
const stat = await fs.promises.stat(filePath);
|
|
19
|
+
const square = await openSquare(filePath, { ...options, env: options.env ?? {}, signal: control?.signal }, control);
|
|
20
|
+
const projection = await listPresentation(square, control).finally(() => closeOpenSquare(square));
|
|
21
|
+
return {
|
|
22
|
+
path: path.relative(root, filePath) || path.basename(filePath),
|
|
23
|
+
lastActiveAt: stat.mtimeMs,
|
|
24
|
+
context: [...projection.context].map((line) => line.trim()).filter(Boolean),
|
|
25
|
+
participants: [...projection.participants],
|
|
26
|
+
activities: projection.activities,
|
|
27
|
+
};
|
|
22
28
|
}
|
|
23
|
-
catch {
|
|
29
|
+
catch (error) {
|
|
30
|
+
control?.signal?.throwIfAborted();
|
|
31
|
+
// A vanished, unreadable or undecodable candidate does not abort discovery.
|
|
24
32
|
return null;
|
|
25
33
|
}
|
|
26
|
-
const square = await probeSquare(filePath);
|
|
27
|
-
if (square === undefined)
|
|
28
|
-
return null;
|
|
29
|
-
const projection = await listPresentation(square).finally(() => closeOpenSquare(square));
|
|
30
|
-
const relative = path.relative(root, filePath) || path.basename(filePath);
|
|
31
|
-
return {
|
|
32
|
-
path: relative,
|
|
33
|
-
lastActiveAt: stat.mtimeMs,
|
|
34
|
-
context: [...projection.context].map((line) => line.trim()).filter(Boolean),
|
|
35
|
-
participants: [...projection.participants],
|
|
36
|
-
activities: projection.activities,
|
|
37
|
-
};
|
|
38
34
|
}
|
|
39
|
-
|
|
35
|
+
/** Bounded deterministic discovery. Only the application calls this private operation. */
|
|
36
|
+
export async function discoverSquares(root, options = {}, control, openOptions = {}) {
|
|
37
|
+
const depth = options.depth ?? DEFAULT_LIST_DEPTH;
|
|
38
|
+
const limit = options.limit ?? DEFAULT_LIST_LIMIT;
|
|
39
|
+
if (!Number.isSafeInteger(depth) || depth < 0 || depth > MAX_LIST_DEPTH
|
|
40
|
+
|| !Number.isSafeInteger(limit) || limit < 1 || limit > MAX_LIST_LIMIT
|
|
41
|
+
|| (options.after !== undefined && (options.after.length === 0 || path.isAbsolute(options.after)))) {
|
|
42
|
+
throw new SquareError('invalid_args', 'Invalid discovery depth, limit or relative cursor');
|
|
43
|
+
}
|
|
40
44
|
const items = [];
|
|
41
45
|
let examined = 0;
|
|
42
46
|
let stopped = false;
|
|
43
|
-
async function walk(dir,
|
|
47
|
+
async function walk(dir, level) {
|
|
48
|
+
control?.signal?.throwIfAborted();
|
|
44
49
|
if (stopped)
|
|
45
50
|
return;
|
|
46
51
|
let entries;
|
|
@@ -48,110 +53,32 @@ async function collectSquareList(root, maxDepth) {
|
|
|
48
53
|
entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
49
54
|
}
|
|
50
55
|
catch {
|
|
51
|
-
|
|
56
|
+
control?.signal?.throwIfAborted();
|
|
52
57
|
return;
|
|
53
58
|
}
|
|
54
59
|
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
55
60
|
for (const entry of entries) {
|
|
61
|
+
control?.signal?.throwIfAborted();
|
|
56
62
|
if (stopped)
|
|
57
63
|
return;
|
|
58
|
-
examined
|
|
59
|
-
if (examined === LIST_DISCOVERY_BUDGET)
|
|
64
|
+
if (++examined === LIST_DISCOVERY_BUDGET)
|
|
60
65
|
stopped = true;
|
|
61
66
|
const fullPath = path.join(dir, entry.name);
|
|
62
67
|
if (entry.isDirectory()) {
|
|
63
|
-
if (!stopped &&
|
|
64
|
-
await walk(fullPath,
|
|
65
|
-
continue;
|
|
68
|
+
if (!stopped && level < depth && !LIST_SKIP_DIRS.has(entry.name))
|
|
69
|
+
await walk(fullPath, level + 1);
|
|
66
70
|
}
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
items.push(item);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
await walk(root, 0);
|
|
75
|
-
return { items: items.sort((a, b) => a.path.localeCompare(b.path)), stopped };
|
|
76
|
-
}
|
|
77
|
-
function characterPreview(value) {
|
|
78
|
-
const characters = Array.from(value);
|
|
79
|
-
return characters.length <= DISPLAY_CHARACTER_LIMIT ? value : `${characters.slice(0, DISPLAY_CHARACTER_LIMIT - 1).join('')}…`;
|
|
80
|
-
}
|
|
81
|
-
function renderSquareList(items, stopped, depth, limit, after) {
|
|
82
|
-
const page = after === undefined ? items : items.filter((item) => item.path.localeCompare(after) > 0);
|
|
83
|
-
const shownItems = page.slice(0, limit);
|
|
84
|
-
if (items.length === 0) {
|
|
85
|
-
return [`(no squares found)`, ...(stopped ? [style('dim', `○ the walk stopped early — deeper squares may still be hiding`)] : [])].join('\n') + '\n';
|
|
86
|
-
}
|
|
87
|
-
const now = Date.now();
|
|
88
|
-
const lines = ['squares'];
|
|
89
|
-
for (const item of shownItems) {
|
|
90
|
-
const glyph = item.activities > 0 ? '●' : style('dim', '○');
|
|
91
|
-
lines.push(`${glyph} ${characterPreview(item.path)}${style('dim', ` · ${formatRelativeTime(item.lastActiveAt, now)} · ${item.participants.length} in the square · ${item.activities} ${item.activities === 1 ? 'activity' : 'activities'}`)}`);
|
|
92
|
-
const shownContext = item.context.slice(0, CONTEXT_PREVIEW_LINES);
|
|
93
|
-
if (shownContext.length === 0) {
|
|
94
|
-
lines.push(` ${style('dim', 'context')} · (none)`);
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
shownContext.forEach((line, index) => lines.push(` ${index === 0 ? style('dim', 'context') : ' '} · ${characterPreview(line)}`));
|
|
98
|
-
const hiddenContext = item.context.length - shownContext.length;
|
|
99
|
-
if (hiddenContext > 0)
|
|
100
|
-
lines.push(style('dim', ` · … ${hiddenContext} more ${hiddenContext === 1 ? 'line' : 'lines'}`));
|
|
101
|
-
}
|
|
102
|
-
const shownParticipants = item.participants.slice(0, PARTICIPANT_PREVIEW_COUNT);
|
|
103
|
-
const hiddenParticipants = item.participants.length - shownParticipants.length;
|
|
104
|
-
const participantNames = shownParticipants.length === 0 ? 'nobody' : shownParticipants.map((participant) => participantIdentity(characterPreview(participant))).join(' · ');
|
|
105
|
-
lines.push(` ${style('dim', 'participants')} · ${participantNames}${hiddenParticipants > 0 ? style('dim', ` · … ${hiddenParticipants} more`) : ''}`);
|
|
106
|
-
}
|
|
107
|
-
const hiddenItems = page.length - shownItems.length;
|
|
108
|
-
if (hiddenItems > 0) {
|
|
109
|
-
const cursor = shownItems.at(-1)?.path;
|
|
110
|
-
lines.push(style('dim', stopped ? ' … more squares' : ` … ${hiddenItems} more ${hiddenItems === 1 ? 'square' : 'squares'}`));
|
|
111
|
-
if (cursor !== undefined)
|
|
112
|
-
lines.push(`square list --depth ${depth} --limit ${limit} --after ${quoteShell(cursor)}`);
|
|
113
|
-
}
|
|
114
|
-
if (stopped)
|
|
115
|
-
lines.push(style('dim', `○ the walk stopped early — deeper squares may still be hiding`));
|
|
116
|
-
return lines.join('\n') + '\n';
|
|
117
|
-
}
|
|
118
|
-
function parseListOptions(args, usage) {
|
|
119
|
-
let depth = DEFAULT_LIST_DEPTH;
|
|
120
|
-
let limit = DEFAULT_LIST_LIMIT;
|
|
121
|
-
let after;
|
|
122
|
-
for (let index = 0; index < args.length; index += 2) {
|
|
123
|
-
const option = args[index];
|
|
124
|
-
const value = args[index + 1];
|
|
125
|
-
if (value === undefined || (option !== '--depth' && option !== '--limit' && option !== '--after')) {
|
|
126
|
-
usage();
|
|
127
|
-
return { depth, limit };
|
|
128
|
-
}
|
|
129
|
-
if (option === '--after') {
|
|
130
|
-
if (after !== undefined || value.length === 0 || path.isAbsolute(value)) {
|
|
131
|
-
usage();
|
|
132
|
-
return { depth, limit };
|
|
71
|
+
else if (entry.isFile()) {
|
|
72
|
+
const item = await readSquareListItem(fullPath, root, openOptions, control);
|
|
73
|
+
if (item !== null)
|
|
74
|
+
items.push(item);
|
|
133
75
|
}
|
|
134
|
-
after = value;
|
|
135
|
-
continue;
|
|
136
76
|
}
|
|
137
|
-
if (!/^\d+$/.test(value)) {
|
|
138
|
-
usage();
|
|
139
|
-
return { depth, limit };
|
|
140
|
-
}
|
|
141
|
-
const parsed = Number(value);
|
|
142
|
-
if (!Number.isSafeInteger(parsed) || (option === '--depth' ? parsed > MAX_LIST_DEPTH : parsed === 0 || parsed > MAX_LIST_LIMIT)) {
|
|
143
|
-
usage();
|
|
144
|
-
return { depth, limit };
|
|
145
|
-
}
|
|
146
|
-
if (option === '--depth')
|
|
147
|
-
depth = parsed;
|
|
148
|
-
else
|
|
149
|
-
limit = parsed;
|
|
150
77
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
|
|
78
|
+
await walk(root, 0);
|
|
79
|
+
const page = items.sort((a, b) => a.path.localeCompare(b.path))
|
|
80
|
+
.filter((item) => options.after === undefined || item.path.localeCompare(options.after) > 0);
|
|
81
|
+
const selected = page.slice(0, limit);
|
|
82
|
+
const remaining = page.length - selected.length;
|
|
83
|
+
return { items: selected, total: items.length, stopped, remaining, ...(remaining > 0 ? { next: selected.at(-1).path } : {}) };
|
|
157
84
|
}
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import {
|
|
2
|
+
import type { SquareApplicationContext } from './square-facade.js';
|
|
3
3
|
export interface SquareMcpOptions extends SquareApplicationContext {
|
|
4
4
|
}
|
|
5
5
|
export type SquareMcpServer = McpServer;
|
package/dist/mcp.js
CHANGED
|
@@ -5,7 +5,6 @@ import { SquareError, isSquareError } from './model.js';
|
|
|
5
5
|
import { operationEnv } from './automatic-session.js';
|
|
6
6
|
import { SQUARE_IDENTITY } from './identity.js';
|
|
7
7
|
import { createSquareApplication } from './square-application.js';
|
|
8
|
-
import { toPublicActivity } from './views.js';
|
|
9
8
|
const activityId = z.string().regex(/^act\/(0|[1-9][0-9]*)$/);
|
|
10
9
|
const stringArray = z.array(z.string());
|
|
11
10
|
const participantName = z.string().optional().describe("Participant name, same as --as. Defaults to the server's configured participant.");
|
|
@@ -23,36 +22,6 @@ const TOOL_DEFINITIONS = [
|
|
|
23
22
|
{ name: 'status', description: 'Read the public status of the square.', inputSchema: z.object({}).strict() },
|
|
24
23
|
{ name: 'participants', description: 'List participants standing in or done with the square.', inputSchema: z.object({}).strict() },
|
|
25
24
|
];
|
|
26
|
-
function isObject(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); }
|
|
27
|
-
function publicActivity(activity) { return { ...activity }; }
|
|
28
|
-
function publicResult(name, value) {
|
|
29
|
-
if (name === 'status') {
|
|
30
|
-
const result = value;
|
|
31
|
-
const state = result.status;
|
|
32
|
-
const { latestAct, participants, ...rest } = state;
|
|
33
|
-
return {
|
|
34
|
-
hardCap: rest.hardCap,
|
|
35
|
-
...(rest.throttlePerMinute === undefined ? {} : { throttlePerMinute: rest.throttlePerMinute }),
|
|
36
|
-
activeCount: rest.activeCount,
|
|
37
|
-
doneCount: rest.doneCount,
|
|
38
|
-
hold: rest.holdActive ? { by: rest.holdActor, ...(rest.holdReason === undefined ? {} : { reason: rest.holdReason }), ...(rest.holdAt === undefined ? {} : { at: rest.holdAt }) } : null,
|
|
39
|
-
participants: participants.filter((participant) => participant.state !== 'not joined').map((participant) => ({ name: participant.name, state: participant.state, presence: participant.presence, activityCount: participant.activityCount, ...(participant.lastActiveAt === undefined ? {} : { lastActiveAt: participant.lastActiveAt }), unreadActivityCount: participant.unreadActivityCount, pendingMentionCount: participant.pendingMentionCount, listening: participant.listening })),
|
|
40
|
-
...(latestAct === undefined ? {} : { latestActivity: publicActivity(toPublicActivity(latestAct)) }),
|
|
41
|
-
now: rest.now,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
if (name === 'express' || name === 'hold' || name === 'resume' || name === 'done') {
|
|
45
|
-
const result = value;
|
|
46
|
-
return { ...(result.activity === undefined ? {} : { activity: result.activity === null ? null : publicActivity(result.activity) }), ...(result.waited === undefined ? {} : { waited: result.waited }), ...(result.replyAuthorNotHere === undefined ? {} : { replyAuthorNotHere: result.replyAuthorNotHere }) };
|
|
47
|
-
}
|
|
48
|
-
if (name === 'history')
|
|
49
|
-
return { activities: value };
|
|
50
|
-
if (name === 'participants')
|
|
51
|
-
return { participants: value };
|
|
52
|
-
if (name === 'listening')
|
|
53
|
-
return { listening: value };
|
|
54
|
-
return value;
|
|
55
|
-
}
|
|
56
25
|
function operation(app, name, args, control) {
|
|
57
26
|
switch (name) {
|
|
58
27
|
case 'join': return app.join({ takeover: args.takeover }, control);
|
|
@@ -68,8 +37,8 @@ function operation(app, name, args, control) {
|
|
|
68
37
|
case 'hold': return app.hold(args.reason, control);
|
|
69
38
|
case 'resume': return app.resume(control);
|
|
70
39
|
case 'done': return app.done(undefined, control);
|
|
71
|
-
case 'status': return app.status();
|
|
72
|
-
case 'participants': return app.participants();
|
|
40
|
+
case 'status': return app.status(undefined, control);
|
|
41
|
+
case 'participants': return app.participants(control);
|
|
73
42
|
default: throw new SquareError('invalid_args', `Unknown tool: ${name}`);
|
|
74
43
|
}
|
|
75
44
|
}
|
|
@@ -90,9 +59,8 @@ export function createSquareMcpServer(options) {
|
|
|
90
59
|
? operationEnv('opencode', opencodeSessionId, baseEnv)
|
|
91
60
|
: baseEnv;
|
|
92
61
|
const app = createSquareApplication({ ...options, env, participant: participant ?? options.participant });
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const structuredContent = isObject(projected) ? projected : { result: projected };
|
|
62
|
+
const outcome = await operation(app, tool.name, operationArgs, { signal: extra.signal });
|
|
63
|
+
const structuredContent = outcome.data;
|
|
96
64
|
return { content: [{ type: 'text', text: JSON.stringify(structuredContent) }], structuredContent };
|
|
97
65
|
}
|
|
98
66
|
catch (error) {
|
|
@@ -101,7 +69,9 @@ export function createSquareMcpServer(options) {
|
|
|
101
69
|
: isSquareError(error)
|
|
102
70
|
? { code: error.code, message: error.message, ...(error.facts === undefined ? {} : { facts: error.facts }) }
|
|
103
71
|
: { code: 'internal', message: error instanceof Error ? error.message : String(error) };
|
|
104
|
-
|
|
72
|
+
const operation = error instanceof Error ? error.operation : undefined;
|
|
73
|
+
const failure = operation === undefined ? normalized : { ...normalized, operation };
|
|
74
|
+
return { isError: true, content: [{ type: 'text', text: JSON.stringify(failure) }], structuredContent: { error: failure } };
|
|
105
75
|
}
|
|
106
76
|
});
|
|
107
77
|
}
|
package/dist/model.d.ts
CHANGED
|
@@ -15,8 +15,6 @@ export interface WakeRoute {
|
|
|
15
15
|
address: Record<string, string>;
|
|
16
16
|
updatedAt: number;
|
|
17
17
|
}
|
|
18
|
-
export interface ReceiverRoute extends WakeRoute {
|
|
19
|
-
}
|
|
20
18
|
export type SquareErrorCode = 'invalid_name' | 'invalid_args' | 'unknown_participant' | 'not_joined' | 'already_joined' | 'already_done' | 'held' | 'capped' | 'throttled' | 'bell_quota' | 'behind' | 'io' | 'unavailable';
|
|
21
19
|
export type InternalSquareErrorCode = SquareErrorCode | 'not_found' | 'cap_reached' | 'conflict' | 'pending_peer';
|
|
22
20
|
export interface SquareErrorFacts {
|
|
@@ -24,9 +22,11 @@ export interface SquareErrorFacts {
|
|
|
24
22
|
activityUnsent?: true;
|
|
25
23
|
/** Why a name could not be resolved: never in the roster, no longer standing in it, a bell
|
|
26
24
|
* colliding with a mention, an @name that matches nobody, or an activity catch cannot address. */
|
|
27
|
-
reason?: 'never_joined' | 'not_standing' | 'bell_mention_conflict' | 'unmatched_mention' | 'not_addressed';
|
|
25
|
+
reason?: 'never_joined' | 'not_standing' | 'bell_mention_conflict' | 'unmatched_mention' | 'not_addressed' | 'migration_required' | 'explicit_reach_required' | 'invalid_reply' | 'invalid_done_body';
|
|
28
26
|
/** The activity id a `catch --id` refusal named. */
|
|
29
27
|
activityId?: string;
|
|
28
|
+
/** Requested recipient spellings, without parsing presentation copy. */
|
|
29
|
+
targets?: readonly string[];
|
|
30
30
|
/** Whether the artifact holds that activity at all; an unknown id needs an ordinary page. */
|
|
31
31
|
activityExists?: boolean;
|
|
32
32
|
pending?: number;
|
|
@@ -37,6 +37,7 @@ export interface SquareErrorFacts {
|
|
|
37
37
|
declare class SquareErrorBase<Code extends string> extends Error {
|
|
38
38
|
code: Code;
|
|
39
39
|
facts?: SquareErrorFacts | undefined;
|
|
40
|
+
operation?: import('./square-facade.js').ApplicationFailureDetail;
|
|
40
41
|
constructor(code: Code, message: string, facts?: SquareErrorFacts | undefined);
|
|
41
42
|
}
|
|
42
43
|
export declare class SquareError extends SquareErrorBase<SquareErrorCode> {
|
|
@@ -55,7 +56,6 @@ export type StoredAct = Act & {
|
|
|
55
56
|
index: number;
|
|
56
57
|
at: number;
|
|
57
58
|
};
|
|
58
|
-
export type StoredActHead = StoredAct extends infer T ? T extends StoredAct ? Omit<T, 'body' | 'through' | 'index'> : never : never;
|
|
59
59
|
export type ObservationState = 'seen';
|
|
60
60
|
export interface ActivityObservation {
|
|
61
61
|
state: ObservationState;
|
|
@@ -85,40 +85,6 @@ export interface InboxMembership {
|
|
|
85
85
|
notifications: InboxNotification[];
|
|
86
86
|
catchLease?: WatchLease;
|
|
87
87
|
}
|
|
88
|
-
export interface SquareRuntimeState {
|
|
89
|
-
nextActIndex: number;
|
|
90
|
-
observations: Record<string, Record<string, ActivityObservation>>;
|
|
91
|
-
leases: Record<string, WatchLease>;
|
|
92
|
-
}
|
|
93
|
-
export interface SquareState {
|
|
94
|
-
hardCap: HardCap;
|
|
95
|
-
throttlePerMinute?: number;
|
|
96
|
-
preamble: string[];
|
|
97
|
-
warmup: string[];
|
|
98
|
-
acts: StoredAct[];
|
|
99
|
-
routes?: ReceiverRoute[];
|
|
100
|
-
runtime: SquareRuntimeState;
|
|
101
|
-
}
|
|
102
|
-
export interface ActivitiesOptions {
|
|
103
|
-
lastN?: number | null;
|
|
104
|
-
participants?: string[];
|
|
105
|
-
/** Exclusive lower bound on act.at (ms). Alias of --since. */
|
|
106
|
-
after?: number;
|
|
107
|
-
/** Exclusive lower bound on stable act index (--after act/<index>). */
|
|
108
|
-
afterIndex?: number;
|
|
109
|
-
/** Exclusive upper bound on stable act index (--before act/<index>). */
|
|
110
|
-
beforeIndex?: number;
|
|
111
|
-
/** Center act indexes for context windows (--at). */
|
|
112
|
-
atIndexes?: number[];
|
|
113
|
-
beforeContext?: number;
|
|
114
|
-
afterContext?: number;
|
|
115
|
-
mention?: string;
|
|
116
|
-
grep?: string;
|
|
117
|
-
fixed?: string;
|
|
118
|
-
order?: 'asc' | 'desc';
|
|
119
|
-
format?: string[];
|
|
120
|
-
json?: boolean;
|
|
121
|
-
}
|
|
122
88
|
export interface WatchOptions {
|
|
123
89
|
id?: ActivityId;
|
|
124
90
|
participants?: string[];
|
|
@@ -134,16 +100,10 @@ export type PublicAct = Extract<StoredAct, {
|
|
|
134
100
|
export type RoomChangeAct = Extract<StoredAct, {
|
|
135
101
|
kind: 'join' | 'done' | 'hold' | 'resume' | 'listen' | 'ignore';
|
|
136
102
|
}>;
|
|
137
|
-
export interface HoldState {
|
|
138
|
-
active: boolean;
|
|
139
|
-
at?: number;
|
|
140
|
-
reason?: string;
|
|
141
|
-
}
|
|
142
103
|
export declare function formatHardCap(hardCap: HardCap): string;
|
|
143
104
|
export declare function parseParticipantList(value: string): string[];
|
|
144
105
|
export declare function nameKey(name: string): string;
|
|
145
106
|
export declare function sameName(a: string, b: string): boolean;
|
|
146
|
-
export declare function findParticipantName(participants: string[], name: string): string | undefined;
|
|
147
107
|
/** One name grapheme: Unicode letters, digits, marks, hyphens, or underscores (no isolated variation selectors), or a complete RGI emoji. Shared by name validation and body @mention scanning. */
|
|
148
108
|
export declare const NAME_GRAPHEME_SOURCE: string;
|
|
149
109
|
export declare function validateName(name: string): void;
|
package/dist/model.js
CHANGED
|
@@ -7,6 +7,7 @@ export function isWakeRouteKind(value) {
|
|
|
7
7
|
class SquareErrorBase extends Error {
|
|
8
8
|
code;
|
|
9
9
|
facts;
|
|
10
|
+
operation;
|
|
10
11
|
constructor(code, message, facts) {
|
|
11
12
|
super(message);
|
|
12
13
|
this.code = code;
|
|
@@ -36,9 +37,6 @@ export function nameKey(name) {
|
|
|
36
37
|
export function sameName(a, b) {
|
|
37
38
|
return nameKey(a) === nameKey(b);
|
|
38
39
|
}
|
|
39
|
-
export function findParticipantName(participants, name) {
|
|
40
|
-
return participants.find((participant) => sameName(participant, name));
|
|
41
|
-
}
|
|
42
40
|
/** One name grapheme: Unicode letters, digits, marks, hyphens, or underscores (no isolated variation selectors), or a complete RGI emoji. Shared by name validation and body @mention scanning. */
|
|
43
41
|
export const NAME_GRAPHEME_SOURCE = String.raw `[[\p{L}\p{N}\p{M}_\x2D]--[\p{Variation_Selector}]]|\p{RGI_Emoji}`;
|
|
44
42
|
const NAME_PATTERN = new RegExp(`^(?:${NAME_GRAPHEME_SOURCE})+(?:/(?:${NAME_GRAPHEME_SOURCE})+)*$`, 'v');
|
package/dist/notifications.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ interface ProcessNotificationOptions {
|
|
|
8
8
|
env?: NodeJS.ProcessEnv;
|
|
9
9
|
now?: () => number;
|
|
10
10
|
}
|
|
11
|
-
export declare function defaultWakeAdapters(): Promise<WakeAdapter[]>;
|
|
11
|
+
export declare function defaultWakeAdapters(env?: NodeJS.ProcessEnv): Promise<WakeAdapter[]>;
|
|
12
12
|
export declare function createDefaultWakeTransport(hostLedger: import('./host-ledger.js').HostLedgerPort, clock: () => number, env?: NodeJS.ProcessEnv, suppliedAdapters?: readonly WakeAdapter[]): Promise<WakeTransportPort>;
|
|
13
13
|
export declare function createWakeTransport(adapters: readonly WakeAdapter[], hostLedger: import('./host-ledger.js').HostLedgerPort, clock: () => number, nativePorts?: Readonly<Partial<Record<import('./model.js').WakeRouteKind, WakeTransportPort>>>): WakeTransportPort;
|
|
14
14
|
export declare function processActNotificationsOnce(squarePath: string, actIndex: number, opts?: ProcessNotificationOptions): Promise<import("./ports.js").DeliveryResult>;
|
package/dist/notifications.js
CHANGED
|
@@ -3,10 +3,12 @@ import path from 'node:path';
|
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import { SquareError } from './model.js';
|
|
5
5
|
import { displayAttentionPath } from './attention-presentation.js';
|
|
6
|
-
import { openSquare } from './square
|
|
6
|
+
import { openSquare } from './open-square.js';
|
|
7
7
|
import { closeOpenSquare } from './open-square.js';
|
|
8
8
|
import { deliverPending, sweepPending } from './delivery-operations.js';
|
|
9
|
-
import {
|
|
9
|
+
import { projectWakeEvidence } from './wake-eligibility.js';
|
|
10
|
+
import { pendingHead } from './delivery.js';
|
|
11
|
+
import { parseActivityId } from './square-core.js';
|
|
10
12
|
import { canonicalPath } from './canonical-path.js';
|
|
11
13
|
import { createHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
12
14
|
export const PRIVILEGED_HOOK_BUDGET_MS = 3000;
|
|
@@ -17,11 +19,11 @@ export function wakeGraceMs(env = process.env) {
|
|
|
17
19
|
}
|
|
18
20
|
return value;
|
|
19
21
|
}
|
|
20
|
-
export async function defaultWakeAdapters() {
|
|
22
|
+
export async function defaultWakeAdapters(env = process.env) {
|
|
21
23
|
const adapters = [];
|
|
22
24
|
try {
|
|
23
25
|
const { CodexQueueAdapter } = await import('./codex-queue.js');
|
|
24
|
-
adapters.push(new CodexQueueAdapter());
|
|
26
|
+
adapters.push(new CodexQueueAdapter({ env }));
|
|
25
27
|
}
|
|
26
28
|
catch {
|
|
27
29
|
// Codex is unavailable only when this build omits its local adapter.
|
|
@@ -36,7 +38,7 @@ export async function defaultWakeAdapters() {
|
|
|
36
38
|
return adapters;
|
|
37
39
|
}
|
|
38
40
|
export async function createDefaultWakeTransport(hostLedger, clock, env = process.env, suppliedAdapters) {
|
|
39
|
-
const adapters = suppliedAdapters ?? await defaultWakeAdapters();
|
|
41
|
+
const adapters = suppliedAdapters ?? await defaultWakeAdapters(env);
|
|
40
42
|
const { createClaudeWakeTransport } = await import('./claude-delivery.js');
|
|
41
43
|
return createWakeTransport(suppliedAdapters === undefined && env.SQUARE_DISABLE_PASEO_WAKE === '1' ? adapters.filter((adapter) => adapter.kind !== 'paseo') : adapters, hostLedger, clock, { 'claude-native': createClaudeWakeTransport(hostLedger, env) });
|
|
42
44
|
}
|
|
@@ -45,8 +47,12 @@ async function observeWakeRequest(request, hostLedger, now) {
|
|
|
45
47
|
try {
|
|
46
48
|
const location = await canonicalPath(request.location);
|
|
47
49
|
square = await openSquare(location, { hostLedger });
|
|
48
|
-
const {
|
|
49
|
-
|
|
50
|
+
const { value: facts } = await square.artifact.read((facts) => {
|
|
51
|
+
const index = parseActivityId(request.activity);
|
|
52
|
+
const head = index === undefined ? undefined : pendingHead(facts, request.participant, index);
|
|
53
|
+
return { routes: facts.routes(), pending: head === undefined ? [] : [head] };
|
|
54
|
+
});
|
|
55
|
+
const eligibility = await projectWakeEvidence({ ...facts, hostLedger, location, now });
|
|
50
56
|
return { ...eligibility.currentness({ ...request, location }), observationAvailable: true };
|
|
51
57
|
}
|
|
52
58
|
catch {
|