dsh-code 1.0.3 → 1.0.5
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 +293 -285
- package/bin/deepseek.mjs +245 -12
- package/cordis.patch.yml +12 -14
- package/lib/index.mjs +1939 -903
- package/lib/types/app.d.ts +11 -2
- package/lib/types/commands.d.ts +13 -0
- package/lib/types/git-workflow.d.ts +7 -2
- package/lib/types/history.d.ts +18 -11
- package/lib/types/index.d.ts +28 -0
- package/lib/types/input-split.d.ts +54 -0
- package/lib/types/kernel-panels.d.ts +3 -1
- package/lib/types/keyboard.d.ts +8 -0
- package/lib/types/presets.d.ts +4 -1
- package/lib/types/provider-settings.d.ts +77 -0
- package/lib/types/questions.d.ts +16 -12
- package/lib/types/render/projection.d.ts +9 -2
- package/lib/types/render/status.d.ts +22 -15
- package/lib/types/settings-file.d.ts +8 -0
- package/lib/types/skills.d.ts +1 -1
- package/package.json +49 -46
- package/src/app.ts +5459 -4900
- package/src/approval.ts +8 -3
- package/src/authorization-panel.ts +2 -4
- package/src/commands.ts +27 -3
- package/src/git-workflow.ts +29 -10
- package/src/history.ts +22 -13
- package/src/index.ts +203 -61
- package/src/input-split.ts +191 -0
- package/src/internals.ts +26 -8
- package/src/kernel-panels.ts +26 -10
- package/src/keyboard.ts +123 -88
- package/src/mentions.ts +42 -9
- package/src/permissions.ts +1 -1
- package/src/presets.ts +19 -6
- package/src/provider-settings.ts +204 -0
- package/src/questions.ts +58 -55
- package/src/render/export.ts +7 -7
- package/src/render/lines.ts +24 -12
- package/src/render/markdown.ts +15 -13
- package/src/render/projection.ts +101 -13
- package/src/render/status.ts +76 -71
- package/src/render/text.ts +9 -3
- package/src/settings-file.ts +38 -6
- package/src/skills.ts +19 -6
- package/src/theme-panel.ts +79 -72
package/bin/deepseek.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { spawn, spawnSync } from 'node:child_process'
|
|
|
4
4
|
import { existsSync, readFileSync, realpathSync } from 'node:fs'
|
|
5
5
|
import { createRequire } from 'node:module'
|
|
6
6
|
import { homedir } from 'node:os'
|
|
7
|
-
import { join, resolve } from 'node:path'
|
|
7
|
+
import { dirname, join, resolve } from 'node:path'
|
|
8
8
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
9
9
|
|
|
10
10
|
const packageRequire = createRequire(import.meta.url)
|
|
@@ -49,6 +49,81 @@ export function profileHasDshCode(profileDir = cliProfileDir(), fileExists = exi
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/** The dsh-code dependency the cli profile declares (e.g. '1.0.5' or 'link:C:/repo'). */
|
|
53
|
+
export function profileDependencySpec(profileDir = cliProfileDir(), fileExists = existsSync, readFile = readFileSync) {
|
|
54
|
+
const manifest = join(profileDir, 'package.json')
|
|
55
|
+
if (!fileExists(manifest)) return undefined
|
|
56
|
+
try {
|
|
57
|
+
const raw = JSON.parse(readFile(manifest, 'utf8'))
|
|
58
|
+
const spec = raw?.dependencies?.['dsh-code']
|
|
59
|
+
return typeof spec === 'string' ? spec : undefined
|
|
60
|
+
} catch {
|
|
61
|
+
return undefined
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The dsh-code version the cli profile actually resolves and boots. */
|
|
66
|
+
export function profileMountedVersion(profileDir = cliProfileDir(), fileExists = existsSync, readFile = readFileSync) {
|
|
67
|
+
const manifest = join(profileDir, 'node_modules', 'dsh-code', 'package.json')
|
|
68
|
+
if (!fileExists(manifest)) return undefined
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(readFile(manifest, 'utf8'))?.version ?? undefined
|
|
71
|
+
} catch {
|
|
72
|
+
return undefined
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** The harness release line a dsh-code release expects, read from its peers. */
|
|
77
|
+
export function harnessLineFromPeers(peers) {
|
|
78
|
+
if (typeof peers !== 'object' || peers === null) return undefined
|
|
79
|
+
const anchor = peers['@deepseek-ai/dsh-session']
|
|
80
|
+
if (typeof anchor === 'string' && anchor !== '') return anchor
|
|
81
|
+
for (const [name, spec] of Object.entries(peers)) {
|
|
82
|
+
if (name.startsWith('@deepseek-ai/dsh-') && typeof spec === 'string' && spec !== '') return spec
|
|
83
|
+
}
|
|
84
|
+
return undefined
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Decide what `update --apply` installs. The global DSH launcher is pinned
|
|
89
|
+
* to the harness line the target dsh-code release declares in its peers,
|
|
90
|
+
* so the launcher can never move ahead of the plugin it must boot. A
|
|
91
|
+
* profile that mounts a local checkout (link:/file:) keeps its mount.
|
|
92
|
+
*/
|
|
93
|
+
export function updatePlan({ latestCode, peers, profileSpec }) {
|
|
94
|
+
const line = harnessLineFromPeers(peers)
|
|
95
|
+
return {
|
|
96
|
+
dshSpec: line === undefined ? '@deepseek-ai/dsh@latest' : `@deepseek-ai/dsh@${line}`,
|
|
97
|
+
lineLocked: line !== undefined,
|
|
98
|
+
codeSpec: `dsh-code@${latestCode}`,
|
|
99
|
+
profileStep: !(typeof profileSpec === 'string' && /^(link|file):/iu.test(profileSpec)),
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Run wrapper-owned child steps in order, stopping at the first failure. */
|
|
104
|
+
export function runSequence(steps, spawnProcess = spawn) {
|
|
105
|
+
return new Promise(resolve => {
|
|
106
|
+
const run = index => {
|
|
107
|
+
const step = steps[index]
|
|
108
|
+
if (step === undefined) {
|
|
109
|
+
resolve(0)
|
|
110
|
+
return
|
|
111
|
+
}
|
|
112
|
+
const needsShell = process.platform === 'win32' && /\.(cmd|bat)$/iu.test(step.command)
|
|
113
|
+
const child = spawnProcess(step.command, step.args, { stdio: 'inherit', ...(needsShell ? { shell: true } : {}) })
|
|
114
|
+
child.once('error', error => {
|
|
115
|
+
console.error(`dsh-code: ${step.label} failed: ${error.message}`)
|
|
116
|
+
resolve(1)
|
|
117
|
+
})
|
|
118
|
+
child.once('exit', (code, signal) => {
|
|
119
|
+
if (code === 0) run(index + 1)
|
|
120
|
+
else resolve(code ?? 1)
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
run(0)
|
|
124
|
+
})
|
|
125
|
+
}
|
|
126
|
+
|
|
52
127
|
/** Npm global-prefix roots that may contain DSH when this launcher is globally linked to a checkout. */
|
|
53
128
|
export function globalDshRoots() {
|
|
54
129
|
return [...new Set([
|
|
@@ -58,6 +133,12 @@ export function globalDshRoots() {
|
|
|
58
133
|
].filter(Boolean))]
|
|
59
134
|
}
|
|
60
135
|
|
|
136
|
+
/** Convert a file URL to a windows-style path even when resolved on a non-windows host. */
|
|
137
|
+
function fileUrlToWindowsPath(url) {
|
|
138
|
+
const pathname = decodeURIComponent(new URL(url).pathname)
|
|
139
|
+
return pathname.replace(/^\/([A-Za-z]:)/, '$1').replace(/\//g, '\\')
|
|
140
|
+
}
|
|
141
|
+
|
|
61
142
|
/** Resolve the DSH entrypoint without passing user arguments through a Windows shell. */
|
|
62
143
|
export function rawDshCommand(args, {
|
|
63
144
|
platform = process.platform,
|
|
@@ -67,7 +148,9 @@ export function rawDshCommand(args, {
|
|
|
67
148
|
resolvePackage = packageRequire.resolve,
|
|
68
149
|
} = {}) {
|
|
69
150
|
if (platform !== 'win32') return { command: 'dsh', args }
|
|
70
|
-
|
|
151
|
+
// fileURLToPath follows the HOST separator; the win32 target needs a
|
|
152
|
+
// windows-style path regardless of where this resolver itself runs.
|
|
153
|
+
const adjacentEntrypoint = fileUrlToWindowsPath(new URL('../../@deepseek-ai/dsh/lib/bin.js', moduleUrl))
|
|
71
154
|
if (fileExists(adjacentEntrypoint)) return { command: process.execPath, args: [adjacentEntrypoint, ...args] }
|
|
72
155
|
for (const root of roots) {
|
|
73
156
|
try {
|
|
@@ -111,7 +194,12 @@ function printDoctor(resolveCommand = rawDshCommand, spawnCommand = spawnSync) {
|
|
|
111
194
|
}
|
|
112
195
|
|
|
113
196
|
function launchChild(command, args) {
|
|
114
|
-
|
|
197
|
+
// Windows .cmd/.bat shims (npm.cmd) need a shell since Node's
|
|
198
|
+
// CVE-2024-27980 fix rejects spawning them directly with EINVAL. Every
|
|
199
|
+
// launch through here uses fixed, wrapper-owned arguments, so the shell
|
|
200
|
+
// surface adds no injection risk.
|
|
201
|
+
const needsShell = process.platform === 'win32' && /\.(cmd|bat)$/iu.test(command)
|
|
202
|
+
const child = spawn(command, args, { stdio: 'inherit', ...(needsShell ? { shell: true } : {}) })
|
|
115
203
|
child.once('error', error => {
|
|
116
204
|
console.error(`dsh-code: command failed: ${error.message}`)
|
|
117
205
|
process.exitCode = 1
|
|
@@ -120,6 +208,144 @@ function launchChild(command, args) {
|
|
|
120
208
|
return child
|
|
121
209
|
}
|
|
122
210
|
|
|
211
|
+
/**
|
|
212
|
+
* How to invoke npm. The JavaScript entrypoint is preferred: running it
|
|
213
|
+
* with this process's node avoids the Windows .cmd shim, whose shell
|
|
214
|
+
* workaround draws a Node deprecation warning on every call.
|
|
215
|
+
*/
|
|
216
|
+
export function npmInvocation({
|
|
217
|
+
fileExists = existsSync,
|
|
218
|
+
roots = globalDshRoots(),
|
|
219
|
+
resolvePackage = packageRequire.resolve,
|
|
220
|
+
} = {}) {
|
|
221
|
+
const besideNode = join(dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js')
|
|
222
|
+
if (fileExists(besideNode)) return { command: process.execPath, args: [besideNode] }
|
|
223
|
+
for (const root of roots) {
|
|
224
|
+
try {
|
|
225
|
+
const cli = resolvePackage('npm/bin/npm-cli.js', { paths: [root] })
|
|
226
|
+
return { command: process.execPath, args: [cli] }
|
|
227
|
+
} catch {
|
|
228
|
+
// The next configured global prefix may own npm instead.
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return { command: process.platform === 'win32' ? 'npm.cmd' : 'npm', args: [] }
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Read one `npm view` field as JSON, or undefined when the query fails.
|
|
236
|
+
* The subject arrives as argument parts: without a shell, a space inside
|
|
237
|
+
* one argument would reach npm as a single selector and fail.
|
|
238
|
+
*/
|
|
239
|
+
function viewJson(subjectParts, spawnCommand = spawnSync, invocation = npmInvocation()) {
|
|
240
|
+
const needsShell = process.platform === 'win32' && /\.(cmd|bat)$/iu.test(invocation.command)
|
|
241
|
+
const result = spawnCommand(invocation.command, [...invocation.args, 'view', ...subjectParts, '--json'], { encoding: 'utf8', windowsHide: true, ...(needsShell ? { shell: true } : {}) })
|
|
242
|
+
if (result.status !== 0) return undefined
|
|
243
|
+
try {
|
|
244
|
+
return JSON.parse(result.stdout)
|
|
245
|
+
} catch {
|
|
246
|
+
return undefined
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The version of @deepseek-ai/dsh this launcher would boot, when present.
|
|
252
|
+
* Probes the same surfaces rawDshCommand resolves: the adjacent global
|
|
253
|
+
* install first, then every configured npm global prefix.
|
|
254
|
+
*/
|
|
255
|
+
function installedDshVersion({
|
|
256
|
+
platform = process.platform,
|
|
257
|
+
moduleUrl = import.meta.url,
|
|
258
|
+
fileExists = existsSync,
|
|
259
|
+
roots = globalDshRoots(),
|
|
260
|
+
resolvePackage = packageRequire.resolve,
|
|
261
|
+
} = {}) {
|
|
262
|
+
const readVersion = path => {
|
|
263
|
+
try {
|
|
264
|
+
return JSON.parse(readFileSync(path, 'utf8')).version
|
|
265
|
+
} catch {
|
|
266
|
+
return undefined
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
if (platform === 'win32') {
|
|
270
|
+
const adjacent = fileUrlToWindowsPath(new URL('../../@deepseek-ai/dsh/package.json', moduleUrl))
|
|
271
|
+
if (fileExists(adjacent)) return readVersion(adjacent)
|
|
272
|
+
} else {
|
|
273
|
+
try {
|
|
274
|
+
const adjacent = fileURLToPath(new URL('../../@deepseek-ai/dsh/package.json', moduleUrl))
|
|
275
|
+
if (fileExists(adjacent)) return readVersion(adjacent)
|
|
276
|
+
} catch {
|
|
277
|
+
// A non-file URL or an unreadable sibling falls through to the roots.
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const root of roots) {
|
|
281
|
+
try {
|
|
282
|
+
return readVersion(resolvePackage('@deepseek-ai/dsh/package.json', { paths: [root] }))
|
|
283
|
+
} catch {
|
|
284
|
+
// The next configured global prefix may own DSH instead.
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return undefined
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/** Show what is installed, what is latest, and what the cli profile boots. */
|
|
291
|
+
function printUpdateStatus() {
|
|
292
|
+
const codeLatest = viewJson(['dsh-code', 'version'])
|
|
293
|
+
const dshLatest = viewJson(['@deepseek-ai/dsh', 'version'])
|
|
294
|
+
const dshInstalled = installedDshVersion()
|
|
295
|
+
const spec = profileDependencySpec()
|
|
296
|
+
const mounted = profileMountedVersion()
|
|
297
|
+
console.log(`dsh-code: ${packageVersion} (this launcher), latest ${codeLatest ?? 'unknown'}`)
|
|
298
|
+
console.log(`@deepseek-ai/dsh: ${dshInstalled ?? 'not found'} (global), latest ${dshLatest ?? 'unknown'}`)
|
|
299
|
+
console.log(`cli profile: ${mounted !== undefined ? `dsh-code ${mounted}` : spec ?? 'not mounted'}`)
|
|
300
|
+
console.log('Run `deepseek update --apply` to upgrade the global packages and the cli profile together.')
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Upgrade the global launcher and the cli profile plugin together. The
|
|
305
|
+
* global install is pinned to the harness line the new dsh-code release
|
|
306
|
+
* declares, the profile follows through `dsh plugin add` with the same
|
|
307
|
+
* pinned spec, and the mounted version is verified at the end.
|
|
308
|
+
*/
|
|
309
|
+
async function applyUpdate({
|
|
310
|
+
view = viewJson,
|
|
311
|
+
resolveCommand = rawDshCommand,
|
|
312
|
+
spawnProcess = spawn,
|
|
313
|
+
} = {}) {
|
|
314
|
+
const npm = npmInvocation()
|
|
315
|
+
const latestCode = view(['dsh-code', 'version'], undefined, npm)
|
|
316
|
+
if (latestCode === undefined) {
|
|
317
|
+
console.error('dsh-code: could not read the latest dsh-code version from npm')
|
|
318
|
+
process.exitCode = 1
|
|
319
|
+
return
|
|
320
|
+
}
|
|
321
|
+
const peers = view([`dsh-code@${latestCode}`, 'peerDependencies'], undefined, npm)
|
|
322
|
+
const plan = updatePlan({ latestCode, peers, profileSpec: profileDependencySpec() })
|
|
323
|
+
if (!plan.lineLocked) {
|
|
324
|
+
console.log('dsh-code: could not read the compatible harness line; installing @deepseek-ai/dsh@latest')
|
|
325
|
+
}
|
|
326
|
+
const steps = [{ command: npm.command, args: [...npm.args, 'install', '-g', plan.dshSpec, plan.codeSpec], label: 'npm install' }]
|
|
327
|
+
if (plan.profileStep) {
|
|
328
|
+
const command = resolveCommand(['plugin', '--profile', 'cli', 'add', plan.codeSpec])
|
|
329
|
+
if (command === undefined) {
|
|
330
|
+
console.error('dsh-code: could not resolve the dsh command for the profile update')
|
|
331
|
+
process.exitCode = 1
|
|
332
|
+
return
|
|
333
|
+
}
|
|
334
|
+
steps.push({ command: command.command, args: command.args, label: 'dsh plugin add' })
|
|
335
|
+
} else {
|
|
336
|
+
console.log('cli profile mounts a local checkout; leaving the profile untouched')
|
|
337
|
+
}
|
|
338
|
+
const code = await runSequence(steps, spawnProcess)
|
|
339
|
+
const mounted = profileMountedVersion()
|
|
340
|
+
if (mounted !== undefined) console.log(`cli profile now mounts dsh-code ${mounted}`)
|
|
341
|
+
if (code === 0 && plan.profileStep && mounted !== latestCode) {
|
|
342
|
+
console.error(`dsh-code: the cli profile still mounts ${mounted ?? 'nothing'}; run: dsh plugin --profile cli add ${plan.codeSpec}`)
|
|
343
|
+
process.exitCode = 1
|
|
344
|
+
return
|
|
345
|
+
}
|
|
346
|
+
process.exitCode = code
|
|
347
|
+
}
|
|
348
|
+
|
|
123
349
|
/** Run one wrapper-owned operational command. */
|
|
124
350
|
export function launchOperation(args = process.argv.slice(2)) {
|
|
125
351
|
const operation = operationName(args)
|
|
@@ -148,16 +374,14 @@ export function launchOperation(args = process.argv.slice(2)) {
|
|
|
148
374
|
}
|
|
149
375
|
return launchChild(command.command, command.args)
|
|
150
376
|
}
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
377
|
+
if (operation === 'update') {
|
|
378
|
+
if (args.includes('--apply')) {
|
|
379
|
+
void applyUpdate()
|
|
380
|
+
return true
|
|
381
|
+
}
|
|
382
|
+
printUpdateStatus()
|
|
383
|
+
return true
|
|
158
384
|
}
|
|
159
|
-
console.log('Run `deepseek update --apply` to install the latest versions.')
|
|
160
|
-
return true
|
|
161
385
|
}
|
|
162
386
|
|
|
163
387
|
/** Launch the installed DSH CLI while preserving its exit status and stdio. */
|
|
@@ -166,12 +390,21 @@ export function launchDsh(
|
|
|
166
390
|
spawnProcess = spawn,
|
|
167
391
|
resolveCommand = dshCommand,
|
|
168
392
|
isProfileReady = profileHasDshCode,
|
|
393
|
+
isInteractiveStdin = () => process.stdin.isTTY === true,
|
|
169
394
|
) {
|
|
170
395
|
if (!isProfileReady()) {
|
|
171
396
|
console.error('dsh-code: the cli profile does not mount dsh-code yet. Run: dsh plugin --profile cli add dsh-code')
|
|
172
397
|
process.exitCode = 1
|
|
173
398
|
return undefined
|
|
174
399
|
}
|
|
400
|
+
// The interactive TUI is a raw-mode terminal application: with piped or
|
|
401
|
+
// otherwise non-TTY stdin it would die deep inside Ink's raw-mode gate
|
|
402
|
+
// with a cryptic stack. Fail here with one actionable line instead.
|
|
403
|
+
if (!isInteractiveStdin()) {
|
|
404
|
+
console.error('dsh-code: this terminal UI requires an interactive TTY on stdin; run it in a real terminal instead of a pipe')
|
|
405
|
+
process.exitCode = 1
|
|
406
|
+
return undefined
|
|
407
|
+
}
|
|
175
408
|
const command = resolveCommand(args)
|
|
176
409
|
if (command === undefined) {
|
|
177
410
|
console.error('dsh-code: @deepseek-ai/dsh must be installed globally beside dsh-code; run: npm install -g @deepseek-ai/dsh dsh-code')
|
package/cordis.patch.yml
CHANGED
|
@@ -40,6 +40,8 @@
|
|
|
40
40
|
disabled: true
|
|
41
41
|
- id: tool-skill
|
|
42
42
|
disabled: true
|
|
43
|
+
- id: command-goal
|
|
44
|
+
disabled: true
|
|
43
45
|
- id: tool-goal
|
|
44
46
|
disabled: true
|
|
45
47
|
- id: plan-mode
|
|
@@ -68,15 +70,9 @@
|
|
|
68
70
|
disabled: true
|
|
69
71
|
- id: tool-todo
|
|
70
72
|
disabled: true
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
# (web-fetch-http below) needs no API key. The per-preset tool-web rows
|
|
75
|
-
# keep `fetch: false` on the agent plane; through the scope-layered tool
|
|
76
|
-
# registry the preset's web_search shadows the host's same-name tool while
|
|
77
|
-
# the host's web_fetch stays visible, so every model still sees both.
|
|
78
|
-
fetch: true
|
|
79
|
-
searchTimeoutMs: 60000
|
|
73
|
+
# tool-web keeps the 0.1.2-rc.1 base default (web_fetch enabled over the
|
|
74
|
+
# bundled web-fetch-http provider): the host row exposes web_fetch while the
|
|
75
|
+
# per-preset agent-plane rows keep their own fetch stance.
|
|
80
76
|
|
|
81
77
|
- insert:
|
|
82
78
|
# Code Mode is a core execution capability, not a Web component.
|
|
@@ -111,11 +107,13 @@
|
|
|
111
107
|
- id: cordis-host-runner
|
|
112
108
|
name: '@deepseek-ai/dsh-cordis-host-runner'
|
|
113
109
|
|
|
114
|
-
#
|
|
115
|
-
#
|
|
116
|
-
# this
|
|
117
|
-
|
|
118
|
-
|
|
110
|
+
# Host-owned opt-in the preset delegation tools sample: standard/ptc's
|
|
111
|
+
# tool-subagent rows set `modelSelectionSettings: true`, whose start
|
|
112
|
+
# resolves this service and fails the whole preset mount when absent
|
|
113
|
+
# ("failed to apply loader entry delegation (cordis:group)"). The upstream
|
|
114
|
+
# web-app bundle adds this host row in 0.1.2-rc.1; dsh-base does not ship it.
|
|
115
|
+
- id: subagent-model-selection-settings
|
|
116
|
+
name: '@deepseek-ai/dsh-tool-subagent/model-selection-settings'
|
|
119
117
|
|
|
120
118
|
# Interactive provider authorization. The base bundle supplies the
|
|
121
119
|
# credential store; mounting the neutral authorization seam wakes the
|