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
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
executeCodegraphSessionStartHook,
|
|
10
|
+
type CodegraphSessionStartOutcome,
|
|
11
|
+
type WorkerSpawnInvocation,
|
|
12
|
+
} from "../src/hook.ts";
|
|
13
|
+
import { recordSessionStartFailure } from "../src/session-start-cooldown.ts";
|
|
14
|
+
|
|
15
|
+
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
16
|
+
|
|
17
|
+
function createAllowedWorkspace(prefix: string): string {
|
|
18
|
+
return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe("CodeGraph SessionStart spawn guards", () => {
|
|
22
|
+
it("#given an inconclusive probe timeout #when SessionStart runs #then timeout is not treated as uninitialized", async () => {
|
|
23
|
+
// given
|
|
24
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-timeout-home-"));
|
|
25
|
+
const workspace = createAllowedWorkspace("codegraph-timeout-workspace");
|
|
26
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
27
|
+
try {
|
|
28
|
+
// when
|
|
29
|
+
const result = await executeCodegraphSessionStartHook({
|
|
30
|
+
ancestorProbe: () => ({ kind: "inconclusive", reason: "status timed out" }),
|
|
31
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
32
|
+
cwd: workspace,
|
|
33
|
+
env: { HOME: homeDir },
|
|
34
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
35
|
+
stdin: Readable.from(["{}"]),
|
|
36
|
+
sweepZombies: () => undefined,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// then
|
|
40
|
+
expect(result).toEqual({ action: "skipped-inconclusive", exitCode: 0 });
|
|
41
|
+
expect(spawned).toEqual([]);
|
|
42
|
+
} finally {
|
|
43
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
44
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("#given one hook already owns the project lock #when a second SessionStart runs #then it records skipped-locked without spawning", async () => {
|
|
49
|
+
// given
|
|
50
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-dedup-home-"));
|
|
51
|
+
const workspace = createAllowedWorkspace("codegraph-dedup-workspace");
|
|
52
|
+
const outcomes: CodegraphSessionStartOutcome[] = [];
|
|
53
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
54
|
+
const options = {
|
|
55
|
+
ancestorProbe: () => ({ kind: "uninitialized" } as const),
|
|
56
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
57
|
+
cwd: workspace,
|
|
58
|
+
env: { HOME: homeDir },
|
|
59
|
+
logOutcome: (outcome: CodegraphSessionStartOutcome) => outcomes.push(outcome),
|
|
60
|
+
spawnWorker: (invocation: WorkerSpawnInvocation) => {
|
|
61
|
+
spawned.push(invocation);
|
|
62
|
+
},
|
|
63
|
+
stdin: Readable.from(["{}"]),
|
|
64
|
+
sweepZombies: () => undefined,
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
await executeCodegraphSessionStartHook(options);
|
|
68
|
+
|
|
69
|
+
// when
|
|
70
|
+
const second = await executeCodegraphSessionStartHook({ ...options, stdin: Readable.from(["{}"]) });
|
|
71
|
+
|
|
72
|
+
// then
|
|
73
|
+
expect(second).toEqual({ action: "skipped-locked", exitCode: 0 });
|
|
74
|
+
expect(spawned).toHaveLength(1);
|
|
75
|
+
expect(outcomes).toContainEqual({ action: "skipped-locked", projectRoot: workspace });
|
|
76
|
+
} finally {
|
|
77
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
78
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("#given a failed worker cooldown #when SessionStart retries before and after expiry #then only the expired retry spawns", async () => {
|
|
83
|
+
// given
|
|
84
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-hook-home-"));
|
|
85
|
+
const workspace = createAllowedWorkspace("codegraph-cooldown-hook-workspace");
|
|
86
|
+
const outcomes: CodegraphSessionStartOutcome[] = [];
|
|
87
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
88
|
+
try {
|
|
89
|
+
recordSessionStartFailure({
|
|
90
|
+
action: "failed",
|
|
91
|
+
baseCooldownMs: 60_000,
|
|
92
|
+
homeDir,
|
|
93
|
+
nowMs: 1_000,
|
|
94
|
+
projectRoot: workspace,
|
|
95
|
+
});
|
|
96
|
+
const baseOptions = {
|
|
97
|
+
ancestorProbe: () => ({ kind: "uninitialized" } as const),
|
|
98
|
+
config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
|
|
99
|
+
cwd: workspace,
|
|
100
|
+
env: { HOME: homeDir },
|
|
101
|
+
logOutcome: (outcome: CodegraphSessionStartOutcome) => outcomes.push(outcome),
|
|
102
|
+
spawnWorker: (invocation: WorkerSpawnInvocation) => {
|
|
103
|
+
spawned.push(invocation);
|
|
104
|
+
},
|
|
105
|
+
sweepZombies: () => undefined,
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// when
|
|
109
|
+
const suppressed = await executeCodegraphSessionStartHook({ ...baseOptions, nowMs: 60_999, stdin: Readable.from(["{}"]) });
|
|
110
|
+
const expired = await executeCodegraphSessionStartHook({ ...baseOptions, nowMs: 61_000, stdin: Readable.from(["{}"]) });
|
|
111
|
+
|
|
112
|
+
// then
|
|
113
|
+
expect(suppressed).toEqual({ action: "skipped-cooldown", exitCode: 0 });
|
|
114
|
+
expect(expired).toEqual({ action: "spawned", exitCode: 0 });
|
|
115
|
+
expect(spawned).toHaveLength(1);
|
|
116
|
+
expect(outcomes).toContainEqual({
|
|
117
|
+
action: "skipped-cooldown",
|
|
118
|
+
cooldownUntil: 61_000,
|
|
119
|
+
failureCount: 1,
|
|
120
|
+
projectRoot: workspace,
|
|
121
|
+
});
|
|
122
|
+
} finally {
|
|
123
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
124
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it("#given an ancestor has a CodeGraph database #when SessionStart runs in a nested project #then it records skipped-nested-root", async () => {
|
|
129
|
+
// given
|
|
130
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-nested-home-"));
|
|
131
|
+
const ancestorRoot = createAllowedWorkspace("codegraph-nested-ancestor");
|
|
132
|
+
const workspace = join(ancestorRoot, "apps", "server");
|
|
133
|
+
const outcomes: CodegraphSessionStartOutcome[] = [];
|
|
134
|
+
const spawned: WorkerSpawnInvocation[] = [];
|
|
135
|
+
try {
|
|
136
|
+
mkdirSync(join(ancestorRoot, ".codegraph"), { recursive: true });
|
|
137
|
+
mkdirSync(workspace, { recursive: true });
|
|
138
|
+
writeFileSync(join(ancestorRoot, ".codegraph", "codegraph.db"), "fixture");
|
|
139
|
+
|
|
140
|
+
// when
|
|
141
|
+
const result = await executeCodegraphSessionStartHook({
|
|
142
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
143
|
+
cwd: workspace,
|
|
144
|
+
env: { HOME: homeDir },
|
|
145
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
146
|
+
spawnWorker: (invocation) => spawned.push(invocation),
|
|
147
|
+
stdin: Readable.from(["{}"]),
|
|
148
|
+
sweepZombies: () => undefined,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// then
|
|
152
|
+
expect(result).toEqual({ action: "skipped-nested-root", exitCode: 0 });
|
|
153
|
+
expect(spawned).toEqual([]);
|
|
154
|
+
expect(outcomes).toContainEqual({ action: "skipped-nested-root", ancestorRoot, projectRoot: workspace });
|
|
155
|
+
} finally {
|
|
156
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
157
|
+
rmSync(ancestorRoot, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
5
5
|
import { Readable } from "node:stream";
|
|
@@ -9,108 +9,33 @@ import { executeCodegraphSessionStartHook, type WorkerSpawnInvocation } from "..
|
|
|
9
9
|
|
|
10
10
|
const pluginRoot = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
|
|
11
11
|
|
|
12
|
-
// Observed verbatim from a REAL codegraph 1.4.1 binary running `status --json` (exit 0)
|
|
13
|
-
// against a project store built by a REAL codegraph 1.0.1 binary
|
|
14
|
-
// (see .omo/evidence/codegraph-daemon-process-hygiene/task-2-store-upgrade.txt).
|
|
15
|
-
const MIGRATED_1_0_1_STORE_STATUS_JSON = JSON.stringify({
|
|
16
|
-
initialized: true,
|
|
17
|
-
version: "1.4.1",
|
|
18
|
-
projectPath: "/private/tmp/cg-task2/fixture",
|
|
19
|
-
indexPath: "/private/tmp/cg-task2/fixture/.codegraph",
|
|
20
|
-
lastIndexed: "2026-07-21T04:28:09.593Z",
|
|
21
|
-
fileCount: 2,
|
|
22
|
-
nodeCount: 5,
|
|
23
|
-
edgeCount: 4,
|
|
24
|
-
dbSizeBytes: 159744,
|
|
25
|
-
backend: "node-sqlite",
|
|
26
|
-
journalMode: "wal",
|
|
27
|
-
nodesByKind: { file: 2, function: 3 },
|
|
28
|
-
languages: ["typescript"],
|
|
29
|
-
pendingChanges: { added: 0, modified: 0, removed: 0 },
|
|
30
|
-
worktreeMismatch: null,
|
|
31
|
-
index: {
|
|
32
|
-
builtWithVersion: "1.0.1",
|
|
33
|
-
builtWithExtractionVersion: 24,
|
|
34
|
-
currentExtractionVersion: 24,
|
|
35
|
-
reindexRecommended: false,
|
|
36
|
-
state: null,
|
|
37
|
-
pendingRefs: 0,
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
12
|
function createAllowedWorkspace(prefix: string): string {
|
|
42
13
|
return mkdtempSync(join(pluginRoot, `.tmp-${prefix}-`));
|
|
43
14
|
}
|
|
44
15
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
function createFakeCodegraphBin(scripts: {
|
|
48
|
-
readonly posix: string;
|
|
49
|
-
readonly win32: string;
|
|
50
|
-
readonly win32Sidecar?: string;
|
|
51
|
-
}): { readonly binPath: string; readonly dir: string } {
|
|
52
|
-
const dir = mkdtempSync(join(tmpdir(), "omo-codegraph-fake-bin-"));
|
|
53
|
-
if (process.platform === "win32") {
|
|
54
|
-
const binPath = join(dir, "codegraph.cmd");
|
|
55
|
-
writeFileSync(binPath, scripts.win32);
|
|
56
|
-
if (scripts.win32Sidecar !== undefined) writeFileSync(join(dir, "hang.cjs"), scripts.win32Sidecar);
|
|
57
|
-
return { binPath, dir };
|
|
58
|
-
}
|
|
59
|
-
const binPath = join(dir, "codegraph");
|
|
60
|
-
writeFileSync(binPath, scripts.posix, { mode: 0o755 });
|
|
61
|
-
chmodSync(binPath, 0o755);
|
|
62
|
-
return { binPath, dir };
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// Keep the probe hermetic on POSIX but viable on win32: resolveCodegraphCommandInvocation wraps
|
|
66
|
-
// the fake .cmd in `cmd.exe /d /s /c`, and Windows can only resolve cmd.exe when the child env
|
|
67
|
-
// carries the real system PATH (System32) plus SystemRoot (both whitelisted in SAFE_AMBIENT_ENV_KEYS).
|
|
68
|
-
// A POSIX-only PATH makes the probe spawn fail, so the hook reports not-initialized and spawns.
|
|
69
|
-
function probeEnv(homeDir: string, binPath: string): Record<string, string> {
|
|
70
|
-
if (process.platform === "win32") {
|
|
71
|
-
const env: Record<string, string> = {
|
|
72
|
-
HOME: homeDir,
|
|
73
|
-
OMO_CODEGRAPH_BIN: binPath,
|
|
74
|
-
};
|
|
75
|
-
if (process.env["PATH"] !== undefined) env["PATH"] = process.env["PATH"];
|
|
76
|
-
if (process.env["SystemRoot"] !== undefined) env["SystemRoot"] = process.env["SystemRoot"];
|
|
77
|
-
return env;
|
|
78
|
-
}
|
|
79
|
-
return { HOME: homeDir, OMO_CODEGRAPH_BIN: binPath, PATH: "/usr/bin:/bin" };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function isProcessAlive(pid: number): boolean {
|
|
83
|
-
try {
|
|
84
|
-
process.kill(pid, 0);
|
|
85
|
-
return true;
|
|
86
|
-
} catch {
|
|
87
|
-
return false;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1.4.1 binary", () => {
|
|
92
|
-
it("#given a real 1.4.1 status payload for a migrated 1.0.1 store #when SessionStart probes via the default probe #then it stays silent without spawning a re-init worker", async () => {
|
|
16
|
+
describe("CodeGraph SessionStart hook with a migrated 1.0.1 project store under CodeGraph 1.5.0", () => {
|
|
17
|
+
it("#given the migrated store has an exact database #when SessionStart runs #then it never invokes the CodeGraph CLI", async () => {
|
|
93
18
|
// given
|
|
94
19
|
const stdout: string[] = [];
|
|
95
20
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
96
21
|
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-upgrade-home-"));
|
|
97
|
-
// The payload is a single JSON line with no cmd metacharacters (% ^ & < > |), so a plain echo is safe.
|
|
98
|
-
const fake = createFakeCodegraphBin({
|
|
99
|
-
posix: `#!/bin/sh\nprintf '%s\\n' '${MIGRATED_1_0_1_STORE_STATUS_JSON}'\n`,
|
|
100
|
-
win32: `@echo off\r\n@echo ${MIGRATED_1_0_1_STORE_STATUS_JSON}\r\n`,
|
|
101
|
-
});
|
|
102
22
|
const workspace = createAllowedWorkspace("codegraph-upgrade-workspace");
|
|
103
|
-
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
104
|
-
|
|
105
23
|
try {
|
|
24
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
25
|
+
writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "migrated-store");
|
|
26
|
+
|
|
106
27
|
// when
|
|
107
28
|
const result = await executeCodegraphSessionStartHook({
|
|
29
|
+
ancestorProbe: () => {
|
|
30
|
+
throw new Error("the exact database check must be the complete fast path");
|
|
31
|
+
},
|
|
108
32
|
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
109
33
|
cwd: workspace,
|
|
110
|
-
env:
|
|
34
|
+
env: { HOME: homeDir },
|
|
111
35
|
stdin: Readable.from(["{}"]),
|
|
112
36
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
113
37
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
38
|
+
sweepZombies: () => undefined,
|
|
114
39
|
});
|
|
115
40
|
|
|
116
41
|
// then
|
|
@@ -119,58 +44,7 @@ describe("CodeGraph SessionStart hook with a 1.0.1-era project store under the 1
|
|
|
119
44
|
expect(stdout.join("")).toBe("");
|
|
120
45
|
} finally {
|
|
121
46
|
rmSync(homeDir, { recursive: true, force: true });
|
|
122
|
-
rmSync(
|
|
123
|
-
rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
it("#given the status probe spawns a hanging descendant #when SessionStart times out #then it exits promptly and reaps the descendant", async () => {
|
|
128
|
-
// given
|
|
129
|
-
const stdout: string[] = [];
|
|
130
|
-
const spawned: WorkerSpawnInvocation[] = [];
|
|
131
|
-
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-slow-home-"));
|
|
132
|
-
const survivorPidPath = join(homeDir, "survivor.pid");
|
|
133
|
-
const fake = createFakeCodegraphBin({
|
|
134
|
-
posix: "#!/bin/sh\nsleep 30 &\necho \"$!\" > \"$HOME/survivor.pid\"\nwait\n",
|
|
135
|
-
win32: '@echo off\r\nnode "%~dp0hang.cjs"\r\n',
|
|
136
|
-
win32Sidecar: [
|
|
137
|
-
'const { spawn } = require("node:child_process");',
|
|
138
|
-
'const { writeFileSync } = require("node:fs");',
|
|
139
|
-
'const { join } = require("node:path");',
|
|
140
|
-
'const child = spawn(process.execPath, ["-e", "setInterval(() => {}, 1000)"], { stdio: "ignore" });',
|
|
141
|
-
'writeFileSync(join(process.env.HOME, "survivor.pid"), String(child.pid));',
|
|
142
|
-
"setInterval(() => {}, 1000);",
|
|
143
|
-
"",
|
|
144
|
-
].join("\n"),
|
|
145
|
-
});
|
|
146
|
-
const workspace = createAllowedWorkspace("codegraph-slow-probe-workspace");
|
|
147
|
-
let descendantPid: number | undefined;
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
// when
|
|
151
|
-
const startedAt = Date.now();
|
|
152
|
-
const result = await executeCodegraphSessionStartHook({
|
|
153
|
-
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
154
|
-
cwd: workspace,
|
|
155
|
-
env: probeEnv(homeDir, fake.binPath),
|
|
156
|
-
stdin: Readable.from(["{}"]),
|
|
157
|
-
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
158
|
-
spawnWorker: (invocation) => spawned.push(invocation),
|
|
159
|
-
});
|
|
160
|
-
const elapsedMs = Date.now() - startedAt;
|
|
161
|
-
descendantPid = Number.parseInt(readFileSync(survivorPidPath, "utf8").trim(), 10);
|
|
162
|
-
|
|
163
|
-
// then
|
|
164
|
-
expect(result.exitCode).toBe(0);
|
|
165
|
-
expect(result.action).toBe("spawned");
|
|
166
|
-
expect(spawned).toHaveLength(1);
|
|
167
|
-
expect(elapsedMs).toBeLessThan(15_000);
|
|
168
|
-
expect(isProcessAlive(descendantPid)).toBeFalse();
|
|
169
|
-
} finally {
|
|
170
|
-
if (descendantPid !== undefined && isProcessAlive(descendantPid)) process.kill(descendantPid, "SIGKILL");
|
|
171
|
-
rmSync(homeDir, { recursive: true, force: true });
|
|
172
|
-
rmSync(fake.dir, { recursive: true, force: true });
|
|
173
|
-
rmSync(workspace, { recursive: true, force: true, maxRetries: 10, retryDelay: 500 });
|
|
47
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
174
48
|
}
|
|
175
49
|
});
|
|
176
50
|
});
|
|
@@ -39,8 +39,9 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
39
39
|
env: { HOME: homeDir },
|
|
40
40
|
stdin: Readable.from(["{}"]),
|
|
41
41
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
42
|
+
ancestorProbe: () => ({ kind: "uninitialized" }),
|
|
42
43
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
43
|
-
|
|
44
|
+
sweepZombies: () => undefined,
|
|
44
45
|
});
|
|
45
46
|
|
|
46
47
|
// then
|
|
@@ -114,6 +115,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
114
115
|
env: {},
|
|
115
116
|
stdin: Readable.from(["{}"]),
|
|
116
117
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
118
|
+
sweepZombies: () => undefined,
|
|
117
119
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
118
120
|
});
|
|
119
121
|
|
|
@@ -132,7 +134,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
132
134
|
try {
|
|
133
135
|
mkdirSync(join(homeDir, ".omo"), { recursive: true });
|
|
134
136
|
writeFileSync(
|
|
135
|
-
join(homeDir, ".omo", "
|
|
137
|
+
join(homeDir, ".omo", "omo.jsonc"),
|
|
136
138
|
'{ "codegraph": { "enabled": true }, "[codex]": { "codegraph": { "enabled": false } } }\n',
|
|
137
139
|
);
|
|
138
140
|
|
|
@@ -142,6 +144,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
142
144
|
env: { HOME: homeDir },
|
|
143
145
|
stdin: Readable.from(["{}"]),
|
|
144
146
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
147
|
+
sweepZombies: () => undefined,
|
|
145
148
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
146
149
|
});
|
|
147
150
|
|
|
@@ -164,8 +167,8 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
164
167
|
try {
|
|
165
168
|
mkdirSync(join(homeDir, ".omo"), { recursive: true });
|
|
166
169
|
mkdirSync(join(workspace, ".omo"), { recursive: true });
|
|
167
|
-
writeFileSync(join(homeDir, ".omo", "
|
|
168
|
-
writeFileSync(join(workspace, ".omo", "
|
|
170
|
+
writeFileSync(join(homeDir, ".omo", "omo.jsonc"), '{ "codegraph": { "enabled": true } }\n');
|
|
171
|
+
writeFileSync(join(workspace, ".omo", "omo.jsonc"), '{ "[codex]": { "codegraph": { "enabled": false } } }\n');
|
|
169
172
|
|
|
170
173
|
// when
|
|
171
174
|
const result = await executeCodegraphSessionStartHook({
|
|
@@ -173,6 +176,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
173
176
|
env: { HOME: homeDir },
|
|
174
177
|
stdin: Readable.from(["{}"]),
|
|
175
178
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
179
|
+
sweepZombies: () => undefined,
|
|
176
180
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
177
181
|
});
|
|
178
182
|
|
|
@@ -193,13 +197,14 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
193
197
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
194
198
|
try {
|
|
195
199
|
mkdirSync(join(homeDir, ".omo"), { recursive: true });
|
|
196
|
-
writeFileSync(join(homeDir, ".omo", "
|
|
200
|
+
writeFileSync(join(homeDir, ".omo", "omo.jsonc"), '{ "codegraph": { "enabled": true } }\n');
|
|
197
201
|
|
|
198
202
|
// when
|
|
199
203
|
const result = await executeCodegraphSessionStartHook({
|
|
200
204
|
env: { CODEX_CODEGRAPH_ENABLED: "0", HOME: homeDir },
|
|
201
205
|
stdin: Readable.from(["{}"]),
|
|
202
206
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
207
|
+
sweepZombies: () => undefined,
|
|
203
208
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
204
209
|
});
|
|
205
210
|
|
|
@@ -215,38 +220,33 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
215
220
|
// given
|
|
216
221
|
const stdout: string[] = [];
|
|
217
222
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
218
|
-
const statusProbeDaemonValues: boolean[] = [];
|
|
219
223
|
const workspace = createAllowedWorkspace("codegraph-workspace");
|
|
224
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-spawn-home-"));
|
|
220
225
|
|
|
221
226
|
try {
|
|
222
227
|
// when
|
|
223
228
|
const result = await executeCodegraphSessionStartHook({
|
|
229
|
+
ancestorProbe: () => ({ kind: "uninitialized" }),
|
|
224
230
|
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
225
231
|
cwd: workspace,
|
|
226
|
-
env: { HOME:
|
|
232
|
+
env: { HOME: homeDir, KEEP: "1", OPENAI_API_KEY: "sk-test-secret" },
|
|
227
233
|
stdin: Readable.from(["{}"]),
|
|
228
234
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
229
|
-
spawnWorker: (invocation) =>
|
|
230
|
-
|
|
231
|
-
statusProbeDaemonValues.push(options.daemon);
|
|
232
|
-
return Promise.resolve(false);
|
|
235
|
+
spawnWorker: (invocation) => {
|
|
236
|
+
spawned.push(invocation);
|
|
233
237
|
},
|
|
238
|
+
sweepZombies: () => undefined,
|
|
234
239
|
workerCliPath: "/plugin/components/codegraph/dist/cli.js",
|
|
235
240
|
});
|
|
236
241
|
|
|
237
242
|
// then
|
|
238
243
|
expect(result).toEqual({ action: "spawned", exitCode: 0 });
|
|
239
|
-
expect(
|
|
240
|
-
expect(spawned).toEqual([
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
HOME: "/tmp/home",
|
|
246
|
-
OMO_CODEGRAPH_SESSION_START_CWD: workspace,
|
|
247
|
-
},
|
|
248
|
-
},
|
|
249
|
-
]);
|
|
244
|
+
expect(spawned).toHaveLength(1);
|
|
245
|
+
expect(spawned[0]?.args).toEqual(["/plugin/components/codegraph/dist/cli.js", "hook", "session-start-worker"]);
|
|
246
|
+
expect(spawned[0]?.command).toBe(process.execPath);
|
|
247
|
+
expect(spawned[0]?.env["HOME"]).toBe(homeDir);
|
|
248
|
+
expect(spawned[0]?.env["OMO_CODEGRAPH_SESSION_START_CWD"]).toBe(workspace);
|
|
249
|
+
expect(spawned[0]?.env["OMO_CODEGRAPH_SESSION_START_LOCK_TOKEN"]).toMatch(/^[0-9a-f-]{36}$/);
|
|
250
250
|
expect(spawned[0]?.env["OPENAI_API_KEY"]).toBeUndefined();
|
|
251
251
|
expect(spawned[0]?.env["KEEP"]).toBeUndefined();
|
|
252
252
|
expect(JSON.parse(stdout.join(""))).toEqual({
|
|
@@ -256,6 +256,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
256
256
|
},
|
|
257
257
|
});
|
|
258
258
|
} finally {
|
|
259
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
259
260
|
rmSync(workspace, { recursive: true, force: true });
|
|
260
261
|
}
|
|
261
262
|
});
|
|
@@ -265,17 +266,24 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
265
266
|
const stdout: string[] = [];
|
|
266
267
|
const spawned: WorkerSpawnInvocation[] = [];
|
|
267
268
|
const workspace = createAllowedWorkspace("codegraph-initialized-workspace");
|
|
269
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-initialized-home-"));
|
|
268
270
|
|
|
269
271
|
try {
|
|
272
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
273
|
+
writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
|
|
274
|
+
|
|
270
275
|
// when
|
|
271
276
|
const result = await executeCodegraphSessionStartHook({
|
|
277
|
+
ancestorProbe: () => {
|
|
278
|
+
throw new Error("an initialized exact root must not invoke any fallback probe");
|
|
279
|
+
},
|
|
272
280
|
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
273
281
|
cwd: workspace,
|
|
274
|
-
env: { HOME:
|
|
282
|
+
env: { HOME: homeDir, KEEP: "1" },
|
|
275
283
|
stdin: Readable.from(["{}"]),
|
|
276
284
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
285
|
+
sweepZombies: () => undefined,
|
|
277
286
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
278
|
-
statusProbe: () => Promise.resolve(true),
|
|
279
287
|
});
|
|
280
288
|
|
|
281
289
|
// then
|
|
@@ -283,6 +291,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
283
291
|
expect(spawned).toEqual([]);
|
|
284
292
|
expect(stdout.join("")).toBe("");
|
|
285
293
|
} finally {
|
|
294
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
286
295
|
rmSync(workspace, { recursive: true, force: true });
|
|
287
296
|
}
|
|
288
297
|
});
|
|
@@ -298,6 +307,7 @@ describe("CodeGraph SessionStart hook", () => {
|
|
|
298
307
|
env: {},
|
|
299
308
|
stdin: Readable.from(["{not-json"]),
|
|
300
309
|
stdout: { write: (chunk) => stdout.push(chunk) },
|
|
310
|
+
sweepZombies: () => undefined,
|
|
301
311
|
spawnWorker: (invocation) => spawned.push(invocation),
|
|
302
312
|
});
|
|
303
313
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { chmodSync, writeFileSync } from "node:fs";
|
|
2
2
|
|
|
3
|
-
export const
|
|
3
|
+
export const CODEGRAPH_150_DEFAULT_TOOLS: readonly Record<string, unknown>[] = [
|
|
4
4
|
{
|
|
5
5
|
name: "codegraph_explore",
|
|
6
6
|
description:
|
|
@@ -41,10 +41,10 @@ export function writeFakeNewlineCodegraph(filePath: string): void {
|
|
|
41
41
|
"rl.on('line', (line) => {",
|
|
42
42
|
" const request = JSON.parse(line);",
|
|
43
43
|
" if (request.method === 'initialize') {",
|
|
44
|
-
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.
|
|
44
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { capabilities: { tools: { listChanged: false } }, protocolVersion: request.params.protocolVersion, serverInfo: { name: 'codegraph', version: '1.5.0' } } }) + '\\n');",
|
|
45
45
|
" }",
|
|
46
46
|
" if (request.method === 'tools/list') {",
|
|
47
|
-
` process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: ${JSON.stringify(
|
|
47
|
+
` process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: ${JSON.stringify(CODEGRAPH_150_DEFAULT_TOOLS)} } }) + '\\n');`,
|
|
48
48
|
" }",
|
|
49
49
|
"});",
|
|
50
50
|
].join("\n"),
|
|
@@ -43,7 +43,7 @@ describe("CodeGraph component runtime package metadata", () => {
|
|
|
43
43
|
const files = packageJson.files ?? [];
|
|
44
44
|
|
|
45
45
|
// then
|
|
46
|
-
expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.
|
|
46
|
+
expect(optionalDependencies["@colbymchenry/codegraph"]).toBe("1.5.0");
|
|
47
47
|
expect(files).toContain("LICENSE");
|
|
48
48
|
expect(files).toContain("NODE-RUNTIME-LICENSES.md");
|
|
49
49
|
expect(files).toContain("NOTICE");
|
|
@@ -58,7 +58,7 @@ describe("CodeGraph component runtime package metadata", () => {
|
|
|
58
58
|
// given
|
|
59
59
|
const notice = readFileSync(resolve(componentRoot, "NOTICE"), "utf8");
|
|
60
60
|
|
|
61
|
-
expect(notice).toContain("@colbymchenry/codegraph@1.0
|
|
61
|
+
expect(notice).toContain("@colbymchenry/codegraph@1.5.0");
|
|
62
62
|
expect(notice).toContain("MIT license");
|
|
63
63
|
expect(notice).toContain("Node.js v24.16.0 runtime");
|
|
64
64
|
expect(notice).toContain("NODE-RUNTIME-LICENSES.md");
|
|
@@ -77,19 +77,19 @@ describe("CodeGraph provisioned launcher Node guard", () => {
|
|
|
77
77
|
source: provisioned === null ? "path" : "provisioned",
|
|
78
78
|
};
|
|
79
79
|
},
|
|
80
|
+
resolveManagedBin: () => binPath,
|
|
80
81
|
runCommand: (_projectRoot, command, args) => {
|
|
81
82
|
calls.push({ args, command });
|
|
82
|
-
|
|
83
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
84
|
+
writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
|
|
85
|
+
return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
|
|
83
86
|
},
|
|
84
87
|
},
|
|
85
88
|
});
|
|
86
89
|
|
|
87
90
|
// then
|
|
88
91
|
expect(result).toEqual({ action: "initialized" });
|
|
89
|
-
expect(calls).toEqual([
|
|
90
|
-
{ args: ["status", "--json"], command: binPath },
|
|
91
|
-
{ args: ["init"], command: binPath },
|
|
92
|
-
]);
|
|
92
|
+
expect(calls).toEqual([{ args: ["init"], command: binPath }]);
|
|
93
93
|
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
|
|
94
94
|
} finally {
|
|
95
95
|
rmSync(workspace, { recursive: true, force: true });
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
8
8
|
import {
|
|
9
9
|
arrayProperty,
|
|
10
|
-
|
|
10
|
+
CODEGRAPH_150_DEFAULT_TOOLS,
|
|
11
11
|
findTool,
|
|
12
12
|
frameMcpRequest,
|
|
13
13
|
parseMcpBodies,
|
|
@@ -87,14 +87,14 @@ describe("runCodegraphServe MCP protocol bridge", () => {
|
|
|
87
87
|
result: {
|
|
88
88
|
capabilities: { tools: { listChanged: false } },
|
|
89
89
|
protocolVersion: "2025-06-18",
|
|
90
|
-
serverInfo: { name: "codegraph", version: "1.
|
|
90
|
+
serverInfo: { name: "codegraph", version: "1.5.0" },
|
|
91
91
|
},
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
id: 2,
|
|
95
95
|
jsonrpc: "2.0",
|
|
96
96
|
result: {
|
|
97
|
-
tools:
|
|
97
|
+
tools: CODEGRAPH_150_DEFAULT_TOOLS,
|
|
98
98
|
},
|
|
99
99
|
},
|
|
100
100
|
]);
|
|
@@ -48,7 +48,7 @@ describe("runCodegraphServe MCP unavailable facade", () => {
|
|
|
48
48
|
result: {
|
|
49
49
|
capabilities: { tools: { listChanged: false } },
|
|
50
50
|
protocolVersion: "2025-06-18",
|
|
51
|
-
serverInfo: { name: "codegraph", version: "1.
|
|
51
|
+
serverInfo: { name: "codegraph", version: "1.5.0" },
|
|
52
52
|
},
|
|
53
53
|
});
|
|
54
54
|
});
|