@neat.is/core 0.10.1 → 0.10.3-dev.20260930

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.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  resolveNeatVersion,
9
9
  startK8sSubstratePolling,
10
10
  writeDaemonRecord
11
- } from "./chunk-AWIK6T3G.js";
11
+ } from "./chunk-DLQNMU3R.js";
12
12
  import {
13
13
  buildSearchIndex
14
14
  } from "./chunk-BC53SCT7.js";
@@ -17,6 +17,7 @@ import {
17
17
  PolicyViolationsLog,
18
18
  ProjectNameCollisionError,
19
19
  Projects,
20
+ RegistryError,
20
21
  SCHEMA_VERSION,
21
22
  addCallEdges,
22
23
  addConfigNodes,
@@ -42,9 +43,12 @@ import {
42
43
  evaluateAllPolicies,
43
44
  extractFromDirectory,
44
45
  findDaemonByProject,
46
+ findProjectByPath,
45
47
  formatExtractionBanner,
46
48
  formatPrecisionFloorBanner,
49
+ formatSkippedBanner,
47
50
  getGraph,
51
+ getProject,
48
52
  getProviderFieldSchema,
49
53
  isEnvRef,
50
54
  isPushProvider,
@@ -78,7 +82,7 @@ import {
78
82
  startStalenessLoop,
79
83
  upsertConnectorEntry,
80
84
  validateConnectorEntry
81
- } from "./chunk-E3YFFIHE.js";
85
+ } from "./chunk-LNIVRE4L.js";
82
86
  import {
83
87
  startOtelGrpcReceiver
84
88
  } from "./chunk-5SJHA5ZH.js";
@@ -93,7 +97,7 @@ import {
93
97
  } from "./chunk-M7CGATVC.js";
94
98
 
95
99
  // src/cli.ts
96
- import path20 from "path";
100
+ import path21 from "path";
97
101
  import os5 from "os";
98
102
  import { promises as fs18 } from "fs";
99
103
 
@@ -3937,6 +3941,20 @@ import path10 from "path";
3937
3941
  import { fileURLToPath as fileURLToPath2 } from "url";
3938
3942
  import { spawn as spawn2 } from "child_process";
3939
3943
  import readline from "readline";
3944
+ var SnapshotWriteError = class extends Error {
3945
+ constructor(scanPath, nodeCount, edgeCount, cause) {
3946
+ super(`could not write the snapshot for ${scanPath}: ${cause.message}`);
3947
+ this.scanPath = scanPath;
3948
+ this.nodeCount = nodeCount;
3949
+ this.edgeCount = edgeCount;
3950
+ this.cause = cause;
3951
+ this.name = "SnapshotWriteError";
3952
+ }
3953
+ scanPath;
3954
+ nodeCount;
3955
+ edgeCount;
3956
+ cause;
3957
+ };
3940
3958
  async function extractAndPersist(opts) {
3941
3959
  const services = await discoverServices(opts.scanPath);
3942
3960
  const languages = [...new Set(services.map((s) => s.node.language))].sort();
@@ -3948,7 +3966,11 @@ async function extractAndPersist(opts) {
3948
3966
  errorsPath: projectPaths.errorsPath
3949
3967
  });
3950
3968
  if (!opts.dryRun) {
3951
- await saveGraphToDisk(graph, projectPaths.snapshotPath);
3969
+ try {
3970
+ await saveGraphToDisk(graph, projectPaths.snapshotPath);
3971
+ } catch (err) {
3972
+ throw new SnapshotWriteError(opts.scanPath, graph.order, graph.size, err);
3973
+ }
3952
3974
  }
3953
3975
  return {
3954
3976
  graph,
@@ -4186,9 +4208,15 @@ async function snapshotProjectStatus(restPort, project, body) {
4186
4208
  }
4187
4209
  return [{ name: project, status: await probeProjectHealth(restPort, project) }];
4188
4210
  }
4189
- async function waitForDaemonReady(restPort, project, timeoutMs) {
4190
- const deadline = Date.now() + timeoutMs;
4191
- let lastBootstrapping = [];
4211
+ var STILL_WAITING_INTERVAL_MS = 1e4;
4212
+ function daemonProgressLine(project, event) {
4213
+ if (event.kind === "starting") return `starting the daemon for ${project}\u2026`;
4214
+ return `still waiting for ${project}'s daemon (${Math.round(event.elapsedMs / 1e3)}s)`;
4215
+ }
4216
+ async function waitForDaemonReady(restPort, project, timeoutMs, onProgress, reminderIntervalMs = STILL_WAITING_INTERVAL_MS) {
4217
+ const startedAt = Date.now();
4218
+ const deadline = startedAt + timeoutMs;
4219
+ let nextReminderAt = startedAt + reminderIntervalMs;
4192
4220
  while (Date.now() < deadline) {
4193
4221
  const body = await fetchDaemonHealth(restPort);
4194
4222
  if (body !== null) {
@@ -4198,15 +4226,10 @@ async function waitForDaemonReady(restPort, project, timeoutMs) {
4198
4226
  if (bootstrapping.length === 0) {
4199
4227
  return { ready: true, brokenProjects: broken, stillBootstrapping: [] };
4200
4228
  }
4201
- const key = bootstrapping.slice().sort().join(",");
4202
- const prevKey = lastBootstrapping.slice().sort().join(",");
4203
- if (key !== prevKey) {
4204
- const plural = bootstrapping.length === 1 ? "" : "s";
4205
- console.log(
4206
- `neat: waiting on ${bootstrapping.length} project${plural}: ${bootstrapping.join(", ")}`
4207
- );
4208
- lastBootstrapping = bootstrapping;
4209
- }
4229
+ }
4230
+ if (Date.now() >= nextReminderAt) {
4231
+ onProgress?.({ kind: "waiting", elapsedMs: Date.now() - startedAt });
4232
+ nextReminderAt += reminderIntervalMs;
4210
4233
  }
4211
4234
  await new Promise((r) => setTimeout(r, PROBE_INTERVAL_MS));
4212
4235
  }
@@ -4331,6 +4354,16 @@ async function healthIsForProject(restPort, project) {
4331
4354
  function daemonLogPath(projectPath3) {
4332
4355
  return path10.join(projectPath3, "neat-out", "daemon.log");
4333
4356
  }
4357
+ var DAEMON_LOG_TAIL_LINES = 12;
4358
+ async function readDaemonLogTail(projectPath3, maxLines = DAEMON_LOG_TAIL_LINES) {
4359
+ try {
4360
+ const raw = await fs9.readFile(daemonLogPath(projectPath3), "utf8");
4361
+ const lines = raw.split(/\r?\n/).map((l) => l.trimEnd()).filter((l) => l.trim().length > 0);
4362
+ return lines.slice(-maxLines);
4363
+ } catch {
4364
+ return [];
4365
+ }
4366
+ }
4334
4367
  function spawnDaemonDetached(spec) {
4335
4368
  const here = path10.dirname(fileURLToPath2(import.meta.url));
4336
4369
  const candidates = [
@@ -4377,6 +4410,73 @@ function spawnDaemonDetached(spec) {
4377
4410
  if (logFd !== null) fsSync.closeSync(logFd);
4378
4411
  return child;
4379
4412
  }
4413
+ async function ensureProjectDaemon(opts) {
4414
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS;
4415
+ const bindHost = resolveHost(
4416
+ {},
4417
+ typeof process.env.NEAT_AUTH_TOKEN === "string" && process.env.NEAT_AUTH_TOKEN.length > 0
4418
+ );
4419
+ const persistedPorts = await persistedPortsFor(opts.projectPath);
4420
+ if (persistedPorts && await healthIsForProject(persistedPorts.rest, opts.project)) {
4421
+ return { status: "already-running", ports: persistedPorts };
4422
+ }
4423
+ let allocated;
4424
+ if (persistedPorts && await isPortFree(persistedPorts.rest, bindHost) && await tripleFree(persistedPorts, bindHost)) {
4425
+ allocated = persistedPorts;
4426
+ } else {
4427
+ allocated = await allocatePorts(bindHost);
4428
+ }
4429
+ if (!allocated) return { status: "no-ports" };
4430
+ const release = await acquireSpawnLock(opts.projectPath);
4431
+ if (!release) {
4432
+ const reused = await waitForPeerDaemon(allocated.rest, opts.project, timeoutMs);
4433
+ return reused ? { status: "already-running", ports: allocated } : { status: "peer-timeout" };
4434
+ }
4435
+ try {
4436
+ if (await healthIsForProject(allocated.rest, opts.project)) {
4437
+ return { status: "already-running", ports: allocated };
4438
+ }
4439
+ spawnDaemonDetached({
4440
+ project: opts.project,
4441
+ projectPath: opts.projectPath,
4442
+ ports: allocated
4443
+ });
4444
+ opts.onProgress?.({ kind: "starting" });
4445
+ const ready = await waitForDaemonReady(allocated.rest, opts.project, timeoutMs, opts.onProgress);
4446
+ if (!ready.ready) {
4447
+ return {
4448
+ status: "timed-out",
4449
+ ports: allocated,
4450
+ stillBootstrapping: ready.stillBootstrapping,
4451
+ brokenProjects: ready.brokenProjects
4452
+ };
4453
+ }
4454
+ return { status: "spawned", ports: allocated, brokenProjects: ready.brokenProjects };
4455
+ } catch (err) {
4456
+ return { status: "spawn-failed", message: err.message };
4457
+ } finally {
4458
+ await release();
4459
+ }
4460
+ }
4461
+ async function describeDaemonTimeout(outcome, projectPath3, timeoutMs) {
4462
+ const lines = [`neat: daemon did not become ready within ${timeoutMs}ms`];
4463
+ if (outcome.stillBootstrapping.length > 0) {
4464
+ lines.push(`neat: still bootstrapping: ${outcome.stillBootstrapping.join(", ")}`);
4465
+ }
4466
+ if (outcome.brokenProjects.length > 0) {
4467
+ lines.push(`neat: broken projects: ${outcome.brokenProjects.join(", ")}`);
4468
+ }
4469
+ const logPath = daemonLogPath(projectPath3);
4470
+ const tail = await readDaemonLogTail(projectPath3);
4471
+ if (tail.length > 0) {
4472
+ lines.push("");
4473
+ lines.push(`neat: the daemon's last words (${path10.relative(projectPath3, logPath)}):`);
4474
+ for (const line of tail) lines.push(` ${line}`);
4475
+ } else {
4476
+ lines.push(`neat: see ${logPath}`);
4477
+ }
4478
+ return lines;
4479
+ }
4380
4480
  function openBrowser(url) {
4381
4481
  if (!process.stdout.isTTY) return "failed";
4382
4482
  const platform = process.platform;
@@ -4410,14 +4510,26 @@ async function runOrchestrator(opts) {
4410
4510
  result.exitCode = 2;
4411
4511
  return result;
4412
4512
  }
4413
- printBanner();
4513
+ if (!opts.skipBanner) printBanner();
4414
4514
  console.log(`neat: ${opts.scanPath}`);
4415
4515
  console.log("");
4416
- const persisted = await extractAndPersist({
4417
- scanPath: opts.scanPath,
4418
- project: opts.project,
4419
- projectExplicit: opts.projectExplicit
4420
- });
4516
+ let persisted;
4517
+ try {
4518
+ persisted = await extractAndPersist({
4519
+ scanPath: opts.scanPath,
4520
+ project: opts.project,
4521
+ projectExplicit: opts.projectExplicit
4522
+ });
4523
+ } catch (err) {
4524
+ if (!(err instanceof SnapshotWriteError)) throw err;
4525
+ console.error(`neat: extracted ${opts.scanPath}, but could not write the snapshot.`);
4526
+ console.error(`neat: the graph came to ${err.nodeCount} nodes and ${err.edgeCount} edges \u2014 too large to save.`);
4527
+ console.error(`neat: point neat at one project instead of a tree that holds many:`);
4528
+ console.error(`neat: npx neat.is <path-to-one-project>`);
4529
+ console.error(`neat: cause: ${err.cause.message}`);
4530
+ result.exitCode = 1;
4531
+ return result;
4532
+ }
4421
4533
  const { graph, services, languages } = persisted;
4422
4534
  result.steps.discovery = { services: services.length, languages };
4423
4535
  console.log(`discovered ${services.length} service(s) across ${languages.length} language(s)`);
@@ -4458,20 +4570,6 @@ async function runOrchestrator(opts) {
4458
4570
  result.exitCode = 1;
4459
4571
  return result;
4460
4572
  }
4461
- const siblings = await listProjects();
4462
- const paused = [];
4463
- for (const p of siblings) {
4464
- if (p.name !== currentProjectName && p.status === "active") {
4465
- await setStatus(p.name, "paused");
4466
- paused.push(p.name);
4467
- }
4468
- }
4469
- if (paused.length > 0) {
4470
- const plural = paused.length === 1 ? "" : "s";
4471
- console.log(
4472
- `neat: paused ${paused.length} sibling project${plural}; run \`neat resume <name>\` to bring one back active.`
4473
- );
4474
- }
4475
4573
  if (!runApply) {
4476
4574
  result.steps.apply.skipped = true;
4477
4575
  console.log("skipped instrumentation (--no-instrument)");
@@ -4487,75 +4585,46 @@ async function runOrchestrator(opts) {
4487
4585
  }
4488
4586
  }
4489
4587
  const timeoutMs = opts.daemonReadyTimeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS;
4490
- const bindHost = resolveHost(
4491
- {},
4492
- typeof process.env.NEAT_AUTH_TOKEN === "string" && process.env.NEAT_AUTH_TOKEN.length > 0
4493
- );
4494
- const persistedPorts = await persistedPortsFor(opts.scanPath);
4495
- let allocated = null;
4496
- if (persistedPorts && await healthIsForProject(persistedPorts.rest, currentProjectName)) {
4497
- result.steps.daemon = "already-running";
4498
- allocated = persistedPorts;
4499
- } else {
4500
- if (persistedPorts && await isPortFree(persistedPorts.rest, bindHost) && await tripleFree(persistedPorts, bindHost)) {
4501
- allocated = persistedPorts;
4502
- } else {
4503
- allocated = await allocatePorts(bindHost);
4504
- }
4505
- if (!allocated) {
4588
+ const outcome = await ensureProjectDaemon({
4589
+ project: currentProjectName,
4590
+ projectPath: opts.scanPath,
4591
+ timeoutMs,
4592
+ onProgress: (event) => console.log(`neat: ${daemonProgressLine(currentProjectName, event)}`)
4593
+ });
4594
+ const allocated = "ports" in outcome ? outcome.ports : null;
4595
+ switch (outcome.status) {
4596
+ case "already-running":
4597
+ result.steps.daemon = "already-running";
4598
+ break;
4599
+ case "spawned":
4600
+ result.steps.daemon = "spawned";
4601
+ if (outcome.brokenProjects.length > 0) {
4602
+ console.warn(
4603
+ `neat: ${outcome.brokenProjects.length} project(s) reported broken: ${outcome.brokenProjects.join(", ")}`
4604
+ );
4605
+ }
4606
+ break;
4607
+ case "no-ports":
4506
4608
  for (const line of formatPortCollisionMessage(NEAT_PORTS[0])) {
4507
4609
  console.error(line);
4508
4610
  }
4509
4611
  result.exitCode = 3;
4510
4612
  return result;
4511
- }
4512
- const release = await acquireSpawnLock(opts.scanPath);
4513
- if (!release) {
4514
- const reused = await waitForPeerDaemon(allocated.rest, currentProjectName, timeoutMs);
4515
- if (reused) {
4516
- result.steps.daemon = "already-running";
4517
- } else {
4518
- console.error("neat: another `neat` is spawning this project but its daemon did not come up in time");
4519
- result.exitCode = 1;
4520
- return result;
4521
- }
4522
- } else {
4523
- try {
4524
- if (await healthIsForProject(allocated.rest, currentProjectName)) {
4525
- result.steps.daemon = "already-running";
4526
- } else {
4527
- spawnDaemonDetached({
4528
- project: currentProjectName,
4529
- projectPath: opts.scanPath,
4530
- ports: allocated
4531
- });
4532
- const ready = await waitForDaemonReady(allocated.rest, currentProjectName, timeoutMs);
4533
- result.steps.daemon = ready.ready ? "spawned" : "timed-out";
4534
- if (!ready.ready) {
4535
- console.error(`neat: daemon did not become ready within ${timeoutMs}ms`);
4536
- if (ready.stillBootstrapping.length > 0) {
4537
- console.error(`neat: still bootstrapping: ${ready.stillBootstrapping.join(", ")}`);
4538
- }
4539
- if (ready.brokenProjects.length > 0) {
4540
- console.error(`neat: broken projects: ${ready.brokenProjects.join(", ")}`);
4541
- }
4542
- result.exitCode = 1;
4543
- return result;
4544
- }
4545
- if (ready.brokenProjects.length > 0) {
4546
- console.warn(
4547
- `neat: ${ready.brokenProjects.length} project(s) reported broken: ${ready.brokenProjects.join(", ")}`
4548
- );
4549
- }
4550
- }
4551
- } catch (err) {
4552
- console.error(`neat: daemon spawn failed \u2014 ${err.message}`);
4553
- result.exitCode = 1;
4554
- return result;
4555
- } finally {
4556
- await release();
4613
+ case "timed-out":
4614
+ result.steps.daemon = "timed-out";
4615
+ for (const line of await describeDaemonTimeout(outcome, opts.scanPath, timeoutMs)) {
4616
+ console.error(line);
4557
4617
  }
4558
- }
4618
+ result.exitCode = 1;
4619
+ return result;
4620
+ case "peer-timeout":
4621
+ console.error("neat: another `neat` is spawning this project but its daemon did not come up in time");
4622
+ result.exitCode = 1;
4623
+ return result;
4624
+ case "spawn-failed":
4625
+ console.error(`neat: daemon spawn failed \u2014 ${outcome.message}`);
4626
+ result.exitCode = 1;
4627
+ return result;
4559
4628
  }
4560
4629
  const webPort = allocated?.web ?? NEAT_PORTS[2];
4561
4630
  const dashboardUrl = opts.dashboardUrl ?? `http://localhost:${webPort}`;
@@ -5335,9 +5404,9 @@ function parseGitHubRemote(url) {
5335
5404
  if (!owner || !name) return null;
5336
5405
  return { owner, name };
5337
5406
  }
5338
- async function cpGetJson(fetchImpl, cpUrl, path21, accessToken) {
5407
+ async function cpGetJson(fetchImpl, cpUrl, path22, accessToken) {
5339
5408
  try {
5340
- const res = await fetchImpl(`${cpUrl}${path21}`, {
5409
+ const res = await fetchImpl(`${cpUrl}${path22}`, {
5341
5410
  headers: { authorization: `Bearer ${accessToken}`, accept: "application/json" },
5342
5411
  signal: AbortSignal.timeout(CP_TIMEOUT_MS)
5343
5412
  });
@@ -5815,10 +5884,10 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
5815
5884
  const root = baseUrl.replace(/\/$/, "");
5816
5885
  const authHeader = bearerToken && bearerToken.length > 0 ? { authorization: `Bearer ${bearerToken}` } : {};
5817
5886
  return {
5818
- async get(path21) {
5887
+ async get(path22) {
5819
5888
  let res;
5820
5889
  try {
5821
- res = await fetchImpl(`${root}${path21}`, {
5890
+ res = await fetchImpl(`${root}${path22}`, {
5822
5891
  headers: { ...authHeader }
5823
5892
  });
5824
5893
  } catch (err) {
@@ -5830,16 +5899,16 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
5830
5899
  const body = await res.text().catch(() => "");
5831
5900
  throw new HttpError(
5832
5901
  res.status,
5833
- `${res.status} ${res.statusText} on GET ${path21}: ${body}`,
5902
+ `${res.status} ${res.statusText} on GET ${path22}: ${body}`,
5834
5903
  body
5835
5904
  );
5836
5905
  }
5837
5906
  return await res.json();
5838
5907
  },
5839
- async post(path21, body) {
5908
+ async post(path22, body) {
5840
5909
  let res;
5841
5910
  try {
5842
- res = await fetchImpl(`${root}${path21}`, {
5911
+ res = await fetchImpl(`${root}${path22}`, {
5843
5912
  method: "POST",
5844
5913
  headers: { "content-type": "application/json", ...authHeader },
5845
5914
  body: JSON.stringify(body)
@@ -5853,7 +5922,7 @@ function createHttpClient(baseUrl, bearerToken, fetchImpl = fetch) {
5853
5922
  const text = await res.text().catch(() => "");
5854
5923
  throw new HttpError(
5855
5924
  res.status,
5856
- `${res.status} ${res.statusText} on POST ${path21}: ${text}`,
5925
+ `${res.status} ${res.statusText} on POST ${path22}: ${text}`,
5857
5926
  text
5858
5927
  );
5859
5928
  }
@@ -5867,12 +5936,12 @@ function projectPath(project, suffix) {
5867
5936
  }
5868
5937
  async function runRootCause(client, input) {
5869
5938
  const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : "";
5870
- const path21 = projectPath(
5939
+ const path22 = projectPath(
5871
5940
  input.project,
5872
5941
  `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`
5873
5942
  );
5874
5943
  try {
5875
- const result = await client.get(path21);
5944
+ const result = await client.get(path22);
5876
5945
  const arrowPath = result.traversalPath.join(" \u2190 ");
5877
5946
  const provenances = result.edgeProvenances.length ? result.edgeProvenances.join(", ") : "(direct, no edges traversed)";
5878
5947
  const summary = `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` + result.rootCauseReason + (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : "");
@@ -5898,12 +5967,12 @@ async function runRootCause(client, input) {
5898
5967
  }
5899
5968
  async function runBlastRadius(client, input) {
5900
5969
  const qs = input.depth !== void 0 ? `?depth=${input.depth}` : "";
5901
- const path21 = projectPath(
5970
+ const path22 = projectPath(
5902
5971
  input.project,
5903
5972
  `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`
5904
5973
  );
5905
5974
  try {
5906
- const result = await client.get(path21);
5975
+ const result = await client.get(path22);
5907
5976
  if (result.totalAffected === 0) {
5908
5977
  return {
5909
5978
  summary: `${result.origin} has no dependents. Nothing else would break if it failed.`
@@ -5937,12 +6006,12 @@ function formatBlastEntry(n) {
5937
6006
  }
5938
6007
  async function runDependencies(client, input) {
5939
6008
  const depth = input.depth ?? 3;
5940
- const path21 = projectPath(
6009
+ const path22 = projectPath(
5941
6010
  input.project,
5942
6011
  `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`
5943
6012
  );
5944
6013
  try {
5945
- const result = await client.get(path21);
6014
+ const result = await client.get(path22);
5946
6015
  if (result.total === 0) {
5947
6016
  return {
5948
6017
  summary: depth === 1 ? `${input.nodeId} has no direct dependencies in the graph.` : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`
@@ -6034,9 +6103,9 @@ function formatDuration(ms) {
6034
6103
  return `${Math.round(h / 24)}d`;
6035
6104
  }
6036
6105
  async function runIncidents(client, input) {
6037
- const path21 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
6106
+ const path22 = input.nodeId ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`) : projectPath(input.project, "/incidents");
6038
6107
  try {
6039
- const body = await client.get(path21);
6108
+ const body = await client.get(path22);
6040
6109
  const events = body.events;
6041
6110
  if (events.length === 0) {
6042
6111
  return {
@@ -6517,6 +6586,122 @@ async function runDoctorCommand(argv, deps = {}) {
6517
6586
  return checks.every((c) => c.ok) ? 0 : 1;
6518
6587
  }
6519
6588
 
6589
+ // src/up-cli.ts
6590
+ import path14 from "path";
6591
+ function parseUpArgs(argv, env) {
6592
+ const args = { json: false, help: false };
6593
+ for (let i = 0; i < argv.length; i++) {
6594
+ const a = argv[i];
6595
+ if (a === "--json") args.json = true;
6596
+ else if (a === "-h" || a === "--help") args.help = true;
6597
+ else if (a === "--project") args.project = argv[++i];
6598
+ else if (a.startsWith("--project=")) args.project = a.slice("--project=".length);
6599
+ else if (a === "--profile") args.profile = argv[++i];
6600
+ else if (a.startsWith("--profile=")) args.profile = a.slice("--profile=".length);
6601
+ else if (args.unknown === void 0) args.unknown = a;
6602
+ }
6603
+ if (!args.project && env.NEAT_PROJECT && env.NEAT_PROJECT.length > 0) args.project = env.NEAT_PROJECT;
6604
+ return args;
6605
+ }
6606
+ var USAGE = [
6607
+ "usage: neat up [--project <name>] [--json]",
6608
+ "",
6609
+ "Start this project's daemon, or recover it if it died. Does nothing when it is",
6610
+ "already running. Extracts and instruments nothing \u2014 run `neat` for that."
6611
+ ];
6612
+ async function runUpCommand(argv, deps) {
6613
+ const cwd = deps.cwd ?? process.cwd();
6614
+ const env = deps.env ?? process.env;
6615
+ const out = deps.out ?? ((line) => console.log(line));
6616
+ const err = deps.err ?? ((line) => console.error(line));
6617
+ const ensure = deps.ensureDaemon ?? ensureProjectDaemon;
6618
+ const args = parseUpArgs(argv, env);
6619
+ if (args.help) {
6620
+ for (const line of USAGE) out(line);
6621
+ return 0;
6622
+ }
6623
+ if (args.unknown !== void 0) {
6624
+ err(`neat up: unexpected argument \`${args.unknown}\``);
6625
+ for (const line of USAGE) err(line);
6626
+ return 2;
6627
+ }
6628
+ let entry2;
6629
+ try {
6630
+ entry2 = args.project ? await getProject(args.project) : await findProjectByPath(cwd);
6631
+ } catch {
6632
+ entry2 = void 0;
6633
+ }
6634
+ if (!entry2) {
6635
+ err(
6636
+ args.project ? `neat up: no project named "${args.project}" is registered on this machine \u2014 \`neat list\` shows what is.` : "neat up: This directory isn't a NEAT project yet \u2014 run `npx neat.is` here first, or pass --project <name>."
6637
+ );
6638
+ return 2;
6639
+ }
6640
+ let target;
6641
+ try {
6642
+ target = await deps.resolveTarget({ project: entry2.name, profile: args.profile });
6643
+ } catch (e) {
6644
+ err(`neat up: ${e.message}`);
6645
+ return 2;
6646
+ }
6647
+ if (!target.local) {
6648
+ err(`neat up: queries from here go to ${target.endpoint}, through ${target.via}.`);
6649
+ err("neat up: that daemon doesn't run on this machine, so it isn't yours to start.");
6650
+ return 2;
6651
+ }
6652
+ const project = entry2.name;
6653
+ const outcome = await ensure({
6654
+ project,
6655
+ projectPath: entry2.path,
6656
+ // `--json` prints one object and nothing else, so progress stays quiet there.
6657
+ ...args.json ? {} : { onProgress: (event) => out(`neat up: ${daemonProgressLine(project, event)}`) }
6658
+ });
6659
+ const log = daemonLogPath(entry2.path);
6660
+ if (args.json) {
6661
+ const ports = "ports" in outcome ? outcome.ports : void 0;
6662
+ out(
6663
+ JSON.stringify({
6664
+ project: entry2.name,
6665
+ path: entry2.path,
6666
+ status: outcome.status,
6667
+ ...ports ? { endpoint: `http://localhost:${ports.rest}`, ports } : {},
6668
+ ...outcome.status === "spawn-failed" ? { error: outcome.message } : {},
6669
+ log
6670
+ })
6671
+ );
6672
+ }
6673
+ switch (outcome.status) {
6674
+ case "already-running":
6675
+ if (!args.json) {
6676
+ out(`neat up: ${entry2.name} is already running \u2014 http://localhost:${outcome.ports.rest}`);
6677
+ }
6678
+ return 0;
6679
+ case "spawned":
6680
+ if (!args.json) {
6681
+ out(`neat up: started ${entry2.name} \u2014 http://localhost:${outcome.ports.rest}`);
6682
+ out(`neat up: traces on :${outcome.ports.otlp}, log at ${path14.relative(cwd, log) || log}`);
6683
+ }
6684
+ return 0;
6685
+ case "timed-out":
6686
+ if (!args.json) {
6687
+ for (const line of await describeDaemonTimeout(outcome, entry2.path, DEFAULT_DAEMON_READY_TIMEOUT_MS)) err(line);
6688
+ }
6689
+ return 1;
6690
+ case "peer-timeout":
6691
+ if (!args.json) {
6692
+ err("neat up: another `neat` is starting this project, and its daemon did not come up in time.");
6693
+ err(`neat up: see ${log}`);
6694
+ }
6695
+ return 1;
6696
+ case "spawn-failed":
6697
+ if (!args.json) err(`neat up: could not start the daemon \u2014 ${outcome.message}`);
6698
+ return 1;
6699
+ case "no-ports":
6700
+ if (!args.json) for (const line of formatPortCollisionMessage(NEAT_PORTS[0])) err(line);
6701
+ return 3;
6702
+ }
6703
+ }
6704
+
6520
6705
  // src/login-cli.ts
6521
6706
  import readline3 from "readline/promises";
6522
6707
  var DEFAULT_PROFILE_NAME = "hosted";
@@ -6778,7 +6963,7 @@ async function defaultReadSecret(prompt) {
6778
6963
 
6779
6964
  // src/welcome.ts
6780
6965
  import { promises as fs13 } from "fs";
6781
- import path14 from "path";
6966
+ import path15 from "path";
6782
6967
  import readline4 from "readline/promises";
6783
6968
  var WORDMARK = [
6784
6969
  "\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
@@ -6966,10 +7151,11 @@ async function runSelfHosted(out, readLine, orchestrator, cwd, readRegistry2, in
6966
7151
  out("Building your local graph now\u2026");
6967
7152
  out("");
6968
7153
  const overrides = {
7154
+ headerShown: true,
6969
7155
  ...project !== void 0 ? { project } : {},
6970
7156
  ...declined === void 0 ? {} : declined ? { noInstrument: true } : { yes: true }
6971
7157
  };
6972
- return orchestrator(cwd, Object.keys(overrides).length > 0 ? overrides : void 0);
7158
+ return orchestrator(cwd, overrides);
6973
7159
  }
6974
7160
  async function askToInstrument(out, readLine) {
6975
7161
  out("Instrument the services for OpenTelemetry now?");
@@ -6985,8 +7171,8 @@ async function askToInstrument(out, readLine) {
6985
7171
  return declined;
6986
7172
  }
6987
7173
  async function resolveProjectName(out, readLine, cwd, readRegistry2) {
6988
- const here = path14.resolve(cwd);
6989
- const base = path14.basename(here);
7174
+ const here = path15.resolve(cwd);
7175
+ const base = path15.basename(here);
6990
7176
  let taken;
6991
7177
  try {
6992
7178
  const { projects } = await readRegistry2();
@@ -6995,7 +7181,7 @@ async function resolveProjectName(out, readLine, cwd, readRegistry2) {
6995
7181
  return void 0;
6996
7182
  }
6997
7183
  const clash = taken.get(base);
6998
- if (clash === void 0 || path14.resolve(clash) === here) return void 0;
7184
+ if (clash === void 0 || path15.resolve(clash) === here) return void 0;
6999
7185
  out("");
7000
7186
  out(`A project named \`${base}\` is already registered (${clash}).`);
7001
7187
  const suggested = firstFreeName(base, taken);
@@ -7008,7 +7194,7 @@ async function resolveProjectName(out, readLine, cwd, readRegistry2) {
7008
7194
  continue;
7009
7195
  }
7010
7196
  const other = taken.get(chosen);
7011
- if (other !== void 0 && path14.resolve(other) !== here) {
7197
+ if (other !== void 0 && path15.resolve(other) !== here) {
7012
7198
  out(`\`${chosen}\` is registered too (${other}).`);
7013
7199
  continue;
7014
7200
  }
@@ -7033,9 +7219,9 @@ async function shouldShowWelcome(deps = {}) {
7033
7219
  const readRegistry2 = deps.readRegistry ?? (() => readRegistry());
7034
7220
  const hasSnapshot = deps.hasSnapshot ?? defaultHasSnapshot;
7035
7221
  try {
7036
- const here = path14.resolve(cwd);
7222
+ const here = path15.resolve(cwd);
7037
7223
  const { projects } = await readRegistry2();
7038
- if (projects.some((p) => path14.resolve(p.path) === here)) return false;
7224
+ if (projects.some((p) => path15.resolve(p.path) === here)) return false;
7039
7225
  if (await hasSnapshot(here)) return false;
7040
7226
  return true;
7041
7227
  } catch {
@@ -7044,7 +7230,7 @@ async function shouldShowWelcome(deps = {}) {
7044
7230
  }
7045
7231
  async function defaultHasSnapshot(cwd) {
7046
7232
  try {
7047
- const entries = await fs13.readdir(path14.join(cwd, "neat-out"));
7233
+ const entries = await fs13.readdir(path15.join(cwd, "neat-out"));
7048
7234
  return entries.some((e) => e.endsWith(".json"));
7049
7235
  } catch {
7050
7236
  return false;
@@ -7061,7 +7247,7 @@ async function defaultReadLine2(prompt) {
7061
7247
  }
7062
7248
 
7063
7249
  // src/hooks-cli.ts
7064
- import path15 from "path";
7250
+ import path16 from "path";
7065
7251
  import os2 from "os";
7066
7252
  import { promises as fs14 } from "fs";
7067
7253
  import { fileURLToPath as fileURLToPath3 } from "url";
@@ -7070,14 +7256,14 @@ var GUIDE_FILENAME = "GRAPH_FIRST.md";
7070
7256
  var GUIDE_INSTALL_NAME = "neat-graph-first.md";
7071
7257
  var HOOK_MATCHER = "Grep|Glob|Bash";
7072
7258
  function moduleDir() {
7073
- return typeof __dirname !== "undefined" ? __dirname : path15.dirname(fileURLToPath3(import.meta.url));
7259
+ return typeof __dirname !== "undefined" ? __dirname : path16.dirname(fileURLToPath3(import.meta.url));
7074
7260
  }
7075
7261
  async function readSkillAsset(rel) {
7076
7262
  const here = moduleDir();
7077
7263
  const candidates = [
7078
- path15.resolve(here, "../../claude-skill", rel),
7079
- path15.resolve(here, "../../../claude-skill", rel),
7080
- path15.resolve(here, "../claude-skill", rel)
7264
+ path16.resolve(here, "../../claude-skill", rel),
7265
+ path16.resolve(here, "../../../claude-skill", rel),
7266
+ path16.resolve(here, "../claude-skill", rel)
7081
7267
  ];
7082
7268
  for (const candidate of candidates) {
7083
7269
  try {
@@ -7091,20 +7277,20 @@ async function readSkillAsset(rel) {
7091
7277
  }
7092
7278
  function neatHome2() {
7093
7279
  const override = process.env.NEAT_HOME;
7094
- if (override && override.length > 0) return path15.resolve(override);
7095
- return path15.join(os2.homedir(), ".neat");
7280
+ if (override && override.length > 0) return path16.resolve(override);
7281
+ return path16.join(os2.homedir(), ".neat");
7096
7282
  }
7097
7283
  function claudeSettingsPath() {
7098
7284
  const override = process.env.NEAT_CLAUDE_SETTINGS;
7099
- if (override && override.length > 0) return path15.resolve(override);
7285
+ if (override && override.length > 0) return path16.resolve(override);
7100
7286
  const home = process.env.HOME ?? process.env.USERPROFILE ?? os2.homedir();
7101
- return path15.join(home, ".claude", "settings.json");
7287
+ return path16.join(home, ".claude", "settings.json");
7102
7288
  }
7103
7289
  function installedHookPath() {
7104
- return path15.join(neatHome2(), "hooks", HOOK_FILENAME);
7290
+ return path16.join(neatHome2(), "hooks", HOOK_FILENAME);
7105
7291
  }
7106
7292
  function gateFlagPath() {
7107
- return path15.join(neatHome2(), "hooks", "gate-enabled");
7293
+ return path16.join(neatHome2(), "hooks", "gate-enabled");
7108
7294
  }
7109
7295
  function isNeatSearchEntry(entry2) {
7110
7296
  return (entry2.hooks ?? []).some(
@@ -7137,9 +7323,9 @@ async function runHooks(opts) {
7137
7323
  const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`);
7138
7324
  const guide = await readSkillAsset(GUIDE_FILENAME);
7139
7325
  const scriptPath = installedHookPath();
7140
- await fs14.mkdir(path15.dirname(scriptPath), { recursive: true });
7326
+ await fs14.mkdir(path16.dirname(scriptPath), { recursive: true });
7141
7327
  await fs14.writeFile(scriptPath, hookScript, { mode: 493 });
7142
- const guidePath = path15.join(neatHome2(), GUIDE_INSTALL_NAME);
7328
+ const guidePath = path16.join(neatHome2(), GUIDE_INSTALL_NAME);
7143
7329
  await fs14.writeFile(guidePath, guide, "utf8");
7144
7330
  const settingsFile = claudeSettingsPath();
7145
7331
  let settings = {};
@@ -7166,11 +7352,11 @@ async function runHooks(opts) {
7166
7352
  ...settings,
7167
7353
  hooks: { ...hooks, PreToolUse: preToolUse }
7168
7354
  };
7169
- await fs14.mkdir(path15.dirname(settingsFile), { recursive: true });
7355
+ await fs14.mkdir(path16.dirname(settingsFile), { recursive: true });
7170
7356
  await fs14.writeFile(settingsFile, JSON.stringify(merged, null, 2) + "\n", "utf8");
7171
7357
  const flag = gateFlagPath();
7172
7358
  if (opts.gate) {
7173
- await fs14.mkdir(path15.dirname(flag), { recursive: true });
7359
+ await fs14.mkdir(path16.dirname(flag), { recursive: true });
7174
7360
  await fs14.writeFile(flag, "1\n", "utf8");
7175
7361
  } else {
7176
7362
  await fs14.rm(flag, { force: true });
@@ -7262,7 +7448,7 @@ async function runHooksCommand(args) {
7262
7448
  }
7263
7449
 
7264
7450
  // src/claude-cli.ts
7265
- import path16 from "path";
7451
+ import path17 from "path";
7266
7452
  import { promises as fs15 } from "fs";
7267
7453
  var NEAT_SECTION_HEADING = "## neat";
7268
7454
  var NEAT_DIRECTIVE_BODY = `This project has NEAT wired in: a live, fused semantic graph of the system \u2014
@@ -7297,8 +7483,8 @@ ${NEAT_DIRECTIVE_BODY}
7297
7483
  }
7298
7484
  function claudeMdPath() {
7299
7485
  const override = process.env.NEAT_CLAUDE_MD;
7300
- if (override && override.length > 0) return path16.resolve(override);
7301
- return path16.join(process.cwd(), "CLAUDE.md");
7486
+ if (override && override.length > 0) return path17.resolve(override);
7487
+ return path17.join(process.cwd(), "CLAUDE.md");
7302
7488
  }
7303
7489
  function splitAroundSection(raw) {
7304
7490
  const lines = raw.split("\n");
@@ -7337,7 +7523,7 @@ async function runInstall() {
7337
7523
  const raw = await readIfExists(file) ?? "";
7338
7524
  const { before, after, found } = splitAroundSection(raw);
7339
7525
  const next = compose(before, after);
7340
- await fs15.mkdir(path16.dirname(file), { recursive: true });
7526
+ await fs15.mkdir(path17.dirname(file), { recursive: true });
7341
7527
  await fs15.writeFile(file, next, "utf8");
7342
7528
  const verb = raw.length === 0 ? "created" : found ? "refreshed" : "added";
7343
7529
  console.log(`neat claude: ${verb} the \`${NEAT_SECTION_HEADING}\` section in ${file}`);
@@ -7401,7 +7587,7 @@ async function runClaudeCommand(args) {
7401
7587
  }
7402
7588
 
7403
7589
  // src/codex-cli.ts
7404
- import path17 from "path";
7590
+ import path18 from "path";
7405
7591
  import os3 from "os";
7406
7592
  import { promises as fs16 } from "fs";
7407
7593
  import { isDeepStrictEqual } from "util";
@@ -7421,14 +7607,14 @@ var NEAT_GRAPH_FIRST_START = "<!-- neat:graph-first -->";
7421
7607
  var NEAT_GRAPH_FIRST_END = "<!-- /neat:graph-first -->";
7422
7608
  function codexConfigPath() {
7423
7609
  const override = process.env.NEAT_CODEX_CONFIG;
7424
- if (override && override.length > 0) return path17.resolve(override);
7610
+ if (override && override.length > 0) return path18.resolve(override);
7425
7611
  const home = process.env.HOME ?? process.env.USERPROFILE ?? os3.homedir();
7426
- return path17.join(home, ".codex", "config.toml");
7612
+ return path18.join(home, ".codex", "config.toml");
7427
7613
  }
7428
7614
  function agentsFilePath() {
7429
7615
  const override = process.env.NEAT_CODEX_AGENTS;
7430
- if (override && override.length > 0) return path17.resolve(override);
7431
- return path17.join(process.cwd(), "AGENTS.md");
7616
+ if (override && override.length > 0) return path18.resolve(override);
7617
+ return path18.join(process.cwd(), "AGENTS.md");
7432
7618
  }
7433
7619
  function isTableHeader(line) {
7434
7620
  return /^\s*\[\[?[^\]]+\]\]?\s*$/.test(line);
@@ -7611,14 +7797,14 @@ async function runCodex(opts) {
7611
7797
  return { exitCode: 0 };
7612
7798
  }
7613
7799
  if (config.changed) {
7614
- await fs16.mkdir(path17.dirname(configPath), { recursive: true });
7800
+ await fs16.mkdir(path18.dirname(configPath), { recursive: true });
7615
7801
  await fs16.writeFile(configPath, config.text, "utf8");
7616
7802
  console.log(`neat codex: wrote [mcp_servers.neat] to ${configPath}`);
7617
7803
  } else {
7618
7804
  console.log(`neat codex: ${configPath} already has NEAT's MCP server`);
7619
7805
  }
7620
7806
  if (agents.changed) {
7621
- await fs16.mkdir(path17.dirname(agentsPath), { recursive: true });
7807
+ await fs16.mkdir(path18.dirname(agentsPath), { recursive: true });
7622
7808
  await fs16.writeFile(agentsPath, agents.text, "utf8");
7623
7809
  console.log(`neat codex: wrote the graph-first block to ${agentsPath}`);
7624
7810
  } else {
@@ -7675,7 +7861,7 @@ async function runCodexCommand(args) {
7675
7861
  }
7676
7862
 
7677
7863
  // src/editors-cli.ts
7678
- import path18 from "path";
7864
+ import path19 from "path";
7679
7865
  import os4 from "os";
7680
7866
  import { promises as fs17 } from "fs";
7681
7867
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
@@ -7701,17 +7887,17 @@ function homeDir() {
7701
7887
  }
7702
7888
  function xdgConfigDir() {
7703
7889
  const xdg = process.env.XDG_CONFIG_HOME;
7704
- return xdg && xdg.length > 0 ? path18.resolve(xdg) : path18.join(homeDir(), ".config");
7890
+ return xdg && xdg.length > 0 ? path19.resolve(xdg) : path19.join(homeDir(), ".config");
7705
7891
  }
7706
7892
  function envOverride(name) {
7707
7893
  const v = process.env[name];
7708
- return v && v.length > 0 ? path18.resolve(v) : void 0;
7894
+ return v && v.length > 0 ? path19.resolve(v) : void 0;
7709
7895
  }
7710
7896
  var CURSOR_CLIENT = {
7711
7897
  id: "cursor",
7712
7898
  label: "Cursor",
7713
7899
  docsUrl: "https://docs.cursor.com/context/mcp",
7714
- mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? path18.join(homeDir(), ".cursor", "mcp.json"),
7900
+ mcpConfigPath: () => envOverride("NEAT_CURSOR_CONFIG") ?? path19.join(homeDir(), ".cursor", "mcp.json"),
7715
7901
  mcpContainerKey: "mcpServers",
7716
7902
  format: "json",
7717
7903
  // Cursor still reads a single `.cursorrules` at the project root (the modern
@@ -7723,7 +7909,7 @@ var DEVIN_CLIENT = {
7723
7909
  id: "devin",
7724
7910
  label: "Devin Desktop (Cascade)",
7725
7911
  docsUrl: "https://docs.devin.ai/desktop/cascade/mcp",
7726
- mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? path18.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
7912
+ mcpConfigPath: () => envOverride("NEAT_DEVIN_CONFIG") ?? path19.join(homeDir(), ".codeium", "windsurf", "mcp_config.json"),
7727
7913
  mcpContainerKey: "mcpServers",
7728
7914
  format: "json",
7729
7915
  rulesFileName: ".windsurfrules"
@@ -7732,7 +7918,7 @@ var GEMINI_CLIENT = {
7732
7918
  id: "gemini",
7733
7919
  label: "Gemini CLI",
7734
7920
  docsUrl: "https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md",
7735
- mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? path18.join(homeDir(), ".gemini", "settings.json"),
7921
+ mcpConfigPath: () => envOverride("NEAT_GEMINI_CONFIG") ?? path19.join(homeDir(), ".gemini", "settings.json"),
7736
7922
  mcpContainerKey: "mcpServers",
7737
7923
  format: "json",
7738
7924
  rulesFileName: "GEMINI.md"
@@ -7741,7 +7927,7 @@ var QWEN_CLIENT = {
7741
7927
  id: "qwen",
7742
7928
  label: "Qwen Code",
7743
7929
  docsUrl: "https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/",
7744
- mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? path18.join(homeDir(), ".qwen", "settings.json"),
7930
+ mcpConfigPath: () => envOverride("NEAT_QWEN_CONFIG") ?? path19.join(homeDir(), ".qwen", "settings.json"),
7745
7931
  mcpContainerKey: "mcpServers",
7746
7932
  format: "json",
7747
7933
  rulesFileName: "QWEN.md"
@@ -7750,7 +7936,7 @@ var AMAZONQ_CLIENT = {
7750
7936
  id: "amazonq",
7751
7937
  label: "Amazon Q Developer CLI",
7752
7938
  docsUrl: "https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html",
7753
- mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? path18.join(homeDir(), ".aws", "amazonq", "mcp.json"),
7939
+ mcpConfigPath: () => envOverride("NEAT_AMAZONQ_CONFIG") ?? path19.join(homeDir(), ".aws", "amazonq", "mcp.json"),
7754
7940
  mcpContainerKey: "mcpServers",
7755
7941
  format: "json"
7756
7942
  };
@@ -7758,7 +7944,7 @@ var ROOCODE_CLIENT = {
7758
7944
  id: "roocode",
7759
7945
  label: "Roo Code",
7760
7946
  docsUrl: "https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo",
7761
- mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? path18.join(process.cwd(), ".roo", "mcp.json"),
7947
+ mcpConfigPath: () => envOverride("NEAT_ROOCODE_CONFIG") ?? path19.join(process.cwd(), ".roo", "mcp.json"),
7762
7948
  mcpContainerKey: "mcpServers",
7763
7949
  format: "json"
7764
7950
  };
@@ -7771,9 +7957,9 @@ var ZED_CLIENT = {
7771
7957
  if (override) return override;
7772
7958
  if (process.platform === "win32") {
7773
7959
  const appData = process.env.APPDATA;
7774
- if (appData && appData.length > 0) return path18.join(appData, "Zed", "settings.json");
7960
+ if (appData && appData.length > 0) return path19.join(appData, "Zed", "settings.json");
7775
7961
  }
7776
- return path18.join(homeDir(), ".config", "zed", "settings.json");
7962
+ return path19.join(homeDir(), ".config", "zed", "settings.json");
7777
7963
  },
7778
7964
  mcpContainerKey: "context_servers",
7779
7965
  format: "jsonc",
@@ -7783,7 +7969,7 @@ var OPENCODE_CLIENT = {
7783
7969
  id: "opencode",
7784
7970
  label: "OpenCode",
7785
7971
  docsUrl: "https://opencode.ai/docs/mcp-servers/",
7786
- mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? path18.join(xdgConfigDir(), "opencode", "opencode.json"),
7972
+ mcpConfigPath: () => envOverride("NEAT_OPENCODE_CONFIG") ?? path19.join(xdgConfigDir(), "opencode", "opencode.json"),
7787
7973
  mcpContainerKey: "mcp",
7788
7974
  format: "json",
7789
7975
  serverEntry: NEAT_OPENCODE_SERVER,
@@ -7793,7 +7979,7 @@ var CRUSH_CLIENT = {
7793
7979
  id: "crush",
7794
7980
  label: "Crush",
7795
7981
  docsUrl: "https://charmbracelet-crush.mintlify.app/configuration/mcp",
7796
- mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? path18.join(xdgConfigDir(), "crush", "crush.json"),
7982
+ mcpConfigPath: () => envOverride("NEAT_CRUSH_CONFIG") ?? path19.join(xdgConfigDir(), "crush", "crush.json"),
7797
7983
  mcpContainerKey: "mcp",
7798
7984
  format: "json",
7799
7985
  serverEntry: NEAT_CRUSH_SERVER,
@@ -7898,7 +8084,7 @@ async function runEditorInstall(client, opts) {
7898
8084
  const mcpPath = client.mcpConfigPath();
7899
8085
  const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER;
7900
8086
  const hasRules = typeof client.rulesFileName === "string";
7901
- const rulesPath = hasRules ? path18.join(opts.projectDir, client.rulesFileName) : "";
8087
+ const rulesPath = hasRules ? path19.join(opts.projectDir, client.rulesFileName) : "";
7902
8088
  const mcp = await planMcp(client, mcpPath);
7903
8089
  if (mcp === null) return { exitCode: 1 };
7904
8090
  let existingRules = "";
@@ -7941,10 +8127,10 @@ async function runEditorInstall(client, opts) {
7941
8127
  );
7942
8128
  return { exitCode: 0 };
7943
8129
  }
7944
- await fs17.mkdir(path18.dirname(mcpPath), { recursive: true });
8130
+ await fs17.mkdir(path19.dirname(mcpPath), { recursive: true });
7945
8131
  await fs17.writeFile(mcpPath, mcp.text, "utf8");
7946
8132
  if (hasRules) {
7947
- await fs17.mkdir(path18.dirname(rulesPath), { recursive: true });
8133
+ await fs17.mkdir(path19.dirname(rulesPath), { recursive: true });
7948
8134
  await fs17.writeFile(rulesPath, newRules, "utf8");
7949
8135
  }
7950
8136
  console.log(`neat ${client.id}: wired NEAT into ${client.label}`);
@@ -8445,7 +8631,7 @@ function sleep(ms, signal) {
8445
8631
  }
8446
8632
 
8447
8633
  // src/cli-verbs.ts
8448
- import path19 from "path";
8634
+ import path20 from "path";
8449
8635
  async function resolveProjectEntry(opts) {
8450
8636
  const entries = await listProjects();
8451
8637
  if (opts.project) {
@@ -8455,7 +8641,7 @@ async function resolveProjectEntry(opts) {
8455
8641
  const cwd = opts.cwd ?? process.cwd();
8456
8642
  const resolvedCwd = await normalizeProjectPath(cwd);
8457
8643
  for (const entry2 of entries) {
8458
- if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${path19.sep}`)) {
8644
+ if (resolvedCwd === entry2.path || resolvedCwd.startsWith(`${entry2.path}${path20.sep}`)) {
8459
8645
  return entry2;
8460
8646
  }
8461
8647
  }
@@ -8774,6 +8960,8 @@ function usage5() {
8774
8960
  console.log(" test <id> re-check an existing connector's credential");
8775
8961
  console.log(" Credentials default to an env-var reference ($VAR) resolved at");
8776
8962
  console.log(" run time; the config file is written owner-only (0600).");
8963
+ console.log(" up Start this project's daemon, or recover it if it died. Does");
8964
+ console.log(" nothing when it is already running. Flags: --project, --json.");
8777
8965
  console.log(" doctor Preflight this directory's setup \u2014 Node version, project,");
8778
8966
  console.log(" and daemon reachability \u2014 and print a fix for anything down.");
8779
8967
  console.log(" Flags: --json. Exits 0 when all pass, 1 when a check fails.");
@@ -9041,12 +9229,12 @@ async function runInit(opts) {
9041
9229
  printDiscoveryReport(opts, services);
9042
9230
  const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project);
9043
9231
  const patch = renderPatch(sections);
9044
- const patchPath = path20.join(opts.scanPath, "neat.patch");
9232
+ const patchPath = path21.join(opts.scanPath, "neat.patch");
9045
9233
  if (opts.dryRun) {
9046
9234
  await fs18.writeFile(patchPath, patch, "utf8");
9047
9235
  written.push(patchPath);
9048
9236
  console.log(`dry-run: patch written to ${patchPath}`);
9049
- const gitignorePath = path20.join(opts.scanPath, ".gitignore");
9237
+ const gitignorePath = path21.join(opts.scanPath, ".gitignore");
9050
9238
  const gitignoreExists = await fs18.stat(gitignorePath).then(() => true).catch(() => false);
9051
9239
  const verb = gitignoreExists ? "append" : "create";
9052
9240
  console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`);
@@ -9058,9 +9246,9 @@ async function runInit(opts) {
9058
9246
  const graph = getGraph(graphKey);
9059
9247
  const projectPaths = pathsForProject(
9060
9248
  graphKey,
9061
- path20.join(opts.scanPath, "neat-out")
9249
+ path21.join(opts.scanPath, "neat-out")
9062
9250
  );
9063
- const errorsPath = path20.join(path20.dirname(opts.outPath), path20.basename(projectPaths.errorsPath));
9251
+ const errorsPath = path21.join(path21.dirname(opts.outPath), path21.basename(projectPaths.errorsPath));
9064
9252
  const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath });
9065
9253
  await saveGraphToDisk(graph, opts.outPath);
9066
9254
  written.push(opts.outPath);
@@ -9069,15 +9257,13 @@ async function runInit(opts) {
9069
9257
  written.push(gitignoreResult.file);
9070
9258
  }
9071
9259
  const languages = [...new Set(services.map((s) => s.node.language))].sort();
9072
- let currentProjectName = opts.project;
9073
9260
  try {
9074
- const entry2 = await addProject({
9261
+ await addProject({
9075
9262
  name: opts.project,
9076
9263
  path: opts.scanPath,
9077
9264
  languages,
9078
9265
  status: "active"
9079
9266
  });
9080
- currentProjectName = entry2.name;
9081
9267
  } catch (err) {
9082
9268
  if (err instanceof ProjectNameCollisionError) {
9083
9269
  console.error(`neat init: ${err.message}`);
@@ -9086,20 +9272,6 @@ async function runInit(opts) {
9086
9272
  }
9087
9273
  throw err;
9088
9274
  }
9089
- const siblings = await listProjects();
9090
- const paused = [];
9091
- for (const p of siblings) {
9092
- if (p.name !== currentProjectName && p.status === "active") {
9093
- await setStatus(p.name, "paused");
9094
- paused.push(p.name);
9095
- }
9096
- }
9097
- if (paused.length > 0) {
9098
- const plural = paused.length === 1 ? "" : "s";
9099
- console.log(
9100
- `neat: paused ${paused.length} sibling project${plural}; run \`neat resume <name>\` to bring one back active.`
9101
- );
9102
- }
9103
9275
  if (!opts.noInstall) {
9104
9276
  if (opts.apply) {
9105
9277
  let instrumented = 0;
@@ -9160,6 +9332,8 @@ async function runInit(opts) {
9160
9332
  if (result.extractionErrors > 0) {
9161
9333
  console.log(`errors: ${errorsPath}`);
9162
9334
  }
9335
+ const skippedBanner = formatSkippedBanner(result.skippedFiles);
9336
+ if (skippedBanner) console.log(skippedBanner);
9163
9337
  console.log(formatPrecisionFloorBanner(result.extractedDropped));
9164
9338
  if (result.extractionErrors > 0 && isStrictExtractionEnabled()) {
9165
9339
  return { exitCode: 4, writtenFiles: written };
@@ -9180,9 +9354,9 @@ var CLAUDE_SKILL_CONFIG = {
9180
9354
  };
9181
9355
  function claudeConfigPath() {
9182
9356
  const override = process.env.NEAT_CLAUDE_CONFIG;
9183
- if (override && override.length > 0) return path20.resolve(override);
9357
+ if (override && override.length > 0) return path21.resolve(override);
9184
9358
  const home = process.env.HOME ?? process.env.USERPROFILE ?? "";
9185
- return path20.join(home, ".claude.json");
9359
+ return path21.join(home, ".claude.json");
9186
9360
  }
9187
9361
  async function runSkill(opts) {
9188
9362
  const snippet = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + "\n";
@@ -9206,7 +9380,7 @@ async function runSkill(opts) {
9206
9380
  ...existing,
9207
9381
  mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat }
9208
9382
  };
9209
- await fs18.mkdir(path20.dirname(target), { recursive: true });
9383
+ await fs18.mkdir(path21.dirname(target), { recursive: true });
9210
9384
  await fs18.writeFile(target, JSON.stringify(merged, null, 2) + "\n", "utf8");
9211
9385
  console.log(`neat skill: wrote mcpServers.neat to ${target}`);
9212
9386
  console.log("restart Claude Code to pick up the new MCP server.");
@@ -9256,6 +9430,21 @@ async function main() {
9256
9430
  if (code !== 0) process.exit(code);
9257
9431
  return;
9258
9432
  }
9433
+ if (cmd0 === "up") {
9434
+ const code = await runUpCommand(argv.slice(1), {
9435
+ resolveTarget: async (opts) => {
9436
+ const target = await resolveClientTarget(opts);
9437
+ const named = opts.profile ?? process.env.NEAT_PROFILE;
9438
+ return {
9439
+ endpoint: target.endpoint,
9440
+ local: isLoopbackEndpoint(target.endpoint),
9441
+ via: target.source === "profile" ? `the \`${named}\` profile` : target.source === "active" ? "your active profile" : "your environment"
9442
+ };
9443
+ }
9444
+ });
9445
+ if (code !== 0) process.exit(code);
9446
+ return;
9447
+ }
9259
9448
  if (cmd0 === "login") {
9260
9449
  const code = await runLoginCommand(argv.slice(1));
9261
9450
  if (code !== 0) process.exit(code);
@@ -9328,12 +9517,12 @@ async function main() {
9328
9517
  console.error("neat init: --apply and --dry-run are mutually exclusive");
9329
9518
  process.exit(2);
9330
9519
  }
9331
- const scanPath = path20.resolve(target);
9520
+ const scanPath = path21.resolve(target);
9332
9521
  const projectExplicit = parsed.project !== null;
9333
- const projectName = projectExplicit ? project : path20.basename(scanPath);
9522
+ const projectName = projectExplicit ? project : path21.basename(scanPath);
9334
9523
  const projectKey = projectExplicit ? project : DEFAULT_PROJECT;
9335
- const fallback = pathsForProject(projectKey, path20.join(scanPath, "neat-out")).snapshotPath;
9336
- const outPath = path20.resolve(process.env.NEAT_OUT_PATH ?? fallback);
9524
+ const fallback = pathsForProject(projectKey, path21.join(scanPath, "neat-out")).snapshotPath;
9525
+ const outPath = path21.resolve(process.env.NEAT_OUT_PATH ?? fallback);
9337
9526
  const result = await runInit({
9338
9527
  scanPath,
9339
9528
  outPath,
@@ -9354,21 +9543,21 @@ async function main() {
9354
9543
  usage5();
9355
9544
  process.exit(2);
9356
9545
  }
9357
- const scanPath = path20.resolve(target);
9546
+ const scanPath = path21.resolve(target);
9358
9547
  const stat = await fs18.stat(scanPath).catch(() => null);
9359
9548
  if (!stat || !stat.isDirectory()) {
9360
9549
  console.error(`neat watch: ${scanPath} is not a directory`);
9361
9550
  process.exit(2);
9362
9551
  }
9363
- const projectPaths = pathsForProject(project, path20.join(scanPath, "neat-out"));
9364
- const outPath = path20.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
9365
- const errorsPath = path20.resolve(
9366
- process.env.NEAT_ERRORS_PATH ?? path20.join(path20.dirname(outPath), path20.basename(projectPaths.errorsPath))
9552
+ const projectPaths = pathsForProject(project, path21.join(scanPath, "neat-out"));
9553
+ const outPath = path21.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath);
9554
+ const errorsPath = path21.resolve(
9555
+ process.env.NEAT_ERRORS_PATH ?? path21.join(path21.dirname(outPath), path21.basename(projectPaths.errorsPath))
9367
9556
  );
9368
- const staleEventsPath = path20.resolve(
9369
- process.env.NEAT_STALE_EVENTS_PATH ?? path20.join(path20.dirname(outPath), path20.basename(projectPaths.staleEventsPath))
9557
+ const staleEventsPath = path21.resolve(
9558
+ process.env.NEAT_STALE_EVENTS_PATH ?? path21.join(path21.dirname(outPath), path21.basename(projectPaths.staleEventsPath))
9370
9559
  );
9371
- const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? path20.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
9560
+ const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH ? path21.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH) : void 0;
9372
9561
  const handle = await startWatch(getGraph(project), {
9373
9562
  scanPath,
9374
9563
  outPath,
@@ -9377,7 +9566,7 @@ async function main() {
9377
9566
  project,
9378
9567
  // Resolve NEAT_HOME so a `neat watch` picks up connectors added to
9379
9568
  // ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.
9380
- neatHome: process.env.NEAT_HOME ? path20.resolve(process.env.NEAT_HOME) : path20.join(os5.homedir(), ".neat"),
9569
+ neatHome: process.env.NEAT_HOME ? path21.resolve(process.env.NEAT_HOME) : path21.join(os5.homedir(), ".neat"),
9381
9570
  ...embeddingsCachePath ? { embeddingsCachePath } : {},
9382
9571
  host: process.env.HOST ?? "0.0.0.0",
9383
9572
  port: Number(process.env.PORT ?? 8080),
@@ -9558,12 +9747,12 @@ async function main() {
9558
9747
  usage5();
9559
9748
  process.exit(1);
9560
9749
  }
9561
- async function tryOrchestrator(cmd, parsed) {
9562
- const scanPath = path20.resolve(cmd);
9750
+ async function tryOrchestrator(cmd, parsed, overrides = {}) {
9751
+ const scanPath = path21.resolve(cmd);
9563
9752
  const stat = await fs18.stat(scanPath).catch(() => null);
9564
9753
  if (!stat || !stat.isDirectory()) return null;
9565
9754
  const projectExplicit = parsed.project !== null;
9566
- const projectName = projectExplicit ? parsed.project : path20.basename(scanPath);
9755
+ const projectName = projectExplicit ? parsed.project : path21.basename(scanPath);
9567
9756
  const result = await runOrchestrator({
9568
9757
  scanPath,
9569
9758
  project: projectName,
@@ -9571,7 +9760,8 @@ async function tryOrchestrator(cmd, parsed) {
9571
9760
  noInstrument: parsed.noInstrument,
9572
9761
  open: parsed.open,
9573
9762
  noOpen: parsed.noOpen,
9574
- yes: parsed.yes
9763
+ yes: parsed.yes,
9764
+ ...overrides.skipBanner ? { skipBanner: true } : {}
9575
9765
  });
9576
9766
  return result.exitCode;
9577
9767
  }
@@ -9581,13 +9771,18 @@ async function runWelcomeFlow(parsed) {
9581
9771
  // What the person chose at the door reaches the orchestrator as the flags they
9582
9772
  // stand for: the name as `--project`, the instrument answer as `--no-instrument`
9583
9773
  // or as `yes` (which keeps the orchestrator's own prompt quiet, since the door
9584
- // already asked).
9585
- orchestrator: async (cwd, opts) => await tryOrchestrator(cwd, {
9586
- ...parsed,
9587
- ...opts?.project !== void 0 ? { project: opts.project } : {},
9588
- ...opts?.noInstrument !== void 0 ? { noInstrument: opts.noInstrument } : {},
9589
- ...opts?.yes !== void 0 ? { yes: opts.yes } : {}
9590
- }) ?? 0,
9774
+ // already asked). `headerShown` isn't a flag anyone can type — it says the
9775
+ // door's wordmark already opened this run, so the orchestrator's banner is skipped.
9776
+ orchestrator: async (cwd, opts) => await tryOrchestrator(
9777
+ cwd,
9778
+ {
9779
+ ...parsed,
9780
+ ...opts?.project !== void 0 ? { project: opts.project } : {},
9781
+ ...opts?.noInstrument !== void 0 ? { noInstrument: opts.noInstrument } : {},
9782
+ ...opts?.yes !== void 0 ? { yes: opts.yes } : {}
9783
+ },
9784
+ { skipBanner: opts?.headerShown === true }
9785
+ ) ?? 0,
9591
9786
  // An explicit flag is an answer; don't ask again.
9592
9787
  instrumentFlagGiven: parsed.noInstrument || parsed.dryRun
9593
9788
  });
@@ -9629,9 +9824,10 @@ function isLoopbackEndpoint(endpoint) {
9629
9824
  return false;
9630
9825
  }
9631
9826
  }
9632
- async function resolveProjectForVerb(client, parsed) {
9827
+ async function resolveProjectForVerb(client, parsed, cwdProject) {
9633
9828
  const explicit = resolveProjectFlag(parsed);
9634
9829
  if (explicit) return explicit;
9830
+ if (cwdProject) return cwdProject;
9635
9831
  const projects = await client.get("/projects");
9636
9832
  if (projects.some((p) => p.name === DEFAULT_PROJECT)) {
9637
9833
  return void 0;
@@ -9678,14 +9874,28 @@ async function resolveClientTarget(opts = {}) {
9678
9874
  }
9679
9875
  return { endpoint: "http://localhost:8080", source: "default" };
9680
9876
  }
9877
+ async function projectForCwd(cwd = process.cwd()) {
9878
+ try {
9879
+ return (await findProjectByPath(cwd))?.name;
9880
+ } catch {
9881
+ return void 0;
9882
+ }
9883
+ }
9884
+ function cwdProjectApplies(source) {
9885
+ return source === "daemon-record" || source === "default";
9886
+ }
9681
9887
  async function resolveDaemonUrl(project, profile) {
9682
9888
  return (await resolveClientTarget({ project, profile })).endpoint;
9683
9889
  }
9684
9890
  async function runQueryVerb(cmd, parsed) {
9685
9891
  const requestedProject = resolveProjectFlag(parsed);
9892
+ const cwdProject = requestedProject ? void 0 : await projectForCwd();
9686
9893
  let target;
9687
9894
  try {
9688
- target = await resolveClientTarget({ project: requestedProject, profile: parsed.profile ?? void 0 });
9895
+ target = await resolveClientTarget({
9896
+ project: requestedProject ?? cwdProject,
9897
+ profile: parsed.profile ?? void 0
9898
+ });
9689
9899
  } catch (err) {
9690
9900
  if (err instanceof UnknownProfileError) {
9691
9901
  process.stderr.write(`${err.message}
@@ -9844,7 +10054,11 @@ async function runQueryVerb(cmd, parsed) {
9844
10054
  return 2;
9845
10055
  }
9846
10056
  try {
9847
- const project = await resolveProjectForVerb(client, parsed);
10057
+ const project = await resolveProjectForVerb(
10058
+ client,
10059
+ parsed,
10060
+ cwdProjectApplies(target.source) ? cwdProject : void 0
10061
+ );
9848
10062
  const result = await makeWork(project);
9849
10063
  if (parsed.json) process.stdout.write(formatJson(result) + "\n");
9850
10064
  else process.stdout.write(formatHuman(result) + "\n");
@@ -9860,7 +10074,8 @@ async function runQueryVerb(cmd, parsed) {
9860
10074
  } else if (err instanceof TransportError) {
9861
10075
  console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (endpoint=${target.endpoint})`);
9862
10076
  if (isLoopbackEndpoint(target.endpoint)) {
9863
- console.error(`neat ${cmd}: start one with \`neat watch .\`, or \`neat\` to extract and start in one step.`);
10077
+ const upCommand = requestedProject ? `neat up --project ${requestedProject}` : "neat up";
10078
+ console.error(`neat ${cmd}: run \`${upCommand}\` to start it.`);
9864
10079
  }
9865
10080
  } else {
9866
10081
  console.error(`neat ${cmd}: ${err.message}`);
@@ -9870,9 +10085,13 @@ async function runQueryVerb(cmd, parsed) {
9870
10085
  }
9871
10086
  async function runMonitorVerb(parsed) {
9872
10087
  const requestedProject = resolveProjectFlag(parsed);
10088
+ const cwdProject = requestedProject ? void 0 : await projectForCwd();
9873
10089
  let target;
9874
10090
  try {
9875
- target = await resolveClientTarget({ project: requestedProject, profile: parsed.profile ?? void 0 });
10091
+ target = await resolveClientTarget({
10092
+ project: requestedProject ?? cwdProject,
10093
+ profile: parsed.profile ?? void 0
10094
+ });
9876
10095
  } catch (err) {
9877
10096
  if (err instanceof UnknownProfileError) return 0;
9878
10097
  throw err;
@@ -9880,7 +10099,11 @@ async function runMonitorVerb(parsed) {
9880
10099
  const client = createHttpClient(target.endpoint, target.authToken);
9881
10100
  let project;
9882
10101
  try {
9883
- project = await resolveProjectForVerb(client, parsed);
10102
+ project = await resolveProjectForVerb(
10103
+ client,
10104
+ parsed,
10105
+ cwdProjectApplies(target.source) ? cwdProject : void 0
10106
+ );
9884
10107
  } catch (err) {
9885
10108
  if (err instanceof ProjectResolutionError) {
9886
10109
  console.error(`neat monitor: ${err.message}`);
@@ -9904,11 +10127,18 @@ async function runMonitorVerb(parsed) {
9904
10127
  process.off("SIGTERM", onSignal);
9905
10128
  }
9906
10129
  }
10130
+ function reportFatal(err, log = console.error) {
10131
+ if (err instanceof RegistryError) {
10132
+ log(`neat: ${err.message}`);
10133
+ return 1;
10134
+ }
10135
+ log(err);
10136
+ return 1;
10137
+ }
9907
10138
  var entry = process.argv[1] ?? "";
9908
10139
  if (/[\\/](?:cli\.(?:cjs|js)|cli|neat|neat\.is)$/.test(entry)) {
9909
10140
  main().catch((err) => {
9910
- console.error(err);
9911
- process.exit(1);
10141
+ process.exit(reportFatal(err));
9912
10142
  });
9913
10143
  }
9914
10144
  export {
@@ -9917,12 +10147,15 @@ export {
9917
10147
  QUERY_VERBS,
9918
10148
  UnknownProfileError,
9919
10149
  commandPrefix,
10150
+ cwdProjectApplies,
9920
10151
  isLoopbackEndpoint,
9921
10152
  isNpxInvocation,
9922
10153
  main,
9923
10154
  parseArgs,
9924
10155
  printBanner,
10156
+ projectForCwd,
9925
10157
  readPackageVersion,
10158
+ reportFatal,
9926
10159
  resolveClientTarget,
9927
10160
  resolveDaemonUrl,
9928
10161
  resolveProjectForVerb,