lurqrun 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +312 -148
  2. package/dist/{auditHandler-JCOJSUYW.js → auditHandler-VWCXSDVO.js} +12 -11
  3. package/dist/autopilotInit-Q62MX5M6.js +178 -0
  4. package/dist/bin/lurq.js +235 -83
  5. package/dist/{browserAuth-B6G27USY.js → browserAuth-J7APSD4P.js} +4 -3
  6. package/dist/{cache-DKI34SVS.js → cache-AEAKCV4I.js} +2 -2
  7. package/dist/check-2JTQDQA6.js +2613 -0
  8. package/dist/{check-2FDGUOV7.js → check-PQSQ2MMA.js} +1 -1
  9. package/dist/checkUpgrade-5YW77OBL.js +24 -0
  10. package/dist/{chunk-BCANRN5B.js → chunk-2GAYNIHG.js} +8 -1
  11. package/dist/{chunk-EA3DP5HG.js → chunk-2O6Z37IT.js} +155 -25
  12. package/dist/{chunk-J5FZYN4A.js → chunk-2WD4QAH4.js} +1 -1
  13. package/dist/{chunk-CUP36ND3.js → chunk-3676XOBU.js} +145 -36
  14. package/dist/chunk-3D2MPGOQ.js +181 -0
  15. package/dist/{chunk-LYMPYETA.js → chunk-4JHDSVIN.js} +270 -6
  16. package/dist/chunk-53SG6XWA.js +141 -0
  17. package/dist/chunk-5ABNDB3I.js +37 -0
  18. package/dist/chunk-5ALIJFDA.js +114 -0
  19. package/dist/{chunk-BULZAX2U.js → chunk-64ZF7KO4.js} +55 -38
  20. package/dist/{chunk-2VMOWSRY.js → chunk-6DM6UQFD.js} +19 -1
  21. package/dist/{chunk-HWBBVLOT.js → chunk-6L67QMCP.js} +1 -1
  22. package/dist/{chunk-GPTKSNR6.js → chunk-72Y2FDVS.js} +2 -1
  23. package/dist/{chunk-B43LCXBM.js → chunk-A3TYI2TF.js} +81 -16
  24. package/dist/{chunk-IQ4SDKKY.js → chunk-B2UUYRBX.js} +31 -228
  25. package/dist/{chunk-DB2VF5UD.js → chunk-BJT2LHAR.js} +16 -11
  26. package/dist/chunk-BM3LF5T6.js +132 -0
  27. package/dist/{chunk-3N3Q3DSW.js → chunk-BN3NM47Q.js} +8 -8
  28. package/dist/chunk-D3K6IZVR.js +12845 -0
  29. package/dist/{chunk-AHBP533R.js → chunk-D3VTZS7V.js} +7 -5
  30. package/dist/{chunk-UDVNA7EA.js → chunk-DM37MTOO.js} +161 -8
  31. package/dist/chunk-DONTW3NE.js +171 -0
  32. package/dist/{chunk-M6NYEXCW.js → chunk-DSROTZ3Z.js} +1 -1
  33. package/dist/{chunk-4F7ZESPO.js → chunk-EQCXENKZ.js} +3 -5
  34. package/dist/{chunk-CW5HJ3LX.js → chunk-EYAKM6YN.js} +1 -1
  35. package/dist/{chunk-VL2E5T2A.js → chunk-FDFPMBCA.js} +6 -3
  36. package/dist/{chunk-BV32UNLL.js → chunk-FVYFV5HA.js} +2 -2
  37. package/dist/{chunk-DWAGCNEL.js → chunk-GM5Y555O.js} +36 -103
  38. package/dist/{chunk-PSX3GIAN.js → chunk-HWFX4BC4.js} +2 -1
  39. package/dist/chunk-IFNONGRQ.js +603 -0
  40. package/dist/chunk-J3U2CPSK.js +136 -0
  41. package/dist/{chunk-Y5GI7RL3.js → chunk-J6XQ7OPZ.js} +9 -1
  42. package/dist/{chunk-LBFGSSF2.js → chunk-KMV4Y6R3.js} +2 -1
  43. package/dist/{chunk-L6N4JFW2.js → chunk-KP5ZDDPE.js} +81 -4
  44. package/dist/{chunk-SJOVFF7B.js → chunk-KYKSZ3XZ.js} +3 -2
  45. package/dist/chunk-NEZNAPPN.js +41 -0
  46. package/dist/{chunk-NH5I4KHH.js → chunk-NPVN2THM.js} +1 -5
  47. package/dist/{chunk-6L3U7DZ5.js → chunk-NYZU5NCW.js} +1 -1
  48. package/dist/chunk-O4KHCV6I.js +320 -0
  49. package/dist/{chunk-LO35HLQZ.js → chunk-ONDVTXUO.js} +25 -4
  50. package/dist/{chunk-4ZYCIMY4.js → chunk-OTJFHESY.js} +25 -4
  51. package/dist/chunk-P6MIKSPY.js +243 -0
  52. package/dist/{checkUpgrade-F2WESBPM.js → chunk-QCRBX3LV.js} +72 -10
  53. package/dist/{chunk-LRD4GBYE.js → chunk-QUIMQ7YL.js} +1 -1
  54. package/dist/chunk-RG3YLU6E.js +49 -0
  55. package/dist/{chunk-ST2X2GYN.js → chunk-SHZFOSXC.js} +109 -20
  56. package/dist/{chunk-CIDWNUAP.js → chunk-SOXFMMXC.js} +8 -2
  57. package/dist/chunk-TDTYV6QI.js +119 -0
  58. package/dist/{chunk-FW6BD2NO.js → chunk-TUXQ32WE.js} +457 -121
  59. package/dist/{chunk-WQ23REYT.js → chunk-VGCDRK3S.js} +1 -1
  60. package/dist/{chunk-U5AT3TD4.js → chunk-X4W64MHU.js} +1735 -1858
  61. package/dist/chunk-XBQA4I36.js +92 -0
  62. package/dist/chunk-XGOV6KV4.js +413 -0
  63. package/dist/{chunk-OQS4GUSI.js → chunk-XIFQIFSZ.js} +210 -661
  64. package/dist/{chunk-XBIDMHSK.js → chunk-XLXPVN3Y.js} +2 -34
  65. package/dist/chunk-ZJMLQ37G.js +90 -0
  66. package/dist/{client-IRKAMDYZ.js → client-MU4EUDZV.js} +3 -3
  67. package/dist/{commands-FIL5ET6P.js → commands-UOOTMBKA.js} +145 -33
  68. package/dist/{compat-R3UTFQ5Q.js → compat-Q5DVPITN.js} +6 -6
  69. package/dist/constants-DJFOFZ44.js +24 -0
  70. package/dist/{dashboardIssue-WYYMBFIB.js → dashboardIssue-KBKLQMGC.js} +105 -23
  71. package/dist/{diff-GZA2774U.js → diff-I4SNUHU3.js} +1 -1
  72. package/dist/domains-VRT4BRVZ.js +14 -0
  73. package/dist/env-UN6KGZ7S.js +15 -0
  74. package/dist/envCheck-KUPTORFQ.js +71 -0
  75. package/dist/{extract-NKGKLIVT.js → extract-6WG265BL.js} +14 -3
  76. package/dist/{fetch-QYTUJVG2.js → fetch-PJ3SC32M.js} +4 -4
  77. package/dist/{firstTouch-QQTJH4QX.js → firstTouch-COJCMOB3.js} +1 -1
  78. package/dist/fix-3EDWNKW3.js +220 -0
  79. package/dist/{handlers-GEJAVZDK.js → handlers-4Q37WIFT.js} +19 -17
  80. package/dist/hook-NA66XJLC.js +412 -0
  81. package/dist/{http-ETPYMBGD.js → http-25GJ6SKK.js} +2078 -510
  82. package/dist/{ingestQueue-VKN4KBIF.js → ingestQueue-FSVJC3AA.js} +14 -12
  83. package/dist/{install-EK3W2COX.js → install-G2HHXYJ2.js} +6 -6
  84. package/dist/{installSkill-VQJWJVCL.js → installSkill-5TIMYIJZ.js} +21 -3
  85. package/dist/manifest-ENMIC54B.js +13 -0
  86. package/dist/{mcp-3JHD5SUZ.js → mcp-PENLL2PK.js} +60 -32
  87. package/dist/mcpConfig-3LYPRY5Q.js +80 -0
  88. package/dist/{mcpHandlers-QFN4MCFL.js → mcpHandlers-PO7GENA7.js} +7 -7
  89. package/dist/{mcpScan-QZHWENIP.js → mcpScan-ULP626TQ.js} +306 -442
  90. package/dist/{mcpScanWorkflow-JPYCBGC4.js → mcpScanWorkflow-27O44FOE.js} +29 -12
  91. package/dist/{mcpStack-BYJCZNIV.js → mcpStack-ZNYIFXZ5.js} +1 -1
  92. package/dist/model-ASMZWLM7.js +214 -0
  93. package/dist/{packages-THVFMWFP.js → packages-RWF2LXST.js} +3 -5
  94. package/dist/{plan-V4OEI3J4.js → plan-SDILIDZT.js} +23 -21
  95. package/dist/{planView-JRXGCG2N.js → planView-ZAKRTGVS.js} +4 -1
  96. package/dist/{policy-3P6BGRDN.js → policy-JAGNMQJI.js} +5 -5
  97. package/dist/probe-3IK646WN.js +610 -0
  98. package/dist/publicUpgrades-WTBGLDIK.js +42 -0
  99. package/dist/{references-6N7VEPHT.js → references-I6Y4BSRR.js} +3 -1
  100. package/dist/{release-4U4ABNSJ.js → release-7IU2R4YG.js} +5 -5
  101. package/dist/{remote-YGCXYI4V.js → remote-FN6225AH.js} +13 -3
  102. package/dist/rename-OS6JYBZQ.js +204 -0
  103. package/dist/{reportRuns-CKQQYLY4.js → reportRuns-O4X7ZFTX.js} +15 -2
  104. package/dist/safeFetch-COERXGFN.js +19 -0
  105. package/dist/{sandbox-MEZLAODF.js → sandbox-SAPSRKEI.js} +4 -4
  106. package/dist/sarif-WLVJFJ7U.js +125 -0
  107. package/dist/server-OLTY3NYT.js +59 -0
  108. package/dist/{surface-V62GE554.js → surface-7MHE3RL7.js} +18 -16
  109. package/dist/{surface-YL6O67W3.js → surface-JS2XU3U3.js} +5 -3
  110. package/dist/{surfaceHandlers-X2IZKA3E.js → surfaceHandlers-4B6TMZ34.js} +5 -5
  111. package/dist/{typecheck-X7U5ELMR.js → typecheck-NGOKNAJY.js} +23 -9
  112. package/dist/{uninstall-P7RGBX6G.js → uninstall-I2IJP5JZ.js} +30 -4
  113. package/dist/{upgrade-NQ5IWFZB.js → upgrade-FS26DJGG.js} +86 -32
  114. package/dist/{upgradePlan-A4LRKLEG.js → upgradePlan-ZS5IOVMZ.js} +46 -11
  115. package/dist/upkeepHandler-VFGYXJKB.js +13 -0
  116. package/dist/{userConfig-Z3GQE776.js → userConfig-ICASHI47.js} +1 -1
  117. package/dist/{watch-DGFMWUDL.js → watch-OCNEUXG6.js} +24 -34
  118. package/package.json +3 -2
  119. package/templates/skill-instructions.md +22 -3
  120. package/dist/chunk-6AAEVQ7I.js +0 -6336
  121. package/dist/chunk-I2JUKN6Z.js +0 -24
  122. package/dist/server-KFUD5X57.js +0 -55
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
2
  import {
3
3
  checkApi
4
- } from "./chunk-CIDWNUAP.js";
4
+ } from "./chunk-SOXFMMXC.js";
5
5
  import {
6
6
  require_dist
7
7
  } from "./chunk-QKGYDMWB.js";
@@ -0,0 +1,24 @@
1
+ import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
+ import {
3
+ SCAN_LIMIT,
4
+ fixableTargets,
5
+ modeDisagreement,
6
+ parseUpgradeSpec,
7
+ planMode,
8
+ planUpgrades,
9
+ runCheckUpgrade,
10
+ targetsFromPlanFile,
11
+ targetsFromUpgrades
12
+ } from "./chunk-QCRBX3LV.js";
13
+ import "./chunk-I3M2KJXB.js";
14
+ export {
15
+ SCAN_LIMIT,
16
+ fixableTargets,
17
+ modeDisagreement,
18
+ parseUpgradeSpec,
19
+ planMode,
20
+ planUpgrades,
21
+ runCheckUpgrade,
22
+ targetsFromPlanFile,
23
+ targetsFromUpgrades
24
+ };
@@ -8,8 +8,14 @@ init_esm_shims();
8
8
  var DEFAULT_REPO_POLICY = {
9
9
  enabled: false,
10
10
  scope: "blocking",
11
- autoMerge: false
11
+ autoMerge: false,
12
+ // Stated rather than relied upon. `permits()` already reads an absent
13
+ // `checks` as on, so a repo connected before this shipped behaves the same as
14
+ // a new one — which is the point of the inversion. Writing it here keeps the
15
+ // default visible in the policy the dashboard round-trips.
16
+ checks: { env: true }
12
17
  };
18
+ var RUN_TRIGGERS = ["schedule", "dispatch", "push", "pull_request", "other"];
13
19
  var UPGRADE_SEVERITIES = ["blocking", "warning", "ok", "unverified"];
14
20
  var UPGRADE_RUN_STATUSES = [
15
21
  "checked",
@@ -25,6 +31,7 @@ var TRANSITIVE_DETAIL_CAP = 100;
25
31
 
26
32
  export {
27
33
  DEFAULT_REPO_POLICY,
34
+ RUN_TRIGGERS,
28
35
  UPGRADE_SEVERITIES,
29
36
  UPGRADE_RUN_STATUSES,
30
37
  REPO_MANIFEST_CAP,
@@ -1,10 +1,4 @@
1
1
  import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
- import {
3
- MissingKeyError
4
- } from "./chunk-4ZYCIMY4.js";
5
- import {
6
- openInBrowser
7
- } from "./chunk-TNTXWSYA.js";
8
2
  import {
9
3
  bold,
10
4
  dim,
@@ -18,18 +12,24 @@ import {
18
12
  lurqInvocation,
19
13
  printInstallReport,
20
14
  resolveAgents
21
- } from "./chunk-UDVNA7EA.js";
15
+ } from "./chunk-DM37MTOO.js";
16
+ import {
17
+ MissingKeyError
18
+ } from "./chunk-OTJFHESY.js";
22
19
  import {
23
20
  readUserConfig,
24
21
  resolveApiKey,
25
22
  resolveEndpoint,
26
23
  writeUserConfig
27
- } from "./chunk-Y5GI7RL3.js";
24
+ } from "./chunk-J6XQ7OPZ.js";
25
+ import {
26
+ openInBrowser
27
+ } from "./chunk-TNTXWSYA.js";
28
28
  import {
29
29
  DEFAULT_ENDPOINT,
30
30
  KEYS_URL,
31
31
  PACKAGE_NAME
32
- } from "./chunk-GPTKSNR6.js";
32
+ } from "./chunk-72Y2FDVS.js";
33
33
  import {
34
34
  init_esm_shims
35
35
  } from "./chunk-I3M2KJXB.js";
@@ -37,6 +37,50 @@ import {
37
37
  // src/cli/install.ts
38
38
  init_esm_shims();
39
39
  import { spawnSync } from "child_process";
40
+
41
+ // src/cli/agentLink.ts
42
+ init_esm_shims();
43
+ import { spawn } from "child_process";
44
+ var LINK_PREFIX = "LURQ_SIGNIN ";
45
+ var LINK_WAIT_MS = 15 * 6e4;
46
+ var START_TIMEOUT_MS = 15e3;
47
+ function setupMode(o) {
48
+ if (o.yes) return o.hasKey ? "non-interactive" : "needs-key";
49
+ if (o.tty) return "interactive";
50
+ if (o.hasKey) return "non-interactive";
51
+ return o.ci || o.selfHosted ? "needs-key" : "agent-link";
52
+ }
53
+ function startAgentLink(opts, spawnImpl = spawn) {
54
+ const args = [...process.execArgv, process.argv[1] ?? "", "setup", "--wait-for-signin"];
55
+ if (opts.agent) args.push("--agent", opts.agent);
56
+ if (opts.noOpen) args.push("--no-open");
57
+ const child = spawnImpl(process.execPath, args, {
58
+ detached: true,
59
+ stdio: ["ignore", "pipe", "ignore"],
60
+ // The link has to be the first thing it prints; an update notice first would only be noise.
61
+ env: { ...process.env, NO_UPDATE_NOTIFIER: "1" }
62
+ });
63
+ return new Promise((resolve) => {
64
+ let buffered = "";
65
+ const done = (link) => {
66
+ clearTimeout(timer);
67
+ child.stdout?.removeAllListeners("data");
68
+ child.stdout?.destroy();
69
+ child.unref();
70
+ resolve(link);
71
+ };
72
+ const timer = setTimeout(() => done(null), START_TIMEOUT_MS);
73
+ child.stdout?.on("data", (chunk) => {
74
+ buffered += chunk.toString();
75
+ const line = buffered.split("\n").find((l) => l.startsWith(LINK_PREFIX));
76
+ if (line) done(line.slice(LINK_PREFIX.length).trim());
77
+ });
78
+ child.once("error", () => done(null));
79
+ child.once("exit", () => done(null));
80
+ });
81
+ }
82
+
83
+ // src/cli/install.ts
40
84
  async function withSetupOnMissingKey(run, ask = askToConnect, setup = () => runSetup({})) {
41
85
  try {
42
86
  await run();
@@ -50,7 +94,10 @@ async function askToConnect() {
50
94
  const interactive = process.stdin.isTTY && process.stdout.isTTY && !process.env.CI && !process.argv.includes("--json");
51
95
  if (!interactive) return false;
52
96
  const { confirm } = await import("./dist-4XXIXHHZ.js");
53
- return confirm({ message: "This machine has no lurq API key yet. Connect it now?", default: true });
97
+ return confirm({
98
+ message: "This machine has no lurq API key yet. Connect it now?",
99
+ default: true
100
+ });
54
101
  }
55
102
  async function validateKey(url, apiKey) {
56
103
  try {
@@ -91,20 +138,31 @@ function installGlobally() {
91
138
  console.log(yellow("skipped"));
92
139
  const reason = (res.stderr || res.error?.message || "").trim().split("\n").pop();
93
140
  if (reason) console.log(dim(` ${reason}`));
94
- console.log(dim(` Setup continues. Run \`npm install -g ${PACKAGE_NAME}\` later if you want it.`));
141
+ console.log(
142
+ dim(` Setup continues. Run \`npm install -g ${PACKAGE_NAME}\` later if you want it.`)
143
+ );
95
144
  }
96
145
  async function runSetup(opts) {
97
- const interactive = !opts.yes;
98
- if (interactive && !(process.stdin.isTTY && process.stdout.isTTY)) {
146
+ if (opts.waitForSignin) return waitForSigninAndFinish(opts);
147
+ const url = resolveEndpoint(opts.url) ?? DEFAULT_ENDPOINT;
148
+ let apiKey = resolveApiKey(opts.apiKey);
149
+ const selfHosted = url !== DEFAULT_ENDPOINT;
150
+ const mode = setupMode({
151
+ yes: Boolean(opts.yes),
152
+ tty: Boolean(process.stdin.isTTY && process.stdout.isTTY),
153
+ ci: Boolean(process.env.CI),
154
+ hasKey: Boolean(apiKey),
155
+ selfHosted
156
+ });
157
+ if (mode === "agent-link") return runAgentLink(opts);
158
+ if (mode === "needs-key" && !opts.yes) {
99
159
  throw new Error(
100
160
  `lurq setup asks questions, and this is not an interactive terminal (CI, a pipe, or an agent shell).
101
161
  Run it non-interactively: npx ${PACKAGE_NAME} setup --yes --api-key <key>
102
162
  Get a key at ${KEYS_URL}`
103
163
  );
104
164
  }
105
- const url = resolveEndpoint(opts.url) ?? DEFAULT_ENDPOINT;
106
- let apiKey = resolveApiKey(opts.apiKey);
107
- const selfHosted = url !== DEFAULT_ENDPOINT;
165
+ const interactive = mode === "interactive";
108
166
  if (interactive) {
109
167
  const { input, checkbox, confirm, select } = await import("./dist-4XXIXHHZ.js");
110
168
  console.log(`
@@ -129,7 +187,7 @@ Get a key at ${KEYS_URL}`
129
187
  if (!reuse) apiKey = void 0;
130
188
  }
131
189
  if (!apiKey && !selfHosted) {
132
- const { keyViaBrowser } = await import("./browserAuth-B6G27USY.js");
190
+ const { keyViaBrowser } = await import("./browserAuth-J7APSD4P.js");
133
191
  console.log(" Sign in and this machine gets its key. Nothing to copy.\n");
134
192
  process.stdout.write(" Waiting for the browser\u2026 ");
135
193
  const skip = new AbortController();
@@ -138,6 +196,7 @@ Get a key at ${KEYS_URL}`
138
196
  const handoff = await keyViaBrowser({
139
197
  noOpen: opts.noOpen,
140
198
  signal: skip.signal,
199
+ via: "terminal",
141
200
  // Printed rather than only opened: the browser may not have launched,
142
201
  // and a spinner pointing at a URL nobody can see is a hung flow.
143
202
  onUrl: (link) => console.log(`
@@ -235,7 +294,10 @@ Get a key at ${KEYS_URL}`
235
294
  checked: s.detected
236
295
  }))
237
296
  });
238
- await finish(specs.filter((s) => ids.includes(s.id)), { url, apiKey });
297
+ await finish(
298
+ specs.filter((s) => ids.includes(s.id)),
299
+ { url, apiKey }
300
+ );
239
301
  return;
240
302
  }
241
303
  if (!apiKey) {
@@ -257,6 +319,46 @@ Get a key at ${KEYS_URL}`
257
319
  const selected = opts.agent ? resolveAgents(opts.agent) : agentSpecs().filter((s) => s.detected);
258
320
  await finish(selected, { url, apiKey });
259
321
  }
322
+ async function runAgentLink(opts) {
323
+ const link = await startAgentLink({ agent: opts.agent, noOpen: opts.noOpen });
324
+ if (!link) {
325
+ throw new Error(
326
+ `Could not start the sign-in listener on this machine.
327
+ Run it non-interactively instead: npx ${PACKAGE_NAME} setup --yes --api-key <key>
328
+ Get a key at ${KEYS_URL}`
329
+ );
330
+ }
331
+ const selected = opts.agent ? resolveAgents(opts.agent) : agentSpecs().filter((s) => s.detected);
332
+ console.log(
333
+ "lurq needs a one-time sign-in to connect this machine. Open this link on this computer:\n"
334
+ );
335
+ console.log(` ${link}
336
+ `);
337
+ console.log(
338
+ `Signing in finishes setup by itself: the key is stored${selected.length ? ` and lurq is connected to ${selected.map((s) => s.label).join(", ")}` : " for the lurq CLI (no coding agents detected)"}. The link works for ${LINK_WAIT_MS / 6e4} minutes.`
339
+ );
340
+ console.log("Afterwards, restart your coding agent so it loads lurq.");
341
+ }
342
+ async function waitForSigninAndFinish(opts) {
343
+ process.stdout.on("error", () => {
344
+ });
345
+ const { keyViaBrowser } = await import("./browserAuth-J7APSD4P.js");
346
+ const handoff = await keyViaBrowser({
347
+ noOpen: opts.noOpen,
348
+ deadlineMs: LINK_WAIT_MS,
349
+ via: "agent",
350
+ onUrl: (link) => {
351
+ process.stdout.write(`${LINK_PREFIX}${link}
352
+ `);
353
+ console.log = () => {
354
+ };
355
+ }
356
+ });
357
+ if (!handoff) return;
358
+ if (await validateKey(DEFAULT_ENDPOINT, handoff.key) !== "valid") return;
359
+ const selected = opts.agent ? resolveAgents(opts.agent) : agentSpecs().filter((s) => s.detected);
360
+ await finish(selected, { url: DEFAULT_ENDPOINT, apiKey: handoff.key });
361
+ }
260
362
  async function finish(selected, remote) {
261
363
  const configPath = writeUserConfig({
262
364
  apiKey: remote.apiKey,
@@ -271,19 +373,47 @@ ${green("\u2713")} API key saved to ${configPath} ${dim("(mode 0600)")}`);
271
373
  );
272
374
  const { command } = lurqInvocation();
273
375
  console.log(
274
- dim(` \`${command} verify <package>\`, \`evaluate\`, \`compare\`, \`usage\` now work anywhere.`)
376
+ dim(
377
+ ` \`${command} verify <package>\`, \`evaluate\`, \`compare\`, \`usage\` now work anywhere.`
378
+ )
275
379
  );
276
380
  if (selected.length === 0) {
277
381
  console.log(
278
382
  "\nNo agents selected or detected. Re-run `lurq setup --agent <id>` once your assistant is installed."
279
383
  );
280
- return;
384
+ } else {
385
+ const mode = { kind: "remote", ...remote };
386
+ const results = selected.map((s) => installAgent(s, mode));
387
+ const instructionsPath = installInstructionsFile();
388
+ console.log("");
389
+ printInstallReport(results, instructionsPath, mode);
390
+ }
391
+ await printFirstScan(remote);
392
+ }
393
+ var FIRST_SCAN_TIMEOUT_MS = 15e3;
394
+ async function printFirstScan(remote) {
395
+ try {
396
+ const { buildUpgradePlan, planHeadline, scanSourceDrift } = await import("./upgradePlan-ZS5IOVMZ.js");
397
+ const [plan, source] = await Promise.all([
398
+ buildUpgradePlan(process.cwd(), {
399
+ url: remote.url,
400
+ apiKey: remote.apiKey,
401
+ timeoutMs: FIRST_SCAN_TIMEOUT_MS
402
+ }),
403
+ scanSourceDrift(process.cwd())
404
+ ]);
405
+ const headline = planHeadline(plan, source);
406
+ if (!headline) return;
407
+ const { command } = lurqInvocation();
408
+ console.log(`
409
+ ${yellow("!")} ${bold("In this project right now:")} ${headline}`);
410
+ console.log(
411
+ dim(
412
+ ` \`${command} upgrade-plan\` for the list, \`${command} fix\` to write the changes that need no judgement.`
413
+ )
414
+ );
415
+ } catch {
281
416
  }
282
- const mode = { kind: "remote", ...remote };
283
- const results = selected.map((s) => installAgent(s, mode));
284
- const instructionsPath = installInstructionsFile();
285
- console.log("");
286
- printInstallReport(results, instructionsPath, mode);
287
417
  }
288
418
 
289
419
  export {
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
2
  import {
3
3
  stackResolutions
4
- } from "./chunk-LYMPYETA.js";
4
+ } from "./chunk-4JHDSVIN.js";
5
5
  import {
6
6
  getConfig
7
7
  } from "./chunk-GRJXQBQZ.js";
@@ -1,11 +1,25 @@
1
1
  import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
2
2
  import {
3
3
  handleAudit
4
- } from "./chunk-IQ4SDKKY.js";
4
+ } from "./chunk-B2UUYRBX.js";
5
+ import {
6
+ ReadBuffer,
7
+ serializeMessage
8
+ } from "./chunk-NEZNAPPN.js";
9
+ import {
10
+ searchCapabilities
11
+ } from "./chunk-KP5ZDDPE.js";
12
+ import {
13
+ handleMcpDrift,
14
+ handleMcpSurface
15
+ } from "./chunk-BN3NM47Q.js";
16
+ import {
17
+ handleDiffSurface,
18
+ handleResolveSurface
19
+ } from "./chunk-BJT2LHAR.js";
5
20
  import {
6
21
  AjvJsonSchemaValidator,
7
22
  Protocol,
8
- ReadBuffer,
9
23
  assertClientRequestTaskCapability,
10
24
  assertToolsCallTaskCapability,
11
25
  getLiteralValue,
@@ -19,20 +33,8 @@ import {
19
33
  objectFromShape,
20
34
  safeParse,
21
35
  safeParseAsync,
22
- serializeMessage,
23
36
  toJsonSchemaCompat
24
- } from "./chunk-XBIDMHSK.js";
25
- import {
26
- searchCapabilities
27
- } from "./chunk-L6N4JFW2.js";
28
- import {
29
- handleMcpDrift,
30
- handleMcpSurface
31
- } from "./chunk-3N3Q3DSW.js";
32
- import {
33
- handleDiffSurface,
34
- handleResolveSurface
35
- } from "./chunk-DB2VF5UD.js";
37
+ } from "./chunk-XLXPVN3Y.js";
36
38
  import {
37
39
  CallToolRequestSchema,
38
40
  CallToolResultSchema,
@@ -59,10 +61,10 @@ import {
59
61
  SetLevelRequestSchema,
60
62
  assertCompleteRequestPrompt,
61
63
  assertCompleteRequestResourceTemplate
62
- } from "./chunk-6AAEVQ7I.js";
64
+ } from "./chunk-D3K6IZVR.js";
63
65
  import {
64
66
  handleDiagram
65
- } from "./chunk-4F7ZESPO.js";
67
+ } from "./chunk-EQCXENKZ.js";
66
68
  import {
67
69
  handleCompare,
68
70
  handleCompat,
@@ -71,13 +73,13 @@ import {
71
73
  handleReportOutcome,
72
74
  handleUsage,
73
75
  handleVerify
74
- } from "./chunk-BULZAX2U.js";
76
+ } from "./chunk-64ZF7KO4.js";
75
77
  import {
76
78
  createDb
77
- } from "./chunk-WQ23REYT.js";
79
+ } from "./chunk-VGCDRK3S.js";
78
80
  import {
79
81
  ownerUsageDaily
80
- } from "./chunk-LYMPYETA.js";
82
+ } from "./chunk-4JHDSVIN.js";
81
83
  import {
82
84
  require_semver
83
85
  } from "./chunk-3GHJR7XR.js";
@@ -94,7 +96,7 @@ import {
94
96
  import {
95
97
  SERVER_NAME,
96
98
  VERSION
97
- } from "./chunk-GPTKSNR6.js";
99
+ } from "./chunk-72Y2FDVS.js";
98
100
  import {
99
101
  __toESM,
100
102
  init_esm_shims
@@ -1654,6 +1656,32 @@ var StdioServerTransport = class {
1654
1656
  // src/mcp/server.ts
1655
1657
  var import_semver = __toESM(require_semver(), 1);
1656
1658
 
1659
+ // src/clients/types.ts
1660
+ init_esm_shims();
1661
+ var CLIENT_IDS = [
1662
+ "claude-code",
1663
+ "claude-desktop",
1664
+ "claude-ai",
1665
+ "claude-api",
1666
+ "chatgpt",
1667
+ "openai-responses",
1668
+ "codex",
1669
+ "gemini-cli",
1670
+ "cursor",
1671
+ "vscode",
1672
+ "windsurf",
1673
+ "zed",
1674
+ "jetbrains-ai",
1675
+ "junie",
1676
+ "cline",
1677
+ "continue",
1678
+ "goose",
1679
+ "lovable",
1680
+ "replit",
1681
+ "bolt",
1682
+ "v0"
1683
+ ];
1684
+
1657
1685
  // src/mcp/metrics.ts
1658
1686
  init_esm_shims();
1659
1687
  var stats = /* @__PURE__ */ new Map();
@@ -1754,12 +1782,7 @@ async function getUsageByTool(db, ownerId, days) {
1754
1782
  const rows = await db.select({
1755
1783
  tool: ownerUsageDaily.tool,
1756
1784
  count: sql`sum(${ownerUsageDaily.count})::int`
1757
- }).from(ownerUsageDaily).where(
1758
- and(
1759
- eq(ownerUsageDaily.ownerId, ownerId),
1760
- gte(ownerUsageDaily.date, windowStart(days))
1761
- )
1762
- ).groupBy(ownerUsageDaily.tool).orderBy(desc(sql`sum(${ownerUsageDaily.count})`));
1785
+ }).from(ownerUsageDaily).where(and(eq(ownerUsageDaily.ownerId, ownerId), gte(ownerUsageDaily.date, windowStart(days)))).groupBy(ownerUsageDaily.tool).orderBy(desc(sql`sum(${ownerUsageDaily.count})`));
1763
1786
  return rows.map((r) => ({ tool: r.tool, count: Number(r.count) }));
1764
1787
  }
1765
1788
 
@@ -1800,7 +1823,8 @@ async function flush() {
1800
1823
  body: JSON.stringify({ api_key: key, batch }),
1801
1824
  signal: AbortSignal.timeout(5e3)
1802
1825
  });
1803
- if (!res.ok) logger.warn(`posthog batch rejected (${res.status}), dropped ${batch.length} event(s)`);
1826
+ if (!res.ok)
1827
+ logger.warn(`posthog batch rejected (${res.status}), dropped ${batch.length} event(s)`);
1804
1828
  } catch (err) {
1805
1829
  logger.warn("posthog batch failed:", err instanceof Error ? err.message : String(err));
1806
1830
  }
@@ -1834,7 +1858,7 @@ function buildMcpServer(db, ctx = {}) {
1834
1858
  return result;
1835
1859
  } finally {
1836
1860
  void recordUsage(db, ctx.ownerId ?? null, tool);
1837
- capture(ctx.ownerId, "tool_called", { tool, ok });
1861
+ capture(ctx.ownerId, "tool_called", { tool, ok, client: ctx.client ?? null });
1838
1862
  }
1839
1863
  })();
1840
1864
  const reply = (obj) => {
@@ -1900,7 +1924,12 @@ function buildMcpServer(db, ctx = {}) {
1900
1924
  package: npmName.describe("npm package name to verify")
1901
1925
  }
1902
1926
  },
1903
- async (args) => reply(await run("verify", () => handleVerify(db, args, ctx.ownerId ?? null)))
1927
+ async (args) => {
1928
+ const result = await run("verify", () => handleVerify(db, args, ctx.ownerId ?? null));
1929
+ const usable = result.exists && result.verdict.level !== "invalid" && result.verdict.level !== "high";
1930
+ const next = `Before writing code against ${args.package}, call usage with it (and knownVersion if you remember one): its API may have moved since your training.`;
1931
+ return reply(usable ? { ...result, next } : result);
1932
+ }
1904
1933
  );
1905
1934
  server.registerTool(
1906
1935
  "usage",
@@ -1955,7 +1984,21 @@ function buildMcpServer(db, ctx = {}) {
1955
1984
  toVersion: external_exports.string().describe("Version you are moving to")
1956
1985
  }
1957
1986
  },
1958
- async (args) => reply(await run("diff_surface", () => handleDiffSurface(db, args)))
1987
+ async (args) => reply(
1988
+ await run("diff_surface", async () => {
1989
+ const diff = await handleDiffSurface(db, args);
1990
+ if (diff.verdict === "unknown") return diff;
1991
+ const { upgradeGuideFor } = await import("./publicUpgrades-WTBGLDIK.js");
1992
+ const guide = await upgradeGuideFor(
1993
+ db,
1994
+ args.package,
1995
+ args.fromVersion,
1996
+ args.toVersion,
1997
+ getConfig().LURQ_WEB_URL
1998
+ ).catch(() => null);
1999
+ return guide ? { ...diff, upgradeGuide: guide } : diff;
2000
+ })
2001
+ )
1959
2002
  );
1960
2003
  server.registerTool(
1961
2004
  "mcp_stack",
@@ -1966,14 +2009,18 @@ function buildMcpServer(db, ctx = {}) {
1966
2009
  inputSchema: {
1967
2010
  servers: external_exports.array(
1968
2011
  external_exports.object({
1969
- server: external_exports.string().trim().min(1).max(300).describe("npm package name of the MCP server, or any label when `tools` is given"),
2012
+ server: external_exports.string().trim().min(1).max(300).describe(
2013
+ "npm package name of the MCP server, or any label when `tools` is given"
2014
+ ),
1970
2015
  version: external_exports.string().max(100).nullable().optional(),
1971
2016
  tools: external_exports.array(
1972
2017
  external_exports.object({
1973
2018
  name: external_exports.string().min(1).max(256),
1974
2019
  annotations: external_exports.record(external_exports.unknown()).optional()
1975
2020
  })
1976
- ).max(2e3).optional().describe("The tool list as the agent received it; names and annotations are enough")
2021
+ ).max(2e3).optional().describe(
2022
+ "The tool list as the agent received it; names and annotations are enough"
2023
+ )
1977
2024
  }).refine((s) => s.tools !== void 0 || npmName.safeParse(s.server).success, {
1978
2025
  message: "server must be an npm package name unless tools are given"
1979
2026
  })
@@ -1982,7 +2029,7 @@ function buildMcpServer(db, ctx = {}) {
1982
2029
  },
1983
2030
  async (args) => reply(
1984
2031
  await run("mcp_stack", async () => {
1985
- const { checkMcpStack } = await import("./mcpStack-BYJCZNIV.js");
2032
+ const { checkMcpStack } = await import("./mcpStack-ZNYIFXZ5.js");
1986
2033
  return checkMcpStack(
1987
2034
  db,
1988
2035
  args.servers.map((s) => ({
@@ -2021,6 +2068,66 @@ function buildMcpServer(db, ctx = {}) {
2021
2068
  },
2022
2069
  async (args) => reply(await run("mcp_drift", () => handleMcpDrift(db, args)))
2023
2070
  );
2071
+ server.registerTool(
2072
+ "connect_check",
2073
+ {
2074
+ title: "Will this MCP server work in my client?",
2075
+ description: "Before wiring an MCP server into a client, find out whether it will work there and exactly what it takes. Accepts an endpoint URL, an official-registry server name, or an npm package name. Answers per client (Claude Code, Claude.ai, ChatGPT, Cursor, VS Code, Codex, Gemini CLI and more): WORKS; NEEDS_SETUP with the steps (a key to send as a header, an OAuth client to pre-register and the redirect URIs to allow, a URL placeholder to fill); BLOCKED with the reason and which side causes it; or UNKNOWN when a decisive fact is not established. Built from a credential-free probe of the endpoint (whether it answers, how it authenticates, which OAuth registration methods it offers, spec deviations strict clients refuse, tool names and schemas) and from primary-sourced client constraints. Returns ready-to-paste config in each client's own format, with placeholder values. Tell the user what it found, including which client it was checked for. UNKNOWN never means it will not work.",
2076
+ annotations: READ_LIVE,
2077
+ inputSchema: {
2078
+ server: external_exports.string().trim().min(1).max(2048).describe(
2079
+ "Endpoint URL (https://\u2026), official registry name (io.github.acme/weather), or npm package name"
2080
+ ),
2081
+ client: external_exports.enum(CLIENT_IDS).optional().describe(
2082
+ "One client to check, e.g. claude-code, cursor, chatgpt; omit for every client"
2083
+ )
2084
+ }
2085
+ },
2086
+ async (args) => reply(
2087
+ await run("connect_check", async () => {
2088
+ const [{ handleConnectCheck }, { sharedSafeFetch }] = await Promise.all([
2089
+ import("./check-2JTQDQA6.js"),
2090
+ import("./safeFetch-COERXGFN.js")
2091
+ ]);
2092
+ return handleConnectCheck(
2093
+ db,
2094
+ { server: args.server, client: args.client ?? null },
2095
+ { liveProbe: { fetch: sharedSafeFetch() } }
2096
+ );
2097
+ })
2098
+ )
2099
+ );
2100
+ if (ctx.local) {
2101
+ server.registerTool(
2102
+ "upkeep",
2103
+ {
2104
+ title: "What needs fixing in this project",
2105
+ description: "The upkeep plan for the project you are editing, read from its own files. Returns findings across domains: environment variables the code reads that no .env file declares, model identifiers the provider has retired or put an end date on, and \u2014 when you pass `upgrade` \u2014 the call sites an upgrade breaks, the replacement the package itself proves, and the manifest ranges left stale. Each finding carries either exact edits (a rename the package proves, byte ranges you can apply) or a brief with the facts you cannot look up: the exports the target version actually ships, with their kinds and arities. A domain that could not run says so; a skipped domain is never the same as a clean one. Needs no API key. Use it before editing a project you have just opened, or after an upgrade to see what it broke.",
2106
+ annotations: READ_LIVE,
2107
+ inputSchema: {
2108
+ dir: external_exports.string().max(4096).optional().describe(
2109
+ "Project root. Defaults to the working directory this server was started in."
2110
+ ),
2111
+ upgrade: external_exports.array(
2112
+ external_exports.object({
2113
+ package: npmName,
2114
+ fromVersion: external_exports.string().min(1).max(100),
2115
+ toVersion: external_exports.string().min(1).max(100)
2116
+ })
2117
+ ).max(50).optional().describe(
2118
+ "Upgrades to assess. Without this the package domain is skipped, because working out what moved needs the index and this tool runs without a key."
2119
+ ),
2120
+ domains: external_exports.array(external_exports.enum(["package", "mcp-config", "env", "api", "model"])).max(5).optional().describe("Limit to these domains. Default: every domain with a detector.")
2121
+ }
2122
+ },
2123
+ async (args) => reply(
2124
+ await run("upkeep", async () => {
2125
+ const { handleUpkeep } = await import("./upkeepHandler-VFGYXJKB.js");
2126
+ return handleUpkeep(args);
2127
+ })
2128
+ )
2129
+ );
2130
+ }
2024
2131
  server.registerTool(
2025
2132
  "audit",
2026
2133
  {
@@ -2088,7 +2195,9 @@ function buildMcpServer(db, ctx = {}) {
2088
2195
  );
2089
2196
  server.server.registerCapabilities({ resources: {}, prompts: {} });
2090
2197
  server.server.setRequestHandler(ListResourcesRequestSchema, () => ({ resources: [] }));
2091
- server.server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({ resourceTemplates: [] }));
2198
+ server.server.setRequestHandler(ListResourceTemplatesRequestSchema, () => ({
2199
+ resourceTemplates: []
2200
+ }));
2092
2201
  server.server.setRequestHandler(ListPromptsRequestSchema, () => ({ prompts: [] }));
2093
2202
  return server;
2094
2203
  }
@@ -2096,7 +2205,7 @@ var SERVE_NEEDS_DATABASE = "`lurq serve` answers from a local lurq index and nee
2096
2205
  async function startMcpServer() {
2097
2206
  if (!getConfig().DATABASE_URL) throw new Error(SERVE_NEEDS_DATABASE);
2098
2207
  const { db, close } = createDb();
2099
- const server = buildMcpServer(db);
2208
+ const server = buildMcpServer(db, { local: true });
2100
2209
  const shutdown = async () => {
2101
2210
  try {
2102
2211
  await close();