oh-my-opencode 4.19.1 → 4.19.3
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/.agents/command/publish.md +95 -28
- package/.agents/skills/publish/SKILL.md +20 -6
- package/.opencode/command/publish.md +95 -28
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +2 -2
- package/README.ru.md +2 -2
- package/README.zh-cn.md +2 -2
- package/THIRD-PARTY-NOTICES.md +7 -7
- package/dist/agents/atlas/agent.d.ts +4 -2
- package/dist/agents/explore.d.ts +4 -2
- package/dist/agents/hephaestus/agent.d.ts +4 -2
- package/dist/agents/librarian.d.ts +4 -2
- package/dist/agents/metis.d.ts +4 -2
- package/dist/agents/momus.d.ts +3 -2
- package/dist/agents/multimodal-looker.d.ts +4 -2
- package/dist/agents/oracle.d.ts +4 -2
- package/dist/agents/sisyphus/claude-opus-5.d.ts +33 -0
- package/dist/agents/sisyphus/index.d.ts +2 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +5 -2
- package/dist/agents/sisyphus-junior/agent.d.ts +4 -1
- package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +1 -1
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/config-migrate.d.ts +8 -0
- package/dist/cli/doctor/checks/legacy-config-leftovers.d.ts +10 -0
- package/dist/cli/doctor/checks/model-resolution-config.d.ts +1 -1
- package/dist/cli/doctor/checks/tools-lsp.d.ts +1 -1
- package/dist/cli/doctor/framework/constants.d.ts +1 -1
- package/dist/cli/index.js +95391 -88524
- package/dist/cli-node/index.js +95504 -88637
- package/dist/config/schema/agent-names.d.ts +26 -26
- package/dist/config/schema/agent-overrides.d.ts +400 -400
- package/dist/config/schema/browser-automation.d.ts +2 -2
- package/dist/config/schema/categories.d.ts +36 -36
- package/dist/config/schema/commands.d.ts +2 -2
- package/dist/config/schema/dynamic-context-pruning.d.ts +1 -1
- package/dist/config/schema/experimental.d.ts +1 -1
- package/dist/config/schema/fallback-models.d.ts +25 -25
- package/dist/config/schema/hooks.d.ts +43 -43
- package/dist/config/schema/internal/permission.d.ts +9 -9
- package/dist/config/schema/keyword-detector.d.ts +6 -6
- package/dist/config/schema/oh-my-opencode-config.d.ts +402 -402
- package/dist/config/schema/tmux.d.ts +6 -6
- package/dist/config/validate.d.ts +2 -1
- package/dist/config-migration/deep-diff.d.ts +1 -0
- package/dist/config-migration/discovery-paths.d.ts +11 -0
- package/dist/config-migration/discovery-roots.d.ts +7 -0
- package/dist/config-migration/discovery.d.ts +4 -0
- package/dist/config-migration/index.d.ts +9 -0
- package/dist/config-migration/legacy-history.d.ts +3 -0
- package/dist/config-migration/migration-executor.d.ts +4 -0
- package/dist/config-migration/migration-plans.d.ts +14 -0
- package/dist/config-migration/record-values.d.ts +4 -0
- package/dist/config-migration/schema-url.d.ts +1 -0
- package/dist/config-migration/transform-config-jsonc.d.ts +2 -0
- package/dist/config-migration/transform-opencode.d.ts +2 -0
- package/dist/config-migration/transform-types.d.ts +24 -0
- package/dist/config-migration/types.d.ts +39 -0
- package/dist/create-hooks.d.ts +35 -35
- package/dist/features/background-agent/spawner/tmux-callback-invoker.d.ts +11 -0
- package/dist/features/builtin-commands/templates/hyperplan.d.ts +1 -1
- package/dist/features/builtin-commands/templates/start-work.d.ts +1 -1
- package/dist/features/claude-tasks/types.d.ts +4 -4
- package/dist/features/team-mode/team-runtime/shutdown-helpers.d.ts +1 -1
- package/dist/features/team-mode/team-runtime/shutdown-test-fixtures.d.ts +4 -4
- package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +42 -42
- package/dist/features/tmux-subagent/environment-eligibility.d.ts +2 -0
- package/dist/features/tmux-subagent/index.d.ts +1 -0
- package/dist/features/tmux-subagent/tracked-session-state.d.ts +1 -0
- package/dist/features/tui-sidebar/snapshot-schema.d.ts +6 -6
- package/dist/help/schema/acp.d.ts +3 -3
- package/dist/help/schema/doctor.d.ts +4 -4
- package/dist/help/schema/status.d.ts +3 -3
- package/dist/hooks/auto-update-checker/constants.d.ts +3 -3
- package/dist/hooks/goal/types.d.ts +5 -5
- package/dist/hooks/non-interactive-env/constants.d.ts +4 -1
- package/dist/hooks/start-work/parse-user-request.d.ts +2 -0
- package/dist/hooks/start-work/worktree-block.d.ts +5 -0
- package/dist/index.js +35450 -28257
- package/dist/mcp/types.d.ts +3 -3
- package/dist/oh-my-opencode.schema.json +1 -1
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -0
- package/dist/plugin/command-execute-before.d.ts +3 -3
- package/dist/plugin/hooks/create-core-hooks.d.ts +25 -25
- package/dist/plugin-config/omo-config-chain.d.ts +14 -0
- package/dist/plugin-config/unknown-key-diagnostics.d.ts +5 -0
- package/dist/plugin-config.d.ts +2 -2
- package/dist/shared/agent-display-names.d.ts +1 -1
- package/dist/shared/jsonc-parser.d.ts +1 -1
- package/dist/shared/migration.d.ts +5 -1
- package/dist/shared/opencode-config-dir-types.d.ts +0 -1
- package/dist/shared/plugin-identity.d.ts +6 -8
- package/dist/shared/project-discovery-dirs.d.ts +0 -1
- package/dist/shared/tmux/tmux-utils/environment.d.ts +1 -1
- package/dist/shared/tmux/tmux-utils.d.ts +1 -1
- package/dist/shared/typescript-native-source-parser.d.ts +7 -0
- package/dist/skills/coding-agent-sessions/SKILL.md +5 -2
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/dist/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/dist/skills/debugging/SKILL.md +2 -1
- package/dist/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/dist/skills/frontend/ATTRIBUTION.md +7 -0
- package/dist/skills/frontend/SKILL.md +4 -1
- package/dist/skills/frontend/references/design/README.md +8 -0
- package/dist/skills/frontend/references/design/_INDEX.md +14 -1
- package/dist/skills/frontend/references/design/interaction-skill.md +144 -0
- package/dist/skills/programming/SKILL.md +11 -1
- package/dist/skills/programming/references/logging.md +6 -1
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
- package/dist/skills/start-work/SKILL.md +12 -2
- package/dist/skills/ulw-plan/SKILL.md +1 -1
- package/dist/skills/ulw-plan/references/full-workflow.md +12 -1
- package/dist/skills/ulw-plan/references/intent-clear.md +1 -1
- package/dist/startup-migration.d.ts +28 -0
- package/dist/testing/create-plugin-module.d.ts +4 -0
- package/dist/tools/task/types.d.ts +10 -10
- package/dist/tui.js +31812 -26849
- package/package.json +14 -14
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +21 -5
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +11 -2
- package/packages/omo-codex/THIRD-PARTY-NOTICES.md +2 -2
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +8 -4
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +11 -5
- package/packages/omo-codex/plugin/components/codegraph/NOTICE +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +10272 -2600
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +7341 -562
- package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
- package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +33 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +36 -10
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +170 -186
- package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +22 -5
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +106 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +145 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +21 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +139 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +15 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +32 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +109 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +148 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +126 -186
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +9 -4
- package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +160 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +12 -110
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +29 -20
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +3 -3
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +11 -5
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -3
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +2 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +50 -5
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +3 -2
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +24 -13
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +70 -13
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +58 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +104 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +4 -2
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +116 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +114 -119
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +31 -14
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +12 -7
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +12 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +12 -7
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +19 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +42 -41
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/src/config-loader.ts +165 -16
- package/packages/omo-codex/plugin/shared/src/config-migration.ts +162 -0
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +196 -18
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +5 -2
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +7 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +8 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +14 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +144 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +11 -1
- package/packages/omo-codex/plugin/skills/programming/references/logging.md +6 -1
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +12 -7
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +19 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +1 -1
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +22 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +1 -1
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +5 -2
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +15 -5
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +46 -0
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +19 -10
- package/packages/shared-skills/skills/debugging/SKILL.md +2 -1
- package/packages/shared-skills/skills/debugging/references/methodology/03-flaky-triage.md +47 -0
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +7 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +4 -1
- package/packages/shared-skills/skills/frontend/references/design/README.md +8 -0
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +14 -1
- package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +144 -0
- package/packages/shared-skills/skills/programming/SKILL.md +11 -1
- package/packages/shared-skills/skills/programming/references/logging.md +6 -1
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +51 -17
- package/packages/shared-skills/skills/start-work/SKILL.md +12 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +12 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +1 -1
- package/dist/plugin-config/layered-config-loader.d.ts +0 -2
- package/dist/plugin-config/single-config-loader.d.ts +0 -4
- package/dist/shared/migrate-legacy-config-file.d.ts +0 -1
- package/dist/shared/migration/config-migration.d.ts +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sisyphuslabs/codex-codegraph",
|
|
3
|
-
"version": "4.19.
|
|
3
|
+
"version": "4.19.3",
|
|
4
4
|
"description": "Codex plugin MCP wrapper for CodeGraph.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": true,
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"typescript": "^6.0.3"
|
|
26
26
|
},
|
|
27
27
|
"optionalDependencies": {
|
|
28
|
-
"@colbymchenry/codegraph": "1.
|
|
28
|
+
"@colbymchenry/codegraph": "1.5.0"
|
|
29
29
|
},
|
|
30
30
|
"engines": {
|
|
31
31
|
"node": ">=20.0.0"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import type { Readable } from "node:stream";
|
|
3
|
+
|
|
4
|
+
export function resolveHomeDir(env: Record<string, string | undefined>): string {
|
|
5
|
+
return env["HOME"] ?? env["USERPROFILE"] ?? homedir();
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function resolveHookProjectRoot(input: unknown, fallback: string): string {
|
|
9
|
+
if (!isRecord(input)) return fallback;
|
|
10
|
+
const cwd = input["cwd"];
|
|
11
|
+
return typeof cwd === "string" && cwd.trim().length > 0 ? cwd : fallback;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function readHookInput(stdin: Readable & { readonly isTTY?: boolean }): Promise<unknown> {
|
|
15
|
+
if (stdin.isTTY === true) return undefined;
|
|
16
|
+
let text = "";
|
|
17
|
+
for await (const chunk of stdin) text += typeof chunk === "string" ? chunk : String(chunk);
|
|
18
|
+
if (text.trim().length === 0) return undefined;
|
|
19
|
+
return parseJson(text);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isRecord(value: unknown): value is Record<string, unknown> {
|
|
23
|
+
return typeof value === "object" && value !== null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseJson(text: string): unknown {
|
|
27
|
+
try {
|
|
28
|
+
return JSON.parse(text);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error instanceof SyntaxError) return undefined;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -10,10 +10,32 @@ import type {
|
|
|
10
10
|
} from "../../../../../utils/src/codegraph/resolve.ts";
|
|
11
11
|
import type { CodegraphWorkspacePreparation as SharedCodegraphWorkspacePreparation } from "../../../../../utils/src/codegraph/workspace.ts";
|
|
12
12
|
import type { CodegraphConfig as SharedCodegraphConfig } from "../../../../../utils/src/omo-config.ts";
|
|
13
|
+
import type { CodegraphAncestorState, CodegraphProjectState } from "./session-start-project.js";
|
|
13
14
|
|
|
14
|
-
export type SessionStartAction =
|
|
15
|
+
export type SessionStartAction =
|
|
16
|
+
| "skipped-cooldown"
|
|
17
|
+
| "skipped-disabled"
|
|
18
|
+
| "skipped-excluded"
|
|
19
|
+
| "skipped-inconclusive"
|
|
20
|
+
| "skipped-initialized"
|
|
21
|
+
| "skipped-locked"
|
|
22
|
+
| "skipped-nested-root"
|
|
23
|
+
| "skipped-spawn-error"
|
|
24
|
+
| "spawned";
|
|
15
25
|
export type PostToolUseAction = "emitted-guidance" | "skipped";
|
|
16
|
-
export type WorkerAction =
|
|
26
|
+
export type WorkerAction =
|
|
27
|
+
| "failed"
|
|
28
|
+
| "initialized"
|
|
29
|
+
| "skipped-disabled"
|
|
30
|
+
| "skipped-initialized"
|
|
31
|
+
| "skipped-locked"
|
|
32
|
+
| "skipped-nested-root"
|
|
33
|
+
| "skipped-probe-error"
|
|
34
|
+
| "skipped-status"
|
|
35
|
+
| "skipped-unavailable"
|
|
36
|
+
| "skipped-unsupported-node"
|
|
37
|
+
| "synced";
|
|
38
|
+
export type SessionStartOutcomeAction = SessionStartAction | WorkerAction;
|
|
17
39
|
|
|
18
40
|
export interface WorkerSpawnInvocation {
|
|
19
41
|
readonly args: readonly string[];
|
|
@@ -49,9 +71,12 @@ export type CodegraphProvisionResult = SharedCodegraphProvisionResult;
|
|
|
49
71
|
export type CodegraphWorkspacePreparation = SharedCodegraphWorkspacePreparation;
|
|
50
72
|
|
|
51
73
|
export interface CodegraphSessionStartOutcome {
|
|
52
|
-
readonly action:
|
|
74
|
+
readonly action: SessionStartOutcomeAction;
|
|
75
|
+
readonly ancestorRoot?: string;
|
|
76
|
+
readonly cooldownUntil?: number;
|
|
53
77
|
readonly error?: string;
|
|
54
78
|
readonly exitCode?: number;
|
|
79
|
+
readonly failureCount?: number;
|
|
55
80
|
readonly projectRoot?: string;
|
|
56
81
|
readonly source?: CodegraphCommandResolution["source"];
|
|
57
82
|
readonly timedOut?: boolean;
|
|
@@ -60,8 +85,10 @@ export interface CodegraphSessionStartOutcome {
|
|
|
60
85
|
export interface CodegraphSessionStartDeps {
|
|
61
86
|
readonly ensureGitignored: (projectRoot: string) => boolean;
|
|
62
87
|
readonly ensureProvisioned: (options: { readonly installDir?: string; readonly lockDir: string; readonly version: typeof CODEGRAPH_PINNED_VERSION }) => Promise<CodegraphProvisionResult>;
|
|
88
|
+
readonly managedInstallExists: (installDir: string) => boolean;
|
|
63
89
|
readonly prepareWorkspace: (projectRoot: string, options: { readonly homeDir: string }) => CodegraphWorkspacePreparation;
|
|
64
90
|
readonly resolveCommand: (options?: ResolveCodegraphCommandOptions) => CodegraphCommandResolution;
|
|
91
|
+
readonly resolveManagedBin: (installDir: string) => string | null;
|
|
65
92
|
readonly runCommand: (
|
|
66
93
|
projectRoot: string,
|
|
67
94
|
command: string,
|
|
@@ -71,18 +98,15 @@ export interface CodegraphSessionStartDeps {
|
|
|
71
98
|
}
|
|
72
99
|
|
|
73
100
|
export interface SessionStartHookOptions {
|
|
101
|
+
readonly ancestorProbe?: (projectRoot: string) => CodegraphAncestorState;
|
|
74
102
|
readonly argv?: readonly string[];
|
|
75
103
|
readonly config?: CodexOmoConfig;
|
|
76
104
|
readonly cwd?: string;
|
|
77
105
|
readonly env?: Record<string, string | undefined>;
|
|
106
|
+
readonly lockStaleMs?: number;
|
|
107
|
+
readonly logOutcome?: (outcome: CodegraphSessionStartOutcome) => void;
|
|
108
|
+
readonly nowMs?: number;
|
|
78
109
|
readonly spawnWorker?: (invocation: WorkerSpawnInvocation) => void;
|
|
79
|
-
readonly statusProbe?: (options: {
|
|
80
|
-
readonly daemon: boolean;
|
|
81
|
-
readonly env: Record<string, string | undefined>;
|
|
82
|
-
readonly homeDir: string;
|
|
83
|
-
readonly projectRoot: string;
|
|
84
|
-
readonly trustedCodegraphInstallDir?: string;
|
|
85
|
-
}) => Promise<boolean>;
|
|
86
110
|
readonly stdin?: Readable & { readonly isTTY?: boolean };
|
|
87
111
|
readonly stdout?: HookStdout;
|
|
88
112
|
readonly sweepZombies?: (options: SweepCodegraphZombiesOptions) => Promise<unknown> | unknown;
|
|
@@ -102,4 +126,6 @@ export interface SessionStartWorkerOptions {
|
|
|
102
126
|
readonly env?: Record<string, string | undefined>;
|
|
103
127
|
readonly logOutcome?: (outcome: CodegraphSessionStartOutcome) => void;
|
|
104
128
|
readonly nodeVersion?: string;
|
|
129
|
+
readonly nowMs?: number;
|
|
130
|
+
readonly projectProbe?: (projectRoot: string) => CodegraphProjectState;
|
|
105
131
|
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { execFile, spawn } from "node:child_process";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
1
|
import {
|
|
5
2
|
cwd as processCwd,
|
|
6
3
|
env as processEnv,
|
|
@@ -8,25 +5,33 @@ import {
|
|
|
8
5
|
stdin as processStdin,
|
|
9
6
|
stdout as processStdout,
|
|
10
7
|
} from "node:process";
|
|
11
|
-
import type { Readable } from "node:stream";
|
|
12
8
|
import { fileURLToPath } from "node:url";
|
|
13
9
|
|
|
14
|
-
import { buildCodegraphChildEnv
|
|
15
|
-
import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
|
|
16
|
-
import { resolveCodegraphCommand } from "../../../../../utils/src/codegraph/resolve.ts";
|
|
10
|
+
import { buildCodegraphChildEnv } from "../../../../../utils/src/codegraph/env.ts";
|
|
17
11
|
import { shouldExcludeCodegraphProject } from "../../../../../utils/src/codegraph/workspace.ts";
|
|
18
12
|
import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
|
|
19
13
|
import { pruneCodegraphProjectStoresBestEffort } from "./cache-gc.js";
|
|
14
|
+
import { readHookInput, resolveHomeDir, resolveHookProjectRoot } from "./hook-input.js";
|
|
20
15
|
import { sweepCodegraphZombiesBestEffort } from "./hook-sweep.js";
|
|
21
|
-
import { resolveCodegraphCommandInvocation, SESSION_START_CWD_ENV } from "./session-start-worker.js";
|
|
22
16
|
import type {
|
|
23
|
-
|
|
24
|
-
PostToolUseHookOptions,
|
|
25
|
-
PostToolUseHookResult,
|
|
17
|
+
CodegraphSessionStartOutcome,
|
|
26
18
|
SessionStartHookOptions,
|
|
27
19
|
SessionStartHookResult,
|
|
28
|
-
WorkerSpawnInvocation,
|
|
29
20
|
} from "./hook-types.js";
|
|
21
|
+
import {
|
|
22
|
+
DEFAULT_SESSION_START_COOLDOWN_MS,
|
|
23
|
+
readSessionStartCooldown,
|
|
24
|
+
recordSessionStartFailure,
|
|
25
|
+
} from "./session-start-cooldown.js";
|
|
26
|
+
import { spawnDetachedSessionStartWorker, writeSessionStartNotice } from "./session-start-hook-runtime.js";
|
|
27
|
+
import { acquireSessionStartLock, releaseSessionStartLock, type SessionStartLock } from "./session-start-lock.js";
|
|
28
|
+
import { appendSessionStartOutcome } from "./session-start-outcome.js";
|
|
29
|
+
import {
|
|
30
|
+
probeCodegraphAncestors,
|
|
31
|
+
probeExactCodegraphProject,
|
|
32
|
+
type CodegraphProjectState,
|
|
33
|
+
} from "./session-start-project.js";
|
|
34
|
+
import { SESSION_START_CWD_ENV, SESSION_START_LOCK_TOKEN_ENV } from "./session-start-worker.js";
|
|
30
35
|
|
|
31
36
|
export type {
|
|
32
37
|
CodegraphCommandResult,
|
|
@@ -47,25 +52,46 @@ export type {
|
|
|
47
52
|
WorkerAction,
|
|
48
53
|
WorkerSpawnInvocation,
|
|
49
54
|
} from "./hook-types.js";
|
|
50
|
-
export {
|
|
55
|
+
export {
|
|
56
|
+
executeCodegraphPostToolUseHook,
|
|
57
|
+
runCodegraphPostToolUseHook,
|
|
58
|
+
runCodegraphPostToolUseHookCli,
|
|
59
|
+
} from "./post-tool-use-hook.js";
|
|
60
|
+
export { resolveCodegraphCommandInvocation } from "./session-start-command.js";
|
|
61
|
+
export { runCodegraphSessionStartWorker } from "./session-start-worker.js";
|
|
51
62
|
|
|
52
63
|
export const CODEGRAPH_SESSION_START_NOTICE = "LazyCodex CodeGraph bootstrap scheduled in background";
|
|
53
|
-
const
|
|
64
|
+
export const DEFAULT_SESSION_START_LOCK_STALE_MS = 10 * 60 * 1_000;
|
|
65
|
+
|
|
66
|
+
type HookContext = {
|
|
67
|
+
readonly baseCooldownMs: number;
|
|
68
|
+
readonly env: Record<string, string | undefined>;
|
|
69
|
+
readonly homeDir: string;
|
|
70
|
+
readonly logOutcome: (outcome: CodegraphSessionStartOutcome) => void;
|
|
71
|
+
readonly nowMs: number;
|
|
72
|
+
readonly options: SessionStartHookOptions;
|
|
73
|
+
readonly projectRoot: string;
|
|
74
|
+
};
|
|
54
75
|
|
|
55
76
|
export async function runCodegraphSessionStartHook(options: SessionStartHookOptions = {}): Promise<number> {
|
|
56
77
|
return (await executeCodegraphSessionStartHook(options)).exitCode;
|
|
57
78
|
}
|
|
58
79
|
|
|
59
|
-
export async function runCodegraphPostToolUseHookCli(options: PostToolUseHookOptions = {}): Promise<number> {
|
|
60
|
-
return (await executeCodegraphPostToolUseHook(options)).exitCode;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
80
|
export async function executeCodegraphSessionStartHook(options: SessionStartHookOptions = {}): Promise<SessionStartHookResult> {
|
|
64
81
|
const env = options.env ?? processEnv;
|
|
65
82
|
const input = await readHookInput(options.stdin ?? processStdin);
|
|
66
|
-
const projectRoot =
|
|
83
|
+
const projectRoot = resolveHookProjectRoot(input, options.cwd ?? processCwd());
|
|
67
84
|
const homeDir = resolveHomeDir(env);
|
|
68
85
|
const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
|
|
86
|
+
if (config.codegraph?.enabled === false) return { action: "skipped-disabled", exitCode: 0 };
|
|
87
|
+
|
|
88
|
+
const excludedRoots = config.codegraph?.excluded_roots;
|
|
89
|
+
const exclusion = shouldExcludeCodegraphProject(projectRoot, {
|
|
90
|
+
homeDir,
|
|
91
|
+
...(excludedRoots === undefined ? {} : { excludedRoots }),
|
|
92
|
+
});
|
|
93
|
+
if (exclusion.excluded) return { action: "skipped-excluded", exitCode: 0 };
|
|
94
|
+
|
|
69
95
|
pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
|
|
70
96
|
await sweepCodegraphZombiesBestEffort({
|
|
71
97
|
env,
|
|
@@ -74,199 +100,157 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
|
|
|
74
100
|
log: writeDebugLog,
|
|
75
101
|
}, options.sweepZombies);
|
|
76
102
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const exclusion = shouldExcludeCodegraphProject(projectRoot, {
|
|
103
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
104
|
+
const context: HookContext = {
|
|
105
|
+
baseCooldownMs: config.codegraph?.session_start_cooldown_ms ?? DEFAULT_SESSION_START_COOLDOWN_MS,
|
|
106
|
+
env,
|
|
82
107
|
homeDir,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
108
|
+
logOutcome: options.logOutcome ?? ((outcome) => appendSessionStartOutcome(homeDir, outcome, nowMs)),
|
|
109
|
+
nowMs,
|
|
110
|
+
options,
|
|
111
|
+
projectRoot,
|
|
112
|
+
};
|
|
113
|
+
const projectDecision = handleProjectState(resolveHookProjectState(context), context);
|
|
114
|
+
if (projectDecision !== null) return projectDecision;
|
|
88
115
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
env,
|
|
116
|
+
const cooldown = readSessionStartCooldown({
|
|
117
|
+
baseCooldownMs: context.baseCooldownMs,
|
|
92
118
|
homeDir,
|
|
119
|
+
nowMs,
|
|
93
120
|
projectRoot,
|
|
94
|
-
...(config.trustedCodegraphInstallDir === undefined ? {} : { trustedCodegraphInstallDir: config.trustedCodegraphInstallDir }),
|
|
95
121
|
});
|
|
96
|
-
if (
|
|
97
|
-
|
|
122
|
+
if (cooldown.kind === "inconclusive") return { action: "skipped-inconclusive", exitCode: 0 };
|
|
123
|
+
if (cooldown.kind === "active") {
|
|
124
|
+
safeLogOutcome(context.logOutcome, {
|
|
125
|
+
action: "skipped-cooldown",
|
|
126
|
+
cooldownUntil: cooldown.cooldownUntil,
|
|
127
|
+
failureCount: cooldown.failureCount,
|
|
128
|
+
projectRoot,
|
|
129
|
+
});
|
|
130
|
+
return { action: "skipped-cooldown", exitCode: 0 };
|
|
98
131
|
}
|
|
99
132
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
codegraphEnv: { [SESSION_START_CWD_ENV]: projectRoot },
|
|
106
|
-
runtimeEnv: env,
|
|
107
|
-
}),
|
|
108
|
-
});
|
|
109
|
-
writeHookJson(options.stdout ?? processStdout);
|
|
110
|
-
return { action: "spawned", exitCode: 0 };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async function isCodegraphProjectInitialized(options: {
|
|
114
|
-
readonly daemon: boolean;
|
|
115
|
-
readonly env: Record<string, string | undefined>;
|
|
116
|
-
readonly homeDir: string;
|
|
117
|
-
readonly projectRoot: string;
|
|
118
|
-
readonly trustedCodegraphInstallDir?: string;
|
|
119
|
-
}): Promise<boolean> {
|
|
120
|
-
const resolved = resolveCodegraphCommand({
|
|
121
|
-
env: options.env,
|
|
122
|
-
homeDir: options.homeDir,
|
|
123
|
-
provisioned: () => provisionedBinFromInstallDir(options.trustedCodegraphInstallDir),
|
|
124
|
-
});
|
|
125
|
-
if (!resolved.exists) return false;
|
|
126
|
-
|
|
127
|
-
const invocation = resolveCodegraphCommandInvocation(resolved.command, [...resolved.argsPrefix, "status", "--json"]);
|
|
128
|
-
const codegraphEnv = {
|
|
129
|
-
...buildCodegraphEnv({ daemon: options.daemon, homeDir: options.homeDir }),
|
|
130
|
-
...(options.trustedCodegraphInstallDir === undefined ? {} : { CODEGRAPH_INSTALL_DIR: options.trustedCodegraphInstallDir }),
|
|
131
|
-
};
|
|
132
|
-
const status = await runStatusProbe(
|
|
133
|
-
options.projectRoot,
|
|
134
|
-
invocation.command,
|
|
135
|
-
invocation.args,
|
|
136
|
-
buildCodegraphChildEnv({ ambientEnv: options.env, codegraphEnv, runtimeEnv: options.env }),
|
|
137
|
-
);
|
|
138
|
-
if (status.exitCode !== 0 || status.timedOut) return false;
|
|
139
|
-
return codegraphStatusSaysInitialized(status.stdout);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function runStatusProbe(
|
|
143
|
-
projectRoot: string,
|
|
144
|
-
command: string,
|
|
145
|
-
args: readonly string[],
|
|
146
|
-
env: Record<string, string>,
|
|
147
|
-
): Promise<{ readonly exitCode: number; readonly stdout: string; readonly timedOut: boolean }> {
|
|
148
|
-
return new Promise((resolveProbe) => {
|
|
149
|
-
execFile(
|
|
150
|
-
command,
|
|
151
|
-
[...args],
|
|
152
|
-
{
|
|
153
|
-
cwd: projectRoot,
|
|
154
|
-
encoding: "utf8",
|
|
155
|
-
env,
|
|
156
|
-
maxBuffer: 1024 * 1024,
|
|
157
|
-
timeout: STATUS_PROBE_TIMEOUT_MS,
|
|
158
|
-
windowsHide: true,
|
|
159
|
-
},
|
|
160
|
-
(error, stdout) => {
|
|
161
|
-
if (error === null) {
|
|
162
|
-
resolveProbe({ exitCode: 0, stdout: toOutputText(stdout), timedOut: false });
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
resolveProbe({ exitCode: resolveExitCode(error), stdout: toOutputText(stdout), timedOut: error.killed === true });
|
|
166
|
-
},
|
|
167
|
-
);
|
|
133
|
+
const lockResult = acquireSessionStartLock({
|
|
134
|
+
homeDir,
|
|
135
|
+
nowMs,
|
|
136
|
+
projectRoot,
|
|
137
|
+
staleMs: options.lockStaleMs ?? DEFAULT_SESSION_START_LOCK_STALE_MS,
|
|
168
138
|
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (typeof initialized === "boolean") return initialized;
|
|
176
|
-
const status = parsed["status"];
|
|
177
|
-
if (typeof status !== "string") return false;
|
|
178
|
-
const normalized = status.toLowerCase();
|
|
179
|
-
return (normalized.includes("initialized") || normalized.includes("ready")) && !normalized.includes("not initialized") && !normalized.includes("uninitialized");
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
|
|
183
|
-
if (installDir === undefined) return null;
|
|
184
|
-
return join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
|
|
188
|
-
const env = options.env ?? processEnv;
|
|
189
|
-
const input = await readHookInput(options.stdin ?? processStdin);
|
|
190
|
-
const output = runCodegraphPostToolUseHook(input, { homeDir: resolveHomeDir(env) });
|
|
191
|
-
if (output.length === 0) return { action: "skipped", exitCode: 0 };
|
|
192
|
-
|
|
193
|
-
(options.stdout ?? processStdout).write(output);
|
|
194
|
-
return { action: "emitted-guidance", exitCode: 0 };
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function runCodegraphPostToolUseHook(input: unknown, options: { readonly homeDir?: string } = {}): string {
|
|
198
|
-
const toolName = isRecord(input) ? input["tool_name"] : undefined;
|
|
199
|
-
const cwd = isRecord(input) ? input["cwd"] : undefined;
|
|
200
|
-
const toolOutput = isRecord(input) ? (input["tool_response"] ?? input["tool_output"] ?? input["response"]) : input;
|
|
201
|
-
const guidance = buildCodegraphInitGuidanceForToolResult({ cwd, toolName, toolOutput }, options);
|
|
202
|
-
if (guidance === null) return "";
|
|
203
|
-
|
|
204
|
-
return `${JSON.stringify({
|
|
205
|
-
hookSpecificOutput: {
|
|
206
|
-
hookEventName: "PostToolUse",
|
|
207
|
-
additionalContext: guidance,
|
|
208
|
-
},
|
|
209
|
-
})}\n`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function writeHookJson(stdout: HookStdout): void {
|
|
213
|
-
const output = {
|
|
214
|
-
hookSpecificOutput: {
|
|
215
|
-
hookEventName: "SessionStart",
|
|
216
|
-
additionalContext: CODEGRAPH_SESSION_START_NOTICE,
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
stdout.write(`${JSON.stringify(output)}\n`);
|
|
220
|
-
}
|
|
139
|
+
if (lockResult.kind === "inconclusive") return { action: "skipped-inconclusive", exitCode: 0 };
|
|
140
|
+
if (lockResult.kind === "locked") {
|
|
141
|
+
safeLogOutcome(context.logOutcome, { action: "skipped-locked", projectRoot });
|
|
142
|
+
return { action: "skipped-locked", exitCode: 0 };
|
|
143
|
+
}
|
|
144
|
+
if (lockResult.recoveredStale) return handleRecoveredStaleLock(lockResult.lock, context);
|
|
221
145
|
|
|
222
|
-
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
|
|
146
|
+
const lockedProjectDecision = handleProjectState(resolveHookProjectState(context), context);
|
|
147
|
+
if (lockedProjectDecision !== null) {
|
|
148
|
+
releaseSessionStartLock(lockResult.lock);
|
|
149
|
+
return lockedProjectDecision;
|
|
150
|
+
}
|
|
226
151
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
152
|
+
try {
|
|
153
|
+
(options.spawnWorker ?? spawnDetachedSessionStartWorker)({
|
|
154
|
+
args: [options.workerCliPath ?? defaultWorkerCliPath(), "hook", "session-start-worker"],
|
|
155
|
+
command: process.execPath,
|
|
156
|
+
env: buildCodegraphChildEnv({
|
|
157
|
+
ambientEnv: env,
|
|
158
|
+
codegraphEnv: {
|
|
159
|
+
[SESSION_START_CWD_ENV]: projectRoot,
|
|
160
|
+
[SESSION_START_LOCK_TOKEN_ENV]: lockResult.lock.token,
|
|
161
|
+
},
|
|
162
|
+
runtimeEnv: env,
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
} catch (error) {
|
|
166
|
+
if (error instanceof Error) return handleSpawnFailure(error, lockResult.lock, context);
|
|
167
|
+
throw error;
|
|
168
|
+
}
|
|
231
169
|
|
|
232
|
-
|
|
233
|
-
return
|
|
170
|
+
writeSessionStartNotice(options.stdout ?? processStdout, CODEGRAPH_SESSION_START_NOTICE);
|
|
171
|
+
return { action: "spawned", exitCode: 0 };
|
|
234
172
|
}
|
|
235
173
|
|
|
236
|
-
function
|
|
237
|
-
|
|
238
|
-
return
|
|
174
|
+
function resolveHookProjectState(context: HookContext): CodegraphProjectState {
|
|
175
|
+
const exact = probeExactCodegraphProject(context.projectRoot);
|
|
176
|
+
if (exact.kind !== "uninitialized") return exact;
|
|
177
|
+
return (context.options.ancestorProbe ?? probeCodegraphAncestors)(context.projectRoot);
|
|
239
178
|
}
|
|
240
179
|
|
|
241
|
-
function
|
|
242
|
-
|
|
180
|
+
function handleProjectState(state: CodegraphProjectState, context: HookContext): SessionStartHookResult | null {
|
|
181
|
+
switch (state.kind) {
|
|
182
|
+
case "inconclusive":
|
|
183
|
+
return { action: "skipped-inconclusive", exitCode: 0 };
|
|
184
|
+
case "initialized":
|
|
185
|
+
return { action: "skipped-initialized", exitCode: 0 };
|
|
186
|
+
case "nested-root":
|
|
187
|
+
safeLogOutcome(context.logOutcome, { action: "skipped-nested-root", ancestorRoot: state.ancestorRoot, projectRoot: context.projectRoot });
|
|
188
|
+
return { action: "skipped-nested-root", exitCode: 0 };
|
|
189
|
+
case "uninitialized":
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
243
192
|
}
|
|
244
193
|
|
|
245
|
-
function
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
194
|
+
function handleRecoveredStaleLock(lock: SessionStartLock, context: HookContext): SessionStartHookResult {
|
|
195
|
+
try {
|
|
196
|
+
const cooldown = recordSessionStartFailure({
|
|
197
|
+
action: "stale-lock",
|
|
198
|
+
baseCooldownMs: context.baseCooldownMs,
|
|
199
|
+
homeDir: context.homeDir,
|
|
200
|
+
nowMs: context.nowMs,
|
|
201
|
+
projectRoot: context.projectRoot,
|
|
202
|
+
});
|
|
203
|
+
releaseSessionStartLock(lock);
|
|
204
|
+
safeLogOutcome(context.logOutcome, {
|
|
205
|
+
action: "skipped-cooldown",
|
|
206
|
+
cooldownUntil: cooldown.cooldownUntil,
|
|
207
|
+
error: "recovered stale SessionStart worker lock",
|
|
208
|
+
failureCount: cooldown.failureCount,
|
|
209
|
+
projectRoot: context.projectRoot,
|
|
210
|
+
});
|
|
211
|
+
return { action: "skipped-cooldown", exitCode: 0 };
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (error instanceof Error) return { action: "skipped-inconclusive", exitCode: 0 };
|
|
214
|
+
throw error;
|
|
215
|
+
}
|
|
249
216
|
}
|
|
250
217
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
218
|
+
function handleSpawnFailure(error: unknown, lock: SessionStartLock, context: HookContext): SessionStartHookResult {
|
|
219
|
+
try {
|
|
220
|
+
const cooldown = recordSessionStartFailure({
|
|
221
|
+
action: "spawn-failed",
|
|
222
|
+
baseCooldownMs: context.baseCooldownMs,
|
|
223
|
+
homeDir: context.homeDir,
|
|
224
|
+
nowMs: context.nowMs,
|
|
225
|
+
projectRoot: context.projectRoot,
|
|
226
|
+
});
|
|
227
|
+
releaseSessionStartLock(lock);
|
|
228
|
+
safeLogOutcome(context.logOutcome, {
|
|
229
|
+
action: "skipped-spawn-error",
|
|
230
|
+
cooldownUntil: cooldown.cooldownUntil,
|
|
231
|
+
error: error instanceof Error ? error.message : String(error),
|
|
232
|
+
failureCount: cooldown.failureCount,
|
|
233
|
+
projectRoot: context.projectRoot,
|
|
234
|
+
});
|
|
235
|
+
} catch (cooldownError) {
|
|
236
|
+
if (cooldownError instanceof Error) return { action: "skipped-inconclusive", exitCode: 0 };
|
|
237
|
+
throw cooldownError;
|
|
238
|
+
}
|
|
239
|
+
return { action: "skipped-spawn-error", exitCode: 0 };
|
|
257
240
|
}
|
|
258
241
|
|
|
259
|
-
function
|
|
242
|
+
function safeLogOutcome(logOutcome: (outcome: CodegraphSessionStartOutcome) => void, outcome: CodegraphSessionStartOutcome): void {
|
|
260
243
|
try {
|
|
261
|
-
|
|
244
|
+
logOutcome(outcome);
|
|
262
245
|
} catch (error) {
|
|
263
|
-
if (error instanceof
|
|
264
|
-
throw error;
|
|
246
|
+
if (error instanceof Error) writeDebugLog(`failed to write SessionStart outcome: ${error.message}`);
|
|
247
|
+
else throw error;
|
|
265
248
|
}
|
|
266
249
|
}
|
|
267
250
|
|
|
268
|
-
function
|
|
269
|
-
|
|
251
|
+
function writeDebugLog(message: string): void {
|
|
252
|
+
if (processEnv["OMO_CODEGRAPH_DEBUG"] !== "1") return;
|
|
253
|
+
processStderr.write(`${message}\n`);
|
|
270
254
|
}
|
|
271
255
|
|
|
272
256
|
function defaultWorkerCliPath(): string {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { env as processEnv, stdin as processStdin, stdout as processStdout } from "node:process";
|
|
2
|
+
|
|
3
|
+
import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
|
|
4
|
+
import { isRecord, readHookInput, resolveHomeDir } from "./hook-input.js";
|
|
5
|
+
import type { PostToolUseHookOptions, PostToolUseHookResult } from "./hook-types.js";
|
|
6
|
+
|
|
7
|
+
export async function runCodegraphPostToolUseHookCli(options: PostToolUseHookOptions = {}): Promise<number> {
|
|
8
|
+
return (await executeCodegraphPostToolUseHook(options)).exitCode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
|
|
12
|
+
const env = options.env ?? processEnv;
|
|
13
|
+
const input = await readHookInput(options.stdin ?? processStdin);
|
|
14
|
+
const output = runCodegraphPostToolUseHook(input, { homeDir: resolveHomeDir(env) });
|
|
15
|
+
if (output.length === 0) return { action: "skipped", exitCode: 0 };
|
|
16
|
+
|
|
17
|
+
(options.stdout ?? processStdout).write(output);
|
|
18
|
+
return { action: "emitted-guidance", exitCode: 0 };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function runCodegraphPostToolUseHook(input: unknown, options: { readonly homeDir?: string } = {}): string {
|
|
22
|
+
const toolName = isRecord(input) ? input["tool_name"] : undefined;
|
|
23
|
+
const cwd = isRecord(input) ? input["cwd"] : undefined;
|
|
24
|
+
const toolOutput = isRecord(input) ? (input["tool_response"] ?? input["tool_output"] ?? input["response"]) : input;
|
|
25
|
+
const guidance = buildCodegraphInitGuidanceForToolResult({ cwd, toolName, toolOutput }, options);
|
|
26
|
+
if (guidance === null) return "";
|
|
27
|
+
|
|
28
|
+
return `${JSON.stringify({
|
|
29
|
+
hookSpecificOutput: {
|
|
30
|
+
hookEventName: "PostToolUse",
|
|
31
|
+
additionalContext: guidance,
|
|
32
|
+
},
|
|
33
|
+
})}\n`;
|
|
34
|
+
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
buildCodegraphChildEnv,
|
|
17
17
|
buildCodegraphEnv,
|
|
18
18
|
} from "../../../../../utils/src/codegraph/env.ts";
|
|
19
|
+
import { hasCodegraphManagedInstall, resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
|
|
19
20
|
import type { ParentWatchdogConfig } from "../../../../../mcp-stdio-core/src/index.ts";
|
|
20
21
|
import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
|
|
21
22
|
import {
|
|
@@ -72,6 +73,8 @@ export interface RunCodegraphServeOptions {
|
|
|
72
73
|
readonly cwd?: string;
|
|
73
74
|
readonly env?: Record<string, string | undefined>;
|
|
74
75
|
readonly homeDir?: string;
|
|
76
|
+
readonly managedInstallExists?: (installDir: string) => boolean;
|
|
77
|
+
readonly resolveManagedBin?: (installDir: string) => string | null;
|
|
75
78
|
readonly stdin?: Readable;
|
|
76
79
|
readonly stdout?: Writable;
|
|
77
80
|
readonly nodeVersion?: string;
|
|
@@ -113,12 +116,28 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
113
116
|
}
|
|
114
117
|
|
|
115
118
|
const trustedInstallDir = config.trustedCodegraphInstallDir;
|
|
119
|
+
const installDir = trustedInstallDir ?? join(homeDir, ".omo", "codegraph");
|
|
116
120
|
const resolutionOptions = {
|
|
117
121
|
env,
|
|
118
122
|
homeDir,
|
|
119
|
-
provisioned: () => provisionedBinFromInstallDir(
|
|
123
|
+
provisioned: () => provisionedBinFromInstallDir(installDir),
|
|
120
124
|
} satisfies ResolveCodegraphCommandOptions;
|
|
121
125
|
let resolution = options.resolve?.(resolutionOptions) ?? resolveCodegraphCommand(resolutionOptions);
|
|
126
|
+
const resolveManagedBin = options.resolveManagedBin ?? (options.resolve === undefined ? provisionedBinFromInstallDir : () => null);
|
|
127
|
+
const managedInstallExists = options.managedInstallExists ?? (options.resolve === undefined ? hasCodegraphManagedInstall : () => false);
|
|
128
|
+
const managedBin = resolveManagedBin(installDir);
|
|
129
|
+
if (resolution.source !== "env" && managedBin !== null) {
|
|
130
|
+
resolution = { argsPrefix: [], command: managedBin, exists: true, source: "provisioned" };
|
|
131
|
+
} else if (resolution.source !== "env" && codegraphConfig.auto_provision !== false && managedInstallExists(installDir)) {
|
|
132
|
+
const upgraded = await provisionMissingCodegraph({
|
|
133
|
+
config: codegraphConfig,
|
|
134
|
+
ensureProvisioned: options.ensureProvisioned ?? ensureCodegraphProvisioned,
|
|
135
|
+
homeDir,
|
|
136
|
+
resolution,
|
|
137
|
+
...(trustedInstallDir === undefined ? {} : { trustedInstallDir }),
|
|
138
|
+
});
|
|
139
|
+
if (upgraded !== null) resolution = upgraded;
|
|
140
|
+
}
|
|
122
141
|
const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
|
|
123
142
|
if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync)) {
|
|
124
143
|
if (resolution.source === "path" && !nodeSupport.supported) {
|
|
@@ -142,7 +161,7 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
|
|
145
|
-
const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, codegraphConfig.daemon
|
|
164
|
+
const codegraphEnv = codegraphEnvForConfig(trustedInstallDir, homeDir, codegraphConfig.daemon !== false, options.buildEnv);
|
|
146
165
|
const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
|
|
147
166
|
return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
|
|
148
167
|
cwd: projectCwd,
|
|
@@ -221,9 +240,7 @@ function resolveProjectCwd(env: Record<string, string | undefined>, fallback: st
|
|
|
221
240
|
}
|
|
222
241
|
|
|
223
242
|
function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
|
|
224
|
-
|
|
225
|
-
const candidate = join(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
226
|
-
return existsSync(candidate) ? candidate : null;
|
|
243
|
+
return resolvePinnedCodegraphBin(installDir);
|
|
227
244
|
}
|
|
228
245
|
|
|
229
246
|
export async function runCodegraphServeCli(): Promise<void> {
|