@astrosheep/square 0.3.106 → 0.4.1

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 (206) hide show
  1. package/dist/activity-feed.js +1 -1
  2. package/dist/artifact-store.d.ts +41 -0
  3. package/dist/artifact-store.js +272 -0
  4. package/dist/artifact.d.ts +6 -12
  5. package/dist/artifact.js +43 -344
  6. package/dist/attention-presentation.d.ts +13 -7
  7. package/dist/attention-presentation.js +29 -68
  8. package/dist/boundary-presentation.d.ts +3 -16
  9. package/dist/boundary-presentation.js +29 -109
  10. package/dist/card-presentation.d.ts +1 -0
  11. package/dist/card-presentation.js +2 -0
  12. package/dist/catch-decisions.d.ts +2 -2
  13. package/dist/catch-decisions.js +7 -3
  14. package/dist/catch-selection.d.ts +8 -0
  15. package/dist/catch-selection.js +5 -0
  16. package/dist/claude-delivery.d.ts +14 -12
  17. package/dist/claude-delivery.js +42 -142
  18. package/dist/claude-mcp-context.js +2 -2
  19. package/dist/claude-mod.js +28 -140
  20. package/dist/claude-transport.d.ts +5 -0
  21. package/dist/claude-transport.js +34 -0
  22. package/dist/cli/context.d.ts +2 -2
  23. package/dist/cli/context.js +7 -10
  24. package/dist/cli/maintenance-commands.d.ts +0 -4
  25. package/dist/cli/maintenance-commands.js +2 -29
  26. package/dist/cli/observation-commands.d.ts +2 -0
  27. package/dist/cli/observation-commands.js +12 -2
  28. package/dist/cli/program.js +1 -1
  29. package/dist/cli/registry.js +4 -3
  30. package/dist/codex-address.d.ts +2 -2
  31. package/dist/codex-boundary-state.d.ts +1 -5
  32. package/dist/codex-boundary-state.js +0 -4
  33. package/dist/codex-hook.d.ts +7 -10
  34. package/dist/codex-hook.js +69 -33
  35. package/dist/codex-queue.d.ts +10 -11
  36. package/dist/codex-queue.js +32 -34
  37. package/dist/codex-watch.d.ts +2 -0
  38. package/dist/codex-watch.js +100 -0
  39. package/dist/decisions.js +3 -3
  40. package/dist/delivery-deferral.d.ts +1 -19
  41. package/dist/delivery-deferral.js +1 -29
  42. package/dist/delivery-frame.d.ts +7 -0
  43. package/dist/delivery-frame.js +11 -0
  44. package/dist/delivery-ledger-sqlite.d.ts +97 -0
  45. package/dist/delivery-ledger-sqlite.js +496 -0
  46. package/dist/delivery-ledger.d.ts +196 -0
  47. package/dist/delivery-ledger.js +268 -0
  48. package/dist/delivery-lifetime.d.ts +6 -0
  49. package/dist/delivery-lifetime.js +45 -0
  50. package/dist/harness-links.js +61 -7
  51. package/dist/harness.js +12 -17
  52. package/dist/help.js +3 -6
  53. package/dist/http-delivery.d.ts +5 -9
  54. package/dist/http-delivery.js +20 -79
  55. package/dist/inbox.d.ts +6 -57
  56. package/dist/inbox.js +24 -380
  57. package/dist/index.d.ts +7 -4
  58. package/dist/index.js +5 -2
  59. package/dist/mcp.d.ts +2 -1
  60. package/dist/mcp.js +40 -70
  61. package/dist/message.d.ts +7 -0
  62. package/dist/message.js +23 -0
  63. package/dist/model.d.ts +15 -91
  64. package/dist/model.js +2 -140
  65. package/dist/neutral.d.ts +72 -0
  66. package/dist/neutral.js +27 -0
  67. package/dist/notifications.d.ts +24 -26
  68. package/dist/notifications.js +39 -143
  69. package/dist/operation-control.d.ts +4 -0
  70. package/dist/operation-control.js +20 -0
  71. package/dist/operation-presentation.d.ts +1 -2
  72. package/dist/operation-presentation.js +1 -7
  73. package/dist/owner.d.ts +2 -2
  74. package/dist/owner.js +1 -1
  75. package/dist/packages/agent-delivery/src/claude-native.d.ts +2 -0
  76. package/dist/packages/agent-delivery/src/claude-native.js +5 -0
  77. package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
  78. package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
  79. package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
  80. package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
  81. package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
  82. package/dist/packages/agent-delivery/src/codex.js +41 -4
  83. package/dist/packages/agent-delivery/src/index.d.ts +3 -1
  84. package/dist/packages/agent-delivery/src/index.js +1 -1
  85. package/dist/packages/agent-delivery/src/paseo.js +11 -2
  86. package/dist/packages/agent-delivery/src/types.d.ts +1 -0
  87. package/dist/paseo-delivery.d.ts +5 -5
  88. package/dist/paseo-delivery.js +19 -99
  89. package/dist/paseo.d.ts +1 -1
  90. package/dist/paseo.js +1 -1
  91. package/dist/plugins/opencode/index.d.ts +5 -3
  92. package/dist/plugins/opencode/index.js +99 -21
  93. package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
  94. package/dist/plugins/opencode-shared/delivery.js +109 -0
  95. package/dist/plugins/opencode-v1/index.d.ts +28 -0
  96. package/dist/plugins/opencode-v1/index.js +41 -0
  97. package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
  98. package/dist/plugins/opencode-v1/runtime.js +152 -0
  99. package/dist/plugins/opencode-v1/transport.d.ts +13 -0
  100. package/dist/plugins/opencode-v1/transport.js +50 -0
  101. package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
  102. package/dist/plugins/paseo/shared/card-presentation.js +7 -0
  103. package/dist/ports.d.ts +33 -214
  104. package/dist/presentation.d.ts +5 -5
  105. package/dist/presentation.js +1 -0
  106. package/dist/runtime.js +2 -2
  107. package/dist/search.js +1 -1
  108. package/dist/session-lifecycle.d.ts +8 -7
  109. package/dist/session-lifecycle.js +40 -42
  110. package/dist/sqlite-framing.d.ts +8 -0
  111. package/dist/sqlite-framing.js +31 -0
  112. package/dist/sqlite-square.d.ts +16 -26
  113. package/dist/sqlite-square.js +199 -262
  114. package/dist/sqlite-values.d.ts +21 -0
  115. package/dist/sqlite-values.js +78 -0
  116. package/dist/square-api.d.ts +1 -1
  117. package/dist/square-api.js +5 -8
  118. package/dist/square-core.d.ts +0 -1
  119. package/dist/square-domain.d.ts +12 -10
  120. package/dist/square-domain.js +105 -223
  121. package/dist/square-facade.d.ts +25 -76
  122. package/dist/square-location.d.ts +6 -1
  123. package/dist/square-location.js +1 -1
  124. package/dist/square-post.d.ts +53 -0
  125. package/dist/square-post.js +4 -0
  126. package/dist/square-posting.d.ts +13 -0
  127. package/dist/square-posting.js +174 -0
  128. package/dist/square-producer-sqlite.d.ts +11 -0
  129. package/dist/square-producer-sqlite.js +210 -0
  130. package/dist/square-receive.d.ts +2 -3
  131. package/dist/square-sqlite.d.ts +33 -42
  132. package/dist/square-sqlite.js +236 -768
  133. package/dist/square-tools.d.ts +8 -0
  134. package/dist/square-tools.js +39 -0
  135. package/dist/square-values.d.ts +27 -0
  136. package/dist/square-values.js +90 -0
  137. package/dist/views.d.ts +6 -6
  138. package/dist/views.js +14 -9
  139. package/dist/wake-sink.d.ts +4 -11
  140. package/dist/wake-sink.js +8 -32
  141. package/dist/wake-transports.d.ts +4 -0
  142. package/dist/wake-transports.js +11 -0
  143. package/examples/symmetric-domains.mjs +29 -249
  144. package/guides/change-waits.md +13 -53
  145. package/guides/claude-native.md +19 -172
  146. package/guides/codex-delivery.md +55 -78
  147. package/guides/delivery-primitives.md +48 -207
  148. package/guides/operation-cancellation.md +2 -5
  149. package/guides/participant-ownership.md +25 -89
  150. package/guides/pi-native-delivery.md +19 -56
  151. package/guides/pi-tools.md +6 -8
  152. package/guides/row-runtime-delivery-evidence.md +2 -0
  153. package/guides/row-storage-design.md +19 -44
  154. package/guides/square-api.md +113 -538
  155. package/package.json +8 -8
  156. package/plugins/claude/.claude-plugin/plugin.json +1 -1
  157. package/plugins/claude/hooks/hooks.json +1 -1
  158. package/plugins/claude/{hooks/register.js → mods/square.js} +4 -7
  159. package/plugins/claude/types.d.ts +1 -1
  160. package/plugins/codex/.codex-plugin/plugin.json +1 -1
  161. package/plugins/codex/hooks/hooks.json +11 -23
  162. package/plugins/opencode/index.ts +91 -23
  163. package/plugins/opencode-shared/delivery.ts +91 -0
  164. package/plugins/opencode-v1/index.ts +36 -0
  165. package/plugins/opencode-v1/runtime.ts +134 -0
  166. package/plugins/opencode-v1/transport.ts +41 -0
  167. package/plugins/paseo/OVERVIEW.md +5 -5
  168. package/plugins/paseo/README.md +7 -6
  169. package/plugins/paseo/client/markdown.tsx +5 -5
  170. package/plugins/paseo/client/square-message.tsx +28 -24
  171. package/plugins/paseo/client/transform.ts +8 -5
  172. package/plugins/paseo/shared/card-presentation.ts +16 -0
  173. package/plugins/paseo/shared/message.ts +6 -11
  174. package/plugins/pi/square-pi.js +167 -451
  175. package/dist/channel.d.ts +0 -74
  176. package/dist/channel.js +0 -92
  177. package/dist/claude-delivery-status.d.ts +0 -13
  178. package/dist/claude-delivery-status.js +0 -46
  179. package/dist/cmd/notify-once.d.ts +0 -2
  180. package/dist/cmd/notify-once.js +0 -29
  181. package/dist/delivery-attempts.d.ts +0 -52
  182. package/dist/delivery-attempts.js +0 -73
  183. package/dist/delivery-effects.d.ts +0 -139
  184. package/dist/delivery-effects.js +0 -163
  185. package/dist/delivery-health.d.ts +0 -51
  186. package/dist/delivery-health.js +0 -173
  187. package/dist/delivery-operations.d.ts +0 -9
  188. package/dist/delivery-operations.js +0 -168
  189. package/dist/delivery-primitives.d.ts +0 -5
  190. package/dist/delivery-primitives.js +0 -3
  191. package/dist/delivery.d.ts +0 -45
  192. package/dist/delivery.js +0 -106
  193. package/dist/plugins/opencode/delivery.d.ts +0 -19
  194. package/dist/plugins/opencode/delivery.js +0 -238
  195. package/dist/presentation-operations.d.ts +0 -18
  196. package/dist/presentation-operations.js +0 -86
  197. package/dist/square-index.d.ts +0 -16
  198. package/dist/square-index.js +0 -106
  199. package/dist/square-legacy-framing.d.ts +0 -11
  200. package/dist/square-legacy-framing.js +0 -64
  201. package/dist/square-migration-host-ledger.d.ts +0 -26
  202. package/dist/square-migration-host-ledger.js +0 -169
  203. package/dist/square-migration.d.ts +0 -30
  204. package/dist/square-migration.js +0 -599
  205. package/guides/migration.md +0 -156
  206. package/plugins/opencode/delivery.ts +0 -211
@@ -1,20 +1,8 @@
1
- import { operationEnv } from './participant-identity.js';
2
- import { createArtifactPort } from './artifact.js';
3
- import { recordClaudeDeliveryStatus } from './claude-delivery-status.js';
4
- import { Square } from './square-api.js';
5
1
  import { observeClaudeDelivery } from './claude-delivery.js';
6
- import { processActNotificationsOnce } from './notifications.js';
7
- import { sweepPending } from './delivery-operations.js';
8
2
  import { beginClaudeMcpCall, endClaudeMcpCall } from './claude-mcp-context.js';
9
- import { asSeatRef } from './seats.js';
10
- import { projectSessionSeats } from './inbox.js';
11
- import { restoreSessionSeats } from './session-lifecycle.js';
3
+ import { DeliveryLedger } from './delivery-ledger.js';
4
+ import { attachDeliverySessionRoutes, detachDeliverySession } from './session-lifecycle.js';
12
5
  import { harnessOwner } from './owner.js';
13
- import { InternalSquareError, SquareError } from './model.js';
14
- /** Persisted hook state keeps its wire coordinate; internal consumers keep the located seat. */
15
- function claudeBinding({ location, seat }, sessionId) {
16
- return { location, participant: seat.participant, session: sessionId, generation: seat.generation };
17
- }
18
6
  /** JSON stdin bridge. Identity is explicit per operation; process.env is never rewritten. */
19
7
  export async function runClaudeMod(inputText, env = process.env) {
20
8
  if (inputText.length > 512_000)
@@ -22,10 +10,6 @@ export async function runClaudeMod(inputText, env = process.env) {
22
10
  const input = JSON.parse(inputText);
23
11
  if (!input || typeof input.sessionId !== 'string' || !input.sessionId || typeof input.cwd !== 'string')
24
12
  throw new Error('Claude bridge coordinate missing.');
25
- if (input.operation === 'status') {
26
- const recorded = input.status?.sessionId === input.sessionId && await recordClaudeDeliveryStatus(input.status, env);
27
- return `${JSON.stringify({ recorded })}\n`;
28
- }
29
13
  if (input.operation === 'tool-begin') {
30
14
  return `${JSON.stringify(await beginClaudeMcpCall({ toolUseId: input.toolUseId, sessionId: input.sessionId, cwd: input.cwd, agentId: input.agentId }, env))}\n`;
31
15
  }
@@ -33,140 +17,44 @@ export async function runClaudeMod(inputText, env = process.env) {
33
17
  await endClaudeMcpCall(input.toolUseId, input.token, env);
34
18
  return '{}\n';
35
19
  }
36
- const scoped = operationEnv('claude', input.sessionId, env);
37
- const signal = AbortSignal.timeout(2500);
38
20
  const owner = harnessOwner({ channel: 'claude-code', session: input.sessionId, ...(input.agentId === undefined ? {} : { agent: input.agentId }) });
39
21
  const supported = process.platform === 'darwin' && typeof input.endpoint === 'string' && input.endpoint.startsWith('/');
40
- const sessionSeats = async () => (await projectSessionSeats({ owner, env }, signal)).filter(member => member.seat.attachment === 'attached');
41
- if (input.operation === 'end') {
42
- const retired = [];
43
- const captured = [...input.bindings ?? []];
44
- // Discover committed late joins at the pinned end boundary, never later owners.
45
- if (input.endedAt !== undefined)
46
- for (const member of await projectSessionSeats({ owner, env }, signal)) {
47
- if (member.joinedAt > input.endedAt || captured.some((item) => item.location === member.location
48
- && item.participant === member.seat.participant && item.generation === member.seat.generation))
49
- continue;
50
- captured.push(claudeBinding(member, input.sessionId));
51
- }
52
- for (const binding of captured) {
53
- if (binding.session !== input.sessionId)
54
- continue;
55
- const square = await Square.at({ path: binding.location, env: scoped });
22
+ const routes = supported ? [{ kind: 'claude-native', address: { sessionId: input.sessionId, endpoint: input.endpoint, version: input.version, platform: 'darwin', loaded: 'true' } }] : [];
23
+ const captured = input.bindings?.find(binding => binding.session === input.sessionId)?.generation;
24
+ if (input.operation === 'start') {
25
+ const session = await attachDeliverySessionRoutes(owner, env, routes, AbortSignal.timeout(2500));
26
+ if (session && !supported && session.routes.some(route => route.kind === 'claude-native')) {
27
+ const ledger = await DeliveryLedger.open({ location: env.SQUARE_DELIVERY });
56
28
  try {
57
- const detached = binding.generation === undefined ? null
58
- : await square.detach(binding.participant, { owner, generation: binding.generation });
59
- if (detached)
60
- retired.push(binding);
29
+ await ledger.updateRoutes({ owner, generation: session.generation, routes: session.routes.filter(route => route.kind !== 'claude-native') });
61
30
  }
62
31
  finally {
63
- await square.close();
32
+ await ledger.close();
64
33
  }
65
- if (signal.aborted)
66
- break;
67
34
  }
68
- return `${JSON.stringify({ retired })}\n`;
35
+ return `${JSON.stringify({ available: supported, diagnostic: supported ? undefined : 'Native inbox unavailable: requires macOS Claude with an interactive loaded mod and its real endpoint.', bindings: session ? [{ session: input.sessionId, generation: session.generation }] : [] })}\n`;
69
36
  }
70
- const recovery = new Set();
71
- const cancelledBindings = [...input.cancelledBindings ?? []];
72
- if (input.operation === 'start') {
73
- await restoreSessionSeats(owner, scoped, supported ? {
74
- kind: 'claude-native', address: { sessionId: input.sessionId, endpoint: input.endpoint, version: input.version, platform: 'darwin', loaded: 'true' },
75
- } : undefined, signal);
37
+ if (input.operation === 'end') {
38
+ const retired = captured && await detachDeliverySession(owner, captured, env);
39
+ return `${JSON.stringify({ retired: retired ? input.bindings : [] })}\n`;
76
40
  }
77
- if (input.operation === 'start' || input.operation === 'reconcile' || input.operation === 'cancel' || input.cancelAt !== undefined) {
78
- for (const member of await sessionSeats()) {
79
- if (signal.aborted)
80
- break;
81
- const { location, seat: capturedSeat, joinedAt } = member;
82
- const matches = (item) => item !== undefined
83
- && item.location === location && item.participant === capturedSeat.participant && item.session === input.sessionId
84
- && (item.generation === undefined || item.generation === capturedSeat.generation);
85
- const expected = input.bindings?.find(matches);
86
- const cancelled = input.cancelledBindings?.find(matches) ?? (input.operation === 'cancel' ? expected : undefined);
87
- const lateCancelledJoin = input.operation === 'cancel' && input.cancelAt !== undefined
88
- && joinedAt <= input.cancelAt && expected === undefined;
89
- if (lateCancelledJoin && !cancelledBindings.some(matches))
90
- cancelledBindings.push(claudeBinding(member, input.sessionId));
91
- if (input.operation !== 'start' && input.operation !== 'reconcile' && !lateCancelledJoin && expected === undefined)
92
- continue;
93
- const artifact = createArtifactPort(location, undefined, signal);
94
- try {
95
- const { value: currentSeat } = await artifact.read((facts) => facts.seat(capturedSeat.participant), signal);
96
- if (currentSeat === undefined || currentSeat.attachment !== 'attached' || currentSeat.generation !== capturedSeat.generation
97
- || currentSeat.owner !== capturedSeat.owner)
98
- continue;
99
- const seat = asSeatRef(currentSeat);
100
- const existing = currentSeat.wakeAddress?.kind === 'claude-native' ? currentSeat.wakeAddress : undefined;
101
- const cutoff = input.cancelAt !== undefined && (cancelled !== undefined || lateCancelledJoin) ? input.cancelAt : undefined;
102
- if (cutoff !== undefined) {
103
- const { value: through } = await artifact.read((facts) => {
104
- let beforeIndex;
105
- for (;;) {
106
- const page = facts.activityHeads({ beforeIndex }, { edge: 'newest', limit: 100 });
107
- const last = [...page.items].reverse().find((activity) => activity.at <= cutoff);
108
- if (last !== undefined)
109
- return last.index;
110
- if (!page.hasMore)
111
- return -1;
112
- beforeIndex = page.items[0].index;
113
- }
114
- }, signal);
115
- if (through >= 0)
116
- await artifact.cancelDeliveries(seat, through, signal);
117
- }
118
- if (!supported) {
119
- if (existing !== undefined)
120
- await artifact.transactAs({ kind: 'participant', seat }, (facts) => facts.updateWakeAddress(seat, undefined), signal);
121
- continue;
122
- }
123
- if (existing === undefined || existing.address.endpoint !== input.endpoint)
124
- recovery.add(location);
125
- await artifact.transactAs({ kind: 'participant', seat }, (facts) => facts.updateWakeAddress(seat, {
126
- kind: 'claude-native', address: { sessionId: input.sessionId, endpoint: input.endpoint, version: input.version, platform: 'darwin', loaded: 'true' },
127
- }), signal);
128
- }
129
- catch (error) {
130
- if (error instanceof InternalSquareError && error.code === 'not_found')
131
- throw new SquareError('unavailable', `Square is unavailable at ${location}`);
132
- throw error;
133
- }
134
- finally {
135
- await artifact.close();
41
+ if (input.operation === 'reconcile' || input.operation === 'cancel') {
42
+ const ledger = await DeliveryLedger.open({ location: env.SQUARE_DELIVERY });
43
+ try {
44
+ const session = await ledger.session(owner);
45
+ if (captured && session?.generation === captured && session.state === 'attached') {
46
+ if (input.operation === 'cancel')
47
+ await ledger.cancel({ owner, generation: captured });
48
+ else
49
+ await ledger.updateRoutes({ owner, generation: captured, routes: [...session.routes.filter(route => route.kind !== 'claude-native'), ...routes] });
136
50
  }
51
+ return `${JSON.stringify({ available: supported, diagnostic: supported ? undefined : 'Native inbox unavailable: requires macOS Claude with an interactive loaded mod and its real endpoint.', bindings: input.bindings ?? [], cancelledBindings: input.bindings ?? [] })}\n`;
52
+ }
53
+ finally {
54
+ await ledger.close();
137
55
  }
138
- }
139
- if (input.operation === 'start' || input.operation === 'reconcile' || input.operation === 'cancel') {
140
- const members = await sessionSeats();
141
- // One startup recovery pass for known unsent work. Unknown/admitted sends never replay.
142
- if (supported && input.operation !== 'cancel')
143
- for (const { location } of members) {
144
- if (signal.aborted)
145
- break;
146
- if (input.operation !== 'start' && !recovery.has(location))
147
- continue;
148
- const artifact = createArtifactPort(location, undefined, signal);
149
- let indices;
150
- try {
151
- indices = await sweepPending({ artifact, location, now: Date.now(), graceMs: 0, limit: 8 });
152
- }
153
- catch (error) {
154
- if (error instanceof InternalSquareError && error.code === 'not_found')
155
- throw new SquareError('unavailable', `Square is unavailable at ${location}`);
156
- throw error;
157
- }
158
- finally {
159
- await artifact.close();
160
- }
161
- for (const index of indices) {
162
- if (signal.aborted)
163
- break;
164
- await processActNotificationsOnce(location, index, { env: { ...env, SQUARE_NOTIFY_DELIVERY_WAIT_MS: '200' } });
165
- }
166
- }
167
- return `${JSON.stringify({ available: supported, diagnostic: supported ? undefined : 'Native inbox unavailable: requires macOS Claude with an interactive loaded mod and its real endpoint.', bindings: members.map(member => claudeBinding(member, input.sessionId)), cancelledBindings })}\n`;
168
56
  }
169
57
  if (!['guard', 'admitted', 'stored'].includes(input.operation) || typeof input.text !== 'string')
170
58
  throw new Error('Unknown Claude bridge operation.');
171
- return `${JSON.stringify(await observeClaudeDelivery(input.sessionId, input.text, input.operation, env))}\n`;
59
+ return `${JSON.stringify(await observeClaudeDelivery(input.sessionId, input.text, input.operation, env, input.refs))}\n`;
172
60
  }
@@ -0,0 +1,5 @@
1
+ import type { DeliveryTransport } from './delivery-ledger.js';
2
+ export declare function nativeTokens(text: string): string[];
3
+ export declare function nativePayload(token: string, text: string): string;
4
+ export declare function hashPayload(payload: string): string;
5
+ export declare function createClaudeWakeTransport(env?: NodeJS.ProcessEnv): DeliveryTransport;
@@ -0,0 +1,34 @@
1
+ import { stat } from 'node:fs/promises';
2
+ import { createHash, randomUUID } from 'node:crypto';
3
+ import { renderDeliveryReminder } from './delivery-frame.js';
4
+ import { writeClaudeNative } from './packages/agent-delivery/src/claude-native.js';
5
+ const marker = /(?:^|\n)\[square-inbox:([a-zA-Z0-9-]+)\](?:\n|$)/g;
6
+ export function nativeTokens(text) { return [...text.matchAll(marker)].map(match => match[1]); }
7
+ export function nativePayload(token, text) {
8
+ return renderDeliveryReminder([`[square-inbox:${token}]\n${text}\n[/square-inbox:${token}]`], { tagged: false });
9
+ }
10
+ export function hashPayload(payload) { return createHash('sha256').update(payload).digest('hex'); }
11
+ export function createClaudeWakeTransport(env = process.env) {
12
+ return {
13
+ kind: 'claude-native',
14
+ async send(card, address, context) {
15
+ if (address.loaded !== 'true' || !address.endpoint || !address.sessionId)
16
+ return 'not-capable';
17
+ try {
18
+ if (!(await stat(address.endpoint)).isSocket())
19
+ return 'not-capable';
20
+ }
21
+ catch {
22
+ return 'not-capable';
23
+ }
24
+ const messageId = randomUUID();
25
+ const payload = nativePayload(context.token, card.text);
26
+ if (!await context.prepare({ token: context.token, messageId, payloadHash: hashPayload(payload) }))
27
+ return 'not-capable';
28
+ if (context.signal.aborted || Date.now() >= context.deadline)
29
+ return 'not-capable';
30
+ const result = await writeClaudeNative({ sessionId: address.sessionId, endpoint: address.endpoint, messageId, env }, payload, { deadline: context.deadline, signal: context.signal, beforeSend: context.beforeSend });
31
+ return result.outcome === 'unavailable' ? 'failed' : 'unknown';
32
+ },
33
+ };
34
+ }
@@ -1,5 +1,5 @@
1
1
  import { type Owner } from '../square-api.js';
2
- import { type HardCap } from '../model.js';
2
+ import { type HardCap, type WakeAddress } from '../model.js';
3
3
  import { Square } from '../square-api.js';
4
4
  import type { OperationControl } from '../square-facade.js';
5
5
  export interface CommandContext {
@@ -46,7 +46,7 @@ export declare function squareInput(context: CommandContext): {
46
46
  };
47
47
  export declare function commandIdentity(env: NodeJS.ProcessEnv, explicit?: Owner): {
48
48
  owner: Owner;
49
- wakeAddress?: import('../model.js').WakeAddress;
49
+ wakeAddress?: WakeAddress;
50
50
  };
51
51
  /** Adapter lifetime only; each callback uses the actual public resource API. */
52
52
  export declare function withSquare<T>(context: CommandContext, run: (square: Square) => Promise<T>, control?: OperationControl): Promise<T>;
@@ -103,7 +103,6 @@ const LOCATION_REQUIRED_COMMANDS = new Set([
103
103
  'status',
104
104
  'participants',
105
105
  'doctor',
106
- 'migrate',
107
106
  ]);
108
107
  export async function parseGlobalArgs(rawArgs) {
109
108
  const args = [...rawArgs];
@@ -151,22 +150,20 @@ export function squareInput(context) {
151
150
  export function commandIdentity(env, explicit) {
152
151
  if (explicit !== undefined)
153
152
  return { owner: explicit };
154
- const configured = env.SQUARE_OWNER;
155
- if (configured !== undefined)
156
- return { owner: configured };
157
- const selected = harnessSessionSources.flatMap(({ variable, channel }) => env[variable]?.trim() ? [{ channel, session: env[variable].trim() }] : []);
158
- const native = selected.filter(source => source.channel !== 'paseo');
153
+ if (env.SQUARE_OWNER !== undefined)
154
+ return { owner: env.SQUARE_OWNER };
159
155
  if (env.CLAUDE_CODE_CHILD_SESSION === '1')
160
156
  throw new Error('Harness identity is incomplete; provide --owner explicitly.');
157
+ const selected = harnessSessionSources.flatMap(({ variable, channel }) => env[variable]?.trim() ? [{ channel, session: env[variable].trim() }] : []);
158
+ const native = selected.filter(source => source.channel !== 'paseo');
161
159
  if (native.length > 1)
162
160
  throw new Error('Multiple harness execution coordinates are present; select one explicit owner.');
163
- const paseo = selected.find(source => source.channel === 'paseo');
164
- const coordinate = native[0] ?? paseo;
161
+ const coordinate = native[0] ?? selected[0];
165
162
  if (coordinate === undefined)
166
163
  return { owner: localUserOwner() };
167
164
  const owner = harnessOwner({ channel: coordinate.channel, session: coordinate.session });
168
- const wakeAddress = coordinate.channel === 'codex' ? codexWakeAddress(coordinate.session, env)
169
- : paseo === undefined ? undefined : { kind: 'paseo', address: { agentId: paseo.session } };
165
+ const wakeAddress = coordinate.channel === 'codex' ? { ...codexWakeAddress(coordinate.session, env), kind: 'codex-queue' }
166
+ : coordinate.channel === 'paseo' ? { kind: 'paseo', address: { agentId: coordinate.session } } : undefined;
170
167
  return { owner, ...(wakeAddress === undefined ? {} : { wakeAddress }) };
171
168
  }
172
169
  /** Adapter lifetime only; each callback uses the actual public resource API. */
@@ -3,9 +3,5 @@ interface DoctorResult {
3
3
  output: string;
4
4
  exitCode?: number;
5
5
  }
6
- interface MigrateResult {
7
- output: string;
8
- }
9
- export declare const migrateCommand: CommandSpec<undefined, MigrateResult>;
10
6
  export declare const doctorCommand: CommandSpec<undefined, DoctorResult>;
11
7
  export {};
@@ -1,30 +1,6 @@
1
- import { diagnoseSquare, migrateSquare } from '../square-api.js';
2
- import { commandPrefix, renderDoctorClean, renderDoctorUnfixable, withPathOutput } from '../presentation.js';
1
+ import { diagnoseSquare } from '../square-api.js';
2
+ import { renderDoctorClean, renderDoctorUnfixable, withPathOutput } from '../presentation.js';
3
3
  import { requireSquarePath, squareInput, usage } from './context.js';
4
- export const migrateCommand = {
5
- parse(argv, context) {
6
- if (argv.length > 0)
7
- usage(context.command);
8
- return undefined;
9
- },
10
- async execute(_intent, context) {
11
- const squarePath = requireSquarePath(context);
12
- const outcome = await migrateSquare(squareInput(context));
13
- const body = outcome.status === 'migrated'
14
- ? [
15
- '✓ migrated to current row storage',
16
- ...(outcome.counts === undefined ? [] : [
17
- ` · ${outcome.counts.activities} activities · ${outcome.counts.receipts} receipts · ${outcome.counts.leases} leases · ${outcome.counts.routes} routes`,
18
- ` · ${outcome.counts.recoveredSeats} recovered seats · ${outcome.counts.unownedStanding} unowned standing · ${outcome.counts.sharedBodySeats} shared-body seats · ${outcome.counts.skippedEvidence} skipped evidence`,
19
- ]),
20
- ].join('\n')
21
- : '· already current format — nothing changed';
22
- return { output: withPathOutput(squarePath, body, { participantCount: outcome.standing }) };
23
- },
24
- present(result) {
25
- process.stdout.write(result.output);
26
- },
27
- };
28
4
  export const doctorCommand = {
29
5
  parse(argv, context) {
30
6
  if (argv.length > 0)
@@ -34,9 +10,6 @@ export const doctorCommand = {
34
10
  async execute(_intent, context) {
35
11
  const squarePath = requireSquarePath(context);
36
12
  const diagnosis = await diagnoseSquare(squareInput(context));
37
- if (diagnosis.migrationRequired !== undefined) {
38
- return { output: withPathOutput(squarePath, `${diagnosis.migrationRequired}\n${commandPrefix(squarePath)} migrate\n`), exitCode: 2 };
39
- }
40
13
  if (diagnosis.unfixable !== undefined || diagnosis.standingCount === undefined) {
41
14
  return {
42
15
  output: withPathOutput(squarePath, renderDoctorUnfixable(diagnosis.unfixable ?? 'the artifact could not be decoded')),
@@ -27,4 +27,6 @@ interface InboxIntent {
27
27
  export declare const inboxCommand: CommandSpec<InboxIntent, string>;
28
28
  export declare const claudeModCommand: CommandSpec<undefined, string>;
29
29
  export declare const codexHookCommand: CommandSpec<undefined, string>;
30
+ export declare const codexWatchCommand: CommandSpec<undefined, string>;
31
+ export declare const codexInterruptCommand: CommandSpec<undefined, string>;
30
32
  export {};
@@ -1,7 +1,8 @@
1
1
  import path from 'node:path';
2
2
  import { once } from 'node:events';
3
3
  import { runClaudeMod } from '../claude-mod.js';
4
- import { runCodexHook } from '../codex-hook.js';
4
+ import { runCodexHook, runCodexInterrupt } from '../codex-hook.js';
5
+ import { runCodexWatch } from '../codex-watch.js';
5
6
  import { isSquareError } from '../model.js';
6
7
  import { commandPrefix, participantIdentity, truncateChars, withPathOutput, quoteShell, } from '../presentation.js';
7
8
  import { PARTICIPANTS_DEFAULT_LIMIT, PARTICIPANTS_MAX_LIMIT, renderHistoryResult, renderParticipantsResult, renderStatusResult, } from '../operation-presentation.js';
@@ -526,4 +527,13 @@ function hookCommand(runHook) {
526
527
  };
527
528
  }
528
529
  export const claudeModCommand = hookCommand(runClaudeMod);
529
- export const codexHookCommand = hookCommand(runCodexHook);
530
+ export const codexHookCommand = {
531
+ parse(argv, context) { if (argv.length > 0)
532
+ usage(context.command); return undefined; },
533
+ execute: async () => runCodexHook(await readStdin(), process.env, text => new Promise((resolve, reject) => {
534
+ process.stdout.write(text, error => error ? reject(error) : resolve());
535
+ })),
536
+ present: () => { },
537
+ };
538
+ export const codexWatchCommand = hookCommand(input => runCodexWatch(input, process.env));
539
+ export const codexInterruptCommand = hookCommand(input => runCodexInterrupt(input, process.env));
@@ -9,7 +9,7 @@ async function handleSquareError(error, context) {
9
9
  throw error;
10
10
  const detail = error.operation;
11
11
  const squarePath = context?.squarePath;
12
- const recovery = error.facts?.reason === 'migration_required' || context === undefined || squarePath === undefined ? undefined
12
+ const recovery = context === undefined || squarePath === undefined ? undefined
13
13
  : await withSquare({ ...context, name: detail?.participant ?? context.name }, (square) => square.recovery(detail?.participant ?? context.name)).catch(() => undefined);
14
14
  const name = detail?.participant ?? recovery?.participant ?? context?.name;
15
15
  const lines = renderFailureLines(error, { squarePath, name, owner: context?.owner ?? context?.env.SQUARE_OWNER });
@@ -1,10 +1,10 @@
1
1
  import { buildCommand, doneCommand, expressCommand, ignoreCommand, joinCommand, listenCommand, listeningCommand, unlistenCommand } from './square-commands.js';
2
- import { doctorCommand, migrateCommand } from './maintenance-commands.js';
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
5
  import { mcpServerCommand } from './mcp-server-command.js';
6
6
  import { JSON_COMMANDS } from './json.js';
7
- import { catchCommand, claudeModCommand, codexHookCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand, } from './observation-commands.js';
7
+ import { catchCommand, claudeModCommand, codexHookCommand, codexWatchCommand, codexInterruptCommand, historyCommand, inboxCommand, listCommand, participantsCommand, statusCommand, streamCommand, } from './observation-commands.js';
8
8
  /** Every public command is an executable adapter, including aliases and utility commands. */
9
9
  export const commandRegistry = [
10
10
  { names: ['build'], spec: buildCommand },
@@ -14,6 +14,8 @@ export const commandRegistry = [
14
14
  { names: ['inbox'], spec: inboxCommand },
15
15
  { names: ['claude-mod'], spec: claudeModCommand },
16
16
  { names: ['codex-hook'], spec: codexHookCommand },
17
+ { names: ['codex-watch'], spec: codexWatchCommand },
18
+ { names: ['codex-interrupt'], spec: codexInterruptCommand },
17
19
  { names: ['catch'], spec: catchCommand },
18
20
  { names: ['express'], spec: expressCommand },
19
21
  { names: ['listen'], spec: listenCommand },
@@ -25,7 +27,6 @@ export const commandRegistry = [
25
27
  { names: ['uninstall'], spec: uninstallCommand },
26
28
  { names: ['harness'], spec: harnessCommand },
27
29
  { names: ['doctor'], spec: doctorCommand },
28
- { names: ['migrate'], spec: migrateCommand },
29
30
  { names: ['history'], spec: historyCommand },
30
31
  { names: ['status'], spec: statusCommand },
31
32
  { names: ['participants'], spec: participantsCommand },
@@ -1,3 +1,3 @@
1
- import type { WakeAddress } from './model.js';
1
+ import type { DeliveryRoute } from './delivery-ledger.js';
2
2
  /** Capture the receiver's CLI configuration when its seat is established, not at send time. */
3
- export declare function codexWakeAddress(threadId: string, env: NodeJS.ProcessEnv): WakeAddress;
3
+ export declare function codexWakeAddress(threadId: string, env: NodeJS.ProcessEnv): DeliveryRoute;
@@ -1,6 +1,2 @@
1
- export type { CodexBoundary } from './packages/agent-delivery/src/codex-boundary.js';
1
+ export type { CodexBoundary, CodexStopEpoch } from './packages/agent-delivery/src/codex-boundary.js';
2
2
  export declare function codexBoundaryStore(env?: NodeJS.ProcessEnv): import("./packages/agent-delivery/src/codex-boundary.js").CodexBoundaryStore;
3
- export declare const readCodexBoundary: (id: string, env?: NodeJS.ProcessEnv) => Promise<import("./packages/agent-delivery/src/codex-boundary.js").CodexBoundary | undefined>;
4
- export declare const codexQueueEligible: (id: string, env?: NodeJS.ProcessEnv) => Promise<boolean>;
5
- export declare const recordCodexBoundary: (id: string, event: "Stop" | "non-stop" | "start" | "end", env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<void>;
6
- export declare const clearCodexBoundary: (id: string, env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<void>;
@@ -4,7 +4,3 @@ import { createCodexBoundaryStore } from './packages/agent-delivery/src/codex-bo
4
4
  export function codexBoundaryStore(env = process.env) {
5
5
  return createCodexBoundaryStore(env.SQUARE_CODEX_BOUNDARIES || path.join(os.homedir(), '.square', 'codex-boundaries.json'));
6
6
  }
7
- export const readCodexBoundary = (id, env) => codexBoundaryStore(env).read(id);
8
- export const codexQueueEligible = (id, env) => codexBoundaryStore(env).queueEligible(id);
9
- export const recordCodexBoundary = (id, event, env, signal) => codexBoundaryStore(env).record(id, event, signal);
10
- export const clearCodexBoundary = (id, env, signal) => codexBoundaryStore(env).clear(id, signal);
@@ -1,12 +1,9 @@
1
- import { type Owner } from './owner.js';
2
- import type { PendingMembership } from './model.js';
3
- import type { WakeTransports } from './notifications.js';
4
- export interface CodexHookInput {
5
- session_id?: unknown;
6
- hook_event_name?: unknown;
7
- cwd?: unknown;
8
- }
1
+ import { type CodexHookInput } from './packages/agent-delivery/src/codex-hook.js';
9
2
  export type HookTrace = (line: string) => void;
10
3
  export declare const CODEX_HOOK_BUDGET_MS = 4500;
11
- export declare function codexHookResponse(input: CodexHookInput, lookup?: (identity: Owner, env?: NodeJS.ProcessEnv, signal?: AbortSignal) => Promise<PendingMembership[]> | PendingMembership[], env?: NodeJS.ProcessEnv, deliveryTransports?: WakeTransports, trace?: HookTrace): Promise<object | undefined>;
12
- export declare function runCodexHook(inputText: string, env?: NodeJS.ProcessEnv): Promise<string>;
4
+ /** sink resolves only after stdout has accepted the complete hook response. */
5
+ export declare function codexHookResponse(value: unknown, sink: ((text: string) => void | Promise<void>) | undefined, env?: NodeJS.ProcessEnv, trace?: HookTrace): Promise<object | undefined>;
6
+ export declare function parseCodexHookText(text: string): CodexHookInput | undefined;
7
+ /** The caller owns stdout; no receipt is written when no output sink is supplied. */
8
+ export declare function runCodexHook(inputText: string, env?: NodeJS.ProcessEnv, sink?: (text: string) => void | Promise<void>): Promise<string>;
9
+ export declare function runCodexInterrupt(inputText: string, env?: NodeJS.ProcessEnv): Promise<string>;
@@ -1,49 +1,85 @@
1
- import { handleCodexHook } from './packages/agent-delivery/src/codex-hook.js';
1
+ import { handleCodexHook, parseCodexHook } from './packages/agent-delivery/src/codex-hook.js';
2
2
  import { presentPendingAtBoundary } from './boundary-presentation.js';
3
- import { sessionInbox } from './inbox.js';
3
+ import { DeliveryLedger } from './delivery-ledger.js';
4
4
  import { harnessOwner } from './owner.js';
5
- import { detachSessionSeats, restoreSessionSeats } from './session-lifecycle.js';
5
+ import { attachDeliverySessionRoutes, detachDeliverySession } from './session-lifecycle.js';
6
6
  import { codexBoundaryStore } from './codex-boundary-state.js';
7
7
  import { codexWakeAddress } from './codex-address.js';
8
- import { PRIVILEGED_HOOK_BUDGET_MS, sweepPrivilegedPending } from './notifications.js';
9
8
  export const CODEX_HOOK_BUDGET_MS = 4500;
10
- const defaultTrace = (line) => { process.stderr.write(`${line}\n`); };
11
- export async function codexHookResponse(input, lookup = sessionInbox, env = process.env, deliveryTransports, trace = defaultTrace) {
9
+ const defaultTrace = line => { process.stderr.write(`${line}\n`); };
10
+ /** sink resolves only after stdout has accepted the complete hook response. */
11
+ export async function codexHookResponse(value, sink, env = process.env, trace = defaultTrace) {
12
+ const input = parseCodexHook(value);
13
+ if (!input)
14
+ return;
12
15
  const configured = Number(env.SQUARE_CODEX_HOOK_BUDGET_MS ?? CODEX_HOOK_BUDGET_MS);
13
- const startedAt = Date.now();
14
- let mark = startedAt;
15
- const timeoutMs = Number.isFinite(configured) && configured > 0 ? configured : CODEX_HOOK_BUDGET_MS;
16
+ const timeoutMs = Math.min(input.hook_event_name === 'Interrupt' || input.hook_event_name === 'SessionEnd' ? 2500 : CODEX_HOOK_BUDGET_MS, Number.isFinite(configured) && configured > 0 ? configured : CODEX_HOOK_BUDGET_MS);
16
17
  const signal = AbortSignal.timeout(timeoutMs);
17
- if ((input.hook_event_name === 'SessionStart' || input.hook_event_name === 'SessionResume')
18
- && typeof input.session_id === 'string' && input.session_id.trim()) {
19
- await restoreSessionSeats(harnessOwner({ channel: 'codex', session: input.session_id }), env, codexWakeAddress(input.session_id, env), signal);
18
+ const owner = harnessOwner({ channel: 'codex', session: input.session_id });
19
+ // Capture before any asynchronous boundary update; a replacement attachment
20
+ // must never inherit this callback's cancellation or detachment.
21
+ let generation;
22
+ if (input.hook_event_name === 'SessionEnd' || input.hook_event_name === 'Interrupt') {
23
+ const ledger = await DeliveryLedger.open({ location: env.SQUARE_DELIVERY });
24
+ try {
25
+ generation = (await ledger.session(owner))?.generation;
26
+ }
27
+ finally {
28
+ await ledger.close();
29
+ }
20
30
  }
21
- return handleCodexHook(input, {
22
- boundaries: codexBoundaryStore(env),
23
- timeoutMs,
24
- signal,
25
- sweepTimeoutMs: PRIVILEGED_HOOK_BUDGET_MS,
26
- pull: (id, signal) => presentPendingAtBoundary(harnessOwner({ channel: 'codex', session: id }), (context) => context, lookup, env, signal),
27
- sweep: (cwd, deadline, signal) => sweepPrivilegedPending(cwd ?? process.cwd(), env, deliveryTransports, deadline, signal),
28
- end: async (id) => { await detachSessionSeats('codex', id, env); },
29
- trace: (name, detail = '') => {
30
- const now = Date.now();
31
- const durationMs = now - mark;
32
- mark = now;
33
- trace(`square-codex-hook: stage=${name} durationMs=${durationMs} totalMs=${now - startedAt}${detail ? ` ${detail}` : ''}`);
31
+ const result = await handleCodexHook(input, {
32
+ boundaries: codexBoundaryStore(env), timeoutMs, signal,
33
+ pull: async (_sessionId, pullSignal, event) => {
34
+ if (!sink)
35
+ return;
36
+ return presentPendingAtBoundary(owner, async (context) => {
37
+ await sink(`${JSON.stringify({ hookSpecificOutput: { hookEventName: event, additionalContext: context } })}\n`);
38
+ return context;
39
+ }, env, pullSignal);
34
40
  },
41
+ end: async () => { if (generation)
42
+ await detachDeliverySession(owner, generation, env); },
43
+ interrupt: async () => {
44
+ if (!generation || signal.aborted)
45
+ return;
46
+ const ledger = await DeliveryLedger.open({ location: env.SQUARE_DELIVERY });
47
+ try {
48
+ await ledger.cancel({ owner, generation });
49
+ }
50
+ finally {
51
+ await ledger.close();
52
+ }
53
+ },
54
+ trace: name => trace(`square-codex-hook: stage=${name}`),
35
55
  });
56
+ // Disarm before rotating the native attachment, even if there is no old session.
57
+ if (input.hook_event_name === 'SessionStart' && !signal.aborted)
58
+ await attachDeliverySessionRoutes(owner, env, [codexWakeAddress(input.session_id, env)], signal);
59
+ return result;
36
60
  }
37
- export async function runCodexHook(inputText, env = process.env) {
38
- let input;
61
+ export function parseCodexHookText(text) {
39
62
  try {
40
- input = JSON.parse(inputText);
63
+ return parseCodexHook(JSON.parse(text));
41
64
  }
42
65
  catch {
43
- return '';
66
+ return;
67
+ }
68
+ }
69
+ /** The caller owns stdout; no receipt is written when no output sink is supplied. */
70
+ export async function runCodexHook(inputText, env = process.env, sink) {
71
+ await codexHookResponse(parseCodexHookText(inputText), sink, env);
72
+ return '';
73
+ }
74
+ export async function runCodexInterrupt(inputText, env = process.env) {
75
+ const input = parseCodexHookText(inputText);
76
+ if (input?.hook_event_name === 'Interrupt') {
77
+ try {
78
+ await codexHookResponse(input, undefined, env);
79
+ }
80
+ catch {
81
+ throw new Error('Codex interrupt unavailable.');
82
+ }
44
83
  }
45
- if (input === null || typeof input !== 'object')
46
- return '';
47
- const result = await codexHookResponse(input, sessionInbox, env);
48
- return result === undefined ? '' : `${JSON.stringify(result)}\n`;
84
+ return '';
49
85
  }
@@ -1,15 +1,14 @@
1
- import { type CodexCliAgent, type CodexCliConnectOptions } from './packages/agent-delivery/src/index.js';
2
- export { sendCodexQueue, CodexQueueSendError } from './packages/agent-delivery/src/codex-queue.js';
3
- export type { CodexQueueRequest, CodexQueueFailureKind } from './packages/agent-delivery/src/codex-queue.js';
4
- import type { WakeRequest, WakeOutcome, WakeTransportPort } from './ports.js';
5
- import type { WakeRoute } from './model.js';
1
+ import { type CodexStopEpoch } from './codex-boundary-state.js';
2
+ import type { DeliveryCard, DeliveryTransport, DeliveryTransportContext, TransportOutcome } from './delivery-ledger.js';
6
3
  export interface CodexQueueTransportOptions {
7
- env?: NodeJS.ProcessEnv;
8
- connect?: (options: CodexCliConnectOptions) => Promise<CodexCliAgent>;
4
+ readonly epoch: CodexStopEpoch;
5
+ readonly address: Readonly<Record<string, string>>;
6
+ readonly env?: NodeJS.ProcessEnv;
9
7
  }
10
- export declare class CodexQueueTransport implements WakeTransportPort {
8
+ /** Instantiated only by the receiver, for one captured Stop epoch. */
9
+ export declare class CodexQueueTransport implements DeliveryTransport {
11
10
  private readonly opts;
12
- constructor(opts?: CodexQueueTransportOptions);
13
- attempt(request: WakeRequest, timeoutMs: number, beforeSend: () => Promise<boolean>): Promise<WakeOutcome>;
11
+ readonly kind = "codex-queue";
12
+ constructor(opts: CodexQueueTransportOptions);
13
+ send(card: DeliveryCard, address: Readonly<Record<string, string>>, context: DeliveryTransportContext): Promise<TransportOutcome>;
14
14
  }
15
- export type { WakeRoute };