@canonmsg/codex-plugin 0.9.7 → 0.9.8
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/adapter.d.ts +2 -1
- package/dist/adapter.js +25 -4
- package/dist/host.js +31 -14
- package/package.json +2 -2
package/dist/adapter.d.ts
CHANGED
|
@@ -64,7 +64,8 @@ export declare class CodexConversationAdapter {
|
|
|
64
64
|
setModel(model: string | null): void;
|
|
65
65
|
isRunning(): boolean;
|
|
66
66
|
interrupt(): Promise<void>;
|
|
67
|
-
runTurn(prompt: string, onEvent: (event: CodexEvent) => void, onLog?: (line: string) => void, imagePaths?: readonly string[]): Promise<CodexTurnResult>;
|
|
67
|
+
runTurn(prompt: string, onEvent: (event: CodexEvent) => void, onLog?: (line: string) => void, imagePaths?: readonly string[], extraAddDirs?: readonly string[]): Promise<CodexTurnResult>;
|
|
68
|
+
private buildAddDirs;
|
|
68
69
|
private buildArgs;
|
|
69
70
|
private canResumeWithCurrentPolicy;
|
|
70
71
|
private clearActiveProcess;
|
package/dist/adapter.js
CHANGED
|
@@ -51,11 +51,11 @@ export class CodexConversationAdapter {
|
|
|
51
51
|
this.child.kill('SIGKILL');
|
|
52
52
|
}, 5_000);
|
|
53
53
|
}
|
|
54
|
-
async runTurn(prompt, onEvent, onLog, imagePaths = []) {
|
|
54
|
+
async runTurn(prompt, onEvent, onLog, imagePaths = [], extraAddDirs = []) {
|
|
55
55
|
if (this.child) {
|
|
56
56
|
throw new Error('A Codex turn is already in progress for this conversation');
|
|
57
57
|
}
|
|
58
|
-
const args = this.buildArgs(prompt, imagePaths);
|
|
58
|
+
const args = this.buildArgs(prompt, imagePaths, extraAddDirs);
|
|
59
59
|
const child = spawn(this.codexBin, args, {
|
|
60
60
|
cwd: this.cwd,
|
|
61
61
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
@@ -147,7 +147,19 @@ export class CodexConversationAdapter {
|
|
|
147
147
|
});
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
|
-
|
|
150
|
+
buildAddDirs(extraAddDirs = []) {
|
|
151
|
+
const seen = new Set();
|
|
152
|
+
const dirs = [];
|
|
153
|
+
for (const value of [...this.addDirs, ...extraAddDirs]) {
|
|
154
|
+
const trimmed = value.trim();
|
|
155
|
+
if (!trimmed || seen.has(trimmed))
|
|
156
|
+
continue;
|
|
157
|
+
seen.add(trimmed);
|
|
158
|
+
dirs.push(value);
|
|
159
|
+
}
|
|
160
|
+
return dirs;
|
|
161
|
+
}
|
|
162
|
+
buildArgs(prompt, imagePaths = [], extraAddDirs = []) {
|
|
151
163
|
if (this.threadId && this.canResumeWithCurrentPolicy()) {
|
|
152
164
|
const args = ['exec', 'resume', '--json', '--skip-git-repo-check'];
|
|
153
165
|
if (this.model) {
|
|
@@ -159,6 +171,9 @@ export class CodexConversationAdapter {
|
|
|
159
171
|
for (const configOverride of this.configOverrides) {
|
|
160
172
|
args.push('-c', configOverride);
|
|
161
173
|
}
|
|
174
|
+
for (const addDir of this.buildAddDirs(extraAddDirs)) {
|
|
175
|
+
args.push('--add-dir', addDir);
|
|
176
|
+
}
|
|
162
177
|
if (this.fullAuto) {
|
|
163
178
|
args.push('--full-auto');
|
|
164
179
|
}
|
|
@@ -168,6 +183,9 @@ export class CodexConversationAdapter {
|
|
|
168
183
|
for (const imagePath of imagePaths) {
|
|
169
184
|
args.push('-i', imagePath);
|
|
170
185
|
}
|
|
186
|
+
if (imagePaths.length > 0) {
|
|
187
|
+
args.push('--');
|
|
188
|
+
}
|
|
171
189
|
args.push(this.threadId, prompt);
|
|
172
190
|
return args;
|
|
173
191
|
}
|
|
@@ -189,7 +207,7 @@ export class CodexConversationAdapter {
|
|
|
189
207
|
if (this.codexProfile) {
|
|
190
208
|
args.push('-p', this.codexProfile);
|
|
191
209
|
}
|
|
192
|
-
for (const addDir of this.
|
|
210
|
+
for (const addDir of this.buildAddDirs(extraAddDirs)) {
|
|
193
211
|
args.push('--add-dir', addDir);
|
|
194
212
|
}
|
|
195
213
|
for (const configOverride of this.configOverrides) {
|
|
@@ -204,6 +222,9 @@ export class CodexConversationAdapter {
|
|
|
204
222
|
for (const imagePath of imagePaths) {
|
|
205
223
|
args.push('-i', imagePath);
|
|
206
224
|
}
|
|
225
|
+
if (imagePaths.length > 0) {
|
|
226
|
+
args.push('--');
|
|
227
|
+
}
|
|
207
228
|
args.push(prompt);
|
|
208
229
|
return args;
|
|
209
230
|
}
|
package/dist/host.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { setDefaultResultOrder } from 'node:dns';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
4
5
|
import { parseArgs } from 'node:util';
|
|
5
6
|
import { getCodexImagePath, materializeMessageMedia, } from '@canonmsg/agent-sdk';
|
|
6
7
|
import { buildCanonHostPrompt, buildConfiguredWorkspaceOptionsWithRoots, buildFirstPartyCodingRuntimeDescriptor, buildHydratedInboundContext, buildPublicWorkspaceRoots, buildPublicWorkspaceOptions, createConversationMetadataLoader, createRuntimeStatePublisher, EXECUTION_ENVIRONMENT_MODES, ExecutionEnvironmentError, CanonClient, CanonStream, DEFAULT_PARTICIPATION_HISTORY_FETCH_LIMIT, DEFAULT_RUNTIME_CAPABILITIES, FINAL_MESSAGE_HANDOFF_MS, getActiveProfileLock, initRTDBAuth, buildLocalRuntimeId, heartbeatLocalRuntimeEntry, loadRuntimeSessionState, markLocalRuntimeStopped, normalizeTurnMetadata, normalizeTurnState, prepareConversationEnvironment, loadHostSessionConfig, releaseConversationEnvironment, resolveCanonAgent, rtdbRead, rtdbWrite, shouldTriggerAgentTurn, saveRuntimeSessionState, publishHostAgentRuntime, publishHostSessionSnapshots, renderCanonHostInboundContent, resolveHostWorkspaceCwd, upsertLocalRuntimeEntry, } from '@canonmsg/core';
|
|
@@ -207,6 +208,9 @@ function summarizeCommand(command) {
|
|
|
207
208
|
function sleep(ms) {
|
|
208
209
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
209
210
|
}
|
|
211
|
+
function uniqueStrings(values) {
|
|
212
|
+
return Array.from(new Set(values.filter((value) => value.trim().length > 0)));
|
|
213
|
+
}
|
|
210
214
|
export async function main() {
|
|
211
215
|
setDefaultResultOrder('ipv4first');
|
|
212
216
|
const { values: args } = parseArgs({
|
|
@@ -525,6 +529,7 @@ export async function main() {
|
|
|
525
529
|
turnState: 'idle',
|
|
526
530
|
currentTurnId: null,
|
|
527
531
|
currentTurnOpenedAt: null,
|
|
532
|
+
activeSelfContextId: null,
|
|
528
533
|
lastAcceptedIntent: null,
|
|
529
534
|
lastActivity: Date.now(),
|
|
530
535
|
typingKeepaliveTimer: null,
|
|
@@ -553,8 +558,8 @@ export async function main() {
|
|
|
553
558
|
pendingSessionCreations.delete(conversationId);
|
|
554
559
|
}
|
|
555
560
|
}
|
|
556
|
-
function enqueuePrompt(session, prompt, intent = 'queue', toFront = false, sourceMessageId, markAccepted = false, imagePaths = []) {
|
|
557
|
-
const nextPrompt = { prompt, intent, sourceMessageId, markAccepted, imagePaths };
|
|
561
|
+
function enqueuePrompt(session, prompt, intent = 'queue', toFront = false, sourceMessageId, markAccepted = false, imagePaths = [], mediaAddDirs = []) {
|
|
562
|
+
const nextPrompt = { prompt, intent, sourceMessageId, markAccepted, imagePaths, mediaAddDirs };
|
|
558
563
|
if (toFront) {
|
|
559
564
|
session.queue.unshift(nextPrompt);
|
|
560
565
|
}
|
|
@@ -582,6 +587,7 @@ export async function main() {
|
|
|
582
587
|
const imagePaths = materialized
|
|
583
588
|
.map((attachment) => getCodexImagePath(attachment))
|
|
584
589
|
.filter((path) => path !== null);
|
|
590
|
+
const mediaAddDirs = uniqueStrings(materialized.map((attachment) => dirname(attachment.path)));
|
|
585
591
|
const content = renderInboundContent(input.message, materialized);
|
|
586
592
|
const hydrated = await loadHydratedInboundContext({
|
|
587
593
|
conversationId: input.conversationId,
|
|
@@ -591,11 +597,11 @@ export async function main() {
|
|
|
591
597
|
hydratedPage: input.hydratedPage,
|
|
592
598
|
});
|
|
593
599
|
const behavior = input.behavior ?? hydrated.behavior;
|
|
594
|
-
const
|
|
595
|
-
? hydrated.
|
|
596
|
-
: Array.isArray(input.
|
|
597
|
-
? input.
|
|
598
|
-
: hydrated.
|
|
600
|
+
const selfContexts = hydrated.hydratedFromPage
|
|
601
|
+
? hydrated.selfContexts
|
|
602
|
+
: Array.isArray(input.selfContexts)
|
|
603
|
+
? input.selfContexts
|
|
604
|
+
: hydrated.selfContexts;
|
|
599
605
|
const participantContext = hydrated.participantContext;
|
|
600
606
|
const autoReply = decideAutoReply(participantContext, behavior);
|
|
601
607
|
if (!autoReply.allow) {
|
|
@@ -612,6 +618,7 @@ export async function main() {
|
|
|
612
618
|
const userMessage = error instanceof ExecutionEnvironmentError ? error.userMessage : message;
|
|
613
619
|
console.error(`[canon-codex] [${input.conversationId.slice(0, 8)}] Failed to create session: ${message}`);
|
|
614
620
|
await client.sendMessage(input.conversationId, `I couldn't start a coding session for this workspace: ${userMessage}`, {
|
|
621
|
+
...(selfContexts[0]?.id ? { selfContextId: selfContexts[0].id } : {}),
|
|
615
622
|
metadata: {
|
|
616
623
|
turnSemantics: 'turn_complete',
|
|
617
624
|
turnComplete: true,
|
|
@@ -621,6 +628,7 @@ export async function main() {
|
|
|
621
628
|
return;
|
|
622
629
|
}
|
|
623
630
|
const turnMetadata = normalizeTurnMetadata(input.message.metadata);
|
|
631
|
+
session.activeSelfContextId = selfContexts[0]?.id ?? null;
|
|
624
632
|
const deliveryIntent = turnMetadata?.deliveryIntent ?? 'queue';
|
|
625
633
|
const shouldMarkAccepted = turnMetadata?.inboundDisposition === 'queued';
|
|
626
634
|
const prompt = buildCanonPrompt({
|
|
@@ -628,18 +636,17 @@ export async function main() {
|
|
|
628
636
|
conversationId: input.conversationId,
|
|
629
637
|
participantContext,
|
|
630
638
|
behavior,
|
|
631
|
-
|
|
632
|
-
workSessions,
|
|
639
|
+
selfContexts,
|
|
633
640
|
});
|
|
634
641
|
if (session.running && deliveryIntent === 'interrupt') {
|
|
635
|
-
enqueuePrompt(session, prompt, deliveryIntent, true, input.message.id, shouldMarkAccepted, imagePaths);
|
|
642
|
+
enqueuePrompt(session, prompt, deliveryIntent, true, input.message.id, shouldMarkAccepted, imagePaths, mediaAddDirs);
|
|
636
643
|
console.error(`[canon-codex] [${input.conversationId.slice(0, 8)}] Interrupting current turn for explicit human send-now`);
|
|
637
644
|
await session.adapter.interrupt().catch(() => { });
|
|
638
645
|
clearStreaming(input.conversationId);
|
|
639
646
|
client.setTyping(input.conversationId, false).catch(() => { });
|
|
640
647
|
return;
|
|
641
648
|
}
|
|
642
|
-
enqueuePrompt(session, prompt, deliveryIntent, false, input.message.id, shouldMarkAccepted, imagePaths);
|
|
649
|
+
enqueuePrompt(session, prompt, deliveryIntent, false, input.message.id, shouldMarkAccepted, imagePaths, mediaAddDirs);
|
|
643
650
|
}
|
|
644
651
|
async function runNextTurn(session) {
|
|
645
652
|
if (session.running || session.closed)
|
|
@@ -669,6 +676,7 @@ export async function main() {
|
|
|
669
676
|
throw new ExecutionEnvironmentError(modelGuard, modelGuard);
|
|
670
677
|
}
|
|
671
678
|
const turnImagePaths = nextTurn.imagePaths ?? [];
|
|
679
|
+
const turnMediaAddDirs = nextTurn.mediaAddDirs ?? [];
|
|
672
680
|
const handleCodexEvent = (event) => {
|
|
673
681
|
session.lastActivity = Date.now();
|
|
674
682
|
if (event.type === 'thread.started') {
|
|
@@ -708,7 +716,7 @@ export async function main() {
|
|
|
708
716
|
clearStoredThreadId(runtimeId, agentId, session.conversationId, session.environment.baseCwd, session.environment.mode);
|
|
709
717
|
session.adapter.clearThreadId();
|
|
710
718
|
};
|
|
711
|
-
const runTurnOnce = () => session.adapter.runTurn(nextTurn.prompt, handleCodexEvent, logCodexLine, turnImagePaths);
|
|
719
|
+
const runTurnOnce = () => session.adapter.runTurn(nextTurn.prompt, handleCodexEvent, logCodexLine, turnImagePaths, turnMediaAddDirs);
|
|
712
720
|
let result = await runTurnOnce();
|
|
713
721
|
if (!result.interrupted
|
|
714
722
|
&& !result.finalMessage
|
|
@@ -727,6 +735,9 @@ export async function main() {
|
|
|
727
735
|
clearStoredThread();
|
|
728
736
|
}
|
|
729
737
|
await client.sendMessage(session.conversationId, result.finalMessage, {
|
|
738
|
+
...(session.activeSelfContextId
|
|
739
|
+
? { selfContextId: session.activeSelfContextId }
|
|
740
|
+
: {}),
|
|
730
741
|
metadata: {
|
|
731
742
|
turnId: session.currentTurnId,
|
|
732
743
|
turnSemantics: 'turn_complete',
|
|
@@ -745,6 +756,9 @@ export async function main() {
|
|
|
745
756
|
console.error(`[canon-codex] [${session.conversationId.slice(0, 8)}] Turn exited ${result.exitCode}: ${result.errorText}`);
|
|
746
757
|
}
|
|
747
758
|
await client.sendMessage(session.conversationId, userVisibleError, {
|
|
759
|
+
...(session.activeSelfContextId
|
|
760
|
+
? { selfContextId: session.activeSelfContextId }
|
|
761
|
+
: {}),
|
|
748
762
|
metadata: {
|
|
749
763
|
turnId: session.currentTurnId,
|
|
750
764
|
turnSemantics: 'turn_complete',
|
|
@@ -773,6 +787,9 @@ export async function main() {
|
|
|
773
787
|
session.state.lastError = message;
|
|
774
788
|
writeState(session);
|
|
775
789
|
await client.sendMessage(session.conversationId, message, {
|
|
790
|
+
...(session.activeSelfContextId
|
|
791
|
+
? { selfContextId: session.activeSelfContextId }
|
|
792
|
+
: {}),
|
|
776
793
|
metadata: {
|
|
777
794
|
turnId: session.currentTurnId,
|
|
778
795
|
turnSemantics: 'turn_complete',
|
|
@@ -969,7 +986,7 @@ export async function main() {
|
|
|
969
986
|
senderName: message.senderName || message.senderId,
|
|
970
987
|
isOwner: message.isOwner ?? (ownerId != null && message.senderId === ownerId),
|
|
971
988
|
behavior: payload.behavior,
|
|
972
|
-
|
|
989
|
+
selfContexts: payload.selfContexts,
|
|
973
990
|
});
|
|
974
991
|
if (message.id) {
|
|
975
992
|
saveRuntimeSessionState(runtimeId, {
|
|
@@ -1076,7 +1093,7 @@ export async function main() {
|
|
|
1076
1093
|
senderName: latestMessage.senderId,
|
|
1077
1094
|
isOwner: ownerId != null && latestMessage.senderId === ownerId,
|
|
1078
1095
|
behavior: latestPage.behavior,
|
|
1079
|
-
|
|
1096
|
+
selfContexts: latestPage.selfContexts,
|
|
1080
1097
|
hydratedPage: latestPage,
|
|
1081
1098
|
});
|
|
1082
1099
|
if (latestMessage.id) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@canonmsg/codex-plugin",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.8",
|
|
4
4
|
"description": "Canon host integration for Codex CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"prepack": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@canonmsg/agent-sdk": "^1.1.
|
|
32
|
+
"@canonmsg/agent-sdk": "^1.1.4",
|
|
33
33
|
"@canonmsg/core": "^0.15.4"
|
|
34
34
|
},
|
|
35
35
|
"engines": {
|