@canonmsg/claude-code-plugin 0.9.5 โ 0.9.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.
- package/dist/host-runtime.d.ts +21 -0
- package/dist/host-runtime.js +80 -2
- package/dist/host.js +82 -14
- package/package.json +3 -3
package/dist/host-runtime.d.ts
CHANGED
|
@@ -37,6 +37,12 @@ interface HostWorkspaceResolverOption {
|
|
|
37
37
|
id: string;
|
|
38
38
|
cwd: string;
|
|
39
39
|
}
|
|
40
|
+
export declare const HOST_ADMISSION_ACTION_CAPABILITIES: Readonly<{
|
|
41
|
+
canStartDirectConversation: false;
|
|
42
|
+
canSendContactRequest: false;
|
|
43
|
+
canApprovePendingContactRequests: false;
|
|
44
|
+
canRejectPendingContactRequests: false;
|
|
45
|
+
}>;
|
|
40
46
|
export declare function buildCanonHostPrompt(input: {
|
|
41
47
|
hostLabel: string;
|
|
42
48
|
content: string;
|
|
@@ -82,6 +88,21 @@ export declare function buildHydratedInboundContext(input: {
|
|
|
82
88
|
hydratedFromPage: boolean;
|
|
83
89
|
};
|
|
84
90
|
export declare function publishHostAgentRuntime(agentId: string, clientType: AgentClientType, runtime: AgentRuntime): Promise<void>;
|
|
91
|
+
export declare function publishHostSessionSnapshots(input: {
|
|
92
|
+
conversationIds: string[];
|
|
93
|
+
agentId: string;
|
|
94
|
+
clientType: AgentClientType;
|
|
95
|
+
runtime: AgentRuntime;
|
|
96
|
+
workspaceOptions: HostWorkspaceResolverOption[];
|
|
97
|
+
defaultCwd: string;
|
|
98
|
+
liveSessionConfigByConversation?: ReadonlyMap<string, {
|
|
99
|
+
model?: string;
|
|
100
|
+
permissionMode?: string;
|
|
101
|
+
workspaceId?: string;
|
|
102
|
+
executionMode?: SessionWorkspaceConfig['executionMode'];
|
|
103
|
+
executionBranch?: string | null;
|
|
104
|
+
}>;
|
|
105
|
+
}): Promise<void>;
|
|
85
106
|
export declare function readHostSessionConfig<TExtra extends string = never>(raw: unknown, extraStringFields?: readonly TExtra[]): (SessionWorkspaceConfig & Partial<Record<TExtra, string>>) | null;
|
|
86
107
|
export declare function loadHostSessionConfig<TExtra extends string = never>(input: {
|
|
87
108
|
conversationId: string;
|
package/dist/host-runtime.js
CHANGED
|
@@ -11,7 +11,13 @@
|
|
|
11
11
|
* behavior here, update that copy too and adjust the shared golden
|
|
12
12
|
* fixture test (`packages/claude-code-plugin/src/host-runtime.test.ts`).
|
|
13
13
|
*/
|
|
14
|
-
import { buildBehaviorPolicyLines, buildParticipationHistorySnapshot, buildWorkSessionsPromptLines, mergeWorkSessionContexts, normalizeOptionalString, readSessionWorkspaceConfig, resolveConfiguredWorkspaceCwd, rtdbRead, rtdbWrite, } from '@canonmsg/core';
|
|
14
|
+
import { buildAgentSessionSnapshot, buildConversationWorktreeSpec, buildBehaviorPolicyLines, buildParticipationHistorySnapshot, buildWorkSessionsPromptLines, mergeWorkSessionContexts, normalizeOptionalString, patchAgentSessionSnapshot, readSessionWorkspaceConfig, resolveConfiguredWorkspaceCwd, rtdbRead, rtdbWrite, } from '@canonmsg/core';
|
|
15
|
+
export const HOST_ADMISSION_ACTION_CAPABILITIES = Object.freeze({
|
|
16
|
+
canStartDirectConversation: false,
|
|
17
|
+
canSendContactRequest: false,
|
|
18
|
+
canApprovePendingContactRequests: false,
|
|
19
|
+
canRejectPendingContactRequests: false,
|
|
20
|
+
});
|
|
15
21
|
export function buildCanonHostPrompt(input) {
|
|
16
22
|
const resolvedWorkSessions = mergeWorkSessionContexts(input.workSession, input.workSessions);
|
|
17
23
|
return [
|
|
@@ -70,7 +76,21 @@ function describeContactCard(card) {
|
|
|
70
76
|
if (card.about)
|
|
71
77
|
parts.push(`about: ${card.about}`);
|
|
72
78
|
const identity = `๐ Contact card: "${card.displayName}" (${parts.join(' ยท ')}).`;
|
|
73
|
-
const
|
|
79
|
+
const missingCapabilities = [
|
|
80
|
+
!HOST_ADMISSION_ACTION_CAPABILITIES.canStartDirectConversation
|
|
81
|
+
? 'start a direct conversation'
|
|
82
|
+
: null,
|
|
83
|
+
!HOST_ADMISSION_ACTION_CAPABILITIES.canSendContactRequest
|
|
84
|
+
? 'send a contact request'
|
|
85
|
+
: null,
|
|
86
|
+
!HOST_ADMISSION_ACTION_CAPABILITIES.canApprovePendingContactRequests
|
|
87
|
+
? 'approve pending requests'
|
|
88
|
+
: null,
|
|
89
|
+
!HOST_ADMISSION_ACTION_CAPABILITIES.canRejectPendingContactRequests
|
|
90
|
+
? 'reject pending requests'
|
|
91
|
+
: null,
|
|
92
|
+
].filter(Boolean).join(', ');
|
|
93
|
+
const hint = `This host can inspect the card, but Canon admission actions are missing here. Missing capabilities: ${missingCapabilities}. Use another Canon surface for userId ${card.userId}.`;
|
|
74
94
|
return `${identity}\n${hint}`;
|
|
75
95
|
}
|
|
76
96
|
function describeAttachment(attachment, materialized) {
|
|
@@ -117,6 +137,64 @@ export async function publishHostAgentRuntime(agentId, clientType, runtime) {
|
|
|
117
137
|
updatedAt: { '.sv': 'timestamp' },
|
|
118
138
|
});
|
|
119
139
|
}
|
|
140
|
+
export async function publishHostSessionSnapshots(input) {
|
|
141
|
+
if (input.conversationIds.length === 0) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
await Promise.all(input.conversationIds.map(async (conversationId) => {
|
|
145
|
+
const persistedConfig = await loadHostSessionConfig({
|
|
146
|
+
conversationId,
|
|
147
|
+
agentId: input.agentId,
|
|
148
|
+
extraStringFields: ['permissionMode'],
|
|
149
|
+
});
|
|
150
|
+
const liveConfig = input.liveSessionConfigByConversation?.get(conversationId) ?? null;
|
|
151
|
+
const mergedConfig = {
|
|
152
|
+
...(persistedConfig ?? {}),
|
|
153
|
+
...(liveConfig ?? {}),
|
|
154
|
+
};
|
|
155
|
+
const snapshot = buildAgentSessionSnapshot({
|
|
156
|
+
conversationId,
|
|
157
|
+
agentId: input.agentId,
|
|
158
|
+
runtime: {
|
|
159
|
+
...input.runtime,
|
|
160
|
+
clientType: input.clientType,
|
|
161
|
+
hostMode: true,
|
|
162
|
+
},
|
|
163
|
+
sessionConfig: {
|
|
164
|
+
...(mergedConfig.model ? { model: mergedConfig.model } : {}),
|
|
165
|
+
...(mergedConfig.permissionMode ? { permissionMode: mergedConfig.permissionMode } : {}),
|
|
166
|
+
...(mergedConfig.workspaceId ? { workspaceId: mergedConfig.workspaceId } : {}),
|
|
167
|
+
...(mergedConfig.executionMode ? { executionMode: mergedConfig.executionMode } : {}),
|
|
168
|
+
},
|
|
169
|
+
lastHeartbeatAt: undefined,
|
|
170
|
+
});
|
|
171
|
+
let executionBranch = liveConfig?.executionBranch ?? null;
|
|
172
|
+
if (!executionBranch && snapshot.executionMode === 'worktree' && snapshot.workspaceId) {
|
|
173
|
+
const workspace = input.workspaceOptions.find((option) => option.id === snapshot.workspaceId);
|
|
174
|
+
if (workspace) {
|
|
175
|
+
executionBranch = buildConversationWorktreeSpec({
|
|
176
|
+
agentId: input.agentId,
|
|
177
|
+
conversationId,
|
|
178
|
+
workspaceCwd: workspace.cwd,
|
|
179
|
+
}).branch;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return patchAgentSessionSnapshot(conversationId, input.agentId, {
|
|
183
|
+
clientType: input.clientType,
|
|
184
|
+
hostMode: true,
|
|
185
|
+
model: snapshot.model ?? null,
|
|
186
|
+
permissionMode: snapshot.permissionMode ?? null,
|
|
187
|
+
workspaceId: snapshot.workspaceId ?? null,
|
|
188
|
+
executionMode: snapshot.executionMode ?? null,
|
|
189
|
+
executionBranch,
|
|
190
|
+
modelOptions: snapshot.modelOptions,
|
|
191
|
+
permissionModeOptions: snapshot.permissionModeOptions,
|
|
192
|
+
workspaceOptions: snapshot.workspaceOptions,
|
|
193
|
+
availableExecutionModes: snapshot.availableExecutionModes,
|
|
194
|
+
lastHeartbeatAt: { '.sv': 'timestamp' },
|
|
195
|
+
});
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
120
198
|
export function readHostSessionConfig(raw, extraStringFields = []) {
|
|
121
199
|
const baseConfig = readSessionWorkspaceConfig(raw);
|
|
122
200
|
if (!raw || typeof raw !== 'object') {
|
package/dist/host.js
CHANGED
|
@@ -26,8 +26,8 @@ import { execFileSync } from 'node:child_process';
|
|
|
26
26
|
import { existsSync } from 'node:fs';
|
|
27
27
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
28
28
|
import { isAnthropicImageAttachment, materializeMessageMedia, toAnthropicImageBlock, } from '@canonmsg/agent-sdk';
|
|
29
|
-
import { CLAUDE_PERMISSION_MODE_OPTIONS, buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, buildPublicWorkspaceOptions, EXECUTION_ENVIRONMENT_MODES, CanonClient, CanonStream, clearTurnState, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, ExecutionEnvironmentError, FINAL_MESSAGE_HANDOFF_MS, normalizeTurnMetadata, prepareConversationEnvironment, resolveCanonAgent, getActiveProfile, releaseLock, initRTDBAuth, rtdbRead, rtdbWrite, writeSessionState, clearSessionState, writeTurnState, releaseConversationEnvironment, } from '@canonmsg/core';
|
|
30
|
-
import { buildCanonHostPrompt, buildHydratedInboundContext, createConversationMetadataLoader, loadHostSessionConfig, publishHostAgentRuntime, renderCanonHostInboundContent, resolveHostWorkspaceCwd, } from './host-runtime.js';
|
|
29
|
+
import { CLAUDE_PERMISSION_MODE_OPTIONS, buildConfiguredWorkspaceOptions, buildConversationEnvironmentKey, buildPlanApprovalRequest, buildQuestionRequest, buildPublicWorkspaceOptions, EXECUTION_ENVIRONMENT_MODES, CanonClient, CanonStream, clearTurnState, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, ExecutionEnvironmentError, FINAL_MESSAGE_HANDOFF_MS, normalizeTurnMetadata, prepareConversationEnvironment, resolveCanonAgent, getActiveProfile, releaseLock, initRTDBAuth, rtdbRead, rtdbWrite, writeSessionState, clearSessionState, writeTurnState, releaseConversationEnvironment, } from '@canonmsg/core';
|
|
30
|
+
import { buildCanonHostPrompt, buildHydratedInboundContext, createConversationMetadataLoader, loadHostSessionConfig, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, resolveHostWorkspaceCwd, } from './host-runtime.js';
|
|
31
31
|
import { buildInboundContextLines, decideAutoReply, } from './inbound-policy.js';
|
|
32
32
|
import { createStreamingBuffer } from './streaming-buffer.js';
|
|
33
33
|
import { runCli } from './cli-entry.js';
|
|
@@ -222,7 +222,7 @@ function createSession(conversationId, environment, agentId, client, onSessionEn
|
|
|
222
222
|
// eslint-disable-next-line prefer-const -- session must be declared before queryOptions but assigned after query()
|
|
223
223
|
let session;
|
|
224
224
|
const REPLY_TIMEOUT_MS = 10 * 60 * 1000; // 10 minutes
|
|
225
|
-
function waitForReply() {
|
|
225
|
+
function waitForReply(type, requestId) {
|
|
226
226
|
// Keep session alive while waiting for user input
|
|
227
227
|
session.lastActivity = Date.now();
|
|
228
228
|
return new Promise((resolve, reject) => {
|
|
@@ -231,6 +231,8 @@ function createSession(conversationId, environment, agentId, client, onSessionEn
|
|
|
231
231
|
reject(new Error('Timed out waiting for user reply'));
|
|
232
232
|
}, REPLY_TIMEOUT_MS);
|
|
233
233
|
session.pendingReply = {
|
|
234
|
+
type,
|
|
235
|
+
requestId,
|
|
234
236
|
resolve: (metadata) => {
|
|
235
237
|
clearTimeout(timer);
|
|
236
238
|
resolve(metadata);
|
|
@@ -260,17 +262,16 @@ function createSession(conversationId, environment, agentId, client, onSessionEn
|
|
|
260
262
|
try {
|
|
261
263
|
const questionId = randomUUID();
|
|
262
264
|
const questions = input.questions ?? [];
|
|
263
|
-
|
|
265
|
+
const questionCard = buildQuestionRequest(questionId, questions);
|
|
266
|
+
await client.sendMessage(conversationId, questionCard.text, {
|
|
264
267
|
metadata: {
|
|
265
|
-
|
|
266
|
-
questionId,
|
|
267
|
-
questions,
|
|
268
|
+
...questionCard.metadata,
|
|
268
269
|
turnSemantics: 'control',
|
|
269
270
|
replyBehavior: 'suppress_auto_reply',
|
|
270
271
|
},
|
|
271
272
|
});
|
|
272
273
|
console.error(`[canon-host] [${conversationId.slice(0, 8)}] Question sent (${questionId.slice(0, 8)})`);
|
|
273
|
-
const reply = await waitForReply();
|
|
274
|
+
const reply = await waitForReply('question_reply', questionId);
|
|
274
275
|
return {
|
|
275
276
|
behavior: 'allow',
|
|
276
277
|
updatedInput: { ...input, answers: reply.answers },
|
|
@@ -283,16 +284,16 @@ function createSession(conversationId, environment, agentId, client, onSessionEn
|
|
|
283
284
|
if (toolName === 'ExitPlanMode') {
|
|
284
285
|
try {
|
|
285
286
|
const planId = randomUUID();
|
|
286
|
-
|
|
287
|
+
const planApproval = buildPlanApprovalRequest(planId);
|
|
288
|
+
await client.sendMessage(conversationId, planApproval.text, {
|
|
287
289
|
metadata: {
|
|
288
|
-
|
|
289
|
-
planId,
|
|
290
|
+
...planApproval.metadata,
|
|
290
291
|
turnSemantics: 'control',
|
|
291
292
|
replyBehavior: 'suppress_auto_reply',
|
|
292
293
|
},
|
|
293
294
|
});
|
|
294
295
|
console.error(`[canon-host] [${conversationId.slice(0, 8)}] Plan approval sent (${planId.slice(0, 8)})`);
|
|
295
|
-
const reply = await waitForReply();
|
|
296
|
+
const reply = await waitForReply('plan_approval_reply', planId);
|
|
296
297
|
if (reply.decision === 'approve') {
|
|
297
298
|
return { behavior: 'allow' };
|
|
298
299
|
}
|
|
@@ -759,12 +760,41 @@ export async function main() {
|
|
|
759
760
|
availableWorkspaces: buildPublicWorkspaceOptions(workspaceOptions),
|
|
760
761
|
availableExecutionModes: hostAvailableExecutionModes,
|
|
761
762
|
};
|
|
763
|
+
const conversationCache = new Map();
|
|
764
|
+
const knownConversationIds = new Set();
|
|
765
|
+
let lastKnownConversationRefreshAt = 0;
|
|
762
766
|
const publishRuntimeHeartbeat = async () => {
|
|
763
767
|
if (!streamConnected)
|
|
764
768
|
return;
|
|
769
|
+
await refreshKnownConversationIds().catch((error) => {
|
|
770
|
+
console.error('[canon-host] Failed to refresh known conversations:', error);
|
|
771
|
+
});
|
|
765
772
|
await publishAgentRuntime(agentId, runtimeDescriptor).catch((error) => {
|
|
766
773
|
console.error('[canon-host] Failed to publish agent runtime:', error);
|
|
767
774
|
});
|
|
775
|
+
await publishHostSessionSnapshots({
|
|
776
|
+
conversationIds: Array.from(knownConversationIds),
|
|
777
|
+
agentId,
|
|
778
|
+
clientType: 'claude-code',
|
|
779
|
+
runtime: runtimeDescriptor,
|
|
780
|
+
workspaceOptions,
|
|
781
|
+
defaultCwd: workingDir,
|
|
782
|
+
liveSessionConfigByConversation: new Map(Array.from(sessions.values()).map((session) => {
|
|
783
|
+
const workspaceId = resolveWorkspaceIdForBaseCwd(session.environment.baseCwd);
|
|
784
|
+
return [
|
|
785
|
+
session.conversationId,
|
|
786
|
+
{
|
|
787
|
+
...(session.state.model ? { model: session.state.model } : {}),
|
|
788
|
+
...(session.state.permissionMode ? { permissionMode: session.state.permissionMode } : {}),
|
|
789
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
790
|
+
executionMode: session.environment.mode,
|
|
791
|
+
executionBranch: session.environment.branch ?? null,
|
|
792
|
+
},
|
|
793
|
+
];
|
|
794
|
+
})),
|
|
795
|
+
}).catch((error) => {
|
|
796
|
+
console.error('[canon-host] Failed to publish session snapshots:', error);
|
|
797
|
+
});
|
|
768
798
|
};
|
|
769
799
|
// โโ Load conversations (informational โ sessions created on demand) โโ
|
|
770
800
|
try {
|
|
@@ -790,6 +820,11 @@ export async function main() {
|
|
|
790
820
|
}
|
|
791
821
|
try {
|
|
792
822
|
const convos = await client.getConversations();
|
|
823
|
+
lastKnownConversationRefreshAt = Date.now();
|
|
824
|
+
for (const conversation of convos) {
|
|
825
|
+
knownConversationIds.add(conversation.id);
|
|
826
|
+
conversationCache.set(conversation.id, conversation);
|
|
827
|
+
}
|
|
793
828
|
console.error(`[canon-host] ${convos.length} conversations`);
|
|
794
829
|
}
|
|
795
830
|
catch {
|
|
@@ -800,11 +835,25 @@ export async function main() {
|
|
|
800
835
|
const pendingSessionCreations = new Map();
|
|
801
836
|
/** Saved SDK session IDs for resume after idle eviction, keyed by conversation + workspace */
|
|
802
837
|
const savedSessionIds = new Map();
|
|
803
|
-
const conversationCache = new Map();
|
|
804
838
|
const { getConversationMeta } = createConversationMetadataLoader({
|
|
805
839
|
client,
|
|
806
840
|
conversationCache,
|
|
807
841
|
});
|
|
842
|
+
function resolveWorkspaceIdForBaseCwd(baseCwd) {
|
|
843
|
+
return workspaceOptions.find((option) => option.cwd === baseCwd)?.id;
|
|
844
|
+
}
|
|
845
|
+
async function refreshKnownConversationIds(force = false) {
|
|
846
|
+
if (!force && Date.now() - lastKnownConversationRefreshAt < HEARTBEAT_MS) {
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
const conversations = await client.getConversations();
|
|
850
|
+
knownConversationIds.clear();
|
|
851
|
+
for (const conversation of conversations) {
|
|
852
|
+
knownConversationIds.add(conversation.id);
|
|
853
|
+
conversationCache.set(conversation.id, conversation);
|
|
854
|
+
}
|
|
855
|
+
lastKnownConversationRefreshAt = Date.now();
|
|
856
|
+
}
|
|
808
857
|
async function loadHydratedInboundContext(input) {
|
|
809
858
|
const [conversation, page] = await Promise.all([
|
|
810
859
|
getConversationMeta(input.conversationId),
|
|
@@ -865,6 +914,7 @@ export async function main() {
|
|
|
865
914
|
}
|
|
866
915
|
}
|
|
867
916
|
async function getOrCreateSession(conversationId) {
|
|
917
|
+
knownConversationIds.add(conversationId);
|
|
868
918
|
const existing = sessions.get(conversationId);
|
|
869
919
|
if (existing && !existing.closed) {
|
|
870
920
|
existing.lastActivity = Date.now();
|
|
@@ -937,15 +987,33 @@ export async function main() {
|
|
|
937
987
|
if (m.senderId === agentId)
|
|
938
988
|
return;
|
|
939
989
|
const convoId = payload.conversationId;
|
|
990
|
+
knownConversationIds.add(convoId);
|
|
940
991
|
// Check for metadata replies (question answers, plan approvals)
|
|
941
992
|
if (m.metadata?.type === 'question_reply' || m.metadata?.type === 'plan_approval_reply') {
|
|
942
993
|
const existingSession = sessions.get(convoId);
|
|
994
|
+
const pendingReply = existingSession?.pendingReply;
|
|
995
|
+
const isOwnerReply = m.isOwner ?? (ownerId != null && m.senderId === ownerId);
|
|
996
|
+
const replyRequestId = m.metadata.type === 'question_reply'
|
|
997
|
+
? m.metadata.questionId
|
|
998
|
+
: m.metadata.planId;
|
|
999
|
+
if (!pendingReply) {
|
|
1000
|
+
console.error(`[canon-host] [${convoId.slice(0, 8)}] Ignoring stale ${m.metadata.type} with no pending request`);
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
if (!isOwnerReply) {
|
|
1004
|
+
console.error(`[canon-host] [${convoId.slice(0, 8)}] Ignoring ${m.metadata.type} from non-owner ${m.senderId}`);
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
if (pendingReply.type !== m.metadata.type || pendingReply.requestId !== replyRequestId) {
|
|
1008
|
+
console.error(`[canon-host] [${convoId.slice(0, 8)}] Ignoring mismatched ${m.metadata.type} (${String(replyRequestId ?? 'missing-id')})`);
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
943
1011
|
if (existingSession?.pendingReply) {
|
|
944
1012
|
const { resolve } = existingSession.pendingReply;
|
|
945
1013
|
existingSession.pendingReply = null;
|
|
946
1014
|
existingSession.lastActivity = Date.now();
|
|
947
1015
|
resolve(m.metadata);
|
|
948
|
-
console.error(`[canon-host] [${convoId.slice(0, 8)}] Reply received (${m.metadata.type})`);
|
|
1016
|
+
console.error(`[canon-host] [${convoId.slice(0, 8)}] Reply received (${m.metadata.type}:${pendingReply.requestId.slice(0, 8)})`);
|
|
949
1017
|
return;
|
|
950
1018
|
}
|
|
951
1019
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/claude-code-plugin",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.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",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@anthropic-ai/claude-agent-sdk": "^0.2.101",
|
|
34
|
-
"@canonmsg/agent-sdk": "^0.8.
|
|
35
|
-
"@canonmsg/core": "^0.7.
|
|
34
|
+
"@canonmsg/agent-sdk": "^0.8.3",
|
|
35
|
+
"@canonmsg/core": "^0.7.5",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|