oh-my-opencode 5.0.0-beta.10 → 5.0.0-beta.12

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.
Files changed (73) hide show
  1. package/dist/cli/index.js +34 -86
  2. package/dist/cli-node/index.js +34 -86
  3. package/dist/index.js +80 -93
  4. package/dist/tools/delegate-task/builtin-categories.d.ts +1 -0
  5. package/dist/tools/delegate-task/builtin-category-definition.d.ts +1 -0
  6. package/dist/tools/delegate-task/tool-description.d.ts +3 -1
  7. package/dist/tui.js +19 -71
  8. package/package.json +14 -14
  9. package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
  10. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +6 -6
  11. package/packages/lsp-core/src/lsp/client-wrapper.ts +5 -6
  12. package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
  13. package/packages/lsp-core/src/lsp/workspace-markers.ts +1 -0
  14. package/packages/lsp-daemon/dist/cli.js +94 -59
  15. package/packages/lsp-daemon/dist/client.js +72 -37
  16. package/packages/lsp-daemon/dist/index.js +78 -43
  17. package/packages/lsp-tools-mcp/dist/cli.js +68 -33
  18. package/packages/lsp-tools-mcp/dist/mcp.js +68 -33
  19. package/packages/lsp-tools-mcp/dist/tools.js +68 -33
  20. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  21. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  22. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +9 -0
  24. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +9 -0
  25. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  27. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  29. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  30. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  33. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +83 -54
  34. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  35. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  36. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  37. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  38. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  39. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  40. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  41. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  42. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  43. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  44. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  45. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  46. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  47. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  71. package/packages/omo-codex/plugin/package-lock.json +13 -13
  72. package/packages/omo-codex/plugin/package.json +1 -1
  73. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
@@ -1,7 +1,7 @@
1
1
  // src/daemon-client.ts
2
2
  import { connect } from "node:net";
3
3
  import { homedir as homedir3 } from "node:os";
4
- import { join as join7 } from "node:path";
4
+ import { join as join8 } from "node:path";
5
5
 
6
6
  // ../lsp-core/src/request-context.ts
7
7
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -1141,8 +1141,8 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
1141
1141
  };
1142
1142
  }
1143
1143
  // ../lsp-core/src/lsp/client-wrapper.ts
1144
- import { existsSync as existsSync10, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
1145
- import { basename as basename3, dirname as dirname8, join as join4, resolve as resolve7 } from "node:path";
1144
+ import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
1145
+ import { basename as basename3, dirname as dirname9, join as join5, resolve as resolve7 } from "node:path";
1146
1146
 
1147
1147
  // ../lsp-core/src/lsp/effective-extension.ts
1148
1148
  import { basename as basename2, extname } from "node:path";
@@ -4157,15 +4157,52 @@ async function disposeDefaultLspManager() {
4157
4157
  }
4158
4158
  }
4159
4159
 
4160
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
4161
+ import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
4162
+ import { dirname as dirname7, join as join3 } from "node:path";
4163
+
4164
+ // ../lsp-core/src/lsp/workspace-markers.ts
4165
+ var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4166
+
4167
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
4168
+ function findWorkspaceRootOutsideContext(directory) {
4169
+ const marked = nearestMarkedAncestor(directory);
4170
+ if (marked !== undefined)
4171
+ return marked;
4172
+ return realpathSync4(nearestExistingAncestor(directory));
4173
+ }
4174
+ function nearestMarkedAncestor(directory) {
4175
+ let current = directory;
4176
+ for (;; ) {
4177
+ if (existsSync7(current) && WORKSPACE_MARKERS.some((marker) => existsSync7(join3(current, marker)))) {
4178
+ return realpathSync4(current);
4179
+ }
4180
+ const parent = dirname7(current);
4181
+ if (parent === current)
4182
+ return;
4183
+ current = parent;
4184
+ }
4185
+ }
4186
+ function nearestExistingAncestor(directory) {
4187
+ let current = directory;
4188
+ while (!existsSync7(current)) {
4189
+ const parent = dirname7(current);
4190
+ if (parent === current)
4191
+ return current;
4192
+ current = parent;
4193
+ }
4194
+ return current;
4195
+ }
4196
+
4160
4197
  // ../lsp-core/src/lsp/server-install-state.ts
4161
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4162
- import { dirname as dirname7 } from "node:path";
4198
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4199
+ import { dirname as dirname8 } from "node:path";
4163
4200
  function getInstallDecisionsPath() {
4164
4201
  return lspRequestContext().installDecisionsPath;
4165
4202
  }
4166
4203
  function loadInstallDecisions() {
4167
4204
  const path2 = getInstallDecisionsPath();
4168
- if (!existsSync7(path2))
4205
+ if (!existsSync8(path2))
4169
4206
  return {};
4170
4207
  try {
4171
4208
  const parsed = JSON.parse(readFileSync4(path2, "utf8"));
@@ -4187,7 +4224,7 @@ function isInstallDecision(value) {
4187
4224
  }
4188
4225
  function writeInstallDecisions(decisions) {
4189
4226
  const path2 = getInstallDecisionsPath();
4190
- mkdirSync3(dirname7(path2), { recursive: true });
4227
+ mkdirSync3(dirname8(path2), { recursive: true });
4191
4228
  const tmpPath = `${path2}.tmp`;
4192
4229
  writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
4193
4230
  `, "utf8");
@@ -4206,7 +4243,7 @@ function isRecord5(value) {
4206
4243
  }
4207
4244
 
4208
4245
  // ../lsp-core/src/lsp/config-loader.ts
4209
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
4246
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
4210
4247
 
4211
4248
  // ../lsp-core/src/lsp/server-definitions.ts
4212
4249
  var LSP_INSTALL_HINTS = {
@@ -4363,7 +4400,7 @@ function getUserConfigPath() {
4363
4400
  return lspRequestContext().userConfigPath;
4364
4401
  }
4365
4402
  function loadJsonFile(path2) {
4366
- if (!existsSync8(path2))
4403
+ if (!existsSync9(path2))
4367
4404
  return null;
4368
4405
  try {
4369
4406
  const parsed = JSON.parse(readFileSync5(path2, "utf-8"));
@@ -4551,8 +4588,8 @@ function getDisabledServerIds() {
4551
4588
  }
4552
4589
 
4553
4590
  // ../lsp-core/src/lsp/server-installation.ts
4554
- import { existsSync as existsSync9 } from "node:fs";
4555
- import { delimiter as delimiter3, join as join3 } from "node:path";
4591
+ import { existsSync as existsSync10 } from "node:fs";
4592
+ import { delimiter as delimiter3, join as join4 } from "node:path";
4556
4593
  function isServerInstalled(command, _workingDirectory) {
4557
4594
  if (command.length === 0)
4558
4595
  return false;
@@ -4560,7 +4597,7 @@ function isServerInstalled(command, _workingDirectory) {
4560
4597
  if (!cmd)
4561
4598
  return false;
4562
4599
  if (cmd.includes("/") || cmd.includes("\\")) {
4563
- if (existsSync9(cmd))
4600
+ if (existsSync10(cmd))
4564
4601
  return true;
4565
4602
  }
4566
4603
  const isWindows = process.platform === "win32";
@@ -4581,7 +4618,7 @@ function isServerInstalled(command, _workingDirectory) {
4581
4618
  const paths = pathEnv.split(delimiter3);
4582
4619
  for (const p of paths) {
4583
4620
  for (const suffix of exts) {
4584
- if (existsSync9(join3(p, cmd + suffix))) {
4621
+ if (existsSync10(join4(p, cmd + suffix))) {
4585
4622
  return true;
4586
4623
  }
4587
4624
  }
@@ -4677,7 +4714,6 @@ function getAllServers() {
4677
4714
  }
4678
4715
 
4679
4716
  // ../lsp-core/src/lsp/client-wrapper.ts
4680
- var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4681
4717
  function isDirectoryPath(filePath) {
4682
4718
  try {
4683
4719
  return statSync4(filePath).isDirectory();
@@ -4690,21 +4726,23 @@ function findWorkspaceRoot(filePath) {
4690
4726
  const abs = resolveReadablePathInsideContext(filePath);
4691
4727
  let dir = abs;
4692
4728
  if (!isDirectoryPath(dir)) {
4693
- dir = dirname8(dir);
4729
+ dir = dirname9(dir);
4694
4730
  }
4731
+ if (!isPathInside(cwd, abs))
4732
+ return findWorkspaceRootOutsideContext(dir);
4695
4733
  const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
4696
4734
  while (isPathInside(cwd, dir)) {
4697
4735
  const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4698
4736
  if (canonicalDir !== undefined) {
4699
4737
  for (const marker of WORKSPACE_MARKERS) {
4700
- if (existsSync10(join4(dir, marker))) {
4738
+ if (existsSync11(join5(dir, marker))) {
4701
4739
  return canonicalDir;
4702
4740
  }
4703
4741
  }
4704
4742
  }
4705
4743
  if (dir === cwd)
4706
4744
  break;
4707
- dir = dirname8(dir);
4745
+ dir = dirname9(dir);
4708
4746
  }
4709
4747
  return fallbackRoot;
4710
4748
  }
@@ -4716,10 +4754,7 @@ function resolveReadablePathInsideContext(filePath) {
4716
4754
  const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
4717
4755
  if (rebased !== undefined)
4718
4756
  return rebased;
4719
- const canonical = canonicalizeExistingOrNearestAncestor(abs);
4720
- if (isPathInside(cwd, canonical))
4721
- return canonical;
4722
- throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4757
+ return canonicalizeExistingOrNearestAncestor(abs);
4723
4758
  }
4724
4759
  function resolvePathInsideContext(filePath) {
4725
4760
  const cwd = contextCwd();
@@ -4734,12 +4769,12 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
4734
4769
  let current = path2;
4735
4770
  const suffix = [];
4736
4771
  while (true) {
4737
- if (existsSync10(current)) {
4738
- const canonical = realpathSync4(current);
4772
+ if (existsSync11(current)) {
4773
+ const canonical = realpathSync5(current);
4739
4774
  if (isPathInside(cwd, canonical))
4740
- return suffix.length === 0 ? canonical : join4(canonical, ...suffix);
4775
+ return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4741
4776
  }
4742
- const parent = dirname8(current);
4777
+ const parent = dirname9(current);
4743
4778
  if (parent === current)
4744
4779
  return;
4745
4780
  suffix.unshift(basename3(current));
@@ -4747,9 +4782,9 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
4747
4782
  }
4748
4783
  }
4749
4784
  function existingDirectoryInsideContext(directory, cwd) {
4750
- if (!existsSync10(directory))
4785
+ if (!existsSync11(directory))
4751
4786
  return;
4752
- const canonical = realpathSync4(directory);
4787
+ const canonical = realpathSync5(directory);
4753
4788
  if (!statSync4(canonical).isDirectory())
4754
4789
  return;
4755
4790
  return isPathInside(cwd, canonical) ? canonical : undefined;
@@ -4762,7 +4797,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
4762
4797
  return canonical;
4763
4798
  if (current === cwd)
4764
4799
  return;
4765
- current = dirname8(current);
4800
+ current = dirname9(current);
4766
4801
  }
4767
4802
  return;
4768
4803
  }
@@ -4880,8 +4915,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4880
4915
  }
4881
4916
 
4882
4917
  // ../lsp-core/src/lsp/directory-diagnostics.ts
4883
- import { existsSync as existsSync11, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
4884
- import { join as join5, resolve as resolve8 } from "node:path";
4918
+ import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
4919
+ import { join as join6, resolve as resolve8 } from "node:path";
4885
4920
 
4886
4921
  // ../lsp-core/src/lsp/formatters.ts
4887
4922
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -5011,7 +5046,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
5011
5046
  for (const entry of entries) {
5012
5047
  if (files.length >= maxFiles)
5013
5048
  return;
5014
- const fullPath = join5(currentDir, entry);
5049
+ const fullPath = join6(currentDir, entry);
5015
5050
  let stat;
5016
5051
  try {
5017
5052
  stat = lstatSync5(fullPath);
@@ -5037,7 +5072,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
5037
5072
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
5038
5073
  }
5039
5074
  const absDir = resolve8(options.workspaceRoot ?? contextCwd(), directory);
5040
- if (!existsSync11(absDir)) {
5075
+ if (!existsSync12(absDir)) {
5041
5076
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
5042
5077
  }
5043
5078
  const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
@@ -5124,7 +5159,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
5124
5159
 
5125
5160
  // ../lsp-core/src/lsp/infer-extension.ts
5126
5161
  import { lstatSync as lstatSync6, readdirSync as readdirSync4 } from "node:fs";
5127
- import { join as join6 } from "node:path";
5162
+ import { join as join7 } from "node:path";
5128
5163
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
5129
5164
  var MAX_SCAN_ENTRIES = 500;
5130
5165
  function inferExtensionFromDirectory(directory) {
@@ -5142,7 +5177,7 @@ function inferExtensionFromDirectory(directory) {
5142
5177
  for (const entry of entries) {
5143
5178
  if (scanned >= MAX_SCAN_ENTRIES)
5144
5179
  return;
5145
- const fullPath = join6(dir, entry);
5180
+ const fullPath = join7(dir, entry);
5146
5181
  let stat;
5147
5182
  try {
5148
5183
  stat = lstatSync6(fullPath);
@@ -5946,9 +5981,9 @@ function currentRequestContext(env = process.env) {
5946
5981
  const home = env["HOME"] ?? homedir3();
5947
5982
  return parseLspRequestContext({
5948
5983
  cwd,
5949
- projectConfigPaths: [join7(cwd, ".codex", "lsp-client.json")],
5950
- userConfigPath: join7(home, ".codex", "lsp-client.json"),
5951
- installDecisionsPath: join7(home, ".codex", "lsp-install-decisions.json"),
5984
+ projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
5985
+ userConfigPath: join8(home, ".codex", "lsp-client.json"),
5986
+ installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
5952
5987
  capabilities: { installDecisionTool: true }
5953
5988
  });
5954
5989
  }
@@ -3013,7 +3013,7 @@ async function disposeDefaultLspManager() {
3013
3013
  // src/daemon-client.ts
3014
3014
  import { connect } from "node:net";
3015
3015
  import { homedir as homedir3 } from "node:os";
3016
- import { join as join7 } from "node:path";
3016
+ import { join as join8 } from "node:path";
3017
3017
 
3018
3018
  // ../lsp-core/src/request-context.ts
3019
3019
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -4153,18 +4153,55 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
4153
4153
  };
4154
4154
  }
4155
4155
  // ../lsp-core/src/lsp/client-wrapper.ts
4156
- import { existsSync as existsSync10, realpathSync as realpathSync4, statSync as statSync4 } from "node:fs";
4157
- import { basename as basename3, dirname as dirname8, join as join4, resolve as resolve7 } from "node:path";
4156
+ import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
4157
+ import { basename as basename3, dirname as dirname9, join as join5, resolve as resolve7 } from "node:path";
4158
+
4159
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
4160
+ import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
4161
+ import { dirname as dirname7, join as join3 } from "node:path";
4162
+
4163
+ // ../lsp-core/src/lsp/workspace-markers.ts
4164
+ var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4165
+
4166
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
4167
+ function findWorkspaceRootOutsideContext(directory) {
4168
+ const marked = nearestMarkedAncestor(directory);
4169
+ if (marked !== undefined)
4170
+ return marked;
4171
+ return realpathSync4(nearestExistingAncestor(directory));
4172
+ }
4173
+ function nearestMarkedAncestor(directory) {
4174
+ let current = directory;
4175
+ for (;; ) {
4176
+ if (existsSync7(current) && WORKSPACE_MARKERS.some((marker) => existsSync7(join3(current, marker)))) {
4177
+ return realpathSync4(current);
4178
+ }
4179
+ const parent = dirname7(current);
4180
+ if (parent === current)
4181
+ return;
4182
+ current = parent;
4183
+ }
4184
+ }
4185
+ function nearestExistingAncestor(directory) {
4186
+ let current = directory;
4187
+ while (!existsSync7(current)) {
4188
+ const parent = dirname7(current);
4189
+ if (parent === current)
4190
+ return current;
4191
+ current = parent;
4192
+ }
4193
+ return current;
4194
+ }
4158
4195
 
4159
4196
  // ../lsp-core/src/lsp/server-install-state.ts
4160
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4161
- import { dirname as dirname7 } from "node:path";
4197
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4198
+ import { dirname as dirname8 } from "node:path";
4162
4199
  function getInstallDecisionsPath() {
4163
4200
  return lspRequestContext().installDecisionsPath;
4164
4201
  }
4165
4202
  function loadInstallDecisions() {
4166
4203
  const path2 = getInstallDecisionsPath();
4167
- if (!existsSync7(path2))
4204
+ if (!existsSync8(path2))
4168
4205
  return {};
4169
4206
  try {
4170
4207
  const parsed = JSON.parse(readFileSync4(path2, "utf8"));
@@ -4186,7 +4223,7 @@ function isInstallDecision(value) {
4186
4223
  }
4187
4224
  function writeInstallDecisions(decisions) {
4188
4225
  const path2 = getInstallDecisionsPath();
4189
- mkdirSync3(dirname7(path2), { recursive: true });
4226
+ mkdirSync3(dirname8(path2), { recursive: true });
4190
4227
  const tmpPath = `${path2}.tmp`;
4191
4228
  writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
4192
4229
  `, "utf8");
@@ -4205,7 +4242,7 @@ function isRecord5(value) {
4205
4242
  }
4206
4243
 
4207
4244
  // ../lsp-core/src/lsp/config-loader.ts
4208
- import { existsSync as existsSync8, readFileSync as readFileSync5 } from "node:fs";
4245
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
4209
4246
 
4210
4247
  // ../lsp-core/src/lsp/server-definitions.ts
4211
4248
  var LSP_INSTALL_HINTS = {
@@ -4362,7 +4399,7 @@ function getUserConfigPath() {
4362
4399
  return lspRequestContext().userConfigPath;
4363
4400
  }
4364
4401
  function loadJsonFile(path2) {
4365
- if (!existsSync8(path2))
4402
+ if (!existsSync9(path2))
4366
4403
  return null;
4367
4404
  try {
4368
4405
  const parsed = JSON.parse(readFileSync5(path2, "utf-8"));
@@ -4550,8 +4587,8 @@ function getDisabledServerIds() {
4550
4587
  }
4551
4588
 
4552
4589
  // ../lsp-core/src/lsp/server-installation.ts
4553
- import { existsSync as existsSync9 } from "node:fs";
4554
- import { delimiter as delimiter3, join as join3 } from "node:path";
4590
+ import { existsSync as existsSync10 } from "node:fs";
4591
+ import { delimiter as delimiter3, join as join4 } from "node:path";
4555
4592
  function isServerInstalled(command, _workingDirectory) {
4556
4593
  if (command.length === 0)
4557
4594
  return false;
@@ -4559,7 +4596,7 @@ function isServerInstalled(command, _workingDirectory) {
4559
4596
  if (!cmd)
4560
4597
  return false;
4561
4598
  if (cmd.includes("/") || cmd.includes("\\")) {
4562
- if (existsSync9(cmd))
4599
+ if (existsSync10(cmd))
4563
4600
  return true;
4564
4601
  }
4565
4602
  const isWindows = process.platform === "win32";
@@ -4580,7 +4617,7 @@ function isServerInstalled(command, _workingDirectory) {
4580
4617
  const paths = pathEnv.split(delimiter3);
4581
4618
  for (const p of paths) {
4582
4619
  for (const suffix of exts) {
4583
- if (existsSync9(join3(p, cmd + suffix))) {
4620
+ if (existsSync10(join4(p, cmd + suffix))) {
4584
4621
  return true;
4585
4622
  }
4586
4623
  }
@@ -4676,7 +4713,6 @@ function getAllServers() {
4676
4713
  }
4677
4714
 
4678
4715
  // ../lsp-core/src/lsp/client-wrapper.ts
4679
- var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4680
4716
  function isDirectoryPath(filePath) {
4681
4717
  try {
4682
4718
  return statSync4(filePath).isDirectory();
@@ -4689,21 +4725,23 @@ function findWorkspaceRoot(filePath) {
4689
4725
  const abs = resolveReadablePathInsideContext(filePath);
4690
4726
  let dir = abs;
4691
4727
  if (!isDirectoryPath(dir)) {
4692
- dir = dirname8(dir);
4728
+ dir = dirname9(dir);
4693
4729
  }
4730
+ if (!isPathInside(cwd, abs))
4731
+ return findWorkspaceRootOutsideContext(dir);
4694
4732
  const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
4695
4733
  while (isPathInside(cwd, dir)) {
4696
4734
  const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4697
4735
  if (canonicalDir !== undefined) {
4698
4736
  for (const marker of WORKSPACE_MARKERS) {
4699
- if (existsSync10(join4(dir, marker))) {
4737
+ if (existsSync11(join5(dir, marker))) {
4700
4738
  return canonicalDir;
4701
4739
  }
4702
4740
  }
4703
4741
  }
4704
4742
  if (dir === cwd)
4705
4743
  break;
4706
- dir = dirname8(dir);
4744
+ dir = dirname9(dir);
4707
4745
  }
4708
4746
  return fallbackRoot;
4709
4747
  }
@@ -4715,10 +4753,7 @@ function resolveReadablePathInsideContext(filePath) {
4715
4753
  const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
4716
4754
  if (rebased !== undefined)
4717
4755
  return rebased;
4718
- const canonical = canonicalizeExistingOrNearestAncestor(abs);
4719
- if (isPathInside(cwd, canonical))
4720
- return canonical;
4721
- throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4756
+ return canonicalizeExistingOrNearestAncestor(abs);
4722
4757
  }
4723
4758
  function resolvePathInsideContext(filePath) {
4724
4759
  const cwd = contextCwd();
@@ -4733,12 +4768,12 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
4733
4768
  let current = path2;
4734
4769
  const suffix = [];
4735
4770
  while (true) {
4736
- if (existsSync10(current)) {
4737
- const canonical = realpathSync4(current);
4771
+ if (existsSync11(current)) {
4772
+ const canonical = realpathSync5(current);
4738
4773
  if (isPathInside(cwd, canonical))
4739
- return suffix.length === 0 ? canonical : join4(canonical, ...suffix);
4774
+ return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4740
4775
  }
4741
- const parent = dirname8(current);
4776
+ const parent = dirname9(current);
4742
4777
  if (parent === current)
4743
4778
  return;
4744
4779
  suffix.unshift(basename3(current));
@@ -4746,9 +4781,9 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
4746
4781
  }
4747
4782
  }
4748
4783
  function existingDirectoryInsideContext(directory, cwd) {
4749
- if (!existsSync10(directory))
4784
+ if (!existsSync11(directory))
4750
4785
  return;
4751
- const canonical = realpathSync4(directory);
4786
+ const canonical = realpathSync5(directory);
4752
4787
  if (!statSync4(canonical).isDirectory())
4753
4788
  return;
4754
4789
  return isPathInside(cwd, canonical) ? canonical : undefined;
@@ -4761,7 +4796,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
4761
4796
  return canonical;
4762
4797
  if (current === cwd)
4763
4798
  return;
4764
- current = dirname8(current);
4799
+ current = dirname9(current);
4765
4800
  }
4766
4801
  return;
4767
4802
  }
@@ -4879,8 +4914,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4879
4914
  }
4880
4915
 
4881
4916
  // ../lsp-core/src/lsp/directory-diagnostics.ts
4882
- import { existsSync as existsSync11, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
4883
- import { join as join5, resolve as resolve8 } from "node:path";
4917
+ import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
4918
+ import { join as join6, resolve as resolve8 } from "node:path";
4884
4919
 
4885
4920
  // ../lsp-core/src/lsp/formatters.ts
4886
4921
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -5010,7 +5045,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
5010
5045
  for (const entry of entries) {
5011
5046
  if (files.length >= maxFiles)
5012
5047
  return;
5013
- const fullPath = join5(currentDir, entry);
5048
+ const fullPath = join6(currentDir, entry);
5014
5049
  let stat;
5015
5050
  try {
5016
5051
  stat = lstatSync5(fullPath);
@@ -5036,7 +5071,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
5036
5071
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
5037
5072
  }
5038
5073
  const absDir = resolve8(options.workspaceRoot ?? contextCwd(), directory);
5039
- if (!existsSync11(absDir)) {
5074
+ if (!existsSync12(absDir)) {
5040
5075
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
5041
5076
  }
5042
5077
  const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
@@ -5123,7 +5158,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
5123
5158
 
5124
5159
  // ../lsp-core/src/lsp/infer-extension.ts
5125
5160
  import { lstatSync as lstatSync6, readdirSync as readdirSync4 } from "node:fs";
5126
- import { join as join6 } from "node:path";
5161
+ import { join as join7 } from "node:path";
5127
5162
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
5128
5163
  var MAX_SCAN_ENTRIES = 500;
5129
5164
  function inferExtensionFromDirectory(directory) {
@@ -5141,7 +5176,7 @@ function inferExtensionFromDirectory(directory) {
5141
5176
  for (const entry of entries) {
5142
5177
  if (scanned >= MAX_SCAN_ENTRIES)
5143
5178
  return;
5144
- const fullPath = join6(dir, entry);
5179
+ const fullPath = join7(dir, entry);
5145
5180
  let stat;
5146
5181
  try {
5147
5182
  stat = lstatSync6(fullPath);
@@ -5945,9 +5980,9 @@ function currentRequestContext(env = process.env) {
5945
5980
  const home = env["HOME"] ?? homedir3();
5946
5981
  return parseLspRequestContext({
5947
5982
  cwd,
5948
- projectConfigPaths: [join7(cwd, ".codex", "lsp-client.json")],
5949
- userConfigPath: join7(home, ".codex", "lsp-client.json"),
5950
- installDecisionsPath: join7(home, ".codex", "lsp-install-decisions.json"),
5983
+ projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
5984
+ userConfigPath: join8(home, ".codex", "lsp-client.json"),
5985
+ installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
5951
5986
  capabilities: { installDecisionTool: true }
5952
5987
  });
5953
5988
  }
@@ -6079,8 +6114,8 @@ function isRetryableTool(name) {
6079
6114
  return name !== "rename" && name !== "lsp_rename";
6080
6115
  }
6081
6116
  // src/proxy.ts
6082
- import { existsSync as existsSync12, realpathSync as realpathSync5 } from "node:fs";
6083
- import { basename as basename4, delimiter as delimiter4, dirname as dirname9, isAbsolute as isAbsolute5 } from "node:path";
6117
+ import { existsSync as existsSync13, realpathSync as realpathSync6 } from "node:fs";
6118
+ import { basename as basename4, delimiter as delimiter4, dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
6084
6119
  var DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
6085
6120
  async function runMcpStdioProxy(options = {}) {
6086
6121
  const input = options.input ?? process.stdin;
@@ -6203,18 +6238,18 @@ function canonicalizePathList(value) {
6203
6238
  return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
6204
6239
  }
6205
6240
  function canonicalizePath(value) {
6206
- if (value === undefined || !isAbsolute5(value) || !existsSync12(value))
6241
+ if (value === undefined || !isAbsolute5(value) || !existsSync13(value))
6207
6242
  return value;
6208
- return realpathSync5(value);
6243
+ return realpathSync6(value);
6209
6244
  }
6210
6245
  function projectRootFromOpenCodeConfigPath(path2) {
6211
6246
  if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
6212
6247
  return;
6213
- const configDir = dirname9(path2);
6248
+ const configDir = dirname10(path2);
6214
6249
  const configDirName = basename4(configDir);
6215
6250
  if (configDirName !== ".opencode" && configDirName !== ".omo")
6216
6251
  return;
6217
- return dirname9(configDir);
6252
+ return dirname10(configDir);
6218
6253
  }
6219
6254
  export {
6220
6255
  validateDaemonVersion,