@nudojs/lsp 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Freeze inventory for `@nudojs/lsp` public surface (A1/A7).
3
+ *
4
+ * Pure constants — importable without starting the language server
5
+ * (`server.ts` has side effects on import). Human-readable inventory:
6
+ * `packages/lsp/PUBLIC_API.md`.
7
+ *
8
+ * Protocol contract:
9
+ * - executeCommand uses **dot** form: `nudo.check`
10
+ * - custom requests use **slash** form: `nudo/check` (canonical protocol)
11
+ * - every slash-form agent request has a matching executeCommand name
12
+ */
13
+ /** workspace/executeCommand names (dot form) — declared on initialize */
14
+ declare const NUDO_EXECUTE_COMMANDS: readonly ["nudo.whatIf", "nudo.suggestCase", "nudo.trace", "nudo.check", "nudo.hover", "nudo.infer", "nudo.interface", "nudo.interface.draft", "nudo.interfaceDraft", "nudo.interfaceEmit", "nudo.interface.emit", "nudo.selectCase", "nudo.getActiveCases"];
15
+ /**
16
+ * Custom LSP request method names (slash form) — the protocol contract.
17
+ * Agent tools also register the dot-form method as an alias for MCP bridges.
18
+ */
19
+ declare const NUDO_SLASH_REQUESTS: readonly ["nudo/selectCase", "nudo/getActiveCases", "nudo/whatIf", "nudo/suggestCase", "nudo/trace", "nudo/check", "nudo/hover", "nudo/infer", "nudo/interface", "nudo/interface.draft", "nudo/interface.emit"];
20
+ /**
21
+ * Agent-tool names shared by executeCommand / slash requests / AGENT_TOOL_SOURCES.
22
+ * `codeLens` is server-computed only (no command/request); `selectCase` /
23
+ * `getActiveCases` are editor commands, not agent tools.
24
+ */
25
+ declare const NUDO_AGENT_TOOL_NAMES: readonly ["whatIf", "suggestCase", "trace", "check", "hover", "infer", "interface", "interface.draft", "interface.emit"];
26
+ /** executeCommand aliases kept for CodeLens / Marketplace command palette */
27
+ declare const NUDO_COMMAND_ALIASES: Readonly<Record<string, string>>;
28
+ /** Capability keys declared in connection.onInitialize */
29
+ declare const NUDO_INITIALIZE_CAPABILITIES: readonly ["textDocumentSync", "hoverProvider", "completionProvider", "codeLensProvider", "inlayHintProvider", "definitionProvider", "referencesProvider", "renameProvider", "documentSymbolProvider", "workspaceSymbolProvider", "codeActionProvider", "signatureHelpProvider", "semanticTokensProvider", "executeCommandProvider", "diagnosticProvider"];
30
+ /** Slash-form → matching executeCommand (dot form) */
31
+ declare function slashToExecuteCommand(slash: string): string;
32
+ /** npm package public surface (mirrors packages/lsp/package.json) */
33
+ declare const NUDO_LSP_PACKAGE_SURFACE: {
34
+ readonly name: "@nudojs/lsp";
35
+ readonly bin: "nudo-lsp";
36
+ readonly entry: ".";
37
+ readonly entryPath: "./dist/server.js";
38
+ readonly files: readonly ["dist"];
39
+ /** Machine-readable freeze inventory (no server side effects). */
40
+ readonly publicApiExport: "./public-api";
41
+ readonly publicApiPath: "./dist/public-api.js";
42
+ };
43
+
44
+ export { NUDO_AGENT_TOOL_NAMES, NUDO_COMMAND_ALIASES, NUDO_EXECUTE_COMMANDS, NUDO_INITIALIZE_CAPABILITIES, NUDO_LSP_PACKAGE_SURFACE, NUDO_SLASH_REQUESTS, slashToExecuteCommand };
@@ -0,0 +1,89 @@
1
+ import { createRequire as __nudoCreateRequire } from "module";
2
+ import { fileURLToPath as __nudoFileURLToPath } from "url";
3
+ const require = __nudoCreateRequire(import.meta.url);
4
+ const __filename = __nudoFileURLToPath(import.meta.url);
5
+ const __dirname = __nudoFileURLToPath(new URL(".", import.meta.url));
6
+
7
+ // src/public-api.ts
8
+ var NUDO_EXECUTE_COMMANDS = [
9
+ "nudo.whatIf",
10
+ "nudo.suggestCase",
11
+ "nudo.trace",
12
+ "nudo.check",
13
+ "nudo.hover",
14
+ "nudo.infer",
15
+ "nudo.interface",
16
+ "nudo.interface.draft",
17
+ "nudo.interfaceDraft",
18
+ "nudo.interfaceEmit",
19
+ "nudo.interface.emit",
20
+ "nudo.selectCase",
21
+ "nudo.getActiveCases"
22
+ ];
23
+ var NUDO_SLASH_REQUESTS = [
24
+ "nudo/selectCase",
25
+ "nudo/getActiveCases",
26
+ "nudo/whatIf",
27
+ "nudo/suggestCase",
28
+ "nudo/trace",
29
+ "nudo/check",
30
+ "nudo/hover",
31
+ "nudo/infer",
32
+ "nudo/interface",
33
+ "nudo/interface.draft",
34
+ "nudo/interface.emit"
35
+ ];
36
+ var NUDO_AGENT_TOOL_NAMES = [
37
+ "whatIf",
38
+ "suggestCase",
39
+ "trace",
40
+ "check",
41
+ "hover",
42
+ "infer",
43
+ "interface",
44
+ "interface.draft",
45
+ "interface.emit"
46
+ ];
47
+ var NUDO_COMMAND_ALIASES = {
48
+ "nudo.interfaceDraft": "nudo.interface.draft",
49
+ "nudo.interfaceEmit": "nudo.interface.emit"
50
+ };
51
+ var NUDO_INITIALIZE_CAPABILITIES = [
52
+ "textDocumentSync",
53
+ "hoverProvider",
54
+ "completionProvider",
55
+ "codeLensProvider",
56
+ "inlayHintProvider",
57
+ "definitionProvider",
58
+ "referencesProvider",
59
+ "renameProvider",
60
+ "documentSymbolProvider",
61
+ "workspaceSymbolProvider",
62
+ "codeActionProvider",
63
+ "signatureHelpProvider",
64
+ "semanticTokensProvider",
65
+ "executeCommandProvider",
66
+ "diagnosticProvider"
67
+ ];
68
+ function slashToExecuteCommand(slash) {
69
+ return slash.replace(/^nudo\//, "nudo.");
70
+ }
71
+ var NUDO_LSP_PACKAGE_SURFACE = {
72
+ name: "@nudojs/lsp",
73
+ bin: "nudo-lsp",
74
+ entry: ".",
75
+ entryPath: "./dist/server.js",
76
+ files: ["dist"],
77
+ /** Machine-readable freeze inventory (no server side effects). */
78
+ publicApiExport: "./public-api",
79
+ publicApiPath: "./dist/public-api.js"
80
+ };
81
+ export {
82
+ NUDO_AGENT_TOOL_NAMES,
83
+ NUDO_COMMAND_ALIASES,
84
+ NUDO_EXECUTE_COMMANDS,
85
+ NUDO_INITIALIZE_CAPABILITIES,
86
+ NUDO_LSP_PACKAGE_SURFACE,
87
+ NUDO_SLASH_REQUESTS,
88
+ slashToExecuteCommand
89
+ };
package/dist/server.js CHANGED
@@ -52430,7 +52430,7 @@ var require_util2 = __commonJS({
52430
52430
  return path;
52431
52431
  }
52432
52432
  exports.normalize = normalize;
52433
- function join10(aRoot, aPath) {
52433
+ function join11(aRoot, aPath) {
52434
52434
  if (aRoot === "") {
52435
52435
  aRoot = ".";
52436
52436
  }
@@ -52462,7 +52462,7 @@ var require_util2 = __commonJS({
52462
52462
  }
52463
52463
  return joined;
52464
52464
  }
52465
- exports.join = join10;
52465
+ exports.join = join11;
52466
52466
  exports.isAbsolute = function(aPath) {
52467
52467
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
52468
52468
  };
@@ -52635,7 +52635,7 @@ var require_util2 = __commonJS({
52635
52635
  parsed.path = parsed.path.substring(0, index + 1);
52636
52636
  }
52637
52637
  }
52638
- sourceURL = join10(urlGenerate(parsed), sourceURL);
52638
+ sourceURL = join11(urlGenerate(parsed), sourceURL);
52639
52639
  }
52640
52640
  return normalize(sourceURL);
52641
52641
  }
@@ -63161,7 +63161,7 @@ ${lanes.join("\n")}
63161
63161
  return process.memoryUsage().heapUsed;
63162
63162
  },
63163
63163
  getFileSize(path) {
63164
- const stat = statSync10(path);
63164
+ const stat = statSync11(path);
63165
63165
  if (stat == null ? void 0 : stat.isFile()) {
63166
63166
  return stat.size;
63167
63167
  }
@@ -63205,7 +63205,7 @@ ${lanes.join("\n")}
63205
63205
  }
63206
63206
  };
63207
63207
  return nodeSystem;
63208
- function statSync10(path) {
63208
+ function statSync11(path) {
63209
63209
  try {
63210
63210
  return _fs.statSync(path, statSyncOptions);
63211
63211
  } catch {
@@ -63264,7 +63264,7 @@ ${lanes.join("\n")}
63264
63264
  activeSession.post("Profiler.stop", (err, { profile }) => {
63265
63265
  var _a;
63266
63266
  if (!err) {
63267
- if ((_a = statSync10(profilePath)) == null ? void 0 : _a.isDirectory()) {
63267
+ if ((_a = statSync11(profilePath)) == null ? void 0 : _a.isDirectory()) {
63268
63268
  profilePath = _path.join(profilePath, `${(/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-")}+P${process.pid}.cpuprofile`);
63269
63269
  }
63270
63270
  try {
@@ -63384,7 +63384,7 @@ ${lanes.join("\n")}
63384
63384
  let stat;
63385
63385
  if (typeof dirent === "string" || dirent.isSymbolicLink()) {
63386
63386
  const name = combinePaths(path, entry);
63387
- stat = statSync10(name);
63387
+ stat = statSync11(name);
63388
63388
  if (!stat) {
63389
63389
  continue;
63390
63390
  }
@@ -63408,7 +63408,7 @@ ${lanes.join("\n")}
63408
63408
  return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames2, process.cwd(), depth, getAccessibleFileSystemEntries, realpath);
63409
63409
  }
63410
63410
  function fileSystemEntryExists(path, entryKind) {
63411
- const stat = statSync10(path);
63411
+ const stat = statSync11(path);
63412
63412
  if (!stat) {
63413
63413
  return false;
63414
63414
  }
@@ -63450,7 +63450,7 @@ ${lanes.join("\n")}
63450
63450
  }
63451
63451
  function getModifiedTime3(path) {
63452
63452
  var _a;
63453
- return (_a = statSync10(path)) == null ? void 0 : _a.mtime;
63453
+ return (_a = statSync11(path)) == null ? void 0 : _a.mtime;
63454
63454
  }
63455
63455
  function setModifiedTime(path, time) {
63456
63456
  try {
@@ -265681,7 +265681,12 @@ function isRelFn(a) {
265681
265681
  if (!s || s.k !== "fn") return false;
265682
265682
  if (s.returnType === void 0) return false;
265683
265683
  if (s.paramTypes === void 0) return s.params.length === 0;
265684
- return s.paramTypes.length === s.params.length;
265684
+ if (s.paramTypes.length === s.params.length) return true;
265685
+ let required = 0;
265686
+ for (const p of s.params) {
265687
+ if (p && !p.startsWith("...") && !p.endsWith("?")) required++;
265688
+ }
265689
+ return s.paramTypes.length === required;
265685
265690
  }
265686
265691
  function litOfTerm(t) {
265687
265692
  return t.op === "lit" ? t.value : void 0;
@@ -268166,6 +268171,15 @@ function ok() {
268166
268171
  function fail(reason) {
268167
268172
  return { ok: false, reason };
268168
268173
  }
268174
+ function requiredFnArity(params) {
268175
+ if (!params) return 0;
268176
+ let n = 0;
268177
+ for (const p of params) {
268178
+ if (!p || p.startsWith("...") || p.endsWith("?")) continue;
268179
+ n++;
268180
+ }
268181
+ return n;
268182
+ }
268169
268183
  function leqAbs(src, tgt, opts = {}) {
268170
268184
  const phi2 = opts.phi ?? pTrue;
268171
268185
  return leqWithPred(src, tgt, phi2, opts.env ?? null, 0);
@@ -268318,8 +268332,12 @@ function leqShape(src, tgt, phi2, env, depth) {
268318
268332
  }
268319
268333
  if (t.k === "fn") {
268320
268334
  if (s.k !== "fn") return fail(`shape ${s.k} \u22AD fn`);
268321
- if (s.params.length !== t.params.length) {
268322
- return fail(`fn arity ${s.params.length} \u22AD ${t.params.length}`);
268335
+ const sReq = requiredFnArity(s.params);
268336
+ const tReq = requiredFnArity(t.params);
268337
+ if (sReq > tReq) {
268338
+ return fail(
268339
+ `fn arity required ${sReq} \u22AD target required ${tReq} (params ${s.params.length} / ${t.params.length})`
268340
+ );
268323
268341
  }
268324
268342
  if (t.returnType !== void 0) {
268325
268343
  const sr = s.returnType;
@@ -270515,13 +270533,39 @@ function formatShape(a) {
270515
270533
  case "tuple":
270516
270534
  return `[${s.elements.map(formatShape).join(", ")}]`;
270517
270535
  case "fn": {
270518
- if (s.paramTypes && s.paramTypes.length > 0) {
270519
- const ps = s.paramTypes.map((p) => formatShapeSlot(p));
270520
- const ret2 = s.returnType !== void 0 ? formatShapeSlot(s.returnType) : "?";
270521
- return `(${ps.join(", ")}) => ${ret2}`;
270522
- }
270523
270536
  const ret = s.returnType !== void 0 ? formatShapeSlot(s.returnType) : "?";
270524
- return `(${s.params.join(", ")}) => ${ret}`;
270537
+ const labels = s.params ?? [];
270538
+ const paramTypes = s.paramTypes;
270539
+ const hasMarkers = labels.some(
270540
+ (p) => p.startsWith("...") || p.endsWith("?")
270541
+ );
270542
+ const renderLabeled = () => {
270543
+ const ps = [];
270544
+ const n = paramTypes ? Math.max(paramTypes.length, labels.length) : labels.length;
270545
+ for (let i = 0; i < n; i++) {
270546
+ const label = labels[i];
270547
+ const type = paramTypes?.[i];
270548
+ const typeText = type !== void 0 ? formatShapeSlot(type) : void 0;
270549
+ if (label?.startsWith("...")) {
270550
+ ps.push(typeText ? `...${label.slice(3)}: ${typeText}` : label);
270551
+ } else if (label?.endsWith("?")) {
270552
+ ps.push(typeText ? `${label.slice(0, -1)}?: ${typeText}` : label);
270553
+ } else if (typeText !== void 0) {
270554
+ ps.push(typeText);
270555
+ } else if (label) {
270556
+ ps.push(label);
270557
+ }
270558
+ }
270559
+ return ps;
270560
+ };
270561
+ if (hasMarkers) {
270562
+ return `(${renderLabeled().join(", ")}) => ${ret}`;
270563
+ }
270564
+ if (paramTypes && paramTypes.length > 0) {
270565
+ const ps = paramTypes.map((p) => formatShapeSlot(p));
270566
+ return `(${ps.join(", ")}) => ${ret}`;
270567
+ }
270568
+ return `(${labels.join(", ")}) => ${ret}`;
270525
270569
  }
270526
270570
  case "brand":
270527
270571
  return `${s.name}`;
@@ -280651,6 +280695,19 @@ function envFn(paramTypes, returnType, apply, opts) {
280651
280695
  if (opts?.conf && opts.conf !== "exact") a.conf = opts.conf;
280652
280696
  return a;
280653
280697
  }
280698
+ function envFnVariadic(restType, returnType, opts) {
280699
+ const required = opts?.required ?? [];
280700
+ const restName = opts?.restName ?? "...rest";
280701
+ const paramTypes = [...required, restType];
280702
+ const params = [
280703
+ ...required.map((_, i) => `x${i}`),
280704
+ restName
280705
+ ];
280706
+ return envFn(paramTypes, returnType, opts?.apply, {
280707
+ params,
280708
+ ...opts?.name ? { name: opts.name } : {}
280709
+ });
280710
+ }
280654
280711
  function slotsOf(entries) {
280655
280712
  const out = {};
280656
280713
  for (const [k, v2] of Object.entries(entries)) {
@@ -281398,6 +281455,106 @@ function defineEnv3() {
281398
281455
  chmodSync: envFn([prim.str(), prim.num()], undef2()),
281399
281456
  chownSync: envFn([prim.str(), prim.num(), prim.num()], undef2()),
281400
281457
  accessSync: envFn([prim.str(), prim.num()], undef2()),
281458
+ // Callback-style async on `fs` / `node:fs` (Node actual API).
281459
+ // Promise APIs live only under fs.promises / node:fs/promises.
281460
+ readFile: envFn(
281461
+ [prim.str(), prim.unknown, prim.unknown],
281462
+ undef2(),
281463
+ void 0,
281464
+ { params: ["path", "options?", "callback"] }
281465
+ ),
281466
+ writeFile: envFn(
281467
+ [prim.str(), unionOf(prim.str(), bufferBrand), prim.unknown],
281468
+ undef2(),
281469
+ void 0,
281470
+ { params: ["path", "data", "callback"] }
281471
+ ),
281472
+ mkdir: envFn(
281473
+ [prim.str(), prim.unknown, prim.unknown],
281474
+ undef2(),
281475
+ void 0,
281476
+ { params: ["path", "options?", "callback"] }
281477
+ ),
281478
+ rm: envFn(
281479
+ [prim.str(), prim.unknown, prim.unknown],
281480
+ undef2(),
281481
+ void 0,
281482
+ { params: ["path", "options?", "callback"] }
281483
+ ),
281484
+ stat: envFn(
281485
+ [prim.str(), prim.unknown, prim.unknown],
281486
+ undef2(),
281487
+ void 0,
281488
+ { params: ["path", "options?", "callback"] }
281489
+ ),
281490
+ readdir: envFn(
281491
+ [prim.str(), prim.unknown, prim.unknown],
281492
+ undef2(),
281493
+ void 0,
281494
+ { params: ["path", "options?", "callback"] }
281495
+ ),
281496
+ access: envFn(
281497
+ [prim.str(), prim.unknown, prim.unknown],
281498
+ undef2(),
281499
+ void 0,
281500
+ { params: ["path", "mode?", "callback"] }
281501
+ ),
281502
+ appendFile: envFn(
281503
+ [prim.str(), unionOf(prim.str(), bufferBrand), prim.unknown],
281504
+ undef2(),
281505
+ void 0,
281506
+ { params: ["path", "data", "callback"] }
281507
+ ),
281508
+ unlink: envFn(
281509
+ [prim.str(), prim.unknown, prim.unknown],
281510
+ undef2(),
281511
+ void 0,
281512
+ { params: ["path", "options?", "callback"] }
281513
+ ),
281514
+ rename: envFn(
281515
+ [prim.str(), prim.str(), prim.unknown],
281516
+ undef2(),
281517
+ void 0,
281518
+ { params: ["oldPath", "newPath", "callback"] }
281519
+ ),
281520
+ copyFile: envFn(
281521
+ [prim.str(), prim.str(), prim.unknown],
281522
+ undef2(),
281523
+ void 0,
281524
+ { params: ["src", "dest", "callback"] }
281525
+ ),
281526
+ realpath: envFn(
281527
+ [prim.str(), prim.unknown, prim.unknown],
281528
+ undef2(),
281529
+ void 0,
281530
+ { params: ["path", "options?", "callback"] }
281531
+ ),
281532
+ readlink: envFn(
281533
+ [prim.str(), prim.unknown, prim.unknown],
281534
+ undef2(),
281535
+ void 0,
281536
+ { params: ["path", "options?", "callback"] }
281537
+ ),
281538
+ symlink: envFn(
281539
+ [prim.str(), prim.str(), prim.unknown, prim.unknown],
281540
+ undef2(),
281541
+ void 0,
281542
+ { params: ["target", "path", "type?", "callback"] }
281543
+ ),
281544
+ chmod: envFn(
281545
+ [prim.str(), prim.num(), prim.unknown],
281546
+ undef2(),
281547
+ void 0,
281548
+ { params: ["path", "mode", "callback"] }
281549
+ ),
281550
+ open: envFn(
281551
+ [prim.str(), prim.unknown, prim.unknown],
281552
+ undef2(),
281553
+ void 0,
281554
+ { params: ["path", "flags?", "callback"] }
281555
+ )
281556
+ };
281557
+ const fsPromisesModule = {
281401
281558
  readFile: envFn(
281402
281559
  [prim.str(), prim.unknown],
281403
281560
  promiseOf(unionOf(prim.str(), bufferBrand))
@@ -281416,7 +281573,19 @@ function defineEnv3() {
281416
281573
  [prim.str(), prim.unknown],
281417
281574
  promiseOf(arrOf(prim.unknown))
281418
281575
  ),
281419
- access: envFn([prim.str(), prim.num()], promiseOf(undef2()))
281576
+ access: envFn([prim.str(), prim.num()], promiseOf(undef2())),
281577
+ appendFile: envFn(
281578
+ [prim.str(), unionOf(prim.str(), bufferBrand)],
281579
+ promiseOf(undef2())
281580
+ ),
281581
+ unlink: envFn([prim.str()], promiseOf(undef2())),
281582
+ rename: envFn([prim.str(), prim.str()], promiseOf(undef2())),
281583
+ copyFile: envFn([prim.str(), prim.str()], promiseOf(undef2())),
281584
+ realpath: envFn([prim.str()], promiseOf(prim.str())),
281585
+ readlink: envFn([prim.str()], promiseOf(prim.str())),
281586
+ symlink: envFn([prim.str(), prim.str()], promiseOf(undef2())),
281587
+ chmod: envFn([prim.str(), prim.num()], promiseOf(undef2())),
281588
+ open: envFn([prim.str(), prim.str()], promiseOf(prim.unknown))
281420
281589
  };
281421
281590
  const strImpl1Abs = (fn2) => (args) => {
281422
281591
  const a = absStr2(args[0]);
@@ -281446,10 +281615,21 @@ function defineEnv3() {
281446
281615
  return p !== void 0 ? boolLit(nodePath.isAbsolute(p)) : void 0;
281447
281616
  };
281448
281617
  const pathModule = {
281449
- join: envFn([prim.str(), prim.str()], prim.str(), pathJoinAbs),
281450
- resolve: envFn([prim.str()], prim.str(), pathResolveAbs),
281618
+ // Node variadic: declare min required arity + rest label (not n fixed slots).
281619
+ join: envFnVariadic(prim.str(), prim.str(), {
281620
+ apply: pathJoinAbs,
281621
+ required: [prim.str()],
281622
+ restName: "...paths"
281623
+ }),
281624
+ resolve: envFnVariadic(prim.str(), prim.str(), {
281625
+ apply: pathResolveAbs,
281626
+ restName: "...paths"
281627
+ }),
281451
281628
  dirname: envFn([prim.str()], prim.str(), strImpl1Abs(nodePath.dirname)),
281452
- basename: envFn([prim.str(), prim.str()], prim.str(), pathBasenameAbs),
281629
+ // ext is optional in Node — required arity 1; label+type render `ext?: string`.
281630
+ basename: envFn([prim.str(), prim.str()], prim.str(), pathBasenameAbs, {
281631
+ params: ["path", "ext?"]
281632
+ }),
281453
281633
  extname: envFn([prim.str()], prim.str(), strImpl1Abs(nodePath.extname)),
281454
281634
  relative: envFn([prim.str(), prim.str()], prim.str(), pathRelativeAbs),
281455
281635
  normalize: envFn([prim.str()], prim.str(), strImpl1Abs(nodePath.normalize)),
@@ -281527,6 +281707,7 @@ function defineEnv3() {
281527
281707
  toJSON: envFn([], prim.str())
281528
281708
  });
281529
281709
  const urlModule = {
281710
+ // base is optional in Node — required arity 1; label+type render `base?: string`.
281530
281711
  URL: envFn(
281531
281712
  [prim.str(), prim.str()],
281532
281713
  nodeUrlObj,
@@ -281554,7 +281735,8 @@ function defineEnv3() {
281554
281735
  } catch {
281555
281736
  return void 0;
281556
281737
  }
281557
- }
281738
+ },
281739
+ { params: ["href", "base?"] }
281558
281740
  ),
281559
281741
  URLSearchParams: envFn(
281560
281742
  [prim.unknown],
@@ -281652,15 +281834,27 @@ function defineEnv3() {
281652
281834
  fork: envFn([prim.str(), arrOf(prim.str()), prim.unknown], prim.unknown)
281653
281835
  };
281654
281836
  const utilModule = {
281655
- promisify: envFn([prim.unknown], prim.unknown),
281837
+ // Signature-level: promisify preserves fn-ness only as unknown (no generic).
281838
+ promisify: envFn([prim.unknown], prim.unknown, void 0, { name: "util.promisify" }),
281656
281839
  inspect: envFn([prim.unknown, prim.unknown], prim.str()),
281657
- format: envFn([prim.str()], prim.str()),
281840
+ format: envFnVariadic(prim.unknown, prim.str(), {
281841
+ // util.format() with zero args is valid in Node.
281842
+ restName: "...args",
281843
+ name: "util.format"
281844
+ }),
281845
+ callbackify: envFn([prim.unknown], prim.unknown),
281846
+ deprecate: envFn([prim.unknown, prim.str()], prim.unknown),
281847
+ inherits: envFn([prim.unknown, prim.unknown], undef2()),
281848
+ isDeepStrictEqual: envFn([prim.unknown, prim.unknown], prim.bool()),
281658
281849
  types: objAbs({
281659
281850
  isDate: envFn([prim.unknown], prim.bool()),
281660
281851
  isRegExp: envFn([prim.unknown], prim.bool()),
281661
281852
  isPromise: envFn([prim.unknown], prim.bool()),
281662
281853
  isArrayBuffer: envFn([prim.unknown], prim.bool()),
281663
- isTypedArray: envFn([prim.unknown], prim.bool())
281854
+ isTypedArray: envFn([prim.unknown], prim.bool()),
281855
+ isNativeError: envFn([prim.unknown], prim.bool()),
281856
+ isAsyncFunction: envFn([prim.unknown], prim.bool()),
281857
+ isGeneratorFunction: envFn([prim.unknown], prim.bool())
281664
281858
  }),
281665
281859
  TextEncoder: envFn(
281666
281860
  [],
@@ -281671,6 +281865,79 @@ function defineEnv3() {
281671
281865
  objAbs({ decode: envFn([prim.unknown], prim.str()) })
281672
281866
  )
281673
281867
  };
281868
+ const eventEmitterShape = objAbs({
281869
+ on: envFn([prim.str(), prim.unknown], prim.unknown),
281870
+ once: envFn([prim.str(), prim.unknown], prim.unknown),
281871
+ off: envFn([prim.str(), prim.unknown], prim.unknown),
281872
+ emit: envFn([prim.str()], prim.bool()),
281873
+ addListener: envFn([prim.str(), prim.unknown], prim.unknown),
281874
+ removeListener: envFn([prim.str(), prim.unknown], prim.unknown),
281875
+ removeAllListeners: envFn([prim.str()], prim.unknown),
281876
+ listeners: envFn([prim.str()], arrOf(prim.unknown)),
281877
+ listenerCount: envFn([prim.str()], prim.num()),
281878
+ eventNames: envFn([], arrOf(prim.str()))
281879
+ });
281880
+ const eventEmitterInstance = brandOf2("EventEmitter", eventEmitterShape);
281881
+ const EventEmitterCtor = envFn([prim.unknown], eventEmitterInstance, void 0, {
281882
+ params: ["options?"]
281883
+ });
281884
+ const eventsModule = {
281885
+ EventEmitter: EventEmitterCtor,
281886
+ once: envFn(
281887
+ [prim.unknown, prim.str()],
281888
+ promiseOf(arrOf(prim.unknown))
281889
+ ),
281890
+ on: envFn([prim.unknown, prim.str()], prim.unknown),
281891
+ listenerCount: envFn([prim.unknown, prim.str()], prim.num())
281892
+ };
281893
+ const streamIoMethods = {
281894
+ on: envFn([prim.str(), prim.unknown], prim.unknown),
281895
+ once: envFn([prim.str(), prim.unknown], prim.unknown),
281896
+ off: envFn([prim.str(), prim.unknown], prim.unknown),
281897
+ emit: envFn([prim.str()], prim.bool()),
281898
+ pipe: envFn([prim.unknown], prim.unknown),
281899
+ destroy: envFn([prim.unknown], undef2()),
281900
+ read: envFn([prim.num()], prim.unknown),
281901
+ write: envFn([unionOf(prim.str(), bufferBrand)], prim.bool()),
281902
+ end: envFn([prim.unknown], undef2()),
281903
+ pause: envFn([], prim.unknown),
281904
+ resume: envFn([], prim.unknown),
281905
+ setEncoding: envFn([prim.str()], prim.unknown)
281906
+ };
281907
+ const streamCtor = (brandName) => envFn([prim.unknown], brandOf2(brandName, objAbs(streamIoMethods)), void 0, {
281908
+ params: ["options?"]
281909
+ });
281910
+ const streamModule = {
281911
+ Readable: streamCtor("Readable"),
281912
+ Writable: streamCtor("Writable"),
281913
+ Duplex: streamCtor("Duplex"),
281914
+ Transform: streamCtor("Transform"),
281915
+ pipeline: envFnVariadic(prim.unknown, promiseOf(undef2()), {
281916
+ restName: "...streams"
281917
+ }),
281918
+ finished: envFn([prim.unknown], promiseOf(undef2()))
281919
+ };
281920
+ const parsedQueryString = brandOf2(
281921
+ "ParsedQueryString",
281922
+ objAbs({})
281923
+ );
281924
+ const querystringModule = {
281925
+ // sep/eq/options optional — required arity 1; labels+types render `sep?: string` etc.
281926
+ parse: envFn(
281927
+ [prim.str(), prim.str(), prim.str(), prim.unknown],
281928
+ parsedQueryString,
281929
+ void 0,
281930
+ { params: ["str", "sep?", "eq?", "options?"] }
281931
+ ),
281932
+ stringify: envFn(
281933
+ [prim.unknown, prim.str(), prim.str(), prim.unknown],
281934
+ prim.str(),
281935
+ void 0,
281936
+ { params: ["obj", "sep?", "eq?", "options?"] }
281937
+ ),
281938
+ escape: envFn([prim.str()], prim.str()),
281939
+ unescape: envFn([prim.str()], prim.str())
281940
+ };
281674
281941
  const nodeGlobals = {
281675
281942
  process: objAbs({
281676
281943
  env: objAbs({}),
@@ -281740,15 +282007,8 @@ function defineEnv3() {
281740
282007
  const modules = {
281741
282008
  fs: fsModule,
281742
282009
  "node:fs": fsModule,
281743
- "node:fs/promises": {
281744
- readFile: fsModule.readFile,
281745
- writeFile: fsModule.writeFile,
281746
- mkdir: fsModule.mkdir,
281747
- rm: fsModule.rm,
281748
- stat: fsModule.stat,
281749
- readdir: fsModule.readdir,
281750
- access: fsModule.access
281751
- },
282010
+ "fs/promises": fsPromisesModule,
282011
+ "node:fs/promises": fsPromisesModule,
281752
282012
  path: pathModule,
281753
282013
  "node:path": pathModule,
281754
282014
  os: osModule,
@@ -281760,7 +282020,13 @@ function defineEnv3() {
281760
282020
  child_process: childProcessModule,
281761
282021
  "node:child_process": childProcessModule,
281762
282022
  util: utilModule,
281763
- "node:util": utilModule
282023
+ "node:util": utilModule,
282024
+ events: eventsModule,
282025
+ "node:events": eventsModule,
282026
+ stream: streamModule,
282027
+ "node:stream": streamModule,
282028
+ querystring: querystringModule,
282029
+ "node:querystring": querystringModule
281764
282030
  };
281765
282031
  return {
281766
282032
  globals: { ...esEnv.globals, ...nodeGlobals },
@@ -283676,6 +283942,47 @@ function collectEnvModules(envNames) {
283676
283942
  }
283677
283943
  return out;
283678
283944
  }
283945
+ var envHarvestConflictCollector = null;
283946
+ function setEnvHarvestConflictCollector(collector2) {
283947
+ const prev = envHarvestConflictCollector;
283948
+ envHarvestConflictCollector = collector2;
283949
+ return prev;
283950
+ }
283951
+ function mergeHarvestUnderEnv(harvestModules, envModules, opts) {
283952
+ const out = {};
283953
+ for (const [mod2, exports] of Object.entries(harvestModules)) {
283954
+ const named = { ...exports.named };
283955
+ out[mod2] = exports.default !== void 0 ? { named, default: exports.default } : { named };
283956
+ }
283957
+ const notify = opts?.onConflict ?? envHarvestConflictCollector;
283958
+ for (const [mod2, envExports] of Object.entries(envModules)) {
283959
+ const existing = out[mod2];
283960
+ if (!existing) {
283961
+ const named2 = { ...envExports.named };
283962
+ out[mod2] = envExports.default !== void 0 ? { named: named2, default: envExports.default } : { named: named2 };
283963
+ continue;
283964
+ }
283965
+ const overwritten = [];
283966
+ for (const key of Object.keys(envExports.named)) {
283967
+ if (existing.named[key] !== void 0) overwritten.push(key);
283968
+ }
283969
+ const defaultOverwritten = envExports.default !== void 0 && existing.default !== void 0;
283970
+ if (notify && (overwritten.length > 0 || defaultOverwritten)) {
283971
+ try {
283972
+ notify({
283973
+ module: mod2,
283974
+ exports: overwritten,
283975
+ defaultOverwritten
283976
+ });
283977
+ } catch {
283978
+ }
283979
+ }
283980
+ const named = { ...existing.named, ...envExports.named };
283981
+ const defaultAbs = envExports.default !== void 0 ? envExports.default : existing.default;
283982
+ out[mod2] = defaultAbs !== void 0 ? { named, default: defaultAbs } : { named };
283983
+ }
283984
+ return out;
283985
+ }
283679
283986
  function collectBPathReplacements(source) {
283680
283987
  const targets = [];
283681
283988
  const values = {};
@@ -283790,7 +284097,7 @@ function tryRunBPath(source, filePath, opts = {}) {
283790
284097
  try {
283791
284098
  const { modules: graphMods, issues } = evalAbsModuleGraph(source, filePath);
283792
284099
  const envMods = collectEnvModules(opts.envNames ?? []);
283793
- const modules = { ...envMods, ...graphMods };
284100
+ const modules = mergeHarvestUnderEnv(graphMods, envMods);
283794
284101
  const { targets, values, asTargets, asValues } = collectBPathReplacements(source);
283795
284102
  const envGlobals = {
283796
284103
  ...collectEnvGlobals(opts.envNames ?? []),
@@ -284616,6 +284923,24 @@ function analyzeFileUncached(filePath, source, activeCases2, externalCallRecords
284616
284923
  () => analyzeFileUncachedInner(filePath, source, activeCases2, externalCallRecords, loadModule)
284617
284924
  );
284618
284925
  }
284926
+ function findModuleImportLoc(source, module) {
284927
+ const bare = module.startsWith("node:") ? module.slice("node:".length) : module;
284928
+ const alts = [.../* @__PURE__ */ new Set([module, bare, `node:${bare}`])];
284929
+ const lines = source.split(/\r?\n/);
284930
+ for (let i = 0; i < lines.length; i++) {
284931
+ const line = lines[i];
284932
+ for (const alt of alts) {
284933
+ const re = new RegExp(
284934
+ `["'\`]${alt.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}["'\`]`
284935
+ );
284936
+ const m = re.exec(line);
284937
+ if (m && m.index !== void 0) {
284938
+ return { line: i, column: m.index, length: m[0].length };
284939
+ }
284940
+ }
284941
+ }
284942
+ return null;
284943
+ }
284619
284944
  function analyzeFileUncachedInner(filePath, source, activeCases2, externalCallRecords, loadModule) {
284620
284945
  const ast = parse(source);
284621
284946
  const functions = extractDirectives(ast);
@@ -284624,6 +284949,18 @@ function analyzeFileUncachedInner(filePath, source, activeCases2, externalCallRe
284624
284949
  const nodeAbsMap = /* @__PURE__ */ new Map();
284625
284950
  const functionResults = [];
284626
284951
  const caseHints = [];
284952
+ const envHarvestConflicts = [];
284953
+ const prevHarvestConflictCollector = setEnvHarvestConflictCollector((c) => {
284954
+ if (!envHarvestConflicts.some((x) => x.module === c.module)) {
284955
+ envHarvestConflicts.push(c);
284956
+ } else {
284957
+ const prev = envHarvestConflicts.find((x) => x.module === c.module);
284958
+ for (const e of c.exports) {
284959
+ if (!prev.exports.includes(e)) prev.exports.push(e);
284960
+ }
284961
+ prev.defaultOverwritten ||= c.defaultOverwritten;
284962
+ }
284963
+ });
284627
284964
  const fileDirectives = extractFileDirectives(ast);
284628
284965
  const fileEnvNames = fileDirectives.filter((d) => d.kind === "env").flatMap((d) => d.envs);
284629
284966
  const projectConfig = findProjectConfig(dirname9(filePath));
@@ -284713,7 +285050,7 @@ function analyzeFileUncachedInner(filePath, source, activeCases2, externalCallRe
284713
285050
  seedFns: seeds.seedFns,
284714
285051
  ...loadModule ? { loadModule } : {}
284715
285052
  });
284716
- absGraphModules = { ...collectEnvModules(envNames), ...g.modules };
285053
+ absGraphModules = mergeHarvestUnderEnv(g.modules, collectEnvModules(envNames));
284717
285054
  pushBModuleIssues(g.issues);
284718
285055
  } catch {
284719
285056
  }
@@ -285319,6 +285656,24 @@ function analyzeFileUncachedInner(filePath, source, activeCases2, externalCallRe
285319
285656
  filePath,
285320
285657
  analysisConfig(projectConfig?.config).callSiteBudget
285321
285658
  );
285659
+ setEnvHarvestConflictCollector(prevHarvestConflictCollector);
285660
+ for (const c of envHarvestConflicts) {
285661
+ const parts = [];
285662
+ if (c.exports.length > 0) parts.push(`export(s) ${c.exports.join(", ")}`);
285663
+ if (c.defaultOverwritten) parts.push("default");
285664
+ const detail = parts.length > 0 ? ` \u2014 ${parts.join("; ")}` : "";
285665
+ const loc = findModuleImportLoc(source, c.module);
285666
+ const range = loc ? {
285667
+ start: { line: loc.line, column: loc.column },
285668
+ end: { line: loc.line, column: loc.column + loc.length }
285669
+ } : { start: { line: 0, column: 0 }, end: { line: 0, column: 0 } };
285670
+ diagnostics.push({
285671
+ range,
285672
+ severity: "warning",
285673
+ message: `handwritten @nudo:env wins over harvest on module "${c.module}"${detail}; harvest only fills missing slots (B8). code=nudo:env-harvest-conflict`,
285674
+ code: "nudo:env-harvest-conflict"
285675
+ });
285676
+ }
285322
285677
  return {
285323
285678
  functions: functionResults,
285324
285679
  diagnostics,
@@ -285431,7 +285786,7 @@ function collectAbsCallRecords(source, seeds, filePath, precomputedModules, envN
285431
285786
  }
285432
285787
  }
285433
285788
  if (envNames.length > 0) {
285434
- modules = { ...collectEnvModules(envNames), ...modules ?? {} };
285789
+ modules = mergeHarvestUnderEnv(modules ?? {}, collectEnvModules(envNames));
285435
285790
  }
285436
285791
  try {
285437
285792
  importLocals = buildAbsImportLocalMap(source, filePath);
@@ -286436,7 +286791,8 @@ function collectLoadDepContents(filePath, source, loadModule) {
286436
286791
  }
286437
286792
 
286438
286793
  // ../service/src/harvest-node.ts
286439
- import { existsSync as existsSync11 } from "fs";
286794
+ import { existsSync as existsSync11, statSync as statSync8 } from "fs";
286795
+ import { join as join7 } from "path";
286440
286796
 
286441
286797
  // ../service/src/semantic-tokens.ts
286442
286798
  var SEMANTIC_TOKEN_TYPES = [
@@ -287343,7 +287699,7 @@ function joinSections(base, sectionTexts) {
287343
287699
 
287344
287700
  // ../service/src/interface-draft.ts
287345
287701
  import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync4, realpathSync as realpathSync2 } from "fs";
287346
- import { basename as basename3, dirname as dirname15, isAbsolute as isAbsolute2, join as join7, relative as relative4 } from "path";
287702
+ import { basename as basename3, dirname as dirname15, isAbsolute as isAbsolute2, join as join8, relative as relative4 } from "path";
287347
287703
  function collectParamBodyAccesses(source) {
287348
287704
  const out = /* @__PURE__ */ new Map();
287349
287705
  let ast;
@@ -287860,7 +288216,7 @@ function safeRealpath(p) {
287860
288216
  return realpathSync2(p);
287861
288217
  } catch {
287862
288218
  try {
287863
- return join7(realpathSync2(dirname15(p)), basename3(p));
288219
+ return join8(realpathSync2(dirname15(p)), basename3(p));
287864
288220
  } catch {
287865
288221
  return p;
287866
288222
  }
@@ -287945,8 +288301,8 @@ import { basename as basename4, dirname as dirname16, relative as relative5, res
287945
288301
 
287946
288302
  // src/symbols.ts
287947
288303
  var import_traverse3 = __toESM(require_lib8(), 1);
287948
- import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync2, statSync as statSync8 } from "fs";
287949
- import { dirname as dirname17, join as join8, resolve as resolve12 } from "path";
288304
+ import { existsSync as existsSync16, readFileSync as readFileSync15, readdirSync as readdirSync2, statSync as statSync9 } from "fs";
288305
+ import { dirname as dirname17, join as join9, resolve as resolve12 } from "path";
287950
288306
  function locFromNode2(node) {
287951
288307
  return {
287952
288308
  start: { line: node.loc?.start.line ?? 1, column: node.loc?.start.column ?? 0 },
@@ -288147,12 +288503,12 @@ function resolveRelativeModule(spec, fromFile) {
288147
288503
  `${base}.ts`,
288148
288504
  `${base}.mts`,
288149
288505
  `${base}.cts`,
288150
- join8(base, "index.js"),
288151
- join8(base, "index.mjs"),
288152
- join8(base, "index.ts")
288506
+ join9(base, "index.js"),
288507
+ join9(base, "index.mjs"),
288508
+ join9(base, "index.ts")
288153
288509
  ]) {
288154
288510
  try {
288155
- if (existsSync16(cand) && statSync8(cand).isFile()) return cand;
288511
+ if (existsSync16(cand) && statSync9(cand).isFile()) return cand;
288156
288512
  } catch {
288157
288513
  }
288158
288514
  }
@@ -288280,9 +288636,9 @@ function collectJsFiles(dir, out, max, depth) {
288280
288636
  }
288281
288637
  for (const name of entries) {
288282
288638
  if (name === "node_modules" || name === ".git" || name === "dist") continue;
288283
- const full = join8(dir, name);
288639
+ const full = join9(dir, name);
288284
288640
  try {
288285
- const st = statSync8(full);
288641
+ const st = statSync9(full);
288286
288642
  if (st.isDirectory()) {
288287
288643
  collectJsFiles(full, out, max, depth + 1);
288288
288644
  } else if (/\.(js|mjs|cjs|ts|mts)$/.test(name) && !/\.d\.ts$/.test(name)) {
@@ -289511,6 +289867,34 @@ function computeInterfaceLenses(source, filePath, deps = {}) {
289511
289867
  return lenses;
289512
289868
  }
289513
289869
 
289870
+ // src/public-api.ts
289871
+ var NUDO_EXECUTE_COMMANDS = [
289872
+ "nudo.whatIf",
289873
+ "nudo.suggestCase",
289874
+ "nudo.trace",
289875
+ "nudo.check",
289876
+ "nudo.hover",
289877
+ "nudo.infer",
289878
+ "nudo.interface",
289879
+ "nudo.interface.draft",
289880
+ "nudo.interfaceDraft",
289881
+ "nudo.interfaceEmit",
289882
+ "nudo.interface.emit",
289883
+ "nudo.selectCase",
289884
+ "nudo.getActiveCases"
289885
+ ];
289886
+ var NUDO_AGENT_TOOL_NAMES = [
289887
+ "whatIf",
289888
+ "suggestCase",
289889
+ "trace",
289890
+ "check",
289891
+ "hover",
289892
+ "infer",
289893
+ "interface",
289894
+ "interface.draft",
289895
+ "interface.emit"
289896
+ ];
289897
+
289514
289898
  // src/a6-relax.ts
289515
289899
  function escapeRegExp2(s) {
289516
289900
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -289608,21 +289992,7 @@ function relaxSidecarConstraint(sidecarSource, fnName, param, constraintText) {
289608
289992
  }
289609
289993
 
289610
289994
  // src/server.ts
289611
- var NUDO_COMMANDS = [
289612
- "nudo.whatIf",
289613
- "nudo.suggestCase",
289614
- "nudo.trace",
289615
- "nudo.check",
289616
- "nudo.hover",
289617
- "nudo.infer",
289618
- "nudo.interface",
289619
- "nudo.interface.draft",
289620
- "nudo.interfaceDraft",
289621
- "nudo.interfaceEmit",
289622
- "nudo.interface.emit",
289623
- "nudo.selectCase",
289624
- "nudo.getActiveCases"
289625
- ];
289995
+ var NUDO_COMMANDS = NUDO_EXECUTE_COMMANDS;
289626
289996
  if (!process.argv.some(
289627
289997
  (a) => a === "--stdio" || a === "--node-ipc" || a.startsWith("--socket=")
289628
289998
  )) {
@@ -290572,7 +290942,7 @@ connection.onRequest("nudo/getActiveCases", handleGetActiveCases);
290572
290942
  function dispatchAgentRequest(command, params) {
290573
290943
  return dispatchNudoCommand(command, params);
290574
290944
  }
290575
- for (const name of ["whatIf", "suggestCase", "trace", "check", "hover", "infer", "interface", "interface.draft", "interface.emit"]) {
290945
+ for (const name of NUDO_AGENT_TOOL_NAMES) {
290576
290946
  const command = `nudo.${name}`;
290577
290947
  const handler = (params) => dispatchAgentRequest(command, params);
290578
290948
  connection.onRequest(`nudo/${name}`, handler);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nudojs/lsp",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -23,6 +23,10 @@
23
23
  ".": {
24
24
  "types": "./dist/server.d.ts",
25
25
  "default": "./dist/server.js"
26
+ },
27
+ "./public-api": {
28
+ "types": "./dist/public-api.d.ts",
29
+ "default": "./dist/public-api.js"
26
30
  }
27
31
  },
28
32
  "files": [
@@ -43,9 +47,9 @@
43
47
  "dependencies": {
44
48
  "vscode-languageserver": "^9.0.0",
45
49
  "vscode-languageserver-textdocument": "^1.0.0",
46
- "@nudojs/core": "2.0.0",
47
- "@nudojs/service": "2.0.0",
48
- "@nudojs/parser": "0.5.0"
50
+ "@nudojs/service": "3.0.0",
51
+ "@nudojs/parser": "0.5.1",
52
+ "@nudojs/core": "2.0.1"
49
53
  },
50
54
  "scripts": {
51
55
  "build": "tsup"