@canonmsg/claude-code-plugin 0.25.4 → 0.25.6

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.4",
4
+ "version": "0.25.6",
5
5
  "channels": [
6
6
  {
7
7
  "server": "canon-channel",
package/dist/host.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { type SDKControlReloadPluginsResponse } from '@anthropic-ai/claude-agent-sdk';
2
+ import { type PermissionResult, type SDKControlReloadPluginsResponse } from '@anthropic-ai/claude-agent-sdk';
3
3
  import { type CanonRuntimeCommandDescriptor } from '@canonmsg/core';
4
+ export declare function buildClaudePlanAllowResult(input: Record<string, unknown>): PermissionResult;
4
5
  /**
5
6
  * Claude Code's own slash commands (built-ins, plugins, project .claude/
6
7
  * commands) are executable when sent as prompt text, so the runtime's command
package/dist/host.js CHANGED
@@ -92,6 +92,9 @@ let runtimeMetadata = {
92
92
  let runtimeMetadataRefresh = null;
93
93
  /** Bound on native slash commands exposed to the composer palette. */
94
94
  const MAX_NATIVE_SLASH_COMMANDS = 50;
95
+ export function buildClaudePlanAllowResult(input) {
96
+ return { behavior: 'allow', updatedInput: input };
97
+ }
95
98
  /**
96
99
  * Claude Code's own slash commands (built-ins, plugins, project .claude/
97
100
  * commands) are executable when sent as prompt text, so the runtime's command
@@ -841,25 +844,6 @@ function createSession(conversationId, environment, agentId, client, typingSigna
841
844
  }
842
845
  });
843
846
  }
844
- function waitForReply(type, requestId, responseUserId) {
845
- // Keep session alive while waiting for user input
846
- session.lastActivity = Date.now();
847
- return new Promise((resolve, reject) => {
848
- const timer = setTimeout(() => {
849
- session.pendingReply = null;
850
- reject(new Error('Timed out waiting for user reply'));
851
- }, REPLY_TIMEOUT_MS);
852
- session.pendingReply = {
853
- type,
854
- requestId,
855
- responseUserId,
856
- resolve: (metadata) => {
857
- clearTimeout(timer);
858
- resolve(metadata);
859
- },
860
- };
861
- });
862
- }
863
847
  function buildArtifactMediaMetadata() {
864
848
  return {
865
849
  ...(session.currentTurnId ? { turnId: session.currentTurnId } : {}),
@@ -939,24 +923,24 @@ function createSession(conversationId, environment, agentId, client, typingSigna
939
923
  const planBody = typeof input.plan === 'string' && input.plan.trim()
940
924
  ? input.plan.trim()
941
925
  : undefined;
942
- // Route plan-CREATE through the unified spine (`/runtime-plan/request`):
943
- // seeds the server-owned pending node/attention/state and authors the
944
- // `plan_approval` card. Resolution is UNCHANGED — the gate still blocks
945
- // on the server-authored `plan_approval_reply` below.
946
- await client.createRuntimePlanRequest({
947
- conversationId,
948
- planId,
926
+ const reply = await config.runtimeInputManager.request('plan', conversationId, {
949
927
  title: 'Plan ready for review.',
950
928
  summary: 'Claude has prepared a plan and is asking permission to continue.',
951
929
  ...(planBody ? { body: planBody } : {}),
952
930
  responseUserId: turnResponseRouting.responseUserId,
953
931
  ...(allowedPrompts.length > 0 ? { allowedPrompts } : {}),
954
932
  ...(session.currentTurnId ? { turnId: session.currentTurnId } : {}),
933
+ }, {
934
+ requestId: planId,
955
935
  expiresAt: Date.now() + REPLY_TIMEOUT_MS,
936
+ responderPolicy: 'infer',
937
+ signal: options.signal,
938
+ onCreated: () => {
939
+ session.lastActivity = Date.now();
940
+ console.error(`[canon-host] [${conversationId.slice(0, 8)}] Plan approval sent (${planId.slice(0, 8)})`);
941
+ },
956
942
  });
957
- console.error(`[canon-host] [${conversationId.slice(0, 8)}] Plan approval sent (${planId.slice(0, 8)})`);
958
- const reply = await waitForReply('plan_approval_reply', planId, turnResponseRouting.responseUserId);
959
- if (reply.decision === 'approve') {
943
+ if (reply.status === 'approve') {
960
944
  // Honor opt-in selective grants: when the card sent an explicit
961
945
  // granted subset, pre-approve those tools as session rules so they
962
946
  // do not re-prompt. Owner-turn only; absent grants preserve the
@@ -998,15 +982,23 @@ function createSession(conversationId, environment, agentId, client, typingSigna
998
982
  // instead of waiting for the next 30s heartbeat (lag fix).
999
983
  config.publishSessionSnapshots?.([conversationId]);
1000
984
  }
1001
- return { behavior: 'allow' };
985
+ return buildClaudePlanAllowResult(input);
1002
986
  }
1003
- if (reply.decision === 'reject') {
987
+ if (reply.status === 'reject') {
1004
988
  return {
1005
989
  behavior: 'deny',
1006
990
  message: reply.feedback?.trim()
1007
991
  || 'Plan declined — keep planning and wait for guidance before proceeding.',
1008
992
  };
1009
993
  }
994
+ if (reply.status === 'cancelled' || reply.status === 'timeout') {
995
+ return {
996
+ behavior: 'deny',
997
+ message: reply.status === 'timeout'
998
+ ? 'No reply received (timed out)'
999
+ : 'The plan review was cancelled.',
1000
+ };
1001
+ }
1010
1002
  return {
1011
1003
  behavior: 'deny',
1012
1004
  message: reply.feedback?.trim() || 'User requested changes to the plan.',
@@ -1093,7 +1085,6 @@ function createSession(conversationId, environment, agentId, client, typingSigna
1093
1085
  controlInterruptPending: false,
1094
1086
  closed: false,
1095
1087
  sdkSessionId: resumeSessionId || null,
1096
- pendingReply: null,
1097
1088
  writeState: () => writeState(),
1098
1089
  writeTurn: () => writeTurn(),
1099
1090
  clearStreaming: () => clearStreaming(),
@@ -2559,28 +2550,14 @@ export async function main() {
2559
2550
  return true;
2560
2551
  }
2561
2552
  }
2562
- if (message.metadata?.type !== 'plan_approval_reply')
2563
- return false;
2564
- const existingSession = sessions.get(conversationId);
2565
- const pendingReply = existingSession?.pendingReply;
2566
- const replyRequestId = message.metadata.planId;
2567
- if (!pendingReply) {
2568
- console.error(`[canon-host] [${conversationId.slice(0, 8)}] Ignoring stale ${message.metadata.type} with no pending request`);
2569
- return true;
2570
- }
2571
- if (message.senderId !== pendingReply.responseUserId) {
2572
- console.error(`[canon-host] [${conversationId.slice(0, 8)}] Ignoring ${message.metadata.type} from unexpected responder ${message.senderId}`);
2573
- return true;
2574
- }
2575
- if (pendingReply.type !== message.metadata.type || pendingReply.requestId !== replyRequestId) {
2576
- console.error(`[canon-host] [${conversationId.slice(0, 8)}] Ignoring mismatched ${message.metadata.type} (${String(replyRequestId ?? 'missing-id')})`);
2577
- return true;
2553
+ const consumed = runtimeInputManager.handleMessage(conversationId, {
2554
+ senderId: message.senderId,
2555
+ metadata: message.metadata,
2556
+ });
2557
+ if (consumed) {
2558
+ console.error(`[canon-host] [${conversationId.slice(0, 8)}] Runtime response receipt woke canonical polling`);
2578
2559
  }
2579
- existingSession.pendingReply = null;
2580
- existingSession.lastActivity = Date.now();
2581
- pendingReply.resolve(message.metadata);
2582
- console.error(`[canon-host] [${conversationId.slice(0, 8)}] Reply received (${message.metadata.type}:${pendingReply.requestId.slice(0, 8)})`);
2583
- return true;
2560
+ return consumed;
2584
2561
  }
2585
2562
  function persistedConversationCursors(conversationId) {
2586
2563
  const canonicalCursor = loadRuntimeSessionState(runtimeId, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canonmsg/claude-code-plugin",
3
- "version": "0.25.4",
3
+ "version": "0.25.6",
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",
@@ -33,7 +33,7 @@
33
33
  "@anthropic-ai/claude-agent-sdk": "0.3.204",
34
34
  "@canonmsg/agent-sdk": "^5.1.1",
35
35
  "@canonmsg/coding-agent-host": "^0.2.2",
36
- "@canonmsg/core": "^4.2.2",
36
+ "@canonmsg/core": "^4.2.3",
37
37
  "@modelcontextprotocol/sdk": "^1.29.0"
38
38
  },
39
39
  "engines": {