lurqrun 0.1.6 → 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.
- package/README.md +311 -139
- package/dist/auditHandler-VWCXSDVO.js +24 -0
- package/dist/autopilotInit-Q62MX5M6.js +178 -0
- package/dist/bin/lurq.js +3255 -23319
- package/dist/browserAuth-J7APSD4P.js +96 -0
- package/dist/cache-AEAKCV4I.js +12 -0
- package/dist/check-2JTQDQA6.js +2613 -0
- package/dist/check-PQSQ2MMA.js +192 -0
- package/dist/checkUpgrade-5YW77OBL.js +24 -0
- package/dist/chunk-2GAYNIHG.js +40 -0
- package/dist/chunk-2O6Z37IT.js +423 -0
- package/dist/chunk-2WD4QAH4.js +116 -0
- package/dist/chunk-3676XOBU.js +2235 -0
- package/dist/chunk-3D2MPGOQ.js +181 -0
- package/dist/chunk-3GHJR7XR.js +2049 -0
- package/dist/chunk-4ESO33J6.js +34 -0
- package/dist/chunk-4JHDSVIN.js +1229 -0
- package/dist/chunk-4KCPOMG6.js +68 -0
- package/dist/chunk-53SG6XWA.js +141 -0
- package/dist/chunk-5ABNDB3I.js +37 -0
- package/dist/chunk-5ALIJFDA.js +114 -0
- package/dist/chunk-63MUJNZL.js +318 -0
- package/dist/chunk-64ZF7KO4.js +1571 -0
- package/dist/chunk-6DM6UQFD.js +318 -0
- package/dist/chunk-6EQ3ARXA.js +304 -0
- package/dist/chunk-6L67QMCP.js +92 -0
- package/dist/chunk-72Y2FDVS.js +172 -0
- package/dist/chunk-A3TYI2TF.js +288 -0
- package/dist/chunk-B2UUYRBX.js +536 -0
- package/dist/chunk-BJT2LHAR.js +320 -0
- package/dist/chunk-BM3LF5T6.js +132 -0
- package/dist/chunk-BN3NM47Q.js +214 -0
- package/dist/chunk-BUALU27S.js +123 -0
- package/dist/chunk-C6GLE626.js +160 -0
- package/dist/chunk-D3K6IZVR.js +12845 -0
- package/dist/chunk-D3VTZS7V.js +222 -0
- package/dist/chunk-DM37MTOO.js +636 -0
- package/dist/chunk-DONTW3NE.js +171 -0
- package/dist/chunk-DSROTZ3Z.js +38 -0
- package/dist/chunk-ELGCAM7P.js +184 -0
- package/dist/chunk-EQCXENKZ.js +130 -0
- package/dist/chunk-EYAKM6YN.js +96 -0
- package/dist/chunk-FDFPMBCA.js +112 -0
- package/dist/chunk-FVYFV5HA.js +154 -0
- package/dist/chunk-GE37NVLN.js +15 -0
- package/dist/chunk-GM5Y555O.js +143 -0
- package/dist/chunk-GRJXQBQZ.js +793 -0
- package/dist/chunk-HWFX4BC4.js +177 -0
- package/dist/chunk-I3M2KJXB.js +56 -0
- package/dist/chunk-IFNONGRQ.js +603 -0
- package/dist/chunk-J3U2CPSK.js +136 -0
- package/dist/chunk-J6XQ7OPZ.js +74 -0
- package/dist/chunk-KMV4Y6R3.js +127 -0
- package/dist/chunk-KP5ZDDPE.js +340 -0
- package/dist/chunk-KYKSZ3XZ.js +202 -0
- package/dist/chunk-LEGPB7DO.js +81 -0
- package/dist/chunk-LUAKDHLZ.js +40 -0
- package/dist/chunk-MHUEVBVO.js +35 -0
- package/dist/chunk-MYGSLK44.js +37 -0
- package/dist/chunk-NEZNAPPN.js +41 -0
- package/dist/chunk-NPVN2THM.js +197 -0
- package/dist/chunk-NYZU5NCW.js +23 -0
- package/dist/chunk-O4KHCV6I.js +320 -0
- package/dist/chunk-ONDVTXUO.js +240 -0
- package/dist/chunk-OTJFHESY.js +176 -0
- package/dist/chunk-P6MIKSPY.js +243 -0
- package/dist/chunk-Q5VPF4WI.js +26 -0
- package/dist/chunk-QCRBX3LV.js +165 -0
- package/dist/chunk-QKGYDMWB.js +7409 -0
- package/dist/chunk-QSL6QN5X.js +115 -0
- package/dist/chunk-QUIMQ7YL.js +73 -0
- package/dist/chunk-RG3YLU6E.js +49 -0
- package/dist/chunk-SHCEBP3J.js +107 -0
- package/dist/chunk-SHZFOSXC.js +462 -0
- package/dist/chunk-SOXFMMXC.js +151 -0
- package/dist/chunk-TDTYV6QI.js +119 -0
- package/dist/chunk-TNTXWSYA.js +19 -0
- package/dist/chunk-TUXQ32WE.js +2251 -0
- package/dist/chunk-VGCDRK3S.js +37 -0
- package/dist/chunk-VLRHFMGJ.js +58 -0
- package/dist/chunk-WHX2ZFCG.js +4048 -0
- package/dist/chunk-X4W64MHU.js +2005 -0
- package/dist/chunk-XBQA4I36.js +92 -0
- package/dist/chunk-XGOV6KV4.js +413 -0
- package/dist/chunk-XIFQIFSZ.js +940 -0
- package/dist/chunk-XLXPVN3Y.js +15393 -0
- package/dist/chunk-ZJMLQ37G.js +90 -0
- package/dist/client-MU4EUDZV.js +15 -0
- package/dist/commands-UOOTMBKA.js +1023 -0
- package/dist/compat-Q5DVPITN.js +201 -0
- package/dist/constants-DJFOFZ44.js +24 -0
- package/dist/dashboardIssue-KBKLQMGC.js +274 -0
- package/dist/diff-I4SNUHU3.js +13 -0
- package/dist/dist-4XXIXHHZ.js +12945 -0
- package/dist/domains-VRT4BRVZ.js +14 -0
- package/dist/e2b-FVPHDULZ.js +172 -0
- package/dist/env-UN6KGZ7S.js +15 -0
- package/dist/envCheck-KUPTORFQ.js +71 -0
- package/dist/extract-6WG265BL.js +455 -0
- package/dist/fetch-PJ3SC32M.js +22 -0
- package/dist/firstTouch-COJCMOB3.js +55 -0
- package/dist/fix-3EDWNKW3.js +220 -0
- package/dist/handlers-4Q37WIFT.js +55 -0
- package/dist/hook-NA66XJLC.js +412 -0
- package/dist/http-25GJ6SKK.js +6928 -0
- package/dist/ingestQueue-FSVJC3AA.js +37 -0
- package/dist/install-G2HHXYJ2.js +20 -0
- package/dist/installSkill-5TIMYIJZ.js +70 -0
- package/dist/inventory-5AWSLJYU.js +31 -0
- package/dist/local-XPZMRH5R.js +13 -0
- package/dist/manifest-ENMIC54B.js +13 -0
- package/dist/mcp-PENLL2PK.js +500 -0
- package/dist/mcpConfig-3LYPRY5Q.js +80 -0
- package/dist/mcpHandlers-PO7GENA7.js +22 -0
- package/dist/mcpScan-ULP626TQ.js +1735 -0
- package/dist/mcpScanWorkflow-27O44FOE.js +98 -0
- package/dist/mcpStack-ZNYIFXZ5.js +20 -0
- package/dist/model-ASMZWLM7.js +214 -0
- package/dist/packages-RWF2LXST.js +40 -0
- package/dist/plan-SDILIDZT.js +465 -0
- package/dist/planView-ZAKRTGVS.js +82 -0
- package/dist/policy-JAGNMQJI.js +115 -0
- package/dist/probe-3IK646WN.js +610 -0
- package/dist/publicUpgrades-WTBGLDIK.js +42 -0
- package/dist/references-I6Y4BSRR.js +16 -0
- package/dist/release-7IU2R4YG.js +128 -0
- package/dist/remote-FN6225AH.js +42 -0
- package/dist/rename-OS6JYBZQ.js +204 -0
- package/dist/reportRuns-O4X7ZFTX.js +77 -0
- package/dist/safeFetch-COERXGFN.js +19 -0
- package/dist/sandbox-SAPSRKEI.js +39 -0
- package/dist/sarif-WLVJFJ7U.js +125 -0
- package/dist/server-OLTY3NYT.js +59 -0
- package/dist/surface-7MHE3RL7.js +143 -0
- package/dist/surface-JS2XU3U3.js +38 -0
- package/dist/surfaceHandlers-4B6TMZ34.js +20 -0
- package/dist/typecheck-NGOKNAJY.js +282 -0
- package/dist/types-M5JP2W3D.js +10 -0
- package/dist/uninstall-I2IJP5JZ.js +200 -0
- package/dist/upgrade-FS26DJGG.js +650 -0
- package/dist/upgradePlan-ZS5IOVMZ.js +181 -0
- package/dist/upkeepHandler-VFGYXJKB.js +13 -0
- package/dist/userConfig-ICASHI47.js +20 -0
- package/dist/watch-OCNEUXG6.js +204 -0
- package/package.json +26 -20
- package/templates/agent-rules.md +4 -4
- package/templates/skill-instructions.md +35 -17
- package/dist/bin/lurq.js.map +0 -1
- package/dist/index.d.ts +0 -805
- package/dist/index.js +0 -23570
- package/dist/index.js.map +0 -1
- package/drizzle/0000_confused_fabian_cortez.sql +0 -54
- package/drizzle/0001_aspiring_timeslip.sql +0 -15
- package/drizzle/0002_lyrical_lila_cheney.sql +0 -14
- package/drizzle/0003_violet_giant_girl.sql +0 -14
- package/drizzle/0004_slim_valeria_richards.sql +0 -15
- package/drizzle/0005_petite_luke_cage.sql +0 -12
- package/drizzle/0006_calm_nighthawk.sql +0 -3
- package/drizzle/0007_slimy_naoko.sql +0 -1
- package/drizzle/0008_peaceful_tigra.sql +0 -1
- package/drizzle/0009_smooth_harrier.sql +0 -10
- package/drizzle/0010_curved_amphibian.sql +0 -2
- package/drizzle/0011_compat_provenance_closures.sql +0 -11
- package/drizzle/0012_api_surfaces.sql +0 -9
- package/drizzle/0013_nice_thanos.sql +0 -1
- package/drizzle/0014_luxuriant_malcolm_colcord.sql +0 -10
- package/drizzle/0015_past_fat_cobra.sql +0 -11
- package/drizzle/0016_futuristic_junta.sql +0 -50
- package/drizzle/0017_absent_grandmaster.sql +0 -20
- package/drizzle/0018_rainy_proemial_gods.sql +0 -1
- package/drizzle/0019_dashing_korvac.sql +0 -11
- package/drizzle/0020_normal_vulture.sql +0 -3
- package/drizzle/0021_dazzling_blue_shield.sql +0 -17
- package/drizzle/0022_massive_ghost_rider.sql +0 -24
- package/drizzle/0023_next_shatterstar.sql +0 -1
- package/drizzle/0024_dusty_maelstrom.sql +0 -15
- package/drizzle/0025_gifted_harpoon.sql +0 -5
- package/drizzle/0026_awesome_mordo.sql +0 -1
- package/drizzle/0027_charming_ulik.sql +0 -2
- package/drizzle/0028_romantic_loners.sql +0 -2
- package/drizzle/0029_busy_korvac.sql +0 -16
- package/drizzle/0030_steady_mathemanic.sql +0 -6
- package/drizzle/0031_redundant_maginty.sql +0 -2
- package/drizzle/0032_stack_resolutions.sql +0 -14
- package/drizzle/0033_graceful_tyger_tiger.sql +0 -3
- package/drizzle/0034_uneven_thunderbird.sql +0 -1
- package/drizzle/0035_api_key_scopes.sql +0 -1
- package/drizzle/0036_policy_audit.sql +0 -21
- package/drizzle/0037_subscription_seats.sql +0 -1
- package/drizzle/0038_symbol_offsets.sql +0 -2
- package/drizzle/0039_mcp_runtime_scans.sql +0 -80
- package/drizzle/0040_subscription_overage_and_interval.sql +0 -4
- package/drizzle/0041_account_email.sql +0 -38
- package/drizzle/0042_alert_channels.sql +0 -21
- package/drizzle/meta/0000_snapshot.json +0 -370
- package/drizzle/meta/0001_snapshot.json +0 -482
- package/drizzle/meta/0002_snapshot.json +0 -575
- package/drizzle/meta/0003_snapshot.json +0 -667
- package/drizzle/meta/0004_snapshot.json +0 -769
- package/drizzle/meta/0005_snapshot.json +0 -864
- package/drizzle/meta/0006_snapshot.json +0 -882
- package/drizzle/meta/0007_snapshot.json +0 -876
- package/drizzle/meta/0008_snapshot.json +0 -882
- package/drizzle/meta/0009_snapshot.json +0 -948
- package/drizzle/meta/0010_snapshot.json +0 -969
- package/drizzle/meta/0011_snapshot.json +0 -1049
- package/drizzle/meta/0012_snapshot.json +0 -1115
- package/drizzle/meta/0013_snapshot.json +0 -1121
- package/drizzle/meta/0014_snapshot.json +0 -1190
- package/drizzle/meta/0015_snapshot.json +0 -1280
- package/drizzle/meta/0016_snapshot.json +0 -1683
- package/drizzle/meta/0017_snapshot.json +0 -1834
- package/drizzle/meta/0018_snapshot.json +0 -1834
- package/drizzle/meta/0019_snapshot.json +0 -1909
- package/drizzle/meta/0020_snapshot.json +0 -1921
- package/drizzle/meta/0021_snapshot.json +0 -2045
- package/drizzle/meta/0022_snapshot.json +0 -2246
- package/drizzle/meta/0023_snapshot.json +0 -2252
- package/drizzle/meta/0024_snapshot.json +0 -2375
- package/drizzle/meta/0025_snapshot.json +0 -2407
- package/drizzle/meta/0026_snapshot.json +0 -2413
- package/drizzle/meta/0027_snapshot.json +0 -2425
- package/drizzle/meta/0028_snapshot.json +0 -2438
- package/drizzle/meta/0029_snapshot.json +0 -2546
- package/drizzle/meta/0030_snapshot.json +0 -2586
- package/drizzle/meta/0031_snapshot.json +0 -2598
- package/drizzle/meta/0032_snapshot.json +0 -2699
- package/drizzle/meta/0033_snapshot.json +0 -2712
- package/drizzle/meta/0034_snapshot.json +0 -2719
- package/drizzle/meta/0035_snapshot.json +0 -2726
- package/drizzle/meta/0036_snapshot.json +0 -2876
- package/drizzle/meta/0037_snapshot.json +0 -2883
- package/drizzle/meta/0038_snapshot.json +0 -2895
- package/drizzle/meta/0039_snapshot.json +0 -3501
- package/drizzle/meta/0040_snapshot.json +0 -3527
- package/drizzle/meta/0041_snapshot.json +0 -3824
- package/drizzle/meta/0042_snapshot.json +0 -3960
- package/drizzle/meta/_journal.json +0 -307
- package/src/data/seed.json +0 -253
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
checkApi
|
|
4
|
+
} from "./chunk-SOXFMMXC.js";
|
|
5
|
+
import {
|
|
6
|
+
require_dist
|
|
7
|
+
} from "./chunk-QKGYDMWB.js";
|
|
8
|
+
import "./chunk-3GHJR7XR.js";
|
|
9
|
+
import {
|
|
10
|
+
__toESM,
|
|
11
|
+
init_esm_shims
|
|
12
|
+
} from "./chunk-I3M2KJXB.js";
|
|
13
|
+
|
|
14
|
+
// src/api/check.ts
|
|
15
|
+
init_esm_shims();
|
|
16
|
+
import { execFile } from "child_process";
|
|
17
|
+
import { existsSync, readFileSync } from "fs";
|
|
18
|
+
import { relative, resolve } from "path";
|
|
19
|
+
import { promisify } from "util";
|
|
20
|
+
|
|
21
|
+
// src/api/openapi.ts
|
|
22
|
+
init_esm_shims();
|
|
23
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
24
|
+
var METHODS = ["get", "put", "post", "delete", "options", "head", "patch", "trace"];
|
|
25
|
+
var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
26
|
+
function deref(root, node, seen = /* @__PURE__ */ new Set()) {
|
|
27
|
+
if (!isRecord(node)) return null;
|
|
28
|
+
const ref = node.$ref;
|
|
29
|
+
if (typeof ref !== "string") return node;
|
|
30
|
+
if (!ref.startsWith("#/") || seen.has(ref)) return null;
|
|
31
|
+
seen.add(ref);
|
|
32
|
+
let cursor = root;
|
|
33
|
+
for (const segment of ref.slice(2).split("/")) {
|
|
34
|
+
if (!isRecord(cursor)) return null;
|
|
35
|
+
cursor = cursor[segment.replace(/~1/g, "/").replace(/~0/g, "~")];
|
|
36
|
+
}
|
|
37
|
+
return deref(root, cursor, seen);
|
|
38
|
+
}
|
|
39
|
+
function readParams(root, shared, own) {
|
|
40
|
+
const required = /* @__PURE__ */ new Set();
|
|
41
|
+
const optional = /* @__PURE__ */ new Set();
|
|
42
|
+
for (const list of [shared, own]) {
|
|
43
|
+
if (!Array.isArray(list)) continue;
|
|
44
|
+
for (const raw of list) {
|
|
45
|
+
const param = deref(root, raw);
|
|
46
|
+
const name = param?.name;
|
|
47
|
+
if (typeof name !== "string") continue;
|
|
48
|
+
const key = `${name} (${typeof param?.in === "string" ? param.in : "unknown"})`;
|
|
49
|
+
if (param?.required === true) {
|
|
50
|
+
required.add(key);
|
|
51
|
+
optional.delete(key);
|
|
52
|
+
} else if (!required.has(key)) {
|
|
53
|
+
optional.add(key);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { required: [...required].sort(), optional: [...optional].sort() };
|
|
58
|
+
}
|
|
59
|
+
function readBodyFields(root, requestBody) {
|
|
60
|
+
const body = deref(root, requestBody);
|
|
61
|
+
if (!body || body.required !== true) return [];
|
|
62
|
+
const content = body.content;
|
|
63
|
+
if (!isRecord(content)) return [];
|
|
64
|
+
const out = /* @__PURE__ */ new Set();
|
|
65
|
+
for (const media of Object.values(content)) {
|
|
66
|
+
const schema = deref(root, isRecord(media) ? media.schema : null);
|
|
67
|
+
const required = schema?.required;
|
|
68
|
+
if (!Array.isArray(required)) continue;
|
|
69
|
+
for (const field of required) if (typeof field === "string") out.add(field);
|
|
70
|
+
}
|
|
71
|
+
return [...out].sort();
|
|
72
|
+
}
|
|
73
|
+
function extractApiSurface(source, label = "document") {
|
|
74
|
+
const empty = { title: null, version: null, operations: /* @__PURE__ */ new Map() };
|
|
75
|
+
let doc;
|
|
76
|
+
try {
|
|
77
|
+
doc = (0, import_yaml.parse)(source);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
return {
|
|
80
|
+
...empty,
|
|
81
|
+
unreadableReason: `${label} is not valid YAML or JSON: ${err instanceof Error ? err.message : String(err)}`
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
if (!isRecord(doc)) return { ...empty, unreadableReason: `${label} is not an object` };
|
|
85
|
+
if (!doc.openapi && !doc.swagger) {
|
|
86
|
+
return { ...empty, unreadableReason: `${label} has no openapi/swagger version field` };
|
|
87
|
+
}
|
|
88
|
+
const info = isRecord(doc.info) ? doc.info : {};
|
|
89
|
+
const paths = isRecord(doc.paths) ? doc.paths : {};
|
|
90
|
+
const operations = /* @__PURE__ */ new Map();
|
|
91
|
+
for (const [path, rawItem] of Object.entries(paths)) {
|
|
92
|
+
const item = deref(doc, rawItem);
|
|
93
|
+
if (!item) continue;
|
|
94
|
+
for (const method of METHODS) {
|
|
95
|
+
const op = item[method];
|
|
96
|
+
if (!isRecord(op)) continue;
|
|
97
|
+
const { required, optional } = readParams(doc, item.parameters, op.parameters);
|
|
98
|
+
const responses = isRecord(op.responses) ? Object.keys(op.responses).sort() : [];
|
|
99
|
+
const id = `${method.toUpperCase()} ${path}`;
|
|
100
|
+
operations.set(id, {
|
|
101
|
+
id,
|
|
102
|
+
method: method.toUpperCase(),
|
|
103
|
+
path,
|
|
104
|
+
requiredParams: required,
|
|
105
|
+
optionalParams: optional,
|
|
106
|
+
requiredBodyFields: readBodyFields(doc, op.requestBody),
|
|
107
|
+
responseCodes: responses,
|
|
108
|
+
deprecated: op.deprecated === true
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
title: typeof info.title === "string" ? info.title : null,
|
|
114
|
+
version: typeof info.version === "string" ? info.version : null,
|
|
115
|
+
operations,
|
|
116
|
+
...operations.size === 0 ? { unreadableReason: `${label} declares no operations` } : {}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/api/check.ts
|
|
121
|
+
var execFileP = promisify(execFile);
|
|
122
|
+
var CANDIDATES = [
|
|
123
|
+
"openapi.yaml",
|
|
124
|
+
"openapi.yml",
|
|
125
|
+
"openapi.json",
|
|
126
|
+
"swagger.yaml",
|
|
127
|
+
"swagger.yml",
|
|
128
|
+
"swagger.json",
|
|
129
|
+
"api/openapi.yaml",
|
|
130
|
+
"api/openapi.yml",
|
|
131
|
+
"api/openapi.json",
|
|
132
|
+
"docs/openapi.yaml",
|
|
133
|
+
"docs/openapi.yml"
|
|
134
|
+
];
|
|
135
|
+
function findSpec(dir) {
|
|
136
|
+
for (const candidate of CANDIDATES) {
|
|
137
|
+
const full = resolve(dir, candidate);
|
|
138
|
+
if (existsSync(full)) return full;
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
async function showAtRevision(dir, rev, repoPath) {
|
|
143
|
+
try {
|
|
144
|
+
const { stdout } = await execFileP("git", ["show", `${rev}:${repoPath}`], {
|
|
145
|
+
cwd: dir,
|
|
146
|
+
maxBuffer: 32 * 1024 * 1024
|
|
147
|
+
});
|
|
148
|
+
return stdout;
|
|
149
|
+
} catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async function runApiCheck(dir, opts = {}) {
|
|
154
|
+
const against = opts.against ?? "HEAD";
|
|
155
|
+
const specPath = opts.spec ? resolve(dir, opts.spec) : findSpec(dir);
|
|
156
|
+
const spec = specPath ? relative(dir, specPath) || specPath : "(none found)";
|
|
157
|
+
const base = { spec, against, title: null, fromVersion: null, toVersion: null };
|
|
158
|
+
if (!specPath) {
|
|
159
|
+
return {
|
|
160
|
+
...base,
|
|
161
|
+
verdict: "inconclusive",
|
|
162
|
+
versionCovers: null,
|
|
163
|
+
diff: {
|
|
164
|
+
breaking: [],
|
|
165
|
+
other: [],
|
|
166
|
+
inconclusive: `no OpenAPI document found in ${dir}. Name one: lurq check-api <file>`
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const current = extractApiSurface(readFileSync(specPath, "utf8"), spec);
|
|
171
|
+
const previousSource = await showAtRevision(dir, against, spec);
|
|
172
|
+
if (previousSource === null) {
|
|
173
|
+
return {
|
|
174
|
+
...base,
|
|
175
|
+
title: current.title,
|
|
176
|
+
toVersion: current.version,
|
|
177
|
+
verdict: "inconclusive",
|
|
178
|
+
versionCovers: null,
|
|
179
|
+
diff: {
|
|
180
|
+
breaking: [],
|
|
181
|
+
other: [],
|
|
182
|
+
inconclusive: `${spec} does not exist at ${against}, so there is nothing to compare against`
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const previous = extractApiSurface(previousSource, `${spec} at ${against}`);
|
|
187
|
+
return { ...base, ...checkApi(previous, current) };
|
|
188
|
+
}
|
|
189
|
+
export {
|
|
190
|
+
findSpec,
|
|
191
|
+
runApiCheck
|
|
192
|
+
};
|
|
@@ -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
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-I3M2KJXB.js";
|
|
5
|
+
|
|
6
|
+
// src/github/types.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
var DEFAULT_REPO_POLICY = {
|
|
9
|
+
enabled: false,
|
|
10
|
+
scope: "blocking",
|
|
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 }
|
|
17
|
+
};
|
|
18
|
+
var RUN_TRIGGERS = ["schedule", "dispatch", "push", "pull_request", "other"];
|
|
19
|
+
var UPGRADE_SEVERITIES = ["blocking", "warning", "ok", "unverified"];
|
|
20
|
+
var UPGRADE_RUN_STATUSES = [
|
|
21
|
+
"checked",
|
|
22
|
+
"skipped",
|
|
23
|
+
"edited",
|
|
24
|
+
"pr_open",
|
|
25
|
+
"merged",
|
|
26
|
+
"failed"
|
|
27
|
+
];
|
|
28
|
+
var REPO_MANIFEST_CAP = 25;
|
|
29
|
+
var REPO_DRIFT_DETAIL_CAP = 200;
|
|
30
|
+
var TRANSITIVE_DETAIL_CAP = 100;
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
DEFAULT_REPO_POLICY,
|
|
34
|
+
RUN_TRIGGERS,
|
|
35
|
+
UPGRADE_SEVERITIES,
|
|
36
|
+
UPGRADE_RUN_STATUSES,
|
|
37
|
+
REPO_MANIFEST_CAP,
|
|
38
|
+
REPO_DRIFT_DETAIL_CAP,
|
|
39
|
+
TRANSITIVE_DETAIL_CAP
|
|
40
|
+
};
|
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
bold,
|
|
4
|
+
dim,
|
|
5
|
+
green,
|
|
6
|
+
yellow
|
|
7
|
+
} from "./chunk-4KCPOMG6.js";
|
|
8
|
+
import {
|
|
9
|
+
agentSpecs,
|
|
10
|
+
installAgent,
|
|
11
|
+
installInstructionsFile,
|
|
12
|
+
lurqInvocation,
|
|
13
|
+
printInstallReport,
|
|
14
|
+
resolveAgents
|
|
15
|
+
} from "./chunk-DM37MTOO.js";
|
|
16
|
+
import {
|
|
17
|
+
MissingKeyError
|
|
18
|
+
} from "./chunk-OTJFHESY.js";
|
|
19
|
+
import {
|
|
20
|
+
readUserConfig,
|
|
21
|
+
resolveApiKey,
|
|
22
|
+
resolveEndpoint,
|
|
23
|
+
writeUserConfig
|
|
24
|
+
} from "./chunk-J6XQ7OPZ.js";
|
|
25
|
+
import {
|
|
26
|
+
openInBrowser
|
|
27
|
+
} from "./chunk-TNTXWSYA.js";
|
|
28
|
+
import {
|
|
29
|
+
DEFAULT_ENDPOINT,
|
|
30
|
+
KEYS_URL,
|
|
31
|
+
PACKAGE_NAME
|
|
32
|
+
} from "./chunk-72Y2FDVS.js";
|
|
33
|
+
import {
|
|
34
|
+
init_esm_shims
|
|
35
|
+
} from "./chunk-I3M2KJXB.js";
|
|
36
|
+
|
|
37
|
+
// src/cli/install.ts
|
|
38
|
+
init_esm_shims();
|
|
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
|
|
84
|
+
async function withSetupOnMissingKey(run, ask = askToConnect, setup = () => runSetup({})) {
|
|
85
|
+
try {
|
|
86
|
+
await run();
|
|
87
|
+
} catch (err) {
|
|
88
|
+
if (!(err instanceof MissingKeyError) || !await ask()) throw err;
|
|
89
|
+
await setup();
|
|
90
|
+
await run();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function askToConnect() {
|
|
94
|
+
const interactive = process.stdin.isTTY && process.stdout.isTTY && !process.env.CI && !process.argv.includes("--json");
|
|
95
|
+
if (!interactive) return false;
|
|
96
|
+
const { confirm } = await import("./dist-4XXIXHHZ.js");
|
|
97
|
+
return confirm({
|
|
98
|
+
message: "This machine has no lurq API key yet. Connect it now?",
|
|
99
|
+
default: true
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
async function validateKey(url, apiKey) {
|
|
103
|
+
try {
|
|
104
|
+
const res = await fetch(url, {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: {
|
|
107
|
+
"Content-Type": "application/json",
|
|
108
|
+
Accept: "application/json, text/event-stream",
|
|
109
|
+
Authorization: `Bearer ${apiKey}`
|
|
110
|
+
},
|
|
111
|
+
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/list" }),
|
|
112
|
+
// A black-holed endpoint must not hang setup; it reads as unreachable.
|
|
113
|
+
signal: AbortSignal.timeout(15e3)
|
|
114
|
+
});
|
|
115
|
+
if (res.ok) return "valid";
|
|
116
|
+
if (res.status === 401 || res.status === 403) return "invalid";
|
|
117
|
+
return "unreachable";
|
|
118
|
+
} catch {
|
|
119
|
+
return "unreachable";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
function runningFromNpx(moduleUrl = import.meta.url) {
|
|
123
|
+
return moduleUrl.includes("/_npx/");
|
|
124
|
+
}
|
|
125
|
+
function installGlobally() {
|
|
126
|
+
process.stdout.write(` Installing ${PACKAGE_NAME} globally (npm install -g, a few seconds)\u2026 `);
|
|
127
|
+
const res = spawnSync("npm", ["install", "--global", `${PACKAGE_NAME}@latest`], {
|
|
128
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
129
|
+
encoding: "utf8",
|
|
130
|
+
// npm is a .cmd shim on Windows, which is not directly executable.
|
|
131
|
+
shell: process.platform === "win32"
|
|
132
|
+
});
|
|
133
|
+
if (res.status === 0) {
|
|
134
|
+
console.log(green("ok"));
|
|
135
|
+
console.log(dim(" `lurq` now works in any terminal, no npx needed."));
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
console.log(yellow("skipped"));
|
|
139
|
+
const reason = (res.stderr || res.error?.message || "").trim().split("\n").pop();
|
|
140
|
+
if (reason) console.log(dim(` ${reason}`));
|
|
141
|
+
console.log(
|
|
142
|
+
dim(` Setup continues. Run \`npm install -g ${PACKAGE_NAME}\` later if you want it.`)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
async function runSetup(opts) {
|
|
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) {
|
|
159
|
+
throw new Error(
|
|
160
|
+
`lurq setup asks questions, and this is not an interactive terminal (CI, a pipe, or an agent shell).
|
|
161
|
+
Run it non-interactively: npx ${PACKAGE_NAME} setup --yes --api-key <key>
|
|
162
|
+
Get a key at ${KEYS_URL}`
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
const interactive = mode === "interactive";
|
|
166
|
+
if (interactive) {
|
|
167
|
+
const { input, checkbox, confirm, select } = await import("./dist-4XXIXHHZ.js");
|
|
168
|
+
console.log(`
|
|
169
|
+
${bold("lurq setup")}: connect this machine to the package index.
|
|
170
|
+
`);
|
|
171
|
+
console.log(` Endpoint: ${url}${selfHosted ? dim(" (your own server)") : ""}
|
|
172
|
+
`);
|
|
173
|
+
if (runningFromNpx()) {
|
|
174
|
+
const goGlobal = await confirm({
|
|
175
|
+
message: `Install ${PACKAGE_NAME} globally, so \`lurq\` works without npx?`,
|
|
176
|
+
default: true
|
|
177
|
+
});
|
|
178
|
+
if (goGlobal) installGlobally();
|
|
179
|
+
console.log("");
|
|
180
|
+
}
|
|
181
|
+
if (apiKey && !opts.apiKey) {
|
|
182
|
+
const stored = readUserConfig().apiKey === apiKey;
|
|
183
|
+
const reuse = await confirm({
|
|
184
|
+
message: `Use the API key already configured${stored ? " on this machine" : " in your environment"}?`,
|
|
185
|
+
default: true
|
|
186
|
+
});
|
|
187
|
+
if (!reuse) apiKey = void 0;
|
|
188
|
+
}
|
|
189
|
+
if (!apiKey && !selfHosted) {
|
|
190
|
+
const { keyViaBrowser } = await import("./browserAuth-J7APSD4P.js");
|
|
191
|
+
console.log(" Sign in and this machine gets its key. Nothing to copy.\n");
|
|
192
|
+
process.stdout.write(" Waiting for the browser\u2026 ");
|
|
193
|
+
const skip = new AbortController();
|
|
194
|
+
const onEnter = () => skip.abort();
|
|
195
|
+
process.stdin.once("data", onEnter);
|
|
196
|
+
const handoff = await keyViaBrowser({
|
|
197
|
+
noOpen: opts.noOpen,
|
|
198
|
+
signal: skip.signal,
|
|
199
|
+
via: "terminal",
|
|
200
|
+
// Printed rather than only opened: the browser may not have launched,
|
|
201
|
+
// and a spinner pointing at a URL nobody can see is a hung flow.
|
|
202
|
+
onUrl: (link) => console.log(`
|
|
203
|
+
|
|
204
|
+
${dim(link)}
|
|
205
|
+
${dim("Press Enter to paste a key instead.")}
|
|
206
|
+
`)
|
|
207
|
+
});
|
|
208
|
+
process.stdin.off("data", onEnter);
|
|
209
|
+
process.stdin.pause();
|
|
210
|
+
if (handoff) {
|
|
211
|
+
apiKey = handoff.key;
|
|
212
|
+
console.log(green(` \u2713 key received${handoff.label ? dim(` (${handoff.label})`) : ""}
|
|
213
|
+
`));
|
|
214
|
+
} else {
|
|
215
|
+
console.log(yellow(skip.signal.aborted ? " skipped" : " no response"));
|
|
216
|
+
console.log(dim(" Falling back to pasting it in.\n"));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!apiKey) {
|
|
220
|
+
if (selfHosted) {
|
|
221
|
+
console.log(` Issue a key on the machine running ${url}:
|
|
222
|
+
`);
|
|
223
|
+
console.log(` ${bold("lurq keys create --label my-laptop")}
|
|
224
|
+
`);
|
|
225
|
+
console.log(" Then paste it below.\n");
|
|
226
|
+
} else {
|
|
227
|
+
if (!opts.noOpen) {
|
|
228
|
+
console.log(` Opening ${KEYS_URL}
|
|
229
|
+
`);
|
|
230
|
+
openInBrowser(KEYS_URL);
|
|
231
|
+
} else {
|
|
232
|
+
console.log(` Open ${KEYS_URL}
|
|
233
|
+
`);
|
|
234
|
+
}
|
|
235
|
+
console.log(" 1. Sign in, or create an account. It takes a moment.");
|
|
236
|
+
console.log(" 2. Create an API key and copy it.");
|
|
237
|
+
console.log(" 3. Paste it below.\n");
|
|
238
|
+
}
|
|
239
|
+
apiKey = (await input({
|
|
240
|
+
message: "Paste your lurq API key",
|
|
241
|
+
validate: (v) => v.trim().startsWith("lurq_") ? true : "Keys look like lurq_live_\u2026 "
|
|
242
|
+
})).trim();
|
|
243
|
+
}
|
|
244
|
+
process.stdout.write(" Validating key\u2026 ");
|
|
245
|
+
const check2 = await validateKey(url, apiKey);
|
|
246
|
+
console.log(
|
|
247
|
+
check2 === "valid" ? green("ok") : check2 === "invalid" ? yellow("rejected") : yellow("could not reach endpoint")
|
|
248
|
+
);
|
|
249
|
+
if (check2 !== "valid") {
|
|
250
|
+
const proceed = await confirm({
|
|
251
|
+
message: check2 === "invalid" ? `That key was rejected (401) by ${url}. Continue anyway?` : `Couldn't reach ${url} to validate the key. Continue anyway?`,
|
|
252
|
+
default: false
|
|
253
|
+
});
|
|
254
|
+
if (!proceed) {
|
|
255
|
+
console.log("Aborted. No config was changed.");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (opts.agent) {
|
|
260
|
+
await finish(resolveAgents(opts.agent), { url, apiKey });
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
const specs = agentSpecs();
|
|
264
|
+
const detected = specs.filter((s) => s.detected);
|
|
265
|
+
const primary = detected.find((s) => s.id === "claude-code") ?? detected[0];
|
|
266
|
+
if (primary) {
|
|
267
|
+
const others = detected.length - 1;
|
|
268
|
+
const choice = await select({
|
|
269
|
+
message: others > 0 ? `Looks like you have ${detected.map((s) => s.label).join(", ")}. Connect lurq to them?` : `Looks like you have ${primary.label}. Connect lurq to it?`,
|
|
270
|
+
default: "yes",
|
|
271
|
+
choices: [
|
|
272
|
+
{
|
|
273
|
+
name: others > 0 ? `Yes, set up all ${detected.length} detected agents` : `Yes, set up ${primary.label} for me`,
|
|
274
|
+
value: "yes"
|
|
275
|
+
},
|
|
276
|
+
{ name: "No, let me choose which agent(s)", value: "other" },
|
|
277
|
+
{ name: "Cancel, change nothing", value: "cancel" }
|
|
278
|
+
]
|
|
279
|
+
});
|
|
280
|
+
if (choice === "cancel") {
|
|
281
|
+
console.log("No problem. Nothing was changed; run `lurq setup` again anytime.");
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (choice === "yes") {
|
|
285
|
+
await finish(detected, { url, apiKey });
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
const ids = await checkbox({
|
|
290
|
+
message: "Which assistant(s) should I configure?",
|
|
291
|
+
choices: specs.map((s) => ({
|
|
292
|
+
name: `${s.label}${s.detected ? " (detected)" : ""}`,
|
|
293
|
+
value: s.id,
|
|
294
|
+
checked: s.detected
|
|
295
|
+
}))
|
|
296
|
+
});
|
|
297
|
+
await finish(
|
|
298
|
+
specs.filter((s) => ids.includes(s.id)),
|
|
299
|
+
{ url, apiKey }
|
|
300
|
+
);
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
if (!apiKey) {
|
|
304
|
+
throw new Error(
|
|
305
|
+
`No API key. Pass --api-key <key> or set LURQ_API_KEY (or drop --yes to be prompted). Get a key at ${KEYS_URL}`
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
const check = await validateKey(url, apiKey);
|
|
309
|
+
if (check === "invalid") {
|
|
310
|
+
throw new Error(
|
|
311
|
+
`${url} rejected that API key (401). Nothing was written. ` + (selfHosted ? `Issue one on the server with \`lurq keys create\`.` : `Check it, or create a new one at ${KEYS_URL}`)
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
if (check === "unreachable") {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`Could not reach ${url} to validate the API key. Nothing was written. Check the URL and your connection, then re-run.`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
const selected = opts.agent ? resolveAgents(opts.agent) : agentSpecs().filter((s) => s.detected);
|
|
320
|
+
await finish(selected, { url, apiKey });
|
|
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
|
+
}
|
|
362
|
+
async function finish(selected, remote) {
|
|
363
|
+
const configPath = writeUserConfig({
|
|
364
|
+
apiKey: remote.apiKey,
|
|
365
|
+
// Only persist a non-default endpoint. Storing the default would pin this
|
|
366
|
+
// machine to today's URL and quietly ignore a later change to the built-in.
|
|
367
|
+
endpoint: remote.url === DEFAULT_ENDPOINT ? void 0 : remote.url
|
|
368
|
+
});
|
|
369
|
+
console.log(`
|
|
370
|
+
${green("\u2713")} API key saved to ${configPath} ${dim("(mode 0600)")}`);
|
|
371
|
+
console.log(
|
|
372
|
+
`${green("\u2713")} Pointed at ${remote.url}${remote.url === DEFAULT_ENDPOINT ? "" : dim(" (your own server)")}`
|
|
373
|
+
);
|
|
374
|
+
const { command } = lurqInvocation();
|
|
375
|
+
console.log(
|
|
376
|
+
dim(
|
|
377
|
+
` \`${command} verify <package>\`, \`evaluate\`, \`compare\`, \`usage\` now work anywhere.`
|
|
378
|
+
)
|
|
379
|
+
);
|
|
380
|
+
if (selected.length === 0) {
|
|
381
|
+
console.log(
|
|
382
|
+
"\nNo agents selected or detected. Re-run `lurq setup --agent <id>` once your assistant is installed."
|
|
383
|
+
);
|
|
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 {
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
export {
|
|
420
|
+
withSetupOnMissingKey,
|
|
421
|
+
runningFromNpx,
|
|
422
|
+
runSetup
|
|
423
|
+
};
|