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

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 (196) hide show
  1. package/.agents/command/publish.md +44 -16
  2. package/.agents/skills/publish/SKILL.md +44 -16
  3. package/.agents/skills/work-with-pr/SKILL.md +37 -23
  4. package/.opencode/command/publish.md +44 -16
  5. package/.opencode/skills/work-with-pr/SKILL.md +37 -23
  6. package/README.md +12 -1
  7. package/dist/agents/atlas/agent.d.ts +0 -1
  8. package/dist/agents/sisyphus/grok-4.d.ts +20 -0
  9. package/dist/agents/sisyphus/index.d.ts +2 -0
  10. package/dist/agents/sisyphus-agent-config.d.ts +6 -0
  11. package/dist/agents/sisyphus-agent-factory.d.ts +1 -1
  12. package/dist/agents/sisyphus-runtime-prompt-reconciler.d.ts +15 -4
  13. package/dist/agents/types.d.ts +2 -2
  14. package/dist/cli/index.js +797 -465
  15. package/dist/cli/run/on-complete-hook.d.ts +2 -0
  16. package/dist/cli-node/index.js +797 -465
  17. package/dist/hooks/atlas/final-wave-approval-gate.test-support.d.ts +50 -0
  18. package/dist/hooks/atlas/system-reminder-templates.d.ts +0 -1
  19. package/dist/index.js +1511 -1140
  20. package/dist/shared/normalize-sdk-response.d.ts +1 -0
  21. package/dist/shared/shell-env.d.ts +1 -1
  22. package/dist/skills/coding-agent-sessions/SKILL.md +3 -2
  23. package/dist/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  24. package/dist/skills/coding-agent-sessions/references/senpi.md +4 -4
  25. package/dist/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  26. package/dist/skills/frontend/SKILL.md +10 -7
  27. package/dist/skills/frontend/references/design/_INDEX.md +1 -0
  28. package/dist/skills/frontend/references/design/stylegallery.md +80 -0
  29. package/dist/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  30. package/dist/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  31. package/dist/skills/ultimate-browsing/engine/templates/package.json +1 -1
  32. package/dist/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
  33. package/dist/skills/ulw-plan/SKILL.md +2 -2
  34. package/dist/skills/ulw-plan/references/full-workflow.md +27 -3
  35. package/dist/skills/ulw-plan/references/intent-clear.md +2 -1
  36. package/dist/skills/ulw-plan/references/intent-unclear.md +3 -3
  37. package/dist/tui.js +176 -14
  38. package/package.json +21 -19
  39. package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +44 -0
  40. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +0 -28
  41. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +60 -7
  42. package/packages/lsp-core/src/lsp/client-wrapper.ts +69 -16
  43. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +20 -1
  44. package/packages/lsp-core/src/tools/diagnostics.ts +3 -3
  45. package/packages/lsp-core/src/tools/navigation.ts +4 -2
  46. package/packages/lsp-core/src/tools/rename.ts +4 -2
  47. package/packages/lsp-core/src/tools/symbols.ts +1 -1
  48. package/packages/lsp-daemon/dist/cli.js +83 -29
  49. package/packages/lsp-daemon/dist/client.js +76 -22
  50. package/packages/lsp-daemon/dist/index.js +81 -27
  51. package/packages/lsp-tools-mcp/dist/cli.js +76 -22
  52. package/packages/lsp-tools-mcp/dist/mcp.js +76 -22
  53. package/packages/lsp-tools-mcp/dist/tools.js +76 -22
  54. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  55. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  56. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  57. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +118 -8
  58. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +118 -8
  59. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  60. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  61. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  63. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  64. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  65. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  66. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +3 -17
  67. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  68. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +83 -29
  69. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  70. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  71. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  72. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  73. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
  74. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +16 -23
  75. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
  76. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
  77. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
  78. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
  79. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
  80. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +37 -69
  81. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
  82. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +1 -15
  83. package/packages/omo-codex/plugin/components/start-work-continuation/AGENTS.md +3 -2
  84. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
  85. package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
  86. package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +0 -3
  87. package/packages/omo-codex/plugin/components/start-work-continuation/test/codex-hook.test.ts +2 -16
  88. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  89. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  90. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +3 -9
  91. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +24 -12
  92. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +24 -12
  93. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  94. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  95. package/packages/omo-codex/plugin/components/ultrawork/directive.md +6 -0
  96. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  97. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  98. package/packages/omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md +6 -0
  99. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +2 -2
  100. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +27 -3
  101. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
  102. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +3 -3
  103. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
  104. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
  105. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +6 -0
  106. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  107. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  108. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +3 -2
  109. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
  110. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +1 -0
  111. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
  112. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +2 -2
  113. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
  114. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +2 -35
  115. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +4 -5
  116. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  121. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  122. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  123. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  124. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  125. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  126. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  127. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  128. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  129. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  130. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  131. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  132. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
  133. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  134. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
  135. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  136. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  137. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  138. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  139. package/packages/omo-codex/plugin/package-lock.json +20 -20
  140. package/packages/omo-codex/plugin/package.json +1 -1
  141. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
  142. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  143. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
  144. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  145. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +10 -7
  146. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  147. package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
  148. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  149. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  150. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  151. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
  152. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +6 -0
  153. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -2
  154. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
  155. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +1 -0
  156. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -2
  157. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +27 -3
  158. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
  159. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +3 -3
  160. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  161. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +4 -24
  162. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  163. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  164. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  165. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  166. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  167. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  168. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +1 -119
  169. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  170. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  171. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  172. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  173. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  174. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +0 -3
  175. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  176. package/packages/omo-codex/scripts/install-dist/install-local.mjs +57 -19
  177. package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +7 -2
  178. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
  179. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  180. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
  181. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  182. package/packages/shared-skills/skills/frontend/SKILL.md +10 -7
  183. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  184. package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
  185. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  186. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +179 -0
  187. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  188. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +11 -11
  189. package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -2
  190. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +27 -3
  191. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
  192. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +3 -3
  193. package/dist/tools/call-omo-agent/background-agent-executor.d.ts +0 -5
  194. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  195. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  196. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
@@ -4,8 +4,9 @@ import { join } from "node:path";
4
4
  import { afterEach, describe, expect, it } from "bun:test";
5
5
 
6
6
  import { createStandaloneMcpRequestContext, runWithRequestContext } from "../request-context.js";
7
- import { findWorkspaceRoot, resolvePathInsideContext } from "./client-wrapper.js";
7
+ import { findWorkspaceRoot, resolveReadablePathInsideContext, withLspClient } from "./client-wrapper.js";
8
8
  import { LspInvalidPathError } from "./errors.js";
9
+ import { LspManager } from "./manager.js";
9
10
 
10
11
  const tempDirectories: string[] = [];
11
12
 
@@ -48,16 +49,68 @@ describe("LSP client path confinement", () => {
48
49
  ).toThrow(LspInvalidPathError);
49
50
  });
50
51
 
51
- it("#given a symlink inside cwd that points outside #when resolving #then rejects the escape", () => {
52
+ it("#given a symlink inside cwd that points outside #when resolving read path #then keeps lexical path and cwd root", () => {
52
53
  const root = tempRoot("lsp-client-wrapper-symlink-root-");
53
54
  const outside = tempRoot("lsp-client-wrapper-symlink-outside-");
55
+ mkdirSync(join(root, ".git"), { recursive: true });
56
+ mkdirSync(join(outside, ".git"), { recursive: true });
54
57
  writeFileSync(join(outside, "file.ts"), "export const outside = true;\n");
55
58
  symlinkSync(outside, join(root, "linked"));
56
59
 
57
- expect(() =>
58
- runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
59
- resolvePathInsideContext("linked/file.ts"),
60
- ),
61
- ).toThrow(LspInvalidPathError);
60
+ const result = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () => ({
61
+ filePath: resolveReadablePathInsideContext("linked/file.ts"),
62
+ workspaceRoot: findWorkspaceRoot("linked/file.ts"),
63
+ }));
64
+
65
+ expect(result.filePath).toBe(join(realpathSync(root), "linked", "file.ts"));
66
+ expect(result.workspaceRoot).toBe(realpathSync(root));
67
+ });
68
+
69
+ it("#given an absolute macOS alias path through an outside symlink #when resolving read path #then preserves the lexical suffix", () => {
70
+ const root = tempRoot("lsp-client-wrapper-alias-root-");
71
+ const outside = tempRoot("lsp-client-wrapper-alias-outside-");
72
+ mkdirSync(join(root, ".git"), { recursive: true });
73
+ writeFileSync(join(outside, "file.ts"), "export const outside = true;\n");
74
+ symlinkSync(outside, join(root, "linked"));
75
+
76
+ const result = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
77
+ resolveReadablePathInsideContext(join(root, "linked", "file.ts")),
78
+ );
79
+
80
+ expect(result).toBe(join(realpathSync(root), "linked", "file.ts"));
81
+ });
82
+
83
+ it("#given missing parent directories without markers #when resolving workspace #then uses an existing directory", () => {
84
+ const root = tempRoot("lsp-client-wrapper-missing-root-");
85
+ const workspace = runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
86
+ findWorkspaceRoot("missing/deep/file.ts"),
87
+ );
88
+
89
+ expect(workspace).toBe(realpathSync(root));
90
+ });
91
+
92
+ it("#given a symlink inside cwd that points outside #when starting rename #then rejects before client acquisition", async () => {
93
+ const root = tempRoot("lsp-client-wrapper-rename-root-");
94
+ const outside = tempRoot("lsp-client-wrapper-rename-outside-");
95
+ writeFileSync(join(outside, "file.ts"), "export const outside = true;\n");
96
+ symlinkSync(outside, join(root, "linked"));
97
+ let clientFactoryCalls = 0;
98
+ const manager = new LspManager({
99
+ clientFactory: () => {
100
+ clientFactoryCalls += 1;
101
+ throw new Error("client acquisition must not start");
102
+ },
103
+ });
104
+
105
+ try {
106
+ await expect(
107
+ runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
108
+ withLspClient("linked/file.ts", async () => undefined, "rename", { manager }),
109
+ ),
110
+ ).rejects.toThrow(LspInvalidPathError);
111
+ expect(clientFactoryCalls).toBe(0);
112
+ } finally {
113
+ await manager.stopAll();
114
+ }
62
115
  });
63
116
  });
@@ -1,5 +1,5 @@
1
- import { existsSync, statSync } from "node:fs";
2
- import { dirname, join, resolve } from "node:path";
1
+ import { existsSync, realpathSync, statSync } from "node:fs";
2
+ import { basename, dirname, join, resolve } from "node:path";
3
3
  import {
4
4
  canonicalizeExistingOrNearestAncestor,
5
5
  contextCwd,
@@ -31,30 +31,48 @@ export function isDirectoryPath(filePath: string): boolean {
31
31
  }
32
32
 
33
33
  export function findWorkspaceRoot(filePath: string): string {
34
- const abs = resolvePathInsideContext(filePath);
34
+ const cwd = contextCwd();
35
+ const abs = resolveReadablePathInsideContext(filePath);
35
36
  let dir = abs;
36
37
 
37
38
  if (!isDirectoryPath(dir)) {
38
39
  dir = dirname(dir);
39
40
  }
40
41
 
41
- let prevDir = "";
42
- while (dir !== prevDir) {
43
- for (const marker of WORKSPACE_MARKERS) {
44
- if (existsSync(join(dir, marker))) {
45
- return dir;
42
+ const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
43
+ while (isPathInside(cwd, dir)) {
44
+ const canonicalDir = existingDirectoryInsideContext(dir, cwd);
45
+ if (canonicalDir !== undefined) {
46
+ for (const marker of WORKSPACE_MARKERS) {
47
+ if (existsSync(join(dir, marker))) {
48
+ return canonicalDir;
49
+ }
46
50
  }
47
51
  }
48
- prevDir = dir;
52
+ if (dir === cwd) break;
49
53
  dir = dirname(dir);
50
54
  }
51
55
 
52
- return dirname(abs);
56
+ return fallbackRoot;
53
57
  }
54
58
 
55
- export function resolvePathInsideContext(filePath: string): string {
59
+ export function resolveReadablePathInsideContext(filePath: string): string {
56
60
  const cwd = contextCwd();
57
61
  const abs = resolve(cwd, filePath);
62
+ if (isPathInside(cwd, abs)) return abs;
63
+
64
+ const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
65
+ if (rebased !== undefined) return rebased;
66
+
67
+ const canonical = canonicalizeExistingOrNearestAncestor(abs);
68
+ if (isPathInside(cwd, canonical)) return canonical;
69
+
70
+ throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
71
+ }
72
+
73
+ export function resolvePathInsideContext(filePath: string): string {
74
+ const cwd = contextCwd();
75
+ const abs = resolveReadablePathInsideContext(filePath);
58
76
  const canonical = canonicalizeExistingOrNearestAncestor(abs);
59
77
  if (!isPathInside(cwd, canonical)) {
60
78
  throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
@@ -62,6 +80,39 @@ export function resolvePathInsideContext(filePath: string): string {
62
80
  return canonical;
63
81
  }
64
82
 
83
+ function rebaseThroughCanonicalAncestor(path: string, cwd: string): string | undefined {
84
+ let current = path;
85
+ const suffix: string[] = [];
86
+ while (true) {
87
+ if (existsSync(current)) {
88
+ const canonical = realpathSync(current);
89
+ if (isPathInside(cwd, canonical)) return suffix.length === 0 ? canonical : join(canonical, ...suffix);
90
+ }
91
+ const parent = dirname(current);
92
+ if (parent === current) return undefined;
93
+ suffix.unshift(basename(current));
94
+ current = parent;
95
+ }
96
+ }
97
+
98
+ function existingDirectoryInsideContext(directory: string, cwd: string): string | undefined {
99
+ if (!existsSync(directory)) return undefined;
100
+ const canonical = realpathSync(directory);
101
+ if (!statSync(canonical).isDirectory()) return undefined;
102
+ return isPathInside(cwd, canonical) ? canonical : undefined;
103
+ }
104
+
105
+ function nearestExistingDirectoryInsideContext(directory: string, cwd: string): string | undefined {
106
+ let current = directory;
107
+ while (isPathInside(cwd, current)) {
108
+ const canonical = existingDirectoryInsideContext(current, cwd);
109
+ if (canonical !== undefined) return canonical;
110
+ if (current === cwd) return undefined;
111
+ current = dirname(current);
112
+ }
113
+ return undefined;
114
+ }
115
+
65
116
  export function formatServerLookupError(result: Exclude<ServerLookupResult, { status: "found" }>): string {
66
117
  if (result.status === "not_installed") {
67
118
  return formatNotInstalled(result);
@@ -143,7 +194,7 @@ export interface WithLspClientOptions {
143
194
  manager?: LspManager;
144
195
  }
145
196
 
146
- const READ_ONLY_RETRY_TOOLS = new Set([
197
+ const READ_ONLY_TOOLS = new Set([
147
198
  "diagnostics",
148
199
  "definition",
149
200
  "references",
@@ -154,11 +205,13 @@ const READ_ONLY_RETRY_TOOLS = new Set([
154
205
 
155
206
  export async function withLspClient<T>(
156
207
  filePath: string,
157
- fn: (client: LspClient, workspaceRoot: string) => Promise<T>,
208
+ fn: (client: LspClient, workspaceRoot: string, resolvedFilePath: string) => Promise<T>,
158
209
  toolName: string,
159
210
  options: WithLspClientOptions = {},
160
211
  ): Promise<T> {
161
- const absPath = resolvePathInsideContext(filePath);
212
+ const absPath = READ_ONLY_TOOLS.has(toolName)
213
+ ? resolveReadablePathInsideContext(filePath)
214
+ : resolvePathInsideContext(filePath);
162
215
 
163
216
  if (isDirectoryPath(absPath)) {
164
217
  throw new LspInvalidPathError(
@@ -181,9 +234,9 @@ export async function withLspClient<T>(
181
234
  const client = await manager.getClient(root, server, options.signal);
182
235
 
183
236
  try {
184
- return await fn(client, root);
237
+ return await fn(client, root, absPath);
185
238
  } catch (err) {
186
- if (allowRetry && READ_ONLY_RETRY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
239
+ if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
187
240
  manager.invalidateClient(root, server.id, client);
188
241
  return acquireAndCall(false);
189
242
  }
@@ -1,4 +1,4 @@
1
- import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
1
+ import { mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
@@ -87,6 +87,25 @@ describe("workspace edit adversarial inputs", () => {
87
87
  expect(readFileSync(outsideFile, "utf-8")).toBe("outside bytes\n");
88
88
  });
89
89
 
90
+ it("#given an in-workspace symlink to an outside file #when applying an edit #then rejects without modifying target", () => {
91
+ const workspace = makeTempDirectory("lsp-workspace-");
92
+ const outside = makeTempDirectory("lsp-outside-");
93
+ const outsideFile = join(outside, "outside.ts");
94
+ const canonicalWorkspace = realpathSync(workspace);
95
+ const linkedDirectory = join(canonicalWorkspace, "linked");
96
+ writeFileSync(outsideFile, "outside bytes\n", "utf-8");
97
+ symlinkSync(outside, linkedDirectory);
98
+
99
+ const result = applyWorkspaceEdit(
100
+ { changes: { [pathToFileURL(join(linkedDirectory, "outside.ts")).href]: [insertion()] } },
101
+ { workspaceRoot: canonicalWorkspace },
102
+ );
103
+
104
+ expect(result.success).toBe(false);
105
+ expect(result.errors.join("\n")).toContain("outside workspace");
106
+ expect(readFileSync(outsideFile, "utf-8")).toBe("outside bytes\n");
107
+ });
108
+
90
109
  it("#given annotations or mixed edit representations #when planned #then unsupported claims are rejected", () => {
91
110
  const workspace = makeTempDirectory("lsp-workspace-");
92
111
  const unsupported = [
@@ -1,4 +1,4 @@
1
- import { isDirectoryPath, resolvePathInsideContext, withLspClient } from "../lsp/client-wrapper.js";
1
+ import { isDirectoryPath, resolveReadablePathInsideContext, withLspClient } from "../lsp/client-wrapper.js";
2
2
  import { DEFAULT_MAX_DIAGNOSTICS } from "../lsp/constants.js";
3
3
  import { aggregateDiagnosticsForDirectory } from "../lsp/directory-diagnostics.js";
4
4
  import { filterDiagnosticsBySeverity, formatDiagnostic } from "../lsp/formatters.js";
@@ -23,7 +23,7 @@ export async function executeLspDiagnostics(
23
23
  const severity = severityFilter(params);
24
24
 
25
25
  try {
26
- const absPath = resolvePathInsideContext(filePath);
26
+ const absPath = resolveReadablePathInsideContext(filePath);
27
27
  if (isDirectoryPath(absPath)) {
28
28
  const extension = inferExtensionFromDirectory(absPath);
29
29
  if (!extension) {
@@ -62,7 +62,7 @@ export async function executeLspDiagnostics(
62
62
 
63
63
  const result = await withLspClient(
64
64
  filePath,
65
- async (client) => client.diagnostics(filePath, signal),
65
+ async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal),
66
66
  "diagnostics",
67
67
  clientOptions(signal),
68
68
  );
@@ -17,7 +17,8 @@ export async function executeLspGotoDefinition(
17
17
  try {
18
18
  const result = await withLspClient(
19
19
  filePath,
20
- async (client) => client.definition(filePath, line, character, signal),
20
+ async (client, _workspaceRoot, resolvedFilePath) =>
21
+ client.definition(resolvedFilePath, line, character, signal),
21
22
  "definition",
22
23
  clientOptions(signal),
23
24
  );
@@ -49,7 +50,8 @@ export async function executeLspFindReferences(
49
50
  try {
50
51
  const result = await withLspClient(
51
52
  filePath,
52
- async (client) => client.references(filePath, line, character, includeDeclaration, signal),
53
+ async (client, _workspaceRoot, resolvedFilePath) =>
54
+ client.references(resolvedFilePath, line, character, includeDeclaration, signal),
53
55
  "references",
54
56
  clientOptions(signal),
55
57
  );
@@ -16,7 +16,8 @@ export async function executeLspPrepareRename(
16
16
  try {
17
17
  const result = await withLspClient(
18
18
  filePath,
19
- async (client) => client.prepareRename(filePath, line, character, signal),
19
+ async (client, _workspaceRoot, resolvedFilePath) =>
20
+ client.prepareRename(resolvedFilePath, line, character, signal),
20
21
  "prepareRename",
21
22
  clientOptions(signal),
22
23
  );
@@ -46,7 +47,8 @@ export async function executeLspRename(
46
47
  try {
47
48
  const result = await withLspClient(
48
49
  filePath,
49
- async (client) => client.rename(filePath, line, character, newName, signal),
50
+ async (client, _workspaceRoot, resolvedFilePath) =>
51
+ client.rename(resolvedFilePath, line, character, newName, signal),
50
52
  "rename",
51
53
  clientOptions(signal),
52
54
  );
@@ -47,7 +47,7 @@ export async function executeLspSymbols(
47
47
 
48
48
  const symbols = await withLspClient(
49
49
  filePath,
50
- async (client) => client.documentSymbols(filePath, signal),
50
+ async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal),
51
51
  "documentSymbols",
52
52
  clientOptions(signal),
53
53
  );
@@ -4,8 +4,8 @@
4
4
  import { argv, stderr } from "node:process";
5
5
 
6
6
  // src/proxy.ts
7
- import { existsSync as existsSync12, realpathSync as realpathSync4 } from "node:fs";
8
- import { basename as basename3, delimiter as delimiter4, dirname as dirname9, isAbsolute as isAbsolute5 } from "node:path";
7
+ import { existsSync as existsSync12, realpathSync as realpathSync5 } from "node:fs";
8
+ import { basename as basename4, delimiter as delimiter4, dirname as dirname9, isAbsolute as isAbsolute5 } from "node:path";
9
9
 
10
10
  // ../mcp-stdio-core/src/record.ts
11
11
  function isPlainRecord(value) {
@@ -315,8 +315,8 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
315
315
  };
316
316
  }
317
317
  // ../lsp-core/src/lsp/client-wrapper.ts
318
- import { existsSync as existsSync9, statSync as statSync3 } from "node:fs";
319
- import { dirname as dirname6, join as join4, resolve as resolve7 } from "node:path";
318
+ import { existsSync as existsSync9, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
319
+ import { basename as basename3, dirname as dirname6, join as join4, resolve as resolve7 } from "node:path";
320
320
 
321
321
  // ../lsp-core/src/request-context.ts
322
322
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -4029,32 +4029,86 @@ function isDirectoryPath(filePath) {
4029
4029
  }
4030
4030
  }
4031
4031
  function findWorkspaceRoot(filePath) {
4032
- const abs = resolvePathInsideContext(filePath);
4032
+ const cwd = contextCwd();
4033
+ const abs = resolveReadablePathInsideContext(filePath);
4033
4034
  let dir = abs;
4034
4035
  if (!isDirectoryPath(dir)) {
4035
4036
  dir = dirname6(dir);
4036
4037
  }
4037
- let prevDir = "";
4038
- while (dir !== prevDir) {
4039
- for (const marker of WORKSPACE_MARKERS) {
4040
- if (existsSync9(join4(dir, marker))) {
4041
- return dir;
4038
+ const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
4039
+ while (isPathInside(cwd, dir)) {
4040
+ const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4041
+ if (canonicalDir !== undefined) {
4042
+ for (const marker of WORKSPACE_MARKERS) {
4043
+ if (existsSync9(join4(dir, marker))) {
4044
+ return canonicalDir;
4045
+ }
4042
4046
  }
4043
4047
  }
4044
- prevDir = dir;
4048
+ if (dir === cwd)
4049
+ break;
4045
4050
  dir = dirname6(dir);
4046
4051
  }
4047
- return dirname6(abs);
4052
+ return fallbackRoot;
4048
4053
  }
4049
- function resolvePathInsideContext(filePath) {
4054
+ function resolveReadablePathInsideContext(filePath) {
4050
4055
  const cwd = contextCwd();
4051
4056
  const abs = resolve7(cwd, filePath);
4057
+ if (isPathInside(cwd, abs))
4058
+ return abs;
4059
+ const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
4060
+ if (rebased !== undefined)
4061
+ return rebased;
4062
+ const canonical = canonicalizeExistingOrNearestAncestor(abs);
4063
+ if (isPathInside(cwd, canonical))
4064
+ return canonical;
4065
+ throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4066
+ }
4067
+ function resolvePathInsideContext(filePath) {
4068
+ const cwd = contextCwd();
4069
+ const abs = resolveReadablePathInsideContext(filePath);
4052
4070
  const canonical = canonicalizeExistingOrNearestAncestor(abs);
4053
4071
  if (!isPathInside(cwd, canonical)) {
4054
4072
  throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4055
4073
  }
4056
4074
  return canonical;
4057
4075
  }
4076
+ function rebaseThroughCanonicalAncestor(path, cwd) {
4077
+ let current = path;
4078
+ const suffix = [];
4079
+ while (true) {
4080
+ if (existsSync9(current)) {
4081
+ const canonical = realpathSync4(current);
4082
+ if (isPathInside(cwd, canonical))
4083
+ return suffix.length === 0 ? canonical : join4(canonical, ...suffix);
4084
+ }
4085
+ const parent = dirname6(current);
4086
+ if (parent === current)
4087
+ return;
4088
+ suffix.unshift(basename3(current));
4089
+ current = parent;
4090
+ }
4091
+ }
4092
+ function existingDirectoryInsideContext(directory, cwd) {
4093
+ if (!existsSync9(directory))
4094
+ return;
4095
+ const canonical = realpathSync4(directory);
4096
+ if (!statSync3(canonical).isDirectory())
4097
+ return;
4098
+ return isPathInside(cwd, canonical) ? canonical : undefined;
4099
+ }
4100
+ function nearestExistingDirectoryInsideContext(directory, cwd) {
4101
+ let current = directory;
4102
+ while (isPathInside(cwd, current)) {
4103
+ const canonical = existingDirectoryInsideContext(current, cwd);
4104
+ if (canonical !== undefined)
4105
+ return canonical;
4106
+ if (current === cwd)
4107
+ return;
4108
+ current = dirname6(current);
4109
+ }
4110
+ return;
4111
+ }
4058
4112
  function formatServerLookupError(result) {
4059
4113
  if (result.status === "not_installed") {
4060
4114
  return formatNotInstalled(result);
@@ -4125,7 +4179,7 @@ function formatNotInstalled(result) {
4125
4179
  ].join(`
4126
4180
  `);
4127
4181
  }
4128
- var READ_ONLY_RETRY_TOOLS = new Set([
4182
+ var READ_ONLY_TOOLS = new Set([
4129
4183
  "diagnostics",
4130
4184
  "definition",
4131
4185
  "references",
@@ -4134,7 +4188,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
4134
4188
  "prepareRename"
4135
4189
  ]);
4136
4190
  async function withLspClient(filePath, fn, toolName, options = {}) {
4137
- const absPath = resolvePathInsideContext(filePath);
4191
+ const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
4138
4192
  if (isDirectoryPath(absPath)) {
4139
4193
  throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
4140
4194
  }
@@ -4149,9 +4203,9 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4149
4203
  const acquireAndCall = async (allowRetry) => {
4150
4204
  const client = await manager.getClient(root, server2, options.signal);
4151
4205
  try {
4152
- return await fn(client, root);
4206
+ return await fn(client, root, absPath);
4153
4207
  } catch (err) {
4154
- if (allowRetry && READ_ONLY_RETRY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4208
+ if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4155
4209
  manager.invalidateClient(root, server2.id, client);
4156
4210
  return acquireAndCall(false);
4157
4211
  }
@@ -4606,7 +4660,7 @@ async function executeLspDiagnostics(params, signal) {
4606
4660
  const filePath = requireString(params, "filePath");
4607
4661
  const severity = severityFilter(params);
4608
4662
  try {
4609
- const absPath = resolvePathInsideContext(filePath);
4663
+ const absPath = resolveReadablePathInsideContext(filePath);
4610
4664
  if (isDirectoryPath(absPath)) {
4611
4665
  const extension = inferExtensionFromDirectory(absPath);
4612
4666
  if (!extension) {
@@ -4635,7 +4689,7 @@ async function executeLspDiagnostics(params, signal) {
4635
4689
  };
4636
4690
  return text(output2.output, details2);
4637
4691
  }
4638
- const result = await withLspClient(filePath, async (client) => client.diagnostics(filePath, signal), "diagnostics", clientOptions(signal));
4692
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
4639
4693
  if (result.transientError) {
4640
4694
  const message = result.transientError.message;
4641
4695
  const details2 = {
@@ -4710,7 +4764,7 @@ async function executeLspGotoDefinition(params, signal) {
4710
4764
  const line = requireNumber(params, "line");
4711
4765
  const character = requireNumber(params, "character");
4712
4766
  try {
4713
- const result = await withLspClient(filePath, async (client) => client.definition(filePath, line, character, signal), "definition", clientOptions(signal));
4767
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
4714
4768
  const locations = !result ? [] : Array.isArray(result) ? result : [result];
4715
4769
  const details = { filePath, line, character, locations };
4716
4770
  if (locations.length === 0)
@@ -4735,7 +4789,7 @@ async function executeLspFindReferences(params, signal) {
4735
4789
  const character = requireNumber(params, "character");
4736
4790
  const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
4737
4791
  try {
4738
- const result = await withLspClient(filePath, async (client) => client.references(filePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
4792
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
4739
4793
  const references = Array.isArray(result) ? result : [];
4740
4794
  const total = references.length;
4741
4795
  const truncated = total > DEFAULT_MAX_REFERENCES;
@@ -4777,7 +4831,7 @@ async function executeLspPrepareRename(params, signal) {
4777
4831
  const line = requireNumber(params, "line");
4778
4832
  const character = requireNumber(params, "character");
4779
4833
  try {
4780
- const result = await withLspClient(filePath, async (client) => client.prepareRename(filePath, line, character, signal), "prepareRename", clientOptions(signal));
4834
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
4781
4835
  const details = { filePath, line, character, result };
4782
4836
  return text(formatPrepareRenameResult(result), details);
4783
4837
  } catch (error) {
@@ -4798,7 +4852,7 @@ async function executeLspRename(params, signal) {
4798
4852
  const character = requireNumber(params, "character");
4799
4853
  const newName = requireString(params, "newName");
4800
4854
  try {
4801
- const result = await withLspClient(filePath, async (client) => client.rename(filePath, line, character, newName, signal), "rename", clientOptions(signal));
4855
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
4802
4856
  const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
4803
4857
  return text(formatApplyResult(result.apply), details, !result.apply.success);
4804
4858
  } catch (error) {
@@ -4878,7 +4932,7 @@ async function executeLspSymbols(params, signal) {
4878
4932
  const symbols2 = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
4879
4933
  return formatSymbolsResult(filePath, scope, symbols2, limit, query);
4880
4934
  }
4881
- const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(filePath, signal), "documentSymbols", clientOptions(signal));
4935
+ const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
4882
4936
  return formatSymbolsResult(filePath, scope, symbols, limit);
4883
4937
  } catch (error) {
4884
4938
  const query = optionalString(params, "query");
@@ -6160,13 +6214,13 @@ function canonicalizePathList(value) {
6160
6214
  function canonicalizePath(value) {
6161
6215
  if (value === undefined || !isAbsolute5(value) || !existsSync12(value))
6162
6216
  return value;
6163
- return realpathSync4(value);
6217
+ return realpathSync5(value);
6164
6218
  }
6165
6219
  function projectRootFromOpenCodeConfigPath(path2) {
6166
- if (basename3(path2) !== "lsp.json" && basename3(path2) !== "lsp-client.json")
6220
+ if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
6167
6221
  return;
6168
6222
  const configDir = dirname9(path2);
6169
- const configDirName = basename3(configDir);
6223
+ const configDirName = basename4(configDir);
6170
6224
  if (configDirName !== ".opencode" && configDirName !== ".omo")
6171
6225
  return;
6172
6226
  return dirname9(configDir);
@@ -6417,7 +6471,7 @@ function parseEndpoint(value) {
6417
6471
  // src/version-reap.ts
6418
6472
  import { execFile } from "node:child_process";
6419
6473
  import { readdir, readFile, rm } from "node:fs/promises";
6420
- import { basename as basename4, dirname as dirname12, join as join8 } from "node:path";
6474
+ import { basename as basename5, dirname as dirname12, join as join8 } from "node:path";
6421
6475
  var TERM_GRACE_MS = 5000;
6422
6476
  var KILL_GRACE_MS = 1000;
6423
6477
  var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
@@ -6547,7 +6601,7 @@ function splitCmdline(buffer) {
6547
6601
  function isNodeCliDaemonArgv(argv) {
6548
6602
  if (argv.length < 2 || !argv.includes("daemon"))
6549
6603
  return false;
6550
- const executable = basename4(argv[0] ?? "");
6604
+ const executable = basename5(argv[0] ?? "");
6551
6605
  if (!/^node(?:\.exe)?$/i.test(executable))
6552
6606
  return false;
6553
6607
  return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));