@canonmsg/claude-code-plugin 0.13.1 → 0.14.1
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/README.md +3 -1
- package/dist/host.js +171 -13
- package/dist/inbound-policy.d.ts +3 -1
- package/dist/inbound-policy.js +4 -1
- package/dist/register.js +3 -1
- package/dist/server.js +3 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ canon-register --name "My Claude" --description "My Claude Code agent" --phone "
|
|
|
15
15
|
canon-claude
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Send a message to your agent in the Canon app. Claude Code responds with full capabilities (file read/write, bash, etc.).
|
|
18
|
+
Send a message to your agent in the Canon app. Claude Code responds with full capabilities (file read/write, bash, etc.). `canon-claude` is the local agent process. Keep that terminal open while you want Canon to reach the agent. Closing it, logging out, rebooting, or sleeping long enough to stop the process takes this local agent offline until you revive it.
|
|
19
19
|
|
|
20
20
|
After a restart or closed terminal, use the shared local manager to list and revive all recorded local agents:
|
|
21
21
|
|
|
@@ -25,6 +25,8 @@ canon-necromance
|
|
|
25
25
|
canon-necromance revive frontend
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
Public docs: <https://canonmail.com/agents/integrations>. Coding-host concepts: <https://canonmail.com/agents/coding-agents>.
|
|
29
|
+
|
|
28
30
|
## Features
|
|
29
31
|
|
|
30
32
|
- **Two-way messaging** — Messages from Canon flow to Claude Code and back
|
package/dist/host.js
CHANGED
|
@@ -26,7 +26,7 @@ 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, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildCanonHostPrompt, buildConfiguredWorkspaceOptionsWithRoots, buildConversationEnvironmentKey, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, buildPlanApprovalRequest, buildQuestionRequest, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, createConversationMetadataLoader, createRuntimeStatePublisher, EXECUTION_ENVIRONMENT_MODES, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, ExecutionEnvironmentError, FINAL_MESSAGE_HANDOFF_MS, buildLocalRuntimeId, getActiveProfileLock, heartbeatLocalRuntimeEntry, normalizeTurnMetadata, prepareConversationEnvironment, resolveCanonAgent, initRTDBAuth, rtdbRead, rtdbWrite, loadHostSessionConfig, loadRuntimeSessionState, markLocalRuntimeStopped, releaseConversationEnvironment, saveRuntimeSessionState, clearRuntimeSessionState, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, resolveHostWorkspaceCwd, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
29
|
+
import { CLAUDE_PERMISSION_MODE_OPTIONS, RUNTIME_NEW_SESSION_ACTION, RUNTIME_STOP_ACTION, RUNTIME_STOP_AND_DROP_ACTION, buildCanonHostPrompt, buildConfiguredWorkspaceOptionsWithRoots, buildConversationEnvironmentKey, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, diffCanonMemberIds, buildPlanApprovalRequest, buildQuestionRequest, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, createConversationMetadataLoader, createRuntimeStatePublisher, EXECUTION_ENVIRONMENT_MODES, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, HOST_ADMISSION_ACTIONS_DISABLED, ExecutionEnvironmentError, FINAL_MESSAGE_HANDOFF_MS, buildLocalRuntimeId, getActiveProfileLock, heartbeatLocalRuntimeEntry, normalizeTurnMetadata, prepareConversationEnvironment, resolveCanonAgent, initRTDBAuth, rtdbRead, rtdbWrite, loadHostSessionConfig, loadRuntimeSessionState, markLocalRuntimeStopped, releaseConversationEnvironment, saveRuntimeSessionState, clearRuntimeSessionState, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, resolveHostWorkspaceCwd, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
30
30
|
import { buildInboundContextLines, decideAutoReply, } from './inbound-policy.js';
|
|
31
31
|
import { createStreamingBuffer } from './streaming-buffer.js';
|
|
32
32
|
import { runCli } from './cli-entry.js';
|
|
@@ -51,7 +51,10 @@ EXAMPLES
|
|
|
51
51
|
canon-claude --cwd ~/dev/canon
|
|
52
52
|
canon-claude --cwd ~/dev/canon --workspace-root ~/dev
|
|
53
53
|
|
|
54
|
-
Keep this terminal open while you want Canon to reach the agent
|
|
54
|
+
Keep this terminal open while you want Canon to reach the agent. Closing it,
|
|
55
|
+
logging out, rebooting, or sleeping long enough to stop the process takes the
|
|
56
|
+
local agent offline until you revive it. Docs:
|
|
57
|
+
https://canonmail.com/agents/integrations`;
|
|
55
58
|
let workingDir = process.cwd();
|
|
56
59
|
let workspaceOptions = [];
|
|
57
60
|
let workspaceRoots = [];
|
|
@@ -68,6 +71,103 @@ let runtimeMetadata = {
|
|
|
68
71
|
};
|
|
69
72
|
let runtimeMetadataRefresh = null;
|
|
70
73
|
function buildClaudeRuntimeDescriptor(input) {
|
|
74
|
+
const commands = [
|
|
75
|
+
{
|
|
76
|
+
id: 'plan',
|
|
77
|
+
label: 'Plan first',
|
|
78
|
+
description: 'Switch Claude into Plan mode. Text after /plan is kept as a ready prompt while the mode applies.',
|
|
79
|
+
aliases: ['plan'],
|
|
80
|
+
category: 'plan',
|
|
81
|
+
placements: ['composer_slash', 'command_palette'],
|
|
82
|
+
availability: ['always'],
|
|
83
|
+
trailingTextBehavior: 'send_as_prompt',
|
|
84
|
+
dispatch: {
|
|
85
|
+
kind: 'control',
|
|
86
|
+
controlId: 'permissionMode',
|
|
87
|
+
value: 'plan',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
id: 'runtime-status',
|
|
92
|
+
label: 'Runtime status',
|
|
93
|
+
description: 'Open Claude runtime details, including account, project, and policy status.',
|
|
94
|
+
primitive: 'runtime.status',
|
|
95
|
+
aliases: ['status'],
|
|
96
|
+
category: 'details',
|
|
97
|
+
placements: ['composer_slash', 'command_palette'],
|
|
98
|
+
availability: ['always'],
|
|
99
|
+
dispatch: { kind: 'open_details', target: 'status' },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'mcp-inventory',
|
|
103
|
+
label: 'MCP servers',
|
|
104
|
+
description: 'Open the Claude MCP inventory published by the host.',
|
|
105
|
+
aliases: ['mcp'],
|
|
106
|
+
category: 'details',
|
|
107
|
+
placements: ['composer_slash', 'command_palette'],
|
|
108
|
+
availability: ['always'],
|
|
109
|
+
dispatch: { kind: 'open_details', target: 'mcp' },
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: 'plugin-inventory',
|
|
113
|
+
label: 'Plugins',
|
|
114
|
+
description: 'Open the Claude plugin and command inventory published by the host.',
|
|
115
|
+
aliases: ['plugins'],
|
|
116
|
+
category: 'details',
|
|
117
|
+
placements: ['composer_slash', 'command_palette'],
|
|
118
|
+
availability: ['always'],
|
|
119
|
+
dispatch: { kind: 'open_details', target: 'plugins' },
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: 'model-details',
|
|
123
|
+
label: 'Model control',
|
|
124
|
+
description: 'Open runtime details and use the live Model control.',
|
|
125
|
+
aliases: ['model'],
|
|
126
|
+
category: 'details',
|
|
127
|
+
placements: ['composer_slash', 'command_palette'],
|
|
128
|
+
availability: ['always'],
|
|
129
|
+
dispatch: { kind: 'open_details', target: 'model' },
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
id: 'permission-details',
|
|
133
|
+
label: 'Permission mode',
|
|
134
|
+
description: 'Open runtime details and use the live Permission mode control.',
|
|
135
|
+
aliases: ['permission'],
|
|
136
|
+
category: 'details',
|
|
137
|
+
placements: ['composer_slash', 'command_palette'],
|
|
138
|
+
availability: ['always'],
|
|
139
|
+
dispatch: { kind: 'open_details', target: 'permissionMode' },
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'effort-details',
|
|
143
|
+
label: 'Thinking level',
|
|
144
|
+
description: 'Set Claude effort using /effort or /think.',
|
|
145
|
+
primitive: 'runtime.reasoning.set',
|
|
146
|
+
aliases: ['effort', 'think'],
|
|
147
|
+
category: 'runtime',
|
|
148
|
+
placements: ['composer_slash', 'command_palette'],
|
|
149
|
+
availability: ['always'],
|
|
150
|
+
args: [{
|
|
151
|
+
id: 'level',
|
|
152
|
+
label: 'Level',
|
|
153
|
+
kind: 'enum',
|
|
154
|
+
required: true,
|
|
155
|
+
choices: [
|
|
156
|
+
{ value: 'low', label: 'Low' },
|
|
157
|
+
{ value: 'medium', label: 'Medium' },
|
|
158
|
+
{ value: 'high', label: 'High' },
|
|
159
|
+
],
|
|
160
|
+
}],
|
|
161
|
+
dispatch: {
|
|
162
|
+
kind: 'control',
|
|
163
|
+
controlId: 'effort',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
...RUNTIME_NEW_SESSION_ACTION,
|
|
168
|
+
primitive: 'session.new',
|
|
169
|
+
},
|
|
170
|
+
];
|
|
71
171
|
return buildFirstPartyCodingRuntimeDescriptor({
|
|
72
172
|
clientType: 'claude-code',
|
|
73
173
|
models: input.models,
|
|
@@ -78,6 +178,7 @@ function buildClaudeRuntimeDescriptor(input) {
|
|
|
78
178
|
defaultPermissionMode: 'default',
|
|
79
179
|
streamingTextMode: 'delta',
|
|
80
180
|
admissionActions: HOST_ADMISSION_ACTIONS_DISABLED,
|
|
181
|
+
commands,
|
|
81
182
|
actions: [
|
|
82
183
|
{
|
|
83
184
|
id: 'plan',
|
|
@@ -1322,10 +1423,12 @@ export async function main() {
|
|
|
1322
1423
|
initRTDBAuth(client);
|
|
1323
1424
|
let agentId;
|
|
1324
1425
|
let ownerId = null;
|
|
1426
|
+
let ownerName = null;
|
|
1325
1427
|
try {
|
|
1326
1428
|
const ctx = await client.getAgentMe();
|
|
1327
1429
|
agentId = ctx.agentId;
|
|
1328
1430
|
ownerId = ctx.ownerId;
|
|
1431
|
+
ownerName = ctx.ownerName;
|
|
1329
1432
|
console.error(`[canon-host] Connected as ${ctx.displayName || agentId}`);
|
|
1330
1433
|
}
|
|
1331
1434
|
catch {
|
|
@@ -1390,6 +1493,8 @@ export async function main() {
|
|
|
1390
1493
|
};
|
|
1391
1494
|
const conversationCache = new Map();
|
|
1392
1495
|
const knownConversationIds = new Set();
|
|
1496
|
+
const promptedGroupContextConversationIds = new Set();
|
|
1497
|
+
const pendingMembershipChanges = new Map();
|
|
1393
1498
|
let lastKnownConversationRefreshAt = 0;
|
|
1394
1499
|
const publishRuntimeHeartbeat = async () => {
|
|
1395
1500
|
heartbeatLocalRuntimeEntry(runtimeId, {
|
|
@@ -1542,18 +1647,65 @@ export async function main() {
|
|
|
1542
1647
|
}
|
|
1543
1648
|
lastKnownConversationRefreshAt = Date.now();
|
|
1544
1649
|
}
|
|
1650
|
+
function handleConversationUpdated(payload) {
|
|
1651
|
+
const rawMemberIds = payload.changes.memberIds;
|
|
1652
|
+
if (!Array.isArray(rawMemberIds))
|
|
1653
|
+
return;
|
|
1654
|
+
const memberIds = rawMemberIds.filter((id) => typeof id === 'string');
|
|
1655
|
+
const cached = conversationCache.get(payload.conversationId);
|
|
1656
|
+
const membershipChange = payload.membershipChange
|
|
1657
|
+
?? (cached ? diffCanonMemberIds(cached.memberIds, memberIds) : null);
|
|
1658
|
+
if (cached) {
|
|
1659
|
+
conversationCache.set(payload.conversationId, {
|
|
1660
|
+
...cached,
|
|
1661
|
+
memberIds,
|
|
1662
|
+
});
|
|
1663
|
+
}
|
|
1664
|
+
if (membershipChange) {
|
|
1665
|
+
pendingMembershipChanges.set(payload.conversationId, membershipChange);
|
|
1666
|
+
}
|
|
1667
|
+
if (!memberIds.includes(agentId)) {
|
|
1668
|
+
knownConversationIds.delete(payload.conversationId);
|
|
1669
|
+
conversationCache.delete(payload.conversationId);
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
function getGroupContextMode(conversationId, conversation) {
|
|
1673
|
+
if (conversation?.type !== 'group')
|
|
1674
|
+
return undefined;
|
|
1675
|
+
if (pendingMembershipChanges.has(conversationId))
|
|
1676
|
+
return 'membership_change';
|
|
1677
|
+
if (!promptedGroupContextConversationIds.has(conversationId))
|
|
1678
|
+
return 'initial';
|
|
1679
|
+
return undefined;
|
|
1680
|
+
}
|
|
1681
|
+
function markGroupContextModeUsed(conversationId, mode) {
|
|
1682
|
+
if (!mode)
|
|
1683
|
+
return;
|
|
1684
|
+
promptedGroupContextConversationIds.add(conversationId);
|
|
1685
|
+
if (mode === 'membership_change') {
|
|
1686
|
+
pendingMembershipChanges.delete(conversationId);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1545
1689
|
async function loadHydratedInboundContext(input) {
|
|
1546
1690
|
const [conversation, page] = await Promise.all([
|
|
1547
1691
|
getConversationMeta(input.conversationId),
|
|
1548
|
-
|
|
1692
|
+
input.hydratedPage
|
|
1693
|
+
? Promise.resolve(input.hydratedPage)
|
|
1694
|
+
: client.getMessagesPage(input.conversationId, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT).catch(() => null),
|
|
1549
1695
|
]);
|
|
1550
1696
|
return buildHydratedInboundContext({
|
|
1551
1697
|
agentId,
|
|
1552
1698
|
conversation,
|
|
1553
1699
|
page,
|
|
1700
|
+
activeSelfContextId: input.activeSelfContextId,
|
|
1701
|
+
selfContexts: input.selfContexts,
|
|
1554
1702
|
message: input.message,
|
|
1555
1703
|
senderName: input.senderName,
|
|
1556
1704
|
isOwner: input.isOwner,
|
|
1705
|
+
ownerId,
|
|
1706
|
+
ownerName,
|
|
1707
|
+
membershipChange: pendingMembershipChanges.get(input.conversationId) ?? null,
|
|
1708
|
+
groupContextMode: getGroupContextMode(input.conversationId, conversation),
|
|
1557
1709
|
});
|
|
1558
1710
|
}
|
|
1559
1711
|
function closeSession(conversationId, options = {}) {
|
|
@@ -1788,15 +1940,18 @@ export async function main() {
|
|
|
1788
1940
|
message: m,
|
|
1789
1941
|
senderName: sender,
|
|
1790
1942
|
isOwner,
|
|
1943
|
+
hydratedPage: input.hydratedPage,
|
|
1791
1944
|
});
|
|
1792
1945
|
const behavior = input.hydratedPage?.behavior ?? hydrated.behavior;
|
|
1793
|
-
const
|
|
1946
|
+
const activeSelfContextId = hydrated.activeSelfContextId;
|
|
1947
|
+
const selfContexts = hydrated.selfContexts;
|
|
1794
1948
|
const participantContext = hydrated.participantContext;
|
|
1795
1949
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
1796
1950
|
if (!autoReply.allow) {
|
|
1797
1951
|
console.error(`[canon-host] [${input.conversationId.slice(0, 8)}] Suppressed recovered auto-reply: ${autoReply.reason}`);
|
|
1798
1952
|
return;
|
|
1799
1953
|
}
|
|
1954
|
+
markGroupContextModeUsed(input.conversationId, participantContext.groupContextMode);
|
|
1800
1955
|
let session;
|
|
1801
1956
|
try {
|
|
1802
1957
|
session = await getOrCreateSession(input.conversationId);
|
|
@@ -1806,7 +1961,7 @@ export async function main() {
|
|
|
1806
1961
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
1807
1962
|
console.error(`[canon-host] [${input.conversationId.slice(0, 8)}] Failed to create recovered session: ${message}`);
|
|
1808
1963
|
await client.sendMessage(input.conversationId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
1809
|
-
...(
|
|
1964
|
+
...(activeSelfContextId ? { selfContextId: activeSelfContextId } : {}),
|
|
1810
1965
|
metadata: {
|
|
1811
1966
|
turnSemantics: 'turn_complete',
|
|
1812
1967
|
turnComplete: true,
|
|
@@ -1816,7 +1971,7 @@ export async function main() {
|
|
|
1816
1971
|
return;
|
|
1817
1972
|
}
|
|
1818
1973
|
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
1819
|
-
session.activeSelfContextId =
|
|
1974
|
+
session.activeSelfContextId = activeSelfContextId;
|
|
1820
1975
|
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
1821
1976
|
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
1822
1977
|
const promptText = buildCanonPrompt({
|
|
@@ -1934,19 +2089,19 @@ export async function main() {
|
|
|
1934
2089
|
message: m,
|
|
1935
2090
|
senderName: sender,
|
|
1936
2091
|
isOwner,
|
|
2092
|
+
activeSelfContextId: payload.activeSelfContextId,
|
|
2093
|
+
selfContexts: payload.selfContexts,
|
|
1937
2094
|
});
|
|
1938
2095
|
const behavior = payload.behavior ?? hydrated.behavior;
|
|
1939
|
-
const
|
|
1940
|
-
|
|
1941
|
-
: Array.isArray(payload.selfContexts)
|
|
1942
|
-
? payload.selfContexts
|
|
1943
|
-
: hydrated.selfContexts;
|
|
2096
|
+
const activeSelfContextId = hydrated.activeSelfContextId;
|
|
2097
|
+
const selfContexts = hydrated.selfContexts;
|
|
1944
2098
|
const participantContext = hydrated.participantContext;
|
|
1945
2099
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
1946
2100
|
if (!autoReply.allow) {
|
|
1947
2101
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Suppressed auto-reply: ${autoReply.reason}`);
|
|
1948
2102
|
return;
|
|
1949
2103
|
}
|
|
2104
|
+
markGroupContextModeUsed(convoId, participantContext.groupContextMode);
|
|
1950
2105
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Message from ${sender}: "${content.slice(0, 80)}" (${autoReply.reason})`);
|
|
1951
2106
|
let session;
|
|
1952
2107
|
try {
|
|
@@ -1957,7 +2112,7 @@ export async function main() {
|
|
|
1957
2112
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
1958
2113
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Failed to create session: ${message}`);
|
|
1959
2114
|
await client.sendMessage(convoId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
1960
|
-
...(
|
|
2115
|
+
...(activeSelfContextId ? { selfContextId: activeSelfContextId } : {}),
|
|
1961
2116
|
metadata: {
|
|
1962
2117
|
turnSemantics: 'turn_complete',
|
|
1963
2118
|
turnComplete: true,
|
|
@@ -1967,7 +2122,7 @@ export async function main() {
|
|
|
1967
2122
|
return;
|
|
1968
2123
|
}
|
|
1969
2124
|
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
1970
|
-
session.activeSelfContextId =
|
|
2125
|
+
session.activeSelfContextId = activeSelfContextId;
|
|
1971
2126
|
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
1972
2127
|
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
1973
2128
|
const promptText = buildCanonPrompt({
|
|
@@ -1996,6 +2151,9 @@ export async function main() {
|
|
|
1996
2151
|
}
|
|
1997
2152
|
})();
|
|
1998
2153
|
},
|
|
2154
|
+
onConversationUpdated: (payload) => {
|
|
2155
|
+
handleConversationUpdated(payload);
|
|
2156
|
+
},
|
|
1999
2157
|
onConnected: () => {
|
|
2000
2158
|
streamConnected = true;
|
|
2001
2159
|
void publishRuntimeHeartbeat();
|
package/dist/inbound-policy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type CanonConversation, type ResolvedAgentBehaviorPolicy } from '@canonmsg/core';
|
|
1
|
+
import { type CanonGroupContext, type CanonGroupContextMode, type CanonConversation, type ResolvedAgentBehaviorPolicy } from '@canonmsg/core';
|
|
2
2
|
export interface InboundParticipantContext {
|
|
3
3
|
conversationType: CanonConversation['type'] | 'unknown';
|
|
4
4
|
memberCount: number | null;
|
|
@@ -6,6 +6,8 @@ export interface InboundParticipantContext {
|
|
|
6
6
|
senderName: string;
|
|
7
7
|
isOwner: boolean;
|
|
8
8
|
mentionedAgent: boolean;
|
|
9
|
+
groupContext?: CanonGroupContext;
|
|
10
|
+
groupContextMode?: CanonGroupContextMode;
|
|
9
11
|
recentSenderTypes: Array<'human' | 'ai_agent'>;
|
|
10
12
|
recentHumanCount: number;
|
|
11
13
|
recentAgentCount: number;
|
package/dist/inbound-policy.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { evaluateParticipationPolicy, resolveAgentBehaviorPolicy, } from '@canonmsg/core';
|
|
1
|
+
import { buildCompactGroupContextLines, evaluateParticipationPolicy, resolveAgentBehaviorPolicy, } from '@canonmsg/core';
|
|
2
2
|
function formatRecentSenders(senderTypes) {
|
|
3
3
|
if (senderTypes.length === 0)
|
|
4
4
|
return 'none';
|
|
@@ -18,6 +18,9 @@ export function buildInboundContextLines(context) {
|
|
|
18
18
|
`Latest sender name: ${context.senderName}`,
|
|
19
19
|
`Latest sender type: ${context.senderType}`,
|
|
20
20
|
`Conversation type: ${conversationTypeLabel}`,
|
|
21
|
+
...(context.groupContext && context.groupContextMode
|
|
22
|
+
? buildCompactGroupContextLines(context.groupContext, context.groupContextMode)
|
|
23
|
+
: []),
|
|
21
24
|
`Directly addressed to this agent: ${context.mentionedAgent ? 'yes' : 'no'}`,
|
|
22
25
|
`Recent sender pattern: ${formatRecentSenders(context.recentSenderTypes)}`,
|
|
23
26
|
`Recent human messages: ${context.recentHumanCount}`,
|
package/dist/register.js
CHANGED
|
@@ -107,7 +107,9 @@ export async function main() {
|
|
|
107
107
|
console.log(`Approved! Agent: ${result.agentName} (${result.agentId})`);
|
|
108
108
|
console.log(`Saved as profile "${profileName}" in ~/.canon/agents.json`);
|
|
109
109
|
console.log('Start it with: CANON_AGENT=' + profileName + ' canon-claude --cwd /path/to/project');
|
|
110
|
-
console.log('Keep that terminal open
|
|
110
|
+
console.log('Keep that terminal open while you want Canon to reach the agent.');
|
|
111
|
+
console.log('Closing it, logging out, rebooting, or sleeping long enough to stop the process takes this local agent offline until you revive it.');
|
|
112
|
+
console.log('Docs: https://canonmail.com/agents/integrations');
|
|
111
113
|
break;
|
|
112
114
|
}
|
|
113
115
|
case 'rejected':
|
package/dist/server.js
CHANGED
|
@@ -447,6 +447,9 @@ async function handleInboundMessage(payload) {
|
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
449
|
if (Array.isArray(payload.selfContexts) && payload.selfContexts.length > 0) {
|
|
450
|
+
if (payload.activeSelfContextId) {
|
|
451
|
+
meta.active_self_context_id = payload.activeSelfContextId;
|
|
452
|
+
}
|
|
450
453
|
meta.self_context_ids = payload.selfContexts
|
|
451
454
|
.map((selfContext) => selfContext.id)
|
|
452
455
|
.join('\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/claude-code-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.1",
|
|
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": "^1.
|
|
35
|
-
"@canonmsg/core": "^0.
|
|
34
|
+
"@canonmsg/agent-sdk": "^1.3.1",
|
|
35
|
+
"@canonmsg/core": "^0.17.2",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|