@astrosheep/square 0.3.86 → 0.3.88

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 (143) hide show
  1. package/dist/artifact.d.ts +6 -1
  2. package/dist/artifact.js +79 -10
  3. package/dist/boundary-presentation.d.ts +5 -4
  4. package/dist/boundary-presentation.js +21 -25
  5. package/dist/catch-decisions.js +2 -1
  6. package/dist/claude-delivery-status.d.ts +8 -2
  7. package/dist/claude-delivery-status.js +26 -10
  8. package/dist/claude-delivery.d.ts +8 -4
  9. package/dist/claude-delivery.js +114 -104
  10. package/dist/claude-mcp-context.js +2 -2
  11. package/dist/claude-mod.js +119 -105
  12. package/dist/cli/context.d.ts +3 -1
  13. package/dist/cli/context.js +25 -1
  14. package/dist/cli/express-presentation.d.ts +3 -1
  15. package/dist/cli/express-presentation.js +14 -10
  16. package/dist/cli/mcp-server-command.js +2 -2
  17. package/dist/cli/observation-commands.js +1 -0
  18. package/dist/cli/registry.js +0 -2
  19. package/dist/cli/square-commands.d.ts +4 -2
  20. package/dist/cli/square-commands.js +21 -6
  21. package/dist/codex-hook.d.ts +3 -3
  22. package/dist/codex-hook.js +4 -4
  23. package/dist/codex-queue.d.ts +5 -6
  24. package/dist/codex-queue.js +9 -5
  25. package/dist/decisions.d.ts +3 -2
  26. package/dist/decisions.js +18 -6
  27. package/dist/delivery-health.d.ts +32 -2
  28. package/dist/delivery-health.js +108 -45
  29. package/dist/delivery-operations.d.ts +1 -2
  30. package/dist/delivery-operations.js +155 -196
  31. package/dist/delivery.d.ts +14 -23
  32. package/dist/delivery.js +48 -18
  33. package/dist/file-lock.d.ts +8 -1
  34. package/dist/file-lock.js +2 -0
  35. package/dist/help.js +8 -11
  36. package/dist/inbox.d.ts +35 -9
  37. package/dist/inbox.js +228 -144
  38. package/dist/index.d.ts +3 -4
  39. package/dist/index.js +1 -3
  40. package/dist/list.js +9 -4
  41. package/dist/mcp.js +12 -1
  42. package/dist/model.d.ts +39 -5
  43. package/dist/model.js +84 -0
  44. package/dist/notifications.d.ts +8 -6
  45. package/dist/notifications.js +56 -143
  46. package/dist/operation-presentation.js +7 -4
  47. package/dist/participant-identity.d.ts +0 -3
  48. package/dist/participant-identity.js +0 -31
  49. package/dist/paseo-delivery.d.ts +5 -6
  50. package/dist/paseo-delivery.js +13 -8
  51. package/dist/paseo.d.ts +1 -1
  52. package/dist/paseo.js +1 -1
  53. package/dist/plugins/opencode/delivery.d.ts +8 -3
  54. package/dist/plugins/opencode/delivery.js +187 -132
  55. package/dist/plugins/opencode/index.js +12 -38
  56. package/dist/ports.d.ts +112 -40
  57. package/dist/presentation-operations.d.ts +1 -1
  58. package/dist/presentation-operations.js +51 -35
  59. package/dist/presentation.js +8 -3
  60. package/dist/seats.d.ts +7 -0
  61. package/dist/seats.js +27 -0
  62. package/dist/session-lifecycle.d.ts +2 -2
  63. package/dist/session-lifecycle.js +10 -12
  64. package/dist/sqlite-square.d.ts +20 -9
  65. package/dist/sqlite-square.js +476 -341
  66. package/dist/square-api.d.ts +1 -0
  67. package/dist/square-api.js +3 -4
  68. package/dist/square-core.d.ts +3 -2
  69. package/dist/square-domain.d.ts +12 -5
  70. package/dist/square-domain.js +163 -7
  71. package/dist/square-facade.d.ts +16 -10
  72. package/dist/square-index.d.ts +24 -0
  73. package/dist/square-index.js +131 -0
  74. package/dist/square-legacy-framing.d.ts +9 -0
  75. package/dist/square-legacy-framing.js +56 -0
  76. package/dist/square-migration-host-ledger.d.ts +26 -0
  77. package/dist/square-migration-host-ledger.js +168 -0
  78. package/dist/square-migration.d.ts +5 -5
  79. package/dist/square-migration.js +373 -71
  80. package/dist/square-sqlite.d.ts +9 -9
  81. package/dist/square-sqlite.js +329 -79
  82. package/dist/square-stdio.d.ts +1 -1
  83. package/dist/square-stdio.js +12 -7
  84. package/dist/square-tools.d.ts +1 -1
  85. package/dist/square-tools.js +80 -27
  86. package/dist/stdio-server.js +4 -2
  87. package/dist/stream.d.ts +3 -2
  88. package/dist/stream.js +9 -10
  89. package/dist/views.d.ts +9 -14
  90. package/dist/views.js +52 -70
  91. package/dist/wakes.d.ts +6 -5
  92. package/dist/wakes.js +20 -17
  93. package/guides/application-facade-delivery-evidence.md +1 -1
  94. package/guides/claude-native.md +9 -9
  95. package/guides/mcp.md +2 -2
  96. package/guides/migration.md +107 -67
  97. package/guides/pi-tools.md +1 -1
  98. package/guides/row-storage-design.md +1 -1
  99. package/guides/square-api.md +61 -28
  100. package/package.json +1 -1
  101. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  102. package/plugins/claude/hooks/register.js +1 -1
  103. package/plugins/claude/skills/square/SKILL.md +4 -4
  104. package/plugins/claude/types.d.ts +1 -1
  105. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  106. package/plugins/opencode/delivery.ts +170 -118
  107. package/plugins/opencode/index.ts +12 -30
  108. package/plugins/pi/square-pi.js +56 -18
  109. package/skills/square/SKILL.md +4 -4
  110. package/dist/cli/ledger-command.d.ts +0 -12
  111. package/dist/cli/ledger-command.js +0 -72
  112. package/dist/host-ledger-file-adapter.d.ts +0 -47
  113. package/dist/host-ledger-file-adapter.js +0 -384
  114. package/dist/host-ledger-migration.d.ts +0 -27
  115. package/dist/host-ledger-migration.js +0 -264
  116. package/dist/host-ledger-root.d.ts +0 -2
  117. package/dist/host-ledger-root.js +0 -9
  118. package/dist/host-ledger-sqlite.d.ts +0 -65
  119. package/dist/host-ledger-sqlite.js +0 -368
  120. package/dist/host-ledger.d.ts +0 -195
  121. package/dist/host-ledger.js +0 -1
  122. package/dist/ledger-maintenance.d.ts +0 -30
  123. package/dist/ledger-maintenance.js +0 -110
  124. package/dist/open-square.d.ts +0 -38
  125. package/dist/open-square.js +0 -81
  126. package/dist/participant-host.d.ts +0 -23
  127. package/dist/participant-host.js +0 -92
  128. package/dist/registry.d.ts +0 -55
  129. package/dist/registry.js +0 -123
  130. package/dist/routes.d.ts +0 -39
  131. package/dist/routes.js +0 -99
  132. package/dist/square-actions.d.ts +0 -56
  133. package/dist/square-actions.js +0 -353
  134. package/dist/square-projections.d.ts +0 -31
  135. package/dist/square-projections.js +0 -64
  136. package/dist/wake-attempts.d.ts +0 -10
  137. package/dist/wake-attempts.js +0 -39
  138. package/dist/wake-eligibility.d.ts +0 -53
  139. package/dist/wake-eligibility.js +0 -123
  140. package/dist/wake-evidence.d.ts +0 -33
  141. package/dist/wake-evidence.js +0 -32
  142. package/guides/host-ledger.md +0 -58
  143. package/guides/indexed-host-ledger-performance.md +0 -39
@@ -3,9 +3,10 @@ import path from 'node:path';
3
3
  import { createInterface } from 'node:readline';
4
4
  import { SquareError } from './model.js';
5
5
  import { harnessSessionSources } from './participant-identity.js';
6
+ import { requireJoinName } from './seats.js';
6
7
  export const STDIO_PROTOCOL_VERSION = 1;
7
8
  export const STDIO_MAX_FRAME_BYTES = 8 * 1024 * 1024;
8
- export const identityVariables = [...harnessSessionSources.flatMap(source => [source.variable, ...(source.childVariable ? [source.childVariable] : [])]), 'SQUARE_PARTICIPANT_NAME'];
9
+ export const identityVariables = [...harnessSessionSources.flatMap(source => [source.variable, ...(source.childVariable ? [source.childVariable] : [])])];
9
10
  export function wireIdentity(env) {
10
11
  return Object.fromEntries(identityVariables.map(key => [key, env[key] ?? '']));
11
12
  }
@@ -162,7 +163,11 @@ class StdioSquare {
162
163
  participantHandle(name) {
163
164
  return {
164
165
  name,
165
- express: (body, options, control) => this.call('express', [body, options], control, name),
166
+ express: ((bodyOrInput, optionsOrControl, control) => {
167
+ if (typeof bodyOrInput === 'object' && bodyOrInput !== null)
168
+ return this.call('express', [bodyOrInput, undefined], optionsOrControl, name);
169
+ return this.call('express', [bodyOrInput, optionsOrControl], control, name);
170
+ }),
166
171
  catch: (options, control) => this.call('catch', [options], control, name),
167
172
  listen: (target, options, control) => this.call('listen', [target, options], control, name),
168
173
  ignore: (target, options, control) => this.call('ignore', [target, options], control, name),
@@ -176,6 +181,7 @@ class StdioSquare {
176
181
  }
177
182
  async participant(name) { return this.participantHandle(await this.call('participant', [name])); }
178
183
  async join(...[name, options, control]) {
184
+ requireJoinName(name);
179
185
  const result = await this.call('join', [name, options], control);
180
186
  return { ...result, participant: this.participantHandle(result.participant) };
181
187
  }
@@ -187,14 +193,13 @@ class StdioSquare {
187
193
  stream() { unsupported('stream'); }
188
194
  recognize() { return Promise.reject(new SquareError('invalid_args', 'stdio does not support host recognition; select a participant explicitly')); }
189
195
  implicitJoin() { unsupported('host implicit join'); }
190
- doneOwnedSession() { unsupported('host session cleanup'); }
191
196
  endOwnedSession() { unsupported('host session cleanup'); }
192
- retireEndedSessionRoutes() { unsupported('host wake routes'); }
197
+ cancelDeliveries() { unsupported('host delivery cancellation'); }
193
198
  close() { return this.connection.close(); }
194
199
  }
195
200
  export async function openStdioSquare(location, selected, input, backends, build, control) {
196
- if (input.clock || input.hostLedger || input.wakeTransport)
197
- unsupported('client clock, hostLedger or wakeTransport injection');
201
+ if (input.clock || input.wakeTransport)
202
+ unsupported('client clock or wakeTransport injection');
198
203
  if (control?.signal?.aborted)
199
204
  throw control.signal.reason ?? new Error('Operation cancelled');
200
205
  const backend = Object.hasOwn(backends, selected.backend) ? backends[selected.backend] : undefined;
@@ -205,7 +210,7 @@ export async function openStdioSquare(location, selected, input, backends, build
205
210
  const connection = new Connection(command, backend.args ?? [], path.resolve(cwd, backend.cwd ?? '.'), { ...(input.env ?? process.env), ...backend.env });
206
211
  try {
207
212
  const result = await connection.request('square/open', { version: STDIO_PROTOCOL_VERSION, key: selected.key, location,
208
- identity: wireIdentity(input.env ?? process.env), participant: input.participant, build }, control);
213
+ identity: wireIdentity(input.env ?? process.env), body: input.body, participant: input.participant, build }, control);
209
214
  if (result.version !== STDIO_PROTOCOL_VERSION || typeof result.handle !== 'string')
210
215
  throw new SquareError('unavailable', 'Backend protocol version mismatch');
211
216
  return new StdioSquare(location, connection, result.handle);
@@ -16,7 +16,7 @@ interface ToolDefinition {
16
16
  export interface ToolControl extends OperationControl {
17
17
  readonly observe?: boolean;
18
18
  }
19
- export declare const SQUARE_TOOL_INSTRUCTIONS = "The catch tool consumes activities. Use history with act/<index> cursors for read-only archive access.";
19
+ export declare const SQUARE_TOOL_INSTRUCTIONS = "Join once. Then express to speak, and catch to take in what reached you. History looks back without taking anything in.";
20
20
  export declare const SQUARE_TOOLS: readonly ToolDefinition[];
21
21
  export declare function squareToolFailure(error: unknown, signal?: AbortSignal): JsonObject;
22
22
  /** Readable failure text with the same recovery commands the CLI offers, never raw JSON. */
@@ -1,9 +1,9 @@
1
1
  import { z } from 'zod/v4';
2
2
  import { isSquareError } from './model.js';
3
3
  import { CATCH_DEFAULT_LIMIT } from './square-api.js';
4
- import { renderCatchOutcome, renderExpression, renderFailureLines, renderHistoryResult, renderJoinResult, renderLifecycleResult, renderListenerChange, renderListeningResult, renderParticipantsResult, renderStatusResult, } from './operation-presentation.js';
5
- const location = z.string().optional().describe('Local .square artifact path or configured backend URI (stdio://name/key). Relative paths use the current working directory. Defaults to the configured square.');
6
- const participant = z.string().optional().describe('Participant name. Defaults to the configured participant or the current session’s unambiguous participant.');
4
+ import { renderCatchOutcome, renderExpression, renderFailureLines, renderHistoryResult, renderJoinResult, renderLifecycleResult, renderListenerChange, renderStatusResult, } from './operation-presentation.js';
5
+ const location = z.string().optional().describe('Which square: a .square file path, or a backend URI like stdio://name/key. Relative paths start from the working directory. Leave it out for the configured square.');
6
+ const participant = z.string().optional().describe('Your name in the square. Leave it out if you hold exactly one name here.');
7
7
  const activityId = z.string().regex(/^act\/(0|[1-9][0-9]*)$/);
8
8
  const stringArray = z.array(z.string());
9
9
  /** Keep the observation request internal: it is not an argument a caller decides. */
@@ -14,50 +14,103 @@ function observation(control) {
14
14
  function rendering(render) {
15
15
  return (result, args) => render(result, args);
16
16
  }
17
+ /**
18
+ * Tool receipts are the one machine surface without activity metadata: a receipt copy drops every
19
+ * property named `metadata` while domain activities keep theirs for SDK, CLI, stdio and stream readers.
20
+ */
21
+ function withoutActivityMetadata(value) {
22
+ if (Array.isArray(value))
23
+ return value.map(withoutActivityMetadata);
24
+ if (value === null || typeof value !== 'object')
25
+ return value;
26
+ const prototype = Object.getPrototypeOf(value);
27
+ if (prototype !== Object.prototype && prototype !== null)
28
+ return value;
29
+ return Object.fromEntries(Object.entries(value).filter(([key]) => key !== 'metadata')
30
+ .map(([key, item]) => [key, withoutActivityMetadata(item)]));
31
+ }
32
+ /**
33
+ * Human text renders from the unfiltered receipt, so metadata-only says keep the placeholder the
34
+ * CLI prints and every other sentence stays identical. Machines only ever receive the filtered copy.
35
+ */
36
+ const renderingReceipts = new WeakMap();
37
+ function renderingReceipt(receipt) {
38
+ return (renderingReceipts.get(receipt) ?? receipt);
39
+ }
17
40
  function tool(name, description, shape, run, render) {
18
41
  const inputSchema = z.object({ ...shape, location }).strict();
19
- return { name, description, inputSchema, render, run: (square, args, control) => {
42
+ return { name, description, inputSchema, render: (receipt, args) => render(renderingReceipt(receipt), args),
43
+ run: async (square, args, control) => {
20
44
  const { location: _location, ...operationArgs } = inputSchema.parse(args);
21
- return run(square, operationArgs, control);
45
+ const receipt = await run(square, operationArgs, control);
46
+ const filtered = withoutActivityMetadata(receipt);
47
+ renderingReceipts.set(filtered, receipt);
48
+ return filtered;
22
49
  } };
23
50
  }
24
- export const SQUARE_TOOL_INSTRUCTIONS = 'The catch tool consumes activities. Use history with act/<index> cursors for read-only archive access.';
51
+ export const SQUARE_TOOL_INSTRUCTIONS = 'Join once. Then express to speak, and catch to take in what reached you. History looks back without taking anything in.';
52
+ const target = z.string().describe('The participant to turn toward or away from.');
25
53
  export const SQUARE_TOOLS = [
26
- tool('join', 'Join the square as a participant.', { as: participant, takeover: z.boolean().optional().describe('Take the name from its current session owner.') }, async (square, { as, takeover }, control) => {
54
+ tool('join', 'Step into the square under your name. Do this once before you speak or catch. You arrive seeing what was said most recently.', {
55
+ as: z.string().optional().describe('Your name in the square. Give it explicitly when joining.'), takeover: z.boolean().optional().describe('Claim this name even though another session holds it now. That session loses it.'),
56
+ }, async (square, { as, takeover }, control) => {
27
57
  const { participant, ...receipt } = await square.join(as, { takeover, ...observation(control) }, control);
28
58
  return { ...receipt, participant: participant.name };
29
59
  }, rendering((result) => renderJoinResult(result))),
30
- tool('express', 'Express a message or embodied action in the square. Mentions and replies direct attention; bell reaches everyone and keeps body @names literal. Bell cannot combine with explicit mentions. Bare activity is valid even with no listeners.', {
31
- as: participant, body: z.string(), mentions: stringArray.optional(), reach: z.enum(['bell']).optional(),
32
- reply: activityId.optional(), noMention: z.boolean().optional().describe('Disable body @name scanning; explicit mentions and reply still apply.'),
33
- force: z.boolean().optional().describe('Speak without first catching unread activity or satisfying attention etiquette.'),
34
- noWait: z.boolean().optional().describe('Return an error rather than waiting when held or throttled.'),
60
+ tool('express', 'Speak or act in the square. Plain words, half-formed ideas and *actions* all belong here. Mention or reply to someone to be heard by them; ring the bell to be heard by everyone. Said to no one in particular, your words reach those who listen to you.', {
61
+ as: participant,
62
+ body: z.string().describe('What you say or do. Markdown works; *asterisks* mark an action.'),
63
+ mentions: stringArray.optional().describe('Who you are speaking to. An @name in the body that matches someone here counts too.'),
64
+ reach: z.enum(['bell']).optional().describe('"bell" calls everyone in the square. Cannot be used with mentions.'),
65
+ reply: activityId.optional().describe('The activity you are answering, like act/12. Its author hears you if still here.'),
66
+ noMention: z.boolean().optional().describe('Leave @names in the body as plain text. Mentions and reply still reach people.'),
67
+ force: z.boolean().optional().describe('Speak now, even if something reached you that you have not caught yet.'),
68
+ noWait: z.boolean().optional().describe('If a hand is raised or you are speaking too fast, return at once instead of waiting.'),
35
69
  }, async (square, { body, as, ...options }, control) => {
36
70
  const { delivery: _delivery, ...result } = await (await square.participant(as)).express(body, { ...options, ...observation(control) }, control);
37
71
  return result;
38
72
  }, rendering((result) => renderExpression(result.observation?.location ?? '', result))),
39
- tool('catch', 'Catch and consume activities perceptible to the participant. idle waits for relevant activity or this many milliseconds of quiet; omitted means immediate. id catches one activity and cannot be combined with filters, idle or limit.', {
40
- as: participant, id: activityId.optional(), idle: z.number().finite().min(0).optional(), from: stringArray.optional(),
41
- mention: z.boolean().optional(), limit: z.number().int().min(1).optional(),
73
+ tool('catch', 'Take in what reached you since you last looked: mentions, replies, bells, and words from those you listen to. What you catch no longer waits for you; history lets you look back.', {
74
+ as: participant,
75
+ id: activityId.optional().describe('Take in this activity in full, like act/12, even if you caught it before. Do not combine with idle, from, mention or limit.'),
76
+ idle: z.number().finite().min(0).optional().describe('When nothing is waiting, wait until something arrives or until it has been quiet this many milliseconds. Leave it out to return at once.'),
77
+ from: stringArray.optional().describe('Only what these participants said.'),
78
+ mention: z.boolean().optional().describe('Only what was addressed to you, and bells.'),
79
+ limit: z.number().int().min(1).optional().describe('At most this many at once (default 10, up to 100). The rest keeps waiting.'),
42
80
  }, async (square, { as, ...options }, control) => (await square.participant(as)).catch({ ...options, ...observation(control) }, control), rendering((result, args) => {
43
81
  // The CLI always spells the default cap in its continuation, so the tool does too.
44
82
  const options = args;
45
83
  const renderOptions = options.id === undefined ? { ...options, limit: options.limit ?? CATCH_DEFAULT_LIMIT } : options;
46
84
  return renderCatchOutcome(result.observation?.location ?? '', result, renderOptions).stdout;
47
85
  })),
48
- tool('history', 'Read the activity stream without consuming it, using stable activity-id cursors. Default page size is 10, maximum 100. grep is a regex; fixed is literal text; use only one.', {
49
- limit: z.number().int().min(1).optional(), order: z.enum(['asc', 'desc']).optional(), before: activityId.optional(), after: activityId.optional(),
50
- grep: z.string().optional(), fixed: z.string().optional(), from: stringArray.optional(), mention: z.string().optional(),
86
+ tool('history', 'Look back at what was said. Reading here takes nothing in: whatever waits for catch keeps waiting. Page with before or after.', {
87
+ limit: z.number().int().min(1).optional().describe('How many per page (default 10, up to 100).'),
88
+ order: z.enum(['asc', 'desc']).optional().describe('"asc" for oldest first (default), "desc" for newest first.'),
89
+ before: activityId.optional().describe('The page just before this activity, like act/12.'),
90
+ after: activityId.optional().describe('The page just after this activity, like act/12.'),
91
+ grep: z.string().optional().describe('Only activities matching this regular expression in their names, ids or words. Use grep or fixed, not both.'),
92
+ fixed: z.string().optional().describe('Only activities containing this exact text.'),
93
+ from: stringArray.optional().describe('Only what these participants said.'),
94
+ mention: z.string().optional().describe('Only what was addressed to this participant.'),
51
95
  }, (square, args, control) => square.history({ ...args, ...observation(control) }, control), rendering((result, args) => renderHistoryResult(result.observation?.location ?? '', result, { query: args }))),
52
- tool('listen', 'Listen for future activity from a participant, clearing any ignore of them.', { as: participant, target: z.string() }, async (square, { as, target }, control) => (await square.participant(as)).listen(target, observation(control), control), rendering((result) => renderListenerChange(result.observation?.location ?? '', 'listen', result))),
53
- tool('ignore', 'Block a participant’s future mentions and bare activity. Listening again clears the ignore; already landed activity is unchanged.', { as: participant, target: z.string() }, async (square, { as, target }, control) => (await square.participant(as)).ignore(target, observation(control), control), rendering((result) => renderListenerChange(result.observation?.location ?? '', 'ignore', result))),
54
- tool('unlisten', 'Stop listening to a participant’s future activity; mentions and replies still reach you. An existing ignore is unchanged.', { as: participant, target: z.string() }, async (square, { as, target }, control) => (await square.participant(as)).unlisten(target, observation(control), control), rendering((result) => renderListenerChange(result.observation?.location ?? '', 'unlisten', result))),
55
- tool('listening', 'List participants this participant is listening to.', { as: participant }, async (square, { as }, control) => (await square.participant(as)).listening(observation(control), control), rendering((result) => renderListeningResult(result.observation?.location ?? '', result))),
56
- tool('hold', 'Raise a hand to hold the square.', { as: participant, reason: z.string().optional() }, async (square, { as, reason }, control) => (await square.participant(as)).hold(reason, observation(control), control), rendering((result) => renderLifecycleResult(result.observation?.location ?? '', 'hold', result))),
57
- tool('resume', 'Release the current hold.', { as: participant }, async (square, { as }, control) => (await square.participant(as)).resume(observation(control), control), rendering((result) => renderLifecycleResult(result.observation?.location ?? '', 'resume', result))),
58
- tool('done', 'Leave the square without adding a message.', { as: participant }, async (square, { as }, control) => (await square.participant(as)).done(undefined, observation(control), control), rendering((result) => renderLifecycleResult(result.observation?.location ?? '', 'done', result))),
59
- tool('status', 'Read the public status of the square.', {}, (square, _args, control) => square.status(observation(control), control), rendering((result) => renderStatusResult(result.observation?.location ?? '', result))),
60
- tool('participants', 'List participants standing in or done with the square.', {}, (square, _args, control) => square.participants(observation(control), control), rendering((result) => renderParticipantsResult(result.observation?.location ?? '', result))),
96
+ tool('attention', 'Turn toward someone or away from them, from now on. Listen: hear everything they say, even to others. Unlisten: stop listening without clearing an ignore; mentions and replies still reach you unless ignored. Ignore: hear nothing from them but bells. What was already said stays as it was.', {
97
+ as: participant, action: z.enum(['listen', 'unlisten', 'ignore']).describe('"listen", "unlisten" or "ignore". Listening again ends an ignore.'), target,
98
+ }, async (square, { as, action, target }, control) => {
99
+ const self = await square.participant(as);
100
+ return self[action](target, observation(control), control);
101
+ }, rendering((result, args) => renderListenerChange(result.observation?.location ?? '', args.action, result))),
102
+ tool('hold', 'Raise a hand to pause the conversation; lower it with release. While a hand is up, new words wait to land.', {
103
+ as: participant,
104
+ reason: z.string().optional().describe('Why you are pausing. Everyone sees it.'),
105
+ release: z.boolean().optional().describe('true lowers the raised hand so the conversation goes on.'),
106
+ }, async (square, { as, reason, release }, control) => {
107
+ const self = await square.participant(as);
108
+ return release === true ? self.resume(observation(control), control) : self.hold(reason, observation(control), control);
109
+ }, rendering((result, args) => renderLifecycleResult(result.observation?.location ?? '', args.release === true ? 'resume' : 'hold', result))),
110
+ tool('done', 'Step out of the square. Everyone sees you leave, and you stop listening to anyone. Leaving carries no words, so say goodbye with express first. Stay instead if someone may still need you; you can join again later.', { as: participant }, async (square, { as }, control) => (await square.participant(as)).done(undefined, observation(control), control), rendering((result) => renderLifecycleResult(result.observation?.location ?? '', 'done', result))),
111
+ tool('status', 'Look around the square: who is here, whether a hand is raised, the latest activity, and who you listen to.', {
112
+ as: z.string().optional().describe('Whose listening to show. Leave it out if you hold exactly one name here.'),
113
+ }, (square, { as }, control) => square.status({ viewer: as, ...observation(control) }, control), rendering((result) => renderStatusResult(result.observation?.location ?? '', result))),
61
114
  ];
62
115
  export function squareToolFailure(error, signal) {
63
116
  const normalized = signal?.aborted
@@ -4,7 +4,7 @@ import fs from 'node:fs/promises';
4
4
  import { createInterface } from 'node:readline';
5
5
  import { pathToFileURL } from 'node:url';
6
6
  import { SqliteSquare } from './sqlite-square.js';
7
- import { SquareError } from './model.js';
7
+ import { SquareError, validateBody } from './model.js';
8
8
  import { canonicalPath } from './canonical-path.js';
9
9
  import { STDIO_PROTOCOL_VERSION, STDIO_MAX_FRAME_BYTES, encodeError, identityVariables } from './square-stdio.js';
10
10
  import { parseSquareLocation } from './square-location.js';
@@ -71,7 +71,9 @@ export async function runSquareStdioServer(root) {
71
71
  throw new SquareError('invalid_args', 'Invalid operation identity');
72
72
  env[key] = value ?? '';
73
73
  }
74
- const input = { path: target, env, participant: params.participant };
74
+ const input = { path: target, env, body: params.body, participant: params.participant };
75
+ if (params.body !== undefined)
76
+ validateBody(params.body);
75
77
  square = params.build === undefined ? await SqliteSquare.at(input, control, false)
76
78
  : await SqliteSquare.build({ ...params.build, ...input }, control, false);
77
79
  location = parsed.uri;
package/dist/stream.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- import type { OpenOptions, OperationControl, StreamOptions, StreamRecord } from './square-facade.js';
1
+ import type { SquareArtifactPort } from './ports.js';
2
+ import type { OperationControl, StreamOptions, StreamRecord } from './square-facade.js';
2
3
  /** Pull-based observation; return interrupts an outstanding pull before awaiting its cleanup. */
3
- export declare function streamSquare(squarePath: string, options?: StreamOptions, control?: OperationControl, openOptions?: OpenOptions): AsyncIterable<StreamRecord>;
4
+ export declare function streamSquare(squarePath: string, options?: StreamOptions, control?: OperationControl, borrowed?: SquareArtifactPort): AsyncIterable<StreamRecord>;
package/dist/stream.js CHANGED
@@ -1,15 +1,13 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import { SquareError } from './model.js';
3
- import { observeSquareRevision } from './artifact.js';
4
- import { openSquare, closeOpenSquare } from './open-square.js';
3
+ import { createArtifactPort, observeSquareRevision } from './artifact.js';
5
4
  import { streamProjection, streamTailProjection } from './views.js';
6
5
  /** Pull-based observation; return interrupts an outstanding pull before awaiting its cleanup. */
7
- export function streamSquare(squarePath, options = {}, control, openOptions = {}) {
6
+ export function streamSquare(squarePath, options = {}, control, borrowed) {
8
7
  return {
9
8
  [Symbol.asyncIterator]() {
10
9
  const disposal = new AbortController();
11
10
  const signal = control?.signal === undefined ? disposal.signal : AbortSignal.any([control.signal, disposal.signal]);
12
- const iterationControl = { ...control, signal };
13
11
  const records = observe();
14
12
  return {
15
13
  next: () => records.next(),
@@ -43,19 +41,20 @@ export function streamSquare(squarePath, options = {}, control, openOptions = {}
43
41
  let projection;
44
42
  try {
45
43
  baseline = await observer.read(signal);
46
- const square = await openSquare(squarePath, { ...openOptions, env: openOptions.env ?? {}, signal }, iterationControl);
44
+ const artifact = borrowed ?? createArtifactPort(squarePath, undefined, signal);
47
45
  try {
48
- projection = initial === undefined
49
- ? await streamProjection(square, cursor, options.recipient, iterationControl)
50
- : await streamTailProjection(square, initial.last, options.recipient, iterationControl);
46
+ projection = (await artifact.read(facts => initial === undefined
47
+ ? streamProjection(facts, cursor, options.recipient)
48
+ : streamTailProjection(facts, initial.last, options.recipient), signal)).value;
51
49
  }
52
50
  finally {
53
- await closeOpenSquare(square);
51
+ if (borrowed === undefined)
52
+ await artifact.close();
54
53
  }
55
54
  }
56
55
  catch (error) {
57
56
  signal.throwIfAborted();
58
- if (error instanceof SquareError && error.code === 'invalid_args')
57
+ if (borrowed !== undefined || error instanceof SquareError && error.code === 'invalid_args')
59
58
  throw error;
60
59
  // Repair/replacement is a hint, not a reason to scan history on a timer.
61
60
  await observer.hinted(generation, Infinity, signal);
package/dist/views.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { type ActivityId } from './square-core.js';
2
2
  import { type StoredAct } from './model.js';
3
- import type { OpenSquare } from './open-square.js';
4
3
  import type { ActivityFilter, SquareRead } from './ports.js';
5
- import type { Activity, ArchiveRecord, HistoryQuery, HistoryContinuation, OperationControl, ParticipantsResult, SquareSnapshot, EntryPresentation, ListPresentation, StatusResult, SquareObservation, CatchPresence, StreamProjection } from './square-facade.js';
4
+ import type { Activity, ArchiveRecord, HistoryQuery, HistoryContinuation, ParticipantsResult, SquareSnapshot, EntryPresentation, ListPresentation, StatusResult, SquareObservation, CatchPresence, StreamProjection } from './square-facade.js';
6
5
  export type { EntryPresentation, ListPresentation, CatchPresence, StreamProjection } from './square-facade.js';
7
6
  export declare const HISTORY_DEFAULT_LIMIT = 10;
8
7
  export declare const HISTORY_MAX_LIMIT = 100;
@@ -18,12 +17,8 @@ export declare function selectHistory(facts: SquareRead, query: HistoryQuery, li
18
17
  totalMatches: number;
19
18
  };
20
19
  export declare function publicActivities(activities: readonly ArchiveRecord[]): Activity[];
21
- export declare function resolveParticipant(square: OpenSquare, name: string, control?: OperationControl): Promise<{
22
- name: string;
23
- }>;
24
- export declare function currentParticipant(square: OpenSquare, name: string, control?: OperationControl): Promise<string | undefined>;
25
- export declare function snapshot(square: OpenSquare, control?: OperationControl): Promise<SquareSnapshot>;
26
- export declare function recoveryObservation(square: OpenSquare, name: string, control?: OperationControl): Promise<{
20
+ export declare function snapshot(facts: SquareRead, now: number): SquareSnapshot;
21
+ export declare function recoveryObservation(facts: SquareRead, name: string, now: number): {
27
22
  ownActivityCount: number;
28
23
  hardCap: import("./model.js").HardCap;
29
24
  holdReason?: string | undefined;
@@ -32,12 +27,12 @@ export declare function recoveryObservation(square: OpenSquare, name: string, co
32
27
  activitySummaries: import("./square-facade.js").UnreadActivitySummary[];
33
28
  standingCount: number;
34
29
  held: boolean;
35
- }>;
36
- export declare function entryPresentation(square: OpenSquare, name: string, lastN?: number | null, control?: OperationControl): Promise<EntryPresentation>;
30
+ };
31
+ export declare function entryPresentation(facts: SquareRead, name: string, lastN?: number | null): EntryPresentation;
37
32
  type ParticipantQueryContext = Pick<SquareObservation, 'location' | 'now' | 'automaticDeliveryAvailable'>;
38
33
  export declare function queryParticipants(facts: SquareRead, context: ParticipantQueryContext, observe?: boolean): ParticipantsResult;
39
- export declare function listPresentation(square: OpenSquare, control?: OperationControl): Promise<ListPresentation>;
34
+ export declare function listPresentation(facts: SquareRead): ListPresentation;
40
35
  export declare function queryStatus(facts: SquareRead, context: ParticipantQueryContext, viewer?: string, observe?: boolean): StatusResult;
41
- export declare function catchPresence(square: OpenSquare, control?: OperationControl): Promise<CatchPresence>;
42
- export declare function streamProjection(square: OpenSquare, cursor: number, recipient?: string, control?: OperationControl): Promise<StreamProjection>;
43
- export declare function streamTailProjection(square: OpenSquare, last?: number, recipient?: string, control?: OperationControl): Promise<StreamProjection>;
36
+ export declare function catchPresence(facts: SquareRead, now: number): CatchPresence;
37
+ export declare function streamProjection(facts: SquareRead, cursor: number, recipient?: string): StreamProjection;
38
+ export declare function streamTailProjection(facts: SquareRead, last?: number, recipient?: string): StreamProjection;
package/dist/views.js CHANGED
@@ -18,6 +18,7 @@ export function toPublicActivity(stored) {
18
18
  return { id: formatActivityId(stored.index), at: stored.at, kind: stored.kind, actor: stored.actor,
19
19
  ...(stored.kind === 'say' && stored.reach !== undefined ? { reach: stored.reach } : {}),
20
20
  ...('body' in stored && stored.body !== undefined ? { body: stored.body } : {}),
21
+ ...(stored.kind === 'say' && stored.metadata !== undefined ? { metadata: stored.metadata } : {}),
21
22
  mentions: stored.kind === 'say' ? stored.mentions ?? [] : [], ...('target' in stored ? { target: stored.target } : {}),
22
23
  ...(stored.kind === 'say' && stored.reply !== undefined ? { reply: formatActivityId(stored.reply) } : {}) };
23
24
  }
@@ -104,46 +105,34 @@ export function selectHistory(facts, query, limit, kinds, presentation = true) {
104
105
  export function publicActivities(activities) {
105
106
  return activities.flatMap((activity) => activity.kind === 'read' || activity.actor === undefined ? [] : [toPublicActivity(activity)]);
106
107
  }
107
- export async function resolveParticipant(square, name, control) {
108
- return (await square.artifact.read((facts) => ({ name: resolveKnownName(facts, name) }), control?.signal)).value;
109
- }
110
- export async function currentParticipant(square, name, control) {
111
- return (await square.artifact.read((facts) => { const p = facts.participant(name); return p?.joined ? p.name : undefined; }, control?.signal)).value;
112
- }
113
108
  function statuses(facts, now) {
114
109
  return coreParticipants(facts, now).filter((p) => p.state !== 'not joined').map((p) => {
115
110
  const cursor = readCursor(facts, p.name);
116
111
  return { name: p.name, state: p.state === 'done' ? 'done' : 'joined', consumedThrough: cursor < 0 ? null : formatActivityId(cursor), watching: p.presence === 'watching', listening: p.listening };
117
112
  });
118
113
  }
119
- export async function snapshot(square, control) {
120
- return (await square.artifact.read((facts) => {
121
- const header = facts.header(), hold = facts.hold();
122
- const names = new Map(facts.roster().map((p) => [nameKey(p.name), p.name]));
123
- const receipts = new Set(facts.receiptAssignments().map((r) => JSON.stringify([r.owner, r.index])));
124
- return { context: [...header.preamble, ...header.warmup].join('\n'), actCount: facts.activityCount({ kinds: NON_READ }), hardCap: header.hardCap,
125
- ...(header.throttlePerMinute === undefined ? {} : { throttlePerMinute: header.throttlePerMinute }),
126
- held: hold.active && hold.actor !== undefined ? { by: hold.actor, ...(hold.reason === undefined ? {} : { reason: hold.reason }) } : null,
127
- participants: statuses(facts, square.clock()), delivered(name, id) { return receipts.has(JSON.stringify([names.get(nameKey(name)) ?? name, parseRequiredActivityId(id)])); } };
128
- }, control?.signal)).value;
129
- }
130
- export async function recoveryObservation(square, name, control) {
131
- return (await square.artifact.read((facts) => {
132
- const known = resolveKnownName(facts, name), hold = facts.hold();
133
- return { participant: known, roster: rosterNames(facts), activitySummaries: unreadActivitySummaries(facts, known, square.clock()), standingCount: inSquareCount(facts), held: hold.active,
134
- ...(hold.reason === undefined ? {} : { holdReason: hold.reason }), ownActivityCount: facts.participant(known).sayCount, hardCap: facts.header().hardCap };
135
- }, control?.signal)).value;
136
- }
137
- export async function entryPresentation(square, name, lastN = HISTORY_DEFAULT_LIMIT, control) {
138
- return (await square.artifact.read((facts) => {
139
- const header = facts.header();
140
- const recentActivities = selectHistory(facts, {}, lastN, ['say', 'done']).activities;
141
- return { joinedBefore: facts.activityCount({ kinds: ['join'], actors: [name] }) > 1,
142
- scene: header.warmup.join('\n').trim(),
143
- joinContext: (header.preamble.at(-1) === '---' ? header.preamble.slice(0, -1) : header.preamble).join('\n').trim(), recentActivities,
144
- perceptions: Object.fromEntries(recentActivities.map((a) => [a.index, perceiveActivity(facts, a, name)])),
145
- sayNumbers: facts.sayOrdinals(recentActivities.map((a) => a.index)) };
146
- }, control?.signal)).value;
114
+ export function snapshot(facts, now) {
115
+ const header = facts.header(), hold = facts.hold();
116
+ const names = new Map(facts.roster().map((p) => [nameKey(p.name), p.name]));
117
+ const receipts = new Set(facts.receiptAssignments().map((r) => JSON.stringify([r.owner, r.index])));
118
+ return { context: [...header.preamble, ...header.warmup].join('\n'), actCount: facts.activityCount({ kinds: NON_READ }), hardCap: header.hardCap,
119
+ ...(header.throttlePerMinute === undefined ? {} : { throttlePerMinute: header.throttlePerMinute }),
120
+ held: hold.active && hold.actor !== undefined ? { by: hold.actor, ...(hold.reason === undefined ? {} : { reason: hold.reason }) } : null,
121
+ participants: statuses(facts, now), delivered(name, id) { return receipts.has(JSON.stringify([names.get(nameKey(name)) ?? name, parseRequiredActivityId(id)])); } };
122
+ }
123
+ export function recoveryObservation(facts, name, now) {
124
+ const known = resolveKnownName(facts, name), hold = facts.hold();
125
+ return { participant: known, roster: rosterNames(facts), activitySummaries: unreadActivitySummaries(facts, known, now), standingCount: inSquareCount(facts), held: hold.active,
126
+ ...(hold.reason === undefined ? {} : { holdReason: hold.reason }), ownActivityCount: facts.participant(known).sayCount, hardCap: facts.header().hardCap };
127
+ }
128
+ export function entryPresentation(facts, name, lastN = HISTORY_DEFAULT_LIMIT) {
129
+ const header = facts.header();
130
+ const recentActivities = selectHistory(facts, {}, lastN, ['say', 'done']).activities;
131
+ return { joinedBefore: facts.activityCount({ kinds: ['join'], actors: [name] }) > 1,
132
+ scene: header.warmup.join('\n').trim(),
133
+ joinContext: (header.preamble.at(-1) === '---' ? header.preamble.slice(0, -1) : header.preamble).join('\n').trim(), recentActivities,
134
+ perceptions: Object.fromEntries(recentActivities.map((a) => [a.index, perceiveActivity(facts, a, name)])),
135
+ sayNumbers: facts.sayOrdinals(recentActivities.map((a) => a.index)) };
147
136
  }
148
137
  function classifyPresence(participants, now) {
149
138
  const here = participants.filter((participant) => participant.state === 'active' && (participant.presence === 'watching'
@@ -159,18 +148,17 @@ export function queryParticipants(facts, context, observe = false) {
159
148
  return { participants, ...(!observe ? {} : { observation: { ...context, ...classifyPresence(participants, context.now),
160
149
  standingCount: inSquareCount(facts), held: facts.hold().active } }) };
161
150
  }
162
- export async function listPresentation(square, control) {
163
- return (await square.artifact.read((facts) => {
164
- const participants = facts.roster().filter((p) => p.joined).map((p) => {
165
- const receiptAt = facts.receiptFacts(p.name, p.lastJoinIndex ?? -1).latestAt;
166
- return { name: p.name, lastActiveAt: receiptAt === undefined ? p.lastActiveAt : Math.max(p.lastActiveAt ?? -Infinity, receiptAt) };
167
- }).sort(compareParticipantActivity).map((p) => p.name);
168
- return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }) };
169
- }, control?.signal)).value;
151
+ export function listPresentation(facts) {
152
+ const participants = facts.roster().filter((p) => p.joined).map((p) => {
153
+ const receiptAt = facts.receiptFacts(p.name, p.lastJoinIndex ?? -1).latestAt;
154
+ return { name: p.name, lastActiveAt: receiptAt === undefined ? p.lastActiveAt : Math.max(p.lastActiveAt ?? -Infinity, receiptAt) };
155
+ }).sort(compareParticipantActivity).map((p) => p.name);
156
+ return { context: facts.header().preamble, participants, activities: facts.activityCount({ kinds: ['say'] }) };
170
157
  }
171
158
  export function queryStatus(facts, context, viewer = '', observe = false) {
172
159
  const participants = coreParticipants(facts, context.now);
173
160
  const header = facts.header(), hold = facts.hold(), standingCount = inSquareCount(facts);
161
+ const listener = participants.find((p) => p.state !== 'not joined' && nameKey(p.name) === nameKey(viewer));
174
162
  const latest = facts.activityHeads({ kinds: ['say', 'done'] }, { edge: 'newest', limit: 1 }).items[0];
175
163
  const latestAct = latest === undefined ? undefined : facts.activity(latest.index);
176
164
  const data = {
@@ -182,6 +170,7 @@ export function queryStatus(facts, context, viewer = '', observe = false) {
182
170
  ...(hold.reason === undefined ? {} : { reason: hold.reason }),
183
171
  ...(hold.at === undefined ? {} : { at: hold.at }),
184
172
  } : null,
173
+ ...(listener === undefined ? {} : { listening: listener.listening }),
185
174
  participants: participants.filter((p) => p.state !== 'not joined'), now: context.now,
186
175
  ...(latestAct === undefined || latestAct.actor === undefined || latestAct.kind === 'read' ? {} : { latestActivity: toPublicActivity(latestAct) }),
187
176
  };
@@ -204,33 +193,26 @@ export function queryStatus(facts, context, viewer = '', observe = false) {
204
193
  },
205
194
  };
206
195
  }
207
- export async function catchPresence(square, control) {
208
- return (await square.artifact.read((facts) => {
209
- const now = square.clock();
210
- const participants = coreParticipants(facts, now).filter((participant) => participant.state === 'done' || participant.presence === 'watching'
211
- || (participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= PRESENCE_WINDOW_MS));
212
- return { participants, now };
213
- }, control?.signal)).value;
214
- }
215
- export async function streamProjection(square, cursor, recipient, control) {
216
- return (await square.artifact.read((facts) => {
217
- const page = facts.activityHeads({ afterIndex: cursor }, { edge: 'oldest', limit: PAGE_SIZE });
218
- const heads = page.items.flatMap((head) => {
219
- const route = recipient === undefined ? undefined : facts.directedAt(recipient, head.index)?.route;
220
- return recipient !== undefined && route === undefined ? [] : [{ index: head.index, route }];
221
- });
222
- return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => {
223
- const route = heads.find((h) => h.index === activity.index).route;
224
- return { activity, ...(route === undefined ? {} : { route }) };
225
- }), cursor: page.items.at(-1)?.index ?? cursor, hasMore: page.hasMore };
226
- }, control?.signal)).value;
196
+ export function catchPresence(facts, now) {
197
+ const participants = coreParticipants(facts, now).filter((participant) => participant.state === 'done' || participant.presence === 'watching'
198
+ || (participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= PRESENCE_WINDOW_MS));
199
+ return { participants, now };
227
200
  }
228
- export async function streamTailProjection(square, last = HISTORY_DEFAULT_LIMIT, recipient, control) {
229
- return (await square.artifact.read((facts) => {
230
- if (!Number.isSafeInteger(last) || last < 0 || last > PAGE_SIZE)
231
- throw new SquareError('invalid_args', `Invalid stream tail: expected a non-negative safe integer no greater than ${PAGE_SIZE}.`);
232
- const heads = last === 0 ? [] : recipient === undefined ? facts.activityHeads({}, { edge: 'newest', limit: last }).items : facts.directed(recipient, {}, { edge: 'newest', limit: last }).items;
233
- return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => ({ activity,
234
- ...(recipient === undefined ? {} : { route: facts.directedAt(recipient, activity.index).route }) })), cursor: facts.header().lastActIndex, hasMore: false };
235
- }, control?.signal)).value;
201
+ export function streamProjection(facts, cursor, recipient) {
202
+ const page = facts.activityHeads({ afterIndex: cursor }, { edge: 'oldest', limit: PAGE_SIZE });
203
+ const heads = page.items.flatMap((head) => {
204
+ const route = recipient === undefined ? undefined : facts.directedAt(recipient, head.index)?.route;
205
+ return recipient !== undefined && route === undefined ? [] : [{ index: head.index, route }];
206
+ });
207
+ return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => {
208
+ const route = heads.find((h) => h.index === activity.index).route;
209
+ return { activity, ...(route === undefined ? {} : { route }) };
210
+ }), cursor: page.items.at(-1)?.index ?? cursor, hasMore: page.hasMore };
211
+ }
212
+ export function streamTailProjection(facts, last = HISTORY_DEFAULT_LIMIT, recipient) {
213
+ if (!Number.isSafeInteger(last) || last < 0 || last > PAGE_SIZE)
214
+ throw new SquareError('invalid_args', `Invalid stream tail: expected a non-negative safe integer no greater than ${PAGE_SIZE}.`);
215
+ const heads = last === 0 ? [] : recipient === undefined ? facts.activityHeads({}, { edge: 'newest', limit: last }).items : facts.directed(recipient, {}, { edge: 'newest', limit: last }).items;
216
+ return { activities: facts.activities(heads.map((h) => h.index)).map((activity) => ({ activity,
217
+ ...(recipient === undefined ? {} : { route: facts.directedAt(recipient, activity.index).route }) })), cursor: facts.header().lastActIndex, hasMore: false };
236
218
  }
package/dist/wakes.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { type WatchLease, type WatchOptions } from './model.js';
2
- import type { OpenSquare } from './open-square.js';
2
+ import type { SquareArtifactPort } from './ports.js';
3
+ import type { Seat } from './model.js';
3
4
  export type WatchLeaseStart = {
4
5
  readonly type: 'started';
5
6
  readonly leaseId: string;
@@ -21,7 +22,7 @@ export type WatchLeasePulse = {
21
22
  readonly type: 'sleep';
22
23
  readonly heartbeatAt?: number;
23
24
  };
24
- export declare function acquireWatchLease(square: OpenSquare, name: string, leaseId: string, options: WatchOptions, signal?: AbortSignal): Promise<WatchLeaseStart>;
25
- export declare function pulseWatchLease(square: OpenSquare, name: string, leaseId: string, options: WatchOptions, heartbeatDue: boolean, signal?: AbortSignal): Promise<WatchLeasePulse>;
26
- export declare function releaseWatchLease(square: OpenSquare, name: string, leaseId: string | undefined): Promise<void>;
27
- export declare function ownsWatchLease(square: OpenSquare, name: string, leaseId: string, signal?: AbortSignal): Promise<boolean>;
25
+ export declare function acquireWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, options: WatchOptions, signal?: AbortSignal): Promise<WatchLeaseStart>;
26
+ export declare function pulseWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, options: WatchOptions, heartbeatDue: boolean, signal?: AbortSignal): Promise<WatchLeasePulse>;
27
+ export declare function releaseWatchLease(artifact: SquareArtifactPort, seat: Seat, leaseId: string): Promise<void>;
28
+ export declare function ownsWatchLease(artifact: SquareArtifactPort, seat: Seat, at: number, leaseId: string, signal?: AbortSignal): Promise<boolean>;