@canonmsg/claude-code-plugin 0.14.2 → 0.14.3
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 +2 -2
- package/dist/host.js +40 -3
- package/dist/server.js +8 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ Advertise multiple project choices to the Canon app:
|
|
|
48
48
|
canon-claude --cwd ~/dev --workspace-root ~/dev
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
`--cwd` is the default workspace. Each `--workspace-root` value is an approved local root; the host discovers immediate child projects with common markers such as `.git`, `package.json`, `pyproject.toml`, `Cargo.toml`, or `go.mod` and publishes them as selectable projects during session creation. Use repeated `--workspace /path/to/project` entries to advertise specific projects outside those roots. Worktree mode creates a per-conversation git worktree under `~/.canon/conversation-worktrees`; shared-project mode runs directly in the selected directory.
|
|
51
|
+
`--cwd` is the default workspace. Each `--workspace-root` value is an approved local root; the host discovers immediate child projects with common markers such as `.git`, `package.json`, `pyproject.toml`, `Cargo.toml`, or `go.mod` and publishes them as selectable projects during session creation. Use repeated `--workspace /path/to/project` entries to advertise specific projects outside those roots. Worktree mode creates a best-effort per-conversation git worktree under `~/.canon/conversation-worktrees`; shared-project mode runs directly in the selected directory.
|
|
52
52
|
|
|
53
53
|
Current Canon truth for Claude host mode:
|
|
54
54
|
|
|
@@ -56,7 +56,7 @@ Current Canon truth for Claude host mode:
|
|
|
56
56
|
- thinking level / effort is live-editable when the host reports it
|
|
57
57
|
- workspace selection is setup-only
|
|
58
58
|
- execution mode selection is setup-only
|
|
59
|
-
- permission modes are
|
|
59
|
+
- permission modes are the known Claude Code modes supported by this host; Claude Code applies and enforces the selected mode
|
|
60
60
|
- if worktree creation is unavailable for the selected project, Canon may fall back to shared-project execution and surface the fallback reason in session details
|
|
61
61
|
|
|
62
62
|
## Multiple agents
|
package/dist/host.js
CHANGED
|
@@ -25,7 +25,7 @@ import { randomUUID } from 'node:crypto';
|
|
|
25
25
|
import { execFileSync } from 'node:child_process';
|
|
26
26
|
import { existsSync } from 'node:fs';
|
|
27
27
|
import { query, } from '@anthropic-ai/claude-agent-sdk';
|
|
28
|
-
import { isAnthropicImageAttachment, materializeMessageMedia, toAnthropicImageBlock, } from '@canonmsg/agent-sdk';
|
|
28
|
+
import { isAnthropicImageAttachment, materializeMessageMedia, materializeReplyContextMedia, toAnthropicImageBlock, } from '@canonmsg/agent-sdk';
|
|
29
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';
|
|
@@ -618,6 +618,21 @@ function buildClaudeSessionContextLines(session) {
|
|
|
618
618
|
function renderInboundContent(message, materialized) {
|
|
619
619
|
return renderCanonHostInboundContent(message, materialized);
|
|
620
620
|
}
|
|
621
|
+
async function materializePromptReplyContext(input) {
|
|
622
|
+
if (!input.replyContext?.found || !input.replyContext.attachments?.length) {
|
|
623
|
+
return { replyContext: input.replyContext, materialized: [] };
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
return await materializeReplyContextMedia(input.replyContext, {
|
|
627
|
+
agentId: input.agentId,
|
|
628
|
+
conversationId: input.conversationId,
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
console.error(`${input.logPrefix} Failed to materialize replied-to media:`, error instanceof Error ? error.message : error);
|
|
633
|
+
return { replyContext: input.replyContext, materialized: [] };
|
|
634
|
+
}
|
|
635
|
+
}
|
|
621
636
|
/**
|
|
622
637
|
* Build the multimodal `content` payload handed to the Claude Code SDK.
|
|
623
638
|
*
|
|
@@ -1945,6 +1960,13 @@ export async function main() {
|
|
|
1945
1960
|
const behavior = input.hydratedPage?.behavior ?? hydrated.behavior;
|
|
1946
1961
|
const activeSelfContextId = hydrated.activeSelfContextId;
|
|
1947
1962
|
const selfContexts = hydrated.selfContexts;
|
|
1963
|
+
const replyMedia = await materializePromptReplyContext({
|
|
1964
|
+
replyContext: hydrated.replyContext,
|
|
1965
|
+
agentId,
|
|
1966
|
+
conversationId: input.conversationId,
|
|
1967
|
+
logPrefix: `[canon-host] [${input.conversationId.slice(0, 8)}]`,
|
|
1968
|
+
});
|
|
1969
|
+
const replyContext = replyMedia.replyContext;
|
|
1948
1970
|
const participantContext = hydrated.participantContext;
|
|
1949
1971
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
1950
1972
|
if (!autoReply.allow) {
|
|
@@ -1980,9 +2002,13 @@ export async function main() {
|
|
|
1980
2002
|
participantContext,
|
|
1981
2003
|
behavior,
|
|
1982
2004
|
selfContexts,
|
|
2005
|
+
replyContext,
|
|
1983
2006
|
session,
|
|
1984
2007
|
});
|
|
1985
|
-
const messageContent = await buildCanonUserContent({
|
|
2008
|
+
const messageContent = await buildCanonUserContent({
|
|
2009
|
+
promptText,
|
|
2010
|
+
materialized: [...replyMedia.materialized, ...materialized],
|
|
2011
|
+
});
|
|
1986
2012
|
session.enqueueInbound({
|
|
1987
2013
|
type: 'user',
|
|
1988
2014
|
message: {
|
|
@@ -2095,6 +2121,13 @@ export async function main() {
|
|
|
2095
2121
|
const behavior = payload.behavior ?? hydrated.behavior;
|
|
2096
2122
|
const activeSelfContextId = hydrated.activeSelfContextId;
|
|
2097
2123
|
const selfContexts = hydrated.selfContexts;
|
|
2124
|
+
const replyMedia = await materializePromptReplyContext({
|
|
2125
|
+
replyContext: hydrated.replyContext,
|
|
2126
|
+
agentId,
|
|
2127
|
+
conversationId: convoId,
|
|
2128
|
+
logPrefix: `[canon-host] [${convoId.slice(0, 8)}]`,
|
|
2129
|
+
});
|
|
2130
|
+
const replyContext = replyMedia.replyContext;
|
|
2098
2131
|
const participantContext = hydrated.participantContext;
|
|
2099
2132
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
2100
2133
|
if (!autoReply.allow) {
|
|
@@ -2131,9 +2164,13 @@ export async function main() {
|
|
|
2131
2164
|
participantContext,
|
|
2132
2165
|
behavior,
|
|
2133
2166
|
selfContexts,
|
|
2167
|
+
replyContext,
|
|
2134
2168
|
session,
|
|
2135
2169
|
});
|
|
2136
|
-
const messageContent = await buildCanonUserContent({
|
|
2170
|
+
const messageContent = await buildCanonUserContent({
|
|
2171
|
+
promptText,
|
|
2172
|
+
materialized: [...replyMedia.materialized, ...materialized],
|
|
2173
|
+
});
|
|
2137
2174
|
session.enqueueInbound({
|
|
2138
2175
|
type: 'user',
|
|
2139
2176
|
message: {
|
package/dist/server.js
CHANGED
|
@@ -476,6 +476,9 @@ async function handleInboundMessage(payload) {
|
|
|
476
476
|
}
|
|
477
477
|
}
|
|
478
478
|
const primaryAttachment = getPrimaryAttachment(m);
|
|
479
|
+
if (m.attachments?.length) {
|
|
480
|
+
meta.attachments_json = JSON.stringify(m.attachments);
|
|
481
|
+
}
|
|
479
482
|
if (primaryAttachment?.url) {
|
|
480
483
|
meta.attachment_kind = primaryAttachment.kind;
|
|
481
484
|
meta.attachment_url = primaryAttachment.url;
|
|
@@ -489,6 +492,11 @@ async function handleInboundMessage(payload) {
|
|
|
489
492
|
const primaryMaterialized = materialized.find((attachment) => attachment.index === 0);
|
|
490
493
|
if (primaryMaterialized?.path)
|
|
491
494
|
meta.attachment_path = primaryMaterialized.path;
|
|
495
|
+
if (materialized.length > 0) {
|
|
496
|
+
meta.attachment_paths = materialized
|
|
497
|
+
.map((attachment) => attachment.path)
|
|
498
|
+
.join('\n');
|
|
499
|
+
}
|
|
492
500
|
const renderedContent = renderInboundContent(m, materialized);
|
|
493
501
|
console.error(`[canon] Inbound message from ${meta.sender_name}: "${renderedContent}"`);
|
|
494
502
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/claude-code-plugin",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
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.4.
|
|
35
|
-
"@canonmsg/core": "^0.18.
|
|
34
|
+
"@canonmsg/agent-sdk": "^1.4.1",
|
|
35
|
+
"@canonmsg/core": "^0.18.1",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|