oh-my-opencode 4.19.0 → 4.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/command/omomomo.md +1 -1
- package/.agents/skills/omomomo/SKILL.md +1 -1
- package/.opencode/command/omomomo.md +1 -1
- package/README.ja.md +6 -6
- package/README.ko.md +6 -6
- package/README.md +6 -6
- package/README.ru.md +6 -6
- package/README.zh-cn.md +6 -6
- package/dist/agents/atlas/agent.d.ts +1 -1
- package/dist/agents/gpt-prompt-identity.d.ts +3 -0
- package/dist/agents/sisyphus/gpt-5-5.d.ts +1 -1
- package/dist/agents/sisyphus/gpt-task-system-guide.d.ts +1 -0
- package/dist/agents/sisyphus-junior/gpt-5-5.d.ts +2 -2
- package/dist/cli/index.js +148 -94
- package/dist/cli-node/index.js +148 -94
- package/dist/config/schema/agent-overrides.d.ts +48 -48
- package/dist/config/schema/categories.d.ts +6 -6
- package/dist/config/schema/codegraph.d.ts +2 -0
- package/dist/config/schema/fallback-models.d.ts +5 -5
- package/dist/config/schema/oh-my-opencode-config.d.ts +50 -48
- package/dist/hooks/codegraph-bootstrap/hook.d.ts +3 -2
- package/dist/hooks/sisyphus-junior-notepad/constants.d.ts +1 -1
- package/dist/hooks/start-work/notepad-scaffold.d.ts +10 -0
- package/dist/index.js +2612 -1473
- package/dist/oh-my-opencode.schema.json +11 -0
- package/dist/shared/omo-process-sweep.d.ts +18 -0
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
- package/dist/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/dist/skills/ulw-plan/SKILL.md +20 -1
- package/dist/testing/create-plugin-module.d.ts +1 -0
- package/dist/tui.js +66 -56
- package/package.json +13 -13
- package/packages/git-bash-mcp/dist/cli.js +54 -8
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +60 -0
- package/packages/lsp-core/src/lsp/client.ts +14 -1
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +2 -2
- package/packages/lsp-core/src/mcp.ts +9 -0
- package/packages/lsp-daemon/dist/cli.js +319 -51
- package/packages/lsp-daemon/dist/client.js +136 -48
- package/packages/lsp-daemon/dist/daemon-client.d.ts +0 -10
- package/packages/lsp-daemon/dist/daemon-client.js +4 -34
- package/packages/lsp-daemon/dist/daemon-failure-result.d.ts +3 -0
- package/packages/lsp-daemon/dist/daemon-failure-result.js +38 -0
- package/packages/lsp-daemon/dist/daemon-request-error.d.ts +14 -0
- package/packages/lsp-daemon/dist/daemon-request-error.js +26 -0
- package/packages/lsp-daemon/dist/daemon-server.js +5 -1
- package/packages/lsp-daemon/dist/index.js +137 -48
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +1 -0
- package/packages/lsp-daemon/dist/version-reap.d.ts +26 -0
- package/packages/lsp-daemon/dist/version-reap.js +182 -0
- package/packages/lsp-tools-mcp/dist/cli.js +61 -10
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +6 -1
- package/packages/lsp-tools-mcp/dist/mcp.js +61 -10
- package/packages/lsp-tools-mcp/dist/tools.js +6 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +64 -8
- 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/bootstrap/src/setup.ts +22 -2
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +555 -251
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +178 -89
- package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +3 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +98 -32
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +5 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +15 -6
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +6 -2
- package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +1 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +148 -0
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +31 -2
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +65 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -7
- 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 +57 -3
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +41 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +109 -8
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +43 -0
- 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 +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +80 -40
- 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 +11 -0
- 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 +11 -0
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +60 -0
- 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/agents/lazycodex-clone-fidelity-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +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 +20 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +42 -0
- package/packages/omo-codex/plugin/components/ulw-loop/README.md +6 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.d.ts +21 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +64 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +15 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.d.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-steering.js +85 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +0 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +13 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +998 -593
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/constants.js +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/goal-status.js +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +10 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +84 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.d.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +81 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +7 -59
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +12 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/validation-batch.js +122 -0
- 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/references/full-workflow.md +8 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +84 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +13 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-steering.ts +49 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +13 -45
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/constants.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +7 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/goal-status.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +4 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +20 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +125 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-mutations.ts +59 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +6 -58
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +12 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/validation-batch.ts +122 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +76 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint-continuation.test.ts +111 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-steering-batch.test.ts +67 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-validation-batch.test.ts +57 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +152 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +29 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch-checkpoint.test.ts +147 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/validation-batch.test.ts +73 -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 +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 +41 -41
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +43 -0
- package/packages/omo-codex/plugin/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +8 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +20 -1
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +9 -9
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +26 -0
- package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +41 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +49 -5
- package/packages/omo-codex/scripts/install-marketplace-cache.test.mjs +4 -1
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.test.ts +87 -0
- package/packages/shared-skills/skills/programming/scripts/typescript/check-no-excuse-rules.ts +35 -5
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +20 -1
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// components/codegraph/src/cli.ts
|
|
4
|
-
import { realpathSync as
|
|
5
|
-
import { basename as basename5, resolve as
|
|
4
|
+
import { realpathSync as realpathSync7 } from "node:fs";
|
|
5
|
+
import { basename as basename5, resolve as resolve8 } from "node:path";
|
|
6
6
|
import { stderr as processStderr4 } from "node:process";
|
|
7
7
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
8
8
|
|
|
9
9
|
// components/codegraph/src/hook.ts
|
|
10
10
|
import { execFile as execFile4, spawn } from "node:child_process";
|
|
11
11
|
import { homedir as homedir13 } from "node:os";
|
|
12
|
-
import { join as
|
|
12
|
+
import { join as join14 } from "node:path";
|
|
13
13
|
import {
|
|
14
14
|
cwd as processCwd2,
|
|
15
15
|
env as processEnv2,
|
|
@@ -56,6 +56,7 @@ var SAFE_AMBIENT_ENV_KEYS = new Set([
|
|
|
56
56
|
var SAFE_CODEGRAPH_RUNTIME_ENV_KEYS = new Set([
|
|
57
57
|
"CODEGRAPH_ALLOW_UNSAFE_NODE",
|
|
58
58
|
"CODEGRAPH_BIN",
|
|
59
|
+
"CODEGRAPH_DAEMON_IDLE_TIMEOUT_MS",
|
|
59
60
|
"CODEGRAPH_FAKE_LOG",
|
|
60
61
|
"CODEGRAPH_NO_DAEMON",
|
|
61
62
|
"CODEGRAPH_NODE_BIN",
|
|
@@ -67,7 +68,7 @@ function buildCodegraphEnv(options = {}) {
|
|
|
67
68
|
const homeDir = options.homeDir ?? homedir();
|
|
68
69
|
return {
|
|
69
70
|
[CODEGRAPH_INSTALL_DIR_ENV]: join(homeDir, ".omo", "codegraph"),
|
|
70
|
-
[CODEGRAPH_NO_DAEMON_ENV]: "1",
|
|
71
|
+
...options.daemon === true ? {} : { [CODEGRAPH_NO_DAEMON_ENV]: "1" },
|
|
71
72
|
[CODEGRAPH_NO_DOWNLOAD_ENV]: "1",
|
|
72
73
|
[CODEGRAPH_TELEMETRY_ENV]: "0",
|
|
73
74
|
[DO_NOT_TRACK_ENV]: "1"
|
|
@@ -399,6 +400,9 @@ var ANSI_ESCAPE_PATTERN = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
|
|
|
399
400
|
var CODEGRAPH_STATUS_PROJECT_PATTERN = /^.*?\bProject:\s*(.+?)\s*$/im;
|
|
400
401
|
var CODEGRAPH_STATUS_UNINITIALIZED_PATTERN = /^.*?\bNot initialized\s*$/im;
|
|
401
402
|
var CODEGRAPH_INIT_HINT_PATTERN = /Run\s+["'`]codegraph init["'`]\s+(?:in that project first|to initialize)\.?/i;
|
|
403
|
+
var CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN = /The project at (.+?) isn't indexed with codegraph\b/i;
|
|
404
|
+
var CODEGRAPH_NO_PROJECT_LOADED_PATTERN = /No CodeGraph project is loaded for this session\./i;
|
|
405
|
+
var CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN = /^Searched for a \.codegraph\/ directory starting from:\s*(.+?)\s*$/im;
|
|
402
406
|
function getCodegraphUninitializedProject(input) {
|
|
403
407
|
const output = textFromUnknown(input.toolOutput);
|
|
404
408
|
if (!isCodegraphTool(input.toolName))
|
|
@@ -439,6 +443,16 @@ function extractProjectPath(output) {
|
|
|
439
443
|
const uninitializedProject = uninitializedMatch?.[1]?.trim();
|
|
440
444
|
if (uninitializedProject && uninitializedProject.length > 0)
|
|
441
445
|
return uninitializedProject;
|
|
446
|
+
const notIndexedMatch = normalizedOutput.match(CODEGRAPH_PROJECT_NOT_INDEXED_PATTERN);
|
|
447
|
+
const notIndexedProject = notIndexedMatch?.[1]?.trim();
|
|
448
|
+
if (notIndexedProject && notIndexedProject.length > 0)
|
|
449
|
+
return notIndexedProject;
|
|
450
|
+
if (CODEGRAPH_NO_PROJECT_LOADED_PATTERN.test(normalizedOutput)) {
|
|
451
|
+
const searchedFromMatch = normalizedOutput.match(CODEGRAPH_NO_PROJECT_SEARCHED_FROM_PATTERN);
|
|
452
|
+
const searchedFromProject = searchedFromMatch?.[1]?.trim();
|
|
453
|
+
if (searchedFromProject && searchedFromProject.length > 0)
|
|
454
|
+
return searchedFromProject;
|
|
455
|
+
}
|
|
442
456
|
if (!looksLikeCodegraphUninitializedOutput(normalizedOutput))
|
|
443
457
|
return null;
|
|
444
458
|
const statusMatch = normalizedOutput.match(CODEGRAPH_STATUS_PROJECT_PATTERN);
|
|
@@ -1597,8 +1611,9 @@ function parseJsoncSafe(content) {
|
|
|
1597
1611
|
var HARNESS_IDS = ["codex", "opencode", "omo"];
|
|
1598
1612
|
var SETTING_HARNESS_SUPPORT = {
|
|
1599
1613
|
"codegraph.auto_provision": HARNESS_IDS,
|
|
1614
|
+
"codegraph.daemon": ["codex", "opencode"],
|
|
1600
1615
|
"codegraph.enabled": HARNESS_IDS,
|
|
1601
|
-
"codegraph.excluded_roots": ["codex"],
|
|
1616
|
+
"codegraph.excluded_roots": ["codex", "opencode"],
|
|
1602
1617
|
"codegraph.install_dir": HARNESS_IDS,
|
|
1603
1618
|
"codegraph.telemetry": HARNESS_IDS,
|
|
1604
1619
|
"codegraph.watch_debounce_ms": ["opencode", "omo"]
|
|
@@ -1615,6 +1630,7 @@ var BUILT_IN_DEFAULTS = {
|
|
|
1615
1630
|
var HARNESS_BLOCK_KEYS = HARNESS_IDS.map((harness) => `[${harness}]`);
|
|
1616
1631
|
var CODEGRAPH_SETTING_KEYS = [
|
|
1617
1632
|
"auto_provision",
|
|
1633
|
+
"daemon",
|
|
1618
1634
|
"enabled",
|
|
1619
1635
|
"excluded_roots",
|
|
1620
1636
|
"install_dir",
|
|
@@ -1688,6 +1704,10 @@ function setCodegraphSetting(config, key, value) {
|
|
|
1688
1704
|
if (typeof value === "boolean")
|
|
1689
1705
|
config.auto_provision = value;
|
|
1690
1706
|
return;
|
|
1707
|
+
case "daemon":
|
|
1708
|
+
if (typeof value === "boolean")
|
|
1709
|
+
config.daemon = value;
|
|
1710
|
+
return;
|
|
1691
1711
|
case "enabled":
|
|
1692
1712
|
if (typeof value === "boolean")
|
|
1693
1713
|
config.enabled = value;
|
|
@@ -2007,77 +2027,131 @@ function isNonFatalCodegraphGcError(error) {
|
|
|
2007
2027
|
|
|
2008
2028
|
// components/codegraph/src/hook-sweep.ts
|
|
2009
2029
|
import { fileURLToPath } from "node:url";
|
|
2010
|
-
// ../../utils/src/
|
|
2030
|
+
// ../../utils/src/process-sweep/sweeper.ts
|
|
2011
2031
|
import { existsSync as existsSync7, mkdirSync as mkdirSync2, statSync as statSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2012
2032
|
import { homedir as homedir10 } from "node:os";
|
|
2013
|
-
import { dirname as
|
|
2014
|
-
|
|
2015
|
-
// ../../utils/src/codegraph/process-exec.ts
|
|
2016
|
-
import { execFile } from "node:child_process";
|
|
2033
|
+
import { dirname as dirname5, join as join11 } from "node:path";
|
|
2017
2034
|
|
|
2018
|
-
// ../../utils/src/codegraph/
|
|
2019
|
-
import {
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2035
|
+
// ../../utils/src/codegraph/daemon-lock.ts
|
|
2036
|
+
import { readFileSync as readFileSync4, realpathSync as realpathSync4 } from "node:fs";
|
|
2037
|
+
import { dirname as dirname4, join as join9, resolve as resolve5 } from "node:path";
|
|
2038
|
+
function parseDaemonLock(raw) {
|
|
2039
|
+
const trimmed = raw.trim();
|
|
2040
|
+
if (trimmed.length === 0)
|
|
2041
|
+
return null;
|
|
2042
|
+
try {
|
|
2043
|
+
const parsed = JSON.parse(trimmed);
|
|
2044
|
+
if (typeof parsed === "object" && parsed !== null && "pid" in parsed) {
|
|
2045
|
+
const pid = parsed.pid;
|
|
2046
|
+
if (typeof pid === "number" && Number.isSafeInteger(pid) && pid > 0) {
|
|
2047
|
+
const record = parsed;
|
|
2048
|
+
return {
|
|
2049
|
+
pid,
|
|
2050
|
+
...typeof record["socketPath"] === "string" ? { socketPath: record["socketPath"] } : {},
|
|
2051
|
+
...typeof record["startedAt"] === "number" ? { startedAt: record["startedAt"] } : {},
|
|
2052
|
+
...typeof record["version"] === "string" ? { version: record["version"] } : {}
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
return null;
|
|
2057
|
+
} catch (error) {
|
|
2058
|
+
if (!(error instanceof SyntaxError))
|
|
2059
|
+
throw error;
|
|
2034
2060
|
}
|
|
2035
|
-
|
|
2061
|
+
const legacyPid = Number(trimmed);
|
|
2062
|
+
if (Number.isSafeInteger(legacyPid) && legacyPid > 0)
|
|
2063
|
+
return { pid: legacyPid };
|
|
2064
|
+
return null;
|
|
2036
2065
|
}
|
|
2037
|
-
function
|
|
2038
|
-
const
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2066
|
+
function daemonLockCandidates(projectRoot) {
|
|
2067
|
+
const dirs = new Set;
|
|
2068
|
+
const resolved = resolve5(projectRoot);
|
|
2069
|
+
collectAncestors(resolved, dirs);
|
|
2070
|
+
collectAncestors(realpathIfPossible2(resolved), dirs);
|
|
2071
|
+
return [...dirs].map((dir) => join9(dir, ".codegraph", "daemon.pid"));
|
|
2072
|
+
}
|
|
2073
|
+
function evaluateDaemonStaleness(pid, projectRoot) {
|
|
2074
|
+
let sawLock = false;
|
|
2075
|
+
for (const lockPath of daemonLockCandidates(projectRoot)) {
|
|
2076
|
+
const raw = readLockIfPresent(lockPath);
|
|
2077
|
+
if (raw === undefined)
|
|
2043
2078
|
continue;
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2079
|
+
if (raw === null)
|
|
2080
|
+
return { stale: false, reason: "lock-unreadable" };
|
|
2081
|
+
sawLock = true;
|
|
2082
|
+
const lock = parseDaemonLock(raw);
|
|
2083
|
+
if (lock === null)
|
|
2084
|
+
return { stale: false, reason: "lock-unparseable" };
|
|
2085
|
+
if (lock.pid === pid)
|
|
2086
|
+
return { stale: false, reason: "lock-pid-match" };
|
|
2087
|
+
}
|
|
2088
|
+
return sawLock ? { stale: true, reason: "lock-pid-mismatch" } : { stale: true, reason: "lock-absent" };
|
|
2089
|
+
}
|
|
2090
|
+
function readLockIfPresent(lockPath) {
|
|
2091
|
+
try {
|
|
2092
|
+
return readFileSync4(lockPath, "utf8");
|
|
2093
|
+
} catch (error) {
|
|
2094
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT")
|
|
2095
|
+
return;
|
|
2096
|
+
if (error instanceof Error && "code" in error && error.code === "ENOTDIR")
|
|
2097
|
+
return;
|
|
2098
|
+
return null;
|
|
2050
2099
|
}
|
|
2051
|
-
return processes;
|
|
2052
2100
|
}
|
|
2053
|
-
function
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
continue;
|
|
2062
|
-
if (!isOrphaned(processInfo, livePids))
|
|
2063
|
-
continue;
|
|
2064
|
-
zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
|
|
2101
|
+
function collectAncestors(start, output) {
|
|
2102
|
+
let current = start;
|
|
2103
|
+
for (;; ) {
|
|
2104
|
+
output.add(current);
|
|
2105
|
+
const parent = dirname4(current);
|
|
2106
|
+
if (parent === current)
|
|
2107
|
+
return;
|
|
2108
|
+
current = parent;
|
|
2065
2109
|
}
|
|
2066
|
-
return zombies;
|
|
2067
2110
|
}
|
|
2068
|
-
function
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2111
|
+
function realpathIfPossible2(path) {
|
|
2112
|
+
try {
|
|
2113
|
+
return realpathSync4(path);
|
|
2114
|
+
} catch (error) {
|
|
2115
|
+
if (error instanceof Error)
|
|
2116
|
+
return path;
|
|
2117
|
+
throw error;
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
|
|
2121
|
+
// ../../utils/src/process-sweep/command-match.ts
|
|
2122
|
+
import { posix, win32 } from "node:path";
|
|
2123
|
+
function splitCommandTokens(command) {
|
|
2124
|
+
const tokens = [];
|
|
2125
|
+
let current = "";
|
|
2126
|
+
let quote = null;
|
|
2127
|
+
let tokenStarted = false;
|
|
2128
|
+
for (const char of command) {
|
|
2129
|
+
if (quote !== null) {
|
|
2130
|
+
if (char === quote) {
|
|
2131
|
+
quote = null;
|
|
2132
|
+
} else {
|
|
2133
|
+
current += char;
|
|
2134
|
+
}
|
|
2135
|
+
continue;
|
|
2136
|
+
}
|
|
2137
|
+
if (char === '"' || char === "'") {
|
|
2138
|
+
quote = char;
|
|
2139
|
+
tokenStarted = true;
|
|
2072
2140
|
continue;
|
|
2073
|
-
const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
|
|
2074
|
-
if (hasExecutableToken(normalizedCommand, serveWrapper))
|
|
2075
|
-
return { kind: "serve-wrapper", root };
|
|
2076
|
-
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
|
|
2077
|
-
return { kind: "upstream-codegraph", root };
|
|
2078
2141
|
}
|
|
2142
|
+
if (/\s/.test(char)) {
|
|
2143
|
+
if (tokenStarted || current.length > 0) {
|
|
2144
|
+
tokens.push(current);
|
|
2145
|
+
current = "";
|
|
2146
|
+
tokenStarted = false;
|
|
2147
|
+
}
|
|
2148
|
+
continue;
|
|
2149
|
+
}
|
|
2150
|
+
current += char;
|
|
2079
2151
|
}
|
|
2080
|
-
|
|
2152
|
+
if (tokenStarted || current.length > 0)
|
|
2153
|
+
tokens.push(current);
|
|
2154
|
+
return tokens;
|
|
2081
2155
|
}
|
|
2082
2156
|
function hasExecutableToken(command, expectedPath) {
|
|
2083
2157
|
let searchFrom = 0;
|
|
@@ -2093,24 +2167,19 @@ function hasExecutableToken(command, expectedPath) {
|
|
|
2093
2167
|
}
|
|
2094
2168
|
}
|
|
2095
2169
|
function tokenLooksExecutable(command, tokenStart) {
|
|
2096
|
-
|
|
2170
|
+
let prefix = command.slice(0, tokenStart).trimEnd();
|
|
2097
2171
|
if (prefix.length === 0)
|
|
2098
2172
|
return true;
|
|
2099
|
-
const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
|
|
2100
|
-
const previousToken = prefix.slice(previousTokenStart);
|
|
2101
|
-
const executableName = previousToken.split("/").at(-1) ?? previousToken;
|
|
2102
|
-
return /^node\d*(\.exe)?$/.test(executableName) || /^bun(\.exe)?$/.test(executableName);
|
|
2103
|
-
}
|
|
2104
|
-
function upstreamPackagePathIsUnderRoot(command, root) {
|
|
2105
|
-
let searchFrom = 0;
|
|
2106
2173
|
for (;; ) {
|
|
2107
|
-
const
|
|
2108
|
-
|
|
2174
|
+
const previousTokenStart = findTokenStart(prefix, prefix.length - 1);
|
|
2175
|
+
const previousToken = prefix.slice(previousTokenStart);
|
|
2176
|
+
if (!previousToken.startsWith("-")) {
|
|
2177
|
+
const executableName = previousToken.split("/").at(-1) ?? previousToken;
|
|
2178
|
+
return /^node\d*(\.exe)?$/i.test(executableName) || /^bun(\.exe)?$/i.test(executableName);
|
|
2179
|
+
}
|
|
2180
|
+
prefix = prefix.slice(0, previousTokenStart).trimEnd();
|
|
2181
|
+
if (prefix.length === 0)
|
|
2109
2182
|
return false;
|
|
2110
|
-
const tokenStart = findTokenStart(command, packageIndex);
|
|
2111
|
-
if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
|
|
2112
|
-
return true;
|
|
2113
|
-
searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
|
|
2114
2183
|
}
|
|
2115
2184
|
}
|
|
2116
2185
|
function findTokenStart(command, index) {
|
|
@@ -2144,6 +2213,39 @@ function normalizeForComparison2(value, platform) {
|
|
|
2144
2213
|
const normalized = value.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
2145
2214
|
return platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
2146
2215
|
}
|
|
2216
|
+
|
|
2217
|
+
// ../../utils/src/process-sweep/process-table.ts
|
|
2218
|
+
function parsePosixProcessTable(output) {
|
|
2219
|
+
const processes = [];
|
|
2220
|
+
for (const line of output.split(/\r?\n/)) {
|
|
2221
|
+
const match = /^\s*(\d+)\s+(\d+)\s+(.+?)\s*$/.exec(line);
|
|
2222
|
+
if (match === null)
|
|
2223
|
+
continue;
|
|
2224
|
+
const pid = Number(match[1]);
|
|
2225
|
+
const ppid = Number(match[2]);
|
|
2226
|
+
const command = match[3];
|
|
2227
|
+
if (!isValidProcessId(pid) || !Number.isInteger(ppid) || ppid < 0 || command === undefined)
|
|
2228
|
+
continue;
|
|
2229
|
+
processes.push({ command, pid, ppid });
|
|
2230
|
+
}
|
|
2231
|
+
return processes;
|
|
2232
|
+
}
|
|
2233
|
+
function parseWindowsProcessTable(output) {
|
|
2234
|
+
const parsed = parseJson(output);
|
|
2235
|
+
const entries = Array.isArray(parsed) ? parsed : parsed === undefined ? [] : [parsed];
|
|
2236
|
+
const processes = [];
|
|
2237
|
+
for (const entry of entries) {
|
|
2238
|
+
if (!isRecord3(entry))
|
|
2239
|
+
continue;
|
|
2240
|
+
const pid = numberField(entry, "ProcessId");
|
|
2241
|
+
const ppid = numberField(entry, "ParentProcessId");
|
|
2242
|
+
const command = stringField(entry, "CommandLine");
|
|
2243
|
+
if (pid === undefined || ppid === undefined || command === undefined || command.trim().length === 0)
|
|
2244
|
+
continue;
|
|
2245
|
+
processes.push({ command, pid, ppid });
|
|
2246
|
+
}
|
|
2247
|
+
return processes;
|
|
2248
|
+
}
|
|
2147
2249
|
function isOrphaned(processInfo, livePids) {
|
|
2148
2250
|
return processInfo.ppid === 1 || !livePids.has(processInfo.ppid);
|
|
2149
2251
|
}
|
|
@@ -2171,13 +2273,113 @@ function isRecord3(value) {
|
|
|
2171
2273
|
return typeof value === "object" && value !== null;
|
|
2172
2274
|
}
|
|
2173
2275
|
|
|
2174
|
-
// ../../utils/src/
|
|
2175
|
-
|
|
2276
|
+
// ../../utils/src/process-sweep/codegraph-family.ts
|
|
2277
|
+
var SERVE_WRAPPER_SUFFIX = "/components/codegraph/dist/serve.js";
|
|
2278
|
+
var UPSTREAM_PACKAGE_SEGMENT = "/@colbymchenry/codegraph/";
|
|
2279
|
+
function selectZombieCodegraphProcesses(processes, options) {
|
|
2280
|
+
const platform = options.platform ?? process.platform;
|
|
2281
|
+
const livePids = new Set(processes.map((processInfo) => processInfo.pid));
|
|
2282
|
+
const roots = normalizeRoots(options.ownedRoots, platform);
|
|
2283
|
+
const zombies = [];
|
|
2284
|
+
for (const processInfo of processes) {
|
|
2285
|
+
const daemon = matchDaemonCommand(processInfo.command, roots, platform);
|
|
2286
|
+
if (daemon !== null) {
|
|
2287
|
+
if (!isOrphaned(processInfo, livePids))
|
|
2288
|
+
continue;
|
|
2289
|
+
zombies.push({
|
|
2290
|
+
...processInfo,
|
|
2291
|
+
daemonProjectRoot: daemon.projectRoot,
|
|
2292
|
+
matchedRoot: daemon.root,
|
|
2293
|
+
matchKind: "upstream-daemon"
|
|
2294
|
+
});
|
|
2295
|
+
continue;
|
|
2296
|
+
}
|
|
2297
|
+
const match = matchOwnedCodegraphCommand(processInfo.command, roots, platform);
|
|
2298
|
+
if (match === null)
|
|
2299
|
+
continue;
|
|
2300
|
+
if (!isOrphaned(processInfo, livePids))
|
|
2301
|
+
continue;
|
|
2302
|
+
zombies.push({ ...processInfo, matchedRoot: match.root, matchKind: match.kind });
|
|
2303
|
+
}
|
|
2304
|
+
return zombies;
|
|
2305
|
+
}
|
|
2306
|
+
var STANDALONE_LAUNCHER_SUFFIXES = ["/bin/codegraph", "/bin/codegraph.exe"];
|
|
2307
|
+
var BUNDLE_SCRIPT_SUFFIX = "/lib/dist/bin/codegraph.js";
|
|
2308
|
+
function matchDaemonCommand(command, roots, platform) {
|
|
2309
|
+
const projectRoot = extractDaemonProjectRoot(splitCommandTokens(command));
|
|
2310
|
+
if (projectRoot === null)
|
|
2311
|
+
return null;
|
|
2312
|
+
const normalizedCommand = normalizeForComparison2(command, platform);
|
|
2313
|
+
for (const root of roots) {
|
|
2314
|
+
if (root.length === 0)
|
|
2315
|
+
continue;
|
|
2316
|
+
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root))
|
|
2317
|
+
return { projectRoot, root };
|
|
2318
|
+
for (const suffix of STANDALONE_LAUNCHER_SUFFIXES) {
|
|
2319
|
+
if (hasExecutableToken(normalizedCommand, `${root}${suffix}`))
|
|
2320
|
+
return { projectRoot, root };
|
|
2321
|
+
}
|
|
2322
|
+
if (hasExecutableToken(normalizedCommand, `${root}${BUNDLE_SCRIPT_SUFFIX}`))
|
|
2323
|
+
return { projectRoot, root };
|
|
2324
|
+
}
|
|
2325
|
+
return null;
|
|
2326
|
+
}
|
|
2327
|
+
function extractDaemonProjectRoot(tokens) {
|
|
2328
|
+
if (!tokens.includes("serve") || !tokens.includes("--mcp"))
|
|
2329
|
+
return null;
|
|
2330
|
+
const pathIndex = tokens.indexOf("--path");
|
|
2331
|
+
if (pathIndex < 0)
|
|
2332
|
+
return null;
|
|
2333
|
+
const value = tokens[pathIndex + 1];
|
|
2334
|
+
if (value === undefined || value.length === 0 || value.startsWith("--"))
|
|
2335
|
+
return null;
|
|
2336
|
+
return value;
|
|
2337
|
+
}
|
|
2338
|
+
function matchOwnedCodegraphCommand(command, roots, platform) {
|
|
2339
|
+
const normalizedCommand = normalizeForComparison2(command, platform);
|
|
2340
|
+
for (const root of roots) {
|
|
2341
|
+
if (root.length === 0)
|
|
2342
|
+
continue;
|
|
2343
|
+
const serveWrapper = `${root}${SERVE_WRAPPER_SUFFIX}`;
|
|
2344
|
+
if (hasExecutableToken(normalizedCommand, serveWrapper))
|
|
2345
|
+
return { kind: "serve-wrapper", root };
|
|
2346
|
+
if (upstreamPackagePathIsUnderRoot(normalizedCommand, root)) {
|
|
2347
|
+
return { kind: "upstream-codegraph", root };
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return null;
|
|
2351
|
+
}
|
|
2352
|
+
function upstreamPackagePathIsUnderRoot(command, root) {
|
|
2353
|
+
let searchFrom = 0;
|
|
2354
|
+
for (;; ) {
|
|
2355
|
+
const packageIndex = command.indexOf(UPSTREAM_PACKAGE_SEGMENT, searchFrom);
|
|
2356
|
+
if (packageIndex < 0)
|
|
2357
|
+
return false;
|
|
2358
|
+
const tokenStart = findTokenStart(command, packageIndex);
|
|
2359
|
+
if (command.slice(tokenStart).startsWith(`${root}/`) && tokenLooksExecutable(command, tokenStart))
|
|
2360
|
+
return true;
|
|
2361
|
+
searchFrom = packageIndex + UPSTREAM_PACKAGE_SEGMENT.length;
|
|
2362
|
+
}
|
|
2363
|
+
}
|
|
2364
|
+
|
|
2365
|
+
// ../../utils/src/process-sweep/exec.ts
|
|
2366
|
+
import { execFile } from "node:child_process";
|
|
2367
|
+
function enumerateProcesses(platform = process.platform) {
|
|
2176
2368
|
return platform === "win32" ? enumerateWindowsProcesses() : enumeratePosixProcesses();
|
|
2177
2369
|
}
|
|
2178
|
-
function
|
|
2370
|
+
function createDefaultProcessKiller(platform = process.platform) {
|
|
2179
2371
|
return platform === "win32" ? createWindowsKiller() : createPosixKiller();
|
|
2180
2372
|
}
|
|
2373
|
+
function defaultIsProcessAlive(pid) {
|
|
2374
|
+
try {
|
|
2375
|
+
process.kill(pid, 0);
|
|
2376
|
+
return true;
|
|
2377
|
+
} catch (error) {
|
|
2378
|
+
if (!(error instanceof Error))
|
|
2379
|
+
throw error;
|
|
2380
|
+
return processKillErrorMeansAlive(error);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2181
2383
|
function enumeratePosixProcesses() {
|
|
2182
2384
|
return execFileText("ps", ["-eo", "pid=,ppid=,command="]).then(parsePosixProcessTable);
|
|
2183
2385
|
}
|
|
@@ -2191,16 +2393,7 @@ function enumerateWindowsProcesses() {
|
|
|
2191
2393
|
}
|
|
2192
2394
|
function createPosixKiller() {
|
|
2193
2395
|
return {
|
|
2194
|
-
isAlive:
|
|
2195
|
-
try {
|
|
2196
|
-
process.kill(pid, 0);
|
|
2197
|
-
return true;
|
|
2198
|
-
} catch (error) {
|
|
2199
|
-
if (!(error instanceof Error))
|
|
2200
|
-
throw error;
|
|
2201
|
-
return processKillErrorMeansAlive(error);
|
|
2202
|
-
}
|
|
2203
|
-
},
|
|
2396
|
+
isAlive: defaultIsProcessAlive,
|
|
2204
2397
|
kill: (pid) => {
|
|
2205
2398
|
process.kill(pid, "SIGKILL");
|
|
2206
2399
|
return Promise.resolve();
|
|
@@ -2213,16 +2406,7 @@ function createPosixKiller() {
|
|
|
2213
2406
|
}
|
|
2214
2407
|
function createWindowsKiller() {
|
|
2215
2408
|
return {
|
|
2216
|
-
isAlive:
|
|
2217
|
-
try {
|
|
2218
|
-
process.kill(pid, 0);
|
|
2219
|
-
return true;
|
|
2220
|
-
} catch (error) {
|
|
2221
|
-
if (!(error instanceof Error))
|
|
2222
|
-
throw error;
|
|
2223
|
-
return processKillErrorMeansAlive(error);
|
|
2224
|
-
}
|
|
2225
|
-
},
|
|
2409
|
+
isAlive: defaultIsProcessAlive,
|
|
2226
2410
|
kill: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T", "/F"]),
|
|
2227
2411
|
terminate: (pid) => execFileVoid("taskkill.exe", ["/PID", String(pid), "/T"])
|
|
2228
2412
|
};
|
|
@@ -2252,10 +2436,10 @@ function processKillErrorMeansAlive(error) {
|
|
|
2252
2436
|
return false;
|
|
2253
2437
|
}
|
|
2254
2438
|
|
|
2255
|
-
// ../../utils/src/
|
|
2256
|
-
import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as
|
|
2439
|
+
// ../../utils/src/process-sweep/roots.ts
|
|
2440
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as realpathSync5 } from "node:fs";
|
|
2257
2441
|
import { homedir as homedir9 } from "node:os";
|
|
2258
|
-
import { join as
|
|
2442
|
+
import { join as join10, resolve as resolve6 } from "node:path";
|
|
2259
2443
|
function discoverCodegraphOwnedRoots(options = {}) {
|
|
2260
2444
|
const env = options.env ?? process.env;
|
|
2261
2445
|
const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
|
|
@@ -2265,33 +2449,33 @@ function discoverCodegraphOwnedRoots(options = {}) {
|
|
|
2265
2449
|
addRoot(roots, options.pluginRoot);
|
|
2266
2450
|
for (const root of options.extraRoots ?? [])
|
|
2267
2451
|
addRoot(roots, root);
|
|
2268
|
-
for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ??
|
|
2452
|
+
for (const root of readCodexPluginCacheRoots(options.codexHome ?? env["CODEX_HOME"] ?? join10(homeDir, ".codex"))) {
|
|
2269
2453
|
addRoot(roots, root);
|
|
2270
2454
|
}
|
|
2271
2455
|
return [...roots];
|
|
2272
2456
|
}
|
|
2273
2457
|
function readCodexPluginCacheRoots(codexHome) {
|
|
2274
|
-
const cacheRoot =
|
|
2458
|
+
const cacheRoot = join10(codexHome, "plugins", "cache");
|
|
2275
2459
|
if (!existsSync6(cacheRoot))
|
|
2276
2460
|
return [];
|
|
2277
2461
|
const roots = [];
|
|
2278
2462
|
for (const publisher of safeReadDir(cacheRoot)) {
|
|
2279
2463
|
if (!OMO_CODEX_PLUGIN_CACHE_PUBLISHERS.has(publisher))
|
|
2280
2464
|
continue;
|
|
2281
|
-
const omoRoot =
|
|
2465
|
+
const omoRoot = join10(cacheRoot, publisher, "omo");
|
|
2282
2466
|
if (!existsSync6(omoRoot))
|
|
2283
2467
|
continue;
|
|
2284
2468
|
for (const version of safeReadDir(omoRoot))
|
|
2285
|
-
roots.push(
|
|
2469
|
+
roots.push(join10(omoRoot, version));
|
|
2286
2470
|
}
|
|
2287
2471
|
return roots;
|
|
2288
2472
|
}
|
|
2289
2473
|
function addRoot(roots, root) {
|
|
2290
2474
|
if (root === undefined || root.trim().length === 0)
|
|
2291
2475
|
return;
|
|
2292
|
-
const resolved =
|
|
2476
|
+
const resolved = resolve6(root);
|
|
2293
2477
|
roots.add(resolved);
|
|
2294
|
-
roots.add(
|
|
2478
|
+
roots.add(realpathIfPossible3(resolved));
|
|
2295
2479
|
}
|
|
2296
2480
|
function safeReadDir(path) {
|
|
2297
2481
|
try {
|
|
@@ -2302,12 +2486,12 @@ function safeReadDir(path) {
|
|
|
2302
2486
|
throw error;
|
|
2303
2487
|
}
|
|
2304
2488
|
}
|
|
2305
|
-
function
|
|
2489
|
+
function realpathIfPossible3(path) {
|
|
2306
2490
|
try {
|
|
2307
|
-
return
|
|
2491
|
+
return realpathSync5(path);
|
|
2308
2492
|
} catch (error) {
|
|
2309
2493
|
if (error instanceof Error)
|
|
2310
|
-
return
|
|
2494
|
+
return resolve6(path);
|
|
2311
2495
|
throw error;
|
|
2312
2496
|
}
|
|
2313
2497
|
}
|
|
@@ -2319,70 +2503,109 @@ function isNonFatalFsError(error) {
|
|
|
2319
2503
|
}
|
|
2320
2504
|
var OMO_CODEX_PLUGIN_CACHE_PUBLISHERS = new Set(["sisyphuslabs"]);
|
|
2321
2505
|
|
|
2322
|
-
// ../../utils/src/
|
|
2506
|
+
// ../../utils/src/process-sweep/sweeper.ts
|
|
2323
2507
|
var DEFAULT_GRACE_MS = 2000;
|
|
2324
2508
|
var DEFAULT_THROTTLE_MS = 60 * 60 * 1000;
|
|
2325
|
-
|
|
2326
|
-
async function sweepCodegraphZombies(options = {}) {
|
|
2327
|
-
const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
|
|
2328
|
-
const stampFile = join10(codegraphDataRoot(homeDir), SWEEP_STAMP_FILE);
|
|
2509
|
+
async function runProcessFamilySweep(config, options) {
|
|
2329
2510
|
const nowMs = options.nowMs ?? Date.now();
|
|
2330
2511
|
const dryRun = options.dryRun === true;
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
return emptyResult("throttled", dryRun, ownedRoots, stampFile);
|
|
2512
|
+
if (options.force !== true && isSweepThrottled(config.stampFile, nowMs, options.throttleMs ?? DEFAULT_THROTTLE_MS)) {
|
|
2513
|
+
return { action: "throttled", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
|
|
2334
2514
|
}
|
|
2335
2515
|
try {
|
|
2336
|
-
const
|
|
2337
|
-
const
|
|
2338
|
-
ownedRoots,
|
|
2339
|
-
...options.platform === undefined ? {} : { platform: options.platform }
|
|
2340
|
-
});
|
|
2341
|
-
const result = dryRun ? { failed: [], killed: [] } : await killCandidates(candidates, options.killer ?? createDefaultCodegraphProcessKiller(options.platform), options);
|
|
2516
|
+
const plan = await config.collect();
|
|
2517
|
+
const { failed, killed } = dryRun ? { failed: [], killed: [] } : await killTargets(plan.killList, options.killer ?? createDefaultProcessKiller(options.platform), options, config.familyLabel);
|
|
2342
2518
|
if (!dryRun)
|
|
2343
|
-
writeSweepStamp(stampFile, nowMs);
|
|
2344
|
-
return {
|
|
2519
|
+
writeSweepStamp(config.stampFile, nowMs);
|
|
2520
|
+
return {
|
|
2521
|
+
action: "swept",
|
|
2522
|
+
candidates: plan.candidates,
|
|
2523
|
+
dryRun,
|
|
2524
|
+
failed,
|
|
2525
|
+
killed,
|
|
2526
|
+
spared: plan.spared,
|
|
2527
|
+
stampFile: config.stampFile
|
|
2528
|
+
};
|
|
2345
2529
|
} catch (error) {
|
|
2346
|
-
options.log?.(
|
|
2347
|
-
return
|
|
2530
|
+
options.log?.(`${config.familyLabel} skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
2531
|
+
return { action: "failed", candidates: [], dryRun, failed: [], killed: [], spared: [], stampFile: config.stampFile };
|
|
2348
2532
|
}
|
|
2349
2533
|
}
|
|
2350
|
-
|
|
2534
|
+
var CODEGRAPH_SWEEP_STAMP_FILE = "zombie-sweep.stamp";
|
|
2535
|
+
async function sweepCodegraphZombies(options = {}) {
|
|
2536
|
+
const homeDir = options.homeDir ?? options.env?.["HOME"] ?? options.env?.["USERPROFILE"] ?? homedir10();
|
|
2537
|
+
const stampFile = join11(codegraphDataRoot(homeDir), CODEGRAPH_SWEEP_STAMP_FILE);
|
|
2538
|
+
const ownedRoots = options.ownedRoots ?? discoverCodegraphOwnedRoots(options);
|
|
2539
|
+
const result = await runProcessFamilySweep({
|
|
2540
|
+
familyLabel: "CodeGraph zombie sweep",
|
|
2541
|
+
stampFile,
|
|
2542
|
+
collect: async () => {
|
|
2543
|
+
const provider = options.processProvider ?? (() => enumerateProcesses(options.platform));
|
|
2544
|
+
const candidates = selectZombieCodegraphProcesses(await provider(), {
|
|
2545
|
+
ownedRoots,
|
|
2546
|
+
...options.platform === undefined ? {} : { platform: options.platform }
|
|
2547
|
+
});
|
|
2548
|
+
const { killList, spared } = partitionByDaemonStaleness(candidates, options.log);
|
|
2549
|
+
return { candidates, killList, spared };
|
|
2550
|
+
}
|
|
2551
|
+
}, options);
|
|
2552
|
+
return { ...result, ownedRoots };
|
|
2553
|
+
}
|
|
2554
|
+
function partitionByDaemonStaleness(candidates, log) {
|
|
2555
|
+
const killList = [];
|
|
2556
|
+
const spared = [];
|
|
2557
|
+
for (const candidate of candidates) {
|
|
2558
|
+
if (candidate.matchKind !== "upstream-daemon") {
|
|
2559
|
+
killList.push(candidate);
|
|
2560
|
+
continue;
|
|
2561
|
+
}
|
|
2562
|
+
const staleness = evaluateDaemonStaleness(candidate.pid, candidate.daemonProjectRoot ?? candidate.matchedRoot);
|
|
2563
|
+
if (staleness.stale) {
|
|
2564
|
+
log?.(`CodeGraph zombie sweep sweeping stale daemon pid ${candidate.pid} (${staleness.reason})`);
|
|
2565
|
+
killList.push(candidate);
|
|
2566
|
+
continue;
|
|
2567
|
+
}
|
|
2568
|
+
log?.(`CodeGraph zombie sweep spared live daemon pid ${candidate.pid} (${staleness.reason})`);
|
|
2569
|
+
spared.push(candidate);
|
|
2570
|
+
}
|
|
2571
|
+
return { killList, spared };
|
|
2572
|
+
}
|
|
2573
|
+
async function killTargets(targets, killer, options, familyLabel) {
|
|
2351
2574
|
const failed = [];
|
|
2352
2575
|
const killed = [];
|
|
2353
|
-
for (const
|
|
2354
|
-
const terminated = await safelyTerminate(
|
|
2576
|
+
for (const target of targets) {
|
|
2577
|
+
const terminated = await safelyTerminate(target.pid, killer, failed, options.log, familyLabel);
|
|
2355
2578
|
if (!terminated)
|
|
2356
2579
|
continue;
|
|
2357
2580
|
await delay(options.graceMs ?? DEFAULT_GRACE_MS);
|
|
2358
|
-
if (!await killer.isAlive(
|
|
2359
|
-
killed.push(
|
|
2581
|
+
if (!await killer.isAlive(target.pid)) {
|
|
2582
|
+
killed.push(target);
|
|
2360
2583
|
continue;
|
|
2361
2584
|
}
|
|
2362
|
-
if (await safelyKill(
|
|
2363
|
-
killed.push(
|
|
2585
|
+
if (await safelyKill(target.pid, killer, failed, options.log, familyLabel))
|
|
2586
|
+
killed.push(target);
|
|
2364
2587
|
}
|
|
2365
2588
|
return { failed, killed };
|
|
2366
2589
|
}
|
|
2367
|
-
async function safelyTerminate(pid, killer, failed, log) {
|
|
2590
|
+
async function safelyTerminate(pid, killer, failed, log, familyLabel) {
|
|
2368
2591
|
try {
|
|
2369
2592
|
await killer.terminate(pid);
|
|
2370
2593
|
return true;
|
|
2371
2594
|
} catch (error) {
|
|
2372
2595
|
const message = error instanceof Error ? error.message : String(error);
|
|
2373
2596
|
failed.push({ error: message, pid, stage: "terminate" });
|
|
2374
|
-
log?.(
|
|
2597
|
+
log?.(`${familyLabel} failed to terminate pid ${pid}: ${message}`);
|
|
2375
2598
|
return false;
|
|
2376
2599
|
}
|
|
2377
2600
|
}
|
|
2378
|
-
async function safelyKill(pid, killer, failed, log) {
|
|
2601
|
+
async function safelyKill(pid, killer, failed, log, familyLabel) {
|
|
2379
2602
|
try {
|
|
2380
2603
|
await killer.kill(pid);
|
|
2381
2604
|
return true;
|
|
2382
2605
|
} catch (error) {
|
|
2383
2606
|
const message = error instanceof Error ? error.message : String(error);
|
|
2384
2607
|
failed.push({ error: message, pid, stage: "kill" });
|
|
2385
|
-
log?.(
|
|
2608
|
+
log?.(`${familyLabel} failed to kill pid ${pid}: ${message}`);
|
|
2386
2609
|
return false;
|
|
2387
2610
|
}
|
|
2388
2611
|
}
|
|
@@ -2392,15 +2615,12 @@ function isSweepThrottled(stampFile, nowMs, throttleMs) {
|
|
|
2392
2615
|
return nowMs - statSync2(stampFile).mtimeMs < throttleMs;
|
|
2393
2616
|
}
|
|
2394
2617
|
function writeSweepStamp(stampFile, nowMs) {
|
|
2395
|
-
mkdirSync2(
|
|
2618
|
+
mkdirSync2(dirname5(stampFile), { recursive: true });
|
|
2396
2619
|
writeFileSync2(stampFile, `${new Date(nowMs).toISOString()}
|
|
2397
2620
|
`);
|
|
2398
2621
|
const stampDate = new Date(nowMs);
|
|
2399
2622
|
utimesSync(stampFile, stampDate, stampDate);
|
|
2400
2623
|
}
|
|
2401
|
-
function emptyResult(action, dryRun, ownedRoots, stampFile) {
|
|
2402
|
-
return { action, candidates: [], dryRun, failed: [], killed: [], ownedRoots, stampFile };
|
|
2403
|
-
}
|
|
2404
2624
|
function delay(ms) {
|
|
2405
2625
|
if (ms <= 0)
|
|
2406
2626
|
return Promise.resolve();
|
|
@@ -2428,56 +2648,55 @@ function defaultPluginRoot() {
|
|
|
2428
2648
|
import { execFile as execFile3 } from "node:child_process";
|
|
2429
2649
|
import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "node:fs";
|
|
2430
2650
|
import { homedir as homedir12 } from "node:os";
|
|
2431
|
-
import { extname, join as
|
|
2651
|
+
import { extname, join as join13 } from "node:path";
|
|
2432
2652
|
import { cwd as processCwd, env as processEnv, execPath as processExecPath, stderr as processStderr } from "node:process";
|
|
2433
2653
|
|
|
2434
|
-
// ../../utils/src/codegraph/provision.ts
|
|
2435
|
-
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
2436
|
-
import { execFile as execFile2 } from "node:child_process";
|
|
2437
|
-
import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
2438
|
-
import { existsSync as existsSync8 } from "node:fs";
|
|
2439
|
-
import { homedir as homedir11, hostname } from "node:os";
|
|
2440
|
-
import { basename as basename3, join as join11 } from "node:path";
|
|
2441
|
-
import { promisify } from "node:util";
|
|
2442
|
-
|
|
2443
2654
|
// ../../utils/src/codegraph/manifest.ts
|
|
2655
|
+
var CODEGRAPH_PINNED_VERSION = "1.4.1";
|
|
2444
2656
|
var CODEGRAPH_PROVISION_MANIFEST = {
|
|
2445
2657
|
assets: {
|
|
2446
2658
|
"darwin-arm64": {
|
|
2447
2659
|
executableName: "codegraph",
|
|
2448
|
-
sha256: "
|
|
2449
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.
|
|
2660
|
+
sha256: "4a679ae5a5cb9fff900dd59bb786da6a581b7f68f4cf713bdedd137e347d34dc",
|
|
2661
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-arm64.tar.gz"
|
|
2450
2662
|
},
|
|
2451
2663
|
"darwin-x64": {
|
|
2452
2664
|
executableName: "codegraph",
|
|
2453
|
-
sha256: "
|
|
2454
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.
|
|
2665
|
+
sha256: "436f96943cfd926ea6d0a8454f18833d21254d5fd9b3d224317b1426132def95",
|
|
2666
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-darwin-x64.tar.gz"
|
|
2455
2667
|
},
|
|
2456
2668
|
"linux-arm64": {
|
|
2457
2669
|
executableName: "codegraph",
|
|
2458
|
-
sha256: "
|
|
2459
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.
|
|
2670
|
+
sha256: "0d62c5eb2722f8d19d20f7a1bd974445e18d5294cb59be116a0c3d55ce87591f",
|
|
2671
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-arm64.tar.gz"
|
|
2460
2672
|
},
|
|
2461
2673
|
"linux-x64": {
|
|
2462
2674
|
executableName: "codegraph",
|
|
2463
|
-
sha256: "
|
|
2464
|
-
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.
|
|
2675
|
+
sha256: "fb585ff5018d6faaa46d282b61f4f689bc7967ed8a1b467a5c556dd7ced9b542",
|
|
2676
|
+
url: "https://github.com/colbymchenry/codegraph/releases/download/v1.4.1/codegraph-linux-x64.tar.gz"
|
|
2465
2677
|
},
|
|
2466
2678
|
"win32-arm64": {
|
|
2467
2679
|
executableName: "codegraph.cmd",
|
|
2468
|
-
sha256: "
|
|
2469
|
-
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.
|
|
2680
|
+
sha256: "e2a2a28c802a79804c7df203afa50bd461309c6c180ce3f76079fdc7cddc7697",
|
|
2681
|
+
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-arm64/-/codegraph-win32-arm64-1.4.1.tgz"
|
|
2470
2682
|
},
|
|
2471
2683
|
"win32-x64": {
|
|
2472
2684
|
executableName: "codegraph.cmd",
|
|
2473
|
-
sha256: "
|
|
2474
|
-
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.
|
|
2685
|
+
sha256: "4f08700fda5f4a03ad5b2956135c5788d739a351b3433db2b5820e5d5224c30d",
|
|
2686
|
+
url: "https://registry.npmjs.org/@colbymchenry/codegraph-win32-x64/-/codegraph-win32-x64-1.4.1.tgz"
|
|
2475
2687
|
}
|
|
2476
2688
|
},
|
|
2477
|
-
version:
|
|
2689
|
+
version: CODEGRAPH_PINNED_VERSION
|
|
2478
2690
|
};
|
|
2479
2691
|
|
|
2480
2692
|
// ../../utils/src/codegraph/provision.ts
|
|
2693
|
+
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
2694
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
2695
|
+
import { chmod, mkdir, readdir, readFile, rename, rm, rmdir, stat, writeFile } from "node:fs/promises";
|
|
2696
|
+
import { existsSync as existsSync8 } from "node:fs";
|
|
2697
|
+
import { homedir as homedir11, hostname } from "node:os";
|
|
2698
|
+
import { basename as basename3, join as join12 } from "node:path";
|
|
2699
|
+
import { promisify } from "node:util";
|
|
2481
2700
|
var DEFAULT_LOCK_WAIT_MS = 5000;
|
|
2482
2701
|
var DEFAULT_LOCK_STALE_MS = 120000;
|
|
2483
2702
|
var DEFAULT_DOWNLOAD_TIMEOUT_MS = 60000;
|
|
@@ -2486,10 +2705,10 @@ function platformKey() {
|
|
|
2486
2705
|
return `${process.platform}-${process.arch}`;
|
|
2487
2706
|
}
|
|
2488
2707
|
function markerPath(installDir, version) {
|
|
2489
|
-
return
|
|
2708
|
+
return join12(installDir, ".provisioned", `codegraph-${version}.json`);
|
|
2490
2709
|
}
|
|
2491
2710
|
function defaultInstallDir() {
|
|
2492
|
-
return
|
|
2711
|
+
return join12(homedir11(), ".omo", "codegraph");
|
|
2493
2712
|
}
|
|
2494
2713
|
function sha256(bytes) {
|
|
2495
2714
|
return createHash2("sha256").update(bytes).digest("hex");
|
|
@@ -2509,7 +2728,7 @@ async function removeEmptyDirectory(path) {
|
|
|
2509
2728
|
}
|
|
2510
2729
|
}
|
|
2511
2730
|
function sleep(ms) {
|
|
2512
|
-
return new Promise((
|
|
2731
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
2513
2732
|
}
|
|
2514
2733
|
async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
|
|
2515
2734
|
const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -2523,7 +2742,7 @@ function forcedBadChecksumOptions(options) {
|
|
|
2523
2742
|
const key = options.platformKey ?? platformKey();
|
|
2524
2743
|
return {
|
|
2525
2744
|
downloader: async () => new TextEncoder().encode("checksum mismatch"),
|
|
2526
|
-
installDir: options.installDir ??
|
|
2745
|
+
installDir: options.installDir ?? join12(options.lockDir, "codegraph-force-bad-checksum"),
|
|
2527
2746
|
manifest: {
|
|
2528
2747
|
assets: {
|
|
2529
2748
|
[key]: { executableName: process.platform === "win32" ? "codegraph.cmd" : "codegraph", sha256: "0000", url: "memory://bad" }
|
|
@@ -2551,7 +2770,7 @@ async function readMarker(path) {
|
|
|
2551
2770
|
}
|
|
2552
2771
|
async function acquireLock(lockPath, waitMs, staleMs) {
|
|
2553
2772
|
const startedAt = Date.now();
|
|
2554
|
-
await mkdir(
|
|
2773
|
+
await mkdir(join12(lockPath, ".."), { recursive: true });
|
|
2555
2774
|
while (Date.now() - startedAt <= waitMs) {
|
|
2556
2775
|
try {
|
|
2557
2776
|
await mkdir(lockPath);
|
|
@@ -2576,14 +2795,14 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
|
|
|
2576
2795
|
const roots = await readdir(extractDir);
|
|
2577
2796
|
if (roots.length !== 1)
|
|
2578
2797
|
throw new Error(`CodeGraph archive should contain one root directory, found ${roots.length}`);
|
|
2579
|
-
const bundleDir =
|
|
2798
|
+
const bundleDir = join12(extractDir, roots[0] ?? "");
|
|
2580
2799
|
const bundleEntries = await readdir(bundleDir);
|
|
2581
2800
|
await mkdir(installDir, { recursive: true });
|
|
2582
2801
|
for (const entry of bundleEntries) {
|
|
2583
|
-
await rm(
|
|
2584
|
-
await rename(
|
|
2802
|
+
await rm(join12(installDir, entry), { force: true, recursive: true });
|
|
2803
|
+
await rename(join12(bundleDir, entry), join12(installDir, entry));
|
|
2585
2804
|
}
|
|
2586
|
-
const destination =
|
|
2805
|
+
const destination = join12(installDir, "bin", executableName);
|
|
2587
2806
|
if (!existsSync8(destination))
|
|
2588
2807
|
throw new Error(`CodeGraph archive did not contain bin/${executableName}`);
|
|
2589
2808
|
await chmod(destination, 493);
|
|
@@ -2591,9 +2810,9 @@ async function installExtractedBundle(extractDir, installDir, executableName) {
|
|
|
2591
2810
|
}
|
|
2592
2811
|
async function installAsset(layout) {
|
|
2593
2812
|
const { asset, downloader, installDir, version } = layout;
|
|
2594
|
-
const stagingDir =
|
|
2595
|
-
const archivePath =
|
|
2596
|
-
const extractDir =
|
|
2813
|
+
const stagingDir = join12(installDir, ".staging", randomUUID());
|
|
2814
|
+
const archivePath = join12(stagingDir, basename3(asset.url));
|
|
2815
|
+
const extractDir = join12(stagingDir, "extract");
|
|
2597
2816
|
try {
|
|
2598
2817
|
await mkdir(extractDir, { recursive: true });
|
|
2599
2818
|
const bytes = await downloader(asset);
|
|
@@ -2607,13 +2826,13 @@ async function installAsset(layout) {
|
|
|
2607
2826
|
await writeFile(archivePath, bytes);
|
|
2608
2827
|
await extractTarGz(archivePath, extractDir);
|
|
2609
2828
|
const destination = await installExtractedBundle(extractDir, installDir, asset.executableName);
|
|
2610
|
-
await mkdir(
|
|
2829
|
+
await mkdir(join12(installDir, ".provisioned"), { recursive: true });
|
|
2611
2830
|
await writeFile(markerPath(installDir, version), `${JSON.stringify({ binPath: destination, version })}
|
|
2612
2831
|
`);
|
|
2613
2832
|
return destination;
|
|
2614
2833
|
} finally {
|
|
2615
2834
|
await rm(stagingDir, { force: true, recursive: true });
|
|
2616
|
-
await removeEmptyDirectory(
|
|
2835
|
+
await removeEmptyDirectory(join12(installDir, ".staging"));
|
|
2617
2836
|
}
|
|
2618
2837
|
}
|
|
2619
2838
|
async function ensureCodegraphProvisioned(options) {
|
|
@@ -2626,7 +2845,7 @@ async function ensureCodegraphProvisioned(options) {
|
|
|
2626
2845
|
const existing = await readMarker(marker);
|
|
2627
2846
|
if (existing !== null)
|
|
2628
2847
|
return { binPath: existing, provisioned: true };
|
|
2629
|
-
const lockPath =
|
|
2848
|
+
const lockPath = join12(options.lockDir, `codegraph-${hostname()}.lock`);
|
|
2630
2849
|
const release = await acquireLock(lockPath, options.lockWaitMs ?? DEFAULT_LOCK_WAIT_MS, options.lockStaleMs ?? DEFAULT_LOCK_STALE_MS);
|
|
2631
2850
|
if (release === null)
|
|
2632
2851
|
return { error: "timed out waiting for codegraph provisioning lock", provisioned: false };
|
|
@@ -2652,7 +2871,7 @@ async function ensureCodegraphProvisioned(options) {
|
|
|
2652
2871
|
|
|
2653
2872
|
// components/codegraph/src/session-start-worker.ts
|
|
2654
2873
|
var SESSION_START_CWD_ENV = "OMO_CODEGRAPH_SESSION_START_CWD";
|
|
2655
|
-
var CODEGRAPH_VERSION =
|
|
2874
|
+
var CODEGRAPH_VERSION = CODEGRAPH_PINNED_VERSION;
|
|
2656
2875
|
var COMMAND_TIMEOUT_MS = 60000;
|
|
2657
2876
|
var WINDOWS_CMD_EXTENSIONS = new Set([".bat", ".cmd"]);
|
|
2658
2877
|
var WINDOWS_NODE_SCRIPT_EXTENSIONS = new Set([".cjs", ".js", ".mjs"]);
|
|
@@ -2716,15 +2935,15 @@ async function resolveOrProvisionCommand(deps, config, env, homeDir, nodeSupport
|
|
|
2716
2935
|
return { kind: "unsupported-node" };
|
|
2717
2936
|
if (config.auto_provision === false)
|
|
2718
2937
|
return { error: "codegraph binary unavailable and auto_provision is disabled", kind: "unavailable", source: resolved.source };
|
|
2719
|
-
const installDir = trustedInstallDir ??
|
|
2720
|
-
const provisioned = await deps.ensureProvisioned({ installDir, lockDir:
|
|
2938
|
+
const installDir = trustedInstallDir ?? join13(homeDir, ".omo", "codegraph");
|
|
2939
|
+
const provisioned = await deps.ensureProvisioned({ installDir, lockDir: join13(installDir, ".locks"), version: CODEGRAPH_VERSION });
|
|
2721
2940
|
if (!provisioned.provisioned || provisioned.binPath === undefined) {
|
|
2722
2941
|
return { error: provisioned.error ?? "provisioning did not produce a binary", kind: "unavailable", source: resolved.source };
|
|
2723
2942
|
}
|
|
2724
2943
|
return { kind: "resolved", resolution: { argsPrefix: [], command: provisioned.binPath, exists: true, source: "provisioned" } };
|
|
2725
2944
|
}
|
|
2726
2945
|
function codegraphEnvForConfig(config, homeDir) {
|
|
2727
|
-
const env = buildCodegraphEnv({ homeDir });
|
|
2946
|
+
const env = buildCodegraphEnv({ daemon: false, homeDir });
|
|
2728
2947
|
return config.trustedCodegraphInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: config.trustedCodegraphInstallDir };
|
|
2729
2948
|
}
|
|
2730
2949
|
function canUseResolvedCommand(resolved, nodeSupport) {
|
|
@@ -2785,9 +3004,9 @@ function resolveCodegraphCommandInvocation(command, args, platform = process.pla
|
|
|
2785
3004
|
return { args: ["/d", "/s", "/c", command, ...args], command: "cmd.exe" };
|
|
2786
3005
|
}
|
|
2787
3006
|
function appendOutcome(homeDir, outcome) {
|
|
2788
|
-
const logDir =
|
|
3007
|
+
const logDir = join13(homeDir, ".omo", "codegraph");
|
|
2789
3008
|
mkdirSync3(logDir, { recursive: true });
|
|
2790
|
-
appendFileSync2(
|
|
3009
|
+
appendFileSync2(join13(logDir, "session-start.jsonl"), `${JSON.stringify({ ...outcome, timestamp: new Date().toISOString() })}
|
|
2791
3010
|
`);
|
|
2792
3011
|
}
|
|
2793
3012
|
function safeLogOutcome(logOutcome, outcome) {
|
|
@@ -2804,7 +3023,7 @@ function safeLogOutcome(logOutcome, outcome) {
|
|
|
2804
3023
|
function provisionedBinFromInstallDir(installDir) {
|
|
2805
3024
|
if (installDir === undefined)
|
|
2806
3025
|
return null;
|
|
2807
|
-
const candidate =
|
|
3026
|
+
const candidate = join13(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
2808
3027
|
return existsSync9(candidate) ? candidate : null;
|
|
2809
3028
|
}
|
|
2810
3029
|
function resolveExitCode(error) {
|
|
@@ -2865,6 +3084,7 @@ async function executeCodegraphSessionStartHook(options = {}) {
|
|
|
2865
3084
|
return { action: "skipped-excluded", exitCode: 0 };
|
|
2866
3085
|
}
|
|
2867
3086
|
const isInitialized = await (options.statusProbe ?? isCodegraphProjectInitialized)({
|
|
3087
|
+
daemon: config.codegraph?.daemon === true,
|
|
2868
3088
|
env,
|
|
2869
3089
|
homeDir,
|
|
2870
3090
|
projectRoot,
|
|
@@ -2895,7 +3115,7 @@ async function isCodegraphProjectInitialized(options) {
|
|
|
2895
3115
|
return false;
|
|
2896
3116
|
const invocation = resolveCodegraphCommandInvocation(resolved.command, [...resolved.argsPrefix, "status", "--json"]);
|
|
2897
3117
|
const codegraphEnv = {
|
|
2898
|
-
...buildCodegraphEnv({ homeDir: options.homeDir }),
|
|
3118
|
+
...buildCodegraphEnv({ daemon: options.daemon, homeDir: options.homeDir }),
|
|
2899
3119
|
...options.trustedCodegraphInstallDir === undefined ? {} : { CODEGRAPH_INSTALL_DIR: options.trustedCodegraphInstallDir }
|
|
2900
3120
|
};
|
|
2901
3121
|
const status = await runStatusProbe(options.projectRoot, invocation.command, invocation.args, buildCodegraphChildEnv({ ambientEnv: options.env, codegraphEnv, runtimeEnv: options.env }));
|
|
@@ -2937,7 +3157,7 @@ function codegraphStatusSaysInitialized(stdout) {
|
|
|
2937
3157
|
function provisionedBinFromInstallDir2(installDir) {
|
|
2938
3158
|
if (installDir === undefined)
|
|
2939
3159
|
return null;
|
|
2940
|
-
return
|
|
3160
|
+
return join14(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
2941
3161
|
}
|
|
2942
3162
|
async function executeCodegraphPostToolUseHook(options = {}) {
|
|
2943
3163
|
const env = options.env ?? processEnv2;
|
|
@@ -3027,9 +3247,9 @@ function defaultWorkerCliPath() {
|
|
|
3027
3247
|
}
|
|
3028
3248
|
|
|
3029
3249
|
// components/codegraph/src/serve.ts
|
|
3030
|
-
import { existsSync as existsSync10, realpathSync as
|
|
3250
|
+
import { existsSync as existsSync10, realpathSync as realpathSync6 } from "node:fs";
|
|
3031
3251
|
import { homedir as homedir14 } from "node:os";
|
|
3032
|
-
import { basename as basename4, join as
|
|
3252
|
+
import { basename as basename4, join as join15, resolve as resolve7 } from "node:path";
|
|
3033
3253
|
import {
|
|
3034
3254
|
cwd as processCwd3,
|
|
3035
3255
|
env as processEnv3,
|
|
@@ -3090,7 +3310,7 @@ ${body}` : `${body}
|
|
|
3090
3310
|
await writeChunk(output, payload);
|
|
3091
3311
|
}
|
|
3092
3312
|
function writeChunk(output, chunk) {
|
|
3093
|
-
return new Promise((
|
|
3313
|
+
return new Promise((resolve7, reject) => {
|
|
3094
3314
|
let settled = false;
|
|
3095
3315
|
const onError = (error) => {
|
|
3096
3316
|
if (settled)
|
|
@@ -3110,7 +3330,7 @@ function writeChunk(output, chunk) {
|
|
|
3110
3330
|
return;
|
|
3111
3331
|
}
|
|
3112
3332
|
output.removeListener("error", onError);
|
|
3113
|
-
|
|
3333
|
+
resolve7();
|
|
3114
3334
|
});
|
|
3115
3335
|
} catch (error) {
|
|
3116
3336
|
output.removeListener("error", onError);
|
|
@@ -3202,16 +3422,35 @@ function bufferFromChunk(chunk) {
|
|
|
3202
3422
|
|
|
3203
3423
|
// ../../mcp-stdio-core/src/server.ts
|
|
3204
3424
|
var DEFAULT_IDLE_TIMEOUT_MS = 10 * 60000;
|
|
3425
|
+
var DEFAULT_PARENT_POLL_INTERVAL_MS = 30000;
|
|
3205
3426
|
var noopLog = () => {};
|
|
3427
|
+
function isProcessAlive(pid) {
|
|
3428
|
+
try {
|
|
3429
|
+
process.kill(pid, 0);
|
|
3430
|
+
return true;
|
|
3431
|
+
} catch (error) {
|
|
3432
|
+
return !hasErrorCode(error, "ESRCH");
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3206
3435
|
async function runJsonRpcStdioServer(config) {
|
|
3207
3436
|
const log = config.log ?? noopLog;
|
|
3208
3437
|
const idleTimeoutMs = config.idleTimeoutMs ?? DEFAULT_IDLE_TIMEOUT_MS;
|
|
3209
|
-
|
|
3438
|
+
let isClosed = false;
|
|
3439
|
+
const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
|
|
3440
|
+
isClosed = true;
|
|
3441
|
+
config.onIdleTimeout?.();
|
|
3442
|
+
});
|
|
3443
|
+
const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
|
|
3444
|
+
isClosed = true;
|
|
3445
|
+
log("parent_exit", { parent_pid: parentPid, poll_interval_ms: pollIntervalMs });
|
|
3446
|
+
config.onParentExit?.();
|
|
3447
|
+
config.input.destroy();
|
|
3448
|
+
});
|
|
3210
3449
|
log("stdio_started", { cwd: process.cwd(), idle_timeout_ms: idleTimeoutMs });
|
|
3211
3450
|
idleTimer.arm();
|
|
3212
3451
|
try {
|
|
3213
3452
|
for await (const message of readStdioJsonRpcMessages(config.input)) {
|
|
3214
|
-
if (
|
|
3453
|
+
if (isClosed)
|
|
3215
3454
|
break;
|
|
3216
3455
|
idleTimer.arm();
|
|
3217
3456
|
if (message.kind === "parse_error") {
|
|
@@ -3222,8 +3461,12 @@ async function runJsonRpcStdioServer(config) {
|
|
|
3222
3461
|
if (!await handleRequest(message, config, log))
|
|
3223
3462
|
break;
|
|
3224
3463
|
}
|
|
3464
|
+
} catch (error) {
|
|
3465
|
+
if (!(isClosed && hasErrorCode(error, "ERR_STREAM_PREMATURE_CLOSE")))
|
|
3466
|
+
throw error;
|
|
3225
3467
|
} finally {
|
|
3226
3468
|
idleTimer.clear();
|
|
3469
|
+
watchdog.clear();
|
|
3227
3470
|
log("stdio_stopped");
|
|
3228
3471
|
}
|
|
3229
3472
|
}
|
|
@@ -3279,9 +3522,33 @@ function isTerminalOutputError(error) {
|
|
|
3279
3522
|
return false;
|
|
3280
3523
|
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
3281
3524
|
}
|
|
3282
|
-
function
|
|
3525
|
+
function hasErrorCode(error, code) {
|
|
3526
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
3527
|
+
}
|
|
3528
|
+
function createParentWatchdog(config, onDeadParent) {
|
|
3529
|
+
if (config === undefined)
|
|
3530
|
+
return { clear: () => {} };
|
|
3531
|
+
const pollIntervalMs = config.pollIntervalMs ?? DEFAULT_PARENT_POLL_INTERVAL_MS;
|
|
3532
|
+
if (pollIntervalMs <= 0)
|
|
3533
|
+
return { clear: () => {} };
|
|
3534
|
+
const parentPid = config.parentPid ?? process.ppid;
|
|
3535
|
+
const probeAlive = config.probeAlive ?? isProcessAlive;
|
|
3536
|
+
let fired = false;
|
|
3537
|
+
const timer = setInterval(() => {
|
|
3538
|
+
if (fired || probeAlive(parentPid))
|
|
3539
|
+
return;
|
|
3540
|
+
fired = true;
|
|
3541
|
+
onDeadParent(parentPid, pollIntervalMs);
|
|
3542
|
+
}, pollIntervalMs);
|
|
3543
|
+
timer.unref();
|
|
3544
|
+
return {
|
|
3545
|
+
clear: () => {
|
|
3546
|
+
clearInterval(timer);
|
|
3547
|
+
}
|
|
3548
|
+
};
|
|
3549
|
+
}
|
|
3550
|
+
function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
3283
3551
|
let timer = null;
|
|
3284
|
-
let isClosed = false;
|
|
3285
3552
|
return {
|
|
3286
3553
|
arm: () => {
|
|
3287
3554
|
if (timer !== null)
|
|
@@ -3289,9 +3556,8 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
3289
3556
|
if (idleTimeoutMs <= 0)
|
|
3290
3557
|
return;
|
|
3291
3558
|
timer = setTimeout(() => {
|
|
3292
|
-
isClosed = true;
|
|
3293
3559
|
log("idle_timeout", { idle_timeout_ms: idleTimeoutMs });
|
|
3294
|
-
|
|
3560
|
+
onTimeout();
|
|
3295
3561
|
}, idleTimeoutMs);
|
|
3296
3562
|
timer.unref();
|
|
3297
3563
|
},
|
|
@@ -3300,8 +3566,7 @@ function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
|
3300
3566
|
return;
|
|
3301
3567
|
clearTimeout(timer);
|
|
3302
3568
|
timer = null;
|
|
3303
|
-
}
|
|
3304
|
-
closed: () => isClosed
|
|
3569
|
+
}
|
|
3305
3570
|
};
|
|
3306
3571
|
}
|
|
3307
3572
|
// components/codegraph/src/serve-invocation.ts
|
|
@@ -3334,6 +3599,7 @@ class CodegraphBridgeStdioError extends Error {
|
|
|
3334
3599
|
var CODEGRAPH_NODE_DESCRIPTION = "Inspect one named symbol or file. In symbol mode, includeCode=true includes leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces return structural outlines with member lists by design. For container source, request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit.";
|
|
3335
3600
|
var CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION = "Symbol mode: include leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces intentionally return structural outlines with members; request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit for source.";
|
|
3336
3601
|
var CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE = "Container symbols intentionally return structural outlines with members. For source, request a specific member symbol or call codegraph_node in file mode with symbolsOnly=false plus offset/limit around the symbol location.";
|
|
3602
|
+
var SIGKILL_ESCALATION_MS = 2000;
|
|
3337
3603
|
async function runBridgedCodegraphProcess(command, args, options) {
|
|
3338
3604
|
const invocation = resolveServeProcessInvocation(command, args);
|
|
3339
3605
|
const child = spawn2(invocation.command, invocation.args, {
|
|
@@ -3359,17 +3625,24 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3359
3625
|
resolveExit(signal === null ? 0 : 1);
|
|
3360
3626
|
});
|
|
3361
3627
|
});
|
|
3362
|
-
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
3363
|
-
defaultResponseMode = mode;
|
|
3364
|
-
});
|
|
3365
|
-
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode);
|
|
3366
|
-
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
3367
|
-
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
3368
3628
|
const destroyChildPipes = () => {
|
|
3369
3629
|
childInput.destroy();
|
|
3370
3630
|
childOutput.destroy();
|
|
3371
3631
|
};
|
|
3372
3632
|
childExit.then(destroyChildPipes, destroyChildPipes);
|
|
3633
|
+
let parentWatchdogFired = false;
|
|
3634
|
+
const parentWatchdog = createParentWatchdog(options.parentWatchdog, () => {
|
|
3635
|
+
parentWatchdogFired = true;
|
|
3636
|
+
options.input.destroy();
|
|
3637
|
+
destroyChildPipes();
|
|
3638
|
+
terminateCodegraphChild(child);
|
|
3639
|
+
});
|
|
3640
|
+
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
3641
|
+
defaultResponseMode = mode;
|
|
3642
|
+
}, () => parentWatchdogFired);
|
|
3643
|
+
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode, () => parentWatchdogFired);
|
|
3644
|
+
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
3645
|
+
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
3373
3646
|
try {
|
|
3374
3647
|
return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
|
|
3375
3648
|
} catch (error) {
|
|
@@ -3380,39 +3653,66 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3380
3653
|
return;
|
|
3381
3654
|
});
|
|
3382
3655
|
throw error;
|
|
3656
|
+
} finally {
|
|
3657
|
+
parentWatchdog.clear();
|
|
3383
3658
|
}
|
|
3384
3659
|
}
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3660
|
+
function terminateCodegraphChild(child) {
|
|
3661
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
3662
|
+
return;
|
|
3663
|
+
child.kill("SIGTERM");
|
|
3664
|
+
const escalation = setTimeout(() => {
|
|
3665
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
3666
|
+
child.kill("SIGKILL");
|
|
3667
|
+
}, SIGKILL_ESCALATION_MS);
|
|
3668
|
+
escalation.unref();
|
|
3669
|
+
}
|
|
3670
|
+
function isWatchdogTeardownError(error) {
|
|
3671
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
3672
|
+
return false;
|
|
3673
|
+
return error.code === "ERR_STREAM_PREMATURE_CLOSE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END" || error.code === "EPIPE";
|
|
3674
|
+
}
|
|
3675
|
+
async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode, tolerateWatchdogClose) {
|
|
3676
|
+
try {
|
|
3677
|
+
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
3678
|
+
if (message.kind === "parse_error") {
|
|
3679
|
+
continue;
|
|
3680
|
+
}
|
|
3681
|
+
const responseMode = message.responseMode;
|
|
3682
|
+
setDefaultResponseMode(responseMode);
|
|
3683
|
+
const key = responseModeKey(message.payload);
|
|
3684
|
+
if (key !== null) {
|
|
3685
|
+
pendingResponses.set(key, {
|
|
3686
|
+
method: jsonRpcMethod(message.payload),
|
|
3687
|
+
responseMode,
|
|
3688
|
+
toolName: jsonRpcToolName(message.payload)
|
|
3689
|
+
});
|
|
3690
|
+
}
|
|
3691
|
+
await writeLine(childInput, JSON.stringify(message.payload));
|
|
3399
3692
|
}
|
|
3400
|
-
|
|
3693
|
+
childInput.end();
|
|
3694
|
+
} catch (error) {
|
|
3695
|
+
if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
|
|
3696
|
+
throw error;
|
|
3401
3697
|
}
|
|
3402
|
-
childInput.end();
|
|
3403
3698
|
}
|
|
3404
|
-
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3699
|
+
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode, tolerateWatchdogClose) {
|
|
3700
|
+
try {
|
|
3701
|
+
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
3702
|
+
if (message.kind === "parse_error") {
|
|
3703
|
+
await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3704
|
+
continue;
|
|
3705
|
+
}
|
|
3706
|
+
const key = responseModeKey(message.payload);
|
|
3707
|
+
const pendingResponse = key === null ? undefined : pendingResponses.get(key);
|
|
3708
|
+
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
3709
|
+
if (key !== null)
|
|
3710
|
+
pendingResponses.delete(key);
|
|
3711
|
+
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3409
3712
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
if (key !== null)
|
|
3414
|
-
pendingResponses.delete(key);
|
|
3415
|
-
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3713
|
+
} catch (error) {
|
|
3714
|
+
if (!(tolerateWatchdogClose() && isWatchdogTeardownError(error)))
|
|
3715
|
+
throw error;
|
|
3416
3716
|
}
|
|
3417
3717
|
}
|
|
3418
3718
|
function responseModeKey(payload) {
|
|
@@ -3544,7 +3844,8 @@ async function runUnavailableCodegraphMcpServer(options) {
|
|
|
3544
3844
|
serverVersion: options.serverVersion
|
|
3545
3845
|
},
|
|
3546
3846
|
input: options.input,
|
|
3547
|
-
output: options.output
|
|
3847
|
+
output: options.output,
|
|
3848
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3548
3849
|
});
|
|
3549
3850
|
}
|
|
3550
3851
|
async function handleUnavailableCodegraphMcpRequest(input, options) {
|
|
@@ -3588,7 +3889,7 @@ var CODEGRAPH_DISABLED_HINT = `CodeGraph MCP skipped: disabled by OMO SOT config
|
|
|
3588
3889
|
`;
|
|
3589
3890
|
var CODEGRAPH_EXCLUDED_HINT = `CodeGraph MCP skipped: project excluded by OMO CodeGraph policy.
|
|
3590
3891
|
`;
|
|
3591
|
-
var CODEGRAPH_VERSION2 =
|
|
3892
|
+
var CODEGRAPH_VERSION2 = CODEGRAPH_PINNED_VERSION;
|
|
3592
3893
|
var PROJECT_CWD_ENV_KEYS = ["OMO_CODEGRAPH_PROJECT_CWD", SESSION_START_CWD_ENV, "PWD"];
|
|
3593
3894
|
async function runCodegraphServe(options = {}) {
|
|
3594
3895
|
const env = options.env ?? processEnv3;
|
|
@@ -3636,7 +3937,7 @@ async function runCodegraphServe(options = {}) {
|
|
|
3636
3937
|
return runUnavailableMcp(buildCodegraphNodeSkipHint(nodeSupport), options);
|
|
3637
3938
|
}
|
|
3638
3939
|
const runProcess = options.runProcess ?? runBridgedCodegraphProcess;
|
|
3639
|
-
const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, options.buildEnv);
|
|
3940
|
+
const codegraphEnv = codegraphEnvForConfig2(trustedInstallDir, homeDir, codegraphConfig.daemon === true, options.buildEnv);
|
|
3640
3941
|
const mergedEnv = buildCodegraphChildEnv({ ambientEnv: env, codegraphEnv, runtimeEnv: env });
|
|
3641
3942
|
return runProcess(resolution.command, [...resolution.argsPrefix, "serve", "--mcp"], {
|
|
3642
3943
|
cwd: projectCwd,
|
|
@@ -3644,7 +3945,8 @@ async function runCodegraphServe(options = {}) {
|
|
|
3644
3945
|
input: options.stdin ?? processStdin2,
|
|
3645
3946
|
output: options.stdout ?? processStdout2,
|
|
3646
3947
|
stderr: options.stderr ?? processStderr3,
|
|
3647
|
-
stdio: "pipe"
|
|
3948
|
+
stdio: "pipe",
|
|
3949
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3648
3950
|
});
|
|
3649
3951
|
}
|
|
3650
3952
|
async function runUnavailableMcp(reason, options) {
|
|
@@ -3653,7 +3955,8 @@ async function runUnavailableMcp(reason, options) {
|
|
|
3653
3955
|
input: options.stdin ?? processStdin2,
|
|
3654
3956
|
output: options.stdout ?? processStdout2,
|
|
3655
3957
|
reason,
|
|
3656
|
-
serverVersion: CODEGRAPH_VERSION2
|
|
3958
|
+
serverVersion: CODEGRAPH_VERSION2,
|
|
3959
|
+
parentWatchdog: options.parentWatchdog ?? {}
|
|
3657
3960
|
});
|
|
3658
3961
|
return 0;
|
|
3659
3962
|
}
|
|
@@ -3662,10 +3965,10 @@ async function provisionMissingCodegraph(options) {
|
|
|
3662
3965
|
return null;
|
|
3663
3966
|
if (options.config.auto_provision === false)
|
|
3664
3967
|
return null;
|
|
3665
|
-
const installDir = options.trustedInstallDir ??
|
|
3968
|
+
const installDir = options.trustedInstallDir ?? join15(options.homeDir, ".omo", "codegraph");
|
|
3666
3969
|
const result = await options.ensureProvisioned({
|
|
3667
3970
|
installDir,
|
|
3668
|
-
lockDir:
|
|
3971
|
+
lockDir: join15(installDir, ".locks"),
|
|
3669
3972
|
version: CODEGRAPH_VERSION2
|
|
3670
3973
|
});
|
|
3671
3974
|
if (!result.provisioned || result.binPath === undefined)
|
|
@@ -3682,8 +3985,8 @@ function shouldSkipResolvedCommand(resolution, commandExists) {
|
|
|
3682
3985
|
function looksLikePath2(command) {
|
|
3683
3986
|
return command.includes("/") || command.includes("\\");
|
|
3684
3987
|
}
|
|
3685
|
-
function codegraphEnvForConfig2(trustedInstallDir, homeDir, buildEnv) {
|
|
3686
|
-
const env =
|
|
3988
|
+
function codegraphEnvForConfig2(trustedInstallDir, homeDir, daemon, buildEnv) {
|
|
3989
|
+
const env = buildEnv?.({ daemon, homeDir }) ?? buildCodegraphEnv({ daemon, homeDir });
|
|
3687
3990
|
return trustedInstallDir === undefined ? env : { ...env, CODEGRAPH_INSTALL_DIR: trustedInstallDir };
|
|
3688
3991
|
}
|
|
3689
3992
|
function resolveProjectCwd(env, fallback) {
|
|
@@ -3691,16 +3994,16 @@ function resolveProjectCwd(env, fallback) {
|
|
|
3691
3994
|
const candidate = env[key]?.trim();
|
|
3692
3995
|
if (candidate === undefined || candidate.length === 0)
|
|
3693
3996
|
continue;
|
|
3694
|
-
const resolved =
|
|
3997
|
+
const resolved = resolve7(candidate);
|
|
3695
3998
|
if (existsSync10(resolved))
|
|
3696
3999
|
return resolved;
|
|
3697
4000
|
}
|
|
3698
|
-
return
|
|
4001
|
+
return resolve7(fallback);
|
|
3699
4002
|
}
|
|
3700
4003
|
function provisionedBinFromInstallDir3(installDir) {
|
|
3701
4004
|
if (installDir === undefined)
|
|
3702
4005
|
return null;
|
|
3703
|
-
const candidate =
|
|
4006
|
+
const candidate = join15(installDir, "bin", process.platform === "win32" ? "codegraph.cmd" : "codegraph");
|
|
3704
4007
|
return existsSync10(candidate) ? candidate : null;
|
|
3705
4008
|
}
|
|
3706
4009
|
async function runCodegraphServeCli() {
|
|
@@ -3720,7 +4023,7 @@ function isDirectInvocation(argvPath) {
|
|
|
3720
4023
|
const moduleName = basename4(modulePath);
|
|
3721
4024
|
if (moduleName !== "serve.js" && moduleName !== "serve.ts")
|
|
3722
4025
|
return false;
|
|
3723
|
-
return
|
|
4026
|
+
return realpathSync6(resolve7(argvPath)) === realpathSync6(modulePath);
|
|
3724
4027
|
}
|
|
3725
4028
|
|
|
3726
4029
|
// components/codegraph/src/sweep-cli.ts
|
|
@@ -3767,6 +4070,7 @@ function writeSweepReport(stdout, result) {
|
|
|
3767
4070
|
failed: result.failed,
|
|
3768
4071
|
killed: result.killed.map(formatProcess),
|
|
3769
4072
|
ownedRoots: result.ownedRoots,
|
|
4073
|
+
spared: result.spared.map(formatProcess),
|
|
3770
4074
|
stampFile: result.stampFile
|
|
3771
4075
|
})}
|
|
3772
4076
|
`);
|
|
@@ -3830,7 +4134,7 @@ function isDirectInvocation2(argvPath) {
|
|
|
3830
4134
|
const moduleName = basename5(modulePath);
|
|
3831
4135
|
if (moduleName !== "cli.js" && moduleName !== "cli.ts")
|
|
3832
4136
|
return false;
|
|
3833
|
-
return
|
|
4137
|
+
return realpathSync7(resolve8(argvPath)) === realpathSync7(modulePath);
|
|
3834
4138
|
}
|
|
3835
4139
|
export {
|
|
3836
4140
|
runCodegraphCli
|