@astrosheep/square 0.3.61 → 0.3.62

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 (87) hide show
  1. package/claude-plugin/.claude-plugin/plugin.json +1 -1
  2. package/claude-plugin/skills/square/SKILL.md +5 -7
  3. package/codex-plugin/.codex-plugin/plugin.json +1 -1
  4. package/dist/activity.d.ts +6 -2
  5. package/dist/activity.js +168 -133
  6. package/dist/artifact.d.ts +4 -0
  7. package/dist/artifact.js +43 -14
  8. package/dist/attention-presentation.d.ts +1 -0
  9. package/dist/attention-presentation.js +8 -6
  10. package/dist/automatic-session.js +14 -24
  11. package/dist/boundary-presentation.d.ts +1 -2
  12. package/dist/boundary-presentation.js +4 -19
  13. package/dist/cli/context.d.ts +2 -0
  14. package/dist/cli/context.js +2 -18
  15. package/dist/cli/harness-command.js +1 -1
  16. package/dist/cli/mcp-server-command.d.ts +2 -0
  17. package/dist/cli/mcp-server-command.js +13 -0
  18. package/dist/cli/observation-commands.js +47 -19
  19. package/dist/cli/program.js +5 -2
  20. package/dist/cli/registry.js +2 -0
  21. package/dist/cli/square-commands.d.ts +1 -1
  22. package/dist/cli/square-commands.js +93 -125
  23. package/dist/decisions.d.ts +2 -0
  24. package/dist/decisions.js +44 -3
  25. package/dist/delivery-operations.d.ts +1 -2
  26. package/dist/delivery-operations.js +1 -4
  27. package/dist/file-changes.d.ts +12 -0
  28. package/dist/file-changes.js +235 -0
  29. package/dist/help.js +4 -8
  30. package/dist/host-ledger-file-adapter.d.ts +15 -13
  31. package/dist/host-ledger-file-adapter.js +131 -79
  32. package/dist/host-ledger-root.d.ts +2 -0
  33. package/dist/host-ledger-root.js +9 -0
  34. package/dist/host-ledger.d.ts +4 -24
  35. package/dist/inbox.d.ts +10 -5
  36. package/dist/inbox.js +152 -67
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.js +1 -0
  39. package/dist/mcp.d.ts +7 -0
  40. package/dist/mcp.js +122 -0
  41. package/dist/mention-parse.d.ts +8 -0
  42. package/dist/mention-parse.js +107 -0
  43. package/dist/model.d.ts +5 -0
  44. package/dist/model.js +4 -1
  45. package/dist/notifications.d.ts +1 -0
  46. package/dist/notifications.js +25 -20
  47. package/dist/participant-host.js +2 -2
  48. package/dist/ports.d.ts +2 -9
  49. package/dist/presentation.d.ts +12 -1
  50. package/dist/presentation.js +42 -12
  51. package/dist/presented.js +2 -1
  52. package/dist/registry.d.ts +8 -4
  53. package/dist/registry.js +41 -74
  54. package/dist/routes.d.ts +19 -2
  55. package/dist/routes.js +48 -5
  56. package/dist/runtime.d.ts +2 -0
  57. package/dist/runtime.js +2 -0
  58. package/dist/square-actions.d.ts +26 -13
  59. package/dist/square-actions.js +200 -84
  60. package/dist/square-application.d.ts +58 -0
  61. package/dist/square-application.js +183 -0
  62. package/dist/square-facade.d.ts +24 -9
  63. package/dist/square-file-adapter.d.ts +5 -12
  64. package/dist/square-file-adapter.js +12 -64
  65. package/dist/square-projections.d.ts +3 -2
  66. package/dist/square-projections.js +12 -3
  67. package/dist/square-storage.js +27 -34
  68. package/dist/square-wiring.d.ts +12 -7
  69. package/dist/square-wiring.js +36 -32
  70. package/dist/state-cell.d.ts +1 -1
  71. package/dist/stream.js +30 -26
  72. package/dist/views.d.ts +3 -3
  73. package/dist/views.js +4 -4
  74. package/dist/wake-attempts.js +2 -1
  75. package/dist/wake-evidence.js +2 -8
  76. package/dist/wakes.d.ts +1 -0
  77. package/dist/wakes.js +5 -5
  78. package/dist/watch.d.ts +6 -1
  79. package/dist/watch.js +20 -18
  80. package/extensions/square-pi.js +100 -112
  81. package/guides/application-boundary.md +32 -0
  82. package/guides/change-waits.md +28 -0
  83. package/guides/host-ledger.md +9 -0
  84. package/guides/mcp.md +9 -0
  85. package/guides/operation-cancellation.md +17 -0
  86. package/package.json +8 -2
  87. package/skills/square/SKILL.md +5 -7
@@ -1,6 +1,5 @@
1
1
  import type { InboxMembership } from './model.js';
2
- /** A fresh blocking catch owns only the notifications admitted by its filter. */
3
- export declare function pendingAtBoundary(inbox: InboxMembership[]): InboxMembership[];
2
+ export { pendingAtBoundary } from './square-projections.js';
4
3
  export declare function renderPendingAtBoundary(inbox: InboxMembership[]): string;
5
4
  /** Serialize a boundary across hook processes so one stale inbox cannot render twice. */
6
5
  export declare function presentPendingAtBoundary<T>(sessionId: string, present: (context: string) => T | Promise<T>, lookup?: (sessionId: string, env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<InboxMembership[]> | InboxMembership[], env?: NodeJS.ProcessEnv, signal?: AbortSignal): Promise<T | undefined>;
@@ -1,14 +1,14 @@
1
+ import { hostLedgerRoot } from './host-ledger-root.js';
1
2
  import { createHash } from 'node:crypto';
2
- import os from 'node:os';
3
3
  import path from 'node:path';
4
- import { leaseOwnsNotification } from './delivery.js';
5
4
  import { withFileLock } from './file-lock.js';
6
5
  import { openSquare } from './square-file-adapter.js';
7
6
  import { closeOpenSquare } from './open-square.js';
8
7
  import { presentPending } from './presentation-operations.js';
9
8
  import { hostLedgerForEnv, sessionInbox } from './inbox.js';
10
9
  import { attentionBodyIsClipped, renderAttentionPreview } from './attention-presentation.js';
11
- import { presentationSuppressesWake, projectPresentationEvidence } from './square-projections.js';
10
+ import { pendingAtBoundary, presentationSuppressesWake, projectPresentationEvidence } from './square-projections.js';
11
+ export { pendingAtBoundary } from './square-projections.js';
12
12
  import { formatActivityId } from './square-core.js';
13
13
  const CONTEXT_MAX = 1200;
14
14
  const presentationLocks = new Map();
@@ -38,20 +38,6 @@ async function awaitWithSignal(promise, signal) {
38
38
  function pendingCount(inbox) {
39
39
  return inbox.reduce((total, membership) => total + membership.notifications.length, 0);
40
40
  }
41
- /** A fresh blocking catch owns only the notifications admitted by its filter. */
42
- export function pendingAtBoundary(inbox) {
43
- return inbox
44
- .map((membership) => {
45
- const lease = membership.catchLease;
46
- if (lease === undefined)
47
- return membership;
48
- return {
49
- ...membership,
50
- notifications: membership.notifications.filter((notification) => !leaseOwnsNotification(lease, { ...notification, recipient: membership.name })),
51
- };
52
- })
53
- .filter((membership) => membership.notifications.length > 0);
54
- }
55
41
  export function renderPendingAtBoundary(inbox) {
56
42
  return renderBoundary(inbox).context;
57
43
  }
@@ -165,8 +151,7 @@ async function presentPendingAtBoundaryUnlocked(sessionId, present, lookup = ses
165
151
  }
166
152
  /** Serialize a boundary across hook processes so one stale inbox cannot render twice. */
167
153
  export async function presentPendingAtBoundary(sessionId, present, lookup = sessionInbox, env = process.env, signal) {
168
- const ledgerRoot = env.SQUARE_HOST_LEDGER_USER
169
- ?? (env.SQUARE_REGISTRY === undefined ? path.join(os.homedir(), '.square', 'host-ledger') : path.dirname(env.SQUARE_REGISTRY));
154
+ const ledgerRoot = hostLedgerRoot(env);
170
155
  const ownerKey = createHash('sha256').update(sessionId).digest('hex');
171
156
  return withFileLock(path.join(ledgerRoot, `presentation-boundary-${ownerKey}.lock`), { retryMs: 10, signal }, () => presentPendingAtBoundaryUnlocked(sessionId, present, lookup, env, signal));
172
157
  }
@@ -1,5 +1,7 @@
1
1
  import { type HardCap } from '../model.js';
2
2
  export interface CommandContext {
3
+ cwd: string;
4
+ env: NodeJS.ProcessEnv;
3
5
  squarePath?: string;
4
6
  name?: string;
5
7
  homeDir: string;
@@ -113,6 +113,7 @@ const LOCATION_REQUIRED_COMMANDS = new Set([
113
113
  'history',
114
114
  'status',
115
115
  'participants',
116
+ 'mcp-server',
116
117
  'doctor',
117
118
  ]);
118
119
  function configuredLocation() {
@@ -126,22 +127,10 @@ function configuredName() {
126
127
  validateName(value);
127
128
  return value;
128
129
  }
129
- function withoutAsCommand(rawArgs) {
130
- const args = [];
131
- for (let index = 0; index < rawArgs.length; index++) {
132
- if (rawArgs[index] === '--as') {
133
- index += 1;
134
- continue;
135
- }
136
- args.push(rawArgs[index]);
137
- }
138
- return `square ${args.map((arg) => /^[A-Za-z0-9_./:=@+,-]+$/.test(arg) ? arg : `'${arg.replace(/'/g, "'\\''")}'`).join(' ')}`;
139
- }
140
130
  export async function parseGlobalArgs(rawArgs) {
141
131
  const args = [...rawArgs];
142
132
  let requestedPath;
143
133
  let name;
144
- let hasExplicitName = false;
145
134
  for (let index = 0; index < args.length; index++) {
146
135
  if (args[index] === '--location') {
147
136
  requestedPath = requireValue(args, index, args[index]);
@@ -150,15 +139,11 @@ export async function parseGlobalArgs(rawArgs) {
150
139
  }
151
140
  else if (args[index] === '--as') {
152
141
  name = requireValue(args, index, args[index]);
153
- hasExplicitName = true;
154
142
  args.splice(index, 2);
155
143
  index -= 1;
156
144
  }
157
145
  }
158
146
  const command = args[0];
159
- if (command === 'history' && hasExplicitName) {
160
- fail(`✕ history is an archive and does not use --as\n${withoutAsCommand(rawArgs)}`);
161
- }
162
147
  if (name === undefined)
163
148
  name = configuredName();
164
149
  if (name !== undefined)
@@ -174,7 +159,6 @@ export async function parseGlobalArgs(rawArgs) {
174
159
  hostLedger: createHostLedgerPort(),
175
160
  location: squarePath,
176
161
  sessionId,
177
- scopes: ['user', 'local'],
178
162
  })))).flat();
179
163
  const names = new Set(bindings.map((binding) => binding.participant));
180
164
  name = names.size === 1 ? [...names][0] : undefined;
@@ -185,7 +169,7 @@ export function locationIsRequired(command) {
185
169
  return LOCATION_REQUIRED_COMMANDS.has(command);
186
170
  }
187
171
  export function defaultContext(command, squarePath, name) {
188
- return { command, squarePath, name, homeDir: os.homedir() };
172
+ return { command, cwd: process.cwd(), env: { ...process.env }, squarePath, name, homeDir: os.homedir() };
189
173
  }
190
174
  export function requireSquarePath(context) {
191
175
  if (context.squarePath === undefined)
@@ -102,7 +102,7 @@ export function formatHarnessResult(result) {
102
102
  return `${[...result.notes, ...result.lines, ...result.failures].join('\n')}\n`;
103
103
  }
104
104
  export function runHarnessCommand(argv, squarePath) {
105
- const context = { homeDir: os.homedir(), ...(squarePath === undefined ? {} : { squarePath }), command: 'harness' };
105
+ const context = { cwd: process.cwd(), env: { ...process.env }, homeDir: os.homedir(), ...(squarePath === undefined ? {} : { squarePath }), command: 'harness' };
106
106
  const intent = harnessCommand.parse(argv, context);
107
107
  return Promise.resolve(harnessCommand.execute(intent, context)).then(formatHarnessResult);
108
108
  }
@@ -0,0 +1,2 @@
1
+ import { type CommandSpec } from './context.js';
2
+ export declare const mcpServerCommand: CommandSpec<undefined, void>;
@@ -0,0 +1,13 @@
1
+ import { fail } from './context.js';
2
+ export const mcpServerCommand = {
3
+ parse(argv) {
4
+ if (argv.length > 0)
5
+ fail('Usage: square [--location <square>] [--as <name>] mcp-server');
6
+ return undefined;
7
+ },
8
+ async execute(_intent, context) {
9
+ const { runSquareMcpStdio } = await import('../mcp.js');
10
+ await runSquareMcpStdio({ cwd: context.cwd, env: context.env, squarePath: context.squarePath, participant: context.name });
11
+ },
12
+ present() { },
13
+ };
@@ -12,7 +12,9 @@ import { formatRelativeTime, formatTimestamp, parseTimeOrRelative } from '../tim
12
12
  import { cmdWatch } from '../watch.js';
13
13
  import { openSquare } from '../square-file-adapter.js';
14
14
  import { closeOpenSquare } from '../open-square.js';
15
- import { historyPresentation, participantsPresentation, statusPresentation } from '../views.js';
15
+ import { createSquareApplication } from '../square-application.js';
16
+ import { historyPresentation } from '../views.js';
17
+ import { hostLedgerForEnv } from '../registry.js';
16
18
  import { fail, parseBoundedLimit, parseDurationMs, parseNameList, parseNonNegativeInteger, readStdin, requireParticipant, requireSquarePath, requireValue, usage, } from './context.js';
17
19
  import { CATCH_DEFAULT_LIMIT, CATCH_MAX_LIMIT } from '../catch-decisions.js';
18
20
  const STATUS_PARTICIPANT_PREVIEW_LIMIT = 10;
@@ -147,7 +149,7 @@ export const catchCommand = {
147
149
  },
148
150
  async execute(intent, context) {
149
151
  const squarePath = requireSquarePath(context);
150
- const caught = await cmdWatch(squarePath, requireParticipant(context.name), intent);
152
+ const caught = await cmdWatch(squarePath, requireParticipant(context.name), intent, { cwd: context.cwd, env: context.env });
151
153
  if (caught !== false)
152
154
  await sweepPendingNotifications(squarePath);
153
155
  },
@@ -303,6 +305,30 @@ function parseHistory(argv, context) {
303
305
  continuationArgs: historyContinuationArgs(argv),
304
306
  };
305
307
  }
308
+ function applicationHistoryQuery(options) {
309
+ return {
310
+ ...(options.participants === undefined || options.participants.length === 0 ? {} : { from: options.participants }),
311
+ ...(options.mention === undefined ? {} : { mention: options.mention }),
312
+ ...(options.afterIndex === undefined ? {} : { after: actId(options.afterIndex) }),
313
+ ...(options.beforeIndex === undefined ? {} : { before: actId(options.beforeIndex) }),
314
+ ...(options.grep === undefined ? {} : { grep: options.grep }), ...(options.fixed === undefined ? {} : { fixed: options.fixed }),
315
+ order: 'asc',
316
+ };
317
+ }
318
+ function activityAsStored(activity) {
319
+ const index = parseActivityId(activity.id);
320
+ if (index === undefined)
321
+ throw new Error('Application returned a non-canonical activity id');
322
+ switch (activity.kind) {
323
+ case 'say': return { index, kind: 'say', actor: activity.actor, at: activity.at, body: activity.body ?? '', mentions: activity.mentions, ...(activity.reach === undefined ? {} : { reach: activity.reach }), ...(activity.reply === undefined ? {} : { reply: parseActivityId(activity.reply) ?? undefined }) };
324
+ case 'done': return { index, kind: 'done', actor: activity.actor, at: activity.at, body: activity.body ?? '' };
325
+ case 'hold': return { index, kind: 'hold', actor: activity.actor, at: activity.at, ...(activity.body === undefined ? {} : { body: activity.body }) };
326
+ case 'resume': return { index, kind: 'resume', actor: activity.actor, at: activity.at };
327
+ case 'join': return { index, kind: 'join', actor: activity.actor, at: activity.at };
328
+ case 'listen': return { index, kind: 'listen', actor: activity.actor, target: activity.target ?? '', at: activity.at };
329
+ case 'ignore': return { index, kind: 'ignore', actor: activity.actor, target: activity.target ?? '', at: activity.at };
330
+ }
331
+ }
306
332
  function historyContinuationCommand(options, squarePath, direction, index) {
307
333
  const args = [...(options.continuationArgs ?? []), direction, actId(index), '--limit', String(options.lastN ?? HISTORY_DEFAULT_LIMIT)];
308
334
  return `${commandPrefix(squarePath)} history ${args.map((arg) => arg.startsWith('-') || /^act\/\d+$/.test(arg) || /^\d+$/.test(arg) ? arg : quoteShell(arg)).join(' ')}`;
@@ -311,6 +337,10 @@ function boundedHistoryCommand(options, squarePath) {
311
337
  const args = [...(options.continuationArgs ?? []), '--limit', String(HISTORY_MAX_LIMIT)];
312
338
  return `${commandPrefix(squarePath)} history ${args.map((arg) => arg.startsWith('-') || /^act\/\d+$/.test(arg) || /^\d+$/.test(arg) ? arg : quoteShell(arg)).join(' ')}`;
313
339
  }
340
+ /** The archive-visible activity model: content plus the lifecycle moves that keep its story honest — a raised hand pairs with its lowering, and a departure pairs with the return. */
341
+ function isArchiveActivity(item) {
342
+ return item.kind === 'say' || item.kind === 'done' || item.kind === 'hold' || item.kind === 'resume' || item.kind === 'join';
343
+ }
314
344
  function renderFields(sayNumbers, item, fields) {
315
345
  return fields.map((field) => {
316
346
  switch (field) {
@@ -344,7 +374,7 @@ function jsonLine(sayNumbers, item) {
344
374
  });
345
375
  }
346
376
  function renderHistoryProjection(projection, visible, noTruncate, squarePath) {
347
- const shown = visible.filter((activity) => activity.kind === 'say' || activity.kind === 'done');
377
+ const shown = visible.filter(isArchiveActivity);
348
378
  const preview = noTruncate || shown.length <= 1 ? undefined : 200;
349
379
  const chunks = [];
350
380
  for (const activity of shown) {
@@ -370,12 +400,16 @@ export const historyCommand = {
370
400
  parse(argv, context) { return parseHistory(argv, context); },
371
401
  async execute(options, context) {
372
402
  const squarePath = requireSquarePath(context);
373
- const square = await openSquare(squarePath, { clock: nowMs });
403
+ const square = await openSquare(squarePath, { clock: nowMs, env: context.env, hostLedger: hostLedgerForEnv(context.env) });
374
404
  try {
375
405
  // Keep the projection chronological; pagination chooses a stable edge,
376
406
  // then --order only changes how the selected page is displayed.
377
407
  const projection = await historyPresentation(square, { ...options, order: 'asc' });
378
- let events = [...projection.activities];
408
+ const useApplicationHistory = options.atIndexes === undefined && options.beforeContext === undefined && options.afterContext === undefined && options.after === undefined;
409
+ const applicationHistory = useApplicationHistory
410
+ ? await createSquareApplication({ cwd: context.cwd, env: { ...context.env, SQUARE_PARTICIPANT_NAME: undefined }, squarePath, clock: nowMs }).history(applicationHistoryQuery(options))
411
+ : undefined;
412
+ let events = applicationHistory === undefined ? [...projection.activities] : applicationHistory.map(activityAsStored);
379
413
  if (options.lastN === null && events.length > HISTORY_MAX_LIMIT) {
380
414
  fail(`✕ history is capped at ${HISTORY_MAX_LIMIT} activities\n${boundedHistoryCommand(options, squarePath)}`);
381
415
  }
@@ -397,8 +431,8 @@ export const historyCommand = {
397
431
  const output = pattern === undefined || pattern === ''
398
432
  ? renderHistoryProjection(projection, events, options.noTruncate === true, squarePath)
399
433
  : renderGrepActivitiesView(events, totalMatches, options.noTruncate, squarePath, pattern, options.fixed !== undefined, () => 'full');
400
- const publicEvents = events.filter((item) => item.kind === 'say' || item.kind === 'done');
401
- const allPublic = projection.activities.filter((item) => item.kind === 'say' || item.kind === 'done');
434
+ const publicEvents = events.filter(isArchiveActivity);
435
+ const allPublic = projection.activities.filter(isArchiveActivity);
402
436
  const pageMin = publicEvents.length === 0 ? undefined : Math.min(...publicEvents.map((item) => item.index));
403
437
  const pageMax = publicEvents.length === 0 ? undefined : Math.max(...publicEvents.map((item) => item.index));
404
438
  const hasMore = options.lastN != null && publicEvents.length > 0 && (options.afterIndex !== undefined
@@ -432,10 +466,10 @@ export const participantsCommand = {
432
466
  parse(argv, context) { return parseParticipants(argv, context); },
433
467
  async execute(intent, context) {
434
468
  const squarePath = requireSquarePath(context);
435
- const square = await openSquare(squarePath, { clock: nowMs });
436
- try {
469
+ const application = createSquareApplication({ cwd: context.cwd, env: context.env, squarePath, clock: nowMs });
470
+ {
437
471
  const now = nowMs();
438
- const participants = await participantsPresentation(square);
472
+ const participants = await application.participants();
439
473
  const lines = participants.slice(0, intent.limit).map((participant) => {
440
474
  const recent = participant.lastActiveAt !== undefined && now - participant.lastActiveAt <= STATUS_HERE_WINDOW_MS;
441
475
  const glyph = participant.state === 'done' ? '○' : participant.presence === 'watching' ? '◎' : participant.activityCount > 0 && recent ? '●' : '○';
@@ -456,9 +490,6 @@ export const participantsCommand = {
456
490
  participantCount,
457
491
  });
458
492
  }
459
- finally {
460
- await closeOpenSquare(square);
461
- }
462
493
  },
463
494
  present: (result) => process.stdout.write(result),
464
495
  };
@@ -467,9 +498,9 @@ export const statusCommand = {
467
498
  usage(context.command); return undefined; },
468
499
  async execute(_intent, context) {
469
500
  const squarePath = requireSquarePath(context);
470
- const square = await openSquare(squarePath, { clock: nowMs });
471
- try {
472
- const presentation = await statusPresentation(square);
501
+ const application = createSquareApplication({ cwd: context.cwd, env: context.env, squarePath, clock: nowMs });
502
+ {
503
+ const presentation = await application.status();
473
504
  const result = presentation.status;
474
505
  const active = result.participants.filter((participant) => participant.state === 'active');
475
506
  const here = active.filter((participant) => participant.presence === 'watching'
@@ -561,9 +592,6 @@ export const statusCommand = {
561
592
  ].join('\n');
562
593
  return withPathOutput(squarePath, output, { participantCount: result.activeCount, held: result.holdActive });
563
594
  }
564
- finally {
565
- await closeOpenSquare(square);
566
- }
567
595
  },
568
596
  present: (result) => process.stdout.write(result),
569
597
  };
@@ -1,6 +1,6 @@
1
1
  import { helpRequest } from '../help.js';
2
2
  import { isSquareError } from '../model.js';
3
- import { formatRefusal, joinRecoveryCommand, participantsRecoveryCommand } from '../presentation.js';
3
+ import { formatRefusal, joinRecoveryCommand, participantsRecoveryCommand, takeoverRecoveryLines } from '../presentation.js';
4
4
  import { inSquareCount, nowMs } from '../runtime.js';
5
5
  import { openSquare } from '../square-file-adapter.js';
6
6
  import { closeOpenSquare } from '../open-square.js';
@@ -23,7 +23,10 @@ async function participantCountFor(squarePath) {
23
23
  async function handleSquareError(error, squarePath, name) {
24
24
  if (isSquareError(error)) {
25
25
  const existing = [error.message];
26
- if (squarePath !== undefined && /^✕ .* has never stepped into/.test(error.message)) {
26
+ if (squarePath !== undefined && name !== undefined && error.code === 'already_joined') {
27
+ existing.push(...takeoverRecoveryLines(squarePath, name));
28
+ }
29
+ else if (squarePath !== undefined && /^✕ .* has never stepped into/.test(error.message)) {
27
30
  // The caller's name has never joined this square; only a join admits it.
28
31
  if (name !== undefined)
29
32
  existing.push(joinRecoveryCommand(squarePath, name));
@@ -2,6 +2,7 @@ import { buildCommand, doneCommand, expressCommand, holdCommand, ignoreCommand,
2
2
  import { doctorCommand } from './maintenance-commands.js';
3
3
  import { harnessCommand, installCommand, uninstallCommand } from './harness-command.js';
4
4
  import { helpCommand, versionCommand } from './meta-commands.js';
5
+ import { mcpServerCommand } from './mcp-server-command.js';
5
6
  import { catchCommand, claudeHookCommand, codexHookCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand, } from './observation-commands.js';
6
7
  /** Every public command is an executable adapter, including aliases and utility commands. */
7
8
  export const commandRegistry = [
@@ -29,6 +30,7 @@ export const commandRegistry = [
29
30
  { names: ['participants'], spec: participantsCommand },
30
31
  { names: ['help'], spec: helpCommand },
31
32
  { names: ['version', '--version', '-v'], spec: versionCommand },
33
+ { names: ['mcp-server'], spec: mcpServerCommand },
32
34
  ];
33
35
  export function findCommand(name) {
34
36
  return commandRegistry.find((command) => command.names.includes(name));
@@ -19,7 +19,7 @@ interface ActivityIntent {
19
19
  noMention: boolean;
20
20
  mentions: string[];
21
21
  reach?: Reach;
22
- reply?: number;
22
+ reply?: string;
23
23
  }
24
24
  interface BodyIntent {
25
25
  name: string;