@tickernelz/paperclip-pro-adapter-codex-local 2026.925.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.
Files changed (268) hide show
  1. package/LICENSE +22 -0
  2. package/dist/cli/format-event.d.ts +2 -0
  3. package/dist/cli/format-event.d.ts.map +1 -0
  4. package/dist/cli/format-event.js +218 -0
  5. package/dist/cli/format-event.js.map +1 -0
  6. package/dist/cli/index.d.ts +2 -0
  7. package/dist/cli/index.d.ts.map +1 -0
  8. package/dist/cli/index.js +2 -0
  9. package/dist/cli/index.js.map +1 -0
  10. package/dist/cli/quota-probe.d.ts +3 -0
  11. package/dist/cli/quota-probe.d.ts.map +1 -0
  12. package/dist/cli/quota-probe.js +104 -0
  13. package/dist/cli/quota-probe.js.map +1 -0
  14. package/dist/index.d.ts +21 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +155 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/index.test.d.ts +2 -0
  19. package/dist/index.test.d.ts.map +1 -0
  20. package/dist/index.test.js +58 -0
  21. package/dist/index.test.js.map +1 -0
  22. package/dist/server/acp.d.ts +30 -0
  23. package/dist/server/acp.d.ts.map +1 -0
  24. package/dist/server/acp.js +532 -0
  25. package/dist/server/acp.js.map +1 -0
  26. package/dist/server/acp.test.d.ts +2 -0
  27. package/dist/server/acp.test.d.ts.map +1 -0
  28. package/dist/server/acp.test.js +1087 -0
  29. package/dist/server/acp.test.js.map +1 -0
  30. package/dist/server/adapter-auth-promotion.d.ts +102 -0
  31. package/dist/server/adapter-auth-promotion.d.ts.map +1 -0
  32. package/dist/server/adapter-auth-promotion.js +210 -0
  33. package/dist/server/adapter-auth-promotion.js.map +1 -0
  34. package/dist/server/adapter-auth-promotion.test.d.ts +2 -0
  35. package/dist/server/adapter-auth-promotion.test.d.ts.map +1 -0
  36. package/dist/server/adapter-auth-promotion.test.js +658 -0
  37. package/dist/server/adapter-auth-promotion.test.js.map +1 -0
  38. package/dist/server/auth-check.d.ts +8 -0
  39. package/dist/server/auth-check.d.ts.map +1 -0
  40. package/dist/server/auth-check.js +8 -0
  41. package/dist/server/auth-check.js.map +1 -0
  42. package/dist/server/auth-precedence.d.ts +16 -0
  43. package/dist/server/auth-precedence.d.ts.map +1 -0
  44. package/dist/server/auth-precedence.js +20 -0
  45. package/dist/server/auth-precedence.js.map +1 -0
  46. package/dist/server/auth-precedence.test.d.ts +2 -0
  47. package/dist/server/auth-precedence.test.d.ts.map +1 -0
  48. package/dist/server/auth-precedence.test.js +100 -0
  49. package/dist/server/auth-precedence.test.js.map +1 -0
  50. package/dist/server/codex-args.d.ts +13 -0
  51. package/dist/server/codex-args.d.ts.map +1 -0
  52. package/dist/server/codex-args.js +76 -0
  53. package/dist/server/codex-args.js.map +1 -0
  54. package/dist/server/codex-args.test.d.ts +2 -0
  55. package/dist/server/codex-args.test.d.ts.map +1 -0
  56. package/dist/server/codex-args.test.js +243 -0
  57. package/dist/server/codex-args.test.js.map +1 -0
  58. package/dist/server/codex-auth-cache.d.ts +206 -0
  59. package/dist/server/codex-auth-cache.d.ts.map +1 -0
  60. package/dist/server/codex-auth-cache.js +501 -0
  61. package/dist/server/codex-auth-cache.js.map +1 -0
  62. package/dist/server/codex-auth-cache.test.d.ts +2 -0
  63. package/dist/server/codex-auth-cache.test.d.ts.map +1 -0
  64. package/dist/server/codex-auth-cache.test.js +497 -0
  65. package/dist/server/codex-auth-cache.test.js.map +1 -0
  66. package/dist/server/codex-auth-copyback.d.ts +53 -0
  67. package/dist/server/codex-auth-copyback.d.ts.map +1 -0
  68. package/dist/server/codex-auth-copyback.js +123 -0
  69. package/dist/server/codex-auth-copyback.js.map +1 -0
  70. package/dist/server/codex-auth-copyback.test.d.ts +2 -0
  71. package/dist/server/codex-auth-copyback.test.d.ts.map +1 -0
  72. package/dist/server/codex-auth-copyback.test.js +507 -0
  73. package/dist/server/codex-auth-copyback.test.js.map +1 -0
  74. package/dist/server/codex-auth-merge-decision.cjs +170 -0
  75. package/dist/server/codex-auth-merge-decision.d.ts +22 -0
  76. package/dist/server/codex-auth-merge-decision.d.ts.map +1 -0
  77. package/dist/server/codex-auth-merge-decision.js +58 -0
  78. package/dist/server/codex-auth-merge-decision.js.map +1 -0
  79. package/dist/server/codex-auth-merge-decision.test.d.ts +2 -0
  80. package/dist/server/codex-auth-merge-decision.test.d.ts.map +1 -0
  81. package/dist/server/codex-auth-merge-decision.test.js +230 -0
  82. package/dist/server/codex-auth-merge-decision.test.js.map +1 -0
  83. package/dist/server/codex-auth-merge-extract.sh +73 -0
  84. package/dist/server/codex-auth-merge-scripts.d.ts +21 -0
  85. package/dist/server/codex-auth-merge-scripts.d.ts.map +1 -0
  86. package/dist/server/codex-auth-merge-scripts.js +40 -0
  87. package/dist/server/codex-auth-merge-scripts.js.map +1 -0
  88. package/dist/server/codex-auth-merge.test.d.ts +2 -0
  89. package/dist/server/codex-auth-merge.test.d.ts.map +1 -0
  90. package/dist/server/codex-auth-merge.test.js +714 -0
  91. package/dist/server/codex-auth-merge.test.js.map +1 -0
  92. package/dist/server/codex-auth-seed-write.d.ts +30 -0
  93. package/dist/server/codex-auth-seed-write.d.ts.map +1 -0
  94. package/dist/server/codex-auth-seed-write.js +41 -0
  95. package/dist/server/codex-auth-seed-write.js.map +1 -0
  96. package/dist/server/codex-home.d.ts +162 -0
  97. package/dist/server/codex-home.d.ts.map +1 -0
  98. package/dist/server/codex-home.js +771 -0
  99. package/dist/server/codex-home.js.map +1 -0
  100. package/dist/server/codex-home.test.d.ts +2 -0
  101. package/dist/server/codex-home.test.d.ts.map +1 -0
  102. package/dist/server/codex-home.test.js +1183 -0
  103. package/dist/server/codex-home.test.js.map +1 -0
  104. package/dist/server/config-schema.d.ts +3 -0
  105. package/dist/server/config-schema.d.ts.map +1 -0
  106. package/dist/server/config-schema.js +67 -0
  107. package/dist/server/config-schema.js.map +1 -0
  108. package/dist/server/device-login-export.d.ts +56 -0
  109. package/dist/server/device-login-export.d.ts.map +1 -0
  110. package/dist/server/device-login-export.js +230 -0
  111. package/dist/server/device-login-export.js.map +1 -0
  112. package/dist/server/device-login-export.test.d.ts +2 -0
  113. package/dist/server/device-login-export.test.d.ts.map +1 -0
  114. package/dist/server/device-login-export.test.js +245 -0
  115. package/dist/server/device-login-export.test.js.map +1 -0
  116. package/dist/server/device-login-parse.d.ts +20 -0
  117. package/dist/server/device-login-parse.d.ts.map +1 -0
  118. package/dist/server/device-login-parse.js +155 -0
  119. package/dist/server/device-login-parse.js.map +1 -0
  120. package/dist/server/device-login-parse.test.d.ts +2 -0
  121. package/dist/server/device-login-parse.test.d.ts.map +1 -0
  122. package/dist/server/device-login-parse.test.js +269 -0
  123. package/dist/server/device-login-parse.test.js.map +1 -0
  124. package/dist/server/device-login-runner.d.ts +69 -0
  125. package/dist/server/device-login-runner.d.ts.map +1 -0
  126. package/dist/server/device-login-runner.js +109 -0
  127. package/dist/server/device-login-runner.js.map +1 -0
  128. package/dist/server/device-login-runner.test.d.ts +2 -0
  129. package/dist/server/device-login-runner.test.d.ts.map +1 -0
  130. package/dist/server/device-login-runner.test.js +201 -0
  131. package/dist/server/device-login-runner.test.js.map +1 -0
  132. package/dist/server/engine-availability.test.d.ts +2 -0
  133. package/dist/server/engine-availability.test.d.ts.map +1 -0
  134. package/dist/server/engine-availability.test.js +41 -0
  135. package/dist/server/engine-availability.test.js.map +1 -0
  136. package/dist/server/execute.acp-fallback.test.d.ts +2 -0
  137. package/dist/server/execute.acp-fallback.test.d.ts.map +1 -0
  138. package/dist/server/execute.acp-fallback.test.js +123 -0
  139. package/dist/server/execute.acp-fallback.test.js.map +1 -0
  140. package/dist/server/execute.auth-precedence.test.d.ts +2 -0
  141. package/dist/server/execute.auth-precedence.test.d.ts.map +1 -0
  142. package/dist/server/execute.auth-precedence.test.js +137 -0
  143. package/dist/server/execute.auth-precedence.test.js.map +1 -0
  144. package/dist/server/execute.auth.test.d.ts +2 -0
  145. package/dist/server/execute.auth.test.d.ts.map +1 -0
  146. package/dist/server/execute.auth.test.js +197 -0
  147. package/dist/server/execute.auth.test.js.map +1 -0
  148. package/dist/server/execute.d.ts +40 -0
  149. package/dist/server/execute.d.ts.map +1 -0
  150. package/dist/server/execute.js +1290 -0
  151. package/dist/server/execute.js.map +1 -0
  152. package/dist/server/execute.remote.test.d.ts +2 -0
  153. package/dist/server/execute.remote.test.d.ts.map +1 -0
  154. package/dist/server/execute.remote.test.js +556 -0
  155. package/dist/server/execute.remote.test.js.map +1 -0
  156. package/dist/server/execute.stderr-error.test.d.ts +2 -0
  157. package/dist/server/execute.stderr-error.test.d.ts.map +1 -0
  158. package/dist/server/execute.stderr-error.test.js +142 -0
  159. package/dist/server/execute.stderr-error.test.js.map +1 -0
  160. package/dist/server/execute.test.d.ts +2 -0
  161. package/dist/server/execute.test.d.ts.map +1 -0
  162. package/dist/server/execute.test.js +240 -0
  163. package/dist/server/execute.test.js.map +1 -0
  164. package/dist/server/index.d.ts +18 -0
  165. package/dist/server/index.d.ts.map +1 -0
  166. package/dist/server/index.js +71 -0
  167. package/dist/server/index.js.map +1 -0
  168. package/dist/server/output-inactivity-monitor.d.ts +62 -0
  169. package/dist/server/output-inactivity-monitor.d.ts.map +1 -0
  170. package/dist/server/output-inactivity-monitor.integration.test.d.ts +2 -0
  171. package/dist/server/output-inactivity-monitor.integration.test.d.ts.map +1 -0
  172. package/dist/server/output-inactivity-monitor.integration.test.js +136 -0
  173. package/dist/server/output-inactivity-monitor.integration.test.js.map +1 -0
  174. package/dist/server/output-inactivity-monitor.js +112 -0
  175. package/dist/server/output-inactivity-monitor.js.map +1 -0
  176. package/dist/server/output-inactivity-monitor.test.d.ts +2 -0
  177. package/dist/server/output-inactivity-monitor.test.d.ts.map +1 -0
  178. package/dist/server/output-inactivity-monitor.test.js +284 -0
  179. package/dist/server/output-inactivity-monitor.test.js.map +1 -0
  180. package/dist/server/parse.d.ts +51 -0
  181. package/dist/server/parse.d.ts.map +1 -0
  182. package/dist/server/parse.js +261 -0
  183. package/dist/server/parse.js.map +1 -0
  184. package/dist/server/parse.test.d.ts +2 -0
  185. package/dist/server/parse.test.d.ts.map +1 -0
  186. package/dist/server/parse.test.js +186 -0
  187. package/dist/server/parse.test.js.map +1 -0
  188. package/dist/server/process-activity-monitor.d.ts +21 -0
  189. package/dist/server/process-activity-monitor.d.ts.map +1 -0
  190. package/dist/server/process-activity-monitor.js +103 -0
  191. package/dist/server/process-activity-monitor.js.map +1 -0
  192. package/dist/server/process-activity-monitor.test.d.ts +2 -0
  193. package/dist/server/process-activity-monitor.test.d.ts.map +1 -0
  194. package/dist/server/process-activity-monitor.test.js +82 -0
  195. package/dist/server/process-activity-monitor.test.js.map +1 -0
  196. package/dist/server/quota-spawn-error.test.d.ts +2 -0
  197. package/dist/server/quota-spawn-error.test.d.ts.map +1 -0
  198. package/dist/server/quota-spawn-error.test.js +174 -0
  199. package/dist/server/quota-spawn-error.test.js.map +1 -0
  200. package/dist/server/quota.d.ts +66 -0
  201. package/dist/server/quota.d.ts.map +1 -0
  202. package/dist/server/quota.js +511 -0
  203. package/dist/server/quota.js.map +1 -0
  204. package/dist/server/runtime-config.d.ts +11 -0
  205. package/dist/server/runtime-config.d.ts.map +1 -0
  206. package/dist/server/runtime-config.js +380 -0
  207. package/dist/server/runtime-config.js.map +1 -0
  208. package/dist/server/runtime-config.test.d.ts +2 -0
  209. package/dist/server/runtime-config.test.d.ts.map +1 -0
  210. package/dist/server/runtime-config.test.js +367 -0
  211. package/dist/server/runtime-config.test.js.map +1 -0
  212. package/dist/server/skills.d.ts +8 -0
  213. package/dist/server/skills.d.ts.map +1 -0
  214. package/dist/server/skills.js +26 -0
  215. package/dist/server/skills.js.map +1 -0
  216. package/dist/server/test.d.ts +3 -0
  217. package/dist/server/test.d.ts.map +1 -0
  218. package/dist/server/test.js +458 -0
  219. package/dist/server/test.js.map +1 -0
  220. package/dist/server/test.remote.test.d.ts +2 -0
  221. package/dist/server/test.remote.test.d.ts.map +1 -0
  222. package/dist/server/test.remote.test.js +396 -0
  223. package/dist/server/test.remote.test.js.map +1 -0
  224. package/dist/ui/build-config.d.ts +5 -0
  225. package/dist/ui/build-config.d.ts.map +1 -0
  226. package/dist/ui/build-config.js +229 -0
  227. package/dist/ui/build-config.js.map +1 -0
  228. package/dist/ui/build-config.test.d.ts +2 -0
  229. package/dist/ui/build-config.test.d.ts.map +1 -0
  230. package/dist/ui/build-config.test.js +272 -0
  231. package/dist/ui/build-config.test.js.map +1 -0
  232. package/dist/ui/index.d.ts +4 -0
  233. package/dist/ui/index.d.ts.map +1 -0
  234. package/dist/ui/index.js +8 -0
  235. package/dist/ui/index.js.map +1 -0
  236. package/dist/ui/parse-stdout.d.ts +3 -0
  237. package/dist/ui/parse-stdout.d.ts.map +1 -0
  238. package/dist/ui/parse-stdout.js +265 -0
  239. package/dist/ui/parse-stdout.js.map +1 -0
  240. package/dist/ui/parse-stdout.test.d.ts +2 -0
  241. package/dist/ui/parse-stdout.test.d.ts.map +1 -0
  242. package/dist/ui/parse-stdout.test.js +77 -0
  243. package/dist/ui/parse-stdout.test.js.map +1 -0
  244. package/package.json +61 -0
  245. package/skills/agentmail/SKILL.md +70 -0
  246. package/skills/paperclip/SKILL.md +712 -0
  247. package/skills/paperclip/references/api-reference.md +1675 -0
  248. package/skills/paperclip/references/artifacts.md +158 -0
  249. package/skills/paperclip/references/cases.md +295 -0
  250. package/skills/paperclip/references/company-skills.md +266 -0
  251. package/skills/paperclip/references/issue-workspaces.md +80 -0
  252. package/skills/paperclip/references/routines.md +231 -0
  253. package/skills/paperclip/references/workflows.md +141 -0
  254. package/skills/paperclip/scripts/paperclip-upload-artifact.sh +592 -0
  255. package/skills/paperclip-board/SKILL.md +619 -0
  256. package/skills/paperclip-converting-plans-to-tasks/SKILL.md +60 -0
  257. package/skills/paperclip-create-agent/SKILL.md +179 -0
  258. package/skills/paperclip-create-agent/references/agent-instruction-templates.md +123 -0
  259. package/skills/paperclip-create-agent/references/agents/coder.md +64 -0
  260. package/skills/paperclip-create-agent/references/agents/qa.md +88 -0
  261. package/skills/paperclip-create-agent/references/agents/securityengineer.md +135 -0
  262. package/skills/paperclip-create-agent/references/agents/uxdesigner.md +115 -0
  263. package/skills/paperclip-create-agent/references/api-reference.md +110 -0
  264. package/skills/paperclip-create-agent/references/baseline-role-guide.md +168 -0
  265. package/skills/paperclip-create-agent/references/draft-review-checklist.md +95 -0
  266. package/skills/para-memory-files/SKILL.md +100 -0
  267. package/skills/para-memory-files/references/schemas.md +35 -0
  268. package/skills/slack/SKILL.md +65 -0
@@ -0,0 +1,58 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { codexLocalReasoningEffortsForModel, DEFAULT_CODEX_LOCAL_MODEL, isCodexLocalFastModeSupported, models, normalizeCodexModel, } from "./index.js";
3
+ describe("codex local adapter metadata", () => {
4
+ it("advertises current Codex-capable OpenAI models without changing the default", () => {
5
+ const modelIds = models.map((model) => model.id);
6
+ // Default to the concrete gpt-5.6-sol slug — Codex ships no metadata for the bare gpt-5.6
7
+ // alias, so it must not be advertised or used as the default (it triggers a fallback warning).
8
+ expect(DEFAULT_CODEX_LOCAL_MODEL).toBe("gpt-5.6-sol");
9
+ expect(modelIds.slice(0, 6)).toEqual([
10
+ "gpt-5.6-sol",
11
+ "gpt-6-astra",
12
+ "gpt-6-sol",
13
+ "gpt-6-luna",
14
+ "gpt-5.6-terra",
15
+ "gpt-5.6-luna",
16
+ ]);
17
+ expect(modelIds).not.toContain("gpt-5.6");
18
+ expect(isCodexLocalFastModeSupported(DEFAULT_CODEX_LOCAL_MODEL)).toBe(true);
19
+ expect(isCodexLocalFastModeSupported("gpt-6-astra")).toBe(true);
20
+ expect(isCodexLocalFastModeSupported("gpt-6-sol")).toBe(true);
21
+ expect(modelIds).not.toContain("gpt-5.3-codex");
22
+ expect(modelIds).not.toContain("gpt-5.3-codex-spark");
23
+ });
24
+ it.each(["gpt-6-astra", "gpt-6-sol", " gpt-6-sol ", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6"])("uses the reasoning efforts advertised for %s", (model) => {
25
+ expect(codexLocalReasoningEffortsForModel(model)).toEqual([
26
+ "low",
27
+ "medium",
28
+ "high",
29
+ "xhigh",
30
+ "max",
31
+ "ultra",
32
+ ]);
33
+ });
34
+ it.each(["gpt-5.5", "custom-model"])("preserves legacy efforts for %s", (model) => {
35
+ expect(codexLocalReasoningEffortsForModel(model)).toEqual([
36
+ "minimal",
37
+ "low",
38
+ "medium",
39
+ "high",
40
+ "xhigh",
41
+ ]);
42
+ });
43
+ it.each(["gpt-6-luna", "gpt-5.6-luna"])("caps %s at max and supports Fast mode", (model) => {
44
+ expect(codexLocalReasoningEffortsForModel(model)).toEqual(["low", "medium", "high", "xhigh", "max"]);
45
+ expect(isCodexLocalFastModeSupported(model)).toBe(true);
46
+ });
47
+ it("normalizes the legacy bare gpt-5.6 alias to the concrete gpt-5.6-sol slug", () => {
48
+ expect(normalizeCodexModel("gpt-5.6")).toBe("gpt-5.6-sol");
49
+ expect(normalizeCodexModel(" gpt-5.6 ")).toBe("gpt-5.6-sol");
50
+ // Concrete slugs and unknown/manual model IDs pass through untouched.
51
+ expect(normalizeCodexModel("gpt-5.6-sol")).toBe("gpt-5.6-sol");
52
+ expect(normalizeCodexModel("gpt-5.5")).toBe("gpt-5.5");
53
+ expect(normalizeCodexModel("future-model")).toBe("future-model");
54
+ expect(normalizeCodexModel("")).toBe("");
55
+ expect(normalizeCodexModel(null)).toBe("");
56
+ });
57
+ });
58
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { AdapterBillingType, AdapterEnvironmentTestContext, AdapterEnvironmentTestResult, AdapterExecutionContext, AdapterExecutionResult } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ import type { AcpxEngineExecutorOptions } from "@tickernelz/paperclip-pro-adapter-utils/acpx-engine/execute";
3
+ export type CodexExecutionEngine = "cli" | "acp";
4
+ export interface CodexEngineSelection {
5
+ engine: CodexExecutionEngine;
6
+ explicit: boolean;
7
+ unavailableReason?: string;
8
+ }
9
+ type CodexEngineResolutionInput = Pick<AdapterExecutionContext, "config"> & Partial<Pick<AdapterExecutionContext, "executionTarget" | "executionTransport">>;
10
+ type CodexAcpExecutorOptions = Omit<AcpxEngineExecutorOptions, "adapterType" | "moduleDir" | "packageRootDir">;
11
+ type CodexAcpExecutor = (ctx: AdapterExecutionContext) => Promise<AdapterExecutionResult>;
12
+ export declare function resolveCodexExecutionEngine(config: Record<string, unknown>): CodexEngineSelection;
13
+ export declare function resolveCodexExecutionEngineForRun(input: CodexEngineResolutionInput): Promise<CodexEngineSelection>;
14
+ export declare function buildCodexAcpConfig(config: Record<string, unknown>): Record<string, unknown>;
15
+ /**
16
+ * Classify billing the same way the Codex CLI lane does so ACP runs land in
17
+ * the cost ledger with a real provider/billingType instead of acpx/unknown.
18
+ * Host env only counts for local execution targets; remote targets see just
19
+ * the adapter-config env.
20
+ */
21
+ export declare function resolveCodexAcpBillingIdentity(ctx: Pick<AdapterExecutionContext, "config"> & Partial<Pick<AdapterExecutionContext, "executionTarget" | "executionTransport">>): {
22
+ provider: string;
23
+ biller: string;
24
+ billingType: AdapterBillingType;
25
+ };
26
+ export declare function createCodexAcpExecutor(options?: CodexAcpExecutorOptions): CodexAcpExecutor;
27
+ export declare function nodeVersionMeetsCodexAcpMinimum(version?: string): boolean;
28
+ export declare function testCodexAcpEnvironment(ctx: AdapterEnvironmentTestContext): Promise<AdapterEnvironmentTestResult>;
29
+ export {};
30
+ //# sourceMappingURL=acp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp.d.ts","sourceRoot":"","sources":["../../src/server/acp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,4BAA4B,EAC5B,uBAAuB,EACvB,sBAAsB,EACvB,MAAM,yCAAyC,CAAC;AAiBjD,OAAO,KAAK,EACV,yBAAyB,EAG1B,MAAM,6DAA6D,CAAC;AAuBrE,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,KAAK,CAAC;AAEjD,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,oBAAoB,CAAC;IAC7B,QAAQ,EAAE,OAAO,CAAC;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,KAAK,0BAA0B,GAC7B,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,GACvC,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,iBAAiB,GAAG,oBAAoB,CAAC,CAAC,CAAC;AAEnF,KAAK,uBAAuB,GAAG,IAAI,CACjC,yBAAyB,EACzB,aAAa,GAAG,WAAW,GAAG,gBAAgB,CAC/C,CAAC;AAEF,KAAK,gBAAgB,GAAG,CAAC,GAAG,EAAE,uBAAuB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;AAS1F,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,CAEjG;AAED,wBAAsB,iCAAiC,CACrD,KAAK,EAAE,0BAA0B,GAChC,OAAO,CAAC,oBAAoB,CAAC,CAuB/B;AAWD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwC5F;AAqID;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,GAC1C,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,iBAAiB,GAAG,oBAAoB,CAAC,CAAC,GACjF;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,kBAAkB,CAAA;CAAE,CAuBvE;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,gBAAgB,CAe9F;AAQD,wBAAgB,+BAA+B,CAAC,OAAO,SAAkB,GAAG,OAAO,CAMlF;AA0HD,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,6BAA6B,GACjC,OAAO,CAAC,4BAA4B,CAAC,CA6JvC"}
@@ -0,0 +1,532 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { parseLocalProcessFilesystemScope, parseLocalProcessNetworkScope, } from "@tickernelz/paperclip-pro-adapter-utils/local-process-sandbox";
5
+ import { inferOpenAiCompatibleBiller } from "@tickernelz/paperclip-pro-adapter-utils";
6
+ import { ensureAdapterExecutionTargetCommandResolvable, readAdapterExecutionTarget, resolveAdapterExecutionTargetCwd, } from "@tickernelz/paperclip-pro-adapter-utils/execution-target";
7
+ import { DEFAULT_ACP_ENGINE_MODE, DEFAULT_ACP_ENGINE_NON_INTERACTIVE_PERMISSIONS, DEFAULT_ACP_ENGINE_PERMISSION_MODE, DEFAULT_ACP_ENGINE_WARM_HANDLE_IDLE_MS, } from "@tickernelz/paperclip-pro-adapter-utils/acpx-engine/constants";
8
+ import { asNumber, asString, asStringArray, parseObject, } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
9
+ import { createWorkspaceRestoreTeardown } from "@tickernelz/paperclip-pro-adapter-utils/workspace-restore-teardown";
10
+ import { normalizeCodexModel } from "../index.js";
11
+ import { classifyCodexAuthRefreshFailure } from "./parse.js";
12
+ import { copyBackCodexAuth } from "./codex-auth-copyback.js";
13
+ import { buildCodexAuthInboundProvision } from "./codex-auth-merge-scripts.js";
14
+ import { evaluateCodexCredentialReadiness, resolveSharedCodexHomeDir, stageCodexHomeForSync, } from "./codex-home.js";
15
+ import { ADAPTER_AUTH_MISSING_CHECK_CODE } from "./auth-check.js";
16
+ const moduleDir = path.dirname(fileURLToPath(import.meta.url));
17
+ const packageRootDir = path.resolve(moduleDir, "../..");
18
+ const MIN_ACP_NODE_VERSION = "24.11.0";
19
+ function normalizeEngine(value) {
20
+ const raw = typeof value === "string" ? value.trim().toLowerCase() : "";
21
+ if (raw === "acp")
22
+ return { engine: "acp", explicit: true };
23
+ if (raw === "cli")
24
+ return { engine: "cli", explicit: true };
25
+ return { engine: "acp", explicit: false };
26
+ }
27
+ export function resolveCodexExecutionEngine(config) {
28
+ return normalizeEngine(config.engine);
29
+ }
30
+ export async function resolveCodexExecutionEngineForRun(input) {
31
+ const selection = normalizeEngine(input.config.engine);
32
+ // Engine availability must never change the agent's execution or permission contract.
33
+ if (selection.engine === "cli")
34
+ return selection;
35
+ const unavailable = (reason) => ({
36
+ ...selection,
37
+ unavailableReason: `${reason} Repair the ACP setup, or explicitly set engine=cli to use the CLI engine.`,
38
+ });
39
+ const target = readAdapterExecutionTarget({
40
+ executionTarget: input.executionTarget,
41
+ legacyRemoteExecution: input.executionTransport?.remoteExecution,
42
+ });
43
+ if (target?.workspaceRealization?.mode === "in_place") {
44
+ return unavailable("In-place workspace realization requires the Codex CLI engine; ACP archive staging is not supported.");
45
+ }
46
+ const filesystemScope = parseLocalProcessFilesystemScope(input.config.filesystemScope);
47
+ const networkScope = parseLocalProcessNetworkScope(input.config.networkScope);
48
+ if (filesystemScope || networkScope) {
49
+ return unavailable("Local filesystem/network confinement requires the Codex CLI engine; ACP confinement is not supported.");
50
+ }
51
+ const reason = await codexAcpUnavailableReason(input);
52
+ return reason ? unavailable(reason) : selection;
53
+ }
54
+ function firstNonEmptyString(...values) {
55
+ for (const value of values) {
56
+ if (typeof value !== "string")
57
+ continue;
58
+ const trimmed = value.trim();
59
+ if (trimmed.length > 0)
60
+ return trimmed;
61
+ }
62
+ return undefined;
63
+ }
64
+ export function buildCodexAcpConfig(config) {
65
+ const agentCommand = firstNonEmptyString(config.agentCommand, config.acpAgentCommand);
66
+ const stateDir = firstNonEmptyString(config.stateDir, config.acpStateDir);
67
+ const mode = firstNonEmptyString(config.mode, config.acpMode) ?? DEFAULT_ACP_ENGINE_MODE;
68
+ const permissionMode = firstNonEmptyString(config.permissionMode, config.acpPermissionMode) ??
69
+ DEFAULT_ACP_ENGINE_PERMISSION_MODE;
70
+ const nonInteractivePermissions = firstNonEmptyString(config.nonInteractivePermissions, config.acpNonInteractivePermissions) ??
71
+ DEFAULT_ACP_ENGINE_NON_INTERACTIVE_PERMISSIONS;
72
+ const warmHandleIdleMs = config.warmHandleIdleMs ??
73
+ config.acpWarmHandleIdleMs ??
74
+ DEFAULT_ACP_ENGINE_WARM_HANDLE_IDLE_MS;
75
+ // Rewrite legacy model aliases (e.g. bare gpt-5.6) to the concrete slug Codex has metadata for,
76
+ // so the ACP session config matches the CLI lane and avoids the fallback-metadata warning.
77
+ const normalizedModel = normalizeCodexModel(typeof config.model === "string" ? config.model : "");
78
+ const env = parseObject(config.env);
79
+ let networkAccess = env.PAPERCLIP_CODEX_ACP_NETWORK_ACCESS !== "false";
80
+ const extraArgs = asStringArray(config.extraArgs);
81
+ for (const arg of extraArgs.length > 0 ? extraArgs : asStringArray(config.args)) {
82
+ const match = /^(?:(?:--config=|-c=?)\s*)?sandbox_workspace_write\.network_access\s*=\s*(true|false)\s*$/.exec(arg);
83
+ if (match)
84
+ networkAccess = match[1] === "true";
85
+ }
86
+ return {
87
+ ...config,
88
+ env: { ...env, PAPERCLIP_CODEX_ACP_NETWORK_ACCESS: String(networkAccess) },
89
+ agent: "codex",
90
+ mode,
91
+ permissionMode,
92
+ nonInteractivePermissions,
93
+ warmHandleIdleMs,
94
+ ...(normalizedModel ? { model: normalizedModel } : {}),
95
+ ...(agentCommand ? { agentCommand } : {}),
96
+ ...(stateDir ? { stateDir } : {}),
97
+ };
98
+ }
99
+ /**
100
+ * Codex remote managed-home seed + auth copy-back for the runner-backed remote
101
+ * sandbox ACP lane. Mirrors the codex CLI lane (`codex-local/execute.ts`): stage
102
+ * the managed `CODEX_HOME` (auth.json + config.toml + skills) into the sandbox
103
+ * as the `home` asset — carrying the inbound auth-merge `provision` and the
104
+ * outbound `restore` copy-back seams — then repoint `CODEX_HOME` onto the
105
+ * in-sandbox `assetDirs.home` path. The copy-back rides the asset `restore`,
106
+ * which fires inside `restoreWorkspace()` at teardown.
107
+ *
108
+ * The engine already resolved+seeded the host managed Codex home and set
109
+ * `env.CODEX_HOME` to it (a HOST path) before this seam runs, so `env.CODEX_HOME`
110
+ * is exactly the home to stage. Seed inbound and copy-back outbound land together
111
+ * (never seed-without-copy-back): Codex refresh tokens are single-use, so a
112
+ * refreshed sandbox token that is never copied back would spend the host's token
113
+ * and corrupt the host credential.
114
+ */
115
+ async function prepareCodexRemoteManagedHome(input) {
116
+ const { env, runId, onLog } = input;
117
+ // The host managed Codex home the engine seeded and set on env.CODEX_HOME.
118
+ const effectiveCodexHome = env.CODEX_HOME;
119
+ if (!effectiveCodexHome) {
120
+ // No managed home resolved (e.g. custom CODEX_HOME cleared) — stage the
121
+ // workspace with no home asset, identical to the no-seam fallback.
122
+ return { stagedRuntime: await input.stage([]) };
123
+ }
124
+ // Curated allowlist temp dir (auth/config/skills only); caller owns cleanup.
125
+ const stagedCodexHomeDir = await stageCodexHomeForSync(effectiveCodexHome, { runId });
126
+ let stagedRuntime;
127
+ try {
128
+ stagedRuntime = await input.stage([
129
+ {
130
+ key: "home",
131
+ localDir: stagedCodexHomeDir,
132
+ followSymlinks: true,
133
+ // Inbound (host→sandbox) auth-merge: keeps whichever credential is newer
134
+ // when the sandbox image already carries a Codex auth.json.
135
+ provision: buildCodexAuthInboundProvision(),
136
+ // Outbound (sandbox→host) copy-back at teardown, under the same
137
+ // direction-agnostic decision predicate + directory merge-lock +
138
+ // atomic-rename + 0600 guard. Target is the SHARED host auth.json
139
+ // (the symlink source managed homes point at), never an in-sandbox copy.
140
+ restore: async ({ assetDir, readFile }) => void (await copyBackCodexAuth({
141
+ readSandboxAuth: () => readFile(path.posix.join(assetDir, "auth.json")),
142
+ hostAuthPath: path.join(input.config.managedAiConnection ? effectiveCodexHome : resolveSharedCodexHomeDir(process.env), "auth.json"),
143
+ log: (line) => onLog("stdout", `${line}\n`),
144
+ })),
145
+ },
146
+ ]);
147
+ }
148
+ catch (err) {
149
+ await fs.rm(stagedCodexHomeDir, { recursive: true, force: true }).catch(() => { });
150
+ throw err;
151
+ }
152
+ // Repoint CODEX_HOME from the HOST path onto the seeded in-sandbox home.
153
+ env.CODEX_HOME =
154
+ stagedRuntime.assetDirs.home ??
155
+ path.posix.join(stagedRuntime.runtimeRootDir ?? "", "home");
156
+ return {
157
+ stagedRuntime,
158
+ // Per-run copy-back: fires on EVERY run's teardown (including a compatible
159
+ // resume that reuses this staged runtime). It reads the sandbox auth.json /
160
+ // workspace live and copies back to the host; it does NOT remove the staged
161
+ // in-sandbox home, so re-running it across resumes can't leave a later run
162
+ // without its staged home. Host staged-temp removal is deliberately NOT here
163
+ // — see `disposeStaged` — so caching this runtime for reuse never destroys
164
+ // resources the next resume needs.
165
+ // Fail-soft: a teardown copy-back miss loses this rotation and surfaces
166
+ // loudly as refresh_token_reused on the next host Codex use (re-auth
167
+ // recovers) — never silent host-credential corruption, so it must not
168
+ // mask the run result.
169
+ teardown: createWorkspaceRestoreTeardown({
170
+ stagedRuntime,
171
+ onLog,
172
+ startMessage: "[paperclip] Restoring workspace changes and Codex auth from the sandbox.\n",
173
+ failurePrefix: "[paperclip] Codex ACP teardown restore/copy-back failed",
174
+ }),
175
+ // One-time cleanup of the HOST staged home temp dir. Fired ONLY when the
176
+ // staged runtime is dropped (failed/cancelled/timed-out turn, incompatible
177
+ // re-stage, idle eviction) — never on a clean turn that keeps the runtime
178
+ // warm — so it can't remove the staged home while a reuse still depends on
179
+ // it. Idempotent: `force: true` no-ops if it was already removed.
180
+ disposeStaged: async () => {
181
+ await fs.rm(stagedCodexHomeDir, { recursive: true, force: true }).catch(async (error) => {
182
+ await onLog("stderr", `[paperclip] Failed to remove staged Codex home "${stagedCodexHomeDir}": ${error instanceof Error ? error.message : String(error)}\n`);
183
+ });
184
+ },
185
+ };
186
+ }
187
+ function withCodexAcpDefaults(options) {
188
+ return {
189
+ resolveBillingIdentity: resolveCodexAcpBillingIdentity,
190
+ prepareRemoteManagedHome: prepareCodexRemoteManagedHome,
191
+ ...options,
192
+ adapterType: "codex_local",
193
+ moduleDir,
194
+ packageRootDir,
195
+ };
196
+ }
197
+ function withCodexAuthRefreshFailureClassification(result) {
198
+ if ((result.exitCode ?? 0) === 0)
199
+ return result;
200
+ const resultJson = parseObject(result.resultJson);
201
+ const stopReason = asString(resultJson.stopReason, "");
202
+ const authFailure = classifyCodexAuthRefreshFailure({
203
+ errorMessage: [result.errorMessage ?? "", result.summary ?? "", stopReason]
204
+ .map((line) => line.trim())
205
+ .filter(Boolean)
206
+ .join("\n"),
207
+ });
208
+ if (!authFailure)
209
+ return result;
210
+ return {
211
+ ...result,
212
+ errorCode: authFailure,
213
+ errorFamily: authFailure,
214
+ resultJson: {
215
+ ...(result.resultJson ?? {}),
216
+ errorFamily: authFailure,
217
+ },
218
+ };
219
+ }
220
+ /**
221
+ * Classify billing the same way the Codex CLI lane does so ACP runs land in
222
+ * the cost ledger with a real provider/billingType instead of acpx/unknown.
223
+ * Host env only counts for local execution targets; remote targets see just
224
+ * the adapter-config env.
225
+ */
226
+ export function resolveCodexAcpBillingIdentity(ctx) {
227
+ const envConfig = parseObject(parseObject(ctx.config).env);
228
+ const target = readAdapterExecutionTarget({
229
+ executionTarget: ctx.executionTarget,
230
+ legacyRemoteExecution: ctx.executionTransport?.remoteExecution,
231
+ });
232
+ const considerHostEnv = target?.kind !== "remote";
233
+ const mergedEnv = {
234
+ ...(considerHostEnv ? process.env : {}),
235
+ ...Object.fromEntries(Object.entries(envConfig).filter((entry) => typeof entry[1] === "string")),
236
+ };
237
+ const apiKey = typeof mergedEnv.OPENAI_API_KEY === "string" && mergedEnv.OPENAI_API_KEY.trim().length > 0;
238
+ const billingType = apiKey ? "api" : "subscription";
239
+ const openAiCompatibleBiller = inferOpenAiCompatibleBiller(mergedEnv, "openai");
240
+ const biller = openAiCompatibleBiller === "openrouter"
241
+ ? "openrouter"
242
+ : billingType === "subscription"
243
+ ? "chatgpt"
244
+ : openAiCompatibleBiller ?? "openai";
245
+ return { provider: "openai", biller, billingType };
246
+ }
247
+ export function createCodexAcpExecutor(options = {}) {
248
+ let executor = null;
249
+ return async (ctx) => {
250
+ let currentExecutor = executor;
251
+ if (!currentExecutor) {
252
+ const { createAcpxEngineExecutor } = await import("@tickernelz/paperclip-pro-adapter-utils/acpx-engine/execute");
253
+ currentExecutor = createAcpxEngineExecutor(withCodexAcpDefaults(options));
254
+ executor = currentExecutor;
255
+ }
256
+ const result = await currentExecutor({
257
+ ...ctx,
258
+ config: buildCodexAcpConfig(ctx.config),
259
+ });
260
+ return withCodexAuthRefreshFailureClassification(result);
261
+ };
262
+ }
263
+ function parseVersion(version) {
264
+ const match = version.match(/^v?(\d+)\.(\d+)\.(\d+)/);
265
+ if (!match)
266
+ return [0, 0, 0];
267
+ return [Number(match[1]), Number(match[2]), Number(match[3])];
268
+ }
269
+ export function nodeVersionMeetsCodexAcpMinimum(version = process.version) {
270
+ const [major, minor, patch] = parseVersion(version);
271
+ const [minMajor, minMinor, minPatch] = parseVersion(MIN_ACP_NODE_VERSION);
272
+ if (major !== minMajor)
273
+ return major > minMajor;
274
+ if (minor !== minMinor)
275
+ return minor > minMinor;
276
+ return patch >= minPatch;
277
+ }
278
+ async function pathExists(candidate) {
279
+ return fs.access(candidate).then(() => true).catch(() => false);
280
+ }
281
+ function hasPathSeparator(command) {
282
+ return command.includes("/") || command.includes("\\");
283
+ }
284
+ function looksLikeShellCommand(command) {
285
+ return /\s/.test(command.trim());
286
+ }
287
+ async function findCommandOnPath(binName) {
288
+ const pathValue = process.env.PATH ?? "";
289
+ for (const segment of pathValue.split(path.delimiter)) {
290
+ if (!segment)
291
+ continue;
292
+ const candidate = path.join(segment, binName);
293
+ if (await pathExists(candidate))
294
+ return candidate;
295
+ }
296
+ return null;
297
+ }
298
+ async function findAncestorBin(startDir, binName) {
299
+ let current = path.resolve(startDir);
300
+ while (true) {
301
+ const candidate = path.join(current, "node_modules", ".bin", binName);
302
+ if (await pathExists(candidate))
303
+ return candidate;
304
+ const parent = path.dirname(current);
305
+ if (parent === current)
306
+ return null;
307
+ current = parent;
308
+ }
309
+ }
310
+ async function commandIsResolvable(command, input) {
311
+ const trimmed = command.trim();
312
+ if (!trimmed)
313
+ return false;
314
+ if (looksLikeShellCommand(trimmed))
315
+ return true;
316
+ const target = readAdapterExecutionTarget({
317
+ executionTarget: input?.executionTarget,
318
+ legacyRemoteExecution: input?.executionTransport?.remoteExecution,
319
+ });
320
+ if (target?.kind === "remote") {
321
+ try {
322
+ await ensureAdapterExecutionTargetCommandResolvable(trimmed, target, resolveAdapterExecutionTargetCwd(target, asString(input?.config.cwd, ""), process.cwd()), process.env);
323
+ return true;
324
+ }
325
+ catch {
326
+ return false;
327
+ }
328
+ }
329
+ if (path.isAbsolute(trimmed) || hasPathSeparator(trimmed))
330
+ return pathExists(trimmed);
331
+ return (await findCommandOnPath(trimmed)) !== null;
332
+ }
333
+ async function resolveCodexAcpCommand(config) {
334
+ const configured = firstNonEmptyString(config.agentCommand, config.acpAgentCommand);
335
+ if (configured)
336
+ return configured;
337
+ return ((await findAncestorBin(packageRootDir, "codex-acp")) ??
338
+ (await findCommandOnPath("codex-acp")) ??
339
+ path.join(packageRootDir, "node_modules", ".bin", "codex-acp"));
340
+ }
341
+ function sandboxTargetHasProcessSessionBridge(target) {
342
+ return target?.kind === "remote" && target.transport === "sandbox" && Boolean(target.runner);
343
+ }
344
+ async function resolveCodexAcpCommandForTarget(config, target) {
345
+ const configured = firstNonEmptyString(config.agentCommand, config.acpAgentCommand);
346
+ if (configured)
347
+ return configured;
348
+ if (target?.kind === "remote")
349
+ return "codex-acp";
350
+ return resolveCodexAcpCommand(config);
351
+ }
352
+ async function codexAcpUnavailableReason(input) {
353
+ const target = readAdapterExecutionTarget({
354
+ executionTarget: input.executionTarget,
355
+ legacyRemoteExecution: input.executionTransport?.remoteExecution,
356
+ });
357
+ if (target?.kind === "remote" && !sandboxTargetHasProcessSessionBridge(target)) {
358
+ if (target.transport === "sandbox") {
359
+ return "Codex ACP requires a bidirectional remote process target; this sandbox exposes only one-shot command execution.";
360
+ }
361
+ return "Codex ACP supports sandbox remote targets only; this run targets a non-sandbox remote environment.";
362
+ }
363
+ if (!nodeVersionMeetsCodexAcpMinimum()) {
364
+ return `Node ${process.version} (${process.execPath}) does not satisfy Codex ACP's Node >=${MIN_ACP_NODE_VERSION} prerequisite.`;
365
+ }
366
+ const command = await resolveCodexAcpCommandForTarget(input.config, target);
367
+ if (!(await commandIsResolvable(command, input))) {
368
+ return `Codex ACP server command is not available: ${command}.`;
369
+ }
370
+ return null;
371
+ }
372
+ function summarizeStatus(checks) {
373
+ if (checks.some((check) => check.level === "error"))
374
+ return "fail";
375
+ if (checks.some((check) => check.level === "warn"))
376
+ return "warn";
377
+ return "pass";
378
+ }
379
+ function isNonEmpty(value) {
380
+ return typeof value === "string" && value.trim().length > 0;
381
+ }
382
+ export async function testCodexAcpEnvironment(ctx) {
383
+ const checks = [];
384
+ const config = parseObject(ctx.config);
385
+ const target = ctx.executionTarget ?? null;
386
+ const targetIsRemote = target?.kind === "remote";
387
+ const targetIsSandbox = target?.kind === "remote" && target.transport === "sandbox";
388
+ checks.push({
389
+ code: "codex_engine_selected",
390
+ level: "info",
391
+ message: "Execution engine selected: ACP.",
392
+ hint: "Set engine=cli to use the existing Codex CLI lane.",
393
+ });
394
+ if (targetIsRemote) {
395
+ checks.push({
396
+ code: "codex_acp_remote_target",
397
+ level: "info",
398
+ message: "Codex ACP will run against the remote execution environment.",
399
+ hint: "Remote ACP requires a bidirectional process target such as SSH or Paperclip's sandbox process-session bridge.",
400
+ });
401
+ }
402
+ const cwd = asString(config.cwd, process.cwd());
403
+ try {
404
+ await fs.mkdir(cwd, { recursive: true });
405
+ checks.push({
406
+ code: "codex_acp_cwd_valid",
407
+ level: "info",
408
+ message: `Working directory is valid: ${cwd}`,
409
+ });
410
+ }
411
+ catch (err) {
412
+ checks.push({
413
+ code: "codex_acp_cwd_invalid",
414
+ level: "error",
415
+ message: err instanceof Error ? err.message : "Invalid working directory",
416
+ detail: cwd,
417
+ });
418
+ }
419
+ checks.push({
420
+ code: nodeVersionMeetsCodexAcpMinimum() ? "codex_acp_node_supported" : "codex_acp_node_unsupported",
421
+ level: nodeVersionMeetsCodexAcpMinimum() ? "info" : "error",
422
+ message: nodeVersionMeetsCodexAcpMinimum()
423
+ ? `Node ${process.version} satisfies ACP runtime requirements.`
424
+ : `Node ${process.version} (${process.execPath}) does not satisfy ACP runtime requirements.`,
425
+ hint: nodeVersionMeetsCodexAcpMinimum()
426
+ ? undefined
427
+ : `Run Codex ACP with Node >=${MIN_ACP_NODE_VERSION} or switch engine=cli.`,
428
+ });
429
+ const command = await resolveCodexAcpCommandForTarget(config, target);
430
+ const commandResolvable = await commandIsResolvable(command, {
431
+ config,
432
+ executionTarget: ctx.executionTarget,
433
+ });
434
+ checks.push({
435
+ code: commandResolvable ? "codex_acp_command_resolvable" : "codex_acp_command_missing",
436
+ level: commandResolvable ? "info" : "error",
437
+ message: commandResolvable
438
+ ? `Codex ACP server command is executable: ${command}`
439
+ : `Codex ACP server command is not available: ${command}`,
440
+ hint: commandResolvable
441
+ ? undefined
442
+ : "Install dependencies so @agentclientprotocol/codex-acp is present, or set agentCommand to a valid Codex ACP server command.",
443
+ });
444
+ const envConfig = parseObject(config.env);
445
+ if (!targetIsRemote) {
446
+ const configApiKey = isNonEmpty(envConfig.OPENAI_API_KEY) ? envConfig.OPENAI_API_KEY : null;
447
+ const hostApiKey = Object.prototype.hasOwnProperty.call(envConfig, "OPENAI_API_KEY")
448
+ ? null
449
+ : isNonEmpty(process.env.OPENAI_API_KEY)
450
+ ? process.env.OPENAI_API_KEY
451
+ : null;
452
+ const configuredApiKey = configApiKey ?? hostApiKey;
453
+ const configuredCodexHome = isNonEmpty(envConfig.CODEX_HOME) ? envConfig.CODEX_HOME : null;
454
+ const credentialReadiness = await evaluateCodexCredentialReadiness({
455
+ env: process.env,
456
+ companyId: ctx.companyId,
457
+ configuredCodexHome,
458
+ configuredApiKey,
459
+ });
460
+ if (credentialReadiness.ready && credentialReadiness.authMode === "api") {
461
+ checks.push({
462
+ code: "codex_acp_openai_api_key_detected",
463
+ level: "info",
464
+ message: "OPENAI_API_KEY is set for Codex ACP authentication.",
465
+ detail: `Detected in ${configApiKey ? "adapter config env" : "server environment"}.`,
466
+ });
467
+ }
468
+ else if (credentialReadiness.ready && !credentialReadiness.managed) {
469
+ checks.push({
470
+ code: "codex_acp_external_home_configured",
471
+ level: "info",
472
+ message: "Codex ACP will use an externally managed CODEX_HOME.",
473
+ detail: credentialReadiness.effectiveHome,
474
+ });
475
+ }
476
+ else if (credentialReadiness.ready) {
477
+ checks.push({
478
+ code: "codex_acp_native_auth_detected",
479
+ level: "info",
480
+ message: "Codex ACP can use Codex native authentication.",
481
+ detail: `Credentials are available through ${credentialReadiness.effectiveHome} or shared source ${credentialReadiness.sharedSourceHome}.`,
482
+ });
483
+ }
484
+ else {
485
+ checks.push({
486
+ code: "codex_acp_credentials_missing",
487
+ level: "warn",
488
+ message: "No Codex ACP credentials visible to the Paperclip server were detected.",
489
+ hint: "Set OPENAI_API_KEY in the agent adapter env, set it in the Paperclip server environment, or run `codex login` for the same OS user that runs the Paperclip server before starting a Codex ACP agent. A `/login` in a separate Codex/chat session does not authenticate the server.",
490
+ });
491
+ }
492
+ }
493
+ else if (targetIsSandbox) {
494
+ // The ACP Test does not probe the sandbox, so it predicts readiness from the
495
+ // credentials the Paperclip server can seed into the sandbox. The host
496
+ // environment is not seeded, so only the adapter config key counts here.
497
+ const configApiKey = isNonEmpty(envConfig.OPENAI_API_KEY) ? envConfig.OPENAI_API_KEY : null;
498
+ const configuredCodexHome = isNonEmpty(envConfig.CODEX_HOME) ? envConfig.CODEX_HOME : null;
499
+ const credentialReadiness = await evaluateCodexCredentialReadiness({
500
+ env: process.env,
501
+ companyId: ctx.companyId,
502
+ configuredCodexHome,
503
+ configuredApiKey: configApiKey,
504
+ });
505
+ if (!credentialReadiness.ready) {
506
+ // Emit the neutral canonical check so the user interface can decide login
507
+ // eligibility from a stable code. The user interface does not read the
508
+ // message text or the top-level status.
509
+ checks.push({
510
+ code: ADAPTER_AUTH_MISSING_CHECK_CODE,
511
+ level: "warn",
512
+ message: "This environment has no ready authentication for this adapter.",
513
+ hint: "Provide credentials for this adapter, or start login in the environment.",
514
+ });
515
+ }
516
+ }
517
+ const mode = firstNonEmptyString(config.mode, config.acpMode) ?? DEFAULT_ACP_ENGINE_MODE;
518
+ const warmHandleIdleMs = asNumber(config.warmHandleIdleMs ?? config.acpWarmHandleIdleMs, DEFAULT_ACP_ENGINE_WARM_HANDLE_IDLE_MS);
519
+ checks.push({
520
+ code: "codex_acp_runtime_scaffold",
521
+ level: "info",
522
+ message: "Codex ACP runtime execution is available through the shared ACP engine.",
523
+ detail: `mode=${mode}; warmHandleIdleMs=${warmHandleIdleMs}`,
524
+ });
525
+ return {
526
+ adapterType: ctx.adapterType,
527
+ status: summarizeStatus(checks),
528
+ checks,
529
+ testedAt: new Date().toISOString(),
530
+ };
531
+ }
532
+ //# sourceMappingURL=acp.js.map