@canonmsg/codex-plugin 0.6.2 → 0.6.4

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/cli-entry.js CHANGED
@@ -1,10 +1,20 @@
1
+ import { realpathSync } from 'node:fs';
1
2
  import { resolve } from 'node:path';
2
3
  import { pathToFileURL } from 'node:url';
3
4
  export function isDirectExecution(moduleUrl) {
4
5
  const entry = process.argv[1];
5
6
  if (!entry)
6
7
  return false;
7
- return pathToFileURL(resolve(entry)).href === moduleUrl;
8
+ const abs = resolve(entry);
9
+ let real = abs;
10
+ try {
11
+ real = realpathSync(abs);
12
+ }
13
+ catch {
14
+ // argv[1] may not exist on disk in rare harnesses; fall back to abs
15
+ }
16
+ return (pathToFileURL(real).href === moduleUrl ||
17
+ pathToFileURL(abs).href === moduleUrl);
8
18
  }
9
19
  export function runCli(moduleUrl, main, onError) {
10
20
  if (!isDirectExecution(moduleUrl)) {
@@ -31,6 +31,7 @@ type HostInboundMessage = {
31
31
  attachments?: CanonMessage['attachments'];
32
32
  senderType?: CanonMessage['senderType'];
33
33
  mentions?: string[] | null;
34
+ contactCard?: CanonMessage['contactCard'];
34
35
  };
35
36
  interface HostWorkspaceResolverOption {
36
37
  id: string;
@@ -54,9 +54,24 @@ export function renderCanonHostInboundContent(message, materialized) {
54
54
  const mat = materialized?.find((m) => m.index === i) ?? null;
55
55
  placeholders.push(describeAttachment(att, mat));
56
56
  }
57
+ if (message.contentType === 'contact_card' && message.contactCard) {
58
+ placeholders.push(describeContactCard(message.contactCard));
59
+ }
57
60
  const rendered = [...placeholders, body].filter(Boolean).join('\n');
58
61
  return rendered || '[Empty message]';
59
62
  }
63
+ function describeContactCard(card) {
64
+ const parts = [`${card.userType} · userId: ${card.userId}`];
65
+ if (card.accessLevel)
66
+ parts.push(`access: ${card.accessLevel}`);
67
+ if (card.ownerName)
68
+ parts.push(`owner: ${card.ownerName}`);
69
+ if (card.about)
70
+ parts.push(`about: ${card.about}`);
71
+ const identity = `📇 Contact card: "${card.displayName}" (${parts.join(' · ')}).`;
72
+ const hint = `This card is informational only in host mode. Canon does not currently expose a host-side tool here for starting a new direct conversation or sending a contact request to userId ${card.userId}.`;
73
+ return `${identity}\n${hint}`;
74
+ }
60
75
  function describeAttachment(attachment, materialized) {
61
76
  if (attachment.kind === 'image') {
62
77
  return '[Image attached]';
package/dist/host.js CHANGED
@@ -3,7 +3,7 @@ import { setDefaultResultOrder } from 'node:dns';
3
3
  import { randomUUID } from 'node:crypto';
4
4
  import { parseArgs } from 'node:util';
5
5
  import { getCodexImagePath, materializeMessageMedia, } from '@canonmsg/agent-sdk';
6
- import { buildConfiguredWorkspaceOptions, buildPublicWorkspaceOptions, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, isEnabledFlag, CanonClient, CanonStream, clearSessionState, clearTurnState, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfile, initRTDBAuth, normalizeTurnMetadata, normalizeTurnState, prepareConversationEnvironment, releaseLock, releaseConversationEnvironment, resolveCanonAgent, rtdbRead, rtdbWrite, shouldTriggerAgentTurn, writeSessionState, writeTurnState, } from '@canonmsg/core';
6
+ import { buildConfiguredWorkspaceOptions, buildPublicWorkspaceOptions, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, clearSessionState, clearTurnState, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfile, initRTDBAuth, normalizeTurnMetadata, normalizeTurnState, prepareConversationEnvironment, releaseLock, releaseConversationEnvironment, resolveCanonAgent, rtdbRead, rtdbWrite, shouldTriggerAgentTurn, writeSessionState, writeTurnState, } from '@canonmsg/core';
7
7
  import { buildCanonHostPrompt, buildHydratedInboundContext, createConversationMetadataLoader, loadHostSessionConfig, publishHostAgentRuntime, renderCanonHostInboundContent, resolveHostWorkspaceCwd, } from './host-runtime.js';
8
8
  import { buildInboundContextLines, decideAutoReply, } from './inbound-policy.js';
9
9
  import { CodexConversationAdapter, } from './adapter.js';
@@ -49,13 +49,11 @@ async function loadSessionConfig(conversationId, agentId) {
49
49
  extraStringFields: ['permissionMode'],
50
50
  });
51
51
  }
52
- const SESSION_EXECUTION_MODE_REQUIRED = 'Session execution mode required; please select a mode before starting the session.';
53
- function requireSessionExecutionMode(config) {
54
- const mode = config?.executionMode;
55
- if (!mode) {
56
- throw new ExecutionEnvironmentError(SESSION_EXECUTION_MODE_REQUIRED, SESSION_EXECUTION_MODE_REQUIRED);
57
- }
58
- return mode;
52
+ // Default to 'locked' (shared workspace) when no mode has been picked. The
53
+ // UI still lets owners flip to 'worktree'; this just stops sessions from
54
+ // failing closed when the mode has never been written.
55
+ function resolveSessionExecutionMode(config) {
56
+ return config?.executionMode ?? 'locked';
59
57
  }
60
58
  function resolveWorkspaceCwd(config) {
61
59
  return resolveHostWorkspaceCwd({
@@ -106,17 +104,12 @@ export async function main() {
106
104
  config: { type: 'string', multiple: true },
107
105
  'codex-bin': { type: 'string' },
108
106
  'full-auto': { type: 'boolean' },
109
- 'enable-worktrees': { type: 'boolean' },
110
107
  'dangerously-bypass-approvals-and-sandbox': { type: 'boolean' },
111
108
  },
112
109
  strict: true,
113
110
  });
114
111
  workingDir = (typeof args.cwd === 'string' ? args.cwd : null) || process.cwd();
115
112
  workspaceOptions = buildConfiguredWorkspaceOptions(workingDir, args.workspace ?? []);
116
- const allowWorktrees = isEnabledFlag(args['enable-worktrees'] ?? process.env.CANON_ENABLE_WORKTREES);
117
- if (!allowWorktrees) {
118
- console.error('[canon-codex] Worktree isolation is disabled; sessions will lock their selected workspace unless explicitly enabled.');
119
- }
120
113
  if (typeof args['ask-for-approval'] === 'string') {
121
114
  console.error('[canon-codex] Note: newer Codex CLI releases do not accept --ask-for-approval for `codex exec`; Canon will translate compatible legacy usage when possible.');
122
115
  }
@@ -256,10 +249,7 @@ export async function main() {
256
249
  }
257
250
  const creation = (async () => {
258
251
  const config = await loadSessionConfig(conversationId, agentId);
259
- const sessionExecutionMode = requireSessionExecutionMode(config);
260
- if (sessionExecutionMode === 'worktree' && !allowWorktrees) {
261
- throw new ExecutionEnvironmentError('This host does not allow worktree sessions (launched without --enable-worktrees).', 'This Canon host was started without worktree isolation enabled. Choose "Lock the workspace" or restart the host with --enable-worktrees.');
262
- }
252
+ const sessionExecutionMode = resolveSessionExecutionMode(config);
263
253
  const workspaceCwd = resolveWorkspaceCwd(config);
264
254
  const environment = prepareConversationEnvironment({
265
255
  agentId,
@@ -548,9 +538,9 @@ export async function main() {
548
538
  }
549
539
  let controlStopped = false;
550
540
  let streamConnected = false;
551
- const hostAvailableExecutionModes = allowWorktrees
552
- ? [...EXECUTION_ENVIRONMENT_MODES]
553
- : ['locked'];
541
+ const hostAvailableExecutionModes = [
542
+ ...EXECUTION_ENVIRONMENT_MODES,
543
+ ];
554
544
  const codexPermissionEnvelope = deriveCodexPermissionEnvelope(args);
555
545
  let runtimeDescriptor = {
556
546
  defaultWorkspaceId: workspaceOptions[0]?.id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/codex-plugin",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "Canon host integration for Codex CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,8 +28,8 @@
28
28
  "prepack": "npm run build"
29
29
  },
30
30
  "dependencies": {
31
- "@canonmsg/agent-sdk": "^0.8.1",
32
- "@canonmsg/core": "^0.7.1"
31
+ "@canonmsg/agent-sdk": "^0.8.2",
32
+ "@canonmsg/core": "^0.7.3"
33
33
  },
34
34
  "engines": {
35
35
  "node": ">=18.0.0"