@canonmsg/codex-plugin 0.29.2 → 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.
@@ -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 ? CODEX_APP_TOOL_NAMES.has(toolName) : false);
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 || !CODEX_APP_TOOL_NAMES.has(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
@@ -272,14 +272,6 @@ export function resolveWorkspaceCwd() {
272
272
  defaultCwd: workingDir,
273
273
  });
274
274
  }
275
- function resolveExecutionFallbackReason(environment) {
276
- if (!environment?.reason || environment.mode !== 'locked') {
277
- return null;
278
- }
279
- return environment.reason === 'Sharing the base workspace (locked mode)'
280
- ? null
281
- : environment.reason;
282
- }
283
275
  function stringArg(args, key) {
284
276
  const value = args[key];
285
277
  return typeof value === 'string' && value.trim() ? value.trim() : undefined;
@@ -810,9 +802,6 @@ export async function main() {
810
802
  client,
811
803
  conversationCache,
812
804
  });
813
- function resolveWorkspaceIdForBaseCwd(baseCwd) {
814
- return workspaceOptions.find((option) => option.cwd === baseCwd)?.id;
815
- }
816
805
  async function refreshKnownConversationIds(force = false) {
817
806
  if (!force && Date.now() - lastKnownConversationRefreshAt < HEARTBEAT_MS) {
818
807
  return;
@@ -2590,71 +2579,18 @@ export async function main() {
2590
2579
  if (signal.aborted)
2591
2580
  return;
2592
2581
  const results = await Promise.allSettled(Array.from(knownConversationIds).map(async (conversationId) => {
2593
- const session = sessions.get(conversationId);
2594
- const workspaceId = session
2595
- ? resolveWorkspaceIdForBaseCwd(session.environment.baseCwd)
2596
- : runtimeDescriptor.defaultWorkspaceId;
2597
- const workspace = workspaceOptions.find((option) => option.id === workspaceId) ?? null;
2598
2582
  const descriptor = runtimeDescriptor.runtimeDescriptor;
2599
2583
  if (!descriptor)
2600
2584
  return;
2601
- const payload = {
2602
- descriptor,
2585
+ await runtimeState.writeRuntimeInfo(conversationId, {
2603
2586
  surfaceMode: 'host',
2604
- // The exec --json transport cannot block on approvals — without a
2605
- // strip-level warning a user can believe they have an approval
2606
- // gate they do not have.
2607
- ...(useAppServer
2608
- ? {}
2609
- : { warning: "Approvals can't block on this Codex CLI — update Codex to enable the app-server transport and approval gates." }),
2610
- statusItems: [
2611
- {
2612
- id: 'transport',
2613
- label: 'Transport',
2614
- value: useAppServer ? 'app-server' : 'exec --json',
2615
- },
2616
- {
2617
- id: 'streaming',
2618
- label: 'Live output',
2619
- value: useAppServer
2620
- ? 'Plans, questions, approvals, tools, and message deltas'
2621
- : 'Thinking, tools, and completed-message previews',
2622
- },
2623
- {
2624
- id: 'codex-cli',
2625
- label: 'Codex CLI',
2626
- value: codexCliStatus.version ?? (codexCliStatus.raw ?? 'Version unknown'),
2627
- tone: codexCliStatus.version ? 'default' : 'warning',
2628
- },
2629
- {
2630
- id: 'nativeActions',
2631
- label: 'Native actions',
2632
- value: useAppServer ? 'Enabled' : 'Limited until app-server transport',
2633
- ...(useAppServer ? {} : { tone: 'warning' }),
2634
- },
2635
- {
2636
- id: 'mediaOut',
2637
- label: 'Media out',
2638
- value: 'Generated media artifacts',
2639
- },
2640
- ],
2641
- execution: {
2642
- resolvedWorkspaceLabel: workspace?.label ?? workspaceId ?? null,
2643
- resolvedCwd: session?.cwd ?? workspace?.cwd ?? workingDir,
2644
- workspaceRootId: workspace?.workspaceRootId ?? null,
2645
- workspaceRelativePath: workspace?.workspaceRelativePath ?? null,
2646
- executionMode: session?.environment.mode ?? null,
2647
- executionBranch: session?.environment.branch ?? null,
2648
- worktreePath: session?.environment.worktreePath ?? null,
2649
- fallbackReason: resolveExecutionFallbackReason(session?.environment),
2587
+ descriptor: {
2588
+ coreControls: [],
2589
+ supportsInterrupt: descriptor.supportsInterrupt,
2590
+ supportsInputInterrupt: descriptor.supportsInputInterrupt,
2591
+ streamingTextMode: descriptor.streamingTextMode,
2650
2592
  },
2651
- notes: [
2652
- useAppServer
2653
- ? 'This Codex host uses the app-server transport, so Canon can route native plan mode, runtime questions, approvals, and live turn updates.'
2654
- : '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.',
2655
- ],
2656
- };
2657
- await runtimeState.writeRuntimeInfo(conversationId, payload);
2593
+ });
2658
2594
  }));
2659
2595
  const failure = results.find((result) => result.status === 'rejected');
2660
2596
  if (failure?.status === 'rejected')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/codex-plugin",
3
- "version": "0.29.2",
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.2.0",
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.2.0",
35
+ "@canonmsg/core": "^12.3.0",
36
36
  "@canonmsg/rich-cards": "^0.10.4"
37
37
  },
38
38
  "engines": {