oh-my-opencode 4.18.1 → 4.19.0
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/skills/codex-qa/scripts/lsp-e2e.sh +39 -16
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +111 -28
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +4 -4
- package/README.ru.md +2 -2
- package/README.zh-cn.md +2 -2
- package/bin/AGENTS.md +33 -0
- package/dist/agents/atlas/agent.d.ts +6 -5
- package/dist/agents/sisyphus/index.d.ts +5 -0
- package/dist/agents/sisyphus/kimi-k3.d.ts +19 -0
- package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
- package/dist/agents/sisyphus-junior/agent.d.ts +8 -4
- package/dist/agents/sisyphus-junior/index.d.ts +2 -0
- package/dist/agents/sisyphus-junior/kimi-k3.d.ts +12 -0
- package/dist/agents/types.d.ts +2 -2
- package/dist/cli/index.js +690 -139
- package/dist/cli-node/index.js +690 -139
- package/dist/config/index.d.ts +1 -1
- package/dist/config/schema/browser-automation.d.ts +1 -0
- package/dist/config/schema/commands.d.ts +1 -3
- package/dist/config/schema/default-mode.d.ts +1 -1
- package/dist/config/schema/goal.d.ts +7 -0
- package/dist/config/schema/hooks.d.ts +1 -1
- package/dist/config/schema/oh-my-opencode-config.d.ts +6 -10
- package/dist/config/schema/ralph-loop.d.ts +1 -1
- package/dist/config/schema.d.ts +1 -1
- package/dist/create-hooks.d.ts +1 -1
- package/dist/features/builtin-commands/templates/goal.d.ts +1 -0
- package/dist/features/builtin-commands/templates/stop-continuation.d.ts +1 -1
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/hooks/anthropic-context-window-limit-recovery/empty-content-recovery-sdk.d.ts +6 -0
- package/dist/hooks/auto-slash-command/executor.d.ts +1 -0
- package/dist/hooks/category-skill-reminder/hook.d.ts +9 -1
- package/dist/hooks/comment-checker/hook.d.ts +8 -1
- package/dist/hooks/goal/command-arguments.d.ts +13 -0
- package/dist/hooks/goal/controller.d.ts +26 -0
- package/dist/hooks/goal/index.d.ts +23 -0
- package/dist/hooks/goal/prompt.d.ts +3 -0
- package/dist/hooks/goal/store.d.ts +8 -0
- package/dist/hooks/goal/tools.d.ts +10 -0
- package/dist/hooks/goal/types.d.ts +93 -0
- package/dist/hooks/goal/validation.d.ts +4 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/keyword-detector/hook.d.ts +1 -2
- package/dist/hooks/ralph-loop/types.d.ts +1 -1
- package/dist/hooks/todo-continuation-enforcer/types.d.ts +3 -0
- package/dist/index.js +3706 -4329
- package/dist/oh-my-opencode.schema.json +23 -19
- package/dist/plugin/chat-message/loop-commands.d.ts +1 -1
- package/dist/plugin/chat-message/types.d.ts +23 -10
- package/dist/plugin/hooks/create-core-hooks.d.ts +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +3 -2
- package/dist/plugin/hooks/create-transform-hooks.d.ts +0 -2
- package/dist/plugin/messages-transform.d.ts +1 -0
- package/dist/plugin/stop-continuation.d.ts +2 -2
- package/dist/plugin-handlers/prometheus-agent-config-builder.d.ts +2 -0
- package/dist/shared/system-directive.d.ts +0 -1
- package/dist/skills/ulw-plan/SKILL.md +11 -7
- package/dist/skills/ulw-plan/references/full-workflow.md +117 -6
- package/dist/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/dist/skills/ulw-research/SKILL.md +3 -3
- package/dist/tools/delegate-task/types.d.ts +0 -1
- package/dist/tui.js +115 -28
- package/package.json +14 -14
- package/packages/git-bash-mcp/dist/cli.js +81 -19
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +4 -4
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +118 -1
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +1 -1
- package/packages/lsp-daemon/dist/cli.js +262 -63
- package/packages/lsp-daemon/dist/client.js +194 -50
- package/packages/lsp-daemon/dist/daemon-client.d.ts +2 -2
- package/packages/lsp-daemon/dist/daemon-client.js +26 -2
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +5 -4
- package/packages/lsp-daemon/dist/ensure-daemon.js +79 -18
- package/packages/lsp-daemon/dist/index.js +262 -63
- package/packages/lsp-daemon/dist/proxy.d.ts +2 -0
- package/packages/lsp-daemon/dist/proxy.js +79 -23
- package/packages/lsp-tools-mcp/dist/cli.js +82 -20
- package/packages/lsp-tools-mcp/dist/mcp.js +82 -20
- package/packages/lsp-tools-mcp/dist/tools.js +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +352 -17
- 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 +7 -6
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +195 -56
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +100 -28
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +21 -9
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +35 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +69 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +57 -1
- 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/.mcp.json +2 -1
- package/packages/omo-codex/plugin/components/lsp/AGENTS.md +1 -0
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +113 -31
- 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/lsp/test/package-smoke.test.ts +1 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +5 -3
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +8 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/README.md +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/directive.md +3 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +148 -61
- 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/start-work-continuation/src/boulder-reader.ts +4 -72
- package/packages/omo-codex/plugin/components/start-work-continuation/src/codex-hook.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/src/plan-checklist.ts +171 -0
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +213 -24
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +4 -3
- package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +25 -4
- package/packages/omo-codex/plugin/components/start-work-continuation/test/fixtures/plan-scaffold.md +15 -0
- 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.md +10 -10
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +3 -3
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +50 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +5 -6
- 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 +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +5 -6
- package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +2 -2
- 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 +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +32 -28
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +17 -45
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +455 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +13 -20
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +7 -0
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +3 -2
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +50 -33
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +11 -7
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/omo-codex/plugin/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +62 -0
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +271 -14
- package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +38 -22
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +0 -5
- package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +293 -0
- package/packages/omo-codex/scripts/install-config.test.mjs +10 -10
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +353 -18
- package/packages/omo-codex/scripts/install-generated-bundle.test.mjs +39 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +11 -7
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +117 -6
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +46 -10
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/dist/features/builtin-commands/templates/ralph-loop.d.ts +0 -3
- package/dist/skills/ultraresearch/SKILL.md +0 -10
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +0 -273
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -12
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -107
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +0 -128
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +0 -268
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +0 -11
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +0 -10
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-contribute-bug-fix/scripts/create-pr-body.mjs +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-doctor/agents/openai.yaml +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/SKILL.md +0 -0
- /package/{dist → packages/omo-codex/plugin/components/lcx}/skills/lcx-report-bug/agents/openai.yaml +0 -0
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// components/codegraph/src/cli.ts
|
|
4
4
|
import { realpathSync as realpathSync6 } from "node:fs";
|
|
5
|
-
import { basename as basename5, resolve as
|
|
5
|
+
import { basename as basename5, resolve as resolve7 } from "node:path";
|
|
6
6
|
import { stderr as processStderr4 } from "node:process";
|
|
7
7
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
8
8
|
|
|
@@ -98,8 +98,9 @@ function buildCodegraphChildEnv(options = {}) {
|
|
|
98
98
|
import { homedir as homedir5 } from "node:os";
|
|
99
99
|
|
|
100
100
|
// ../../utils/src/codegraph/workspace.ts
|
|
101
|
+
import { execFileSync } from "node:child_process";
|
|
101
102
|
import { appendFileSync, existsSync as existsSync2, lstatSync as lstatSync2, mkdirSync, realpathSync as realpathSync3, readFileSync as readFileSync2, statSync, symlinkSync } from "node:fs";
|
|
102
|
-
import { join as join5 } from "node:path";
|
|
103
|
+
import { dirname, join as join5, resolve as resolve3 } from "node:path";
|
|
103
104
|
|
|
104
105
|
// ../../utils/src/codegraph/paths.ts
|
|
105
106
|
import { createHash } from "node:crypto";
|
|
@@ -305,12 +306,52 @@ function prepareCodegraphWorkspace(workspace, options = {}) {
|
|
|
305
306
|
}
|
|
306
307
|
}
|
|
307
308
|
function ensureCodegraphGitignored(workspace) {
|
|
308
|
-
const
|
|
309
|
-
if (!existsSync2(
|
|
309
|
+
const gitMarkerPath = join5(workspace, ".git");
|
|
310
|
+
if (!existsSync2(gitMarkerPath))
|
|
310
311
|
return false;
|
|
311
|
-
const excludePath = join5(gitDir, "info", "exclude");
|
|
312
312
|
try {
|
|
313
|
-
|
|
313
|
+
const isWorktree = execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
314
|
+
cwd: workspace,
|
|
315
|
+
encoding: "utf8",
|
|
316
|
+
shell: false,
|
|
317
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
318
|
+
timeout: 5000,
|
|
319
|
+
windowsHide: true
|
|
320
|
+
}).trim();
|
|
321
|
+
if (isWorktree !== "true")
|
|
322
|
+
return false;
|
|
323
|
+
const gitTopLevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
|
|
324
|
+
cwd: workspace,
|
|
325
|
+
encoding: "utf8",
|
|
326
|
+
shell: false,
|
|
327
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
328
|
+
timeout: 5000,
|
|
329
|
+
windowsHide: true
|
|
330
|
+
}).trim();
|
|
331
|
+
if (gitTopLevel.length === 0 || realpathSync3.native(gitTopLevel) !== realpathSync3.native(workspace))
|
|
332
|
+
return false;
|
|
333
|
+
const gitDir = execFileSync("git", ["rev-parse", "--absolute-git-dir"], {
|
|
334
|
+
cwd: workspace,
|
|
335
|
+
encoding: "utf8",
|
|
336
|
+
shell: false,
|
|
337
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
338
|
+
timeout: 5000,
|
|
339
|
+
windowsHide: true
|
|
340
|
+
}).trim();
|
|
341
|
+
if (gitDir.length === 0 || !gitMarkerOwnsGitDir(gitMarkerPath, workspace, gitDir))
|
|
342
|
+
return false;
|
|
343
|
+
const gitExcludePath = execFileSync("git", ["rev-parse", "--git-path", "info/exclude"], {
|
|
344
|
+
cwd: workspace,
|
|
345
|
+
encoding: "utf8",
|
|
346
|
+
shell: false,
|
|
347
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
348
|
+
timeout: 5000,
|
|
349
|
+
windowsHide: true
|
|
350
|
+
}).trim();
|
|
351
|
+
if (gitExcludePath.length === 0)
|
|
352
|
+
return false;
|
|
353
|
+
const excludePath = resolve3(workspace, gitExcludePath);
|
|
354
|
+
mkdirSync(dirname(excludePath), { recursive: true });
|
|
314
355
|
const existing = existsSync2(excludePath) ? readFileSync2(excludePath, "utf8") : "";
|
|
315
356
|
if (existing.split(/\r?\n/).includes(".codegraph"))
|
|
316
357
|
return true;
|
|
@@ -319,12 +360,38 @@ function ensureCodegraphGitignored(workspace) {
|
|
|
319
360
|
`}.codegraph
|
|
320
361
|
`);
|
|
321
362
|
return true;
|
|
322
|
-
} catch
|
|
323
|
-
|
|
324
|
-
return false;
|
|
325
|
-
throw error;
|
|
363
|
+
} catch {
|
|
364
|
+
return false;
|
|
326
365
|
}
|
|
327
366
|
}
|
|
367
|
+
function gitMarkerOwnsGitDir(gitMarkerPath, workspace, gitDir) {
|
|
368
|
+
const markerStat = lstatSync2(gitMarkerPath);
|
|
369
|
+
if (markerStat.isSymbolicLink())
|
|
370
|
+
return false;
|
|
371
|
+
const resolvedGitDir = realpathSync3.native(gitDir);
|
|
372
|
+
if (markerStat.isDirectory())
|
|
373
|
+
return realpathSync3.native(gitMarkerPath) === resolvedGitDir;
|
|
374
|
+
if (!markerStat.isFile())
|
|
375
|
+
return false;
|
|
376
|
+
const markerMatch = /^gitdir:\s*(.+)\s*$/i.exec(readFileSync2(gitMarkerPath, "utf8").trim());
|
|
377
|
+
if (markerMatch?.[1] === undefined)
|
|
378
|
+
return false;
|
|
379
|
+
if (realpathSync3.native(resolve3(workspace, markerMatch[1])) !== resolvedGitDir)
|
|
380
|
+
return false;
|
|
381
|
+
const backlinkPath = join5(resolvedGitDir, "gitdir");
|
|
382
|
+
if (existsSync2(backlinkPath)) {
|
|
383
|
+
const backlink = readFileSync2(backlinkPath, "utf8").trim();
|
|
384
|
+
return backlink.length > 0 && realpathSync3.native(resolve3(resolvedGitDir, backlink)) === realpathSync3.native(gitMarkerPath);
|
|
385
|
+
}
|
|
386
|
+
const coreWorktree = execFileSync("git", ["config", "--file", join5(resolvedGitDir, "config"), "--get", "core.worktree"], {
|
|
387
|
+
encoding: "utf8",
|
|
388
|
+
shell: false,
|
|
389
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
390
|
+
timeout: 5000,
|
|
391
|
+
windowsHide: true
|
|
392
|
+
}).trim();
|
|
393
|
+
return coreWorktree.length > 0 && realpathSync3.native(resolve3(resolvedGitDir, coreWorktree)) === realpathSync3.native(workspace);
|
|
394
|
+
}
|
|
328
395
|
|
|
329
396
|
// ../../utils/src/codegraph/guidance.ts
|
|
330
397
|
var CODEGRAPH_UNINITIALIZED_PATTERN = /CodeGraph not initialized in ([\s\S]*?)\.\s*Run ['`]codegraph init['`] in that project first\./i;
|
|
@@ -416,7 +483,7 @@ function isRecord(value) {
|
|
|
416
483
|
import { existsSync as existsSync3 } from "node:fs";
|
|
417
484
|
import { homedir as homedir6 } from "node:os";
|
|
418
485
|
import { spawnSync } from "node:child_process";
|
|
419
|
-
import { basename as basename2, dirname, join as join7 } from "node:path";
|
|
486
|
+
import { basename as basename2, dirname as dirname2, join as join7 } from "node:path";
|
|
420
487
|
import { createRequire } from "node:module";
|
|
421
488
|
|
|
422
489
|
// ../../utils/src/runtime/which.ts
|
|
@@ -603,7 +670,7 @@ function defaultProvisionedBin(homeDir, fileExists) {
|
|
|
603
670
|
function resolveBundledShim(requireResolve, fileExists) {
|
|
604
671
|
try {
|
|
605
672
|
const packageJson = requireResolve(`${CODEGRAPH_PACKAGE}/package.json`);
|
|
606
|
-
const packageRoot =
|
|
673
|
+
const packageRoot = dirname2(packageJson);
|
|
607
674
|
const candidates = [join7(packageRoot, "bin", "codegraph.js"), join7(packageRoot, "npm-shim.js")];
|
|
608
675
|
return candidates.find((candidate) => fileExists(candidate)) ?? null;
|
|
609
676
|
} catch (error) {
|
|
@@ -1819,14 +1886,14 @@ function buildEnvOverrides(harness, env, warnings, merge) {
|
|
|
1819
1886
|
|
|
1820
1887
|
// ../../utils/src/omo-config/resolve.ts
|
|
1821
1888
|
import { existsSync as existsSync4 } from "node:fs";
|
|
1822
|
-
import { dirname as
|
|
1889
|
+
import { dirname as dirname3, isAbsolute as isAbsolute2, join as join8, relative, resolve as resolve4 } from "node:path";
|
|
1823
1890
|
function containsPath(parent, child) {
|
|
1824
1891
|
const pathToChild = relative(parent, child);
|
|
1825
1892
|
return pathToChild === "" || !pathToChild.startsWith("..") && !isAbsolute2(pathToChild);
|
|
1826
1893
|
}
|
|
1827
1894
|
function findProjectConfigPathsNearestFirst(cwd, homeDir) {
|
|
1828
|
-
const startDir =
|
|
1829
|
-
const stopBeforeDir = containsPath(
|
|
1895
|
+
const startDir = resolve4(cwd);
|
|
1896
|
+
const stopBeforeDir = containsPath(resolve4(homeDir), startDir) ? resolve4(homeDir) : null;
|
|
1830
1897
|
const paths = [];
|
|
1831
1898
|
let currentDir = startDir;
|
|
1832
1899
|
while (true) {
|
|
@@ -1836,7 +1903,7 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
|
|
|
1836
1903
|
if (existsSync4(configPath)) {
|
|
1837
1904
|
paths.push(configPath);
|
|
1838
1905
|
}
|
|
1839
|
-
const parentDir =
|
|
1906
|
+
const parentDir = dirname3(currentDir);
|
|
1840
1907
|
if (parentDir === currentDir)
|
|
1841
1908
|
break;
|
|
1842
1909
|
currentDir = parentDir;
|
|
@@ -1844,7 +1911,7 @@ function findProjectConfigPathsNearestFirst(cwd, homeDir) {
|
|
|
1844
1911
|
return paths;
|
|
1845
1912
|
}
|
|
1846
1913
|
function resolveOmoConfigPaths(options) {
|
|
1847
|
-
const globalPath = join8(
|
|
1914
|
+
const globalPath = join8(resolve4(options.homeDir), ".omo", "config.jsonc");
|
|
1848
1915
|
const projectPathsFarthestFirst = findProjectConfigPathsNearestFirst(options.cwd, options.homeDir).reverse();
|
|
1849
1916
|
return [
|
|
1850
1917
|
{ path: globalPath, scope: "global" },
|
|
@@ -1943,7 +2010,7 @@ import { fileURLToPath } from "node:url";
|
|
|
1943
2010
|
// ../../utils/src/codegraph/process-sweeper.ts
|
|
1944
2011
|
import { existsSync as existsSync7, mkdirSync as mkdirSync2, statSync as statSync2, utimesSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1945
2012
|
import { homedir as homedir10 } from "node:os";
|
|
1946
|
-
import { dirname as
|
|
2013
|
+
import { dirname as dirname4, join as join10 } from "node:path";
|
|
1947
2014
|
|
|
1948
2015
|
// ../../utils/src/codegraph/process-exec.ts
|
|
1949
2016
|
import { execFile } from "node:child_process";
|
|
@@ -2188,7 +2255,7 @@ function processKillErrorMeansAlive(error) {
|
|
|
2188
2255
|
// ../../utils/src/codegraph/process-roots.ts
|
|
2189
2256
|
import { existsSync as existsSync6, readdirSync as readdirSync2, realpathSync as realpathSync4 } from "node:fs";
|
|
2190
2257
|
import { homedir as homedir9 } from "node:os";
|
|
2191
|
-
import { join as join9, resolve as
|
|
2258
|
+
import { join as join9, resolve as resolve5 } from "node:path";
|
|
2192
2259
|
function discoverCodegraphOwnedRoots(options = {}) {
|
|
2193
2260
|
const env = options.env ?? process.env;
|
|
2194
2261
|
const homeDir = options.homeDir ?? env["HOME"] ?? env["USERPROFILE"] ?? homedir9();
|
|
@@ -2222,7 +2289,7 @@ function readCodexPluginCacheRoots(codexHome) {
|
|
|
2222
2289
|
function addRoot(roots, root) {
|
|
2223
2290
|
if (root === undefined || root.trim().length === 0)
|
|
2224
2291
|
return;
|
|
2225
|
-
const resolved =
|
|
2292
|
+
const resolved = resolve5(root);
|
|
2226
2293
|
roots.add(resolved);
|
|
2227
2294
|
roots.add(realpathIfPossible2(resolved));
|
|
2228
2295
|
}
|
|
@@ -2240,7 +2307,7 @@ function realpathIfPossible2(path) {
|
|
|
2240
2307
|
return realpathSync4(path);
|
|
2241
2308
|
} catch (error) {
|
|
2242
2309
|
if (error instanceof Error)
|
|
2243
|
-
return
|
|
2310
|
+
return resolve5(path);
|
|
2244
2311
|
throw error;
|
|
2245
2312
|
}
|
|
2246
2313
|
}
|
|
@@ -2325,7 +2392,7 @@ function isSweepThrottled(stampFile, nowMs, throttleMs) {
|
|
|
2325
2392
|
return nowMs - statSync2(stampFile).mtimeMs < throttleMs;
|
|
2326
2393
|
}
|
|
2327
2394
|
function writeSweepStamp(stampFile, nowMs) {
|
|
2328
|
-
mkdirSync2(
|
|
2395
|
+
mkdirSync2(dirname4(stampFile), { recursive: true });
|
|
2329
2396
|
writeFileSync2(stampFile, `${new Date(nowMs).toISOString()}
|
|
2330
2397
|
`);
|
|
2331
2398
|
const stampDate = new Date(nowMs);
|
|
@@ -2442,7 +2509,7 @@ async function removeEmptyDirectory(path) {
|
|
|
2442
2509
|
}
|
|
2443
2510
|
}
|
|
2444
2511
|
function sleep(ms) {
|
|
2445
|
-
return new Promise((
|
|
2512
|
+
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
2446
2513
|
}
|
|
2447
2514
|
async function defaultDownloader(asset, timeoutMs = DEFAULT_DOWNLOAD_TIMEOUT_MS) {
|
|
2448
2515
|
const response = await fetch(asset.url, { signal: AbortSignal.timeout(timeoutMs) });
|
|
@@ -2962,7 +3029,7 @@ function defaultWorkerCliPath() {
|
|
|
2962
3029
|
// components/codegraph/src/serve.ts
|
|
2963
3030
|
import { existsSync as existsSync10, realpathSync as realpathSync5 } from "node:fs";
|
|
2964
3031
|
import { homedir as homedir14 } from "node:os";
|
|
2965
|
-
import { basename as basename4, join as join14, resolve as
|
|
3032
|
+
import { basename as basename4, join as join14, resolve as resolve6 } from "node:path";
|
|
2966
3033
|
import {
|
|
2967
3034
|
cwd as processCwd3,
|
|
2968
3035
|
env as processEnv3,
|
|
@@ -2989,6 +3056,9 @@ function errorResponse(id, code, message, data) {
|
|
|
2989
3056
|
function jsonRpcId(value) {
|
|
2990
3057
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
2991
3058
|
}
|
|
3059
|
+
function messageFromError(error) {
|
|
3060
|
+
return error instanceof Error ? error.message : String(error);
|
|
3061
|
+
}
|
|
2992
3062
|
// ../../mcp-stdio-core/src/transport.ts
|
|
2993
3063
|
var HEADER_SEPARATOR = Buffer.from(`\r
|
|
2994
3064
|
\r
|
|
@@ -3011,16 +3081,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
3011
3081
|
yield parseJsonPayload(trailing, "line");
|
|
3012
3082
|
}
|
|
3013
3083
|
}
|
|
3014
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3084
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
3015
3085
|
const body = JSON.stringify(response);
|
|
3016
|
-
|
|
3017
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3086
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
3018
3087
|
\r
|
|
3019
|
-
${body}`
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3088
|
+
${body}` : `${body}
|
|
3089
|
+
`;
|
|
3090
|
+
await writeChunk(output, payload);
|
|
3091
|
+
}
|
|
3092
|
+
function writeChunk(output, chunk) {
|
|
3093
|
+
return new Promise((resolve6, reject) => {
|
|
3094
|
+
let settled = false;
|
|
3095
|
+
const onError = (error) => {
|
|
3096
|
+
if (settled)
|
|
3097
|
+
return;
|
|
3098
|
+
settled = true;
|
|
3099
|
+
reject(error);
|
|
3100
|
+
};
|
|
3101
|
+
output.once("error", onError);
|
|
3102
|
+
try {
|
|
3103
|
+
output.write(chunk, (error) => {
|
|
3104
|
+
if (settled)
|
|
3105
|
+
return;
|
|
3106
|
+
settled = true;
|
|
3107
|
+
if (error) {
|
|
3108
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
3109
|
+
reject(error);
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3112
|
+
output.removeListener("error", onError);
|
|
3113
|
+
resolve6();
|
|
3114
|
+
});
|
|
3115
|
+
} catch (error) {
|
|
3116
|
+
output.removeListener("error", onError);
|
|
3117
|
+
if (settled)
|
|
3118
|
+
return;
|
|
3119
|
+
settled = true;
|
|
3120
|
+
reject(error);
|
|
3121
|
+
}
|
|
3122
|
+
});
|
|
3024
3123
|
}
|
|
3025
3124
|
function readNextMessage(buffer) {
|
|
3026
3125
|
if (buffer.length === 0)
|
|
@@ -3116,40 +3215,70 @@ async function runJsonRpcStdioServer(config) {
|
|
|
3116
3215
|
break;
|
|
3117
3216
|
idleTimer.arm();
|
|
3118
3217
|
if (message.kind === "parse_error") {
|
|
3119
|
-
handleParseError(message, config, log)
|
|
3218
|
+
if (!await handleParseError(message, config, log))
|
|
3219
|
+
break;
|
|
3120
3220
|
continue;
|
|
3121
3221
|
}
|
|
3122
|
-
await handleRequest(message, config, log)
|
|
3222
|
+
if (!await handleRequest(message, config, log))
|
|
3223
|
+
break;
|
|
3123
3224
|
}
|
|
3124
3225
|
} finally {
|
|
3125
3226
|
idleTimer.clear();
|
|
3126
3227
|
log("stdio_stopped");
|
|
3127
3228
|
}
|
|
3128
3229
|
}
|
|
3129
|
-
function handleParseError(message, config, log) {
|
|
3230
|
+
async function handleParseError(message, config, log) {
|
|
3130
3231
|
log("parse_error", { message: message.message });
|
|
3131
3232
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
3132
|
-
if (response
|
|
3133
|
-
|
|
3134
|
-
|
|
3233
|
+
if (response === undefined)
|
|
3234
|
+
return true;
|
|
3235
|
+
return writeResponse(response, {
|
|
3236
|
+
output: config.output,
|
|
3237
|
+
responseMode: message.responseMode,
|
|
3238
|
+
log
|
|
3239
|
+
});
|
|
3135
3240
|
}
|
|
3136
3241
|
async function handleRequest(message, config, log) {
|
|
3137
3242
|
const parsed = message.payload;
|
|
3138
3243
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
3139
3244
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
3140
3245
|
log("request", { id: id === null ? null : String(id), method });
|
|
3246
|
+
let response;
|
|
3141
3247
|
try {
|
|
3142
|
-
|
|
3143
|
-
if (response === undefined)
|
|
3144
|
-
return;
|
|
3145
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
3146
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3248
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
3147
3249
|
} catch (error) {
|
|
3148
3250
|
if (config.onHandlerError === undefined)
|
|
3149
3251
|
throw error;
|
|
3150
3252
|
config.onHandlerError(error);
|
|
3253
|
+
return true;
|
|
3254
|
+
}
|
|
3255
|
+
if (response === undefined)
|
|
3256
|
+
return true;
|
|
3257
|
+
if (!await writeResponse(response, {
|
|
3258
|
+
output: config.output,
|
|
3259
|
+
responseMode: message.responseMode,
|
|
3260
|
+
log
|
|
3261
|
+
}))
|
|
3262
|
+
return false;
|
|
3263
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
3264
|
+
return true;
|
|
3265
|
+
}
|
|
3266
|
+
async function writeResponse(response, context) {
|
|
3267
|
+
try {
|
|
3268
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
3269
|
+
return true;
|
|
3270
|
+
} catch (error) {
|
|
3271
|
+
if (!isTerminalOutputError(error))
|
|
3272
|
+
throw error;
|
|
3273
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
3274
|
+
return false;
|
|
3151
3275
|
}
|
|
3152
3276
|
}
|
|
3277
|
+
function isTerminalOutputError(error) {
|
|
3278
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
3279
|
+
return false;
|
|
3280
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
3281
|
+
}
|
|
3153
3282
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
3154
3283
|
let timer = null;
|
|
3155
3284
|
let isClosed = false;
|
|
@@ -3230,18 +3359,28 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
3230
3359
|
resolveExit(signal === null ? 0 : 1);
|
|
3231
3360
|
});
|
|
3232
3361
|
});
|
|
3233
|
-
const
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
]);
|
|
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);
|
|
3239
3368
|
const destroyChildPipes = () => {
|
|
3240
3369
|
childInput.destroy();
|
|
3241
3370
|
childOutput.destroy();
|
|
3242
3371
|
};
|
|
3243
3372
|
childExit.then(destroyChildPipes, destroyChildPipes);
|
|
3244
|
-
|
|
3373
|
+
try {
|
|
3374
|
+
return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
|
|
3375
|
+
} catch (error) {
|
|
3376
|
+
destroyChildPipes();
|
|
3377
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
3378
|
+
child.kill("SIGKILL");
|
|
3379
|
+
await childExit.catch(() => {
|
|
3380
|
+
return;
|
|
3381
|
+
});
|
|
3382
|
+
throw error;
|
|
3383
|
+
}
|
|
3245
3384
|
}
|
|
3246
3385
|
async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode) {
|
|
3247
3386
|
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
@@ -3265,7 +3404,7 @@ async function forwardClientToCodegraph(input, childInput, pendingResponses, set
|
|
|
3265
3404
|
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
|
|
3266
3405
|
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
3267
3406
|
if (message.kind === "parse_error") {
|
|
3268
|
-
writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3407
|
+
await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
3269
3408
|
continue;
|
|
3270
3409
|
}
|
|
3271
3410
|
const key = responseModeKey(message.payload);
|
|
@@ -3273,7 +3412,7 @@ async function forwardCodegraphToClient(childOutput, output, pendingResponses, d
|
|
|
3273
3412
|
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
3274
3413
|
if (key !== null)
|
|
3275
3414
|
pendingResponses.delete(key);
|
|
3276
|
-
writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3415
|
+
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
3277
3416
|
}
|
|
3278
3417
|
}
|
|
3279
3418
|
function responseModeKey(payload) {
|
|
@@ -3552,11 +3691,11 @@ function resolveProjectCwd(env, fallback) {
|
|
|
3552
3691
|
const candidate = env[key]?.trim();
|
|
3553
3692
|
if (candidate === undefined || candidate.length === 0)
|
|
3554
3693
|
continue;
|
|
3555
|
-
const resolved =
|
|
3694
|
+
const resolved = resolve6(candidate);
|
|
3556
3695
|
if (existsSync10(resolved))
|
|
3557
3696
|
return resolved;
|
|
3558
3697
|
}
|
|
3559
|
-
return
|
|
3698
|
+
return resolve6(fallback);
|
|
3560
3699
|
}
|
|
3561
3700
|
function provisionedBinFromInstallDir3(installDir) {
|
|
3562
3701
|
if (installDir === undefined)
|
|
@@ -3581,7 +3720,7 @@ function isDirectInvocation(argvPath) {
|
|
|
3581
3720
|
const moduleName = basename4(modulePath);
|
|
3582
3721
|
if (moduleName !== "serve.js" && moduleName !== "serve.ts")
|
|
3583
3722
|
return false;
|
|
3584
|
-
return realpathSync5(
|
|
3723
|
+
return realpathSync5(resolve6(argvPath)) === realpathSync5(modulePath);
|
|
3585
3724
|
}
|
|
3586
3725
|
|
|
3587
3726
|
// components/codegraph/src/sweep-cli.ts
|
|
@@ -3691,7 +3830,7 @@ function isDirectInvocation2(argvPath) {
|
|
|
3691
3830
|
const moduleName = basename5(modulePath);
|
|
3692
3831
|
if (moduleName !== "cli.js" && moduleName !== "cli.ts")
|
|
3693
3832
|
return false;
|
|
3694
|
-
return realpathSync6(
|
|
3833
|
+
return realpathSync6(resolve7(argvPath)) === realpathSync6(modulePath);
|
|
3695
3834
|
}
|
|
3696
3835
|
export {
|
|
3697
3836
|
runCodegraphCli
|
|
@@ -1897,6 +1897,9 @@ function errorResponse(id, code, message, data) {
|
|
|
1897
1897
|
function jsonRpcId(value) {
|
|
1898
1898
|
return typeof value === "string" || typeof value === "number" || value === null ? value : null;
|
|
1899
1899
|
}
|
|
1900
|
+
function messageFromError(error) {
|
|
1901
|
+
return error instanceof Error ? error.message : String(error);
|
|
1902
|
+
}
|
|
1900
1903
|
// ../../../../mcp-stdio-core/src/transport.ts
|
|
1901
1904
|
var HEADER_SEPARATOR = Buffer.from(`\r
|
|
1902
1905
|
\r
|
|
@@ -1919,16 +1922,45 @@ async function* readStdioJsonRpcMessages(input) {
|
|
|
1919
1922
|
yield parseJsonPayload(trailing, "line");
|
|
1920
1923
|
}
|
|
1921
1924
|
}
|
|
1922
|
-
function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
1925
|
+
async function writeStdioJsonRpcResponse(output, response, responseMode) {
|
|
1923
1926
|
const body = JSON.stringify(response);
|
|
1924
|
-
|
|
1925
|
-
output.write(`Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
1927
|
+
const payload = responseMode === "framed" ? `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
1926
1928
|
\r
|
|
1927
|
-
${body}`
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1929
|
+
${body}` : `${body}
|
|
1930
|
+
`;
|
|
1931
|
+
await writeChunk(output, payload);
|
|
1932
|
+
}
|
|
1933
|
+
function writeChunk(output, chunk) {
|
|
1934
|
+
return new Promise((resolve3, reject) => {
|
|
1935
|
+
let settled = false;
|
|
1936
|
+
const onError = (error) => {
|
|
1937
|
+
if (settled)
|
|
1938
|
+
return;
|
|
1939
|
+
settled = true;
|
|
1940
|
+
reject(error);
|
|
1941
|
+
};
|
|
1942
|
+
output.once("error", onError);
|
|
1943
|
+
try {
|
|
1944
|
+
output.write(chunk, (error) => {
|
|
1945
|
+
if (settled)
|
|
1946
|
+
return;
|
|
1947
|
+
settled = true;
|
|
1948
|
+
if (error) {
|
|
1949
|
+
queueMicrotask(() => output.removeListener("error", onError));
|
|
1950
|
+
reject(error);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
output.removeListener("error", onError);
|
|
1954
|
+
resolve3();
|
|
1955
|
+
});
|
|
1956
|
+
} catch (error) {
|
|
1957
|
+
output.removeListener("error", onError);
|
|
1958
|
+
if (settled)
|
|
1959
|
+
return;
|
|
1960
|
+
settled = true;
|
|
1961
|
+
reject(error);
|
|
1962
|
+
}
|
|
1963
|
+
});
|
|
1932
1964
|
}
|
|
1933
1965
|
function readNextMessage(buffer) {
|
|
1934
1966
|
if (buffer.length === 0)
|
|
@@ -2024,40 +2056,70 @@ async function runJsonRpcStdioServer(config) {
|
|
|
2024
2056
|
break;
|
|
2025
2057
|
idleTimer.arm();
|
|
2026
2058
|
if (message.kind === "parse_error") {
|
|
2027
|
-
handleParseError(message, config, log)
|
|
2059
|
+
if (!await handleParseError(message, config, log))
|
|
2060
|
+
break;
|
|
2028
2061
|
continue;
|
|
2029
2062
|
}
|
|
2030
|
-
await handleRequest(message, config, log)
|
|
2063
|
+
if (!await handleRequest(message, config, log))
|
|
2064
|
+
break;
|
|
2031
2065
|
}
|
|
2032
2066
|
} finally {
|
|
2033
2067
|
idleTimer.clear();
|
|
2034
2068
|
log("stdio_stopped");
|
|
2035
2069
|
}
|
|
2036
2070
|
}
|
|
2037
|
-
function handleParseError(message, config, log) {
|
|
2071
|
+
async function handleParseError(message, config, log) {
|
|
2038
2072
|
log("parse_error", { message: message.message });
|
|
2039
2073
|
const response = config.parseErrorResponse?.(message.message) ?? errorResponse(null, -32700, "Parse error", message.message);
|
|
2040
|
-
if (response
|
|
2041
|
-
|
|
2042
|
-
|
|
2074
|
+
if (response === undefined)
|
|
2075
|
+
return true;
|
|
2076
|
+
return writeResponse(response, {
|
|
2077
|
+
output: config.output,
|
|
2078
|
+
responseMode: message.responseMode,
|
|
2079
|
+
log
|
|
2080
|
+
});
|
|
2043
2081
|
}
|
|
2044
2082
|
async function handleRequest(message, config, log) {
|
|
2045
2083
|
const parsed = message.payload;
|
|
2046
2084
|
const id = isPlainRecord(parsed) ? jsonRpcId(parsed["id"]) : null;
|
|
2047
2085
|
const method = isPlainRecord(parsed) && typeof parsed["method"] === "string" ? parsed["method"] : null;
|
|
2048
2086
|
log("request", { id: id === null ? null : String(id), method });
|
|
2087
|
+
let response;
|
|
2049
2088
|
try {
|
|
2050
|
-
|
|
2051
|
-
if (response === undefined)
|
|
2052
|
-
return;
|
|
2053
|
-
writeStdioJsonRpcResponse(config.output, response, message.responseMode);
|
|
2054
|
-
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
2089
|
+
response = await config.handler(parsed, config.handlerOptions);
|
|
2055
2090
|
} catch (error) {
|
|
2056
2091
|
if (config.onHandlerError === undefined)
|
|
2057
2092
|
throw error;
|
|
2058
2093
|
config.onHandlerError(error);
|
|
2094
|
+
return true;
|
|
2095
|
+
}
|
|
2096
|
+
if (response === undefined)
|
|
2097
|
+
return true;
|
|
2098
|
+
if (!await writeResponse(response, {
|
|
2099
|
+
output: config.output,
|
|
2100
|
+
responseMode: message.responseMode,
|
|
2101
|
+
log
|
|
2102
|
+
}))
|
|
2103
|
+
return false;
|
|
2104
|
+
log("response", { id: String(response.id), method, is_error: response.error !== undefined });
|
|
2105
|
+
return true;
|
|
2106
|
+
}
|
|
2107
|
+
async function writeResponse(response, context) {
|
|
2108
|
+
try {
|
|
2109
|
+
await writeStdioJsonRpcResponse(context.output, response, context.responseMode);
|
|
2110
|
+
return true;
|
|
2111
|
+
} catch (error) {
|
|
2112
|
+
if (!isTerminalOutputError(error))
|
|
2113
|
+
throw error;
|
|
2114
|
+
context.log("output_error", { message: messageFromError(error) });
|
|
2115
|
+
return false;
|
|
2059
2116
|
}
|
|
2060
2117
|
}
|
|
2118
|
+
function isTerminalOutputError(error) {
|
|
2119
|
+
if (!(error instanceof Error) || !("code" in error))
|
|
2120
|
+
return false;
|
|
2121
|
+
return error.code === "EPIPE" || error.code === "ERR_STREAM_DESTROYED" || error.code === "ERR_STREAM_WRITE_AFTER_END";
|
|
2122
|
+
}
|
|
2061
2123
|
function createIdleTimer(idleTimeoutMs, log, onIdleTimeout) {
|
|
2062
2124
|
let timer = null;
|
|
2063
2125
|
let isClosed = false;
|
|
@@ -2138,18 +2200,28 @@ async function runBridgedCodegraphProcess(command, args, options) {
|
|
|
2138
2200
|
resolveExit(signal === null ? 0 : 1);
|
|
2139
2201
|
});
|
|
2140
2202
|
});
|
|
2141
|
-
const
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
]);
|
|
2203
|
+
const clientForwardingDone = forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
2204
|
+
defaultResponseMode = mode;
|
|
2205
|
+
});
|
|
2206
|
+
const responseForwardingDone = forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode);
|
|
2207
|
+
const bridgeDone = Promise.all([clientForwardingDone, responseForwardingDone]);
|
|
2208
|
+
const childAndResponsesDone = Promise.all([childExit, responseForwardingDone]).then(([exitCode]) => exitCode);
|
|
2147
2209
|
const destroyChildPipes = () => {
|
|
2148
2210
|
childInput.destroy();
|
|
2149
2211
|
childOutput.destroy();
|
|
2150
2212
|
};
|
|
2151
2213
|
childExit.then(destroyChildPipes, destroyChildPipes);
|
|
2152
|
-
|
|
2214
|
+
try {
|
|
2215
|
+
return await Promise.race([childAndResponsesDone, bridgeDone.then(() => childExit)]);
|
|
2216
|
+
} catch (error) {
|
|
2217
|
+
destroyChildPipes();
|
|
2218
|
+
if (child.exitCode === null && child.signalCode === null)
|
|
2219
|
+
child.kill("SIGKILL");
|
|
2220
|
+
await childExit.catch(() => {
|
|
2221
|
+
return;
|
|
2222
|
+
});
|
|
2223
|
+
throw error;
|
|
2224
|
+
}
|
|
2153
2225
|
}
|
|
2154
2226
|
async function forwardClientToCodegraph(input, childInput, pendingResponses, setDefaultResponseMode) {
|
|
2155
2227
|
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
@@ -2173,7 +2245,7 @@ async function forwardClientToCodegraph(input, childInput, pendingResponses, set
|
|
|
2173
2245
|
async function forwardCodegraphToClient(childOutput, output, pendingResponses, defaultResponseMode) {
|
|
2174
2246
|
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
2175
2247
|
if (message.kind === "parse_error") {
|
|
2176
|
-
writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
2248
|
+
await writeStdioJsonRpcResponse(output, errorResponse(null, -32700, "Parse error", message.message), defaultResponseMode());
|
|
2177
2249
|
continue;
|
|
2178
2250
|
}
|
|
2179
2251
|
const key = responseModeKey(message.payload);
|
|
@@ -2181,7 +2253,7 @@ async function forwardCodegraphToClient(childOutput, output, pendingResponses, d
|
|
|
2181
2253
|
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
2182
2254
|
if (key !== null)
|
|
2183
2255
|
pendingResponses.delete(key);
|
|
2184
|
-
writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
2256
|
+
await writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
2185
2257
|
}
|
|
2186
2258
|
}
|
|
2187
2259
|
function responseModeKey(payload) {
|