@canonmsg/claude-code-plugin 0.34.1 → 0.34.2

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "Canon",
3
3
  "description": "Connect Claude Code to Canon — messaging where AI agents are first-class citizens",
4
- "version": "0.34.1",
4
+ "version": "0.34.2",
5
5
  "channels": [
6
6
  {
7
7
  "server": "canon-channel",
package/dist/host.js CHANGED
@@ -29,7 +29,7 @@ import { query, } from '@anthropic-ai/claude-agent-sdk';
29
29
  import { materializeMessageMedia, materializeReplyContextMedia, sendMediaFileMessage, } from '@canonmsg/agent-sdk';
30
30
  import { captureTurnArtifactSnapshot, createTurnArtifactRouter, IDLE_TIMEOUT_MS, collectMissedInboundMessages, createRecoveryCheckpointTracker, createReconnectRecoveryCoordinator, STARTUP_RECOVERY_PAGE_SIZE, } from '@canonmsg/coding-agent-host';
31
31
  import { buildCanonUserContent, renderClaudeInboundContent, withClaudeReplyContextMediaReferences, } from './canon-user-content.js';
32
- import { EFFORT_OPTIONS, CLAUDE_PERMISSION_MODE_OPTIONS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildCanonInboundFrameV1, buildCanonTurnContextV2, buildConfiguredWorkspaceOptionsWithRoots, buildConversationEnvironmentKey, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, normalizeRuntimeCommandDescriptors, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createTurnOutputController, createRuntimeStatePublisher, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, ControlChannelPoller, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, ApprovalManager, RuntimeRequestManager, FINAL_MESSAGE_HANDOFF_MS, buildLocalRuntimeId, getActiveProfileLock, heartbeatLocalRuntimeEntry, normalizeTurnMetadata, parseTurnVerbosityConfig, prepareConversationEnvironment, resolveCanonAgent, verifyResolvedAgentEnvironment, decideAutoReply, initRTDBAuth, isChunkedSendMessageError, sendMessageWithRetry, sendMessageWithRetryChunked, loadRuntimeSessionState, markLocalRuntimeStopped, releaseConversationEnvironment, resolveLocalRuntimeSessionState, saveRuntimeSessionState, clearRuntimeSessionState, publishHostAgentRuntime, publishHostSessionSnapshots, renderCodingHostInboundPrompt, resolveConfiguredWorkspaceCwd, resolveTurnVerbosity, shouldTriggerAgentTurn, upsertLocalRuntimeEntry, } from '@canonmsg/core';
32
+ import { EFFORT_OPTIONS, CLAUDE_PERMISSION_MODE_OPTIONS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildCanonInboundFrameV1, buildCanonTurnContextV2, buildConfiguredWorkspaceOptionsWithRoots, buildConversationEnvironmentKey, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, buildRuntimePresentationPolicy, normalizeRuntimeCommandDescriptors, DEFAULT_FIRST_PARTY_RUNTIME_PRESENTATION, createConversationMetadataLoader, createTurnOutputController, createRuntimeStatePublisher, createRuntimeHeartbeat, createTypingStatusPublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, ControlChannelPoller, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, ApprovalManager, RuntimeRequestManager, FINAL_MESSAGE_HANDOFF_MS, buildLocalRuntimeId, getActiveProfileLock, heartbeatLocalRuntimeEntry, normalizeTurnMetadata, parseTurnVerbosityConfig, prepareConversationEnvironment, resolveCanonAgent, verifyResolvedAgentEnvironment, decideAutoReply, initRTDBAuth, isChunkedSendMessageError, sendMessageWithRetry, sendMessageWithRetryChunked, loadRuntimeSessionState, markLocalRuntimeStopped, releaseConversationEnvironment, resolveLocalRuntimeSessionState, saveRuntimeSessionState, clearRuntimeSessionState, publishHostSessionSnapshots, renderCodingHostInboundPrompt, resolveConfiguredWorkspaceCwd, resolveTurnVerbosity, shouldTriggerAgentTurn, upsertLocalRuntimeEntry, } from '@canonmsg/core';
33
33
  import { runCli } from '@canonmsg/core';
34
34
  import { CANON_VERB_MCP_SERVER_NAME, createCanonVerbMcpServer } from '@canonmsg/agent-tools';
35
35
  import { synthesizeClaudeApprovalDiff } from './approval-diff.js';
@@ -414,9 +414,6 @@ function acceptClaudeCli(source, cliPath) {
414
414
  function toModelOptions(models) {
415
415
  return models.map(claudeModelInfoToOption);
416
416
  }
417
- async function publishAgentRuntime(agentId, runtime, rtdb) {
418
- await publishHostAgentRuntime(agentId, 'claude-code', runtime, rtdb);
419
- }
420
417
  export function resolveSessionExecutionMode(defaultExecutionMode = 'worktree') {
421
418
  return defaultExecutionMode;
422
419
  }
@@ -2529,18 +2526,20 @@ export async function main() {
2529
2526
  console.error('[canon-host] Failed to publish session snapshots:', error);
2530
2527
  });
2531
2528
  }
2532
- const publishRuntimeHeartbeat = async () => {
2529
+ const publishLocalHeartbeat = () => {
2533
2530
  heartbeatLocalRuntimeEntry(runtimeId, {
2534
2531
  agentId,
2535
2532
  agentName: profileAgentName,
2536
2533
  cwd: workingDir,
2537
2534
  baseCwd: workingDir,
2538
2535
  });
2539
- if (!streamConnected)
2540
- return;
2536
+ };
2537
+ const refreshRuntimeDetails = async (signal) => {
2541
2538
  await refreshKnownConversationIds().catch((error) => {
2542
2539
  console.error('[canon-host] Failed to refresh known conversations:', error);
2543
2540
  });
2541
+ if (signal.aborted)
2542
+ return;
2544
2543
  const activeSessionQuery = sessions.values().next().value?.query ?? null;
2545
2544
  const metadata = await refreshClaudeRuntimeMetadata({
2546
2545
  cwd: workingDir,
@@ -2549,9 +2548,8 @@ export async function main() {
2549
2548
  console.error('[canon-host] Failed to refresh Claude runtime metadata:', error);
2550
2549
  return runtimeMetadata;
2551
2550
  });
2552
- await publishAgentRuntime(agentId, runtimeDescriptor, rtdb).catch((error) => {
2553
- console.error('[canon-host] Failed to publish agent runtime:', error);
2554
- });
2551
+ if (signal.aborted)
2552
+ return;
2555
2553
  await publishSessionSnapshots(Array.from(knownConversationIds));
2556
2554
  // Rebuild so the descriptor picks up native slash commands from the
2557
2555
  // metadata refresh above — the initial descriptor is built before the
@@ -2569,7 +2567,9 @@ export async function main() {
2569
2567
  }),
2570
2568
  };
2571
2569
  }
2572
- await Promise.all(Array.from(knownConversationIds).map(async (conversationId) => {
2570
+ if (signal.aborted)
2571
+ return;
2572
+ const results = await Promise.allSettled(Array.from(knownConversationIds).map(async (conversationId) => {
2573
2573
  const session = sessions.get(conversationId);
2574
2574
  const workspaceId = session
2575
2575
  ? resolveWorkspaceIdForBaseCwd(session.environment.baseCwd)
@@ -2591,10 +2591,19 @@ export async function main() {
2591
2591
  fallbackReason: resolveExecutionFallbackReason(session?.environment),
2592
2592
  });
2593
2593
  await runtimeState.writeRuntimeInfo(conversationId, payload);
2594
- })).catch((error) => {
2595
- console.error('[canon-host] Failed to publish runtime info:', error);
2596
- });
2594
+ }));
2595
+ const failure = results.find((result) => result.status === 'rejected');
2596
+ if (failure?.status === 'rejected')
2597
+ throw failure.reason;
2597
2598
  };
2599
+ const runtimeHeartbeat = createRuntimeHeartbeat({
2600
+ publisher: runtimeState,
2601
+ getRuntime: () => runtimeDescriptor,
2602
+ refreshDetails: refreshRuntimeDetails,
2603
+ onError: (error, operation) => {
2604
+ console.error(`[canon-host] Runtime ${operation} failed:`, error);
2605
+ },
2606
+ });
2598
2607
  // ── Load conversations (informational — sessions created on demand) ──
2599
2608
  try {
2600
2609
  runtimeModels = await detectRuntimeModels(workingDir);
@@ -3004,7 +3013,7 @@ export async function main() {
3004
3013
  runtimeState.clearTurnState(convoId).catch(() => { });
3005
3014
  }, (descriptor) => {
3006
3015
  runtimeDescriptor = descriptor;
3007
- void publishRuntimeHeartbeat();
3016
+ runtimeHeartbeat.refresh();
3008
3017
  }, {
3009
3018
  model: runtimeModels[0]?.value,
3010
3019
  permissionMode: 'default',
@@ -3460,7 +3469,8 @@ export async function main() {
3460
3469
  },
3461
3470
  onConnected: () => {
3462
3471
  streamConnected = true;
3463
- void publishRuntimeHeartbeat();
3472
+ publishLocalHeartbeat();
3473
+ runtimeHeartbeat.connect();
3464
3474
  const recovery = reconnectRecovery.onConnected();
3465
3475
  if (recovery) {
3466
3476
  void recovery.catch((error) => {
@@ -3471,7 +3481,7 @@ export async function main() {
3471
3481
  },
3472
3482
  onDisconnected: () => {
3473
3483
  streamConnected = false;
3474
- runtimeState.clearAgentRuntime().catch(() => { });
3484
+ void runtimeHeartbeat.disconnect();
3475
3485
  console.error('[canon-host] SSE disconnected');
3476
3486
  },
3477
3487
  onError: (err) => console.error(`[canon-host] SSE error: ${err.message}`),
@@ -3571,7 +3581,7 @@ export async function main() {
3571
3581
  session.writeTurn();
3572
3582
  }
3573
3583
  }
3574
- void publishRuntimeHeartbeat();
3584
+ publishLocalHeartbeat();
3575
3585
  }, HEARTBEAT_MS);
3576
3586
  // ── Idle session cleanup ──
3577
3587
  const idleCheck = setInterval(() => {
@@ -3595,7 +3605,7 @@ export async function main() {
3595
3605
  stream.stop();
3596
3606
  approvalManager?.dispose();
3597
3607
  runtimeInputManager.dispose();
3598
- await runtimeState.clearAgentRuntime().catch(() => { });
3608
+ await runtimeHeartbeat.dispose();
3599
3609
  for (const convoId of [...sessions.keys()]) {
3600
3610
  closeSession(convoId);
3601
3611
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/claude-code-plugin",
3
- "version": "0.34.1",
3
+ "version": "0.34.2",
4
4
  "description": "Canon channel plugin for Claude Code — messaging where AI agents are first-class citizens",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,10 +31,10 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@anthropic-ai/claude-agent-sdk": "0.3.228",
34
- "@canonmsg/agent-sdk": "^10.1.0",
34
+ "@canonmsg/agent-sdk": "^10.2.0",
35
35
  "@canonmsg/agent-tools": "^0.9.0",
36
36
  "@canonmsg/coding-agent-host": "^0.7.0",
37
- "@canonmsg/core": "^12.1.0",
37
+ "@canonmsg/core": "^12.2.0",
38
38
  "@canonmsg/rich-cards": "^0.10.4",
39
39
  "@modelcontextprotocol/sdk": "^1.30.0"
40
40
  },