@canonmsg/claude-code-plugin 0.25.3 → 0.25.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.
@@ -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.25.3",
4
+ "version": "0.25.4",
5
5
  "channels": [
6
6
  {
7
7
  "server": "canon-channel",
package/dist/host.js CHANGED
@@ -35,7 +35,7 @@ import { synthesizeClaudeApprovalDiff } from './approval-diff.js';
35
35
  import { decideClaudeToolPermissionForMode, parseAllowedNonOwnerClaudeTools, } from './tool-policy.js';
36
36
  import { applyClaudeSessionControl, buildClaudeFinalMessageId, claudeModelInfoToOption, confirmClaudeInterrupt, createClaudeInputEnvelope, formatClaudeControlError, isClaudeCustomModelOption, mergeClaudeDiscoveredModelOptions, resolveClaudeTurnResponseRouting, resolveClaudeModelOptions, resetClaudeCompletedTurnState, shouldDeliverClaudeFinal, } from './session-state.js';
37
37
  import { CLAUDE_SUPPORTED_DIALOG_KINDS, buildClaudeAskUserPermissionDenied, buildClaudeAskUserPermissionResult, createClaudeUserDialogCoordinator, parseClaudeAskUserDialog, parseClaudeAskUserToolInput, resolveClaudeUserDialogRequestId, } from './user-dialog.js';
38
- import { collectMissedInboundMessages, STARTUP_RECOVERY_MAX_MESSAGES, STARTUP_RECOVERY_PAGE_SIZE, } from './startup-recovery.js';
38
+ import { collectMissedInboundMessages, createReconnectRecoveryGate, STARTUP_RECOVERY_MAX_MESSAGES, STARTUP_RECOVERY_PAGE_SIZE, } from './startup-recovery.js';
39
39
  function parseRuntimeVisibilityPreset(value) {
40
40
  return value === 'normal' || value === 'minimal' || value === 'full' ? value : undefined;
41
41
  }
@@ -2663,6 +2663,7 @@ export async function main() {
2663
2663
  });
2664
2664
  return recoveryInFlight;
2665
2665
  }
2666
+ const shouldRecoverAfterStreamConnect = createReconnectRecoveryGate();
2666
2667
  await recoverMissedInboundMessages();
2667
2668
  // ── Connect SSE stream for inbound Canon messages ──
2668
2669
  const stream = new CanonStream({
@@ -2799,7 +2800,9 @@ export async function main() {
2799
2800
  onConnected: () => {
2800
2801
  streamConnected = true;
2801
2802
  void publishRuntimeHeartbeat();
2802
- void recoverMissedInboundMessages();
2803
+ if (shouldRecoverAfterStreamConnect()) {
2804
+ void recoverMissedInboundMessages();
2805
+ }
2803
2806
  console.error('[canon-host] SSE connected');
2804
2807
  },
2805
2808
  onDisconnected: () => {
@@ -40,6 +40,11 @@ export interface StartupRecoveryResult<TPage extends StartupRecoveryPage> {
40
40
  /** First page fetched — reusable as hydration context for recovered turns. */
41
41
  newestPage: TPage;
42
42
  }
43
+ /**
44
+ * Startup recovery runs before the stream starts. The first SSE connection
45
+ * therefore needs no second pass, while later reconnects still need catch-up.
46
+ */
47
+ export declare function createReconnectRecoveryGate(): () => boolean;
43
48
  export declare function collectMissedInboundMessages<TPage extends StartupRecoveryPage>(input: {
44
49
  fetchPage: (before?: string) => Promise<TPage>;
45
50
  cursor: string | null | undefined;
@@ -11,6 +11,18 @@
11
11
  */
12
12
  export const STARTUP_RECOVERY_PAGE_SIZE = 25;
13
13
  export const STARTUP_RECOVERY_MAX_MESSAGES = 500;
14
+ /**
15
+ * Startup recovery runs before the stream starts. The first SSE connection
16
+ * therefore needs no second pass, while later reconnects still need catch-up.
17
+ */
18
+ export function createReconnectRecoveryGate() {
19
+ let hasConnected = false;
20
+ return () => {
21
+ const shouldRecover = hasConnected;
22
+ hasConnected = true;
23
+ return shouldRecover;
24
+ };
25
+ }
14
26
  export async function collectMissedInboundMessages(input) {
15
27
  const maxMessages = input.maxMessages ?? STARTUP_RECOVERY_MAX_MESSAGES;
16
28
  const newestPage = await input.fetchPage();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/claude-code-plugin",
3
- "version": "0.25.3",
3
+ "version": "0.25.4",
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",