@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.
- package/dist/activity-feed.js +1 -1
- package/dist/artifact-store.d.ts +41 -0
- package/dist/artifact-store.js +272 -0
- package/dist/artifact.d.ts +6 -12
- package/dist/artifact.js +43 -344
- package/dist/attention-presentation.d.ts +13 -7
- package/dist/attention-presentation.js +29 -68
- package/dist/boundary-presentation.d.ts +3 -16
- package/dist/boundary-presentation.js +29 -109
- package/dist/card-presentation.d.ts +1 -0
- package/dist/card-presentation.js +2 -0
- package/dist/catch-decisions.d.ts +2 -2
- package/dist/catch-decisions.js +7 -3
- package/dist/catch-selection.d.ts +8 -0
- package/dist/catch-selection.js +5 -0
- package/dist/claude-delivery.d.ts +14 -12
- package/dist/claude-delivery.js +42 -142
- package/dist/claude-mcp-context.js +2 -2
- package/dist/claude-mod.js +28 -140
- package/dist/claude-transport.d.ts +5 -0
- package/dist/claude-transport.js +34 -0
- package/dist/cli/context.d.ts +2 -2
- package/dist/cli/context.js +7 -10
- package/dist/cli/maintenance-commands.d.ts +0 -4
- package/dist/cli/maintenance-commands.js +2 -29
- package/dist/cli/observation-commands.d.ts +2 -0
- package/dist/cli/observation-commands.js +12 -2
- package/dist/cli/program.js +1 -1
- package/dist/cli/registry.js +4 -3
- 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 -34
- package/dist/codex-watch.d.ts +2 -0
- package/dist/codex-watch.js +100 -0
- package/dist/decisions.js +3 -3
- package/dist/delivery-deferral.d.ts +1 -19
- package/dist/delivery-deferral.js +1 -29
- 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-links.js +61 -7
- package/dist/harness.js +12 -17
- package/dist/help.js +3 -6
- package/dist/http-delivery.d.ts +5 -9
- package/dist/http-delivery.js +20 -79
- package/dist/inbox.d.ts +6 -57
- package/dist/inbox.js +24 -380
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -2
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.js +40 -70
- package/dist/message.d.ts +7 -0
- package/dist/message.js +23 -0
- package/dist/model.d.ts +15 -91
- package/dist/model.js +2 -140
- package/dist/neutral.d.ts +72 -0
- package/dist/neutral.js +27 -0
- package/dist/notifications.d.ts +24 -26
- package/dist/notifications.js +39 -143
- package/dist/operation-control.d.ts +4 -0
- package/dist/operation-control.js +20 -0
- package/dist/operation-presentation.d.ts +1 -2
- package/dist/operation-presentation.js +1 -7
- package/dist/owner.d.ts +2 -2
- package/dist/owner.js +1 -1
- 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 -99
- 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 +33 -214
- package/dist/presentation.d.ts +5 -5
- package/dist/presentation.js +1 -0
- package/dist/runtime.js +2 -2
- package/dist/search.js +1 -1
- package/dist/session-lifecycle.d.ts +8 -7
- package/dist/session-lifecycle.js +40 -42
- package/dist/sqlite-framing.d.ts +8 -0
- package/dist/sqlite-framing.js +31 -0
- package/dist/sqlite-square.d.ts +16 -26
- package/dist/sqlite-square.js +199 -262
- package/dist/sqlite-values.d.ts +21 -0
- package/dist/sqlite-values.js +78 -0
- package/dist/square-api.d.ts +1 -1
- package/dist/square-api.js +5 -8
- package/dist/square-core.d.ts +0 -1
- package/dist/square-domain.d.ts +12 -10
- package/dist/square-domain.js +105 -223
- package/dist/square-facade.d.ts +25 -76
- package/dist/square-location.d.ts +6 -1
- package/dist/square-location.js +1 -1
- 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-receive.d.ts +2 -3
- package/dist/square-sqlite.d.ts +33 -42
- package/dist/square-sqlite.js +236 -768
- package/dist/square-tools.d.ts +8 -0
- package/dist/square-tools.js +39 -0
- package/dist/square-values.d.ts +27 -0
- package/dist/square-values.js +90 -0
- package/dist/views.d.ts +6 -6
- package/dist/views.js +14 -9
- package/dist/wake-sink.d.ts +4 -11
- package/dist/wake-sink.js +8 -32
- package/dist/wake-transports.d.ts +4 -0
- package/dist/wake-transports.js +11 -0
- package/examples/symmetric-domains.mjs +29 -249
- package/guides/change-waits.md +13 -53
- package/guides/claude-native.md +19 -172
- package/guides/codex-delivery.md +55 -78
- package/guides/delivery-primitives.md +48 -207
- 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/row-runtime-delivery-evidence.md +2 -0
- package/guides/row-storage-design.md +19 -44
- package/guides/square-api.md +113 -538
- package/package.json +8 -8
- package/plugins/claude/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/hooks/hooks.json +1 -1
- package/plugins/claude/{hooks/register.js → mods/square.js} +4 -7
- package/plugins/claude/types.d.ts +1 -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 +167 -451
- package/dist/channel.d.ts +0 -74
- package/dist/channel.js +0 -92
- package/dist/claude-delivery-status.d.ts +0 -13
- package/dist/claude-delivery-status.js +0 -46
- 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 -9
- package/dist/delivery-operations.js +0 -168
- package/dist/delivery-primitives.d.ts +0 -5
- package/dist/delivery-primitives.js +0 -3
- package/dist/delivery.d.ts +0 -45
- package/dist/delivery.js +0 -106
- package/dist/plugins/opencode/delivery.d.ts +0 -19
- package/dist/plugins/opencode/delivery.js +0 -238
- package/dist/presentation-operations.d.ts +0 -18
- package/dist/presentation-operations.js +0 -86
- package/dist/square-index.d.ts +0 -16
- package/dist/square-index.js +0 -106
- package/dist/square-legacy-framing.d.ts +0 -11
- package/dist/square-legacy-framing.js +0 -64
- package/dist/square-migration-host-ledger.d.ts +0 -26
- package/dist/square-migration-host-ledger.js +0 -169
- package/dist/square-migration.d.ts +0 -30
- package/dist/square-migration.js +0 -599
- package/guides/migration.md +0 -156
- package/plugins/opencode/delivery.ts +0 -211
package/dist/claude-mod.js
CHANGED
|
@@ -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 {
|
|
10
|
-
import {
|
|
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
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
|
32
|
+
await ledger.close();
|
|
64
33
|
}
|
|
65
|
-
if (signal.aborted)
|
|
66
|
-
break;
|
|
67
34
|
}
|
|
68
|
-
return `${JSON.stringify({
|
|
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
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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 === '
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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
|
+
}
|
package/dist/cli/context.d.ts
CHANGED
|
@@ -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?:
|
|
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>;
|
package/dist/cli/context.js
CHANGED
|
@@ -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
|
-
|
|
155
|
-
|
|
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
|
|
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
|
-
:
|
|
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
|
|
2
|
-
import {
|
|
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 =
|
|
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));
|
package/dist/cli/program.js
CHANGED
|
@@ -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 =
|
|
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 });
|
package/dist/cli/registry.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { buildCommand, doneCommand, expressCommand, ignoreCommand, joinCommand, listenCommand, listeningCommand, unlistenCommand } from './square-commands.js';
|
|
2
|
-
import { doctorCommand
|
|
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 },
|
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 './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
|
-
|
|
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 };
|