@astrosheep/square 0.3.70 → 0.3.72

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 (126) hide show
  1. package/dist/activity-feed.d.ts +4 -5
  2. package/dist/activity-feed.js +14 -10
  3. package/dist/artifact.d.ts +26 -33
  4. package/dist/artifact.js +346 -317
  5. package/dist/attention-presentation.js +2 -9
  6. package/dist/automatic-session.js +6 -6
  7. package/dist/boundary-presentation.js +3 -3
  8. package/dist/catch-decisions.d.ts +19 -12
  9. package/dist/catch-decisions.js +32 -68
  10. package/dist/claude-delivery.js +7 -7
  11. package/dist/claude-mod.js +18 -7
  12. package/dist/cli/catch-presentation.d.ts +7 -0
  13. package/dist/cli/catch-presentation.js +55 -0
  14. package/dist/cli/context.d.ts +1 -1
  15. package/dist/cli/context.js +5 -23
  16. package/dist/cli/express-presentation.d.ts +10 -0
  17. package/dist/cli/express-presentation.js +196 -0
  18. package/dist/cli/maintenance-commands.d.ts +4 -0
  19. package/dist/cli/maintenance-commands.js +29 -6
  20. package/dist/cli/observation-commands.d.ts +7 -5
  21. package/dist/cli/observation-commands.js +275 -262
  22. package/dist/cli/program.d.ts +1 -1
  23. package/dist/cli/program.js +43 -56
  24. package/dist/cli/registry.js +2 -1
  25. package/dist/cli/square-commands.d.ts +3 -9
  26. package/dist/cli/square-commands.js +134 -255
  27. package/dist/codex-queue.js +4 -1
  28. package/dist/decisions.d.ts +26 -74
  29. package/dist/decisions.js +190 -335
  30. package/dist/delivery-health.js +13 -22
  31. package/dist/delivery-operations.d.ts +0 -11
  32. package/dist/delivery-operations.js +44 -33
  33. package/dist/delivery.d.ts +33 -32
  34. package/dist/delivery.js +70 -81
  35. package/dist/help.js +6 -1
  36. package/dist/inbox.d.ts +27 -0
  37. package/dist/inbox.js +55 -18
  38. package/dist/index.d.ts +2 -4
  39. package/dist/index.js +1 -1
  40. package/dist/list.d.ts +7 -1
  41. package/dist/list.js +49 -122
  42. package/dist/mcp.d.ts +1 -1
  43. package/dist/mcp.js +7 -37
  44. package/dist/model.d.ts +4 -44
  45. package/dist/model.js +1 -3
  46. package/dist/notifications.d.ts +1 -1
  47. package/dist/notifications.js +13 -7
  48. package/dist/open-square.d.ts +16 -2
  49. package/dist/open-square.js +40 -1
  50. package/dist/packages/agent-delivery/src/claude.d.ts +2 -11
  51. package/dist/packages/agent-delivery/src/index.d.ts +2 -42
  52. package/dist/packages/agent-delivery/src/opencode.d.ts +2 -11
  53. package/dist/packages/agent-delivery/src/paseo.d.ts +2 -13
  54. package/dist/packages/agent-delivery/src/pi-client.d.ts +2 -9
  55. package/dist/packages/agent-delivery/src/types.d.ts +42 -0
  56. package/dist/participant-host.d.ts +6 -3
  57. package/dist/participant-host.js +44 -38
  58. package/dist/perception-projection.d.ts +6 -15
  59. package/dist/perception-projection.js +6 -26
  60. package/dist/plugins/opencode/delivery.js +9 -9
  61. package/dist/plugins/opencode/index.js +3 -3
  62. package/dist/ports.d.ts +156 -11
  63. package/dist/presentation-operations.d.ts +1 -1
  64. package/dist/presentation-operations.js +35 -44
  65. package/dist/presentation.d.ts +12 -19
  66. package/dist/presentation.js +33 -54
  67. package/dist/registry.d.ts +2 -0
  68. package/dist/registry.js +1 -1
  69. package/dist/routes.d.ts +7 -14
  70. package/dist/routes.js +34 -72
  71. package/dist/runtime.d.ts +12 -39
  72. package/dist/runtime.js +33 -164
  73. package/dist/square-actions.d.ts +11 -21
  74. package/dist/square-actions.js +171 -275
  75. package/dist/square-application.d.ts +31 -55
  76. package/dist/square-application.js +625 -141
  77. package/dist/square-core.d.ts +3 -94
  78. package/dist/square-core.js +8 -353
  79. package/dist/square-domain.d.ts +24 -0
  80. package/dist/square-domain.js +77 -0
  81. package/dist/square-facade.d.ts +360 -9
  82. package/dist/square-migration.d.ts +24 -0
  83. package/dist/square-migration.js +211 -0
  84. package/dist/square-projections.d.ts +2 -42
  85. package/dist/square-projections.js +1 -37
  86. package/dist/square-sqlite.d.ts +59 -0
  87. package/dist/square-sqlite.js +702 -0
  88. package/dist/stream.d.ts +3 -10
  89. package/dist/stream.js +81 -52
  90. package/dist/views.d.ts +27 -95
  91. package/dist/views.js +217 -87
  92. package/dist/wake-eligibility.d.ts +15 -5
  93. package/dist/wake-eligibility.js +32 -16
  94. package/dist/wakes.d.ts +3 -3
  95. package/dist/wakes.js +31 -27
  96. package/guides/application-facade-delivery-evidence.md +200 -0
  97. package/guides/application-facade-design.md +95 -0
  98. package/guides/change-waits.md +4 -4
  99. package/guides/migration.md +77 -0
  100. package/guides/postcommit-simplification-performance.md +36 -0
  101. package/guides/primitive-catch-consolidation.md +85 -0
  102. package/guides/primitive-history-consolidation.md +76 -0
  103. package/guides/primitive-status-consolidation.md +87 -0
  104. package/guides/primitive-storage-consolidation.md +128 -0
  105. package/guides/row-runtime-delivery-evidence.md +160 -0
  106. package/guides/row-storage-design.md +567 -0
  107. package/package.json +1 -1
  108. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  109. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  110. package/plugins/opencode/delivery.ts +11 -11
  111. package/plugins/opencode/index.ts +3 -3
  112. package/plugins/paseo/client/square-message.tsx +77 -64
  113. package/plugins/paseo/shared/message.ts +16 -0
  114. package/plugins/pi/square-pi.js +5 -1
  115. package/dist/activity.d.ts +0 -14
  116. package/dist/activity.js +0 -248
  117. package/dist/square-file-adapter.d.ts +0 -26
  118. package/dist/square-file-adapter.js +0 -85
  119. package/dist/square-state.d.ts +0 -6
  120. package/dist/square-state.js +0 -138
  121. package/dist/square-storage.d.ts +0 -14
  122. package/dist/square-storage.js +0 -188
  123. package/dist/square-wiring.d.ts +0 -33
  124. package/dist/square-wiring.js +0 -109
  125. package/dist/watch.d.ts +0 -8
  126. package/dist/watch.js +0 -252
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { Square } from './square-wiring.js';
1
+ export { Square } from './square-application.js';
2
2
  export { createSquareApplication } from './square-application.js';
3
3
  export { SquareError } from './model.js';
4
4
  export { squareAssignedParticipantName } from './registry.js';
@@ -6,6 +6,4 @@ export { createDefaultWakeTransport } from './notifications.js';
6
6
  export { createHostLedgerPort, FileHostLedgerPort } from './host-ledger-file-adapter.js';
7
7
  export type { HostLedgerPort, PresenceRecord, EvidenceRecord } from './host-ledger.js';
8
8
  export type { PresentationSinkPort } from './ports.js';
9
- export type { SquareApplication, SquareApplicationContext, JoinApplicationOptions, JoinApplicationResult, ExpressApplicationOptions, ApplicationStatus, ApplicationStatusProjection, ApplicationParticipants } from './square-application.js';
10
- export type { ActivityId } from './square-core.js';
11
- export type { Activity, CatchOptions, CatchResult, ExpressOptions, ExpressResult, HistoryQuery, OperationControl, OperationProgress, ListenerChangeResult, OpenOptions, Participant, ParticipantStatus, PerceivedActivity, SquareAtInput, SquareBuildInput, SquareSnapshot, SquareSource, } from './square-facade.js';
9
+ export type * from './square-facade.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { Square } from './square-wiring.js';
1
+ export { Square } from './square-application.js';
2
2
  export { createSquareApplication } from './square-application.js';
3
3
  export { SquareError } from './model.js';
4
4
  export { squareAssignedParticipantName } from './registry.js';
package/dist/list.d.ts CHANGED
@@ -1 +1,7 @@
1
- export declare function cmdListSquares(args: string[], usage: () => void): Promise<void>;
1
+ import type { DiscoveryApplicationData, DiscoveryApplicationOptions, OpenOptions, OperationControl } from './square-facade.js';
2
+ export declare const DEFAULT_LIST_DEPTH = 4;
3
+ export declare const MAX_LIST_DEPTH = 16;
4
+ export declare const DEFAULT_LIST_LIMIT = 20;
5
+ export declare const MAX_LIST_LIMIT = 100;
6
+ /** Bounded deterministic discovery. Only the application calls this private operation. */
7
+ export declare function discoverSquares(root: string, options?: DiscoveryApplicationOptions, control?: OperationControl, openOptions?: OpenOptions): Promise<DiscoveryApplicationData>;
package/dist/list.js CHANGED
@@ -1,46 +1,51 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
- import { probeSquare } from './square-file-adapter.js';
3
+ import { openSquare } from './open-square.js';
4
4
  import { closeOpenSquare } from './open-square.js';
5
5
  import { listPresentation } from './views.js';
6
- import { formatRelativeTime } from './time.js';
7
- import { participantIdentity, quoteShell } from './presentation.js';
8
- import { style } from './tty-style.js';
9
- const DEFAULT_LIST_DEPTH = 4;
10
- const MAX_LIST_DEPTH = 16;
11
- const DEFAULT_LIST_LIMIT = 20;
12
- const MAX_LIST_LIMIT = 100;
6
+ import { SquareError } from './model.js';
7
+ export const DEFAULT_LIST_DEPTH = 4;
8
+ export const MAX_LIST_DEPTH = 16;
9
+ export const DEFAULT_LIST_LIMIT = 20;
10
+ export const MAX_LIST_LIMIT = 100;
13
11
  const LIST_DISCOVERY_BUDGET = 10_000;
14
- const CONTEXT_PREVIEW_LINES = 2;
15
- const PARTICIPANT_PREVIEW_COUNT = 3;
16
- const DISPLAY_CHARACTER_LIMIT = 160;
17
12
  const LIST_SKIP_DIRS = new Set(['.git', 'node_modules', 'dist']);
18
- async function readSquareListItem(filePath, root) {
19
- let stat;
13
+ async function readSquareListItem(filePath, root, options, control) {
14
+ if (!filePath.endsWith('.square'))
15
+ return null;
20
16
  try {
21
- stat = await fs.promises.stat(filePath);
17
+ control?.signal?.throwIfAborted();
18
+ const stat = await fs.promises.stat(filePath);
19
+ const square = await openSquare(filePath, { ...options, env: options.env ?? {}, signal: control?.signal }, control);
20
+ const projection = await listPresentation(square, control).finally(() => closeOpenSquare(square));
21
+ return {
22
+ path: path.relative(root, filePath) || path.basename(filePath),
23
+ lastActiveAt: stat.mtimeMs,
24
+ context: [...projection.context].map((line) => line.trim()).filter(Boolean),
25
+ participants: [...projection.participants],
26
+ activities: projection.activities,
27
+ };
22
28
  }
23
- catch {
29
+ catch (error) {
30
+ control?.signal?.throwIfAborted();
31
+ // A vanished, unreadable or undecodable candidate does not abort discovery.
24
32
  return null;
25
33
  }
26
- const square = await probeSquare(filePath);
27
- if (square === undefined)
28
- return null;
29
- const projection = await listPresentation(square).finally(() => closeOpenSquare(square));
30
- const relative = path.relative(root, filePath) || path.basename(filePath);
31
- return {
32
- path: relative,
33
- lastActiveAt: stat.mtimeMs,
34
- context: [...projection.context].map((line) => line.trim()).filter(Boolean),
35
- participants: [...projection.participants],
36
- activities: projection.activities,
37
- };
38
34
  }
39
- async function collectSquareList(root, maxDepth) {
35
+ /** Bounded deterministic discovery. Only the application calls this private operation. */
36
+ export async function discoverSquares(root, options = {}, control, openOptions = {}) {
37
+ const depth = options.depth ?? DEFAULT_LIST_DEPTH;
38
+ const limit = options.limit ?? DEFAULT_LIST_LIMIT;
39
+ if (!Number.isSafeInteger(depth) || depth < 0 || depth > MAX_LIST_DEPTH
40
+ || !Number.isSafeInteger(limit) || limit < 1 || limit > MAX_LIST_LIMIT
41
+ || (options.after !== undefined && (options.after.length === 0 || path.isAbsolute(options.after)))) {
42
+ throw new SquareError('invalid_args', 'Invalid discovery depth, limit or relative cursor');
43
+ }
40
44
  const items = [];
41
45
  let examined = 0;
42
46
  let stopped = false;
43
- async function walk(dir, depth) {
47
+ async function walk(dir, level) {
48
+ control?.signal?.throwIfAborted();
44
49
  if (stopped)
45
50
  return;
46
51
  let entries;
@@ -48,110 +53,32 @@ async function collectSquareList(root, maxDepth) {
48
53
  entries = await fs.promises.readdir(dir, { withFileTypes: true });
49
54
  }
50
55
  catch {
51
- // Directory vanished or became unreadable mid-walk — skip it, don't abort the scan.
56
+ control?.signal?.throwIfAborted();
52
57
  return;
53
58
  }
54
59
  entries.sort((left, right) => left.name.localeCompare(right.name));
55
60
  for (const entry of entries) {
61
+ control?.signal?.throwIfAborted();
56
62
  if (stopped)
57
63
  return;
58
- examined += 1;
59
- if (examined === LIST_DISCOVERY_BUDGET)
64
+ if (++examined === LIST_DISCOVERY_BUDGET)
60
65
  stopped = true;
61
66
  const fullPath = path.join(dir, entry.name);
62
67
  if (entry.isDirectory()) {
63
- if (!stopped && depth < maxDepth && !LIST_SKIP_DIRS.has(entry.name))
64
- await walk(fullPath, depth + 1);
65
- continue;
68
+ if (!stopped && level < depth && !LIST_SKIP_DIRS.has(entry.name))
69
+ await walk(fullPath, level + 1);
66
70
  }
67
- if (!entry.isFile())
68
- continue;
69
- const item = await readSquareListItem(fullPath, root);
70
- if (item)
71
- items.push(item);
72
- }
73
- }
74
- await walk(root, 0);
75
- return { items: items.sort((a, b) => a.path.localeCompare(b.path)), stopped };
76
- }
77
- function characterPreview(value) {
78
- const characters = Array.from(value);
79
- return characters.length <= DISPLAY_CHARACTER_LIMIT ? value : `${characters.slice(0, DISPLAY_CHARACTER_LIMIT - 1).join('')}…`;
80
- }
81
- function renderSquareList(items, stopped, depth, limit, after) {
82
- const page = after === undefined ? items : items.filter((item) => item.path.localeCompare(after) > 0);
83
- const shownItems = page.slice(0, limit);
84
- if (items.length === 0) {
85
- return [`(no squares found)`, ...(stopped ? [style('dim', `○ the walk stopped early — deeper squares may still be hiding`)] : [])].join('\n') + '\n';
86
- }
87
- const now = Date.now();
88
- const lines = ['squares'];
89
- for (const item of shownItems) {
90
- const glyph = item.activities > 0 ? '●' : style('dim', '○');
91
- lines.push(`${glyph} ${characterPreview(item.path)}${style('dim', ` · ${formatRelativeTime(item.lastActiveAt, now)} · ${item.participants.length} in the square · ${item.activities} ${item.activities === 1 ? 'activity' : 'activities'}`)}`);
92
- const shownContext = item.context.slice(0, CONTEXT_PREVIEW_LINES);
93
- if (shownContext.length === 0) {
94
- lines.push(` ${style('dim', 'context')} · (none)`);
95
- }
96
- else {
97
- shownContext.forEach((line, index) => lines.push(` ${index === 0 ? style('dim', 'context') : ' '} · ${characterPreview(line)}`));
98
- const hiddenContext = item.context.length - shownContext.length;
99
- if (hiddenContext > 0)
100
- lines.push(style('dim', ` · … ${hiddenContext} more ${hiddenContext === 1 ? 'line' : 'lines'}`));
101
- }
102
- const shownParticipants = item.participants.slice(0, PARTICIPANT_PREVIEW_COUNT);
103
- const hiddenParticipants = item.participants.length - shownParticipants.length;
104
- const participantNames = shownParticipants.length === 0 ? 'nobody' : shownParticipants.map((participant) => participantIdentity(characterPreview(participant))).join(' · ');
105
- lines.push(` ${style('dim', 'participants')} · ${participantNames}${hiddenParticipants > 0 ? style('dim', ` · … ${hiddenParticipants} more`) : ''}`);
106
- }
107
- const hiddenItems = page.length - shownItems.length;
108
- if (hiddenItems > 0) {
109
- const cursor = shownItems.at(-1)?.path;
110
- lines.push(style('dim', stopped ? ' … more squares' : ` … ${hiddenItems} more ${hiddenItems === 1 ? 'square' : 'squares'}`));
111
- if (cursor !== undefined)
112
- lines.push(`square list --depth ${depth} --limit ${limit} --after ${quoteShell(cursor)}`);
113
- }
114
- if (stopped)
115
- lines.push(style('dim', `○ the walk stopped early — deeper squares may still be hiding`));
116
- return lines.join('\n') + '\n';
117
- }
118
- function parseListOptions(args, usage) {
119
- let depth = DEFAULT_LIST_DEPTH;
120
- let limit = DEFAULT_LIST_LIMIT;
121
- let after;
122
- for (let index = 0; index < args.length; index += 2) {
123
- const option = args[index];
124
- const value = args[index + 1];
125
- if (value === undefined || (option !== '--depth' && option !== '--limit' && option !== '--after')) {
126
- usage();
127
- return { depth, limit };
128
- }
129
- if (option === '--after') {
130
- if (after !== undefined || value.length === 0 || path.isAbsolute(value)) {
131
- usage();
132
- return { depth, limit };
71
+ else if (entry.isFile()) {
72
+ const item = await readSquareListItem(fullPath, root, openOptions, control);
73
+ if (item !== null)
74
+ items.push(item);
133
75
  }
134
- after = value;
135
- continue;
136
76
  }
137
- if (!/^\d+$/.test(value)) {
138
- usage();
139
- return { depth, limit };
140
- }
141
- const parsed = Number(value);
142
- if (!Number.isSafeInteger(parsed) || (option === '--depth' ? parsed > MAX_LIST_DEPTH : parsed === 0 || parsed > MAX_LIST_LIMIT)) {
143
- usage();
144
- return { depth, limit };
145
- }
146
- if (option === '--depth')
147
- depth = parsed;
148
- else
149
- limit = parsed;
150
77
  }
151
- return { depth, limit, after };
152
- }
153
- export async function cmdListSquares(args, usage) {
154
- const options = parseListOptions(args, usage);
155
- const discovery = await collectSquareList(process.cwd(), options.depth);
156
- process.stdout.write(renderSquareList(discovery.items, discovery.stopped, options.depth, options.limit, options.after));
78
+ await walk(root, 0);
79
+ const page = items.sort((a, b) => a.path.localeCompare(b.path))
80
+ .filter((item) => options.after === undefined || item.path.localeCompare(options.after) > 0);
81
+ const selected = page.slice(0, limit);
82
+ const remaining = page.length - selected.length;
83
+ return { items: selected, total: items.length, stopped, remaining, ...(remaining > 0 ? { next: selected.at(-1).path } : {}) };
157
84
  }
package/dist/mcp.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { type SquareApplicationContext } from './square-application.js';
2
+ import type { SquareApplicationContext } from './square-facade.js';
3
3
  export interface SquareMcpOptions extends SquareApplicationContext {
4
4
  }
5
5
  export type SquareMcpServer = McpServer;
package/dist/mcp.js CHANGED
@@ -5,7 +5,6 @@ import { SquareError, isSquareError } from './model.js';
5
5
  import { operationEnv } from './automatic-session.js';
6
6
  import { SQUARE_IDENTITY } from './identity.js';
7
7
  import { createSquareApplication } from './square-application.js';
8
- import { toPublicActivity } from './views.js';
9
8
  const activityId = z.string().regex(/^act\/(0|[1-9][0-9]*)$/);
10
9
  const stringArray = z.array(z.string());
11
10
  const participantName = z.string().optional().describe("Participant name, same as --as. Defaults to the server's configured participant.");
@@ -23,36 +22,6 @@ const TOOL_DEFINITIONS = [
23
22
  { name: 'status', description: 'Read the public status of the square.', inputSchema: z.object({}).strict() },
24
23
  { name: 'participants', description: 'List participants standing in or done with the square.', inputSchema: z.object({}).strict() },
25
24
  ];
26
- function isObject(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); }
27
- function publicActivity(activity) { return { ...activity }; }
28
- function publicResult(name, value) {
29
- if (name === 'status') {
30
- const result = value;
31
- const state = result.status;
32
- const { latestAct, participants, ...rest } = state;
33
- return {
34
- hardCap: rest.hardCap,
35
- ...(rest.throttlePerMinute === undefined ? {} : { throttlePerMinute: rest.throttlePerMinute }),
36
- activeCount: rest.activeCount,
37
- doneCount: rest.doneCount,
38
- hold: rest.holdActive ? { by: rest.holdActor, ...(rest.holdReason === undefined ? {} : { reason: rest.holdReason }), ...(rest.holdAt === undefined ? {} : { at: rest.holdAt }) } : null,
39
- participants: participants.filter((participant) => participant.state !== 'not joined').map((participant) => ({ name: participant.name, state: participant.state, presence: participant.presence, activityCount: participant.activityCount, ...(participant.lastActiveAt === undefined ? {} : { lastActiveAt: participant.lastActiveAt }), unreadActivityCount: participant.unreadActivityCount, pendingMentionCount: participant.pendingMentionCount, listening: participant.listening })),
40
- ...(latestAct === undefined ? {} : { latestActivity: publicActivity(toPublicActivity(latestAct)) }),
41
- now: rest.now,
42
- };
43
- }
44
- if (name === 'express' || name === 'hold' || name === 'resume' || name === 'done') {
45
- const result = value;
46
- return { ...(result.activity === undefined ? {} : { activity: result.activity === null ? null : publicActivity(result.activity) }), ...(result.waited === undefined ? {} : { waited: result.waited }), ...(result.replyAuthorNotHere === undefined ? {} : { replyAuthorNotHere: result.replyAuthorNotHere }) };
47
- }
48
- if (name === 'history')
49
- return { activities: value };
50
- if (name === 'participants')
51
- return { participants: value };
52
- if (name === 'listening')
53
- return { listening: value };
54
- return value;
55
- }
56
25
  function operation(app, name, args, control) {
57
26
  switch (name) {
58
27
  case 'join': return app.join({ takeover: args.takeover }, control);
@@ -68,8 +37,8 @@ function operation(app, name, args, control) {
68
37
  case 'hold': return app.hold(args.reason, control);
69
38
  case 'resume': return app.resume(control);
70
39
  case 'done': return app.done(undefined, control);
71
- case 'status': return app.status();
72
- case 'participants': return app.participants();
40
+ case 'status': return app.status(undefined, control);
41
+ case 'participants': return app.participants(control);
73
42
  default: throw new SquareError('invalid_args', `Unknown tool: ${name}`);
74
43
  }
75
44
  }
@@ -90,9 +59,8 @@ export function createSquareMcpServer(options) {
90
59
  ? operationEnv('opencode', opencodeSessionId, baseEnv)
91
60
  : baseEnv;
92
61
  const app = createSquareApplication({ ...options, env, participant: participant ?? options.participant });
93
- const value = await operation(app, tool.name, operationArgs, { signal: extra.signal });
94
- const projected = publicResult(tool.name, value);
95
- const structuredContent = isObject(projected) ? projected : { result: projected };
62
+ const outcome = await operation(app, tool.name, operationArgs, { signal: extra.signal });
63
+ const structuredContent = outcome.data;
96
64
  return { content: [{ type: 'text', text: JSON.stringify(structuredContent) }], structuredContent };
97
65
  }
98
66
  catch (error) {
@@ -101,7 +69,9 @@ export function createSquareMcpServer(options) {
101
69
  : isSquareError(error)
102
70
  ? { code: error.code, message: error.message, ...(error.facts === undefined ? {} : { facts: error.facts }) }
103
71
  : { code: 'internal', message: error instanceof Error ? error.message : String(error) };
104
- return { isError: true, content: [{ type: 'text', text: JSON.stringify(normalized) }], structuredContent: { error: normalized } };
72
+ const operation = error instanceof Error ? error.operation : undefined;
73
+ const failure = operation === undefined ? normalized : { ...normalized, operation };
74
+ return { isError: true, content: [{ type: 'text', text: JSON.stringify(failure) }], structuredContent: { error: failure } };
105
75
  }
106
76
  });
107
77
  }
package/dist/model.d.ts CHANGED
@@ -15,8 +15,6 @@ export interface WakeRoute {
15
15
  address: Record<string, string>;
16
16
  updatedAt: number;
17
17
  }
18
- export interface ReceiverRoute extends WakeRoute {
19
- }
20
18
  export type SquareErrorCode = 'invalid_name' | 'invalid_args' | 'unknown_participant' | 'not_joined' | 'already_joined' | 'already_done' | 'held' | 'capped' | 'throttled' | 'bell_quota' | 'behind' | 'io' | 'unavailable';
21
19
  export type InternalSquareErrorCode = SquareErrorCode | 'not_found' | 'cap_reached' | 'conflict' | 'pending_peer';
22
20
  export interface SquareErrorFacts {
@@ -24,9 +22,11 @@ export interface SquareErrorFacts {
24
22
  activityUnsent?: true;
25
23
  /** Why a name could not be resolved: never in the roster, no longer standing in it, a bell
26
24
  * colliding with a mention, an @name that matches nobody, or an activity catch cannot address. */
27
- reason?: 'never_joined' | 'not_standing' | 'bell_mention_conflict' | 'unmatched_mention' | 'not_addressed';
25
+ reason?: 'never_joined' | 'not_standing' | 'bell_mention_conflict' | 'unmatched_mention' | 'not_addressed' | 'migration_required' | 'explicit_reach_required' | 'invalid_reply' | 'invalid_done_body';
28
26
  /** The activity id a `catch --id` refusal named. */
29
27
  activityId?: string;
28
+ /** Requested recipient spellings, without parsing presentation copy. */
29
+ targets?: readonly string[];
30
30
  /** Whether the artifact holds that activity at all; an unknown id needs an ordinary page. */
31
31
  activityExists?: boolean;
32
32
  pending?: number;
@@ -37,6 +37,7 @@ export interface SquareErrorFacts {
37
37
  declare class SquareErrorBase<Code extends string> extends Error {
38
38
  code: Code;
39
39
  facts?: SquareErrorFacts | undefined;
40
+ operation?: import('./square-facade.js').ApplicationFailureDetail;
40
41
  constructor(code: Code, message: string, facts?: SquareErrorFacts | undefined);
41
42
  }
42
43
  export declare class SquareError extends SquareErrorBase<SquareErrorCode> {
@@ -55,7 +56,6 @@ export type StoredAct = Act & {
55
56
  index: number;
56
57
  at: number;
57
58
  };
58
- export type StoredActHead = StoredAct extends infer T ? T extends StoredAct ? Omit<T, 'body' | 'through' | 'index'> : never : never;
59
59
  export type ObservationState = 'seen';
60
60
  export interface ActivityObservation {
61
61
  state: ObservationState;
@@ -85,40 +85,6 @@ export interface InboxMembership {
85
85
  notifications: InboxNotification[];
86
86
  catchLease?: WatchLease;
87
87
  }
88
- export interface SquareRuntimeState {
89
- nextActIndex: number;
90
- observations: Record<string, Record<string, ActivityObservation>>;
91
- leases: Record<string, WatchLease>;
92
- }
93
- export interface SquareState {
94
- hardCap: HardCap;
95
- throttlePerMinute?: number;
96
- preamble: string[];
97
- warmup: string[];
98
- acts: StoredAct[];
99
- routes?: ReceiverRoute[];
100
- runtime: SquareRuntimeState;
101
- }
102
- export interface ActivitiesOptions {
103
- lastN?: number | null;
104
- participants?: string[];
105
- /** Exclusive lower bound on act.at (ms). Alias of --since. */
106
- after?: number;
107
- /** Exclusive lower bound on stable act index (--after act/<index>). */
108
- afterIndex?: number;
109
- /** Exclusive upper bound on stable act index (--before act/<index>). */
110
- beforeIndex?: number;
111
- /** Center act indexes for context windows (--at). */
112
- atIndexes?: number[];
113
- beforeContext?: number;
114
- afterContext?: number;
115
- mention?: string;
116
- grep?: string;
117
- fixed?: string;
118
- order?: 'asc' | 'desc';
119
- format?: string[];
120
- json?: boolean;
121
- }
122
88
  export interface WatchOptions {
123
89
  id?: ActivityId;
124
90
  participants?: string[];
@@ -134,16 +100,10 @@ export type PublicAct = Extract<StoredAct, {
134
100
  export type RoomChangeAct = Extract<StoredAct, {
135
101
  kind: 'join' | 'done' | 'hold' | 'resume' | 'listen' | 'ignore';
136
102
  }>;
137
- export interface HoldState {
138
- active: boolean;
139
- at?: number;
140
- reason?: string;
141
- }
142
103
  export declare function formatHardCap(hardCap: HardCap): string;
143
104
  export declare function parseParticipantList(value: string): string[];
144
105
  export declare function nameKey(name: string): string;
145
106
  export declare function sameName(a: string, b: string): boolean;
146
- export declare function findParticipantName(participants: string[], name: string): string | undefined;
147
107
  /** One name grapheme: Unicode letters, digits, marks, hyphens, or underscores (no isolated variation selectors), or a complete RGI emoji. Shared by name validation and body @mention scanning. */
148
108
  export declare const NAME_GRAPHEME_SOURCE: string;
149
109
  export declare function validateName(name: string): void;
package/dist/model.js CHANGED
@@ -7,6 +7,7 @@ export function isWakeRouteKind(value) {
7
7
  class SquareErrorBase extends Error {
8
8
  code;
9
9
  facts;
10
+ operation;
10
11
  constructor(code, message, facts) {
11
12
  super(message);
12
13
  this.code = code;
@@ -36,9 +37,6 @@ export function nameKey(name) {
36
37
  export function sameName(a, b) {
37
38
  return nameKey(a) === nameKey(b);
38
39
  }
39
- export function findParticipantName(participants, name) {
40
- return participants.find((participant) => sameName(participant, name));
41
- }
42
40
  /** One name grapheme: Unicode letters, digits, marks, hyphens, or underscores (no isolated variation selectors), or a complete RGI emoji. Shared by name validation and body @mention scanning. */
43
41
  export const NAME_GRAPHEME_SOURCE = String.raw `[[\p{L}\p{N}\p{M}_\x2D]--[\p{Variation_Selector}]]|\p{RGI_Emoji}`;
44
42
  const NAME_PATTERN = new RegExp(`^(?:${NAME_GRAPHEME_SOURCE})+(?:/(?:${NAME_GRAPHEME_SOURCE})+)*$`, 'v');
@@ -8,7 +8,7 @@ interface ProcessNotificationOptions {
8
8
  env?: NodeJS.ProcessEnv;
9
9
  now?: () => number;
10
10
  }
11
- export declare function defaultWakeAdapters(): Promise<WakeAdapter[]>;
11
+ export declare function defaultWakeAdapters(env?: NodeJS.ProcessEnv): Promise<WakeAdapter[]>;
12
12
  export declare function createDefaultWakeTransport(hostLedger: import('./host-ledger.js').HostLedgerPort, clock: () => number, env?: NodeJS.ProcessEnv, suppliedAdapters?: readonly WakeAdapter[]): Promise<WakeTransportPort>;
13
13
  export declare function createWakeTransport(adapters: readonly WakeAdapter[], hostLedger: import('./host-ledger.js').HostLedgerPort, clock: () => number, nativePorts?: Readonly<Partial<Record<import('./model.js').WakeRouteKind, WakeTransportPort>>>): WakeTransportPort;
14
14
  export declare function processActNotificationsOnce(squarePath: string, actIndex: number, opts?: ProcessNotificationOptions): Promise<import("./ports.js").DeliveryResult>;
@@ -3,10 +3,12 @@ import path from 'node:path';
3
3
  import fs from 'node:fs';
4
4
  import { SquareError } from './model.js';
5
5
  import { displayAttentionPath } from './attention-presentation.js';
6
- import { openSquare } from './square-file-adapter.js';
6
+ import { openSquare } from './open-square.js';
7
7
  import { closeOpenSquare } from './open-square.js';
8
8
  import { deliverPending, sweepPending } from './delivery-operations.js';
9
- import { projectWakeEvidenceFromState } from './square-projections.js';
9
+ import { projectWakeEvidence } from './wake-eligibility.js';
10
+ import { pendingHead } from './delivery.js';
11
+ import { parseActivityId } from './square-core.js';
10
12
  import { canonicalPath } from './canonical-path.js';
11
13
  import { createHostLedgerPort } from './host-ledger-file-adapter.js';
12
14
  export const PRIVILEGED_HOOK_BUDGET_MS = 3000;
@@ -17,11 +19,11 @@ export function wakeGraceMs(env = process.env) {
17
19
  }
18
20
  return value;
19
21
  }
20
- export async function defaultWakeAdapters() {
22
+ export async function defaultWakeAdapters(env = process.env) {
21
23
  const adapters = [];
22
24
  try {
23
25
  const { CodexQueueAdapter } = await import('./codex-queue.js');
24
- adapters.push(new CodexQueueAdapter());
26
+ adapters.push(new CodexQueueAdapter({ env }));
25
27
  }
26
28
  catch {
27
29
  // Codex is unavailable only when this build omits its local adapter.
@@ -36,7 +38,7 @@ export async function defaultWakeAdapters() {
36
38
  return adapters;
37
39
  }
38
40
  export async function createDefaultWakeTransport(hostLedger, clock, env = process.env, suppliedAdapters) {
39
- const adapters = suppliedAdapters ?? await defaultWakeAdapters();
41
+ const adapters = suppliedAdapters ?? await defaultWakeAdapters(env);
40
42
  const { createClaudeWakeTransport } = await import('./claude-delivery.js');
41
43
  return createWakeTransport(suppliedAdapters === undefined && env.SQUARE_DISABLE_PASEO_WAKE === '1' ? adapters.filter((adapter) => adapter.kind !== 'paseo') : adapters, hostLedger, clock, { 'claude-native': createClaudeWakeTransport(hostLedger, env) });
42
44
  }
@@ -45,8 +47,12 @@ async function observeWakeRequest(request, hostLedger, now) {
45
47
  try {
46
48
  const location = await canonicalPath(request.location);
47
49
  square = await openSquare(location, { hostLedger });
48
- const { state } = await square.artifact.read();
49
- const eligibility = await projectWakeEvidenceFromState({ state, hostLedger, location, now });
50
+ const { value: facts } = await square.artifact.read((facts) => {
51
+ const index = parseActivityId(request.activity);
52
+ const head = index === undefined ? undefined : pendingHead(facts, request.participant, index);
53
+ return { routes: facts.routes(), pending: head === undefined ? [] : [head] };
54
+ });
55
+ const eligibility = await projectWakeEvidence({ ...facts, hostLedger, location, now });
50
56
  return { ...eligibility.currentness({ ...request, location }), observationAvailable: true };
51
57
  }
52
58
  catch {
@@ -1,5 +1,6 @@
1
1
  import type { HostLedgerPort, SquareArtifactPort, WakeTransportPort } from './ports.js';
2
- /** Private binding assembled by storage and consumed by the four concerns. */
2
+ import type { OperationControl } from './square-facade.js';
3
+ /** Host-bound resource: artifact, captured environment, clock, ledger and transport. */
3
4
  export interface OpenSquare {
4
5
  readonly artifact: SquareArtifactPort;
5
6
  readonly clock: () => number;
@@ -8,5 +9,18 @@ export interface OpenSquare {
8
9
  readonly wakeTransport?: WakeTransportPort;
9
10
  readonly env?: NodeJS.ProcessEnv;
10
11
  }
11
- /** Package-private lifecycle boundary for bound squares. */
12
+ export interface SquareBuildOptions {
13
+ markdown: string;
14
+ hardCap?: number | null;
15
+ throttlePerMinute?: number;
16
+ clock?: () => number;
17
+ hostLedger?: HostLedgerPort;
18
+ wakeTransport?: WakeTransportPort;
19
+ env?: NodeJS.ProcessEnv;
20
+ /** One caller deadline propagated into artifact busy retries. */
21
+ signal?: AbortSignal;
22
+ }
23
+ export declare function openSquare(squarePath: string, options?: Pick<SquareBuildOptions, 'clock' | 'hostLedger' | 'wakeTransport' | 'env' | 'signal'>, control?: OperationControl): Promise<OpenSquare>;
24
+ export declare function buildSquare(squarePath: string, options: SquareBuildOptions): Promise<OpenSquare>;
25
+ export declare function buildMemorySquare(options: SquareBuildOptions): OpenSquare;
12
26
  export declare function closeOpenSquare(square: OpenSquare): Promise<void>;
@@ -1,4 +1,43 @@
1
- /** Package-private lifecycle boundary for bound squares. */
1
+ import { createArtifactPort, createSquare, prepareSquareBuild } from './artifact.js';
2
+ import { InternalSquareError, SquareError } from './model.js';
3
+ import { hostLedgerRoot } from './host-ledger-root.js';
4
+ import { createHostLedgerPort } from './host-ledger-file-adapter.js';
5
+ export async function openSquare(squarePath, options = {}, control) {
6
+ const env = { ...(options.env ?? process.env) };
7
+ const artifact = createArtifactPort(squarePath, undefined, options.signal);
8
+ try {
9
+ await artifact.read(facts => facts.header(), control?.signal);
10
+ return {
11
+ artifact, clock: options.clock ?? Date.now, location: squarePath, env,
12
+ hostLedger: options.hostLedger ?? createHostLedgerPort({ rootPath: hostLedgerRoot(env) }),
13
+ wakeTransport: options.wakeTransport,
14
+ };
15
+ }
16
+ catch (error) {
17
+ await artifact.close();
18
+ if (error instanceof InternalSquareError && error.code === 'not_found')
19
+ throw new SquareError('unavailable', `Square is unavailable at ${squarePath}`);
20
+ throw error;
21
+ }
22
+ }
23
+ export async function buildSquare(squarePath, options) {
24
+ try {
25
+ await createSquare(squarePath, { ...options, force: false }, options.markdown, options.signal);
26
+ }
27
+ catch (error) {
28
+ if (error instanceof InternalSquareError && error.code === 'conflict')
29
+ throw new SquareError('io', `Cannot build over an existing square at ${squarePath}`);
30
+ throw error;
31
+ }
32
+ return openSquare(squarePath, { ...options, signal: undefined });
33
+ }
34
+ export function buildMemorySquare(options) {
35
+ return {
36
+ artifact: createArtifactPort(':memory:', prepareSquareBuild(options, options.markdown)),
37
+ clock: options.clock ?? Date.now, location: 'memory',
38
+ hostLedger: options.hostLedger, wakeTransport: options.wakeTransport,
39
+ };
40
+ }
2
41
  export function closeOpenSquare(square) {
3
42
  return square.artifact.close();
4
43
  }
@@ -1,14 +1,5 @@
1
- import type { ClaudeDeliveryResult, ClaudeSendTextOptions, ClaudeTarget } from './types.js';
2
- export interface ClaudeConnectExistingOptions {
3
- readonly harness: 'claude';
4
- readonly sessionId: string;
5
- readonly endpoint: string;
6
- readonly token?: string;
7
- readonly claudeHome?: string;
8
- readonly timeoutMs?: number;
9
- readonly signal?: AbortSignal;
10
- }
1
+ import type { ClaudeConnectOptions, ClaudeDeliveryResult, ClaudeSendTextOptions, ClaudeTarget } from './types.js';
11
2
  /** Resolve an explicitly identified existing Claude native inbox; never discovers or starts one. */
12
- export declare function connectExisting(options: ClaudeConnectExistingOptions): Promise<ClaudeTarget>;
3
+ export declare function connectExisting(options: ClaudeConnectOptions): Promise<ClaudeTarget>;
13
4
  /** Write once to Claude's next native boundary; local write is never native admission. */
14
5
  export declare function sendText(target: ClaudeTarget, text: string, options?: ClaudeSendTextOptions): Promise<ClaudeDeliveryResult>;
@@ -1,4 +1,6 @@
1
1
  import { DeliveryError } from './errors.js';
2
+ import type { OpenCodeConnectOptions, ClaudeConnectOptions, PiConnectOptions, PaseoConnectOptions } from './types.js';
3
+ export type { OpenCodeConnectOptions, ClaudeConnectOptions, PiConnectOptions, PaseoConnectOptions } from './types.js';
2
4
  export interface SendOptions {
3
5
  readonly timeoutMs?: number;
4
6
  readonly signal?: AbortSignal;
@@ -16,48 +18,6 @@ export interface Steerable<O = SendOptions> {
16
18
  export interface Queueable<O = SendOptions> {
17
19
  queue(text: string, options?: O): Promise<Receipt>;
18
20
  }
19
- export interface OpenCodeConnectOptions {
20
- readonly harness: 'opencode';
21
- readonly sessionId: string;
22
- readonly endpoint?: {
23
- readonly url: string;
24
- readonly auth?: {
25
- readonly type: 'basic';
26
- readonly username: string;
27
- readonly password: string;
28
- };
29
- };
30
- readonly registrationFile?: string;
31
- readonly timeoutMs?: number;
32
- readonly signal?: AbortSignal;
33
- }
34
- export interface ClaudeConnectOptions {
35
- readonly harness: 'claude';
36
- readonly sessionId: string;
37
- readonly endpoint: string;
38
- readonly token?: string;
39
- readonly claudeHome?: string;
40
- readonly timeoutMs?: number;
41
- readonly signal?: AbortSignal;
42
- }
43
- export interface PiConnectOptions {
44
- readonly harness: 'pi';
45
- readonly sessionId: string;
46
- readonly endpoint: string;
47
- readonly timeoutMs?: number;
48
- readonly signal?: AbortSignal;
49
- }
50
- export interface PaseoConnectOptions {
51
- readonly harness: 'paseo';
52
- readonly agentId: string;
53
- readonly endpoint?: string;
54
- readonly password?: string;
55
- readonly authHeader?: string;
56
- readonly localCredential?: string;
57
- readonly paseoHome?: string;
58
- readonly timeoutMs?: number;
59
- readonly signal?: AbortSignal;
60
- }
61
21
  export type OpenCodeAgent = Steerable<KeyedSendOptions> & Queueable<KeyedSendOptions> & {
62
22
  readonly harness: 'opencode';
63
23
  readonly sessionId: string;