@canonmsg/codex-plugin 0.29.1 → 0.29.3
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/codex-app-tools.js +8 -48
- package/dist/host.js +46 -114
- package/package.json +3 -3
package/dist/codex-app-tools.js
CHANGED
|
@@ -142,31 +142,6 @@ const CODEX_NO_REPLY_TOOL = tool(CODEX_NO_REPLY_TOOL_NAME, 'End your turn withou
|
|
|
142
142
|
},
|
|
143
143
|
}, false);
|
|
144
144
|
export const CODEX_APP_DYNAMIC_TOOLS = [
|
|
145
|
-
tool('automation_update', 'Create, update, view, or delete Codex app automations. Canon exposes the name for compatibility, but does not manage Desktop automations.', {
|
|
146
|
-
type: 'object',
|
|
147
|
-
additionalProperties: false,
|
|
148
|
-
properties: {
|
|
149
|
-
id: { type: 'string' },
|
|
150
|
-
mode: { type: 'string' },
|
|
151
|
-
kind: { type: 'string' },
|
|
152
|
-
name: { type: 'string' },
|
|
153
|
-
prompt: { type: 'string' },
|
|
154
|
-
rrule: { type: 'string' },
|
|
155
|
-
cwds: {
|
|
156
|
-
anyOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
|
|
157
|
-
},
|
|
158
|
-
destination: { type: 'string' },
|
|
159
|
-
executionEnvironment: { type: 'string' },
|
|
160
|
-
localEnvironmentConfigPath: { type: ['string', 'null'] },
|
|
161
|
-
model: { type: 'string' },
|
|
162
|
-
reasoningEffort: { type: 'string' },
|
|
163
|
-
targetThreadId: { type: 'string' },
|
|
164
|
-
status: { type: 'string' },
|
|
165
|
-
},
|
|
166
|
-
}),
|
|
167
|
-
tool('navigate_to_codex_page', 'Navigate the Codex Desktop UI. Canon exposes the name for compatibility, but has no Codex Desktop page to navigate.', { type: 'object', additionalProperties: true, properties: {} }),
|
|
168
|
-
tool('read_thread_terminal', 'Read the Codex Desktop terminal output for this thread. Canon exposes the name for compatibility, but has no Desktop terminal pane.', emptyObjectSchema, false),
|
|
169
|
-
tool('load_workspace_dependencies', 'Locate bundled Desktop workspace dependency runtimes. Canon exposes the name for compatibility, but does not provide Desktop bundle paths.', emptyObjectSchema, false),
|
|
170
145
|
tool('fork_thread', 'Fork a Codex thread. Omit threadId to fork the calling thread. Canon supports same-directory forks.', {
|
|
171
146
|
type: 'object',
|
|
172
147
|
additionalProperties: false,
|
|
@@ -175,17 +150,6 @@ export const CODEX_APP_DYNAMIC_TOOLS = [
|
|
|
175
150
|
environment: forkEnvironmentSchema,
|
|
176
151
|
},
|
|
177
152
|
}),
|
|
178
|
-
tool('handoff_thread', 'Move a Codex thread between a checkout and worktree. Canon exposes the name for compatibility, but does not manage Desktop handoffs.', {
|
|
179
|
-
type: 'object',
|
|
180
|
-
additionalProperties: false,
|
|
181
|
-
properties: { threadId: { type: 'string' } },
|
|
182
|
-
required: ['threadId'],
|
|
183
|
-
}),
|
|
184
|
-
tool('get_handoff_status', 'Read Codex Desktop handoff status. Canon exposes the name for compatibility, but does not manage Desktop handoffs.', {
|
|
185
|
-
type: 'object',
|
|
186
|
-
additionalProperties: false,
|
|
187
|
-
properties: { threadId: { type: 'string' } },
|
|
188
|
-
}),
|
|
189
153
|
tool('list_projects', 'List Canon workspaces available to Codex app tools.', emptyObjectSchema),
|
|
190
154
|
tool('create_thread', 'Create a separate Codex thread only when the user explicitly asks for a new or separate thread. Canon supports local project targets.', {
|
|
191
155
|
type: 'object',
|
|
@@ -224,15 +188,6 @@ export const CODEX_APP_DYNAMIC_TOOLS = [
|
|
|
224
188
|
},
|
|
225
189
|
required: ['threadId', 'prompt'],
|
|
226
190
|
}),
|
|
227
|
-
tool('set_thread_pinned', 'Pin or unpin a Codex thread. Canon exposes the name for compatibility, but pinned state is Desktop-only.', {
|
|
228
|
-
type: 'object',
|
|
229
|
-
additionalProperties: false,
|
|
230
|
-
properties: {
|
|
231
|
-
threadId: { type: 'string' },
|
|
232
|
-
pinned: { type: 'boolean' },
|
|
233
|
-
},
|
|
234
|
-
required: ['threadId', 'pinned'],
|
|
235
|
-
}),
|
|
236
191
|
tool('set_thread_archived', 'Archive or unarchive a Codex thread.', {
|
|
237
192
|
type: 'object',
|
|
238
193
|
additionalProperties: false,
|
|
@@ -278,7 +233,6 @@ export function filterCodexCommunicationTools(tools, outboundPolicy) {
|
|
|
278
233
|
*/
|
|
279
234
|
export const CODEX_DETACHED_THREAD_DYNAMIC_TOOLS = CODEX_APP_DYNAMIC_TOOLS.filter((entry) => (entry.name !== CANON_RUNTIME_CONTROL_TOOL_NAME
|
|
280
235
|
&& entry.name !== CODEX_NO_REPLY_TOOL_NAME));
|
|
281
|
-
const CODEX_APP_TOOL_NAMES = new Set(CODEX_APP_DYNAMIC_TOOLS.map((entry) => String(entry.name)));
|
|
282
236
|
const UNSUPPORTED_TOOLS = new Map([
|
|
283
237
|
['automation_update', 'Canon does not manage Codex Desktop automations.'],
|
|
284
238
|
['navigate_to_codex_page', 'Canon has no Codex Desktop page to navigate.'],
|
|
@@ -288,6 +242,12 @@ const UNSUPPORTED_TOOLS = new Map([
|
|
|
288
242
|
['get_handoff_status', 'Canon does not manage Codex Desktop handoffs.'],
|
|
289
243
|
['set_thread_pinned', 'Pinned thread state is Codex Desktop-only.'],
|
|
290
244
|
]);
|
|
245
|
+
// Historical calls must still reach their specific rejection, even though
|
|
246
|
+
// unsupported tools are no longer advertised to the model.
|
|
247
|
+
const RECOGNIZED_CODEX_APP_TOOL_NAMES = new Set([
|
|
248
|
+
...CODEX_APP_DYNAMIC_TOOLS.map((entry) => entry.name),
|
|
249
|
+
...UNSUPPORTED_TOOLS.keys(),
|
|
250
|
+
]);
|
|
291
251
|
export function isCodexAppToolCall(params) {
|
|
292
252
|
const namespace = typeof params.namespace === 'string' ? params.namespace : null;
|
|
293
253
|
const rawTool = typeof params.tool === 'string' ? params.tool.trim() : '';
|
|
@@ -296,7 +256,7 @@ export function isCodexAppToolCall(params) {
|
|
|
296
256
|
return rawTool.startsWith('codex_app.');
|
|
297
257
|
return namespace === 'codex_app'
|
|
298
258
|
|| rawTool.startsWith('codex_app.')
|
|
299
|
-
|| (toolName ?
|
|
259
|
+
|| (toolName ? RECOGNIZED_CODEX_APP_TOOL_NAMES.has(toolName) : false);
|
|
300
260
|
}
|
|
301
261
|
export function deniedCodexAppToolResult(reason) {
|
|
302
262
|
return toolResult(false, { error: reason });
|
|
@@ -397,7 +357,7 @@ export function classifyCodexAppToolRequest(input) {
|
|
|
397
357
|
}
|
|
398
358
|
export async function handleCodexAppToolCall(runtime, params) {
|
|
399
359
|
const toolName = normalizeToolName(params.tool);
|
|
400
|
-
if (!toolName || !
|
|
360
|
+
if (!toolName || !RECOGNIZED_CODEX_APP_TOOL_NAMES.has(toolName)) {
|
|
401
361
|
return toolResult(false, { error: `Unsupported codex_app tool: ${String(params.tool ?? 'unknown')}` });
|
|
402
362
|
}
|
|
403
363
|
if (toolName === CODEX_NO_REPLY_TOOL_NAME) {
|
package/dist/host.js
CHANGED
|
@@ -6,7 +6,7 @@ import { dirname } from 'node:path';
|
|
|
6
6
|
import { parseArgs } from 'node:util';
|
|
7
7
|
import { getCodexImagePath, materializeMessageMedia, materializeReplyContextMedia, sendMediaFileMessage, } from '@canonmsg/agent-sdk';
|
|
8
8
|
import { buildTrailBlockId, buildUndeliverableFinalNotice, captureTurnArtifactSnapshot, createTurnArtifactRouter, IDLE_TIMEOUT_MS, PLAN_BLOCK_TITLE, resolveTurnArtifactRouting, collectMissedInboundMessages, createRecoveryCheckpointTracker, createReconnectRecoveryCoordinator, STARTUP_RECOVERY_PAGE_SIZE, } from '@canonmsg/coding-agent-host';
|
|
9
|
-
import { RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, resolveQuestionAllowOther, buildCanonTurnContextV2, buildConfiguredWorkspaceOptionsWithRoots, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, buildCanonInboundFrameV1, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createRuntimeStatePublisher, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfileLock, decideAutoReply, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, markLocalRuntimeStopped, normalizeTurnMetadata, parseTurnVerbosityConfig, RuntimeRequestManager, prepareConversationEnvironment, releaseConversationEnvironment, resolveLocalRuntimeSessionState, resolveCanonAgent, verifyResolvedAgentEnvironment, CanonApiError, loadRuntimeSessionState, sendMessageWithRetry, sendMessageWithRetryChunked, saveRuntimeSessionState,
|
|
9
|
+
import { RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildRuntimeCardOutcome, resolveQuestionAllowOther, buildCanonTurnContextV2, buildConfiguredWorkspaceOptionsWithRoots, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, buildCanonInboundFrameV1, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createRuntimeStatePublisher, createRuntimeHeartbeat, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfileLock, decideAutoReply, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, markLocalRuntimeStopped, normalizeTurnMetadata, parseTurnVerbosityConfig, RuntimeRequestManager, prepareConversationEnvironment, releaseConversationEnvironment, resolveLocalRuntimeSessionState, resolveCanonAgent, verifyResolvedAgentEnvironment, CanonApiError, loadRuntimeSessionState, sendMessageWithRetry, sendMessageWithRetryChunked, saveRuntimeSessionState, publishHostSessionSnapshots, renderCanonHostInboundContent, renderCodingHostInboundPrompt, resolveConfiguredWorkspaceCwd, isSilentTurnSuppressed, resolveSilentTurnDelivery, resolveTurnVerbosity, shouldTriggerAgentTurn, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
10
10
|
import { validateCard } from '@canonmsg/rich-cards';
|
|
11
11
|
import { CodexConversationAdapter, } from './adapter.js';
|
|
12
12
|
import { CodexAppServerAdapter, } from './app-server-adapter.js';
|
|
@@ -253,9 +253,6 @@ export function buildCodexTurnResponseRouting(input) {
|
|
|
253
253
|
export function getCodexRequestingUserId(message) {
|
|
254
254
|
return message.senderType === 'human' ? message.senderId : null;
|
|
255
255
|
}
|
|
256
|
-
async function publishAgentRuntime(agentId, runtime, rtdb) {
|
|
257
|
-
await publishHostAgentRuntime(agentId, 'codex', runtime, rtdb);
|
|
258
|
-
}
|
|
259
256
|
export function resolveSessionExecutionMode(serviceAgentMode = false, defaultExecutionMode = 'worktree') {
|
|
260
257
|
if (serviceAgentMode)
|
|
261
258
|
return 'locked';
|
|
@@ -275,14 +272,6 @@ export function resolveWorkspaceCwd() {
|
|
|
275
272
|
defaultCwd: workingDir,
|
|
276
273
|
});
|
|
277
274
|
}
|
|
278
|
-
function resolveExecutionFallbackReason(environment) {
|
|
279
|
-
if (!environment?.reason || environment.mode !== 'locked') {
|
|
280
|
-
return null;
|
|
281
|
-
}
|
|
282
|
-
return environment.reason === 'Sharing the base workspace (locked mode)'
|
|
283
|
-
? null
|
|
284
|
-
: environment.reason;
|
|
285
|
-
}
|
|
286
275
|
function stringArg(args, key) {
|
|
287
276
|
const value = args[key];
|
|
288
277
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
@@ -813,9 +802,6 @@ export async function main() {
|
|
|
813
802
|
client,
|
|
814
803
|
conversationCache,
|
|
815
804
|
});
|
|
816
|
-
function resolveWorkspaceIdForBaseCwd(baseCwd) {
|
|
817
|
-
return workspaceOptions.find((option) => option.cwd === baseCwd)?.id;
|
|
818
|
-
}
|
|
819
805
|
async function refreshKnownConversationIds(force = false) {
|
|
820
806
|
if (!force && Date.now() - lastKnownConversationRefreshAt < HEARTBEAT_MS) {
|
|
821
807
|
return;
|
|
@@ -2022,7 +2008,7 @@ export async function main() {
|
|
|
2022
2008
|
return;
|
|
2023
2009
|
}
|
|
2024
2010
|
if (event.type === 'skills.changed') {
|
|
2025
|
-
void refreshCodexSkillInventory(true).then(() =>
|
|
2011
|
+
void refreshCodexSkillInventory(true).then(() => runtimeHeartbeat.refresh());
|
|
2026
2012
|
return;
|
|
2027
2013
|
}
|
|
2028
2014
|
if (event.type === 'settings.updated') {
|
|
@@ -2401,7 +2387,6 @@ export async function main() {
|
|
|
2401
2387
|
acceptedInboundMessageIds.delete(oldest);
|
|
2402
2388
|
}
|
|
2403
2389
|
}
|
|
2404
|
-
let streamConnected = false;
|
|
2405
2390
|
const hostAvailableExecutionModes = serviceAgentMode
|
|
2406
2391
|
? ['locked']
|
|
2407
2392
|
: [...EXECUTION_ENVIRONMENT_MODES];
|
|
@@ -2569,108 +2554,56 @@ export async function main() {
|
|
|
2569
2554
|
console.error(`[canon-codex] [${(error.conversationId ?? 'unknown').slice(0, 8)}] Control ${error.key ?? 'poll'} handler failed:`, error.error instanceof Error ? error.error.message : error.error);
|
|
2570
2555
|
},
|
|
2571
2556
|
});
|
|
2572
|
-
|
|
2573
|
-
const publishRuntimeHeartbeat = async () => {
|
|
2557
|
+
const publishLocalHeartbeat = () => {
|
|
2574
2558
|
heartbeatLocalRuntimeEntry(runtimeId, {
|
|
2575
2559
|
agentId,
|
|
2576
2560
|
agentName: profileAgentName,
|
|
2577
2561
|
cwd: workingDir,
|
|
2578
2562
|
baseCwd: workingDir,
|
|
2579
2563
|
});
|
|
2580
|
-
|
|
2564
|
+
};
|
|
2565
|
+
const refreshRuntimeDetails = async (signal) => {
|
|
2566
|
+
await refreshKnownConversationIds().catch((error) => {
|
|
2567
|
+
console.error('[canon-codex] Failed to refresh known conversations:', error);
|
|
2568
|
+
});
|
|
2569
|
+
if (signal.aborted)
|
|
2581
2570
|
return;
|
|
2582
|
-
await
|
|
2583
|
-
|
|
2571
|
+
await publishHostSessionSnapshots({
|
|
2572
|
+
conversationIds: Array.from(knownConversationIds),
|
|
2573
|
+
agentId,
|
|
2574
|
+
rtdb,
|
|
2575
|
+
clientType: 'codex',
|
|
2576
|
+
}).catch((error) => {
|
|
2577
|
+
console.error('[canon-codex] Failed to publish session snapshots:', error);
|
|
2584
2578
|
});
|
|
2585
|
-
if (
|
|
2579
|
+
if (signal.aborted)
|
|
2586
2580
|
return;
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
});
|
|
2600
|
-
await Promise.all(Array.from(knownConversationIds).map(async (conversationId) => {
|
|
2601
|
-
const session = sessions.get(conversationId);
|
|
2602
|
-
const workspaceId = session
|
|
2603
|
-
? resolveWorkspaceIdForBaseCwd(session.environment.baseCwd)
|
|
2604
|
-
: runtimeDescriptor.defaultWorkspaceId;
|
|
2605
|
-
const workspace = workspaceOptions.find((option) => option.id === workspaceId) ?? null;
|
|
2606
|
-
const descriptor = runtimeDescriptor.runtimeDescriptor;
|
|
2607
|
-
if (!descriptor)
|
|
2608
|
-
return;
|
|
2609
|
-
const payload = {
|
|
2610
|
-
descriptor,
|
|
2611
|
-
surfaceMode: 'host',
|
|
2612
|
-
// The exec --json transport cannot block on approvals — without a
|
|
2613
|
-
// strip-level warning a user can believe they have an approval
|
|
2614
|
-
// gate they do not have.
|
|
2615
|
-
...(useAppServer
|
|
2616
|
-
? {}
|
|
2617
|
-
: { warning: "Approvals can't block on this Codex CLI — update Codex to enable the app-server transport and approval gates." }),
|
|
2618
|
-
statusItems: [
|
|
2619
|
-
{
|
|
2620
|
-
id: 'transport',
|
|
2621
|
-
label: 'Transport',
|
|
2622
|
-
value: useAppServer ? 'app-server' : 'exec --json',
|
|
2623
|
-
},
|
|
2624
|
-
{
|
|
2625
|
-
id: 'streaming',
|
|
2626
|
-
label: 'Live output',
|
|
2627
|
-
value: useAppServer
|
|
2628
|
-
? 'Plans, questions, approvals, tools, and message deltas'
|
|
2629
|
-
: 'Thinking, tools, and completed-message previews',
|
|
2630
|
-
},
|
|
2631
|
-
{
|
|
2632
|
-
id: 'codex-cli',
|
|
2633
|
-
label: 'Codex CLI',
|
|
2634
|
-
value: codexCliStatus.version ?? (codexCliStatus.raw ?? 'Version unknown'),
|
|
2635
|
-
tone: codexCliStatus.version ? 'default' : 'warning',
|
|
2636
|
-
},
|
|
2637
|
-
{
|
|
2638
|
-
id: 'nativeActions',
|
|
2639
|
-
label: 'Native actions',
|
|
2640
|
-
value: useAppServer ? 'Enabled' : 'Limited until app-server transport',
|
|
2641
|
-
...(useAppServer ? {} : { tone: 'warning' }),
|
|
2642
|
-
},
|
|
2643
|
-
{
|
|
2644
|
-
id: 'mediaOut',
|
|
2645
|
-
label: 'Media out',
|
|
2646
|
-
value: 'Generated media artifacts',
|
|
2647
|
-
},
|
|
2648
|
-
],
|
|
2649
|
-
execution: {
|
|
2650
|
-
resolvedWorkspaceLabel: workspace?.label ?? workspaceId ?? null,
|
|
2651
|
-
resolvedCwd: session?.cwd ?? workspace?.cwd ?? workingDir,
|
|
2652
|
-
workspaceRootId: workspace?.workspaceRootId ?? null,
|
|
2653
|
-
workspaceRelativePath: workspace?.workspaceRelativePath ?? null,
|
|
2654
|
-
executionMode: session?.environment.mode ?? null,
|
|
2655
|
-
executionBranch: session?.environment.branch ?? null,
|
|
2656
|
-
worktreePath: session?.environment.worktreePath ?? null,
|
|
2657
|
-
fallbackReason: resolveExecutionFallbackReason(session?.environment),
|
|
2658
|
-
},
|
|
2659
|
-
notes: [
|
|
2660
|
-
useAppServer
|
|
2661
|
-
? 'This Codex host uses the app-server transport, so Canon can route native plan mode, runtime questions, approvals, and live turn updates.'
|
|
2662
|
-
: 'This Codex host uses the current exec --json transport, so Canon can show thinking, tool activity, and completed assistant-message previews, but not native plan questions or structured approvals.',
|
|
2663
|
-
],
|
|
2664
|
-
};
|
|
2665
|
-
await runtimeState.writeRuntimeInfo(conversationId, payload);
|
|
2666
|
-
})).catch((error) => {
|
|
2667
|
-
console.error('[canon-codex] Failed to publish runtime info:', error);
|
|
2581
|
+
const results = await Promise.allSettled(Array.from(knownConversationIds).map(async (conversationId) => {
|
|
2582
|
+
const descriptor = runtimeDescriptor.runtimeDescriptor;
|
|
2583
|
+
if (!descriptor)
|
|
2584
|
+
return;
|
|
2585
|
+
await runtimeState.writeRuntimeInfo(conversationId, {
|
|
2586
|
+
surfaceMode: 'host',
|
|
2587
|
+
descriptor: {
|
|
2588
|
+
coreControls: [],
|
|
2589
|
+
supportsInterrupt: descriptor.supportsInterrupt,
|
|
2590
|
+
supportsInputInterrupt: descriptor.supportsInputInterrupt,
|
|
2591
|
+
streamingTextMode: descriptor.streamingTextMode,
|
|
2592
|
+
},
|
|
2668
2593
|
});
|
|
2669
|
-
}
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2594
|
+
}));
|
|
2595
|
+
const failure = results.find((result) => result.status === 'rejected');
|
|
2596
|
+
if (failure?.status === 'rejected')
|
|
2597
|
+
throw failure.reason;
|
|
2673
2598
|
};
|
|
2599
|
+
const runtimeHeartbeat = createRuntimeHeartbeat({
|
|
2600
|
+
publisher: runtimeState,
|
|
2601
|
+
getRuntime: () => runtimeDescriptor,
|
|
2602
|
+
refreshDetails: refreshRuntimeDetails,
|
|
2603
|
+
onError: (error, operation) => {
|
|
2604
|
+
console.error(`[canon-codex] Runtime ${operation} failed:`, error);
|
|
2605
|
+
},
|
|
2606
|
+
});
|
|
2674
2607
|
let startupRecoveryComplete = false;
|
|
2675
2608
|
async function recoverInboundMessageGaps() {
|
|
2676
2609
|
// A reconnect can reveal conversations created while this host was
|
|
@@ -2796,14 +2729,13 @@ export async function main() {
|
|
|
2796
2729
|
codexDynamicTools = filterCodexCommunicationTools(baseCodexDynamicTools, outboundPolicy);
|
|
2797
2730
|
},
|
|
2798
2731
|
onConnected: () => {
|
|
2799
|
-
|
|
2800
|
-
|
|
2732
|
+
publishLocalHeartbeat();
|
|
2733
|
+
runtimeHeartbeat.connect();
|
|
2801
2734
|
observeReconnectRecovery('reconnect', reconnectRecovery.onConnected());
|
|
2802
2735
|
console.error('[canon-codex] SSE connected');
|
|
2803
2736
|
},
|
|
2804
2737
|
onDisconnected: () => {
|
|
2805
|
-
|
|
2806
|
-
runtimeState.clearAgentRuntime().catch(() => { });
|
|
2738
|
+
void runtimeHeartbeat.disconnect();
|
|
2807
2739
|
console.error('[canon-codex] SSE disconnected');
|
|
2808
2740
|
},
|
|
2809
2741
|
onReplayExpired: () => observeReconnectRecovery('replay-expired', reconnectRecovery.onReplayExpired()),
|
|
@@ -2840,7 +2772,7 @@ export async function main() {
|
|
|
2840
2772
|
writeTurn(session);
|
|
2841
2773
|
}
|
|
2842
2774
|
}
|
|
2843
|
-
|
|
2775
|
+
publishLocalHeartbeat();
|
|
2844
2776
|
}, HEARTBEAT_MS);
|
|
2845
2777
|
const idleCheck = setInterval(() => {
|
|
2846
2778
|
const now = Date.now();
|
|
@@ -2864,7 +2796,7 @@ export async function main() {
|
|
|
2864
2796
|
}
|
|
2865
2797
|
runtimeRequests.dispose();
|
|
2866
2798
|
stream.stop();
|
|
2867
|
-
await
|
|
2799
|
+
await runtimeHeartbeat.dispose();
|
|
2868
2800
|
for (const session of [...sessions.values()]) {
|
|
2869
2801
|
await session.adapter.interrupt().catch(() => { });
|
|
2870
2802
|
closeSession(session.conversationId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/codex-plugin",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.3",
|
|
4
4
|
"description": "Canon host integration for Codex CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@canonmsg/agent-sdk": "^10.1
|
|
32
|
+
"@canonmsg/agent-sdk": "^10.2.1",
|
|
33
33
|
"@canonmsg/agent-tools": "^0.9.0",
|
|
34
34
|
"@canonmsg/coding-agent-host": "^0.7.0",
|
|
35
|
-
"@canonmsg/core": "^12.
|
|
35
|
+
"@canonmsg/core": "^12.3.0",
|
|
36
36
|
"@canonmsg/rich-cards": "^0.10.4"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|