oh-my-opencode 4.19.2 → 4.19.4
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/get-unpublished-changes.md +2 -0
- package/.agents/command/omomomo.md +1 -1
- package/.agents/command/publish.md +102 -28
- package/.agents/skills/get-unpublished-changes/SKILL.md +2 -0
- package/.agents/skills/hyperplan/SKILL.md +3 -3
- package/.agents/skills/omomomo/SKILL.md +1 -1
- package/.agents/skills/publish/SKILL.md +27 -6
- package/.opencode/command/get-unpublished-changes.md +2 -0
- package/.opencode/command/omomomo.md +1 -1
- package/.opencode/command/publish.md +102 -28
- package/.opencode/skills/hyperplan/SKILL.md +3 -3
- package/THIRD-PARTY-NOTICES.md +7 -7
- package/dist/agents/sisyphus-junior/agent.d.ts +1 -1
- package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +1 -1
- package/dist/cli/config-migrate.d.ts +8 -0
- package/dist/cli/doctor/checks/deprecated-reasoning-keys.d.ts +2 -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 +95684 -92814
- package/dist/cli-node/index.js +95650 -92780
- package/dist/config/schema/agent-overrides.d.ts +800 -0
- package/dist/config/schema/categories.d.ts +132 -0
- package/dist/config/schema/fallback-models.d.ts +50 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +818 -2
- 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 +10 -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 +15 -0
- package/dist/config-migration/reasoning-unification.d.ts +3 -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/features/builtin-commands/templates/hyperplan.d.ts +1 -1
- package/dist/features/team-mode/tools/lifecycle-test-fixture.d.ts +2 -0
- package/dist/hooks/auto-update-checker/constants.d.ts +3 -3
- package/dist/hooks/codegraph-bootstrap/command-runner.d.ts +1 -0
- package/dist/hooks/model-fallback/next-fallback.d.ts +1 -0
- package/dist/hooks/runtime-fallback/constants.d.ts +1 -1
- package/dist/index.js +12368 -9788
- package/dist/oh-my-opencode.schema.json +1672 -8
- 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/plugin-handlers/prometheus-agent-config-builder.d.ts +1 -0
- package/dist/shared/agent-display-names.d.ts +1 -1
- package/dist/shared/agent-variant.d.ts +11 -0
- 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/session-prompt-params-helpers.d.ts +6 -1
- package/dist/skills/coding-agent-sessions/SKILL.md +4 -3
- package/dist/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
- package/dist/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
- package/dist/skills/data-scientist/SKILL.md +243 -0
- package/dist/skills/data-scientist/references/common-scenarios.md +176 -0
- package/dist/skills/data-scientist/references/execution-templates.md +197 -0
- package/dist/skills/data-scientist/references/integration-patterns.md +153 -0
- package/dist/skills/data-scientist/references/performance-benchmarks.md +37 -0
- package/dist/skills/data-scientist/references/uv-setup.md +78 -0
- package/dist/skills/data-scientist/scripts/quick-query.py +111 -0
- package/dist/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
- package/dist/skills/data-scientist/scripts/setup-uv.sh +60 -0
- package/dist/skills/debugging/SKILL.md +1 -1
- 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 +1 -2
- package/dist/skills/ulw-plan/SKILL.md +1 -1
- package/dist/skills/ulw-research/SKILL.md +122 -11
- package/dist/startup-migration.d.ts +28 -0
- package/dist/testing/create-plugin-module.d.ts +4 -0
- package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
- package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
- package/dist/tools/delegate-task/constants.d.ts +1 -1
- package/dist/tui.js +6040 -5443
- package/package.json +13 -13
- 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 +21 -3
- 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 +10373 -2570
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +7502 -574
- 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 +164 -159
- 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 +20 -2
- 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 -175
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +4 -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 -138
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +34 -24
- 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 +5 -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 +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +45 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +2 -2
- 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 +58 -57
- 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 +32 -15
- 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/rules/src/post-compact-budget.ts +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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
- 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 +17 -0
- 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/scripts/sync-skills.mjs +6 -0
- 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 +186 -9
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +4 -3
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +243 -0
- package/packages/omo-codex/plugin/skills/data-scientist/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +176 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +197 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +153 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +37 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +78 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/quick-query.py +111 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.sh +60 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +1 -1
- 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 +1 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +17 -0
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +121 -11
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +12 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +24 -5
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +4 -3
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
- package/packages/shared-skills/skills/data-scientist/SKILL.md +243 -0
- package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +176 -0
- package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +197 -0
- package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +153 -0
- package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +37 -0
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +78 -0
- package/packages/shared-skills/skills/data-scientist/scripts/quick-query.py +111 -0
- package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
- package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.sh +60 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +1 -1
- 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 +1 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +122 -11
- 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.4",
|
|
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,5 +1,3 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
1
|
import {
|
|
4
2
|
cwd as processCwd,
|
|
5
3
|
env as processEnv,
|
|
@@ -7,27 +5,33 @@ import {
|
|
|
7
5
|
stdin as processStdin,
|
|
8
6
|
stdout as processStdout,
|
|
9
7
|
} from "node:process";
|
|
10
|
-
import type { Readable } from "node:stream";
|
|
11
8
|
import { fileURLToPath } from "node:url";
|
|
12
9
|
|
|
13
|
-
import { buildCodegraphChildEnv
|
|
14
|
-
import { buildCodegraphInitGuidanceForToolResult } from "../../../../../utils/src/codegraph/guidance.ts";
|
|
15
|
-
import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
|
|
16
|
-
import { resolveCodegraphCommand } from "../../../../../utils/src/codegraph/resolve.ts";
|
|
17
|
-
import { runProcessWithTreeTimeout } from "../../../../../utils/src/process-tree.ts";
|
|
10
|
+
import { buildCodegraphChildEnv } from "../../../../../utils/src/codegraph/env.ts";
|
|
18
11
|
import { shouldExcludeCodegraphProject } from "../../../../../utils/src/codegraph/workspace.ts";
|
|
19
12
|
import { getCodexOmoConfig } from "../../../shared/src/config-loader.ts";
|
|
20
13
|
import { pruneCodegraphProjectStoresBestEffort } from "./cache-gc.js";
|
|
14
|
+
import { readHookInput, resolveHomeDir, resolveHookProjectRoot } from "./hook-input.js";
|
|
21
15
|
import { sweepCodegraphZombiesBestEffort } from "./hook-sweep.js";
|
|
22
|
-
import { resolveCodegraphCommandInvocation, SESSION_START_CWD_ENV } from "./session-start-worker.js";
|
|
23
16
|
import type {
|
|
24
|
-
|
|
25
|
-
PostToolUseHookOptions,
|
|
26
|
-
PostToolUseHookResult,
|
|
17
|
+
CodegraphSessionStartOutcome,
|
|
27
18
|
SessionStartHookOptions,
|
|
28
19
|
SessionStartHookResult,
|
|
29
|
-
WorkerSpawnInvocation,
|
|
30
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";
|
|
31
35
|
|
|
32
36
|
export type {
|
|
33
37
|
CodegraphCommandResult,
|
|
@@ -48,37 +52,45 @@ export type {
|
|
|
48
52
|
WorkerAction,
|
|
49
53
|
WorkerSpawnInvocation,
|
|
50
54
|
} from "./hook-types.js";
|
|
51
|
-
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";
|
|
52
62
|
|
|
53
63
|
export const CODEGRAPH_SESSION_START_NOTICE = "LazyCodex CodeGraph bootstrap scheduled in background";
|
|
54
|
-
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
|
+
};
|
|
55
75
|
|
|
56
76
|
export async function runCodegraphSessionStartHook(options: SessionStartHookOptions = {}): Promise<number> {
|
|
57
77
|
return (await executeCodegraphSessionStartHook(options)).exitCode;
|
|
58
78
|
}
|
|
59
79
|
|
|
60
|
-
export async function runCodegraphPostToolUseHookCli(options: PostToolUseHookOptions = {}): Promise<number> {
|
|
61
|
-
return (await executeCodegraphPostToolUseHook(options)).exitCode;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
80
|
export async function executeCodegraphSessionStartHook(options: SessionStartHookOptions = {}): Promise<SessionStartHookResult> {
|
|
65
81
|
const env = options.env ?? processEnv;
|
|
66
82
|
const input = await readHookInput(options.stdin ?? processStdin);
|
|
67
|
-
const projectRoot =
|
|
83
|
+
const projectRoot = resolveHookProjectRoot(input, options.cwd ?? processCwd());
|
|
68
84
|
const homeDir = resolveHomeDir(env);
|
|
69
85
|
const config = options.config ?? getCodexOmoConfig({ cwd: projectRoot, env, homeDir });
|
|
86
|
+
if (config.codegraph?.enabled === false) return { action: "skipped-disabled", exitCode: 0 };
|
|
70
87
|
|
|
71
|
-
if (config.codegraph?.enabled === false) {
|
|
72
|
-
return { action: "skipped-disabled", exitCode: 0 };
|
|
73
|
-
}
|
|
74
88
|
const excludedRoots = config.codegraph?.excluded_roots;
|
|
75
89
|
const exclusion = shouldExcludeCodegraphProject(projectRoot, {
|
|
76
90
|
homeDir,
|
|
77
91
|
...(excludedRoots === undefined ? {} : { excludedRoots }),
|
|
78
92
|
});
|
|
79
|
-
if (exclusion.excluded) {
|
|
80
|
-
return { action: "skipped-excluded", exitCode: 0 };
|
|
81
|
-
}
|
|
93
|
+
if (exclusion.excluded) return { action: "skipped-excluded", exitCode: 0 };
|
|
82
94
|
|
|
83
95
|
pruneCodegraphProjectStoresBestEffort(homeDir, { debugLog: writeDebugLog });
|
|
84
96
|
await sweepCodegraphZombiesBestEffort({
|
|
@@ -88,164 +100,157 @@ export async function executeCodegraphSessionStartHook(options: SessionStartHook
|
|
|
88
100
|
log: writeDebugLog,
|
|
89
101
|
}, options.sweepZombies);
|
|
90
102
|
|
|
91
|
-
const
|
|
92
|
-
|
|
103
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
104
|
+
const context: HookContext = {
|
|
105
|
+
baseCooldownMs: config.codegraph?.session_start_cooldown_ms ?? DEFAULT_SESSION_START_COOLDOWN_MS,
|
|
93
106
|
env,
|
|
94
107
|
homeDir,
|
|
108
|
+
logOutcome: options.logOutcome ?? ((outcome) => appendSessionStartOutcome(homeDir, outcome, nowMs)),
|
|
109
|
+
nowMs,
|
|
110
|
+
options,
|
|
95
111
|
projectRoot,
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
return { action: "skipped-initialized", exitCode: 0 };
|
|
100
|
-
}
|
|
112
|
+
};
|
|
113
|
+
const projectDecision = handleProjectState(resolveHookProjectState(context), context);
|
|
114
|
+
if (projectDecision !== null) return projectDecision;
|
|
101
115
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
codegraphEnv: { [SESSION_START_CWD_ENV]: projectRoot },
|
|
108
|
-
runtimeEnv: env,
|
|
109
|
-
}),
|
|
116
|
+
const cooldown = readSessionStartCooldown({
|
|
117
|
+
baseCooldownMs: context.baseCooldownMs,
|
|
118
|
+
homeDir,
|
|
119
|
+
nowMs,
|
|
120
|
+
projectRoot,
|
|
110
121
|
});
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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 };
|
|
131
|
+
}
|
|
114
132
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
readonly trustedCodegraphInstallDir?: string;
|
|
121
|
-
}): Promise<boolean> {
|
|
122
|
-
const resolved = resolveCodegraphCommand({
|
|
123
|
-
env: options.env,
|
|
124
|
-
homeDir: options.homeDir,
|
|
125
|
-
provisioned: () => provisionedBinFromInstallDir(options.trustedCodegraphInstallDir),
|
|
133
|
+
const lockResult = acquireSessionStartLock({
|
|
134
|
+
homeDir,
|
|
135
|
+
nowMs,
|
|
136
|
+
projectRoot,
|
|
137
|
+
staleMs: options.lockStaleMs ?? DEFAULT_SESSION_START_LOCK_STALE_MS,
|
|
126
138
|
});
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
};
|
|
134
|
-
const status = await runStatusProbe(
|
|
135
|
-
options.projectRoot,
|
|
136
|
-
invocation.command,
|
|
137
|
-
invocation.args,
|
|
138
|
-
buildCodegraphChildEnv({ ambientEnv: options.env, codegraphEnv, runtimeEnv: options.env }),
|
|
139
|
-
);
|
|
140
|
-
if (status.exitCode !== 0 || status.timedOut) return false;
|
|
141
|
-
return codegraphStatusSaysInitialized(status.stdout);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function runStatusProbe(
|
|
145
|
-
projectRoot: string,
|
|
146
|
-
command: string,
|
|
147
|
-
args: readonly string[],
|
|
148
|
-
env: Record<string, string>,
|
|
149
|
-
): Promise<{ readonly exitCode: number; readonly stdout: string; readonly timedOut: boolean }> {
|
|
150
|
-
return runProcessWithTreeTimeout({
|
|
151
|
-
args,
|
|
152
|
-
command,
|
|
153
|
-
cwd: projectRoot,
|
|
154
|
-
env,
|
|
155
|
-
maxBuffer: 1024 * 1024,
|
|
156
|
-
timeoutMs: STATUS_PROBE_TIMEOUT_MS,
|
|
157
|
-
}).then(({ exitCode, stdout, timedOut }) => ({ exitCode, stdout, timedOut }));
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
function codegraphStatusSaysInitialized(stdout: string): boolean {
|
|
161
|
-
const parsed = parseJson(stdout);
|
|
162
|
-
if (!isRecord(parsed)) return false;
|
|
163
|
-
const initialized = parsed["initialized"] ?? parsed["isInitialized"] ?? parsed["ready"];
|
|
164
|
-
if (typeof initialized === "boolean") return initialized;
|
|
165
|
-
const status = parsed["status"];
|
|
166
|
-
if (typeof status !== "string") return false;
|
|
167
|
-
const normalized = status.toLowerCase();
|
|
168
|
-
return (normalized.includes("initialized") || normalized.includes("ready")) && !normalized.includes("not initialized") && !normalized.includes("uninitialized");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function provisionedBinFromInstallDir(installDir: string | undefined): string | null {
|
|
172
|
-
return resolvePinnedCodegraphBin(installDir);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export async function executeCodegraphPostToolUseHook(options: PostToolUseHookOptions = {}): Promise<PostToolUseHookResult> {
|
|
176
|
-
const env = options.env ?? processEnv;
|
|
177
|
-
const input = await readHookInput(options.stdin ?? processStdin);
|
|
178
|
-
const output = runCodegraphPostToolUseHook(input, { homeDir: resolveHomeDir(env) });
|
|
179
|
-
if (output.length === 0) return { action: "skipped", exitCode: 0 };
|
|
180
|
-
|
|
181
|
-
(options.stdout ?? processStdout).write(output);
|
|
182
|
-
return { action: "emitted-guidance", exitCode: 0 };
|
|
183
|
-
}
|
|
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);
|
|
184
145
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
if (guidance === null) return "";
|
|
191
|
-
|
|
192
|
-
return `${JSON.stringify({
|
|
193
|
-
hookSpecificOutput: {
|
|
194
|
-
hookEventName: "PostToolUse",
|
|
195
|
-
additionalContext: guidance,
|
|
196
|
-
},
|
|
197
|
-
})}\n`;
|
|
198
|
-
}
|
|
146
|
+
const lockedProjectDecision = handleProjectState(resolveHookProjectState(context), context);
|
|
147
|
+
if (lockedProjectDecision !== null) {
|
|
148
|
+
releaseSessionStartLock(lockResult.lock);
|
|
149
|
+
return lockedProjectDecision;
|
|
150
|
+
}
|
|
199
151
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
+
}
|
|
209
169
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
processStderr.write(`${message}\n`);
|
|
170
|
+
writeSessionStartNotice(options.stdout ?? processStdout, CODEGRAPH_SESSION_START_NOTICE);
|
|
171
|
+
return { action: "spawned", exitCode: 0 };
|
|
213
172
|
}
|
|
214
173
|
|
|
215
|
-
function
|
|
216
|
-
const
|
|
217
|
-
|
|
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);
|
|
218
178
|
}
|
|
219
179
|
|
|
220
|
-
function
|
|
221
|
-
|
|
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
|
+
}
|
|
222
192
|
}
|
|
223
193
|
|
|
224
|
-
function
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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
|
+
}
|
|
228
216
|
}
|
|
229
217
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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 };
|
|
236
240
|
}
|
|
237
241
|
|
|
238
|
-
function
|
|
242
|
+
function safeLogOutcome(logOutcome: (outcome: CodegraphSessionStartOutcome) => void, outcome: CodegraphSessionStartOutcome): void {
|
|
239
243
|
try {
|
|
240
|
-
|
|
244
|
+
logOutcome(outcome);
|
|
241
245
|
} catch (error) {
|
|
242
|
-
if (error instanceof
|
|
243
|
-
throw error;
|
|
246
|
+
if (error instanceof Error) writeDebugLog(`failed to write SessionStart outcome: ${error.message}`);
|
|
247
|
+
else throw error;
|
|
244
248
|
}
|
|
245
249
|
}
|
|
246
250
|
|
|
247
|
-
function
|
|
248
|
-
|
|
251
|
+
function writeDebugLog(message: string): void {
|
|
252
|
+
if (processEnv["OMO_CODEGRAPH_DEBUG"] !== "1") return;
|
|
253
|
+
processStderr.write(`${message}\n`);
|
|
249
254
|
}
|
|
250
255
|
|
|
251
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,7 +16,7 @@ import {
|
|
|
16
16
|
buildCodegraphChildEnv,
|
|
17
17
|
buildCodegraphEnv,
|
|
18
18
|
} from "../../../../../utils/src/codegraph/env.ts";
|
|
19
|
-
import { resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
|
|
19
|
+
import { hasCodegraphManagedInstall, resolvePinnedCodegraphBin } from "../../../../../utils/src/codegraph/managed-runtime.ts";
|
|
20
20
|
import type { ParentWatchdogConfig } from "../../../../../mcp-stdio-core/src/index.ts";
|
|
21
21
|
import { CODEGRAPH_PINNED_VERSION } from "../../../../../utils/src/codegraph/manifest.ts";
|
|
22
22
|
import {
|
|
@@ -73,6 +73,8 @@ export interface RunCodegraphServeOptions {
|
|
|
73
73
|
readonly cwd?: string;
|
|
74
74
|
readonly env?: Record<string, string | undefined>;
|
|
75
75
|
readonly homeDir?: string;
|
|
76
|
+
readonly managedInstallExists?: (installDir: string) => boolean;
|
|
77
|
+
readonly resolveManagedBin?: (installDir: string) => string | null;
|
|
76
78
|
readonly stdin?: Readable;
|
|
77
79
|
readonly stdout?: Writable;
|
|
78
80
|
readonly nodeVersion?: string;
|
|
@@ -114,12 +116,28 @@ export async function runCodegraphServe(options: RunCodegraphServeOptions = {}):
|
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
const trustedInstallDir = config.trustedCodegraphInstallDir;
|
|
119
|
+
const installDir = trustedInstallDir ?? join(homeDir, ".omo", "codegraph");
|
|
117
120
|
const resolutionOptions = {
|
|
118
121
|
env,
|
|
119
122
|
homeDir,
|
|
120
|
-
provisioned: () => provisionedBinFromInstallDir(
|
|
123
|
+
provisioned: () => provisionedBinFromInstallDir(installDir),
|
|
121
124
|
} satisfies ResolveCodegraphCommandOptions;
|
|
122
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
|
+
}
|
|
123
141
|
const nodeSupport = evaluateCodegraphNodeSupport({ env, nodeVersion: options.nodeVersion });
|
|
124
142
|
if (!resolution.exists || shouldSkipResolvedCommand(resolution, options.commandExists ?? existsSync)) {
|
|
125
143
|
if (resolution.source === "path" && !nodeSupport.supported) {
|