@astrosheep/square 0.3.63 → 0.3.65
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/claude-plugin/.claude-plugin/plugin.json +3 -2
- package/claude-plugin/hooks/hooks.json +1 -22
- package/claude-plugin/hooks/register.js +119 -0
- package/claude-plugin/types.d.ts +7 -0
- package/codex-plugin/.codex-plugin/plugin.json +1 -1
- package/dist/activity-feed.d.ts +1 -10
- package/dist/activity-feed.js +1 -27
- package/dist/activity.js +57 -25
- package/dist/artifact.d.ts +1 -1
- package/dist/artifact.js +24 -25
- package/dist/attention-presentation.js +1 -0
- package/dist/automatic-session.d.ts +3 -1
- package/dist/automatic-session.js +21 -34
- package/dist/boundary-presentation.js +4 -13
- package/dist/canonical-path.d.ts +11 -0
- package/dist/canonical-path.js +47 -0
- package/dist/catch-decisions.js +14 -10
- package/dist/catch-selection.d.ts +6 -0
- package/dist/catch-selection.js +14 -0
- package/dist/claude-delivery.d.ts +11 -0
- package/dist/claude-delivery.js +145 -0
- package/dist/claude-mod.d.ts +8 -0
- package/dist/claude-mod.js +164 -0
- package/dist/cli/context.d.ts +0 -1
- package/dist/cli/context.js +9 -21
- package/dist/cli/harness-command.d.ts +0 -1
- package/dist/cli/harness-command.js +0 -6
- package/dist/cli/observation-commands.d.ts +1 -1
- package/dist/cli/observation-commands.js +31 -58
- package/dist/cli/program.js +20 -18
- package/dist/cli/registry.js +2 -2
- package/dist/cli/square-commands.js +10 -6
- package/dist/codex-boundary-state.d.ts +2 -2
- package/dist/codex-boundary-state.js +4 -4
- package/dist/codex-hook.js +12 -15
- package/dist/codex-queue.d.ts +2 -2
- package/dist/codex-queue.js +7 -5
- package/dist/decisions.d.ts +2 -6
- package/dist/decisions.js +16 -17
- package/dist/delivery-health.d.ts +1 -2
- package/dist/delivery-health.js +4 -5
- package/dist/delivery-operations.d.ts +2 -5
- package/dist/delivery-operations.js +77 -214
- package/dist/delivery.d.ts +25 -47
- package/dist/delivery.js +14 -46
- package/dist/diagnostic-redaction.js +7 -9
- package/dist/file-changes.d.ts +0 -1
- package/dist/file-changes.js +2 -19
- package/dist/harness-claude.js +8 -6
- package/dist/harness-codex.d.ts +0 -2
- package/dist/harness-codex.js +0 -2
- package/dist/harness-links.js +13 -17
- package/dist/harness.js +3 -7
- package/dist/help.js +4 -3
- package/dist/host-ledger-file-adapter.d.ts +17 -8
- package/dist/host-ledger-file-adapter.js +164 -80
- package/dist/host-ledger.d.ts +55 -50
- package/dist/inbox.d.ts +0 -3
- package/dist/inbox.js +88 -50
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/list.js +1 -4
- package/dist/mcp.js +24 -41
- package/dist/mention-parse.js +3 -9
- package/dist/model.d.ts +11 -2
- package/dist/model.js +1 -1
- package/dist/notifications.d.ts +3 -16
- package/dist/notifications.js +41 -122
- package/dist/opencode-delivery.d.ts +14 -0
- package/dist/opencode-delivery.js +171 -0
- package/dist/opencode.d.ts +39 -18
- package/dist/opencode.js +145 -40
- package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
- package/dist/packages/agent-delivery/src/claude-auth.js +75 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
- package/dist/packages/agent-delivery/src/claude-native.js +68 -0
- package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
- package/dist/packages/agent-delivery/src/claude.js +66 -0
- package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
- package/dist/packages/agent-delivery/src/deadline.js +41 -0
- package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
- package/dist/packages/agent-delivery/src/errors.js +41 -0
- package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
- package/dist/packages/agent-delivery/src/guards.js +6 -0
- package/dist/packages/agent-delivery/src/index.d.ts +83 -0
- package/dist/packages/agent-delivery/src/index.js +110 -0
- package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
- package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
- package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
- package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
- package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
- package/dist/packages/agent-delivery/src/opencode.js +127 -0
- package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
- package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
- package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
- package/dist/packages/agent-delivery/src/paseo.js +106 -0
- package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
- package/dist/packages/agent-delivery/src/pi-client.js +106 -0
- package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
- package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
- package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
- package/dist/packages/agent-delivery/src/pi-send.js +4 -0
- package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
- package/dist/packages/agent-delivery/src/pi.js +209 -0
- package/dist/packages/agent-delivery/src/types.d.ts +120 -0
- package/dist/participant-host.js +12 -13
- package/dist/participant-identity.d.ts +21 -0
- package/dist/participant-identity.js +32 -11
- package/dist/paseo-delivery.d.ts +2 -2
- package/dist/paseo-delivery.js +35 -27
- package/dist/paseo-timeline.js +25 -21
- package/dist/paseo.d.ts +2 -2
- package/dist/paseo.js +1 -2
- package/dist/ports.d.ts +7 -20
- package/dist/presentation-operations.js +16 -4
- package/dist/presentation.d.ts +19 -10
- package/dist/presentation.js +99 -177
- package/dist/registry.d.ts +15 -66
- package/dist/registry.js +45 -123
- package/dist/routes.d.ts +1 -28
- package/dist/routes.js +22 -104
- package/dist/runtime.d.ts +3 -9
- package/dist/runtime.js +14 -67
- package/dist/search.d.ts +0 -2
- package/dist/search.js +3 -10
- package/dist/square-actions.js +48 -72
- package/dist/square-application.js +32 -30
- package/dist/square-core.d.ts +3 -0
- package/dist/square-core.js +22 -5
- package/dist/square-facade.d.ts +2 -0
- package/dist/square-file-adapter.d.ts +2 -1
- package/dist/square-file-adapter.js +6 -9
- package/dist/square-projections.d.ts +40 -45
- package/dist/square-projections.js +60 -74
- package/dist/square-state.js +1 -4
- package/dist/square-storage.d.ts +5 -8
- package/dist/square-storage.js +13 -36
- package/dist/square-wiring.d.ts +2 -7
- package/dist/square-wiring.js +6 -24
- package/dist/stream.js +4 -6
- package/dist/time.js +2 -7
- package/dist/views.d.ts +6 -18
- package/dist/views.js +14 -21
- package/dist/wake-attempts.d.ts +2 -56
- package/dist/wake-attempts.js +15 -110
- package/dist/wake-eligibility.d.ts +43 -0
- package/dist/wake-eligibility.js +106 -0
- package/dist/wake-evidence.d.ts +32 -9
- package/dist/wake-evidence.js +29 -24
- package/dist/wake-sink.d.ts +13 -9
- package/dist/wake-sink.js +35 -54
- package/dist/watch.js +13 -21
- package/extensions/square-pi.js +27 -13
- package/guides/change-waits.md +1 -1
- package/guides/claude-native.md +101 -0
- package/guides/host-ledger.md +3 -1
- package/guides/participant.md +14 -7
- package/guides/pi-native-delivery.md +49 -0
- package/package.json +4 -3
- package/dist/claude-hook.d.ts +0 -10
- package/dist/claude-hook.js +0 -60
- package/dist/paseo-connection.d.ts +0 -15
- package/dist/paseo-connection.js +0 -141
- package/dist/presence.d.ts +0 -2
- package/dist/presence.js +0 -24
- package/dist/presented.d.ts +0 -2
- package/dist/presented.js +0 -10
- package/dist/state-cell.d.ts +0 -14
- package/dist/wake-port.d.ts +0 -23
- package/dist/wake-port.js +0 -27
- /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
package/dist/registry.js
CHANGED
|
@@ -1,97 +1,47 @@
|
|
|
1
|
-
/**
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { sameName, SquareError } from './model.js';
|
|
5
|
-
import { isCurrentlyJoined } from './runtime.js';
|
|
6
|
-
import { squareAssignedParticipantName as computeSquareAssignedParticipantName } from './participant-identity.js';
|
|
1
|
+
/** Participant ownership and local session identity on the host ledger. */
|
|
2
|
+
import { SquareError } from './model.js';
|
|
3
|
+
import { harnessSessionSources, squareAssignedParticipantName as computeSquareAssignedParticipantName } from './participant-identity.js';
|
|
7
4
|
import { createHostLedgerPort } from './host-ledger-file-adapter.js';
|
|
8
5
|
import { hostLedgerRoot } from './host-ledger-root.js';
|
|
9
|
-
|
|
10
|
-
const PRESENCE_CLAIM_LOCK = { retryMs: 10 };
|
|
11
|
-
const LOCAL_SESSION_SOURCES = [
|
|
12
|
-
{ variable: 'CLAUDE_CODE_SESSION_ID', channel: 'claude-code', child: 'CLAUDE_CODE_CHILD_SESSION' },
|
|
13
|
-
{ variable: 'CODEX_THREAD_ID', channel: 'codex' },
|
|
14
|
-
{ variable: 'OPENCODE_SESSION_ID', channel: 'opencode' },
|
|
15
|
-
{ variable: 'PI_SESSION_ID', channel: 'pi' },
|
|
16
|
-
];
|
|
17
|
-
export function registryPath(env = process.env) { return env.SQUARE_REGISTRY || path.join(hostLedgerRoot(env), '..', 'sessions.ndjsonl'); }
|
|
18
|
-
export async function canonicalSquarePath(squarePath) { const absolute = path.resolve(squarePath); try {
|
|
19
|
-
return await (await import('node:fs/promises')).realpath(absolute);
|
|
20
|
-
}
|
|
21
|
-
catch {
|
|
22
|
-
return absolute;
|
|
23
|
-
} }
|
|
24
|
-
function ledgerRoot(env) { return hostLedgerRoot(env); }
|
|
25
|
-
function ledger(env) { return createHostLedgerPort({ rootPath: ledgerRoot(env) }); }
|
|
6
|
+
import { canonicalPath } from './canonical-path.js';
|
|
26
7
|
export function presenceEpoch(record) {
|
|
27
8
|
return typeof record?.epoch === 'number' && Number.isSafeInteger(record.epoch) && record.epoch > 0 ? record.epoch : 0;
|
|
28
9
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
name: record.participant,
|
|
33
|
-
squarePath: record.location,
|
|
34
|
-
channel: record.channel,
|
|
35
|
-
child: false,
|
|
36
|
-
...(record.route === undefined ? {} : { route: record.route }),
|
|
37
|
-
updatedAt: record.updatedAt ?? 0,
|
|
38
|
-
epoch: presenceEpoch(record),
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
function presenceClaimLockPath(env) {
|
|
42
|
-
return path.join(ledgerRoot(env), 'presence-claim.lock');
|
|
43
|
-
}
|
|
44
|
-
/** Runs `fn` inside the ownership claim critical section, under the same lock as claims and finalize. */
|
|
45
|
-
export async function withOwnershipClaimLock(env, fn, signal) {
|
|
46
|
-
return withFileLock(presenceClaimLockPath(env), { ...PRESENCE_CLAIM_LOCK, signal }, fn);
|
|
47
|
-
}
|
|
48
|
-
async function activeBindings(now, env) { return (await ledger(env).listPresence({ now })).map(toBinding).sort((a, b) => b.updatedAt - a.updatedAt); }
|
|
49
|
-
async function writePresence(sessionId, name, squarePath, options, done) { if (!sessionId || !name || !squarePath)
|
|
50
|
-
return; const env = options.env ?? process.env; const channel = options.channel ?? 'unknown'; const port = ledger(env); const location = await canonicalSquarePath(squarePath); if (done)
|
|
51
|
-
await port.removePresence({ location, participant: name, session: sessionId, channel });
|
|
52
|
-
else
|
|
53
|
-
await port.ensurePresence({ location, participant: name, session: sessionId, channel, updatedAt: options.at ?? Date.now() }); }
|
|
54
|
-
export function recordJoin(sessionId, name, squarePath, options = {}) { return writePresence(sessionId, name, squarePath, options, false); }
|
|
55
|
-
export async function recordDone(sessionId, name, squarePath, options = {}) {
|
|
56
|
-
await writePresence(sessionId, name, squarePath, options, true);
|
|
10
|
+
/** The current owner: the highest epoch wins, then the most recently updated row. */
|
|
11
|
+
function currentOwner(rows) {
|
|
12
|
+
return [...rows].sort((left, right) => presenceEpoch(right) - presenceEpoch(left) || (right.updatedAt ?? 0) - (left.updatedAt ?? 0))[0];
|
|
57
13
|
}
|
|
58
|
-
export async function
|
|
59
|
-
return await activeBindings(now, env);
|
|
60
|
-
}
|
|
61
|
-
catch {
|
|
62
|
-
return [];
|
|
63
|
-
} }
|
|
64
|
-
export async function lookupSessionBindings(sessionId, now = Date.now(), env = process.env) { return (await readActiveBindings(now, env)).filter((binding) => binding.sessionId === sessionId); }
|
|
65
|
-
export async function lookupSession(sessionId, now = Date.now(), env = process.env) { return (await lookupSessionBindings(sessionId, now, env)).map(({ name, squarePath }) => ({ name, squarePath })); }
|
|
66
|
-
export async function lookupParticipant(squarePath, name, now = Date.now(), env = process.env) { const canonicalPath = await canonicalSquarePath(squarePath); return (await readActiveBindings(now, env)).filter((binding) => binding.squarePath === canonicalPath && sameName(binding.name, name)); }
|
|
67
|
-
export async function localParticipantOwner(squarePath, name, env = process.env, now = Date.now()) { const sessionIds = new Set(localSessionIdentities(env).map((identity) => identity.sessionId)); if (sessionIds.size === 0)
|
|
68
|
-
return undefined; return (await lookupParticipant(squarePath, name, now, env)).find((binding) => sessionIds.has(binding.sessionId))?.sessionId; }
|
|
69
|
-
export async function localParticipantName(squarePath, env = process.env) { const canonicalPath = await canonicalSquarePath(squarePath); const names = new Set((await Promise.all(localSessionIdentities(env).map(async (identity) => (await lookupSession(identity.sessionId, Date.now(), env)).filter((item) => item.squarePath === canonicalPath).map((item) => item.name)))).flat()); return names.size === 1 ? [...names][0] : undefined; }
|
|
14
|
+
export async function localParticipantName(squarePath, hostLedger, env = process.env) { const canonical = await canonicalPath(squarePath); const names = new Set((await Promise.all(localSessionIdentities(env).map(async (identity) => (await hostLedger.listPresence({ location: canonical, session: identity.sessionId })).map((row) => row.participant)))).flat()); return names.size === 1 ? [...names][0] : undefined; }
|
|
70
15
|
export function squareAssignedParticipantName(env = process.env) { return computeSquareAssignedParticipantName(env); }
|
|
71
|
-
export async function readParticipantOwner(squarePath, name,
|
|
72
|
-
|
|
73
|
-
|
|
16
|
+
export async function readParticipantOwner(squarePath, name, hostLedger) {
|
|
17
|
+
// The registry cache this read replaces reported an unreadable cache as "no visible owner";
|
|
18
|
+
// an ownership read stays equally tolerant so a degraded ledger cannot fail an operation.
|
|
19
|
+
const rows = await participantPresence(squarePath, name, hostLedger).catch(() => []);
|
|
20
|
+
return currentOwner(rows);
|
|
21
|
+
}
|
|
22
|
+
async function participantPresence(squarePath, name, hostLedger) {
|
|
23
|
+
const canonical = await canonicalPath(squarePath);
|
|
24
|
+
return hostLedger.listPresence({ location: canonical, participant: name, now: Date.now() });
|
|
74
25
|
}
|
|
75
|
-
export async function sessionOwnsParticipant(squarePath, name, sessionId,
|
|
76
|
-
const owner = await readParticipantOwner(squarePath, name,
|
|
77
|
-
if (owner === undefined || owner.
|
|
26
|
+
export async function sessionOwnsParticipant(squarePath, name, sessionId, hostLedger, expectedEpoch) {
|
|
27
|
+
const owner = await readParticipantOwner(squarePath, name, hostLedger);
|
|
28
|
+
if (owner === undefined || owner.session !== sessionId)
|
|
78
29
|
return false;
|
|
79
|
-
return expectedEpoch === undefined || owner
|
|
30
|
+
return expectedEpoch === undefined || presenceEpoch(owner) === expectedEpoch;
|
|
80
31
|
}
|
|
81
|
-
export async function releaseSessionParticipantClaim(
|
|
32
|
+
export async function releaseSessionParticipantClaim(hostLedger, claim) {
|
|
82
33
|
if (claim?.status !== 'acquired')
|
|
83
34
|
return;
|
|
84
|
-
|
|
85
|
-
await port.removePresenceIfUnchanged(claim.record);
|
|
35
|
+
await hostLedger.removePresenceIfUnchanged(claim.record);
|
|
86
36
|
}
|
|
87
|
-
export async function claimSessionParticipant(squarePath, name, env = process.env, signal) {
|
|
37
|
+
export async function claimSessionParticipant(squarePath, name, hostLedger, env = process.env, signal) {
|
|
88
38
|
const identity = localSessionIdentities(env)[0];
|
|
89
39
|
if (identity === undefined)
|
|
90
40
|
return undefined;
|
|
91
41
|
if (signal?.aborted)
|
|
92
42
|
throw signal.reason ?? new Error('Operation aborted');
|
|
93
|
-
const location = await
|
|
94
|
-
const result = await
|
|
43
|
+
const location = await canonicalPath(squarePath);
|
|
44
|
+
const result = await hostLedger.claimPresence({
|
|
95
45
|
location,
|
|
96
46
|
participant: name,
|
|
97
47
|
session: identity.sessionId,
|
|
@@ -108,28 +58,25 @@ export async function claimSessionParticipant(squarePath, name, env = process.en
|
|
|
108
58
|
}
|
|
109
59
|
/**
|
|
110
60
|
* Fenced takeover: the ownership claim and the lifecycle run as one critical section under the
|
|
111
|
-
*
|
|
61
|
+
* claim lock, so no second takeover can interleave between claim and commit. The claim
|
|
112
62
|
* persists nothing until the lifecycle commits: standing owner rows stay authoritative through
|
|
113
63
|
* the lifecycle (a self-takeover can therefore never clobber its own standing row). On success
|
|
114
64
|
* the standing rows are replaced by the new owner's row at the claim epoch; on refusal, rows
|
|
115
65
|
* carrying the claim token (session + channel + claim epoch) are withdrawn and the captured
|
|
116
66
|
* standing rows are restored exactly.
|
|
117
67
|
*/
|
|
118
|
-
export async function claimSessionTakeover(squarePath, name, env = process.env, opts = {}, lifecycle, signal) {
|
|
68
|
+
export async function claimSessionTakeover(squarePath, name, hostLedger, env = process.env, opts = {}, lifecycle, signal) {
|
|
119
69
|
const identity = localSessionIdentities(env)[0];
|
|
120
70
|
if (identity === undefined)
|
|
121
71
|
throw new SquareError('invalid_args', 'No local session identity for takeover');
|
|
122
|
-
const location = await
|
|
123
|
-
return
|
|
124
|
-
const
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
.map((row) => toBinding(row))
|
|
128
|
-
.sort((left, right) => right.epoch - left.epoch || right.updatedAt - left.updatedAt)[0];
|
|
129
|
-
const currentEpoch = owner?.epoch ?? 0;
|
|
72
|
+
const location = await canonicalPath(squarePath);
|
|
73
|
+
return hostLedger.withClaimLock(async () => {
|
|
74
|
+
const standing = await hostLedger.listPresence({ location, participant: name });
|
|
75
|
+
const owner = currentOwner(standing);
|
|
76
|
+
const currentEpoch = presenceEpoch(owner);
|
|
130
77
|
const epochMatches = opts.expectedEpoch === undefined || currentEpoch === opts.expectedEpoch;
|
|
131
78
|
const sessionMatches = opts.expectedSession === undefined
|
|
132
|
-
|| (opts.expectedSession === '' ? owner === undefined : owner?.
|
|
79
|
+
|| (opts.expectedSession === '' ? owner === undefined : owner?.session === opts.expectedSession);
|
|
133
80
|
if (!epochMatches || !sessionMatches) {
|
|
134
81
|
return { status: 'busy', epoch: currentEpoch };
|
|
135
82
|
}
|
|
@@ -143,59 +90,34 @@ export async function claimSessionTakeover(squarePath, name, env = process.env,
|
|
|
143
90
|
// token (session + channel + epoch) — whatever the lifecycle itself ensured — then restore
|
|
144
91
|
// the captured standing rows so the old owner survives byte-consistently. Foreign rows and
|
|
145
92
|
// later owners are never touched.
|
|
146
|
-
const tokenRows = await
|
|
93
|
+
const tokenRows = await hostLedger.listPresence({ location, participant: name, session: identity.sessionId });
|
|
147
94
|
for (const row of tokenRows) {
|
|
148
95
|
if (row.channel === identity.channel && presenceEpoch(row) === epoch)
|
|
149
|
-
await
|
|
96
|
+
await hostLedger.removePresence({ location: row.location, participant: row.participant, session: row.session, channel: row.channel });
|
|
150
97
|
}
|
|
151
98
|
for (const row of standing)
|
|
152
|
-
await
|
|
99
|
+
await hostLedger.ensurePresence(row);
|
|
153
100
|
throw error;
|
|
154
101
|
}
|
|
155
102
|
// Finalize: the lifecycle committed. Replace the standing owner with the new owner's row at
|
|
156
103
|
// the claim epoch where the owner was visible, so exactly one current owner
|
|
157
104
|
// remains — also when the takeover is a self-takeover (same session as the standing owner).
|
|
158
105
|
for (const row of standing)
|
|
159
|
-
await
|
|
160
|
-
await
|
|
106
|
+
await hostLedger.removePresence({ location: row.location, participant: row.participant, session: row.session, channel: row.channel });
|
|
107
|
+
await hostLedger.ensurePresence({ location, participant: name, session: identity.sessionId, channel: identity.channel, updatedAt: Date.now(), epoch });
|
|
161
108
|
return { status: 'acquired', sessionId: identity.sessionId, epoch, result };
|
|
162
|
-
});
|
|
109
|
+
}, signal);
|
|
163
110
|
}
|
|
164
|
-
export async function releaseSessionParticipant(squarePath, name, env = process.env) {
|
|
111
|
+
export async function releaseSessionParticipant(squarePath, name, hostLedger, env = process.env) {
|
|
165
112
|
const identity = localSessionIdentities(env)[0];
|
|
166
113
|
if (identity === undefined)
|
|
167
114
|
return;
|
|
168
|
-
await
|
|
115
|
+
await hostLedger.removePresence({ location: squarePath, participant: name, session: identity.sessionId, channel: identity.channel });
|
|
169
116
|
}
|
|
170
|
-
export async function bindCurrentParticipant(squarePath, name, env = process.env) { if (squareAssignedParticipantName(env) !== name)
|
|
171
|
-
throw new SquareError('invalid_args', `The current session is not assigned ${name}`); const sessionId = await localParticipantOwner(squarePath, name, env); if (sessionId !== undefined)
|
|
172
|
-
return { created: false, sessionId }; if ((await lookupParticipant(squarePath, name, Date.now(), env)).at(0) !== undefined)
|
|
173
|
-
throw new SquareError('already_joined', `✕ ${name} already stands here — another session holds the name`); await recordLocalJoin(name, squarePath, env); const currentSessionId = await localParticipantOwner(squarePath, name, env); if (currentSessionId === undefined)
|
|
174
|
-
throw new Error(`Current participant binding did not commit for ${name}`); return { created: true, sessionId: currentSessionId }; }
|
|
175
|
-
export async function unbindCurrentParticipant(squarePath, name, env = process.env) { const identities = new Set(localSessionIdentities(env).map((identity) => identity.sessionId)); const current = (await lookupParticipant(squarePath, name, Date.now(), env)).filter((binding) => identities.has(binding.sessionId)); for (const binding of current)
|
|
176
|
-
await recordSessionDone(binding.sessionId, binding.name, binding.squarePath, binding.channel, env); return current.length > 0; }
|
|
177
|
-
function bindingIsProvablyObsolete(binding, acts) { return acts !== undefined && !isCurrentlyJoined(acts, binding.name); }
|
|
178
|
-
export async function pruneRegistry(readActs, now = Date.now()) { const active = await readActiveBindings(now); let removed = 0; for (const binding of active) {
|
|
179
|
-
if (!bindingIsProvablyObsolete(binding, await readActs(binding.squarePath)))
|
|
180
|
-
continue;
|
|
181
|
-
await recordDone(binding.sessionId, binding.name, binding.squarePath, { channel: binding.channel, at: now });
|
|
182
|
-
removed++;
|
|
183
|
-
} return { removed, kept: active.length - removed }; }
|
|
184
117
|
function addLocalSession(identities, sessionId, channel, child, paseoAgentId) { if (!sessionId || identities.some((identity) => identity.sessionId === sessionId))
|
|
185
118
|
return; identities.push({ sessionId, channel, child, ...(paseoAgentId ? { paseoAgentId } : {}) }); }
|
|
186
|
-
export function localSessionIdentities(env = process.env) { const paseoAgentId = env.PASEO_AGENT_ID?.trim() || undefined; const identities = []; for (const source of
|
|
187
|
-
addLocalSession(identities, env[source.variable]?.trim(), source.channel, source.
|
|
119
|
+
export function localSessionIdentities(env = process.env) { const paseoAgentId = env.PASEO_AGENT_ID?.trim() || undefined; const identities = []; for (const source of harnessSessionSources)
|
|
120
|
+
addLocalSession(identities, env[source.variable]?.trim(), source.channel, source.childVariable !== undefined && env[source.childVariable] === '1', paseoAgentId); return identities; }
|
|
188
121
|
export function hasAutomaticDeliveryIdentity(env = process.env) { return localSessionIdentities(env).length > 0; }
|
|
189
|
-
export async function recordLocalJoin(name, squarePath, env = process.env) { const at = Date.now(); const identities = localSessionIdentities(env); const current = await lookupParticipant(squarePath, name, at, env); for (const identity of identities) {
|
|
190
|
-
for (const binding of current.filter((item) => item.sessionId === identity.sessionId))
|
|
191
|
-
await recordDone(binding.sessionId, binding.name, binding.squarePath, { channel: binding.channel, at, env });
|
|
192
|
-
await recordJoin(identity.sessionId, name, squarePath, { ...identity, at, env });
|
|
193
|
-
} }
|
|
194
|
-
export async function recordLocalDone(name, squarePath, env = process.env) { const at = Date.now(); const identities = new Set(localSessionIdentities(env).map((identity) => identity.sessionId)); const current = (await lookupParticipant(squarePath, name, at, env)).filter((binding) => identities.has(binding.sessionId)); for (const binding of current)
|
|
195
|
-
await recordDone(binding.sessionId, binding.name, binding.squarePath, { channel: binding.channel, at, env }); }
|
|
196
|
-
export async function recordSessionJoin(sessionId, name, squarePath, channel, env = process.env) { const at = Date.now(); const current = (await lookupParticipant(squarePath, name, at, env)).filter((binding) => binding.sessionId === sessionId); for (const binding of current)
|
|
197
|
-
await recordDone(binding.sessionId, binding.name, binding.squarePath, { channel: binding.channel, at, env }); await recordJoin(sessionId, name, squarePath, { channel, at, env }); return sessionId; }
|
|
198
|
-
export async function recordSessionDone(sessionId, name, squarePath, channel, env = process.env) { const canonicalPath = await canonicalSquarePath(squarePath); const binding = (await lookupSessionBindings(sessionId, Date.now(), env)).find((item) => item.squarePath === canonicalPath && sameName(item.name, name) && item.channel === channel); if (binding === undefined)
|
|
199
|
-
return false; const options = { channel, at: Date.now(), env }; await recordDone(sessionId, binding.name, binding.squarePath, options); return true; }
|
|
200
122
|
/** Bind the host ledger to the caller's captured environment. */
|
|
201
|
-
export function hostLedgerForEnv(env = process.env) { return
|
|
123
|
+
export function hostLedgerForEnv(env = process.env) { return createHostLedgerPort({ rootPath: hostLedgerRoot(env) }); }
|
package/dist/routes.d.ts
CHANGED
|
@@ -13,25 +13,8 @@ export interface WakeRouteCapabilities {
|
|
|
13
13
|
readonly canUse: (kind: WakeRouteKind, address: Readonly<Record<string, string>>) => boolean;
|
|
14
14
|
}
|
|
15
15
|
export declare function defaultWakeRouteCapabilities(hostLedger?: import('./host-ledger.js').HostLedgerPort): Promise<WakeRouteCapabilities>;
|
|
16
|
-
export declare function selectPrimaryWakeRoute(input: {
|
|
17
|
-
readonly boundary: WakeBoundary;
|
|
18
|
-
readonly env: NodeJS.ProcessEnv;
|
|
19
|
-
readonly capabilities: WakeRouteCapabilities;
|
|
20
|
-
}): Omit<WakeRoute, 'updatedAt'> | undefined;
|
|
21
|
-
export declare function routeIdentityKey(route: Pick<WakeRoute, 'location' | 'participant' | 'sessionId'>, location?: string): string;
|
|
22
16
|
export declare function resolvePrimaryWakeRoute(boundary: WakeBoundary, env: NodeJS.ProcessEnv, capabilities: WakeRouteCapabilities): Omit<WakeRoute, 'updatedAt'> | undefined;
|
|
23
|
-
export declare function
|
|
24
|
-
location?: string;
|
|
25
|
-
participant?: string;
|
|
26
|
-
sessionId?: string;
|
|
27
|
-
freshOnly?: boolean;
|
|
28
|
-
now?: number;
|
|
29
|
-
env?: NodeJS.ProcessEnv;
|
|
30
|
-
}): Promise<WakeRoute[]>;
|
|
31
|
-
export declare function upsertWakeRoute(route: Omit<WakeRoute, 'updatedAt'>, opts?: {
|
|
32
|
-
at?: number;
|
|
33
|
-
env?: NodeJS.ProcessEnv;
|
|
34
|
-
}): Promise<void>;
|
|
17
|
+
export declare function routeIdentityKey(route: Pick<WakeRoute, 'location' | 'participant' | 'sessionId'>, location?: string): string;
|
|
35
18
|
export type RouteEpoch = {
|
|
36
19
|
readonly epoch?: number;
|
|
37
20
|
};
|
|
@@ -53,21 +36,11 @@ export declare function dropEndedSessionWakeRoutesFromState(state: import('./mod
|
|
|
53
36
|
readonly participant?: string;
|
|
54
37
|
}): void;
|
|
55
38
|
export declare function dropParticipantWakeRoutesFromState(state: import('./model.js').SquareState, location: string, participant: string): void;
|
|
56
|
-
export declare function sessionOwnsParticipantRoutes(state: import('./model.js').SquareState, location: string, participant: string, sessionId: string): boolean;
|
|
57
39
|
export declare function sessionCanEndParticipant(state: import('./model.js').SquareState, location: string, participant: string, sessionId: string, currentSessionId?: string): boolean;
|
|
58
40
|
export declare function publishWakeRoute(artifact: import('./ports.js').SquareArtifactPort, route: Omit<WakeRoute, 'updatedAt'> & RouteEpoch, opts?: {
|
|
59
41
|
at?: number;
|
|
60
42
|
requireCurrentSession?: boolean;
|
|
61
43
|
}): Promise<void>;
|
|
62
|
-
export declare function retireWakeRoute(route: WakeRoute, opts?: {
|
|
63
|
-
at?: number;
|
|
64
|
-
env?: NodeJS.ProcessEnv;
|
|
65
|
-
expectedEpoch?: number;
|
|
66
|
-
}): Promise<void>;
|
|
67
44
|
export declare function retireWakeRouteFromArtifact(artifact: import('./ports.js').SquareArtifactPort, route: Pick<WakeRoute, 'location' | 'participant' | 'sessionId'>, opts?: {
|
|
68
45
|
readonly expectedEpoch?: number;
|
|
69
46
|
}): Promise<void>;
|
|
70
|
-
export declare function retireWakeRoutesForSessionFromArtifact(artifact: import('./ports.js').SquareArtifactPort, route: Pick<WakeRoute, 'location' | 'sessionId'>, opts?: {
|
|
71
|
-
readonly expectedEpoch?: number;
|
|
72
|
-
}): Promise<void>;
|
|
73
|
-
export declare function canonicalRouteLocation(location: string): Promise<string>;
|
package/dist/routes.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
1
|
import { nameKey } from './model.js';
|
|
4
|
-
import { openSquare } from './square-file-adapter.js';
|
|
5
|
-
import { closeOpenSquare } from './open-square.js';
|
|
6
2
|
import { isCurrentlyJoined } from './runtime.js';
|
|
3
|
+
import { canonicalPath, canonicalPathSync } from './canonical-path.js';
|
|
7
4
|
export { WAKE_ROUTE_KINDS } from './model.js';
|
|
8
5
|
export const ROUTE_FRESH_MS = 24 * 60 * 60 * 1000;
|
|
9
6
|
export async function defaultWakeRouteCapabilities(hostLedger) {
|
|
@@ -29,90 +26,35 @@ export async function defaultWakeRouteCapabilities(hostLedger) {
|
|
|
29
26
|
catch { /* optional */ }
|
|
30
27
|
return { canUse: (kind, address) => userCapable && available.has(kind) && Object.values(address).every((value) => value.trim() !== '') };
|
|
31
28
|
}
|
|
32
|
-
function
|
|
33
|
-
if (boundary.provider === 'codex')
|
|
34
|
-
return { kind: 'codex-queue', address: { threadId: boundary.sessionId } };
|
|
35
|
-
if (boundary.provider === 'claude')
|
|
36
|
-
return { kind: 'claude-native', address: { sessionId: boundary.sessionId } };
|
|
37
|
-
if (boundary.provider === 'opencode')
|
|
38
|
-
return { kind: 'opencode-server', address: { sessionId: boundary.sessionId } };
|
|
39
|
-
if (boundary.provider === 'pi')
|
|
40
|
-
return { kind: 'pi-extension', address: { sessionId: boundary.sessionId } };
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
export function selectPrimaryWakeRoute(input) {
|
|
44
|
-
const { boundary, env, capabilities } = input;
|
|
29
|
+
export function resolvePrimaryWakeRoute(boundary, env, capabilities) {
|
|
45
30
|
const paseoAgentId = env.PASEO_AGENT_ID?.trim();
|
|
46
31
|
const candidates = [];
|
|
47
32
|
if (paseoAgentId)
|
|
48
33
|
candidates.push({ kind: 'paseo', address: { agentId: paseoAgentId } });
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
candidates.push(native);
|
|
34
|
+
if (boundary.provider === 'codex')
|
|
35
|
+
candidates.push({ kind: 'codex-queue', address: { threadId: boundary.sessionId } });
|
|
52
36
|
const chosen = candidates.find((candidate) => Object.values(candidate.address).every((value) => value.trim() !== '') && capabilities.canUse(candidate.kind, candidate.address));
|
|
53
37
|
return chosen === undefined ? undefined : { location: boundary.location, participant: boundary.participant, sessionId: boundary.sessionId, channel: boundary.provider === 'paseo' ? 'paseo' : boundary.provider === 'claude' ? 'claude-code' : boundary.provider, ...chosen };
|
|
54
38
|
}
|
|
55
39
|
export function routeIdentityKey(route, location = route.location) {
|
|
56
40
|
return JSON.stringify([location, nameKey(route.participant), route.sessionId]);
|
|
57
41
|
}
|
|
58
|
-
export function resolvePrimaryWakeRoute(boundary, env, capabilities) {
|
|
59
|
-
return selectPrimaryWakeRoute({ boundary, env, capabilities });
|
|
60
|
-
}
|
|
61
|
-
async function withArtifact(location, fn) {
|
|
62
|
-
if (location === undefined)
|
|
63
|
-
return undefined;
|
|
64
|
-
try {
|
|
65
|
-
await fs.promises.access(location);
|
|
66
|
-
const square = await openSquare(location);
|
|
67
|
-
try {
|
|
68
|
-
return await fn(square);
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
await closeOpenSquare(square);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
catch {
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
export async function readWakeRoutes(opts = {}) {
|
|
79
|
-
const now = opts.now ?? Date.now();
|
|
80
|
-
const canonicalLocation = opts.location === undefined ? undefined : await canonicalRouteLocation(opts.location);
|
|
81
|
-
const routes = await withArtifact(canonicalLocation, async (square) => (await square.artifact.read()).state.routes ?? []) ?? [];
|
|
82
|
-
const filtered = routes.filter((route) => (opts.participant === undefined || nameKey(route.participant) === nameKey(opts.participant)) && (opts.sessionId === undefined || route.sessionId === opts.sessionId) && (!opts.freshOnly || now - route.updatedAt < ROUTE_FRESH_MS));
|
|
83
|
-
const canonicalized = await Promise.all(filtered.map(async (route) => ({ ...route, location: await canonicalRouteLocation(route.location), address: { ...route.address } })));
|
|
84
|
-
return canonicalLocation === undefined ? canonicalized : canonicalized.filter((route) => route.location === canonicalLocation);
|
|
85
|
-
}
|
|
86
|
-
export async function upsertWakeRoute(route, opts = {}) {
|
|
87
|
-
const location = await canonicalRouteLocation(route.location);
|
|
88
|
-
await withArtifact(location, async (square) => publishWakeRoute(square.artifact, { ...route, location }, opts));
|
|
89
|
-
}
|
|
90
42
|
function sameRouteAddress(left, right) {
|
|
91
43
|
const leftKeys = Object.keys(left).sort();
|
|
92
44
|
const rightKeys = Object.keys(right).sort();
|
|
93
45
|
return leftKeys.length === rightKeys.length && leftKeys.every((key, index) => rightKeys[index] === key && left[key] === right[key]);
|
|
94
46
|
}
|
|
95
|
-
function canonicalRouteLocationSync(location) {
|
|
96
|
-
const absolute = path.resolve(location);
|
|
97
|
-
// Match fs.promises.realpath used by artifact and presence adapters, including Windows 8.3 aliases.
|
|
98
|
-
try {
|
|
99
|
-
return fs.realpathSync.native(absolute);
|
|
100
|
-
}
|
|
101
|
-
catch {
|
|
102
|
-
return absolute;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
47
|
export function applyWakeRouteToState(state, route, at = Date.now()) {
|
|
106
|
-
const location =
|
|
48
|
+
const location = canonicalPathSync(route.location);
|
|
107
49
|
state.routes = [...(state.routes ?? []).filter((item) => {
|
|
108
|
-
const itemLocation =
|
|
50
|
+
const itemLocation = canonicalPathSync(item.location);
|
|
109
51
|
return !(itemLocation === location && routeIdentityKey(item, itemLocation) === routeIdentityKey(route, location));
|
|
110
52
|
}), { ...route, location, updatedAt: at }];
|
|
111
53
|
}
|
|
112
54
|
export function dropSessionWakeRoutesFromState(state, location, sessionId, expectedEpoch) {
|
|
113
|
-
const canonical =
|
|
55
|
+
const canonical = canonicalPathSync(location);
|
|
114
56
|
state.routes = (state.routes ?? []).filter((item) => {
|
|
115
|
-
if (item.sessionId !== sessionId ||
|
|
57
|
+
if (item.sessionId !== sessionId || canonicalPathSync(item.location) !== canonical)
|
|
116
58
|
return true;
|
|
117
59
|
if (expectedEpoch === undefined)
|
|
118
60
|
return false;
|
|
@@ -129,9 +71,9 @@ export function dropSessionWakeRoutesFromState(state, location, sessionId, expec
|
|
|
129
71
|
* published by a later generation.
|
|
130
72
|
*/
|
|
131
73
|
export function dropEndedSessionWakeRoutesFromState(state, location, sessionId, opts) {
|
|
132
|
-
const canonical =
|
|
74
|
+
const canonical = canonicalPathSync(location);
|
|
133
75
|
state.routes = (state.routes ?? []).filter((item) => {
|
|
134
|
-
if (item.sessionId !== sessionId ||
|
|
76
|
+
if (item.sessionId !== sessionId || canonicalPathSync(item.location) !== canonical)
|
|
135
77
|
return true;
|
|
136
78
|
if (opts.participant !== undefined && nameKey(item.participant) !== nameKey(opts.participant))
|
|
137
79
|
return true;
|
|
@@ -149,66 +91,42 @@ export function dropEndedSessionWakeRoutesFromState(state, location, sessionId,
|
|
|
149
91
|
});
|
|
150
92
|
}
|
|
151
93
|
export function dropParticipantWakeRoutesFromState(state, location, participant) {
|
|
152
|
-
const canonical =
|
|
153
|
-
state.routes = (state.routes ?? []).filter((item) => !(nameKey(item.participant) === nameKey(participant) &&
|
|
154
|
-
}
|
|
155
|
-
export function sessionOwnsParticipantRoutes(state, location, participant, sessionId) {
|
|
156
|
-
const canonical = canonicalRouteLocationSync(location);
|
|
157
|
-
const owned = (state.routes ?? []).filter((item) => nameKey(item.participant) === nameKey(participant) && canonicalRouteLocationSync(item.location) === canonical);
|
|
158
|
-
return owned.length > 0 && owned.every((item) => item.sessionId === sessionId);
|
|
94
|
+
const canonical = canonicalPathSync(location);
|
|
95
|
+
state.routes = (state.routes ?? []).filter((item) => !(nameKey(item.participant) === nameKey(participant) && canonicalPathSync(item.location) === canonical));
|
|
159
96
|
}
|
|
160
97
|
export function sessionCanEndParticipant(state, location, participant, sessionId, currentSessionId) {
|
|
161
|
-
const canonical =
|
|
162
|
-
const owned = (state.routes ?? []).filter((item) => nameKey(item.participant) === nameKey(participant) &&
|
|
98
|
+
const canonical = canonicalPathSync(location);
|
|
99
|
+
const owned = (state.routes ?? []).filter((item) => nameKey(item.participant) === nameKey(participant) && canonicalPathSync(item.location) === canonical);
|
|
163
100
|
if (owned.length === 0)
|
|
164
101
|
return currentSessionId === sessionId;
|
|
165
102
|
return owned.every((item) => item.sessionId === sessionId) && (currentSessionId === undefined || currentSessionId === sessionId);
|
|
166
103
|
}
|
|
167
104
|
export async function publishWakeRoute(artifact, route, opts = {}) {
|
|
168
|
-
const location = await
|
|
105
|
+
const location = await canonicalPath(route.location);
|
|
169
106
|
const at = opts.at ?? Date.now();
|
|
170
107
|
await artifact.transact((state) => {
|
|
171
108
|
if (opts.requireCurrentSession) {
|
|
172
|
-
|
|
173
|
-
|
|
109
|
+
if (!isCurrentlyJoined(state.acts, route.participant)
|
|
110
|
+
|| (state.routes ?? []).some((item) => nameKey(item.participant) === nameKey(route.participant) && canonicalPathSync(item.location) === location && item.sessionId !== route.sessionId))
|
|
174
111
|
return { state, result: undefined };
|
|
175
112
|
}
|
|
176
113
|
const identity = routeIdentityKey({ ...route, location });
|
|
177
|
-
const matching = (state.routes ?? []).filter((item) => routeIdentityKey(item,
|
|
114
|
+
const matching = (state.routes ?? []).filter((item) => routeIdentityKey(item, canonicalPathSync(item.location)) === identity);
|
|
178
115
|
const existing = matching[0];
|
|
179
116
|
const existingEpoch = existing?.epoch;
|
|
180
117
|
const epochMatches = route.epoch === undefined ? existingEpoch === undefined : existingEpoch === route.epoch;
|
|
181
118
|
if (matching.length === 1 && existing !== undefined && existing.updatedAt > at - ROUTE_FRESH_MS && existing.kind === route.kind && existing.channel === route.channel && sameRouteAddress(existing.address, route.address) && epochMatches)
|
|
182
119
|
return { result: undefined };
|
|
183
|
-
return { state: { ...state, routes: [...(state.routes ?? []).filter((item) => routeIdentityKey(item,
|
|
120
|
+
return { state: { ...state, routes: [...(state.routes ?? []).filter((item) => routeIdentityKey(item, canonicalPathSync(item.location)) !== identity), { ...route, location, updatedAt: at }] }, result: undefined };
|
|
184
121
|
});
|
|
185
122
|
}
|
|
186
|
-
export async function retireWakeRoute(route, opts = {}) {
|
|
187
|
-
const location = await canonicalRouteLocation(route.location);
|
|
188
|
-
await withArtifact(location, async (square) => retireWakeRouteFromArtifact(square.artifact, { ...route, location }, opts));
|
|
189
|
-
}
|
|
190
123
|
export async function retireWakeRouteFromArtifact(artifact, route, opts = {}) {
|
|
191
|
-
const location = await
|
|
124
|
+
const location = await canonicalPath(route.location);
|
|
192
125
|
const target = routeIdentityKey({ ...route, location });
|
|
193
126
|
await artifact.transact((state) => ({ state: { ...state, routes: (state.routes ?? []).filter((item) => {
|
|
194
|
-
const itemLocation =
|
|
127
|
+
const itemLocation = canonicalPathSync(item.location);
|
|
195
128
|
if (routeIdentityKey(item, itemLocation) !== target)
|
|
196
129
|
return true;
|
|
197
|
-
|
|
198
|
-
return opts.expectedEpoch !== undefined && itemEpoch !== opts.expectedEpoch;
|
|
199
|
-
}) }, result: undefined }));
|
|
200
|
-
}
|
|
201
|
-
export async function retireWakeRoutesForSessionFromArtifact(artifact, route, opts = {}) {
|
|
202
|
-
const location = canonicalRouteLocationSync(route.location);
|
|
203
|
-
await artifact.transact((state) => ({ state: { ...state, routes: (state.routes ?? []).filter((item) => {
|
|
204
|
-
if (canonicalRouteLocationSync(item.location) !== location || item.sessionId !== route.sessionId)
|
|
205
|
-
return true;
|
|
206
|
-
if (opts.expectedEpoch === undefined)
|
|
207
|
-
return false;
|
|
208
|
-
const itemEpoch = item.epoch;
|
|
209
|
-
return itemEpoch !== undefined && itemEpoch !== opts.expectedEpoch;
|
|
130
|
+
return opts.expectedEpoch !== undefined && item.epoch !== opts.expectedEpoch;
|
|
210
131
|
}) }, result: undefined }));
|
|
211
132
|
}
|
|
212
|
-
export async function canonicalRouteLocation(location) {
|
|
213
|
-
return canonicalRouteLocationSync(location);
|
|
214
|
-
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { type ActivityId, type LandedAudienceReplay, type Reach } from './square-core.js';
|
|
2
|
-
import { type StoredAct, type SquareState, type HoldState, type
|
|
2
|
+
import { type StoredAct, type SquareState, type HoldState, type ObservationState, type WatchLease } from './model.js';
|
|
3
3
|
export declare const WATCH_HEARTBEAT_MS: number;
|
|
4
4
|
export declare const SLEEP_MS: number;
|
|
5
5
|
export declare const STALE_MS: number;
|
|
6
6
|
export declare const WATCH_STALE_MS: number;
|
|
7
|
-
export declare const LOCK_RETRY_MS: number;
|
|
8
7
|
export declare const THROTTLE_WINDOW_MS: number;
|
|
9
8
|
export declare const UNREAD_BLOCK_GRACE_MS: number;
|
|
10
9
|
/** A held express waits for the hand to lower, but not forever: past this budget it gives up exactly like --no-wait (draft saved, retry printed). 0 disables waiting. */
|
|
@@ -20,12 +19,10 @@ export declare function foldedState(squareState: SquareState): import("./square-
|
|
|
20
19
|
export declare function rosterNames(squareState: SquareState): string[];
|
|
21
20
|
export declare function inSquareCount(squareState: SquareState): number;
|
|
22
21
|
export declare function resolveRosterName(squareState: SquareState, name: string): string | undefined;
|
|
23
|
-
export declare function hasQuorum(squareState: SquareState, name: string, outs: Set<string>): boolean;
|
|
24
22
|
export declare function countSays(acts: StoredAct[], name: string): number;
|
|
25
23
|
export declare function sayNumberFor(acts: StoredAct[], target: StoredAct): number;
|
|
26
24
|
/** Shared terminal condition for a participant's watch lifecycle. */
|
|
27
25
|
export declare function watchTerminalStatus(squareState: SquareState, name: string): 'capped' | 'quorum' | undefined;
|
|
28
|
-
export declare function doneNames(acts: StoredAct[]): Set<string>;
|
|
29
26
|
export declare function joinedNames(acts: StoredAct[]): Set<string>;
|
|
30
27
|
export declare function isCurrentlyJoined(acts: StoredAct[], name: string): boolean;
|
|
31
28
|
/** Stable index of the recipient's most recent join act, if any. */
|
|
@@ -36,19 +33,16 @@ export declare function currentHold(acts: StoredAct[]): HoldState;
|
|
|
36
33
|
export declare function publicActs(acts: StoredAct[]): Array<Extract<StoredAct, {
|
|
37
34
|
kind: 'say' | 'done';
|
|
38
35
|
}>>;
|
|
39
|
-
export declare function observationFor(squareState: SquareState, name: string, index: number): ActivityObservation | undefined;
|
|
40
36
|
export declare function recordObservation(squareState: SquareState, name: string, index: number, state: ObservationState, at?: number): boolean;
|
|
41
37
|
export declare function readCursor(squareState: SquareState, name: string, landed?: LandedAudienceReplay): number;
|
|
42
|
-
export declare function latestActIndex(acts: StoredAct[]): number;
|
|
43
38
|
/**
|
|
39
|
+
* The last public act the participant was verifiably present for, or -1 when there is no evidence.
|
|
40
|
+
*
|
|
44
41
|
* "Was here" is a claim of presence, so it rides on evidence: the participant's own acts
|
|
45
42
|
* and seen receipts after their latest join. Anything else — in particular acts merely
|
|
46
43
|
* not addressed to them — says nothing about where they actually were.
|
|
47
44
|
*/
|
|
48
|
-
export declare function presenceEvidenceCursor(squareState: SquareState, name: string, landed?: LandedAudienceReplay): number;
|
|
49
|
-
/** The last public act the participant was verifiably present for, or -1 when there is no evidence. */
|
|
50
45
|
export declare function presenceAnchor(squareState: SquareState, name: string, landed?: LandedAudienceReplay): number;
|
|
51
46
|
export declare function freshWatchLease(squareState: SquareState, name: string, at?: number): WatchLease | undefined;
|
|
52
|
-
export declare function watchLease(squareState: SquareState, name: string): WatchLease | undefined;
|
|
53
47
|
export declare function writeWatchLease(squareState: SquareState, name: string, lease: WatchLease): void;
|
|
54
48
|
export declare function removeWatchLease(squareState: SquareState, name: string, leaseId: string): boolean;
|