@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,269 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { describe, expect, it } from "vitest";
5
+ import { parseDeviceLoginPrompt } from "./device-login-parse.js";
6
+ const fixturesDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "__fixtures__");
7
+ function readFixture(name) {
8
+ return readFileSync(path.join(fixturesDir, name), "utf8");
9
+ }
10
+ const EXACT_URL = "https://auth.openai.com/codex/device";
11
+ describe("parseDeviceLoginPrompt", () => {
12
+ it("parse_returns_url_and_code_from_sample", () => {
13
+ const result = parseDeviceLoginPrompt(readFixture("device-login-sample.txt"));
14
+ expect(result).not.toBeNull();
15
+ expect(result?.url).toBe(EXACT_URL);
16
+ // The committed sample keeps the capture-time redaction of the code. The
17
+ // parser extracts the four-hyphen-five structure without a real secret.
18
+ expect(result?.code).toBe("????-?????");
19
+ });
20
+ it("parse_returns_url_and_code_from_ansi_colored_output", () => {
21
+ // Codex CLI 0.128.0 and later add ANSI color (SGR) sequences around the URL
22
+ // and the code. A live sandbox run confirmed this format. The parser removes
23
+ // the Control Sequence Introducer sequences and reads the tokens the same as
24
+ // plain output.
25
+ const cyan = "\x1b[36m";
26
+ const bold = "\x1b[1m";
27
+ const reset = "\x1b[0m";
28
+ const text = [
29
+ "1. Open this link in your browser and sign in to your account",
30
+ `${cyan}${EXACT_URL}${reset}`,
31
+ "2. Enter this one-time code (expires in 15 minutes)",
32
+ `${bold}ABCD-EFGHJ${reset}`,
33
+ ].join("\n");
34
+ const result = parseDeviceLoginPrompt(text);
35
+ expect(result).not.toBeNull();
36
+ expect(result?.url).toBe(EXACT_URL);
37
+ expect(result?.code).toBe("ABCD-EFGHJ");
38
+ });
39
+ it("parse_returns_url_and_code_from_carriage_return_line_endings", () => {
40
+ // A pseudo-terminal ends each line with a carriage return and a line feed.
41
+ // The carriage return is whitespace, so the URL token stops before it, and the
42
+ // code line trims it. The parser reads the tokens the same as line-feed output.
43
+ const text = [
44
+ "1. Open this link in your browser and sign in to your account",
45
+ EXACT_URL,
46
+ "2. Enter this one-time code (expires in 15 minutes)",
47
+ "ABCD-EFGHJ",
48
+ ].join("\r\n");
49
+ const result = parseDeviceLoginPrompt(text);
50
+ expect(result).not.toBeNull();
51
+ expect(result?.url).toBe(EXACT_URL);
52
+ expect(result?.code).toBe("ABCD-EFGHJ");
53
+ });
54
+ it("parse_returns_url_and_code_with_a_terminal_title_osc_sequence", () => {
55
+ // A pseudo-terminal can emit an Operating System Command (OSC) title sequence
56
+ // in the stream. The device-auth prompt still prints the URL and the code as
57
+ // plain standalone tokens on their own lines. The OSC title sequence carries no
58
+ // URL token, so it does not shift the URL or the code, and the parser reads
59
+ // both tokens.
60
+ const osc = "\x1b]0;Codex\x07";
61
+ const text = [
62
+ `${osc}1. Open this link in your browser and sign in to your account`,
63
+ EXACT_URL,
64
+ "2. Enter this one-time code (expires in 15 minutes)",
65
+ "ABCD-EFGHJ",
66
+ ].join("\n");
67
+ const result = parseDeviceLoginPrompt(text);
68
+ expect(result).not.toBeNull();
69
+ expect(result?.url).toBe(EXACT_URL);
70
+ expect(result?.code).toBe("ABCD-EFGHJ");
71
+ });
72
+ it("parse_returns_url_and_code_from_a_merged_raw_pseudo_terminal_frame", () => {
73
+ // One buffer holds the whole prompt as a real pseudo-terminal emits it: a
74
+ // leading title Operating System Command (OSC) sequence, color Control
75
+ // Sequence Introducer (CSI) sequences around the URL and the code, and
76
+ // carriage-return line endings. The parser removes the color sequences and
77
+ // reads the plain tokens.
78
+ const title = "\x1b]0;Codex login\x07";
79
+ const cyan = "\x1b[36m";
80
+ const bold = "\x1b[1m";
81
+ const reset = "\x1b[0m";
82
+ const text = `${title}1. Open this link in your browser and sign in to your account\r\n` +
83
+ `${cyan}${EXACT_URL}${reset}\r\n` +
84
+ `2. Enter this one-time code (expires in 15 minutes)\r\n` +
85
+ `${bold}ABCD-EFGHJ${reset}\r\n`;
86
+ const result = parseDeviceLoginPrompt(text);
87
+ expect(result).not.toBeNull();
88
+ expect(result?.url).toBe(EXACT_URL);
89
+ expect(result?.code).toBe("ABCD-EFGHJ");
90
+ });
91
+ it("parse_returns_null_when_prompt_absent", () => {
92
+ const text = "Some unrelated log line\nNothing to see here\n";
93
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
94
+ });
95
+ it("parse_returns_null_for_url_with_query_or_fragment", () => {
96
+ const withQuery = [
97
+ "Open this link",
98
+ "https://auth.openai.com/codex/device?foo=bar",
99
+ "ABCD-EFGHJ",
100
+ ].join("\n");
101
+ const withFragment = [
102
+ "Open this link",
103
+ "https://auth.openai.com/codex/device#section",
104
+ "ABCD-EFGHJ",
105
+ ].join("\n");
106
+ expect(parseDeviceLoginPrompt(withQuery)).toBeNull();
107
+ expect(parseDeviceLoginPrompt(withFragment)).toBeNull();
108
+ });
109
+ it("parse_returns_the_printed_url_with_a_bare_trailing_fragment_marker", () => {
110
+ // A printed URL that ends with a bare `#` carries an empty fragment. The
111
+ // platform `URL` parser keeps the marker in its normalized form. The parser
112
+ // returns that normalized form, not the fixed constant.
113
+ const preamble = "2. Enter this one-time code (expires in 15 minutes)";
114
+ const text = [`${EXACT_URL}#`, preamble, "ABCD-EFGHJ"].join("\n");
115
+ const result = parseDeviceLoginPrompt(text);
116
+ expect(result).not.toBeNull();
117
+ expect(result?.url).toBe("https://auth.openai.com/codex/device#");
118
+ });
119
+ it("parse_returns_the_normalized_url_for_an_explicit_default_port_or_an_uppercase_host", () => {
120
+ // The platform `URL` parser normalizes an explicit default port and an
121
+ // uppercase host. The parser returns that normalized form.
122
+ const preamble = "2. Enter this one-time code (expires in 15 minutes)";
123
+ const withPort = [`${EXACT_URL.replace("auth.openai.com", "auth.openai.com:443")}`, preamble, "ABCD-EFGHJ"].join("\n");
124
+ const withUppercaseHost = [
125
+ `${EXACT_URL.replace("auth.openai.com", "AUTH.OPENAI.COM")}`,
126
+ preamble,
127
+ "ABCD-EFGHJ",
128
+ ].join("\n");
129
+ expect(parseDeviceLoginPrompt(withPort)?.url).toBe(EXACT_URL);
130
+ expect(parseDeviceLoginPrompt(withUppercaseHost)?.url).toBe(EXACT_URL);
131
+ });
132
+ it("parse_returns_null_for_wrong_origin_or_path", () => {
133
+ const wrongOrigin = [
134
+ "Open this link",
135
+ "https://auth.example.com/codex/device",
136
+ "ABCD-EFGHJ",
137
+ ].join("\n");
138
+ const wrongPath = [
139
+ "Open this link",
140
+ "https://auth.openai.com/codex/device/extra",
141
+ "ABCD-EFGHJ",
142
+ ].join("\n");
143
+ const httpScheme = [
144
+ "Open this link",
145
+ "http://auth.openai.com/codex/device",
146
+ "ABCD-EFGHJ",
147
+ ].join("\n");
148
+ expect(parseDeviceLoginPrompt(wrongOrigin)).toBeNull();
149
+ expect(parseDeviceLoginPrompt(wrongPath)).toBeNull();
150
+ expect(parseDeviceLoginPrompt(httpScheme)).toBeNull();
151
+ });
152
+ it("parse_returns_null_for_malformed_short_code", () => {
153
+ // Each input carries the code preamble after the URL, so the test exercises
154
+ // the code-structure check and not the preamble check.
155
+ const preamble = "2. Enter this one-time code (expires in 15 minutes)";
156
+ const shortCode = [EXACT_URL, preamble, "ABC-EFGHJ"].join("\n"); // 3 then 5
157
+ const longCode = [EXACT_URL, preamble, "ABCDE-EFGHJ"].join("\n"); // 5 then 5
158
+ const noHyphen = [EXACT_URL, preamble, "ABCDEFGHJ"].join("\n");
159
+ const noCode = [EXACT_URL, preamble, "no code on this line"].join("\n");
160
+ expect(parseDeviceLoginPrompt(shortCode)).toBeNull();
161
+ expect(parseDeviceLoginPrompt(longCode)).toBeNull();
162
+ expect(parseDeviceLoginPrompt(noHyphen)).toBeNull();
163
+ expect(parseDeviceLoginPrompt(noCode)).toBeNull();
164
+ });
165
+ it("parse_binds_code_to_url_and_ignores_a_code_before_the_url", () => {
166
+ // A code-shaped token appears before the URL. The parser reads the code only
167
+ // after the URL, so it uses the code that follows the URL.
168
+ const text = [
169
+ "WXYZ-98765",
170
+ "1. Open this link in your browser and sign in to your account",
171
+ EXACT_URL,
172
+ "2. Enter this one-time code (expires in 15 minutes)",
173
+ "ABCD-EFGHJ",
174
+ ].join("\n");
175
+ const result = parseDeviceLoginPrompt(text);
176
+ expect(result).not.toBeNull();
177
+ expect(result?.code).toBe("ABCD-EFGHJ");
178
+ });
179
+ it("parse_returns_null_when_only_code_is_before_the_url", () => {
180
+ // The only code-shaped token sits before the URL. No code follows the URL,
181
+ // so the parser rejects the output instead of binding the earlier token.
182
+ const text = ["WXYZ-98765", "Open this link", EXACT_URL].join("\n");
183
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
184
+ });
185
+ it("parse_returns_null_when_code_is_far_after_the_url", () => {
186
+ // A code-shaped token sits far below the URL, past the proximity window. The
187
+ // parser does not bind a distant token to the URL.
188
+ const filler = "unrelated log line\n".repeat(40);
189
+ const text = [EXACT_URL, filler, "ABCD-EFGHJ"].join("\n");
190
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
191
+ });
192
+ it("parse_ignores_a_code_between_the_url_and_the_code_preamble", () => {
193
+ // A code-shaped token sits after the URL but before the "one-time code"
194
+ // preamble line. The parser anchors the code on the preamble, so it ignores
195
+ // the earlier token and returns the real code after the preamble.
196
+ const text = [
197
+ "1. Open this link in your browser and sign in to your account",
198
+ EXACT_URL,
199
+ "session id WXYZ-98765 for this attempt",
200
+ "2. Enter this one-time code (expires in 15 minutes)",
201
+ "ABCD-EFGHJ",
202
+ ].join("\n");
203
+ const result = parseDeviceLoginPrompt(text);
204
+ expect(result).not.toBeNull();
205
+ expect(result?.code).toBe("ABCD-EFGHJ");
206
+ });
207
+ it("parse_ignores_a_code_that_shares_the_preamble_line", () => {
208
+ // A code-shaped token shares the preamble line with the "one-time code"
209
+ // phrase. The parser advances past the whole preamble line, so it ignores the
210
+ // token on that line and returns the code from the dedicated code line below.
211
+ const text = [
212
+ EXACT_URL,
213
+ "2. Enter this one-time code (ref WXYZ-98765, expires in 15 minutes)",
214
+ "ABCD-EFGHJ",
215
+ ].join("\n");
216
+ const result = parseDeviceLoginPrompt(text);
217
+ expect(result).not.toBeNull();
218
+ expect(result?.code).toBe("ABCD-EFGHJ");
219
+ });
220
+ it("parse_returns_null_when_a_noise_line_follows_the_preamble", () => {
221
+ // A line that mixes a code-shaped token with other text sits right after the
222
+ // preamble line. The parser reads the code only from a dedicated code line, so
223
+ // it never surfaces the embedded token. It rejects the output instead. This
224
+ // proves the parser binds the code to the prompt-code line and not to any
225
+ // nearby code-shaped token.
226
+ const text = [
227
+ EXACT_URL,
228
+ "2. Enter this one-time code (expires in 15 minutes)",
229
+ "your session token is WXYZ-98765 here",
230
+ "ABCD-EFGHJ",
231
+ ].join("\n");
232
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
233
+ });
234
+ it("parse_returns_null_when_the_code_preamble_is_absent", () => {
235
+ // A valid code follows the URL, but the "one-time code" preamble is absent.
236
+ // The parser requires the preamble, so it rejects the output. This binds the
237
+ // code to the prompt structure and not to a bare code-shaped token.
238
+ const text = [
239
+ "1. Open this link in your browser and sign in to your account",
240
+ EXACT_URL,
241
+ "ABCD-EFGHJ",
242
+ ].join("\n");
243
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
244
+ });
245
+ it("parse_ignores_token_like_text", () => {
246
+ // Token-like noise without the exact device URL must not yield a prompt.
247
+ const text = [
248
+ "tokens received",
249
+ "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.payload.signature",
250
+ "sk-proj-ABCD1234ABCD1234ABCD1234",
251
+ "ABCD-EFGHJ",
252
+ ].join("\n");
253
+ expect(parseDeviceLoginPrompt(text)).toBeNull();
254
+ });
255
+ it("parse_returns_null_for_edge_sample", () => {
256
+ // The grounded edge row carries a URL, but a wrong path and a wrong origin
257
+ // segment, so the parser rejects it.
258
+ expect(parseDeviceLoginPrompt(readFixture("device-login-edge.txt"))).toBeNull();
259
+ });
260
+ it("keeps the url and the code out of a thrown error", () => {
261
+ // A non-string input is a programming error, but the message must never
262
+ // carry secret-bearing input. The parser returns null instead of throwing.
263
+ // @ts-expect-error deliberate wrong type
264
+ expect(parseDeviceLoginPrompt(undefined)).toBeNull();
265
+ // @ts-expect-error deliberate wrong type
266
+ expect(parseDeviceLoginPrompt(12345)).toBeNull();
267
+ });
268
+ });
269
+ //# sourceMappingURL=device-login-parse.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login-parse.test.js","sourceRoot":"","sources":["../../src/server/device-login-parse.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ import { type LoginRunnerDisposable, type LoginRunnerLifecycleOptions, type LoginRunnerOutcome, type LoginRunnerResult } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ import { type DeviceLoginPrompt } from "./device-login-parse.js";
3
+ /** The default Codex device-login command. */
4
+ export declare const CODEX_DEVICE_LOGIN_COMMAND = "codex login --device-auth";
5
+ /**
6
+ * The sandbox side of the device-login run. The runner never calls Daytona
7
+ * directly; a caller injects a concrete driver. A production driver binds `start`
8
+ * to the shared login pseudo-terminal (PTY) transport, binds `readFile` to a
9
+ * descriptor-bound credential read, and binds `dispose` to the transport dispose.
10
+ *
11
+ * The `start` shape matches the shared login pseudo-terminal transport start
12
+ * method, so the driver runs the login command on a real pseudo-terminal. The
13
+ * login command
14
+ * needs a pseudo-terminal: pipe stdio emits no login prompt. The runner never
15
+ * calls `stop` or `write` on the driver; the device-login flow needs no delayed
16
+ * input, and the service owns the sandbox delete. The runner disposes the driver
17
+ * one time on every terminal state.
18
+ */
19
+ export interface SandboxLoginDriver extends LoginRunnerDisposable {
20
+ /**
21
+ * Starts `command` on a pseudo-terminal and streams the terminal output to
22
+ * `onData` in memory, in order, as the pseudo-terminal emits it. Resolves with
23
+ * the command exit code when the command ends. A driver must not persist the raw
24
+ * output to any durable log.
25
+ */
26
+ start(command: string, onData: (chunk: string) => void): Promise<{
27
+ exitCode: number | null;
28
+ }>;
29
+ /**
30
+ * Reads the credential bytes with one descriptor-bound read. The read is
31
+ * separate from the pseudo-terminal session; the session has no file-read
32
+ * method. A driver runs one fixed, server-controlled operation that opens the
33
+ * verified session home and the credential file with no symlink follow, checks
34
+ * the opened descriptor, and reads only from that same descriptor.
35
+ */
36
+ readFile(path: string): Promise<Buffer>;
37
+ }
38
+ /** Receives the parsed prompt one time in memory. The caller displays it. */
39
+ export type DeviceLoginPromptSink = (prompt: DeviceLoginPrompt) => void;
40
+ /** The device-login runner outcome. It is a fixed, non-secret status. */
41
+ export type DeviceLoginOutcome = LoginRunnerOutcome;
42
+ /** The runner result. It never carries a URL, a code, or a token byte. */
43
+ export type DeviceLoginResult = LoginRunnerResult;
44
+ export interface RunDeviceLoginOptions extends LoginRunnerLifecycleOptions {
45
+ /** The login command. Defaults to {@link CODEX_DEVICE_LOGIN_COMMAND}. */
46
+ command?: string;
47
+ /** Parses the prompt from the login output. Defaults to
48
+ * {@link parseDeviceLoginPrompt}. */
49
+ parsePrompt?: (output: string) => DeviceLoginPrompt | null;
50
+ /** Receives the parsed prompt one time in memory. The caller displays it. */
51
+ onPrompt: DeviceLoginPromptSink;
52
+ /**
53
+ * Receives the sandbox `auth.json` bytes one time in memory on success. The
54
+ * runner reads the bytes with {@link SandboxLoginDriver.readFile} before it
55
+ * disposes the driver. Set together with {@link authPath}.
56
+ */
57
+ onCredential?: (authBytes: Buffer) => void | Promise<void>;
58
+ /** The sandbox path of the credential file to read on success. */
59
+ authPath?: string;
60
+ }
61
+ /**
62
+ * Runs the device-login command through `driver`. Surfaces the prompt one time
63
+ * through `onPrompt`. On success it reads the credential and surfaces the bytes
64
+ * one time through `onCredential`. Returns a fixed status. Always disposes the
65
+ * driver. Never logs the raw stream, and never puts a URL, a code, or a token
66
+ * into a log line, the result, or a thrown error.
67
+ */
68
+ export declare function runDeviceLogin(driver: SandboxLoginDriver, options: RunDeviceLoginOptions): Promise<DeviceLoginResult>;
69
+ //# sourceMappingURL=device-login-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login-runner.d.ts","sourceRoot":"","sources":["../../src/server/device-login-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,yCAAyC,CAAC;AACjD,OAAO,EAA0B,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAiBzF,8CAA8C;AAC9C,eAAO,MAAM,0BAA0B,8BAA8B,CAAC;AAatE;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,kBAAmB,SAAQ,qBAAqB;IAC/D;;;;;OAKG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;IAC9F;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACzC;AAED,6EAA6E;AAC7E,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;AAExE,yEAAyE;AACzE,MAAM,MAAM,kBAAkB,GAAG,kBAAkB,CAAC;AAEpD,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,CAAC;AAElD,MAAM,WAAW,qBAAsB,SAAQ,2BAA2B;IACxE,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;0CACsC;IACtC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,GAAG,IAAI,CAAC;IAC3D,6EAA6E;IAC7E,QAAQ,EAAE,qBAAqB,CAAC;IAChC;;;;OAIG;IACH,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3D,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,kBAAkB,EAC1B,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CA0E5B"}
@@ -0,0 +1,109 @@
1
+ import { raceLoginRunnerExit, } from "@tickernelz/paperclip-pro-adapter-utils";
2
+ import { parseDeviceLoginPrompt } from "./device-login-parse.js";
3
+ // The device-login runner. It runs the Codex device-login command through an
4
+ // injected {@link SandboxLoginDriver}, surfaces the login prompt one time in
5
+ // memory, and handles a timeout and a cancellation. The runner always disposes
6
+ // the driver.
7
+ //
8
+ // Security (Control 1 — secret handling): the runner treats every byte of the
9
+ // sandbox stream as secret-bearing, untrusted input. It parses the stream in an
10
+ // in-memory buffer only. It drops the buffer as soon as it finds the prompt. It
11
+ // never forwards the raw text to a log or an artifact, and it never stores the
12
+ // raw text on the result. The runner reports only a fixed, non-secret status. It
13
+ // passes the prompt one time through the in-memory `onPrompt` callback. It passes
14
+ // the credential bytes one time through the in-memory `onCredential` callback.
15
+ // The runner keeps the URL, the code, and any token byte out of every log line
16
+ // and every thrown error.
17
+ /** The default Codex device-login command. */
18
+ export const CODEX_DEVICE_LOGIN_COMMAND = "codex login --device-auth";
19
+ /**
20
+ * The maximum number of characters the runner keeps for the next chunk. The
21
+ * Codex prompt is small and puts the URL and the code close together. A sandbox
22
+ * can stream a large volume of output before the prompt. So after each parse the
23
+ * runner keeps only the most recent characters up to this limit. The retained
24
+ * buffer cannot grow without a bound across many chunks. The limit is far larger
25
+ * than the prompt, so the trailing window never drops a real prompt that spans a
26
+ * chunk boundary.
27
+ */
28
+ const MAX_PARSE_BUFFER_CHARS = 64 * 1024;
29
+ /**
30
+ * Runs the device-login command through `driver`. Surfaces the prompt one time
31
+ * through `onPrompt`. On success it reads the credential and surfaces the bytes
32
+ * one time through `onCredential`. Returns a fixed status. Always disposes the
33
+ * driver. Never logs the raw stream, and never puts a URL, a code, or a token
34
+ * into a log line, the result, or a thrown error.
35
+ */
36
+ export async function runDeviceLogin(driver, options) {
37
+ const { onPrompt, onCredential, authPath, timeoutMs, signal } = options;
38
+ const command = options.command ?? CODEX_DEVICE_LOGIN_COMMAND;
39
+ const parsePrompt = options.parsePrompt ?? parseDeviceLoginPrompt;
40
+ const log = options.log ?? (() => { });
41
+ let promptSurfaced = false;
42
+ // The in-memory parse buffer. The runner drops it as soon as it finds the
43
+ // prompt, so the secret-bearing stream never lives longer than one parse. The
44
+ // runner parses the full buffer, and it includes the whole new chunk. So a
45
+ // prompt at the start of one large chunk still parses. The runner bounds only
46
+ // the buffer that it keeps for the next chunk to {@link MAX_PARSE_BUFFER_CHARS}.
47
+ // The runner keeps the trailing window and drops the oldest characters. The
48
+ // prompt puts the URL and the code close together, so the trailing window
49
+ // always holds a real prompt that spans a chunk boundary.
50
+ let buffer = "";
51
+ const onStdout = (chunk) => {
52
+ if (promptSurfaced)
53
+ return;
54
+ buffer += chunk;
55
+ const prompt = parsePrompt(buffer);
56
+ if (prompt) {
57
+ promptSurfaced = true;
58
+ buffer = "";
59
+ onPrompt(prompt);
60
+ return;
61
+ }
62
+ if (buffer.length > MAX_PARSE_BUFFER_CHARS) {
63
+ buffer = buffer.slice(buffer.length - MAX_PARSE_BUFFER_CHARS);
64
+ }
65
+ };
66
+ try {
67
+ if (signal?.aborted) {
68
+ log("[paperclip] Device login cancelled before start.");
69
+ return { outcome: "cancelled", exitCode: null, promptSurfaced };
70
+ }
71
+ const started = driver.start(command, onStdout);
72
+ const raced = await raceLoginRunnerExit(started, timeoutMs, signal);
73
+ if (raced.kind === "timeout") {
74
+ log("[paperclip] Device login timed out; disposing the sandbox.");
75
+ return { outcome: "timeout", exitCode: null, promptSurfaced };
76
+ }
77
+ if (raced.kind === "cancelled") {
78
+ log("[paperclip] Device login cancelled; disposing the sandbox.");
79
+ return { outcome: "cancelled", exitCode: null, promptSurfaced };
80
+ }
81
+ const exitCode = raced.exitCode;
82
+ if (exitCode !== 0) {
83
+ log("[paperclip] Device login command ended with a non-zero exit code.");
84
+ return { outcome: "failure", exitCode, promptSurfaced };
85
+ }
86
+ if (onCredential && authPath) {
87
+ const authBytes = await driver.readFile(authPath);
88
+ await onCredential(authBytes);
89
+ }
90
+ log("[paperclip] Device login command ended successfully.");
91
+ return { outcome: "success", exitCode, promptSurfaced };
92
+ }
93
+ catch {
94
+ // Convert any driver error to a fixed, non-secret error. The original error
95
+ // may embed streamed bytes, so the runner never propagates its message.
96
+ throw new Error("device login failed: the sandbox login command errored.");
97
+ }
98
+ finally {
99
+ // Always dispose the driver. A dispose error must not leak or mask the
100
+ // result, so the runner swallows it and logs a fixed line.
101
+ try {
102
+ await driver.dispose();
103
+ }
104
+ catch {
105
+ log("[paperclip] Device login: the sandbox dispose step errored.");
106
+ }
107
+ }
108
+ }
109
+ //# sourceMappingURL=device-login-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login-runner.js","sourceRoot":"","sources":["../../src/server/device-login-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=device-login-runner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login-runner.test.d.ts","sourceRoot":"","sources":["../../src/server/device-login-runner.test.ts"],"names":[],"mappings":""}