@canonmsg/claude-code-plugin 0.14.7 → 0.14.9
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 +32 -20
- package/dist/session-state.d.ts +1 -0
- package/dist/session-state.js +1 -0
- package/package.json +3 -3
package/dist/host.js
CHANGED
|
@@ -687,6 +687,8 @@ async function buildCanonUserContent(input) {
|
|
|
687
687
|
// ── Session factory ─────────────────────────────────────────────────
|
|
688
688
|
function createSession(conversationId, environment, agentId, client, runtimeState, onSessionEnd, onRuntimeDescriptorUpdate, config, resumeSessionId) {
|
|
689
689
|
const { cwd } = environment;
|
|
690
|
+
const cardResponseUserId = config.ownerId ?? undefined;
|
|
691
|
+
const cardResponseUser = cardResponseUserId ? { responseUserId: cardResponseUserId } : undefined;
|
|
690
692
|
// Per-session input stream with message queue
|
|
691
693
|
let resolveInput = null;
|
|
692
694
|
let inputDone = false;
|
|
@@ -783,7 +785,7 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
783
785
|
try {
|
|
784
786
|
const questionId = randomUUID();
|
|
785
787
|
const questions = input.questions ?? [];
|
|
786
|
-
const questionCard = buildQuestionRequest(questionId, questions);
|
|
788
|
+
const questionCard = buildQuestionRequest(questionId, questions, cardResponseUser);
|
|
787
789
|
await client.sendMessage(conversationId, questionCard.text, {
|
|
788
790
|
...(session.activeSelfContextId
|
|
789
791
|
? { selfContextId: session.activeSelfContextId }
|
|
@@ -828,9 +830,11 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
828
830
|
: [];
|
|
829
831
|
const planApproval = buildPlanApprovalRequest(planId, 'Plan ready for review.', allowedPrompts.length > 0 ? {
|
|
830
832
|
summary: 'Claude has prepared a plan and is asking permission to continue.',
|
|
833
|
+
...(cardResponseUser ?? {}),
|
|
831
834
|
allowedPrompts,
|
|
832
835
|
} : {
|
|
833
836
|
summary: 'Claude has prepared a plan and is asking permission to continue.',
|
|
837
|
+
...(cardResponseUser ?? {}),
|
|
834
838
|
});
|
|
835
839
|
await client.sendMessage(conversationId, planApproval.text, {
|
|
836
840
|
...(session.activeSelfContextId
|
|
@@ -909,6 +913,7 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
909
913
|
turnState: 'idle',
|
|
910
914
|
currentTurnId: null,
|
|
911
915
|
currentTurnOpenedAt: null,
|
|
916
|
+
currentTurnUpdatedAt: null,
|
|
912
917
|
activeSelfContextId: null,
|
|
913
918
|
lastAcceptedIntent: null,
|
|
914
919
|
lastActivity: Date.now(),
|
|
@@ -1130,6 +1135,13 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
1130
1135
|
writeState();
|
|
1131
1136
|
}
|
|
1132
1137
|
function writeTurn() {
|
|
1138
|
+
const isOpenTurn = session.turnState === 'thinking'
|
|
1139
|
+
|| session.turnState === 'streaming'
|
|
1140
|
+
|| session.turnState === 'tool'
|
|
1141
|
+
|| session.turnState === 'waiting_input';
|
|
1142
|
+
if (isOpenTurn) {
|
|
1143
|
+
session.currentTurnUpdatedAt = Date.now();
|
|
1144
|
+
}
|
|
1133
1145
|
runtimeState.writeTurnState(conversationId, {
|
|
1134
1146
|
turnId: session.currentTurnId,
|
|
1135
1147
|
state: session.turnState,
|
|
@@ -1138,6 +1150,7 @@ function createSession(conversationId, environment, agentId, client, runtimeStat
|
|
|
1138
1150
|
lastAcceptedIntent: session.lastAcceptedIntent,
|
|
1139
1151
|
capabilities: CLAUDE_RUNTIME_CAPABILITIES,
|
|
1140
1152
|
...(session.currentTurnOpenedAt ? { openedAt: session.currentTurnOpenedAt } : {}),
|
|
1153
|
+
...(isOpenTurn && session.currentTurnUpdatedAt ? { turnUpdatedAt: session.currentTurnUpdatedAt } : {}),
|
|
1141
1154
|
...(session.turnState === 'idle' || session.turnState === 'completed' || session.turnState === 'interrupted'
|
|
1142
1155
|
? { completedAt: { '.sv': 'timestamp' } }
|
|
1143
1156
|
: {}),
|
|
@@ -1485,6 +1498,11 @@ export async function main() {
|
|
|
1485
1498
|
// ── Canon API client + RTDB auth ──
|
|
1486
1499
|
const client = new CanonClient(apiKey, baseUrl);
|
|
1487
1500
|
initRTDBAuth(client);
|
|
1501
|
+
async function markQueuedMessageAcceptedForConversation(conversationId, sourceMessageId, markAccepted) {
|
|
1502
|
+
if (!markAccepted || !sourceMessageId)
|
|
1503
|
+
return;
|
|
1504
|
+
await client.updateMessageDisposition(conversationId, sourceMessageId, 'accepted_now').catch(() => { });
|
|
1505
|
+
}
|
|
1488
1506
|
let agentId;
|
|
1489
1507
|
let ownerId = null;
|
|
1490
1508
|
let ownerName = null;
|
|
@@ -1885,18 +1903,7 @@ export async function main() {
|
|
|
1885
1903
|
session.pendingInputs = session.pendingInputs.filter((input) => input.sourceMessageId !== sourceMessageId);
|
|
1886
1904
|
if (session.pendingInputs.length === before)
|
|
1887
1905
|
return;
|
|
1888
|
-
|
|
1889
|
-
turnId: session.currentTurnId,
|
|
1890
|
-
state: session.turnState,
|
|
1891
|
-
queueDepth: session.pendingInputs.length,
|
|
1892
|
-
currentSpeakerId: agentId,
|
|
1893
|
-
lastAcceptedIntent: session.lastAcceptedIntent,
|
|
1894
|
-
capabilities: CLAUDE_RUNTIME_CAPABILITIES,
|
|
1895
|
-
...(session.currentTurnOpenedAt ? { openedAt: session.currentTurnOpenedAt } : {}),
|
|
1896
|
-
...(session.turnState === 'idle' || session.turnState === 'completed' || session.turnState === 'interrupted'
|
|
1897
|
-
? { completedAt: { '.sv': 'timestamp' } }
|
|
1898
|
-
: {}),
|
|
1899
|
-
}).catch(() => { });
|
|
1906
|
+
session.writeTurn();
|
|
1900
1907
|
}
|
|
1901
1908
|
function evictOldestIdle() {
|
|
1902
1909
|
let oldest = null;
|
|
@@ -1981,6 +1988,7 @@ export async function main() {
|
|
|
1981
1988
|
approvalManager,
|
|
1982
1989
|
canRequestApproval: () => canRequestCanonApproval(conversationId),
|
|
1983
1990
|
runtimeId,
|
|
1991
|
+
ownerId,
|
|
1984
1992
|
}, resumeId);
|
|
1985
1993
|
sessions.set(conversationId, session);
|
|
1986
1994
|
await Promise.all([
|
|
@@ -2067,6 +2075,9 @@ export async function main() {
|
|
|
2067
2075
|
return;
|
|
2068
2076
|
}
|
|
2069
2077
|
markGroupContextModeUsed(input.conversationId, participantContext.groupContextMode);
|
|
2078
|
+
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
2079
|
+
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
2080
|
+
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
2070
2081
|
let session;
|
|
2071
2082
|
try {
|
|
2072
2083
|
session = await getOrCreateSession(input.conversationId);
|
|
@@ -2075,6 +2086,7 @@ export async function main() {
|
|
|
2075
2086
|
const message = error instanceof Error ? error.message : String(error);
|
|
2076
2087
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
2077
2088
|
console.error(`[canon-host] [${input.conversationId.slice(0, 8)}] Failed to create recovered session: ${message}`);
|
|
2089
|
+
await markQueuedMessageAcceptedForConversation(input.conversationId, m.id ?? null, shouldMarkAccepted);
|
|
2078
2090
|
await client.sendMessage(input.conversationId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
2079
2091
|
...(activeSelfContextId ? { selfContextId: activeSelfContextId } : {}),
|
|
2080
2092
|
metadata: {
|
|
@@ -2085,10 +2097,7 @@ export async function main() {
|
|
|
2085
2097
|
}).catch(() => { });
|
|
2086
2098
|
return;
|
|
2087
2099
|
}
|
|
2088
|
-
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
2089
2100
|
session.activeSelfContextId = activeSelfContextId;
|
|
2090
|
-
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
2091
|
-
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
2092
2101
|
const promptText = buildCanonPrompt({
|
|
2093
2102
|
content,
|
|
2094
2103
|
conversationId: input.conversationId,
|
|
@@ -2245,6 +2254,9 @@ export async function main() {
|
|
|
2245
2254
|
}
|
|
2246
2255
|
markGroupContextModeUsed(convoId, participantContext.groupContextMode);
|
|
2247
2256
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Message from ${sender}: "${content.slice(0, 80)}" (${autoReply.reason})`);
|
|
2257
|
+
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
2258
|
+
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
2259
|
+
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
2248
2260
|
let session;
|
|
2249
2261
|
try {
|
|
2250
2262
|
session = await getOrCreateSession(convoId);
|
|
@@ -2253,6 +2265,7 @@ export async function main() {
|
|
|
2253
2265
|
const message = error instanceof Error ? error.message : String(error);
|
|
2254
2266
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
2255
2267
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Failed to create session: ${message}`);
|
|
2268
|
+
await markQueuedMessageAcceptedForConversation(convoId, m.id ?? null, shouldMarkAccepted);
|
|
2256
2269
|
await client.sendMessage(convoId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
2257
2270
|
...(activeSelfContextId ? { selfContextId: activeSelfContextId } : {}),
|
|
2258
2271
|
metadata: {
|
|
@@ -2263,10 +2276,7 @@ export async function main() {
|
|
|
2263
2276
|
}).catch(() => { });
|
|
2264
2277
|
return;
|
|
2265
2278
|
}
|
|
2266
|
-
const turnMetadata = normalizeTurnMetadata(m.metadata);
|
|
2267
2279
|
session.activeSelfContextId = activeSelfContextId;
|
|
2268
|
-
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
2269
|
-
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
2270
2280
|
const promptText = buildCanonPrompt({
|
|
2271
2281
|
content,
|
|
2272
2282
|
conversationId: convoId,
|
|
@@ -2457,7 +2467,9 @@ export async function main() {
|
|
|
2457
2467
|
const heartbeat = setInterval(() => {
|
|
2458
2468
|
for (const session of sessions.values()) {
|
|
2459
2469
|
session.writeState();
|
|
2460
|
-
session.
|
|
2470
|
+
if (session.state.state !== 'running' && session.state.state !== 'requires_action') {
|
|
2471
|
+
session.writeTurn();
|
|
2472
|
+
}
|
|
2461
2473
|
}
|
|
2462
2474
|
void publishRuntimeHeartbeat();
|
|
2463
2475
|
}, HEARTBEAT_MS);
|
package/dist/session-state.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export interface ClaudeCompletedTurnState {
|
|
|
31
31
|
turnState: TurnLifecycleState;
|
|
32
32
|
currentTurnId: string | null;
|
|
33
33
|
currentTurnOpenedAt: number | null;
|
|
34
|
+
currentTurnUpdatedAt: number | null;
|
|
34
35
|
lastAcceptedIntent: DeliveryIntent | null;
|
|
35
36
|
}
|
|
36
37
|
export declare function createClaudeInputEnvelope(input: {
|
package/dist/session-state.js
CHANGED
|
@@ -36,6 +36,7 @@ export function resetClaudeCompletedTurnState(session) {
|
|
|
36
36
|
session.state.state = 'idle';
|
|
37
37
|
session.currentTurnId = null;
|
|
38
38
|
session.currentTurnOpenedAt = null;
|
|
39
|
+
session.currentTurnUpdatedAt = null;
|
|
39
40
|
session.lastAcceptedIntent = null;
|
|
40
41
|
session.pendingFinalText = null;
|
|
41
42
|
session.pendingFinalDelivery = null;
|
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.9",
|
|
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.5.
|
|
35
|
-
"@canonmsg/core": "^0.
|
|
34
|
+
"@canonmsg/agent-sdk": "^1.5.5",
|
|
35
|
+
"@canonmsg/core": "^0.21.0",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|