@astrosheep/square 0.4.0 → 0.4.2
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.
- package/dist/artifact.d.ts +1 -3
- package/dist/artifact.js +12 -36
- package/dist/attention-presentation.d.ts +2 -22
- package/dist/attention-presentation.js +9 -12
- package/dist/boundary-presentation.d.ts +3 -14
- package/dist/boundary-presentation.js +29 -104
- package/dist/card-presentation.d.ts +1 -0
- package/dist/card-presentation.js +2 -0
- package/dist/catch-decisions.js +1 -7
- package/dist/claude-boundary-state.d.ts +20 -0
- package/dist/claude-boundary-state.js +84 -0
- package/dist/claude-hook.d.ts +2 -0
- package/dist/claude-hook.js +231 -0
- package/dist/claude-mcp-context.d.ts +1 -1
- package/dist/claude-mcp-context.js +12 -3
- package/dist/cli/context.js +7 -9
- package/dist/cli/observation-commands.d.ts +4 -1
- package/dist/cli/observation-commands.js +37 -4
- package/dist/cli/registry.js +5 -2
- package/dist/codex-address.d.ts +2 -2
- package/dist/codex-boundary-state.d.ts +1 -5
- package/dist/codex-boundary-state.js +0 -4
- package/dist/codex-hook.d.ts +7 -10
- package/dist/codex-hook.js +69 -33
- package/dist/codex-queue.d.ts +10 -11
- package/dist/codex-queue.js +32 -32
- package/dist/codex-watch.d.ts +2 -0
- package/dist/codex-watch.js +100 -0
- package/dist/decisions.js +2 -2
- package/dist/delivery-deferral.d.ts +8 -17
- package/dist/delivery-deferral.js +0 -28
- package/dist/delivery-frame.d.ts +7 -0
- package/dist/delivery-frame.js +11 -0
- package/dist/delivery-ledger-sqlite.d.ts +97 -0
- package/dist/delivery-ledger-sqlite.js +496 -0
- package/dist/delivery-ledger.d.ts +196 -0
- package/dist/delivery-ledger.js +268 -0
- package/dist/delivery-lifetime.d.ts +6 -0
- package/dist/delivery-lifetime.js +45 -0
- package/dist/harness-claude.js +3 -4
- package/dist/harness-links.js +63 -7
- package/dist/harness.js +12 -17
- package/dist/help.js +4 -1
- package/dist/http-delivery.d.ts +5 -9
- package/dist/http-delivery.js +20 -77
- package/dist/inbox.d.ts +6 -49
- package/dist/inbox.js +24 -371
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -1
- package/dist/mcp.js +2 -3
- package/dist/model.d.ts +7 -47
- package/dist/model.js +1 -7
- package/dist/notifications.d.ts +24 -20
- package/dist/notifications.js +39 -108
- package/dist/operation-control.d.ts +4 -0
- package/dist/operation-control.js +20 -0
- package/dist/packages/agent-delivery/src/claude-native.d.ts +2 -0
- package/dist/packages/agent-delivery/src/claude-native.js +5 -0
- package/dist/packages/agent-delivery/src/codex-boundary.d.ts +11 -6
- package/dist/packages/agent-delivery/src/codex-boundary.js +31 -40
- package/dist/packages/agent-delivery/src/codex-hook.d.ts +17 -12
- package/dist/packages/agent-delivery/src/codex-hook.js +26 -39
- package/dist/packages/agent-delivery/src/codex.d.ts +3 -0
- package/dist/packages/agent-delivery/src/codex.js +41 -4
- package/dist/packages/agent-delivery/src/index.d.ts +3 -1
- package/dist/packages/agent-delivery/src/index.js +1 -1
- package/dist/packages/agent-delivery/src/paseo.js +11 -2
- package/dist/packages/agent-delivery/src/types.d.ts +1 -0
- package/dist/paseo-delivery.d.ts +5 -5
- package/dist/paseo-delivery.js +19 -97
- package/dist/paseo.d.ts +1 -1
- package/dist/paseo.js +1 -1
- package/dist/plugins/opencode/index.d.ts +5 -3
- package/dist/plugins/opencode/index.js +99 -21
- package/dist/plugins/opencode-shared/delivery.d.ts +23 -0
- package/dist/plugins/opencode-shared/delivery.js +109 -0
- package/dist/plugins/opencode-v1/index.d.ts +28 -0
- package/dist/plugins/opencode-v1/index.js +41 -0
- package/dist/plugins/opencode-v1/runtime.d.ts +56 -0
- package/dist/plugins/opencode-v1/runtime.js +152 -0
- package/dist/plugins/opencode-v1/transport.d.ts +13 -0
- package/dist/plugins/opencode-v1/transport.js +50 -0
- package/dist/plugins/paseo/shared/card-presentation.d.ts +10 -0
- package/dist/plugins/paseo/shared/card-presentation.js +7 -0
- package/dist/ports.d.ts +31 -90
- package/dist/session-lifecycle.d.ts +8 -7
- package/dist/session-lifecycle.js +40 -42
- package/dist/sqlite-square.d.ts +14 -23
- package/dist/sqlite-square.js +132 -139
- package/dist/square-api.js +4 -7
- package/dist/square-core.d.ts +0 -1
- package/dist/square-domain.d.ts +5 -17
- package/dist/square-domain.js +104 -221
- package/dist/square-facade.d.ts +18 -15
- package/dist/square-post.d.ts +53 -0
- package/dist/square-post.js +4 -0
- package/dist/square-posting.d.ts +13 -0
- package/dist/square-posting.js +174 -0
- package/dist/square-producer-sqlite.d.ts +11 -0
- package/dist/square-producer-sqlite.js +210 -0
- package/dist/square-sqlite.d.ts +15 -25
- package/dist/square-sqlite.js +150 -226
- package/dist/views.d.ts +2 -2
- package/dist/views.js +0 -1
- package/dist/wake-sink.d.ts +4 -11
- package/dist/wake-sink.js +8 -32
- package/dist/wake-transports.d.ts +4 -7
- package/dist/wake-transports.js +7 -39
- package/examples/symmetric-domains.mjs +29 -249
- package/guides/change-waits.md +13 -53
- package/guides/claude-native.md +7 -171
- package/guides/codex-delivery.md +55 -80
- package/guides/delivery-primitives.md +48 -207
- package/guides/mcp.md +1 -1
- package/guides/operation-cancellation.md +2 -5
- package/guides/participant-ownership.md +25 -89
- package/guides/pi-native-delivery.md +19 -56
- package/guides/pi-tools.md +6 -8
- package/guides/square-api.md +113 -615
- package/package.json +8 -8
- package/plugins/claude/.claude-plugin/plugin.json +2 -3
- package/plugins/claude/hooks/hooks.json +11 -1
- package/plugins/codex/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/hooks/hooks.json +11 -23
- package/plugins/opencode/index.ts +91 -23
- package/plugins/opencode-shared/delivery.ts +91 -0
- package/plugins/opencode-v1/index.ts +36 -0
- package/plugins/opencode-v1/runtime.ts +134 -0
- package/plugins/opencode-v1/transport.ts +41 -0
- package/plugins/paseo/OVERVIEW.md +5 -5
- package/plugins/paseo/README.md +7 -6
- package/plugins/paseo/client/markdown.tsx +5 -5
- package/plugins/paseo/client/square-message.tsx +28 -24
- package/plugins/paseo/client/transform.ts +8 -5
- package/plugins/paseo/shared/card-presentation.ts +16 -0
- package/plugins/paseo/shared/message.ts +6 -11
- package/plugins/pi/square-pi.js +156 -417
- package/dist/channel-artifact.d.ts +0 -10
- package/dist/channel-artifact.js +0 -55
- package/dist/channel-delivery.d.ts +0 -11
- package/dist/channel-delivery.js +0 -51
- package/dist/channel-domain.d.ts +0 -3
- package/dist/channel-domain.js +0 -83
- package/dist/channel-facade.d.ts +0 -76
- package/dist/channel-facade.js +0 -1
- package/dist/channel-internal.d.ts +0 -126
- package/dist/channel-internal.js +0 -440
- package/dist/channel-metadata.d.ts +0 -11
- package/dist/channel-metadata.js +0 -1
- package/dist/channel-ports.d.ts +0 -241
- package/dist/channel-ports.js +0 -1
- package/dist/channel-presentation.d.ts +0 -17
- package/dist/channel-presentation.js +0 -22
- package/dist/channel-sqlite-schema.d.ts +0 -13
- package/dist/channel-sqlite-schema.js +0 -81
- package/dist/channel-transport.d.ts +0 -62
- package/dist/channel-transport.js +0 -1
- package/dist/channel.d.ts +0 -84
- package/dist/channel.js +0 -60
- package/dist/claude-delivery-status.d.ts +0 -13
- package/dist/claude-delivery-status.js +0 -46
- package/dist/claude-delivery.d.ts +0 -12
- package/dist/claude-delivery.js +0 -108
- package/dist/claude-mod.d.ts +0 -8
- package/dist/claude-mod.js +0 -172
- package/dist/claude-transport.d.ts +0 -5
- package/dist/claude-transport.js +0 -58
- package/dist/cmd/notify-once.d.ts +0 -2
- package/dist/cmd/notify-once.js +0 -29
- package/dist/delivery-attempts.d.ts +0 -52
- package/dist/delivery-attempts.js +0 -73
- package/dist/delivery-effects.d.ts +0 -139
- package/dist/delivery-effects.js +0 -163
- package/dist/delivery-health.d.ts +0 -51
- package/dist/delivery-health.js +0 -173
- package/dist/delivery-operations.d.ts +0 -22
- package/dist/delivery-operations.js +0 -198
- package/dist/delivery-primitives.d.ts +0 -5
- package/dist/delivery-primitives.js +0 -3
- package/dist/delivery.d.ts +0 -56
- package/dist/delivery.js +0 -80
- package/dist/plugins/opencode/delivery.d.ts +0 -19
- package/dist/plugins/opencode/delivery.js +0 -223
- package/dist/presentation-operations.d.ts +0 -5
- package/dist/presentation-operations.js +0 -86
- package/dist/sqlite-channel.d.ts +0 -15
- package/dist/sqlite-channel.js +0 -600
- package/dist/square-index.d.ts +0 -16
- package/dist/square-index.js +0 -106
- package/dist/wake-preview.d.ts +0 -7
- package/dist/wake-preview.js +0 -15
- package/plugins/claude/hooks/register.js +0 -132
- package/plugins/claude/types.d.ts +0 -7
- package/plugins/opencode/delivery.ts +0 -198
- /package/dist/{channel-values.d.ts → square-values.d.ts} +0 -0
- /package/dist/{channel-values.js → square-values.js} +0 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { DeliveryLedger, deliveryLedgerLocation } from './delivery-ledger.js';
|
|
3
|
+
import { claudeBoundaryStore } from './claude-boundary-state.js';
|
|
4
|
+
import { harnessOwner } from './owner.js';
|
|
5
|
+
import { attachDeliverySessionRoutes, detachDeliverySession } from './session-lifecycle.js';
|
|
6
|
+
import { presentPendingAtBoundary } from './boundary-presentation.js';
|
|
7
|
+
import { renderDeliveryReminder } from './delivery-frame.js';
|
|
8
|
+
import { beginClaudeMcpCall, endClaudeMcpCallForSession } from './claude-mcp-context.js';
|
|
9
|
+
import { retainDeliveryLedger } from './delivery-lifetime.js';
|
|
10
|
+
import { z } from 'zod/v4';
|
|
11
|
+
const nativeId = z.string().min(1).max(4096).regex(/^[^\x00-\x1f\x7f]+$/u);
|
|
12
|
+
const hookInput = z.object({
|
|
13
|
+
hook_event_name: nativeId, session_id: nativeId, cwd: z.string().optional(),
|
|
14
|
+
prompt_id: nativeId.optional().catch(undefined), prompt: z.string().optional(),
|
|
15
|
+
tool_use_id: nativeId.optional().catch(undefined), tool_name: z.string().optional(), agent_id: nativeId.optional(),
|
|
16
|
+
});
|
|
17
|
+
const route = 'claude-async-hook';
|
|
18
|
+
const ownerFor = (input) => harnessOwner({ channel: 'claude-code', session: input.session_id });
|
|
19
|
+
function parseInput(text) {
|
|
20
|
+
try {
|
|
21
|
+
const value = hookInput.safeParse(JSON.parse(text));
|
|
22
|
+
return value.success ? value.data : undefined;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function observedFrames(prompt) {
|
|
29
|
+
const prefix = renderDeliveryReminder([''], { tagged: false });
|
|
30
|
+
const result = [];
|
|
31
|
+
for (const match of prompt.matchAll(/\[square-delivery:([a-f0-9-]+)\]\n[\s\S]*?\n\[\/square-delivery:\1\]/g)) {
|
|
32
|
+
const start = match.index - prefix.length;
|
|
33
|
+
if (start < 0 || prompt.slice(start, match.index) !== prefix)
|
|
34
|
+
continue;
|
|
35
|
+
result.push({ token: match[1], payloadHash: createHash('sha256').update(prefix + match[0]).digest('hex') });
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
function claudeFrame(card, token) {
|
|
40
|
+
return renderDeliveryReminder([`[square-delivery:${token}]\n${card.text}\n[/square-delivery:${token}]`], { tagged: false });
|
|
41
|
+
}
|
|
42
|
+
export async function runClaudeHook(text, env = process.env, sink = value => { process.stdout.write(value); }) {
|
|
43
|
+
const input = parseInput(text);
|
|
44
|
+
if (!input) {
|
|
45
|
+
let raw;
|
|
46
|
+
try {
|
|
47
|
+
raw = JSON.parse(text);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
if (raw?.hook_event_name === 'PreToolUse' && typeof raw.tool_name === 'string' && raw.tool_name.startsWith('mcp__plugin_square_square__'))
|
|
53
|
+
await denyMcpTool(sink);
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
const boundaries = claudeBoundaryStore(input.session_id, env);
|
|
57
|
+
const mainOwner = ownerFor(input);
|
|
58
|
+
const owner = harnessOwner({ channel: 'claude-code', session: input.session_id, ...(input.agent_id === undefined ? {} : { agent: input.agent_id }) });
|
|
59
|
+
if (input.hook_event_name === 'SessionStart') {
|
|
60
|
+
await boundaries.start(async () => {
|
|
61
|
+
const session = await attachDeliverySessionRoutes(mainOwner, env, [{ kind: route, address: { sessionId: input.session_id } }], AbortSignal.timeout(4500));
|
|
62
|
+
if (!session)
|
|
63
|
+
return false;
|
|
64
|
+
const ledger = await DeliveryLedger.open({ location: deliveryLedgerLocation(env) });
|
|
65
|
+
try {
|
|
66
|
+
await ledger.updateRoutes({ owner: mainOwner, generation: session.generation, routes: session.routes.filter(item => item.kind !== 'claude-native') });
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await ledger.close();
|
|
70
|
+
}
|
|
71
|
+
return session.generation;
|
|
72
|
+
});
|
|
73
|
+
return '';
|
|
74
|
+
}
|
|
75
|
+
if (input.hook_event_name === 'SessionEnd') {
|
|
76
|
+
const captured = await boundaries.end();
|
|
77
|
+
if (captured)
|
|
78
|
+
await detachDeliverySession(mainOwner, captured.generation, env);
|
|
79
|
+
return '';
|
|
80
|
+
}
|
|
81
|
+
if (input.hook_event_name === 'UserPromptSubmit') {
|
|
82
|
+
await boundaries.prompt(input.prompt_id);
|
|
83
|
+
if (!input.prompt_id)
|
|
84
|
+
return '';
|
|
85
|
+
if (input.prompt) {
|
|
86
|
+
const ledger = await DeliveryLedger.open({ location: deliveryLedgerLocation(env) });
|
|
87
|
+
try {
|
|
88
|
+
for (const frame of observedFrames(input.prompt)) {
|
|
89
|
+
const handoff = await ledger.handoff(frame.token);
|
|
90
|
+
if (!handoff || handoff.owner !== owner || handoff.routeKind !== route || handoff.payloadHash !== frame.payloadHash)
|
|
91
|
+
continue;
|
|
92
|
+
await ledger.observePresentation(handoff);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
await ledger.close();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
await presentPendingAtBoundary(owner, async (context) => {
|
|
100
|
+
await sink(`${JSON.stringify({ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext: context } })}\n`);
|
|
101
|
+
}, env, AbortSignal.timeout(4500));
|
|
102
|
+
return '';
|
|
103
|
+
}
|
|
104
|
+
if (input.hook_event_name === 'PreToolUse' && input.tool_name?.startsWith('mcp__plugin_square_square__')) {
|
|
105
|
+
if (!input.tool_use_id || !input.cwd) {
|
|
106
|
+
await denyMcpTool(sink);
|
|
107
|
+
return '';
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
await beginClaudeMcpCall({ toolUseId: input.tool_use_id, sessionId: input.session_id, cwd: input.cwd, agentId: input.agent_id }, env);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
await denyMcpTool(sink);
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if ((input.hook_event_name === 'PostToolUse' || input.hook_event_name === 'PostToolUseFailure')
|
|
118
|
+
&& input.tool_name?.startsWith('mcp__plugin_square_square__') && input.tool_use_id) {
|
|
119
|
+
await endClaudeMcpCallForSession(input.tool_use_id, input.session_id, env, input.agent_id).catch(() => undefined);
|
|
120
|
+
}
|
|
121
|
+
if (['PreToolUse', 'PostToolUse', 'PostToolUseFailure'].includes(input.hook_event_name)) {
|
|
122
|
+
await presentPendingAtBoundary(owner, async (context) => {
|
|
123
|
+
await sink(`${JSON.stringify({ hookSpecificOutput: { hookEventName: input.hook_event_name, additionalContext: context } })}\n`);
|
|
124
|
+
}, env, AbortSignal.timeout(4500));
|
|
125
|
+
}
|
|
126
|
+
return '';
|
|
127
|
+
}
|
|
128
|
+
async function denyMcpTool(sink) {
|
|
129
|
+
try {
|
|
130
|
+
await sink(`${JSON.stringify({ hookSpecificOutput: {
|
|
131
|
+
hookEventName: 'PreToolUse', permissionDecision: 'deny',
|
|
132
|
+
permissionDecisionReason: 'Square MCP call identity is unavailable; this call did not run.',
|
|
133
|
+
} })}\n`);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
process.exitCode = 2;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export async function runClaudeWatch(text, env = process.env, signal, output = frame => new Promise((resolve, reject) => {
|
|
140
|
+
process.stderr.write(frame, error => error ? reject(error) : resolve());
|
|
141
|
+
})) {
|
|
142
|
+
const input = parseInput(text);
|
|
143
|
+
if (!input || input.hook_event_name !== 'Stop' || !input.prompt_id)
|
|
144
|
+
return '';
|
|
145
|
+
const owner = ownerFor(input);
|
|
146
|
+
const boundaries = claudeBoundaryStore(input.session_id, env);
|
|
147
|
+
const controller = new AbortController();
|
|
148
|
+
const timer = setTimeout(() => controller.abort(), 86_400_000);
|
|
149
|
+
const stop = () => controller.abort();
|
|
150
|
+
process.once('SIGTERM', stop);
|
|
151
|
+
process.once('SIGINT', stop);
|
|
152
|
+
const combined = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;
|
|
153
|
+
try {
|
|
154
|
+
const captured = await boundaries.capture(input.prompt_id);
|
|
155
|
+
if (!captured)
|
|
156
|
+
return '';
|
|
157
|
+
await boundaries.watch(combined, async () => {
|
|
158
|
+
if (!await boundaries.current(captured))
|
|
159
|
+
return;
|
|
160
|
+
const ledger = await DeliveryLedger.open({ location: deliveryLedgerLocation(env) });
|
|
161
|
+
const lifetime = retainDeliveryLedger(ledger);
|
|
162
|
+
const observer = await ledger.observe(owner);
|
|
163
|
+
try {
|
|
164
|
+
while (!combined.aborted) {
|
|
165
|
+
let version = await observer.read(combined);
|
|
166
|
+
const live = await boundaries.current(captured);
|
|
167
|
+
const session = await ledger.session(owner);
|
|
168
|
+
if (!live || session?.state !== 'attached' || session.generation !== captured.generation || !session.routes.some(item => item.kind === route))
|
|
169
|
+
return;
|
|
170
|
+
const cards = await ledger.pending(owner, { generation: captured.generation });
|
|
171
|
+
const held = new Set((await ledger.handoffs(owner, { generation: captured.generation }))
|
|
172
|
+
.filter(attempt => !['failed', 'released'].includes(attempt.outcome)).map(attempt => attempt.seq));
|
|
173
|
+
for (const card of cards) {
|
|
174
|
+
if (held.has(card.seq))
|
|
175
|
+
continue;
|
|
176
|
+
const transport = {
|
|
177
|
+
kind: route,
|
|
178
|
+
async send(deliveryCard, address, context) {
|
|
179
|
+
if (address.sessionId !== input.session_id)
|
|
180
|
+
return 'not-capable';
|
|
181
|
+
const frame = claudeFrame(deliveryCard, context.token);
|
|
182
|
+
const payloadHash = createHash('sha256').update(frame).digest('hex');
|
|
183
|
+
if (!await context.prepare({ token: context.token, messageId: context.token, payloadHash }))
|
|
184
|
+
return 'not-capable';
|
|
185
|
+
const currentSession = await ledger.session(owner);
|
|
186
|
+
if (currentSession?.state !== 'attached' || currentSession.generation !== captured.generation
|
|
187
|
+
|| !currentSession.routes.some(item => item.kind === route) || !await context.beforeSend())
|
|
188
|
+
return 'not-capable';
|
|
189
|
+
const native = await boundaries.current(captured);
|
|
190
|
+
if (!native || context.signal.aborted || Date.now() >= context.deadline)
|
|
191
|
+
return 'not-capable';
|
|
192
|
+
try {
|
|
193
|
+
await output(frame);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
await boundaries.consume(captured);
|
|
197
|
+
}
|
|
198
|
+
process.exitCode = 2;
|
|
199
|
+
return 'unknown';
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
const result = await ledger.dispatchHandoff(owner, card.key, transport, {
|
|
203
|
+
generation: captured.generation, timeoutMs: 5000, signal: combined,
|
|
204
|
+
});
|
|
205
|
+
lifetime.track(result);
|
|
206
|
+
if (result.outcome === 'unknown' || result.outcome === 'accepted' || result.outcome === 'presented')
|
|
207
|
+
return;
|
|
208
|
+
// Drain our own unsuccessful claim/settlement edge before waiting;
|
|
209
|
+
// a not-capable route must not make filesystem hints a retry loop.
|
|
210
|
+
version = await observer.read(combined);
|
|
211
|
+
}
|
|
212
|
+
await observer.changed(version, 1000, combined);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
finally {
|
|
216
|
+
observer.close();
|
|
217
|
+
await lifetime.close();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
catch {
|
|
222
|
+
if (!combined.aborted)
|
|
223
|
+
return '';
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
clearTimeout(timer);
|
|
227
|
+
process.off('SIGTERM', stop);
|
|
228
|
+
process.off('SIGINT', stop);
|
|
229
|
+
}
|
|
230
|
+
return '';
|
|
231
|
+
}
|
|
@@ -10,6 +10,6 @@ export declare function beginClaudeMcpCall(input: ClaudeMcpCall, env?: NodeJS.Pr
|
|
|
10
10
|
token: string;
|
|
11
11
|
}>;
|
|
12
12
|
export declare function endClaudeMcpCall(toolUseId: string, token: string, env?: NodeJS.ProcessEnv): Promise<void>;
|
|
13
|
-
|
|
13
|
+
export declare function endClaudeMcpCallForSession(toolUseId: string, sessionId: string, env?: NodeJS.ProcessEnv, agentId?: string): Promise<void>;
|
|
14
14
|
export declare function readClaudeMcpCall(toolUseId: unknown, env?: NodeJS.ProcessEnv): Promise<ClaudeMcpCall>;
|
|
15
15
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
2
|
import { promises as fs } from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { deliveryLedgerLocation } from './delivery-ledger.js';
|
|
4
5
|
import { z } from 'zod/v4';
|
|
5
6
|
import { withFileLock } from './file-lock.js';
|
|
6
|
-
import { squareIndexPath } from './square-index.js';
|
|
7
7
|
import { SquareError } from './model.js';
|
|
8
8
|
const LEASE_MS = 10 * 60 * 1000;
|
|
9
9
|
const text = z.string().max(4096).refine(value => value.trim().length > 0 && !/[\x00-\x1f\x7f]/u.test(value));
|
|
@@ -12,7 +12,7 @@ const coordinate = z.object({
|
|
|
12
12
|
});
|
|
13
13
|
const record = coordinate.extend({ token: z.string().regex(/^[a-f0-9]{64}$/u), expiresAt: z.number() });
|
|
14
14
|
const unavailable = () => new SquareError('unavailable', 'Claude MCP call context unavailable');
|
|
15
|
-
const storeRoot = (env) => path.join(path.dirname(
|
|
15
|
+
const storeRoot = (env) => path.join(path.dirname(deliveryLedgerLocation(env)), 'claude-mcp-calls');
|
|
16
16
|
const callFile = (root, id) => path.join(root, `${createHash('sha256').update(id).digest('hex')}.json`);
|
|
17
17
|
async function readRecord(file) {
|
|
18
18
|
try {
|
|
@@ -71,7 +71,16 @@ export async function endClaudeMcpCall(toolUseId, token, env = process.env) {
|
|
|
71
71
|
await fs.unlink(file);
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
|
|
74
|
+
export async function endClaudeMcpCallForSession(toolUseId, sessionId, env = process.env, agentId) {
|
|
75
|
+
if (!text.safeParse(toolUseId).success || !text.safeParse(sessionId).success)
|
|
76
|
+
throw unavailable();
|
|
77
|
+
await mutate(env, async (root) => {
|
|
78
|
+
const file = callFile(root, toolUseId);
|
|
79
|
+
const stored = await readRecord(file);
|
|
80
|
+
if (stored?.toolUseId === toolUseId && stored.sessionId === sessionId && stored.agentId === agentId)
|
|
81
|
+
await fs.unlink(file);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
75
84
|
export async function readClaudeMcpCall(toolUseId, env = process.env) {
|
|
76
85
|
if (!text.safeParse(toolUseId).success)
|
|
77
86
|
throw unavailable();
|
package/dist/cli/context.js
CHANGED
|
@@ -150,22 +150,20 @@ export function squareInput(context) {
|
|
|
150
150
|
export function commandIdentity(env, explicit) {
|
|
151
151
|
if (explicit !== undefined)
|
|
152
152
|
return { owner: explicit };
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return { owner: configured };
|
|
156
|
-
const selected = harnessSessionSources.flatMap(({ variable, channel }) => env[variable]?.trim() ? [{ channel, session: env[variable].trim() }] : []);
|
|
157
|
-
const native = selected.filter(source => source.channel !== 'paseo');
|
|
153
|
+
if (env.SQUARE_OWNER !== undefined)
|
|
154
|
+
return { owner: env.SQUARE_OWNER };
|
|
158
155
|
if (env.CLAUDE_CODE_CHILD_SESSION === '1')
|
|
159
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');
|
|
160
159
|
if (native.length > 1)
|
|
161
160
|
throw new Error('Multiple harness execution coordinates are present; select one explicit owner.');
|
|
162
|
-
const
|
|
163
|
-
const coordinate = native[0] ?? paseo;
|
|
161
|
+
const coordinate = native[0] ?? selected[0];
|
|
164
162
|
if (coordinate === undefined)
|
|
165
163
|
return { owner: localUserOwner() };
|
|
166
164
|
const owner = harnessOwner({ channel: coordinate.channel, session: coordinate.session });
|
|
167
|
-
const wakeAddress = coordinate.channel === 'codex' ? codexWakeAddress(coordinate.session, env)
|
|
168
|
-
:
|
|
165
|
+
const wakeAddress = coordinate.channel === 'codex' ? { ...codexWakeAddress(coordinate.session, env), kind: 'codex-queue' }
|
|
166
|
+
: coordinate.channel === 'paseo' ? { kind: 'paseo', address: { agentId: coordinate.session } } : undefined;
|
|
169
167
|
return { owner, ...(wakeAddress === undefined ? {} : { wakeAddress }) };
|
|
170
168
|
}
|
|
171
169
|
/** Adapter lifetime only; each callback uses the actual public resource API. */
|
|
@@ -25,6 +25,9 @@ interface InboxIntent {
|
|
|
25
25
|
limit: number;
|
|
26
26
|
}
|
|
27
27
|
export declare const inboxCommand: CommandSpec<InboxIntent, string>;
|
|
28
|
-
export declare const
|
|
28
|
+
export declare const claudeHookCommand: CommandSpec<undefined, string>;
|
|
29
|
+
export declare const claudeWatchCommand: CommandSpec<undefined, string>;
|
|
29
30
|
export declare const codexHookCommand: CommandSpec<undefined, string>;
|
|
31
|
+
export declare const codexWatchCommand: CommandSpec<undefined, string>;
|
|
32
|
+
export declare const codexInterruptCommand: CommandSpec<undefined, string>;
|
|
30
33
|
export {};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { once } from 'node:events';
|
|
3
|
-
import {
|
|
4
|
-
import { runCodexHook } from '../codex-hook.js';
|
|
3
|
+
import { runClaudeHook, runClaudeWatch } from '../claude-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';
|
|
@@ -525,5 +526,37 @@ function hookCommand(runHook) {
|
|
|
525
526
|
present: (result) => process.stdout.write(result),
|
|
526
527
|
};
|
|
527
528
|
}
|
|
528
|
-
export const
|
|
529
|
-
|
|
529
|
+
export const claudeHookCommand = {
|
|
530
|
+
parse(argv, context) { if (argv.length > 0)
|
|
531
|
+
usage(context.command); return undefined; },
|
|
532
|
+
execute: async () => {
|
|
533
|
+
try {
|
|
534
|
+
return await runClaudeHook(await readStdin(), process.env, text => new Promise((resolve, reject) => {
|
|
535
|
+
process.stdout.write(text, error => { if (error)
|
|
536
|
+
reject(error);
|
|
537
|
+
else
|
|
538
|
+
resolve(); });
|
|
539
|
+
}));
|
|
540
|
+
}
|
|
541
|
+
catch {
|
|
542
|
+
return '';
|
|
543
|
+
}
|
|
544
|
+
},
|
|
545
|
+
present: () => { },
|
|
546
|
+
};
|
|
547
|
+
export const claudeWatchCommand = {
|
|
548
|
+
parse(argv, context) { if (argv.length > 0)
|
|
549
|
+
usage(context.command); return undefined; },
|
|
550
|
+
execute: async () => runClaudeWatch(await readStdin(), process.env),
|
|
551
|
+
present: () => { },
|
|
552
|
+
};
|
|
553
|
+
export const codexHookCommand = {
|
|
554
|
+
parse(argv, context) { if (argv.length > 0)
|
|
555
|
+
usage(context.command); return undefined; },
|
|
556
|
+
execute: async () => runCodexHook(await readStdin(), process.env, text => new Promise((resolve, reject) => {
|
|
557
|
+
process.stdout.write(text, error => error ? reject(error) : resolve());
|
|
558
|
+
})),
|
|
559
|
+
present: () => { },
|
|
560
|
+
};
|
|
561
|
+
export const codexWatchCommand = hookCommand(input => runCodexWatch(input, process.env));
|
|
562
|
+
export const codexInterruptCommand = hookCommand(input => runCodexInterrupt(input, process.env));
|
package/dist/cli/registry.js
CHANGED
|
@@ -4,7 +4,7 @@ import { harnessCommand, installCommand, uninstallCommand } from './harness-comm
|
|
|
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,
|
|
7
|
+
import { catchCommand, claudeHookCommand, claudeWatchCommand, 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 },
|
|
@@ -12,8 +12,11 @@ export const commandRegistry = [
|
|
|
12
12
|
{ names: ['join'], spec: joinCommand },
|
|
13
13
|
{ names: ['stream'], spec: streamCommand },
|
|
14
14
|
{ names: ['inbox'], spec: inboxCommand },
|
|
15
|
-
{ names: ['claude-
|
|
15
|
+
{ names: ['claude-hook'], spec: claudeHookCommand },
|
|
16
|
+
{ names: ['claude-watch'], spec: claudeWatchCommand },
|
|
16
17
|
{ names: ['codex-hook'], spec: codexHookCommand },
|
|
18
|
+
{ names: ['codex-watch'], spec: codexWatchCommand },
|
|
19
|
+
{ names: ['codex-interrupt'], spec: codexInterruptCommand },
|
|
17
20
|
{ names: ['catch'], spec: catchCommand },
|
|
18
21
|
{ names: ['express'], spec: expressCommand },
|
|
19
22
|
{ names: ['listen'], spec: listenCommand },
|
package/dist/codex-address.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
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):
|
|
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);
|
package/dist/codex-hook.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import { type
|
|
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
|
-
|
|
12
|
-
export declare function
|
|
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>;
|
package/dist/codex-hook.js
CHANGED
|
@@ -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 {
|
|
3
|
+
import { DeliveryLedger } from './delivery-ledger.js';
|
|
4
4
|
import { harnessOwner } from './owner.js';
|
|
5
|
-
import {
|
|
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 =
|
|
11
|
-
|
|
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
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
boundaries: codexBoundaryStore(env),
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
38
|
-
let input;
|
|
61
|
+
export function parseCodexHookText(text) {
|
|
39
62
|
try {
|
|
40
|
-
|
|
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
|
-
|
|
46
|
-
return '';
|
|
47
|
-
const result = await codexHookResponse(input, sessionInbox, env);
|
|
48
|
-
return result === undefined ? '' : `${JSON.stringify(result)}\n`;
|
|
84
|
+
return '';
|
|
49
85
|
}
|
package/dist/codex-queue.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
|
|
3
|
-
export type { CodexQueueRequest, CodexQueueFailureKind } from './packages/agent-delivery/src/codex-queue.js';
|
|
4
|
-
import type { WakeRequest, WakeOutcome, WakeTransportPort } from './channel-transport.js';
|
|
5
|
-
import type { WakeRoute } from './channel-values.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
|
-
|
|
8
|
-
|
|
4
|
+
readonly epoch: CodexStopEpoch;
|
|
5
|
+
readonly address: Readonly<Record<string, string>>;
|
|
6
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
9
7
|
}
|
|
10
|
-
|
|
8
|
+
/** Instantiated only by the receiver, for one captured Stop epoch. */
|
|
9
|
+
export declare class CodexQueueTransport implements DeliveryTransport {
|
|
11
10
|
private readonly opts;
|
|
12
|
-
|
|
13
|
-
|
|
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 };
|