@canonmsg/claude-code-plugin 0.22.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/.claude-plugin/plugin.json +25 -0
- package/README.md +18 -2
- package/dist/approval-diff.d.ts +1 -1
- package/dist/approval-diff.js +1 -1
- package/dist/approval-server.d.ts +33 -0
- package/dist/approval-server.js +200 -0
- package/dist/cli-entry.d.ts +2 -2
- package/dist/cli-entry.js +1 -1
- package/dist/host.d.ts +1 -1
- package/dist/host.js +1079 -678
- package/dist/inbound-policy.d.ts +22 -0
- package/dist/inbound-policy.js +46 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/mcp-args.d.ts +45 -0
- package/dist/mcp-args.js +179 -0
- package/dist/register.js +25 -73
- package/dist/server.d.ts +2 -0
- package/dist/server.js +699 -0
- package/dist/session-state.d.ts +47 -54
- package/dist/session-state.js +88 -166
- package/dist/setup.d.ts +3 -2
- package/dist/setup.js +29 -5
- package/dist/startup-recovery.d.ts +46 -0
- package/dist/startup-recovery.js +59 -0
- package/dist/streaming-buffer.d.ts +16 -0
- package/dist/streaming-buffer.js +52 -0
- package/dist/tool-policy.d.ts +1 -2
- package/package.json +11 -11
- package/skills/configure/SKILL.md +10 -4
- package/dist/bridge-bin.d.ts +0 -14
- package/dist/bridge-bin.js +0 -27
- package/dist/session-defaults.d.ts +0 -35
- package/dist/session-defaults.js +0 -124
- package/dist/subagent-activity.d.ts +0 -11
- package/dist/subagent-activity.js +0 -51
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CanonGroupContext, type CanonGroupContextMode, type CanonConversation, type ResolvedAgentBehaviorPolicy } from '@canonmsg/core';
|
|
2
|
+
export interface InboundParticipantContext {
|
|
3
|
+
conversationType: CanonConversation['type'] | 'unknown';
|
|
4
|
+
memberCount: number | null;
|
|
5
|
+
senderType: 'human' | 'ai_agent';
|
|
6
|
+
senderName: string;
|
|
7
|
+
isOwner: boolean;
|
|
8
|
+
mentionedAgent: boolean;
|
|
9
|
+
groupContext?: CanonGroupContext;
|
|
10
|
+
groupContextMode?: CanonGroupContextMode;
|
|
11
|
+
recentSenderTypes: Array<'human' | 'ai_agent'>;
|
|
12
|
+
recentHumanCount: number;
|
|
13
|
+
recentAgentCount: number;
|
|
14
|
+
consecutiveAgentTurns: number;
|
|
15
|
+
currentAgentStreakStartedByHuman: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface AutoReplyDecision {
|
|
18
|
+
allow: boolean;
|
|
19
|
+
reason: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function buildInboundContextLines(context: InboundParticipantContext): string[];
|
|
22
|
+
export declare function decideAutoReply(context: InboundParticipantContext, behavior?: ResolvedAgentBehaviorPolicy | null): AutoReplyDecision;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { buildCompactGroupContextLines, evaluateParticipationPolicy, resolveAgentBehaviorPolicy, } from '@canonmsg/core';
|
|
2
|
+
function formatRecentSenders(senderTypes) {
|
|
3
|
+
if (senderTypes.length === 0)
|
|
4
|
+
return 'none';
|
|
5
|
+
return senderTypes.map((senderType) => (senderType === 'ai_agent' ? 'agent' : 'human')).join(' -> ');
|
|
6
|
+
}
|
|
7
|
+
export function buildInboundContextLines(context) {
|
|
8
|
+
const conversationTypeLabel = context.conversationType === 'unknown'
|
|
9
|
+
? 'unknown'
|
|
10
|
+
: `${context.conversationType}${context.memberCount ? ` (${context.memberCount} members)` : ''}`;
|
|
11
|
+
const senderRole = context.isOwner
|
|
12
|
+
? 'The latest sender is the verified human owner of this Canon agent.'
|
|
13
|
+
: context.senderType === 'ai_agent'
|
|
14
|
+
? 'The latest sender is another AI agent in Canon.'
|
|
15
|
+
: 'The latest sender is a human Canon participant.';
|
|
16
|
+
return [
|
|
17
|
+
senderRole,
|
|
18
|
+
`Latest sender name: ${context.senderName}`,
|
|
19
|
+
`Latest sender type: ${context.senderType}`,
|
|
20
|
+
`Conversation type: ${conversationTypeLabel}`,
|
|
21
|
+
...(context.groupContext && context.groupContextMode
|
|
22
|
+
? buildCompactGroupContextLines(context.groupContext, context.groupContextMode)
|
|
23
|
+
: []),
|
|
24
|
+
`Directly addressed to this agent: ${context.mentionedAgent ? 'yes' : 'no'}`,
|
|
25
|
+
`Recent sender pattern: ${formatRecentSenders(context.recentSenderTypes)}`,
|
|
26
|
+
`Recent human messages: ${context.recentHumanCount}`,
|
|
27
|
+
`Recent agent messages: ${context.recentAgentCount}`,
|
|
28
|
+
`Consecutive recent agent turns: ${context.consecutiveAgentTurns}`,
|
|
29
|
+
`Current agent streak started after a human message: ${context.currentAgentStreakStartedByHuman ? 'yes' : 'no'}`,
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
export function decideAutoReply(context, behavior) {
|
|
33
|
+
const decision = evaluateParticipationPolicy(behavior ?? resolveAgentBehaviorPolicy(), {
|
|
34
|
+
conversationType: context.conversationType,
|
|
35
|
+
senderType: context.senderType,
|
|
36
|
+
isOwner: context.isOwner,
|
|
37
|
+
mentionedAgent: context.mentionedAgent,
|
|
38
|
+
recentHumanCount: context.recentHumanCount,
|
|
39
|
+
consecutiveAgentTurns: context.consecutiveAgentTurns,
|
|
40
|
+
currentAgentStreakStartedByHuman: context.currentAgentStreakStartedByHuman,
|
|
41
|
+
});
|
|
42
|
+
return {
|
|
43
|
+
allow: decision.allow,
|
|
44
|
+
reason: decision.reason,
|
|
45
|
+
};
|
|
46
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { DirectSessionSelection, SendContextualMessageOptions } from '@canonmsg/core';
|
|
2
|
+
export type McpParseResult<T> = {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: T;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
error: string;
|
|
8
|
+
};
|
|
9
|
+
type ContentType = 'text' | 'image' | 'audio' | 'video' | 'file';
|
|
10
|
+
export interface ReplyArgs {
|
|
11
|
+
conversationId: string;
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function parseReplyArgs(value: unknown): McpParseResult<ReplyArgs>;
|
|
15
|
+
export interface SendMessageArgs {
|
|
16
|
+
conversationId: string;
|
|
17
|
+
text: string;
|
|
18
|
+
contentType: ContentType;
|
|
19
|
+
imageUrl?: string;
|
|
20
|
+
audioUrl?: string;
|
|
21
|
+
videoUrl?: string;
|
|
22
|
+
fileUrl?: string;
|
|
23
|
+
mediaPath?: string;
|
|
24
|
+
fileName?: string;
|
|
25
|
+
mimeType?: string;
|
|
26
|
+
durationMs?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function parseSendMessageArgs(value: unknown): McpParseResult<SendMessageArgs>;
|
|
29
|
+
export interface SendContextualMessageArgs {
|
|
30
|
+
sourceConversationId: string;
|
|
31
|
+
targetConversationId?: string;
|
|
32
|
+
targetUserId?: string;
|
|
33
|
+
text: string;
|
|
34
|
+
selfContext: SendContextualMessageOptions['selfContext'];
|
|
35
|
+
sessionSelection?: DirectSessionSelection;
|
|
36
|
+
messageOptions?: SendContextualMessageOptions['messageOptions'];
|
|
37
|
+
}
|
|
38
|
+
export declare function parseSendContextualMessageArgs(value: unknown): McpParseResult<SendContextualMessageArgs>;
|
|
39
|
+
export interface SetTypingArgs {
|
|
40
|
+
conversationId: string;
|
|
41
|
+
typing: boolean;
|
|
42
|
+
status?: 'typing' | 'thinking';
|
|
43
|
+
}
|
|
44
|
+
export declare function parseSetTypingArgs(value: unknown): McpParseResult<SetTypingArgs>;
|
|
45
|
+
export {};
|
package/dist/mcp-args.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
function isRecord(value) {
|
|
2
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
3
|
+
}
|
|
4
|
+
function requiredString(record, key, maxLength = 4096) {
|
|
5
|
+
const value = record[key];
|
|
6
|
+
if (typeof value !== 'string') {
|
|
7
|
+
return { ok: false, error: `Missing ${key}` };
|
|
8
|
+
}
|
|
9
|
+
const trimmed = value.trim();
|
|
10
|
+
if (!trimmed) {
|
|
11
|
+
return { ok: false, error: `Missing ${key}` };
|
|
12
|
+
}
|
|
13
|
+
if (trimmed.length > maxLength) {
|
|
14
|
+
return { ok: false, error: `${key} is too long` };
|
|
15
|
+
}
|
|
16
|
+
return { ok: true, value: trimmed };
|
|
17
|
+
}
|
|
18
|
+
function optionalString(record, key, maxLength = 4096) {
|
|
19
|
+
const value = record[key];
|
|
20
|
+
if (typeof value !== 'string')
|
|
21
|
+
return undefined;
|
|
22
|
+
const trimmed = value.trim();
|
|
23
|
+
return trimmed && trimmed.length <= maxLength ? trimmed : undefined;
|
|
24
|
+
}
|
|
25
|
+
function optionalNumber(record, key) {
|
|
26
|
+
const value = record[key];
|
|
27
|
+
return typeof value === 'number' && Number.isFinite(value) && value >= 0
|
|
28
|
+
? value
|
|
29
|
+
: undefined;
|
|
30
|
+
}
|
|
31
|
+
function parseContentType(value) {
|
|
32
|
+
if (value == null)
|
|
33
|
+
return { ok: true, value: 'text' };
|
|
34
|
+
if (value === 'text' || value === 'image' || value === 'audio' || value === 'video' || value === 'file') {
|
|
35
|
+
return { ok: true, value };
|
|
36
|
+
}
|
|
37
|
+
return { ok: false, error: 'Invalid content_type' };
|
|
38
|
+
}
|
|
39
|
+
export function parseReplyArgs(value) {
|
|
40
|
+
if (!isRecord(value))
|
|
41
|
+
return { ok: false, error: 'Arguments must be an object' };
|
|
42
|
+
const conversationId = requiredString(value, 'conversation_id', 256);
|
|
43
|
+
if (!conversationId.ok)
|
|
44
|
+
return conversationId;
|
|
45
|
+
const text = requiredString(value, 'text');
|
|
46
|
+
if (!text.ok)
|
|
47
|
+
return text;
|
|
48
|
+
return {
|
|
49
|
+
ok: true,
|
|
50
|
+
value: {
|
|
51
|
+
conversationId: conversationId.value,
|
|
52
|
+
text: text.value,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
export function parseSendMessageArgs(value) {
|
|
57
|
+
if (!isRecord(value))
|
|
58
|
+
return { ok: false, error: 'Arguments must be an object' };
|
|
59
|
+
const conversationId = requiredString(value, 'conversation_id', 256);
|
|
60
|
+
if (!conversationId.ok)
|
|
61
|
+
return conversationId;
|
|
62
|
+
const contentType = parseContentType(value.content_type);
|
|
63
|
+
if (!contentType.ok)
|
|
64
|
+
return contentType;
|
|
65
|
+
const imageUrl = optionalString(value, 'image_url', 4096);
|
|
66
|
+
const audioUrl = optionalString(value, 'audio_url', 4096);
|
|
67
|
+
const videoUrl = optionalString(value, 'video_url', 4096);
|
|
68
|
+
const fileUrl = optionalString(value, 'file_url', 4096);
|
|
69
|
+
const mediaPath = optionalString(value, 'media_path', 4096);
|
|
70
|
+
const fileName = optionalString(value, 'file_name', 512);
|
|
71
|
+
const mimeType = optionalString(value, 'mime_type', 256);
|
|
72
|
+
const durationMs = optionalNumber(value, 'duration_ms');
|
|
73
|
+
return {
|
|
74
|
+
ok: true,
|
|
75
|
+
value: {
|
|
76
|
+
conversationId: conversationId.value,
|
|
77
|
+
text: optionalString(value, 'text') ?? '',
|
|
78
|
+
contentType: contentType.value,
|
|
79
|
+
...(imageUrl ? { imageUrl } : {}),
|
|
80
|
+
...(audioUrl ? { audioUrl } : {}),
|
|
81
|
+
...(videoUrl ? { videoUrl } : {}),
|
|
82
|
+
...(fileUrl ? { fileUrl } : {}),
|
|
83
|
+
...(mediaPath ? { mediaPath } : {}),
|
|
84
|
+
...(fileName ? { fileName } : {}),
|
|
85
|
+
...(mimeType ? { mimeType } : {}),
|
|
86
|
+
...(durationMs != null ? { durationMs } : {}),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function parseSessionSelection(value) {
|
|
91
|
+
if (value == null)
|
|
92
|
+
return { ok: true, value: undefined };
|
|
93
|
+
const raw = typeof value === 'string'
|
|
94
|
+
? value
|
|
95
|
+
: isRecord(value) && typeof value.mode === 'string'
|
|
96
|
+
? value.mode
|
|
97
|
+
: null;
|
|
98
|
+
const mode = raw?.trim().toLowerCase().replace(/-/g, '_');
|
|
99
|
+
if (!mode)
|
|
100
|
+
return { ok: false, error: 'Invalid session_selection' };
|
|
101
|
+
if (mode === 'new' || mode === 'fresh' || mode === 'start_new') {
|
|
102
|
+
return { ok: true, value: { mode: 'new' } };
|
|
103
|
+
}
|
|
104
|
+
if (mode === 'continue_latest' || mode === 'latest' || mode === 'continue') {
|
|
105
|
+
return { ok: true, value: { mode: 'continue_latest' } };
|
|
106
|
+
}
|
|
107
|
+
if (mode === 'continue_or_create' || mode === 'auto' || mode === 'reuse_or_create') {
|
|
108
|
+
return { ok: true, value: { mode: 'continue_or_create' } };
|
|
109
|
+
}
|
|
110
|
+
return { ok: false, error: 'session_selection must be new, continue_latest, or continue_or_create' };
|
|
111
|
+
}
|
|
112
|
+
export function parseSendContextualMessageArgs(value) {
|
|
113
|
+
if (!isRecord(value))
|
|
114
|
+
return { ok: false, error: 'Arguments must be an object' };
|
|
115
|
+
const sourceConversationId = requiredString(value, 'source_conversation_id', 256);
|
|
116
|
+
if (!sourceConversationId.ok)
|
|
117
|
+
return sourceConversationId;
|
|
118
|
+
const text = requiredString(value, 'text');
|
|
119
|
+
if (!text.ok)
|
|
120
|
+
return text;
|
|
121
|
+
const targetConversationId = optionalString(value, 'target_conversation_id', 256);
|
|
122
|
+
const targetUserId = optionalString(value, 'target_user_id', 256);
|
|
123
|
+
if (Boolean(targetConversationId) === Boolean(targetUserId)) {
|
|
124
|
+
return { ok: false, error: 'Provide exactly one target_conversation_id or target_user_id' };
|
|
125
|
+
}
|
|
126
|
+
if (!isRecord(value.self_context)) {
|
|
127
|
+
return { ok: false, error: 'Missing self_context' };
|
|
128
|
+
}
|
|
129
|
+
const type = value.self_context.type;
|
|
130
|
+
const context = requiredString(value.self_context, 'context');
|
|
131
|
+
if (!context.ok)
|
|
132
|
+
return context;
|
|
133
|
+
if (type !== 'cross_session') {
|
|
134
|
+
return { ok: false, error: 'self_context.type must be cross_session' };
|
|
135
|
+
}
|
|
136
|
+
const sessionSelection = parseSessionSelection(value.session_selection);
|
|
137
|
+
if (!sessionSelection.ok)
|
|
138
|
+
return sessionSelection;
|
|
139
|
+
const messageOptions = isRecord(value.message_options)
|
|
140
|
+
? value.message_options
|
|
141
|
+
: undefined;
|
|
142
|
+
return {
|
|
143
|
+
ok: true,
|
|
144
|
+
value: {
|
|
145
|
+
sourceConversationId: sourceConversationId.value,
|
|
146
|
+
...(targetConversationId ? { targetConversationId } : {}),
|
|
147
|
+
...(targetUserId ? { targetUserId } : {}),
|
|
148
|
+
text: text.value,
|
|
149
|
+
selfContext: {
|
|
150
|
+
type: 'cross_session',
|
|
151
|
+
context: context.value,
|
|
152
|
+
},
|
|
153
|
+
...(sessionSelection.value ? { sessionSelection: sessionSelection.value } : {}),
|
|
154
|
+
...(messageOptions ? { messageOptions } : {}),
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
export function parseSetTypingArgs(value) {
|
|
159
|
+
if (!isRecord(value))
|
|
160
|
+
return { ok: false, error: 'Arguments must be an object' };
|
|
161
|
+
const conversationId = requiredString(value, 'conversation_id', 256);
|
|
162
|
+
if (!conversationId.ok)
|
|
163
|
+
return conversationId;
|
|
164
|
+
if (typeof value.typing !== 'boolean') {
|
|
165
|
+
return { ok: false, error: 'typing must be a boolean' };
|
|
166
|
+
}
|
|
167
|
+
const status = value.status;
|
|
168
|
+
if (status !== undefined && status !== 'typing' && status !== 'thinking') {
|
|
169
|
+
return { ok: false, error: 'Invalid status' };
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
ok: true,
|
|
173
|
+
value: {
|
|
174
|
+
conversationId: conversationId.value,
|
|
175
|
+
typing: value.typing,
|
|
176
|
+
...(status ? { status } : {}),
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
}
|
package/dist/register.js
CHANGED
|
@@ -9,47 +9,10 @@ import { setDefaultResultOrder } from 'node:dns';
|
|
|
9
9
|
*
|
|
10
10
|
* On approval, saves the agent to ~/.canon/agents.json under the profile name.
|
|
11
11
|
*/
|
|
12
|
-
import {
|
|
13
|
-
import { clearPendingRegistration, getOrCreatePendingRegistration, updatePendingRegistration, upsertAgentProfile, AGENTS_PATH, } from '@canonmsg/core/local';
|
|
14
|
-
import { resolvePackagedBridgeBin } from './bridge-bin.js';
|
|
15
|
-
import { connectBridge } from '@canonmsg/framework';
|
|
12
|
+
import { ackRegistrationApproval, clearPendingRegistration, getOrCreatePendingRegistration, registerAndWaitForApproval, updatePendingRegistration, upsertAgentProfile, AGENTS_PATH, } from '@canonmsg/core';
|
|
16
13
|
import { readFileSync } from 'node:fs';
|
|
17
14
|
import { parseArgs } from 'node:util';
|
|
18
15
|
import { runCli } from './cli-entry.js';
|
|
19
|
-
/**
|
|
20
|
-
* Registration rides the bridge (Phase 6, same shape as the Hermes port): a
|
|
21
|
-
* short-lived PRE-IDENTITY registration daemon (offline stub +
|
|
22
|
-
* CANON_BRIDGE_REGISTRATION_BASE_URL, managed-child so it dies with this
|
|
23
|
-
* process) serves the three unauthenticated §B10 routes over JSON-RPC.
|
|
24
|
-
*/
|
|
25
|
-
async function openRegistrationBridge(baseUrl) {
|
|
26
|
-
return connectBridge({
|
|
27
|
-
profile: 'registration',
|
|
28
|
-
mode: 'managed-child',
|
|
29
|
-
...(resolvePackagedBridgeBin() ? { binPath: resolvePackagedBridgeBin() } : {}),
|
|
30
|
-
env: {
|
|
31
|
-
...process.env,
|
|
32
|
-
CANON_BRIDGE_AGENT_ID: 'canon-registration',
|
|
33
|
-
CANON_BRIDGE_REGISTRATION_BASE_URL: baseUrl,
|
|
34
|
-
},
|
|
35
|
-
hello: { clientType: 'claude-code', wantFamilies: [] },
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
function bridgeRegistrationTransport(bridge) {
|
|
39
|
-
return {
|
|
40
|
-
register: (_baseUrl, body) => bridge.client.call('register', body),
|
|
41
|
-
checkStatus: (_baseUrl, requestId, pollToken) => bridge.client.call('getRegistrationStatus', {
|
|
42
|
-
requestId,
|
|
43
|
-
...(pollToken ? { pollToken } : {}),
|
|
44
|
-
}),
|
|
45
|
-
ackRegistrationStatus: async (_baseUrl, requestId, pollToken) => {
|
|
46
|
-
await bridge.client.call('ackRegistrationStatus', {
|
|
47
|
-
requestId,
|
|
48
|
-
...(pollToken ? { pollToken } : {}),
|
|
49
|
-
});
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
16
|
const HELP = `canon-register — register or reconnect a Claude Code agent in Canon
|
|
54
17
|
|
|
55
18
|
USAGE
|
|
@@ -99,39 +62,29 @@ export async function main() {
|
|
|
99
62
|
}
|
|
100
63
|
console.log(`Registering agent "${values.name}" (profile: ${profileName})...`);
|
|
101
64
|
const pending = getOrCreatePendingRegistration(profileName, 'claude-code');
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
},
|
|
126
|
-
onPollUpdate: () => {
|
|
127
|
-
process.stdout.write('.');
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
catch (error) {
|
|
132
|
-
bridge.client.close();
|
|
133
|
-
throw error;
|
|
134
|
-
}
|
|
65
|
+
const result = await registerAndWaitForApproval({
|
|
66
|
+
name: values.name,
|
|
67
|
+
description: values.description,
|
|
68
|
+
ownerPhone: values.phone,
|
|
69
|
+
developerInfo: 'Claude Code plugin',
|
|
70
|
+
clientType: 'claude-code',
|
|
71
|
+
baseUrl: values['base-url'],
|
|
72
|
+
requestedAgentId: existingAgentId,
|
|
73
|
+
localRegistrationId: pending.localRegistrationId,
|
|
74
|
+
}, {
|
|
75
|
+
onSubmitted: (requestId, pollToken) => {
|
|
76
|
+
updatePendingRegistration(profileName, {
|
|
77
|
+
requestId,
|
|
78
|
+
pollToken,
|
|
79
|
+
clientType: 'claude-code',
|
|
80
|
+
});
|
|
81
|
+
console.log(`Registration submitted (request ID: ${requestId}).`);
|
|
82
|
+
console.log('Waiting for approval in Canon app...');
|
|
83
|
+
},
|
|
84
|
+
onPollUpdate: () => {
|
|
85
|
+
process.stdout.write('.');
|
|
86
|
+
},
|
|
87
|
+
});
|
|
135
88
|
console.log(''); // newline after dots
|
|
136
89
|
switch (result.status) {
|
|
137
90
|
case 'approved': {
|
|
@@ -148,7 +101,7 @@ export async function main() {
|
|
|
148
101
|
...(typeof values['base-url'] === 'string' ? { baseUrl: values['base-url'] } : {}),
|
|
149
102
|
});
|
|
150
103
|
if (result.requestId) {
|
|
151
|
-
await
|
|
104
|
+
await ackRegistrationApproval(values['base-url'], result.requestId, result.pollToken);
|
|
152
105
|
}
|
|
153
106
|
clearPendingRegistration(profileName);
|
|
154
107
|
console.log(`Approved! Agent: ${result.agentName} (${result.agentId})`);
|
|
@@ -168,7 +121,6 @@ export async function main() {
|
|
|
168
121
|
process.exit(1);
|
|
169
122
|
break;
|
|
170
123
|
}
|
|
171
|
-
bridge.client.close();
|
|
172
124
|
}
|
|
173
125
|
runCli(import.meta.url, main, (error) => {
|
|
174
126
|
console.error('[canon-register] Fatal error:', error);
|
package/dist/server.d.ts
ADDED