Skip to content

Commit 2eb711c

Browse files
committed
fix: handle Grok CLI null-status probe
1 parent 3fa2505 commit 2eb711c

2 files changed

Lines changed: 15 additions & 4 deletions

File tree

changelogs/unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ WorkspaceDataAbsorptionScopeGate · DocsSiteVisualAcceptanceGate · OmissionOnly
5858
- 补齐 `uninstall --host grok` 生命周期:复用 `HostAdapterScopeV1`,官方卸载用户插件并只移除 DevCodex 受管配置,保留 workspace source、未知键/注释与重复卸载幂等性。
5959
- 关闭诊断与 launcher 的作用域旁路:从子项目执行 `status/doctor` 也检查工作区 owner;`devcodex grok` 先消费官方 `--cwd`,拒绝 system-prompt override/重复 cwd,并在 root kernel 缺失、nested workspace 或 Windows 路径大小写变体下保持 fail-closed/同一身份。
6060
- 修复无 Grok CLI 环境下 workspace plugin 安装降级路径:仍写入 canonical `plugins.enabled` registration 与 migration receipt,但 installation 保持 `unavailable`,避免 CI/Linux 无 CLI 时 status/doctor 与 host-installation 契约漂移。
61+
- 补强 Grok CLI 探测降级:当 clean Linux/CI 环境返回 `status=null` 且无 stdout/stderr 时,按 CLI 不可用处理并保留 `unavailable` receipt;真实非零 CLI 输出仍 fail,避免 `GROK_PLUGIN_CLI_UNAVAILABLE: null` 逃逸。
6162

6263
### 内部完整交付与用户可见输出契约(2026-07-19)
6364

scripts/lib/host-adapter-scope.js

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,16 @@ function grokHomePath(env = process.env) {
378378
return env.GROK_HOME ? path.resolve(env.GROK_HOME) : path.join(os.homedir(), '.grok')
379379
}
380380

381+
function isGrokCliUnavailableResult(result) {
382+
if (result?.error?.code === 'ENOENT' || result?.error?.code === 'EACCES') return true
383+
return Boolean(result && result.status === null && !result.signal && !result.stdout && !result.stderr)
384+
}
385+
386+
function formatGrokCommandOutput(result) {
387+
const output = String(result?.stderr || result?.stdout || '').trim()
388+
return output || result?.error?.message || 'no output'
389+
}
390+
381391
function readInstalledPluginRegistry(env = process.env) {
382392
const registryFile = path.join(grokHomePath(env), 'installed-plugins', 'registry.json')
383393
if (!fs.existsSync(registryFile)) return { registryFile, value: { version: 1, repos: {} } }
@@ -429,7 +439,7 @@ function inspectGrokPluginInstallation(pluginPath, env = process.env) {
429439
function syncGrokPluginInstallation({ pluginPath, dryRun = false, env = process.env }) {
430440
const source = path.resolve(pluginPath)
431441
const probe = spawnSync('grok', ['version'], { encoding: 'utf8', windowsHide: true, env })
432-
if (probe.error?.code === 'ENOENT') {
442+
if (isGrokCliUnavailableResult(probe)) {
433443
return {
434444
schemaVersion: 'GrokPluginInstallationReceiptV1',
435445
status: 'unavailable',
@@ -439,7 +449,7 @@ function syncGrokPluginInstallation({ pluginPath, dryRun = false, env = process.
439449
}
440450
}
441451
if (probe.status !== 0) {
442-
const error = new Error(`GROK_PLUGIN_CLI_UNAVAILABLE: ${String(probe.stderr || probe.stdout).trim()}`)
452+
const error = new Error(`GROK_PLUGIN_CLI_UNAVAILABLE: ${formatGrokCommandOutput(probe)}`)
443453
error.code = 'GROK_PLUGIN_CLI_UNAVAILABLE'
444454
throw error
445455
}
@@ -584,7 +594,7 @@ function syncGrokWorkspacePluginInstallation({
584594
}
585595

586596
const probe = spawnSync('grok', ['version'], { encoding: 'utf8', windowsHide: true, env })
587-
if (probe.error?.code === 'ENOENT') {
597+
if (isGrokCliUnavailableResult(probe)) {
588598
const configBase = configSnapshot.existed
589599
? configSnapshot.content
590600
: (fs.existsSync(configPath) ? fs.readFileSync(configPath, 'utf8') : '')
@@ -614,7 +624,7 @@ function syncGrokWorkspacePluginInstallation({
614624
}
615625
}
616626
if (probe.status !== 0) {
617-
const error = new Error(`GROK_PLUGIN_CLI_UNAVAILABLE: ${String(probe.stderr || probe.stdout).trim()}`)
627+
const error = new Error(`GROK_PLUGIN_CLI_UNAVAILABLE: ${formatGrokCommandOutput(probe)}`)
618628
error.code = 'GROK_PLUGIN_CLI_UNAVAILABLE'
619629
throw error
620630
}

0 commit comments

Comments
 (0)