@canonmsg/claude-code-plugin 0.23.0 → 0.24.0
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 +116 -69
- package/dist/session-state.d.ts +42 -1
- package/dist/session-state.js +71 -0
- package/package.json +3 -3
package/dist/host.js
CHANGED
|
@@ -33,7 +33,7 @@ import { decideAutoReply, } from './inbound-policy.js';
|
|
|
33
33
|
import { runCli } from './cli-entry.js';
|
|
34
34
|
import { synthesizeClaudeApprovalDiff } from './approval-diff.js';
|
|
35
35
|
import { decideClaudeToolPermissionForMode, parseAllowedNonOwnerClaudeTools, } from './tool-policy.js';
|
|
36
|
-
import { buildClaudeFinalMessageId, createClaudeInputEnvelope, formatClaudeControlError, mergeClaudeModelOptions, resetClaudeCompletedTurnState, shouldDeliverClaudeFinal, } from './session-state.js';
|
|
36
|
+
import { applyClaudeSessionControl, buildClaudeFinalMessageId, createClaudeInputEnvelope, formatClaudeControlError, mergeClaudeModelOptions, resetClaudeCompletedTurnState, shouldDeliverClaudeFinal, } from './session-state.js';
|
|
37
37
|
function parseRuntimeVisibilityPreset(value) {
|
|
38
38
|
return value === 'normal' || value === 'minimal' || value === 'full' ? value : undefined;
|
|
39
39
|
}
|
|
@@ -195,6 +195,26 @@ function buildClaudeRuntimeDescriptor(input) {
|
|
|
195
195
|
controlId: 'effort',
|
|
196
196
|
},
|
|
197
197
|
},
|
|
198
|
+
{
|
|
199
|
+
id: 'ultracode-details',
|
|
200
|
+
label: 'Ultracode',
|
|
201
|
+
description: 'Toggle Claude ultracode using /ultracode.',
|
|
202
|
+
aliases: ['ultracode'],
|
|
203
|
+
category: 'runtime',
|
|
204
|
+
placements: ['composer_slash', 'command_palette'],
|
|
205
|
+
availability: ['always'],
|
|
206
|
+
args: [{
|
|
207
|
+
id: 'level',
|
|
208
|
+
label: 'Level',
|
|
209
|
+
kind: 'enum',
|
|
210
|
+
required: true,
|
|
211
|
+
choices: [...CLAUDE_ULTRACODE_OPTIONS],
|
|
212
|
+
}],
|
|
213
|
+
dispatch: {
|
|
214
|
+
kind: 'control',
|
|
215
|
+
controlId: 'ultracode',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
198
218
|
{
|
|
199
219
|
...RUNTIME_NEW_SESSION_ACTION,
|
|
200
220
|
primitive: 'session.new',
|
|
@@ -212,6 +232,15 @@ function buildClaudeRuntimeDescriptor(input) {
|
|
|
212
232
|
permissionModes: CLAUDE_PERMISSION_MODE_OPTIONS,
|
|
213
233
|
defaultPermissionMode: 'default',
|
|
214
234
|
effortOptions: [...CLAUDE_EFFORT_OPTIONS],
|
|
235
|
+
extraRuntimeControls: [{
|
|
236
|
+
id: 'ultracode',
|
|
237
|
+
label: 'Ultracode',
|
|
238
|
+
options: [...CLAUDE_ULTRACODE_OPTIONS],
|
|
239
|
+
defaultValue: 'off',
|
|
240
|
+
availability: 'setup_and_live',
|
|
241
|
+
liveBehavior: 'immediate',
|
|
242
|
+
selectionPolicy: 'inherit',
|
|
243
|
+
}],
|
|
215
244
|
streamingTextMode: 'delta',
|
|
216
245
|
turnModes: [
|
|
217
246
|
{
|
|
@@ -257,6 +286,16 @@ function normalizeClaudeEffortLevel(value) {
|
|
|
257
286
|
async function applyClaudeEffortLevel(q, effort) {
|
|
258
287
|
await q.applyFlagSettings({ effortLevel: effort });
|
|
259
288
|
}
|
|
289
|
+
const CLAUDE_ULTRACODE_OPTIONS = [
|
|
290
|
+
{ value: 'on', label: 'On' },
|
|
291
|
+
{ value: 'off', label: 'Off' },
|
|
292
|
+
];
|
|
293
|
+
function parseClaudeUltracodeMode(value) {
|
|
294
|
+
return value === 'on' || value === 'off' ? value : undefined;
|
|
295
|
+
}
|
|
296
|
+
async function applyClaudeUltracode(q, enabled) {
|
|
297
|
+
await q.applyFlagSettings({ ultracode: enabled });
|
|
298
|
+
}
|
|
260
299
|
let cachedClaudeCliPath;
|
|
261
300
|
// The SDK bundles a Bun-compiled `claude` Mach-O binary next to
|
|
262
301
|
// claude-agent-sdk-darwin-arm64. On some macOS setups that exact binary gets
|
|
@@ -314,6 +353,7 @@ async function loadSessionConfig(conversationId, agentId) {
|
|
|
314
353
|
? parseClaudePermissionMode(config.permissionMode) ?? undefined
|
|
315
354
|
: undefined,
|
|
316
355
|
effort: normalizeClaudeEffortLevel(config?.effort),
|
|
356
|
+
ultracode: parseClaudeUltracodeMode(config?.runtimeControlValues?.ultracode),
|
|
317
357
|
};
|
|
318
358
|
}
|
|
319
359
|
function resolveSessionExecutionMode(config) {
|
|
@@ -988,6 +1028,9 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
988
1028
|
if (session.state.permissionMode === 'plan') {
|
|
989
1029
|
session.state.permissionMode = 'default';
|
|
990
1030
|
writeState();
|
|
1031
|
+
// Converge the app immediately on the SDK-driven plan-mode exit
|
|
1032
|
+
// instead of waiting for the next 30s heartbeat (lag fix).
|
|
1033
|
+
config.publishSessionSnapshots?.([conversationId]);
|
|
991
1034
|
}
|
|
992
1035
|
return { behavior: 'allow' };
|
|
993
1036
|
}
|
|
@@ -1056,6 +1099,7 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
1056
1099
|
model: undefined,
|
|
1057
1100
|
permissionMode: config.permissionMode,
|
|
1058
1101
|
effort: undefined,
|
|
1102
|
+
ultracode: undefined,
|
|
1059
1103
|
state: 'idle',
|
|
1060
1104
|
},
|
|
1061
1105
|
availableModels: config.availableModels,
|
|
@@ -1324,10 +1368,17 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
1324
1368
|
else if (config.effort !== undefined) {
|
|
1325
1369
|
controlState.effort = { value: config.effort, source: 'requested' };
|
|
1326
1370
|
}
|
|
1371
|
+
if (session.state.ultracode !== undefined) {
|
|
1372
|
+
controlState.ultracode = { value: session.state.ultracode, source: 'applied', appliedAt };
|
|
1373
|
+
}
|
|
1374
|
+
else if (config.ultracode !== undefined) {
|
|
1375
|
+
controlState.ultracode = { value: config.ultracode, source: 'requested' };
|
|
1376
|
+
}
|
|
1327
1377
|
runtimeState.writeSessionState(conversationId, {
|
|
1328
1378
|
model: session.state.model,
|
|
1329
1379
|
permissionMode: session.state.permissionMode,
|
|
1330
1380
|
effort: session.state.effort,
|
|
1381
|
+
...(session.state.ultracode ? { runtimeControlValues: { ultracode: session.state.ultracode } } : {}),
|
|
1331
1382
|
controlState,
|
|
1332
1383
|
runtimeControlErrors,
|
|
1333
1384
|
contextUsage: session.state.contextUsage,
|
|
@@ -1666,6 +1717,15 @@ function createSession(conversationId, environment, agentId, client, typingSigna
|
|
|
1666
1717
|
console.error(`[canon-host] [${conversationId.slice(0, 8)}] Failed to set initial effort:`, err);
|
|
1667
1718
|
}
|
|
1668
1719
|
}
|
|
1720
|
+
if (config.ultracode) {
|
|
1721
|
+
try {
|
|
1722
|
+
await applyClaudeUltracode(q, config.ultracode === 'on');
|
|
1723
|
+
session.state.ultracode = config.ultracode;
|
|
1724
|
+
}
|
|
1725
|
+
catch (err) {
|
|
1726
|
+
console.error(`[canon-host] [${conversationId.slice(0, 8)}] Failed to set initial ultracode:`, err);
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1669
1729
|
if (!resumeSessionId) {
|
|
1670
1730
|
// New session — send seed message to activate streaming input mode
|
|
1671
1731
|
sendInput(createClaudeInputEnvelope({
|
|
@@ -1848,31 +1908,15 @@ export async function main() {
|
|
|
1848
1908
|
const promptedGroupContextConversationIds = new Set();
|
|
1849
1909
|
const pendingMembershipChanges = new Map();
|
|
1850
1910
|
let lastKnownConversationRefreshAt = 0;
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
});
|
|
1858
|
-
if (!streamConnected)
|
|
1911
|
+
// Publish the app-subscribed /agent-session snapshot for the given
|
|
1912
|
+
// conversations. Extracted from the heartbeat so control handlers can converge
|
|
1913
|
+
// the app immediately instead of waiting for the next 30s heartbeat
|
|
1914
|
+
// (session-control lag fix). Hoisted so it is reachable from earlier code.
|
|
1915
|
+
async function publishSessionSnapshots(conversationIds) {
|
|
1916
|
+
if (!streamConnected || conversationIds.length === 0)
|
|
1859
1917
|
return;
|
|
1860
|
-
await refreshKnownConversationIds().catch((error) => {
|
|
1861
|
-
console.error('[canon-host] Failed to refresh known conversations:', error);
|
|
1862
|
-
});
|
|
1863
|
-
const activeSessionQuery = sessions.values().next().value?.query ?? null;
|
|
1864
|
-
const metadata = await refreshClaudeRuntimeMetadata({
|
|
1865
|
-
cwd: workingDir,
|
|
1866
|
-
activeQuery: activeSessionQuery,
|
|
1867
|
-
}).catch((error) => {
|
|
1868
|
-
console.error('[canon-host] Failed to refresh Claude runtime metadata:', error);
|
|
1869
|
-
return runtimeMetadata;
|
|
1870
|
-
});
|
|
1871
|
-
await publishAgentRuntime(agentId, runtimeDescriptor).catch((error) => {
|
|
1872
|
-
console.error('[canon-host] Failed to publish agent runtime:', error);
|
|
1873
|
-
});
|
|
1874
1918
|
await publishHostSessionSnapshots({
|
|
1875
|
-
conversationIds
|
|
1919
|
+
conversationIds,
|
|
1876
1920
|
agentId,
|
|
1877
1921
|
clientType: 'claude-code',
|
|
1878
1922
|
runtime: runtimeDescriptor,
|
|
@@ -1887,6 +1931,7 @@ export async function main() {
|
|
|
1887
1931
|
...(session.state.model ? { model: session.state.model } : {}),
|
|
1888
1932
|
...(session.state.permissionMode ? { permissionMode: session.state.permissionMode } : {}),
|
|
1889
1933
|
...(session.state.effort ? { effort: session.state.effort } : {}),
|
|
1934
|
+
...(session.state.ultracode ? { runtimeControlValues: { ultracode: session.state.ultracode } } : {}),
|
|
1890
1935
|
...(workspaceId ? { workspaceId } : {}),
|
|
1891
1936
|
executionMode: session.environment.mode,
|
|
1892
1937
|
executionBranch: session.environment.branch ?? null,
|
|
@@ -1896,6 +1941,31 @@ export async function main() {
|
|
|
1896
1941
|
}).catch((error) => {
|
|
1897
1942
|
console.error('[canon-host] Failed to publish session snapshots:', error);
|
|
1898
1943
|
});
|
|
1944
|
+
}
|
|
1945
|
+
const publishRuntimeHeartbeat = async () => {
|
|
1946
|
+
heartbeatLocalRuntimeEntry(runtimeId, {
|
|
1947
|
+
agentId,
|
|
1948
|
+
agentName: profileAgentName,
|
|
1949
|
+
cwd: workingDir,
|
|
1950
|
+
baseCwd: workingDir,
|
|
1951
|
+
});
|
|
1952
|
+
if (!streamConnected)
|
|
1953
|
+
return;
|
|
1954
|
+
await refreshKnownConversationIds().catch((error) => {
|
|
1955
|
+
console.error('[canon-host] Failed to refresh known conversations:', error);
|
|
1956
|
+
});
|
|
1957
|
+
const activeSessionQuery = sessions.values().next().value?.query ?? null;
|
|
1958
|
+
const metadata = await refreshClaudeRuntimeMetadata({
|
|
1959
|
+
cwd: workingDir,
|
|
1960
|
+
activeQuery: activeSessionQuery,
|
|
1961
|
+
}).catch((error) => {
|
|
1962
|
+
console.error('[canon-host] Failed to refresh Claude runtime metadata:', error);
|
|
1963
|
+
return runtimeMetadata;
|
|
1964
|
+
});
|
|
1965
|
+
await publishAgentRuntime(agentId, runtimeDescriptor).catch((error) => {
|
|
1966
|
+
console.error('[canon-host] Failed to publish agent runtime:', error);
|
|
1967
|
+
});
|
|
1968
|
+
await publishSessionSnapshots(Array.from(knownConversationIds));
|
|
1899
1969
|
// Rebuild so the descriptor picks up native slash commands from the
|
|
1900
1970
|
// metadata refresh above — the initial descriptor is built before the
|
|
1901
1971
|
// command inventory has loaded.
|
|
@@ -2293,6 +2363,7 @@ export async function main() {
|
|
|
2293
2363
|
model: config?.model ?? runtimeModels[0]?.value,
|
|
2294
2364
|
permissionMode: config?.permissionMode ?? 'default',
|
|
2295
2365
|
effort: config?.effort,
|
|
2366
|
+
ultracode: config?.ultracode,
|
|
2296
2367
|
availableModels: runtimeModels,
|
|
2297
2368
|
availableExecutionModes: hostAvailableExecutionModes,
|
|
2298
2369
|
runtimePresentation,
|
|
@@ -2300,6 +2371,7 @@ export async function main() {
|
|
|
2300
2371
|
canRequestApproval: () => canRequestCanonApproval(conversationId),
|
|
2301
2372
|
runtimeId,
|
|
2302
2373
|
ownerId,
|
|
2374
|
+
publishSessionSnapshots: (ids) => { void publishSessionSnapshots(ids); },
|
|
2303
2375
|
}, resumeId);
|
|
2304
2376
|
sessions.set(conversationId, session);
|
|
2305
2377
|
await controlPoller.baseline([conversationId]);
|
|
@@ -2609,51 +2681,26 @@ export async function main() {
|
|
|
2609
2681
|
return { consume: false };
|
|
2610
2682
|
const ctrl = event.control;
|
|
2611
2683
|
console.error(`[canon-host] [${convoId.slice(0, 8)}] Control:`, ctrl);
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
session.state.permissionMode = nextPermissionMode;
|
|
2633
|
-
session.clearRuntimeControlError('permissionMode');
|
|
2634
|
-
console.error(`[canon-host] [${convoId.slice(0, 8)}] Mode → ${nextPermissionMode}`);
|
|
2635
|
-
}
|
|
2636
|
-
catch (err) {
|
|
2637
|
-
session.setRuntimeControlError('permissionMode', nextPermissionMode, err);
|
|
2638
|
-
console.error(`[canon-host] [${convoId.slice(0, 8)}] Failed to set mode:`, err);
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
const nextEffort = normalizeClaudeEffortLevel(ctrl.effort);
|
|
2642
|
-
if (nextEffort && nextEffort !== session.state.effort) {
|
|
2643
|
-
try {
|
|
2644
|
-
await applyClaudeEffortLevel(session.query, nextEffort);
|
|
2645
|
-
session.state.effort = nextEffort;
|
|
2646
|
-
session.clearRuntimeControlError('effort');
|
|
2647
|
-
console.error(`[canon-host] [${convoId.slice(0, 8)}] Effort → ${nextEffort}`);
|
|
2648
|
-
}
|
|
2649
|
-
catch (err) {
|
|
2650
|
-
session.setRuntimeControlError('effort', nextEffort, err);
|
|
2651
|
-
console.error(`[canon-host] [${convoId.slice(0, 8)}] Failed to set effort:`, err);
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
else if (ctrl.effort && !nextEffort) {
|
|
2655
|
-
session.setRuntimeControlError('effort', String(ctrl.effort), new Error('Unsupported Claude thinking level.'));
|
|
2656
|
-
}
|
|
2684
|
+
await applyClaudeSessionControl({
|
|
2685
|
+
model: ctrl.model,
|
|
2686
|
+
permissionMode: ctrl.permissionMode,
|
|
2687
|
+
effort: ctrl.effort,
|
|
2688
|
+
ultracode: ctrl.runtimeControlValues?.ultracode,
|
|
2689
|
+
}, {
|
|
2690
|
+
state: session.state,
|
|
2691
|
+
parsePermissionMode: parseClaudePermissionMode,
|
|
2692
|
+
normalizeEffort: normalizeClaudeEffortLevel,
|
|
2693
|
+
parseUltracode: parseClaudeUltracodeMode,
|
|
2694
|
+
setModel: (model) => session.query.setModel(model),
|
|
2695
|
+
setPermissionMode: (mode) => session.query.setPermissionMode(mode),
|
|
2696
|
+
applyEffort: (level) => applyClaudeEffortLevel(session.query, level),
|
|
2697
|
+
applyUltracode: (enabled) => applyClaudeUltracode(session.query, enabled),
|
|
2698
|
+
setRuntimeControlError: (controlId, value, error) => session.setRuntimeControlError(controlId, value, error),
|
|
2699
|
+
clearRuntimeControlError: (controlId) => session.clearRuntimeControlError(controlId),
|
|
2700
|
+
// Publish the app-subscribed snapshot immediately so the control-pending
|
|
2701
|
+
// gate clears now instead of at the next 30s heartbeat (lag fix).
|
|
2702
|
+
publishSnapshot: () => { void publishSessionSnapshots([convoId]); },
|
|
2703
|
+
});
|
|
2657
2704
|
session.writeState();
|
|
2658
2705
|
}
|
|
2659
2706
|
// Interrupt/stop-clear signal. Throwing leaves the node in place
|
package/dist/session-state.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
1
|
+
import type { PermissionMode, SDKUserMessage } from '@anthropic-ai/claude-agent-sdk';
|
|
2
2
|
import type { DeliveryIntent, ModelOption, TurnLifecycleState } from '@canonmsg/core';
|
|
3
3
|
import type { TurnArtifactSnapshot } from '@canonmsg/coding-agent-host';
|
|
4
4
|
export type ClaudeInputKind = 'seed' | 'canon';
|
|
@@ -66,3 +66,44 @@ export declare function mergeClaudeModelOptions(input: {
|
|
|
66
66
|
selectedModel?: string | null;
|
|
67
67
|
}): ModelOption[];
|
|
68
68
|
export declare function formatClaudeControlError(error: unknown): string;
|
|
69
|
+
/** Requested session-control values from the control plane (raw, pre-validation). */
|
|
70
|
+
export interface ClaudeSessionControlInput {
|
|
71
|
+
model?: string;
|
|
72
|
+
permissionMode?: string;
|
|
73
|
+
effort?: string;
|
|
74
|
+
ultracode?: string;
|
|
75
|
+
}
|
|
76
|
+
/** Mutable mirror of the live session's control state — mutated in place on success. */
|
|
77
|
+
export interface ClaudeSessionControlState {
|
|
78
|
+
model?: string;
|
|
79
|
+
permissionMode?: string;
|
|
80
|
+
effort?: string;
|
|
81
|
+
ultracode?: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Injected validators + side effects so the apply logic stays host-agnostic and
|
|
85
|
+
* unit-testable. The host wires these to the live SDK query and its runtime
|
|
86
|
+
* control-error bookkeeping; tests inject fakes.
|
|
87
|
+
*/
|
|
88
|
+
export interface ClaudeSessionControlDeps {
|
|
89
|
+
state: ClaudeSessionControlState;
|
|
90
|
+
parsePermissionMode: (value: unknown) => PermissionMode | null;
|
|
91
|
+
normalizeEffort: (value: unknown) => string | undefined;
|
|
92
|
+
parseUltracode: (value: unknown) => string | undefined;
|
|
93
|
+
setModel: (model: string) => Promise<void>;
|
|
94
|
+
setPermissionMode: (mode: PermissionMode) => Promise<void>;
|
|
95
|
+
applyEffort: (level: string) => Promise<void>;
|
|
96
|
+
applyUltracode: (enabled: boolean) => Promise<void>;
|
|
97
|
+
setRuntimeControlError: (controlId: string, value: string, error: unknown) => void;
|
|
98
|
+
clearRuntimeControlError: (controlId: string) => void;
|
|
99
|
+
publishSnapshot: () => void;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Apply a session-control request to the live Claude session. Mirrors the host's
|
|
103
|
+
* control semantics (validation, only-if-different checks, error recording,
|
|
104
|
+
* clear-on-success). Whenever a live op is invoked — on success OR caught
|
|
105
|
+
* failure — publishSnapshot() is called exactly once so the app-subscribed
|
|
106
|
+
* /agent-session snapshot converges immediately instead of waiting for the next
|
|
107
|
+
* heartbeat. If nothing changed, publishSnapshot() is not called.
|
|
108
|
+
*/
|
|
109
|
+
export declare function applyClaudeSessionControl(control: ClaudeSessionControlInput, deps: ClaudeSessionControlDeps): Promise<void>;
|
package/dist/session-state.js
CHANGED
|
@@ -82,3 +82,74 @@ export function formatClaudeControlError(error) {
|
|
|
82
82
|
}
|
|
83
83
|
return 'Claude Code did not apply that control.';
|
|
84
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Apply a session-control request to the live Claude session. Mirrors the host's
|
|
87
|
+
* control semantics (validation, only-if-different checks, error recording,
|
|
88
|
+
* clear-on-success). Whenever a live op is invoked — on success OR caught
|
|
89
|
+
* failure — publishSnapshot() is called exactly once so the app-subscribed
|
|
90
|
+
* /agent-session snapshot converges immediately instead of waiting for the next
|
|
91
|
+
* heartbeat. If nothing changed, publishSnapshot() is not called.
|
|
92
|
+
*/
|
|
93
|
+
export async function applyClaudeSessionControl(control, deps) {
|
|
94
|
+
const { state } = deps;
|
|
95
|
+
let liveOpInvoked = false;
|
|
96
|
+
if (control.model && control.model !== state.model) {
|
|
97
|
+
liveOpInvoked = true;
|
|
98
|
+
try {
|
|
99
|
+
await deps.setModel(control.model);
|
|
100
|
+
state.model = control.model;
|
|
101
|
+
deps.clearRuntimeControlError('model');
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
deps.setRuntimeControlError('model', control.model, err);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const nextPermissionMode = deps.parsePermissionMode(control.permissionMode);
|
|
108
|
+
if (control.permissionMode && !nextPermissionMode) {
|
|
109
|
+
deps.setRuntimeControlError('permissionMode', control.permissionMode, new Error(`Unsupported Claude permission mode: ${control.permissionMode}`));
|
|
110
|
+
}
|
|
111
|
+
else if (nextPermissionMode && nextPermissionMode !== state.permissionMode) {
|
|
112
|
+
liveOpInvoked = true;
|
|
113
|
+
try {
|
|
114
|
+
await deps.setPermissionMode(nextPermissionMode);
|
|
115
|
+
state.permissionMode = nextPermissionMode;
|
|
116
|
+
deps.clearRuntimeControlError('permissionMode');
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
deps.setRuntimeControlError('permissionMode', nextPermissionMode, err);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const nextEffort = deps.normalizeEffort(control.effort);
|
|
123
|
+
if (nextEffort && nextEffort !== state.effort) {
|
|
124
|
+
liveOpInvoked = true;
|
|
125
|
+
try {
|
|
126
|
+
await deps.applyEffort(nextEffort);
|
|
127
|
+
state.effort = nextEffort;
|
|
128
|
+
deps.clearRuntimeControlError('effort');
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
deps.setRuntimeControlError('effort', nextEffort, err);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (control.effort && !nextEffort) {
|
|
135
|
+
deps.setRuntimeControlError('effort', String(control.effort), new Error('Unsupported Claude thinking level.'));
|
|
136
|
+
}
|
|
137
|
+
const nextUltracode = deps.parseUltracode(control.ultracode);
|
|
138
|
+
if (control.ultracode && !nextUltracode) {
|
|
139
|
+
deps.setRuntimeControlError('ultracode', String(control.ultracode), new Error('Unsupported Claude ultracode mode.'));
|
|
140
|
+
}
|
|
141
|
+
else if (nextUltracode && nextUltracode !== state.ultracode) {
|
|
142
|
+
liveOpInvoked = true;
|
|
143
|
+
try {
|
|
144
|
+
await deps.applyUltracode(nextUltracode === 'on');
|
|
145
|
+
state.ultracode = nextUltracode;
|
|
146
|
+
deps.clearRuntimeControlError('ultracode');
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
deps.setRuntimeControlError('ultracode', nextUltracode, err);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (liveOpInvoked) {
|
|
153
|
+
deps.publishSnapshot();
|
|
154
|
+
}
|
|
155
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/claude-code-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
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",
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"test": "vitest run"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@anthropic-ai/claude-agent-sdk": "^0.
|
|
33
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.200",
|
|
34
34
|
"@canonmsg/agent-sdk": "^5.0.0",
|
|
35
35
|
"@canonmsg/coding-agent-host": "^0.2.2",
|
|
36
|
-
"@canonmsg/core": "^4.
|
|
36
|
+
"@canonmsg/core": "^4.1.0",
|
|
37
37
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|