lurqrun 0.1.6 → 0.1.7
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 +18 -10
- package/dist/auditHandler-JCOJSUYW.js +23 -0
- package/dist/bin/lurq.js +3090 -23306
- package/dist/browserAuth-B6G27USY.js +95 -0
- package/dist/cache-DKI34SVS.js +12 -0
- package/dist/check-2FDGUOV7.js +192 -0
- package/dist/checkUpgrade-F2WESBPM.js +103 -0
- package/dist/chunk-2VMOWSRY.js +300 -0
- package/dist/chunk-3GHJR7XR.js +2049 -0
- package/dist/chunk-3N3Q3DSW.js +214 -0
- package/dist/chunk-4ESO33J6.js +34 -0
- package/dist/chunk-4F7ZESPO.js +132 -0
- package/dist/chunk-4KCPOMG6.js +68 -0
- package/dist/chunk-4ZYCIMY4.js +155 -0
- package/dist/chunk-63MUJNZL.js +318 -0
- package/dist/chunk-6AAEVQ7I.js +6336 -0
- package/dist/chunk-6EQ3ARXA.js +304 -0
- package/dist/chunk-6L3U7DZ5.js +23 -0
- package/dist/chunk-AHBP533R.js +220 -0
- package/dist/chunk-B43LCXBM.js +223 -0
- package/dist/chunk-BCANRN5B.js +33 -0
- package/dist/chunk-BUALU27S.js +123 -0
- package/dist/chunk-BULZAX2U.js +1554 -0
- package/dist/chunk-BV32UNLL.js +154 -0
- package/dist/chunk-C6GLE626.js +160 -0
- package/dist/chunk-CIDWNUAP.js +145 -0
- package/dist/chunk-CUP36ND3.js +2126 -0
- package/dist/chunk-CW5HJ3LX.js +96 -0
- package/dist/chunk-DB2VF5UD.js +315 -0
- package/dist/chunk-DWAGCNEL.js +210 -0
- package/dist/chunk-EA3DP5HG.js +293 -0
- package/dist/chunk-ELGCAM7P.js +184 -0
- package/dist/chunk-FW6BD2NO.js +1915 -0
- package/dist/chunk-GE37NVLN.js +15 -0
- package/dist/chunk-GPTKSNR6.js +171 -0
- package/dist/chunk-GRJXQBQZ.js +793 -0
- package/dist/chunk-HWBBVLOT.js +92 -0
- package/dist/chunk-I2JUKN6Z.js +24 -0
- package/dist/chunk-I3M2KJXB.js +56 -0
- package/dist/chunk-IQ4SDKKY.js +733 -0
- package/dist/chunk-J5FZYN4A.js +116 -0
- package/dist/chunk-L6N4JFW2.js +263 -0
- package/dist/chunk-LBFGSSF2.js +126 -0
- package/dist/chunk-LEGPB7DO.js +81 -0
- package/dist/chunk-LO35HLQZ.js +219 -0
- package/dist/chunk-LRD4GBYE.js +73 -0
- package/dist/chunk-LUAKDHLZ.js +40 -0
- package/dist/chunk-LYMPYETA.js +965 -0
- package/dist/chunk-M6NYEXCW.js +38 -0
- package/dist/chunk-MHUEVBVO.js +35 -0
- package/dist/chunk-MYGSLK44.js +37 -0
- package/dist/chunk-NH5I4KHH.js +201 -0
- package/dist/chunk-OQS4GUSI.js +1391 -0
- package/dist/chunk-PSX3GIAN.js +176 -0
- package/dist/chunk-Q5VPF4WI.js +26 -0
- package/dist/chunk-QKGYDMWB.js +7409 -0
- package/dist/chunk-QSL6QN5X.js +115 -0
- package/dist/chunk-SHCEBP3J.js +107 -0
- package/dist/chunk-SJOVFF7B.js +201 -0
- package/dist/chunk-ST2X2GYN.js +373 -0
- package/dist/chunk-TNTXWSYA.js +19 -0
- package/dist/chunk-U5AT3TD4.js +2128 -0
- package/dist/chunk-UDVNA7EA.js +483 -0
- package/dist/chunk-VL2E5T2A.js +109 -0
- package/dist/chunk-VLRHFMGJ.js +58 -0
- package/dist/chunk-WHX2ZFCG.js +4048 -0
- package/dist/chunk-WQ23REYT.js +37 -0
- package/dist/chunk-XBIDMHSK.js +15425 -0
- package/dist/chunk-Y5GI7RL3.js +66 -0
- package/dist/client-IRKAMDYZ.js +15 -0
- package/dist/commands-FIL5ET6P.js +911 -0
- package/dist/compat-R3UTFQ5Q.js +201 -0
- package/dist/dashboardIssue-WYYMBFIB.js +192 -0
- package/dist/diff-GZA2774U.js +13 -0
- package/dist/dist-4XXIXHHZ.js +12945 -0
- package/dist/e2b-FVPHDULZ.js +172 -0
- package/dist/extract-NKGKLIVT.js +444 -0
- package/dist/fetch-QYTUJVG2.js +22 -0
- package/dist/firstTouch-QQTJH4QX.js +55 -0
- package/dist/handlers-GEJAVZDK.js +53 -0
- package/dist/http-ETPYMBGD.js +5360 -0
- package/dist/ingestQueue-VKN4KBIF.js +35 -0
- package/dist/install-EK3W2COX.js +20 -0
- package/dist/installSkill-VQJWJVCL.js +52 -0
- package/dist/inventory-5AWSLJYU.js +31 -0
- package/dist/local-XPZMRH5R.js +13 -0
- package/dist/mcp-3JHD5SUZ.js +472 -0
- package/dist/mcpHandlers-QFN4MCFL.js +22 -0
- package/dist/mcpScan-QZHWENIP.js +1871 -0
- package/dist/mcpScanWorkflow-JPYCBGC4.js +81 -0
- package/dist/mcpStack-BYJCZNIV.js +20 -0
- package/dist/packages-THVFMWFP.js +42 -0
- package/dist/plan-V4OEI3J4.js +463 -0
- package/dist/planView-JRXGCG2N.js +79 -0
- package/dist/policy-3P6BGRDN.js +115 -0
- package/dist/references-6N7VEPHT.js +14 -0
- package/dist/release-4U4ABNSJ.js +128 -0
- package/dist/remote-YGCXYI4V.js +32 -0
- package/dist/reportRuns-CKQQYLY4.js +64 -0
- package/dist/sandbox-MEZLAODF.js +39 -0
- package/dist/server-KFUD5X57.js +55 -0
- package/dist/surface-V62GE554.js +141 -0
- package/dist/surface-YL6O67W3.js +36 -0
- package/dist/surfaceHandlers-X2IZKA3E.js +20 -0
- package/dist/typecheck-X7U5ELMR.js +268 -0
- package/dist/types-M5JP2W3D.js +10 -0
- package/dist/uninstall-P7RGBX6G.js +174 -0
- package/dist/upgrade-NQ5IWFZB.js +596 -0
- package/dist/upgradePlan-A4LRKLEG.js +146 -0
- package/dist/userConfig-Z3GQE776.js +20 -0
- package/dist/watch-DGFMWUDL.js +214 -0
- package/package.json +26 -21
- package/templates/agent-rules.md +4 -4
- package/templates/skill-instructions.md +13 -14
- 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,96 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_ECOSYSTEM
|
|
4
|
+
} from "./chunk-VLRHFMGJ.js";
|
|
5
|
+
import {
|
|
6
|
+
compatEdges,
|
|
7
|
+
compatVerifyQueue,
|
|
8
|
+
packages
|
|
9
|
+
} from "./chunk-LYMPYETA.js";
|
|
10
|
+
import {
|
|
11
|
+
init_esm_shims
|
|
12
|
+
} from "./chunk-I3M2KJXB.js";
|
|
13
|
+
|
|
14
|
+
// src/db/compat.ts
|
|
15
|
+
init_esm_shims();
|
|
16
|
+
import { and, eq, inArray, sql } from "drizzle-orm";
|
|
17
|
+
async function getCompatMetadata(db, names, ecosystem = DEFAULT_ECOSYSTEM) {
|
|
18
|
+
if (names.length === 0) return [];
|
|
19
|
+
return db.select({
|
|
20
|
+
name: packages.name,
|
|
21
|
+
latestVersion: packages.latestVersion,
|
|
22
|
+
peerDependencies: packages.peerDependencies,
|
|
23
|
+
peerDependenciesMeta: packages.peerDependenciesMeta,
|
|
24
|
+
engines: packages.engines
|
|
25
|
+
}).from(packages).where(and(inArray(packages.name, names), eq(packages.ecosystem, ecosystem)));
|
|
26
|
+
}
|
|
27
|
+
function canonicalPair(a, b) {
|
|
28
|
+
const [low, high] = a.name <= b.name ? [a, b] : [b, a];
|
|
29
|
+
return { packageA: low.name, versionA: low.version, packageB: high.name, versionB: high.version };
|
|
30
|
+
}
|
|
31
|
+
function provenanceRank(col) {
|
|
32
|
+
return sql`case ${col} when 'conflict' then 3 when 'verified' then 2 when 'observed' then 1 else 0 end`;
|
|
33
|
+
}
|
|
34
|
+
function conflictSet() {
|
|
35
|
+
const incomingWins = sql`${provenanceRank(sql`excluded.provenance`)} >= ${provenanceRank(compatEdges.provenance)}`;
|
|
36
|
+
return {
|
|
37
|
+
status: sql`case when ${incomingWins} then excluded.status else ${compatEdges.status} end`,
|
|
38
|
+
provenance: sql`case when ${incomingWins} then excluded.provenance else ${compatEdges.provenance} end`,
|
|
39
|
+
driver: sql`case when ${incomingWins} then excluded.driver else ${compatEdges.driver} end`,
|
|
40
|
+
ranAt: sql`case when ${incomingWins} then excluded.ran_at else ${compatEdges.ranAt} end`,
|
|
41
|
+
witnessCount: sql`${compatEdges.witnessCount} + excluded.witness_count`
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
var CONFLICT_TARGET = [
|
|
45
|
+
compatEdges.packageA,
|
|
46
|
+
compatEdges.versionA,
|
|
47
|
+
compatEdges.packageB,
|
|
48
|
+
compatEdges.versionB
|
|
49
|
+
];
|
|
50
|
+
async function upsertCompatEdge(db, edge) {
|
|
51
|
+
await db.insert(compatEdges).values(edge).onConflictDoUpdate({ target: [...CONFLICT_TARGET], set: conflictSet() });
|
|
52
|
+
}
|
|
53
|
+
async function getSandboxEdges(db, names) {
|
|
54
|
+
if (names.length === 0) return [];
|
|
55
|
+
return db.select().from(compatEdges).where(
|
|
56
|
+
and(
|
|
57
|
+
inArray(compatEdges.packageA, names),
|
|
58
|
+
inArray(compatEdges.packageB, names),
|
|
59
|
+
inArray(compatEdges.provenance, ["verified", "conflict"])
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
function pairKey(a, b) {
|
|
64
|
+
return a <= b ? `${a}|${b}` : `${b}|${a}`;
|
|
65
|
+
}
|
|
66
|
+
function compatSetKey(names) {
|
|
67
|
+
return [...new Set(names)].sort().join("|");
|
|
68
|
+
}
|
|
69
|
+
async function enqueueCompatVerify(db, names) {
|
|
70
|
+
const packages2 = [...new Set(names)].filter(Boolean);
|
|
71
|
+
if (packages2.length < 2) return false;
|
|
72
|
+
const inserted = await db.insert(compatVerifyQueue).values({ setKey: compatSetKey(packages2), packages: packages2 }).onConflictDoNothing({ target: compatVerifyQueue.setKey }).returning({ id: compatVerifyQueue.id });
|
|
73
|
+
return inserted.length > 0;
|
|
74
|
+
}
|
|
75
|
+
async function getPendingCompatVerify(db, limit) {
|
|
76
|
+
return db.select().from(compatVerifyQueue).orderBy(compatVerifyQueue.requestedAt).limit(limit);
|
|
77
|
+
}
|
|
78
|
+
async function deleteCompatVerify(db, id) {
|
|
79
|
+
await db.delete(compatVerifyQueue).where(eq(compatVerifyQueue.id, id));
|
|
80
|
+
}
|
|
81
|
+
async function bumpCompatVerifyAttempt(db, id) {
|
|
82
|
+
const [row] = await db.update(compatVerifyQueue).set({ attempts: sql`${compatVerifyQueue.attempts} + 1` }).where(eq(compatVerifyQueue.id, id)).returning({ attempts: compatVerifyQueue.attempts });
|
|
83
|
+
return row?.attempts ?? 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
getCompatMetadata,
|
|
88
|
+
canonicalPair,
|
|
89
|
+
upsertCompatEdge,
|
|
90
|
+
getSandboxEdges,
|
|
91
|
+
pairKey,
|
|
92
|
+
enqueueCompatVerify,
|
|
93
|
+
getPendingCompatVerify,
|
|
94
|
+
deleteCompatVerify,
|
|
95
|
+
bumpCompatVerifyAttempt
|
|
96
|
+
};
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
diffSurfaces
|
|
4
|
+
} from "./chunk-SHCEBP3J.js";
|
|
5
|
+
import {
|
|
6
|
+
canonicalKey,
|
|
7
|
+
enqueueSurface,
|
|
8
|
+
mcpSurfaceRef,
|
|
9
|
+
surfaceRef
|
|
10
|
+
} from "./chunk-LO35HLQZ.js";
|
|
11
|
+
import {
|
|
12
|
+
cached
|
|
13
|
+
} from "./chunk-HWBBVLOT.js";
|
|
14
|
+
import {
|
|
15
|
+
UNBOUNDED_ARITY,
|
|
16
|
+
claims,
|
|
17
|
+
entities,
|
|
18
|
+
observations,
|
|
19
|
+
symbols
|
|
20
|
+
} from "./chunk-LYMPYETA.js";
|
|
21
|
+
import {
|
|
22
|
+
logger
|
|
23
|
+
} from "./chunk-MYGSLK44.js";
|
|
24
|
+
import {
|
|
25
|
+
init_esm_shims
|
|
26
|
+
} from "./chunk-I3M2KJXB.js";
|
|
27
|
+
|
|
28
|
+
// src/mcp/surfaceHandlers.ts
|
|
29
|
+
init_esm_shims();
|
|
30
|
+
import { createHash } from "crypto";
|
|
31
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
32
|
+
|
|
33
|
+
// src/pipeline/fillSurface.ts
|
|
34
|
+
init_esm_shims();
|
|
35
|
+
import { sql } from "drizzle-orm";
|
|
36
|
+
var TIER = "shipped_js_ast";
|
|
37
|
+
var MAX_QUEUED = 32;
|
|
38
|
+
var MAX_ATTEMPTED = 5e4;
|
|
39
|
+
var BATCH = 500;
|
|
40
|
+
var attempted = /* @__PURE__ */ new Set();
|
|
41
|
+
var pending = /* @__PURE__ */ new Set();
|
|
42
|
+
var queue = [];
|
|
43
|
+
var draining = null;
|
|
44
|
+
function needsFill(rows) {
|
|
45
|
+
const tierA = rows.filter((r) => r.tier === TIER);
|
|
46
|
+
return tierA.length > 0 && tierA.every((r) => r.sourceOffset === null && r.maxArity === null);
|
|
47
|
+
}
|
|
48
|
+
function scheduleFill(db, pkg, version, entityId, fill = fillOne) {
|
|
49
|
+
const key = `${pkg}@${version}`;
|
|
50
|
+
if (pending.has(key)) return true;
|
|
51
|
+
if (attempted.has(key) || queue.length >= MAX_QUEUED) return false;
|
|
52
|
+
if (attempted.size >= MAX_ATTEMPTED) attempted.clear();
|
|
53
|
+
attempted.add(key);
|
|
54
|
+
pending.add(key);
|
|
55
|
+
queue.push({ db, pkg, version, entityId, fill });
|
|
56
|
+
draining ??= drain().finally(() => {
|
|
57
|
+
draining = null;
|
|
58
|
+
});
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
async function drain() {
|
|
62
|
+
for (let job = queue.shift(); job; job = queue.shift()) {
|
|
63
|
+
const key = `${job.pkg}@${job.version}`;
|
|
64
|
+
try {
|
|
65
|
+
const updated = await job.fill(job.db, job.pkg, job.version, job.entityId);
|
|
66
|
+
logger.info(`surface fill ${key}: ${updated} symbol row(s) updated`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
logger.warn(`surface fill failed for ${key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
69
|
+
} finally {
|
|
70
|
+
pending.delete(key);
|
|
71
|
+
}
|
|
72
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async function fillOne(db, pkg, version, entityId) {
|
|
76
|
+
const { fetchAndExtract } = await import("./fetch-QYTUJVG2.js");
|
|
77
|
+
const fetched = await fetchAndExtract(pkg, version);
|
|
78
|
+
if (!fetched) return 0;
|
|
79
|
+
const values = fetched.surface.symbols.filter((s) => s.tier === TIER && (s.sourceRef?.offset !== void 0 || s.maxArity !== void 0)).map((s) => ({
|
|
80
|
+
path: s.path,
|
|
81
|
+
offset: s.sourceRef?.offset ?? null,
|
|
82
|
+
maxArity: s.maxArity === void 0 ? null : s.maxArity ?? UNBOUNDED_ARITY
|
|
83
|
+
}));
|
|
84
|
+
let updated = 0;
|
|
85
|
+
for (let i = 0; i < values.length; i += BATCH) {
|
|
86
|
+
const res = await db.execute(fillStatement(entityId, values.slice(i, i + BATCH)));
|
|
87
|
+
updated += res.count ?? 0;
|
|
88
|
+
}
|
|
89
|
+
return updated;
|
|
90
|
+
}
|
|
91
|
+
function fillStatement(entityId, values) {
|
|
92
|
+
const rows = sql.join(
|
|
93
|
+
values.map((v) => sql`(${v.path}, ${v.offset}::int, ${v.maxArity}::int)`),
|
|
94
|
+
sql`, `
|
|
95
|
+
);
|
|
96
|
+
return sql`
|
|
97
|
+
UPDATE symbols AS s
|
|
98
|
+
SET source_offset = v.new_offset, max_arity = v.new_max_arity
|
|
99
|
+
FROM (VALUES ${rows}) AS v(path, new_offset, new_max_arity)
|
|
100
|
+
WHERE s.entity_id = ${entityId}
|
|
101
|
+
AND s.tier = ${TIER}
|
|
102
|
+
AND s.path = v.path
|
|
103
|
+
AND s.source_offset IS NULL
|
|
104
|
+
AND s.max_arity IS NULL`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/mcp/surfaceHandlers.ts
|
|
108
|
+
function rowsToSurface(pkg, version, rows, tier) {
|
|
109
|
+
const symbolsOut = rows.map((r) => ({
|
|
110
|
+
path: r.path,
|
|
111
|
+
kind: r.kind,
|
|
112
|
+
arity: r.arity,
|
|
113
|
+
origin: r.origin,
|
|
114
|
+
deprecated: r.deprecated,
|
|
115
|
+
tier: r.tier,
|
|
116
|
+
// The signature was dropped on the way back out of the database, so every
|
|
117
|
+
// diff computed from STORED rows saw `signature: undefined` on both sides
|
|
118
|
+
// and reported no signature drift — for tier C, where signatures are the
|
|
119
|
+
// only thing that tier can report, and for the MCP tier, where the entire
|
|
120
|
+
// tool contract is serialized into this field.
|
|
121
|
+
...r.signature !== null ? { signature: r.signature } : {},
|
|
122
|
+
// Offset and maximum arity come back too. Without them a diff computed from
|
|
123
|
+
// stored rows could never find a proven rename or a dropped trailing
|
|
124
|
+
// parameter, and every consumer of the index would see less than the CLI.
|
|
125
|
+
...r.sourceFile ? {
|
|
126
|
+
sourceRef: {
|
|
127
|
+
file: r.sourceFile,
|
|
128
|
+
line: r.sourceLine ?? 0,
|
|
129
|
+
...r.sourceOffset !== null ? { offset: r.sourceOffset } : {}
|
|
130
|
+
}
|
|
131
|
+
} : {},
|
|
132
|
+
...r.maxArity !== null ? { maxArity: r.maxArity === UNBOUNDED_ARITY ? null : r.maxArity } : {}
|
|
133
|
+
}));
|
|
134
|
+
return {
|
|
135
|
+
package: pkg,
|
|
136
|
+
version,
|
|
137
|
+
tier,
|
|
138
|
+
entry: null,
|
|
139
|
+
symbols: symbolsOut,
|
|
140
|
+
filesWalked: 0,
|
|
141
|
+
externalReExports: []
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function loadStored(db, pkg, version, tenantId = 0, kind = "package_surface") {
|
|
145
|
+
let entity;
|
|
146
|
+
if (version === null) {
|
|
147
|
+
const rows2 = await db.select({ e: entities, at: observations.observedAt }).from(entities).innerJoin(claims, eq(claims.subjectId, entities.id)).innerJoin(observations, eq(observations.claimId, claims.id)).where(and(eq(entities.kind, kind), eq(entities.name, pkg))).orderBy(desc(observations.observedAt)).limit(1);
|
|
148
|
+
entity = rows2.find((r) => r.e.tenantId === tenantId)?.e;
|
|
149
|
+
} else {
|
|
150
|
+
const key = canonicalKey(
|
|
151
|
+
kind === "mcp_server" ? mcpSurfaceRef(pkg, version) : surfaceRef(pkg, version)
|
|
152
|
+
);
|
|
153
|
+
const ents = await db.select().from(entities).where(eq(entities.canonicalKey, key)).limit(2);
|
|
154
|
+
entity = ents.find((e) => e.tenantId === tenantId);
|
|
155
|
+
}
|
|
156
|
+
if (!entity) return null;
|
|
157
|
+
const obs = await db.select({ o: observations }).from(observations).innerJoin(claims, eq(observations.claimId, claims.id)).where(eq(claims.subjectId, entity.id)).orderBy(desc(observations.observedAt)).limit(1);
|
|
158
|
+
const latest = obs[0]?.o ?? null;
|
|
159
|
+
const rows = await db.select().from(symbols).where(eq(symbols.entityId, entity.id));
|
|
160
|
+
return {
|
|
161
|
+
entityId: entity.id,
|
|
162
|
+
rows,
|
|
163
|
+
verdict: latest?.verdict ?? "unknown",
|
|
164
|
+
class: latest?.class ?? null,
|
|
165
|
+
tier: latest?.tier ?? null,
|
|
166
|
+
observedAt: latest?.observedAt ? latest.observedAt.toISOString() : null
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
var MISS = {
|
|
170
|
+
verdict: "unknown",
|
|
171
|
+
class: null,
|
|
172
|
+
tier: null,
|
|
173
|
+
symbols: [],
|
|
174
|
+
coverageNote: "not yet extracted, queued; retry shortly. This is NOT evidence of absence.",
|
|
175
|
+
observedAt: null
|
|
176
|
+
};
|
|
177
|
+
function ckey(parts) {
|
|
178
|
+
return createHash("sha1").update(JSON.stringify(parts)).digest("hex").slice(0, 24);
|
|
179
|
+
}
|
|
180
|
+
async function handleResolveSurface(db, input) {
|
|
181
|
+
return cached(
|
|
182
|
+
"resolve_surface",
|
|
183
|
+
ckey([input.package, input.version ?? null]),
|
|
184
|
+
() => resolveSurfaceUncached(db, input),
|
|
185
|
+
{ skipCache: (v) => v.verdict === "unknown" }
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
async function resolveSurfaceUncached(db, input) {
|
|
189
|
+
const version = input.version ?? null;
|
|
190
|
+
let stored = await loadStored(db, input.package, version);
|
|
191
|
+
if (!stored || stored.verdict === "unknown" && stored.rows.length === 0) {
|
|
192
|
+
const { firstTouchSurface } = await import("./firstTouch-QQTJH4QX.js");
|
|
193
|
+
if (await firstTouchSurface(db, input.package, version)) {
|
|
194
|
+
stored = await loadStored(db, input.package, version);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (!stored || stored.verdict === "unknown" && stored.rows.length === 0) {
|
|
198
|
+
await enqueueSurface(db, input.package, version).catch(() => {
|
|
199
|
+
});
|
|
200
|
+
return { package: input.package, version, ...MISS };
|
|
201
|
+
}
|
|
202
|
+
if (stored.verdict === "undeclared") {
|
|
203
|
+
return {
|
|
204
|
+
package: input.package,
|
|
205
|
+
version,
|
|
206
|
+
verdict: "undeclared",
|
|
207
|
+
class: stored.class,
|
|
208
|
+
tier: stored.tier,
|
|
209
|
+
symbols: [],
|
|
210
|
+
coverageNote: "package ships no artifact this tier can read, UNDECLARED, which is a measurement gap, not an empty API",
|
|
211
|
+
observedAt: stored.observedAt
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const runtime = stored.rows.filter((r) => r.kind !== "type_only" && r.origin === "local");
|
|
215
|
+
const excluded = stored.rows.length - runtime.length;
|
|
216
|
+
return {
|
|
217
|
+
package: input.package,
|
|
218
|
+
version,
|
|
219
|
+
verdict: stored.verdict,
|
|
220
|
+
class: stored.class,
|
|
221
|
+
tier: stored.tier,
|
|
222
|
+
symbols: runtime.map((r) => ({
|
|
223
|
+
path: r.path,
|
|
224
|
+
kind: r.kind,
|
|
225
|
+
arity: r.arity,
|
|
226
|
+
deprecated: r.deprecated
|
|
227
|
+
})),
|
|
228
|
+
coverageNote: `${runtime.length} runtime symbol(s)` + (excluded ? `; ${excluded} excluded as type-only or re-exported from another package` : "") + (stored.tier === "shipped_js_ast" ? ". Runtime existence only, signatures require tier C." : ""),
|
|
229
|
+
observedAt: stored.observedAt
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
async function handleDiffSurface(db, input) {
|
|
233
|
+
let filling = false;
|
|
234
|
+
return cached(
|
|
235
|
+
"diff_surface",
|
|
236
|
+
ckey([input.package, input.fromVersion, input.toVersion]),
|
|
237
|
+
() => diffSurfaceUncached(db, input, () => filling = true),
|
|
238
|
+
{ skipCache: (v) => v.verdict === "unknown" || filling }
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
async function diffSurfaceUncached(db, input, onFill) {
|
|
242
|
+
let [a, b] = await Promise.all([
|
|
243
|
+
loadStored(db, input.package, input.fromVersion),
|
|
244
|
+
loadStored(db, input.package, input.toVersion)
|
|
245
|
+
]);
|
|
246
|
+
if (!a || !b || a.rows.length === 0 || b.rows.length === 0) {
|
|
247
|
+
const { firstTouchPair } = await import("./firstTouch-QQTJH4QX.js");
|
|
248
|
+
if (await firstTouchPair(db, input.package, input.fromVersion, input.toVersion)) {
|
|
249
|
+
[a, b] = await Promise.all([
|
|
250
|
+
loadStored(db, input.package, input.fromVersion),
|
|
251
|
+
loadStored(db, input.package, input.toVersion)
|
|
252
|
+
]);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const missing = [];
|
|
256
|
+
if (!a || a.rows.length === 0) missing.push(input.fromVersion);
|
|
257
|
+
if (!b || b.rows.length === 0) missing.push(input.toVersion);
|
|
258
|
+
if (missing.length) {
|
|
259
|
+
for (const v of missing) await enqueueSurface(db, input.package, v).catch(() => {
|
|
260
|
+
});
|
|
261
|
+
return {
|
|
262
|
+
package: input.package,
|
|
263
|
+
fromVersion: input.fromVersion,
|
|
264
|
+
toVersion: input.toVersion,
|
|
265
|
+
verdict: "unknown",
|
|
266
|
+
inconclusive: `no extracted surface for ${missing.join(", ")}, queued; retry shortly. NOT evidence that symbols were removed.`,
|
|
267
|
+
removed: [],
|
|
268
|
+
added: [],
|
|
269
|
+
arityChanged: [],
|
|
270
|
+
typeOnlyRemoved: [],
|
|
271
|
+
// Present-but-empty like every other list above, so a miss and a hit have
|
|
272
|
+
// the same shape and callers never have to branch on which one they got.
|
|
273
|
+
deprecated: [],
|
|
274
|
+
renamed: [],
|
|
275
|
+
observedAt: null
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
for (const [stored, version] of [
|
|
279
|
+
[a, input.fromVersion],
|
|
280
|
+
[b, input.toVersion]
|
|
281
|
+
]) {
|
|
282
|
+
if (needsFill(stored.rows) && scheduleFill(db, input.package, version, stored.entityId)) onFill();
|
|
283
|
+
}
|
|
284
|
+
const diff = diffSurfaces(
|
|
285
|
+
rowsToSurface(input.package, input.fromVersion, a.rows, a.tier ?? "shipped_js_ast"),
|
|
286
|
+
rowsToSurface(input.package, input.toVersion, b.rows, b.tier ?? "shipped_js_ast")
|
|
287
|
+
);
|
|
288
|
+
return {
|
|
289
|
+
package: input.package,
|
|
290
|
+
fromVersion: input.fromVersion,
|
|
291
|
+
toVersion: input.toVersion,
|
|
292
|
+
verdict: diff.inconclusive ? "unknown" : "verified_true",
|
|
293
|
+
class: "derived",
|
|
294
|
+
tier: diff.tier,
|
|
295
|
+
...diff.inconclusive ? { inconclusive: diff.inconclusive } : {},
|
|
296
|
+
/** Breaks `node`. */
|
|
297
|
+
removed: diff.removed.map((s) => ({ path: s.path, kind: s.kind, arity: s.arity })),
|
|
298
|
+
added: diff.added.map((s) => ({ path: s.path, kind: s.kind })),
|
|
299
|
+
arityChanged: diff.arityChanged,
|
|
300
|
+
/** Breaks `tsc`, NOT `node` — returned separately on purpose (§8.1). */
|
|
301
|
+
typeOnlyRemoved: diff.typeOnlyRemoved.map((s) => s.path),
|
|
302
|
+
deprecated: diff.deprecated.map((s) => s.path),
|
|
303
|
+
/** Removed names whose implementation the package still exports under another
|
|
304
|
+
* name. Empty for surfaces stored before declaration offsets were recorded. */
|
|
305
|
+
renamed: diff.renamed,
|
|
306
|
+
observedAt: b.observedAt
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export {
|
|
311
|
+
rowsToSurface,
|
|
312
|
+
loadStored,
|
|
313
|
+
handleResolveSurface,
|
|
314
|
+
handleDiffSurface
|
|
315
|
+
};
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
detectInstallCommand
|
|
4
|
+
} from "./chunk-B43LCXBM.js";
|
|
5
|
+
import {
|
|
6
|
+
REPO_MANIFEST_CAP
|
|
7
|
+
} from "./chunk-BCANRN5B.js";
|
|
8
|
+
import {
|
|
9
|
+
HttpError,
|
|
10
|
+
httpRequest
|
|
11
|
+
} from "./chunk-SJOVFF7B.js";
|
|
12
|
+
import {
|
|
13
|
+
getConfig
|
|
14
|
+
} from "./chunk-GRJXQBQZ.js";
|
|
15
|
+
import {
|
|
16
|
+
logger
|
|
17
|
+
} from "./chunk-MYGSLK44.js";
|
|
18
|
+
import {
|
|
19
|
+
init_esm_shims
|
|
20
|
+
} from "./chunk-I3M2KJXB.js";
|
|
21
|
+
|
|
22
|
+
// src/github/app.ts
|
|
23
|
+
init_esm_shims();
|
|
24
|
+
import { createSign } from "crypto";
|
|
25
|
+
var API_HOST = "api.github.com";
|
|
26
|
+
var API = `https://${API_HOST}`;
|
|
27
|
+
var JWT_TTL_S = 9 * 60;
|
|
28
|
+
var TOKEN_SKEW_MS = 6e4;
|
|
29
|
+
var GithubAppError = class extends Error {
|
|
30
|
+
constructor(message, status) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.status = status;
|
|
33
|
+
this.name = "GithubAppError";
|
|
34
|
+
}
|
|
35
|
+
status;
|
|
36
|
+
};
|
|
37
|
+
function githubAppCredentials() {
|
|
38
|
+
const config = getConfig();
|
|
39
|
+
const appId = config.LURQ_GITHUB_APP_ID;
|
|
40
|
+
const rawKey = config.LURQ_GITHUB_APP_PRIVATE_KEY;
|
|
41
|
+
if (!appId || !rawKey) return null;
|
|
42
|
+
const privateKey = rawKey.includes("\\n") ? rawKey.replace(/\\n/g, "\n") : rawKey;
|
|
43
|
+
return { appId, privateKey };
|
|
44
|
+
}
|
|
45
|
+
function b64url(input) {
|
|
46
|
+
return Buffer.from(input).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
47
|
+
}
|
|
48
|
+
function appJwt(creds, now = /* @__PURE__ */ new Date()) {
|
|
49
|
+
const issued = Math.floor(now.getTime() / 1e3) - 60;
|
|
50
|
+
const header = b64url(JSON.stringify({ alg: "RS256", typ: "JWT" }));
|
|
51
|
+
const payload = b64url(
|
|
52
|
+
JSON.stringify({ iat: issued, exp: issued + JWT_TTL_S, iss: creds.appId })
|
|
53
|
+
);
|
|
54
|
+
const signature = createSign("RSA-SHA256").update(`${header}.${payload}`).sign(creds.privateKey);
|
|
55
|
+
return `${header}.${payload}.${b64url(signature)}`;
|
|
56
|
+
}
|
|
57
|
+
var tokenCache = /* @__PURE__ */ new Map();
|
|
58
|
+
async function installationToken(installationId) {
|
|
59
|
+
const cached = tokenCache.get(installationId);
|
|
60
|
+
if (cached && cached.expiresAt - TOKEN_SKEW_MS > Date.now()) return cached.token;
|
|
61
|
+
const creds = githubAppCredentials();
|
|
62
|
+
if (!creds) throw new GithubAppError("GitHub App is not configured.", 503);
|
|
63
|
+
let res;
|
|
64
|
+
try {
|
|
65
|
+
res = await httpRequest(
|
|
66
|
+
`${API}/app/installations/${installationId}/access_tokens`,
|
|
67
|
+
{
|
|
68
|
+
host: API_HOST,
|
|
69
|
+
ttlMs: 0,
|
|
70
|
+
// never cache credentials to disk
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: {
|
|
73
|
+
Authorization: `Bearer ${appJwt(creds)}`,
|
|
74
|
+
Accept: "application/vnd.github+json",
|
|
75
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (err instanceof HttpError && err.status === 404) {
|
|
81
|
+
throw new GithubAppError("This GitHub installation no longer exists.", 404);
|
|
82
|
+
}
|
|
83
|
+
throw new GithubAppError(
|
|
84
|
+
err instanceof Error ? err.message : "Could not authenticate with GitHub.",
|
|
85
|
+
502
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
const token = res.data?.token;
|
|
89
|
+
if (!token) throw new GithubAppError("GitHub returned no installation token.", 502);
|
|
90
|
+
const expiresAt = res.data.expires_at ? Date.parse(res.data.expires_at) : NaN;
|
|
91
|
+
tokenCache.set(installationId, {
|
|
92
|
+
token,
|
|
93
|
+
// A token with an unparseable expiry is still valid; treat it as short-lived
|
|
94
|
+
// rather than caching it forever on a malformed timestamp.
|
|
95
|
+
expiresAt: Number.isNaN(expiresAt) ? Date.now() + 5 * 6e4 : expiresAt
|
|
96
|
+
});
|
|
97
|
+
return token;
|
|
98
|
+
}
|
|
99
|
+
async function installationGet(installationId, path) {
|
|
100
|
+
const token = await installationToken(installationId);
|
|
101
|
+
const res = await httpRequest(`${API}${path}`, {
|
|
102
|
+
host: API_HOST,
|
|
103
|
+
ttlMs: 0,
|
|
104
|
+
// repo state changes under us; a cached manifest is a wrong answer
|
|
105
|
+
headers: {
|
|
106
|
+
Authorization: `Bearer ${token}`,
|
|
107
|
+
Accept: "application/vnd.github+json",
|
|
108
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
return res.data;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/github/manifests.ts
|
|
115
|
+
init_esm_shims();
|
|
116
|
+
var PAGE_SIZE = 100;
|
|
117
|
+
var MAX_PAGES = 20;
|
|
118
|
+
async function listInstallationRepos(installationId) {
|
|
119
|
+
const out = [];
|
|
120
|
+
for (let page = 1; page <= MAX_PAGES; page++) {
|
|
121
|
+
const data = await installationGet(
|
|
122
|
+
installationId,
|
|
123
|
+
`/installation/repositories?per_page=${PAGE_SIZE}&page=${page}`
|
|
124
|
+
);
|
|
125
|
+
const batch = data.repositories ?? [];
|
|
126
|
+
for (const repo of batch) {
|
|
127
|
+
out.push({
|
|
128
|
+
fullName: repo.full_name,
|
|
129
|
+
defaultBranch: repo.default_branch,
|
|
130
|
+
isPrivate: repo.private,
|
|
131
|
+
pushedAt: repo.pushed_at ?? null
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (batch.length < PAGE_SIZE) break;
|
|
135
|
+
}
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
function manifestPaths(tree) {
|
|
139
|
+
return tree.filter(
|
|
140
|
+
(node) => node.type === "blob" && (node.path === "package.json" || node.path.endsWith("/package.json")) && // A committed node_modules is rare but real, and its manifests are not
|
|
141
|
+
// this project's dependencies — counting them would invent drift.
|
|
142
|
+
!node.path.split("/").includes("node_modules")
|
|
143
|
+
).sort((a, b) => a.path.split("/").length - b.path.split("/").length).map((node) => node.path);
|
|
144
|
+
}
|
|
145
|
+
function parseManifest(path, json) {
|
|
146
|
+
if (!json || typeof json !== "object") return null;
|
|
147
|
+
const pkg = json;
|
|
148
|
+
const deps = {};
|
|
149
|
+
for (const block of ["dependencies", "devDependencies"]) {
|
|
150
|
+
const entry = pkg[block];
|
|
151
|
+
if (!entry || typeof entry !== "object") continue;
|
|
152
|
+
for (const [name, range] of Object.entries(entry)) {
|
|
153
|
+
if (typeof range !== "string") continue;
|
|
154
|
+
if (/^(file|link|workspace|git|github|https?|portal):/i.test(range)) continue;
|
|
155
|
+
if (range.includes("/") && !range.startsWith(">") && !range.startsWith("<")) continue;
|
|
156
|
+
deps[name] = range;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return Object.keys(deps).length > 0 ? { path, deps } : null;
|
|
160
|
+
}
|
|
161
|
+
async function fetchManifests(installationId, fullName, branch) {
|
|
162
|
+
let tree;
|
|
163
|
+
try {
|
|
164
|
+
tree = await installationGet(
|
|
165
|
+
installationId,
|
|
166
|
+
`/repos/${fullName}/git/trees/${encodeURIComponent(branch)}?recursive=1`
|
|
167
|
+
);
|
|
168
|
+
} catch (err) {
|
|
169
|
+
if (err instanceof HttpError && err.status === 409) {
|
|
170
|
+
return { manifests: [], installCommand: detectInstallCommand([]), partial: false, empty: true };
|
|
171
|
+
}
|
|
172
|
+
throw err;
|
|
173
|
+
}
|
|
174
|
+
const nodes = tree.tree ?? [];
|
|
175
|
+
const allPaths = manifestPaths(nodes);
|
|
176
|
+
const lockfiles = nodes.filter((n) => !n.path.includes("/")).map((n) => n.path);
|
|
177
|
+
const paths = allPaths.slice(0, REPO_MANIFEST_CAP);
|
|
178
|
+
const manifests = [];
|
|
179
|
+
for (const path of paths) {
|
|
180
|
+
try {
|
|
181
|
+
const res = await installationGet(
|
|
182
|
+
installationId,
|
|
183
|
+
`/repos/${fullName}/contents/${path.split("/").map(encodeURIComponent).join("/")}?ref=${encodeURIComponent(branch)}`
|
|
184
|
+
);
|
|
185
|
+
if (!res.content || res.encoding !== "base64") continue;
|
|
186
|
+
const parsed = parseManifest(
|
|
187
|
+
path,
|
|
188
|
+
JSON.parse(Buffer.from(res.content, "base64").toString("utf8"))
|
|
189
|
+
);
|
|
190
|
+
if (parsed) manifests.push(parsed);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
logger.debug(`manifest read failed for ${fullName}/${path}: ${err.message}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
manifests,
|
|
197
|
+
installCommand: detectInstallCommand(lockfiles),
|
|
198
|
+
partial: Boolean(tree.truncated) || allPaths.length > paths.length,
|
|
199
|
+
empty: false
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export {
|
|
204
|
+
GithubAppError,
|
|
205
|
+
githubAppCredentials,
|
|
206
|
+
installationGet,
|
|
207
|
+
listInstallationRepos,
|
|
208
|
+
parseManifest,
|
|
209
|
+
fetchManifests
|
|
210
|
+
};
|