@code-yeongyu/senpi 2026.9.10 → 2026.9.11

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 (337) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/dist/core/agent-session.d.ts +57 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +130 -20
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/auth-storage.d.ts +2 -0
  7. package/dist/core/auth-storage.d.ts.map +1 -1
  8. package/dist/core/auth-storage.js +49 -17
  9. package/dist/core/auth-storage.js.map +1 -1
  10. package/dist/core/brand.d.ts +5 -0
  11. package/dist/core/brand.d.ts.map +1 -1
  12. package/dist/core/brand.js +13 -0
  13. package/dist/core/brand.js.map +1 -1
  14. package/dist/core/changelog-source.d.ts +8 -0
  15. package/dist/core/changelog-source.d.ts.map +1 -0
  16. package/dist/core/changelog-source.js +19 -0
  17. package/dist/core/changelog-source.js.map +1 -0
  18. package/dist/core/credential-accounts.d.ts +3 -0
  19. package/dist/core/credential-accounts.d.ts.map +1 -1
  20. package/dist/core/credential-accounts.js +20 -1
  21. package/dist/core/credential-accounts.js.map +1 -1
  22. package/dist/core/credential-pool/classify.d.ts.map +1 -1
  23. package/dist/core/credential-pool/classify.js +8 -0
  24. package/dist/core/credential-pool/classify.js.map +1 -1
  25. package/dist/core/extensions/builtin/account/index.d.ts.map +1 -1
  26. package/dist/core/extensions/builtin/account/index.js +7 -3
  27. package/dist/core/extensions/builtin/account/index.js.map +1 -1
  28. package/dist/core/extensions/builtin/account-display-name.d.ts +7 -0
  29. package/dist/core/extensions/builtin/account-display-name.d.ts.map +1 -0
  30. package/dist/core/extensions/builtin/account-display-name.js +40 -0
  31. package/dist/core/extensions/builtin/account-display-name.js.map +1 -0
  32. package/dist/core/extensions/builtin/ask-user/format.d.ts.map +1 -1
  33. package/dist/core/extensions/builtin/ask-user/format.js +7 -2
  34. package/dist/core/extensions/builtin/ask-user/format.js.map +1 -1
  35. package/dist/core/extensions/builtin/ask-user/pending.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/ask-user/pending.js +3 -0
  37. package/dist/core/extensions/builtin/ask-user/pending.js.map +1 -1
  38. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js +21 -9
  40. package/dist/core/extensions/builtin/claude-sdk-oauth/account-command.js.map +1 -1
  41. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts +1 -0
  42. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.d.ts.map +1 -1
  43. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js +11 -6
  44. package/dist/core/extensions/builtin/claude-sdk-oauth/account-management.js.map +1 -1
  45. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts +9 -0
  46. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js +10 -1
  48. package/dist/core/extensions/builtin/claude-sdk-oauth/accounts.js.map +1 -1
  49. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +3 -0
  50. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  51. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +19 -10
  53. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  54. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js +3 -9
  56. package/dist/core/extensions/builtin/claude-sdk-oauth/settings.js.map +1 -1
  57. package/dist/core/extensions/builtin/config-reload/routine-settings.d.ts.map +1 -1
  58. package/dist/core/extensions/builtin/config-reload/routine-settings.js +1 -0
  59. package/dist/core/extensions/builtin/config-reload/routine-settings.js.map +1 -1
  60. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.d.ts.map +1 -1
  61. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js +5 -3
  62. package/dist/core/extensions/builtin/cursor-cli-oauth/account-command.js.map +1 -1
  63. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts +1 -0
  64. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.d.ts.map +1 -1
  65. package/dist/core/extensions/builtin/cursor-cli-oauth/accounts.js.map +1 -1
  66. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.d.ts.map +1 -1
  67. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js +3 -9
  68. package/dist/core/extensions/builtin/cursor-cli-oauth/settings.js.map +1 -1
  69. package/dist/core/extensions/builtin/goal/agent-end-continuation.d.ts.map +1 -1
  70. package/dist/core/extensions/builtin/goal/agent-end-continuation.js +13 -1
  71. package/dist/core/extensions/builtin/goal/agent-end-continuation.js.map +1 -1
  72. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  73. package/dist/core/extensions/builtin/goal/prompt.js +11 -8
  74. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  75. package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts +1 -0
  76. package/dist/core/extensions/builtin/goal/terminal-provider-error.d.ts.map +1 -1
  77. package/dist/core/extensions/builtin/goal/terminal-provider-error.js +28 -0
  78. package/dist/core/extensions/builtin/goal/terminal-provider-error.js.map +1 -1
  79. package/dist/core/extensions/builtin/goal/todo-gate.js +2 -2
  80. package/dist/core/extensions/builtin/goal/todo-gate.js.map +1 -1
  81. package/dist/core/extensions/builtin/goal/tool-registration.js +2 -2
  82. package/dist/core/extensions/builtin/goal/tool-registration.js.map +1 -1
  83. package/dist/core/extensions/builtin/gpt-account.d.ts.map +1 -1
  84. package/dist/core/extensions/builtin/gpt-account.js +19 -8
  85. package/dist/core/extensions/builtin/gpt-account.js.map +1 -1
  86. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts +3 -0
  87. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.d.ts.map +1 -0
  88. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js +19 -0
  89. package/dist/core/extensions/builtin/prompt-preset/deepseek-v4-1-flash.js.map +1 -0
  90. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +6 -6
  91. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +26 -7
  93. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/presets.d.ts.map +1 -1
  95. package/dist/core/extensions/builtin/prompt-preset/presets.js +29 -0
  96. package/dist/core/extensions/builtin/prompt-preset/presets.js.map +1 -1
  97. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
  98. package/dist/core/extensions/builtin/prompt-preset/settings.d.ts.map +1 -1
  99. package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
  100. package/dist/core/extensions/builtin/prompt-preset/settings.js.map +1 -1
  101. package/dist/core/high-reasoning-warning.d.ts.map +1 -1
  102. package/dist/core/high-reasoning-warning.js +5 -1
  103. package/dist/core/high-reasoning-warning.js.map +1 -1
  104. package/dist/core/manual-continue.d.ts +14 -0
  105. package/dist/core/manual-continue.d.ts.map +1 -1
  106. package/dist/core/manual-continue.js +13 -0
  107. package/dist/core/manual-continue.js.map +1 -1
  108. package/dist/core/model-runtime.d.ts.map +1 -1
  109. package/dist/core/model-runtime.js +2 -2
  110. package/dist/core/model-runtime.js.map +1 -1
  111. package/dist/core/remote-catalog-merge.d.ts +16 -0
  112. package/dist/core/remote-catalog-merge.d.ts.map +1 -0
  113. package/dist/core/remote-catalog-merge.js +75 -0
  114. package/dist/core/remote-catalog-merge.js.map +1 -0
  115. package/dist/core/remote-catalog-provider.d.ts +3 -0
  116. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  117. package/dist/core/remote-catalog-provider.js +12 -40
  118. package/dist/core/remote-catalog-provider.js.map +1 -1
  119. package/dist/core/session-entry-materializer.d.ts +12 -0
  120. package/dist/core/session-entry-materializer.d.ts.map +1 -0
  121. package/dist/core/session-entry-materializer.js +26 -0
  122. package/dist/core/session-entry-materializer.js.map +1 -0
  123. package/dist/core/session-manager.d.ts +36 -1
  124. package/dist/core/session-manager.d.ts.map +1 -1
  125. package/dist/core/session-manager.js +38 -8
  126. package/dist/core/session-manager.js.map +1 -1
  127. package/dist/core/settings-manager.d.ts +3 -0
  128. package/dist/core/settings-manager.d.ts.map +1 -1
  129. package/dist/core/settings-manager.js +10 -0
  130. package/dist/core/settings-manager.js.map +1 -1
  131. package/dist/modes/app-server/daemon/process.d.ts +6 -1
  132. package/dist/modes/app-server/daemon/process.d.ts.map +1 -1
  133. package/dist/modes/app-server/daemon/process.js +23 -4
  134. package/dist/modes/app-server/daemon/process.js.map +1 -1
  135. package/dist/modes/app-server/protocol/account.d.ts +2 -0
  136. package/dist/modes/app-server/protocol/account.d.ts.map +1 -1
  137. package/dist/modes/app-server/protocol/account.js.map +1 -1
  138. package/dist/modes/interactive/components/ask-user-question-keys.d.ts +1 -1
  139. package/dist/modes/interactive/components/ask-user-question-keys.d.ts.map +1 -1
  140. package/dist/modes/interactive/components/ask-user-question-keys.js +65 -17
  141. package/dist/modes/interactive/components/ask-user-question-keys.js.map +1 -1
  142. package/dist/modes/interactive/components/ask-user-question-render.d.ts +2 -1
  143. package/dist/modes/interactive/components/ask-user-question-render.d.ts.map +1 -1
  144. package/dist/modes/interactive/components/ask-user-question-render.js +39 -9
  145. package/dist/modes/interactive/components/ask-user-question-render.js.map +1 -1
  146. package/dist/modes/interactive/components/ask-user-question-state.d.ts +14 -4
  147. package/dist/modes/interactive/components/ask-user-question-state.d.ts.map +1 -1
  148. package/dist/modes/interactive/components/ask-user-question-state.js +63 -6
  149. package/dist/modes/interactive/components/ask-user-question-state.js.map +1 -1
  150. package/dist/modes/interactive/components/ask-user-question.d.ts +2 -0
  151. package/dist/modes/interactive/components/ask-user-question.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/ask-user-question.js +27 -14
  153. package/dist/modes/interactive/components/ask-user-question.js.map +1 -1
  154. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/footer.js +51 -19
  156. package/dist/modes/interactive/components/footer.js.map +1 -1
  157. package/dist/modes/interactive/components/login-dialog.d.ts +11 -0
  158. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/login-dialog.js +29 -9
  160. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  161. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  162. package/dist/modes/interactive/components/tree-selector.js +7 -0
  163. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  164. package/dist/modes/interactive/help-content.d.ts.map +1 -1
  165. package/dist/modes/interactive/help-content.js +4 -0
  166. package/dist/modes/interactive/help-content.js.map +1 -1
  167. package/dist/modes/interactive/interactive-mode.d.ts +13 -4
  168. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  169. package/dist/modes/interactive/interactive-mode.js +44 -15
  170. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  171. package/dist/modes/interactive/tips/catalog/input-tips.js +1 -1
  172. package/dist/modes/interactive/tips/catalog/input-tips.js.map +1 -1
  173. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  174. package/dist/modes/rpc/connection-handler.js +3 -1
  175. package/dist/modes/rpc/connection-handler.js.map +1 -1
  176. package/dist/modes/rpc/connection-question-bridge.js +1 -1
  177. package/dist/modes/rpc/connection-question-bridge.js.map +1 -1
  178. package/dist/modes/rpc/host-ensure.d.ts.map +1 -1
  179. package/dist/modes/rpc/host-ensure.js +33 -11
  180. package/dist/modes/rpc/host-ensure.js.map +1 -1
  181. package/dist/modes/rpc/host-lifecycle.d.ts +14 -0
  182. package/dist/modes/rpc/host-lifecycle.d.ts.map +1 -1
  183. package/dist/modes/rpc/host-lifecycle.js +31 -5
  184. package/dist/modes/rpc/host-lifecycle.js.map +1 -1
  185. package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
  186. package/dist/modes/rpc/rpc-input-validation.js +2 -0
  187. package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
  188. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  189. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  190. package/dist/modes/rpc/rpc-types.js.map +1 -1
  191. package/dist/utils/changelog.d.ts +3 -1
  192. package/dist/utils/changelog.d.ts.map +1 -1
  193. package/dist/utils/changelog.js +89 -23
  194. package/dist/utils/changelog.js.map +1 -1
  195. package/dist/utils/paths.d.ts +5 -0
  196. package/dist/utils/paths.d.ts.map +1 -1
  197. package/dist/utils/paths.js +14 -1
  198. package/dist/utils/paths.js.map +1 -1
  199. package/docs/app-server.md +6 -0
  200. package/docs/extensions.md +19 -3
  201. package/docs/rpc.md +10 -0
  202. package/docs/settings.md +2 -1
  203. package/docs/tui.md +1 -1
  204. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +28 -0
  205. package/node_modules/@code-yeongyu/senpi-codemode/README.md +5 -4
  206. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  207. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output-buffer.ts +58 -0
  208. package/node_modules/@code-yeongyu/senpi-codemode/src/output/streaming-output.ts +9 -64
  209. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt-template.ts +1 -1
  210. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  211. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts +17 -0
  212. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.d.ts.map +1 -0
  213. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js +90 -0
  214. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/discovery.js.map +1 -0
  215. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts +23 -0
  216. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.d.ts.map +1 -0
  217. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js +71 -0
  218. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/frames.js.map +1 -0
  219. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts +873 -0
  220. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.d.ts.map +1 -0
  221. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js +303 -0
  222. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/gen/cascade_pb.js.map +1 -0
  223. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts +12 -0
  224. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.d.ts.map +1 -0
  225. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js +35 -0
  226. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/metadata.js.map +1 -0
  227. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts +23 -0
  228. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.d.ts.map +1 -0
  229. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js +23 -0
  230. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/paths.js.map +1 -0
  231. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts +24 -0
  232. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.d.ts.map +1 -0
  233. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js +116 -0
  234. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/request.js.map +1 -0
  235. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts +20 -0
  236. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.d.ts.map +1 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js +153 -0
  238. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/stream-state.js.map +1 -0
  239. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts +12 -0
  240. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.d.ts.map +1 -0
  241. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js +3 -0
  242. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/types.js.map +1 -0
  243. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts +6 -0
  244. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.d.ts.map +1 -0
  245. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js +6 -0
  246. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent/wire.js.map +1 -0
  247. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts +14 -0
  248. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.d.ts.map +1 -0
  249. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js +162 -0
  250. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.js.map +1 -0
  251. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts +5 -0
  252. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.d.ts.map +1 -0
  253. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js +23 -0
  254. package/node_modules/@earendil-works/pi-ai/dist/api/devin-agent.lazy.js.map +1 -0
  255. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts +25 -0
  256. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.d.ts.map +1 -0
  257. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js +124 -0
  258. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-callback.js.map +1 -0
  259. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts +18 -0
  260. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.d.ts.map +1 -0
  261. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js +101 -0
  262. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin-token.js.map +1 -0
  263. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts +14 -0
  264. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.d.ts.map +1 -0
  265. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js +111 -0
  266. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/devin.js.map +1 -0
  267. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  268. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +5 -1
  269. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
  270. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts +24 -0
  271. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts.map +1 -0
  272. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js +86 -0
  273. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js.map +1 -0
  274. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts +2 -0
  275. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.d.ts.map +1 -1
  276. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js +5 -0
  277. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/load.js.map +1 -1
  278. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts +51 -4
  279. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.d.ts.map +1 -1
  280. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js +196 -7
  281. package/node_modules/@earendil-works/pi-ai/dist/auth/pool/slots.js.map +1 -1
  282. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts +8 -0
  283. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.d.ts.map +1 -1
  284. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js +10 -0
  285. package/node_modules/@earendil-works/pi-ai/dist/auth/resolve.js.map +1 -1
  286. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts +9 -1
  287. package/node_modules/@earendil-works/pi-ai/dist/auth/types.d.ts.map +1 -1
  288. package/node_modules/@earendil-works/pi-ai/dist/auth/types.js.map +1 -1
  289. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.d.ts.map +1 -1
  290. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js +2 -0
  291. package/node_modules/@earendil-works/pi-ai/dist/bun-oauth.js.map +1 -1
  292. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts +1 -0
  293. package/node_modules/@earendil-works/pi-ai/dist/compat.d.ts.map +1 -1
  294. package/node_modules/@earendil-works/pi-ai/dist/compat.js +3 -0
  295. package/node_modules/@earendil-works/pi-ai/dist/compat.js.map +1 -1
  296. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +4 -4
  297. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  298. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +1 -1
  299. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  300. package/node_modules/@earendil-works/pi-ai/dist/models.js +14 -5
  301. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  302. package/node_modules/@earendil-works/pi-ai/dist/providers/all.d.ts.map +1 -1
  303. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js +2 -0
  304. package/node_modules/@earendil-works/pi-ai/dist/providers/all.js.map +1 -1
  305. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  306. package/node_modules/@earendil-works/pi-ai/dist/providers/data/amazon-bedrock.json +1 -1
  307. package/node_modules/@earendil-works/pi-ai/dist/providers/data/baseten.json +1 -1
  308. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  309. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  310. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  311. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opengateway.json +1 -1
  312. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  313. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  314. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  315. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts +12 -0
  316. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.d.ts.map +1 -0
  317. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js +62 -0
  318. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.js.map +1 -0
  319. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts +10 -0
  320. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.d.ts.map +1 -0
  321. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js +28 -0
  322. package/node_modules/@earendil-works/pi-ai/dist/providers/devin.models.js.map +1 -0
  323. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +3 -1
  324. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  325. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  326. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  327. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +4 -0
  328. package/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  329. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  330. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  331. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  332. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts +1 -1
  333. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.d.ts.map +1 -1
  334. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js +55 -16
  335. package/node_modules/@earendil-works/pi-tui/dist/dollar-invocation-autocomplete.js.map +1 -1
  336. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  337. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"credential-accounts.d.ts","sourceRoot":"","sources":["../../src/core/credential-accounts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,wBAAwB,EAAwC,MAAM,kCAAkC,CAAC;AAIlH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjE,mFAAmF;AACnF,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAuCD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAErC;AAED,2FAA2F;AAC3F,wBAAsB,2BAA2B,CAChD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,GAAE,wBAAyD,GACnE,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAuCrC;AAED,4DAA4D;AAC5D,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,IAAI,CAAC,CAef"}
1
+ {"version":3,"file":"credential-accounts.d.ts","sourceRoot":"","sources":["../../src/core/credential-accounts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AASxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,wBAAwB,EAAwC,MAAM,kCAAkC,CAAC;AAIlH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEjE,mFAAmF;AACnF,MAAM,MAAM,wBAAwB,GAAG;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CACzB,CAAC;AAIF,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAMzD;AAuCD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAErC;AAED,2FAA2F;AAC3F,wBAAsB,2BAA2B,CAChD,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,GAAE,wBAAyD,GACnE,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAyCrC;AAED,sGAAsG;AACtG,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,IAAI,GACxB,OAAO,CAAC,IAAI,CAAC,CAgBf;AAED,4DAA4D;AAC5D,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC5C,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,UAAU,CAAC,EAAE,wBAAwB,GACnC,OAAO,CAAC,IAAI,CAAC,CAef"}
@@ -1,5 +1,5 @@
1
1
  import { dirname, join } from "node:path";
2
- import { listSlots, pinSlot, removeSlot } from "@earendil-works/pi-ai/auth/pool/slots";
2
+ import { accountDisplayName, listSlots, pinSlot, removeSlot, renameSlotDisplayName, } from "@earendil-works/pi-ai/auth/pool/slots";
3
3
  import { discoverEnvSlots } from "./credential-pool/env-slots.js";
4
4
  import { CredentialSlotRepository, slotHealth } from "./credential-pool/state-store.js";
5
5
  import { emitProviderAccountsChanged } from "./extensions/builtin/claude-sdk-oauth/account-events.js";
@@ -67,8 +67,10 @@ export async function summarizeCredentialAccounts(provider, stored, env = proces
67
67
  : []
68
68
  : listSlots(credential);
69
69
  for (const slot of storedAccounts) {
70
+ const displayName = accountDisplayName(slot.displayName);
70
71
  summaries.push({
71
72
  name: slot.name,
73
+ ...(displayName === undefined ? {} : { displayName }),
72
74
  source: slot.source ?? "login",
73
75
  blocked: slotBlocked(slot, state[slot.name], now),
74
76
  pinned: pinned === slot.name,
@@ -92,6 +94,23 @@ export async function summarizeCredentialAccounts(provider, stored, env = proces
92
94
  }
93
95
  return summaries;
94
96
  }
97
+ /** Atomically rename/clear stored metadata without changing identity, health or environment state. */
98
+ export async function renameCredentialAccount(storage, provider, name, displayName) {
99
+ await storage.modify(provider, async (current) => {
100
+ if (!current)
101
+ throw new Error(`No stored credential for provider: ${provider}`);
102
+ // Provider-managed OAuth sentinels without an accounts array are not legacy flat accounts.
103
+ // Key this on the credential shape, not one provider id, so sibling managed lanes cannot be promoted.
104
+ if (current.type === "oauth" &&
105
+ !Array.isArray(current.accounts) &&
106
+ current.access === current.refresh &&
107
+ current.access.endsWith("-managed")) {
108
+ throw new Error(`Stored provider account not found: ${name}`);
109
+ }
110
+ return renameSlotDisplayName(current, name, displayName);
111
+ });
112
+ emitProviderAccountsChanged(provider);
113
+ }
95
114
  /** Pins one slot, or clears the pin when `name` is null. */
96
115
  export async function pinCredentialAccount(storage, provider, name, env = process.env, repository) {
97
116
  const repo = repository ?? defaultRepository(storage);
@@ -1 +1 @@
1
- {"version":3,"file":"credential-accounts.js","sourceRoot":"","sources":["../../src/core/credential-accounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, join } from \"node:path\";\nimport type { Credential } from \"@earendil-works/pi-ai\";\nimport { listSlots, type PooledCredential, pinSlot, removeSlot } from \"@earendil-works/pi-ai/auth/pool/slots\";\nimport type { AuthStorage } from \"./auth-storage.ts\";\nimport { discoverEnvSlots } from \"./credential-pool/env-slots.ts\";\nimport { CredentialSlotRepository, type CredentialSlotState, slotHealth } from \"./credential-pool/state-store.ts\";\nimport { emitProviderAccountsChanged } from \"./extensions/builtin/claude-sdk-oauth/account-events.ts\";\nimport { SENTINEL_OAUTH_FIELDS } from \"./extensions/builtin/claude-sdk-oauth/accounts.ts\";\n\nexport type CredentialAccountSource = \"login\" | \"import\" | \"env\";\n\n/** Account metadata safe to surface: names and health only, never key material. */\nexport type CredentialAccountSummary = {\n\treadonly name: string;\n\treadonly source: CredentialAccountSource;\n\treadonly blocked: boolean;\n\treadonly pinned: boolean;\n};\n\nconst ACCOUNT_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;\n\nexport function assertValidAccountName(name: string): void {\n\tif (!ACCOUNT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(\n\t\t\t`Invalid account name '${name}': use letters, digits, '-' or '_', starting with a letter or digit`,\n\t\t);\n\t}\n}\n\nfunction pooledFrom(credential: Credential | undefined): PooledCredential | undefined {\n\treturn credential === undefined ? undefined : credential;\n}\n\nfunction pinnedName(credential: PooledCredential | undefined): string | undefined {\n\treturn credential?.pinned;\n}\n\nfunction numberField(value: object, key: string): number | undefined {\n\tconst found = Object.entries(value).find(([candidate]) => candidate === key)?.[1];\n\treturn typeof found === \"number\" ? found : undefined;\n}\n\nfunction defaultRepository(storage: AuthStorage): CredentialSlotRepository {\n\tconst authPath = storage.getStoragePath();\n\treturn new CredentialSlotRepository(authPath ? join(dirname(authPath), \"credential-pool-state.json\") : undefined);\n}\n\nfunction stringField(value: object, key: string): string | undefined {\n\tconst found = Object.entries(value).find(([candidate]) => candidate === key)?.[1];\n\treturn typeof found === \"string\" ? found : undefined;\n}\n\n/**\n * Block state has two sources and both are authoritative: a slot persisted by an\n * existing provider lane carries its own `blockedUntil`/`blockReason` inside\n * auth.json, while generic pool failover records health in the sidecar. Reading\n * only one would silently downgrade a real block to \"available\".\n */\nfunction slotBlocked(slot: object, sidecar: CredentialSlotState | undefined, now: number): boolean {\n\tif (slotHealth(sidecar, now) === \"blocked\") return true;\n\tconst reason = stringField(slot, \"blockReason\");\n\tif (reason === \"auth_error\" || reason === \"account_disabled\") return true;\n\tconst blockedUntil = numberField(slot, \"blockedUntil\");\n\treturn blockedUntil !== undefined && blockedUntil > now;\n}\n\n/**\n * Lists a provider's credential accounts for ANY provider, not just one lane.\n * Stored slots own the listing when a credential exists; env slots are listed\n * only when nothing is stored, mirroring resolution precedence exactly. Health\n * comes from the pool sidecar, so a cooldown persisted by a failover shows up\n * here without auth.json ever carrying block state.\n */\nexport async function getCredentialAccounts(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<CredentialAccountSummary[]> {\n\treturn summarizeCredentialAccounts(provider, storage.get(provider), env, repository ?? defaultRepository(storage));\n}\n\n/** Storage-free variant for callers that already hold the credential (e.g. auth check). */\nexport async function summarizeCredentialAccounts(\n\tprovider: string,\n\tstored: Credential | undefined,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository: CredentialSlotRepository = new CredentialSlotRepository(),\n): Promise<CredentialAccountSummary[]> {\n\tconst credential = pooledFrom(stored);\n\tconst now = Date.now();\n\tconst pinned = pinnedName(credential);\n\tconst summaries: CredentialAccountSummary[] = [];\n\n\tif (credential) {\n\t\tconst state = await repository.listSlots(provider, \"stored\");\n\t\tconst storedAccounts =\n\t\t\tprovider === \"claude-sdk-oauth\"\n\t\t\t\t? Array.isArray(credential.accounts)\n\t\t\t\t\t? listSlots(credential)\n\t\t\t\t\t: []\n\t\t\t\t: listSlots(credential);\n\t\tfor (const slot of storedAccounts) {\n\t\t\tsummaries.push({\n\t\t\t\tname: slot.name,\n\t\t\t\tsource: slot.source ?? \"login\",\n\t\t\t\tblocked: slotBlocked(slot, state[slot.name], now),\n\t\t\t\tpinned: pinned === slot.name,\n\t\t\t});\n\t\t}\n\t\tif (provider !== \"claude-sdk-oauth\") return summaries;\n\t}\n\n\tconst state = await repository.listSlots(provider, \"env\");\n\tfor (const slot of discoverEnvSlots(provider, (name) => env[name])) {\n\t\tconst persisted = state[slot.name];\n\t\tconst revision = await repository.envCredentialRevision(slot.envVarName, slot.key);\n\t\t// A block belongs to the value that earned it; a rotated env key starts clean.\n\t\tconst applicable = persisted?.credentialRevision === revision ? persisted : undefined;\n\t\tsummaries.push({\n\t\t\tname: slot.name,\n\t\t\tsource: \"env\",\n\t\t\tblocked: slotHealth(applicable, now) === \"blocked\",\n\t\t\tpinned: pinned === slot.name,\n\t\t});\n\t}\n\treturn summaries;\n}\n\n/** Pins one slot, or clears the pin when `name` is null. */\nexport async function pinCredentialAccount(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tname: string | null,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<void> {\n\tconst repo = repository ?? defaultRepository(storage);\n\tif (name !== null) {\n\t\tassertValidAccountName(name);\n\t\tconst accounts = await getCredentialAccounts(storage, provider, env, repo);\n\t\tif (!accounts.some((account) => account.name === name)) {\n\t\t\tthrow new Error(`Provider account not found: ${name}`);\n\t\t}\n\t}\n\tawait storage.modify(provider, async (current) => {\n\t\tif (current === undefined) {\n\t\t\tif (provider !== \"claude-sdk-oauth\" || name === null) {\n\t\t\t\tthrow new Error(`No stored credential for provider: ${provider}`);\n\t\t\t}\n\t\t\treturn pinSlot({ type: \"oauth\", ...SENTINEL_OAUTH_FIELDS, accounts: [] }, name);\n\t\t}\n\t\tif (name === null) {\n\t\t\tif (pinnedName(current) === undefined) return current;\n\t\t\tconst { pinned: _pinned, ...unpinned } = { ...current, pinned: undefined };\n\t\t\treturn unpinned;\n\t\t}\n\t\treturn pinSlot(current, name);\n\t});\n\t// Subscribed clients re-read the list after any mutation; skipping this leaves\n\t// a desktop account picker showing a stale pin.\n\temitProviderAccountsChanged(provider);\n}\n\n/**\n * Removes one stored slot. Env-backed accounts are refused: they are owned by\n * the environment, and deleting one here would silently disagree with the\n * variable that still defines it.\n */\nexport async function removeCredentialAccount(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tname: string,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<void> {\n\tconst repo = repository ?? defaultRepository(storage);\n\tconst accounts = await getCredentialAccounts(storage, provider, env, repo);\n\tconst account = accounts.find((candidate) => candidate.name === name);\n\tif (!account) throw new Error(`Provider account not found: ${name}`);\n\tif (account.source === \"env\") {\n\t\tthrow new Error(`Environment provider account cannot be removed: ${name}`);\n\t}\n\tconst next = await storage.read(provider);\n\tif (next === undefined) throw new Error(`No stored credential for provider: ${provider}`);\n\tconst remaining = removeSlot(next, name);\n\tif (remaining === undefined) await storage.delete(provider);\n\telse await storage.modify(provider, async () => remaining);\n\tawait repo.mutateSlotState(provider, \"stored\", name, () => undefined);\n\temitProviderAccountsChanged(provider);\n}\n"]}
1
+ {"version":3,"file":"credential-accounts.js","sourceRoot":"","sources":["../../src/core/credential-accounts.ts"],"names":[],"mappings":"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","sourcesContent":["import { dirname, join } from \"node:path\";\nimport type { Credential } from \"@earendil-works/pi-ai\";\nimport {\n\taccountDisplayName,\n\tlistSlots,\n\ttype PooledCredential,\n\tpinSlot,\n\tremoveSlot,\n\trenameSlotDisplayName,\n} from \"@earendil-works/pi-ai/auth/pool/slots\";\nimport type { AuthStorage } from \"./auth-storage.ts\";\nimport { discoverEnvSlots } from \"./credential-pool/env-slots.ts\";\nimport { CredentialSlotRepository, type CredentialSlotState, slotHealth } from \"./credential-pool/state-store.ts\";\nimport { emitProviderAccountsChanged } from \"./extensions/builtin/claude-sdk-oauth/account-events.ts\";\nimport { SENTINEL_OAUTH_FIELDS } from \"./extensions/builtin/claude-sdk-oauth/accounts.ts\";\n\nexport type CredentialAccountSource = \"login\" | \"import\" | \"env\";\n\n/** Account metadata safe to surface: names and health only, never key material. */\nexport type CredentialAccountSummary = {\n\treadonly name: string;\n\treadonly displayName?: string;\n\treadonly source: CredentialAccountSource;\n\treadonly blocked: boolean;\n\treadonly pinned: boolean;\n};\n\nconst ACCOUNT_NAME_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;\n\nexport function assertValidAccountName(name: string): void {\n\tif (!ACCOUNT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(\n\t\t\t`Invalid account name '${name}': use letters, digits, '-' or '_', starting with a letter or digit`,\n\t\t);\n\t}\n}\n\nfunction pooledFrom(credential: Credential | undefined): PooledCredential | undefined {\n\treturn credential === undefined ? undefined : credential;\n}\n\nfunction pinnedName(credential: PooledCredential | undefined): string | undefined {\n\treturn credential?.pinned;\n}\n\nfunction numberField(value: object, key: string): number | undefined {\n\tconst found = Object.entries(value).find(([candidate]) => candidate === key)?.[1];\n\treturn typeof found === \"number\" ? found : undefined;\n}\n\nfunction defaultRepository(storage: AuthStorage): CredentialSlotRepository {\n\tconst authPath = storage.getStoragePath();\n\treturn new CredentialSlotRepository(authPath ? join(dirname(authPath), \"credential-pool-state.json\") : undefined);\n}\n\nfunction stringField(value: object, key: string): string | undefined {\n\tconst found = Object.entries(value).find(([candidate]) => candidate === key)?.[1];\n\treturn typeof found === \"string\" ? found : undefined;\n}\n\n/**\n * Block state has two sources and both are authoritative: a slot persisted by an\n * existing provider lane carries its own `blockedUntil`/`blockReason` inside\n * auth.json, while generic pool failover records health in the sidecar. Reading\n * only one would silently downgrade a real block to \"available\".\n */\nfunction slotBlocked(slot: object, sidecar: CredentialSlotState | undefined, now: number): boolean {\n\tif (slotHealth(sidecar, now) === \"blocked\") return true;\n\tconst reason = stringField(slot, \"blockReason\");\n\tif (reason === \"auth_error\" || reason === \"account_disabled\") return true;\n\tconst blockedUntil = numberField(slot, \"blockedUntil\");\n\treturn blockedUntil !== undefined && blockedUntil > now;\n}\n\n/**\n * Lists a provider's credential accounts for ANY provider, not just one lane.\n * Stored slots own the listing when a credential exists; env slots are listed\n * only when nothing is stored, mirroring resolution precedence exactly. Health\n * comes from the pool sidecar, so a cooldown persisted by a failover shows up\n * here without auth.json ever carrying block state.\n */\nexport async function getCredentialAccounts(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<CredentialAccountSummary[]> {\n\treturn summarizeCredentialAccounts(provider, storage.get(provider), env, repository ?? defaultRepository(storage));\n}\n\n/** Storage-free variant for callers that already hold the credential (e.g. auth check). */\nexport async function summarizeCredentialAccounts(\n\tprovider: string,\n\tstored: Credential | undefined,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository: CredentialSlotRepository = new CredentialSlotRepository(),\n): Promise<CredentialAccountSummary[]> {\n\tconst credential = pooledFrom(stored);\n\tconst now = Date.now();\n\tconst pinned = pinnedName(credential);\n\tconst summaries: CredentialAccountSummary[] = [];\n\n\tif (credential) {\n\t\tconst state = await repository.listSlots(provider, \"stored\");\n\t\tconst storedAccounts =\n\t\t\tprovider === \"claude-sdk-oauth\"\n\t\t\t\t? Array.isArray(credential.accounts)\n\t\t\t\t\t? listSlots(credential)\n\t\t\t\t\t: []\n\t\t\t\t: listSlots(credential);\n\t\tfor (const slot of storedAccounts) {\n\t\t\tconst displayName = accountDisplayName(slot.displayName);\n\t\t\tsummaries.push({\n\t\t\t\tname: slot.name,\n\t\t\t\t...(displayName === undefined ? {} : { displayName }),\n\t\t\t\tsource: slot.source ?? \"login\",\n\t\t\t\tblocked: slotBlocked(slot, state[slot.name], now),\n\t\t\t\tpinned: pinned === slot.name,\n\t\t\t});\n\t\t}\n\t\tif (provider !== \"claude-sdk-oauth\") return summaries;\n\t}\n\n\tconst state = await repository.listSlots(provider, \"env\");\n\tfor (const slot of discoverEnvSlots(provider, (name) => env[name])) {\n\t\tconst persisted = state[slot.name];\n\t\tconst revision = await repository.envCredentialRevision(slot.envVarName, slot.key);\n\t\t// A block belongs to the value that earned it; a rotated env key starts clean.\n\t\tconst applicable = persisted?.credentialRevision === revision ? persisted : undefined;\n\t\tsummaries.push({\n\t\t\tname: slot.name,\n\t\t\tsource: \"env\",\n\t\t\tblocked: slotHealth(applicable, now) === \"blocked\",\n\t\t\tpinned: pinned === slot.name,\n\t\t});\n\t}\n\treturn summaries;\n}\n\n/** Atomically rename/clear stored metadata without changing identity, health or environment state. */\nexport async function renameCredentialAccount(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tname: string,\n\tdisplayName: string | null,\n): Promise<void> {\n\tawait storage.modify(provider, async (current) => {\n\t\tif (!current) throw new Error(`No stored credential for provider: ${provider}`);\n\t\t// Provider-managed OAuth sentinels without an accounts array are not legacy flat accounts.\n\t\t// Key this on the credential shape, not one provider id, so sibling managed lanes cannot be promoted.\n\t\tif (\n\t\t\tcurrent.type === \"oauth\" &&\n\t\t\t!Array.isArray((current as { accounts?: unknown }).accounts) &&\n\t\t\tcurrent.access === current.refresh &&\n\t\t\tcurrent.access.endsWith(\"-managed\")\n\t\t) {\n\t\t\tthrow new Error(`Stored provider account not found: ${name}`);\n\t\t}\n\t\treturn renameSlotDisplayName(current, name, displayName);\n\t});\n\temitProviderAccountsChanged(provider);\n}\n\n/** Pins one slot, or clears the pin when `name` is null. */\nexport async function pinCredentialAccount(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tname: string | null,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<void> {\n\tconst repo = repository ?? defaultRepository(storage);\n\tif (name !== null) {\n\t\tassertValidAccountName(name);\n\t\tconst accounts = await getCredentialAccounts(storage, provider, env, repo);\n\t\tif (!accounts.some((account) => account.name === name)) {\n\t\t\tthrow new Error(`Provider account not found: ${name}`);\n\t\t}\n\t}\n\tawait storage.modify(provider, async (current) => {\n\t\tif (current === undefined) {\n\t\t\tif (provider !== \"claude-sdk-oauth\" || name === null) {\n\t\t\t\tthrow new Error(`No stored credential for provider: ${provider}`);\n\t\t\t}\n\t\t\treturn pinSlot({ type: \"oauth\", ...SENTINEL_OAUTH_FIELDS, accounts: [] }, name);\n\t\t}\n\t\tif (name === null) {\n\t\t\tif (pinnedName(current) === undefined) return current;\n\t\t\tconst { pinned: _pinned, ...unpinned } = { ...current, pinned: undefined };\n\t\t\treturn unpinned;\n\t\t}\n\t\treturn pinSlot(current, name);\n\t});\n\t// Subscribed clients re-read the list after any mutation; skipping this leaves\n\t// a desktop account picker showing a stale pin.\n\temitProviderAccountsChanged(provider);\n}\n\n/**\n * Removes one stored slot. Env-backed accounts are refused: they are owned by\n * the environment, and deleting one here would silently disagree with the\n * variable that still defines it.\n */\nexport async function removeCredentialAccount(\n\tstorage: AuthStorage,\n\tprovider: string,\n\tname: string,\n\tenv: NodeJS.ProcessEnv = process.env,\n\trepository?: CredentialSlotRepository,\n): Promise<void> {\n\tconst repo = repository ?? defaultRepository(storage);\n\tconst accounts = await getCredentialAccounts(storage, provider, env, repo);\n\tconst account = accounts.find((candidate) => candidate.name === name);\n\tif (!account) throw new Error(`Provider account not found: ${name}`);\n\tif (account.source === \"env\") {\n\t\tthrow new Error(`Environment provider account cannot be removed: ${name}`);\n\t}\n\tconst next = await storage.read(provider);\n\tif (next === undefined) throw new Error(`No stored credential for provider: ${provider}`);\n\tconst remaining = removeSlot(next, name);\n\tif (remaining === undefined) await storage.delete(provider);\n\telse await storage.modify(provider, async () => remaining);\n\tawait repo.mutateSlotState(provider, \"stored\", name, () => undefined);\n\temitProviderAccountsChanged(provider);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/core/credential-pool/classify.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AACtD,eAAO,MAAM,eAAe,QAAoB,CAAC;AACjD,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,MAAM,MAAM,eAAe,GACxB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC9B;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,OAAO,uBAAuB,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAE5B;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9C;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAStD;AAuBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACtF,gBAAgB,CA4ClB"}
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../../src/core/credential-pool/classify.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,gBAAgB,QAAwB,CAAC;AACtD,eAAO,MAAM,eAAe,QAAoB,CAAC;AACjD,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,MAAM,MAAM,eAAe,GACxB;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,GACxB;IAAE,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC9B;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GACzB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,KAAK,EAAE,eAAe,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,WAAW,EAAE,OAAO,uBAAuB,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,CAAC;AAE5B;;;;GAIG;AACH,wBAAgB,iBAAiB,CAChC,YAAY,EAAE,MAAM,EACpB,YAAY,CAAC,EAAE,MAAM,EACrB,MAAM,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC9C;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,OAAO,CAAA;CAAE,CAStD;AAuBD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GACtF,gBAAgB,CAmDlB"}
@@ -1,3 +1,4 @@
1
+ import { PROVIDER_NOT_CONFIGURED_PREFIX } from "@earendil-works/pi-ai";
1
2
  import { DEFAULT_SLOT_BLOCK_MS, MAX_SLOT_BLOCK_MS } from "@earendil-works/pi-ai/auth/pool/failover";
2
3
  import { normalizeProviderError } from "@earendil-works/pi-ai/utils/error-body";
3
4
  import { getOverflowPatterns } from "@earendil-works/pi-ai/utils/overflow";
@@ -51,6 +52,13 @@ export function classifyCredentialFailure(error, context = {}) {
51
52
  const failureCount = context.failureCount ?? 0;
52
53
  if (isAbort(error, text))
53
54
  return { kind: "fail_request" };
55
+ // A slot whose material no longer resolves to usable auth is a per-credential
56
+ // fault, not a provider-wide one: failing the request here would let ONE bad
57
+ // slot dead-end a pool whose siblings are healthy. The block is permanent
58
+ // because only a re-login or a repaired entry can change that answer.
59
+ if (text.includes(PROVIDER_NOT_CONFIGURED_PREFIX)) {
60
+ return { kind: "failover", block: { reason: "auth_error" } };
61
+ }
54
62
  if (status === 401 || INVALID_KEY_TEXT.test(text)) {
55
63
  return { kind: "failover", block: { reason: "auth_error" } };
56
64
  }
@@ -1 +1 @@
1
- {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../../src/core/credential-pool/classify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AACpG,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AACjD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAYzC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAAoB,EACpB,YAAqB,EACrB,MAAM,GAAwC,EAAE;IAEhD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,eAAe,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,gBAAgB,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACvF,OAAO;QACN,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC;QAClC,mBAAmB,EAAE,OAAO,GAAG,GAAG;KAClC,CAAC;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG,yFAAyF,CAAC;AACnH,MAAM,uBAAuB,GAAG,kEAAkE,CAAC;AACnG,MAAM,eAAe,GAAG,uDAAuD,CAAC;AAChF,MAAM,YAAY,GACjB,2IAA2I,CAAC;AAC7I,MAAM,aAAa,GAAG,aAAa,CAAC;AACpC,MAAM,YAAY,GACjB,0GAA0G,CAAC;AAC5G,MAAM,cAAc,GACnB,oJAAoJ,CAAC;AACtJ,MAAM,UAAU,GAAG,eAAe,CAAC;AAEnC,SAAS,OAAO,CAAC,KAAc,EAAE,OAAe;IAC/C,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACvE,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IACnC,OAAO,mBAAmB,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACxC,KAAc,EACd,OAAO,GAA+E,EAAE;IAExF,MAAM,UAAU,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IACnH,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IACjC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC;IAE/C,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC1D,IAAI,MAAM,KAAK,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACpB,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;YACxC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;YACvD,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC7B,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,sBAAsB,CAAC;YACnC,MAAM,EAAE,MAAM,IAAI,GAAG;YACrB,QAAQ,EAAE,IAAI;SACd,CAAC,CAAC;QACH,OAAO;YACN,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE;gBACN,MAAM,EAAE,YAAY;gBACpB,GAAG,iBAAiB,CAAC,YAAY,EAAE,IAAI,EAAE;oBACxC,MAAM,EAAE,OAAO,CAAC,cAAc;oBAC9B,KAAK,EAAE,OAAO,CAAC,aAAa;iBAC5B,CAAC;aACF;SACD,CAAC;IACH,CAAC;IACD,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3F,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;QAC3G,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AACjC,CAAC","sourcesContent":["import { DEFAULT_SLOT_BLOCK_MS, MAX_SLOT_BLOCK_MS } from \"@earendil-works/pi-ai/auth/pool/failover\";\nimport { normalizeProviderError } from \"@earendil-works/pi-ai/utils/error-body\";\nimport { getOverflowPatterns } from \"@earendil-works/pi-ai/utils/overflow\";\nimport { extract429RetryAfterMs } from \"@earendil-works/pi-ai/utils/retry-hint\";\n\nexport const COOLDOWN_BASE_MS = DEFAULT_SLOT_BLOCK_MS;\nexport const COOLDOWN_CAP_MS = MAX_SLOT_BLOCK_MS;\nexport const RETRY_SAME_MAX_ATTEMPTS = 2;\n\nexport type CredentialBlock =\n\t| { reason: \"auth_error\" }\n\t| { reason: \"account_disabled\" }\n\t| { reason: \"rate_limit\"; cooldownMs: number; retryAfterWasCapped: boolean };\n\nexport type CredentialAction =\n\t| { kind: \"failover\"; block: CredentialBlock }\n\t| { kind: \"retry_same\"; maxAttempts: typeof RETRY_SAME_MAX_ATTEMPTS }\n\t| { kind: \"fail_request\" };\n\n/**\n * Per-slot exponential cooldown with the server hint as a FLOOR, never an\n * override: a hint can only lengthen the wait the failure count already earned,\n * and everything caps at 48 hours with the capping recorded.\n */\nexport function rateLimitCooldown(\n\tfailureCount: number,\n\tserverHintMs?: number,\n\tpolicy: { baseMs?: number; capMs?: number } = {},\n): { cooldownMs: number; retryAfterWasCapped: boolean } {\n\tconst cap = policy.capMs ?? COOLDOWN_CAP_MS;\n\tconst base = policy.baseMs ?? COOLDOWN_BASE_MS;\n\tconst backoff = Math.min(cap, base * 2 ** Math.max(0, failureCount));\n\tconst floored = serverHintMs === undefined ? backoff : Math.max(backoff, serverHintMs);\n\treturn {\n\t\tcooldownMs: Math.min(cap, floored),\n\t\tretryAfterWasCapped: floored > cap,\n\t};\n}\n\nconst INVALID_KEY_TEXT = /invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i;\nconst ACCOUNT_SCOPED_403_TEXT = /account|credential|token|api[ _-]?key|organization|subscription/i;\nconst RATE_LIMIT_TEXT = /rate[ _-]?limit|too many requests|resource_exhausted/i;\nconst BILLING_TEXT =\n\t/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i;\nconst OVERLOAD_TEXT = /overloaded/i;\nconst NETWORK_TEXT =\n\t/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i;\nconst FAIL_FAST_TEXT =\n\t/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i;\nconst ABORT_TEXT = /\\baborted?\\b/i;\n\nfunction isAbort(error: unknown, message: string): boolean {\n\tif (error instanceof Error && error.name === \"AbortError\") return true;\n\treturn ABORT_TEXT.test(message);\n}\n\nfunction isOverflowText(text: string): boolean {\n\treturn getOverflowPatterns().some((pattern) => pattern.test(text));\n}\n\n/**\n * Maps a provider failure onto the credential-pool action space. Credential-\n * scoped failures fail over (permanently for auth/billing, cooldown for rate\n * limits); provider-scoped faults (5xx/overload/network) retry the SAME slot\n * without blocking it, because blocking a healthy credential for a provider\n * outage only destroys prompt-cache locality; everything else fails the\n * request so the model fallback chain above keeps owning it.\n */\nexport function classifyCredentialFailure(\n\terror: unknown,\n\tcontext: { failureCount?: number; cooldownBaseMs?: number; cooldownCapMs?: number } = {},\n): CredentialAction {\n\tconst normalized = normalizeProviderError(error);\n\tconst text = normalized.messageCarriesBody ? normalized.message : `${normalized.message} ${normalized.body ?? \"\"}`;\n\tconst status = normalized.status;\n\tconst failureCount = context.failureCount ?? 0;\n\n\tif (isAbort(error, text)) return { kind: \"fail_request\" };\n\tif (status === 401 || INVALID_KEY_TEXT.test(text)) {\n\t\treturn { kind: \"failover\", block: { reason: \"auth_error\" } };\n\t}\n\tif (status === 403) {\n\t\treturn ACCOUNT_SCOPED_403_TEXT.test(text)\n\t\t\t? { kind: \"failover\", block: { reason: \"auth_error\" } }\n\t\t\t: { kind: \"fail_request\" };\n\t}\n\tif (status === 402 || BILLING_TEXT.test(text)) {\n\t\treturn { kind: \"failover\", block: { reason: \"account_disabled\" } };\n\t}\n\tif (status === 429 || RATE_LIMIT_TEXT.test(text)) {\n\t\tconst hint = extract429RetryAfterMs({\n\t\t\tstatus: status ?? 429,\n\t\t\tbodyText: text,\n\t\t});\n\t\treturn {\n\t\t\tkind: \"failover\",\n\t\t\tblock: {\n\t\t\t\treason: \"rate_limit\",\n\t\t\t\t...rateLimitCooldown(failureCount, hint, {\n\t\t\t\t\tbaseMs: context.cooldownBaseMs,\n\t\t\t\t\tcapMs: context.cooldownCapMs,\n\t\t\t\t}),\n\t\t\t},\n\t\t};\n\t}\n\tif (isOverflowText(text) || status === 400 || status === 404 || FAIL_FAST_TEXT.test(text)) {\n\t\treturn { kind: \"fail_request\" };\n\t}\n\tif (status === 529 || OVERLOAD_TEXT.test(text) || (status !== undefined && status >= 500 && status < 600)) {\n\t\treturn { kind: \"retry_same\", maxAttempts: RETRY_SAME_MAX_ATTEMPTS };\n\t}\n\tif (status === 408 || NETWORK_TEXT.test(text)) {\n\t\treturn { kind: \"retry_same\", maxAttempts: RETRY_SAME_MAX_ATTEMPTS };\n\t}\n\treturn { kind: \"fail_request\" };\n}\n"]}
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../../src/core/credential-pool/classify.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAC;AACpG,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wCAAwC,CAAC;AAEhF,MAAM,CAAC,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AACtD,MAAM,CAAC,MAAM,eAAe,GAAG,iBAAiB,CAAC;AACjD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAYzC;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAChC,YAAoB,EACpB,YAAqB,EACrB,MAAM,GAAwC,EAAE;IAEhD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,eAAe,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,gBAAgB,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IACvF,OAAO;QACN,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC;QAClC,mBAAmB,EAAE,OAAO,GAAG,GAAG;KAClC,CAAC;AACH,CAAC;AAED,MAAM,gBAAgB,GAAG,yFAAyF,CAAC;AACnH,MAAM,uBAAuB,GAAG,kEAAkE,CAAC;AACnG,MAAM,eAAe,GAAG,uDAAuD,CAAC;AAChF,MAAM,YAAY,GACjB,2IAA2I,CAAC;AAC7I,MAAM,aAAa,GAAG,aAAa,CAAC;AACpC,MAAM,YAAY,GACjB,0GAA0G,CAAC;AAC5G,MAAM,cAAc,GACnB,oJAAoJ,CAAC;AACtJ,MAAM,UAAU,GAAG,eAAe,CAAC;AAEnC,SAAS,OAAO,CAAC,KAAc,EAAE,OAAe;IAC/C,IAAI,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACvE,OAAO,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IACnC,OAAO,mBAAmB,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CACxC,KAAc,EACd,OAAO,GAA+E,EAAE;IAExF,MAAM,UAAU,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,UAAU,CAAC,kBAAkB,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,OAAO,IAAI,UAAU,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;IACnH,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IACjC,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,CAAC,CAAC;IAE/C,IAAI,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC1D,8EAA8E;IAC9E,6EAA6E;IAC7E,0EAA0E;IAC1E,sEAAsE;IACtE,IAAI,IAAI,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC;IAC9D,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACpB,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC;YACxC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;YACvD,CAAC,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAC7B,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC;IACpE,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,sBAAsB,CAAC;YACnC,MAAM,EAAE,MAAM,IAAI,GAAG;YACrB,QAAQ,EAAE,IAAI;SACd,CAAC,CAAC;QACH,OAAO;YACN,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE;gBACN,MAAM,EAAE,YAAY;gBACpB,GAAG,iBAAiB,CAAC,YAAY,EAAE,IAAI,EAAE;oBACxC,MAAM,EAAE,OAAO,CAAC,cAAc;oBAC9B,KAAK,EAAE,OAAO,CAAC,aAAa;iBAC5B,CAAC;aACF;SACD,CAAC;IACH,CAAC;IACD,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3F,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IACjC,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;QAC3G,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;IACrE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC;AACjC,CAAC","sourcesContent":["import { PROVIDER_NOT_CONFIGURED_PREFIX } from \"@earendil-works/pi-ai\";\nimport { DEFAULT_SLOT_BLOCK_MS, MAX_SLOT_BLOCK_MS } from \"@earendil-works/pi-ai/auth/pool/failover\";\nimport { normalizeProviderError } from \"@earendil-works/pi-ai/utils/error-body\";\nimport { getOverflowPatterns } from \"@earendil-works/pi-ai/utils/overflow\";\nimport { extract429RetryAfterMs } from \"@earendil-works/pi-ai/utils/retry-hint\";\n\nexport const COOLDOWN_BASE_MS = DEFAULT_SLOT_BLOCK_MS;\nexport const COOLDOWN_CAP_MS = MAX_SLOT_BLOCK_MS;\nexport const RETRY_SAME_MAX_ATTEMPTS = 2;\n\nexport type CredentialBlock =\n\t| { reason: \"auth_error\" }\n\t| { reason: \"account_disabled\" }\n\t| { reason: \"rate_limit\"; cooldownMs: number; retryAfterWasCapped: boolean };\n\nexport type CredentialAction =\n\t| { kind: \"failover\"; block: CredentialBlock }\n\t| { kind: \"retry_same\"; maxAttempts: typeof RETRY_SAME_MAX_ATTEMPTS }\n\t| { kind: \"fail_request\" };\n\n/**\n * Per-slot exponential cooldown with the server hint as a FLOOR, never an\n * override: a hint can only lengthen the wait the failure count already earned,\n * and everything caps at 48 hours with the capping recorded.\n */\nexport function rateLimitCooldown(\n\tfailureCount: number,\n\tserverHintMs?: number,\n\tpolicy: { baseMs?: number; capMs?: number } = {},\n): { cooldownMs: number; retryAfterWasCapped: boolean } {\n\tconst cap = policy.capMs ?? COOLDOWN_CAP_MS;\n\tconst base = policy.baseMs ?? COOLDOWN_BASE_MS;\n\tconst backoff = Math.min(cap, base * 2 ** Math.max(0, failureCount));\n\tconst floored = serverHintMs === undefined ? backoff : Math.max(backoff, serverHintMs);\n\treturn {\n\t\tcooldownMs: Math.min(cap, floored),\n\t\tretryAfterWasCapped: floored > cap,\n\t};\n}\n\nconst INVALID_KEY_TEXT = /invalid[ _-]?(?:api[ _-]?)?key|authentication[_ ]?error|invalid x-api-key|unauthorized/i;\nconst ACCOUNT_SCOPED_403_TEXT = /account|credential|token|api[ _-]?key|organization|subscription/i;\nconst RATE_LIMIT_TEXT = /rate[ _-]?limit|too many requests|resource_exhausted/i;\nconst BILLING_TEXT =\n\t/billing|credits?[ _-]?(?:required|exhausted|balance)|insufficient[ _-]?(?:funds|quota|credit)|payment[ _-]?required|quota[ _-]?exhausted/i;\nconst OVERLOAD_TEXT = /overloaded/i;\nconst NETWORK_TEXT =\n\t/econnreset|econnrefused|etimedout|enotfound|socket hang up|fetch failed|network error|request timed out/i;\nconst FAIL_FAST_TEXT =\n\t/context[ _-]?(?:length|window)|maximum context|invalid[ _-]?model|model[ _-]?not[ _-]?found|malformed[ _-]?stream|premature[ _-]?(?:close|stream)/i;\nconst ABORT_TEXT = /\\baborted?\\b/i;\n\nfunction isAbort(error: unknown, message: string): boolean {\n\tif (error instanceof Error && error.name === \"AbortError\") return true;\n\treturn ABORT_TEXT.test(message);\n}\n\nfunction isOverflowText(text: string): boolean {\n\treturn getOverflowPatterns().some((pattern) => pattern.test(text));\n}\n\n/**\n * Maps a provider failure onto the credential-pool action space. Credential-\n * scoped failures fail over (permanently for auth/billing, cooldown for rate\n * limits); provider-scoped faults (5xx/overload/network) retry the SAME slot\n * without blocking it, because blocking a healthy credential for a provider\n * outage only destroys prompt-cache locality; everything else fails the\n * request so the model fallback chain above keeps owning it.\n */\nexport function classifyCredentialFailure(\n\terror: unknown,\n\tcontext: { failureCount?: number; cooldownBaseMs?: number; cooldownCapMs?: number } = {},\n): CredentialAction {\n\tconst normalized = normalizeProviderError(error);\n\tconst text = normalized.messageCarriesBody ? normalized.message : `${normalized.message} ${normalized.body ?? \"\"}`;\n\tconst status = normalized.status;\n\tconst failureCount = context.failureCount ?? 0;\n\n\tif (isAbort(error, text)) return { kind: \"fail_request\" };\n\t// A slot whose material no longer resolves to usable auth is a per-credential\n\t// fault, not a provider-wide one: failing the request here would let ONE bad\n\t// slot dead-end a pool whose siblings are healthy. The block is permanent\n\t// because only a re-login or a repaired entry can change that answer.\n\tif (text.includes(PROVIDER_NOT_CONFIGURED_PREFIX)) {\n\t\treturn { kind: \"failover\", block: { reason: \"auth_error\" } };\n\t}\n\tif (status === 401 || INVALID_KEY_TEXT.test(text)) {\n\t\treturn { kind: \"failover\", block: { reason: \"auth_error\" } };\n\t}\n\tif (status === 403) {\n\t\treturn ACCOUNT_SCOPED_403_TEXT.test(text)\n\t\t\t? { kind: \"failover\", block: { reason: \"auth_error\" } }\n\t\t\t: { kind: \"fail_request\" };\n\t}\n\tif (status === 402 || BILLING_TEXT.test(text)) {\n\t\treturn { kind: \"failover\", block: { reason: \"account_disabled\" } };\n\t}\n\tif (status === 429 || RATE_LIMIT_TEXT.test(text)) {\n\t\tconst hint = extract429RetryAfterMs({\n\t\t\tstatus: status ?? 429,\n\t\t\tbodyText: text,\n\t\t});\n\t\treturn {\n\t\t\tkind: \"failover\",\n\t\t\tblock: {\n\t\t\t\treason: \"rate_limit\",\n\t\t\t\t...rateLimitCooldown(failureCount, hint, {\n\t\t\t\t\tbaseMs: context.cooldownBaseMs,\n\t\t\t\t\tcapMs: context.cooldownCapMs,\n\t\t\t\t}),\n\t\t\t},\n\t\t};\n\t}\n\tif (isOverflowText(text) || status === 400 || status === 404 || FAIL_FAST_TEXT.test(text)) {\n\t\treturn { kind: \"fail_request\" };\n\t}\n\tif (status === 529 || OVERLOAD_TEXT.test(text) || (status !== undefined && status >= 500 && status < 600)) {\n\t\treturn { kind: \"retry_same\", maxAttempts: RETRY_SAME_MAX_ATTEMPTS };\n\t}\n\tif (status === 408 || NETWORK_TEXT.test(text)) {\n\t\treturn { kind: \"retry_same\", maxAttempts: RETRY_SAME_MAX_ATTEMPTS };\n\t}\n\treturn { kind: \"fail_request\" };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/account/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AAwB5E;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsC/D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/account/index.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AA4B5E;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAwC/D"}
@@ -1,12 +1,14 @@
1
+ import { accountLabel } from "@earendil-works/pi-ai/auth/pool/slots";
1
2
  import { getCredentialAccounts, pinCredentialAccount, removeCredentialAccount, } from "../../../credential-accounts.js";
3
+ import { accountDisplayNameCommand } from "../account-display-name.js";
2
4
  function parseArgs(rawArgs) {
3
5
  return rawArgs.trim().split(/\s+/).filter(Boolean);
4
6
  }
5
7
  function usage(ctx) {
6
- ctx.ui.notify("Usage: /account <provider> [list | pin <name> | unpin | remove <name>]", "error");
8
+ ctx.ui.notify("Usage: /account <provider> [list | pin <id> | unpin | remove <id> | rename <id> <display name...> | clear-name <id>]", "error");
7
9
  }
8
10
  function statusOf(account) {
9
- const states = [account.name, account.source, account.blocked ? "blocked" : "available"];
11
+ const states = [accountLabel(account), account.source, account.blocked ? "blocked" : "available"];
10
12
  if (account.pinned)
11
13
  states.push("pinned");
12
14
  return states.join(" | ");
@@ -29,7 +31,7 @@ async function showAccounts(ctx, provider) {
29
31
  export default function accountExtension(pi) {
30
32
  pi.registerCommand("account", {
31
33
  description: "List and manage credential accounts for any provider.",
32
- argumentHint: "<provider> [list | pin <name> | unpin | remove <name>]",
34
+ argumentHint: "<provider> [list | pin <id> | unpin | remove <id> | rename <id> <display name...> | clear-name <id>]",
33
35
  handler: async (rawArgs, ctx) => {
34
36
  const args = parseArgs(rawArgs);
35
37
  const provider = args[0];
@@ -37,6 +39,8 @@ export default function accountExtension(pi) {
37
39
  usage(ctx);
38
40
  return;
39
41
  }
42
+ if (await accountDisplayNameCommand(ctx, provider, rawArgs.trim().replace(/^\S+\s*/, "")))
43
+ return;
40
44
  const action = args[1] ?? "list";
41
45
  try {
42
46
  if (action === "list") {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/account/index.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype CredentialAccountSummary,\n\tgetCredentialAccounts,\n\tpinCredentialAccount,\n\tremoveCredentialAccount,\n} from \"../../../credential-accounts.ts\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../../types.ts\";\n\nfunction parseArgs(rawArgs: string): string[] {\n\treturn rawArgs.trim().split(/\\s+/).filter(Boolean);\n}\n\nfunction usage(ctx: ExtensionCommandContext): void {\n\tctx.ui.notify(\"Usage: /account <provider> [list | pin <name> | unpin | remove <name>]\", \"error\");\n}\n\nfunction statusOf(account: CredentialAccountSummary): string {\n\tconst states = [account.name, account.source, account.blocked ? \"blocked\" : \"available\"];\n\tif (account.pinned) states.push(\"pinned\");\n\treturn states.join(\" | \");\n}\n\nasync function showAccounts(ctx: ExtensionCommandContext, provider: string): Promise<void> {\n\tconst accounts = await getCredentialAccounts(ctx.modelRegistry.authStorage, provider);\n\tconst lines = [`Credential accounts for ${provider}:`];\n\tif (accounts.length === 0) lines.push(\" (none)\");\n\tfor (const account of accounts) lines.push(` ${statusOf(account)}`);\n\tctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\n/**\n * Provider-neutral `/account` command over the generic credential pool. The\n * existing `/claude-account` and Cursor account commands stay untouched; this\n * command is the one surface that works for every provider. Output carries\n * names and health only, never key material.\n */\nexport default function accountExtension(pi: ExtensionAPI): void {\n\tpi.registerCommand(\"account\", {\n\t\tdescription: \"List and manage credential accounts for any provider.\",\n\t\targumentHint: \"<provider> [list | pin <name> | unpin | remove <name>]\",\n\t\thandler: async (rawArgs, ctx) => {\n\t\t\tconst args = parseArgs(rawArgs);\n\t\t\tconst provider = args[0];\n\t\t\tif (provider === undefined) {\n\t\t\t\tusage(ctx);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst action = args[1] ?? \"list\";\n\t\t\ttry {\n\t\t\t\tif (action === \"list\") {\n\t\t\t\t\tawait showAccounts(ctx, provider);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"pin\" && args[2] !== undefined) {\n\t\t\t\t\tawait pinCredentialAccount(ctx.modelRegistry.authStorage, provider, args[2]);\n\t\t\t\t\tctx.ui.notify(`Pinned ${provider} account '${args[2]}'.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"unpin\") {\n\t\t\t\t\tawait pinCredentialAccount(ctx.modelRegistry.authStorage, provider, null);\n\t\t\t\t\tctx.ui.notify(`Unpinned ${provider} account.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"remove\" && args[2] !== undefined) {\n\t\t\t\t\tawait removeCredentialAccount(ctx.modelRegistry.authStorage, provider, args[2]);\n\t\t\t\t\tctx.ui.notify(`Removed ${provider} account '${args[2]}'.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tusage(ctx);\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/account/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { accountLabel } from \"@earendil-works/pi-ai/auth/pool/slots\";\nimport {\n\ttype CredentialAccountSummary,\n\tgetCredentialAccounts,\n\tpinCredentialAccount,\n\tremoveCredentialAccount,\n} from \"../../../credential-accounts.ts\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../../types.ts\";\nimport { accountDisplayNameCommand } from \"../account-display-name.ts\";\n\nfunction parseArgs(rawArgs: string): string[] {\n\treturn rawArgs.trim().split(/\\s+/).filter(Boolean);\n}\n\nfunction usage(ctx: ExtensionCommandContext): void {\n\tctx.ui.notify(\n\t\t\"Usage: /account <provider> [list | pin <id> | unpin | remove <id> | rename <id> <display name...> | clear-name <id>]\",\n\t\t\"error\",\n\t);\n}\n\nfunction statusOf(account: CredentialAccountSummary): string {\n\tconst states = [accountLabel(account), account.source, account.blocked ? \"blocked\" : \"available\"];\n\tif (account.pinned) states.push(\"pinned\");\n\treturn states.join(\" | \");\n}\n\nasync function showAccounts(ctx: ExtensionCommandContext, provider: string): Promise<void> {\n\tconst accounts = await getCredentialAccounts(ctx.modelRegistry.authStorage, provider);\n\tconst lines = [`Credential accounts for ${provider}:`];\n\tif (accounts.length === 0) lines.push(\" (none)\");\n\tfor (const account of accounts) lines.push(` ${statusOf(account)}`);\n\tctx.ui.notify(lines.join(\"\\n\"), \"info\");\n}\n\n/**\n * Provider-neutral `/account` command over the generic credential pool. The\n * existing `/claude-account` and Cursor account commands stay untouched; this\n * command is the one surface that works for every provider. Output carries\n * names and health only, never key material.\n */\nexport default function accountExtension(pi: ExtensionAPI): void {\n\tpi.registerCommand(\"account\", {\n\t\tdescription: \"List and manage credential accounts for any provider.\",\n\t\targumentHint:\n\t\t\t\"<provider> [list | pin <id> | unpin | remove <id> | rename <id> <display name...> | clear-name <id>]\",\n\t\thandler: async (rawArgs, ctx) => {\n\t\t\tconst args = parseArgs(rawArgs);\n\t\t\tconst provider = args[0];\n\t\t\tif (provider === undefined) {\n\t\t\t\tusage(ctx);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (await accountDisplayNameCommand(ctx, provider, rawArgs.trim().replace(/^\\S+\\s*/, \"\"))) return;\n\t\t\tconst action = args[1] ?? \"list\";\n\t\t\ttry {\n\t\t\t\tif (action === \"list\") {\n\t\t\t\t\tawait showAccounts(ctx, provider);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"pin\" && args[2] !== undefined) {\n\t\t\t\t\tawait pinCredentialAccount(ctx.modelRegistry.authStorage, provider, args[2]);\n\t\t\t\t\tctx.ui.notify(`Pinned ${provider} account '${args[2]}'.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"unpin\") {\n\t\t\t\t\tawait pinCredentialAccount(ctx.modelRegistry.authStorage, provider, null);\n\t\t\t\t\tctx.ui.notify(`Unpinned ${provider} account.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (action === \"remove\" && args[2] !== undefined) {\n\t\t\t\t\tawait removeCredentialAccount(ctx.modelRegistry.authStorage, provider, args[2]);\n\t\t\t\t\tctx.ui.notify(`Removed ${provider} account '${args[2]}'.`, \"info\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tusage(ctx);\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import type { AccountLoginReceipt } from "@earendil-works/pi-ai";
2
+ import type { ExtensionCommandContext } from "../types.ts";
3
+ /** Shared command grammar preserves spaces inside the display name. */
4
+ export declare function accountDisplayNameCommand(ctx: ExtensionCommandContext, provider: string, rawArgs: string): Promise<boolean>;
5
+ /** Naming is a separate, optional operation after a successful login commit. */
6
+ export declare function promptAccountDisplayName(ctx: ExtensionCommandContext, receipt: AccountLoginReceipt | undefined): Promise<void>;
7
+ //# sourceMappingURL=account-display-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-display-name.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/account-display-name.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGjE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAG3D,uEAAuE;AACvE,wBAAsB,yBAAyB,CAC9C,GAAG,EAAE,uBAAuB,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,OAAO,CAAC,CAiBlB;AAED,gFAAgF;AAChF,wBAAsB,wBAAwB,CAC7C,GAAG,EAAE,uBAAuB,EAC5B,OAAO,EAAE,mBAAmB,GAAG,SAAS,GACtC,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -0,0 +1,40 @@
1
+ import { accountLabel } from "@earendil-works/pi-ai/auth/pool/slots";
2
+ import { renameCredentialAccount } from "../../credential-accounts.js";
3
+ import { LOGIN_CANCELLED_MESSAGE } from "./oauth-login-interaction.js";
4
+ /** Shared command grammar preserves spaces inside the display name. */
5
+ export async function accountDisplayNameCommand(ctx, provider, rawArgs) {
6
+ const [action, name, ...words] = rawArgs.trim().split(/\s+/);
7
+ if (action !== "rename" && action !== "clear-name")
8
+ return false;
9
+ try {
10
+ if (!name || (action === "clear-name" && words.length > 0)) {
11
+ throw new Error("Usage: rename <id> <display name...> or clear-name <id>");
12
+ }
13
+ const displayName = action === "clear-name" ? null : rawArgs.trim().replace(/^\S+\s+\S+\s*/, "");
14
+ await renameCredentialAccount(ctx.modelRegistry.authStorage, provider, name, displayName);
15
+ ctx.ui.notify(`Account display name updated: ${accountLabel({ name, displayName: displayName ?? undefined })}.`, "info");
16
+ }
17
+ catch (error) {
18
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
19
+ }
20
+ return true;
21
+ }
22
+ /** Naming is a separate, optional operation after a successful login commit. */
23
+ export async function promptAccountDisplayName(ctx, receipt) {
24
+ if (receipt?.origin !== "generated" || ctx.signal?.aborted)
25
+ return;
26
+ try {
27
+ const answer = await ctx.ui.input(`Display name for account ${receipt.name} (optional)`, "Leave blank to keep the account ID", ctx.signal ? { signal: ctx.signal } : undefined);
28
+ if (answer === undefined || answer.trim() === "" || ctx.signal?.aborted)
29
+ return;
30
+ await renameCredentialAccount(ctx.modelRegistry.authStorage, receipt.providerId, receipt.name, answer);
31
+ ctx.ui.notify(`Account display name: ${accountLabel({ name: receipt.name, displayName: answer })}.`, "info");
32
+ }
33
+ catch (error) {
34
+ const message = error instanceof Error ? error.message : String(error);
35
+ if (ctx.signal?.aborted || message === LOGIN_CANCELLED_MESSAGE)
36
+ return;
37
+ ctx.ui.notify(`Account is saved, but its display name was not changed: ${message}`, "warning");
38
+ }
39
+ }
40
+ //# sourceMappingURL=account-display-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-display-name.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/account-display-name.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AccountLoginReceipt } from \"@earendil-works/pi-ai\";\nimport { accountLabel } from \"@earendil-works/pi-ai/auth/pool/slots\";\nimport { renameCredentialAccount } from \"../../credential-accounts.ts\";\nimport type { ExtensionCommandContext } from \"../types.ts\";\nimport { LOGIN_CANCELLED_MESSAGE } from \"./oauth-login-interaction.ts\";\n\n/** Shared command grammar preserves spaces inside the display name. */\nexport async function accountDisplayNameCommand(\n\tctx: ExtensionCommandContext,\n\tprovider: string,\n\trawArgs: string,\n): Promise<boolean> {\n\tconst [action, name, ...words] = rawArgs.trim().split(/\\s+/);\n\tif (action !== \"rename\" && action !== \"clear-name\") return false;\n\ttry {\n\t\tif (!name || (action === \"clear-name\" && words.length > 0)) {\n\t\t\tthrow new Error(\"Usage: rename <id> <display name...> or clear-name <id>\");\n\t\t}\n\t\tconst displayName = action === \"clear-name\" ? null : rawArgs.trim().replace(/^\\S+\\s+\\S+\\s*/, \"\");\n\t\tawait renameCredentialAccount(ctx.modelRegistry.authStorage, provider, name, displayName);\n\t\tctx.ui.notify(\n\t\t\t`Account display name updated: ${accountLabel({ name, displayName: displayName ?? undefined })}.`,\n\t\t\t\"info\",\n\t\t);\n\t} catch (error) {\n\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t}\n\treturn true;\n}\n\n/** Naming is a separate, optional operation after a successful login commit. */\nexport async function promptAccountDisplayName(\n\tctx: ExtensionCommandContext,\n\treceipt: AccountLoginReceipt | undefined,\n): Promise<void> {\n\tif (receipt?.origin !== \"generated\" || ctx.signal?.aborted) return;\n\ttry {\n\t\tconst answer = await ctx.ui.input(\n\t\t\t`Display name for account ${receipt.name} (optional)`,\n\t\t\t\"Leave blank to keep the account ID\",\n\t\t\tctx.signal ? { signal: ctx.signal } : undefined,\n\t\t);\n\t\tif (answer === undefined || answer.trim() === \"\" || ctx.signal?.aborted) return;\n\t\tawait renameCredentialAccount(ctx.modelRegistry.authStorage, receipt.providerId, receipt.name, answer);\n\t\tctx.ui.notify(`Account display name: ${accountLabel({ name: receipt.name, displayName: answer })}.`, \"info\");\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tif (ctx.signal?.aborted || message === LOGIN_CANCELLED_MESSAGE) return;\n\t\tctx.ui.notify(`Account is saved, but its display name was not changed: ${message}`, \"warning\");\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/format.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,SAAS,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;AAkE9C,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,GAAE,SAAc,GACvB,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,SAAc,GAAG,MAAM,CAElH;AAQD,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,GAAE,SAAc,GACvB,kBAAkB,GAAG,mBAAmB,CA2B1C"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/format.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,cAAc,EAEnB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,kBAAkB,GAAG;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,SAAS,EAAE,eAAe,CAAC,WAAW,CAAC,CAAC;IACxC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACnC,CAAC;AAEF,KAAK,SAAS,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;AAsE9C,wBAAgB,gBAAgB,CAC/B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,GAAE,SAAc,GACvB,MAAM,CAER;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAE,SAAc,GAAG,MAAM,CAElH;AAQD,wBAAgB,mBAAmB,CAClC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,gBAAgB,EAC1B,SAAS,GAAE,SAAc,GACvB,kBAAkB,GAAG,mBAAmB,CA2B1C"}
@@ -34,8 +34,13 @@ function answeredLines(response, questions) {
34
34
  }
35
35
  function formatBody(response, questions) {
36
36
  switch (response.status) {
37
- case "answered":
38
- return answeredLines(response, questions).join("\n");
37
+ case "answered": {
38
+ const lines = answeredLines(response, questions);
39
+ const unanswered = response.unanswered.map((id) => headerFor(id, questions));
40
+ if (unanswered.length > 0)
41
+ lines.push(`Unanswered: ${unanswered.join(", ")}`);
42
+ return lines.join("\n");
43
+ }
39
44
  case "comment-submitted": {
40
45
  const lines = [`The user responded: ${response.comment?.trim() ?? ""}`, ...answeredLines(response, questions)];
41
46
  const unanswered = response.unanswered.map((id) => headerFor(id, questions));
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/format.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,2BAA2B,GAG3B,MAAM,aAAa,CAAC;AAmBrB,SAAS,SAAS,CAAC,EAAU,EAAE,SAAoB;IAClD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;AACvE,CAAC;AAED,SAAS,eAAe,CAAC,EAAU,EAAE,SAAoB;IACxD,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,UAAU,CAAC,MAAyD;IAC5E,IAAI,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAC9B,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,QAA0B,EAAE,SAAoB;IACtE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;QACvD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;YAC1C,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvB,CAAC;IACF,CAAC;IACD,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CAAC,QAA0B,EAAE,SAAoB;IACnE,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;QACzB,KAAK,UAAU;YACd,OAAO,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtD,KAAK,mBAAmB,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,CAAC,uBAAuB,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;YAC/G,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;YAC7E,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,eAAe,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC9E,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,KAAK,WAAW,EAAE,CAAC;YAClB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,mBAAmB,IAAI,2BAA2B,CAAC,GAAG,MAAM,CAAC,CAAC;YACnG,MAAM,KAAK,GAAG;gBACb,kCAAkC,OAAO,yCAAyC;aAClF,CAAC;YACF,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;YACpD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,KAAK,CAAC,IAAI,CAAC,4CAA4C,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAC/E,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,kGAAkG,CAAC,CAAC;YAC/G,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,KAAK,WAAW;YACf,OAAO,kCAAkC,CAAC;QAC3C,KAAK,wBAAwB;YAC5B,OAAO,uFAAuF,CAAC;QAChG,KAAK,aAAa;YACjB,OAAO,oFAAoF,CAAC;IAC9F,CAAC;AACF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC/B,QAAwB,EACxB,QAA0B,EAC1B,SAAS,GAAc,EAAE;IAEzB,OAAO,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAA0B,EAAE,SAAiB,EAAE,SAAS,GAAc,EAAE;IACzG,OAAO,uBAAuB,SAAS,MAAM,UAAU,CAAC,QAAQ,EAAE,SAAS,CAAC,EAAE,CAAC;AAChF,CAAC;AAED,SAAS,eAAe,CAAC,MAA6C;IACrE,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IACjC,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,mBAAmB,CAClC,OAAuB,EACvB,QAA0B,EAC1B,SAAS,GAAc,EAAE;IAEzB,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACzB,MAAM,OAAO,GAAkC,EAAE,CAAC;QAClD,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7D,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,CAAC;QACD,MAAM,OAAO,GAAuB;YACnC,OAAO;YACP,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,MAAM,EAAE,QAAQ,CAAC,MAAM;SACvB,CAAC;QACF,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,CAAC,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;QACvE,OAAO,OAAO,CAAC;IAChB,CAAC;IACD,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,KAAK,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC;IACxE,CAAC;IACD,MAAM,OAAO,GAAwB;QACpC,SAAS;QACT,OAAO;QACP,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,eAAe,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QAC3E,MAAM,EAAE,QAAQ,CAAC,MAAM;KACvB,CAAC;IACF,IAAI,QAAQ,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC;IACxE,OAAO,OAAO,CAAC;AAChB,CAAC","sourcesContent":["import {\n\ttype AskUserVariant,\n\tDEFAULT_ASK_USER_TIMEOUT_MS,\n\ttype QuestionRequest,\n\ttype QuestionResponse,\n} from \"./schema.ts\";\n\nexport type CodexResultDetails = {\n\tanswers: Record<string, { answers: string[] }>;\n\tcomment?: string;\n\tunanswered: string[];\n\tstatus: QuestionResponse[\"status\"];\n};\n\nexport type ClaudeResultDetails = {\n\tquestions: QuestionRequest[\"questions\"];\n\tanswers: Record<string, string>;\n\tfreeText?: string;\n\tunanswered: string[];\n\tstatus: QuestionResponse[\"status\"];\n};\n\ntype Questions = QuestionRequest[\"questions\"];\n\nfunction headerFor(id: string, questions: Questions): string {\n\treturn questions.find((question) => question.id === id)?.header ?? id;\n}\n\nfunction questionTextFor(id: string, questions: Questions): string {\n\treturn questions.find((question) => question.id === id)?.question ?? id;\n}\n\nfunction answerBody(answer: { selected: string[]; text?: string } | undefined): string | undefined {\n\tif (!answer) return undefined;\n\tif (answer.selected.length > 0) return answer.selected.join(\", \");\n\tconst text = answer.text?.trim();\n\treturn text === undefined || text.length === 0 ? undefined : text;\n}\n\nfunction answeredLines(response: QuestionResponse, questions: Questions): string[] {\n\tconst lines: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const question of questions) {\n\t\tconst body = answerBody(response.answers[question.id]);\n\t\tif (body !== undefined) {\n\t\t\tlines.push(`${question.header}: ${body}`);\n\t\t\tseen.add(question.id);\n\t\t}\n\t}\n\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\tif (seen.has(id)) continue;\n\t\tconst body = answerBody(answer);\n\t\tif (body !== undefined) lines.push(`${headerFor(id, questions)}: ${body}`);\n\t}\n\treturn lines;\n}\n\nfunction formatBody(response: QuestionResponse, questions: Questions): string {\n\tswitch (response.status) {\n\t\tcase \"answered\":\n\t\t\treturn answeredLines(response, questions).join(\"\\n\");\n\t\tcase \"comment-submitted\": {\n\t\t\tconst lines = [`The user responded: ${response.comment?.trim() ?? \"\"}`, ...answeredLines(response, questions)];\n\t\t\tconst unanswered = response.unanswered.map((id) => headerFor(id, questions));\n\t\t\tif (unanswered.length > 0) lines.push(`Unanswered: ${unanswered.join(\", \")}`);\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\t\tcase \"timed_out\": {\n\t\t\tconst minutes = Math.round((response.autoResolvedAfterMs ?? DEFAULT_ASK_USER_TIMEOUT_MS) / 60_000);\n\t\t\tconst lines = [\n\t\t\t\t`The user did not answer within ${minutes} minutes. (사용자가 답변을 안하고 timeout 으로 종료됨)`,\n\t\t\t];\n\t\t\tconst selected = answeredLines(response, questions);\n\t\t\tif (selected.length > 0) {\n\t\t\t\tlines.push(`Before going idle the user had selected: ${selected.join(\"; \")}`);\n\t\t\t}\n\t\t\tlines.push(\"Continue the work to completion on your best judgment; do not ask this question again this turn.\");\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\t\tcase \"cancelled\":\n\t\t\treturn \"The user dismissed the question.\";\n\t\tcase \"orphaned-after-restart\":\n\t\t\treturn \"The pending question could not be resumed after a restart; continue on best judgment.\";\n\t\tcase \"unavailable\":\n\t\t\treturn \"This session has no user attached (subagent or headless); decide on best judgment.\";\n\t}\n}\n\nexport function formatResultText(\n\t_variant: AskUserVariant,\n\tresponse: QuestionResponse,\n\tquestions: Questions = [],\n): string {\n\treturn formatBody(response, questions);\n}\n\nexport function formatUserMessage(response: QuestionResponse, requestId: string, questions: Questions = []): string {\n\treturn `[Answer to question ${requestId}]\\n${formatBody(response, questions)}`;\n}\n\nfunction selectedAnswers(answer: { selected: string[]; text?: string }): string[] {\n\tif (answer.selected.length > 0) return answer.selected;\n\tconst text = answer.text?.trim();\n\treturn text === undefined || text.length === 0 ? [] : [text];\n}\n\nexport function formatResultDetails(\n\tvariant: AskUserVariant,\n\tresponse: QuestionResponse,\n\tquestions: Questions = [],\n): CodexResultDetails | ClaudeResultDetails {\n\tif (variant === \"codex\") {\n\t\tconst answers: CodexResultDetails[\"answers\"] = {};\n\t\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\t\tanswers[id] = { answers: selectedAnswers(answer) };\n\t\t}\n\t\tconst details: CodexResultDetails = {\n\t\t\tanswers,\n\t\t\tunanswered: response.unanswered,\n\t\t\tstatus: response.status,\n\t\t};\n\t\tif (response.comment !== undefined) details.comment = response.comment;\n\t\treturn details;\n\t}\n\tconst answers: Record<string, string> = {};\n\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\tconst body = answerBody(answer);\n\t\tif (body !== undefined) answers[questionTextFor(id, questions)] = body;\n\t}\n\tconst details: ClaudeResultDetails = {\n\t\tquestions,\n\t\tanswers,\n\t\tunanswered: response.unanswered.map((id) => questionTextFor(id, questions)),\n\t\tstatus: response.status,\n\t};\n\tif (response.comment !== undefined) details.freeText = response.comment;\n\treturn details;\n}\n"]}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/format.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype AskUserVariant,\n\tDEFAULT_ASK_USER_TIMEOUT_MS,\n\ttype QuestionRequest,\n\ttype QuestionResponse,\n} from \"./schema.ts\";\n\nexport type CodexResultDetails = {\n\tanswers: Record<string, { answers: string[] }>;\n\tcomment?: string;\n\tunanswered: string[];\n\tstatus: QuestionResponse[\"status\"];\n};\n\nexport type ClaudeResultDetails = {\n\tquestions: QuestionRequest[\"questions\"];\n\tanswers: Record<string, string>;\n\tfreeText?: string;\n\tunanswered: string[];\n\tstatus: QuestionResponse[\"status\"];\n};\n\ntype Questions = QuestionRequest[\"questions\"];\n\nfunction headerFor(id: string, questions: Questions): string {\n\treturn questions.find((question) => question.id === id)?.header ?? id;\n}\n\nfunction questionTextFor(id: string, questions: Questions): string {\n\treturn questions.find((question) => question.id === id)?.question ?? id;\n}\n\nfunction answerBody(answer: { selected: string[]; text?: string } | undefined): string | undefined {\n\tif (!answer) return undefined;\n\tif (answer.selected.length > 0) return answer.selected.join(\", \");\n\tconst text = answer.text?.trim();\n\treturn text === undefined || text.length === 0 ? undefined : text;\n}\n\nfunction answeredLines(response: QuestionResponse, questions: Questions): string[] {\n\tconst lines: string[] = [];\n\tconst seen = new Set<string>();\n\tfor (const question of questions) {\n\t\tconst body = answerBody(response.answers[question.id]);\n\t\tif (body !== undefined) {\n\t\t\tlines.push(`${question.header}: ${body}`);\n\t\t\tseen.add(question.id);\n\t\t}\n\t}\n\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\tif (seen.has(id)) continue;\n\t\tconst body = answerBody(answer);\n\t\tif (body !== undefined) lines.push(`${headerFor(id, questions)}: ${body}`);\n\t}\n\treturn lines;\n}\n\nfunction formatBody(response: QuestionResponse, questions: Questions): string {\n\tswitch (response.status) {\n\t\tcase \"answered\": {\n\t\t\tconst lines = answeredLines(response, questions);\n\t\t\tconst unanswered = response.unanswered.map((id) => headerFor(id, questions));\n\t\t\tif (unanswered.length > 0) lines.push(`Unanswered: ${unanswered.join(\", \")}`);\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\t\tcase \"comment-submitted\": {\n\t\t\tconst lines = [`The user responded: ${response.comment?.trim() ?? \"\"}`, ...answeredLines(response, questions)];\n\t\t\tconst unanswered = response.unanswered.map((id) => headerFor(id, questions));\n\t\t\tif (unanswered.length > 0) lines.push(`Unanswered: ${unanswered.join(\", \")}`);\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\t\tcase \"timed_out\": {\n\t\t\tconst minutes = Math.round((response.autoResolvedAfterMs ?? DEFAULT_ASK_USER_TIMEOUT_MS) / 60_000);\n\t\t\tconst lines = [\n\t\t\t\t`The user did not answer within ${minutes} minutes. (사용자가 답변을 안하고 timeout 으로 종료됨)`,\n\t\t\t];\n\t\t\tconst selected = answeredLines(response, questions);\n\t\t\tif (selected.length > 0) {\n\t\t\t\tlines.push(`Before going idle the user had selected: ${selected.join(\"; \")}`);\n\t\t\t}\n\t\t\tlines.push(\"Continue the work to completion on your best judgment; do not ask this question again this turn.\");\n\t\t\treturn lines.join(\"\\n\");\n\t\t}\n\t\tcase \"cancelled\":\n\t\t\treturn \"The user dismissed the question.\";\n\t\tcase \"orphaned-after-restart\":\n\t\t\treturn \"The pending question could not be resumed after a restart; continue on best judgment.\";\n\t\tcase \"unavailable\":\n\t\t\treturn \"This session has no user attached (subagent or headless); decide on best judgment.\";\n\t}\n}\n\nexport function formatResultText(\n\t_variant: AskUserVariant,\n\tresponse: QuestionResponse,\n\tquestions: Questions = [],\n): string {\n\treturn formatBody(response, questions);\n}\n\nexport function formatUserMessage(response: QuestionResponse, requestId: string, questions: Questions = []): string {\n\treturn `[Answer to question ${requestId}]\\n${formatBody(response, questions)}`;\n}\n\nfunction selectedAnswers(answer: { selected: string[]; text?: string }): string[] {\n\tif (answer.selected.length > 0) return answer.selected;\n\tconst text = answer.text?.trim();\n\treturn text === undefined || text.length === 0 ? [] : [text];\n}\n\nexport function formatResultDetails(\n\tvariant: AskUserVariant,\n\tresponse: QuestionResponse,\n\tquestions: Questions = [],\n): CodexResultDetails | ClaudeResultDetails {\n\tif (variant === \"codex\") {\n\t\tconst answers: CodexResultDetails[\"answers\"] = {};\n\t\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\t\tanswers[id] = { answers: selectedAnswers(answer) };\n\t\t}\n\t\tconst details: CodexResultDetails = {\n\t\t\tanswers,\n\t\t\tunanswered: response.unanswered,\n\t\t\tstatus: response.status,\n\t\t};\n\t\tif (response.comment !== undefined) details.comment = response.comment;\n\t\treturn details;\n\t}\n\tconst answers: Record<string, string> = {};\n\tfor (const [id, answer] of Object.entries(response.answers)) {\n\t\tconst body = answerBody(answer);\n\t\tif (body !== undefined) answers[questionTextFor(id, questions)] = body;\n\t}\n\tconst details: ClaudeResultDetails = {\n\t\tquestions,\n\t\tanswers,\n\t\tunanswered: response.unanswered.map((id) => questionTextFor(id, questions)),\n\t\tstatus: response.status,\n\t};\n\tif (response.comment !== undefined) details.freeText = response.comment;\n\treturn details;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/pending.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,MAAM,sBAAsB,GAC/B,UAAU,GACV,mBAAmB,GACnB,WAAW,GACX,WAAW,GACX,wBAAwB,GACxB,aAAa,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,wBAAwB,GAAG,aAAa,CAAC;AAIlF,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,kBAAkB,CAAC;IAC1E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,sBAAsB,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG;IAC7B,KAAK,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,KAAK,CAAC;IAC7E,MAAM,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,gBAAgB,CAAC;IAChD,OAAO,IAAI,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC9C,CAAC;AA+CF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA0FtF"}
1
+ {"version":3,"file":"pending.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/pending.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC5B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAE7D,MAAM,MAAM,sBAAsB,GAC/B,UAAU,GACV,mBAAmB,GACnB,WAAW,GACX,WAAW,GACX,wBAAwB,GACxB,aAAa,CAAC;AAEjB,MAAM,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,sBAAsB,CAAC;IAC/B,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE,eAAe,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,wBAAwB,GAAG,aAAa,CAAC;AAIlF,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG;IACpC,OAAO,EAAE,eAAe,CAAC;IACzB,GAAG,EAAE,MAAM,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAC/C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,kBAAkB,CAAC;IAC1E,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACpD,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,sBAAsB,CAAC;AAEtE,MAAM,MAAM,eAAe,GAAG;IAC7B,KAAK,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IACnC,MAAM,CAAC,OAAO,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,GAAG,KAAK,CAAC;IAC7E,MAAM,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,gBAAgB,CAAC;IAChD,OAAO,IAAI,gBAAgB,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC9C,CAAC;AA+CF,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA6FtF"}
@@ -101,6 +101,9 @@ export function createPendingQuestion(options) {
101
101
  if (unansweredIds(options.request, answers).length === 0) {
102
102
  return settle(buildResponse("answered", options.request, answers, comment), false);
103
103
  }
104
+ if (Object.keys(answers).length > 0) {
105
+ return settle(buildResponse("answered", options.request, answers, comment), false);
106
+ }
104
107
  return false;
105
108
  },
106
109
  cancel(reason = "cancelled") {
@@ -1 +1 @@
1
- {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/pending.ts"],"names":[],"mappings":"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","sourcesContent":["// TODO(t1-merge): import from ./schema.ts\nexport type QuestionOption = {\n\tlabel: string;\n\tdescription?: string;\n};\n\nexport type QuestionItem = {\n\tid: string;\n\theader: string;\n\tquestion: string;\n\toptions: QuestionOption[];\n\tmultiSelect: boolean;\n};\n\nexport type QuestionRequest = {\n\trequestId: string;\n\tquestions: QuestionItem[];\n\twaitForAnswer: boolean;\n\ttimeoutMs: number;\n};\n\nexport type QuestionAnswer = {\n\tselected: string[];\n\ttext?: string;\n};\n\nexport type QuestionAnswers = Record<string, QuestionAnswer>;\n\nexport type QuestionResponseStatus =\n\t| \"answered\"\n\t| \"comment-submitted\"\n\t| \"timed_out\"\n\t| \"cancelled\"\n\t| \"orphaned-after-restart\"\n\t| \"unavailable\";\n\nexport type QuestionResponse = {\n\tstatus: QuestionResponseStatus;\n\tanswers: QuestionAnswers;\n\tcomment?: string;\n\tunanswered: string[];\n\tautoResolvedAfterMs?: number;\n};\n\nexport type QuestionDraft = {\n\tanswers: QuestionAnswers;\n\tcomment?: string;\n};\n\nexport type CancelReason = \"cancelled\" | \"orphaned-after-restart\" | \"unavailable\";\n\nconst DEFAULT_HARD_CAP_MS = 7_200_000;\n\nexport type PendingTimerHandle = ReturnType<typeof setTimeout>;\n\nexport type PendingQuestionOptions = {\n\trequest: QuestionRequest;\n\tnow: () => number;\n\tidleTimeoutMs: number;\n\thardCapMs?: number;\n\tonTimeout?: (result: QuestionResponse) => void;\n\tsetTimeout?: (handler: () => void, delayMs: number) => PendingTimerHandle;\n\tclearTimeout?: (handle: PendingTimerHandle) => void;\n};\n\nexport type PendingQuestionState = \"pending\" | QuestionResponseStatus;\n\nexport type PendingQuestion = {\n\ttouch(draft?: QuestionDraft): void;\n\tsubmit(answers: QuestionAnswers, comment?: string): QuestionResponse | false;\n\tcancel(reason?: CancelReason): QuestionResponse;\n\ttimeout(): QuestionResponse;\n\treadonly state: PendingQuestionState;\n\treadonly deadlineAtMs: number;\n\tremainingMs(now: number): number;\n\treadonly result: QuestionResponse | undefined;\n};\n\nfunction copyAnswers(answers: QuestionAnswers): QuestionAnswers {\n\tconst copied: QuestionAnswers = {};\n\tfor (const [id, answer] of Object.entries(answers)) {\n\t\tcopied[id] = {\n\t\t\tselected: [...answer.selected],\n\t\t\t...(answer.text !== undefined ? { text: answer.text } : {}),\n\t\t};\n\t}\n\treturn copied;\n}\n\nfunction hasAnswer(answer: QuestionAnswer | undefined): boolean {\n\tif (answer === undefined) return false;\n\tif (answer.selected.length > 0) return true;\n\treturn answer.text !== undefined && answer.text.trim() !== \"\";\n}\n\nfunction unansweredIds(request: QuestionRequest, answers: QuestionAnswers): string[] {\n\tconst unanswered: string[] = [];\n\tfor (const question of request.questions) {\n\t\tif (!hasAnswer(answers[question.id])) unanswered.push(question.id);\n\t}\n\treturn unanswered;\n}\n\nfunction isCommentPresent(comment: string | undefined): comment is string {\n\treturn comment !== undefined && comment.trim() !== \"\";\n}\n\nfunction buildResponse(\n\tstatus: QuestionResponseStatus,\n\trequest: QuestionRequest,\n\tanswers: QuestionAnswers,\n\tcomment: string | undefined,\n\tautoResolvedAfterMs?: number,\n): QuestionResponse {\n\treturn {\n\t\tstatus,\n\t\tanswers: copyAnswers(answers),\n\t\t...(isCommentPresent(comment) ? { comment } : {}),\n\t\tunanswered: unansweredIds(request, answers),\n\t\t...(autoResolvedAfterMs !== undefined ? { autoResolvedAfterMs } : {}),\n\t};\n}\n\nexport function createPendingQuestion(options: PendingQuestionOptions): PendingQuestion {\n\tconst createdAtMs = options.now();\n\tconst hardCapMs = options.hardCapMs ?? DEFAULT_HARD_CAP_MS;\n\tconst hardDeadlineAtMs = createdAtMs + hardCapMs;\n\tconst schedule: NonNullable<PendingQuestionOptions[\"setTimeout\"]> =\n\t\toptions.setTimeout ?? ((handler, delayMs) => setTimeout(handler, delayMs));\n\tconst unsched: NonNullable<PendingQuestionOptions[\"clearTimeout\"]> = options.clearTimeout ?? clearTimeout;\n\n\tlet deadlineAtMs = Math.min(createdAtMs + options.idleTimeoutMs, hardDeadlineAtMs);\n\tlet draftAnswers: QuestionAnswers = {};\n\tlet draftComment: string | undefined;\n\tlet terminal: QuestionResponse | undefined;\n\tlet timer: PendingTimerHandle | undefined;\n\n\tconst disarm = () => {\n\t\tif (timer === undefined) return;\n\t\tunsched(timer);\n\t\ttimer = undefined;\n\t};\n\n\tconst settle = (response: QuestionResponse, notifyTimeout: boolean): QuestionResponse => {\n\t\tif (terminal !== undefined) return terminal;\n\t\tterminal = response;\n\t\tdisarm();\n\t\tif (notifyTimeout) options.onTimeout?.(response);\n\t\treturn response;\n\t};\n\n\tconst fireTimeout = (): QuestionResponse => {\n\t\tconst elapsedMs = Math.max(0, options.now() - createdAtMs);\n\t\treturn settle(buildResponse(\"timed_out\", options.request, draftAnswers, draftComment, elapsedMs), true);\n\t};\n\n\tconst arm = () => {\n\t\tdisarm();\n\t\tif (terminal !== undefined) return;\n\t\tconst delayMs = deadlineAtMs - options.now();\n\t\tif (delayMs <= 0) {\n\t\t\tfireTimeout();\n\t\t\treturn;\n\t\t}\n\t\ttimer = schedule(() => {\n\t\t\ttimer = undefined;\n\t\t\tfireTimeout();\n\t\t}, delayMs);\n\t};\n\n\tarm();\n\n\treturn {\n\t\ttouch(draft) {\n\t\t\tif (terminal !== undefined) return;\n\t\t\tif (draft !== undefined) {\n\t\t\t\tdraftAnswers = copyAnswers(draft.answers);\n\t\t\t\tdraftComment = draft.comment;\n\t\t\t}\n\t\t\tdeadlineAtMs = Math.min(options.now() + options.idleTimeoutMs, hardDeadlineAtMs);\n\t\t\tarm();\n\t\t},\n\t\tsubmit(answers, comment) {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\tif (isCommentPresent(comment)) {\n\t\t\t\treturn settle(buildResponse(\"comment-submitted\", options.request, answers, comment), false);\n\t\t\t}\n\t\t\tif (unansweredIds(options.request, answers).length === 0) {\n\t\t\t\treturn settle(buildResponse(\"answered\", options.request, answers, comment), false);\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tcancel(reason = \"cancelled\") {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\treturn settle(buildResponse(reason, options.request, draftAnswers, draftComment), false);\n\t\t},\n\t\ttimeout() {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\treturn fireTimeout();\n\t\t},\n\t\tget state() {\n\t\t\treturn terminal?.status ?? \"pending\";\n\t\t},\n\t\tget deadlineAtMs() {\n\t\t\treturn deadlineAtMs;\n\t\t},\n\t\tremainingMs(now) {\n\t\t\treturn Math.max(0, deadlineAtMs - now);\n\t\t},\n\t\tget result() {\n\t\t\treturn terminal;\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/ask-user/pending.ts"],"names":[],"mappings":"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","sourcesContent":["// TODO(t1-merge): import from ./schema.ts\nexport type QuestionOption = {\n\tlabel: string;\n\tdescription?: string;\n};\n\nexport type QuestionItem = {\n\tid: string;\n\theader: string;\n\tquestion: string;\n\toptions: QuestionOption[];\n\tmultiSelect: boolean;\n};\n\nexport type QuestionRequest = {\n\trequestId: string;\n\tquestions: QuestionItem[];\n\twaitForAnswer: boolean;\n\ttimeoutMs: number;\n};\n\nexport type QuestionAnswer = {\n\tselected: string[];\n\ttext?: string;\n};\n\nexport type QuestionAnswers = Record<string, QuestionAnswer>;\n\nexport type QuestionResponseStatus =\n\t| \"answered\"\n\t| \"comment-submitted\"\n\t| \"timed_out\"\n\t| \"cancelled\"\n\t| \"orphaned-after-restart\"\n\t| \"unavailable\";\n\nexport type QuestionResponse = {\n\tstatus: QuestionResponseStatus;\n\tanswers: QuestionAnswers;\n\tcomment?: string;\n\tunanswered: string[];\n\tautoResolvedAfterMs?: number;\n};\n\nexport type QuestionDraft = {\n\tanswers: QuestionAnswers;\n\tcomment?: string;\n};\n\nexport type CancelReason = \"cancelled\" | \"orphaned-after-restart\" | \"unavailable\";\n\nconst DEFAULT_HARD_CAP_MS = 7_200_000;\n\nexport type PendingTimerHandle = ReturnType<typeof setTimeout>;\n\nexport type PendingQuestionOptions = {\n\trequest: QuestionRequest;\n\tnow: () => number;\n\tidleTimeoutMs: number;\n\thardCapMs?: number;\n\tonTimeout?: (result: QuestionResponse) => void;\n\tsetTimeout?: (handler: () => void, delayMs: number) => PendingTimerHandle;\n\tclearTimeout?: (handle: PendingTimerHandle) => void;\n};\n\nexport type PendingQuestionState = \"pending\" | QuestionResponseStatus;\n\nexport type PendingQuestion = {\n\ttouch(draft?: QuestionDraft): void;\n\tsubmit(answers: QuestionAnswers, comment?: string): QuestionResponse | false;\n\tcancel(reason?: CancelReason): QuestionResponse;\n\ttimeout(): QuestionResponse;\n\treadonly state: PendingQuestionState;\n\treadonly deadlineAtMs: number;\n\tremainingMs(now: number): number;\n\treadonly result: QuestionResponse | undefined;\n};\n\nfunction copyAnswers(answers: QuestionAnswers): QuestionAnswers {\n\tconst copied: QuestionAnswers = {};\n\tfor (const [id, answer] of Object.entries(answers)) {\n\t\tcopied[id] = {\n\t\t\tselected: [...answer.selected],\n\t\t\t...(answer.text !== undefined ? { text: answer.text } : {}),\n\t\t};\n\t}\n\treturn copied;\n}\n\nfunction hasAnswer(answer: QuestionAnswer | undefined): boolean {\n\tif (answer === undefined) return false;\n\tif (answer.selected.length > 0) return true;\n\treturn answer.text !== undefined && answer.text.trim() !== \"\";\n}\n\nfunction unansweredIds(request: QuestionRequest, answers: QuestionAnswers): string[] {\n\tconst unanswered: string[] = [];\n\tfor (const question of request.questions) {\n\t\tif (!hasAnswer(answers[question.id])) unanswered.push(question.id);\n\t}\n\treturn unanswered;\n}\n\nfunction isCommentPresent(comment: string | undefined): comment is string {\n\treturn comment !== undefined && comment.trim() !== \"\";\n}\n\nfunction buildResponse(\n\tstatus: QuestionResponseStatus,\n\trequest: QuestionRequest,\n\tanswers: QuestionAnswers,\n\tcomment: string | undefined,\n\tautoResolvedAfterMs?: number,\n): QuestionResponse {\n\treturn {\n\t\tstatus,\n\t\tanswers: copyAnswers(answers),\n\t\t...(isCommentPresent(comment) ? { comment } : {}),\n\t\tunanswered: unansweredIds(request, answers),\n\t\t...(autoResolvedAfterMs !== undefined ? { autoResolvedAfterMs } : {}),\n\t};\n}\n\nexport function createPendingQuestion(options: PendingQuestionOptions): PendingQuestion {\n\tconst createdAtMs = options.now();\n\tconst hardCapMs = options.hardCapMs ?? DEFAULT_HARD_CAP_MS;\n\tconst hardDeadlineAtMs = createdAtMs + hardCapMs;\n\tconst schedule: NonNullable<PendingQuestionOptions[\"setTimeout\"]> =\n\t\toptions.setTimeout ?? ((handler, delayMs) => setTimeout(handler, delayMs));\n\tconst unsched: NonNullable<PendingQuestionOptions[\"clearTimeout\"]> = options.clearTimeout ?? clearTimeout;\n\n\tlet deadlineAtMs = Math.min(createdAtMs + options.idleTimeoutMs, hardDeadlineAtMs);\n\tlet draftAnswers: QuestionAnswers = {};\n\tlet draftComment: string | undefined;\n\tlet terminal: QuestionResponse | undefined;\n\tlet timer: PendingTimerHandle | undefined;\n\n\tconst disarm = () => {\n\t\tif (timer === undefined) return;\n\t\tunsched(timer);\n\t\ttimer = undefined;\n\t};\n\n\tconst settle = (response: QuestionResponse, notifyTimeout: boolean): QuestionResponse => {\n\t\tif (terminal !== undefined) return terminal;\n\t\tterminal = response;\n\t\tdisarm();\n\t\tif (notifyTimeout) options.onTimeout?.(response);\n\t\treturn response;\n\t};\n\n\tconst fireTimeout = (): QuestionResponse => {\n\t\tconst elapsedMs = Math.max(0, options.now() - createdAtMs);\n\t\treturn settle(buildResponse(\"timed_out\", options.request, draftAnswers, draftComment, elapsedMs), true);\n\t};\n\n\tconst arm = () => {\n\t\tdisarm();\n\t\tif (terminal !== undefined) return;\n\t\tconst delayMs = deadlineAtMs - options.now();\n\t\tif (delayMs <= 0) {\n\t\t\tfireTimeout();\n\t\t\treturn;\n\t\t}\n\t\ttimer = schedule(() => {\n\t\t\ttimer = undefined;\n\t\t\tfireTimeout();\n\t\t}, delayMs);\n\t};\n\n\tarm();\n\n\treturn {\n\t\ttouch(draft) {\n\t\t\tif (terminal !== undefined) return;\n\t\t\tif (draft !== undefined) {\n\t\t\t\tdraftAnswers = copyAnswers(draft.answers);\n\t\t\t\tdraftComment = draft.comment;\n\t\t\t}\n\t\t\tdeadlineAtMs = Math.min(options.now() + options.idleTimeoutMs, hardDeadlineAtMs);\n\t\t\tarm();\n\t\t},\n\t\tsubmit(answers, comment) {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\tif (isCommentPresent(comment)) {\n\t\t\t\treturn settle(buildResponse(\"comment-submitted\", options.request, answers, comment), false);\n\t\t\t}\n\t\t\tif (unansweredIds(options.request, answers).length === 0) {\n\t\t\t\treturn settle(buildResponse(\"answered\", options.request, answers, comment), false);\n\t\t\t}\n\t\t\tif (Object.keys(answers).length > 0) {\n\t\t\t\treturn settle(buildResponse(\"answered\", options.request, answers, comment), false);\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\tcancel(reason = \"cancelled\") {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\treturn settle(buildResponse(reason, options.request, draftAnswers, draftComment), false);\n\t\t},\n\t\ttimeout() {\n\t\t\tif (terminal !== undefined) return terminal;\n\t\t\treturn fireTimeout();\n\t\t},\n\t\tget state() {\n\t\t\treturn terminal?.status ?? \"pending\";\n\t\t},\n\t\tget deadlineAtMs() {\n\t\t\treturn deadlineAtMs;\n\t\t},\n\t\tremainingMs(now) {\n\t\t\treturn Math.max(0, deadlineAtMs - now);\n\t\t},\n\t\tget result() {\n\t\t\treturn terminal;\n\t\t},\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"account-command.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/claude-sdk-oauth/account-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AAM5E,OAAO,EAAE,KAAK,8BAA8B,EAA8C,MAAM,eAAe,CAAC;AAIhH,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACxC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,8BAA8B,CAAC;IAC/D,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAClD;AAsCD,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE5F;AAED,8FAA8F;AAC9F,wBAAgB,uBAAuB,CACtC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,qBAAqB,EAAE,MAAM,GAAG,SAAS,EACzC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,GAAG,IAAI,CA8CxG"}
1
+ {"version":3,"file":"account-command.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/claude-sdk-oauth/account-command.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAA2B,MAAM,gBAAgB,CAAC;AAO5E,OAAO,EAAE,KAAK,8BAA8B,EAA8C,MAAM,eAAe,CAAC;AAIhH,KAAK,kBAAkB,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACxC,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,8BAA8B,CAAC;IAC/D,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAClD;AAsCD,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAE5F;AAED,8FAA8F;AAC9F,wBAAgB,uBAAuB,CACtC,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,qBAAqB,EAAE,MAAM,GAAG,SAAS,EACzC,mBAAmB,EAAE,MAAM,GAAG,SAAS,GACrC,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,4BAA4B,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,GAAE,wBAA6B,GAAG,IAAI,CAkDxG"}
@@ -1,3 +1,5 @@
1
+ import { accountLabel } from "@earendil-works/pi-ai/auth/pool/slots";
2
+ import { accountDisplayNameCommand, promptAccountDisplayName } from "../account-display-name.js";
1
3
  import { createExtensionLoginInteraction, LOGIN_CANCELLED_MESSAGE } from "../oauth-login-interaction.js";
2
4
  import { emitProviderAccountsChanged } from "./account-events.js";
3
5
  import { CLAUDE_SDK_OAUTH_PROVIDER_ID, pinProviderAccount, removeProviderAccount } from "./account-management.js";
@@ -57,8 +59,10 @@ export function registerClaudeAccountCommand(pi, deps = {}) {
57
59
  });
58
60
  pi.registerCommand("claude-account", {
59
61
  description: "List and manage Claude SDK OAuth accounts.",
60
- argumentHint: "[add | remove <name> | pin <name> | unpin]",
62
+ argumentHint: "[add | remove <id> | pin <id> | unpin | rename <id> <display name...> | clear-name <id>]",
61
63
  handler: async (rawArgs, ctx) => {
64
+ if (await accountDisplayNameCommand(ctx, CLAUDE_SDK_OAUTH_PROVIDER_ID, rawArgs))
65
+ return;
62
66
  const args = parseArgs(rawArgs);
63
67
  const action = args[0] ?? "list";
64
68
  if (action === "list") {
@@ -81,7 +85,7 @@ export function registerClaudeAccountCommand(pi, deps = {}) {
81
85
  await unpinAccount(ctx);
82
86
  return;
83
87
  }
84
- ctx.ui.notify("Usage: /claude-account [add | remove <name> | pin <name> | unpin]", "error");
88
+ ctx.ui.notify("Usage: /claude-account [add | remove <id> | pin <id> | unpin | rename <id> <display name...> | clear-name <id>]", "error");
85
89
  },
86
90
  });
87
91
  }
@@ -107,15 +111,16 @@ function showAccounts(ctx, settings, environment) {
107
111
  if (accounts.length === 0)
108
112
  lines.push(" (none)");
109
113
  for (const account of accounts) {
110
- const states = [account.name, account.source, slotStatus(account)];
114
+ const states = [accountLabel(account), account.source, slotStatus(account)];
111
115
  if (account.name === pinned)
112
116
  states.push("pinned");
113
117
  if (account.name === affinityPick)
114
118
  states.push("affinity pick");
115
119
  lines.push(` ${states.join(" | ")}`);
116
120
  }
117
- lines.push(`Pinned account: ${pinned === undefined ? "none" : `${pinned} (${pinSource.toLowerCase()})`}`);
118
- lines.push(`Affinity pick: ${affinityPick ?? (affinityError ? `unavailable - ${affinityError}` : "none")}`);
121
+ const labelFor = (name) => accountLabel(accounts.find((account) => account.name === name) ?? { name });
122
+ lines.push(`Pinned account: ${pinned === undefined ? "none" : `${labelFor(pinned)} (${pinSource.toLowerCase()})`}`);
123
+ lines.push(`Affinity pick: ${affinityPick === undefined ? (affinityError ? `unavailable - ${affinityError}` : "none") : labelFor(affinityPick)}`);
119
124
  ctx.ui.notify(lines.join("\n"), "info");
120
125
  }
121
126
  async function addAccount(ctx, deps) {
@@ -124,12 +129,19 @@ async function addAccount(ctx, deps) {
124
129
  return;
125
130
  }
126
131
  try {
127
- await ctx.modelRegistry.modelRuntime.login(CLAUDE_SDK_OAUTH_PROVIDER_ID, "oauth", createExtensionLoginInteraction(ctx, {
128
- providerLabel: CLAUDE_SDK_OAUTH_PROVIDER_LABEL,
129
- openBrowser: deps.openBrowser,
130
- }));
132
+ let receipt;
133
+ await ctx.modelRegistry.modelRuntime.login(CLAUDE_SDK_OAUTH_PROVIDER_ID, "oauth", {
134
+ ...createExtensionLoginInteraction(ctx, {
135
+ providerLabel: CLAUDE_SDK_OAUTH_PROVIDER_LABEL,
136
+ openBrowser: deps.openBrowser,
137
+ }),
138
+ onAccountCommitted: (committed) => {
139
+ receipt = committed;
140
+ },
141
+ });
131
142
  emitProviderAccountsChanged(CLAUDE_SDK_OAUTH_PROVIDER_ID);
132
143
  ctx.ui.notify("Claude SDK OAuth account added.", "info");
144
+ await promptAccountDisplayName(ctx, receipt);
133
145
  }
134
146
  catch (error) {
135
147
  const message = error instanceof Error ? error.message : String(error);