@ycodium-ai/agent-codex 0.2.3484 → 0.2.3488
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/index.js +103 -72
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -55,7 +55,10 @@ var CODEX_CARD = {
|
|
|
55
55
|
// 出处不是 provider 文档:这是产品此前对所有 provider 统一施加的单图上限(10 MiB),
|
|
56
56
|
// codex 在这个上限下一直把图片以 data URL 内联。没有查到 Codex / OpenAI 对单图的明文
|
|
57
57
|
// 上限,所以不声明尺寸与合计上限;查到后改这里即可,宿主不需要跟着变。
|
|
58
|
-
inlineImages: { maxBytes: 10 * 1024 * 1024 }
|
|
58
|
+
inlineImages: { maxBytes: 10 * 1024 * 1024 },
|
|
59
|
+
// 其它文件夹每轮进 sandboxPolicy.writableRoots(codexTurnSandboxPolicyForNativeMode)。
|
|
60
|
+
// CLI 不读这些文件夹里的 AGENTS.md,说明文件由宿主的开场说明点出。
|
|
61
|
+
acceptsAdditionalDirectories: true
|
|
59
62
|
},
|
|
60
63
|
credentialSources: [],
|
|
61
64
|
diagnostics: [],
|
|
@@ -1682,11 +1685,11 @@ function codexThreadConfigForNativeMode(nativeModeId) {
|
|
|
1682
1685
|
return runtimeModeToThreadConfig("approval-required");
|
|
1683
1686
|
}
|
|
1684
1687
|
}
|
|
1685
|
-
function codexTurnSandboxPolicyForNativeMode(nativeModeId) {
|
|
1688
|
+
function codexTurnSandboxPolicyForNativeMode(nativeModeId, additionalDirectories = []) {
|
|
1686
1689
|
switch (nativeModeId) {
|
|
1687
1690
|
case "workspace-write":
|
|
1688
1691
|
case "auto-review":
|
|
1689
|
-
return runtimeModeToTurnSandboxPolicy("auto-accept-edits");
|
|
1692
|
+
return additionalDirectories.length > 0 ? { type: "workspaceWrite", writableRoots: additionalDirectories } : runtimeModeToTurnSandboxPolicy("auto-accept-edits");
|
|
1690
1693
|
case "full-access":
|
|
1691
1694
|
return runtimeModeToTurnSandboxPolicy("full-access");
|
|
1692
1695
|
default:
|
|
@@ -2726,6 +2729,88 @@ async function createCodexRpcClient(handle, handlers) {
|
|
|
2726
2729
|
};
|
|
2727
2730
|
}
|
|
2728
2731
|
|
|
2732
|
+
// src/processReuse.ts
|
|
2733
|
+
import * as NodeUtil from "node:util";
|
|
2734
|
+
|
|
2735
|
+
// src/skills.ts
|
|
2736
|
+
var SKILLS_LIST_TIMEOUT_MS = 15e3;
|
|
2737
|
+
function codexProbeSkill(raw, includeRepo = false) {
|
|
2738
|
+
if (!isRecord2(raw)) return null;
|
|
2739
|
+
const name = asString(raw["name"]);
|
|
2740
|
+
const path = asString(raw["path"]);
|
|
2741
|
+
const scope = asString(raw["scope"]);
|
|
2742
|
+
if (!name || !path || scope === "repo" && !includeRepo) return null;
|
|
2743
|
+
const face = isRecord2(raw["interface"]) ? raw["interface"] : void 0;
|
|
2744
|
+
const description = asString(raw["description"]);
|
|
2745
|
+
const displayName = asString(face?.["displayName"]);
|
|
2746
|
+
const shortDescription = asString(face?.["shortDescription"]) || asString(raw["shortDescription"]);
|
|
2747
|
+
return {
|
|
2748
|
+
name,
|
|
2749
|
+
path,
|
|
2750
|
+
enabled: raw["enabled"] !== false,
|
|
2751
|
+
...scope ? { scope } : {},
|
|
2752
|
+
...description ? { description } : {},
|
|
2753
|
+
...displayName ? { displayName } : {},
|
|
2754
|
+
...shortDescription ? { shortDescription } : {}
|
|
2755
|
+
};
|
|
2756
|
+
}
|
|
2757
|
+
async function listCodexWorkspaceSkills(rpc, cwd) {
|
|
2758
|
+
const response = await rpc.request("skills/list", { cwds: [cwd] }, SKILLS_LIST_TIMEOUT_MS);
|
|
2759
|
+
if (!isRecord2(response) || !Array.isArray(response["data"])) {
|
|
2760
|
+
throw new Error("skills/list returned an unexpected shape");
|
|
2761
|
+
}
|
|
2762
|
+
const skills = /* @__PURE__ */ new Map();
|
|
2763
|
+
for (const entry of response["data"]) {
|
|
2764
|
+
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
2765
|
+
for (const raw of entry["skills"]) {
|
|
2766
|
+
const skill = codexProbeSkill(raw, true);
|
|
2767
|
+
if (skill !== null) skills.set(skill.path, skill);
|
|
2768
|
+
}
|
|
2769
|
+
}
|
|
2770
|
+
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
2771
|
+
}
|
|
2772
|
+
async function listCodexSkills(rpc) {
|
|
2773
|
+
let response;
|
|
2774
|
+
try {
|
|
2775
|
+
response = await rpc.request("skills/list", {}, SKILLS_LIST_TIMEOUT_MS);
|
|
2776
|
+
} catch {
|
|
2777
|
+
return void 0;
|
|
2778
|
+
}
|
|
2779
|
+
if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
|
|
2780
|
+
const skills = /* @__PURE__ */ new Map();
|
|
2781
|
+
for (const entry of response["data"]) {
|
|
2782
|
+
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
2783
|
+
for (const raw of entry["skills"]) {
|
|
2784
|
+
const skill = codexProbeSkill(raw);
|
|
2785
|
+
if (skill !== null) skills.set(skill.path, skill);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
2789
|
+
}
|
|
2790
|
+
var codexSessionSkillRoot = (skills) => skills === void 0 || skills.names.length === 0 ? void 0 : skills.skillsDir;
|
|
2791
|
+
async function setCodexSessionSkillRoots(rpc, skills, log, threadId) {
|
|
2792
|
+
const root = codexSessionSkillRoot(skills);
|
|
2793
|
+
if (root === void 0) return;
|
|
2794
|
+
try {
|
|
2795
|
+
await rpc.request("skills/extraRoots/set", { extraRoots: [root] });
|
|
2796
|
+
} catch (error) {
|
|
2797
|
+
log.warn("codex did not take the session skill root; skills stay on the built-in tools", {
|
|
2798
|
+
threadId,
|
|
2799
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2800
|
+
});
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
|
|
2804
|
+
// src/processReuse.ts
|
|
2805
|
+
var reusesCodexProcess = (running, input, cwd) => {
|
|
2806
|
+
const { runtime, launch } = running;
|
|
2807
|
+
const resume = input.discardResumeCursor === true ? void 0 : parseCodexResumeCursor(input.resumeCursor);
|
|
2808
|
+
return !runtime.closing && runtime.nativeThreadId !== void 0 && resume?.threadId === runtime.nativeThreadId && runtime.cwd === cwd && codexNativeModeFor(runtime.runtimeMode, runtime.nativeModeId) === codexNativeModeFor(input.runtimeMode, input.nativeModeId) && NodeUtil.isDeepStrictEqual(
|
|
2809
|
+
codexMcpThreadConfig(launch.mcpServers ?? []),
|
|
2810
|
+
codexMcpThreadConfig(input.mcpServers ?? [])
|
|
2811
|
+
) && codexSessionSkillRoot(launch.skills) === codexSessionSkillRoot(input.skills);
|
|
2812
|
+
};
|
|
2813
|
+
|
|
2729
2814
|
// src/sessionRuntime.ts
|
|
2730
2815
|
import * as NodeCrypto4 from "node:crypto";
|
|
2731
2816
|
|
|
@@ -5225,6 +5310,8 @@ var CodexSessionRuntime = class {
|
|
|
5225
5310
|
/** 这个会话见过的主额度快照(按字段合并),额度用尽停轮时点名窗口用。 */
|
|
5226
5311
|
rateLimits;
|
|
5227
5312
|
appServerArgs;
|
|
5313
|
+
/** 会话除 cwd 外的文件夹,每轮随 `sandboxPolicy` 发;变了由 `setAdditionalDirectories` 换上,进程不重启。 */
|
|
5314
|
+
#additionalDirectories;
|
|
5228
5315
|
hasConfiguredMcpServer;
|
|
5229
5316
|
host;
|
|
5230
5317
|
attachments;
|
|
@@ -5250,7 +5337,8 @@ var CodexSessionRuntime = class {
|
|
|
5250
5337
|
/** 同上,沙箱策略那一位。 */
|
|
5251
5338
|
#turnSandboxPolicy() {
|
|
5252
5339
|
return codexTurnSandboxPolicyForNativeMode(
|
|
5253
|
-
codexNativeModeFor(this.runtimeMode, this.nativeModeId)
|
|
5340
|
+
codexNativeModeFor(this.runtimeMode, this.nativeModeId),
|
|
5341
|
+
this.#additionalDirectories
|
|
5254
5342
|
);
|
|
5255
5343
|
}
|
|
5256
5344
|
constructor(host, rpc, emit, input, cwd, appServerArgs, grants, declineRelay, attachments, closeOptions = {}) {
|
|
@@ -5272,6 +5360,7 @@ var CodexSessionRuntime = class {
|
|
|
5272
5360
|
this.runtimeMode = input.runtimeMode;
|
|
5273
5361
|
this.nativeModeId = input.nativeModeId;
|
|
5274
5362
|
this.appServerArgs = appServerArgs;
|
|
5363
|
+
this.#additionalDirectories = input.additionalDirectories ?? [];
|
|
5275
5364
|
this.hasConfiguredMcpServer = (input.mcpServers?.length ?? 0) > 0;
|
|
5276
5365
|
this.grants = grants ?? createApprovalGrantStore();
|
|
5277
5366
|
this.declineRelay = declineRelay ?? createDeclineReasonRelay();
|
|
@@ -5295,6 +5384,10 @@ var CodexSessionRuntime = class {
|
|
|
5295
5384
|
this.writeAcks.set(jsonRpcId, { resolve: resolve4 });
|
|
5296
5385
|
});
|
|
5297
5386
|
}
|
|
5387
|
+
/** 下一轮(含插话)起按这份发可写根;正在跑的一轮不变。 */
|
|
5388
|
+
setAdditionalDirectories(directories) {
|
|
5389
|
+
this.#additionalDirectories = directories;
|
|
5390
|
+
}
|
|
5298
5391
|
settleNativeWrite(requestId, status) {
|
|
5299
5392
|
const ack = this.writeAcks.get(requestId);
|
|
5300
5393
|
if (!ack) return;
|
|
@@ -5906,73 +5999,6 @@ async function listCodexModels(rpc) {
|
|
|
5906
5999
|
return models;
|
|
5907
6000
|
}
|
|
5908
6001
|
|
|
5909
|
-
// src/skills.ts
|
|
5910
|
-
var SKILLS_LIST_TIMEOUT_MS = 15e3;
|
|
5911
|
-
function codexProbeSkill(raw, includeRepo = false) {
|
|
5912
|
-
if (!isRecord2(raw)) return null;
|
|
5913
|
-
const name = asString(raw["name"]);
|
|
5914
|
-
const path = asString(raw["path"]);
|
|
5915
|
-
const scope = asString(raw["scope"]);
|
|
5916
|
-
if (!name || !path || scope === "repo" && !includeRepo) return null;
|
|
5917
|
-
const face = isRecord2(raw["interface"]) ? raw["interface"] : void 0;
|
|
5918
|
-
const description = asString(raw["description"]);
|
|
5919
|
-
const displayName = asString(face?.["displayName"]);
|
|
5920
|
-
const shortDescription = asString(face?.["shortDescription"]) || asString(raw["shortDescription"]);
|
|
5921
|
-
return {
|
|
5922
|
-
name,
|
|
5923
|
-
path,
|
|
5924
|
-
enabled: raw["enabled"] !== false,
|
|
5925
|
-
...scope ? { scope } : {},
|
|
5926
|
-
...description ? { description } : {},
|
|
5927
|
-
...displayName ? { displayName } : {},
|
|
5928
|
-
...shortDescription ? { shortDescription } : {}
|
|
5929
|
-
};
|
|
5930
|
-
}
|
|
5931
|
-
async function listCodexWorkspaceSkills(rpc, cwd) {
|
|
5932
|
-
const response = await rpc.request("skills/list", { cwds: [cwd] }, SKILLS_LIST_TIMEOUT_MS);
|
|
5933
|
-
if (!isRecord2(response) || !Array.isArray(response["data"])) {
|
|
5934
|
-
throw new Error("skills/list returned an unexpected shape");
|
|
5935
|
-
}
|
|
5936
|
-
const skills = /* @__PURE__ */ new Map();
|
|
5937
|
-
for (const entry of response["data"]) {
|
|
5938
|
-
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
5939
|
-
for (const raw of entry["skills"]) {
|
|
5940
|
-
const skill = codexProbeSkill(raw, true);
|
|
5941
|
-
if (skill !== null) skills.set(skill.path, skill);
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
5944
|
-
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
5945
|
-
}
|
|
5946
|
-
async function listCodexSkills(rpc) {
|
|
5947
|
-
let response;
|
|
5948
|
-
try {
|
|
5949
|
-
response = await rpc.request("skills/list", {}, SKILLS_LIST_TIMEOUT_MS);
|
|
5950
|
-
} catch {
|
|
5951
|
-
return void 0;
|
|
5952
|
-
}
|
|
5953
|
-
if (!isRecord2(response) || !Array.isArray(response["data"])) return void 0;
|
|
5954
|
-
const skills = /* @__PURE__ */ new Map();
|
|
5955
|
-
for (const entry of response["data"]) {
|
|
5956
|
-
if (!isRecord2(entry) || !Array.isArray(entry["skills"])) continue;
|
|
5957
|
-
for (const raw of entry["skills"]) {
|
|
5958
|
-
const skill = codexProbeSkill(raw);
|
|
5959
|
-
if (skill !== null) skills.set(skill.path, skill);
|
|
5960
|
-
}
|
|
5961
|
-
}
|
|
5962
|
-
return [...skills.values()].toSorted((left, right) => left.name.localeCompare(right.name));
|
|
5963
|
-
}
|
|
5964
|
-
async function setCodexSessionSkillRoots(rpc, skills, log, threadId) {
|
|
5965
|
-
if (skills === void 0 || skills.names.length === 0) return;
|
|
5966
|
-
try {
|
|
5967
|
-
await rpc.request("skills/extraRoots/set", { extraRoots: [skills.skillsDir] });
|
|
5968
|
-
} catch (error) {
|
|
5969
|
-
log.warn("codex did not take the session skill root; skills stay on the built-in tools", {
|
|
5970
|
-
threadId,
|
|
5971
|
-
error: error instanceof Error ? error.message : String(error)
|
|
5972
|
-
});
|
|
5973
|
-
}
|
|
5974
|
-
}
|
|
5975
|
-
|
|
5976
6002
|
// src/workspaceInventory.ts
|
|
5977
6003
|
import * as NodeFS6 from "node:fs";
|
|
5978
6004
|
import * as NodePath8 from "node:path";
|
|
@@ -7625,6 +7651,11 @@ var createCodexInstance = (config, host, attachments, cache) => {
|
|
|
7625
7651
|
const existing = threads.get(input.threadId);
|
|
7626
7652
|
if (existing !== void 0) {
|
|
7627
7653
|
if (existing.closing) throw new Error(`thread ${input.threadId} is closing`);
|
|
7654
|
+
if (reusesCodexProcess(existing, input, cwd)) {
|
|
7655
|
+
existing.runtime.setAdditionalDirectories(input.additionalDirectories ?? []);
|
|
7656
|
+
host.log.info("session reused", { threadId: input.threadId });
|
|
7657
|
+
return existing.runtime.session;
|
|
7658
|
+
}
|
|
7628
7659
|
await stopBooked(input.threadId, existing);
|
|
7629
7660
|
}
|
|
7630
7661
|
const layout = layoutFor(recipe);
|
|
@@ -7679,7 +7710,7 @@ var createCodexInstance = (config, host, attachments, cache) => {
|
|
|
7679
7710
|
attachments,
|
|
7680
7711
|
{ requestClose: () => stopBooked(input.threadId, booked, "process") }
|
|
7681
7712
|
);
|
|
7682
|
-
booked = { runtime, rpc, handle };
|
|
7713
|
+
booked = { runtime, rpc, handle, launch: input };
|
|
7683
7714
|
threads.set(input.threadId, booked);
|
|
7684
7715
|
try {
|
|
7685
7716
|
await rpc.request("initialize", CODEX_INITIALIZE_PARAMS);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-codex",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3488",
|
|
4
4
|
"description": "Codex executor: Codex CLI over the app-server JSON-RPC protocol.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"tailwindcss": "^4.0.0",
|
|
30
30
|
"typescript": "~6.0.3",
|
|
31
31
|
"vite-plus": "0.2.2",
|
|
32
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
33
|
-
"ycodium-
|
|
34
|
-
"ycodium-
|
|
32
|
+
"@ycodium-ai/plugin-api": "0.2.3488",
|
|
33
|
+
"ycodium-jsonl-stream": "0.0.0",
|
|
34
|
+
"ycodium-executor-testing": "0.0.0"
|
|
35
35
|
},
|
|
36
36
|
"ycodium": {
|
|
37
37
|
"plugin": "./dist/index.js",
|