@askdkc/dsh-cli 0.12.2 → 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.
- package/README.md +6 -1
- package/cordis.patch.yml +12 -131
- package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/session-projection.js +0 -7
- package/lib/types/adapter/ports/channel-view.d.ts +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/dsh-adapter/bundled-presets.d.ts +3 -8
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/bundled-presets.js +5 -20
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +2 -9
- package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/external-commands.js +9 -33
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +2 -1
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +6 -2
- package/lib/types/dsh-adapter/channel/model-actions.js +3 -3
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +0 -1
- package/lib/types/dsh-adapter/channel/permissions.d.ts +1 -6
- package/lib/types/dsh-adapter/channel/permissions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/permissions.js +2 -54
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +15 -70
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +0 -1
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +1 -4
- package/lib/types/dsh-adapter/channel/session-resume.js +2 -2
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +0 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +1 -2
- package/lib/types/dsh-adapter/channel/session-tree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree.js +9 -62
- package/lib/types/dsh-adapter/channel/skill-catalog.js +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +2 -8
- package/lib/types/dsh-adapter/channel/transcript.d.ts +0 -16
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +0 -43
- package/lib/types/dsh-adapter/channel.js +2 -2
- package/lib/types/dsh-adapter/compat/index.d.ts +5 -25
- package/lib/types/dsh-adapter/compat/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/index.js +5 -25
- package/lib/types/dsh-adapter/compat/liveSession.d.ts +12 -23
- package/lib/types/dsh-adapter/compat/liveSession.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/liveSession.js +15 -68
- package/lib/types/dsh-adapter/compat/messages.d.ts +1 -3
- package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/messages.js +2 -10
- package/lib/types/dsh-adapter/compat/persistence.d.ts +2 -3
- package/lib/types/dsh-adapter/compat/persistence.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/persistence.js +9 -14
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts +10 -144
- package/lib/types/dsh-adapter/compat/sessionLog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/sessionLog.js +45 -275
- package/lib/types/dsh-adapter/compat/settings.d.ts +4 -10
- package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/settings.js +6 -23
- package/lib/types/dsh-adapter/compat/shell.d.ts +2 -3
- package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -1
- package/lib/types/dsh-adapter/compat/shell.js +2 -7
- package/lib/types/dsh-adapter/contract.d.ts +4 -34
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +8 -83
- package/lib/types/dsh-adapter/packaged-presets.d.ts +0 -19
- package/lib/types/dsh-adapter/packaged-presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/packaged-presets.js +1 -83
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +25 -168
- package/lib/types/dsh-adapter/preset-resolution.d.ts +1 -22
- package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/preset-resolution.js +0 -34
- package/lib/types/dsh-adapter/presets.d.ts +1 -4
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +3 -6
- package/lib/types/dsh-adapter/questions-answerer.d.ts +5 -43
- package/lib/types/dsh-adapter/questions-answerer.d.ts.map +1 -1
- package/lib/types/dsh-adapter/questions-answerer.js +7 -63
- package/lib/types/dsh-adapter/sessionTree.d.ts +0 -19
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessionTree.js +2 -112
- package/lib/types/dsh-adapter/sessions/header.d.ts +2 -2
- package/lib/types/dsh-adapter/sessions/header.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/header.js +2 -8
- package/lib/types/dsh-adapter/sessions/list.d.ts +7 -28
- package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/list.js +48 -103
- package/lib/types/dsh-adapter/sessions/store.d.ts +1 -2
- package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/store.js +7 -10
- package/lib/types/dsh-adapter/sharp.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sharp.js +0 -1
- package/lib/types/dsh-adapter/subagents.d.ts +1 -2
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +1 -12
- package/lib/types/dsh-adapter/trajectory/aggregate.d.ts +1 -1
- package/lib/types/dsh-adapter/trajectory/aggregate.js +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.d.ts +5 -22
- package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.js +5 -23
- package/lib/types/dsh-adapter/trajectory/projection.d.ts +5 -21
- package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/projection.js +4 -38
- package/lib/types/dsh-adapter/trajectory/types.d.ts +1 -1
- package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
- package/lib/types/i18n.d.ts +2 -22
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +2 -10
- package/lib/types/presetPrefs.d.ts +1 -3
- package/lib/types/presetPrefs.d.ts.map +1 -1
- package/lib/types/presetPrefs.js +2 -4
- package/node_modules/@askdkc/dsh-auth/README.ja.md +28 -3
- package/node_modules/@askdkc/dsh-auth/README.md +19 -3
- package/node_modules/@askdkc/dsh-auth/dsh-plugin.json +3 -3
- package/node_modules/@askdkc/dsh-auth/lib/THIRD_PARTY_NOTICES.txt +168 -0
- package/node_modules/@askdkc/dsh-auth/lib/abortable.d.ts +2 -0
- package/node_modules/@askdkc/dsh-auth/lib/abortable.js +9 -0
- package/node_modules/@askdkc/dsh-auth/lib/auth-contract.d.ts +66 -0
- package/node_modules/@askdkc/dsh-auth/lib/auth-contract.js +1 -0
- package/node_modules/@askdkc/dsh-auth/lib/command.js +15 -1
- package/node_modules/@askdkc/dsh-auth/lib/credentials.d.ts +8 -14
- package/node_modules/@askdkc/dsh-auth/lib/credentials.js +1 -1
- package/node_modules/@askdkc/dsh-auth/lib/index.d.ts +8 -27
- package/node_modules/@askdkc/dsh-auth/lib/index.js +67 -64
- package/node_modules/@askdkc/dsh-auth/lib/interaction.d.ts +5 -5
- package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.d.ts +37 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-adapter.js +197 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.d.ts +72 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-catalog.js +252 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.d.ts +6 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-codec.js +93 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.d.ts +113 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-owned.generated.js +2866 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.d.ts +15 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-replay.js +141 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.d.ts +5 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js +43465 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-sdk.js.map +7 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.d.ts +5 -0
- package/node_modules/@askdkc/dsh-auth/lib/opencode-transport.js +69 -0
- package/node_modules/@askdkc/dsh-auth/lib/pi-ai.d.ts +2 -1
- package/node_modules/@askdkc/dsh-auth/lib/pi-ai.js +2 -1
- package/node_modules/@askdkc/dsh-auth/lib/pi-routes.d.ts +32 -0
- package/node_modules/@askdkc/dsh-auth/lib/pi-routes.js +45 -0
- package/node_modules/@askdkc/dsh-auth/lib/profiles.d.ts +2 -20
- package/node_modules/@askdkc/dsh-auth/lib/profiles.js +6 -35
- package/node_modules/@askdkc/dsh-auth/lib/routes.d.ts +20 -0
- package/node_modules/@askdkc/dsh-auth/lib/routes.js +13 -0
- package/node_modules/@askdkc/dsh-auth/lib/service.d.ts +11 -2
- package/node_modules/@askdkc/dsh-auth/lib/service.js +26 -16
- package/node_modules/@askdkc/dsh-auth/package.json +26 -14
- package/package.json +100 -96
- package/lib/types/dsh-adapter/providerGuard.d.ts +0 -75
- package/lib/types/dsh-adapter/providerGuard.d.ts.map +0 -1
- package/lib/types/dsh-adapter/providerGuard.js +0 -104
- package/lib/types/migrationPrefs.d.ts +0 -60
- package/lib/types/migrationPrefs.d.ts.map +0 -1
- package/lib/types/migrationPrefs.js +0 -97
- 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.
|
|
5
|
+
"version": "0.2.0",
|
|
6
6
|
"manifestVersion": "0.15",
|
|
7
|
-
"description": "
|
|
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": "
|
|
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,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
|
-
*
|
|
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 {
|
|
17
|
-
|
|
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):
|
|
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
|
|
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<
|
|
34
|
+
read(providerId: string): Promise<StoredCredential | undefined>;
|
|
41
35
|
/** Stored credential metadata without resolving or exposing secrets. */
|
|
42
|
-
list(): Promise<readonly
|
|
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:
|
|
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
|
-
*
|
|
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
|
|
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.
|
|
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
|
|
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,25 +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,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
* catalog* is credential-gated. A provider with no stored credential
|
|
79
|
-
* lists no models — its rows never reach any model picker, which is the
|
|
80
|
-
* whole point: picking a model that would only fail with "not signed in"
|
|
81
|
-
* is noise. The gate only shapes `listModels`; `resolveModel` and requests
|
|
82
|
-
* are untouched, so a model id already saved in a session (or named
|
|
83
|
-
* explicitly) keeps resolving exactly as the registry contract promises
|
|
84
|
-
* ("advisory and never changes routing").
|
|
85
|
-
*
|
|
86
|
-
* An expired-but-stored credential still lists: token refresh runs on the
|
|
87
|
-
* next request, and a picker that hid a refreshable provider would look
|
|
88
|
-
* signed-out when it is not.
|
|
89
|
-
*/
|
|
90
|
-
export declare class CredentialGatedAdapter extends PiAiAdapter {
|
|
91
|
-
private readonly hasCredential;
|
|
92
|
-
constructor(options: PiAiAdapterOptions, hasCredential: (provider: string) => Promise<boolean>);
|
|
93
|
-
listModels(provider: string): Promise<readonly LlmModelInfo[]>;
|
|
94
|
-
}
|
|
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';
|
|
95
76
|
/** Mount the routes, the service, and the command. */
|
|
96
|
-
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
|
|
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.
|
|
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 {
|
|
41
|
-
import {
|
|
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,48 +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
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
* auth. `env()` answers from the process environment; `fileExists()` answers
|
|
74
|
-
* about the host process's filesystem (the paths a provider asks about —
|
|
75
|
-
* `~/.aws/credentials` and friends — are facts about where this process
|
|
76
|
-
* runs, not about the project under edit).
|
|
77
|
-
*/
|
|
78
|
-
function hostAuthContext() {
|
|
79
|
-
return {
|
|
80
|
-
env: async (name) => process.env[name],
|
|
81
|
-
fileExists: path => Promise.resolve(path.startsWith('~/') ? existsSync(join(homedir(), path.slice(2))) : existsSync(path)),
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* The adapter the plugin registers: a {@link PiAiAdapter} whose *advisory
|
|
86
|
-
* catalog* is credential-gated. A provider with no stored credential
|
|
87
|
-
* lists no models — its rows never reach any model picker, which is the
|
|
88
|
-
* whole point: picking a model that would only fail with "not signed in"
|
|
89
|
-
* is noise. The gate only shapes `listModels`; `resolveModel` and requests
|
|
90
|
-
* are untouched, so a model id already saved in a session (or named
|
|
91
|
-
* explicitly) keeps resolving exactly as the registry contract promises
|
|
92
|
-
* ("advisory and never changes routing").
|
|
93
|
-
*
|
|
94
|
-
* An expired-but-stored credential still lists: token refresh runs on the
|
|
95
|
-
* next request, and a picker that hid a refreshable provider would look
|
|
96
|
-
* signed-out when it is not.
|
|
97
|
-
*/
|
|
98
|
-
export class CredentialGatedAdapter extends PiAiAdapter {
|
|
99
|
-
hasCredential;
|
|
100
|
-
constructor(options, hasCredential) {
|
|
101
|
-
super(options);
|
|
102
|
-
this.hasCredential = hasCredential;
|
|
103
|
-
}
|
|
104
|
-
async listModels(provider) {
|
|
105
|
-
if (!(await this.hasCredential(provider)))
|
|
106
|
-
return [];
|
|
107
|
-
return super.listModels(provider);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
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';
|
|
110
72
|
/** Mount the routes, the service, and the command. */
|
|
111
|
-
export function apply(ctx, config) {
|
|
73
|
+
export async function apply(ctx, config) {
|
|
112
74
|
const configured = (config.providers ?? [...AUTH_PROVIDER_IDS]).map(canonicalProvider);
|
|
113
75
|
const unknown = configured.filter(id => !AUTH_PROVIDER_IDS.includes(id));
|
|
114
76
|
if (unknown.length > 0 || configured.length === 0) {
|
|
@@ -122,14 +84,35 @@ export function apply(ctx, config) {
|
|
|
122
84
|
if (unknownOverridden.length > 0) {
|
|
123
85
|
throw new Error(`dsh-auth: modelOverrides names provider "${unknownOverridden[0]}", which is not among the mounted providers [${configured.join(', ')}]`);
|
|
124
86
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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' });
|
|
133
116
|
const store = new CredentialFile(config.credentialsFile ?? defaultCredentialsFile());
|
|
134
117
|
const credentialKey = async (provider) => {
|
|
135
118
|
const current = await store.read(provider);
|
|
@@ -160,28 +143,34 @@ export function apply(ctx, config) {
|
|
|
160
143
|
return false;
|
|
161
144
|
}
|
|
162
145
|
};
|
|
163
|
-
const adapter = new CredentialGatedAdapter({
|
|
146
|
+
const adapter = pi ? new pi.CredentialGatedAdapter({
|
|
164
147
|
// One immutable map for the plugin's lifetime: the snapshot memoizes on
|
|
165
148
|
// identity, and route changes here always mean a plugin remount anyway.
|
|
166
|
-
profiles: () =>
|
|
149
|
+
profiles: () => piProfiles,
|
|
167
150
|
// Explicit API keys cover catalog routes too. OAuth catalog routes still
|
|
168
151
|
// resolve their grants through pi-ai's injected credential store.
|
|
169
152
|
resolveApiKey: credentialKey,
|
|
170
153
|
auth: {
|
|
171
154
|
credentials: store,
|
|
172
|
-
authContext: hostAuthContext(),
|
|
155
|
+
authContext: pi.hostAuthContext(),
|
|
173
156
|
},
|
|
174
157
|
resolveAttachments: () => ctx.get('attachments'),
|
|
175
158
|
onReplayDegrade: ({ provider, model, reason }) => {
|
|
176
159
|
ctx.logger.warn(`dsh-auth: replay state on assistant history for ${provider}/${model} degraded: ${reason}`);
|
|
177
160
|
},
|
|
178
|
-
}, 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) });
|
|
179
167
|
// The service is a thin holder so UIs can find the api without importing
|
|
180
168
|
// the plugin module; the defensive get-then-create matches how the TUI
|
|
181
169
|
// mounts userQuestions.
|
|
182
170
|
const service = ctx.get('dshAuth') ?? new DshAuthService(ctx);
|
|
183
171
|
const api = createDshAuthApi({
|
|
184
172
|
profiles,
|
|
173
|
+
catalogs,
|
|
185
174
|
store,
|
|
186
175
|
resolveAsk: () => {
|
|
187
176
|
const questions = ctx.get('userQuestions');
|
|
@@ -190,6 +179,14 @@ export function apply(ctx, config) {
|
|
|
190
179
|
logger: ctx.logger,
|
|
191
180
|
nousClientId: config.nous?.clientId,
|
|
192
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
|
+
}
|
|
193
190
|
const entry = custom.get(provider);
|
|
194
191
|
if (entry === undefined)
|
|
195
192
|
return;
|
|
@@ -206,6 +203,8 @@ export function apply(ctx, config) {
|
|
|
206
203
|
},
|
|
207
204
|
});
|
|
208
205
|
service.api = api;
|
|
206
|
+
for (const catalog of catalogs.values())
|
|
207
|
+
void catalog.start();
|
|
209
208
|
for (const [provider, entry] of custom) {
|
|
210
209
|
void credentialKey(provider).then(key => key === undefined ? undefined : entry.refresh(key))
|
|
211
210
|
.then(count => { if (count !== undefined)
|
|
@@ -225,9 +224,11 @@ export function apply(ctx, config) {
|
|
|
225
224
|
else {
|
|
226
225
|
// Individual registrations: one conflicting route must not strand the
|
|
227
226
|
// rest (the registry keeps the previous owner serving).
|
|
228
|
-
for (const id of
|
|
227
|
+
for (const id of profiles.keys()) {
|
|
229
228
|
try {
|
|
230
|
-
|
|
229
|
+
const owned = catalogs.has(id) ? native : adapter;
|
|
230
|
+
if (owned)
|
|
231
|
+
releases.push(llm.registerAdapter([id], owned));
|
|
231
232
|
}
|
|
232
233
|
catch (error) {
|
|
233
234
|
ctx.logger.error(`dsh-auth: route "${id}" was not registered: ${error instanceof Error ? error.message : String(error)} `
|
|
@@ -243,7 +244,7 @@ export function apply(ctx, config) {
|
|
|
243
244
|
const handler = createAuthCommandHandler(api);
|
|
244
245
|
releases.push(commands.register({
|
|
245
246
|
name: 'auth',
|
|
246
|
-
description: 'Provider authentication: status, login, logout',
|
|
247
|
+
description: 'Provider authentication and catalogs: status, login, logout, models, refresh',
|
|
247
248
|
handler: invocation => {
|
|
248
249
|
const operation = handler(invocation);
|
|
249
250
|
active.add(operation);
|
|
@@ -256,6 +257,8 @@ export function apply(ctx, config) {
|
|
|
256
257
|
// enter while already-started logins finish their final write.
|
|
257
258
|
yield async () => { await Promise.allSettled([...active]); };
|
|
258
259
|
yield () => {
|
|
260
|
+
for (const catalog of catalogs.values())
|
|
261
|
+
catalog.dispose();
|
|
259
262
|
for (const release of releases)
|
|
260
263
|
release();
|
|
261
264
|
};
|