@deepseek-harness-tui/dsh-tui 0.9.0 → 0.9.2

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 (307) hide show
  1. package/README.md +69 -256
  2. package/bin/dsh-tui.js +172 -5
  3. package/cordis.patch.yml +16 -4
  4. package/dsh-ecosystem-spec/protocols/profile-definitions.d.ts +13 -13
  5. package/dsh-ecosystem-spec/protocols/profile-definitions.js +59 -59
  6. package/dsh-ecosystem-spec/protocols/tui-channel-http.d.ts +15 -15
  7. package/dsh-ecosystem-spec/protocols/tui-channel-http.js +32 -32
  8. package/dsh-ecosystem-spec/protocols/tui-channel.d.ts +59 -59
  9. package/dsh-ecosystem-spec/protocols/tui-channel.js +166 -166
  10. package/dsh-ecosystem-spec/protocols/tui-contributions.d.ts +42 -42
  11. package/dsh-ecosystem-spec/protocols/tui-contributions.js +143 -143
  12. package/dsh-ecosystem-spec/registry/README.md +14 -14
  13. package/dsh-ecosystem-spec/registry/host-descriptor.tui.example.json +56 -56
  14. package/dsh-ecosystem-spec/registry/permissions-0.1.json +13 -13
  15. package/dsh-ecosystem-spec/registry/registry-0.15.json +149 -149
  16. package/lib/types/cc/hyperlink.d.ts +7 -1
  17. package/lib/types/cc/hyperlink.d.ts.map +1 -1
  18. package/lib/types/cc/hyperlink.js +3 -2
  19. package/lib/types/cc/markdown.d.ts.map +1 -1
  20. package/lib/types/cc/markdown.js +33 -3
  21. package/lib/types/cc/sessionColors.d.ts +27 -0
  22. package/lib/types/cc/sessionColors.d.ts.map +1 -0
  23. package/lib/types/cc/sessionColors.js +39 -0
  24. package/lib/types/commands.d.ts.map +1 -1
  25. package/lib/types/commands.js +6 -0
  26. package/lib/types/components/AutoRecapRow.d.ts +23 -0
  27. package/lib/types/components/AutoRecapRow.d.ts.map +1 -0
  28. package/lib/types/components/AutoRecapRow.js +23 -0
  29. package/lib/types/components/ColorPicker.d.ts +17 -0
  30. package/lib/types/components/ColorPicker.d.ts.map +1 -0
  31. package/lib/types/components/ColorPicker.js +20 -0
  32. package/lib/types/components/CommandSuggestions.d.ts +3 -1
  33. package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
  34. package/lib/types/components/ContextBarView.d.ts +33 -0
  35. package/lib/types/components/ContextBarView.d.ts.map +1 -0
  36. package/lib/types/components/ContextBarView.js +46 -0
  37. package/lib/types/components/EffortInputBorder.d.ts +12 -1
  38. package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
  39. package/lib/types/components/EffortInputBorder.js +22 -5
  40. package/lib/types/components/FileActionsPanel.d.ts +22 -0
  41. package/lib/types/components/FileActionsPanel.d.ts.map +1 -0
  42. package/lib/types/components/FileActionsPanel.js +28 -0
  43. package/lib/types/components/FileSuggestions.d.ts +3 -1
  44. package/lib/types/components/FileSuggestions.d.ts.map +1 -1
  45. package/lib/types/components/MessageList.d.ts +3 -1
  46. package/lib/types/components/MessageList.d.ts.map +1 -1
  47. package/lib/types/components/MessageList.js +13 -6
  48. package/lib/types/components/ModelPicker.d.ts +26 -4
  49. package/lib/types/components/ModelPicker.d.ts.map +1 -1
  50. package/lib/types/components/ModelPicker.js +26 -6
  51. package/lib/types/components/PromptInput.d.ts.map +1 -1
  52. package/lib/types/components/PromptInput.js +365 -57
  53. package/lib/types/components/RecapPanel.d.ts +25 -0
  54. package/lib/types/components/RecapPanel.d.ts.map +1 -0
  55. package/lib/types/components/RecapPanel.js +55 -0
  56. package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
  57. package/lib/types/components/ScrollbarGutter.js +55 -4
  58. package/lib/types/components/SubagentCard.d.ts.map +1 -1
  59. package/lib/types/components/SubagentCard.js +6 -4
  60. package/lib/types/components/SuggestionCard.d.ts +4 -2
  61. package/lib/types/components/SuggestionCard.d.ts.map +1 -1
  62. package/lib/types/components/TimelineRail.d.ts.map +1 -1
  63. package/lib/types/components/TimelineRail.js +9 -2
  64. package/lib/types/components/design-system/ThemeProvider.d.ts +7 -0
  65. package/lib/types/components/design-system/ThemeProvider.d.ts.map +1 -1
  66. package/lib/types/components/design-system/ThemeProvider.js +2 -1
  67. package/lib/types/components/messages/AssistantToolUseMessage.d.ts +8 -1
  68. package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
  69. package/lib/types/components/messages/AssistantToolUseMessage.js +36 -8
  70. package/lib/types/components/questions/AskUserQuestionPanel.d.ts +7 -3
  71. package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
  72. package/lib/types/components/questions/AskUserQuestionPanel.js +41 -9
  73. package/lib/types/dsh-adapter/channel.d.ts +101 -2
  74. package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
  75. package/lib/types/dsh-adapter/channel.js +969 -93
  76. package/lib/types/dsh-adapter/compat/index.d.ts +8 -6
  77. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  78. package/lib/types/dsh-adapter/compat/index.js +8 -6
  79. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +150 -0
  80. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  81. package/lib/types/dsh-adapter/compat/sessionLog.js +518 -41
  82. package/lib/types/dsh-adapter/contract.d.ts +1 -1
  83. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  84. package/lib/types/dsh-adapter/contract.js +1 -0
  85. package/lib/types/dsh-adapter/extension-events.d.ts +1 -1
  86. package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
  87. package/lib/types/dsh-adapter/index.d.ts +10 -0
  88. package/lib/types/dsh-adapter/index.d.ts.map +1 -1
  89. package/lib/types/dsh-adapter/index.js +5 -0
  90. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/plugin.js +317 -8
  92. package/lib/types/dsh-adapter/presets.d.ts +18 -0
  93. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  94. package/lib/types/dsh-adapter/presets.js +31 -0
  95. package/lib/types/dsh-adapter/providerWizard.d.ts +29 -1
  96. package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
  97. package/lib/types/dsh-adapter/providerWizard.js +89 -5
  98. package/lib/types/dsh-adapter/questions.d.ts +19 -2
  99. package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
  100. package/lib/types/dsh-adapter/questions.js +53 -10
  101. package/lib/types/dsh-adapter/recap.d.ts +49 -0
  102. package/lib/types/dsh-adapter/recap.d.ts.map +1 -0
  103. package/lib/types/dsh-adapter/recap.js +121 -0
  104. package/lib/types/dsh-adapter/sessionTree.d.ts +314 -0
  105. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -0
  106. package/lib/types/dsh-adapter/sessionTree.js +954 -0
  107. package/lib/types/dsh-adapter/shortcuts.d.ts +15 -44
  108. package/lib/types/dsh-adapter/shortcuts.d.ts.map +1 -1
  109. package/lib/types/dsh-adapter/shortcuts.js +28 -165
  110. package/lib/types/dsh-adapter/types.d.ts +1 -1
  111. package/lib/types/dsh-adapter/types.d.ts.map +1 -1
  112. package/lib/types/herdr.js +1 -1
  113. package/lib/types/i18n.d.ts +604 -176
  114. package/lib/types/i18n.d.ts.map +1 -1
  115. package/lib/types/i18n.js +206 -72
  116. package/lib/types/ink/log-update.d.ts.map +1 -1
  117. package/lib/types/ink/log-update.js +21 -0
  118. package/lib/types/migrationPrefs.d.ts +60 -0
  119. package/lib/types/migrationPrefs.d.ts.map +1 -0
  120. package/lib/types/migrationPrefs.js +97 -0
  121. package/lib/types/modelGroups.d.ts +72 -0
  122. package/lib/types/modelGroups.d.ts.map +1 -0
  123. package/lib/types/modelGroups.js +97 -0
  124. package/lib/types/modelRecents.d.ts +39 -0
  125. package/lib/types/modelRecents.d.ts.map +1 -0
  126. package/lib/types/modelRecents.js +97 -0
  127. package/lib/types/native-ts/yoga-layout/index.d.ts +11 -0
  128. package/lib/types/native-ts/yoga-layout/index.d.ts.map +1 -1
  129. package/lib/types/native-ts/yoga-layout/index.js +31 -1
  130. package/lib/types/oauth.d.ts +15 -0
  131. package/lib/types/oauth.d.ts.map +1 -0
  132. package/lib/types/oauth.js +14 -0
  133. package/lib/types/plugin-spec/registry.d.ts +1 -1
  134. package/lib/types/plugin-spec/registry.js +1 -1
  135. package/lib/types/reload.d.ts +109 -0
  136. package/lib/types/reload.d.ts.map +1 -0
  137. package/lib/types/reload.js +118 -0
  138. package/lib/types/screens/Chat.d.ts +3 -1
  139. package/lib/types/screens/Chat.d.ts.map +1 -1
  140. package/lib/types/screens/Chat.js +588 -64
  141. package/lib/types/screens/SessionTree.d.ts +27 -0
  142. package/lib/types/screens/SessionTree.d.ts.map +1 -0
  143. package/lib/types/screens/SessionTree.js +555 -0
  144. package/lib/types/screens/StatusLine.d.ts +0 -9
  145. package/lib/types/screens/StatusLine.d.ts.map +1 -1
  146. package/lib/types/screens/StatusLine.js +215 -52
  147. package/lib/types/screens/StatusMetrics.d.ts +35 -3
  148. package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
  149. package/lib/types/screens/StatusMetrics.js +63 -8
  150. package/lib/types/screens/chatOverlay.d.ts +17 -1
  151. package/lib/types/screens/chatOverlay.d.ts.map +1 -1
  152. package/lib/types/screens/chatOverlay.js +3 -1
  153. package/lib/types/tips.d.ts.map +1 -1
  154. package/lib/types/tips.js +22 -4
  155. package/lib/types/update.d.ts +159 -0
  156. package/lib/types/update.d.ts.map +1 -1
  157. package/lib/types/update.js +496 -30
  158. package/lib/types/utils/debug.d.ts +1 -1
  159. package/lib/types/utils/debug.js +3 -3
  160. package/lib/types/utils/fileTarget.d.ts +46 -0
  161. package/lib/types/utils/fileTarget.d.ts.map +1 -0
  162. package/lib/types/utils/fileTarget.js +178 -0
  163. package/lib/types/utils/keymap.d.ts +134 -0
  164. package/lib/types/utils/keymap.d.ts.map +1 -0
  165. package/lib/types/utils/keymap.js +311 -0
  166. package/lib/types/utils/mentions.d.ts +25 -2
  167. package/lib/types/utils/mentions.d.ts.map +1 -1
  168. package/lib/types/utils/mentions.js +69 -10
  169. package/lib/types/utils/openExternal.d.ts +50 -0
  170. package/lib/types/utils/openExternal.d.ts.map +1 -0
  171. package/lib/types/utils/openExternal.js +170 -0
  172. package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +21 -0
  173. package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +140 -0
  174. package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +11 -0
  175. package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +44 -0
  176. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.d.ts +14 -0
  177. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/command.js +67 -0
  178. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.d.ts +64 -0
  179. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/credentials.js +170 -0
  180. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.d.ts +79 -0
  181. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/index.js +196 -0
  182. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.d.ts +68 -0
  183. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +193 -0
  184. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.d.ts +32 -0
  185. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/opener.js +101 -0
  186. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.d.ts +31 -0
  187. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/profiles.js +68 -0
  188. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.d.ts +69 -0
  189. package/node_modules/@deepseek-harness-tui/dsh-auth/lib/service.js +129 -0
  190. package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +70 -0
  191. package/node_modules/@dsh-std/command/CHANGELOG.md +8 -8
  192. package/node_modules/@dsh-std/command/LICENSE +21 -21
  193. package/node_modules/@dsh-std/command/README.md +26 -26
  194. package/node_modules/@dsh-std/command/README.zh.md +28 -28
  195. package/node_modules/@dsh-std/command/lib/index.js.map +1 -1
  196. package/node_modules/@dsh-std/command/package.json +22 -22
  197. package/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  198. package/node_modules/@dsh-std/connection/LICENSE +21 -21
  199. package/node_modules/@dsh-std/connection/README.md +42 -42
  200. package/node_modules/@dsh-std/connection/README.zh.md +42 -42
  201. package/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  202. package/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  203. package/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  204. package/node_modules/@dsh-std/connection/package.json +20 -20
  205. package/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  206. package/node_modules/@dsh-std/core/LICENSE +21 -21
  207. package/node_modules/@dsh-std/core/README.md +13 -13
  208. package/node_modules/@dsh-std/core/README.zh.md +13 -13
  209. package/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  210. package/node_modules/@dsh-std/core/package.json +21 -21
  211. package/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  212. package/node_modules/@dsh-std/manifest/LICENSE +21 -21
  213. package/node_modules/@dsh-std/manifest/README.md +5 -5
  214. package/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  215. package/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  216. package/node_modules/@dsh-std/manifest/package.json +20 -20
  217. package/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  218. package/node_modules/@dsh-std/messages/CHANGELOG.md +8 -8
  219. package/node_modules/@dsh-std/messages/LICENSE +21 -21
  220. package/node_modules/@dsh-std/messages/README.md +5 -5
  221. package/node_modules/@dsh-std/messages/README.zh.md +7 -7
  222. package/node_modules/@dsh-std/messages/lib/index.js.map +1 -1
  223. package/node_modules/@dsh-std/messages/package.json +20 -20
  224. package/node_modules/@dsh-std/messages/schema/message-observer-envelope-0.15.schema.json +54 -54
  225. package/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  226. package/node_modules/@dsh-std/presentation/LICENSE +21 -21
  227. package/node_modules/@dsh-std/presentation/README.md +27 -27
  228. package/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  229. package/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  230. package/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  231. package/node_modules/@dsh-std/presentation/package.json +25 -25
  232. package/node_modules/@dsh-std/storage/CHANGELOG.md +8 -8
  233. package/node_modules/@dsh-std/storage/LICENSE +21 -21
  234. package/node_modules/@dsh-std/storage/README.md +5 -5
  235. package/node_modules/@dsh-std/storage/README.zh.md +7 -7
  236. package/node_modules/@dsh-std/storage/lib/index.js.map +1 -1
  237. package/node_modules/@dsh-std/storage/package.json +20 -20
  238. package/node_modules/@dsh-std/storage/schema/local-storage-0.15.schema.json +56 -56
  239. package/package.json +17 -5
  240. package/presets/liangshen/.dsh-tui-managed.json +1 -1
  241. package/presets/liangshen/instruction-hint.mjs +8 -0
  242. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  243. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/LICENSE +21 -21
  244. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.md +42 -42
  245. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/README.zh.md +42 -42
  246. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  247. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  248. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  249. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/connection/package.json +20 -20
  250. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  251. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/LICENSE +21 -21
  252. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.md +13 -13
  253. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/README.zh.md +13 -13
  254. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  255. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/core/package.json +21 -21
  256. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/CHANGELOG.md +9 -9
  257. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/LICENSE +21 -21
  258. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.md +5 -5
  259. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/README.zh.md +5 -5
  260. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/lib/index.js.map +1 -1
  261. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/package.json +20 -20
  262. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/manifest/schema/dsh-plugin-0.15.schema.json +144 -144
  263. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/CHANGELOG.md +9 -9
  264. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/LICENSE +21 -21
  265. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.md +27 -27
  266. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/README.zh.md +29 -29
  267. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/callback.js.map +1 -1
  268. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/lib/index.js.map +1 -1
  269. package/vendor/dsh-std/packages/command/node_modules/@dsh-std/presentation/package.json +25 -25
  270. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  271. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/LICENSE +21 -21
  272. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.md +13 -13
  273. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/README.zh.md +13 -13
  274. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  275. package/vendor/dsh-std/packages/connection/node_modules/@dsh-std/core/package.json +21 -21
  276. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  277. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/LICENSE +21 -21
  278. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.md +13 -13
  279. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/README.zh.md +13 -13
  280. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  281. package/vendor/dsh-std/packages/manifest/node_modules/@dsh-std/core/package.json +21 -21
  282. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  283. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/LICENSE +21 -21
  284. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.md +13 -13
  285. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/README.zh.md +13 -13
  286. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  287. package/vendor/dsh-std/packages/messages/node_modules/@dsh-std/core/package.json +21 -21
  288. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/CHANGELOG.md +8 -8
  289. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/LICENSE +21 -21
  290. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.md +42 -42
  291. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/README.zh.md +42 -42
  292. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/index.js.map +1 -1
  293. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/memory.js.map +1 -1
  294. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/lib/resolve-3X6ausgz.js.map +1 -1
  295. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/connection/package.json +20 -20
  296. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  297. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/LICENSE +21 -21
  298. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.md +13 -13
  299. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/README.zh.md +13 -13
  300. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  301. package/vendor/dsh-std/packages/presentation/node_modules/@dsh-std/core/package.json +21 -21
  302. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/CHANGELOG.md +8 -8
  303. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/LICENSE +21 -21
  304. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.md +13 -13
  305. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/README.zh.md +13 -13
  306. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/lib/index.js.map +1 -1
  307. package/vendor/dsh-std/packages/storage/node_modules/@dsh-std/core/package.json +21 -21
@@ -0,0 +1,193 @@
1
+ /**
2
+ * The `AuthInteraction` bridge: pi-ai OAuth flows speak prompts and events;
3
+ * every interactive surface in this ecosystem speaks `ctx.userQuestions`.
4
+ *
5
+ * `prompt()` maps one pi-ai prompt onto one question — `select` prompts carry
6
+ * their options, text/secret/manual-code prompts expect the custom-answer
7
+ * input row.
8
+ *
9
+ * `notify()` restores the host contract pi-ai's browser flows assume: the
10
+ * `auth_url` / `device_code` events expect the *host* to open the browser
11
+ * (their authorize URLs run hundreds of characters — wrapped across panel
12
+ * lines they are unclickable, and hand-copying picks up wrap artifacts that
13
+ * corrupt the encoded `redirect_uri`, which the provider then rejects). So
14
+ * the bridge opens the URL itself, then shows one waiting panel carrying
15
+ * copy / reopen / cancel actions until the flow settles. The device-code
16
+ * path gets the same treatment: its short code is the thing to copy, and
17
+ * the verification page is auto-opened too.
18
+ *
19
+ * One `AbortController` owns the whole run: pi-ai reads `interaction.signal`
20
+ * to abort the flow, every ask request carries it so surfaces close their
21
+ * panels, and the waiting panel's cancel action fires it.
22
+ *
23
+ * Nothing here assumes a browser or GUI *exists* (TUI-RUN-001): when no
24
+ * opener or clipboard helper is available the panel degrades to showing the
25
+ * URL / code verbatim with a clear note, and where no question provider is
26
+ * registered at all, `ask` rejects and the login command turns that into a
27
+ * clear refusal.
28
+ *
29
+ * @module dsh-auth/interaction
30
+ */
31
+ import { copyToClipboard, openInBrowser } from './opener.js';
32
+ /** Human-readable copy for one notify event. */
33
+ export function describeEvent(event) {
34
+ switch (event.type) {
35
+ case 'auth_url':
36
+ return `Open this URL to authorize (a local callback completes sign-in):\n${event.url}`;
37
+ case 'device_code':
38
+ return `Visit ${event.verificationUri} and enter this code:\n ${event.userCode}`;
39
+ case 'info':
40
+ case 'progress':
41
+ return event.message;
42
+ }
43
+ }
44
+ const CANCEL = 'Cancel sign-in';
45
+ const OPEN_AGAIN = 'Open browser again';
46
+ const COPY_LINK = 'Copy authorization link';
47
+ const COPY_CODE = 'Copy code';
48
+ /** One answer row, or a thrown error when the surface returned nothing usable. */
49
+ function singleAnswer(answer) {
50
+ const row = answer.answers[0];
51
+ if (row === undefined)
52
+ throw new Error('dsh-auth: the question surface returned no answer');
53
+ return { selected: row.selected[0], custom: row.custom };
54
+ }
55
+ function authUrlView(url, instructions, opened) {
56
+ const lead = opened
57
+ ? 'Authorization page opened in your browser — complete the sign-in there.\n'
58
+ + 'If it did not open, copy the link below and open it by hand.'
59
+ : `Open this URL to authorize${instructions === undefined ? '' : ` — ${instructions}`}\n`
60
+ + 'Copy the link below (it is too long to select reliably once wrapped):';
61
+ return { body: `${lead}\n${url}`, copyLabel: COPY_LINK, copyText: url, reopenUrl: url };
62
+ }
63
+ function deviceCodeView(userCode, verificationUri, opened) {
64
+ const lead = opened
65
+ ? `Enter this code on the page opened in your browser (${verificationUri}):`
66
+ : `Visit ${verificationUri} and enter this code:`;
67
+ return { body: `${lead}\n ${userCode}`, copyLabel: COPY_CODE, copyText: userCode, reopenUrl: verificationUri };
68
+ }
69
+ /**
70
+ * The bridge for one login run. At most one waiting panel exists at a time;
71
+ * `settle()` retires it when the flow ends (any outcome), so a completed or
72
+ * failed login never leaves an interactive dead end on screen.
73
+ */
74
+ export class QuestionBridge {
75
+ ask;
76
+ runAbort;
77
+ signal;
78
+ openUrl;
79
+ copy;
80
+ waiting;
81
+ waitingClosed = false;
82
+ constructor(ask, runAbort, helpers = {}) {
83
+ this.ask = ask;
84
+ this.runAbort = runAbort;
85
+ this.signal = runAbort.signal;
86
+ this.openUrl = helpers.openUrl ?? openInBrowser;
87
+ this.copy = helpers.copyText ?? copyToClipboard;
88
+ }
89
+ async prompt(prompt) {
90
+ const secretNote = prompt.type === 'secret' ? ' (input is not masked on this surface — mind your screen)' : '';
91
+ const question = prompt.type === 'select'
92
+ ? {
93
+ id: 'dsh-auth-prompt',
94
+ header: 'dsh-auth',
95
+ question: prompt.message,
96
+ options: prompt.options.map(option => ({
97
+ label: option.label,
98
+ ...(option.description === undefined ? {} : { description: option.description }),
99
+ })),
100
+ }
101
+ : {
102
+ id: 'dsh-auth-prompt',
103
+ header: 'dsh-auth',
104
+ question: prompt.message,
105
+ ...(prompt.placeholder === undefined
106
+ ? (secretNote === '' ? {} : { detail: secretNote.slice(1) })
107
+ : { detail: `${prompt.placeholder}${secretNote}` }),
108
+ };
109
+ const answer = singleAnswer(await this.ask({ questions: [question], signal: prompt.signal ?? this.signal }));
110
+ if (prompt.type === 'select') {
111
+ const label = answer.selected;
112
+ const option = label === undefined ? undefined : prompt.options.find(candidate => candidate.label === label);
113
+ if (option === undefined) {
114
+ if (answer.custom !== undefined && answer.custom !== '')
115
+ return answer.custom;
116
+ throw new Error('dsh-auth: the selection answer did not match an offered option');
117
+ }
118
+ return option.id;
119
+ }
120
+ const custom = answer.custom?.trim();
121
+ if (custom === undefined || custom === '')
122
+ throw new Error('dsh-auth: the text answer was empty');
123
+ return custom;
124
+ }
125
+ notify(event) {
126
+ if (event.type === 'auth_url') {
127
+ if (this.waiting !== undefined)
128
+ return;
129
+ const opened = this.openUrl(event.url);
130
+ void this.runWaitingPanel(authUrlView(event.url, event.instructions, opened));
131
+ return;
132
+ }
133
+ if (event.type === 'device_code') {
134
+ if (this.waiting !== undefined)
135
+ return;
136
+ const opened = this.openUrl(event.verificationUri);
137
+ void this.runWaitingPanel(deviceCodeView(event.userCode, event.verificationUri, opened));
138
+ }
139
+ // info / progress lines are transient; the waiting panel already tells
140
+ // the user what to do, and the flow's next prompt carries its own copy.
141
+ }
142
+ /** Close the waiting panel (if any) and stop answering for this run. */
143
+ async settle() {
144
+ this.waitingClosed = true;
145
+ this.waiting?.controller.abort();
146
+ await this.waiting?.answer;
147
+ this.waiting = undefined;
148
+ }
149
+ /**
150
+ * Show the waiting panel until the flow settles or the user cancels,
151
+ * re-asking after a copy/reopen action with a one-line status prefix.
152
+ */
153
+ async runWaitingPanel(view) {
154
+ let body = view.body;
155
+ while (!this.waitingClosed) {
156
+ const controller = new AbortController();
157
+ const answer = this.ask({
158
+ questions: [{
159
+ id: 'dsh-auth-waiting',
160
+ header: 'dsh-auth',
161
+ question: 'Waiting for authorization…',
162
+ detail: body,
163
+ options: [
164
+ { label: view.copyLabel },
165
+ ...(view.reopenUrl === undefined ? [] : [{ label: OPEN_AGAIN }]),
166
+ { label: CANCEL },
167
+ ],
168
+ }],
169
+ signal: controller.signal,
170
+ })
171
+ .then(response => singleAnswer(response).selected)
172
+ .catch(() => undefined);
173
+ this.waiting = { controller, answer };
174
+ const picked = await answer;
175
+ this.waiting = undefined;
176
+ if (picked === undefined || this.waitingClosed)
177
+ return;
178
+ if (picked === CANCEL) {
179
+ this.runAbort.abort('user cancelled sign-in');
180
+ return;
181
+ }
182
+ if (picked === view.copyLabel) {
183
+ const copied = await this.copy(view.copyText);
184
+ body = `${copied ? 'Copied — paste it where you need it.' : 'Copy failed — no clipboard helper answered; select the text manually.'}\n${view.body}`;
185
+ continue;
186
+ }
187
+ if (picked === OPEN_AGAIN && view.reopenUrl !== undefined) {
188
+ this.openUrl(view.reopenUrl);
189
+ body = `Reopened in your browser.\n${view.body}`;
190
+ }
191
+ }
192
+ }
193
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Best-effort host-side conveniences for OAuth flows: opening the default
3
+ * browser and copying short text to the clipboard.
4
+ *
5
+ * pi-ai's flows emit an `auth_url` event whose instructions assume the host
6
+ * opens the browser itself ("A browser window should open…"), because the
7
+ * authorize URL is hundreds of characters — unclickable and practically
8
+ * uncopyable once a terminal panel wraps it (wrap artifacts inside the
9
+ * encoded `redirect_uri` are exactly how hand-copied URLs die with
10
+ * `invalid_authorize_request`). These helpers restore that host contract.
11
+ * Every path is best-effort and never throws: a missing opener or clipboard
12
+ * degrades to the URL staying on screen with a copy action.
13
+ *
14
+ * @module dsh-auth/opener
15
+ */
16
+ /** The browser-opening command for this platform, or undefined when unknown. */
17
+ export declare function openerFor(url: string): {
18
+ command: string;
19
+ args: readonly string[];
20
+ verbatim: boolean;
21
+ } | undefined;
22
+ /**
23
+ * Open `url` in the default browser, detached; the TUI keeps running.
24
+ * @returns whether the opener process could be spawned at all (not whether
25
+ * a browser eventually appeared — that is not observable here).
26
+ */
27
+ export declare function openInBrowser(url: string): boolean;
28
+ /**
29
+ * Copy `text` to the system clipboard, trying this platform's helpers in
30
+ * order. Resolves whether one succeeded; never rejects.
31
+ */
32
+ export declare function copyToClipboard(text: string): Promise<boolean>;
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Best-effort host-side conveniences for OAuth flows: opening the default
3
+ * browser and copying short text to the clipboard.
4
+ *
5
+ * pi-ai's flows emit an `auth_url` event whose instructions assume the host
6
+ * opens the browser itself ("A browser window should open…"), because the
7
+ * authorize URL is hundreds of characters — unclickable and practically
8
+ * uncopyable once a terminal panel wraps it (wrap artifacts inside the
9
+ * encoded `redirect_uri` are exactly how hand-copied URLs die with
10
+ * `invalid_authorize_request`). These helpers restore that host contract.
11
+ * Every path is best-effort and never throws: a missing opener or clipboard
12
+ * degrades to the URL staying on screen with a copy action.
13
+ *
14
+ * @module dsh-auth/opener
15
+ */
16
+ import { spawn } from 'node:child_process';
17
+ /** The browser-opening command for this platform, or undefined when unknown. */
18
+ export function openerFor(url) {
19
+ if (process.platform === 'win32') {
20
+ // cmd.exe parses `&` as a command separator, so an unquoted authorize
21
+ // URL (hundreds of chars of `?a=1&b=2…`) is truncated at the first `&`
22
+ // and the browser opens a param-less page — OpenAI answers "missing
23
+ // required parameter". Node only quotes argv containing spaces/quotes,
24
+ // which a URL has neither of, so the protection must be explicit: the
25
+ // whole `start` command rides as ONE verbatim argv token, with the URL
26
+ // double-quoted inside it (`start` treats a leading quoted arg as the
27
+ // window title, hence the empty "" first).
28
+ return {
29
+ command: 'cmd.exe',
30
+ args: ['/d', '/s', '/c', `start "" "${url}"`],
31
+ verbatim: true,
32
+ };
33
+ }
34
+ if (process.platform === 'darwin')
35
+ return { command: 'open', args: [url], verbatim: false };
36
+ return { command: 'xdg-open', args: [url], verbatim: false };
37
+ }
38
+ /**
39
+ * Open `url` in the default browser, detached; the TUI keeps running.
40
+ * @returns whether the opener process could be spawned at all (not whether
41
+ * a browser eventually appeared — that is not observable here).
42
+ */
43
+ export function openInBrowser(url) {
44
+ const opener = openerFor(url);
45
+ if (opener === undefined)
46
+ return false;
47
+ try {
48
+ const child = spawn(opener.command, [...opener.args], {
49
+ detached: true,
50
+ stdio: 'ignore',
51
+ windowsHide: true,
52
+ ...(opener.verbatim ? { windowsVerbatimArguments: true } : {}),
53
+ });
54
+ child.on('error', () => undefined);
55
+ child.unref();
56
+ return true;
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
62
+ /** Feed `text` to one clipboard helper's stdin; resolves whether it exited 0. */
63
+ function pipeTo(command, args, text) {
64
+ return new Promise(resolve => {
65
+ let child;
66
+ try {
67
+ child = spawn(command, [...args], { stdio: ['pipe', 'ignore', 'ignore'], windowsHide: true });
68
+ }
69
+ catch {
70
+ resolve(false);
71
+ return;
72
+ }
73
+ child.on('error', () => resolve(false));
74
+ child.on('close', code => resolve(code === 0));
75
+ child.stdin.on('error', () => resolve(false));
76
+ child.stdin.end(text);
77
+ });
78
+ }
79
+ /** Clipboard helper candidates per platform, in try order. */
80
+ function clipboardCandidates() {
81
+ if (process.platform === 'win32')
82
+ return [{ command: 'clip.exe', args: [] }];
83
+ if (process.platform === 'darwin')
84
+ return [{ command: 'pbcopy', args: [] }];
85
+ return [
86
+ { command: 'wl-copy', args: [] },
87
+ { command: 'xclip', args: ['-selection', 'clipboard'] },
88
+ { command: 'xsel', args: ['--clipboard', '--input'] },
89
+ ];
90
+ }
91
+ /**
92
+ * Copy `text` to the system clipboard, trying this platform's helpers in
93
+ * order. Resolves whether one succeeded; never rejects.
94
+ */
95
+ export async function copyToClipboard(text) {
96
+ for (const candidate of clipboardCandidates()) {
97
+ if (await pipeTo(candidate.command, candidate.args, text))
98
+ return true;
99
+ }
100
+ return false;
101
+ }
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Provider routes this plugin owns: the pi-ai catalog providers that ship an
3
+ * OAuth flow, mounted with their catalog models, wire implementations, and
4
+ * OAuth flow objects untouched. Credential resolution is not wrapped at all —
5
+ * the adapter's collection carries this plugin's `CredentialStore`
6
+ * (`PiAiAuthInjection`), so requests resolve the stored OAuth credential
7
+ * through the provider's own auth and refresh tokens under the store's lock.
8
+ *
9
+ * The hand-built profile mirrors what an empty llm-pi-ai settings profile
10
+ * resolves to for a catalog route, including the image-request defaults
11
+ * (llm-pi-ai's own `DEFAULT_*` constants are not exported; the values below
12
+ * are those constants, and the comment on each says so).
13
+ *
14
+ * @module dsh-auth/profiles
15
+ */
16
+ import type { Provider } from '@earendil-works/pi-ai';
17
+ import type { ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
18
+ /** Provider routes this build mounts, in picker order. */
19
+ export declare const OAUTH_PROVIDER_IDS: readonly ["openai-codex", "anthropic", "xai"];
20
+ /** One routable provider id. */
21
+ export type OAuthProviderId = (typeof OAUTH_PROVIDER_IDS)[number];
22
+ /** The OAuth flow object for one mounted route (login/refresh/toAuth live here). */
23
+ export declare function oauthOf(route: Provider): NonNullable<Provider['auth']['oauth']>;
24
+ /**
25
+ * Build the resolved profile one route registers under. Mirrors the fields
26
+ * `PiAiAdapter` reads: identity for selectors, the idle timeout, retry
27
+ * policy, and image budgets it forwards per request, and the catalog provider
28
+ * with its own models. Everything optional stays absent — the adapter treats
29
+ * absence as "provider defaults" exactly as an empty llm-pi-ai profile would.
30
+ */
31
+ export declare function buildOAuthProfile(id: string): ResolvedPiAiProviderProfile;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Provider routes this plugin owns: the pi-ai catalog providers that ship an
3
+ * OAuth flow, mounted with their catalog models, wire implementations, and
4
+ * OAuth flow objects untouched. Credential resolution is not wrapped at all —
5
+ * the adapter's collection carries this plugin's `CredentialStore`
6
+ * (`PiAiAuthInjection`), so requests resolve the stored OAuth credential
7
+ * through the provider's own auth and refresh tokens under the store's lock.
8
+ *
9
+ * The hand-built profile mirrors what an empty llm-pi-ai settings profile
10
+ * resolves to for a catalog route, including the image-request defaults
11
+ * (llm-pi-ai's own `DEFAULT_*` constants are not exported; the values below
12
+ * are those constants, and the comment on each says so).
13
+ *
14
+ * @module dsh-auth/profiles
15
+ */
16
+ import { builtinProviders } from '@earendil-works/pi-ai/providers/all';
17
+ import { resolveRetryPolicy } from '@deepseek-ai/dsh-llm';
18
+ /** Provider routes this build mounts, in picker order. */
19
+ export const OAUTH_PROVIDER_IDS = ['openai-codex', 'anthropic', 'xai'];
20
+ /** llm-pi-ai `DEFAULT_MAX_REQUEST_IMAGE_BYTES` (20 MiB, base64 payload bound). */
21
+ const MAX_REQUEST_IMAGE_BYTES = 20 * 1024 * 1024;
22
+ /** llm-pi-ai `DEFAULT_REQUEST_IMAGE_PIXEL_BUDGET` (2048×2048 pixels). */
23
+ const REQUEST_IMAGE_PIXEL_BUDGET = 2048 * 2048;
24
+ /** llm-pi-ai `DEFAULT_REQUEST_IMAGE_MAX_BYTES` (1 MiB per image). */
25
+ const REQUEST_IMAGE_MAX_BYTES = 1024 * 1024;
26
+ /** llm-pi-ai `DEFAULT_STREAM_IDLE_TIMEOUT_MS` (5 minutes). */
27
+ const STREAM_IDLE_TIMEOUT_MS = 300_000;
28
+ /** The installed pi-ai catalog provider for one route, whose OAuth flow we mount. */
29
+ function catalogProviderOf(id) {
30
+ const found = builtinProviders().find(provider => provider.id === id);
31
+ if (found === undefined) {
32
+ throw new Error(`dsh-auth: the installed pi-ai catalog ships no provider "${id}"; `
33
+ + 'remove it from this plugin\'s providers config or update pi-ai');
34
+ }
35
+ return found;
36
+ }
37
+ /** The OAuth flow object for one mounted route (login/refresh/toAuth live here). */
38
+ export function oauthOf(route) {
39
+ const oauth = route.auth.oauth;
40
+ if (oauth === undefined) {
41
+ throw new Error(`dsh-auth: pi-ai provider "${route.id}" ships no OAuth flow`);
42
+ }
43
+ return oauth;
44
+ }
45
+ /**
46
+ * Build the resolved profile one route registers under. Mirrors the fields
47
+ * `PiAiAdapter` reads: identity for selectors, the idle timeout, retry
48
+ * policy, and image budgets it forwards per request, and the catalog provider
49
+ * with its own models. Everything optional stays absent — the adapter treats
50
+ * absence as "provider defaults" exactly as an empty llm-pi-ai profile would.
51
+ */
52
+ export function buildOAuthProfile(id) {
53
+ if (!OAUTH_PROVIDER_IDS.includes(id)) {
54
+ throw new Error(`dsh-auth: "${id}" is not an OAuth provider this build mounts (${OAUTH_PROVIDER_IDS.join(', ')})`);
55
+ }
56
+ const catalog = catalogProviderOf(id);
57
+ return {
58
+ provider: id,
59
+ displayName: catalog.name,
60
+ streamIdleTimeoutMs: STREAM_IDLE_TIMEOUT_MS,
61
+ retryPolicy: resolveRetryPolicy(undefined, `dsh-auth: provider "${id}" retryPolicy`),
62
+ configuredMaxTokens: new Map(),
63
+ piProvider: catalog,
64
+ maxRequestImageBytes: MAX_REQUEST_IMAGE_BYTES,
65
+ requestImagePixelBudget: REQUEST_IMAGE_PIXEL_BUDGET,
66
+ requestImageMaxBytes: REQUEST_IMAGE_MAX_BYTES,
67
+ };
68
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The `ctx.dshAuth` service: the programmatic surface over this plugin's
3
+ * mounted OAuth routes. UIs (the dsh-tui /provider wizard, a web settings
4
+ * page) enumerate providers with masked sign-in state and drive login/logout
5
+ * without touching the credential file or the pi-ai flow objects; the `/auth`
6
+ * command in `command.ts` is a thin textual veneer over the same api.
7
+ *
8
+ * @module dsh-auth/service
9
+ */
10
+ import { Service } from '@deepseek-ai/cordis';
11
+ import type { Context } from '@deepseek-ai/cordis';
12
+ import type { ResolvedPiAiProviderProfile } from '@deepseek-ai/dsh-llm-pi-ai';
13
+ import { CredentialFile } from './credentials.js';
14
+ import { type AskFn } from './interaction.js';
15
+ /** One provider's sign-in state; never carries token material. */
16
+ export interface DshAuthSignInStatus {
17
+ provider: string;
18
+ /** Route display name (selectors, pickers). */
19
+ label: string;
20
+ /** The OAuth flow's own name, e.g. "OpenAI (ChatGPT Plus/Pro)". */
21
+ oauthLabel: string;
22
+ /** The flow's login-call-to-action label, when it ships one. */
23
+ loginLabel: string | undefined;
24
+ signedIn: boolean;
25
+ expiresAt: number | undefined;
26
+ /** Signed in, but the stored access token has expired (refresh may still work). */
27
+ expired: boolean;
28
+ }
29
+ /** The outcome of a successful login. */
30
+ export interface DshAuthLoginResult {
31
+ provider: string;
32
+ oauthLabel: string;
33
+ expiresAt: number;
34
+ }
35
+ /** The service api consumed by commands and UIs. */
36
+ export interface DshAuthApi {
37
+ /** Every mounted provider with masked sign-in state. */
38
+ providers(): Promise<readonly DshAuthSignInStatus[]>;
39
+ /**
40
+ * Run one provider's OAuth login. `provider` omitted asks the interactive
41
+ * surface to choose among providers not currently signed in.
42
+ * @throws Error when no interactive surface is present, the provider is
43
+ * unknown, a login is already running, or the flow itself fails.
44
+ */
45
+ login(provider?: string, signal?: AbortSignal): Promise<DshAuthLoginResult>;
46
+ /** Remove one provider's stored credential; resolves whether one existed. */
47
+ logout(provider: string): Promise<boolean>;
48
+ }
49
+ /** Cordis service holder; `api` is set by the plugin's apply. */
50
+ export declare class DshAuthService extends Service {
51
+ api: DshAuthApi | undefined;
52
+ constructor(ctx: Context);
53
+ }
54
+ /** Everything the api factory needs; all cordis surface is injected, so tests run without a host. */
55
+ export interface DshAuthApiDeps {
56
+ profiles: ReadonlyMap<string, ResolvedPiAiProviderProfile>;
57
+ store: CredentialFile;
58
+ /** The interactive ask surface, resolved per call so mounting order never matters. */
59
+ resolveAsk: () => AskFn | undefined;
60
+ logger: {
61
+ warn(message: string): void;
62
+ };
63
+ }
64
+ /**
65
+ * The api implementation. One login runs per provider at a time (an in-flight
66
+ * map, not a global lock: providers sign in independently); a second login
67
+ * attempt for the same provider fails fast instead of stacking two flows.
68
+ */
69
+ export declare function createDshAuthApi(deps: DshAuthApiDeps): DshAuthApi;
@@ -0,0 +1,129 @@
1
+ /**
2
+ * The `ctx.dshAuth` service: the programmatic surface over this plugin's
3
+ * mounted OAuth routes. UIs (the dsh-tui /provider wizard, a web settings
4
+ * page) enumerate providers with masked sign-in state and drive login/logout
5
+ * without touching the credential file or the pi-ai flow objects; the `/auth`
6
+ * command in `command.ts` is a thin textual veneer over the same api.
7
+ *
8
+ * @module dsh-auth/service
9
+ */
10
+ import { Service } from '@deepseek-ai/cordis';
11
+ import { asStoredCredential } from './credentials.js';
12
+ import { oauthOf } from './profiles.js';
13
+ import { QuestionBridge } from './interaction.js';
14
+ /** Cordis service holder; `api` is set by the plugin's apply. */
15
+ export class DshAuthService extends Service {
16
+ api;
17
+ constructor(ctx) {
18
+ super(ctx, 'dshAuth');
19
+ }
20
+ }
21
+ /** Select a provider interactively among `candidates`. */
22
+ async function chooseProvider(ask, candidates, signal) {
23
+ const answer = await ask({
24
+ questions: [{
25
+ id: 'dsh-auth-provider',
26
+ header: 'dsh-auth',
27
+ question: 'Sign in with which provider?',
28
+ options: candidates.map(row => ({ label: row.oauthLabel, description: row.provider })),
29
+ }],
30
+ signal,
31
+ });
32
+ const row = answer.answers[0];
33
+ const label = row?.selected[0];
34
+ const chosen = candidates.find(candidate => candidate.oauthLabel === label);
35
+ if (chosen === undefined)
36
+ throw new Error('dsh-auth: no provider was chosen');
37
+ return chosen.provider;
38
+ }
39
+ /**
40
+ * The api implementation. One login runs per provider at a time (an in-flight
41
+ * map, not a global lock: providers sign in independently); a second login
42
+ * attempt for the same provider fails fast instead of stacking two flows.
43
+ */
44
+ export function createDshAuthApi(deps) {
45
+ const inflight = new Map();
46
+ const statusOf = async () => {
47
+ const described = new Map((await deps.store.describe()).map(row => [row.provider, row]));
48
+ return [...deps.profiles.entries()].map(([id, profile]) => {
49
+ const oauth = oauthOf(profile.piProvider);
50
+ const row = described.get(id);
51
+ return {
52
+ provider: id,
53
+ label: profile.displayName,
54
+ oauthLabel: oauth.name,
55
+ loginLabel: oauth.loginLabel,
56
+ signedIn: row !== undefined && !row.expired,
57
+ expiresAt: row?.expiresAt,
58
+ expired: row?.expired ?? false,
59
+ };
60
+ });
61
+ };
62
+ const loginOne = async (provider, ask, signal) => {
63
+ const profile = deps.profiles.get(provider);
64
+ if (profile === undefined) {
65
+ throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
66
+ }
67
+ const oauth = oauthOf(profile.piProvider);
68
+ const runAbort = new AbortController();
69
+ if (signal !== undefined) {
70
+ if (signal.aborted)
71
+ runAbort.abort(signal.reason);
72
+ else
73
+ signal.addEventListener('abort', () => runAbort.abort(signal.reason), { once: true });
74
+ }
75
+ const bridge = new QuestionBridge(ask, runAbort);
76
+ try {
77
+ const returned = await oauth.login(bridge);
78
+ const normalized = asStoredCredential(returned);
79
+ if (normalized === undefined) {
80
+ throw new Error(`dsh-auth: the ${oauth.name} flow returned an unusable credential; nothing was stored`);
81
+ }
82
+ const stored = normalized;
83
+ await deps.store.modify(provider, async () => stored);
84
+ return { provider, oauthLabel: oauth.name, expiresAt: stored.expires };
85
+ }
86
+ finally {
87
+ await bridge.settle();
88
+ }
89
+ };
90
+ return {
91
+ providers: statusOf,
92
+ login: async (provider, signal) => {
93
+ const ask = deps.resolveAsk();
94
+ let target = provider;
95
+ if (target === undefined) {
96
+ if (ask === undefined) {
97
+ throw new Error('dsh-auth: provider selection needs an interactive surface; name the provider: /auth login <provider>');
98
+ }
99
+ const statuses = await statusOf();
100
+ const candidates = statuses.filter(row => !row.signedIn);
101
+ if (candidates.length === 0)
102
+ throw new Error('dsh-auth: every mounted provider is already signed in');
103
+ target = await chooseProvider(ask, candidates, signal);
104
+ }
105
+ else if (!deps.profiles.has(target)) {
106
+ throw new Error(`dsh-auth: unknown provider "${target}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
107
+ }
108
+ if (ask === undefined) {
109
+ throw new Error(`dsh-auth: signing in to "${target}" needs an interactive surface (run inside dsh-tui or the web client); `
110
+ + 'this plugin refuses to assume a browser on this machine');
111
+ }
112
+ const existing = inflight.get(target);
113
+ if (existing !== undefined) {
114
+ throw new Error(`dsh-auth: a login for "${target}" is already running`);
115
+ }
116
+ const run = loginOne(target, ask, signal).finally(() => { inflight.delete(target); });
117
+ inflight.set(target, run);
118
+ return run;
119
+ },
120
+ logout: async (provider) => {
121
+ if (!deps.profiles.has(provider)) {
122
+ throw new Error(`dsh-auth: unknown provider "${provider}" (mounted: ${[...deps.profiles.keys()].join(', ')})`);
123
+ }
124
+ const existed = (await deps.store.read(provider)) !== undefined;
125
+ await deps.store.delete(provider);
126
+ return existed;
127
+ },
128
+ };
129
+ }