@bruc3van/dsh-doctor 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cli.mjs +5 -3
- package/src/doctor.mjs +65 -26
- package/src/i18n.mjs +6 -0
- package/src/repair.mjs +22 -4
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -107,11 +107,13 @@ async function main() {
|
|
|
107
107
|
}
|
|
108
108
|
if (actions.length > 0) {
|
|
109
109
|
let confirmed = options.yes === true
|
|
110
|
-
|
|
110
|
+
const plan = formatRepairPlan(actions, { language, prompt: !confirmed })
|
|
111
|
+
if (confirmed) {
|
|
112
|
+
process.stderr.write(`${plan}\n`)
|
|
113
|
+
} else {
|
|
111
114
|
if (!process.stdin.isTTY) throw new Error('--fix needs an interactive terminal or explicit --yes')
|
|
112
|
-
const prompt = formatRepairPlan(actions, { language })
|
|
113
115
|
const reader = createInterface({ input: process.stdin, output: process.stderr })
|
|
114
|
-
const answer = await reader.question(
|
|
116
|
+
const answer = await reader.question(plan)
|
|
115
117
|
reader.close()
|
|
116
118
|
confirmed = /^(?:y(?:es)?|是|确认)$/i.test(answer.trim())
|
|
117
119
|
}
|
package/src/doctor.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { accessSync, constants, existsSync, readFileSync, readdirSync, realpathSync, statSync } from 'node:fs'
|
|
2
|
+
import { builtinModules } from 'node:module'
|
|
2
3
|
import { homedir } from 'node:os'
|
|
3
4
|
import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'
|
|
4
5
|
import yaml from 'js-yaml'
|
|
@@ -16,6 +17,7 @@ export const PLATFORM_MODULES = new Set([
|
|
|
16
17
|
'@deepseek-ai/dsh-client-ui-slots',
|
|
17
18
|
'@deepseek-ai/dsh-client-ui-primitives',
|
|
18
19
|
])
|
|
20
|
+
const BUILTIN_MODULES = new Set(builtinModules.map(name => name.replace(/^node:/, '')))
|
|
19
21
|
|
|
20
22
|
const SEVERITY_ORDER = { error: 0, warning: 1, info: 2 }
|
|
21
23
|
const JS_EXPRESSION = new yaml.Type('tag:yaml.org,2002:js', {
|
|
@@ -71,6 +73,7 @@ function readJson(file, subject, findings) {
|
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
function packagePathParts(name) {
|
|
76
|
+
if (typeof name !== 'string') return undefined
|
|
74
77
|
if (name.startsWith('@')) {
|
|
75
78
|
const parts = name.split('/')
|
|
76
79
|
return parts.length === 2
|
|
@@ -94,7 +97,7 @@ function packageManifestAt(directory, expectedName, findings, source) {
|
|
|
94
97
|
suggestion: 'Reinstall the dependency so its directory and package name agree.',
|
|
95
98
|
}))
|
|
96
99
|
}
|
|
97
|
-
return { directory, file, manifest }
|
|
100
|
+
return { directory, file, manifest, requestedName: expectedName }
|
|
98
101
|
}
|
|
99
102
|
|
|
100
103
|
function findHarnessRoot(start) {
|
|
@@ -118,6 +121,14 @@ function executable(file) {
|
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
123
|
|
|
124
|
+
function regularFile(file) {
|
|
125
|
+
try {
|
|
126
|
+
return statSync(file).isFile()
|
|
127
|
+
} catch {
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
121
132
|
function executableOnPath(name, env) {
|
|
122
133
|
const path = env.PATH ?? env.Path ?? env.path ?? ''
|
|
123
134
|
const extensions = process.platform === 'win32'
|
|
@@ -168,10 +179,10 @@ function commandFromValue(value, env, cwd) {
|
|
|
168
179
|
: value
|
|
169
180
|
const looksLikePath = isAbsolute(expanded) || expanded.includes('/') || expanded.includes('\\') || expanded.startsWith('.')
|
|
170
181
|
const file = looksLikePath ? resolve(cwd, expanded) : executableOnPath(expanded, env)
|
|
171
|
-
if (file === undefined
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
182
|
+
if (file === undefined) return undefined
|
|
183
|
+
if (!regularFile(file)) return undefined
|
|
184
|
+
if (/\.(?:c?js|mjs)$/i.test(file)) return { command: [process.execPath, file], path: file }
|
|
185
|
+
return executable(file) ? { command: [file], path: file } : undefined
|
|
175
186
|
}
|
|
176
187
|
|
|
177
188
|
function resolveDshCli(options, harness, home) {
|
|
@@ -242,7 +253,14 @@ function indexWorkspace(root, findings) {
|
|
|
242
253
|
for (const directory of workspacePackageDirectories(root)) {
|
|
243
254
|
const file = join(directory, 'package.json')
|
|
244
255
|
if (!existsSync(file)) continue
|
|
245
|
-
const
|
|
256
|
+
const manifestFindings = []
|
|
257
|
+
const manifest = readJson(file, 'Harness workspace package manifest', manifestFindings)
|
|
258
|
+
for (const item of manifestFindings) {
|
|
259
|
+
findings.push(finding('warning', 'INVALID_WORKSPACE_MANIFEST', 'A Harness workspace package manifest was ignored because it is invalid.', {
|
|
260
|
+
evidence: item.evidence ?? file,
|
|
261
|
+
suggestion: 'Repair this workspace package manifest to include it in compatibility checks.',
|
|
262
|
+
}))
|
|
263
|
+
}
|
|
246
264
|
if (typeof manifest?.name === 'string') packages.set(manifest.name, { directory, file, manifest })
|
|
247
265
|
}
|
|
248
266
|
return packages
|
|
@@ -256,10 +274,10 @@ function resolveHarnessContext(home, explicitRoot, findings) {
|
|
|
256
274
|
evidence: root,
|
|
257
275
|
suggestion: 'Pass the DeepSeek Harness repository root to --harness-root.',
|
|
258
276
|
}))
|
|
259
|
-
return { root, packages: new Map(), version: undefined, authoritative:
|
|
277
|
+
return { root, packages: new Map(), version: undefined, authoritative: false }
|
|
260
278
|
}
|
|
261
279
|
const manifest = readJson(join(root, 'package.json'), 'Harness root manifest', findings)
|
|
262
|
-
return { root, packages: indexWorkspace(root, findings), version: manifest?.version, authoritative:
|
|
280
|
+
return { root, packages: indexWorkspace(root, findings), version: manifest?.version, authoritative: manifest !== undefined }
|
|
263
281
|
}
|
|
264
282
|
|
|
265
283
|
const sharedDsh = join(home, 'profiles', 'node_modules', '@deepseek-ai', 'dsh')
|
|
@@ -301,8 +319,9 @@ function packageResolver(profileDir, home, harnessPackages, findings) {
|
|
|
301
319
|
return resolved
|
|
302
320
|
}
|
|
303
321
|
const workspace = harnessPackages.get(name)
|
|
304
|
-
|
|
305
|
-
|
|
322
|
+
const resolved = workspace === undefined ? undefined : { ...workspace, requestedName: name }
|
|
323
|
+
cache.set(name, resolved)
|
|
324
|
+
return resolved
|
|
306
325
|
}
|
|
307
326
|
}
|
|
308
327
|
|
|
@@ -346,6 +365,7 @@ function dependencyEntries(value, field, file, findings) {
|
|
|
346
365
|
}
|
|
347
366
|
|
|
348
367
|
function updateRepair(profile, name, commandRepair) {
|
|
368
|
+
if (packagePathParts(name) === undefined) return undefined
|
|
349
369
|
return commandRepair(
|
|
350
370
|
`update-package:${name}`,
|
|
351
371
|
`Update ${name} in profile ${profile}.`,
|
|
@@ -365,11 +385,11 @@ function safePackageFile(packageDir, exported) {
|
|
|
365
385
|
export function extractStaticRequires(source) {
|
|
366
386
|
const values = new Set()
|
|
367
387
|
const code = codePositions(source)
|
|
368
|
-
const pattern =
|
|
388
|
+
const pattern = /(?<![\w$.])require\s*\(\s*(['"])([^'"\\\r\n]+)\1\s*\)/g
|
|
369
389
|
for (const match of source.matchAll(pattern)) {
|
|
370
390
|
if (!code[match.index]) continue
|
|
371
391
|
const specifier = match[2]
|
|
372
|
-
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('node:')) continue
|
|
392
|
+
if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('node:') || BUILTIN_MODULES.has(specifier)) continue
|
|
373
393
|
if (packagePathParts(specifier) !== undefined || specifier.startsWith('@')) values.add(specifier)
|
|
374
394
|
}
|
|
375
395
|
return [...values].sort()
|
|
@@ -424,7 +444,7 @@ function inspectClientPackage(record, context) {
|
|
|
424
444
|
const {
|
|
425
445
|
commandRepair, findings, harnessPackages, harnessPackagesAuthoritative, profile, resolvePackage,
|
|
426
446
|
} = context
|
|
427
|
-
const name = record.manifest.name
|
|
447
|
+
const name = record.requestedName ?? record.manifest.name
|
|
428
448
|
const disableSuggestion = `Upgrade ${name}; if no compatible release exists, remove it through the same DSH installation.`
|
|
429
449
|
const declaration = record.manifest?.dsh?.client
|
|
430
450
|
if (declaration === undefined) return
|
|
@@ -486,7 +506,7 @@ function inspectClientPackage(record, context) {
|
|
|
486
506
|
return
|
|
487
507
|
}
|
|
488
508
|
const file = safePackageFile(record.directory, exported)
|
|
489
|
-
if (file === undefined || !
|
|
509
|
+
if (file === undefined || !regularFile(file)) {
|
|
490
510
|
findings.push(finding('error', 'CLIENT_BUNDLE_MISSING', `${name} client bundle is missing.`, {
|
|
491
511
|
package: name,
|
|
492
512
|
evidence: file ?? `${record.file}: exports["./client"] = ${JSON.stringify(exported)}`,
|
|
@@ -587,7 +607,7 @@ function inspectBundle(name, record, findings) {
|
|
|
587
607
|
return
|
|
588
608
|
}
|
|
589
609
|
const file = safePackageFile(record.directory, patch)
|
|
590
|
-
if (file === undefined || !
|
|
610
|
+
if (file === undefined || !regularFile(file)) {
|
|
591
611
|
findings.push(finding('error', 'BUNDLE_PATCH_MISSING', `${name} bundle patch is missing.`, {
|
|
592
612
|
package: name,
|
|
593
613
|
evidence: file ?? `${record.file}: dsh.bundle.patch = ${JSON.stringify(patch)}`,
|
|
@@ -699,18 +719,19 @@ function inspectCompatibility(record, context) {
|
|
|
699
719
|
mismatches.push(`${name} ${range} (active ${version})`)
|
|
700
720
|
}
|
|
701
721
|
if (mismatches.length > 0) {
|
|
702
|
-
|
|
703
|
-
|
|
722
|
+
const name = record.requestedName ?? record.manifest.name
|
|
723
|
+
findings.push(finding('warning', 'HARNESS_PEER_VERSION_MISMATCH', `${name} has Harness peer ranges that do not accept the active versions.`, {
|
|
724
|
+
package: name,
|
|
704
725
|
evidence: mismatches.join(', '),
|
|
705
|
-
suggestion: `Update ${
|
|
706
|
-
repair: updateRepair(profile,
|
|
726
|
+
suggestion: `Update ${name} to a release compatible with the active Harness.`,
|
|
727
|
+
repair: updateRepair(profile, name, commandRepair),
|
|
707
728
|
}))
|
|
708
729
|
}
|
|
709
730
|
}
|
|
710
731
|
|
|
711
732
|
export function defaultDshHome(env = process.env) {
|
|
712
|
-
const configured = env.DSH_HOME
|
|
713
|
-
if (configured !== undefined && configured.
|
|
733
|
+
const configured = env.DSH_HOME?.trim()
|
|
734
|
+
if (configured !== undefined && configured.length > 0) {
|
|
714
735
|
if (configured === '~') return homedir()
|
|
715
736
|
if (configured.startsWith('~/') || configured.startsWith('~\\')) return resolve(homedir(), configured.slice(2))
|
|
716
737
|
return resolve(configured)
|
|
@@ -759,15 +780,32 @@ export function diagnose(options = {}) {
|
|
|
759
780
|
const resolveBundle = bundleResolver(profileDir, home, harness.packages, findings)
|
|
760
781
|
const dependencyEntriesList = dependencyEntries(profileManifest.dependencies, 'dependencies', profileManifestFile, findings)
|
|
761
782
|
const dependencyNames = dependencyEntriesList.map(([name]) => name)
|
|
762
|
-
const
|
|
783
|
+
const dshConfig = profileManifest.dsh
|
|
784
|
+
const dshConfigValid = dshConfig === undefined || objectRecord(dshConfig) !== undefined
|
|
785
|
+
if (!dshConfigValid) {
|
|
786
|
+
findings.push(finding('error', 'INVALID_DSH_CONFIGURATION', 'dsh must be an object when present.', {
|
|
787
|
+
evidence: profileManifestFile,
|
|
788
|
+
suggestion: 'Repair the dsh configuration object before starting Harness.',
|
|
789
|
+
}))
|
|
790
|
+
}
|
|
791
|
+
const profileConfigValue = objectRecord(dshConfig)?.profile
|
|
792
|
+
const profileConfigValid = profileConfigValue === undefined || objectRecord(profileConfigValue) !== undefined
|
|
793
|
+
if (dshConfigValid && !profileConfigValid) {
|
|
794
|
+
findings.push(finding('error', 'INVALID_PROFILE_CONFIGURATION', 'dsh.profile must be an object when present.', {
|
|
795
|
+
evidence: profileManifestFile,
|
|
796
|
+
suggestion: 'Repair the dsh.profile configuration object before starting Harness.',
|
|
797
|
+
}))
|
|
798
|
+
}
|
|
799
|
+
const profileConfig = objectRecord(profileConfigValue)
|
|
800
|
+
const bundles = profileConfig?.bundles
|
|
763
801
|
if (bundles !== undefined && (!Array.isArray(bundles) || !bundles.every(item => typeof item === 'string'))) {
|
|
764
802
|
findings.push(finding('error', 'INVALID_BUNDLE_LIST', 'dsh.profile.bundles must be a string array.', {
|
|
765
803
|
evidence: profileManifestFile,
|
|
766
804
|
suggestion: 'Repair the profile manifest before starting Harness.',
|
|
767
805
|
}))
|
|
768
806
|
}
|
|
769
|
-
const bundleNames = Array.isArray(bundles) ? bundles.filter(item => typeof item === 'string') : []
|
|
770
|
-
const patchReload =
|
|
807
|
+
const bundleNames = Array.isArray(bundles) ? [...new Set(bundles.filter(item => typeof item === 'string'))] : []
|
|
808
|
+
const patchReload = profileConfig?.patchReload
|
|
771
809
|
if (patchReload !== undefined && patchReload !== 'live' && patchReload !== 'startup') {
|
|
772
810
|
findings.push(finding('error', 'INVALID_PATCH_RELOAD', 'dsh.profile.patchReload must be "live" or "startup".', {
|
|
773
811
|
evidence: profileManifestFile,
|
|
@@ -818,7 +856,8 @@ export function diagnose(options = {}) {
|
|
|
818
856
|
),
|
|
819
857
|
}))
|
|
820
858
|
}
|
|
821
|
-
if (
|
|
859
|
+
if (dshConfigValid && profileConfigValid
|
|
860
|
+
&& record.manifest?.dsh?.bundle?.patch !== undefined && !bundleNames.includes(name)) {
|
|
822
861
|
findings.push(finding('warning', 'INSTALLED_BUNDLE_INACTIVE', `${name} is installed as a bundle but is absent from dsh.profile.bundles.`, {
|
|
823
862
|
package: name,
|
|
824
863
|
evidence: profileManifestFile,
|
|
@@ -871,7 +910,7 @@ export function diagnose(options = {}) {
|
|
|
871
910
|
? { available: false, commandRepairNeeded }
|
|
872
911
|
: { available: true, commandRepairNeeded, ...dshCli },
|
|
873
912
|
packages: thirdPartyRecords.map(record => ({
|
|
874
|
-
name: record.manifest.name,
|
|
913
|
+
name: record.requestedName ?? record.manifest.name,
|
|
875
914
|
version: record.manifest.version,
|
|
876
915
|
directory: record.directory,
|
|
877
916
|
client: record.manifest?.dsh?.client !== undefined,
|
package/src/i18n.mjs
CHANGED
|
@@ -58,6 +58,7 @@ const ZH_MESSAGES = {
|
|
|
58
58
|
INVALID_JSON: item => `${captured(item.message, /^(.+) is not valid JSON\.$/) ?? '该文件'}不是有效的 JSON。`,
|
|
59
59
|
PACKAGE_NAME_MISMATCH: item => `${item.package ?? '依赖'}解析到了名称不匹配的包。`,
|
|
60
60
|
INVALID_HARNESS_ROOT: () => '指定的 Harness 根目录不是有效的源码工作区。',
|
|
61
|
+
INVALID_WORKSPACE_MANIFEST: () => '已忽略一个无效的 Harness workspace 包清单。',
|
|
61
62
|
HARNESS_INSTALLATION_UNKNOWN: () => '无法定位这个 DSH Home 实际使用的 Harness。',
|
|
62
63
|
INVALID_DEPENDENCY_MAP: item => `${captured(item.message, /^(\S+) must be/) ?? '依赖字段'}必须是“包名到版本范围”的对象。`,
|
|
63
64
|
INVALID_CLIENT_DECLARATION: item => `${item.package} 的 dsh.client 声明无效。`,
|
|
@@ -86,6 +87,8 @@ const ZH_MESSAGES = {
|
|
|
86
87
|
HARNESS_PEER_VERSION_MISMATCH: item => `${item.package} 声明的 Harness peer 版本范围不接受当前已安装版本。`,
|
|
87
88
|
INVALID_PROFILE_NAME: item => `Profile 名称无效:${captured(item.message, /^Invalid profile name (.+)\.$/) ?? ''}`,
|
|
88
89
|
PROFILE_NOT_FOUND: item => `Profile ${captured(item.message, /^Profile (.+) does not exist\.$/) ?? ''} 不存在。`,
|
|
90
|
+
INVALID_DSH_CONFIGURATION: () => 'dsh 字段存在时必须是对象。',
|
|
91
|
+
INVALID_PROFILE_CONFIGURATION: () => 'dsh.profile 字段存在时必须是对象。',
|
|
89
92
|
INVALID_BUNDLE_LIST: () => 'dsh.profile.bundles 必须是字符串数组。',
|
|
90
93
|
INVALID_PATCH_RELOAD: () => 'dsh.profile.patchReload 必须是 “live” 或 “startup”。',
|
|
91
94
|
DEPENDENCY_NOT_INSTALLED: item => `Profile 依赖 ${item.package} 尚未安装。`,
|
|
@@ -98,6 +101,7 @@ const ZH_SUGGESTIONS = {
|
|
|
98
101
|
INVALID_JSON: () => '启动该 profile 前,请先修复 JSON。',
|
|
99
102
|
PACKAGE_NAME_MISMATCH: () => '重新安装依赖,使目录位置与包名一致。',
|
|
100
103
|
INVALID_HARNESS_ROOT: () => '诊断源码工作区时,请把 DeepSeek Harness 仓库根目录传给 --harness-root。',
|
|
104
|
+
INVALID_WORKSPACE_MANIFEST: () => '修复该 workspace 包清单后,Doctor 才能把它纳入兼容性检查。',
|
|
101
105
|
HARNESS_INSTALLATION_UNKNOWN: () => '若使用源码工作区,请通过 --harness-root 明确指定;若使用独立 CLI,请通过 --dsh-command 指定。',
|
|
102
106
|
INVALID_DEPENDENCY_MAP: () => '管理或启动 profile 前,请先修复这个依赖字段。',
|
|
103
107
|
INVALID_CLIENT_DECLARATION: update,
|
|
@@ -123,6 +127,8 @@ const ZH_SUGGESTIONS = {
|
|
|
123
127
|
INVALID_CREDENTIALS_LAYOUT: () => '迁移文档结构,不要暴露或修改秘密值。',
|
|
124
128
|
HARNESS_PEER_VERSION_MISMATCH: item => `把 ${item.package} 更新到兼容当前 Harness 的版本。`,
|
|
125
129
|
PROFILE_NOT_FOUND: () => '先启动一次该 profile,或用当前 DSH 安装初始化它。',
|
|
130
|
+
INVALID_DSH_CONFIGURATION: () => '启动 Harness 前,请先修复 dsh 配置对象。',
|
|
131
|
+
INVALID_PROFILE_CONFIGURATION: () => '启动 Harness 前,请先修复 dsh.profile 配置对象。',
|
|
126
132
|
INVALID_BUNDLE_LIST: () => '启动 Harness 前,请修复 profile manifest。',
|
|
127
133
|
INVALID_PATCH_RELOAD: () => '选择该 profile 需要的 reload 生命周期。',
|
|
128
134
|
DEPENDENCY_NOT_INSTALLED: () => '使用下方精确命令安装该 profile 声明的依赖。',
|
package/src/repair.mjs
CHANGED
|
@@ -34,7 +34,10 @@ export function formatRepairPlan(actions, options = {}) {
|
|
|
34
34
|
} else lines.push(` ${zh ? '文件' : 'File'}: ${action.file}`, ` ${zh ? '备份' : 'Backup'}: ${action.file}.dsh-doctor-<timestamp>.bak`)
|
|
35
35
|
lines.push('')
|
|
36
36
|
})
|
|
37
|
-
|
|
37
|
+
const plan = lines.join('\n')
|
|
38
|
+
return options.prompt === false
|
|
39
|
+
? plan.trimEnd()
|
|
40
|
+
: `${plan}${zh ? '执行这些修复吗?[y/N] ' : 'Apply these repairs? [y/N] '}`
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
function localizedDescription(action, zh) {
|
|
@@ -56,8 +59,19 @@ function applyJsonEdit(action) {
|
|
|
56
59
|
}
|
|
57
60
|
const manifest = JSON.parse(current)
|
|
58
61
|
if (action.operation.type !== 'add-bundle') throw new Error(`unsupported JSON repair ${action.operation.type}`)
|
|
59
|
-
|
|
60
|
-
if (
|
|
62
|
+
if (manifest.dsh === undefined) manifest.dsh = {}
|
|
63
|
+
if (manifest.dsh === null || typeof manifest.dsh !== 'object' || Array.isArray(manifest.dsh)) {
|
|
64
|
+
throw new Error(`${action.file} no longer has a valid dsh object`)
|
|
65
|
+
}
|
|
66
|
+
if (manifest.dsh.profile === undefined) manifest.dsh.profile = {}
|
|
67
|
+
if (manifest.dsh.profile === null || typeof manifest.dsh.profile !== 'object' || Array.isArray(manifest.dsh.profile)) {
|
|
68
|
+
throw new Error(`${action.file} no longer has a valid dsh.profile object`)
|
|
69
|
+
}
|
|
70
|
+
if (manifest.dsh.profile.bundles === undefined) manifest.dsh.profile.bundles = []
|
|
71
|
+
const bundles = manifest.dsh.profile.bundles
|
|
72
|
+
if (!Array.isArray(bundles) || !bundles.every(item => typeof item === 'string')) {
|
|
73
|
+
throw new Error(`${action.file} no longer has a valid dsh.profile.bundles array`)
|
|
74
|
+
}
|
|
61
75
|
if (!bundles.includes(action.operation.name)) bundles.push(action.operation.name)
|
|
62
76
|
const stamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
63
77
|
const backup = `${action.file}.dsh-doctor-${stamp}.bak`
|
|
@@ -75,7 +89,11 @@ function applyCommand(action) {
|
|
|
75
89
|
env: action.env === undefined ? process.env : { ...process.env, ...action.env },
|
|
76
90
|
})
|
|
77
91
|
if (result.error != null) throw result.error
|
|
78
|
-
if (result.status !== 0)
|
|
92
|
+
if (result.status !== 0) {
|
|
93
|
+
throw new Error(result.signal === null
|
|
94
|
+
? `${command} exited with status ${String(result.status)}`
|
|
95
|
+
: `${command} was terminated by signal ${result.signal}`)
|
|
96
|
+
}
|
|
79
97
|
return { id: action.id, status: 'applied' }
|
|
80
98
|
}
|
|
81
99
|
|