@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,501 @@
1
+ import { lstat, mkdir, open, readFile, rename, rm } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { resolvePaperclipInstanceRootForAdapter } from "@tickernelz/paperclip-pro-adapter-utils/server-utils";
5
+ import { withDirectoryMergeLock } from "@tickernelz/paperclip-pro-adapter-utils/workspace-restore-merge";
6
+ import { toAccountHandle } from "@tickernelz/paperclip-pro-shared";
7
+ import { USE_SOURCE_EXIT, decideCodexAuthMerge } from "./codex-auth-merge-decision.js";
8
+ import { writeCredentialSeedOrNewer } from "./codex-auth-seed-write.js";
9
+ // The identity-keyed host credential store keeps one usable subscription
10
+ // credential per identity (`account_id`) in a SEPARATE host tree, outside the
11
+ // shared Codex home and outside the symlink allowlist. Each identity's entry
12
+ // directory doubles as that account's addressable home: the device-login
13
+ // promotion writes the durable credential there, and a company secret names the
14
+ // directory by path. The store also still backs the identity-anchored vend: it
15
+ // never changes the copy-back path, the fail-closed decision predicate, or the
16
+ // host default store overwrite, it only refreshes an identity the host already
17
+ // holds, it never seeds an empty host store, and it never picks a credential at
18
+ // random.
19
+ const CACHE_DIR_NAME = "codex-auth-cache";
20
+ const CACHE_ENTRY_FILE = "auth.json";
21
+ // A private directory (owner rwx only). 0o700 has no group/other bits, so a
22
+ // standard umask can never widen it.
23
+ const PRIVATE_DIR_MODE = 0o700;
24
+ // One default-on off-switch. When the flag is an explicit falsy value the cache
25
+ // write and the cache vend become no-ops. The host default overwrite is
26
+ // unchanged in both states.
27
+ export const CODEX_AUTH_CACHE_OFF_SWITCH_ENV = "PAPERCLIP_CODEX_AUTH_CACHE";
28
+ const FALSY_ENV_RE = /^(0|false|no|off)$/i;
29
+ // The cache reuses the same direction-agnostic decision predicate the copy-back
30
+ // and inbound restore run, through the shared `decideCodexAuthMerge` entry point.
31
+ // The predicate answers one question — "should the caller replace `destination`
32
+ // with `source`?" — purely by argument order (first = source, second =
33
+ // destination). Exit 10 = use source; exit 20 = keep destination. The opt-in seed
34
+ // mode fills an ABSENT destination slot from a usable subscription source.
35
+ function nonEmpty(value) {
36
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
37
+ }
38
+ /**
39
+ * True when the cache is enabled. The cache is on by default. It turns off only
40
+ * when {@link CODEX_AUTH_CACHE_OFF_SWITCH_ENV} is an explicit falsy value
41
+ * (`0`, `false`, `no`, or `off`).
42
+ */
43
+ export function isCodexAuthCacheEnabled(env = process.env) {
44
+ const raw = env[CODEX_AUTH_CACHE_OFF_SWITCH_ENV];
45
+ if (typeof raw !== "string")
46
+ return true;
47
+ return !FALSY_ENV_RE.test(raw.trim());
48
+ }
49
+ /**
50
+ * Sanitizes one raw value to a single safe path segment. Rejects an empty value,
51
+ * a relative segment (`.` or `..`), a path separator (`/` or `\`), and a NUL
52
+ * byte, so the value can never become a path traversal. Returns the trimmed,
53
+ * safe segment. The `label` names the value in the error message. (Security
54
+ * condition 3.)
55
+ */
56
+ function toSafePathSegment(value, label) {
57
+ const trimmed = typeof value === "string" ? value.trim() : "";
58
+ if (trimmed.length === 0) {
59
+ throw new Error(`codex auth cache: ${label} is empty`);
60
+ }
61
+ if (trimmed === "." || trimmed === "..") {
62
+ throw new Error(`codex auth cache: ${label} is a relative path segment`);
63
+ }
64
+ if (trimmed.includes("/") || trimmed.includes("\\") || trimmed.includes("\0")) {
65
+ throw new Error(`codex auth cache: ${label} contains a path separator`);
66
+ }
67
+ // Defense in depth: a safe segment is exactly its own basename. Anything else
68
+ // carries a separator or a relative segment the checks above must have caught.
69
+ if (path.basename(trimmed) !== trimmed) {
70
+ throw new Error(`codex auth cache: ${label} is not a single path segment`);
71
+ }
72
+ return trimmed;
73
+ }
74
+ /**
75
+ * Sanitizes an `account_id` to one safe path segment. Rejects an empty value, a
76
+ * relative segment (`.` or `..`), a path separator, and a NUL byte, so a raw
77
+ * `account_id` can never become a path traversal. Returns the trimmed, safe
78
+ * segment. (Security condition 3.)
79
+ */
80
+ export function toCacheKey(accountId) {
81
+ return toSafePathSegment(accountId, "account_id");
82
+ }
83
+ /**
84
+ * Resolves the company-scoped cache root under the same isolation boundary as
85
+ * the managed Codex home (`resolveManagedCodexHomeDir`). The root is always
86
+ * company-scoped, so a Codex credential can never cross a company boundary.
87
+ * There is no instance-global fallback root: `companyId` is required, and an
88
+ * empty value is a fail-loud error. `companyId` is sanitized to a single safe
89
+ * path segment, so a traversal value (`..`, `/etc`, `a/b`) can never make the
90
+ * cache root escape the `companies/` directory. Every downstream path (the
91
+ * entry path, the vend, and the clear) inherits this guard. (Security
92
+ * condition 1.)
93
+ */
94
+ export function resolveCodexAuthCacheDir(env = process.env, companyId) {
95
+ const safeCompanyId = toSafePathSegment(companyId, "companyId");
96
+ const instanceRoot = resolvePaperclipInstanceRootForAdapter({
97
+ homeDir: nonEmpty(env.PAPERCLIP_HOME) ?? undefined,
98
+ instanceId: nonEmpty(env.PAPERCLIP_INSTANCE_ID) ?? undefined,
99
+ env,
100
+ });
101
+ return path.resolve(instanceRoot, "companies", safeCompanyId, CACHE_DIR_NAME);
102
+ }
103
+ /**
104
+ * True when `homePath` sits inside the per-identity credential store of ANY
105
+ * company: `<instanceRoot>/companies/<id>/codex-auth-cache/…` (or is a store
106
+ * root itself). These directories are identity-anchored slots owned by the
107
+ * device-login promotion, the vend, and the copy-back, each under its own
108
+ * lock. The managed-home seeding pass consults this to refuse to symlink,
109
+ * heal, or overwrite an entry's `auth.json`: an agent may bind `CODEX_HOME`
110
+ * to an entry (through the login's account-home secret), and seeding it like
111
+ * an ordinary managed home would silently swap the bound account's durable
112
+ * credential for the host login.
113
+ */
114
+ export function isCodexAuthCachePath(env, homePath) {
115
+ const instanceRoot = resolvePaperclipInstanceRootForAdapter({
116
+ homeDir: nonEmpty(env.PAPERCLIP_HOME) ?? undefined,
117
+ instanceId: nonEmpty(env.PAPERCLIP_INSTANCE_ID) ?? undefined,
118
+ env,
119
+ });
120
+ const companiesRoot = path.resolve(instanceRoot, "companies");
121
+ const resolved = path.resolve(homePath);
122
+ if (!resolved.startsWith(companiesRoot + path.sep))
123
+ return false;
124
+ const segments = resolved.slice(companiesRoot.length + 1).split(path.sep);
125
+ return segments.length >= 2 && segments[1] === CACHE_DIR_NAME;
126
+ }
127
+ /**
128
+ * Resolves the entry path for one identity: `<cacheRoot>/<safeAccountId>/auth.json`.
129
+ * The `account_id` is validated first by {@link toAccountHandle} (a strict
130
+ * allowlist), the entry point of this function, then sanitized again by
131
+ * {@link toCacheKey} (a denylist) as a second, independent layer. After the
132
+ * join, this verifies the resolved entry path stays under the cache root and
133
+ * ends at exactly `<safeAccountId>/auth.json`. This function does no filesystem
134
+ * work; it is safe for a read path (the vend and the clear). (Security
135
+ * condition 3.)
136
+ */
137
+ export function resolveCodexAuthCacheEntryPath(env = process.env, accountId, companyId) {
138
+ const handle = toAccountHandle(accountId);
139
+ if (!handle) {
140
+ throw new Error("codex auth cache: account_id is not a valid account handle");
141
+ }
142
+ const resolvedRoot = resolveCodexAuthCacheDir(env, companyId);
143
+ const safeKey = toCacheKey(handle);
144
+ const entryDir = path.resolve(resolvedRoot, safeKey);
145
+ const entryPath = path.resolve(entryDir, CACHE_ENTRY_FILE);
146
+ const expectedEntryPath = path.join(resolvedRoot, safeKey, CACHE_ENTRY_FILE);
147
+ if (!entryDir.startsWith(resolvedRoot + path.sep) ||
148
+ path.dirname(entryDir) !== resolvedRoot ||
149
+ entryPath !== expectedEntryPath) {
150
+ throw new Error("codex auth cache: resolved entry path escapes the cache root");
151
+ }
152
+ return entryPath;
153
+ }
154
+ /**
155
+ * Ensures one directory exists and is private (mode 0700). Fails closed with
156
+ * `lstat` (not `stat`) when the existing path is a symlink or a non-directory,
157
+ * so the cache never writes through a planted symlink. (Security condition 3.)
158
+ */
159
+ async function ensurePrivateDir(dir) {
160
+ const existing = await lstat(dir).catch((error) => {
161
+ if (error.code === "ENOENT")
162
+ return null;
163
+ throw error;
164
+ });
165
+ if (existing) {
166
+ if (existing.isSymbolicLink() || !existing.isDirectory()) {
167
+ throw new Error("codex auth cache: cache path is a symlink or a non-directory");
168
+ }
169
+ return;
170
+ }
171
+ await mkdir(dir, { recursive: true, mode: PRIVATE_DIR_MODE });
172
+ }
173
+ /**
174
+ * Resolves the entry path and creates the cache root and the entry directory
175
+ * private (mode 0700), each guarded by `lstat`. The `account_id` is validated
176
+ * at the entry point of this function through {@link resolveCodexAuthCacheEntryPath}.
177
+ * Use this on the write path before the entry is written.
178
+ */
179
+ export async function ensureCodexAuthCacheEntryDir(env = process.env, accountId, companyId) {
180
+ const entryPath = resolveCodexAuthCacheEntryPath(env, accountId, companyId);
181
+ await ensurePrivateDir(resolveCodexAuthCacheDir(env, companyId));
182
+ await ensurePrivateDir(path.dirname(entryPath));
183
+ return entryPath;
184
+ }
185
+ /**
186
+ * Same as {@link ensureCodexAuthCacheEntryDir}, but the absence check and the
187
+ * directory creation run inside one lock keyed to the company-scoped cache
188
+ * root. Two different logins for the SAME Codex account can promote at the
189
+ * same time (each login owns its own promotion slot), so a plain
190
+ * check-then-create sequence lets both concurrent callers see the slot as
191
+ * absent and both report `created: true`. Under this lock, only the caller
192
+ * that truly finds the slot absent gets `created: true`; the other caller
193
+ * correctly reports `created: false` and so never deletes a home the first
194
+ * caller's login already wrote to and named with a company secret.
195
+ */
196
+ export async function ensureCodexAuthCacheEntryDirExclusive(env = process.env, accountId, companyId) {
197
+ const cacheRoot = resolveCodexAuthCacheDir(env, companyId);
198
+ await ensurePrivateDir(cacheRoot);
199
+ return withDirectoryMergeLock(cacheRoot, async () => {
200
+ const entryPath = resolveCodexAuthCacheEntryPath(env, accountId, companyId);
201
+ const entryDir = path.dirname(entryPath);
202
+ const created = await lstat(entryDir)
203
+ .then(() => false)
204
+ .catch((error) => {
205
+ if (error.code === "ENOENT")
206
+ return true;
207
+ throw error;
208
+ });
209
+ await ensurePrivateDir(entryDir);
210
+ return { entryPath, created };
211
+ }, env);
212
+ }
213
+ /**
214
+ * Resolves a per-company, named lock target directory under the same
215
+ * instance-scoped `companies/<companyId>/` tree the cache root and the
216
+ * promotion lock use. Two callers that pass the same `lockName` for the same
217
+ * `companyId` always resolve the same directory, so they share one lock; two
218
+ * different `lockName` values never share a lock key, so a caller that holds
219
+ * one of these named locks can still call {@link ensureCodexAuthCacheEntryDirExclusive}
220
+ * (which locks the cache root) or another named lock without nesting a lock
221
+ * inside itself.
222
+ */
223
+ function resolveCodexAuthCacheNamedLockDir(env = process.env, companyId, lockName) {
224
+ const safeCompanyId = toSafePathSegment(companyId, "companyId");
225
+ const instanceRoot = resolvePaperclipInstanceRootForAdapter({
226
+ homeDir: nonEmpty(env.PAPERCLIP_HOME) ?? undefined,
227
+ instanceId: nonEmpty(env.PAPERCLIP_INSTANCE_ID) ?? undefined,
228
+ env,
229
+ });
230
+ return path.resolve(instanceRoot, "companies", safeCompanyId, lockName);
231
+ }
232
+ /**
233
+ * Serializes one company's whole device-login promotion sequence: the
234
+ * account-home directory create-or-reuse decision, the credential write, and
235
+ * the secret bind or cleanup that follows. Two different logins for the SAME
236
+ * Codex account run this sequence one at a time under this lock, so no login
237
+ * can decide to delete the shared account-home directory while another
238
+ * login's flow is still mid-way through writing its credential or binding
239
+ * its own secret to that same directory.
240
+ *
241
+ * `ensureCodexAuthCacheEntryDirExclusive` alone is not enough: it locks only
242
+ * the short directory-creation step, so its lock is already released by the
243
+ * time a login reaches the secret bind. A second login can then write its
244
+ * credential and be about to bind its own secret while the first login's
245
+ * later, unrelated secret-write failure decides to remove the directory both
246
+ * logins now share, deleting a credential home the second login still needs.
247
+ * Holding this lock across the full sequence for every login closes that
248
+ * window: a login that must clean up its own directory always finishes that
249
+ * cleanup, including the directory-recreation of any later login that lands
250
+ * on the now-empty slot, before the next login's sequence starts.
251
+ */
252
+ export async function withCodexAccountHomePromotionLock(env = process.env, companyId, fn) {
253
+ const lockDir = resolveCodexAuthCacheNamedLockDir(env, companyId, "codex-auth-cache-promotion-lock");
254
+ await ensurePrivateDir(lockDir);
255
+ return withDirectoryMergeLock(lockDir, fn, env);
256
+ }
257
+ /**
258
+ * Serializes one company's writes to the literal value of any
259
+ * `local_encrypted` company secret against the account-home cleanup's
260
+ * claimant scan in {@link withCodexAccountHomePromotionLock}'s caller. Only a
261
+ * `local_encrypted` secret can hold a literal directory path, so this is the
262
+ * one provider a cleanup claimant scan must trust. Without this lock, a
263
+ * secret create or rotation can commit its new value after the scan's last
264
+ * pass finds no claimant but before the cleanup deletes the directory: the
265
+ * scan and the write never observe each other, so the write's new value
266
+ * survives past a directory the delete has already removed.
267
+ *
268
+ * The secrets service holds this lock for the full duration of a
269
+ * `local_encrypted` secret's create or rotate call. A cleanup claimant scan
270
+ * holds it for the full duration of its final check-and-delete step. The two
271
+ * critical sections can then never interleave: a write that starts first
272
+ * finishes (and becomes visible to the scan) before the scan's lock-holding
273
+ * check runs, and a write that starts after the scan's lock-holding check
274
+ * finishes only commits once the scan (and any delete it decided on) is
275
+ * done, so it can never name a directory the delete just removed without the
276
+ * scan having had a chance to see it first.
277
+ *
278
+ * This is a separate lock directory from
279
+ * {@link withCodexAccountHomePromotionLock}'s, so a device-login promotion
280
+ * (which holds that lock for its whole sequence, including its own secret
281
+ * create) can still call into a secrets-service write that takes this lock
282
+ * without deadlocking on itself.
283
+ */
284
+ export async function withAccountHomeSecretMutationLock(env = process.env, companyId, fn) {
285
+ const lockDir = resolveCodexAuthCacheNamedLockDir(env, companyId, "codex-account-home-secret-mutation-lock");
286
+ await ensurePrivateDir(lockDir);
287
+ return withDirectoryMergeLock(lockDir, fn, env);
288
+ }
289
+ /**
290
+ * Confirms a `local_encrypted` secret value that names a directory under this
291
+ * company's Codex account-home cache root still exists on disk. Call this
292
+ * inside {@link withAccountHomeSecretMutationLock}, before a create or a
293
+ * rotate commits the value.
294
+ *
295
+ * The lock alone stops a write and the account-home cleanup's
296
+ * check-and-delete from interleaving; it does not stop them from running in
297
+ * either order. When the cleanup's check-and-delete runs first — it finds no
298
+ * secret names the directory, because this write had not committed yet, and
299
+ * removes the directory — a write that was only queued behind the lock still
300
+ * goes on, once the lock frees, to commit the very directory the cleanup
301
+ * just removed. That would leave an active secret naming a directory that
302
+ * does not exist. This check closes that window: a write whose value would
303
+ * name a directory the cleanup already removed fails instead of committing.
304
+ *
305
+ * A value outside this company's cache root is left alone. Only a value
306
+ * under the cache root can ever be an account-home directory, so this never
307
+ * rejects an unrelated `local_encrypted` secret write, such as an API key or
308
+ * a hand-typed token.
309
+ */
310
+ export async function assertAccountHomeCacheDirStillValid(env = process.env, companyId, value) {
311
+ const cacheRoot = resolveCodexAuthCacheDir(env, companyId);
312
+ if (!value.startsWith(cacheRoot + path.sep))
313
+ return;
314
+ const exists = await lstat(value)
315
+ .then(() => true)
316
+ .catch((error) => {
317
+ if (error.code === "ENOENT")
318
+ return false;
319
+ throw error;
320
+ });
321
+ if (!exists) {
322
+ throw new Error("codex auth cache: account-home directory no longer exists; refusing to write a secret that names it");
323
+ }
324
+ }
325
+ /**
326
+ * Reads the usable subscription `account_id` from an `auth.json` payload. Returns
327
+ * `null` for an absent, unusable, or api-key credential (no subscription
328
+ * identity). This mirrors `parseAuth` in `codex-auth-merge-decision.cjs`; keep
329
+ * the two in step when the auth format changes.
330
+ *
331
+ * The returned value is the exact, untrimmed `account_id` string. A caller
332
+ * passes it on to {@link toAccountHandle} unchanged: that function is the
333
+ * one place that decides whether surrounding whitespace is acceptable, and it
334
+ * must see the raw value to reject an identifier that differs from another
335
+ * one only by whitespace. Trimming here, before that check runs, would let
336
+ * two distinct identifiers collapse onto the same account handle.
337
+ */
338
+ export function readSubscriptionAccountId(bytes) {
339
+ let parsed;
340
+ try {
341
+ parsed = JSON.parse(bytes.toString("utf8"));
342
+ }
343
+ catch {
344
+ return null;
345
+ }
346
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
347
+ return null;
348
+ }
349
+ const record = parsed;
350
+ const apiKey = record.OPENAI_API_KEY;
351
+ if (typeof apiKey === "string" && apiKey.trim().length > 0) {
352
+ return null;
353
+ }
354
+ const tokens = record.tokens;
355
+ if (tokens === null || typeof tokens !== "object" || Array.isArray(tokens)) {
356
+ return null;
357
+ }
358
+ const tokenRecord = tokens;
359
+ const rawAccountId = typeof tokenRecord.account_id === "string" ? tokenRecord.account_id : "";
360
+ // A blank-or-whitespace-only value is absent; a value with real content
361
+ // keeps its exact, untrimmed form.
362
+ const accountId = rawAccountId.trim().length > 0 ? rawAccountId : "";
363
+ const hasTokenMaterial = ["id_token", "access_token", "refresh_token"].some((key) => {
364
+ const value = tokenRecord[key];
365
+ return typeof value === "string" && value.trim().length > 0;
366
+ });
367
+ if (!accountId || !hasTokenMaterial) {
368
+ return null;
369
+ }
370
+ return accountId;
371
+ }
372
+ /**
373
+ * Writes `sandboxAuthBytes` into its per-identity cache slot when the slot is
374
+ * absent, or when the source is a strictly-newer same-identity subscription
375
+ * credential (seed mode). The mutation runs under the merge lock on the slot
376
+ * directory, through the shared {@link writeCredentialSeedOrNewer} writer. Never
377
+ * logs token bytes or a raw `account_id`.
378
+ */
379
+ export async function writeCodexAuthCacheEntry(input) {
380
+ const outcome = await writeCredentialSeedOrNewer({
381
+ sourceBytes: input.sandboxAuthBytes,
382
+ destinationPath: input.cacheEntryPath,
383
+ seedIfDestAbsent: true,
384
+ log: input.log,
385
+ writtenLine: "[paperclip] Codex auth cache: wrote the per-identity cache slot at mode 0600.",
386
+ keptLine: "[paperclip] Codex auth cache: kept the cache slot (source is not a strictly-newer same-identity subscription credential).",
387
+ tempPrefix: "auth.json.cache-source",
388
+ errorLabel: "codex auth cache",
389
+ env: input.env,
390
+ });
391
+ return outcome === "written" ? "written" : "kept-slot";
392
+ }
393
+ /**
394
+ * Refreshes the identity the host already holds with a strictly-newer cached
395
+ * credential of the same `account_id`. Identity-anchored:
396
+ *
397
+ * 1. Read the host identity from `sharedHomeAuthPath` first.
398
+ * 2. When the host holds no usable subscription identity, do nothing. The vend
399
+ * never picks a credential from the cache at random (matrix rows 3, 4).
400
+ * 3. Resolve ONLY that exact identity's cache slot. The vend never scans the
401
+ * cache root. (Security condition 4.)
402
+ * 4. Run the DEFAULT-mode predicate (cache slot as source, shared home as
403
+ * destination). Install the cache copy only when it is strictly newer for the
404
+ * same identity.
405
+ *
406
+ * The vend never changes identity and never stages a spent single-use refresh
407
+ * token (the strictly-newer rule guards it). Never logs token bytes or a raw
408
+ * `account_id`.
409
+ */
410
+ export async function selectVendCredential(sharedHomeAuthPath, resolveCacheEntryPath, log, env = process.env) {
411
+ const hostBytes = await readFile(sharedHomeAuthPath).catch((error) => {
412
+ if (error.code === "ENOENT")
413
+ return null;
414
+ throw error;
415
+ });
416
+ const hostAccountId = hostBytes ? readSubscriptionAccountId(hostBytes) : null;
417
+ if (!hostAccountId) {
418
+ // No host identity: the vend does nothing (identity-anchor rule).
419
+ return "no-host-identity";
420
+ }
421
+ let cacheEntryPath;
422
+ try {
423
+ cacheEntryPath = resolveCacheEntryPath(hostAccountId);
424
+ }
425
+ catch {
426
+ // A host identity that cannot form a safe cache key never vends.
427
+ return "no-host-identity";
428
+ }
429
+ const hostDir = path.dirname(sharedHomeAuthPath);
430
+ return withDirectoryMergeLock(hostDir, async () => {
431
+ // Read the cached bytes under the lock, then stage exactly those bytes into a
432
+ // private (0600) temp next to the host target. The predicate reads the temp,
433
+ // so the vend installs exactly the bytes the predicate approved. This closes
434
+ // the read-after-validate skew: a separate reader of `cacheEntryPath` could
435
+ // otherwise see different bytes than the ones installed. The rename over the
436
+ // host target stays device-local and atomic.
437
+ const cacheBytes = await readFile(cacheEntryPath).catch((error) => {
438
+ if (error.code === "ENOENT")
439
+ return null;
440
+ throw error;
441
+ });
442
+ if (!cacheBytes) {
443
+ await log("[paperclip] Codex auth cache: no cached credential for the host identity; host credential kept.");
444
+ return "kept-host";
445
+ }
446
+ const stagedTempPath = path.join(hostDir, `.auth.json.vend-${process.pid}-${randomUUID()}.tmp`);
447
+ const handle = await open(stagedTempPath, "wx", 0o600);
448
+ try {
449
+ await handle.writeFile(cacheBytes);
450
+ await handle.close();
451
+ // Default-mode predicate: install the cache copy only when it is strictly
452
+ // newer for the SAME identity. Same-identity + strictly-newer keeps the
453
+ // change additive and semantics-preserving.
454
+ const decision = await decideCodexAuthMerge(stagedTempPath, sharedHomeAuthPath, {
455
+ errorLabel: "codex auth cache",
456
+ });
457
+ if (decision === USE_SOURCE_EXIT) {
458
+ await rename(stagedTempPath, sharedHomeAuthPath);
459
+ await log("[paperclip] Codex auth cache: refreshed the host credential with a strictly-newer cached copy of the same identity at mode 0600.");
460
+ return "vended";
461
+ }
462
+ await log("[paperclip] Codex auth cache: host credential kept (the cached copy is not strictly newer for the same identity).");
463
+ return "kept-host";
464
+ }
465
+ finally {
466
+ await handle.close().catch(() => undefined);
467
+ await rm(stagedTempPath, { force: true }).catch(() => undefined);
468
+ }
469
+ }, env);
470
+ }
471
+ /**
472
+ * Removes exactly one identity slot from the cache. The `account_id` is
473
+ * sanitized by {@link toCacheKey}, so the removal can never escape the cache
474
+ * root. A missing slot is a benign no-op. Any other removal error is fail-loud.
475
+ */
476
+ export async function clearCodexAuthCacheEntry(env = process.env, accountId, companyId) {
477
+ const entryPath = resolveCodexAuthCacheEntryPath(env, accountId, companyId);
478
+ const entryDir = path.dirname(entryPath);
479
+ // A missing slot is a benign no-op. Pre-check before the lock: the merge lock
480
+ // sits next to the slot under the cache root, so locking a slot whose cache
481
+ // root does not exist would fail on the lock directory itself.
482
+ const existing = await lstat(entryDir).catch((error) => {
483
+ if (error.code === "ENOENT")
484
+ return null;
485
+ throw error;
486
+ });
487
+ if (!existing)
488
+ return;
489
+ await withDirectoryMergeLock(entryDir, async () => {
490
+ await rm(entryDir, { recursive: true, force: true });
491
+ }, env);
492
+ }
493
+ /**
494
+ * Removes every slot in the company-scoped cache root. A missing cache root is a
495
+ * benign no-op.
496
+ */
497
+ export async function clearCodexAuthCache(env = process.env, companyId) {
498
+ const cacheDir = resolveCodexAuthCacheDir(env, companyId);
499
+ await rm(cacheDir, { recursive: true, force: true });
500
+ }
501
+ //# sourceMappingURL=codex-auth-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-auth-cache.js","sourceRoot":"","sources":["../../src/server/codex-auth-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=codex-auth-cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-auth-cache.test.d.ts","sourceRoot":"","sources":["../../src/server/codex-auth-cache.test.ts"],"names":[],"mappings":""}