@canonmsg/codex-plugin 0.18.11 → 0.19.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/README.md +2 -2
- package/dist/app-server-adapter.d.ts +5 -0
- package/dist/app-server-adapter.js +36 -5
- package/dist/app-server-approval.d.ts +1 -1
- package/dist/app-server-approval.js +1 -1
- package/dist/bridge-bin.d.ts +14 -0
- package/dist/bridge-bin.js +27 -0
- package/dist/cli-entry.d.ts +2 -2
- package/dist/cli-entry.js +1 -1
- package/dist/codex-app-tools.d.ts +42 -0
- package/dist/codex-app-tools.js +519 -0
- package/dist/control-channel.d.ts +26 -46
- package/dist/control-channel.js +37 -50
- package/dist/host.d.ts +1 -1
- package/dist/host.js +840 -929
- package/dist/register.js +73 -25
- package/dist/session-store.d.ts +1 -1
- package/dist/session-store.js +2 -2
- package/dist/turn-activity.d.ts +7 -11
- package/dist/turn-activity.js +7 -41
- package/package.json +10 -7
- package/dist/host-lifecycle.d.ts +0 -4
- package/dist/host-lifecycle.js +0 -3
- package/dist/inbound-policy.d.ts +0 -22
- package/dist/inbound-policy.js +0 -46
- package/dist/startup-recovery.d.ts +0 -46
- package/dist/startup-recovery.js +0 -59
package/README.md
CHANGED
|
@@ -108,7 +108,7 @@ ps aux | rg canon-codex
|
|
|
108
108
|
If you installed the package only inside this repo and not globally, run the built host directly:
|
|
109
109
|
|
|
110
110
|
```bash
|
|
111
|
-
node
|
|
111
|
+
node adapters/codex-plugin/dist/host.js --cwd /path/to/project --full-auto
|
|
112
112
|
```
|
|
113
113
|
|
|
114
114
|
If `canon-codex` starts but cannot find the `codex` binary, either fix your `PATH` or launch with an explicit binary path:
|
|
@@ -149,7 +149,7 @@ CANON_AGENT=frontend canon-codex --cwd ~/projects/frontend
|
|
|
149
149
|
## Development
|
|
150
150
|
|
|
151
151
|
```bash
|
|
152
|
-
cd
|
|
152
|
+
cd adapters/codex-plugin
|
|
153
153
|
npm install
|
|
154
154
|
npm run build
|
|
155
155
|
```
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CodexApprovalPolicy, CodexEvent, CodexRunTurnOptions, CodexSandboxMode, CodexTurnResult } from './adapter.js';
|
|
2
|
+
export type JsonRecord = Record<string, unknown>;
|
|
2
3
|
export interface CodexSkillMetadata {
|
|
3
4
|
name: string;
|
|
4
5
|
path: string;
|
|
@@ -18,6 +19,7 @@ export declare class CodexAppServerAdapter {
|
|
|
18
19
|
private readonly configOverrides;
|
|
19
20
|
private readonly fullAuto;
|
|
20
21
|
private readonly bypassApprovalsAndSandbox;
|
|
22
|
+
private readonly dynamicTools;
|
|
21
23
|
private child;
|
|
22
24
|
private threadId;
|
|
23
25
|
private loadedThreadId;
|
|
@@ -49,6 +51,7 @@ export declare class CodexAppServerAdapter {
|
|
|
49
51
|
configOverrides?: string[];
|
|
50
52
|
fullAuto?: boolean;
|
|
51
53
|
bypassApprovalsAndSandbox?: boolean;
|
|
54
|
+
dynamicTools?: readonly JsonRecord[];
|
|
52
55
|
});
|
|
53
56
|
getThreadId(): string | null;
|
|
54
57
|
clearThreadId(): void;
|
|
@@ -65,6 +68,7 @@ export declare class CodexAppServerAdapter {
|
|
|
65
68
|
isRunning(): boolean;
|
|
66
69
|
interrupt(): Promise<void>;
|
|
67
70
|
compactThread(): Promise<void>;
|
|
71
|
+
requestAppServer(method: string, params: unknown): Promise<unknown>;
|
|
68
72
|
close(): void;
|
|
69
73
|
runTurn(prompt: string, onEvent: (event: CodexEvent) => void, onLog?: (line: string) => void, imagePaths?: readonly string[], _extraAddDirs?: readonly string[], options?: CodexRunTurnOptions): Promise<CodexTurnResult>;
|
|
70
74
|
private resolveApprovalPolicy;
|
|
@@ -80,6 +84,7 @@ export declare class CodexAppServerAdapter {
|
|
|
80
84
|
private handleLine;
|
|
81
85
|
private handleServerRequest;
|
|
82
86
|
private handleNotification;
|
|
87
|
+
private isCurrentThreadNotification;
|
|
83
88
|
private resolveCurrentTurn;
|
|
84
89
|
private clearActiveTurn;
|
|
85
90
|
private sendRequest;
|
|
@@ -11,6 +11,7 @@ export class CodexAppServerAdapter {
|
|
|
11
11
|
configOverrides;
|
|
12
12
|
fullAuto;
|
|
13
13
|
bypassApprovalsAndSandbox;
|
|
14
|
+
dynamicTools;
|
|
14
15
|
child = null;
|
|
15
16
|
threadId;
|
|
16
17
|
loadedThreadId = null;
|
|
@@ -42,6 +43,7 @@ export class CodexAppServerAdapter {
|
|
|
42
43
|
this.configOverrides = opts.configOverrides ?? [];
|
|
43
44
|
this.fullAuto = opts.fullAuto ?? false;
|
|
44
45
|
this.bypassApprovalsAndSandbox = opts.bypassApprovalsAndSandbox ?? false;
|
|
46
|
+
this.dynamicTools = opts.dynamicTools ?? [];
|
|
45
47
|
}
|
|
46
48
|
getThreadId() {
|
|
47
49
|
return this.threadId;
|
|
@@ -92,6 +94,10 @@ export class CodexAppServerAdapter {
|
|
|
92
94
|
threadId: this.threadId,
|
|
93
95
|
});
|
|
94
96
|
}
|
|
97
|
+
async requestAppServer(method, params) {
|
|
98
|
+
await this.ensureStarted();
|
|
99
|
+
return await this.sendRequest(method, params);
|
|
100
|
+
}
|
|
95
101
|
close() {
|
|
96
102
|
this.child?.kill('SIGTERM');
|
|
97
103
|
this.child = null;
|
|
@@ -122,6 +128,7 @@ export class CodexAppServerAdapter {
|
|
|
122
128
|
approvalPolicy: this.resolveApprovalPolicy(),
|
|
123
129
|
excludeTurns: true,
|
|
124
130
|
persistExtendedHistory: true,
|
|
131
|
+
...(this.dynamicTools.length ? { dynamicTools: this.dynamicTools } : {}),
|
|
125
132
|
});
|
|
126
133
|
this.loadedThreadId = this.threadId;
|
|
127
134
|
this.rememberResolvedModel(resumed);
|
|
@@ -133,6 +140,7 @@ export class CodexAppServerAdapter {
|
|
|
133
140
|
...(this.sandbox ? { sandbox: this.sandbox } : {}),
|
|
134
141
|
...this.configPayload(),
|
|
135
142
|
approvalPolicy: this.resolveApprovalPolicy(),
|
|
143
|
+
...(this.dynamicTools.length ? { dynamicTools: this.dynamicTools } : {}),
|
|
136
144
|
experimentalRawEvents: false,
|
|
137
145
|
persistExtendedHistory: true,
|
|
138
146
|
});
|
|
@@ -358,16 +366,18 @@ export class CodexAppServerAdapter {
|
|
|
358
366
|
}
|
|
359
367
|
}
|
|
360
368
|
handleNotification(method, params) {
|
|
361
|
-
if (method === 'turn/started') {
|
|
362
|
-
this.currentTurnId = readString(params.turn, 'id') ?? this.currentTurnId;
|
|
363
|
-
this.currentOnEvent?.({ type: 'turn.started' });
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
369
|
if (method === 'skills/changed') {
|
|
367
370
|
this.skillsCache = null;
|
|
368
371
|
this.currentOnEvent?.({ type: 'skills.changed' });
|
|
369
372
|
return;
|
|
370
373
|
}
|
|
374
|
+
if (!this.isCurrentThreadNotification(params))
|
|
375
|
+
return;
|
|
376
|
+
if (method === 'turn/started') {
|
|
377
|
+
this.currentTurnId = readString(params.turn, 'id') ?? this.currentTurnId;
|
|
378
|
+
this.currentOnEvent?.({ type: 'turn.started' });
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
371
381
|
if (method === 'thread/status/changed') {
|
|
372
382
|
const status = params.status;
|
|
373
383
|
if (status?.type === 'active' && Array.isArray(status.activeFlags)) {
|
|
@@ -476,6 +486,15 @@ export class CodexAppServerAdapter {
|
|
|
476
486
|
this.currentErrorText = stringifyPreview(params);
|
|
477
487
|
}
|
|
478
488
|
}
|
|
489
|
+
isCurrentThreadNotification(params) {
|
|
490
|
+
const threadId = readNotificationThreadId(params);
|
|
491
|
+
if (threadId && this.threadId && threadId !== this.threadId)
|
|
492
|
+
return false;
|
|
493
|
+
const turnId = readNotificationTurnId(params);
|
|
494
|
+
if (turnId && this.currentTurnId && turnId !== this.currentTurnId)
|
|
495
|
+
return false;
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
479
498
|
resolveCurrentTurn() {
|
|
480
499
|
const result = {
|
|
481
500
|
threadId: this.threadId,
|
|
@@ -538,6 +557,18 @@ function readRawString(record, key) {
|
|
|
538
557
|
const value = record?.[key];
|
|
539
558
|
return typeof value === 'string' ? value : undefined;
|
|
540
559
|
}
|
|
560
|
+
function readNotificationThreadId(params) {
|
|
561
|
+
return readString(params, 'threadId')
|
|
562
|
+
?? readString(params.thread, 'id')
|
|
563
|
+
?? readString(params.turn, 'threadId')
|
|
564
|
+
?? readString(params.item, 'threadId')
|
|
565
|
+
?? readString(params.status, 'threadId');
|
|
566
|
+
}
|
|
567
|
+
function readNotificationTurnId(params) {
|
|
568
|
+
return readString(params, 'turnId')
|
|
569
|
+
?? readString(params.turn, 'id')
|
|
570
|
+
?? readString(params.item, 'turnId');
|
|
571
|
+
}
|
|
541
572
|
function readNullableString(record, key) {
|
|
542
573
|
const value = record?.[key];
|
|
543
574
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalResult, ApprovalRisk, CanonUnifiedDiff } from '@canonmsg/core';
|
|
1
|
+
import type { ApprovalNativeRequestMetadata, ApprovalRequestCategory, ApprovalRequestDetail, ApprovalResult, ApprovalRisk, CanonUnifiedDiff } from '@canonmsg/core/contract';
|
|
2
2
|
/**
|
|
3
3
|
* Mapping for Codex app-server native approval requests.
|
|
4
4
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sanitizeUnifiedDiffForSharing, truncateUnifiedDiff } from '@canonmsg/core';
|
|
1
|
+
import { sanitizeUnifiedDiffForSharing, truncateUnifiedDiff } from '@canonmsg/core/contract';
|
|
2
2
|
function isRecord(value) {
|
|
3
3
|
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
4
4
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged canon-bridge daemon resolution (bridge plan Phase 6, §F3).
|
|
3
|
+
*
|
|
4
|
+
* On a fresh npm install nothing has populated ~/.canon/bin yet, so
|
|
5
|
+
* connectBridge()'s fallback chain (explicit binPath → $CANON_BRIDGE_BIN →
|
|
6
|
+
* the shared install) has nothing to spawn. The plugin therefore ships the
|
|
7
|
+
* daemon as its own @canonmsg/bridge dependency and passes the packaged
|
|
8
|
+
* dist entry as binPath.
|
|
9
|
+
*
|
|
10
|
+
* $CANON_BRIDGE_BIN still wins: when the env override is set we return
|
|
11
|
+
* undefined and let connectBridge()'s own env resolution take it (an
|
|
12
|
+
* options.binPath would out-rank the env var otherwise).
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolvePackagedBridgeBin(env?: NodeJS.ProcessEnv): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged canon-bridge daemon resolution (bridge plan Phase 6, §F3).
|
|
3
|
+
*
|
|
4
|
+
* On a fresh npm install nothing has populated ~/.canon/bin yet, so
|
|
5
|
+
* connectBridge()'s fallback chain (explicit binPath → $CANON_BRIDGE_BIN →
|
|
6
|
+
* the shared install) has nothing to spawn. The plugin therefore ships the
|
|
7
|
+
* daemon as its own @canonmsg/bridge dependency and passes the packaged
|
|
8
|
+
* dist entry as binPath.
|
|
9
|
+
*
|
|
10
|
+
* $CANON_BRIDGE_BIN still wins: when the env override is set we return
|
|
11
|
+
* undefined and let connectBridge()'s own env resolution take it (an
|
|
12
|
+
* options.binPath would out-rank the env var otherwise).
|
|
13
|
+
*/
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
import { dirname, join as joinPath } from 'node:path';
|
|
16
|
+
export function resolvePackagedBridgeBin(env = process.env) {
|
|
17
|
+
if (env.CANON_BRIDGE_BIN)
|
|
18
|
+
return undefined;
|
|
19
|
+
try {
|
|
20
|
+
const require = createRequire(import.meta.url);
|
|
21
|
+
const manifestPath = require.resolve('@canonmsg/bridge/package.json');
|
|
22
|
+
return joinPath(dirname(manifestPath), 'dist', 'main.js');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
}
|
package/dist/cli-entry.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { handleCliMetadataRequest, isDirectExecution, readCliPackageVersion, runCli, } from '@canonmsg/core';
|
|
2
|
-
export type { CliMetadata, RunCliMetadataOptions, } from '@canonmsg/core';
|
|
1
|
+
export { handleCliMetadataRequest, isDirectExecution, readCliPackageVersion, runCli, } from '@canonmsg/core/local';
|
|
2
|
+
export type { CliMetadata, RunCliMetadataOptions, } from '@canonmsg/core/local';
|
package/dist/cli-entry.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { handleCliMetadataRequest, isDirectExecution, readCliPackageVersion, runCli, } from '@canonmsg/core';
|
|
1
|
+
export { handleCliMetadataRequest, isDirectExecution, readCliPackageVersion, runCli, } from '@canonmsg/core/local';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
type JsonRecord = Record<string, unknown>;
|
|
2
|
+
interface DynamicToolSpec {
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
namespace: 'codex_app';
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
inputSchema: JsonRecord;
|
|
8
|
+
deferLoading?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface CodexAppToolAdapter {
|
|
11
|
+
requestAppServer(method: string, params: unknown): Promise<unknown>;
|
|
12
|
+
}
|
|
13
|
+
export interface CodexAppToolWorkspace {
|
|
14
|
+
id: string;
|
|
15
|
+
label: string;
|
|
16
|
+
cwd: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CodexAppToolRuntime {
|
|
19
|
+
adapter: CodexAppToolAdapter;
|
|
20
|
+
currentThreadId: string | null;
|
|
21
|
+
currentCwd: string;
|
|
22
|
+
workspaces: ReadonlyArray<CodexAppToolWorkspace>;
|
|
23
|
+
model?: string | null;
|
|
24
|
+
effort?: string | null;
|
|
25
|
+
}
|
|
26
|
+
export interface CodexAppToolCallParams {
|
|
27
|
+
arguments?: unknown;
|
|
28
|
+
namespace?: unknown;
|
|
29
|
+
tool?: unknown;
|
|
30
|
+
}
|
|
31
|
+
type DynamicToolCallResponse = {
|
|
32
|
+
success: boolean;
|
|
33
|
+
contentItems: Array<{
|
|
34
|
+
type: 'inputText';
|
|
35
|
+
text: string;
|
|
36
|
+
}>;
|
|
37
|
+
};
|
|
38
|
+
export declare const CODEX_APP_DYNAMIC_TOOLS: ReadonlyArray<DynamicToolSpec>;
|
|
39
|
+
export declare function isCodexAppToolCall(params: Record<string, unknown>): boolean;
|
|
40
|
+
export declare function deniedCodexAppToolResult(reason: string): DynamicToolCallResponse;
|
|
41
|
+
export declare function handleCodexAppToolCall(runtime: CodexAppToolRuntime, params: CodexAppToolCallParams): Promise<DynamicToolCallResponse>;
|
|
42
|
+
export {};
|