@ycodium-ai/agent-codex 0.2.3478 → 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.
Files changed (2) hide show
  1. package/dist/index.js +103 -72
  2. 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.3478",
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.3478",
33
- "ycodium-executor-testing": "0.0.0",
34
- "ycodium-jsonl-stream": "0.0.0"
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",