claude2codex 0.3.5 → 0.3.7
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 -1
- package/README.zh-CN.md +2 -1
- package/dist/server.js +27 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -231,7 +231,8 @@ Codex then enters its goal-continuation loop: after each turn, it checks "did I
|
|
|
231
231
|
| `CODEX_MODEL` | Codex default | Model override |
|
|
232
232
|
| `CODEX_APPROVAL_POLICY` | `never` | Approval policy (autonomous by default) |
|
|
233
233
|
| `CODEX_PERMISSIONS` | Unset | Permissions profile passed to Codex |
|
|
234
|
-
| `CODEX_JOB_TIMEOUT_MS` | `
|
|
234
|
+
| `CODEX_JOB_TIMEOUT_MS` | `7200000` | Overall maximum job duration (2 hours) |
|
|
235
|
+
| `C2C_IDLE_TIMEOUT_MS` | `1200000` | Timeout after no Codex notifications during a running attempt (20 min); `0` disables. Queued/dependency wait time excluded |
|
|
235
236
|
| `CODEX_QUIET_MS` | `30000` | Quiet period before treating an active goal as finished |
|
|
236
237
|
| `GOAL_OBJECTIVE_MAX` | `2000` | Maximum rendered goal-objective length; `codex_implement` rejects over-limit contracts at submit time |
|
|
237
238
|
| `C2C_STATE_DIR` | `~/.claude2codex/jobs` | Persistent job registry (atomic per-job JSON files) |
|
package/README.zh-CN.md
CHANGED
|
@@ -252,7 +252,8 @@ Python 3.12,Poetry。从项目根目录运行。
|
|
|
252
252
|
| `CODEX_MODEL` | Codex 默认 | 模型覆盖 |
|
|
253
253
|
| `CODEX_APPROVAL_POLICY` | `never` | 审批策略(默认自主执行) |
|
|
254
254
|
| `CODEX_PERMISSIONS` | 未设置 | 权限配置透传 |
|
|
255
|
-
| `CODEX_JOB_TIMEOUT_MS` | `
|
|
255
|
+
| `CODEX_JOB_TIMEOUT_MS` | `7200000` | 单任务总时长硬上限(2 小时) |
|
|
256
|
+
| `C2C_IDLE_TIMEOUT_MS` | `1200000` | 运行中的尝试连续无 Codex 通知时超时(20 分钟),`0` 禁用;排队和等待依赖的时间不计入 |
|
|
256
257
|
| `CODEX_QUIET_MS` | `30000` | 判定活跃目标已完成前的静默等待时间 |
|
|
257
258
|
| `GOAL_OBJECTIVE_MAX` | `2000` | 渲染后 goal-objective 的最大长度;超限的合同会被 `codex_implement` 在提交时拒绝 |
|
|
258
259
|
| `C2C_STATE_DIR` | `~/.claude2codex/jobs` | 持久化任务注册表(每任务一个原子写入的 JSON 文件) |
|
package/dist/server.js
CHANGED
|
@@ -262,7 +262,7 @@ var CodexAppServer = class {
|
|
|
262
262
|
*/
|
|
263
263
|
async initialize() {
|
|
264
264
|
const result = await this.request("initialize", {
|
|
265
|
-
clientInfo: { name: "claude2codex", title: "Claude\u2194Codex Contract Bridge", version: "0.3.
|
|
265
|
+
clientInfo: { name: "claude2codex", title: "Claude\u2194Codex Contract Bridge", version: "0.3.7" },
|
|
266
266
|
capabilities: { experimentalApi: true }
|
|
267
267
|
});
|
|
268
268
|
this.notify("initialized", {});
|
|
@@ -641,6 +641,7 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
641
641
|
let lastCodexError;
|
|
642
642
|
let quietTimer;
|
|
643
643
|
let stallTimer;
|
|
644
|
+
let idleTimer;
|
|
644
645
|
let settle;
|
|
645
646
|
const doneSignal = new Promise((res) => settle = res);
|
|
646
647
|
const progress = (event, message) => opts.onProgress?.({ jobId: job.id, event, message });
|
|
@@ -675,6 +676,14 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
675
676
|
settle();
|
|
676
677
|
}, cfg.quietMs);
|
|
677
678
|
}
|
|
679
|
+
function armIdleTimer() {
|
|
680
|
+
clearTimeout(idleTimer);
|
|
681
|
+
if (cfg.idleTimeoutMs === 0) return;
|
|
682
|
+
idleTimer = setTimeout(() => {
|
|
683
|
+
finalize("timeout", `no Codex notification for ${cfg.idleTimeoutMs}ms (C2C_IDLE_TIMEOUT_MS)`);
|
|
684
|
+
settle();
|
|
685
|
+
}, cfg.idleTimeoutMs);
|
|
686
|
+
}
|
|
678
687
|
function clearStallTimer() {
|
|
679
688
|
clearTimeout(stallTimer);
|
|
680
689
|
stallTimer = void 0;
|
|
@@ -708,15 +717,22 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
708
717
|
writeLog("info", "job_resumed", { job_id: job.id, stalled_for_ms: stalledForMs });
|
|
709
718
|
progress("resumed", `job resumed after ${stalledForMs}ms`);
|
|
710
719
|
}
|
|
720
|
+
armIdleTimer();
|
|
711
721
|
job.lastActivityAt = now.toISOString();
|
|
712
722
|
store.save(job);
|
|
713
723
|
if (activeTurn) armStallTimer();
|
|
714
724
|
}
|
|
715
725
|
function finalize(state, error) {
|
|
726
|
+
clearTimeout(idleTimer);
|
|
716
727
|
clearStallTimer();
|
|
728
|
+
if (state === "done" && job.turns === 0) {
|
|
729
|
+
state = "error";
|
|
730
|
+
error = "job ended without running a turn";
|
|
731
|
+
}
|
|
717
732
|
finish(job, state, client, error);
|
|
718
733
|
}
|
|
719
734
|
function handleNotification(method, params) {
|
|
735
|
+
if (job.state !== "starting" && job.state !== "running") return;
|
|
720
736
|
writeLog("debug", "codex_notification", {
|
|
721
737
|
job_id: job.id,
|
|
722
738
|
attempt: job.attempts ?? 1,
|
|
@@ -767,7 +783,7 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
767
783
|
tokens_used: job.goal?.tokensUsed ?? null
|
|
768
784
|
});
|
|
769
785
|
progress("goal_updated", `goal status=${job.goal?.status ?? "unknown"}`);
|
|
770
|
-
if (job.goal?.status && TERMINAL_GOAL_STATUSES.has(job.goal.status) && !activeTurn) {
|
|
786
|
+
if (job.goal?.status && TERMINAL_GOAL_STATUSES.has(job.goal.status) && !activeTurn && job.turns > 0) {
|
|
771
787
|
finalize("done");
|
|
772
788
|
settle();
|
|
773
789
|
}
|
|
@@ -834,10 +850,11 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
834
850
|
if (!activeTurn) armQuietTimer();
|
|
835
851
|
}
|
|
836
852
|
const overallTimer = setTimeout(() => {
|
|
837
|
-
finalize("timeout", `job exceeded ${cfg.jobTimeoutMs}ms`);
|
|
853
|
+
finalize("timeout", `job exceeded ${cfg.jobTimeoutMs}ms (CODEX_JOB_TIMEOUT_MS)`);
|
|
838
854
|
settle();
|
|
839
855
|
}, timeoutMs);
|
|
840
856
|
try {
|
|
857
|
+
armIdleTimer();
|
|
841
858
|
await client.initialize();
|
|
842
859
|
const threadParams = {
|
|
843
860
|
cwd: cfg.cwd,
|
|
@@ -858,11 +875,11 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
858
875
|
if (!job.threadId) throw new Error(`could not determine thread id from ${JSON.stringify(threadRes).slice(0, 300)}`);
|
|
859
876
|
store.save(job);
|
|
860
877
|
log(job, "thread", `thread ${job.threadId} ${opts.resumeThreadId ? "resumed" : "started"}`);
|
|
861
|
-
if (opts.objective) {
|
|
878
|
+
if (opts.objective || opts.resumeThreadId) {
|
|
862
879
|
try {
|
|
863
880
|
const goalRes = await client.request("thread/goal/set", {
|
|
864
881
|
threadId: job.threadId,
|
|
865
|
-
objective: opts.objective,
|
|
882
|
+
...opts.objective ? { objective: opts.objective } : { status: "active" },
|
|
866
883
|
...opts.tokenBudget ? { tokenBudget: opts.tokenBudget } : {}
|
|
867
884
|
});
|
|
868
885
|
job.goalSet = true;
|
|
@@ -886,6 +903,7 @@ async function runAttempt(job, opts, timeoutMs) {
|
|
|
886
903
|
const failure = processError ?? (error instanceof Error ? error : new Error(String(error)));
|
|
887
904
|
return { error: failure, processFailure: client.exited };
|
|
888
905
|
} finally {
|
|
906
|
+
clearTimeout(idleTimer);
|
|
889
907
|
clearTimeout(overallTimer);
|
|
890
908
|
clearTimeout(quietTimer);
|
|
891
909
|
clearStallTimer();
|
|
@@ -925,7 +943,8 @@ function config(cwd) {
|
|
|
925
943
|
model: process.env.CODEX_MODEL || void 0,
|
|
926
944
|
approvalPolicy: process.env.CODEX_APPROVAL_POLICY ?? "never",
|
|
927
945
|
permissions: process.env.CODEX_PERMISSIONS || void 0,
|
|
928
|
-
jobTimeoutMs: envInt("CODEX_JOB_TIMEOUT_MS",
|
|
946
|
+
jobTimeoutMs: envInt("CODEX_JOB_TIMEOUT_MS", 72e5),
|
|
947
|
+
idleTimeoutMs: Math.max(0, envInt("C2C_IDLE_TIMEOUT_MS", 12e5)),
|
|
929
948
|
quietMs: envInt("CODEX_QUIET_MS", 3e4),
|
|
930
949
|
stallWarnMs: Math.max(0, envInt("C2C_STALL_WARN_MS", 12e4)),
|
|
931
950
|
retries: Math.max(0, envInt("C2C_RETRIES", 1)),
|
|
@@ -968,7 +987,7 @@ var SERVER_INSTRUCTIONS = `When the user asks to delegate work to Codex (or to u
|
|
|
968
987
|
If a Codex job itself fails (error, 0 tokens, no handoff), report it and wait; don't implement the task yourself unless the user explicitly asks.
|
|
969
988
|
Full formats: the c2c-workflow prompt.`;
|
|
970
989
|
var server = new McpServer(
|
|
971
|
-
{ name: "c2c-codex", version: "0.3.
|
|
990
|
+
{ name: "c2c-codex", version: "0.3.7" },
|
|
972
991
|
{ instructions: SERVER_INSTRUCTIONS }
|
|
973
992
|
);
|
|
974
993
|
var reasoningEffort = z.enum(["low", "medium", "high", "xhigh", "max", "ultra"]);
|
|
@@ -1127,7 +1146,7 @@ server.registerTool(
|
|
|
1127
1146
|
"codex_rework",
|
|
1128
1147
|
{
|
|
1129
1148
|
title: "Send a Delta Contract to Codex",
|
|
1130
|
-
description: "Resume the Codex thread from a previous implement job and hand it a Delta Contract (review findings + failed success conditions). The existing thread goal
|
|
1149
|
+
description: "Resume the Codex thread from a previous implement job and hand it a Delta Contract (review findings + failed success conditions). The existing thread goal is reactivated, so the /goal loop continues until the objective passes. Returns a new job_id.",
|
|
1131
1150
|
inputSchema: {
|
|
1132
1151
|
job_id: z.string().optional().describe("The original implement job's id (preferred; resolves the thread to resume)."),
|
|
1133
1152
|
thread_id: z.string().optional().describe("Codex thread id, if the job registry is gone (e.g. after a restart)."),
|
package/package.json
CHANGED