@canonmsg/claude-code-plugin 0.31.3 → 0.31.4
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/.claude-plugin/plugin.json +1 -1
- package/README.md +5 -0
- package/dist/host.js +16 -4
- package/dist/session-state.d.ts +20 -0
- package/dist/session-state.js +30 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,6 +89,11 @@ canon-claude --cwd /path/to/project --turn-verbosity quiet
|
|
|
89
89
|
| `verbose` | Live streaming text plus the margin activity rows on the final, everywhere |
|
|
90
90
|
| `quiet` | The thinking indicator and the answer, nothing in between, everywhere |
|
|
91
91
|
|
|
92
|
+
In verbose mode, authored text remains continual across tool use: text before a
|
|
93
|
+
tool stays as its own speech bubble, the tool appears in the activity margin,
|
|
94
|
+
and text after the result resumes in a new bubble. These are ephemeral streaming
|
|
95
|
+
updates; only the final durable `turn_complete` message is notification-eligible.
|
|
96
|
+
|
|
92
97
|
Quiet drops the live `/streaming` narration and the final's `turnTrail` activity rows. It does **not** drop the thinking indicator (which now stays up for the turn's whole working phase rather than handing over to a bubble that never appears; while the turn is parked on an approval the clients suppress an agent's dots and the header line carries the state), the turn state, the answer — including every part of a long chunked one — failure notices, generated files, or approval and question cards and their receipts.
|
|
93
98
|
|
|
94
99
|
This is an agent-developer setting. Canon never changes it, and it is deliberately not part of the per-conversation session config a user can edit. `canon-necromance` replays a stored launch command verbatim, so add the flag at registration time if you want a non-default value.
|
package/dist/host.js
CHANGED
|
@@ -34,7 +34,7 @@ import { runCli } from '@canonmsg/core';
|
|
|
34
34
|
import { CANON_VERB_MCP_SERVER_NAME, createCanonVerbMcpServer } from '@canonmsg/agent-tools';
|
|
35
35
|
import { synthesizeClaudeApprovalDiff } from './approval-diff.js';
|
|
36
36
|
import { decideClaudeToolPermissionForMode, parseAllowedNonOwnerClaudeTools, } from './tool-policy.js';
|
|
37
|
-
import { applyClaudeSessionControl, boundClaudeFinalMetadata, buildClaudeFinalChunkingOptions, buildClaudeFinalMessageId, buildClaudeFinalTurnMetadata, buildClaudePendingFinalDelivery, buildClaudeTurnFailureNotice, buildTruncatedFinalText, buildUndeliverableFinalNotice, canDrainClaudeQueuedInput, claudeFinalWillChunk, classifyFinalDeliveryFailure, claudeInputOwnsTurnSlot, createClaudeTurnActivityState, decideClaudeControlSignalAction, decideClaudeInboundDispatch, dispatchClaudeInput, isClaudeTurnSlotReserved, readClaudeFinalDeliveryResume, releaseClaudeTurnSlot, runClaudeExhaustedFinalDelivery, shouldApplyClaudeEchoedSessionState, shouldReleaseClaudeTurnSlot, isClaudeMainTurnMessage, openClaudeTurn, planClaudeAssistantTrail, planClaudeStreamingWrite, planClaudeToolCallStart, planClaudeToolProgress, planClaudeToolResults, claudeFinalTurnTrail, publishedClaudeTurnState, rememberDispatchedClaudeInput, resetClaudeTurnActivityState, shouldOpenClaudeTurnOnRunning, shouldStopTypingDotsOnStreamedText, isOpenClaudeTurnState, takeClaudeResultOwner, takeClaudeToolBlockIdByIndex, claudeModelInfoToOption, claudeOriginForCanonSender, composeClaudeTurnFinal, describeUndeliveredClaudeFinal, confirmClaudeInterrupt, createClaudeInputEnvelope, deriveClaudeSupplementalModelProbes, formatClaudeCliVersion, formatClaudeControlError, isClaudeCustomModelOption, isSupportedClaudeCliVersion, mergeClaudeDiscoveredModelOptions, parseClaudeCliVersion, resolveClaudeTurnResponseRouting, resolveClaudeModelOptions, resetClaudeCompletedTurnState, shouldDeliverClaudeFinal, shouldRouteClaudeTurnArtifacts, MINIMUM_CLAUDE_CLI_VERSION, } from './session-state.js';
|
|
37
|
+
import { applyClaudeSessionControl, boundClaudeFinalMetadata, buildClaudeFinalChunkingOptions, buildClaudeFinalMessageId, buildClaudeFinalTurnMetadata, buildClaudePendingFinalDelivery, buildClaudeTurnFailureNotice, buildTruncatedFinalText, buildUndeliverableFinalNotice, canDrainClaudeQueuedInput, beginClaudeAssistantResponse, claimClaudeTextSegmentId, claudeFinalWillChunk, classifyFinalDeliveryFailure, claudeInputOwnsTurnSlot, createClaudeTurnActivityState, decideClaudeControlSignalAction, decideClaudeInboundDispatch, dispatchClaudeInput, endClaudeAssistantResponse, isClaudeTurnSlotReserved, readClaudeFinalDeliveryResume, releaseClaudeTurnSlot, runClaudeExhaustedFinalDelivery, shouldApplyClaudeEchoedSessionState, shouldReleaseClaudeTurnSlot, isClaudeMainTurnMessage, openClaudeTurn, planClaudeAssistantTrail, planClaudeStreamingWrite, planClaudeToolCallStart, planClaudeToolProgress, planClaudeToolResults, claudeFinalTurnTrail, publishedClaudeTurnState, rememberDispatchedClaudeInput, resetClaudeTurnActivityState, shouldOpenClaudeTurnOnRunning, shouldStopTypingDotsOnStreamedText, isOpenClaudeTurnState, takeClaudeResultOwner, takeClaudeToolBlockIdByIndex, claudeModelInfoToOption, claudeOriginForCanonSender, composeClaudeTurnFinal, describeUndeliveredClaudeFinal, confirmClaudeInterrupt, createClaudeInputEnvelope, deriveClaudeSupplementalModelProbes, formatClaudeCliVersion, formatClaudeControlError, isClaudeCustomModelOption, isSupportedClaudeCliVersion, mergeClaudeDiscoveredModelOptions, parseClaudeCliVersion, resolveClaudeTurnResponseRouting, resolveClaudeModelOptions, resetClaudeCompletedTurnState, shouldDeliverClaudeFinal, shouldRouteClaudeTurnArtifacts, MINIMUM_CLAUDE_CLI_VERSION, } from './session-state.js';
|
|
38
38
|
import { CLAUDE_SUPPORTED_DIALOG_KINDS, buildClaudeAskUserPermissionDenied, buildClaudeAskUserPermissionResult, createClaudeUserDialogCoordinator, parseClaudeAskUserDialog, parseClaudeAskUserToolInput, resolveClaudeUserDialogRequestId, } from './user-dialog.js';
|
|
39
39
|
function parseRuntimeVisibilityPreset(value) {
|
|
40
40
|
return value === 'normal' || value === 'minimal' || value === 'full' ? value : undefined;
|
|
@@ -2066,7 +2066,17 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
2066
2066
|
// being written.
|
|
2067
2067
|
if (!isClaudeMainTurnMessage(msg.parent_tool_use_id))
|
|
2068
2068
|
break;
|
|
2069
|
-
if (event?.type === '
|
|
2069
|
+
if (event?.type === 'message_start') {
|
|
2070
|
+
beginClaudeAssistantResponse(session.turnActivity);
|
|
2071
|
+
}
|
|
2072
|
+
else if (event?.type === 'message_stop') {
|
|
2073
|
+
endClaudeAssistantResponse(session.turnActivity);
|
|
2074
|
+
}
|
|
2075
|
+
else if (event?.type === 'content_block_start' && event.content_block?.type === 'tool_use') {
|
|
2076
|
+
// A tool is also a response boundary for speech. This fallback
|
|
2077
|
+
// keeps continual streaming correct on SDK streams that omit raw
|
|
2078
|
+
// message_start/message_stop events.
|
|
2079
|
+
endClaudeAssistantResponse(session.turnActivity);
|
|
2070
2080
|
// Claimed per CALL, keyed by the SDK's tool_use id. The old id was
|
|
2071
2081
|
// the turn id, so every call in a turn wrote over the same row.
|
|
2072
2082
|
const commands = planClaudeToolCallStart(session.turnActivity, {
|
|
@@ -2104,8 +2114,10 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
2104
2114
|
stopVisibleWorkSignal();
|
|
2105
2115
|
}
|
|
2106
2116
|
writeTurn();
|
|
2107
|
-
|
|
2108
|
-
|
|
2117
|
+
onStreamDelta(event.delta.text, claimClaudeTextSegmentId(session.turnActivity, {
|
|
2118
|
+
turnId: session.currentTurnId ?? conversationId,
|
|
2119
|
+
index: event.index,
|
|
2120
|
+
}));
|
|
2109
2121
|
}
|
|
2110
2122
|
break;
|
|
2111
2123
|
}
|
package/dist/session-state.d.ts
CHANGED
|
@@ -356,6 +356,10 @@ export interface ClaudeTurnActivityState {
|
|
|
356
356
|
blockIdByToolUseId: Map<string, string>;
|
|
357
357
|
/** This turn's plan block, once TodoWrite has produced one. */
|
|
358
358
|
planBlockId: string | null;
|
|
359
|
+
/** Monotonic identity for assistant responses inside this turn. */
|
|
360
|
+
assistantResponseCount: number;
|
|
361
|
+
/** The response whose text deltas are currently being streamed. */
|
|
362
|
+
activeAssistantResponseKey: string | null;
|
|
359
363
|
}
|
|
360
364
|
/**
|
|
361
365
|
* Whether an SDK message describes the agent's OWN work rather than a
|
|
@@ -367,6 +371,22 @@ export interface ClaudeTurnActivityState {
|
|
|
367
371
|
export declare function isClaudeMainTurnMessage(parentToolUseId: unknown): boolean;
|
|
368
372
|
export declare function createClaudeTurnActivityState(): ClaudeTurnActivityState;
|
|
369
373
|
export declare function resetClaudeTurnActivityState(state: ClaudeTurnActivityState): void;
|
|
374
|
+
/** Open a fresh assistant response, whose content-block indexes start at zero. */
|
|
375
|
+
export declare function beginClaudeAssistantResponse(state: ClaudeTurnActivityState): string;
|
|
376
|
+
/** Close the response so a later text delta cannot reuse its block identity. */
|
|
377
|
+
export declare function endClaudeAssistantResponse(state: ClaudeTurnActivityState): void;
|
|
378
|
+
/**
|
|
379
|
+
* Stable id for one text block inside one assistant response.
|
|
380
|
+
*
|
|
381
|
+
* Anthropic restarts `content_block.index` for every assistant response. The
|
|
382
|
+
* response key is therefore required to distinguish text before a tool from
|
|
383
|
+
* text emitted after its result. Lazily opening a response keeps older SDK
|
|
384
|
+
* streams that omit `message_start` safe as well.
|
|
385
|
+
*/
|
|
386
|
+
export declare function claimClaudeTextSegmentId(state: ClaudeTurnActivityState, input: {
|
|
387
|
+
turnId?: string | null;
|
|
388
|
+
index?: unknown;
|
|
389
|
+
}): string;
|
|
370
390
|
export declare function claudeToolBlockId(toolUseId: string): string;
|
|
371
391
|
export declare function claudePlanBlockId(turnId: string | null | undefined): string;
|
|
372
392
|
/**
|
package/dist/session-state.js
CHANGED
|
@@ -376,12 +376,42 @@ export function createClaudeTurnActivityState() {
|
|
|
376
376
|
blockIdByIndex: new Map(),
|
|
377
377
|
blockIdByToolUseId: new Map(),
|
|
378
378
|
planBlockId: null,
|
|
379
|
+
assistantResponseCount: 0,
|
|
380
|
+
activeAssistantResponseKey: null,
|
|
379
381
|
};
|
|
380
382
|
}
|
|
381
383
|
export function resetClaudeTurnActivityState(state) {
|
|
382
384
|
state.blockIdByIndex.clear();
|
|
383
385
|
state.blockIdByToolUseId.clear();
|
|
384
386
|
state.planBlockId = null;
|
|
387
|
+
state.assistantResponseCount = 0;
|
|
388
|
+
state.activeAssistantResponseKey = null;
|
|
389
|
+
}
|
|
390
|
+
/** Open a fresh assistant response, whose content-block indexes start at zero. */
|
|
391
|
+
export function beginClaudeAssistantResponse(state) {
|
|
392
|
+
state.assistantResponseCount += 1;
|
|
393
|
+
state.activeAssistantResponseKey = `response-${state.assistantResponseCount}`;
|
|
394
|
+
return state.activeAssistantResponseKey;
|
|
395
|
+
}
|
|
396
|
+
/** Close the response so a later text delta cannot reuse its block identity. */
|
|
397
|
+
export function endClaudeAssistantResponse(state) {
|
|
398
|
+
state.activeAssistantResponseKey = null;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Stable id for one text block inside one assistant response.
|
|
402
|
+
*
|
|
403
|
+
* Anthropic restarts `content_block.index` for every assistant response. The
|
|
404
|
+
* response key is therefore required to distinguish text before a tool from
|
|
405
|
+
* text emitted after its result. Lazily opening a response keeps older SDK
|
|
406
|
+
* streams that omit `message_start` safe as well.
|
|
407
|
+
*/
|
|
408
|
+
export function claimClaudeTextSegmentId(state, input) {
|
|
409
|
+
const responseKey = state.activeAssistantResponseKey
|
|
410
|
+
?? beginClaudeAssistantResponse(state);
|
|
411
|
+
const index = typeof input.index === 'number' && Number.isInteger(input.index)
|
|
412
|
+
? input.index
|
|
413
|
+
: 'latest';
|
|
414
|
+
return buildTrailBlockId('text', input.turnId ?? 'turn', responseKey, index);
|
|
385
415
|
}
|
|
386
416
|
export function claudeToolBlockId(toolUseId) {
|
|
387
417
|
return buildTrailBlockId('tool', toolUseId);
|
package/package.json
CHANGED