@canonmsg/codex-plugin 0.22.4 → 0.23.0

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/README.md CHANGED
@@ -13,6 +13,9 @@ npm install -g @canonmsg/codex-plugin
13
13
  # Make sure Codex itself is logged in the way you want Canon to use
14
14
  codex login status
15
15
 
16
+ # Select the Canon trust domain supplied for your account
17
+ export CANON_ENVIRONMENT_ID=canon-legacy-v1
18
+
16
19
  # Register (approve in Canon when prompted)
17
20
  canon-codex-register --name "My Codex" --description "My local coding agent" --phone "+15551234567"
18
21
 
@@ -20,7 +23,12 @@ canon-codex-register --name "My Codex" --description "My local coding agent" --p
20
23
  canon-codex --cwd /path/to/project
21
24
  ```
22
25
 
23
- Registration saves a Canon profile in `~/.canon/agents.json`, the same shared profile store used by the Claude Code integration and supported by the OpenClaw plugin.
26
+ Registration verifies the selected Canon API and stream before sending the
27
+ request, then saves the environment ID and complete endpoint snapshot with the
28
+ credential in `~/.canon/agents.json`. The same environment-bound profile store
29
+ is used by the Claude Code integration and supported by the OpenClaw plugin.
30
+ An older profile without this binding must be reconnected or migrated before a
31
+ new host will start it.
24
32
 
25
33
  `canon-codex` is the local agent process. Keep that terminal open while you want Canon to reach the agent. Closing it, logging out, rebooting, or sleeping long enough to stop the process takes the local agent offline until you revive it.
26
34
 
@@ -120,7 +128,7 @@ canon-codex --cwd /path/to/project --codex-bin /absolute/path/to/codex
120
128
  If Canon rejects authenticated requests with `401 Invalid API key`, the stored Canon profile needs a fresh key. Reconnect the same profile to overwrite `~/.canon/agents.json`, then restart or revive the host:
121
129
 
122
130
  ```bash
123
- canon-codex-register --name "My Codex" --description "My local coding agent" --phone "+15551234567" --profile my-codex
131
+ canon-codex-register --environment canon-legacy-v1 --name "My Codex" --description "My local coding agent" --phone "+15551234567" --profile my-codex
124
132
  ```
125
133
 
126
134
  If Codex reports API-key quota errors while another local tool on the same machine uses OpenAI API keys, check Codex's own stored login state:
@@ -142,7 +150,7 @@ Restart `canon-codex` after changing the Codex login state.
142
150
  ## Multiple agents
143
151
 
144
152
  ```bash
145
- canon-codex-register --name "Frontend" --description "React work" --phone "+1..." --profile frontend
153
+ canon-codex-register --environment canon-legacy-v1 --name "Frontend" --description "React work" --phone "+1..." --profile frontend
146
154
  CANON_AGENT=frontend canon-codex --cwd ~/projects/frontend
147
155
  ```
148
156
 
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 { captureTurnArtifactSnapshot, collectTurnArtifacts, } 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, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, markLocalRuntimeStopped, normalizeTurnMetadata, parseRuntimeCardV1, RuntimeRequestManager, prepareConversationEnvironment, loadHostSessionConfig, releaseConversationEnvironment, resolveCanonAgent, CanonApiError, loadRuntimeSessionState, sendMessageWithRetry, sendMessageWithRetryChunked, saveRuntimeSessionState, buildBoundedTurnTrail, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, renderCodingHostInboundPrompt, resolveHostWorkspaceCwd, shouldTriggerAgentTurn, upsertLocalRuntimeEntry, } from '@canonmsg/core';
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, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, markLocalRuntimeStopped, normalizeTurnMetadata, parseRuntimeCardV1, RuntimeRequestManager, prepareConversationEnvironment, loadHostSessionConfig, releaseConversationEnvironment, resolveCanonAgent, verifyResolvedAgentEnvironment, CanonApiError, loadRuntimeSessionState, sendMessageWithRetry, sendMessageWithRetryChunked, saveRuntimeSessionState, buildBoundedTurnTrail, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, renderCodingHostInboundPrompt, resolveHostWorkspaceCwd, shouldTriggerAgentTurn, upsertLocalRuntimeEntry, } from '@canonmsg/core';
10
10
  import { decideAutoReply, } from './inbound-policy.js';
11
11
  import { CodexConversationAdapter, } from './adapter.js';
12
12
  import { CodexAppServerAdapter, } from './app-server-adapter.js';
@@ -45,7 +45,7 @@ COMMON FLAGS
45
45
 
46
46
  AUTH
47
47
  CANON_AGENT=<profile> canon-codex --cwd /path/to/project
48
- CANON_API_KEY=agk_live_... canon-codex --cwd /path/to/project
48
+ CANON_ENVIRONMENT_ID=<id> CANON_API_KEY=agk_live_... canon-codex --cwd /path/to/project
49
49
 
50
50
  EXAMPLES
51
51
  canon-codex --cwd ~/dev/canon
@@ -487,10 +487,18 @@ export async function main() {
487
487
  console.error(`[canon-codex] Could not detect Codex CLI version for ${codexBin}: ${codexCliStatus.error ?? 'unknown result'}`);
488
488
  }
489
489
  console.error(`[canon-codex] Codex transport: ${useAppServer ? 'app-server' : 'exec --json'}`);
490
- const { apiKey, agentId: profileAgentId, agentName: profileAgentName, profile, baseUrl, lockHandle, } = resolveCanonAgent({ logPrefix: '[canon-codex]', expectedClientType: 'codex' });
490
+ const resolvedAgent = resolveCanonAgent({ logPrefix: '[canon-codex]', expectedClientType: 'codex' });
491
+ const { apiKey, agentId: profileAgentId, agentName: profileAgentName, profile, baseUrl, streamUrl, rtdbUrl, firebaseApiKey, lockHandle, } = resolvedAgent;
491
492
  console.error(`[canon-codex] Starting${profile ? ` (profile: ${profile})` : ''} in ${workingDir}`);
493
+ try {
494
+ await verifyResolvedAgentEnvironment(resolvedAgent);
495
+ }
496
+ catch (error) {
497
+ lockHandle?.release();
498
+ throw error;
499
+ }
492
500
  const client = new CanonClient(apiKey, baseUrl);
493
- const rtdb = initRTDBAuth(client);
501
+ const rtdb = initRTDBAuth(client, { rtdbUrl, firebaseApiKey });
494
502
  const typingSignals = createTypingStatusPublisher({
495
503
  setTyping: (conversationId, typing, status) => status
496
504
  ? client.setTyping(conversationId, typing, status)
@@ -2202,6 +2210,7 @@ export async function main() {
2202
2210
  const stream = new CanonStream({
2203
2211
  apiKey,
2204
2212
  agentId,
2213
+ streamUrl,
2205
2214
  handler: {
2206
2215
  onMessage: (payload) => {
2207
2216
  const message = payload.message;
package/dist/register.js CHANGED
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import { setDefaultResultOrder } from 'node:dns';
3
- import { readFileSync } from 'node:fs';
4
3
  import { parseArgs } from 'node:util';
5
- import { ackRegistrationApproval, clearPendingRegistration, getOrCreatePendingRegistration, registerAndWaitForApproval, updatePendingRegistration, upsertAgentProfile, AGENTS_PATH, } from '@canonmsg/core';
4
+ import { ackRegistrationApproval, clearPendingRegistration, getOrCreatePendingRegistration, registerAndWaitForApproval, resolveCanonRuntimeConnection, loadProfiles, updatePendingRegistration, upsertAgentProfile, verifyCanonRuntimeConnection, } from '@canonmsg/core';
6
5
  import { runCli } from './cli-entry.js';
7
6
  const HELP = `canon-codex-register — register or reconnect a Codex agent in Canon
8
7
 
@@ -16,13 +15,17 @@ REQUIRED
16
15
 
17
16
  FLAGS
18
17
  --profile <name> Local profile name in ~/.canon/agents.json
18
+ --environment <id> Canon environment ID (or CANON_ENVIRONMENT_ID)
19
19
  --base-url <url> Canon API base URL override
20
+ --stream-url <url> Canon stream URL override
21
+ --rtdb-url <url> Canon RTDB URL override
22
+ --firebase-api-key <key> Firebase web API key override (public config)
20
23
  --help, -h Show this help
21
24
  --version, -V Show package version
22
25
 
23
26
  EXAMPLES
24
- canon-codex-register --name "My Codex" --description "Local coding agent" --phone "+15551234567"
25
- canon-codex-register --name "Frontend" --description "React work" --phone "+15551234567" --profile frontend
27
+ canon-codex-register --environment canon-legacy-v1 --name "My Codex" --description "Local coding agent" --phone "+15551234567"
28
+ canon-codex-register --environment canon-legacy-v1 --name "Frontend" --description "React work" --phone "+15551234567" --profile frontend
26
29
 
27
30
  After approval, start it with CANON_AGENT=<profile> canon-codex --cwd /path/to/project.`;
28
31
  export async function main() {
@@ -33,7 +36,11 @@ export async function main() {
33
36
  description: { type: 'string' },
34
37
  phone: { type: 'string' },
35
38
  profile: { type: 'string' },
39
+ environment: { type: 'string' },
36
40
  'base-url': { type: 'string' },
41
+ 'stream-url': { type: 'string' },
42
+ 'rtdb-url': { type: 'string' },
43
+ 'firebase-api-key': { type: 'string' },
37
44
  },
38
45
  strict: true,
39
46
  });
@@ -42,23 +49,31 @@ export async function main() {
42
49
  process.exit(1);
43
50
  }
44
51
  const profileName = values.profile || values.name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
45
- let existingAgentId;
46
- try {
47
- const profiles = JSON.parse(readFileSync(AGENTS_PATH, 'utf-8'));
48
- existingAgentId = profiles[profileName]?.agentId;
49
- }
50
- catch {
51
- // No existing profile state.
52
+ const environmentId = values.environment || process.env.CANON_ENVIRONMENT_ID;
53
+ if (!environmentId) {
54
+ throw new Error('--environment or CANON_ENVIRONMENT_ID is required');
52
55
  }
56
+ const connection = resolveCanonRuntimeConnection({
57
+ environmentId,
58
+ apiBaseUrl: values['base-url'],
59
+ streamUrl: values['stream-url'],
60
+ rtdbUrl: values['rtdb-url'],
61
+ firebaseWebApiKey: values['firebase-api-key'],
62
+ });
63
+ await verifyCanonRuntimeConnection(connection);
64
+ const existingProfile = loadProfiles()[profileName];
65
+ const existingAgentId = existingProfile?.environmentId === connection.environmentId
66
+ ? existingProfile.agentId
67
+ : undefined;
53
68
  console.log(`Registering Codex agent "${values.name}" (profile: ${profileName})...`);
54
- const pending = getOrCreatePendingRegistration(profileName, 'codex');
69
+ const pending = getOrCreatePendingRegistration(profileName, 'codex', connection);
55
70
  const result = await registerAndWaitForApproval({
56
71
  name: values.name,
57
72
  description: values.description,
58
73
  ownerPhone: values.phone,
59
74
  developerInfo: 'Codex host plugin',
60
75
  clientType: 'codex',
61
- baseUrl: values['base-url'],
76
+ baseUrl: connection.apiBaseUrl,
62
77
  requestedAgentId: existingAgentId,
63
78
  localRegistrationId: pending.localRegistrationId,
64
79
  }, {
@@ -87,11 +102,15 @@ export async function main() {
87
102
  agentId: result.agentId,
88
103
  agentName: result.agentName,
89
104
  registeredAt: new Date().toISOString(),
105
+ environmentId: connection.environmentId,
106
+ baseUrl: connection.apiBaseUrl,
107
+ streamUrl: connection.streamUrl,
108
+ rtdbUrl: connection.rtdbUrl,
109
+ firebaseApiKey: connection.firebaseWebApiKey,
90
110
  clientType: 'codex',
91
- ...(typeof values['base-url'] === 'string' ? { baseUrl: values['base-url'] } : {}),
92
111
  });
93
112
  if (result.requestId) {
94
- await ackRegistrationApproval(values['base-url'], result.requestId, result.pollToken);
113
+ await ackRegistrationApproval(connection.apiBaseUrl, result.requestId, result.pollToken);
95
114
  }
96
115
  clearPendingRegistration(profileName);
97
116
  console.log(`Approved! Agent: ${result.agentName} (${result.agentId})`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/codex-plugin",
3
- "version": "0.22.4",
3
+ "version": "0.23.0",
4
4
  "description": "Canon host integration for Codex CLI",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -29,9 +29,9 @@
29
29
  "prepack": "npm run build"
30
30
  },
31
31
  "dependencies": {
32
- "@canonmsg/agent-sdk": "^5.1.3",
32
+ "@canonmsg/agent-sdk": "^6.0.0",
33
33
  "@canonmsg/coding-agent-host": "^0.2.2",
34
- "@canonmsg/core": "^5.0.0"
34
+ "@canonmsg/core": "^6.0.0"
35
35
  },
36
36
  "engines": {
37
37
  "node": ">=18.0.0"