@code-yeongyu/senpi 2026.8.18-3 → 2026.8.19

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 (353) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +4 -0
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +33 -4
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +293 -55
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  11. package/dist/core/compaction/branch-summarization.js +3 -0
  12. package/dist/core/compaction/branch-summarization.js.map +1 -1
  13. package/dist/core/compaction/compaction.d.ts +20 -3
  14. package/dist/core/compaction/compaction.d.ts.map +1 -1
  15. package/dist/core/compaction/compaction.js +182 -52
  16. package/dist/core/compaction/compaction.js.map +1 -1
  17. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts +3 -0
  18. package/dist/core/extensions/builtin/claude-sdk-oauth/index.d.ts.map +1 -1
  19. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js +18 -1
  20. package/dist/core/extensions/builtin/claude-sdk-oauth/index.js.map +1 -1
  21. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.d.ts +1 -0
  22. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.d.ts.map +1 -1
  23. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.js +7 -1
  24. package/dist/core/extensions/builtin/claude-sdk-oauth/oauth-login.js.map +1 -1
  25. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts +8 -0
  26. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -1
  27. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +18 -0
  28. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -1
  29. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.d.ts +7 -0
  30. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.d.ts.map +1 -1
  31. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.js +10 -1
  32. package/dist/core/extensions/builtin/cursor-cli-oauth/guardrails.js.map +1 -1
  33. package/dist/core/extensions/builtin/cursor-cli-oauth/index.d.ts.map +1 -1
  34. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js +12 -1
  35. package/dist/core/extensions/builtin/cursor-cli-oauth/index.js.map +1 -1
  36. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts +12 -1
  37. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.d.ts.map +1 -1
  38. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js +20 -1
  39. package/dist/core/extensions/builtin/cursor-cli-oauth/oauth-login.js.map +1 -1
  40. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts +11 -0
  41. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js +7 -2
  43. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js.map +1 -1
  44. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
  45. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +7 -2
  46. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
  47. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  48. package/dist/core/extensions/builtin/index.js +2 -0
  49. package/dist/core/extensions/builtin/index.js.map +1 -1
  50. package/dist/core/extensions/builtin/loop/command-registration.d.ts +7 -0
  51. package/dist/core/extensions/builtin/loop/command-registration.d.ts.map +1 -0
  52. package/dist/core/extensions/builtin/loop/command-registration.js +13 -0
  53. package/dist/core/extensions/builtin/loop/command-registration.js.map +1 -0
  54. package/dist/core/extensions/builtin/loop/command.d.ts +41 -0
  55. package/dist/core/extensions/builtin/loop/command.d.ts.map +1 -0
  56. package/dist/core/extensions/builtin/loop/command.js +281 -0
  57. package/dist/core/extensions/builtin/loop/command.js.map +1 -0
  58. package/dist/core/extensions/builtin/loop/cron-planner.d.ts +23 -0
  59. package/dist/core/extensions/builtin/loop/cron-planner.d.ts.map +1 -0
  60. package/dist/core/extensions/builtin/loop/cron-planner.js +88 -0
  61. package/dist/core/extensions/builtin/loop/cron-planner.js.map +1 -0
  62. package/dist/core/extensions/builtin/loop/index.d.ts +134 -0
  63. package/dist/core/extensions/builtin/loop/index.d.ts.map +1 -0
  64. package/dist/core/extensions/builtin/loop/index.js +742 -0
  65. package/dist/core/extensions/builtin/loop/index.js.map +1 -0
  66. package/dist/core/extensions/builtin/loop/loopfile.d.ts +40 -0
  67. package/dist/core/extensions/builtin/loop/loopfile.d.ts.map +1 -0
  68. package/dist/core/extensions/builtin/loop/loopfile.js +102 -0
  69. package/dist/core/extensions/builtin/loop/loopfile.js.map +1 -0
  70. package/dist/core/extensions/builtin/loop/parse.d.ts +45 -0
  71. package/dist/core/extensions/builtin/loop/parse.d.ts.map +1 -0
  72. package/dist/core/extensions/builtin/loop/parse.js +92 -0
  73. package/dist/core/extensions/builtin/loop/parse.js.map +1 -0
  74. package/dist/core/extensions/builtin/loop/scheduler.d.ts +225 -0
  75. package/dist/core/extensions/builtin/loop/scheduler.d.ts.map +1 -0
  76. package/dist/core/extensions/builtin/loop/scheduler.js +708 -0
  77. package/dist/core/extensions/builtin/loop/scheduler.js.map +1 -0
  78. package/dist/core/extensions/builtin/loop/status.d.ts +24 -0
  79. package/dist/core/extensions/builtin/loop/status.d.ts.map +1 -0
  80. package/dist/core/extensions/builtin/loop/status.js +113 -0
  81. package/dist/core/extensions/builtin/loop/status.js.map +1 -0
  82. package/dist/core/extensions/builtin/loop/store.d.ts +49 -0
  83. package/dist/core/extensions/builtin/loop/store.d.ts.map +1 -0
  84. package/dist/core/extensions/builtin/loop/store.js +424 -0
  85. package/dist/core/extensions/builtin/loop/store.js.map +1 -0
  86. package/dist/core/extensions/builtin/loop/tick-prompt.d.ts +64 -0
  87. package/dist/core/extensions/builtin/loop/tick-prompt.d.ts.map +1 -0
  88. package/dist/core/extensions/builtin/loop/tick-prompt.js +183 -0
  89. package/dist/core/extensions/builtin/loop/tick-prompt.js.map +1 -0
  90. package/dist/core/extensions/builtin/loop/tools.d.ts +122 -0
  91. package/dist/core/extensions/builtin/loop/tools.d.ts.map +1 -0
  92. package/dist/core/extensions/builtin/loop/tools.js +155 -0
  93. package/dist/core/extensions/builtin/loop/tools.js.map +1 -0
  94. package/dist/core/extensions/builtin/loop/types.d.ts +206 -0
  95. package/dist/core/extensions/builtin/loop/types.d.ts.map +1 -0
  96. package/dist/core/extensions/builtin/loop/types.js +37 -0
  97. package/dist/core/extensions/builtin/loop/types.js.map +1 -0
  98. package/dist/core/extensions/index.d.ts +1 -1
  99. package/dist/core/extensions/index.d.ts.map +1 -1
  100. package/dist/core/extensions/index.js.map +1 -1
  101. package/dist/core/extensions/loader.d.ts.map +1 -1
  102. package/dist/core/extensions/loader.js +10 -5
  103. package/dist/core/extensions/loader.js.map +1 -1
  104. package/dist/core/extensions/types.d.ts +30 -3
  105. package/dist/core/extensions/types.d.ts.map +1 -1
  106. package/dist/core/extensions/types.js.map +1 -1
  107. package/dist/core/footer-data-provider.d.ts.map +1 -1
  108. package/dist/core/footer-data-provider.js +5 -10
  109. package/dist/core/footer-data-provider.js.map +1 -1
  110. package/dist/core/model-registry.d.ts +2 -0
  111. package/dist/core/model-registry.d.ts.map +1 -1
  112. package/dist/core/model-registry.js +4 -0
  113. package/dist/core/model-registry.js.map +1 -1
  114. package/dist/core/model-runtime.d.ts +7 -0
  115. package/dist/core/model-runtime.d.ts.map +1 -1
  116. package/dist/core/model-runtime.js +17 -0
  117. package/dist/core/model-runtime.js.map +1 -1
  118. package/dist/core/package-manager.d.ts.map +1 -1
  119. package/dist/core/package-manager.js +8 -4
  120. package/dist/core/package-manager.js.map +1 -1
  121. package/dist/core/provider-composer.d.ts +8 -0
  122. package/dist/core/provider-composer.d.ts.map +1 -1
  123. package/dist/core/provider-composer.js.map +1 -1
  124. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  125. package/dist/core/remote-catalog-provider.js +2 -1
  126. package/dist/core/remote-catalog-provider.js.map +1 -1
  127. package/dist/core/retry-fallback/chains.d.ts +1 -0
  128. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  129. package/dist/core/retry-fallback/chains.js +3 -0
  130. package/dist/core/retry-fallback/chains.js.map +1 -1
  131. package/dist/core/retry-fallback/controller.d.ts +2 -0
  132. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  133. package/dist/core/retry-fallback/controller.js.map +1 -1
  134. package/dist/core/retry-fallback/expansion.d.ts +8 -0
  135. package/dist/core/retry-fallback/expansion.d.ts.map +1 -1
  136. package/dist/core/retry-fallback/expansion.js +2 -0
  137. package/dist/core/retry-fallback/expansion.js.map +1 -1
  138. package/dist/core/settings-manager.d.ts +1 -1
  139. package/dist/core/settings-manager.d.ts.map +1 -1
  140. package/dist/core/settings-manager.js +14 -3
  141. package/dist/core/settings-manager.js.map +1 -1
  142. package/dist/core/skills.d.ts.map +1 -1
  143. package/dist/core/skills.js +51 -33
  144. package/dist/core/skills.js.map +1 -1
  145. package/dist/core/tools/edit.d.ts.map +1 -1
  146. package/dist/core/tools/edit.js +17 -2
  147. package/dist/core/tools/edit.js.map +1 -1
  148. package/dist/extensions/llama/index.d.ts.map +1 -1
  149. package/dist/extensions/llama/index.js +2 -0
  150. package/dist/extensions/llama/index.js.map +1 -1
  151. package/dist/extensions/llama/provider.d.ts.map +1 -1
  152. package/dist/extensions/llama/provider.js +6 -6
  153. package/dist/extensions/llama/provider.js.map +1 -1
  154. package/dist/index.d.ts +1 -1
  155. package/dist/index.d.ts.map +1 -1
  156. package/dist/index.js.map +1 -1
  157. package/dist/main.d.ts +4 -0
  158. package/dist/main.d.ts.map +1 -1
  159. package/dist/main.js +4 -4
  160. package/dist/main.js.map +1 -1
  161. package/dist/modes/interactive/components/settings-selector.js +1 -1
  162. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  163. package/dist/modes/interactive/editor-paste-transfer.d.ts +10 -1
  164. package/dist/modes/interactive/editor-paste-transfer.d.ts.map +1 -1
  165. package/dist/modes/interactive/editor-paste-transfer.js +27 -2
  166. package/dist/modes/interactive/editor-paste-transfer.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +69 -1
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +434 -63
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/tips/catalog/dag-tips.d.ts +7 -0
  172. package/dist/modes/interactive/tips/catalog/dag-tips.d.ts.map +1 -0
  173. package/dist/modes/interactive/tips/catalog/dag-tips.js +57 -0
  174. package/dist/modes/interactive/tips/catalog/dag-tips.js.map +1 -0
  175. package/dist/modes/interactive/tips/catalog/memory-tips.d.ts +7 -0
  176. package/dist/modes/interactive/tips/catalog/memory-tips.d.ts.map +1 -0
  177. package/dist/modes/interactive/tips/catalog/memory-tips.js +100 -0
  178. package/dist/modes/interactive/tips/catalog/memory-tips.js.map +1 -0
  179. package/dist/modes/interactive/tips/registry.d.ts.map +1 -1
  180. package/dist/modes/interactive/tips/registry.js +4 -0
  181. package/dist/modes/interactive/tips/registry.js.map +1 -1
  182. package/dist/utils/management-http.d.ts +5 -3
  183. package/dist/utils/management-http.d.ts.map +1 -1
  184. package/dist/utils/management-http.js +14 -10
  185. package/dist/utils/management-http.js.map +1 -1
  186. package/docs/compaction.md +17 -0
  187. package/docs/custom-provider.md +5 -2
  188. package/docs/extensions.md +11 -2
  189. package/docs/llama-cpp.md +2 -0
  190. package/docs/models.md +8 -2
  191. package/docs/providers.md +5 -3
  192. package/docs/settings.md +22 -2
  193. package/docs/skills.md +4 -3
  194. package/examples/extensions/border-status-editor.ts +1 -1
  195. package/examples/extensions/git-checkpoint.ts +2 -2
  196. package/examples/extensions/notify.ts +3 -1
  197. package/examples/extensions/subagent/index.ts +6 -1
  198. package/examples/extensions/titlebar-spinner.ts +1 -1
  199. package/examples/rpc-extension-ui.ts +1 -1
  200. package/examples/sdk/06-extensions.ts +1 -1
  201. package/examples/sdk/README.md +1 -1
  202. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  203. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  204. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts +3 -1
  205. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  206. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +51 -17
  207. package/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
  208. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +4 -2
  209. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  210. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +5 -1
  211. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  212. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.d.ts +3 -2
  213. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.d.ts.map +1 -1
  214. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.js +13 -3
  215. package/node_modules/@earendil-works/pi-agent-core/dist/harness/skills.js.map +1 -1
  216. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.d.ts.map +1 -1
  217. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js +14 -1
  218. package/node_modules/@earendil-works/pi-agent-core/dist/harness/tools/edit.js.map +1 -1
  219. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  220. package/node_modules/@earendil-works/pi-ai/README.md +5 -3
  221. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts +7 -1
  222. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  223. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +21 -4
  224. package/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  225. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts +2 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts.map +1 -1
  227. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +7 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
  229. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +39 -2
  231. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.d.ts +22 -1
  233. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.d.ts.map +1 -1
  234. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.js +1 -1
  235. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent/gen/agent_pb.js.map +1 -1
  236. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts +1 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.d.ts.map +1 -1
  238. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js +51 -2
  239. package/node_modules/@earendil-works/pi-ai/dist/api/cursor-agent.js.map +1 -1
  240. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts +2 -2
  241. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts.map +1 -1
  242. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +14 -11
  243. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js.map +1 -1
  244. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.d.ts +5 -2
  245. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.d.ts.map +1 -1
  246. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js +16 -0
  247. package/node_modules/@earendil-works/pi-ai/dist/api/google-shared.js.map +1 -1
  248. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts +2 -2
  249. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts.map +1 -1
  250. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +13 -10
  251. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js.map +1 -1
  252. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.d.ts.map +1 -1
  253. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js +4 -1
  254. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js.map +1 -1
  255. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  256. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +4 -1
  257. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  258. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts +1 -1
  259. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  260. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +45 -29
  261. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  262. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  263. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +8 -1
  264. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  265. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js +1 -1
  266. package/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js.map +1 -1
  267. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.d.ts +4 -0
  268. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.d.ts.map +1 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js +18 -9
  270. package/node_modules/@earendil-works/pi-ai/dist/api/simple-options.js.map +1 -1
  271. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.d.ts +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.d.ts.map +1 -1
  273. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.js +1 -1
  274. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/device-code.js.map +1 -1
  275. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js +22 -9
  277. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/github-copilot.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +2 -1
  279. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  281. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  283. package/node_modules/@earendil-works/pi-ai/dist/providers/data/anthropic.json +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  285. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/providers/data/qwen-token-plan-individual.json +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  291. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xai.json +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-ams.json +1 -1
  293. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-cn.json +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi-token-plan-sgp.json +1 -1
  295. package/node_modules/@earendil-works/pi-ai/dist/providers/data/xiaomi.json +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai-coding-cn.json +1 -1
  297. package/node_modules/@earendil-works/pi-ai/dist/providers/data/zai.json +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js +1 -5
  301. package/node_modules/@earendil-works/pi-ai/dist/providers/xai.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +28 -4
  303. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  304. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.d.ts.map +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +15 -0
  307. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js.map +1 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.d.ts +2 -0
  309. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.d.ts.map +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js +7 -0
  311. package/node_modules/@earendil-works/pi-ai/dist/utils/pi-user-agent.js.map +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts +2 -1
  313. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js +2 -0
  315. package/node_modules/@earendil-works/pi-ai/dist/utils/prompt-cache-ttl.js.map +1 -1
  316. package/node_modules/@earendil-works/pi-ai/package.json +2 -3
  317. package/node_modules/@earendil-works/pi-pty/dist/loader.d.ts +6 -0
  318. package/node_modules/@earendil-works/pi-pty/dist/loader.d.ts.map +1 -1
  319. package/node_modules/@earendil-works/pi-pty/dist/loader.js +11 -0
  320. package/node_modules/@earendil-works/pi-pty/dist/loader.js.map +1 -1
  321. package/node_modules/@earendil-works/pi-pty/dist/quarantine.d.ts +15 -0
  322. package/node_modules/@earendil-works/pi-pty/dist/quarantine.d.ts.map +1 -0
  323. package/node_modules/@earendil-works/pi-pty/dist/quarantine.js +27 -0
  324. package/node_modules/@earendil-works/pi-pty/dist/quarantine.js.map +1 -0
  325. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  326. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  327. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts +73 -1
  328. package/node_modules/@earendil-works/pi-tui/dist/components/editor.d.ts.map +1 -1
  329. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +173 -17
  330. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js.map +1 -1
  331. package/node_modules/@earendil-works/pi-tui/dist/components/text.d.ts.map +1 -1
  332. package/node_modules/@earendil-works/pi-tui/dist/components/text.js +5 -4
  333. package/node_modules/@earendil-works/pi-tui/dist/components/text.js.map +1 -1
  334. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts +69 -0
  335. package/node_modules/@earendil-works/pi-tui/dist/editor-component.d.ts.map +1 -1
  336. package/node_modules/@earendil-works/pi-tui/dist/editor-component.js.map +1 -1
  337. package/node_modules/@earendil-works/pi-tui/dist/image-markers.d.ts +46 -0
  338. package/node_modules/@earendil-works/pi-tui/dist/image-markers.d.ts.map +1 -0
  339. package/node_modules/@earendil-works/pi-tui/dist/image-markers.js +130 -0
  340. package/node_modules/@earendil-works/pi-tui/dist/image-markers.js.map +1 -0
  341. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts +1 -0
  342. package/node_modules/@earendil-works/pi-tui/dist/index.d.ts.map +1 -1
  343. package/node_modules/@earendil-works/pi-tui/dist/index.js +2 -0
  344. package/node_modules/@earendil-works/pi-tui/dist/index.js.map +1 -1
  345. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.d.ts +3 -0
  346. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.d.ts.map +1 -1
  347. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.js +23 -7
  348. package/node_modules/@earendil-works/pi-tui/dist/paste-markers.js.map +1 -1
  349. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.d.ts.map +1 -1
  350. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js +5 -1
  351. package/node_modules/@earendil-works/pi-tui/dist/tui-alt-screen.js.map +1 -1
  352. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  353. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/claude-sdk-oauth/settings.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAgentDir } from \"../../../../config.ts\";\nimport { type Settings, SettingsManager } from \"../../../settings-manager.ts\";\nimport type { SettingSource } from \"./sdk-boundary.ts\";\n\nexport type ClaudeSdkOauthSystemPromptMode = \"preset-append\" | \"full\" | \"override\";\nexport type ClaudeSdkOauthResumeMode = \"auto\" | \"off\";\nexport type ClaudeSdkOauthTokenInjection = \"oauth-slots\" | \"config-dir\" | \"ambient\";\n\nexport interface ClaudeSdkOauthProviderSettings {\n\treadonly appendSystemPrompt?: boolean;\n\treadonly systemPromptMode?: ClaudeSdkOauthSystemPromptMode;\n\treadonly systemPromptFile?: string;\n\treadonly resumeMode?: ClaudeSdkOauthResumeMode;\n\treadonly settingSources?: SettingSource[];\n\treadonly strictMcpConfig?: boolean;\n\treadonly pinnedAccount?: string;\n\treadonly tokenInjection?: ClaudeSdkOauthTokenInjection;\n}\n\nexport type ResolvedSystemPromptMode = {\n\tmode: ClaudeSdkOauthSystemPromptMode;\n\tsource: string;\n\tconflict: boolean;\n};\n\ntype SettingsWithClaudeSdkOauthProvider = Settings & {\n\tclaudeSdkOauthProvider?: unknown;\n};\n\ntype Environment = Readonly<Record<string, string | undefined>>;\n\nconst systemPromptModeSources = new WeakMap<ClaudeSdkOauthProviderSettings, \"env\">();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettingSources(value: unknown): SettingSource[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tif (!value.every((source) => source === \"user\" || source === \"project\" || source === \"local\")) {\n\t\treturn undefined;\n\t}\n\treturn [...value];\n}\n\nfunction parseEnvironmentSettingSources(value: string | undefined): SettingSource[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (value === \"\") return [];\n\treturn parseSettingSources(value.split(\",\").map((source) => source.trim()));\n}\n\nfunction parseSystemPromptMode(value: unknown): ClaudeSdkOauthSystemPromptMode | undefined {\n\treturn value === \"preset-append\" || value === \"full\" || value === \"override\" ? value : undefined;\n}\n\nfunction parseResumeMode(value: unknown): ClaudeSdkOauthResumeMode | undefined {\n\treturn value === \"auto\" || value === \"off\" ? value : undefined;\n}\n\nfunction parseTokenInjection(value: unknown): ClaudeSdkOauthTokenInjection | undefined {\n\treturn value === \"oauth-slots\" || value === \"config-dir\" || value === \"ambient\" ? value : undefined;\n}\n\nfunction parseNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction parseProviderSettings(value: unknown): ClaudeSdkOauthProviderSettings {\n\tif (!isRecord(value)) return {};\n\tconst appendSystemPrompt = typeof value.appendSystemPrompt === \"boolean\" ? value.appendSystemPrompt : undefined;\n\tconst systemPromptMode = parseSystemPromptMode(value.systemPromptMode);\n\tconst systemPromptFile = parseNonEmptyString(value.systemPromptFile);\n\tconst resumeMode = parseResumeMode(value.resumeMode);\n\tconst settingSources = parseSettingSources(value.settingSources);\n\tconst strictMcpConfig = typeof value.strictMcpConfig === \"boolean\" ? value.strictMcpConfig : undefined;\n\tconst pinnedAccount = parseNonEmptyString(value.pinnedAccount);\n\tconst tokenInjection = parseTokenInjection(value.tokenInjection);\n\treturn {\n\t\t...(appendSystemPrompt !== undefined ? { appendSystemPrompt } : {}),\n\t\t...(systemPromptMode !== undefined ? { systemPromptMode } : {}),\n\t\t...(systemPromptFile !== undefined ? { systemPromptFile } : {}),\n\t\t...(resumeMode !== undefined ? { resumeMode } : {}),\n\t\t...(settingSources !== undefined ? { settingSources } : {}),\n\t\t...(strictMcpConfig !== undefined ? { strictMcpConfig } : {}),\n\t\t...(pinnedAccount !== undefined ? { pinnedAccount } : {}),\n\t\t...(tokenInjection !== undefined ? { tokenInjection } : {}),\n\t};\n}\n\nfunction parseEnvironmentSettings(environment: Environment): ClaudeSdkOauthProviderSettings {\n\tconst systemPromptMode = parseSystemPromptMode(environment.SENPI_CLAUDE_SDK_OAUTH_SYSTEM_PROMPT_MODE);\n\tconst systemPromptFile = parseNonEmptyString(environment.SENPI_CLAUDE_SDK_OAUTH_SYSTEM_PROMPT_FILE);\n\tconst resumeMode = parseResumeMode(environment.SENPI_CLAUDE_SDK_OAUTH_RESUME);\n\tconst tokenInjection = parseTokenInjection(environment.SENPI_CLAUDE_SDK_OAUTH_TOKEN_INJECTION);\n\tconst settingSources = parseEnvironmentSettingSources(environment.SENPI_CLAUDE_SDK_OAUTH_SETTING_SOURCES);\n\tconst pinnedAccount = parseNonEmptyString(environment.SENPI_CLAUDE_SDK_OAUTH_PINNED_ACCOUNT);\n\treturn {\n\t\t...(systemPromptMode !== undefined ? { systemPromptMode } : {}),\n\t\t...(systemPromptFile !== undefined ? { systemPromptFile } : {}),\n\t\t...(resumeMode !== undefined ? { resumeMode } : {}),\n\t\t...(tokenInjection !== undefined ? { tokenInjection } : {}),\n\t\t...(settingSources !== undefined ? { settingSources } : {}),\n\t\t...(pinnedAccount !== undefined ? { pinnedAccount } : {}),\n\t};\n}\n\nexport function resolveSystemPromptMode(settings: ClaudeSdkOauthProviderSettings): ResolvedSystemPromptMode {\n\tif (settings.systemPromptMode !== undefined) {\n\t\treturn {\n\t\t\tmode: settings.systemPromptMode,\n\t\t\tsource: systemPromptModeSources.get(settings) ?? \"setting\",\n\t\t\tconflict: settings.appendSystemPrompt !== undefined,\n\t\t};\n\t}\n\tif (settings.appendSystemPrompt !== undefined) {\n\t\treturn {\n\t\t\tmode: settings.appendSystemPrompt ? \"full\" : \"preset-append\",\n\t\t\tsource: \"legacy\",\n\t\t\tconflict: false,\n\t\t};\n\t}\n\treturn { mode: \"full\", source: \"default\", conflict: false };\n}\n\n/** Load the provider block with env values taking precedence over project and global values. */\nexport function loadClaudeSdkOauthProviderSettings(\n\tsettingsManager: SettingsManager,\n\tenvironment: Environment = process.env,\n): ClaudeSdkOauthProviderSettings {\n\tconst global = settingsManager.getGlobalSettings() as SettingsWithClaudeSdkOauthProvider;\n\tconst project = settingsManager.getProjectSettings() as SettingsWithClaudeSdkOauthProvider;\n\tconst environmentSettings = parseEnvironmentSettings(environment);\n\tconst settings = {\n\t\t...parseProviderSettings(global.claudeSdkOauthProvider),\n\t\t...parseProviderSettings(project.claudeSdkOauthProvider),\n\t\t...environmentSettings,\n\t};\n\tif (environmentSettings.systemPromptMode !== undefined) systemPromptModeSources.set(settings, \"env\");\n\treturn settings;\n}\n\n/** Load settings from Senpi's configured global and project settings.json paths. */\nexport function loadClaudeSdkOauthProviderSettingsFromDisk(cwd: string): ClaudeSdkOauthProviderSettings {\n\treturn loadClaudeSdkOauthProviderSettings(SettingsManager.create(cwd, getAgentDir()));\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/claude-sdk-oauth/settings.ts"],"names":[],"mappings":"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","sourcesContent":["import { getAgentDir } from \"../../../../config.ts\";\nimport { type Settings, SettingsManager } from \"../../../settings-manager.ts\";\nimport type { SettingSource } from \"./sdk-boundary.ts\";\n\nexport type ClaudeSdkOauthSystemPromptMode = \"preset-append\" | \"full\" | \"override\";\nexport type ClaudeSdkOauthResumeMode = \"auto\" | \"off\";\nexport type ClaudeSdkOauthTokenInjection = \"oauth-slots\" | \"config-dir\" | \"ambient\";\n\nexport interface ClaudeSdkOauthProviderSettings {\n\t/**\n\t * Explicit opt-in for the ambient (host Claude CLI) auth lane. Absent means\n\t * false: a logged-in host CLI alone never makes this provider available,\n\t * because that would silently spend the user's Claude subscription. Stored\n\t * accounts and `CLAUDE_CODE_OAUTH_TOKEN*` are themselves explicit opt-ins\n\t * and stay available without this flag.\n\t */\n\treadonly enabled?: boolean;\n\treadonly appendSystemPrompt?: boolean;\n\treadonly systemPromptMode?: ClaudeSdkOauthSystemPromptMode;\n\treadonly systemPromptFile?: string;\n\treadonly resumeMode?: ClaudeSdkOauthResumeMode;\n\treadonly settingSources?: SettingSource[];\n\treadonly strictMcpConfig?: boolean;\n\treadonly pinnedAccount?: string;\n\treadonly tokenInjection?: ClaudeSdkOauthTokenInjection;\n}\n\nexport type ResolvedSystemPromptMode = {\n\tmode: ClaudeSdkOauthSystemPromptMode;\n\tsource: string;\n\tconflict: boolean;\n};\n\ntype SettingsWithClaudeSdkOauthProvider = Settings & {\n\tclaudeSdkOauthProvider?: unknown;\n};\n\ntype Environment = Readonly<Record<string, string | undefined>>;\n\nconst systemPromptModeSources = new WeakMap<ClaudeSdkOauthProviderSettings, \"env\">();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseSettingSources(value: unknown): SettingSource[] | undefined {\n\tif (!Array.isArray(value)) return undefined;\n\tif (!value.every((source) => source === \"user\" || source === \"project\" || source === \"local\")) {\n\t\treturn undefined;\n\t}\n\treturn [...value];\n}\n\nfunction parseEnvironmentSettingSources(value: string | undefined): SettingSource[] | undefined {\n\tif (value === undefined) return undefined;\n\tif (value === \"\") return [];\n\treturn parseSettingSources(value.split(\",\").map((source) => source.trim()));\n}\n\nfunction parseSystemPromptMode(value: unknown): ClaudeSdkOauthSystemPromptMode | undefined {\n\treturn value === \"preset-append\" || value === \"full\" || value === \"override\" ? value : undefined;\n}\n\nfunction parseResumeMode(value: unknown): ClaudeSdkOauthResumeMode | undefined {\n\treturn value === \"auto\" || value === \"off\" ? value : undefined;\n}\n\nfunction parseTokenInjection(value: unknown): ClaudeSdkOauthTokenInjection | undefined {\n\treturn value === \"oauth-slots\" || value === \"config-dir\" || value === \"ambient\" ? value : undefined;\n}\n\nfunction parseEnvironmentBoolean(value: string | undefined): boolean | undefined {\n\tif (value === undefined) return undefined;\n\tswitch (value.toLowerCase()) {\n\t\tcase \"1\":\n\t\tcase \"true\":\n\t\t\treturn true;\n\t\tcase \"0\":\n\t\tcase \"false\":\n\t\t\treturn false;\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nfunction parseNonEmptyString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction parseProviderSettings(value: unknown): ClaudeSdkOauthProviderSettings {\n\tif (!isRecord(value)) return {};\n\tconst enabled = typeof value.enabled === \"boolean\" ? value.enabled : undefined;\n\tconst appendSystemPrompt = typeof value.appendSystemPrompt === \"boolean\" ? value.appendSystemPrompt : undefined;\n\tconst systemPromptMode = parseSystemPromptMode(value.systemPromptMode);\n\tconst systemPromptFile = parseNonEmptyString(value.systemPromptFile);\n\tconst resumeMode = parseResumeMode(value.resumeMode);\n\tconst settingSources = parseSettingSources(value.settingSources);\n\tconst strictMcpConfig = typeof value.strictMcpConfig === \"boolean\" ? value.strictMcpConfig : undefined;\n\tconst pinnedAccount = parseNonEmptyString(value.pinnedAccount);\n\tconst tokenInjection = parseTokenInjection(value.tokenInjection);\n\treturn {\n\t\t...(enabled !== undefined ? { enabled } : {}),\n\t\t...(appendSystemPrompt !== undefined ? { appendSystemPrompt } : {}),\n\t\t...(systemPromptMode !== undefined ? { systemPromptMode } : {}),\n\t\t...(systemPromptFile !== undefined ? { systemPromptFile } : {}),\n\t\t...(resumeMode !== undefined ? { resumeMode } : {}),\n\t\t...(settingSources !== undefined ? { settingSources } : {}),\n\t\t...(strictMcpConfig !== undefined ? { strictMcpConfig } : {}),\n\t\t...(pinnedAccount !== undefined ? { pinnedAccount } : {}),\n\t\t...(tokenInjection !== undefined ? { tokenInjection } : {}),\n\t};\n}\n\nfunction parseEnvironmentSettings(environment: Environment): ClaudeSdkOauthProviderSettings {\n\tconst enabled = parseEnvironmentBoolean(environment.SENPI_CLAUDE_SDK_OAUTH_ENABLED);\n\tconst systemPromptMode = parseSystemPromptMode(environment.SENPI_CLAUDE_SDK_OAUTH_SYSTEM_PROMPT_MODE);\n\tconst systemPromptFile = parseNonEmptyString(environment.SENPI_CLAUDE_SDK_OAUTH_SYSTEM_PROMPT_FILE);\n\tconst resumeMode = parseResumeMode(environment.SENPI_CLAUDE_SDK_OAUTH_RESUME);\n\tconst tokenInjection = parseTokenInjection(environment.SENPI_CLAUDE_SDK_OAUTH_TOKEN_INJECTION);\n\tconst settingSources = parseEnvironmentSettingSources(environment.SENPI_CLAUDE_SDK_OAUTH_SETTING_SOURCES);\n\tconst pinnedAccount = parseNonEmptyString(environment.SENPI_CLAUDE_SDK_OAUTH_PINNED_ACCOUNT);\n\treturn {\n\t\t...(enabled !== undefined ? { enabled } : {}),\n\t\t...(systemPromptMode !== undefined ? { systemPromptMode } : {}),\n\t\t...(systemPromptFile !== undefined ? { systemPromptFile } : {}),\n\t\t...(resumeMode !== undefined ? { resumeMode } : {}),\n\t\t...(tokenInjection !== undefined ? { tokenInjection } : {}),\n\t\t...(settingSources !== undefined ? { settingSources } : {}),\n\t\t...(pinnedAccount !== undefined ? { pinnedAccount } : {}),\n\t};\n}\n\nexport function resolveSystemPromptMode(settings: ClaudeSdkOauthProviderSettings): ResolvedSystemPromptMode {\n\tif (settings.systemPromptMode !== undefined) {\n\t\treturn {\n\t\t\tmode: settings.systemPromptMode,\n\t\t\tsource: systemPromptModeSources.get(settings) ?? \"setting\",\n\t\t\tconflict: settings.appendSystemPrompt !== undefined,\n\t\t};\n\t}\n\tif (settings.appendSystemPrompt !== undefined) {\n\t\treturn {\n\t\t\tmode: settings.appendSystemPrompt ? \"full\" : \"preset-append\",\n\t\t\tsource: \"legacy\",\n\t\t\tconflict: false,\n\t\t};\n\t}\n\treturn { mode: \"full\", source: \"default\", conflict: false };\n}\n\n/** Load the provider block with env values taking precedence over project and global values. */\nexport function loadClaudeSdkOauthProviderSettings(\n\tsettingsManager: SettingsManager,\n\tenvironment: Environment = process.env,\n): ClaudeSdkOauthProviderSettings {\n\tconst global = settingsManager.getGlobalSettings() as SettingsWithClaudeSdkOauthProvider;\n\tconst project = settingsManager.getProjectSettings() as SettingsWithClaudeSdkOauthProvider;\n\tconst environmentSettings = parseEnvironmentSettings(environment);\n\tconst settings = {\n\t\t...parseProviderSettings(global.claudeSdkOauthProvider),\n\t\t...parseProviderSettings(project.claudeSdkOauthProvider),\n\t\t...environmentSettings,\n\t};\n\tif (environmentSettings.systemPromptMode !== undefined) systemPromptModeSources.set(settings, \"env\");\n\treturn settings;\n}\n\n/** Load settings from Senpi's configured global and project settings.json paths. */\nexport function loadClaudeSdkOauthProviderSettingsFromDisk(cwd: string): ClaudeSdkOauthProviderSettings {\n\treturn loadClaudeSdkOauthProviderSettings(SettingsManager.create(cwd, getAgentDir()));\n}\n"]}
@@ -72,6 +72,13 @@ export declare function sanitizeCursorCliDenyCommands(entries: readonly string[]
72
72
  * - Force disabled in agent mode is allowed but warns once per session.
73
73
  * - Unproven sandbox modes are ignored with one warning per distinct value.
74
74
  */
75
+ /**
76
+ * True while the settings guarantee an unattended agent-mode refusal: force is
77
+ * requested outside plan mode but `noApprovalAcknowledgedAt` was never set.
78
+ * Shared by the execution policy and the fallback-eligibility hook so the two
79
+ * can never disagree about when the lane refuses.
80
+ */
81
+ export declare function cursorCliForceRefusalPending(input: Pick<CursorCliExecutionPolicyInput, "forceExecution" | "noApprovalAcknowledgedAt" | "executionMode">): boolean;
75
82
  export declare function resolveCursorCliExecutionPolicy(input: CursorCliExecutionPolicyInput, session: CursorCliGuardrailSession, denyCommands?: readonly string[]): CursorCliExecutionDecision;
76
83
  /**
77
84
  * Pre-spawn hook: (re-)apply the deny list to the sandbox HOME's
@@ -1 +1 @@
1
- {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/guardrails.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"guardrails.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/guardrails.ts"],"names":[],"mappings":"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"}
@@ -74,10 +74,19 @@ export function sanitizeCursorCliDenyCommands(entries, warn) {
74
74
  * - Force disabled in agent mode is allowed but warns once per session.
75
75
  * - Unproven sandbox modes are ignored with one warning per distinct value.
76
76
  */
77
+ /**
78
+ * True while the settings guarantee an unattended agent-mode refusal: force is
79
+ * requested outside plan mode but `noApprovalAcknowledgedAt` was never set.
80
+ * Shared by the execution policy and the fallback-eligibility hook so the two
81
+ * can never disagree about when the lane refuses.
82
+ */
83
+ export function cursorCliForceRefusalPending(input) {
84
+ return input.executionMode !== "plan" && input.forceExecution && input.noApprovalAcknowledgedAt === undefined;
85
+ }
77
86
  export function resolveCursorCliExecutionPolicy(input, session, denyCommands = []) {
78
87
  const planMode = input.executionMode === "plan";
79
88
  const wantsForce = !planMode && input.forceExecution;
80
- if (wantsForce && input.noApprovalAcknowledgedAt === undefined) {
89
+ if (cursorCliForceRefusalPending(input)) {
81
90
  const refusal = {
82
91
  kind: "refusal",
83
92
  code: "no_approval_acknowledgement_required",
@@ -1 +1 @@
1
- {"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/guardrails.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CursorCliOauthExecutionMode, createCursorCliOauthSandboxModeValidator } from \"./settings.ts\";\n\n/**\n * Guardrails for unattended Cursor CLI execution.\n *\n * The Cursor CLI runs its own tools the moment `--force` is on the argv, so\n * that decision is never implicit: it requires the explicit\n * `noApprovalAcknowledgedAt` acknowledgement, plan mode never forces, and a\n * disabled force merely warns. Command denylists ride along through the\n * per-account HOME's `cli-config.json`, strictly in the probe-proven shape\n * (task 2: `permissions.deny` with exact full-command `Shell(...)` entries).\n */\n\n/** Sandbox modes the installed CLI accepts (task 2 probe: allowed choices are exactly these). */\nexport const CURSOR_CLI_OAUTH_SANDBOX_MODES: readonly [\"enabled\", \"disabled\"] = [\"enabled\", \"disabled\"];\n\nexport const CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION =\n\t\"The Cursor CLI executes its own tools autonomously: with --force there is no senpi approval, no senpi sandboxing, and no tool-level audit for what it runs.\";\n\nexport const CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP =\n\t'Set \"cursorCliOauthProvider.noApprovalAcknowledgedAt\" to the current ISO-8601 timestamp (for example \"2026-08-17T12:00:00.000Z\") in senpi settings to acknowledge this once.';\n\n/** One warning per session when force is disabled in agent mode (contracts block, task 18). */\nexport const CURSOR_CLI_OAUTH_FORCE_DISABLED_WARNING =\n\t'cursor-cli-oauth: forceExecution is disabled in agent mode, so the Cursor CLI will auto-reject every tool call; set executionMode to \"plan\" for planning turns that do not need execution.';\n\nexport type CursorCliGuardrailWarningCode =\n\t| \"force_execution_disabled\"\n\t| \"sandbox_mode_ignored\"\n\t| \"deny_command_rejected\";\n\nexport type CursorCliGuardrailWarning = {\n\treadonly kind: \"warning\";\n\treadonly code: CursorCliGuardrailWarningCode;\n\treadonly message: string;\n};\n\nexport type CursorCliExecutionRefusal = {\n\treadonly kind: \"refusal\";\n\treadonly code: \"no_approval_acknowledgement_required\";\n\treadonly message: string;\n\treadonly acknowledgementStep: string;\n};\n\nexport type CursorCliGuardrailSession = {\n\t/** Every warning emitted so far in this session; one-time gates live here. */\n\treadonly warnings: readonly CursorCliGuardrailWarning[];\n\t/** Emit a warning once per deduplication key; returns whether it was emitted. */\n\twarn(code: CursorCliGuardrailWarningCode, message: string, key?: string): boolean;\n\t/** Validate a sandbox mode against the probe-proven allowlist, warning once per rejected value. */\n\tvalidateSandboxMode(value: string | undefined): string | undefined;\n};\n\nexport function createCursorCliGuardrailSession(): CursorCliGuardrailSession {\n\tconst warnings: CursorCliGuardrailWarning[] = [];\n\tconst emitted = new Set<string>();\n\tconst warn = (code: CursorCliGuardrailWarningCode, message: string, key: string = code): boolean => {\n\t\tif (emitted.has(key)) return false;\n\t\temitted.add(key);\n\t\twarnings.push({ kind: \"warning\", code, message });\n\t\treturn true;\n\t};\n\tconst validateSandboxMode = createCursorCliOauthSandboxModeValidator(\n\t\tnew Set(CURSOR_CLI_OAUTH_SANDBOX_MODES),\n\t\t(message) => {\n\t\t\twarn(\"sandbox_mode_ignored\", message, `sandbox_mode_ignored:${message}`);\n\t\t},\n\t);\n\treturn {\n\t\twarnings,\n\t\twarn,\n\t\tvalidateSandboxMode,\n\t};\n}\n\nexport type CursorCliExecutionPolicyInput = {\n\treadonly forceExecution: boolean;\n\treadonly noApprovalAcknowledgedAt: string | undefined;\n\treadonly executionMode: CursorCliOauthExecutionMode;\n\treadonly sandboxMode: string | undefined;\n};\n\nexport type CursorCliExecutionDecision =\n\t| { readonly status: \"refused\"; readonly refusal: CursorCliExecutionRefusal }\n\t| {\n\t\t\treadonly status: \"allowed\";\n\t\t\treadonly force: boolean;\n\t\t\treadonly executionMode: CursorCliOauthExecutionMode;\n\t\t\treadonly sandboxMode: string | undefined;\n\t\t\treadonly denyCommands: readonly string[];\n\t\t\t/** Warnings accumulated in the session so far (not only this decision). */\n\t\t\treadonly warnings: readonly CursorCliGuardrailWarning[];\n\t };\n\n/** Typed refusal for an unacknowledged force attempt; never confused with a warning. */\nexport class CursorCliExecutionRefusalError extends Error {\n\treadonly code = \"no_approval_acknowledgement_required\" as const;\n\treadonly refusal: CursorCliExecutionRefusal;\n\n\tconstructor(refusal: CursorCliExecutionRefusal) {\n\t\tsuper(refusal.message);\n\t\tthis.name = \"CursorCliExecutionRefusalError\";\n\t\tthis.refusal = refusal;\n\t}\n}\n\n/** Glob breadth is unproven (task 2 probed exact full commands only), so glob-bearing entries are dropped. */\nconst GLOB_METACHARACTERS = /[*?[]/u;\n\nexport function sanitizeCursorCliDenyCommands(\n\tentries: readonly string[],\n\twarn?: (message: string) => void,\n): readonly string[] {\n\tconst kept: string[] = [];\n\tfor (const entry of entries) {\n\t\tconst command = entry.trim();\n\t\tif (command.length === 0) {\n\t\t\twarn?.(\"Ignoring an empty Cursor CLI deny command entry (exact full commands only)\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (GLOB_METACHARACTERS.test(command)) {\n\t\t\twarn?.(\n\t\t\t\t`Ignoring glob-bearing Cursor CLI deny command (exact full commands only; glob support is unproven): ${command}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tkept.push(command);\n\t}\n\treturn kept;\n}\n\n/**\n * Decide whether a turn may run unattended.\n *\n * - `--force` is emitted only in agent mode, only when force is requested, and\n * only after `noApprovalAcknowledgedAt` is set; otherwise the decision is a\n * typed refusal naming the acknowledgement step.\n * - Plan mode never emits `--force` (the CLI only plans), so it needs no\n * acknowledgement.\n * - Force disabled in agent mode is allowed but warns once per session.\n * - Unproven sandbox modes are ignored with one warning per distinct value.\n */\nexport function resolveCursorCliExecutionPolicy(\n\tinput: CursorCliExecutionPolicyInput,\n\tsession: CursorCliGuardrailSession,\n\tdenyCommands: readonly string[] = [],\n): CursorCliExecutionDecision {\n\tconst planMode = input.executionMode === \"plan\";\n\tconst wantsForce = !planMode && input.forceExecution;\n\tif (wantsForce && input.noApprovalAcknowledgedAt === undefined) {\n\t\tconst refusal: CursorCliExecutionRefusal = {\n\t\t\tkind: \"refusal\",\n\t\t\tcode: \"no_approval_acknowledgement_required\",\n\t\t\tmessage: `${CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION} ${CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP}`,\n\t\t\tacknowledgementStep: CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP,\n\t\t};\n\t\treturn { status: \"refused\", refusal };\n\t}\n\tif (!planMode && !input.forceExecution) {\n\t\tsession.warn(\"force_execution_disabled\", CURSOR_CLI_OAUTH_FORCE_DISABLED_WARNING);\n\t}\n\tconst sandboxMode = session.validateSandboxMode(input.sandboxMode);\n\tconst sanitizedDenyCommands = sanitizeCursorCliDenyCommands(denyCommands, (message) => {\n\t\tsession.warn(\"deny_command_rejected\", message, `deny_command_rejected:${message}`);\n\t});\n\treturn {\n\t\tstatus: \"allowed\",\n\t\tforce: wantsForce,\n\t\texecutionMode: input.executionMode,\n\t\tsandboxMode,\n\t\tdenyCommands: sanitizedDenyCommands,\n\t\twarnings: [...session.warnings],\n\t};\n}\n\nconst CLI_CONFIG_RELATIVE_PATH = join(\".cursor\", \"cli-config.json\");\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction shellDenyEntry(command: string): string {\n\treturn `Shell(${command})`;\n}\n\n/**\n * Pre-spawn hook: (re-)apply the deny list to the sandbox HOME's\n * `cli-config.json`.\n *\n * The CLI rewrites this file during every invocation (task 2 observed its own\n * keys appearing and `cli-config.json.bad` sidecars for malformed content), so\n * this must run immediately before each spawn, composing with the home-store\n * prepare pass that re-writes `auth.json` on the same cadence. Writes only the\n * probe-proven shape (`permissions.deny` with exact `Shell(<full command>)`\n * entries) and preserves every CLI-owned key already present. Writes nothing\n * when no deny commands are configured.\n */\nexport function applyCursorCliDenyConfig(home: string, denyCommands: readonly string[]): void {\n\tif (denyCommands.length === 0) return;\n\tconst configPath = join(home, CLI_CONFIG_RELATIVE_PATH);\n\tlet existing: Record<string, unknown> = {};\n\tif (existsSync(configPath)) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(configPath, \"utf8\"));\n\t\t\tif (isRecord(parsed)) existing = parsed;\n\t\t} catch {\n\t\t\t// The CLI quarantines unparseable config as cli-config.json.bad and\n\t\t\t// proceeds with defaults; start from the proven minimal shape.\n\t\t}\n\t}\n\tconst permissions = isRecord(existing.permissions) ? { ...existing.permissions } : {};\n\tconst config: Record<string, unknown> = {\n\t\t...existing,\n\t\tpermissions: { ...permissions, deny: denyCommands.map(shellDenyEntry) },\n\t};\n\twriteFileSync(configPath, `${JSON.stringify(config, null, \"\\t\")}\\n`, \"utf8\");\n}\n"]}
1
+ {"version":3,"file":"guardrails.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/guardrails.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { type CursorCliOauthExecutionMode, createCursorCliOauthSandboxModeValidator } from \"./settings.ts\";\n\n/**\n * Guardrails for unattended Cursor CLI execution.\n *\n * The Cursor CLI runs its own tools the moment `--force` is on the argv, so\n * that decision is never implicit: it requires the explicit\n * `noApprovalAcknowledgedAt` acknowledgement, plan mode never forces, and a\n * disabled force merely warns. Command denylists ride along through the\n * per-account HOME's `cli-config.json`, strictly in the probe-proven shape\n * (task 2: `permissions.deny` with exact full-command `Shell(...)` entries).\n */\n\n/** Sandbox modes the installed CLI accepts (task 2 probe: allowed choices are exactly these). */\nexport const CURSOR_CLI_OAUTH_SANDBOX_MODES: readonly [\"enabled\", \"disabled\"] = [\"enabled\", \"disabled\"];\n\nexport const CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION =\n\t\"The Cursor CLI executes its own tools autonomously: with --force there is no senpi approval, no senpi sandboxing, and no tool-level audit for what it runs.\";\n\nexport const CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP =\n\t'Set \"cursorCliOauthProvider.noApprovalAcknowledgedAt\" to the current ISO-8601 timestamp (for example \"2026-08-17T12:00:00.000Z\") in senpi settings to acknowledge this once.';\n\n/** One warning per session when force is disabled in agent mode (contracts block, task 18). */\nexport const CURSOR_CLI_OAUTH_FORCE_DISABLED_WARNING =\n\t'cursor-cli-oauth: forceExecution is disabled in agent mode, so the Cursor CLI will auto-reject every tool call; set executionMode to \"plan\" for planning turns that do not need execution.';\n\nexport type CursorCliGuardrailWarningCode =\n\t| \"force_execution_disabled\"\n\t| \"sandbox_mode_ignored\"\n\t| \"deny_command_rejected\";\n\nexport type CursorCliGuardrailWarning = {\n\treadonly kind: \"warning\";\n\treadonly code: CursorCliGuardrailWarningCode;\n\treadonly message: string;\n};\n\nexport type CursorCliExecutionRefusal = {\n\treadonly kind: \"refusal\";\n\treadonly code: \"no_approval_acknowledgement_required\";\n\treadonly message: string;\n\treadonly acknowledgementStep: string;\n};\n\nexport type CursorCliGuardrailSession = {\n\t/** Every warning emitted so far in this session; one-time gates live here. */\n\treadonly warnings: readonly CursorCliGuardrailWarning[];\n\t/** Emit a warning once per deduplication key; returns whether it was emitted. */\n\twarn(code: CursorCliGuardrailWarningCode, message: string, key?: string): boolean;\n\t/** Validate a sandbox mode against the probe-proven allowlist, warning once per rejected value. */\n\tvalidateSandboxMode(value: string | undefined): string | undefined;\n};\n\nexport function createCursorCliGuardrailSession(): CursorCliGuardrailSession {\n\tconst warnings: CursorCliGuardrailWarning[] = [];\n\tconst emitted = new Set<string>();\n\tconst warn = (code: CursorCliGuardrailWarningCode, message: string, key: string = code): boolean => {\n\t\tif (emitted.has(key)) return false;\n\t\temitted.add(key);\n\t\twarnings.push({ kind: \"warning\", code, message });\n\t\treturn true;\n\t};\n\tconst validateSandboxMode = createCursorCliOauthSandboxModeValidator(\n\t\tnew Set(CURSOR_CLI_OAUTH_SANDBOX_MODES),\n\t\t(message) => {\n\t\t\twarn(\"sandbox_mode_ignored\", message, `sandbox_mode_ignored:${message}`);\n\t\t},\n\t);\n\treturn {\n\t\twarnings,\n\t\twarn,\n\t\tvalidateSandboxMode,\n\t};\n}\n\nexport type CursorCliExecutionPolicyInput = {\n\treadonly forceExecution: boolean;\n\treadonly noApprovalAcknowledgedAt: string | undefined;\n\treadonly executionMode: CursorCliOauthExecutionMode;\n\treadonly sandboxMode: string | undefined;\n};\n\nexport type CursorCliExecutionDecision =\n\t| { readonly status: \"refused\"; readonly refusal: CursorCliExecutionRefusal }\n\t| {\n\t\t\treadonly status: \"allowed\";\n\t\t\treadonly force: boolean;\n\t\t\treadonly executionMode: CursorCliOauthExecutionMode;\n\t\t\treadonly sandboxMode: string | undefined;\n\t\t\treadonly denyCommands: readonly string[];\n\t\t\t/** Warnings accumulated in the session so far (not only this decision). */\n\t\t\treadonly warnings: readonly CursorCliGuardrailWarning[];\n\t };\n\n/** Typed refusal for an unacknowledged force attempt; never confused with a warning. */\nexport class CursorCliExecutionRefusalError extends Error {\n\treadonly code = \"no_approval_acknowledgement_required\" as const;\n\treadonly refusal: CursorCliExecutionRefusal;\n\n\tconstructor(refusal: CursorCliExecutionRefusal) {\n\t\tsuper(refusal.message);\n\t\tthis.name = \"CursorCliExecutionRefusalError\";\n\t\tthis.refusal = refusal;\n\t}\n}\n\n/** Glob breadth is unproven (task 2 probed exact full commands only), so glob-bearing entries are dropped. */\nconst GLOB_METACHARACTERS = /[*?[]/u;\n\nexport function sanitizeCursorCliDenyCommands(\n\tentries: readonly string[],\n\twarn?: (message: string) => void,\n): readonly string[] {\n\tconst kept: string[] = [];\n\tfor (const entry of entries) {\n\t\tconst command = entry.trim();\n\t\tif (command.length === 0) {\n\t\t\twarn?.(\"Ignoring an empty Cursor CLI deny command entry (exact full commands only)\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (GLOB_METACHARACTERS.test(command)) {\n\t\t\twarn?.(\n\t\t\t\t`Ignoring glob-bearing Cursor CLI deny command (exact full commands only; glob support is unproven): ${command}`,\n\t\t\t);\n\t\t\tcontinue;\n\t\t}\n\t\tkept.push(command);\n\t}\n\treturn kept;\n}\n\n/**\n * Decide whether a turn may run unattended.\n *\n * - `--force` is emitted only in agent mode, only when force is requested, and\n * only after `noApprovalAcknowledgedAt` is set; otherwise the decision is a\n * typed refusal naming the acknowledgement step.\n * - Plan mode never emits `--force` (the CLI only plans), so it needs no\n * acknowledgement.\n * - Force disabled in agent mode is allowed but warns once per session.\n * - Unproven sandbox modes are ignored with one warning per distinct value.\n */\n/**\n * True while the settings guarantee an unattended agent-mode refusal: force is\n * requested outside plan mode but `noApprovalAcknowledgedAt` was never set.\n * Shared by the execution policy and the fallback-eligibility hook so the two\n * can never disagree about when the lane refuses.\n */\nexport function cursorCliForceRefusalPending(\n\tinput: Pick<CursorCliExecutionPolicyInput, \"forceExecution\" | \"noApprovalAcknowledgedAt\" | \"executionMode\">,\n): boolean {\n\treturn input.executionMode !== \"plan\" && input.forceExecution && input.noApprovalAcknowledgedAt === undefined;\n}\n\nexport function resolveCursorCliExecutionPolicy(\n\tinput: CursorCliExecutionPolicyInput,\n\tsession: CursorCliGuardrailSession,\n\tdenyCommands: readonly string[] = [],\n): CursorCliExecutionDecision {\n\tconst planMode = input.executionMode === \"plan\";\n\tconst wantsForce = !planMode && input.forceExecution;\n\tif (cursorCliForceRefusalPending(input)) {\n\t\tconst refusal: CursorCliExecutionRefusal = {\n\t\t\tkind: \"refusal\",\n\t\t\tcode: \"no_approval_acknowledgement_required\",\n\t\t\tmessage: `${CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION} ${CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP}`,\n\t\t\tacknowledgementStep: CURSOR_CLI_OAUTH_ACKNOWLEDGEMENT_STEP,\n\t\t};\n\t\treturn { status: \"refused\", refusal };\n\t}\n\tif (!planMode && !input.forceExecution) {\n\t\tsession.warn(\"force_execution_disabled\", CURSOR_CLI_OAUTH_FORCE_DISABLED_WARNING);\n\t}\n\tconst sandboxMode = session.validateSandboxMode(input.sandboxMode);\n\tconst sanitizedDenyCommands = sanitizeCursorCliDenyCommands(denyCommands, (message) => {\n\t\tsession.warn(\"deny_command_rejected\", message, `deny_command_rejected:${message}`);\n\t});\n\treturn {\n\t\tstatus: \"allowed\",\n\t\tforce: wantsForce,\n\t\texecutionMode: input.executionMode,\n\t\tsandboxMode,\n\t\tdenyCommands: sanitizedDenyCommands,\n\t\twarnings: [...session.warnings],\n\t};\n}\n\nconst CLI_CONFIG_RELATIVE_PATH = join(\".cursor\", \"cli-config.json\");\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction shellDenyEntry(command: string): string {\n\treturn `Shell(${command})`;\n}\n\n/**\n * Pre-spawn hook: (re-)apply the deny list to the sandbox HOME's\n * `cli-config.json`.\n *\n * The CLI rewrites this file during every invocation (task 2 observed its own\n * keys appearing and `cli-config.json.bad` sidecars for malformed content), so\n * this must run immediately before each spawn, composing with the home-store\n * prepare pass that re-writes `auth.json` on the same cadence. Writes only the\n * probe-proven shape (`permissions.deny` with exact `Shell(<full command>)`\n * entries) and preserves every CLI-owned key already present. Writes nothing\n * when no deny commands are configured.\n */\nexport function applyCursorCliDenyConfig(home: string, denyCommands: readonly string[]): void {\n\tif (denyCommands.length === 0) return;\n\tconst configPath = join(home, CLI_CONFIG_RELATIVE_PATH);\n\tlet existing: Record<string, unknown> = {};\n\tif (existsSync(configPath)) {\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(readFileSync(configPath, \"utf8\"));\n\t\t\tif (isRecord(parsed)) existing = parsed;\n\t\t} catch {\n\t\t\t// The CLI quarantines unparseable config as cli-config.json.bad and\n\t\t\t// proceeds with defaults; start from the proven minimal shape.\n\t\t}\n\t}\n\tconst permissions = isRecord(existing.permissions) ? { ...existing.permissions } : {};\n\tconst config: Record<string, unknown> = {\n\t\t...existing,\n\t\tpermissions: { ...permissions, deny: denyCommands.map(shellDenyEntry) },\n\t};\n\twriteFileSync(configPath, `${JSON.stringify(config, null, \"\\t\")}\\n`, \"utf8\");\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AAMxE,OAAO,EACN,KAAK,8BAA8B,EAInC,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,mEAAmE;AACnE,MAAM,MAAM,2BAA2B,GAAG;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC7D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC/F,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,8BAA8B,CAAC;IACxE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC/E,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,2BAAgC,GAAG,IAAI,CAkE9G;AAED,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAEtE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGzE,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AAOxE,OAAO,EACN,KAAK,8BAA8B,EAInC,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,4BAA4B,EAAE,MAAM,kBAAkB,CAAC;AAChE,YAAY,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEvD,mEAAmE;AACnE,MAAM,MAAM,2BAA2B,GAAG;IACzC,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC7D,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC/F,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,8BAA8B,CAAC;IACxE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;CAC/E,CAAC;AAKF;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,2BAAgC,GAAG,IAAI,CA4E9G;AAED,MAAM,CAAC,OAAO,UAAU,uBAAuB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAEtE"}
@@ -2,6 +2,7 @@ import { getAgentDir } from "../../../../config.js";
2
2
  import { AuthStorage } from "../../../auth-storage.js";
3
3
  import { registerCursorCliAccountCommand } from "./account-command.js";
4
4
  import { defaultCursorAgentExecutableDeps, resolveCursorAgentExecutable } from "./executable.js";
5
+ import { cursorCliForceRefusalPending } from "./guardrails.js";
5
6
  import { resolveCursorCliModelCatalog, STATIC_CURSOR_CLI_MODELS } from "./models.js";
6
7
  import { createCursorCliOauthCredentialReader } from "./native-bootstrap.js";
7
8
  import { CURSOR_CLI_OAUTH_PROVIDER_ID, createCursorCliOauthConfig } from "./oauth-login.js";
@@ -23,9 +24,11 @@ export function registerCursorCliOauthExtension(pi, deps = {}) {
23
24
  createCursorCliOauthCredentialReader({
24
25
  store,
25
26
  readNativeCredential: deps.readNativeCredential ?? (() => store.read("cursor")),
27
+ // Copying the host's native Cursor credential IS the ambient lane, so it
28
+ // requires the explicit flag - never merely a logged-in cursor-agent.
26
29
  canBootstrap: () => {
27
30
  const settings = loadSettings(cwd);
28
- if (!settings.enabled)
31
+ if (!settings.enabled || settings.explicitlyDisabled)
29
32
  return false;
30
33
  try {
31
34
  resolveExecutable(settings);
@@ -49,6 +52,14 @@ export function registerCursorCliOauthExtension(pi, deps = {}) {
49
52
  // Settings, accounts, and the executable are re-resolved inside every
50
53
  // turn; nothing captured here outlives a settings or credential change.
51
54
  streamSimple: (model, context, options) => streamCursorCliOauth(model, context, options, { cwd, agentDir, store }),
55
+ // A kill-switched lane, or one whose unacknowledged --force gate
56
+ // guarantees a refusal, must not consume an implicit fallback-expansion
57
+ // slot it can never serve. Only deterministic settings-level states
58
+ // exclude; explicit selection and /login stay available either way.
59
+ fallbackEligible: () => {
60
+ const current = loadSettings(cwd);
61
+ return !current.explicitlyDisabled && !cursorCliForceRefusalPending(current);
62
+ },
52
63
  oauth: createCursorCliOauthConfig({
53
64
  readCurrent,
54
65
  readSettings: () => loadSettings(cwd),
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Credential, CredentialStore } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../../../../config.ts\";\nimport { AuthStorage } from \"../../../auth-storage.ts\";\nimport type { ExtensionAPI, ProviderModelConfig } from \"../../types.ts\";\nimport { registerCursorCliAccountCommand } from \"./account-command.ts\";\nimport { defaultCursorAgentExecutableDeps, resolveCursorAgentExecutable } from \"./executable.ts\";\nimport { resolveCursorCliModelCatalog, STATIC_CURSOR_CLI_MODELS } from \"./models.ts\";\nimport { createCursorCliOauthCredentialReader } from \"./native-bootstrap.ts\";\nimport { CURSOR_CLI_OAUTH_PROVIDER_ID, createCursorCliOauthConfig } from \"./oauth-login.ts\";\nimport {\n\ttype CursorCliOauthProviderSettings,\n\tloadCursorCliOauthProviderSettingsFromDisk,\n\tpersistCursorCliNoApprovalAcknowledgement,\n\tpersistCursorCliOauthEnabled,\n} from \"./settings.ts\";\nimport { streamCursorCliOauth } from \"./stream.ts\";\n\nexport { CURSOR_CLI_OAUTH_PROVIDER_ID } from \"./oauth-login.ts\";\nexport type { CursorCliStreamDeps } from \"./stream.ts\";\n\n/** Injectable seams; every default resolves real on-disk state. */\nexport type CursorCliOauthExtensionDeps = {\n\treadonly cwd?: string;\n\treadonly agentDir?: string;\n\treadonly store?: CredentialStore;\n\treadonly readCurrent?: () => Promise<Credential | undefined>;\n\treadonly readNativeCredential?: () => Credential | undefined | Promise<Credential | undefined>;\n\treadonly loadSettings?: (cwd: string) => CursorCliOauthProviderSettings;\n\treadonly resolveExecutable?: (settings: { executablePath?: string }) => string;\n};\n\nconst defaultResolveExecutable = (settings: { executablePath?: string }): string =>\n\tresolveCursorAgentExecutable({ ...defaultCursorAgentExecutableDeps(), settings });\n\n/**\n * Registers the cursor-cli-oauth provider lane. Registration is unconditional:\n * the provider ships with the offline model fallback and reports availability\n * through the oauth `check`, so a missing cursor-agent binary never hides the\n * lane - it only makes `check` name the install guidance.\n */\nexport function registerCursorCliOauthExtension(pi: ExtensionAPI, deps: CursorCliOauthExtensionDeps = {}): void {\n\tconst cwd = deps.cwd ?? process.cwd();\n\tconst agentDir = deps.agentDir ?? getAgentDir();\n\tconst store = deps.store ?? AuthStorage.create();\n\tconst readCurrent =\n\t\tdeps.readCurrent ??\n\t\tcreateCursorCliOauthCredentialReader({\n\t\t\tstore,\n\t\t\treadNativeCredential: deps.readNativeCredential ?? (() => store.read(\"cursor\")),\n\t\t\tcanBootstrap: () => {\n\t\t\t\tconst settings = loadSettings(cwd);\n\t\t\t\tif (!settings.enabled) return false;\n\t\t\t\ttry {\n\t\t\t\t\tresolveExecutable(settings);\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\tconst loadSettings = deps.loadSettings ?? loadCursorCliOauthProviderSettingsFromDisk;\n\tconst resolveExecutable = deps.resolveExecutable ?? defaultResolveExecutable;\n\n\t// Todo 21: /cursor-account command plus the reload/shutdown teardown for\n\t// this extension generation (minimal additive wiring).\n\tregisterCursorCliAccountCommand(pi);\n\n\tconst register = (models: readonly ProviderModelConfig[]): void => {\n\t\tpi.registerProvider(CURSOR_CLI_OAUTH_PROVIDER_ID, {\n\t\t\tbaseUrl: CURSOR_CLI_OAUTH_PROVIDER_ID,\n\t\t\tapi: CURSOR_CLI_OAUTH_PROVIDER_ID,\n\t\t\tmodels: models.map((entry) => ({ ...entry })),\n\t\t\t// Settings, accounts, and the executable are re-resolved inside every\n\t\t\t// turn; nothing captured here outlives a settings or credential change.\n\t\t\tstreamSimple: (model, context, options) =>\n\t\t\t\tstreamCursorCliOauth(model, context, options, { cwd, agentDir, store }),\n\t\t\toauth: createCursorCliOauthConfig({\n\t\t\t\treadCurrent,\n\t\t\t\treadSettings: () => loadSettings(cwd),\n\t\t\t\tresolveExecutable,\n\t\t\t\tpersistAcknowledgement: (acknowledgedAt) => persistCursorCliNoApprovalAcknowledgement(cwd, acknowledgedAt),\n\t\t\t\tpersistEnabled: (enabled) => persistCursorCliOauthEnabled(cwd, enabled),\n\t\t\t}),\n\t\t});\n\t};\n\n\t// Register immediately with the offline fallback so a missing, hanging, or\n\t// broken cursor-agent can never delay or block provider registration; the\n\t// probe-backed catalog replaces it once resolved.\n\tregister(STATIC_CURSOR_CLI_MODELS);\n\tconst settings = loadSettings(cwd);\n\tvoid resolveCursorCliModelCatalog({\n\t\tagentDir,\n\t\tsettings: {\n\t\t\tmodelCatalogTtlHours: settings.modelCatalogTtlHours,\n\t\t\texecutablePath: settings.executablePath,\n\t\t},\n\t\tdeps: { resolveExecutable: () => resolveExecutable({ executablePath: settings.executablePath }) },\n\t})\n\t\t.then((models) => {\n\t\t\tconst resolved = models.map((entry) => entry.id).join(\"\\n\");\n\t\t\tif (resolved !== STATIC_CURSOR_CLI_MODELS.map((entry) => entry.id).join(\"\\n\")) register(models);\n\t\t})\n\t\t.catch(() => {\n\t\t\t// The loader degrades to the static fallback itself; keep the registered fallback.\n\t\t});\n}\n\nexport default function cursorCliOauthExtension(pi: ExtensionAPI): void {\n\tregisterCursorCliOauthExtension(pi);\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/index.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Credential, CredentialStore } from \"@earendil-works/pi-ai\";\nimport { getAgentDir } from \"../../../../config.ts\";\nimport { AuthStorage } from \"../../../auth-storage.ts\";\nimport type { ExtensionAPI, ProviderModelConfig } from \"../../types.ts\";\nimport { registerCursorCliAccountCommand } from \"./account-command.ts\";\nimport { defaultCursorAgentExecutableDeps, resolveCursorAgentExecutable } from \"./executable.ts\";\nimport { cursorCliForceRefusalPending } from \"./guardrails.ts\";\nimport { resolveCursorCliModelCatalog, STATIC_CURSOR_CLI_MODELS } from \"./models.ts\";\nimport { createCursorCliOauthCredentialReader } from \"./native-bootstrap.ts\";\nimport { CURSOR_CLI_OAUTH_PROVIDER_ID, createCursorCliOauthConfig } from \"./oauth-login.ts\";\nimport {\n\ttype CursorCliOauthProviderSettings,\n\tloadCursorCliOauthProviderSettingsFromDisk,\n\tpersistCursorCliNoApprovalAcknowledgement,\n\tpersistCursorCliOauthEnabled,\n} from \"./settings.ts\";\nimport { streamCursorCliOauth } from \"./stream.ts\";\n\nexport { CURSOR_CLI_OAUTH_PROVIDER_ID } from \"./oauth-login.ts\";\nexport type { CursorCliStreamDeps } from \"./stream.ts\";\n\n/** Injectable seams; every default resolves real on-disk state. */\nexport type CursorCliOauthExtensionDeps = {\n\treadonly cwd?: string;\n\treadonly agentDir?: string;\n\treadonly store?: CredentialStore;\n\treadonly readCurrent?: () => Promise<Credential | undefined>;\n\treadonly readNativeCredential?: () => Credential | undefined | Promise<Credential | undefined>;\n\treadonly loadSettings?: (cwd: string) => CursorCliOauthProviderSettings;\n\treadonly resolveExecutable?: (settings: { executablePath?: string }) => string;\n};\n\nconst defaultResolveExecutable = (settings: { executablePath?: string }): string =>\n\tresolveCursorAgentExecutable({ ...defaultCursorAgentExecutableDeps(), settings });\n\n/**\n * Registers the cursor-cli-oauth provider lane. Registration is unconditional:\n * the provider ships with the offline model fallback and reports availability\n * through the oauth `check`, so a missing cursor-agent binary never hides the\n * lane - it only makes `check` name the install guidance.\n */\nexport function registerCursorCliOauthExtension(pi: ExtensionAPI, deps: CursorCliOauthExtensionDeps = {}): void {\n\tconst cwd = deps.cwd ?? process.cwd();\n\tconst agentDir = deps.agentDir ?? getAgentDir();\n\tconst store = deps.store ?? AuthStorage.create();\n\tconst readCurrent =\n\t\tdeps.readCurrent ??\n\t\tcreateCursorCliOauthCredentialReader({\n\t\t\tstore,\n\t\t\treadNativeCredential: deps.readNativeCredential ?? (() => store.read(\"cursor\")),\n\t\t\t// Copying the host's native Cursor credential IS the ambient lane, so it\n\t\t\t// requires the explicit flag - never merely a logged-in cursor-agent.\n\t\t\tcanBootstrap: () => {\n\t\t\t\tconst settings = loadSettings(cwd);\n\t\t\t\tif (!settings.enabled || settings.explicitlyDisabled) return false;\n\t\t\t\ttry {\n\t\t\t\t\tresolveExecutable(settings);\n\t\t\t\t\treturn true;\n\t\t\t\t} catch {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t},\n\t\t});\n\tconst loadSettings = deps.loadSettings ?? loadCursorCliOauthProviderSettingsFromDisk;\n\tconst resolveExecutable = deps.resolveExecutable ?? defaultResolveExecutable;\n\n\t// Todo 21: /cursor-account command plus the reload/shutdown teardown for\n\t// this extension generation (minimal additive wiring).\n\tregisterCursorCliAccountCommand(pi);\n\n\tconst register = (models: readonly ProviderModelConfig[]): void => {\n\t\tpi.registerProvider(CURSOR_CLI_OAUTH_PROVIDER_ID, {\n\t\t\tbaseUrl: CURSOR_CLI_OAUTH_PROVIDER_ID,\n\t\t\tapi: CURSOR_CLI_OAUTH_PROVIDER_ID,\n\t\t\tmodels: models.map((entry) => ({ ...entry })),\n\t\t\t// Settings, accounts, and the executable are re-resolved inside every\n\t\t\t// turn; nothing captured here outlives a settings or credential change.\n\t\t\tstreamSimple: (model, context, options) =>\n\t\t\t\tstreamCursorCliOauth(model, context, options, { cwd, agentDir, store }),\n\t\t\t// A kill-switched lane, or one whose unacknowledged --force gate\n\t\t\t// guarantees a refusal, must not consume an implicit fallback-expansion\n\t\t\t// slot it can never serve. Only deterministic settings-level states\n\t\t\t// exclude; explicit selection and /login stay available either way.\n\t\t\tfallbackEligible: () => {\n\t\t\t\tconst current = loadSettings(cwd);\n\t\t\t\treturn !current.explicitlyDisabled && !cursorCliForceRefusalPending(current);\n\t\t\t},\n\t\t\toauth: createCursorCliOauthConfig({\n\t\t\t\treadCurrent,\n\t\t\t\treadSettings: () => loadSettings(cwd),\n\t\t\t\tresolveExecutable,\n\t\t\t\tpersistAcknowledgement: (acknowledgedAt) => persistCursorCliNoApprovalAcknowledgement(cwd, acknowledgedAt),\n\t\t\t\tpersistEnabled: (enabled) => persistCursorCliOauthEnabled(cwd, enabled),\n\t\t\t}),\n\t\t});\n\t};\n\n\t// Register immediately with the offline fallback so a missing, hanging, or\n\t// broken cursor-agent can never delay or block provider registration; the\n\t// probe-backed catalog replaces it once resolved.\n\tregister(STATIC_CURSOR_CLI_MODELS);\n\tconst settings = loadSettings(cwd);\n\tvoid resolveCursorCliModelCatalog({\n\t\tagentDir,\n\t\tsettings: {\n\t\t\tmodelCatalogTtlHours: settings.modelCatalogTtlHours,\n\t\t\texecutablePath: settings.executablePath,\n\t\t},\n\t\tdeps: { resolveExecutable: () => resolveExecutable({ executablePath: settings.executablePath }) },\n\t})\n\t\t.then((models) => {\n\t\t\tconst resolved = models.map((entry) => entry.id).join(\"\\n\");\n\t\t\tif (resolved !== STATIC_CURSOR_CLI_MODELS.map((entry) => entry.id).join(\"\\n\")) register(models);\n\t\t})\n\t\t.catch(() => {\n\t\t\t// The loader degrades to the static fallback itself; keep the registered fallback.\n\t\t});\n}\n\nexport default function cursorCliOauthExtension(pi: ExtensionAPI): void {\n\tregisterCursorCliOauthExtension(pi);\n}\n"]}
@@ -4,7 +4,18 @@ import { type CursorCliOauthProviderSettings } from "./settings.ts";
4
4
  export declare const CURSOR_CLI_OAUTH_PROVIDER_ID = "cursor-cli-oauth";
5
5
  export declare const CURSOR_CLI_OAUTH_NAME = "Cursor CLI (OAuth)";
6
6
  declare const FILE_STORE_LANE: "file-store";
7
- type CursorCliOauthSettings = Pick<CursorCliOauthProviderSettings, "enabled" | "executablePath">;
7
+ type CursorCliOauthSettings = Pick<CursorCliOauthProviderSettings, "enabled" | "executablePath"> & Partial<Pick<CursorCliOauthProviderSettings, "explicitlyDisabled">>;
8
+ /**
9
+ * The opt-in rule, in one place so availability, turn-time resolution, and the
10
+ * host-derived bootstrap gate cannot disagree.
11
+ *
12
+ * - `enabled: false` written verbatim in settings or the environment is a kill
13
+ * switch: the lane is off regardless of what is stored.
14
+ * - Otherwise the flag gates only the host-CLI-derived opt-in. Stored senpi account slots
15
+ * exist only because the user ran `/login cursor-cli-oauth` or
16
+ * `/cursor-account import`, and that explicit action IS the opt-in.
17
+ */
18
+ export declare function isCursorCliOauthLaneEnabled(settings: CursorCliOauthSettings, storedAccountCount: number): boolean;
8
19
  type ImportedCursorCredential = {
9
20
  access: string;
10
21
  refresh: string;
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-login.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/oauth-login.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-login.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/oauth-login.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EAEnB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAEN,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAI7B,MAAM,eAAe,CAAC;AAOvB,OAAO,EACN,KAAK,8BAA8B,EAInC,MAAM,eAAe,CAAC;AAEvB,eAAO,MAAM,4BAA4B,qBAAqB,CAAC;AAC/D,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAI1D,QAAA,MAAM,eAAe,EAAG,YAAqB,CAAC;AAG9C,KAAK,sBAAsB,GAAG,IAAI,CAAC,8BAA8B,EAAE,SAAS,GAAG,gBAAgB,CAAC,GAC/F,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAErE;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAGjH;AAED,KAAK,wBAAwB,GAAG;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACtC,WAAW,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IACnD,YAAY,EAAE,MAAM,sBAAsB,CAAC;IAC3C,iBAAiB,EAAE,CAAC,QAAQ,EAAE,sBAAsB,KAAK,MAAM,CAAC;IAChE,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACzE,oFAAoF;IACpF,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,0GAA0G;IAC1G,sBAAsB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,sEAAsE;IACtE,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IAC1C,IAAI,EAAE,OAAO,eAAe,CAAC;IAC7B,OAAO,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,EAAE,oBAAoB,EAAE,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,EAAE,IAAI,CAAC;IACrB,KAAK,CAAC,KAAK,EAAE;QACZ,GAAG,EAAE,WAAW,CAAC;QACjB,UAAU,CAAC,EAAE,eAAe,CAAC;QAC7B,MAAM,CAAC,EAAE,WAAW,CAAC;KACrB,GAAG,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,SAAS,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACjE,YAAY,CAAC,WAAW,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC5F,SAAS,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACrE,kBAAkB,CAAC,EAAE,MAAM,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC,CAAC;IACzE,QAAQ,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC;CAC3C,CAAC;AAiFF;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,CAKlE;AAED,qHAAqH;AACrH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,wBAAwB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAKrH;AAsED,sHAAsH;AACtH,eAAO,MAAM,kDAAkD,yPAAyI,CAAC;AAIzM;;;;;GAKG;AACH,wBAAsB,yCAAyC,CAC9D,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,GAAG,SAAS,EAC9F,GAAG,EAAE,MAAM,IAAI,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAU7B;AAED,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,wBAAwB,GAAG,oBAAoB,CAkF/F;AAyDD,qGAAqG;AACrG,wBAAsB,2BAA2B,CAChD,OAAO,EAAE,wBAAwB,EACjC,IAAI,GAAE,qBAA0B,GAC9B,OAAO,CAAC,wBAAwB,CAAC,CAoBnC;AAwBD,gGAAgG;AAChG,wBAAsB,4BAA4B,CACjD,OAAO,EAAE,wBAAwB,EACjC,oBAAoB,EAAE,MAAM,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GAClF,OAAO,CAAC,wBAAwB,CAAC,CAMnC;AAED,wBAAgB,2BAA2B,CAC1C,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,GAChD,oBAAoB,CAgBtB"}
@@ -13,6 +13,21 @@ const NO_ACCOUNTS_MESSAGE = "no accounts: run /login cursor-cli-oauth";
13
13
  const DISABLED_MESSAGE = "disabled by settings";
14
14
  const FILE_STORE_LANE = "file-store";
15
15
  const DEFAULT_IMPORTED_EXPIRY_MS = 60 * 60 * 1000;
16
+ /**
17
+ * The opt-in rule, in one place so availability, turn-time resolution, and the
18
+ * host-derived bootstrap gate cannot disagree.
19
+ *
20
+ * - `enabled: false` written verbatim in settings or the environment is a kill
21
+ * switch: the lane is off regardless of what is stored.
22
+ * - Otherwise the flag gates only the host-CLI-derived opt-in. Stored senpi account slots
23
+ * exist only because the user ran `/login cursor-cli-oauth` or
24
+ * `/cursor-account import`, and that explicit action IS the opt-in.
25
+ */
26
+ export function isCursorCliOauthLaneEnabled(settings, storedAccountCount) {
27
+ if (settings.explicitlyDisabled === true)
28
+ return false;
29
+ return settings.enabled || storedAccountCount > 0;
30
+ }
16
31
  /**
17
32
  * One predicate so availability and resolution cannot disagree: evaluates the
18
33
  * same conditions for every caller and reports why the lane is unusable
@@ -20,7 +35,7 @@ const DEFAULT_IMPORTED_EXPIRY_MS = 60 * 60 * 1000;
20
35
  */
21
36
  async function assessConfiguration(deps) {
22
37
  const settings = deps.readSettings();
23
- if (!settings.enabled)
38
+ if (settings.explicitlyDisabled === true)
24
39
  return { status: "disabled" };
25
40
  try {
26
41
  deps.resolveExecutable(settings);
@@ -28,7 +43,11 @@ async function assessConfiguration(deps) {
28
43
  catch (error) {
29
44
  return { status: "not-installed", error };
30
45
  }
46
+ // Read the stored slots before applying the flag: an explicit senpi-side login
47
+ // is itself the opt-in, so only the flagless host-derived shape reports disabled.
31
48
  const accounts = usableAccounts(await deps.readCurrent());
49
+ if (!isCursorCliOauthLaneEnabled(settings, accounts.length))
50
+ return { status: "disabled" };
32
51
  if (accounts.length === 0)
33
52
  return { status: "no-accounts" };
34
53
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-login.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/oauth-login.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile as nodeExecFile } from \"node:child_process\";\nimport { readFile as nodeReadFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tAuthCheck,\n\tAuthContext,\n\tCredential,\n\tOAuthAuth,\n\tOAuthCredential,\n\tOAuthCredentials,\n\tOAuthLoginCallbacks,\n\tProviderAuthInteraction,\n} from \"@earendil-works/pi-ai\";\nimport { cursorProvider } from \"@earendil-works/pi-ai/providers/cursor\";\nimport {\n\taddAccount,\n\ttype CursorCliAccountSlot,\n\ttype CursorCliOauthCredential,\n\temptyCredential,\n\tlistAccounts,\n\tSENTINEL_OAUTH_FIELDS,\n} from \"./accounts.ts\";\nimport {\n\ttype CursorAgentExecutableDeps,\n\tdefaultCursorAgentExecutableDeps,\n\tresolveCursorAgentExecutable,\n} from \"./executable.ts\";\nimport { CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION } from \"./guardrails.ts\";\nimport {\n\ttype CursorCliOauthProviderSettings,\n\tloadCursorCliOauthProviderSettingsFromDisk,\n\tpersistCursorCliNoApprovalAcknowledgement,\n\tpersistCursorCliOauthEnabled,\n} from \"./settings.ts\";\n\nexport const CURSOR_CLI_OAUTH_PROVIDER_ID = \"cursor-cli-oauth\";\nexport const CURSOR_CLI_OAUTH_NAME = \"Cursor CLI (OAuth)\";\n\nconst NO_ACCOUNTS_MESSAGE = \"no accounts: run /login cursor-cli-oauth\";\nconst DISABLED_MESSAGE = \"disabled by settings\";\nconst FILE_STORE_LANE = \"file-store\" as const;\nconst DEFAULT_IMPORTED_EXPIRY_MS = 60 * 60 * 1000;\n\ntype CursorCliOauthSettings = Pick<CursorCliOauthProviderSettings, \"enabled\" | \"executablePath\">;\n\ntype ImportedCursorCredential = {\n\taccess: string;\n\trefresh: string;\n\texpires?: number;\n};\n\nexport type CursorCliOauthConfigDeps = {\n\treadCurrent: () => Promise<Credential | undefined>;\n\treadSettings: () => CursorCliOauthSettings;\n\tresolveExecutable: (settings: CursorCliOauthSettings) => string;\n\tloadOAuth?: () => Promise<OAuthAuth>;\n\treadCursorFile?: () => Promise<ImportedCursorCredential | undefined>;\n\treadCursorKeychain?: () => Promise<ImportedCursorCredential | undefined>;\n\t/** Clock for acknowledgement timestamps; injectable so tests stay deterministic. */\n\tnow?: () => Date;\n\t/** Persists the no-approval acknowledgement; the disk default is wired in defaultCursorCliOauthConfig. */\n\tpersistAcknowledgement?: (acknowledgedAt: string) => void;\n\t/** Persists explicit provider activation after a successful login. */\n\tpersistEnabled?: (enabled: boolean) => void;\n};\n\nexport type CursorCliOauthLaneResolution = {\n\tlane: typeof FILE_STORE_LANE;\n\taccount: CursorCliAccountSlot;\n\taccounts: CursorCliAccountSlot[];\n};\n\nexport type CursorCliOauthConfig = {\n\tname: string;\n\tisSubscription: true;\n\tcheck(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: OAuthCredential;\n\t\tsignal?: AbortSignal;\n\t}): Promise<AuthCheck | undefined>;\n\tlogin(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;\n\trefreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials>;\n\tgetApiKey(credentials: OAuthCredentials): string;\n};\n\nexport type LocalCursorImportDeps = {\n\tplatform?: NodeJS.Platform;\n\treadCursorFile?: () => Promise<ImportedCursorCredential | undefined>;\n\treadCursorKeychain?: () => Promise<ImportedCursorCredential | undefined>;\n\tonPrompt?: OAuthLoginCallbacks[\"onPrompt\"];\n};\n\ntype ConfigurationAssessment = {\n\taccounts: CursorCliAccountSlot[];\n\tmessage: string;\n};\n\n/** The single condition evaluation behind both the tolerant `check` and the throwing turn-time resolution. */\ntype ConfigurationOutcome =\n\t| { status: \"disabled\" }\n\t| { status: \"not-installed\"; error: unknown }\n\t| { status: \"no-accounts\" }\n\t| { status: \"configured\"; assessment: ConfigurationAssessment };\n\n/**\n * One predicate so availability and resolution cannot disagree: evaluates the\n * same conditions for every caller and reports why the lane is unusable\n * instead of deciding per call-site whether that is fatal.\n */\nasync function assessConfiguration(deps: CursorCliOauthConfigDeps): Promise<ConfigurationOutcome> {\n\tconst settings = deps.readSettings();\n\tif (!settings.enabled) return { status: \"disabled\" };\n\ttry {\n\t\tdeps.resolveExecutable(settings);\n\t} catch (error) {\n\t\treturn { status: \"not-installed\", error };\n\t}\n\n\tconst accounts = usableAccounts(await deps.readCurrent());\n\tif (accounts.length === 0) return { status: \"no-accounts\" };\n\treturn {\n\t\tstatus: \"configured\",\n\t\tassessment: { accounts, message: `configured (file-store, ${accounts.length} accounts)` },\n\t};\n}\n\n/** The throwing view used by turn-time resolution; a turn attempted on an unusable lane must still error clearly. */\nasync function configuredFor(deps: CursorCliOauthConfigDeps): Promise<ConfigurationAssessment> {\n\tconst outcome = await assessConfiguration(deps);\n\tswitch (outcome.status) {\n\t\tcase \"disabled\":\n\t\t\tthrow new Error(DISABLED_MESSAGE);\n\t\tcase \"not-installed\":\n\t\t\tthrow cursorAgentNotInstalledError(outcome.error);\n\t\tcase \"no-accounts\":\n\t\t\tthrow new Error(NO_ACCOUNTS_MESSAGE);\n\t\tdefault:\n\t\t\treturn outcome.assessment;\n\t}\n}\n\nfunction isCursorCliOauthCredential(\n\tvalue: Credential | OAuthCredentials | undefined,\n): value is CursorCliOauthCredential {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = value as Partial<CursorCliOauthCredential>;\n\treturn candidate.type === \"oauth\" && Array.isArray(candidate.accounts);\n}\n\nfunction usableAccounts(value: Credential | OAuthCredentials | undefined): CursorCliAccountSlot[] {\n\tif (!isCursorCliOauthCredential(value)) return [];\n\treturn listAccounts(value).filter(\n\t\t(slot) =>\n\t\t\ttypeof slot.name === \"string\" &&\n\t\t\ttypeof slot.access === \"string\" &&\n\t\t\tslot.access.trim().length > 0 &&\n\t\t\ttypeof slot.refresh === \"string\" &&\n\t\t\tslot.refresh.trim().length > 0 &&\n\t\t\ttypeof slot.expires === \"number\" &&\n\t\t\tNumber.isFinite(slot.expires),\n\t);\n}\n\nfunction installationMessage(error: unknown): string {\n\tconst detail = error instanceof Error ? error.message : String(error);\n\treturn `cursor-agent not installed: ${detail.replace(/^Cursor CLI is not installed\\.\\s*/, \"\")}`;\n}\n\n/**\n * The typed turn-path error for a missing cursor-agent binary: carries the\n * `cursor-agent not installed` marker plus the install guidance verbatim, with\n * the underlying resolution failure preserved as `cause`.\n */\nexport function cursorAgentNotInstalledError(cause: unknown): Error {\n\tconst error = new Error(installationMessage(cause));\n\terror.name = \"CursorAgentNotInstalledError\";\n\terror.cause = cause;\n\treturn error;\n}\n\n/** Resolve credentials immediately before execution so a concurrent refresh cannot leave a stale token in memory. */\nexport async function resolveCursorCliOauthLane(deps: CursorCliOauthConfigDeps): Promise<CursorCliOauthLaneResolution> {\n\tconst assessment = await configuredFor(deps);\n\tconst account = assessment.accounts[0];\n\tif (!account) throw new Error(NO_ACCOUNTS_MESSAGE);\n\treturn { lane: FILE_STORE_LANE, account, accounts: assessment.accounts };\n}\n\nasync function loadCursorOAuthFlow(): Promise<OAuthAuth> {\n\tconst flow = cursorProvider().auth.oauth;\n\tif (!flow) throw new Error(\"Cursor OAuth flow is unavailable\");\n\treturn flow;\n}\n\nfunction providerInteraction(callbacks: OAuthLoginCallbacks): ProviderAuthInteraction {\n\treturn {\n\t\tsignal: callbacks.signal ?? new AbortController().signal,\n\t\tprompt: async (prompt) => {\n\t\t\tswitch (prompt.type) {\n\t\t\t\tcase \"select\":\n\t\t\t\t\treturn (await callbacks.onSelect(prompt)) ?? \"\";\n\t\t\t\tcase \"manual_code\":\n\t\t\t\t\treturn callbacks.onManualCodeInput?.() ?? callbacks.onPrompt(prompt);\n\t\t\t\tdefault:\n\t\t\t\t\treturn callbacks.onPrompt(prompt);\n\t\t\t}\n\t\t},\n\t\tnotify: (event) => {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase \"auth_url\":\n\t\t\t\t\tcallbacks.onAuth({ url: event.url, instructions: event.instructions });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"device_code\":\n\t\t\t\t\tcallbacks.onDeviceCode(event);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"progress\":\n\t\t\t\t\tcallbacks.onProgress?.(event.message);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"info\":\n\t\t\t\t\tcallbacks.onProgress?.(event.message);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t};\n}\n\nasync function accountName(\n\texisting: CursorCliAccountSlot[],\n\tonPrompt: OAuthLoginCallbacks[\"onPrompt\"] | undefined,\n): Promise<string> {\n\tif (existing.length === 0) return \"default\";\n\tconst fallback = `account-${existing.length + 1}`;\n\tif (!onPrompt) return fallback;\n\tconst answer = (\n\t\tawait onPrompt({\n\t\t\tmessage: `Name for this account (existing: ${existing.map((slot) => slot.name).join(\", \")})`,\n\t\t\tplaceholder: fallback,\n\t\t})\n\t).trim();\n\treturn answer || fallback;\n}\n\nfunction slotFromCredential(\n\tcredential: Pick<OAuthCredentials, \"access\" | \"refresh\" | \"expires\">,\n\tname: string,\n\tsource: CursorCliAccountSlot[\"source\"],\n): CursorCliAccountSlot {\n\treturn {\n\t\tname,\n\t\taccess: credential.access,\n\t\trefresh: credential.refresh,\n\t\texpires: credential.expires,\n\t\tsource,\n\t};\n}\n\n/** The one-screen login explanation: what unattended Cursor CLI execution gives up, and the plan-mode alternative. */\nexport const CURSOR_CLI_OAUTH_LOGIN_ACKNOWLEDGEMENT_EXPLANATION = `${CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION} Plan mode (planning only, no tool execution) is available via the executionMode setting.`;\n\nconst ACKNOWLEDGEMENT_ACCEPTANCE = new Set([\"yes\", \"y\"]);\n\n/**\n * Present the no-approval explanation exactly once and return the ISO\n * acknowledgement timestamp on explicit confirmation, undefined otherwise.\n * Shared by the login flow and the /cursor-account acknowledge subcommand so\n * both surfaces present the identical explanation and persist identically.\n */\nexport async function confirmCursorCliNoApprovalAcknowledgement(\n\tonPrompt: ((prompt: { message: string; placeholder?: string }) => Promise<string>) | undefined,\n\tnow: () => Date,\n): Promise<string | undefined> {\n\tif (!onPrompt) return undefined;\n\tconst answer = (\n\t\tawait onPrompt({\n\t\t\tmessage: `${CURSOR_CLI_OAUTH_LOGIN_ACKNOWLEDGEMENT_EXPLANATION}\\nType \"yes\" to acknowledge and allow unattended Cursor CLI tool execution; anything else leaves it off.`,\n\t\t})\n\t)\n\t\t.trim()\n\t\t.toLowerCase();\n\treturn ACKNOWLEDGEMENT_ACCEPTANCE.has(answer) ? now().toISOString() : undefined;\n}\n\nexport function createCursorCliOauthConfig(deps: CursorCliOauthConfigDeps): CursorCliOauthConfig {\n\treturn {\n\t\tname: CURSOR_CLI_OAUTH_NAME,\n\t\tisSubscription: true,\n\n\t\tasync check(input) {\n\t\t\t// Tolerant by contract: ModelsImpl.getAvailable runs every provider's\n\t\t\t// check under Promise.all (packages/ai/src/models.ts:544-548) and turns a\n\t\t\t// throw into a rejecting ModelsError, so one throwing check would reject\n\t\t\t// all model listing. Not usable (disabled / not installed / no accounts)\n\t\t\t// reports undefined here - as claude-sdk-oauth's check does - while\n\t\t\t// turn-time resolution keeps throwing via configuredFor.\n\t\t\t//\n\t\t\t// One nuance: the auth-resolution path (checkAuth, resolveStoredOAuth)\n\t\t\t// always passes the stored credential, while bare model listing does not.\n\t\t\t// A credential-backed lane whose executable is missing stays selectable\n\t\t\t// with the install guidance as its source, so a TURN reaches\n\t\t\t// streamCursorCliOauth, which throws the typed not-installed error;\n\t\t\t// without a credential the lane hides exactly as before.\n\t\t\tconst outcome = await assessConfiguration(deps);\n\t\t\tif (outcome.status === \"disabled\" || outcome.status === \"no-accounts\") return undefined;\n\t\t\tif (outcome.status === \"not-installed\") {\n\t\t\t\treturn input.credential === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: { type: \"oauth\", source: installationMessage(outcome.error) };\n\t\t\t}\n\t\t\treturn { type: \"oauth\", source: outcome.assessment.message };\n\t\t},\n\n\t\tasync login(callbacks) {\n\t\t\tconst stored = await deps.readCurrent();\n\t\t\tconst current = isCursorCliOauthCredential(stored) ? stored : emptyCredential();\n\t\t\tconst existing = listAccounts(current);\n\t\t\tconst flow = await (deps.loadOAuth ?? loadCursorOAuthFlow)();\n\t\t\tconst loggedIn = await flow.login(providerInteraction(callbacks));\n\t\t\tconst name = await accountName(existing, callbacks.onPrompt);\n\t\t\t// After the PKCE flow succeeds and before the slot is stored: the\n\t\t\t// one-screen no-approval explanation, confirmed once. Declining still\n\t\t\t// stores the slot; only the acknowledgement stays unset, so force turns\n\t\t\t// refuse until the user acknowledges later.\n\t\t\tconst acknowledgedAt = await confirmCursorCliNoApprovalAcknowledgement(\n\t\t\t\tcallbacks.onPrompt,\n\t\t\t\tdeps.now ?? (() => new Date()),\n\t\t\t);\n\t\t\tif (acknowledgedAt !== undefined) deps.persistAcknowledgement?.(acknowledgedAt);\n\t\t\tconst credential = addAccount(current, slotFromCredential(loggedIn, name, \"login\"));\n\t\t\tdeps.persistEnabled?.(true);\n\t\t\treturn credential;\n\t\t},\n\n\t\tasync refreshToken(credentials, signal) {\n\t\t\tif (!isCursorCliOauthCredential(credentials)) return credentials;\n\t\t\tconst flow = await (deps.loadOAuth ?? loadCursorOAuthFlow)();\n\t\t\tconst accounts: CursorCliAccountSlot[] = [];\n\t\t\tfor (const slot of listAccounts(credentials)) {\n\t\t\t\tif (Date.now() < slot.expires) {\n\t\t\t\t\taccounts.push(slot);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst refreshed = await flow.refresh(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"oauth\",\n\t\t\t\t\t\taccess: slot.access,\n\t\t\t\t\t\trefresh: slot.refresh,\n\t\t\t\t\t\texpires: slot.expires,\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\taccounts.push({\n\t\t\t\t\t...slot,\n\t\t\t\t\taccess: refreshed.access,\n\t\t\t\t\trefresh: refreshed.refresh,\n\t\t\t\t\texpires: refreshed.expires,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { ...credentials, ...SENTINEL_OAUTH_FIELDS, accounts };\n\t\t},\n\n\t\tgetApiKey() {\n\t\t\treturn SENTINEL_OAUTH_FIELDS.access;\n\t\t},\n\t};\n}\n\nfunction execFileOutput(file: string, args: string[]): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tnodeExecFile(file, args, { encoding: \"utf8\" }, (error, stdout) => {\n\t\t\tif (error) {\n\t\t\t\tresolve(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst value = stdout.trim();\n\t\t\tresolve(value.length > 0 ? value : undefined);\n\t\t});\n\t});\n}\n\nasync function defaultKeychainCredential(): Promise<ImportedCursorCredential | undefined> {\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst [access, refresh] = await Promise.all([\n\t\texecFileOutput(\"security\", [\"find-generic-password\", \"-a\", \"cursor-user\", \"-s\", \"cursor-access-token\", \"-w\"]),\n\t\texecFileOutput(\"security\", [\"find-generic-password\", \"-a\", \"cursor-user\", \"-s\", \"cursor-refresh-token\", \"-w\"]),\n\t]);\n\treturn access && refresh ? { access, refresh } : undefined;\n}\n\nfunction localCursorAuthPath(platform: NodeJS.Platform): string | undefined {\n\tswitch (platform) {\n\t\tcase \"darwin\":\n\t\t\treturn join(homedir(), \".cursor\", \"auth.json\");\n\t\tcase \"linux\":\n\t\t\treturn join(process.env.XDG_CONFIG_HOME ?? join(homedir(), \".config\"), \"cursor\", \"auth.json\");\n\t\tcase \"win32\": {\n\t\t\tconst appData = process.env.APPDATA;\n\t\t\treturn appData ? join(appData, \"Cursor\", \"auth.json\") : undefined;\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nasync function defaultFileCredential(platform: NodeJS.Platform): Promise<ImportedCursorCredential | undefined> {\n\tconst path = localCursorAuthPath(platform);\n\tif (!path) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(await nodeReadFile(path, \"utf8\"));\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\tconst access = record.accessToken;\n\t\tconst refresh = record.refreshToken;\n\t\tif (typeof access !== \"string\" || access.length === 0 || typeof refresh !== \"string\" || refresh.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn { access, refresh };\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** Explicitly copy the user's local Cursor credential into this provider's managed account slots. */\nexport async function importLocalCursorCredential(\n\tcurrent: CursorCliOauthCredential,\n\tdeps: LocalCursorImportDeps = {},\n): Promise<CursorCliOauthCredential> {\n\tconst platform = deps.platform ?? process.platform;\n\tconst readKeychain = deps.readCursorKeychain ?? defaultKeychainCredential;\n\tconst readFile = deps.readCursorFile ?? (() => defaultFileCredential(platform));\n\tconst imported = platform === \"darwin\" ? ((await readKeychain()) ?? (await readFile())) : await readFile();\n\tif (!imported) throw new Error(\"No local Cursor OAuth credential found\");\n\tconst existing = listAccounts(current);\n\tconst name = await accountName(existing, deps.onPrompt);\n\treturn addAccount(\n\t\tcurrent,\n\t\tslotFromCredential(\n\t\t\t{\n\t\t\t\taccess: imported.access,\n\t\t\t\trefresh: imported.refresh,\n\t\t\t\texpires: imported.expires ?? Date.now() + DEFAULT_IMPORTED_EXPIRY_MS,\n\t\t\t},\n\t\t\tname,\n\t\t\t\"import\",\n\t\t),\n\t);\n}\n\nfunction isUsableFlatOAuthCredential(value: Credential | undefined): value is OAuthCredential {\n\treturn (\n\t\tvalue?.type === \"oauth\" &&\n\t\ttypeof value.access === \"string\" &&\n\t\tvalue.access.length > 0 &&\n\t\ttypeof value.refresh === \"string\" &&\n\t\tvalue.refresh.length > 0 &&\n\t\ttypeof value.expires === \"number\" &&\n\t\tNumber.isFinite(value.expires)\n\t);\n}\n\nfunction nativeAccountName(existing: readonly CursorCliAccountSlot[]): string {\n\tconst names = new Set(existing.map((account) => account.name));\n\tif (!names.has(\"native\")) return \"native\";\n\tfor (let index = 2; index <= 10_000; index++) {\n\t\tconst candidate = `native-${index}`;\n\t\tif (!names.has(candidate)) return candidate;\n\t}\n\tthrow new Error(\"Could not allocate a Cursor CLI OAuth native account name\");\n}\n\n/** Explicitly copy Senpi's native `cursor` OAuth credential into a managed CLI account slot. */\nexport async function importNativeCursorCredential(\n\tcurrent: CursorCliOauthCredential,\n\treadNativeCredential: () => Credential | undefined | Promise<Credential | undefined>,\n): Promise<CursorCliOauthCredential> {\n\tconst native = await readNativeCredential();\n\tif (!isUsableFlatOAuthCredential(native)) {\n\t\tthrow new Error(\"No stored native Cursor OAuth credential found\");\n\t}\n\treturn addAccount(current, slotFromCredential(native, nativeAccountName(listAccounts(current)), \"import\"));\n}\n\nexport function defaultCursorCliOauthConfig(\n\tcwd: string,\n\treadCurrent: () => Promise<Credential | undefined>,\n): CursorCliOauthConfig {\n\treturn createCursorCliOauthConfig({\n\t\treadCurrent,\n\t\treadSettings: () => loadCursorCliOauthProviderSettingsFromDisk(cwd),\n\t\tresolveExecutable: (settings) => {\n\t\t\tconst executableDeps: CursorAgentExecutableDeps = {\n\t\t\t\t...defaultCursorAgentExecutableDeps(),\n\t\t\t\tsettings,\n\t\t\t};\n\t\t\treturn resolveCursorAgentExecutable(executableDeps);\n\t\t},\n\t\tnow: () => new Date(),\n\t\tpersistAcknowledgement: (acknowledgedAt: string) =>\n\t\t\tpersistCursorCliNoApprovalAcknowledgement(cwd, acknowledgedAt),\n\t\tpersistEnabled: (enabled: boolean) => persistCursorCliOauthEnabled(cwd, enabled),\n\t});\n}\n"]}
1
+ {"version":3,"file":"oauth-login.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/oauth-login.ts"],"names":[],"mappings":"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","sourcesContent":["import { execFile as nodeExecFile } from \"node:child_process\";\nimport { readFile as nodeReadFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type {\n\tAuthCheck,\n\tAuthContext,\n\tCredential,\n\tOAuthAuth,\n\tOAuthCredential,\n\tOAuthCredentials,\n\tOAuthLoginCallbacks,\n\tProviderAuthInteraction,\n} from \"@earendil-works/pi-ai\";\nimport { cursorProvider } from \"@earendil-works/pi-ai/providers/cursor\";\nimport {\n\taddAccount,\n\ttype CursorCliAccountSlot,\n\ttype CursorCliOauthCredential,\n\temptyCredential,\n\tlistAccounts,\n\tSENTINEL_OAUTH_FIELDS,\n} from \"./accounts.ts\";\nimport {\n\ttype CursorAgentExecutableDeps,\n\tdefaultCursorAgentExecutableDeps,\n\tresolveCursorAgentExecutable,\n} from \"./executable.ts\";\nimport { CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION } from \"./guardrails.ts\";\nimport {\n\ttype CursorCliOauthProviderSettings,\n\tloadCursorCliOauthProviderSettingsFromDisk,\n\tpersistCursorCliNoApprovalAcknowledgement,\n\tpersistCursorCliOauthEnabled,\n} from \"./settings.ts\";\n\nexport const CURSOR_CLI_OAUTH_PROVIDER_ID = \"cursor-cli-oauth\";\nexport const CURSOR_CLI_OAUTH_NAME = \"Cursor CLI (OAuth)\";\n\nconst NO_ACCOUNTS_MESSAGE = \"no accounts: run /login cursor-cli-oauth\";\nconst DISABLED_MESSAGE = \"disabled by settings\";\nconst FILE_STORE_LANE = \"file-store\" as const;\nconst DEFAULT_IMPORTED_EXPIRY_MS = 60 * 60 * 1000;\n\ntype CursorCliOauthSettings = Pick<CursorCliOauthProviderSettings, \"enabled\" | \"executablePath\"> &\n\tPartial<Pick<CursorCliOauthProviderSettings, \"explicitlyDisabled\">>;\n\n/**\n * The opt-in rule, in one place so availability, turn-time resolution, and the\n * host-derived bootstrap gate cannot disagree.\n *\n * - `enabled: false` written verbatim in settings or the environment is a kill\n * switch: the lane is off regardless of what is stored.\n * - Otherwise the flag gates only the host-CLI-derived opt-in. Stored senpi account slots\n * exist only because the user ran `/login cursor-cli-oauth` or\n * `/cursor-account import`, and that explicit action IS the opt-in.\n */\nexport function isCursorCliOauthLaneEnabled(settings: CursorCliOauthSettings, storedAccountCount: number): boolean {\n\tif (settings.explicitlyDisabled === true) return false;\n\treturn settings.enabled || storedAccountCount > 0;\n}\n\ntype ImportedCursorCredential = {\n\taccess: string;\n\trefresh: string;\n\texpires?: number;\n};\n\nexport type CursorCliOauthConfigDeps = {\n\treadCurrent: () => Promise<Credential | undefined>;\n\treadSettings: () => CursorCliOauthSettings;\n\tresolveExecutable: (settings: CursorCliOauthSettings) => string;\n\tloadOAuth?: () => Promise<OAuthAuth>;\n\treadCursorFile?: () => Promise<ImportedCursorCredential | undefined>;\n\treadCursorKeychain?: () => Promise<ImportedCursorCredential | undefined>;\n\t/** Clock for acknowledgement timestamps; injectable so tests stay deterministic. */\n\tnow?: () => Date;\n\t/** Persists the no-approval acknowledgement; the disk default is wired in defaultCursorCliOauthConfig. */\n\tpersistAcknowledgement?: (acknowledgedAt: string) => void;\n\t/** Persists explicit provider activation after a successful login. */\n\tpersistEnabled?: (enabled: boolean) => void;\n};\n\nexport type CursorCliOauthLaneResolution = {\n\tlane: typeof FILE_STORE_LANE;\n\taccount: CursorCliAccountSlot;\n\taccounts: CursorCliAccountSlot[];\n};\n\nexport type CursorCliOauthConfig = {\n\tname: string;\n\tisSubscription: true;\n\tcheck(input: {\n\t\tctx: AuthContext;\n\t\tcredential?: OAuthCredential;\n\t\tsignal?: AbortSignal;\n\t}): Promise<AuthCheck | undefined>;\n\tlogin(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;\n\trefreshToken(credentials: OAuthCredentials, signal: AbortSignal): Promise<OAuthCredentials>;\n\tgetApiKey(credentials: OAuthCredentials): string;\n};\n\nexport type LocalCursorImportDeps = {\n\tplatform?: NodeJS.Platform;\n\treadCursorFile?: () => Promise<ImportedCursorCredential | undefined>;\n\treadCursorKeychain?: () => Promise<ImportedCursorCredential | undefined>;\n\tonPrompt?: OAuthLoginCallbacks[\"onPrompt\"];\n};\n\ntype ConfigurationAssessment = {\n\taccounts: CursorCliAccountSlot[];\n\tmessage: string;\n};\n\n/** The single condition evaluation behind both the tolerant `check` and the throwing turn-time resolution. */\ntype ConfigurationOutcome =\n\t| { status: \"disabled\" }\n\t| { status: \"not-installed\"; error: unknown }\n\t| { status: \"no-accounts\" }\n\t| { status: \"configured\"; assessment: ConfigurationAssessment };\n\n/**\n * One predicate so availability and resolution cannot disagree: evaluates the\n * same conditions for every caller and reports why the lane is unusable\n * instead of deciding per call-site whether that is fatal.\n */\nasync function assessConfiguration(deps: CursorCliOauthConfigDeps): Promise<ConfigurationOutcome> {\n\tconst settings = deps.readSettings();\n\tif (settings.explicitlyDisabled === true) return { status: \"disabled\" };\n\ttry {\n\t\tdeps.resolveExecutable(settings);\n\t} catch (error) {\n\t\treturn { status: \"not-installed\", error };\n\t}\n\n\t// Read the stored slots before applying the flag: an explicit senpi-side login\n\t// is itself the opt-in, so only the flagless host-derived shape reports disabled.\n\tconst accounts = usableAccounts(await deps.readCurrent());\n\tif (!isCursorCliOauthLaneEnabled(settings, accounts.length)) return { status: \"disabled\" };\n\tif (accounts.length === 0) return { status: \"no-accounts\" };\n\treturn {\n\t\tstatus: \"configured\",\n\t\tassessment: { accounts, message: `configured (file-store, ${accounts.length} accounts)` },\n\t};\n}\n\n/** The throwing view used by turn-time resolution; a turn attempted on an unusable lane must still error clearly. */\nasync function configuredFor(deps: CursorCliOauthConfigDeps): Promise<ConfigurationAssessment> {\n\tconst outcome = await assessConfiguration(deps);\n\tswitch (outcome.status) {\n\t\tcase \"disabled\":\n\t\t\tthrow new Error(DISABLED_MESSAGE);\n\t\tcase \"not-installed\":\n\t\t\tthrow cursorAgentNotInstalledError(outcome.error);\n\t\tcase \"no-accounts\":\n\t\t\tthrow new Error(NO_ACCOUNTS_MESSAGE);\n\t\tdefault:\n\t\t\treturn outcome.assessment;\n\t}\n}\n\nfunction isCursorCliOauthCredential(\n\tvalue: Credential | OAuthCredentials | undefined,\n): value is CursorCliOauthCredential {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst candidate = value as Partial<CursorCliOauthCredential>;\n\treturn candidate.type === \"oauth\" && Array.isArray(candidate.accounts);\n}\n\nfunction usableAccounts(value: Credential | OAuthCredentials | undefined): CursorCliAccountSlot[] {\n\tif (!isCursorCliOauthCredential(value)) return [];\n\treturn listAccounts(value).filter(\n\t\t(slot) =>\n\t\t\ttypeof slot.name === \"string\" &&\n\t\t\ttypeof slot.access === \"string\" &&\n\t\t\tslot.access.trim().length > 0 &&\n\t\t\ttypeof slot.refresh === \"string\" &&\n\t\t\tslot.refresh.trim().length > 0 &&\n\t\t\ttypeof slot.expires === \"number\" &&\n\t\t\tNumber.isFinite(slot.expires),\n\t);\n}\n\nfunction installationMessage(error: unknown): string {\n\tconst detail = error instanceof Error ? error.message : String(error);\n\treturn `cursor-agent not installed: ${detail.replace(/^Cursor CLI is not installed\\.\\s*/, \"\")}`;\n}\n\n/**\n * The typed turn-path error for a missing cursor-agent binary: carries the\n * `cursor-agent not installed` marker plus the install guidance verbatim, with\n * the underlying resolution failure preserved as `cause`.\n */\nexport function cursorAgentNotInstalledError(cause: unknown): Error {\n\tconst error = new Error(installationMessage(cause));\n\terror.name = \"CursorAgentNotInstalledError\";\n\terror.cause = cause;\n\treturn error;\n}\n\n/** Resolve credentials immediately before execution so a concurrent refresh cannot leave a stale token in memory. */\nexport async function resolveCursorCliOauthLane(deps: CursorCliOauthConfigDeps): Promise<CursorCliOauthLaneResolution> {\n\tconst assessment = await configuredFor(deps);\n\tconst account = assessment.accounts[0];\n\tif (!account) throw new Error(NO_ACCOUNTS_MESSAGE);\n\treturn { lane: FILE_STORE_LANE, account, accounts: assessment.accounts };\n}\n\nasync function loadCursorOAuthFlow(): Promise<OAuthAuth> {\n\tconst flow = cursorProvider().auth.oauth;\n\tif (!flow) throw new Error(\"Cursor OAuth flow is unavailable\");\n\treturn flow;\n}\n\nfunction providerInteraction(callbacks: OAuthLoginCallbacks): ProviderAuthInteraction {\n\treturn {\n\t\tsignal: callbacks.signal ?? new AbortController().signal,\n\t\tprompt: async (prompt) => {\n\t\t\tswitch (prompt.type) {\n\t\t\t\tcase \"select\":\n\t\t\t\t\treturn (await callbacks.onSelect(prompt)) ?? \"\";\n\t\t\t\tcase \"manual_code\":\n\t\t\t\t\treturn callbacks.onManualCodeInput?.() ?? callbacks.onPrompt(prompt);\n\t\t\t\tdefault:\n\t\t\t\t\treturn callbacks.onPrompt(prompt);\n\t\t\t}\n\t\t},\n\t\tnotify: (event) => {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase \"auth_url\":\n\t\t\t\t\tcallbacks.onAuth({ url: event.url, instructions: event.instructions });\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"device_code\":\n\t\t\t\t\tcallbacks.onDeviceCode(event);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"progress\":\n\t\t\t\t\tcallbacks.onProgress?.(event.message);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"info\":\n\t\t\t\t\tcallbacks.onProgress?.(event.message);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t},\n\t};\n}\n\nasync function accountName(\n\texisting: CursorCliAccountSlot[],\n\tonPrompt: OAuthLoginCallbacks[\"onPrompt\"] | undefined,\n): Promise<string> {\n\tif (existing.length === 0) return \"default\";\n\tconst fallback = `account-${existing.length + 1}`;\n\tif (!onPrompt) return fallback;\n\tconst answer = (\n\t\tawait onPrompt({\n\t\t\tmessage: `Name for this account (existing: ${existing.map((slot) => slot.name).join(\", \")})`,\n\t\t\tplaceholder: fallback,\n\t\t})\n\t).trim();\n\treturn answer || fallback;\n}\n\nfunction slotFromCredential(\n\tcredential: Pick<OAuthCredentials, \"access\" | \"refresh\" | \"expires\">,\n\tname: string,\n\tsource: CursorCliAccountSlot[\"source\"],\n): CursorCliAccountSlot {\n\treturn {\n\t\tname,\n\t\taccess: credential.access,\n\t\trefresh: credential.refresh,\n\t\texpires: credential.expires,\n\t\tsource,\n\t};\n}\n\n/** The one-screen login explanation: what unattended Cursor CLI execution gives up, and the plan-mode alternative. */\nexport const CURSOR_CLI_OAUTH_LOGIN_ACKNOWLEDGEMENT_EXPLANATION = `${CURSOR_CLI_OAUTH_NO_APPROVAL_EXPLANATION} Plan mode (planning only, no tool execution) is available via the executionMode setting.`;\n\nconst ACKNOWLEDGEMENT_ACCEPTANCE = new Set([\"yes\", \"y\"]);\n\n/**\n * Present the no-approval explanation exactly once and return the ISO\n * acknowledgement timestamp on explicit confirmation, undefined otherwise.\n * Shared by the login flow and the /cursor-account acknowledge subcommand so\n * both surfaces present the identical explanation and persist identically.\n */\nexport async function confirmCursorCliNoApprovalAcknowledgement(\n\tonPrompt: ((prompt: { message: string; placeholder?: string }) => Promise<string>) | undefined,\n\tnow: () => Date,\n): Promise<string | undefined> {\n\tif (!onPrompt) return undefined;\n\tconst answer = (\n\t\tawait onPrompt({\n\t\t\tmessage: `${CURSOR_CLI_OAUTH_LOGIN_ACKNOWLEDGEMENT_EXPLANATION}\\nType \"yes\" to acknowledge and allow unattended Cursor CLI tool execution; anything else leaves it off.`,\n\t\t})\n\t)\n\t\t.trim()\n\t\t.toLowerCase();\n\treturn ACKNOWLEDGEMENT_ACCEPTANCE.has(answer) ? now().toISOString() : undefined;\n}\n\nexport function createCursorCliOauthConfig(deps: CursorCliOauthConfigDeps): CursorCliOauthConfig {\n\treturn {\n\t\tname: CURSOR_CLI_OAUTH_NAME,\n\t\tisSubscription: true,\n\n\t\tasync check(input) {\n\t\t\t// Tolerant by contract: ModelsImpl.getAvailable runs every provider's\n\t\t\t// check under Promise.all (packages/ai/src/models.ts:544-548) and turns a\n\t\t\t// throw into a rejecting ModelsError, so one throwing check would reject\n\t\t\t// all model listing. Not usable (disabled / not installed / no accounts)\n\t\t\t// reports undefined here - as claude-sdk-oauth's check does - while\n\t\t\t// turn-time resolution keeps throwing via configuredFor.\n\t\t\t//\n\t\t\t// One nuance: the auth-resolution path (checkAuth, resolveStoredOAuth)\n\t\t\t// always passes the stored credential, while bare model listing does not.\n\t\t\t// A credential-backed lane whose executable is missing stays selectable\n\t\t\t// with the install guidance as its source, so a TURN reaches\n\t\t\t// streamCursorCliOauth, which throws the typed not-installed error;\n\t\t\t// without a credential the lane hides exactly as before.\n\t\t\tconst outcome = await assessConfiguration(deps);\n\t\t\tif (outcome.status === \"disabled\" || outcome.status === \"no-accounts\") return undefined;\n\t\t\tif (outcome.status === \"not-installed\") {\n\t\t\t\treturn input.credential === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: { type: \"oauth\", source: installationMessage(outcome.error) };\n\t\t\t}\n\t\t\treturn { type: \"oauth\", source: outcome.assessment.message };\n\t\t},\n\n\t\tasync login(callbacks) {\n\t\t\tconst stored = await deps.readCurrent();\n\t\t\tconst current = isCursorCliOauthCredential(stored) ? stored : emptyCredential();\n\t\t\tconst existing = listAccounts(current);\n\t\t\tconst flow = await (deps.loadOAuth ?? loadCursorOAuthFlow)();\n\t\t\tconst loggedIn = await flow.login(providerInteraction(callbacks));\n\t\t\tconst name = await accountName(existing, callbacks.onPrompt);\n\t\t\t// After the PKCE flow succeeds and before the slot is stored: the\n\t\t\t// one-screen no-approval explanation, confirmed once. Declining still\n\t\t\t// stores the slot; only the acknowledgement stays unset, so force turns\n\t\t\t// refuse until the user acknowledges later.\n\t\t\tconst acknowledgedAt = await confirmCursorCliNoApprovalAcknowledgement(\n\t\t\t\tcallbacks.onPrompt,\n\t\t\t\tdeps.now ?? (() => new Date()),\n\t\t\t);\n\t\t\tif (acknowledgedAt !== undefined) deps.persistAcknowledgement?.(acknowledgedAt);\n\t\t\tconst credential = addAccount(current, slotFromCredential(loggedIn, name, \"login\"));\n\t\t\tdeps.persistEnabled?.(true);\n\t\t\treturn credential;\n\t\t},\n\n\t\tasync refreshToken(credentials, signal) {\n\t\t\tif (!isCursorCliOauthCredential(credentials)) return credentials;\n\t\t\tconst flow = await (deps.loadOAuth ?? loadCursorOAuthFlow)();\n\t\t\tconst accounts: CursorCliAccountSlot[] = [];\n\t\t\tfor (const slot of listAccounts(credentials)) {\n\t\t\t\tif (Date.now() < slot.expires) {\n\t\t\t\t\taccounts.push(slot);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst refreshed = await flow.refresh(\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"oauth\",\n\t\t\t\t\t\taccess: slot.access,\n\t\t\t\t\t\trefresh: slot.refresh,\n\t\t\t\t\t\texpires: slot.expires,\n\t\t\t\t\t},\n\t\t\t\t\tsignal,\n\t\t\t\t);\n\t\t\t\taccounts.push({\n\t\t\t\t\t...slot,\n\t\t\t\t\taccess: refreshed.access,\n\t\t\t\t\trefresh: refreshed.refresh,\n\t\t\t\t\texpires: refreshed.expires,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn { ...credentials, ...SENTINEL_OAUTH_FIELDS, accounts };\n\t\t},\n\n\t\tgetApiKey() {\n\t\t\treturn SENTINEL_OAUTH_FIELDS.access;\n\t\t},\n\t};\n}\n\nfunction execFileOutput(file: string, args: string[]): Promise<string | undefined> {\n\treturn new Promise((resolve) => {\n\t\tnodeExecFile(file, args, { encoding: \"utf8\" }, (error, stdout) => {\n\t\t\tif (error) {\n\t\t\t\tresolve(undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst value = stdout.trim();\n\t\t\tresolve(value.length > 0 ? value : undefined);\n\t\t});\n\t});\n}\n\nasync function defaultKeychainCredential(): Promise<ImportedCursorCredential | undefined> {\n\tif (process.platform !== \"darwin\") return undefined;\n\tconst [access, refresh] = await Promise.all([\n\t\texecFileOutput(\"security\", [\"find-generic-password\", \"-a\", \"cursor-user\", \"-s\", \"cursor-access-token\", \"-w\"]),\n\t\texecFileOutput(\"security\", [\"find-generic-password\", \"-a\", \"cursor-user\", \"-s\", \"cursor-refresh-token\", \"-w\"]),\n\t]);\n\treturn access && refresh ? { access, refresh } : undefined;\n}\n\nfunction localCursorAuthPath(platform: NodeJS.Platform): string | undefined {\n\tswitch (platform) {\n\t\tcase \"darwin\":\n\t\t\treturn join(homedir(), \".cursor\", \"auth.json\");\n\t\tcase \"linux\":\n\t\t\treturn join(process.env.XDG_CONFIG_HOME ?? join(homedir(), \".config\"), \"cursor\", \"auth.json\");\n\t\tcase \"win32\": {\n\t\t\tconst appData = process.env.APPDATA;\n\t\t\treturn appData ? join(appData, \"Cursor\", \"auth.json\") : undefined;\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nasync function defaultFileCredential(platform: NodeJS.Platform): Promise<ImportedCursorCredential | undefined> {\n\tconst path = localCursorAuthPath(platform);\n\tif (!path) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(await nodeReadFile(path, \"utf8\"));\n\t\tif (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return undefined;\n\t\tconst record = parsed as Record<string, unknown>;\n\t\tconst access = record.accessToken;\n\t\tconst refresh = record.refreshToken;\n\t\tif (typeof access !== \"string\" || access.length === 0 || typeof refresh !== \"string\" || refresh.length === 0) {\n\t\t\treturn undefined;\n\t\t}\n\t\treturn { access, refresh };\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/** Explicitly copy the user's local Cursor credential into this provider's managed account slots. */\nexport async function importLocalCursorCredential(\n\tcurrent: CursorCliOauthCredential,\n\tdeps: LocalCursorImportDeps = {},\n): Promise<CursorCliOauthCredential> {\n\tconst platform = deps.platform ?? process.platform;\n\tconst readKeychain = deps.readCursorKeychain ?? defaultKeychainCredential;\n\tconst readFile = deps.readCursorFile ?? (() => defaultFileCredential(platform));\n\tconst imported = platform === \"darwin\" ? ((await readKeychain()) ?? (await readFile())) : await readFile();\n\tif (!imported) throw new Error(\"No local Cursor OAuth credential found\");\n\tconst existing = listAccounts(current);\n\tconst name = await accountName(existing, deps.onPrompt);\n\treturn addAccount(\n\t\tcurrent,\n\t\tslotFromCredential(\n\t\t\t{\n\t\t\t\taccess: imported.access,\n\t\t\t\trefresh: imported.refresh,\n\t\t\t\texpires: imported.expires ?? Date.now() + DEFAULT_IMPORTED_EXPIRY_MS,\n\t\t\t},\n\t\t\tname,\n\t\t\t\"import\",\n\t\t),\n\t);\n}\n\nfunction isUsableFlatOAuthCredential(value: Credential | undefined): value is OAuthCredential {\n\treturn (\n\t\tvalue?.type === \"oauth\" &&\n\t\ttypeof value.access === \"string\" &&\n\t\tvalue.access.length > 0 &&\n\t\ttypeof value.refresh === \"string\" &&\n\t\tvalue.refresh.length > 0 &&\n\t\ttypeof value.expires === \"number\" &&\n\t\tNumber.isFinite(value.expires)\n\t);\n}\n\nfunction nativeAccountName(existing: readonly CursorCliAccountSlot[]): string {\n\tconst names = new Set(existing.map((account) => account.name));\n\tif (!names.has(\"native\")) return \"native\";\n\tfor (let index = 2; index <= 10_000; index++) {\n\t\tconst candidate = `native-${index}`;\n\t\tif (!names.has(candidate)) return candidate;\n\t}\n\tthrow new Error(\"Could not allocate a Cursor CLI OAuth native account name\");\n}\n\n/** Explicitly copy Senpi's native `cursor` OAuth credential into a managed CLI account slot. */\nexport async function importNativeCursorCredential(\n\tcurrent: CursorCliOauthCredential,\n\treadNativeCredential: () => Credential | undefined | Promise<Credential | undefined>,\n): Promise<CursorCliOauthCredential> {\n\tconst native = await readNativeCredential();\n\tif (!isUsableFlatOAuthCredential(native)) {\n\t\tthrow new Error(\"No stored native Cursor OAuth credential found\");\n\t}\n\treturn addAccount(current, slotFromCredential(native, nativeAccountName(listAccounts(current)), \"import\"));\n}\n\nexport function defaultCursorCliOauthConfig(\n\tcwd: string,\n\treadCurrent: () => Promise<Credential | undefined>,\n): CursorCliOauthConfig {\n\treturn createCursorCliOauthConfig({\n\t\treadCurrent,\n\t\treadSettings: () => loadCursorCliOauthProviderSettingsFromDisk(cwd),\n\t\tresolveExecutable: (settings) => {\n\t\t\tconst executableDeps: CursorAgentExecutableDeps = {\n\t\t\t\t...defaultCursorAgentExecutableDeps(),\n\t\t\t\tsettings,\n\t\t\t};\n\t\t\treturn resolveCursorAgentExecutable(executableDeps);\n\t\t},\n\t\tnow: () => new Date(),\n\t\tpersistAcknowledgement: (acknowledgedAt: string) =>\n\t\t\tpersistCursorCliNoApprovalAcknowledgement(cwd, acknowledgedAt),\n\t\tpersistEnabled: (enabled: boolean) => persistCursorCliOauthEnabled(cwd, enabled),\n\t});\n}\n"]}
@@ -1,7 +1,18 @@
1
1
  export type CursorCliOauthExecutionMode = "agent" | "plan";
2
2
  export type CursorCliOauthResumeMode = "auto" | "off";
3
3
  export interface CursorCliOauthProviderSettings {
4
+ /**
5
+ * Explicit senpi-side opt-in for the AMBIENT lane (host-CLI-derived native
6
+ * credential bootstrap). Defaults to false: a logged-in `cursor-agent` on the
7
+ * host is not consent to spend that subscription from senpi.
8
+ */
4
9
  readonly enabled: boolean;
10
+ /**
11
+ * True only when a settings layer or the environment set `enabled` to false
12
+ * verbatim. That is a kill switch and outranks stored accounts, while a merely
13
+ * absent flag leaves an explicit senpi-side login usable.
14
+ */
15
+ readonly explicitlyDisabled: boolean;
5
16
  readonly executablePath: string | undefined;
6
17
  readonly forceExecution: boolean;
7
18
  readonly noApprovalAcknowledgedAt: string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/settings.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,MAAM,CAAC;AAC3D,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,KAAK,CAAC;AAEtD,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,2BAA2B,CAAC;IACpD,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAMD,KAAK,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAmJhE,mFAAmF;AACnF,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,WAAW,GACtB,8BAA8B,CAEhC;AAED;;;GAGG;AACH,wBAAgB,wCAAwC,CACvD,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAClC,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAUnD;AAED,wFAAwF;AACxF,wBAAgB,0CAA0C,CAAC,GAAG,EAAE,MAAM,GAAG,8BAA8B,CAStG;AA4BD,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,yCAAyC,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAKnG"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/cursor-cli-oauth/settings.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,2BAA2B,GAAG,OAAO,GAAG,MAAM,CAAC;AAC3D,MAAM,MAAM,wBAAwB,GAAG,MAAM,GAAG,KAAK,CAAC;AAEtD,MAAM,WAAW,8BAA8B;IAC9C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,aAAa,EAAE,2BAA2B,CAAC;IACpD,QAAQ,CAAC,UAAU,EAAE,wBAAwB,CAAC;IAC9C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,yBAAyB,EAAE,OAAO,CAAC;IAC5C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAMD,KAAK,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;AAwJhE,mFAAmF;AACnF,wBAAgB,mCAAmC,CAClD,KAAK,EAAE,OAAO,EACd,WAAW,EAAE,WAAW,GACtB,8BAA8B,CAEhC;AAED;;;GAGG;AACH,wBAAgB,wCAAwC,CACvD,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,EAClC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,GAClC,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,MAAM,GAAG,SAAS,CAUnD;AAED,wFAAwF;AACxF,wBAAgB,0CAA0C,CAAC,GAAG,EAAE,MAAM,GAAG,8BAA8B,CAStG;AA4BD,mFAAmF;AACnF,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI,CAEhF;AAED;;;;;GAKG;AACH,wBAAgB,yCAAyC,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAKnG"}
@@ -1,7 +1,8 @@
1
1
  import { getAgentDir } from "../../../../config.js";
2
2
  import { FileSettingsStorage, parseSettingsJson, SettingsManager } from "../../../settings-manager.js";
3
3
  const DEFAULT_SETTINGS = {
4
- enabled: true,
4
+ enabled: false,
5
+ explicitlyDisabled: false,
5
6
  executablePath: undefined,
6
7
  forceExecution: true,
7
8
  noApprovalAcknowledgedAt: undefined,
@@ -129,7 +130,11 @@ function parseEnvironmentSettings(environment) {
129
130
  };
130
131
  }
131
132
  function resolveSettings(...layers) {
132
- return Object.assign({}, DEFAULT_SETTINGS, ...layers);
133
+ const resolved = Object.assign({}, DEFAULT_SETTINGS, ...layers);
134
+ // The last layer that names `enabled` wins, exactly as the value merge does;
135
+ // only a verbatim false there is the kill switch.
136
+ const named = layers.filter((layer) => layer.enabled !== undefined);
137
+ return { ...resolved, explicitlyDisabled: named.length > 0 && named[named.length - 1]?.enabled === false };
133
138
  }
134
139
  /** Parse one provider settings block with environment values taking precedence. */
135
140
  export function parseCursorCliOauthProviderSettings(value, environment) {