oh-my-opencode 4.11.1 → 4.12.1

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 (170) hide show
  1. package/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
  2. package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
  3. package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
  4. package/.agents/skills/work-with-pr/SKILL.md +19 -5
  5. package/.opencode/skills/work-with-pr/SKILL.md +19 -5
  6. package/dist/agents/types.d.ts +7 -6
  7. package/dist/cli/index.js +460 -309
  8. package/dist/cli-node/index.js +460 -309
  9. package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
  10. package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
  11. package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
  12. package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
  13. package/dist/index.js +593 -310
  14. package/dist/plugin/tool-execute-before.d.ts +2 -0
  15. package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
  16. package/dist/skills/ultraresearch/SKILL.md +11 -2
  17. package/dist/skills/ulw-plan/SKILL.md +2 -1
  18. package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
  19. package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
  20. package/dist/tools/background-task/constants.d.ts +1 -1
  21. package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
  22. package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
  23. package/dist/tui.js +25 -10
  24. package/package.json +13 -13
  25. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
  26. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
  27. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +336 -173
  30. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
  31. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
  33. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
  34. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
  35. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
  36. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
  37. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
  38. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
  39. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
  40. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
  41. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
  42. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
  43. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  44. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/comment-checker/test/package-smoke.test.ts +2 -71
  46. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  47. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  49. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  50. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  51. package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
  52. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
  53. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  54. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  55. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +12 -92
  56. package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
  57. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  58. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -2
  59. package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
  60. package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
  61. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
  62. package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
  63. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
  64. package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
  65. package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
  66. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
  67. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
  68. package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
  69. package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
  70. package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
  71. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
  72. package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
  73. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  74. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  75. package/packages/omo-codex/plugin/components/test-support/package-smoke-fixture.ts +158 -0
  76. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  77. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  78. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -1
  79. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
  80. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
  82. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
  83. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
  84. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  85. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
  86. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
  87. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
  88. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
  89. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
  90. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
  91. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
  92. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
  93. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
  94. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
  95. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
  96. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
  97. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
  98. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
  99. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
  100. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
  101. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
  102. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
  103. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
  104. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
  105. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
  106. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
  107. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
  108. package/packages/omo-codex/plugin/package-lock.json +30 -22
  109. package/packages/omo-codex/plugin/package.json +2 -1
  110. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
  111. package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
  112. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
  113. package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
  114. package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
  115. package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
  116. package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
  117. package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
  118. package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
  119. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  120. package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
  121. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  122. package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
  123. package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
  124. package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
  125. package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
  126. package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
  127. package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
  128. package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
  129. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
  130. package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
  131. package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
  132. package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
  133. package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
  134. package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
  135. package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
  136. package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
  137. package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
  138. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
  139. package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
  140. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
  141. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
  142. package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
  143. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
  144. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
  145. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
  146. package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
  147. package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
  148. package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
  149. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
  150. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
  151. package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
  152. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
  153. package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
  154. package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
  155. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
  156. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
  157. package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
  158. package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
  159. package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
  160. package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
  161. package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
  162. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
  163. package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
  164. package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
  165. package/packages/omo-codex/scripts/install-local.mjs +1 -0
  166. package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
  167. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
  168. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
  169. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
  170. package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
@@ -2,9 +2,9 @@
2
2
 
3
3
  // src/serve.ts
4
4
  import { spawn } from "node:child_process";
5
- import { existsSync as existsSync4, realpathSync } from "node:fs";
6
- import { homedir as homedir4 } from "node:os";
7
- import { basename as basename2, extname, join as join5, resolve as resolve2 } from "node:path";
5
+ import { existsSync as existsSync5, realpathSync } from "node:fs";
6
+ import { homedir as homedir5 } from "node:os";
7
+ import { basename as basename3, extname, join as join6, resolve as resolve2 } from "node:path";
8
8
  import {
9
9
  cwd as processCwd,
10
10
  env as processEnv,
@@ -59,16 +59,235 @@ function parseNodeMajor(version) {
59
59
  return Number.isNaN(major) ? 0 : major;
60
60
  }
61
61
 
62
- // ../../../../utils/src/codegraph/resolve.ts
62
+ // ../../../../utils/src/codegraph/provision.ts
63
+ import { createHash, randomUUID } from "node:crypto";
64
+ import { execFile } from "node:child_process";
65
+ import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
63
66
  import { existsSync } from "node:fs";
64
- import { homedir as homedir2 } from "node:os";
67
+ import { homedir as homedir2, hostname } from "node:os";
68
+ import { basename, join as join2 } from "node:path";
69
+ import { promisify } from "node:util";
70
+
71
+ // ../../../../utils/src/codegraph/manifest.ts
72
+ var CODEGRAPH_PROVISION_MANIFEST = {
73
+ assets: {
74
+ "darwin-arm64": {
75
+ executableName: "codegraph",
76
+ sha256: "95bb27bf6382b69659e158e0c04d71cc394778951e1317d582be7807e7866908",
77
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-arm64.tar.gz"
78
+ },
79
+ "darwin-x64": {
80
+ executableName: "codegraph",
81
+ sha256: "3311cc1d1f0f0ad742709b6a43d8a9187b1ef0af0dd30e0b58008dc673e29478",
82
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-darwin-x64.tar.gz"
83
+ },
84
+ "linux-arm64": {
85
+ executableName: "codegraph",
86
+ sha256: "e16f612bc96c2ebccd04574cbed500c9939147c80666ad6bb024398dff7992ae",
87
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-arm64.tar.gz"
88
+ },
89
+ "linux-x64": {
90
+ executableName: "codegraph",
91
+ sha256: "d45a068f44596a85c7ba7d0ef924eaf7103fbbf3cafbeb668127daff60a52228",
92
+ url: "https://github.com/colbymchenry/codegraph/releases/download/v1.0.1/codegraph-linux-x64.tar.gz"
93
+ },
94
+ "win32-arm64": {
95
+ executableName: "codegraph.cmd",
96
+ sha256: "8d57ced73b24d35f758f2ede2318e80e1d7241987f37a999e3d80edb6fddf961",
97
+ url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.0.1.tgz"
98
+ },
99
+ "win32-x64": {
100
+ executableName: "codegraph.cmd",
101
+ sha256: "52607fe73b05e741fd1087da2ceca9d3c8f565e36bf1a7070600bdbdf3931e32",
102
+ url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.0.1.tgz"
103
+ }
104
+ },
105
+ version: "1.0.1"
106
+ };
107
+
108
+ // ../../../../utils/src/codegraph/provision.ts
109
+ var DEFAULT_LOCK_WAIT_MS = 5000;
110
+ var DEFAULT_LOCK_STALE_MS = 120000;
111
+ var DEFAULT_DOWNLOAD_TIMEOUT_MS = 60000;
112
+ var execFileAsync = promisify(execFile);
113
+ function platformKey() {
114
+ return `${process.platform}-${process.arch}`;
115
+ }
116
+ function markerPath(installDir, version) {
117
+ return join2(installDir, ".provisioned", `codegraph-${version}.json`);
118
+ }
119
+ function defaultInstallDir() {
120
+ return join2(homedir2(), ".omo", "codegraph");
121
+ }
122
+ function sha256(bytes) {
123
+ return createHash("sha256").update(bytes).digest("hex");
124
+ }
125
+ function isErrnoException(error) {
126
+ return error instanceof Error && "code" in error;
127
+ }
128
+ async function removeEmptyDirectory(path) {
129
+ try {
130
+ await rmdir(path);
131
+ } catch (error) {
132
+ if (isErrnoException(error) && error.code === "ENOENT")
133
+ return;
134
+ if (isErrnoException(error) && error.code === "ENOTEMPTY")
135
+ return;
136
+ throw error;
137
+ }
138
+ }
139
+ function sleep(ms) {
140
+ return new Promise((resolve) => setTimeout(resolve, ms));
141
+ }
142
+ async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
143
+ const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
144
+ if (!response.ok)
145
+ throw new Error(`download failed with HTTP ${response.status}`);
146
+ return new Uint8Array(await response.arrayBuffer());
147
+ }
148
+ function forcedBadChecksumOptions(options) {
149
+ if (options.forceBadChecksum !== true)
150
+ return null;
151
+ const key = options.platformKey ?? platformKey();
152
+ return {
153
+ downloader: async () => new TextEncoder().encode("checksum mismatch"),
154
+ installDir: options.installDir ?? join2(options.lockDir, "codegraph-force-bad-checksum"),
155
+ manifest: {
156
+ assets: {
157
+ [key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
158
+ },
159
+ version: options.version
160
+ },
161
+ platformKey: key
162
+ };
163
+ }
164
+ async function readMarker(path) {
165
+ if (!existsSync(path))
166
+ return null;
167
+ try {
168
+ const raw = JSON.parse(await readFile(path, "utf8"));
169
+ if (typeof raw === "object" && raw !== null && "binPath" in raw) {
170
+ const value = raw.binPath;
171
+ return typeof value === "string" && existsSync(value) ? value : null;
172
+ }
173
+ return null;
174
+ } catch (error) {
175
+ if (error instanceof Error)
176
+ return null;
177
+ throw error;
178
+ }
179
+ }
180
+ async function acquireLock(lockPath, waitMs, staleMs) {
181
+ const startedAt = Date.now();
182
+ await mkdir(join2(lockPath, ".."), { recursive: true });
183
+ while (Date.now() - startedAt <= waitMs) {
184
+ try {
185
+ await mkdir(lockPath);
186
+ return () => rm(lockPath, { force: true, recursive: true });
187
+ } catch (error) {
188
+ if (!isErrnoException(error) || error.code !== "EEXIST")
189
+ throw error;
190
+ const lockStat = await stat(lockPath).catch(() => null);
191
+ if (lockStat !== null && Date.now() - lockStat.mtimeMs > staleMs) {
192
+ await rm(lockPath, { force: true, recursive: true });
193
+ continue;
194
+ }
195
+ await sleep(25);
196
+ }
197
+ }
198
+ return null;
199
+ }
200
+ async function extractTarGz(archivePath, destinationDir) {
201
+ await execFileAsync("tar", ["-xzf", archivePath, "-C", destinationDir]);
202
+ }
203
+ async function installExtractedBundle(extractDir, installDir, executableName) {
204
+ const roots = await readdir(extractDir);
205
+ if (roots.length !== 1)
206
+ throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
207
+ const bundleDir = join2(extractDir, roots[0] ?? "");
208
+ const bundleEntries = await readdir(bundleDir);
209
+ await mkdir(installDir, { recursive: true });
210
+ for (const entry of bundleEntries) {
211
+ await rm(join2(installDir, entry), { force: true, recursive: true });
212
+ await rename(join2(bundleDir, entry), join2(installDir, entry));
213
+ }
214
+ const destination = join2(installDir, "bin", executableName);
215
+ if (!existsSync(destination))
216
+ throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
217
+ await chmod(destination, 493);
218
+ return destination;
219
+ }
220
+ async function installAsset(layout) {
221
+ const { asset, downloader, installDir, version } = layout;
222
+ const stagingDir = join2(installDir, ".staging", randomUUID());
223
+ const archivePath = join2(stagingDir, basename(asset.url));
224
+ const extractDir = join2(stagingDir, "extract");
225
+ try {
226
+ await mkdir(extractDir, { recursive: true });
227
+ const bytes = await downloader(asset);
228
+ const actualChecksum = sha256(bytes);
229
+ if (actualChecksum !== asset.sha256) {
230
+ throw new Error(`checksum mismatch for ${basename(asset.url)}: expected ${asset.sha256}, got ${actualChecksum}`);
231
+ }
232
+ if (!asset.url.endsWith(".tar.gz") && !asset.url.endsWith(".tgz")) {
233
+ throw new Error(`unsupported CodeGraph archive type for ${basename(asset.url)}`);
234
+ }
235
+ await writeFile(archivePath, bytes);
236
+ await extractTarGz(archivePath, extractDir);
237
+ const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
238
+ await mkdir(join2(installDir, ".provisioned"), { recursive: true });
239
+ await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
240
+ `);
241
+ return destination;
242
+ } finally {
243
+ await rm(stagingDir, { force: true, recursive: true });
244
+ await removeEmptyDirectory(join2(installDir, ".staging"));
245
+ }
246
+ }
247
+ async function ensureCodegraphProvisioned(options) {
248
+ const forced = forcedBadChecksumOptions(options);
249
+ const installDir = forced?.installDir ?? options.installDir ?? defaultInstallDir();
250
+ const manifest = forced?.manifest ?? options.manifest ?? CODEGRAPH_PROVISION_MANIFEST;
251
+ const activePlatformKey = forced?.platformKey ?? options.platformKey ?? platformKey();
252
+ const downloader = forced?.downloader ?? options.downloader ?? ((asset) => defaultDownloader(asset, options.downloadTimeoutMs));
253
+ const marker = markerPath(installDir, options.version);
254
+ const existing = await readMarker(marker);
255
+ if (existing !== null)
256
+ return { binPath: existing, provisioned: true };
257
+ const lockPath = join2(options.lockDir, `codegraph-${hostname()}.lock`);
258
+ const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
259
+ if (release === null)
260
+ return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
261
+ try {
262
+ const lockedExisting = await readMarker(marker);
263
+ if (lockedExisting !== null)
264
+ return { binPath: lockedExisting, provisioned: true };
265
+ if (manifest.version !== options.version) {
266
+ return { error: `manifest version ${manifest.version} does not match requested ${options.version}`, provisioned: false };
267
+ }
268
+ const asset = manifest.assets[activePlatformKey];
269
+ if (asset === undefined) {
270
+ return { error: `no CodeGraph ${options.version} asset for ${activePlatformKey}`, provisioned: false };
271
+ }
272
+ const binPath = await installAsset({ asset, downloader, installDir, version: options.version });
273
+ return { binPath, provisioned: true };
274
+ } catch (error) {
275
+ return { error: error instanceof Error ? error.message : String(error), provisioned: false };
276
+ } finally {
277
+ await release();
278
+ }
279
+ }
280
+
281
+ // ../../../../utils/src/codegraph/resolve.ts
282
+ import { existsSync as existsSync2 } from "node:fs";
283
+ import { homedir as homedir3 } from "node:os";
65
284
  import { spawnSync } from "node:child_process";
66
- import { basename, dirname, join as join3 } from "node:path";
285
+ import { basename as basename2, dirname, join as join4 } from "node:path";
67
286
  import { createRequire } from "node:module";
68
287
 
69
288
  // ../../../../utils/src/runtime/which.ts
70
289
  import { accessSync, constants } from "node:fs";
71
- import { delimiter, join as join2 } from "node:path";
290
+ import { delimiter, join as join3 } from "node:path";
72
291
  var runtime = globalThis;
73
292
  function isUnsafeCommandName(commandName) {
74
293
  if (commandName.includes("/") || commandName.includes("\\"))
@@ -123,7 +342,7 @@ function bunWhich(commandName) {
123
342
  return null;
124
343
  for (const pathEntry of pathEntries) {
125
344
  for (const candidateName of candidateNames) {
126
- const candidatePath = join2(pathEntry, candidateName);
345
+ const candidatePath = join3(pathEntry, candidateName);
127
346
  if (isExecutable(candidatePath))
128
347
  return candidatePath;
129
348
  }
@@ -132,6 +351,9 @@ function bunWhich(commandName) {
132
351
  }
133
352
 
134
353
  // ../../../../utils/src/codegraph/resolve.ts
354
+ function codegraphCommandRequiresSupportedLocalNode(resolution) {
355
+ return resolution.source !== "bundled" && resolution.source !== "env" && resolution.source !== "provisioned";
356
+ }
135
357
  var CODEGRAPH_PACKAGE = "@colbymchenry/codegraph";
136
358
  var CODEGRAPH_ENV_BIN = "OMO_CODEGRAPH_BIN";
137
359
  var CODEGRAPH_LEGACY_ENV_BIN = "CODEGRAPH_BIN";
@@ -161,7 +383,7 @@ ${result.stderr}`.trim().split(/\s+/)[0];
161
383
  }
162
384
  }
163
385
  function isNodeExecutableName(filePath) {
164
- const executable = basename(filePath).toLowerCase();
386
+ const executable = basename2(filePath).toLowerCase();
165
387
  return executable === "node" || executable === "node.exe" || /^node\d+(\.exe)?$/.test(executable);
166
388
  }
167
389
  function looksLikePath(command) {
@@ -201,8 +423,8 @@ function defaultNodeRuntime(env, fileExists, which, nodeVersion) {
201
423
  function defaultProvisionedBin(homeDir, fileExists) {
202
424
  const binaryName = process.platform === "win32" ? "codegraph.cmd" : "codegraph";
203
425
  const candidates = [
204
- join3(homeDir, ".omo", "codegraph", "bin", binaryName),
205
- join3(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
426
+ join4(homeDir, ".omo", "codegraph", "bin", binaryName),
427
+ join4(homeDir, ".omo", "codegraph", "node-servers", "node_modules", ".bin", binaryName)
206
428
  ];
207
429
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
208
430
  }
@@ -210,7 +432,7 @@ function resolveBundledShim(requireResolve, fileExists) {
210
432
  try {
211
433
  const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
212
434
  const packageRoot = dirname(packageJson);
213
- const candidates = [join3(packageRoot, "bin", "codegraph.js"), join3(packageRoot, "npm-shim.js")];
435
+ const candidates = [join4(packageRoot, "bin", "codegraph.js"), join4(packageRoot, "npm-shim.js")];
214
436
  return candidates.find((candidate) => fileExists(candidate)) ?? null;
215
437
  } catch (error) {
216
438
  if (error instanceof Error)
@@ -226,7 +448,7 @@ function resolveBundledShim(requireResolve, fileExists) {
226
448
  }
227
449
  function resolveCodegraphCommand(options = {}) {
228
450
  const env = options.env ?? process.env;
229
- const fileExists = options.fileExists ?? existsSync;
451
+ const fileExists = options.fileExists ?? existsSync2;
230
452
  const configuredBin = env[CODEGRAPH_ENV_BIN]?.trim() || env[CODEGRAPH_LEGACY_ENV_BIN]?.trim();
231
453
  if (configuredBin !== undefined && configuredBin.length > 0) {
232
454
  return { argsPrefix: [], command: configuredBin, exists: fileExists(configuredBin), source: "env" };
@@ -238,7 +460,7 @@ function resolveCodegraphCommand(options = {}) {
238
460
  if (bundled !== null && runtime2 !== null) {
239
461
  return { argsPrefix: [bundled], command: runtime2, exists: true, source: "bundled" };
240
462
  }
241
- const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir2(), fileExists);
463
+ const provisioned = options.provisioned?.() ?? defaultProvisionedBin(options.homeDir ?? homedir3(), fileExists);
242
464
  if (provisioned !== null && fileExists(provisioned)) {
243
465
  return { argsPrefix: [], command: provisioned, exists: true, source: "provisioned" };
244
466
  }
@@ -252,8 +474,8 @@ function resolveCodegraphCommand(options = {}) {
252
474
  }
253
475
 
254
476
  // ../../../../utils/src/omo-config/loader.ts
255
- import { existsSync as existsSync3, readFileSync } from "node:fs";
256
- import { homedir as homedir3 } from "node:os";
477
+ import { existsSync as existsSync4, readFileSync } from "node:fs";
478
+ import { homedir as homedir4 } from "node:os";
257
479
 
258
480
  // ../../../../utils/src/deep-merge.ts
259
481
  var DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
@@ -1209,8 +1431,8 @@ function buildEnvOverrides(harness, env, warnings, merge) {
1209
1431
  }
1210
1432
 
1211
1433
  // ../../../../utils/src/omo-config/resolve.ts
1212
- import { existsSync as existsSync2 } from "node:fs";
1213
- import { dirname as dirname2, isAbsolute, join as join4, relative, resolve } from "node:path";
1434
+ import { existsSync as existsSync3 } from "node:fs";
1435
+ import { dirname as dirname2, isAbsolute, join as join5, relative, resolve } from "node:path";
1214
1436
  function containsPath(parent, child) {
1215
1437
  const pathToChild = relative(parent, child);
1216
1438
  return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute(pathToChild);
@@ -1223,8 +1445,8 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
1223
1445
  while (true) {
1224
1446
  if (stopBeforeDir !== null && currentDir === stopBeforeDir)
1225
1447
  break;
1226
- const configPath = join4(currentDir, ".omo", "config.jsonc");
1227
- if (existsSync2(configPath)) {
1448
+ const configPath = join5(currentDir, ".omo", "config.jsonc");
1449
+ if (existsSync3(configPath)) {
1228
1450
  paths.push(configPath);
1229
1451
  }
1230
1452
  const parentDir = dirname2(currentDir);
@@ -1235,7 +1457,7 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
1235
1457
  return paths;
1236
1458
  }
1237
1459
  function resolveOmoConfigPaths(options) {
1238
- const globalPath = join4(resolve(options.homeDir), ".omo", "config.jsonc");
1460
+ const globalPath = join5(resolve(options.homeDir), ".omo", "config.jsonc");
1239
1461
  const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
1240
1462
  return [
1241
1463
  { path: globalPath, scope: "global" },
@@ -1446,13 +1668,13 @@ function validateHarnessApplicability(config, harness) {
1446
1668
  }
1447
1669
  function loadOmoConfig(options) {
1448
1670
  const cwd = options.cwd ?? process.cwd();
1449
- const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir3();
1671
+ const homeDir = options.homeDir ?? process.env["HOME"] ?? process.env["USERPROFILE"] ?? homedir4();
1450
1672
  const env = options.env ?? process.env;
1451
1673
  let config = BUILT_IN_DEFAULTS;
1452
1674
  const sources = [];
1453
1675
  const warnings = [];
1454
1676
  for (const candidate of resolveOmoConfigPaths({ cwd, homeDir })) {
1455
- if (!existsSync3(candidate.path)) {
1677
+ if (!existsSync4(candidate.path)) {
1456
1678
  if (candidate.scope === "global") {
1457
1679
  sources.push(toMissingSource(candidate));
1458
1680
  }
@@ -1494,11 +1716,12 @@ var CODEGRAPH_SKIP_HINT = `CodeGraph MCP skipped: codegraph binary not found. In
1494
1716
  `;
1495
1717
  var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config. Set [codex].codegraph.enabled=true to enable it.
1496
1718
  `;
1719
+ var CODEGRAPH_VERSION = "1.0.1";
1497
1720
  var WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
1498
1721
  var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
1499
1722
  async function runCodegraphServe(options = {}) {
1500
1723
  const env = options.env ?? processEnv;
1501
- const homeDir = options.homeDir ?? homedir4();
1724
+ const homeDir = options.homeDir ?? homedir5();
1502
1725
  const config = options.config ?? getCodexOmoConfig({ cwd: options.cwd ?? processCwd(), env, homeDir });
1503
1726
  const codegraphConfig = config.codegraph ?? {};
1504
1727
  if (codegraphConfig.enabled === false) {
@@ -1510,13 +1733,26 @@ async function runCodegraphServe(options = {}) {
1510
1733
  homeDir,
1511
1734
  provisioned: () => provisionedBinFromInstallDir(codegraphConfig.install_dir)
1512
1735
  };
1513
- const resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
1514
- if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync4)) {
1515
- (options.stderr ?? processStderr).write(CODEGRAPH_SKIP_HINT);
1516
- return 1;
1517
- }
1736
+ let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
1518
1737
  const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
1519
- if (resolution.source !== "bundled" && resolution.source !== "env" && !nodeSupport.supported) {
1738
+ if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync5)) {
1739
+ if (resolution.source === "path" && !nodeSupport.supported) {
1740
+ (options.stderr ?? processStderr).write(buildCodegraphNodeSkipHint(nodeSupport));
1741
+ return 1;
1742
+ }
1743
+ const provisioned = await provisionMissingCodegraph({
1744
+ config: codegraphConfig,
1745
+ ensureProvisioned: options.ensureProvisioned ?? ensureCodegraphProvisioned,
1746
+ homeDir,
1747
+ resolution
1748
+ });
1749
+ if (provisioned === null) {
1750
+ (options.stderr ?? processStderr).write(CODEGRAPH_SKIP_HINT);
1751
+ return 1;
1752
+ }
1753
+ resolution = provisioned;
1754
+ }
1755
+ if (codegraphCommandRequiresSupportedLocalNode(resolution) && !nodeSupport.supported) {
1520
1756
  (options.stderr ?? processStderr).write(buildCodegraphNodeSkipHint(nodeSupport));
1521
1757
  return 1;
1522
1758
  }
@@ -1531,6 +1767,21 @@ async function runCodegraphServe(options = {}) {
1531
1767
  stdio: "inherit"
1532
1768
  });
1533
1769
  }
1770
+ async function provisionMissingCodegraph(options) {
1771
+ if (options.resolution.source === "env")
1772
+ return null;
1773
+ if (options.config.auto_provision === false)
1774
+ return null;
1775
+ const installDir = options.config.install_dir ?? join6(options.homeDir, ".omo", "codegraph");
1776
+ const result = await options.ensureProvisioned({
1777
+ installDir,
1778
+ lockDir: join6(installDir, ".locks"),
1779
+ version: CODEGRAPH_VERSION
1780
+ });
1781
+ if (!result.provisioned || result.binPath === undefined)
1782
+ return null;
1783
+ return { argsPrefix: [], command: result.binPath, exists: true, source: "provisioned" };
1784
+ }
1534
1785
  function shouldSkipResolvedCommand(resolution, commandExists) {
1535
1786
  if (resolution.source !== "env")
1536
1787
  return false;
@@ -1548,8 +1799,8 @@ function codegraphEnvForConfig(config, homeDir, buildEnv) {
1548
1799
  function provisionedBinFromInstallDir(installDir) {
1549
1800
  if (installDir === undefined)
1550
1801
  return null;
1551
- const candidate = join5(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
1552
- return existsSync4(candidate) ? candidate : null;
1802
+ const candidate = join6(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
1803
+ return existsSync5(candidate) ? candidate : null;
1553
1804
  }
1554
1805
  async function runCodegraphServeCli() {
1555
1806
  process.exitCode = await runCodegraphServe();
@@ -1591,7 +1842,7 @@ function isDirectInvocation(argvPath) {
1591
1842
  if (argvPath === undefined)
1592
1843
  return false;
1593
1844
  const modulePath = fileURLToPath(import.meta.url);
1594
- const moduleName = basename2(modulePath);
1845
+ const moduleName = basename3(modulePath);
1595
1846
  if (moduleName !== "serve.js" && moduleName !== "serve.ts")
1596
1847
  return false;
1597
1848
  return realpathSync(resolve2(argvPath)) === realpathSync(modulePath);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sisyphuslabs/codex-codegraph",
3
- "version": "4.11.1",
3
+ "version": "4.12.1",
4
4
  "description": "Codex plugin MCP wrapper for CodeGraph.",
5
5
  "type": "module",
6
6
  "private": true,
@@ -5,8 +5,10 @@ import { stderr as processStderr } from "node:process";
5
5
  import { fileURLToPath } from "node:url";
6
6
 
7
7
  import {
8
+ runCodegraphPostToolUseHookCli,
8
9
  runCodegraphSessionStartHook,
9
10
  runCodegraphSessionStartWorker,
11
+ type PostToolUseHookOptions,
10
12
  type SessionStartHookOptions,
11
13
  type SessionStartWorkerOptions,
12
14
  } from "./hook.js";
@@ -25,6 +27,15 @@ export async function runCodegraphCli(options: RunCodegraphCliOptions = {}): Pro
25
27
  return runCodegraphSessionStartHook(options);
26
28
  }
27
29
 
30
+ if (command === "hook" && subcommand === "post-tool-use") {
31
+ const hookOptions: PostToolUseHookOptions = {
32
+ ...(options.env === undefined ? {} : { env: options.env }),
33
+ ...(options.stdin === undefined ? {} : { stdin: options.stdin }),
34
+ ...(options.stdout === undefined ? {} : { stdout: options.stdout }),
35
+ };
36
+ return runCodegraphPostToolUseHookCli(hookOptions);
37
+ }
38
+
28
39
  if (command === "hook" && subcommand === "session-start-worker") {
29
40
  const workerOptions: SessionStartWorkerOptions = {
30
41
  ...options.workerOptions,
@@ -10,6 +10,7 @@ import type { CodegraphWorkspacePreparation as SharedCodegraphWorkspacePreparati
10
10
  import type { CodegraphConfig as SharedCodegraphConfig } from "../../../../../utils/src/omo-config.ts";
11
11
 
12
12
  export type SessionStartAction = "skipped-disabled" | "spawned";
13
+ export type PostToolUseAction = "emitted-guidance" | "skipped";
13
14
  export type WorkerAction = "failed" | "initialized" | "skipped-disabled" | "skipped-status" | "skipped-unavailable" | "skipped-unsupported-node" | "synced";
14
15
 
15
16
  export interface WorkerSpawnInvocation {
@@ -27,6 +28,11 @@ export interface SessionStartHookResult {
27
28
  readonly exitCode: 0;
28
29
  }
29
30
 
31
+ export interface PostToolUseHookResult {
32
+ readonly action: PostToolUseAction;
33
+ readonly exitCode: 0;
34
+ }
35
+
30
36
  export interface CodegraphCommandResult {
31
37
  readonly exitCode: number;
32
38
  readonly stderr?: string;
@@ -73,6 +79,12 @@ export interface SessionStartHookOptions {
73
79
  readonly workerCliPath?: string;
74
80
  }
75
81
 
82
+ export interface PostToolUseHookOptions {
83
+ readonly env?: Record<string, string | undefined>;
84
+ readonly stdin?: Readable & { readonly isTTY?: boolean };
85
+ readonly stdout?: HookStdout;
86
+ }
87
+
76
88
  export interface SessionStartWorkerOptions {
77
89
  readonly config?: CodexOmoConfig;
78
90
  readonly cwd?: string;
@@ -4,10 +4,13 @@ import { cwd as processCwd, env as processEnv, stdin as processStdin, stdout as
4
4
  import type { Readable } from "node:stream";
5
5
  import { fileURLToPath } from "node:url";
6
6
 
7
+ import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
7
8
  import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
8
9
  import { SESSION_START_CWD_ENV } from "./session-start-worker.js";
9
10
  import type {
10
11
  HookStdout,
12
+ PostToolUseHookOptions,
13
+ PostToolUseHookResult,
11
14
  SessionStartHookOptions,
12
15
  SessionStartHookResult,
13
16
  WorkerSpawnInvocation,
@@ -23,6 +26,8 @@ export type {
23
26
  CodexOmoConfig,
24
27
  HookStdout,
25
28
  OmoConfigSource,
29
+ PostToolUseHookOptions,
30
+ PostToolUseHookResult,
26
31
  SessionStartAction,
27
32
  SessionStartHookOptions,
28
33
  SessionStartHookResult,
@@ -38,6 +43,10 @@ export async function runCodegraphSessionStartHook(options: SessionStartHookOpti
38
43
  return (await executeCodegraphSessionStartHook(options)).exitCode;
39
44
  }
40
45
 
46
+ export async function runCodegraphPostToolUseHookCli(options: PostToolUseHookOptions = {}): Promise<number> {
47
+ return (await executeCodegraphPostToolUseHook(options)).exitCode;
48
+ }
49
+
41
50
  export async function executeCodegraphSessionStartHook(options: SessionStartHookOptions = {}): Promise<SessionStartHookResult> {
42
51
  const env = options.env ?? processEnv;
43
52
  const input = await readHookInput(options.stdin ?? processStdin);
@@ -58,6 +67,31 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
58
67
  return { action: "spawned", exitCode: 0 };
59
68
  }
60
69
 
70
+ export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
71
+ const env = options.env ?? processEnv;
72
+ const input = await readHookInput(options.stdin ?? processStdin);
73
+ const output = runCodegraphPostToolUseHook(input, { homeDir: resolveHomeDir(env) });
74
+ if (output.length === 0) return { action: "skipped", exitCode: 0 };
75
+
76
+ (options.stdout ?? processStdout).write(output);
77
+ return { action: "emitted-guidance", exitCode: 0 };
78
+ }
79
+
80
+ export function runCodegraphPostToolUseHook(input: unknown, options: { readonly homeDir?: string } = {}): string {
81
+ const toolName = isRecord(input) ? input["tool_name"] : undefined;
82
+ const cwd = isRecord(input) ? input["cwd"] : undefined;
83
+ const toolOutput = isRecord(input) ? (input["tool_response"] ?? input["tool_output"] ?? input["response"]) : input;
84
+ const guidance = buildCodegraphInitGuidanceForToolResult({ cwd, toolName, toolOutput }, options);
85
+ if (guidance === null) return "";
86
+
87
+ return `${JSON.stringify({
88
+ hookSpecificOutput: {
89
+ hookEventName: "PostToolUse",
90
+ additionalContext: guidance,
91
+ },
92
+ })}\n`;
93
+ }
94
+
61
95
  function writeHookJson(stdout: HookStdout): void {
62
96
  const output = {
63
97
  hookSpecificOutput: {