@askdkc/dsh-cli 0.12.3 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/cordis.patch.yml +12 -131
  2. package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
  3. package/lib/types/adapter/channel/session-projection.js +0 -7
  4. package/lib/types/adapter/ports/channel-view.d.ts +1 -1
  5. package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
  6. package/lib/types/dsh-adapter/bundled-presets.d.ts +3 -8
  7. package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
  8. package/lib/types/dsh-adapter/bundled-presets.js +5 -20
  9. package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
  10. package/lib/types/dsh-adapter/channel/binding-events.js +2 -9
  11. package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
  12. package/lib/types/dsh-adapter/channel/external-commands.js +9 -33
  13. package/lib/types/dsh-adapter/channel/local-actions.d.ts +2 -1
  14. package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
  15. package/lib/types/dsh-adapter/channel/local-actions.js +6 -2
  16. package/lib/types/dsh-adapter/channel/model-actions.js +3 -3
  17. package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
  18. package/lib/types/dsh-adapter/channel/model-switch.js +0 -1
  19. package/lib/types/dsh-adapter/channel/permissions.d.ts +1 -6
  20. package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
  21. package/lib/types/dsh-adapter/channel/permissions.js +2 -54
  22. package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
  23. package/lib/types/dsh-adapter/channel/projection.js +15 -70
  24. package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
  25. package/lib/types/dsh-adapter/channel/session-fork.js +0 -1
  26. package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
  27. package/lib/types/dsh-adapter/channel/session-metadata.js +1 -4
  28. package/lib/types/dsh-adapter/channel/session-resume.js +2 -2
  29. package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
  30. package/lib/types/dsh-adapter/channel/session-rewind.js +0 -1
  31. package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
  32. package/lib/types/dsh-adapter/channel/session-tree-actions.js +1 -2
  33. package/lib/types/dsh-adapter/channel/session-tree.d.ts.map +1 -1
  34. package/lib/types/dsh-adapter/channel/session-tree.js +9 -62
  35. package/lib/types/dsh-adapter/channel/skill-catalog.js +1 -1
  36. package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
  37. package/lib/types/dsh-adapter/channel/subagent-projection.js +2 -8
  38. package/lib/types/dsh-adapter/channel/transcript.d.ts +0 -16
  39. package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
  40. package/lib/types/dsh-adapter/channel/transcript.js +0 -43
  41. package/lib/types/dsh-adapter/channel.js +2 -2
  42. package/lib/types/dsh-adapter/compat/index.d.ts +5 -25
  43. package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
  44. package/lib/types/dsh-adapter/compat/index.js +5 -25
  45. package/lib/types/dsh-adapter/compat/liveSession.d.ts +12 -23
  46. package/lib/types/dsh-adapter/compat/liveSession.d.ts.map +1 -1
  47. package/lib/types/dsh-adapter/compat/liveSession.js +15 -68
  48. package/lib/types/dsh-adapter/compat/messages.d.ts +1 -3
  49. package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -1
  50. package/lib/types/dsh-adapter/compat/messages.js +2 -10
  51. package/lib/types/dsh-adapter/compat/persistence.d.ts +2 -3
  52. package/lib/types/dsh-adapter/compat/persistence.d.ts.map +1 -1
  53. package/lib/types/dsh-adapter/compat/persistence.js +9 -14
  54. package/lib/types/dsh-adapter/compat/sessionLog.d.ts +10 -144
  55. package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
  56. package/lib/types/dsh-adapter/compat/sessionLog.js +45 -275
  57. package/lib/types/dsh-adapter/compat/settings.d.ts +4 -10
  58. package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -1
  59. package/lib/types/dsh-adapter/compat/settings.js +6 -23
  60. package/lib/types/dsh-adapter/compat/shell.d.ts +2 -3
  61. package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -1
  62. package/lib/types/dsh-adapter/compat/shell.js +2 -7
  63. package/lib/types/dsh-adapter/contract.d.ts +4 -34
  64. package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
  65. package/lib/types/dsh-adapter/contract.js +8 -83
  66. package/lib/types/dsh-adapter/packaged-presets.d.ts +0 -19
  67. package/lib/types/dsh-adapter/packaged-presets.d.ts.map +1 -1
  68. package/lib/types/dsh-adapter/packaged-presets.js +1 -83
  69. package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
  70. package/lib/types/dsh-adapter/plugin.js +25 -168
  71. package/lib/types/dsh-adapter/preset-resolution.d.ts +1 -22
  72. package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
  73. package/lib/types/dsh-adapter/preset-resolution.js +0 -34
  74. package/lib/types/dsh-adapter/presets.d.ts +1 -4
  75. package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
  76. package/lib/types/dsh-adapter/presets.js +3 -6
  77. package/lib/types/dsh-adapter/questions-answerer.d.ts +5 -43
  78. package/lib/types/dsh-adapter/questions-answerer.d.ts.map +1 -1
  79. package/lib/types/dsh-adapter/questions-answerer.js +7 -63
  80. package/lib/types/dsh-adapter/sessionTree.d.ts +0 -19
  81. package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
  82. package/lib/types/dsh-adapter/sessionTree.js +2 -112
  83. package/lib/types/dsh-adapter/sessions/header.d.ts +2 -2
  84. package/lib/types/dsh-adapter/sessions/header.d.ts.map +1 -1
  85. package/lib/types/dsh-adapter/sessions/header.js +2 -8
  86. package/lib/types/dsh-adapter/sessions/list.d.ts +7 -28
  87. package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
  88. package/lib/types/dsh-adapter/sessions/list.js +48 -103
  89. package/lib/types/dsh-adapter/sessions/store.d.ts +1 -2
  90. package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
  91. package/lib/types/dsh-adapter/sessions/store.js +7 -10
  92. package/lib/types/dsh-adapter/sharp.d.ts.map +1 -1
  93. package/lib/types/dsh-adapter/sharp.js +0 -1
  94. package/lib/types/dsh-adapter/subagents.d.ts +1 -2
  95. package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
  96. package/lib/types/dsh-adapter/subagents.js +1 -12
  97. package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +1 -1
  98. package/lib/types/dsh-adapter/trajectory/aggregate.js +1 -1
  99. package/lib/types/dsh-adapter/trajectory/guards.d.ts +5 -22
  100. package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
  101. package/lib/types/dsh-adapter/trajectory/guards.js +5 -23
  102. package/lib/types/dsh-adapter/trajectory/projection.d.ts +5 -21
  103. package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
  104. package/lib/types/dsh-adapter/trajectory/projection.js +4 -38
  105. package/lib/types/dsh-adapter/trajectory/types.d.ts +1 -1
  106. package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
  107. package/lib/types/i18n.d.ts +2 -22
  108. package/lib/types/i18n.d.ts.map +1 -1
  109. package/lib/types/i18n.js +2 -10
  110. package/lib/types/presetPrefs.d.ts +1 -3
  111. package/lib/types/presetPrefs.d.ts.map +1 -1
  112. package/lib/types/presetPrefs.js +2 -4
  113. package/node_modules/@askdkc/dsh-auth/README.ja.md +28 -9
  114. package/node_modules/@askdkc/dsh-auth/README.md +19 -8
  115. package/node_modules/@askdkc/dsh-auth/dsh-plugin.json +3 -3
  116. package/node_modules/@askdkc/dsh-auth/lib/THIRD_PARTY_NOTICES.txt +168 -0
  117. package/node_modules/@askdkc/dsh-auth/lib/abortable.d.ts +2 -0
  118. package/node_modules/@askdkc/dsh-auth/lib/abortable.js +9 -0
  119. package/node_modules/@askdkc/dsh-auth/lib/auth-contract.d.ts +66 -0
  120. package/node_modules/@askdkc/dsh-auth/lib/auth-contract.js +1 -0
  121. package/node_modules/@askdkc/dsh-auth/lib/command.js +15 -1
  122. package/node_modules/@askdkc/dsh-auth/lib/credentials.d.ts +8 -14
  123. package/node_modules/@askdkc/dsh-auth/lib/credentials.js +1 -1
  124. package/node_modules/@askdkc/dsh-auth/lib/index.d.ts +8 -28
  125. package/node_modules/@askdkc/dsh-auth/lib/index.js +67 -65
  126. package/node_modules/@askdkc/dsh-auth/lib/interaction.d.ts +5 -5
  127. package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.d.ts +37 -0
  128. package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.js +197 -0
  129. package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.d.ts +72 -0
  130. package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.js +252 -0
  131. package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.d.ts +6 -0
  132. package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.js +93 -0
  133. package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.d.ts +113 -0
  134. package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.js +2866 -0
  135. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.d.ts +15 -0
  136. package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.js +141 -0
  137. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.d.ts +5 -0
  138. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js +43465 -0
  139. package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js.map +7 -0
  140. package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.d.ts +5 -0
  141. package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.js +69 -0
  142. package/node_modules/@askdkc/dsh-auth/lib/pi-routes.d.ts +32 -0
  143. package/node_modules/@askdkc/dsh-auth/lib/pi-routes.js +45 -0
  144. package/node_modules/@askdkc/dsh-auth/lib/profiles.d.ts +2 -20
  145. package/node_modules/@askdkc/dsh-auth/lib/profiles.js +6 -41
  146. package/node_modules/@askdkc/dsh-auth/lib/routes.d.ts +20 -0
  147. package/node_modules/@askdkc/dsh-auth/lib/routes.js +13 -0
  148. package/node_modules/@askdkc/dsh-auth/lib/service.d.ts +11 -2
  149. package/node_modules/@askdkc/dsh-auth/lib/service.js +26 -16
  150. package/node_modules/@askdkc/dsh-auth/package.json +26 -15
  151. package/package.json +100 -96
  152. package/lib/types/dsh-adapter/providerGuard.d.ts +0 -75
  153. package/lib/types/dsh-adapter/providerGuard.d.ts.map +0 -1
  154. package/lib/types/dsh-adapter/providerGuard.js +0 -104
  155. package/lib/types/migrationPrefs.d.ts +0 -60
  156. package/lib/types/migrationPrefs.d.ts.map +0 -1
  157. package/lib/types/migrationPrefs.js +0 -97
  158. package/node_modules/@askdkc/dsh-auth/lib/fresh-models.d.ts +0 -59
  159. package/node_modules/@askdkc/dsh-auth/lib/fresh-models.js +0 -246
  160. package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.d.ts +0 -321
  161. package/node_modules/@askdkc/dsh-auth/lib/opencode-snapshot.generated.js +0 -528
  162. package/presets/liangshen/.dsh-tui-managed.json +0 -5
@@ -2,9 +2,9 @@
2
2
  "$schema": "https://dsh.community/schemas/dsh-plugin-0.15.json",
3
3
  "id": "com.dsh-tui.dsh-auth",
4
4
  "name": "dsh-auth",
5
- "version": "0.1.0",
5
+ "version": "0.2.0",
6
6
  "manifestVersion": "0.15",
7
- "description": "Subscription OAuth sign-in (ChatGPT/Codex, Claude Pro/Max, SuperGrok) as LLM provider routes for DeepSeek Harness. Registers llm adapter routes through the cordis llm registry; interactive login runs over the user-questions seam and degrades to a clear refusal when no interactive surface is present.",
7
+ "description": "Provider authentication and OpenCode Zen/Go model routes for DeepSeek Harness. Registers llm adapter routes through the cordis llm registry; interactive login runs over the user-questions seam.",
8
8
  "facets": {
9
9
  "host": {
10
10
  "entry": "lib/index.js",
@@ -29,7 +29,7 @@
29
29
  "commands": [
30
30
  {
31
31
  "id": "dsh.auth",
32
- "title": "Sign in with a provider subscription (OAuth)"
32
+ "title": "Manage provider authentication and models"
33
33
  }
34
34
  ]
35
35
  },
@@ -0,0 +1,168 @@
1
+ @ai-sdk/provider@4.0.21 (Apache-2.0)
2
+ Copyright 2023 Vercel, Inc.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+
16
+ ---
17
+
18
+ zod@4.1.8 (MIT)
19
+ MIT License
20
+
21
+ Copyright (c) 2025 Colin McDonnell
22
+
23
+ Permission is hereby granted, free of charge, to any person obtaining a copy
24
+ of this software and associated documentation files (the "Software"), to deal
25
+ in the Software without restriction, including without limitation the rights
26
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
+ copies of the Software, and to permit persons to whom the Software is
28
+ furnished to do so, subject to the following conditions:
29
+
30
+ The above copyright notice and this permission notice shall be included in all
31
+ copies or substantial portions of the Software.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39
+ SOFTWARE.
40
+
41
+
42
+ ---
43
+
44
+ eventsource-parser@3.1.1 (MIT)
45
+ MIT License
46
+
47
+ Copyright (c) 2026 Espen Hovlandsdal <espen@hovlandsdal.com>
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining a copy
50
+ of this software and associated documentation files (the "Software"), to deal
51
+ in the Software without restriction, including without limitation the rights
52
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
53
+ copies of the Software, and to permit persons to whom the Software is
54
+ furnished to do so, subject to the following conditions:
55
+
56
+ The above copyright notice and this permission notice shall be included in all
57
+ copies or substantial portions of the Software.
58
+
59
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
60
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
61
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
62
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
63
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
64
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
65
+ SOFTWARE.
66
+
67
+
68
+ ---
69
+
70
+ @workflow/serde@4.1.0 (Apache-2.0)
71
+ Copyright 2023 Vercel, Inc.
72
+
73
+ Licensed under the Apache License, Version 2.0 (the "License");
74
+ you may not use this file except in compliance with the License.
75
+ You may obtain a copy of the License at
76
+
77
+ http://www.apache.org/licenses/LICENSE-2.0
78
+
79
+ Unless required by applicable law or agreed to in writing, software
80
+ distributed under the License is distributed on an "AS IS" BASIS,
81
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
82
+ See the License for the specific language governing permissions and
83
+ limitations under the License.
84
+
85
+ ---
86
+
87
+ @ai-sdk/provider-utils@5.0.53 (Apache-2.0)
88
+ Copyright 2023 Vercel, Inc.
89
+
90
+ Licensed under the Apache License, Version 2.0 (the "License");
91
+ you may not use this file except in compliance with the License.
92
+ You may obtain a copy of the License at
93
+
94
+ http://www.apache.org/licenses/LICENSE-2.0
95
+
96
+ Unless required by applicable law or agreed to in writing, software
97
+ distributed under the License is distributed on an "AS IS" BASIS,
98
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
99
+ See the License for the specific language governing permissions and
100
+ limitations under the License.
101
+
102
+ ---
103
+
104
+ @ai-sdk/anthropic@4.0.71 (Apache-2.0)
105
+ Copyright 2023 Vercel, Inc.
106
+
107
+ Licensed under the Apache License, Version 2.0 (the "License");
108
+ you may not use this file except in compliance with the License.
109
+ You may obtain a copy of the License at
110
+
111
+ http://www.apache.org/licenses/LICENSE-2.0
112
+
113
+ Unless required by applicable law or agreed to in writing, software
114
+ distributed under the License is distributed on an "AS IS" BASIS,
115
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
116
+ See the License for the specific language governing permissions and
117
+ limitations under the License.
118
+
119
+ ---
120
+
121
+ @ai-sdk/openai@4.0.83 (Apache-2.0)
122
+ Copyright 2023 Vercel, Inc.
123
+
124
+ Licensed under the Apache License, Version 2.0 (the "License");
125
+ you may not use this file except in compliance with the License.
126
+ You may obtain a copy of the License at
127
+
128
+ http://www.apache.org/licenses/LICENSE-2.0
129
+
130
+ Unless required by applicable law or agreed to in writing, software
131
+ distributed under the License is distributed on an "AS IS" BASIS,
132
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133
+ See the License for the specific language governing permissions and
134
+ limitations under the License.
135
+
136
+ ---
137
+
138
+ @ai-sdk/openai-compatible@3.0.62 (Apache-2.0)
139
+ Copyright 2023 Vercel, Inc.
140
+
141
+ Licensed under the Apache License, Version 2.0 (the "License");
142
+ you may not use this file except in compliance with the License.
143
+ You may obtain a copy of the License at
144
+
145
+ http://www.apache.org/licenses/LICENSE-2.0
146
+
147
+ Unless required by applicable law or agreed to in writing, software
148
+ distributed under the License is distributed on an "AS IS" BASIS,
149
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
150
+ See the License for the specific language governing permissions and
151
+ limitations under the License.
152
+
153
+ ---
154
+
155
+ @ai-sdk/google@4.0.87 (Apache-2.0)
156
+ Copyright 2023 Vercel, Inc.
157
+
158
+ Licensed under the Apache License, Version 2.0 (the "License");
159
+ you may not use this file except in compliance with the License.
160
+ You may obtain a copy of the License at
161
+
162
+ http://www.apache.org/licenses/LICENSE-2.0
163
+
164
+ Unless required by applicable law or agreed to in writing, software
165
+ distributed under the License is distributed on an "AS IS" BASIS,
166
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
167
+ See the License for the specific language governing permissions and
168
+ limitations under the License.
@@ -0,0 +1,2 @@
1
+ /** Bound async I/O even when a reader or fixture does not honor fetch cancellation. */
2
+ export declare function abortable<T>(operation: PromiseLike<T>, signal: AbortSignal): Promise<T>;
@@ -0,0 +1,9 @@
1
+ /** Bound async I/O even when a reader or fixture does not honor fetch cancellation. */
2
+ export function abortable(operation, signal) {
3
+ signal.throwIfAborted();
4
+ return new Promise((resolve, reject) => {
5
+ const abort = () => reject(signal.reason);
6
+ signal.addEventListener('abort', abort, { once: true });
7
+ Promise.resolve(operation).then(resolve, reject).finally(() => signal.removeEventListener('abort', abort));
8
+ });
9
+ }
@@ -0,0 +1,66 @@
1
+ /** Auth-owned persistence and interaction contracts; pi routes adapt structurally. */
2
+ export interface StoredOAuthCredential {
3
+ type: 'oauth';
4
+ access: string;
5
+ refresh: string;
6
+ expires: number;
7
+ [key: string]: unknown;
8
+ }
9
+ export interface StoredApiKeyCredential {
10
+ type: 'api_key';
11
+ key?: string;
12
+ env?: Record<string, string>;
13
+ }
14
+ export type StoredCredential = StoredOAuthCredential | StoredApiKeyCredential;
15
+ export interface CredentialInfo {
16
+ providerId: string;
17
+ type: StoredCredential['type'];
18
+ }
19
+ export interface AuthInteraction {
20
+ signal: AbortSignal;
21
+ prompt(prompt: AuthPrompt): Promise<string>;
22
+ notify(event: AuthEvent): void;
23
+ }
24
+ export type AuthPrompt = {
25
+ signal?: AbortSignal;
26
+ } & ({
27
+ type: 'text' | 'secret' | 'manual_code';
28
+ message: string;
29
+ placeholder?: string;
30
+ } | {
31
+ type: 'select';
32
+ message: string;
33
+ options: readonly {
34
+ id: string;
35
+ label: string;
36
+ description?: string;
37
+ }[];
38
+ });
39
+ export type AuthEvent = {
40
+ type: 'info';
41
+ message: string;
42
+ links?: readonly {
43
+ url: string;
44
+ label?: string;
45
+ }[];
46
+ } | {
47
+ type: 'auth_url';
48
+ url: string;
49
+ instructions?: string;
50
+ } | {
51
+ type: 'device_code';
52
+ userCode: string;
53
+ verificationUri: string;
54
+ intervalSeconds?: number;
55
+ expiresInSeconds?: number;
56
+ } | {
57
+ type: 'progress';
58
+ message: string;
59
+ };
60
+ export interface OAuthFlow {
61
+ name: string;
62
+ loginLabel?: string;
63
+ login(interaction: AuthInteraction, options?: {
64
+ getDeviceId?: () => string;
65
+ }): Promise<StoredOAuthCredential>;
66
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * @module dsh-auth/command
6
6
  */
7
- const USAGE = 'Usage: /auth [status] | /auth login [provider] | /auth logout <provider>';
7
+ const USAGE = 'Usage: /auth [status] | /auth login [provider] | /auth logout <provider> | /auth models [provider] | /auth refresh [provider]';
8
8
  function renderStatus(rows) {
9
9
  const lines = rows.map(row => {
10
10
  const state = row.signedIn
@@ -33,6 +33,20 @@ export function createAuthCommandHandler(api) {
33
33
  const { verb, target, extra } = parseArgs(invocation.rawInput);
34
34
  if (extra)
35
35
  return { kind: 'error', text: USAGE };
36
+ if (verb === 'models' || verb === 'refresh') {
37
+ try {
38
+ if (!api.catalogStatus || !api.refreshModels)
39
+ throw new Error('Model catalog operations are unavailable');
40
+ const rows = verb === 'refresh' ? await api.refreshModels(target, invocation.signal) : api.catalogStatus(target);
41
+ if (!rows.length)
42
+ throw new Error('No matching OpenCode catalog is mounted');
43
+ return { kind: rows.some(row => row.warning) && verb === 'refresh' ? 'error' : 'success', text: rows.map(row => `${row.provider}: ${row.available} models (${row.source}); last verified ${new Date(row.fetchedAt).toISOString()}${row.warning ? `; ${row.warning}` : ''}`
44
+ + row.excluded.map(entry => `\n ${entry.id}: ${entry.reason}`).join('')).join('\n') };
45
+ }
46
+ catch (error) {
47
+ return { kind: 'error', text: error instanceof Error ? error.message : 'Model catalog operation failed' };
48
+ }
49
+ }
36
50
  if (verb === undefined || verb === 'status') {
37
51
  if (target !== undefined)
38
52
  return { kind: 'error', text: USAGE };
@@ -1,5 +1,5 @@
1
1
  /**
2
- * File-backed credential persistence: a pi-ai `CredentialStore` over
2
+ * Auth-owned credential persistence, structurally compatible with pi stores, over
3
3
  * one JSON document, one credential per provider id.
4
4
  *
5
5
  * Writes are atomic (temp file + rename) with 0700 directory / 0600 file
@@ -13,16 +13,10 @@
13
13
  *
14
14
  * @module dsh-auth/credentials
15
15
  */
16
- import type { PiAiCredential, PiAiCredentialInfo, PiAiCredentialStore } from './pi-ai.js';
17
- /** The stored credential shapes from pi-ai. */
18
- export type StoredOAuthCredential = Extract<PiAiCredential, {
19
- type: 'oauth';
20
- }>;
21
- export type StoredApiKeyCredential = Extract<PiAiCredential, {
22
- type: 'api_key';
23
- }>;
16
+ import type { StoredCredential, CredentialInfo } from './auth-contract.js';
17
+ export type { StoredOAuthCredential, StoredApiKeyCredential } from './auth-contract.js';
24
18
  /** Narrow an unknown parsed value into a stored credential, or reject it. */
25
- export declare function asStoredCredential(value: unknown): PiAiCredential | undefined;
19
+ export declare function asStoredCredential(value: unknown): StoredCredential | undefined;
26
20
  /** Default credential file location: `$DSH_HOME/dsh-auth/credentials.json` (or `~/.dsh/…`). */
27
21
  export declare function defaultCredentialsFile(): string;
28
22
  /**
@@ -31,22 +25,22 @@ export declare function defaultCredentialsFile(): string;
31
25
  * credential file as "signed out everywhere" would strand every route behind
32
26
  * a fresh login for no reason.
33
27
  */
34
- export declare class CredentialFile implements PiAiCredentialStore {
28
+ export declare class CredentialFile {
35
29
  readonly path: string;
36
30
  /** Serialize all updates in this process; the file lock covers other processes. */
37
31
  private chainTail;
38
32
  constructor(path: string);
39
33
  /** The stored credential for one provider, possibly expired. */
40
- read(providerId: string): Promise<PiAiCredential | undefined>;
34
+ read(providerId: string): Promise<StoredCredential | undefined>;
41
35
  /** Stored credential metadata without resolving or exposing secrets. */
42
- list(): Promise<readonly PiAiCredentialInfo[]>;
36
+ list(): Promise<readonly CredentialInfo[]>;
43
37
  /**
44
38
  * Serialized read-modify-write for one provider. `fn` sees the current
45
39
  * credential; returning a new credential persists it, returning
46
40
  * `undefined` leaves the entry unchanged. Resolves with the post-write
47
41
  * credential. Rejections from `fn` propagate without touching the file.
48
42
  */
49
- modify(providerId: string, fn: (current: PiAiCredential | undefined) => Promise<PiAiCredential | undefined>): Promise<PiAiCredential | undefined>;
43
+ modify(providerId: string, fn: (current: StoredCredential | undefined) => Promise<StoredCredential | undefined>): Promise<StoredCredential | undefined>;
50
44
  /** Remove one provider's credential (logout). */
51
45
  delete(providerId: string): Promise<void>;
52
46
  /** Non-secret metadata for every stored credential, for status surfaces. */
@@ -1,5 +1,5 @@
1
1
  /**
2
- * File-backed credential persistence: a pi-ai `CredentialStore` over
2
+ * Auth-owned credential persistence, structurally compatible with pi stores, over
3
3
  * one JSON document, one credential per provider id.
4
4
  *
5
5
  * Writes are atomic (temp file + rename) with 0700 directory / 0600 file
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * dsh-auth — provider sign-in as LLM provider routes.
3
3
  *
4
- * One cordis plugin mounts pi-ai catalog and custom provider profiles as
4
+ * One cordis plugin mounts owned OpenCode routes and legacy pi profiles as
5
5
  * `llm` registry routes, so
6
- * catalog models appear in every model picker after sign-in. `PiAiAdapter` runs with this
6
+ * catalog models appear in every model picker after sign-in. OpenCode owns
7
+ * its public catalog and bundled SDK transports. Other routes use `PiAiAdapter` with this
7
8
  * plugin's file-backed pi-ai `CredentialStore` injected
8
9
  * (`PiAiAuthInjection`): requests resolve stored credentials through the
9
10
  * provider's own auth or an explicit API key. Refreshes hold the store lock.
@@ -33,10 +34,7 @@
33
34
  */
34
35
  import type { Context } from '@deepseek-ai/cordis';
35
36
  import z from '@deepseek-ai/schemastery';
36
- import type { LlmModelInfo } from '@deepseek-ai/dsh-llm';
37
- import { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai';
38
- import type { PiAiAdapterOptions } from '@deepseek-ai/dsh-llm-pi-ai';
39
- import { type ModelOverride } from './profiles.js';
37
+ import { type ModelOverride } from './routes.js';
40
38
  export declare const name = "dsh-auth";
41
39
  /**
42
40
  * Deliberately empty. A hard code-level inject would deadlock any
@@ -72,26 +70,8 @@ export { QuestionBridge, describeEvent } from './interaction.js';
72
70
  export type { AskFn, QuestionBridgeHelpers } from './interaction.js';
73
71
  export { copyToClipboard, openInBrowser, openerFor } from './opener.js';
74
72
  export { CredentialFile, defaultCredentialsFile } from './credentials.js';
75
- export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, buildOAuthProfile, type ModelOverride } from './profiles.js';
76
- export { freshRosterIds, type FreshRouteId } from './fresh-models.js';
77
- /**
78
- * The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
79
- * catalog* is credential-gated. A provider with no stored credential
80
- * lists no models — its rows never reach any model picker, which is the
81
- * whole point: picking a model that would only fail with "not signed in"
82
- * is noise. The gate only shapes `listModels`; `resolveModel` and requests
83
- * are untouched, so a model id already saved in a session (or named
84
- * explicitly) keeps resolving exactly as the registry contract promises
85
- * ("advisory and never changes routing").
86
- *
87
- * An expired-but-stored credential still lists: token refresh runs on the
88
- * next request, and a picker that hid a refreshable provider would look
89
- * signed-out when it is not.
90
- */
91
- export declare class CredentialGatedAdapter extends PiAiAdapter {
92
- private readonly hasCredential;
93
- constructor(options: PiAiAdapterOptions, hasCredential: (provider: string) => Promise<boolean>);
94
- listModels(provider: string): Promise<readonly LlmModelInfo[]>;
95
- }
73
+ export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, type ModelOverride } from './routes.js';
74
+ export { OpenCodeAdapter } from './opencode-adapter.js';
75
+ export { OpenCodeCatalog } from './opencode-catalog.js';
96
76
  /** Mount the routes, the service, and the command. */
97
- export declare function apply(ctx: Context, config: Config): void;
77
+ export declare function apply(ctx: Context, config: Config): Promise<void>;
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * dsh-auth — provider sign-in as LLM provider routes.
3
3
  *
4
- * One cordis plugin mounts pi-ai catalog and custom provider profiles as
4
+ * One cordis plugin mounts owned OpenCode routes and legacy pi profiles as
5
5
  * `llm` registry routes, so
6
- * catalog models appear in every model picker after sign-in. `PiAiAdapter` runs with this
6
+ * catalog models appear in every model picker after sign-in. OpenCode owns
7
+ * its public catalog and bundled SDK transports. Other routes use `PiAiAdapter` with this
7
8
  * plugin's file-backed pi-ai `CredentialStore` injected
8
9
  * (`PiAiAuthInjection`): requests resolve stored credentials through the
9
10
  * provider's own auth or an explicit API key. Refreshes hold the store lock.
@@ -31,14 +32,12 @@
31
32
  *
32
33
  * @module dsh-auth
33
34
  */
34
- import { existsSync } from 'node:fs';
35
- import { homedir } from 'node:os';
36
- import { join } from 'node:path';
37
35
  import z from '@deepseek-ai/schemastery';
38
- import { PiAiAdapter } from '@deepseek-ai/dsh-llm-pi-ai';
39
36
  import { CredentialFile, defaultCredentialsFile } from './credentials.js';
40
- import { buildOAuthProfile, AUTH_PROVIDER_IDS, canonicalProvider } from './profiles.js';
41
- import { createCustomProfile, CUSTOM_PROVIDER_IDS } from './custom-profiles.js';
37
+ import { AUTH_PROVIDER_IDS, canonicalProvider } from './routes.js';
38
+ import { OpenCodeAdapter } from './opencode-adapter.js';
39
+ import { OpenCodeCatalog, OPEN_CODE_ROUTES } from './opencode-catalog.js';
40
+ import { OPEN_CODE_SNAPSHOTS } from './opencode-owned.generated.js';
42
41
  import { refreshNous } from './nous-oauth.js';
43
42
  import { createDshAuthApi, DshAuthService } from './service.js';
44
43
  import { createAuthCommandHandler } from './command.js';
@@ -67,49 +66,11 @@ export { createDshAuthApi } from './service.js';
67
66
  export { QuestionBridge, describeEvent } from './interaction.js';
68
67
  export { copyToClipboard, openInBrowser, openerFor } from './opener.js';
69
68
  export { CredentialFile, defaultCredentialsFile } from './credentials.js';
70
- export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider, buildOAuthProfile } from './profiles.js';
71
- export { freshRosterIds } from './fresh-models.js';
72
- /**
73
- * The ambient auth context providers may consult while resolving their own
74
- * auth. `env()` answers from the process environment; `fileExists()` answers
75
- * about the host process's filesystem (the paths a provider asks about —
76
- * `~/.aws/credentials` and friends — are facts about where this process
77
- * runs, not about the project under edit).
78
- */
79
- function hostAuthContext() {
80
- return {
81
- env: async (name) => process.env[name],
82
- fileExists: path => Promise.resolve(path.startsWith('~/') ? existsSync(join(homedir(), path.slice(2))) : existsSync(path)),
83
- };
84
- }
85
- /**
86
- * The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
87
- * catalog* is credential-gated. A provider with no stored credential
88
- * lists no models — its rows never reach any model picker, which is the
89
- * whole point: picking a model that would only fail with "not signed in"
90
- * is noise. The gate only shapes `listModels`; `resolveModel` and requests
91
- * are untouched, so a model id already saved in a session (or named
92
- * explicitly) keeps resolving exactly as the registry contract promises
93
- * ("advisory and never changes routing").
94
- *
95
- * An expired-but-stored credential still lists: token refresh runs on the
96
- * next request, and a picker that hid a refreshable provider would look
97
- * signed-out when it is not.
98
- */
99
- export class CredentialGatedAdapter extends PiAiAdapter {
100
- hasCredential;
101
- constructor(options, hasCredential) {
102
- super(options);
103
- this.hasCredential = hasCredential;
104
- }
105
- async listModels(provider) {
106
- if (!(await this.hasCredential(provider)))
107
- return [];
108
- return super.listModels(provider);
109
- }
110
- }
69
+ export { OAUTH_PROVIDER_IDS, CATALOG_PROVIDER_IDS, AUTH_PROVIDER_IDS, canonicalProvider } from './routes.js';
70
+ export { OpenCodeAdapter } from './opencode-adapter.js';
71
+ export { OpenCodeCatalog } from './opencode-catalog.js';
111
72
  /** Mount the routes, the service, and the command. */
112
- export function apply(ctx, config) {
73
+ export async function apply(ctx, config) {
113
74
  const configured = (config.providers ?? [...AUTH_PROVIDER_IDS]).map(canonicalProvider);
114
75
  const unknown = configured.filter(id => !AUTH_PROVIDER_IDS.includes(id));
115
76
  if (unknown.length > 0 || configured.length === 0) {
@@ -123,14 +84,35 @@ export function apply(ctx, config) {
123
84
  if (unknownOverridden.length > 0) {
124
85
  throw new Error(`dsh-auth: modelOverrides names provider "${unknownOverridden[0]}", which is not among the mounted providers [${configured.join(', ')}]`);
125
86
  }
126
- // Profile construction validates the installed catalog loudly: a pi-ai
127
- // downgrade that dropped a provider fails the boot that asked for it, and
128
- // a per-model miss is refused per route (see buildOAuthProfile).
129
- const custom = new Map(CUSTOM_PROVIDER_IDS.filter(id => configured.includes(id))
130
- .map(id => [id, createCustomProfile(id, overrides[id])]));
131
- const profiles = new Map(configured.map(id => [id,
132
- custom.get(id)?.profile ?? buildOAuthProfile(id, overrides[id]),
133
- ]));
87
+ const piIds = configured.filter(id => !OPEN_CODE_ROUTES.includes(id));
88
+ const custom = new Map();
89
+ const piProfiles = new Map();
90
+ const profiles = new Map();
91
+ let pi;
92
+ if (piIds.length) {
93
+ try {
94
+ pi = await import('./pi-routes.js');
95
+ }
96
+ catch {
97
+ ctx.logger.warn('dsh-auth: pi routes unavailable; OpenCode routes remain available');
98
+ }
99
+ if (pi)
100
+ for (const id of piIds) {
101
+ try {
102
+ const entry = pi.CUSTOM_PROVIDER_IDS.includes(id) ? pi.createCustomProfile(id, overrides[id]) : undefined;
103
+ if (entry)
104
+ custom.set(id, entry);
105
+ const profile = entry?.profile ?? pi.buildOAuthProfile(id, overrides[id]);
106
+ piProfiles.set(id, profile);
107
+ profiles.set(id, { provider: id, displayName: profile.displayName, oauth: profile.piProvider?.auth.oauth });
108
+ }
109
+ catch {
110
+ ctx.logger.warn(`dsh-auth: route ${id} unavailable; remaining routes stay mounted`);
111
+ }
112
+ }
113
+ }
114
+ for (const id of configured.filter(id => OPEN_CODE_ROUTES.includes(id)))
115
+ profiles.set(id, { provider: id, displayName: id === 'opencode' ? 'OpenCode Zen' : 'OpenCode Go' });
134
116
  const store = new CredentialFile(config.credentialsFile ?? defaultCredentialsFile());
135
117
  const credentialKey = async (provider) => {
136
118
  const current = await store.read(provider);
@@ -161,28 +143,34 @@ export function apply(ctx, config) {
161
143
  return false;
162
144
  }
163
145
  };
164
- const adapter = new CredentialGatedAdapter({
146
+ const adapter = pi ? new pi.CredentialGatedAdapter({
165
147
  // One immutable map for the plugin's lifetime: the snapshot memoizes on
166
148
  // identity, and route changes here always mean a plugin remount anyway.
167
- profiles: () => profiles,
149
+ profiles: () => piProfiles,
168
150
  // Explicit API keys cover catalog routes too. OAuth catalog routes still
169
151
  // resolve their grants through pi-ai's injected credential store.
170
152
  resolveApiKey: credentialKey,
171
153
  auth: {
172
154
  credentials: store,
173
- authContext: hostAuthContext(),
155
+ authContext: pi.hostAuthContext(),
174
156
  },
175
157
  resolveAttachments: () => ctx.get('attachments'),
176
158
  onReplayDegrade: ({ provider, model, reason }) => {
177
159
  ctx.logger.warn(`dsh-auth: replay state on assistant history for ${provider}/${model} degraded: ${reason}`);
178
160
  },
179
- }, hasCredential);
161
+ }, hasCredential) : undefined;
162
+ const catalogs = new Map();
163
+ for (const id of OPEN_CODE_ROUTES)
164
+ if (configured.includes(id))
165
+ catalogs.set(id, new OpenCodeCatalog(id, OPEN_CODE_SNAPSHOTS[id], { changed: () => service.api?.notifyModelsChanged?.(id) }));
166
+ const native = new OpenCodeAdapter({ catalogs, store, overrides, attachments: () => ctx.get('attachments'), warn: reason => ctx.logger.warn(reason) });
180
167
  // The service is a thin holder so UIs can find the api without importing
181
168
  // the plugin module; the defensive get-then-create matches how the TUI
182
169
  // mounts userQuestions.
183
170
  const service = ctx.get('dshAuth') ?? new DshAuthService(ctx);
184
171
  const api = createDshAuthApi({
185
172
  profiles,
173
+ catalogs,
186
174
  store,
187
175
  resolveAsk: () => {
188
176
  const questions = ctx.get('userQuestions');
@@ -191,6 +179,14 @@ export function apply(ctx, config) {
191
179
  logger: ctx.logger,
192
180
  nousClientId: config.nous?.clientId,
193
181
  credentialChanged: async (provider, credential) => {
182
+ if (catalogs.has(provider)) {
183
+ if (credential) {
184
+ const status = await catalogs.get(provider).refresh();
185
+ if (status.warning)
186
+ throw new Error(status.warning);
187
+ }
188
+ return;
189
+ }
194
190
  const entry = custom.get(provider);
195
191
  if (entry === undefined)
196
192
  return;
@@ -207,6 +203,8 @@ export function apply(ctx, config) {
207
203
  },
208
204
  });
209
205
  service.api = api;
206
+ for (const catalog of catalogs.values())
207
+ void catalog.start();
210
208
  for (const [provider, entry] of custom) {
211
209
  void credentialKey(provider).then(key => key === undefined ? undefined : entry.refresh(key))
212
210
  .then(count => { if (count !== undefined)
@@ -226,9 +224,11 @@ export function apply(ctx, config) {
226
224
  else {
227
225
  // Individual registrations: one conflicting route must not strand the
228
226
  // rest (the registry keeps the previous owner serving).
229
- for (const id of configured) {
227
+ for (const id of profiles.keys()) {
230
228
  try {
231
- releases.push(llm.registerAdapter([id], adapter));
229
+ const owned = catalogs.has(id) ? native : adapter;
230
+ if (owned)
231
+ releases.push(llm.registerAdapter([id], owned));
232
232
  }
233
233
  catch (error) {
234
234
  ctx.logger.error(`dsh-auth: route "${id}" was not registered: ${error instanceof Error ? error.message : String(error)} `
@@ -244,7 +244,7 @@ export function apply(ctx, config) {
244
244
  const handler = createAuthCommandHandler(api);
245
245
  releases.push(commands.register({
246
246
  name: 'auth',
247
- description: 'Provider authentication: status, login, logout',
247
+ description: 'Provider authentication and catalogs: status, login, logout, models, refresh',
248
248
  handler: invocation => {
249
249
  const operation = handler(invocation);
250
250
  active.add(operation);
@@ -257,6 +257,8 @@ export function apply(ctx, config) {
257
257
  // enter while already-started logins finish their final write.
258
258
  yield async () => { await Promise.allSettled([...active]); };
259
259
  yield () => {
260
+ for (const catalog of catalogs.values())
261
+ catalog.dispose();
260
262
  for (const release of releases)
261
263
  release();
262
264
  };