@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.
Files changed (171) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +3 -2
  2. package/claude-plugin/hooks/hooks.json +1 -22
  3. package/claude-plugin/hooks/register.js +119 -0
  4. package/claude-plugin/types.d.ts +7 -0
  5. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  6. package/dist/activity-feed.d.ts +1 -10
  7. package/dist/activity-feed.js +1 -27
  8. package/dist/activity.js +57 -25
  9. package/dist/artifact.d.ts +1 -1
  10. package/dist/artifact.js +24 -25
  11. package/dist/attention-presentation.js +1 -0
  12. package/dist/automatic-session.d.ts +3 -1
  13. package/dist/automatic-session.js +21 -34
  14. package/dist/boundary-presentation.js +4 -13
  15. package/dist/canonical-path.d.ts +11 -0
  16. package/dist/canonical-path.js +47 -0
  17. package/dist/catch-decisions.js +14 -10
  18. package/dist/catch-selection.d.ts +6 -0
  19. package/dist/catch-selection.js +14 -0
  20. package/dist/claude-delivery.d.ts +11 -0
  21. package/dist/claude-delivery.js +145 -0
  22. package/dist/claude-mod.d.ts +8 -0
  23. package/dist/claude-mod.js +164 -0
  24. package/dist/cli/context.d.ts +0 -1
  25. package/dist/cli/context.js +9 -21
  26. package/dist/cli/harness-command.d.ts +0 -1
  27. package/dist/cli/harness-command.js +0 -6
  28. package/dist/cli/observation-commands.d.ts +1 -1
  29. package/dist/cli/observation-commands.js +31 -58
  30. package/dist/cli/program.js +20 -18
  31. package/dist/cli/registry.js +2 -2
  32. package/dist/cli/square-commands.js +10 -6
  33. package/dist/codex-boundary-state.d.ts +2 -2
  34. package/dist/codex-boundary-state.js +4 -4
  35. package/dist/codex-hook.js +12 -15
  36. package/dist/codex-queue.d.ts +2 -2
  37. package/dist/codex-queue.js +7 -5
  38. package/dist/decisions.d.ts +2 -6
  39. package/dist/decisions.js +16 -17
  40. package/dist/delivery-health.d.ts +1 -2
  41. package/dist/delivery-health.js +4 -5
  42. package/dist/delivery-operations.d.ts +2 -5
  43. package/dist/delivery-operations.js +77 -214
  44. package/dist/delivery.d.ts +25 -47
  45. package/dist/delivery.js +14 -46
  46. package/dist/diagnostic-redaction.js +7 -9
  47. package/dist/file-changes.d.ts +0 -1
  48. package/dist/file-changes.js +2 -19
  49. package/dist/harness-claude.js +8 -6
  50. package/dist/harness-codex.d.ts +0 -2
  51. package/dist/harness-codex.js +0 -2
  52. package/dist/harness-links.js +13 -17
  53. package/dist/harness.js +3 -7
  54. package/dist/help.js +4 -3
  55. package/dist/host-ledger-file-adapter.d.ts +17 -8
  56. package/dist/host-ledger-file-adapter.js +164 -80
  57. package/dist/host-ledger.d.ts +55 -50
  58. package/dist/inbox.d.ts +0 -3
  59. package/dist/inbox.js +88 -50
  60. package/dist/index.d.ts +1 -1
  61. package/dist/index.js +1 -1
  62. package/dist/list.js +1 -4
  63. package/dist/mcp.js +24 -41
  64. package/dist/mention-parse.js +3 -9
  65. package/dist/model.d.ts +11 -2
  66. package/dist/model.js +1 -1
  67. package/dist/notifications.d.ts +3 -16
  68. package/dist/notifications.js +41 -122
  69. package/dist/opencode-delivery.d.ts +14 -0
  70. package/dist/opencode-delivery.js +171 -0
  71. package/dist/opencode.d.ts +39 -18
  72. package/dist/opencode.js +145 -40
  73. package/dist/packages/agent-delivery/src/claude-auth.d.ts +13 -0
  74. package/dist/packages/agent-delivery/src/claude-auth.js +75 -0
  75. package/dist/packages/agent-delivery/src/claude-native.d.ts +28 -0
  76. package/dist/packages/agent-delivery/src/claude-native.js +68 -0
  77. package/dist/packages/agent-delivery/src/claude.d.ts +14 -0
  78. package/dist/packages/agent-delivery/src/claude.js +66 -0
  79. package/dist/packages/agent-delivery/src/deadline.d.ts +11 -0
  80. package/dist/packages/agent-delivery/src/deadline.js +41 -0
  81. package/dist/packages/agent-delivery/src/errors.d.ts +16 -0
  82. package/dist/packages/agent-delivery/src/errors.js +41 -0
  83. package/dist/packages/agent-delivery/src/guards.d.ts +6 -0
  84. package/dist/packages/agent-delivery/src/guards.js +6 -0
  85. package/dist/packages/agent-delivery/src/index.d.ts +83 -0
  86. package/dist/packages/agent-delivery/src/index.js +110 -0
  87. package/dist/packages/agent-delivery/src/local-endpoint.d.ts +26 -0
  88. package/dist/packages/agent-delivery/src/local-endpoint.js +114 -0
  89. package/dist/packages/agent-delivery/src/opencode-native.d.ts +33 -0
  90. package/dist/packages/agent-delivery/src/opencode-native.js +75 -0
  91. package/dist/packages/agent-delivery/src/opencode.d.ts +14 -0
  92. package/dist/packages/agent-delivery/src/opencode.js +127 -0
  93. package/dist/packages/agent-delivery/src/paseo-native.d.ts +58 -0
  94. package/dist/packages/agent-delivery/src/paseo-native.js +122 -0
  95. package/dist/packages/agent-delivery/src/paseo.d.ts +19 -0
  96. package/dist/packages/agent-delivery/src/paseo.js +106 -0
  97. package/dist/packages/agent-delivery/src/pi-client.d.ts +10 -0
  98. package/dist/packages/agent-delivery/src/pi-client.js +106 -0
  99. package/dist/packages/agent-delivery/src/pi-protocol.d.ts +15 -0
  100. package/dist/packages/agent-delivery/src/pi-protocol.js +50 -0
  101. package/dist/packages/agent-delivery/src/pi-send.d.ts +23 -0
  102. package/dist/packages/agent-delivery/src/pi-send.js +4 -0
  103. package/dist/packages/agent-delivery/src/pi.d.ts +25 -0
  104. package/dist/packages/agent-delivery/src/pi.js +209 -0
  105. package/dist/packages/agent-delivery/src/types.d.ts +120 -0
  106. package/dist/participant-host.js +12 -13
  107. package/dist/participant-identity.d.ts +21 -0
  108. package/dist/participant-identity.js +32 -11
  109. package/dist/paseo-delivery.d.ts +2 -2
  110. package/dist/paseo-delivery.js +35 -27
  111. package/dist/paseo-timeline.js +25 -21
  112. package/dist/paseo.d.ts +2 -2
  113. package/dist/paseo.js +1 -2
  114. package/dist/ports.d.ts +7 -20
  115. package/dist/presentation-operations.js +16 -4
  116. package/dist/presentation.d.ts +19 -10
  117. package/dist/presentation.js +99 -177
  118. package/dist/registry.d.ts +15 -66
  119. package/dist/registry.js +45 -123
  120. package/dist/routes.d.ts +1 -28
  121. package/dist/routes.js +22 -104
  122. package/dist/runtime.d.ts +3 -9
  123. package/dist/runtime.js +14 -67
  124. package/dist/search.d.ts +0 -2
  125. package/dist/search.js +3 -10
  126. package/dist/square-actions.js +48 -72
  127. package/dist/square-application.js +32 -30
  128. package/dist/square-core.d.ts +3 -0
  129. package/dist/square-core.js +22 -5
  130. package/dist/square-facade.d.ts +2 -0
  131. package/dist/square-file-adapter.d.ts +2 -1
  132. package/dist/square-file-adapter.js +6 -9
  133. package/dist/square-projections.d.ts +40 -45
  134. package/dist/square-projections.js +60 -74
  135. package/dist/square-state.js +1 -4
  136. package/dist/square-storage.d.ts +5 -8
  137. package/dist/square-storage.js +13 -36
  138. package/dist/square-wiring.d.ts +2 -7
  139. package/dist/square-wiring.js +6 -24
  140. package/dist/stream.js +4 -6
  141. package/dist/time.js +2 -7
  142. package/dist/views.d.ts +6 -18
  143. package/dist/views.js +14 -21
  144. package/dist/wake-attempts.d.ts +2 -56
  145. package/dist/wake-attempts.js +15 -110
  146. package/dist/wake-eligibility.d.ts +43 -0
  147. package/dist/wake-eligibility.js +106 -0
  148. package/dist/wake-evidence.d.ts +32 -9
  149. package/dist/wake-evidence.js +29 -24
  150. package/dist/wake-sink.d.ts +13 -9
  151. package/dist/wake-sink.js +35 -54
  152. package/dist/watch.js +13 -21
  153. package/extensions/square-pi.js +27 -13
  154. package/guides/change-waits.md +1 -1
  155. package/guides/claude-native.md +101 -0
  156. package/guides/host-ledger.md +3 -1
  157. package/guides/participant.md +14 -7
  158. package/guides/pi-native-delivery.md +49 -0
  159. package/package.json +4 -3
  160. package/dist/claude-hook.d.ts +0 -10
  161. package/dist/claude-hook.js +0 -60
  162. package/dist/paseo-connection.d.ts +0 -15
  163. package/dist/paseo-connection.js +0 -141
  164. package/dist/presence.d.ts +0 -2
  165. package/dist/presence.js +0 -24
  166. package/dist/presented.d.ts +0 -2
  167. package/dist/presented.js +0 -10
  168. package/dist/state-cell.d.ts +0 -14
  169. package/dist/wake-port.d.ts +0 -23
  170. package/dist/wake-port.js +0 -27
  171. /package/dist/{state-cell.js → packages/agent-delivery/src/types.js} +0 -0
package/dist/registry.js CHANGED
@@ -1,97 +1,47 @@
1
- /** Machine-local participant discovery cache. */
2
- import path from 'node:path';
3
- import { withFileLock } from './file-lock.js';
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
- const MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
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
- function toBinding(record) {
30
- return {
31
- sessionId: record.session,
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 readActiveBindings(now = Date.now(), env = process.env) { try {
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, env = process.env) {
72
- const bindings = await lookupParticipant(squarePath, name, Date.now(), env);
73
- return bindings.sort((left, right) => right.epoch - left.epoch || right.updatedAt - left.updatedAt)[0];
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, env = process.env, expectedEpoch) {
76
- const owner = await readParticipantOwner(squarePath, name, env);
77
- if (owner === undefined || owner.sessionId !== sessionId)
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.epoch === expectedEpoch;
30
+ return expectedEpoch === undefined || presenceEpoch(owner) === expectedEpoch;
80
31
  }
81
- export async function releaseSessionParticipantClaim(squarePath, name, env, claim) {
32
+ export async function releaseSessionParticipantClaim(hostLedger, claim) {
82
33
  if (claim?.status !== 'acquired')
83
34
  return;
84
- const port = ledger(env);
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 canonicalSquarePath(squarePath);
94
- const result = await ledger(env).claimPresence({
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
- * presence-claim lock, so no second takeover can interleave between claim and commit. The claim
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 canonicalSquarePath(squarePath);
123
- return withFileLock(presenceClaimLockPath(env), { ...PRESENCE_CLAIM_LOCK, signal }, async () => {
124
- const port = ledger(env);
125
- const standing = await port.listPresence({ location, participant: name });
126
- const owner = standing
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?.sessionId === opts.expectedSession);
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 ledger(env).listPresence({ location, participant: name, session: identity.sessionId });
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 ledger(env).removePresence({ location: row.location, participant: row.participant, session: row.session, channel: row.channel });
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 ledger(env).ensurePresence(row);
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 ledger(env).removePresence({ location: row.location, participant: row.participant, session: row.session, channel: row.channel });
160
- await ledger(env).ensurePresence({ location, participant: name, session: identity.sessionId, channel: identity.channel, updatedAt: Date.now(), epoch });
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 ledger(env).removePresence({ location: squarePath, participant: name, session: identity.sessionId, channel: identity.channel });
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 LOCAL_SESSION_SOURCES)
187
- addLocalSession(identities, env[source.variable]?.trim(), source.channel, source.child !== undefined && env[source.child] === '1', paseoAgentId); addLocalSession(identities, paseoAgentId, 'paseo', false, paseoAgentId); return identities; }
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 ledger(env); }
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 readWakeRoutes(opts?: {
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 nativeCandidate(boundary) {
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
- const native = nativeCandidate(boundary);
50
- if (native)
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 = canonicalRouteLocationSync(route.location);
48
+ const location = canonicalPathSync(route.location);
107
49
  state.routes = [...(state.routes ?? []).filter((item) => {
108
- const itemLocation = canonicalRouteLocationSync(item.location);
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 = canonicalRouteLocationSync(location);
55
+ const canonical = canonicalPathSync(location);
114
56
  state.routes = (state.routes ?? []).filter((item) => {
115
- if (item.sessionId !== sessionId || canonicalRouteLocationSync(item.location) !== canonical)
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 = canonicalRouteLocationSync(location);
74
+ const canonical = canonicalPathSync(location);
133
75
  state.routes = (state.routes ?? []).filter((item) => {
134
- if (item.sessionId !== sessionId || canonicalRouteLocationSync(item.location) !== canonical)
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 = canonicalRouteLocationSync(location);
153
- state.routes = (state.routes ?? []).filter((item) => !(nameKey(item.participant) === nameKey(participant) && canonicalRouteLocationSync(item.location) === canonical));
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 = canonicalRouteLocationSync(location);
162
- const owned = (state.routes ?? []).filter((item) => nameKey(item.participant) === nameKey(participant) && canonicalRouteLocationSync(item.location) === canonical);
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 canonicalRouteLocation(route.location);
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
- const participantRoutes = (state.routes ?? []).filter((item) => nameKey(item.participant) === nameKey(route.participant) && canonicalRouteLocationSync(item.location) === location);
173
- if (!isCurrentlyJoined(state.acts, route.participant) || participantRoutes.some((item) => item.sessionId !== route.sessionId))
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, canonicalRouteLocationSync(item.location)) === identity);
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, canonicalRouteLocationSync(item.location)) !== identity), { ...route, location, updatedAt: at }] }, result: undefined };
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 canonicalRouteLocation(route.location);
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 = canonicalRouteLocationSync(item.location);
127
+ const itemLocation = canonicalPathSync(item.location);
195
128
  if (routeIdentityKey(item, itemLocation) !== target)
196
129
  return true;
197
- const itemEpoch = item.epoch;
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 ActivityObservation, type ObservationState, type WatchLease } from './model.js';
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;