@neat.is/core 0.4.16 → 0.4.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.d.cts CHANGED
@@ -2,6 +2,11 @@
2
2
  declare function readPackageVersion(): string;
3
3
  declare function printBanner(): void;
4
4
 
5
+ interface HttpClient {
6
+ get<T>(path: string): Promise<T>;
7
+ post?<T>(path: string, body: unknown): Promise<T>;
8
+ }
9
+
5
10
  interface InitOptions {
6
11
  scanPath: string;
7
12
  outPath: string;
@@ -54,7 +59,7 @@ declare const CLAUDE_SKILL_CONFIG: {
54
59
  command: string;
55
60
  args: string[];
56
61
  env: {
57
- NEAT_API_URL: string;
62
+ NEAT_CORE_URL: string;
58
63
  };
59
64
  };
60
65
  };
@@ -68,6 +73,11 @@ declare function runSkill(opts: SkillOptions): Promise<{
68
73
  }>;
69
74
  declare function main(): Promise<void>;
70
75
  declare const QUERY_VERBS: Set<string>;
76
+ declare class ProjectResolutionError extends Error {
77
+ readonly exitCode: number;
78
+ constructor(message: string, exitCode?: number);
79
+ }
80
+ declare function resolveProjectForVerb(client: HttpClient, parsed: ParsedArgs): Promise<string | undefined>;
71
81
  declare function runQueryVerb(cmd: string, parsed: ParsedArgs): Promise<number>;
72
82
 
73
- export { CLAUDE_SKILL_CONFIG, type InitOptions, type InitResult, QUERY_VERBS, type SkillOptions, commandPrefix, isNpxInvocation, main, parseArgs, printBanner, readPackageVersion, runInit, runQueryVerb, runSkill, usage };
83
+ export { CLAUDE_SKILL_CONFIG, type InitOptions, type InitResult, ProjectResolutionError, QUERY_VERBS, type SkillOptions, commandPrefix, isNpxInvocation, main, parseArgs, printBanner, readPackageVersion, resolveProjectForVerb, runInit, runQueryVerb, runSkill, usage };
package/dist/cli.d.ts CHANGED
@@ -2,6 +2,11 @@
2
2
  declare function readPackageVersion(): string;
3
3
  declare function printBanner(): void;
4
4
 
5
+ interface HttpClient {
6
+ get<T>(path: string): Promise<T>;
7
+ post?<T>(path: string, body: unknown): Promise<T>;
8
+ }
9
+
5
10
  interface InitOptions {
6
11
  scanPath: string;
7
12
  outPath: string;
@@ -54,7 +59,7 @@ declare const CLAUDE_SKILL_CONFIG: {
54
59
  command: string;
55
60
  args: string[];
56
61
  env: {
57
- NEAT_API_URL: string;
62
+ NEAT_CORE_URL: string;
58
63
  };
59
64
  };
60
65
  };
@@ -68,6 +73,11 @@ declare function runSkill(opts: SkillOptions): Promise<{
68
73
  }>;
69
74
  declare function main(): Promise<void>;
70
75
  declare const QUERY_VERBS: Set<string>;
76
+ declare class ProjectResolutionError extends Error {
77
+ readonly exitCode: number;
78
+ constructor(message: string, exitCode?: number);
79
+ }
80
+ declare function resolveProjectForVerb(client: HttpClient, parsed: ParsedArgs): Promise<string | undefined>;
71
81
  declare function runQueryVerb(cmd: string, parsed: ParsedArgs): Promise<number>;
72
82
 
73
- export { CLAUDE_SKILL_CONFIG, type InitOptions, type InitResult, QUERY_VERBS, type SkillOptions, commandPrefix, isNpxInvocation, main, parseArgs, printBanner, readPackageVersion, runInit, runQueryVerb, runSkill, usage };
83
+ export { CLAUDE_SKILL_CONFIG, type InitOptions, type InitResult, ProjectResolutionError, QUERY_VERBS, type SkillOptions, commandPrefix, isNpxInvocation, main, parseArgs, printBanner, readPackageVersion, resolveProjectForVerb, runInit, runQueryVerb, runSkill, usage };
package/dist/cli.js CHANGED
@@ -36,6 +36,7 @@ import {
36
36
  normalizeProjectPath,
37
37
  pathsForProject,
38
38
  promoteFrontierNodes,
39
+ pruneRegistry,
39
40
  removeProject,
40
41
  resetGraph,
41
42
  retireEdgesByFile,
@@ -44,7 +45,7 @@ import {
44
45
  setStatus,
45
46
  startPersistLoop,
46
47
  startStalenessLoop
47
- } from "./chunk-XS4CGNRO.js";
48
+ } from "./chunk-LUDSPX5N.js";
48
49
  import {
49
50
  startOtelGrpcReceiver
50
51
  } from "./chunk-GHPHVXYM.js";
@@ -3858,6 +3859,8 @@ function usage() {
3858
3859
  console.log(" uninstall <name>");
3859
3860
  console.log(" Remove a project from the registry. Does not touch");
3860
3861
  console.log(" neat-out/, policy.json, or any user file.");
3862
+ console.log(" prune Drop registry entries whose path is gone from disk.");
3863
+ console.log(" Flags: --json emit the removed list as JSON");
3861
3864
  console.log(" version Print the installed @neat.is/core version and exit.");
3862
3865
  console.log(" Aliases: --version, -v.");
3863
3866
  console.log(" skill Install or print the Claude Code MCP drop-in.");
@@ -3917,6 +3920,7 @@ function usage() {
3917
3920
  console.log("");
3918
3921
  console.log("environment:");
3919
3922
  console.log(" NEAT_API_URL base URL for the core REST API (default http://localhost:8080)");
3923
+ console.log(" alias: NEAT_CORE_URL (the name the MCP server reads)");
3920
3924
  console.log(" NEAT_PROJECT project name when --project isn't passed");
3921
3925
  }
3922
3926
  var STRING_FLAGS = [
@@ -4228,7 +4232,7 @@ var CLAUDE_SKILL_CONFIG = {
4228
4232
  command: "npx",
4229
4233
  args: ["-y", "@neat.is/mcp"],
4230
4234
  env: {
4231
- NEAT_API_URL: "http://localhost:8080"
4235
+ NEAT_CORE_URL: "http://localhost:8080"
4232
4236
  }
4233
4237
  }
4234
4238
  }
@@ -4274,6 +4278,9 @@ async function runSkill(opts) {
4274
4278
  console.log("");
4275
4279
  console.log("Manual install: copy mcpServers.neat from --print-config into ~/.claude.json,");
4276
4280
  console.log("then restart Claude Code. See packages/claude-skill/SKILL.md for the tool list.");
4281
+ console.log("");
4282
+ console.log("The MCP server reads NEAT_CORE_URL for the daemon URL \u2014 point it at a");
4283
+ console.log("non-default daemon by editing that value in the generated config.");
4277
4284
  return { exitCode: 0 };
4278
4285
  }
4279
4286
  async function main() {
@@ -4441,6 +4448,19 @@ async function main() {
4441
4448
  console.log("note: neat-out/, policy.json, and other files at the project path were left in place.");
4442
4449
  return;
4443
4450
  }
4451
+ if (cmd === "prune") {
4452
+ const removed = await pruneRegistry({ ttlMs: 0 });
4453
+ if (parsed.json) {
4454
+ console.log(JSON.stringify(removed.map((p) => ({ name: p.name, path: p.path })), null, 2));
4455
+ return;
4456
+ }
4457
+ if (removed.length === 0) {
4458
+ console.log("nothing to prune \u2014 every registered project path still exists.");
4459
+ return;
4460
+ }
4461
+ console.log(`pruned ${removed.length} project${removed.length === 1 ? "" : "s"}: ${removed.map((p) => p.name).join(", ")}`);
4462
+ return;
4463
+ }
4444
4464
  if (cmd === "deploy") {
4445
4465
  const artifact = await runDeploy();
4446
4466
  const block = renderOtelEnvBlock2(artifact.token);
@@ -4528,12 +4548,44 @@ function resolveProjectFlag(parsed) {
4528
4548
  if (env && env.length > 0 && env !== DEFAULT_PROJECT) return env;
4529
4549
  return void 0;
4530
4550
  }
4551
+ var ProjectResolutionError = class extends Error {
4552
+ constructor(message, exitCode = 2) {
4553
+ super(message);
4554
+ this.exitCode = exitCode;
4555
+ this.name = "ProjectResolutionError";
4556
+ }
4557
+ exitCode;
4558
+ };
4559
+ async function resolveProjectForVerb(client, parsed) {
4560
+ const explicit = resolveProjectFlag(parsed);
4561
+ if (explicit) return explicit;
4562
+ const projects = await client.get("/projects");
4563
+ if (projects.some((p) => p.name === DEFAULT_PROJECT)) {
4564
+ return void 0;
4565
+ }
4566
+ if (projects.length === 1) {
4567
+ return projects[0].name;
4568
+ }
4569
+ if (projects.length === 0) {
4570
+ throw new ProjectResolutionError(
4571
+ "No projects are registered with the daemon yet. Run `npx neat.is` in a repo to build a graph first, then re-run this command."
4572
+ );
4573
+ }
4574
+ const names = projects.map((p) => p.name).sort().map((n) => ` ${n}`).join("\n");
4575
+ throw new ProjectResolutionError(
4576
+ `Several projects are registered and none is named "default", so I can't pick one for you.
4577
+ Pass --project <name> to choose:
4578
+ ${names}`
4579
+ );
4580
+ }
4581
+ function resolveDaemonUrl() {
4582
+ return process.env.NEAT_API_URL ?? process.env.NEAT_CORE_URL ?? "http://localhost:8080";
4583
+ }
4531
4584
  async function runQueryVerb(cmd, parsed) {
4532
- const baseUrl = process.env.NEAT_API_URL ?? "http://localhost:8080";
4585
+ const baseUrl = resolveDaemonUrl();
4533
4586
  const client = createHttpClient(baseUrl, resolveAuthToken());
4534
- const project = resolveProjectFlag(parsed);
4535
4587
  const positional = parsed.positional;
4536
- let work;
4588
+ let makeWork;
4537
4589
  switch (cmd) {
4538
4590
  case "root-cause": {
4539
4591
  const node = positional[0];
@@ -4541,7 +4593,7 @@ async function runQueryVerb(cmd, parsed) {
4541
4593
  console.error("neat root-cause: missing <node-id>");
4542
4594
  return 2;
4543
4595
  }
4544
- work = runRootCause(client, {
4596
+ makeWork = (project) => runRootCause(client, {
4545
4597
  errorNode: node,
4546
4598
  ...parsed.errorId ? { errorId: parsed.errorId } : {},
4547
4599
  ...project ? { project } : {}
@@ -4554,7 +4606,7 @@ async function runQueryVerb(cmd, parsed) {
4554
4606
  console.error("neat blast-radius: missing <node-id>");
4555
4607
  return 2;
4556
4608
  }
4557
- work = runBlastRadius(client, {
4609
+ makeWork = (project) => runBlastRadius(client, {
4558
4610
  nodeId: node,
4559
4611
  ...parsed.depth !== null ? { depth: parsed.depth } : {},
4560
4612
  ...project ? { project } : {}
@@ -4567,7 +4619,7 @@ async function runQueryVerb(cmd, parsed) {
4567
4619
  console.error("neat dependencies: missing <node-id>");
4568
4620
  return 2;
4569
4621
  }
4570
- work = runDependencies(client, {
4622
+ makeWork = (project) => runDependencies(client, {
4571
4623
  nodeId: node,
4572
4624
  ...parsed.depth !== null ? { depth: parsed.depth } : {},
4573
4625
  ...project ? { project } : {}
@@ -4580,14 +4632,14 @@ async function runQueryVerb(cmd, parsed) {
4580
4632
  console.error("neat observed-dependencies: missing <node-id>");
4581
4633
  return 2;
4582
4634
  }
4583
- work = runObservedDependencies(client, {
4635
+ makeWork = (project) => runObservedDependencies(client, {
4584
4636
  nodeId: node,
4585
4637
  ...project ? { project } : {}
4586
4638
  });
4587
4639
  break;
4588
4640
  }
4589
4641
  case "incidents": {
4590
- work = runIncidents(client, {
4642
+ makeWork = (project) => runIncidents(client, {
4591
4643
  ...positional[0] ? { nodeId: positional[0] } : {},
4592
4644
  ...parsed.limit !== null ? { limit: parsed.limit } : {},
4593
4645
  ...project ? { project } : {}
@@ -4600,7 +4652,7 @@ async function runQueryVerb(cmd, parsed) {
4600
4652
  console.error("neat search: missing <query>");
4601
4653
  return 2;
4602
4654
  }
4603
- work = runSearch(client, { query: q, ...project ? { project } : {} });
4655
+ makeWork = (project) => runSearch(client, { query: q, ...project ? { project } : {} });
4604
4656
  break;
4605
4657
  }
4606
4658
  case "diff": {
@@ -4609,14 +4661,14 @@ async function runQueryVerb(cmd, parsed) {
4609
4661
  console.error("neat diff: --against <snapshot-path> is required");
4610
4662
  return 2;
4611
4663
  }
4612
- work = runDiff(client, {
4664
+ makeWork = (project) => runDiff(client, {
4613
4665
  againstSnapshot: against,
4614
4666
  ...project ? { project } : {}
4615
4667
  });
4616
4668
  break;
4617
4669
  }
4618
4670
  case "stale-edges": {
4619
- work = runStaleEdges(client, {
4671
+ makeWork = (project) => runStaleEdges(client, {
4620
4672
  ...parsed.limit !== null ? { limit: parsed.limit } : {},
4621
4673
  ...parsed.edgeType ? { edgeType: parsed.edgeType } : {},
4622
4674
  ...project ? { project } : {}
@@ -4635,7 +4687,7 @@ async function runQueryVerb(cmd, parsed) {
4635
4687
  return 2;
4636
4688
  }
4637
4689
  }
4638
- work = runPolicies(client, {
4690
+ makeWork = (project) => runPolicies(client, {
4639
4691
  ...parsed.node ? { nodeId: parsed.node } : {},
4640
4692
  ...hypothetical ? { hypotheticalAction: hypothetical } : {},
4641
4693
  ...project ? { project } : {}
@@ -4659,7 +4711,7 @@ async function runQueryVerb(cmd, parsed) {
4659
4711
  }
4660
4712
  typeFilter = out;
4661
4713
  }
4662
- work = runDivergences(client, {
4714
+ makeWork = (project) => runDivergences(client, {
4663
4715
  ...typeFilter ? { type: typeFilter } : {},
4664
4716
  ...parsed.minConfidence !== null ? { minConfidence: parsed.minConfidence } : {},
4665
4717
  ...parsed.node ? { node: parsed.node } : {},
@@ -4672,16 +4724,21 @@ async function runQueryVerb(cmd, parsed) {
4672
4724
  return 2;
4673
4725
  }
4674
4726
  try {
4675
- const result = await work;
4727
+ const project = await resolveProjectForVerb(client, parsed);
4728
+ const result = await makeWork(project);
4676
4729
  if (parsed.json) process.stdout.write(formatJson(result) + "\n");
4677
4730
  else process.stdout.write(formatHuman(result) + "\n");
4678
4731
  return 0;
4679
4732
  } catch (err) {
4733
+ if (err instanceof ProjectResolutionError) {
4734
+ console.error(`neat ${cmd}: ${err.message}`);
4735
+ return err.exitCode;
4736
+ }
4680
4737
  if (err instanceof HttpError) {
4681
4738
  const detail = err.responseBody.length > 0 ? err.responseBody : err.message;
4682
4739
  console.error(`neat ${cmd}: ${detail.trim()}`);
4683
4740
  } else if (err instanceof TransportError) {
4684
- console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (NEAT_API_URL=${process.env.NEAT_API_URL ?? "http://localhost:8080"})`);
4741
+ console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (NEAT_API_URL=${resolveDaemonUrl()})`);
4685
4742
  } else {
4686
4743
  console.error(`neat ${cmd}: ${err.message}`);
4687
4744
  }
@@ -4697,6 +4754,7 @@ if (/[\\/]cli\.(?:cjs|js)$/.test(entry) || entry.endsWith("/cli") || entry.endsW
4697
4754
  }
4698
4755
  export {
4699
4756
  CLAUDE_SKILL_CONFIG,
4757
+ ProjectResolutionError,
4700
4758
  QUERY_VERBS,
4701
4759
  commandPrefix,
4702
4760
  isNpxInvocation,
@@ -4704,6 +4762,7 @@ export {
4704
4762
  parseArgs,
4705
4763
  printBanner,
4706
4764
  readPackageVersion,
4765
+ resolveProjectForVerb,
4707
4766
  runInit,
4708
4767
  runQueryVerb,
4709
4768
  runSkill,