@canonmsg/claude-code-plugin 0.12.7 → 0.12.8
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.js +22 -10
- package/dist/server.js +105 -134
- package/package.json +2 -2
package/dist/host.js
CHANGED
|
@@ -654,6 +654,9 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
654
654
|
const questions = input.questions ?? [];
|
|
655
655
|
const questionCard = buildQuestionRequest(questionId, questions);
|
|
656
656
|
await client.sendMessage(conversationId, questionCard.text, {
|
|
657
|
+
...(session.activeSelfContextId
|
|
658
|
+
? { selfContextId: session.activeSelfContextId }
|
|
659
|
+
: {}),
|
|
657
660
|
metadata: {
|
|
658
661
|
...questionCard.metadata,
|
|
659
662
|
turnSemantics: 'control',
|
|
@@ -699,6 +702,9 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
699
702
|
summary: 'Claude has prepared a plan and is asking permission to continue.',
|
|
700
703
|
});
|
|
701
704
|
await client.sendMessage(conversationId, planApproval.text, {
|
|
705
|
+
...(session.activeSelfContextId
|
|
706
|
+
? { selfContextId: session.activeSelfContextId }
|
|
707
|
+
: {}),
|
|
702
708
|
metadata: {
|
|
703
709
|
...planApproval.metadata,
|
|
704
710
|
turnSemantics: 'control',
|
|
@@ -760,6 +766,7 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
760
766
|
turnState: 'idle',
|
|
761
767
|
currentTurnId: null,
|
|
762
768
|
currentTurnOpenedAt: null,
|
|
769
|
+
activeSelfContextId: null,
|
|
763
770
|
lastAcceptedIntent: null,
|
|
764
771
|
lastActivity: Date.now(),
|
|
765
772
|
typingKeepaliveTimer: null,
|
|
@@ -875,6 +882,9 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
875
882
|
try {
|
|
876
883
|
await client.sendMessage(conversationId, finalText, {
|
|
877
884
|
messageId: finalMessageId,
|
|
885
|
+
...(session.activeSelfContextId
|
|
886
|
+
? { selfContextId: session.activeSelfContextId }
|
|
887
|
+
: {}),
|
|
878
888
|
metadata: {
|
|
879
889
|
turnId: session.currentTurnId,
|
|
880
890
|
turnKey: deliverTurn.turnKey,
|
|
@@ -1757,7 +1767,7 @@ export async function main() {
|
|
|
1757
1767
|
isOwner,
|
|
1758
1768
|
});
|
|
1759
1769
|
const behavior = input.hydratedPage?.behavior ?? hydrated.behavior;
|
|
1760
|
-
const
|
|
1770
|
+
const selfContexts = input.hydratedPage?.selfContexts ?? hydrated.selfContexts;
|
|
1761
1771
|
const participantContext = hydrated.participantContext;
|
|
1762
1772
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
1763
1773
|
if (!autoReply.allow) {
|
|
@@ -1773,6 +1783,7 @@ export async function main() {
|
|
|
1773
1783
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
1774
1784
|
console.error(`[canon-host] [${input.conversationId.slice(0, 8)}] Failed to create recovered session: ${message}`);
|
|
1775
1785
|
await client.sendMessage(input.conversationId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
1786
|
+
...(selfContexts[0]?.id ? { selfContextId: selfContexts[0].id } : {}),
|
|
1776
1787
|
metadata: {
|
|
1777
1788
|
turnSemantics: 'turn_complete',
|
|
1778
1789
|
turnComplete: true,
|
|
@@ -1782,6 +1793,7 @@ export async function main() {
|
|
|
1782
1793
|
return;
|
|
1783
1794
|
}
|
|
1784
1795
|
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
1796
|
+
session.activeSelfContextId = selfContexts[0]?.id ?? null;
|
|
1785
1797
|
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
1786
1798
|
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
1787
1799
|
const promptText = buildCanonPrompt({
|
|
@@ -1789,8 +1801,7 @@ export async function main() {
|
|
|
1789
1801
|
conversationId: input.conversationId,
|
|
1790
1802
|
participantContext,
|
|
1791
1803
|
behavior,
|
|
1792
|
-
|
|
1793
|
-
workSessions,
|
|
1804
|
+
selfContexts,
|
|
1794
1805
|
session,
|
|
1795
1806
|
});
|
|
1796
1807
|
const messageContent = await buildCanonUserContent({ promptText, materialized });
|
|
@@ -1902,11 +1913,11 @@ export async function main() {
|
|
|
1902
1913
|
isOwner,
|
|
1903
1914
|
});
|
|
1904
1915
|
const behavior = payload.behavior ?? hydrated.behavior;
|
|
1905
|
-
const
|
|
1906
|
-
? hydrated.
|
|
1907
|
-
: Array.isArray(payload.
|
|
1908
|
-
? payload.
|
|
1909
|
-
: hydrated.
|
|
1916
|
+
const selfContexts = hydrated.hydratedFromPage
|
|
1917
|
+
? hydrated.selfContexts
|
|
1918
|
+
: Array.isArray(payload.selfContexts)
|
|
1919
|
+
? payload.selfContexts
|
|
1920
|
+
: hydrated.selfContexts;
|
|
1910
1921
|
const participantContext = hydrated.participantContext;
|
|
1911
1922
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
1912
1923
|
if (!autoReply.allow) {
|
|
@@ -1923,6 +1934,7 @@ export async function main() {
|
|
|
1923
1934
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
1924
1935
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Failed to create session: ${message}`);
|
|
1925
1936
|
await client.sendMessage(convoId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
1937
|
+
...(selfContexts[0]?.id ? { selfContextId: selfContexts[0].id } : {}),
|
|
1926
1938
|
metadata: {
|
|
1927
1939
|
turnSemantics: 'turn_complete',
|
|
1928
1940
|
turnComplete: true,
|
|
@@ -1932,6 +1944,7 @@ export async function main() {
|
|
|
1932
1944
|
return;
|
|
1933
1945
|
}
|
|
1934
1946
|
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
1947
|
+
session.activeSelfContextId = selfContexts[0]?.id ?? null;
|
|
1935
1948
|
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
1936
1949
|
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
1937
1950
|
const promptText = buildCanonPrompt({
|
|
@@ -1939,8 +1952,7 @@ export async function main() {
|
|
|
1939
1952
|
conversationId: convoId,
|
|
1940
1953
|
participantContext,
|
|
1941
1954
|
behavior,
|
|
1942
|
-
|
|
1943
|
-
workSessions,
|
|
1955
|
+
selfContexts,
|
|
1944
1956
|
session,
|
|
1945
1957
|
});
|
|
1946
1958
|
const messageContent = await buildCanonUserContent({ promptText, materialized });
|
package/dist/server.js
CHANGED
|
@@ -10,7 +10,8 @@ import { setDefaultResultOrder } from 'node:dns';
|
|
|
10
10
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
11
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
12
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
-
import { CanonClient, CanonStream, ApprovalManager, buildLocalRuntimeId, getActiveProfileLock, markLocalRuntimeStopped, loadProfiles, isProfileLocked, resolveCanonAgent, getActiveProfile, releaseLock, upsertLocalRuntimeEntry, initRTDBAuth, writeSessionState, clearSessionState, } from '@canonmsg/core';
|
|
13
|
+
import { CanonClient, CanonStream, ApprovalManager, buildLocalRuntimeId, getActiveProfileLock, markLocalRuntimeStopped, loadProfiles, isProfileLocked, resolveCanonAgent, getActiveProfile, releaseLock, upsertLocalRuntimeEntry, initRTDBAuth, writeSessionState, clearSessionState, renderCanonHostInboundContent, } from '@canonmsg/core';
|
|
14
|
+
import { materializeMessageMedia, sendMediaFileMessage, } from '@canonmsg/agent-sdk';
|
|
14
15
|
import { ApprovalHttpServer } from './approval-server.js';
|
|
15
16
|
import { runCli } from './cli-entry.js';
|
|
16
17
|
const HELP = `canon-channel-server — Claude Code MCP channel server for Canon
|
|
@@ -49,31 +50,8 @@ function getPrimaryAttachment(message) {
|
|
|
49
50
|
return attachment;
|
|
50
51
|
return null;
|
|
51
52
|
}
|
|
52
|
-
function renderInboundContent(message) {
|
|
53
|
-
|
|
54
|
-
const attachment = getPrimaryAttachment(message);
|
|
55
|
-
// MCP channel mode does not yet materialize media into local files. Surface
|
|
56
|
-
// a placeholder that tells the model media *was* attached without inlining a
|
|
57
|
-
// Firebase Storage URL: the model cannot fetch it, and reasoning about a
|
|
58
|
-
// URL-as-string leads to hallucinated image descriptions. The `attachment_*`
|
|
59
|
-
// fields on the structured `meta` sidechannel still carry the URL for UI /
|
|
60
|
-
// telemetry consumers.
|
|
61
|
-
let placeholder = null;
|
|
62
|
-
if (attachment?.kind === 'audio') {
|
|
63
|
-
const duration = attachment.durationMs ? ` (${Math.round(attachment.durationMs / 1000)}s)` : '';
|
|
64
|
-
placeholder = `[Voice message${duration} — ask sender to resend if you need the audio]`;
|
|
65
|
-
}
|
|
66
|
-
else if (attachment?.kind === 'image') {
|
|
67
|
-
placeholder = '[Image attached — not yet materialized into this session; ask sender to describe if needed]';
|
|
68
|
-
}
|
|
69
|
-
else if (attachment?.kind === 'file') {
|
|
70
|
-
const label = attachment.fileName || 'File';
|
|
71
|
-
placeholder = `[File: ${label} — not yet materialized into this session]`;
|
|
72
|
-
}
|
|
73
|
-
if (placeholder) {
|
|
74
|
-
return content ? `${placeholder}\n${content}` : placeholder;
|
|
75
|
-
}
|
|
76
|
-
return content;
|
|
53
|
+
function renderInboundContent(message, materialized) {
|
|
54
|
+
return renderCanonHostInboundContent(message, materialized);
|
|
77
55
|
}
|
|
78
56
|
// ── Tool definitions ───────────────────────────────────────────────────
|
|
79
57
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
@@ -127,54 +105,58 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
127
105
|
type: 'string',
|
|
128
106
|
description: 'File URL (when content_type is file)',
|
|
129
107
|
},
|
|
108
|
+
media_path: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Local image/audio/file path to upload and send',
|
|
111
|
+
},
|
|
130
112
|
file_name: {
|
|
131
113
|
type: 'string',
|
|
132
114
|
description: 'Optional display filename for file attachments',
|
|
133
115
|
},
|
|
116
|
+
mime_type: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
description: 'Optional MIME type for media_path uploads',
|
|
119
|
+
},
|
|
120
|
+
duration_ms: {
|
|
121
|
+
type: 'number',
|
|
122
|
+
description: 'Optional audio duration in milliseconds for media_path uploads',
|
|
123
|
+
},
|
|
134
124
|
},
|
|
135
125
|
required: ['conversation_id'],
|
|
136
126
|
},
|
|
137
127
|
},
|
|
138
128
|
{
|
|
139
|
-
name: '
|
|
140
|
-
description: 'Send a message into another Canon conversation
|
|
129
|
+
name: 'send_contextual_message',
|
|
130
|
+
description: 'Send a message into another Canon conversation or contact with private cross-session self-context',
|
|
141
131
|
inputSchema: {
|
|
142
132
|
type: 'object',
|
|
143
133
|
properties: {
|
|
144
134
|
source_conversation_id: {
|
|
145
135
|
type: 'string',
|
|
146
|
-
description: 'The
|
|
136
|
+
description: 'The Canon conversation where this cross-session intent originated',
|
|
147
137
|
},
|
|
148
138
|
target_conversation_id: {
|
|
149
139
|
type: 'string',
|
|
150
|
-
description: 'The destination conversation to send into',
|
|
140
|
+
description: 'The destination Canon conversation to send into',
|
|
151
141
|
},
|
|
152
|
-
|
|
142
|
+
target_user_id: {
|
|
153
143
|
type: 'string',
|
|
154
|
-
description: '
|
|
144
|
+
description: 'The destination Canon user/contact to reach out to',
|
|
155
145
|
},
|
|
156
|
-
|
|
146
|
+
text: {
|
|
157
147
|
type: 'string',
|
|
158
|
-
description: '
|
|
159
|
-
},
|
|
160
|
-
create_work_session: {
|
|
161
|
-
type: 'object',
|
|
162
|
-
description: 'Optional initial work-session fields when creating a new shared task',
|
|
163
|
-
},
|
|
164
|
-
source_context: {
|
|
165
|
-
type: 'object',
|
|
166
|
-
description: 'Optional scoped context patch for the source conversation',
|
|
148
|
+
description: 'Message text to send',
|
|
167
149
|
},
|
|
168
|
-
|
|
150
|
+
self_context: {
|
|
169
151
|
type: 'object',
|
|
170
|
-
description: '
|
|
152
|
+
description: 'Required { type: "cross_session", context: "why I am saying this here" }',
|
|
171
153
|
},
|
|
172
154
|
message_options: {
|
|
173
155
|
type: 'object',
|
|
174
|
-
description: 'Optional Canon send options for the
|
|
156
|
+
description: 'Optional Canon send options for the contextual outbound message',
|
|
175
157
|
},
|
|
176
158
|
},
|
|
177
|
-
required: ['source_conversation_id', '
|
|
159
|
+
required: ['source_conversation_id', 'text', 'self_context'],
|
|
178
160
|
},
|
|
179
161
|
},
|
|
180
162
|
{
|
|
@@ -256,14 +238,39 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
256
238
|
const imageUrl = typeof args.image_url === 'string' ? args.image_url : null;
|
|
257
239
|
const audioUrl = typeof args.audio_url === 'string' ? args.audio_url : null;
|
|
258
240
|
const fileUrl = typeof args.file_url === 'string' ? args.file_url : null;
|
|
241
|
+
const mediaPath = typeof args.media_path === 'string' ? args.media_path : null;
|
|
259
242
|
const fileName = typeof args.file_name === 'string' ? args.file_name : null;
|
|
243
|
+
const mimeType = typeof args.mime_type === 'string' ? args.mime_type : null;
|
|
244
|
+
const durationMs = typeof args.duration_ms === 'number' ? args.duration_ms : null;
|
|
245
|
+
const metadata = TURN_COMPLETE_METADATA;
|
|
246
|
+
if (mediaPath) {
|
|
247
|
+
const result = await sendMediaFileMessage(client, conversationId, mediaPath, text, {
|
|
248
|
+
...(fileName ? { fileName } : {}),
|
|
249
|
+
...(mimeType ? { mimeType } : {}),
|
|
250
|
+
...(durationMs != null ? { durationMs } : {}),
|
|
251
|
+
metadata,
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
content: [
|
|
255
|
+
{
|
|
256
|
+
type: 'text',
|
|
257
|
+
text: `Message sent (${result.messageId})`,
|
|
258
|
+
},
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
}
|
|
260
262
|
if (contentType === 'image' && imageUrl) {
|
|
261
263
|
opts.contentType = 'image';
|
|
262
264
|
opts.attachments = [{ kind: 'image', url: imageUrl }];
|
|
263
265
|
}
|
|
264
266
|
else if (contentType === 'audio' && audioUrl) {
|
|
265
267
|
opts.contentType = 'audio';
|
|
266
|
-
opts.attachments = [{
|
|
268
|
+
opts.attachments = [{
|
|
269
|
+
kind: 'audio',
|
|
270
|
+
url: audioUrl,
|
|
271
|
+
...(durationMs != null ? { durationMs } : {}),
|
|
272
|
+
...(mimeType ? { mimeType } : {}),
|
|
273
|
+
}];
|
|
267
274
|
}
|
|
268
275
|
else if (contentType === 'file' || fileUrl) {
|
|
269
276
|
opts.contentType = 'file';
|
|
@@ -272,6 +279,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
272
279
|
kind: 'file',
|
|
273
280
|
url: fileUrl,
|
|
274
281
|
...(fileName ? { fileName } : {}),
|
|
282
|
+
...(mimeType ? { mimeType } : {}),
|
|
275
283
|
}];
|
|
276
284
|
}
|
|
277
285
|
}
|
|
@@ -280,7 +288,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
280
288
|
}
|
|
281
289
|
opts.metadata = {
|
|
282
290
|
...(opts.metadata ?? {}),
|
|
283
|
-
...
|
|
291
|
+
...metadata,
|
|
284
292
|
};
|
|
285
293
|
const result = await client.sendMessage(conversationId, text, opts);
|
|
286
294
|
return {
|
|
@@ -292,50 +300,32 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
292
300
|
],
|
|
293
301
|
};
|
|
294
302
|
}
|
|
295
|
-
case '
|
|
303
|
+
case 'send_contextual_message': {
|
|
296
304
|
const sourceConversationId = args.source_conversation_id;
|
|
297
|
-
const targetConversationId = args.target_conversation_id
|
|
298
|
-
|
|
299
|
-
const workSessionId = typeof args.work_session_id === 'string' ? args.work_session_id : undefined;
|
|
300
|
-
const createWorkSession = typeof args.create_work_session === 'object' && args.create_work_session != null
|
|
301
|
-
? args.create_work_session
|
|
302
|
-
: undefined;
|
|
303
|
-
const sourceContext = typeof args.source_context === 'object' && args.source_context != null
|
|
304
|
-
? args.source_context
|
|
305
|
+
const targetConversationId = typeof args.target_conversation_id === 'string'
|
|
306
|
+
? args.target_conversation_id
|
|
305
307
|
: undefined;
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
+
const targetUserId = typeof args.target_user_id === 'string' ? args.target_user_id : undefined;
|
|
309
|
+
const text = args.text;
|
|
310
|
+
const selfContext = typeof args.self_context === 'object' && args.self_context != null
|
|
311
|
+
? args.self_context
|
|
308
312
|
: undefined;
|
|
309
313
|
const messageOptions = typeof args.message_options === 'object' && args.message_options != null
|
|
310
314
|
? args.message_options
|
|
311
315
|
: undefined;
|
|
312
|
-
const
|
|
313
|
-
const result = await client.
|
|
316
|
+
const contextualMessageOptions = messageOptions;
|
|
317
|
+
const result = await client.sendContextualMessage({
|
|
314
318
|
sourceConversationId,
|
|
315
|
-
targetConversationId,
|
|
319
|
+
...(targetConversationId ? { targetConversationId } : {}),
|
|
320
|
+
...(targetUserId ? { targetUserId } : {}),
|
|
316
321
|
text,
|
|
317
|
-
|
|
318
|
-
...(
|
|
319
|
-
? {
|
|
320
|
-
createWorkSession: createWorkSession,
|
|
321
|
-
}
|
|
322
|
-
: {}),
|
|
323
|
-
...(sourceContext
|
|
324
|
-
? {
|
|
325
|
-
sourceContext: sourceContext,
|
|
326
|
-
}
|
|
327
|
-
: {}),
|
|
328
|
-
...(targetContext
|
|
329
|
-
? {
|
|
330
|
-
targetContext: targetContext,
|
|
331
|
-
}
|
|
332
|
-
: {}),
|
|
333
|
-
...(linkedMessageOptions
|
|
322
|
+
selfContext: selfContext,
|
|
323
|
+
...(contextualMessageOptions
|
|
334
324
|
? {
|
|
335
325
|
messageOptions: {
|
|
336
|
-
...
|
|
326
|
+
...contextualMessageOptions,
|
|
337
327
|
metadata: {
|
|
338
|
-
...(
|
|
328
|
+
...(contextualMessageOptions.metadata ?? {}),
|
|
339
329
|
...TURN_COMPLETE_METADATA,
|
|
340
330
|
},
|
|
341
331
|
},
|
|
@@ -346,7 +336,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
346
336
|
content: [
|
|
347
337
|
{
|
|
348
338
|
type: 'text',
|
|
349
|
-
text:
|
|
339
|
+
text: result.status === 'messaged'
|
|
340
|
+
? `Contextual message sent (${result.messageId}) via self-context ${result.selfContextId}`
|
|
341
|
+
: `Contextual message not sent: ${result.status}`,
|
|
350
342
|
},
|
|
351
343
|
],
|
|
352
344
|
};
|
|
@@ -454,58 +446,30 @@ async function handleInboundMessage(payload) {
|
|
|
454
446
|
meta.behavior_instructions = payload.behavior.instructions.join('\n\n');
|
|
455
447
|
}
|
|
456
448
|
}
|
|
457
|
-
if (
|
|
458
|
-
meta.
|
|
459
|
-
|
|
460
|
-
meta.work_session_title = m.workSession.title;
|
|
461
|
-
if (m.workSession.objective)
|
|
462
|
-
meta.work_session_objective = m.workSession.objective;
|
|
463
|
-
if (m.workSession.status)
|
|
464
|
-
meta.work_session_status = m.workSession.status;
|
|
465
|
-
if (m.workSession.currentConversationRole) {
|
|
466
|
-
meta.work_session_role = m.workSession.currentConversationRole;
|
|
467
|
-
}
|
|
468
|
-
if (m.workSession.representation) {
|
|
469
|
-
meta.work_session_representation = m.workSession.representation;
|
|
470
|
-
}
|
|
471
|
-
if (m.workSession.disclosure) {
|
|
472
|
-
meta.work_session_disclosure = m.workSession.disclosure;
|
|
473
|
-
}
|
|
474
|
-
if (m.workSession.summary)
|
|
475
|
-
meta.work_session_summary = m.workSession.summary;
|
|
476
|
-
if (m.workSession.sourceConversationLabel) {
|
|
477
|
-
meta.work_session_source_conversation = m.workSession.sourceConversationLabel;
|
|
478
|
-
}
|
|
479
|
-
else if (m.workSession.sourceConversationId) {
|
|
480
|
-
meta.work_session_source_conversation = m.workSession.sourceConversationId;
|
|
481
|
-
}
|
|
482
|
-
if (m.workSession.sourceParticipantLabel) {
|
|
483
|
-
meta.work_session_source_participant = m.workSession.sourceParticipantLabel;
|
|
484
|
-
}
|
|
485
|
-
else if (m.workSession.sourceParticipantId) {
|
|
486
|
-
meta.work_session_source_participant = m.workSession.sourceParticipantId;
|
|
487
|
-
}
|
|
488
|
-
if (Array.isArray(m.workSession.visibleFacts) && m.workSession.visibleFacts.length > 0) {
|
|
489
|
-
meta.work_session_visible_facts = m.workSession.visibleFacts.join('\n\n');
|
|
490
|
-
}
|
|
491
|
-
if (Array.isArray(m.workSession.pendingQuestions)
|
|
492
|
-
&& m.workSession.pendingQuestions.length > 0) {
|
|
493
|
-
meta.work_session_pending_questions = m.workSession.pendingQuestions.join('\n\n');
|
|
494
|
-
}
|
|
495
|
-
if (Array.isArray(m.workSession.disclosureNotes)
|
|
496
|
-
&& m.workSession.disclosureNotes.length > 0) {
|
|
497
|
-
meta.work_session_disclosure_notes = m.workSession.disclosureNotes.join('\n\n');
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
if (Array.isArray(payload.workSessions) && payload.workSessions.length > 0) {
|
|
501
|
-
meta.active_work_session_ids = payload.workSessions
|
|
502
|
-
.map((workSession) => workSession.id)
|
|
449
|
+
if (Array.isArray(payload.selfContexts) && payload.selfContexts.length > 0) {
|
|
450
|
+
meta.self_context_ids = payload.selfContexts
|
|
451
|
+
.map((selfContext) => selfContext.id)
|
|
503
452
|
.join('\n');
|
|
504
|
-
|
|
505
|
-
.map((
|
|
506
|
-
.
|
|
507
|
-
|
|
508
|
-
|
|
453
|
+
meta.self_context_types = payload.selfContexts
|
|
454
|
+
.map((selfContext) => selfContext.type)
|
|
455
|
+
.join('\n');
|
|
456
|
+
meta.self_context = payload.selfContexts
|
|
457
|
+
.map((selfContext) => selfContext.context)
|
|
458
|
+
.join('\n\n');
|
|
459
|
+
}
|
|
460
|
+
let materialized = [];
|
|
461
|
+
if (m.id && m.attachments?.length) {
|
|
462
|
+
try {
|
|
463
|
+
materialized = await materializeMessageMedia({
|
|
464
|
+
id: m.id,
|
|
465
|
+
attachments: m.attachments ?? [],
|
|
466
|
+
}, {
|
|
467
|
+
agentId: agentContext?.agentId ?? 'claude-code',
|
|
468
|
+
conversationId: payload.conversationId,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
472
|
+
console.error(`[canon] Failed to materialize inbound media: ${error instanceof Error ? error.message : error}`);
|
|
509
473
|
}
|
|
510
474
|
}
|
|
511
475
|
const primaryAttachment = getPrimaryAttachment(m);
|
|
@@ -515,7 +479,14 @@ async function handleInboundMessage(payload) {
|
|
|
515
479
|
}
|
|
516
480
|
if (primaryAttachment?.fileName)
|
|
517
481
|
meta.attachment_file_name = primaryAttachment.fileName;
|
|
518
|
-
|
|
482
|
+
if (primaryAttachment?.mimeType)
|
|
483
|
+
meta.attachment_mime_type = primaryAttachment.mimeType;
|
|
484
|
+
if (primaryAttachment?.durationMs != null)
|
|
485
|
+
meta.attachment_duration_ms = String(primaryAttachment.durationMs);
|
|
486
|
+
const primaryMaterialized = materialized.find((attachment) => attachment.index === 0);
|
|
487
|
+
if (primaryMaterialized?.path)
|
|
488
|
+
meta.attachment_path = primaryMaterialized.path;
|
|
489
|
+
const renderedContent = renderInboundContent(m, materialized);
|
|
519
490
|
console.error(`[canon] Inbound message from ${meta.sender_name}: "${renderedContent}"`);
|
|
520
491
|
try {
|
|
521
492
|
await server.notification({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/claude-code-plugin",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.8",
|
|
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,7 +31,7 @@
|
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@anthropic-ai/claude-agent-sdk": "^0.2.101",
|
|
34
|
-
"@canonmsg/agent-sdk": "^1.1.
|
|
34
|
+
"@canonmsg/agent-sdk": "^1.1.4",
|
|
35
35
|
"@canonmsg/core": "^0.15.4",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
37
37
|
},
|