helloagents 3.0.33 → 3.0.37

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.
Files changed (66) hide show
  1. package/.claude-plugin/marketplace.json +1 -4
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/.codex-plugin/plugin.json +3 -4
  4. package/README.md +78 -74
  5. package/README_CN.md +78 -74
  6. package/bootstrap-lite.md +9 -11
  7. package/bootstrap.md +21 -23
  8. package/gemini-extension.json +1 -1
  9. package/install.ps1 +27 -4
  10. package/install.sh +27 -3
  11. package/package.json +2 -2
  12. package/scripts/capability-registry.mjs +5 -3
  13. package/scripts/cli-doctor-codex.mjs +153 -1
  14. package/scripts/cli-doctor-render.mjs +2 -1
  15. package/scripts/cli-doctor.mjs +3 -3
  16. package/scripts/cli-hosts.mjs +1 -1
  17. package/scripts/cli-lifecycle-hosts.mjs +124 -54
  18. package/scripts/cli-lifecycle.mjs +50 -15
  19. package/scripts/cli-messages.mjs +7 -7
  20. package/scripts/cli-runtime-root.mjs +9 -1
  21. package/scripts/delivery-gate-messages.mjs +5 -4
  22. package/scripts/delivery-gate.mjs +11 -22
  23. package/scripts/guard.mjs +1 -1
  24. package/scripts/notify-closeout.mjs +61 -22
  25. package/scripts/notify-context.mjs +5 -5
  26. package/scripts/notify-route.mjs +1 -1
  27. package/scripts/notify-sound.mjs +2 -1
  28. package/scripts/notify.mjs +2 -2
  29. package/scripts/plan-contract.mjs +10 -14
  30. package/scripts/project-session-cleanup.mjs +91 -31
  31. package/scripts/qa-review-state.mjs +313 -0
  32. package/scripts/ralph-loop.mjs +32 -13
  33. package/scripts/runtime-artifacts.mjs +2 -2
  34. package/scripts/runtime-scope.mjs +14 -13
  35. package/scripts/runtime-ttl.mjs +7 -4
  36. package/scripts/session-capsule.mjs +75 -13
  37. package/scripts/session-token.mjs +44 -9
  38. package/scripts/state-document.mjs +77 -0
  39. package/scripts/workflow-core.mjs +13 -19
  40. package/scripts/workflow-plan-files.mjs +1 -1
  41. package/scripts/workflow-recommendation.mjs +55 -67
  42. package/scripts/workflow-state.mjs +8 -8
  43. package/skills/commands/auto/SKILL.md +12 -12
  44. package/skills/commands/build/SKILL.md +9 -10
  45. package/skills/commands/commit/SKILL.md +1 -1
  46. package/skills/commands/help/SKILL.md +11 -13
  47. package/skills/commands/init/SKILL.md +18 -9
  48. package/skills/commands/loop/SKILL.md +70 -96
  49. package/skills/commands/plan/SKILL.md +7 -8
  50. package/skills/commands/prd/SKILL.md +3 -3
  51. package/skills/commands/qa/SKILL.md +49 -0
  52. package/skills/hello-ui/SKILL.md +3 -3
  53. package/skills/helloagents/SKILL.md +11 -14
  54. package/skills/qa-review/SKILL.md +92 -0
  55. package/templates/plans/contract.json +4 -7
  56. package/templates/plans/plan.md +1 -1
  57. package/templates/plans/tasks.md +1 -1
  58. package/templates/verify.yaml +1 -1
  59. package/scripts/review-state.mjs +0 -193
  60. package/scripts/verify-state.mjs +0 -175
  61. package/skills/commands/global/SKILL.md +0 -71
  62. package/skills/commands/verify/SKILL.md +0 -46
  63. package/skills/commands/wiki/SKILL.md +0 -57
  64. package/skills/hello-review/SKILL.md +0 -42
  65. package/skills/hello-verify/SKILL.md +0 -144
  66. /package/hooks/{hooks.json → hooks-gemini.json} +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.33",
3
+ "version": "3.0.37",
4
4
  "description": "Quality-driven orchestration kernel for AI CLIs",
5
5
  "contextFileName": "bootstrap.md",
6
6
  "author": "HelloWind",
package/install.ps1 CHANGED
@@ -15,6 +15,8 @@ $Target = if ($env:HELLOAGENTS_TARGET) { $env:HELLOAGENTS_TARGET } else { "" }
15
15
  $Mode = if ($env:HELLOAGENTS_MODE) { $env:HELLOAGENTS_MODE } else { "" }
16
16
  $Branch = if ($env:HELLOAGENTS_BRANCH) { $env:HELLOAGENTS_BRANCH } else { "" }
17
17
  $Package = if ($env:HELLOAGENTS_PACKAGE) { $env:HELLOAGENTS_PACKAGE } else { "" }
18
+ $HasExplicitPackage = [bool]$Package
19
+ $HasExplicitTarget = $false
18
20
 
19
21
  if ($env:HELLOAGENTS) {
20
22
  $Parts = $env:HELLOAGENTS.Split(":", 2)
@@ -25,6 +27,8 @@ if ($env:HELLOAGENTS) {
25
27
  if (-not $Mode -and $Parts.Count -gt 1) { $Mode = $Parts[1] }
26
28
  }
27
29
 
30
+ $HasExplicitTarget = [bool]$Target
31
+
28
32
  if (-not $Target) { $Target = "all" }
29
33
  $Target = $Target.ToLowerInvariant()
30
34
  if ($Mode) { $Mode = $Mode.ToLowerInvariant() }
@@ -53,6 +57,23 @@ function Invoke-Npm {
53
57
  }
54
58
  }
55
59
 
60
+ function Clear-HelloagentsEnv {
61
+ foreach ($name in @(
62
+ "HELLOAGENTS",
63
+ "HELLOAGENTS_ACTION",
64
+ "HELLOAGENTS_TARGET",
65
+ "HELLOAGENTS_HOST",
66
+ "HELLOAGENTS_MODE",
67
+ "HELLOAGENTS_BRANCH",
68
+ "HELLOAGENTS_PACKAGE",
69
+ "HELLOAGENTS_DEPLOY"
70
+ )) {
71
+ Remove-Item "Env:$name" -ErrorAction SilentlyContinue
72
+ }
73
+ }
74
+
75
+ Clear-HelloagentsEnv
76
+
56
77
  function Enable-PostinstallDeploy {
57
78
  $env:HELLOAGENTS_DEPLOY = "1"
58
79
  $env:HELLOAGENTS_TARGET = $Target
@@ -89,11 +110,13 @@ function Uninstall-Hosts {
89
110
 
90
111
  switch ($Action) {
91
112
  "install" {
92
- Enable-PostinstallDeploy
113
+ if ($HasExplicitTarget) {
114
+ Enable-PostinstallDeploy
115
+ }
93
116
  Invoke-Npm -NpmArgs @("install", "-g", $Package)
94
117
  }
95
118
  "update" {
96
- if ($Branch -or $env:HELLOAGENTS_PACKAGE) {
119
+ if ($Branch -or $HasExplicitPackage) {
97
120
  Invoke-Npm -NpmArgs @("install", "-g", $Package)
98
121
  } else {
99
122
  & npm update -g helloagents
@@ -107,14 +130,14 @@ switch ($Action) {
107
130
  Cleanup-Hosts
108
131
  }
109
132
  "switch-branch" {
110
- if (-not $Branch -and -not $env:HELLOAGENTS_PACKAGE) {
133
+ if (-not $Branch -and -not $HasExplicitPackage) {
111
134
  throw "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for switch-branch"
112
135
  }
113
136
  Invoke-Npm -NpmArgs @("install", "-g", $Package)
114
137
  Sync-Hosts
115
138
  }
116
139
  "branch" {
117
- if (-not $Branch -and -not $env:HELLOAGENTS_PACKAGE) {
140
+ if (-not $Branch -and -not $HasExplicitPackage) {
118
141
  throw "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for branch"
119
142
  }
120
143
  Invoke-Npm -NpmArgs @("install", "-g", $Package)
package/install.sh CHANGED
@@ -16,6 +16,11 @@ TARGET="${HELLOAGENTS_TARGET:-}"
16
16
  MODE="${HELLOAGENTS_MODE:-}"
17
17
  BRANCH="${HELLOAGENTS_BRANCH:-}"
18
18
  PACKAGE="${HELLOAGENTS_PACKAGE:-}"
19
+ HAS_EXPLICIT_PACKAGE=0
20
+ HAS_EXPLICIT_TARGET=0
21
+ if [ -n "$PACKAGE" ]; then
22
+ HAS_EXPLICIT_PACKAGE=1
23
+ fi
19
24
 
20
25
  if [ -n "${HELLOAGENTS:-}" ]; then
21
26
  SPEC_TARGET="${HELLOAGENTS%%:*}"
@@ -31,6 +36,10 @@ if [ -n "${HELLOAGENTS:-}" ]; then
31
36
  MODE="${MODE:-$SPEC_MODE}"
32
37
  fi
33
38
 
39
+ if [ -n "$TARGET" ]; then
40
+ HAS_EXPLICIT_TARGET=1
41
+ fi
42
+
34
43
  TARGET="${TARGET:-all}"
35
44
  TARGET="$(printf '%s' "$TARGET" | tr '[:upper:]' '[:lower:]')"
36
45
  MODE="$(printf '%s' "$MODE" | tr '[:upper:]' '[:lower:]')"
@@ -55,6 +64,19 @@ if [ -z "$PACKAGE" ]; then
55
64
  fi
56
65
  fi
57
66
 
67
+ clear_lifecycle_env() {
68
+ unset HELLOAGENTS
69
+ unset HELLOAGENTS_ACTION
70
+ unset HELLOAGENTS_TARGET
71
+ unset HELLOAGENTS_HOST
72
+ unset HELLOAGENTS_MODE
73
+ unset HELLOAGENTS_BRANCH
74
+ unset HELLOAGENTS_PACKAGE
75
+ unset HELLOAGENTS_DEPLOY
76
+ }
77
+
78
+ clear_lifecycle_env
79
+
58
80
  sync_hosts() {
59
81
  if [ "$TARGET" = "all" ]; then
60
82
  if [ -n "$MODE" ]; then
@@ -111,11 +133,13 @@ enable_postinstall_deploy() {
111
133
 
112
134
  case "$ACTION" in
113
135
  install)
114
- enable_postinstall_deploy
136
+ if [ "$HAS_EXPLICIT_TARGET" -eq 1 ]; then
137
+ enable_postinstall_deploy
138
+ fi
115
139
  npm install -g "$PACKAGE"
116
140
  ;;
117
141
  update)
118
- if [ -n "$BRANCH" ] || [ -n "${HELLOAGENTS_PACKAGE:-}" ]; then
142
+ if [ -n "$BRANCH" ] || [ "$HAS_EXPLICIT_PACKAGE" -eq 1 ]; then
119
143
  npm install -g "$PACKAGE"
120
144
  else
121
145
  npm update -g helloagents || npm install -g helloagents
@@ -126,7 +150,7 @@ case "$ACTION" in
126
150
  cleanup_hosts
127
151
  ;;
128
152
  switch-branch|branch)
129
- if [ -z "$BRANCH" ] && [ -z "${HELLOAGENTS_PACKAGE:-}" ]; then
153
+ if [ -z "$BRANCH" ] && [ "$HAS_EXPLICIT_PACKAGE" -ne 1 ]; then
130
154
  echo "HELLOAGENTS_BRANCH or HELLOAGENTS_PACKAGE is required for switch-branch" >&2
131
155
  exit 1
132
156
  fi
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "helloagents",
3
- "version": "3.0.33",
3
+ "version": "3.0.37",
4
4
  "type": "module",
5
- "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, quality verification (Ralph Loop), safety guards, and notifications.",
5
+ "description": "HelloAGENTS — The orchestration kernel that makes any AI CLI smarter. Adds intelligent routing, unified QA gates, safety guards, and notifications.",
6
6
  "author": "HelloWind",
7
7
  "license": "Apache-2.0",
8
8
  "homepage": "https://github.com/hellowind777/helloagents",
@@ -30,10 +30,12 @@ export function selectCapabilities({ cwd, skillName = '', options = {} }) {
30
30
  : '独立 advisor:当前契约要求进入收尾前写当前会话 `artifacts/advisor.json`,记录 advisor reason、focus、consultedSources 与结论。',
31
31
  })
32
32
  }
33
- if (plan?.contract?.verifyMode === 'review-first') {
33
+ if ((plan?.contract?.qaFocus || []).length > 0) {
34
34
  capabilities.push({
35
- id: 'review-evaluator',
36
- description: '审查优先:当前验证主路径是 review-first,先做 hello-review,再做 hello-verify。',
35
+ id: 'qa-evaluator',
36
+ description: plan?.contract?.qaMode === 'deep'
37
+ ? `深度 qa-review:当前收尾主路径是 ~qa,按阻断性质量闭环执行;重点:${plan.contract.qaFocus.join(';')}。`
38
+ : `统一 qa-review:当前收尾主路径是 ~qa,重点:${plan.contract.qaFocus.join(';')}。`,
37
39
  })
38
40
  }
39
41
  if (plan?.contract?.ui?.required || existsSync(getProjectDesignContractPath(cwd))) {
@@ -1,4 +1,6 @@
1
+ import { spawnSync } from 'node:child_process'
1
2
  import { existsSync, realpathSync } from 'node:fs'
3
+ import { platform } from 'node:os'
2
4
  import { join } from 'node:path'
3
5
 
4
6
  import { CODEX_MARKETPLACE_NAME, CODEX_PLUGIN_CONFIG_HEADER, CODEX_PLUGIN_NAME } from './cli-codex.mjs'
@@ -76,6 +78,143 @@ function buildDoctorIssue(runtime, code, cn, en) {
76
78
  }
77
79
  }
78
80
 
81
+ function normalizeDoctorText(value = '') {
82
+ return String(value || '').replace(/\s+/g, ' ').trim()
83
+ }
84
+
85
+ function readFirstInteger(value = '') {
86
+ const match = String(value || '').match(/-?\d+/)
87
+ return match ? Number.parseInt(match[0], 10) : null
88
+ }
89
+
90
+ function readNativeDoctorDetail(checks, checkId, detailKey) {
91
+ return String(checks?.[checkId]?.details?.[detailKey] || '').trim()
92
+ }
93
+
94
+ function readNativeDoctorList(value = '') {
95
+ const normalized = normalizeDoctorText(value)
96
+ if (!normalized || normalized === '(none)') return []
97
+ return normalized.split(/\s*,\s*/).map((entry) => entry.trim()).filter(Boolean)
98
+ }
99
+
100
+ function summarizeNativeCodexDoctor(payload = {}) {
101
+ const checks = payload?.checks || {}
102
+ const configCheck = checks['config.load'] || {}
103
+ const sandboxCheck = checks['sandbox.helpers'] || {}
104
+ const mcpCount = readFirstInteger(readNativeDoctorDetail(checks, 'config.load', 'mcp servers'))
105
+ const fsSandbox = readNativeDoctorDetail(checks, 'sandbox.helpers', 'filesystem sandbox').toLowerCase()
106
+ const linuxHelper = readNativeDoctorDetail(checks, 'sandbox.helpers', 'codex-linux-sandbox helper').toLowerCase()
107
+ || readNativeDoctorDetail(checks, 'sandbox.helpers', 'linux helper').toLowerCase()
108
+ const execveHelper = readNativeDoctorDetail(checks, 'sandbox.helpers', 'execve wrapper helper').toLowerCase()
109
+
110
+ let sandboxAvailable = null
111
+ if (sandboxCheck && Object.keys(sandboxCheck).length > 0) {
112
+ sandboxAvailable = Boolean(
113
+ (fsSandbox && !fsSandbox.includes('unrestricted'))
114
+ || (linuxHelper && linuxHelper !== 'none')
115
+ || (execveHelper && execveHelper !== 'none')
116
+ )
117
+ }
118
+
119
+ return {
120
+ version: String(payload?.codexVersion || '').trim(),
121
+ configPath: readNativeDoctorDetail(checks, 'config.load', 'config.toml'),
122
+ resolvedProvider: readNativeDoctorDetail(checks, 'config.load', 'model provider'),
123
+ resolvedModel: readNativeDoctorDetail(checks, 'config.load', 'model'),
124
+ sandboxAvailable,
125
+ mcpPresent: typeof mcpCount === 'number' ? mcpCount > 0 : false,
126
+ skillsSelected: readNativeDoctorList(
127
+ readNativeDoctorDetail(checks, 'config.load', 'selected skills')
128
+ || readNativeDoctorDetail(checks, 'config.load', 'skills selected')
129
+ ),
130
+ }
131
+ }
132
+
133
+ function summarizeNativeCodexDoctorOutput(payload = {}) {
134
+ const checks = Object.values(payload?.checks || {})
135
+ const failedCheck = checks.find((check) => check?.status === 'fail')
136
+ if (failedCheck?.issues?.length) {
137
+ return normalizeDoctorText(failedCheck.issues.map((issue) => issue?.cause || issue?.measured || '').filter(Boolean).join(' | '))
138
+ }
139
+ if (failedCheck?.summary) return normalizeDoctorText(failedCheck.summary)
140
+
141
+ const warningCheck = checks.find((check) => check?.status === 'warn')
142
+ if (warningCheck?.issues?.length) {
143
+ return normalizeDoctorText(warningCheck.issues.map((issue) => issue?.cause || issue?.measured || '').filter(Boolean).join(' | '))
144
+ }
145
+ if (warningCheck?.summary) return normalizeDoctorText(warningCheck.summary)
146
+
147
+ return ''
148
+ }
149
+
150
+ function inspectNativeCodexDoctor(runtime) {
151
+ const command = platform() === 'win32' ? 'codex.cmd' : 'codex'
152
+ try {
153
+ const result = spawnSync(command, ['doctor', '--json'], {
154
+ cwd: process.cwd(),
155
+ env: {
156
+ ...process.env,
157
+ HOME: runtime.home || process.env.HOME,
158
+ USERPROFILE: runtime.home || process.env.USERPROFILE,
159
+ NO_COLOR: process.env.NO_COLOR || '1',
160
+ },
161
+ encoding: 'utf-8',
162
+ timeout: 20_000,
163
+ shell: platform() === 'win32',
164
+ windowsHide: true,
165
+ })
166
+
167
+ if (result.error) {
168
+ return {
169
+ available: false,
170
+ ok: false,
171
+ status: '',
172
+ summary: null,
173
+ output: normalizeDoctorText(result.error.message || ''),
174
+ }
175
+ }
176
+
177
+ const stdout = String(result.stdout || '').trim()
178
+ if (!stdout) {
179
+ return {
180
+ available: true,
181
+ ok: result.status === 0,
182
+ status: '',
183
+ summary: null,
184
+ output: normalizeDoctorText(result.stderr || ''),
185
+ }
186
+ }
187
+
188
+ try {
189
+ const payload = JSON.parse(stdout)
190
+ const status = String(payload?.overallStatus || '').trim().toLowerCase()
191
+ return {
192
+ available: true,
193
+ ok: status ? status !== 'fail' : result.status === 0,
194
+ status,
195
+ summary: summarizeNativeCodexDoctor(payload),
196
+ output: summarizeNativeCodexDoctorOutput(payload),
197
+ }
198
+ } catch {
199
+ return {
200
+ available: true,
201
+ ok: result.status === 0,
202
+ status: '',
203
+ summary: null,
204
+ output: normalizeDoctorText(stdout || result.stderr || ''),
205
+ }
206
+ }
207
+ } catch (error) {
208
+ return {
209
+ available: false,
210
+ ok: false,
211
+ status: '',
212
+ summary: null,
213
+ output: normalizeDoctorText(error?.message || ''),
214
+ }
215
+ }
216
+ }
217
+
79
218
  function normalizeDoctorMode(mode = '') {
80
219
  return mode || 'none'
81
220
  }
@@ -209,6 +348,7 @@ export function inspectCodexDoctor(runtime, settings) {
209
348
  const host = 'codex'
210
349
  const trackedMode = normalizeDoctorMode(runtime.getTrackedHostMode(settings, host))
211
350
  const detectedMode = normalizeDoctorMode(runtime.detectHostMode(host))
351
+ const nativeDoctor = inspectNativeCodexDoctor(runtime)
212
352
  const { checks, pluginVersion, cacheVersion } = buildCodexChecks(runtime, settings, trackedMode, detectedMode)
213
353
  checks.pluginVersionMatch = pluginVersion ? pluginVersion === runtime.pkgVersion : false
214
354
  checks.pluginCacheVersionMatch = cacheVersion ? cacheVersion === runtime.pkgVersion : false
@@ -230,7 +370,19 @@ export function inspectCodexDoctor(runtime, settings) {
230
370
  if (!checks.pluginCacheVersionMatch && !cacheVersion && detectedMode === 'global') notes.push(runtime.msg('未读到 global 插件缓存版本信息', 'Global plugin cache version was not readable'))
231
371
  if (detectedMode !== 'none' && !checks.codexGoalsFeature) notes.push(runtime.msg('Codex /goal 未启用;如需长程执行,可运行 `helloagents codex goals enable`。', 'Codex /goal is not enabled; run `helloagents codex goals enable` if you need long-running goals.'))
232
372
  if (detectedMode !== 'none' && checks.legacyCodexHooksFeature) notes.push(runtime.msg('检测到旧版 `codex_hooks`;HelloAGENTS 只兼容 Codex 最新版,请移除旧 key。', 'Legacy `codex_hooks` was detected; HelloAGENTS targets latest Codex only, so remove the old key.'))
373
+ if (!nativeDoctor.available) notes.push(runtime.msg('未检测到原生 `codex doctor`;当前仅检查 HelloAGENTS 受管覆盖层。', 'Native `codex doctor` was not available; only the HelloAGENTS managed overlay was checked.'))
233
374
 
234
375
  const status = summarizeDoctorStatus(issues, { trackedMode, detectedMode })
235
- return { host, label: runtime.getHostLabel(host), trackedMode, detectedMode, status, checks, issues, notes, suggestedFix: suggestCodexDoctorFix(status, trackedMode) }
376
+ return {
377
+ host,
378
+ label: runtime.getHostLabel(host),
379
+ trackedMode,
380
+ detectedMode,
381
+ status,
382
+ checks,
383
+ nativeDoctor,
384
+ issues,
385
+ notes,
386
+ suggestedFix: suggestCodexDoctorFix(status, trackedMode),
387
+ }
236
388
  }
@@ -20,7 +20,8 @@ export function printDoctorText(runtime, report) {
20
20
  if (entry.nativeDoctor) {
21
21
  console.log(` native_doctor.available: ${entry.nativeDoctor.available ? 'ok' : 'missing'}`)
22
22
  if (entry.nativeDoctor.available) {
23
- console.log(` native_doctor.ok: ${entry.nativeDoctor.ok ? 'ok' : 'missing'}`)
23
+ console.log(` native_doctor.ok: ${entry.nativeDoctor.ok ? 'ok' : 'fail'}`)
24
+ if (entry.nativeDoctor.status) console.log(` native_doctor.status: ${entry.nativeDoctor.status}`)
24
25
  }
25
26
  if (entry.nativeDoctor.summary) {
26
27
  if (entry.nativeDoctor.summary.version) console.log(` native_doctor.version: ${entry.nativeDoctor.summary.version}`)
@@ -106,8 +106,8 @@ function suggestDoctorFix(host, status, trackedMode) {
106
106
  return `helloagents update ${host}${trackedMode && trackedMode !== 'none' ? ` --${trackedMode}` : ''}`
107
107
  }
108
108
  if (status === 'manual-plugin') {
109
- if (host === 'claude') return '/plugin marketplace add hellowind777/helloagents; /plugin install helloagents@helloagents'
110
- if (host === 'gemini') return 'gemini extensions install https://github.com/hellowind777/helloagents'
109
+ if (host === 'claude') return '/plugin marketplace add https://github.com/hellowind777/helloagents.git; /plugin install helloagents@helloagents'
110
+ if (host === 'gemini') return 'helloagents install gemini --global'
111
111
  }
112
112
  if (status === 'not-installed') {
113
113
  return `helloagents install ${host} --standby`
@@ -176,7 +176,7 @@ function inspectGeminiDoctor(settings) {
176
176
  const detectedMode = normalizeDoctorMode(runtime.detectHostMode(host))
177
177
  const geminiDir = join(runtime.home, '.gemini')
178
178
  const geminiSettings = safeJson(join(geminiDir, 'settings.json')) || {}
179
- const expectedHooks = readExpectedHooks('hooks.json', '${extensionPath}')
179
+ const expectedHooks = readExpectedHooks('hooks-gemini.json', '${extensionPath}')
180
180
  const checks = {
181
181
  carrierMarker: (safeRead(join(geminiDir, 'GEMINI.md')) || '').includes('HELLOAGENTS_START'),
182
182
  carrierContentMatch: extractManagedCarrierContent(join(geminiDir, 'GEMINI.md'))
@@ -65,7 +65,7 @@ export function installGeminiStandby(home, pkgRoot) {
65
65
  createLink(pkgRoot, join(geminiDir, 'helloagents'));
66
66
 
67
67
  const settingsPath = join(geminiDir, 'settings.json');
68
- const hooksData = loadHooksWithCliEntry(pkgRoot, 'hooks.json', '${extensionPath}');
68
+ const hooksData = loadHooksWithCliEntry(pkgRoot, 'hooks-gemini.json', '${extensionPath}');
69
69
  if (hooksData) mergeSettingsHooks(settingsPath, hooksData);
70
70
 
71
71
  return true;