返回源码地图

apps/cli/src/plugin.ts

main snapshot · da00f7f5358f · 正文引用章节 04;完整原文可核对,不声称全文件人工逐行审计

完整原文供逐行核对;页面收录不代表每行都经过人工语义审核。MIT 许可见 许可证。

1/** Profile package management and explicit, exact-version compatibility approvals. */
2import { runPluginCommand, runProfilePnpm, setProfileVersionExemption, type PackageOperationOptions } from '@deepseek-ai/dsh-plugin-manager/operations'
3import { INSTALL_ANCHOR } from './profile-boot.ts'
4import { DEFAULT_PROFILE_BUNDLES, initProfile, PROFILE_TEMPLATES, readProfileCompatibility, resolveProfileDir, type ProfileContext } from '@deepseek-ai/dsh-app-boot'
5import { withFileLock } from '@deepseek-ai/dsh-atomic-write'
6import { existsSync } from 'node:fs'
7import { mkdir } from 'node:fs/promises'
8import { join } from 'node:path'
9
10function requireDesktopProfile(dir: string): void {
11 if (!existsSync(join(dir, 'package.json'))) {
12 throw new Error('Open DeepSeek Harness Desktop once to initialize its profile, then fully quit it before running dsh plugin --profile desktop.')
13 }
14}
15
16/** Parse only DSH-owned commands; all other arguments remain pnpm's responsibility. */
17async function versionCommand(profile: string, args: readonly string[]): Promise<number | undefined> {
18 const [command, ...rest] = args
19 if (command !== 'allow-version' && command !== 'revoke-version' && command !== 'version-exemptions') return undefined
20 try {
21 let packageVersion: string | undefined
22 let runtimeVersion: string | undefined
23 let acceptRisk = false
24 const argumentsIterator = rest.values()
25 for (const argument of argumentsIterator) {
26 if (argument === '--accept-risk' && command === 'allow-version' && !acceptRisk) acceptRisk = true
27 else if (argument === '--dsh-version' && runtimeVersion === undefined) runtimeVersion = argumentsIterator.next().value
28 else if (argument.startsWith('--dsh-version=') && runtimeVersion === undefined) runtimeVersion = argument.slice('--dsh-version='.length)
29 else if (!argument.startsWith('-') && packageVersion === undefined) packageVersion = argument
30 else throw new Error(`unexpected argument ${JSON.stringify(argument)}`)
31 }
32 if (command === 'version-exemptions' && rest.length > 0) throw new Error('usage: dsh plugin version-exemptions')
33 let request: { packageVersion: string; runtimeVersion: string } | undefined
34 if (command !== 'version-exemptions') {
35 if (packageVersion === undefined || runtimeVersion === undefined) {
36 throw new Error(`usage: dsh plugin ${command} <package@version> --dsh-version <exact>${command === 'allow-version' ? ' --accept-risk' : ''}`)
37 }
38 request = { packageVersion, runtimeVersion }
39 }
40 if (command === 'allow-version') {
41 process.stderr.write('dsh: warning: allowing incompatible plugin versions can break the application or corrupt data. Approval applies only to the exact package and DSH versions.\n')
42 }
43 const dir = resolveProfileDir(profile)
44 if (profile !== 'desktop') await mkdir(dir, { recursive: true })
45 await withFileLock(join(dir, 'package.json'), async () => {
46 if (profile === 'desktop') requireDesktopProfile(dir)
47 else if (!existsSync(join(dir, 'package.json'))) initProfile(dir, PROFILE_TEMPLATES[profile]?.bundles ?? DEFAULT_PROFILE_BUNDLES)
48 if (request === undefined) {
49 const { exemptions, warnings } = readProfileCompatibility(dir)
50 for (const warning of warnings) process.stderr.write(`dsh: warning: ${warning}\n`)
51 process.stdout.write(JSON.stringify(exemptions, undefined, 2) + '\n')
52 } else {
53 await setProfileVersionExemption(dir, request.packageVersion, request.runtimeVersion, command === 'allow-version', acceptRisk)
54 process.stdout.write(`dsh: ${command === 'allow-version' ? 'allowed' : 'revoked'} ${request.packageVersion} for DSH ${request.runtimeVersion}\n`)
55 }
56 }, { waitMs: 120000 })
57 return 0
58 } catch (error) {
59 process.stderr.write(`dsh: ${String(error)}\n`)
60 return 1
61 }
62}
63
64/** Run package management for a profile.
65 * @param profile Profile name; Desktop's reserved profile must already be initialized by the application.
66 * @param args DSH exemption command or pnpm arguments relative to the invoking directory.
67 * @param packageManager Installation-owned executable and environment for pnpm operations.
68 * @returns Zero on success; nonzero on invalid approval or package-manager failure.
69 */
70export async function runPlugin(profile: string, args: readonly string[], packageManager?: ProfileContext['packageManager']): Promise<number> {
71 if (profile === 'desktop') {
72 try { requireDesktopProfile(resolveProfileDir(profile)) } catch (error) {
73 process.stderr.write(`dsh: ${String(error)}\n`)
74 return 1
75 }
76 }
77 const versionResult = await versionCommand(profile, args)
78 if (versionResult !== undefined) return versionResult
79 const dir = resolveProfileDir(profile)
80 if (existsSync(join(dir, 'package.json'))) {
81 for (const warning of readProfileCompatibility(dir).warnings) process.stderr.write(`dsh: warning: ${warning}\n`)
82 }
83 const context = { profile, dir, installAnchor: INSTALL_ANCHOR, cwd: process.cwd() }
84 const options: PackageOperationOptions = {
85 ...packageManager,
86 execution: 'cli',
87 outputBytes: 16384,
88 lockWaitMs: 120000,
89 lookupTimeoutMs: 120000,
90 onOutput: (text, stream) => { process[stream].write(text) },
91 }
92 const result = profile === 'desktop'
93 ? await withFileLock(join(dir, 'package.json'), async () => {
94 requireDesktopProfile(dir)
95 return runProfilePnpm(context, args, options)
96 }, { waitMs: 120000 })
97 : await runPluginCommand(context, args, options)
98 if (result.exitCode === 127) process.stderr.write('dsh: pnpm was not found; install pnpm and make it available on PATH.\n')
99 for (const { name, version, runtimeVersion } of result.incompatible ?? []) {
100 process.stderr.write(`dsh: to accept the risk, run: dsh plugin --profile ${profile} allow-version ${name}@${version} --dsh-version ${runtimeVersion} --accept-risk\n`)
101 }
102 if (result.exitCode !== 0) process.stderr.write(`dsh: plugin command failed; diagnostics: ${result.logPath}\n`)
103 if (result.exitCode !== 0 && args.some(argument => /^git\+|^github:|\.git(?:#|$)/.test(argument))) {
104 process.stderr.write(`dsh: git-hosted plugins build on install via their prepare script, which pnpm blocks until allowed — add the exact key pnpm printed above under allowBuilds in ${join(resolveProfileDir(profile), 'pnpm-workspace.yaml')}, then re-run\n`)
105 }
106 return result.exitCode
107}