@canonmsg/codex-plugin 0.11.3 → 0.11.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/dist/app-server-approval.d.ts +32 -0
- package/dist/app-server-approval.js +168 -0
- package/dist/host.js +4 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalResult, ApprovalRisk } from '@canonmsg/core';
|
|
2
|
+
/**
|
|
3
|
+
* Mapping for Codex app-server native approval requests.
|
|
4
|
+
*
|
|
5
|
+
* The current Canon Codex host still uses `codex exec --json`, which cannot
|
|
6
|
+
* block on these methods. Keep this as metadata/decision plumbing for the
|
|
7
|
+
* future app-server transport, not as an advertised `exec --json` UI mode.
|
|
8
|
+
*/
|
|
9
|
+
export type CodexAppServerApprovalMethod = 'item/commandExecution/requestApproval' | 'item/fileChange/requestApproval' | 'item/permissions/requestApproval' | 'execCommandApproval' | 'applyPatchApproval';
|
|
10
|
+
export interface CodexNativeApprovalRequest {
|
|
11
|
+
method: CodexAppServerApprovalMethod;
|
|
12
|
+
params: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface CanonCodexApprovalRequest {
|
|
15
|
+
toolName: string;
|
|
16
|
+
toolInput: Record<string, unknown>;
|
|
17
|
+
toolSummary: string;
|
|
18
|
+
category: ApprovalRequestCategory;
|
|
19
|
+
risk: ApprovalRisk;
|
|
20
|
+
riskLevel: 'normal' | 'destructive';
|
|
21
|
+
native: ApprovalNativeRequestMetadata;
|
|
22
|
+
details: ApprovalRequestDetail[];
|
|
23
|
+
}
|
|
24
|
+
export type CodexApprovalDecision = {
|
|
25
|
+
decision: 'accept';
|
|
26
|
+
} | {
|
|
27
|
+
decision: 'acceptForSession';
|
|
28
|
+
} | {
|
|
29
|
+
decision: 'decline';
|
|
30
|
+
};
|
|
31
|
+
export declare function mapCodexAppServerApprovalRequest(request: CodexNativeApprovalRequest): CanonCodexApprovalRequest | null;
|
|
32
|
+
export declare function mapCanonApprovalResultToCodexDecision(result: ApprovalResult): CodexApprovalDecision;
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
function isRecord(value) {
|
|
2
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
3
|
+
}
|
|
4
|
+
function readString(record, keys) {
|
|
5
|
+
for (const key of keys) {
|
|
6
|
+
const value = record[key];
|
|
7
|
+
if (typeof value === 'string' && value.trim())
|
|
8
|
+
return value.trim();
|
|
9
|
+
}
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
function firstString(value) {
|
|
13
|
+
if (typeof value === 'string' && value.trim())
|
|
14
|
+
return value.trim();
|
|
15
|
+
if (Array.isArray(value)) {
|
|
16
|
+
return value.map((entry) => (typeof entry === 'string' ? entry.trim() : '')).find(Boolean);
|
|
17
|
+
}
|
|
18
|
+
return undefined;
|
|
19
|
+
}
|
|
20
|
+
function stringifyPreview(value, maxLength = 500) {
|
|
21
|
+
if (typeof value === 'string')
|
|
22
|
+
return value.length > maxLength ? `${value.slice(0, maxLength - 3)}...` : value;
|
|
23
|
+
const json = JSON.stringify(value ?? {});
|
|
24
|
+
return json.length > maxLength ? `${json.slice(0, maxLength - 3)}...` : json;
|
|
25
|
+
}
|
|
26
|
+
function nativeHandle(method, params) {
|
|
27
|
+
const native = {
|
|
28
|
+
runtime: 'codex',
|
|
29
|
+
method,
|
|
30
|
+
};
|
|
31
|
+
const requestId = readString(params, ['requestId', 'id', 'callId']);
|
|
32
|
+
const provider = readString(params, ['provider']);
|
|
33
|
+
const origin = readString(params, ['origin']);
|
|
34
|
+
const surface = readString(params, ['surface']);
|
|
35
|
+
const threadId = readString(params, ['threadId', 'conversationId']);
|
|
36
|
+
const turnId = readString(params, ['turnId']);
|
|
37
|
+
const runId = readString(params, ['runId']);
|
|
38
|
+
const itemId = readString(params, ['itemId']);
|
|
39
|
+
const toolCallId = readString(params, ['toolCallId', 'toolUseId']);
|
|
40
|
+
const approvalId = readString(params, ['approvalId']);
|
|
41
|
+
const pluginId = readString(params, ['pluginId']);
|
|
42
|
+
const sessionKey = readString(params, ['sessionKey', 'sessionId']);
|
|
43
|
+
const cwd = readString(params, ['cwd', 'workingDirectory']);
|
|
44
|
+
const model = readString(params, ['model']);
|
|
45
|
+
if (requestId)
|
|
46
|
+
native.requestId = requestId;
|
|
47
|
+
if (provider)
|
|
48
|
+
native.provider = provider;
|
|
49
|
+
if (origin)
|
|
50
|
+
native.origin = origin;
|
|
51
|
+
if (surface)
|
|
52
|
+
native.surface = surface;
|
|
53
|
+
if (threadId)
|
|
54
|
+
native.threadId = threadId;
|
|
55
|
+
if (turnId)
|
|
56
|
+
native.turnId = turnId;
|
|
57
|
+
if (runId)
|
|
58
|
+
native.runId = runId;
|
|
59
|
+
if (itemId)
|
|
60
|
+
native.itemId = itemId;
|
|
61
|
+
if (toolCallId)
|
|
62
|
+
native.toolCallId = toolCallId;
|
|
63
|
+
if (approvalId)
|
|
64
|
+
native.approvalId = approvalId;
|
|
65
|
+
if (pluginId)
|
|
66
|
+
native.pluginId = pluginId;
|
|
67
|
+
if (sessionKey)
|
|
68
|
+
native.sessionKey = sessionKey;
|
|
69
|
+
if (cwd)
|
|
70
|
+
native.cwd = cwd;
|
|
71
|
+
if (model)
|
|
72
|
+
native.model = model;
|
|
73
|
+
return native;
|
|
74
|
+
}
|
|
75
|
+
function commandRisk(command) {
|
|
76
|
+
if (/\brm\s+(-rf?|--force)|\bgit\s+reset\s+--hard|\bgit\s+push\s+--force|\bdrop\s+(table|database)\b/i.test(command)) {
|
|
77
|
+
return 'destructive';
|
|
78
|
+
}
|
|
79
|
+
return 'high';
|
|
80
|
+
}
|
|
81
|
+
function detail(label, value, monospace = true) {
|
|
82
|
+
return value ? [{ label, value, monospace }] : [];
|
|
83
|
+
}
|
|
84
|
+
function mapCommandRequest(method, params) {
|
|
85
|
+
const command = readString(params, ['command', 'cmd'])
|
|
86
|
+
?? firstString(params.argv)
|
|
87
|
+
?? firstString(params.args)
|
|
88
|
+
?? stringifyPreview(params);
|
|
89
|
+
const cwd = readString(params, ['cwd', 'workingDirectory']);
|
|
90
|
+
const risk = commandRisk(command);
|
|
91
|
+
return {
|
|
92
|
+
toolName: 'codex.command',
|
|
93
|
+
toolInput: {
|
|
94
|
+
command,
|
|
95
|
+
...(cwd ? { cwd } : {}),
|
|
96
|
+
},
|
|
97
|
+
toolSummary: command,
|
|
98
|
+
category: 'command',
|
|
99
|
+
risk,
|
|
100
|
+
riskLevel: risk === 'destructive' ? 'destructive' : 'normal',
|
|
101
|
+
native: nativeHandle(method, params),
|
|
102
|
+
details: [
|
|
103
|
+
...detail('Command', command),
|
|
104
|
+
...detail('Working directory', cwd),
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function mapFileRequest(method, params) {
|
|
109
|
+
const path = readString(params, ['path', 'filePath', 'targetPath']);
|
|
110
|
+
const summary = path
|
|
111
|
+
?? firstString(params.paths)
|
|
112
|
+
?? stringifyPreview(params.changes ?? params.patch ?? params);
|
|
113
|
+
const patch = readString(params, ['patch', 'diff']);
|
|
114
|
+
const destructive = /\b(delete|remove|unlink)\b/i.test(stringifyPreview(params, 1000));
|
|
115
|
+
return {
|
|
116
|
+
toolName: method === 'applyPatchApproval' ? 'codex.applyPatch' : 'codex.fileChange',
|
|
117
|
+
toolInput: {
|
|
118
|
+
...(path ? { path } : {}),
|
|
119
|
+
...(patch ? { patch } : {}),
|
|
120
|
+
},
|
|
121
|
+
toolSummary: summary,
|
|
122
|
+
category: 'file',
|
|
123
|
+
risk: destructive ? 'destructive' : 'high',
|
|
124
|
+
riskLevel: destructive ? 'destructive' : 'normal',
|
|
125
|
+
native: nativeHandle(method, params),
|
|
126
|
+
details: [
|
|
127
|
+
...detail('Path', path),
|
|
128
|
+
...detail('Patch', patch),
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function mapPermissionRequest(method, params) {
|
|
133
|
+
const action = readString(params, ['action', 'permission', 'toolName', 'tool'])
|
|
134
|
+
?? stringifyPreview(params);
|
|
135
|
+
return {
|
|
136
|
+
toolName: 'codex.permission',
|
|
137
|
+
toolInput: { action },
|
|
138
|
+
toolSummary: action,
|
|
139
|
+
category: 'tool',
|
|
140
|
+
risk: 'normal',
|
|
141
|
+
riskLevel: 'normal',
|
|
142
|
+
native: nativeHandle(method, params),
|
|
143
|
+
details: detail('Permission', action, false),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
export function mapCodexAppServerApprovalRequest(request) {
|
|
147
|
+
if (!isRecord(request.params))
|
|
148
|
+
return null;
|
|
149
|
+
if (request.method === 'item/commandExecution/requestApproval'
|
|
150
|
+
|| request.method === 'execCommandApproval') {
|
|
151
|
+
return mapCommandRequest(request.method, request.params);
|
|
152
|
+
}
|
|
153
|
+
if (request.method === 'item/fileChange/requestApproval'
|
|
154
|
+
|| request.method === 'applyPatchApproval') {
|
|
155
|
+
return mapFileRequest(request.method, request.params);
|
|
156
|
+
}
|
|
157
|
+
if (request.method === 'item/permissions/requestApproval') {
|
|
158
|
+
return mapPermissionRequest(request.method, request.params);
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
export function mapCanonApprovalResultToCodexDecision(result) {
|
|
163
|
+
if (result.decision === 'deny')
|
|
164
|
+
return { decision: 'decline' };
|
|
165
|
+
if (result.sessionRule)
|
|
166
|
+
return { decision: 'acceptForSession' };
|
|
167
|
+
return { decision: 'accept' };
|
|
168
|
+
}
|
package/dist/host.js
CHANGED
|
@@ -413,10 +413,12 @@ export async function main() {
|
|
|
413
413
|
]);
|
|
414
414
|
return buildHydratedInboundContext({
|
|
415
415
|
agentId,
|
|
416
|
+
conversationId: input.conversationId,
|
|
416
417
|
conversation,
|
|
417
418
|
page,
|
|
418
419
|
activeSelfContextId: input.activeSelfContextId,
|
|
419
420
|
selfContexts: input.selfContexts,
|
|
421
|
+
provenance: input.provenance,
|
|
420
422
|
message: input.message,
|
|
421
423
|
senderName: input.senderName,
|
|
422
424
|
isOwner: input.isOwner,
|
|
@@ -687,6 +689,7 @@ export async function main() {
|
|
|
687
689
|
isOwner: input.isOwner,
|
|
688
690
|
activeSelfContextId: input.activeSelfContextId,
|
|
689
691
|
selfContexts: input.selfContexts,
|
|
692
|
+
provenance: input.provenance,
|
|
690
693
|
hydratedPage: input.hydratedPage,
|
|
691
694
|
});
|
|
692
695
|
const behavior = input.behavior ?? hydrated.behavior;
|
|
@@ -1096,6 +1099,7 @@ export async function main() {
|
|
|
1096
1099
|
behavior: payload.behavior,
|
|
1097
1100
|
activeSelfContextId: payload.activeSelfContextId,
|
|
1098
1101
|
selfContexts: payload.selfContexts,
|
|
1102
|
+
provenance: payload.provenance,
|
|
1099
1103
|
});
|
|
1100
1104
|
if (message.id) {
|
|
1101
1105
|
saveRuntimeSessionState(runtimeId, {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { main as hostMain } from './host.js';
|
|
2
2
|
export { main as registerMain } from './register.js';
|
|
3
3
|
export { main as setupMain } from './setup.js';
|
|
4
|
+
export { mapCanonApprovalResultToCodexDecision, mapCodexAppServerApprovalRequest, } from './app-server-approval.js';
|
|
5
|
+
export type { CanonCodexApprovalRequest, CodexAppServerApprovalMethod, CodexApprovalDecision, CodexNativeApprovalRequest, } from './app-server-approval.js';
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/codex-plugin",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.4",
|
|
4
4
|
"description": "Canon host integration for Codex CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@canonmsg/agent-sdk": "^1.
|
|
33
|
-
"@canonmsg/core": "^0.
|
|
32
|
+
"@canonmsg/agent-sdk": "^1.5.0",
|
|
33
|
+
"@canonmsg/core": "^0.19.0"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|
|
36
36
|
"node": ">=18.0.0"
|