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.
- package/README.md +312 -148
- package/dist/{auditHandler-JCOJSUYW.js → auditHandler-VWCXSDVO.js} +12 -11
- package/dist/autopilotInit-Q62MX5M6.js +178 -0
- package/dist/bin/lurq.js +235 -83
- package/dist/{browserAuth-B6G27USY.js → browserAuth-J7APSD4P.js} +4 -3
- package/dist/{cache-DKI34SVS.js → cache-AEAKCV4I.js} +2 -2
- package/dist/check-2JTQDQA6.js +2613 -0
- package/dist/{check-2FDGUOV7.js → check-PQSQ2MMA.js} +1 -1
- package/dist/checkUpgrade-5YW77OBL.js +24 -0
- package/dist/{chunk-BCANRN5B.js → chunk-2GAYNIHG.js} +8 -1
- package/dist/{chunk-EA3DP5HG.js → chunk-2O6Z37IT.js} +155 -25
- package/dist/{chunk-J5FZYN4A.js → chunk-2WD4QAH4.js} +1 -1
- package/dist/{chunk-CUP36ND3.js → chunk-3676XOBU.js} +145 -36
- package/dist/chunk-3D2MPGOQ.js +181 -0
- package/dist/{chunk-LYMPYETA.js → chunk-4JHDSVIN.js} +270 -6
- package/dist/chunk-53SG6XWA.js +141 -0
- package/dist/chunk-5ABNDB3I.js +37 -0
- package/dist/chunk-5ALIJFDA.js +114 -0
- package/dist/{chunk-BULZAX2U.js → chunk-64ZF7KO4.js} +55 -38
- package/dist/{chunk-2VMOWSRY.js → chunk-6DM6UQFD.js} +19 -1
- package/dist/{chunk-HWBBVLOT.js → chunk-6L67QMCP.js} +1 -1
- package/dist/{chunk-GPTKSNR6.js → chunk-72Y2FDVS.js} +2 -1
- package/dist/{chunk-B43LCXBM.js → chunk-A3TYI2TF.js} +81 -16
- package/dist/{chunk-IQ4SDKKY.js → chunk-B2UUYRBX.js} +31 -228
- package/dist/{chunk-DB2VF5UD.js → chunk-BJT2LHAR.js} +16 -11
- package/dist/chunk-BM3LF5T6.js +132 -0
- package/dist/{chunk-3N3Q3DSW.js → chunk-BN3NM47Q.js} +8 -8
- package/dist/chunk-D3K6IZVR.js +12845 -0
- package/dist/{chunk-AHBP533R.js → chunk-D3VTZS7V.js} +7 -5
- package/dist/{chunk-UDVNA7EA.js → chunk-DM37MTOO.js} +161 -8
- package/dist/chunk-DONTW3NE.js +171 -0
- package/dist/{chunk-M6NYEXCW.js → chunk-DSROTZ3Z.js} +1 -1
- package/dist/{chunk-4F7ZESPO.js → chunk-EQCXENKZ.js} +3 -5
- package/dist/{chunk-CW5HJ3LX.js → chunk-EYAKM6YN.js} +1 -1
- package/dist/{chunk-VL2E5T2A.js → chunk-FDFPMBCA.js} +6 -3
- package/dist/{chunk-BV32UNLL.js → chunk-FVYFV5HA.js} +2 -2
- package/dist/{chunk-DWAGCNEL.js → chunk-GM5Y555O.js} +36 -103
- package/dist/{chunk-PSX3GIAN.js → chunk-HWFX4BC4.js} +2 -1
- package/dist/chunk-IFNONGRQ.js +603 -0
- package/dist/chunk-J3U2CPSK.js +136 -0
- package/dist/{chunk-Y5GI7RL3.js → chunk-J6XQ7OPZ.js} +9 -1
- package/dist/{chunk-LBFGSSF2.js → chunk-KMV4Y6R3.js} +2 -1
- package/dist/{chunk-L6N4JFW2.js → chunk-KP5ZDDPE.js} +81 -4
- package/dist/{chunk-SJOVFF7B.js → chunk-KYKSZ3XZ.js} +3 -2
- package/dist/chunk-NEZNAPPN.js +41 -0
- package/dist/{chunk-NH5I4KHH.js → chunk-NPVN2THM.js} +1 -5
- package/dist/{chunk-6L3U7DZ5.js → chunk-NYZU5NCW.js} +1 -1
- package/dist/chunk-O4KHCV6I.js +320 -0
- package/dist/{chunk-LO35HLQZ.js → chunk-ONDVTXUO.js} +25 -4
- package/dist/{chunk-4ZYCIMY4.js → chunk-OTJFHESY.js} +25 -4
- package/dist/chunk-P6MIKSPY.js +243 -0
- package/dist/{checkUpgrade-F2WESBPM.js → chunk-QCRBX3LV.js} +72 -10
- package/dist/{chunk-LRD4GBYE.js → chunk-QUIMQ7YL.js} +1 -1
- package/dist/chunk-RG3YLU6E.js +49 -0
- package/dist/{chunk-ST2X2GYN.js → chunk-SHZFOSXC.js} +109 -20
- package/dist/{chunk-CIDWNUAP.js → chunk-SOXFMMXC.js} +8 -2
- package/dist/chunk-TDTYV6QI.js +119 -0
- package/dist/{chunk-FW6BD2NO.js → chunk-TUXQ32WE.js} +457 -121
- package/dist/{chunk-WQ23REYT.js → chunk-VGCDRK3S.js} +1 -1
- package/dist/{chunk-U5AT3TD4.js → chunk-X4W64MHU.js} +1735 -1858
- package/dist/chunk-XBQA4I36.js +92 -0
- package/dist/chunk-XGOV6KV4.js +413 -0
- package/dist/{chunk-OQS4GUSI.js → chunk-XIFQIFSZ.js} +210 -661
- package/dist/{chunk-XBIDMHSK.js → chunk-XLXPVN3Y.js} +2 -34
- package/dist/chunk-ZJMLQ37G.js +90 -0
- package/dist/{client-IRKAMDYZ.js → client-MU4EUDZV.js} +3 -3
- package/dist/{commands-FIL5ET6P.js → commands-UOOTMBKA.js} +145 -33
- package/dist/{compat-R3UTFQ5Q.js → compat-Q5DVPITN.js} +6 -6
- package/dist/constants-DJFOFZ44.js +24 -0
- package/dist/{dashboardIssue-WYYMBFIB.js → dashboardIssue-KBKLQMGC.js} +105 -23
- package/dist/{diff-GZA2774U.js → diff-I4SNUHU3.js} +1 -1
- package/dist/domains-VRT4BRVZ.js +14 -0
- package/dist/env-UN6KGZ7S.js +15 -0
- package/dist/envCheck-KUPTORFQ.js +71 -0
- package/dist/{extract-NKGKLIVT.js → extract-6WG265BL.js} +14 -3
- package/dist/{fetch-QYTUJVG2.js → fetch-PJ3SC32M.js} +4 -4
- package/dist/{firstTouch-QQTJH4QX.js → firstTouch-COJCMOB3.js} +1 -1
- package/dist/fix-3EDWNKW3.js +220 -0
- package/dist/{handlers-GEJAVZDK.js → handlers-4Q37WIFT.js} +19 -17
- package/dist/hook-NA66XJLC.js +412 -0
- package/dist/{http-ETPYMBGD.js → http-25GJ6SKK.js} +2078 -510
- package/dist/{ingestQueue-VKN4KBIF.js → ingestQueue-FSVJC3AA.js} +14 -12
- package/dist/{install-EK3W2COX.js → install-G2HHXYJ2.js} +6 -6
- package/dist/{installSkill-VQJWJVCL.js → installSkill-5TIMYIJZ.js} +21 -3
- package/dist/manifest-ENMIC54B.js +13 -0
- package/dist/{mcp-3JHD5SUZ.js → mcp-PENLL2PK.js} +60 -32
- package/dist/mcpConfig-3LYPRY5Q.js +80 -0
- package/dist/{mcpHandlers-QFN4MCFL.js → mcpHandlers-PO7GENA7.js} +7 -7
- package/dist/{mcpScan-QZHWENIP.js → mcpScan-ULP626TQ.js} +306 -442
- package/dist/{mcpScanWorkflow-JPYCBGC4.js → mcpScanWorkflow-27O44FOE.js} +29 -12
- package/dist/{mcpStack-BYJCZNIV.js → mcpStack-ZNYIFXZ5.js} +1 -1
- package/dist/model-ASMZWLM7.js +214 -0
- package/dist/{packages-THVFMWFP.js → packages-RWF2LXST.js} +3 -5
- package/dist/{plan-V4OEI3J4.js → plan-SDILIDZT.js} +23 -21
- package/dist/{planView-JRXGCG2N.js → planView-ZAKRTGVS.js} +4 -1
- package/dist/{policy-3P6BGRDN.js → policy-JAGNMQJI.js} +5 -5
- package/dist/probe-3IK646WN.js +610 -0
- package/dist/publicUpgrades-WTBGLDIK.js +42 -0
- package/dist/{references-6N7VEPHT.js → references-I6Y4BSRR.js} +3 -1
- package/dist/{release-4U4ABNSJ.js → release-7IU2R4YG.js} +5 -5
- package/dist/{remote-YGCXYI4V.js → remote-FN6225AH.js} +13 -3
- package/dist/rename-OS6JYBZQ.js +204 -0
- package/dist/{reportRuns-CKQQYLY4.js → reportRuns-O4X7ZFTX.js} +15 -2
- package/dist/safeFetch-COERXGFN.js +19 -0
- package/dist/{sandbox-MEZLAODF.js → sandbox-SAPSRKEI.js} +4 -4
- package/dist/sarif-WLVJFJ7U.js +125 -0
- package/dist/server-OLTY3NYT.js +59 -0
- package/dist/{surface-V62GE554.js → surface-7MHE3RL7.js} +18 -16
- package/dist/{surface-YL6O67W3.js → surface-JS2XU3U3.js} +5 -3
- package/dist/{surfaceHandlers-X2IZKA3E.js → surfaceHandlers-4B6TMZ34.js} +5 -5
- package/dist/{typecheck-X7U5ELMR.js → typecheck-NGOKNAJY.js} +23 -9
- package/dist/{uninstall-P7RGBX6G.js → uninstall-I2IJP5JZ.js} +30 -4
- package/dist/{upgrade-NQ5IWFZB.js → upgrade-FS26DJGG.js} +86 -32
- package/dist/{upgradePlan-A4LRKLEG.js → upgradePlan-ZS5IOVMZ.js} +46 -11
- package/dist/upkeepHandler-VFGYXJKB.js +13 -0
- package/dist/{userConfig-Z3GQE776.js → userConfig-ICASHI47.js} +1 -1
- package/dist/{watch-DGFMWUDL.js → watch-OCNEUXG6.js} +24 -34
- package/package.json +3 -2
- package/templates/skill-instructions.md +22 -3
- package/dist/chunk-6AAEVQ7I.js +0 -6336
- package/dist/chunk-I2JUKN6Z.js +0 -24
- package/dist/server-KFUD5X57.js +0 -55
|
@@ -2,7 +2,7 @@ import { createRequire as __lurqCreateRequire } from 'node:module'; const requir
|
|
|
2
2
|
import {
|
|
3
3
|
PACKAGE_NAME,
|
|
4
4
|
VERSION
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-72Y2FDVS.js";
|
|
6
6
|
import {
|
|
7
7
|
init_esm_shims
|
|
8
8
|
} from "./chunk-I3M2KJXB.js";
|
|
@@ -15,6 +15,10 @@ function cliSpec(version = VERSION) {
|
|
|
15
15
|
return major === "0" ? `${PACKAGE_NAME}@${major}.${minor}` : `${PACKAGE_NAME}@${major}`;
|
|
16
16
|
}
|
|
17
17
|
var DEFAULT_CRON = "0 6 * * 1";
|
|
18
|
+
var SECURITY_CRON = "0 6 * * *";
|
|
19
|
+
function cronForScope(scope) {
|
|
20
|
+
return scope === "security" ? SECURITY_CRON : DEFAULT_CRON;
|
|
21
|
+
}
|
|
18
22
|
function detectInstallCommand(lockfiles) {
|
|
19
23
|
if (lockfiles.includes("pnpm-lock.yaml")) return "pnpm install --frozen-lockfile";
|
|
20
24
|
if (lockfiles.includes("yarn.lock")) return "yarn install --frozen-lockfile";
|
|
@@ -26,13 +30,20 @@ function renderWorkflow(opts = {}) {
|
|
|
26
30
|
const cron = opts.cron ?? DEFAULT_CRON;
|
|
27
31
|
const install = opts.installCommand ?? "npm ci";
|
|
28
32
|
const max = opts.maxUpgrades ?? 3;
|
|
29
|
-
const mode = opts.armed ? "pr" : "comment";
|
|
33
|
+
const mode = opts.mode ?? (opts.armed ? "pr" : "comment");
|
|
30
34
|
const autoMerge = opts.autoMerge ?? false;
|
|
31
35
|
const cli = cliSpec();
|
|
36
|
+
const envCheck = opts.checkEnv === true ? ` - name: Check environment
|
|
37
|
+
run: |
|
|
38
|
+
npx -y ${cli} check-env . > lurq-env.txt
|
|
39
|
+
{ echo '\`\`\`'; cat lurq-env.txt; echo '\`\`\`'; } >> "\${GITHUB_STEP_SUMMARY}"
|
|
40
|
+
|
|
41
|
+
` : "";
|
|
32
42
|
return `# Managed by lurq, https://lurq.run
|
|
33
43
|
#
|
|
34
44
|
# Keeps this repository's dependencies current and rewrites the call sites an
|
|
35
|
-
# upgrade breaks. lurq
|
|
45
|
+
# upgrade breaks. lurq has read-only access to your code, and may start this
|
|
46
|
+
# workflow when a dependency you declare ships a breaking release; every write
|
|
36
47
|
# below is made by this workflow's own GITHUB_TOKEN, scoped by the permissions
|
|
37
48
|
# block. Delete this file to turn the autopilot off.
|
|
38
49
|
name: lurq upgrade
|
|
@@ -43,10 +54,15 @@ on:
|
|
|
43
54
|
workflow_dispatch:
|
|
44
55
|
inputs:
|
|
45
56
|
mode:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
# No default, and deliberately a string rather than a choice. GitHub
|
|
58
|
+
# applies an input default on EVERY dispatch, including the ones lurq
|
|
59
|
+
# sends when a new major lands \u2014 which would fill LURQ_MODE before the
|
|
60
|
+
# "Resolve mode" step could read this repo's dashboard setting, and
|
|
61
|
+
# silently pin every triggered run to whatever was baked in at
|
|
62
|
+
# generation time. Left empty, a dispatch behaves like a scheduled run.
|
|
63
|
+
description: "leave empty to use your dashboard setting; or comment / fix / pr"
|
|
64
|
+
type: string
|
|
65
|
+
required: false
|
|
50
66
|
|
|
51
67
|
# The blast radius. \`contents: write\` permits pushing a BRANCH; branch
|
|
52
68
|
# protection on your default branch is what stops anything landing unreviewed.
|
|
@@ -62,7 +78,11 @@ jobs:
|
|
|
62
78
|
upgrade:
|
|
63
79
|
runs-on: ubuntu-latest
|
|
64
80
|
env:
|
|
65
|
-
|
|
81
|
+
# Empty when nothing explicit set it, which the "Resolve mode" step below
|
|
82
|
+
# then fills from this repository's dashboard setting. Precedence is
|
|
83
|
+
# explicit first: a dispatch input, then a repository variable, then the
|
|
84
|
+
# dashboard, then the mode baked in when this file was generated.
|
|
85
|
+
LURQ_MODE: \${{ inputs.mode || vars.LURQ_MODE || '' }}
|
|
66
86
|
MAX_UPGRADES: "${max}"
|
|
67
87
|
steps:
|
|
68
88
|
- uses: actions/checkout@v6
|
|
@@ -78,6 +98,29 @@ jobs:
|
|
|
78
98
|
LURQ_API_KEY: \${{ secrets.LURQ_API_KEY }}
|
|
79
99
|
run: npx -y ${cli} upgrade-plan . --json > lurq-plan.json
|
|
80
100
|
|
|
101
|
+
# Without this the autopilot switch on the dashboard would only ever
|
|
102
|
+
# affect NEW installs: lurq is Contents:read-only and cannot rewrite this
|
|
103
|
+
# file or set a repository variable, so the mode is read at runtime from
|
|
104
|
+
# the plan above, which already carries this repository's policy.
|
|
105
|
+
#
|
|
106
|
+
# Skipped entirely when something explicit already set the mode, so a
|
|
107
|
+
# repository variable or a dispatch choice still wins. An older server or
|
|
108
|
+
# an unconnected repo sends no mode and the baked-in '${mode}' stands.
|
|
109
|
+
#
|
|
110
|
+
# The value is checked against the three it may be before it reaches the
|
|
111
|
+
# environment \u2014 it arrives over the network, and GITHUB_ENV is not the
|
|
112
|
+
# place to trust a response.
|
|
113
|
+
- name: Resolve mode
|
|
114
|
+
if: env.LURQ_MODE == ''
|
|
115
|
+
run: |
|
|
116
|
+
MODE=$(jq -r '.mode // empty' lurq-plan.json)
|
|
117
|
+
case "$MODE" in
|
|
118
|
+
pr|fix|comment) ;;
|
|
119
|
+
*) MODE='${mode}' ;;
|
|
120
|
+
esac
|
|
121
|
+
echo "LURQ_MODE=$MODE" >> "\${GITHUB_ENV}"
|
|
122
|
+
echo "Mode for this run: $MODE" >> "\${GITHUB_STEP_SUMMARY}"
|
|
123
|
+
|
|
81
124
|
# 2. Narrow that to symbols THIS repo references. Runs entirely locally
|
|
82
125
|
# against both versions' npm tarballs, no API key, no test suite.
|
|
83
126
|
#
|
|
@@ -99,9 +142,10 @@ jobs:
|
|
|
99
142
|
{ echo '\`\`\`'; cat lurq-report.txt; echo '\`\`\`'; } > lurq-report.md
|
|
100
143
|
cat lurq-report.md >> "\${GITHUB_STEP_SUMMARY}"
|
|
101
144
|
|
|
102
|
-
# 3. Editing is opt-in.
|
|
103
|
-
#
|
|
104
|
-
# Anthropic credential is
|
|
145
|
+
${envCheck} # 3. Editing is opt-in. In 'comment' the job stops here having changed
|
|
146
|
+
# nothing, with the brief in the run summary above. 'fix' and 'pr' both
|
|
147
|
+
# continue; only 'pr' needs an Anthropic credential, which is why the
|
|
148
|
+
# check below is gated on it alone and not on editing in general.
|
|
105
149
|
- name: Check agent credentials
|
|
106
150
|
if: env.LURQ_MODE == 'pr'
|
|
107
151
|
env:
|
|
@@ -109,14 +153,27 @@ jobs:
|
|
|
109
153
|
OAUTH_TOKEN: \${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
110
154
|
run: |
|
|
111
155
|
if [ -z "$API_KEY" ] && [ -z "$OAUTH_TOKEN" ]; then
|
|
112
|
-
echo "::error::pr mode needs one of ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in this repository's secrets. A Claude Pro/Max subscription token works for the latter. Set LURQ_MODE=comment to run analysis only."
|
|
156
|
+
echo "::error::pr mode needs one of ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN in this repository's secrets. A Claude Pro/Max subscription token works for the latter. Set LURQ_MODE=fix to still open pull requests using only the changes lurq can prove (no key needed), or LURQ_MODE=comment to run analysis only."
|
|
113
157
|
exit 1
|
|
114
158
|
fi
|
|
115
159
|
|
|
116
160
|
- name: Install dependencies
|
|
117
|
-
if: env.LURQ_MODE == 'pr'
|
|
161
|
+
if: env.LURQ_MODE == 'pr' || env.LURQ_MODE == 'fix'
|
|
118
162
|
run: ${install}
|
|
119
163
|
|
|
164
|
+
# Everything the package itself proves, made WITHOUT a model: renamed call
|
|
165
|
+
# sites, and the range bump in every manifest declaring the dependency.
|
|
166
|
+
#
|
|
167
|
+
# After the install, not before: bumping package.json first fails \`npm ci\`
|
|
168
|
+
# outright with a lock-out-of-sync error, and the agent's own install below
|
|
169
|
+
# reconciles the lockfile afterwards. It takes the same cap the agent is
|
|
170
|
+
# given, so the two cannot disagree about blast radius, and it refuses
|
|
171
|
+
# multi-major upgrades and unplannable sequences \u2014 the same rules the
|
|
172
|
+
# prompt states below, applied by a rule instead of a model.
|
|
173
|
+
- name: Apply what needs no judgement
|
|
174
|
+
if: env.LURQ_MODE == 'pr' || env.LURQ_MODE == 'fix'
|
|
175
|
+
run: npx -y ${cli} fix . --plan lurq-plan.json --apply --max \${{ env.MAX_UPGRADES }}
|
|
176
|
+
|
|
120
177
|
- name: Apply upgrades
|
|
121
178
|
if: env.LURQ_MODE == 'pr'
|
|
122
179
|
uses: anthropics/claude-code-action@v1
|
|
@@ -144,10 +201,17 @@ jobs:
|
|
|
144
201
|
"sequenceNote" is present, the sequence could not be planned,
|
|
145
202
|
treat that dependency as a migration and skip it.
|
|
146
203
|
|
|
204
|
+
A step before you has ALREADY APPLIED every change lurq could
|
|
205
|
+
prove: renamed call sites where the package itself proves the
|
|
206
|
+
replacement, and the range bump in every manifest for those
|
|
207
|
+
upgrades. Read the files before assuming any of it is undone \u2014 you
|
|
208
|
+
cannot run git, so the working tree is the only record. Your job is
|
|
209
|
+
what remains, and re-doing applied work risks reverting it.
|
|
210
|
+
|
|
147
211
|
Take at most \${{ env.MAX_UPGRADES }} entries, hardest first:
|
|
148
212
|
|
|
149
213
|
1. Bump the dependency's range in every manifest listed in
|
|
150
|
-
"declaredIn".
|
|
214
|
+
"declaredIn", where that has not been done already.
|
|
151
215
|
2. Run \`${install.split(" ")[0]} install\` so node_modules holds the
|
|
152
216
|
TARGET version. Until you do, the package on disk is the old one
|
|
153
217
|
and anything you read from it describes the API you are leaving.
|
|
@@ -185,7 +249,7 @@ jobs:
|
|
|
185
249
|
# 4. The workflow does version control, never the model.
|
|
186
250
|
- name: Open pull request
|
|
187
251
|
id: pr
|
|
188
|
-
if: env.LURQ_MODE == 'pr'
|
|
252
|
+
if: env.LURQ_MODE == 'pr' || env.LURQ_MODE == 'fix'
|
|
189
253
|
uses: peter-evans/create-pull-request@v7
|
|
190
254
|
with:
|
|
191
255
|
branch: lurq/upgrades
|
|
@@ -204,7 +268,7 @@ var MERGE_STEP = `
|
|
|
204
268
|
# once the repo's OWN required checks pass; lurq never makes that call.
|
|
205
269
|
# Requires "Allow auto-merge" in repository settings.
|
|
206
270
|
- name: Enable auto-merge
|
|
207
|
-
if: env.LURQ_MODE == 'pr' && steps.pr.outputs.pull-request-number
|
|
271
|
+
if: (env.LURQ_MODE == 'pr' || env.LURQ_MODE == 'fix') && steps.pr.outputs.pull-request-number
|
|
208
272
|
env:
|
|
209
273
|
GH_TOKEN: \${{ secrets.GITHUB_TOKEN }}
|
|
210
274
|
run: gh pr merge --auto --squash "\${{ steps.pr.outputs.pull-request-number }}"
|
|
@@ -217,6 +281,7 @@ function newFileUrl(fullName, branch, content) {
|
|
|
217
281
|
export {
|
|
218
282
|
WORKFLOW_PATH,
|
|
219
283
|
cliSpec,
|
|
284
|
+
cronForScope,
|
|
220
285
|
detectInstallCommand,
|
|
221
286
|
renderWorkflow,
|
|
222
287
|
newFileUrl
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { createRequire as __lurqCreateRequire } from 'node:module'; const require = __lurqCreateRequire(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
checkMcpStack,
|
|
4
|
+
isCrowded
|
|
5
|
+
} from "./chunk-FDFPMBCA.js";
|
|
2
6
|
import {
|
|
3
7
|
loadStored,
|
|
4
8
|
rowsToSurface
|
|
5
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-BJT2LHAR.js";
|
|
10
|
+
import {
|
|
11
|
+
listAccountDeployments
|
|
12
|
+
} from "./chunk-P6MIKSPY.js";
|
|
13
|
+
import {
|
|
14
|
+
MCP_TIER,
|
|
15
|
+
contractOf
|
|
16
|
+
} from "./chunk-6EQ3ARXA.js";
|
|
6
17
|
import {
|
|
7
18
|
fetchServerManifest,
|
|
8
19
|
missingConfig
|
|
@@ -10,31 +21,18 @@ import {
|
|
|
10
21
|
import {
|
|
11
22
|
SEVERITY_RANK
|
|
12
23
|
} from "./chunk-Q5VPF4WI.js";
|
|
13
|
-
import {
|
|
14
|
-
checkMcpStack,
|
|
15
|
-
isCrowded
|
|
16
|
-
} from "./chunk-VL2E5T2A.js";
|
|
17
|
-
import {
|
|
18
|
-
MCP_TIER,
|
|
19
|
-
contractOf
|
|
20
|
-
} from "./chunk-6EQ3ARXA.js";
|
|
21
|
-
import {
|
|
22
|
-
enqueueSurface
|
|
23
|
-
} from "./chunk-LO35HLQZ.js";
|
|
24
24
|
import {
|
|
25
25
|
assessVerdict
|
|
26
26
|
} from "./chunk-QSL6QN5X.js";
|
|
27
27
|
import {
|
|
28
28
|
queryVulnerableInstalls
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-QUIMQ7YL.js";
|
|
30
|
+
import {
|
|
31
|
+
enqueueSurface
|
|
32
|
+
} from "./chunk-ONDVTXUO.js";
|
|
30
33
|
import {
|
|
31
|
-
mcpChangeEvents,
|
|
32
|
-
mcpContracts,
|
|
33
|
-
mcpDeployments,
|
|
34
|
-
mcpObservations,
|
|
35
|
-
mcpPublicReports,
|
|
36
34
|
packages
|
|
37
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-4JHDSVIN.js";
|
|
38
36
|
import {
|
|
39
37
|
require_semver
|
|
40
38
|
} from "./chunk-3GHJR7XR.js";
|
|
@@ -51,200 +49,6 @@ init_esm_shims();
|
|
|
51
49
|
|
|
52
50
|
// src/audit/accountScans.ts
|
|
53
51
|
init_esm_shims();
|
|
54
|
-
|
|
55
|
-
// src/db/mcpScans.ts
|
|
56
|
-
init_esm_shims();
|
|
57
|
-
import { and, desc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
58
|
-
async function putContract(db, row) {
|
|
59
|
-
await db.insert(mcpContracts).values(row).onConflictDoNothing();
|
|
60
|
-
}
|
|
61
|
-
async function getContract(db, contentHash) {
|
|
62
|
-
const [row] = await db.select().from(mcpContracts).where(eq(mcpContracts.contentHash, contentHash)).limit(1);
|
|
63
|
-
return row ?? null;
|
|
64
|
-
}
|
|
65
|
-
async function countDeployments(db, ownerId) {
|
|
66
|
-
const [row] = await db.select({ n: sql`count(*)::int` }).from(mcpDeployments).where(eq(mcpDeployments.ownerId, ownerId));
|
|
67
|
-
return row?.n ?? 0;
|
|
68
|
-
}
|
|
69
|
-
async function deploymentExists(db, ownerId, serverKey, configFingerprint) {
|
|
70
|
-
const [row] = await db.select({ id: mcpDeployments.id }).from(mcpDeployments).where(
|
|
71
|
-
and(
|
|
72
|
-
eq(mcpDeployments.ownerId, ownerId),
|
|
73
|
-
eq(mcpDeployments.serverKey, serverKey),
|
|
74
|
-
eq(mcpDeployments.configFingerprint, configFingerprint)
|
|
75
|
-
)
|
|
76
|
-
).limit(1);
|
|
77
|
-
return !!row;
|
|
78
|
-
}
|
|
79
|
-
async function recordScan(db, input, diff) {
|
|
80
|
-
return db.transaction(async (tx) => {
|
|
81
|
-
const now = /* @__PURE__ */ new Date();
|
|
82
|
-
const inserted = await tx.insert(mcpDeployments).values({
|
|
83
|
-
ownerId: input.ownerId,
|
|
84
|
-
serverKey: input.serverKey,
|
|
85
|
-
configFingerprint: input.configFingerprint,
|
|
86
|
-
alias: input.alias,
|
|
87
|
-
registry: input.registry,
|
|
88
|
-
packageName: input.packageName,
|
|
89
|
-
transport: input.transport,
|
|
90
|
-
lastStatus: input.status,
|
|
91
|
-
firstSeenAt: now,
|
|
92
|
-
lastScannedAt: now
|
|
93
|
-
}).onConflictDoNothing({
|
|
94
|
-
target: [mcpDeployments.ownerId, mcpDeployments.serverKey, mcpDeployments.configFingerprint]
|
|
95
|
-
}).returning({ id: mcpDeployments.id });
|
|
96
|
-
const isFirst = inserted.length > 0;
|
|
97
|
-
const [dep] = await tx.select().from(mcpDeployments).where(
|
|
98
|
-
and(
|
|
99
|
-
eq(mcpDeployments.ownerId, input.ownerId),
|
|
100
|
-
eq(mcpDeployments.serverKey, input.serverKey),
|
|
101
|
-
eq(mcpDeployments.configFingerprint, input.configFingerprint)
|
|
102
|
-
)
|
|
103
|
-
).for("update").limit(1);
|
|
104
|
-
if (!dep) throw new Error("deployment vanished inside its own transaction");
|
|
105
|
-
const [last] = await tx.select().from(mcpObservations).where(eq(mcpObservations.deploymentId, dep.id)).orderBy(desc(mcpObservations.id)).limit(1);
|
|
106
|
-
const same = last && last.status === input.status && last.contentHash === input.contentHash && last.serverVersion === input.serverVersion;
|
|
107
|
-
if (same) {
|
|
108
|
-
await tx.update(mcpObservations).set({ lastSeenAt: now, scanCount: sql`${mcpObservations.scanCount} + 1` }).where(eq(mcpObservations.id, last.id));
|
|
109
|
-
} else {
|
|
110
|
-
await tx.insert(mcpObservations).values({
|
|
111
|
-
deploymentId: dep.id,
|
|
112
|
-
ownerId: input.ownerId,
|
|
113
|
-
status: input.status,
|
|
114
|
-
contentHash: input.contentHash,
|
|
115
|
-
serverVersion: input.serverVersion,
|
|
116
|
-
error: input.error,
|
|
117
|
-
source: input.source,
|
|
118
|
-
firstSeenAt: now,
|
|
119
|
-
lastSeenAt: now
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
let change = isFirst ? "first" : "unchanged";
|
|
123
|
-
let event = null;
|
|
124
|
-
const moved = !isFirst && input.contentHash && dep.lastContentHash && input.contentHash !== dep.lastContentHash;
|
|
125
|
-
if (moved) {
|
|
126
|
-
const [previous] = await tx.select().from(mcpContracts).where(eq(mcpContracts.contentHash, dep.lastContentHash)).limit(1);
|
|
127
|
-
if (previous) {
|
|
128
|
-
const d = diff(previous);
|
|
129
|
-
await tx.insert(mcpChangeEvents).values({
|
|
130
|
-
deploymentId: dep.id,
|
|
131
|
-
ownerId: input.ownerId,
|
|
132
|
-
fromHash: dep.lastContentHash,
|
|
133
|
-
toHash: input.contentHash,
|
|
134
|
-
severity: d.severity,
|
|
135
|
-
summary: d.summary.slice(0, 1e3),
|
|
136
|
-
diff: d,
|
|
137
|
-
createdAt: now
|
|
138
|
-
}).onConflictDoUpdate({
|
|
139
|
-
target: [mcpChangeEvents.deploymentId, mcpChangeEvents.fromHash, mcpChangeEvents.toHash],
|
|
140
|
-
set: { createdAt: now, acknowledgedAt: null, severity: d.severity, summary: d.summary.slice(0, 1e3), diff: d }
|
|
141
|
-
});
|
|
142
|
-
change = "changed";
|
|
143
|
-
event = { at: now, severity: d.severity, summary: d.summary, rugPull: d.rugPull };
|
|
144
|
-
}
|
|
145
|
-
} else if (!isFirst && dep.lastStatus !== input.status) {
|
|
146
|
-
change = "status_changed";
|
|
147
|
-
}
|
|
148
|
-
await tx.update(mcpDeployments).set({
|
|
149
|
-
alias: input.alias,
|
|
150
|
-
transport: input.transport,
|
|
151
|
-
packageName: input.packageName,
|
|
152
|
-
lastStatus: input.status,
|
|
153
|
-
lastError: input.error,
|
|
154
|
-
lastScannedAt: now,
|
|
155
|
-
...input.serverName !== null ? { serverName: input.serverName } : {},
|
|
156
|
-
...input.serverVersion !== null ? { serverVersion: input.serverVersion } : {},
|
|
157
|
-
// A failed scan keeps the last contract that was read: "the server was
|
|
158
|
-
// unreachable today" must not erase what it exposed yesterday.
|
|
159
|
-
...input.contentHash ? { lastContentHash: input.contentHash, worstSeverity: input.worstSeverity } : {},
|
|
160
|
-
...moved || isFirst ? { lastChangedAt: now } : {}
|
|
161
|
-
}).where(eq(mcpDeployments.id, dep.id));
|
|
162
|
-
return { deploymentId: dep.id, change, event };
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
async function reportPublic(db, row) {
|
|
166
|
-
await db.insert(mcpPublicReports).values(row).onConflictDoNothing();
|
|
167
|
-
const [agree] = await db.select({ n: sql`count(distinct ${mcpPublicReports.ownerId})::int` }).from(mcpPublicReports).where(
|
|
168
|
-
and(
|
|
169
|
-
eq(mcpPublicReports.registry, row.registry),
|
|
170
|
-
eq(mcpPublicReports.packageName, row.packageName),
|
|
171
|
-
eq(mcpPublicReports.version, row.version),
|
|
172
|
-
eq(mcpPublicReports.contentHash, row.contentHash)
|
|
173
|
-
)
|
|
174
|
-
);
|
|
175
|
-
return agree?.n ?? 0;
|
|
176
|
-
}
|
|
177
|
-
var RANK = { critical: 0, high: 1, moderate: 2, low: 3, info: 4 };
|
|
178
|
-
async function listDeployments(db, ownerId) {
|
|
179
|
-
const rows = await db.select({ d: mcpDeployments, c: { toolCount: mcpContracts.toolCount, analysis: mcpContracts.analysis } }).from(mcpDeployments).leftJoin(mcpContracts, eq(mcpContracts.contentHash, mcpDeployments.lastContentHash)).where(eq(mcpDeployments.ownerId, ownerId)).orderBy(desc(mcpDeployments.lastScannedAt)).limit(500);
|
|
180
|
-
if (rows.length === 0) return [];
|
|
181
|
-
const open = await db.select({ deploymentId: mcpChangeEvents.deploymentId, severity: mcpChangeEvents.severity }).from(mcpChangeEvents).where(
|
|
182
|
-
and(
|
|
183
|
-
eq(mcpChangeEvents.ownerId, ownerId),
|
|
184
|
-
isNull(mcpChangeEvents.acknowledgedAt),
|
|
185
|
-
inArray(
|
|
186
|
-
mcpChangeEvents.deploymentId,
|
|
187
|
-
rows.map((r) => r.d.id)
|
|
188
|
-
)
|
|
189
|
-
)
|
|
190
|
-
);
|
|
191
|
-
const byDep = /* @__PURE__ */ new Map();
|
|
192
|
-
for (const e of open) {
|
|
193
|
-
const cur = byDep.get(e.deploymentId) ?? { n: 0, worst: null };
|
|
194
|
-
cur.n++;
|
|
195
|
-
if (!cur.worst || RANK[e.severity] < RANK[cur.worst]) cur.worst = e.severity;
|
|
196
|
-
byDep.set(e.deploymentId, cur);
|
|
197
|
-
}
|
|
198
|
-
return rows.map(({ d, c }) => ({
|
|
199
|
-
...d,
|
|
200
|
-
toolCount: c?.toolCount ?? null,
|
|
201
|
-
writes: c?.analysis?.stats.writes ?? null,
|
|
202
|
-
destroys: c?.analysis?.stats.destroys ?? null,
|
|
203
|
-
capabilities: c?.analysis?.stats.capabilities ?? {},
|
|
204
|
-
findings: c?.analysis?.findings.filter((f) => f.severity !== "info").length ?? 0,
|
|
205
|
-
openEvents: byDep.get(d.id)?.n ?? 0,
|
|
206
|
-
openWorst: byDep.get(d.id)?.worst ?? null
|
|
207
|
-
}));
|
|
208
|
-
}
|
|
209
|
-
async function getDeploymentDetail(db, ownerId, id) {
|
|
210
|
-
const [deployment] = await db.select().from(mcpDeployments).where(and(eq(mcpDeployments.id, id), eq(mcpDeployments.ownerId, ownerId))).limit(1);
|
|
211
|
-
if (!deployment) return null;
|
|
212
|
-
const [contract, observations, events] = await Promise.all([
|
|
213
|
-
deployment.lastContentHash ? getContract(db, deployment.lastContentHash) : Promise.resolve(null),
|
|
214
|
-
db.select().from(mcpObservations).where(and(eq(mcpObservations.deploymentId, id), eq(mcpObservations.ownerId, ownerId))).orderBy(desc(mcpObservations.id)).limit(60),
|
|
215
|
-
db.select().from(mcpChangeEvents).where(and(eq(mcpChangeEvents.deploymentId, id), eq(mcpChangeEvents.ownerId, ownerId))).orderBy(desc(mcpChangeEvents.createdAt)).limit(50)
|
|
216
|
-
]);
|
|
217
|
-
return { deployment, contract, observations, events };
|
|
218
|
-
}
|
|
219
|
-
async function listChangeEvents(db, ownerId, opts = {}) {
|
|
220
|
-
const rows = await db.select({ e: mcpChangeEvents, alias: mcpDeployments.alias, serverKey: mcpDeployments.serverKey }).from(mcpChangeEvents).innerJoin(mcpDeployments, eq(mcpDeployments.id, mcpChangeEvents.deploymentId)).where(
|
|
221
|
-
and(eq(mcpChangeEvents.ownerId, ownerId), opts.openOnly ? isNull(mcpChangeEvents.acknowledgedAt) : void 0)
|
|
222
|
-
).orderBy(desc(mcpChangeEvents.createdAt)).limit(Math.min(opts.limit ?? 50, 200));
|
|
223
|
-
return rows.map((r) => ({ ...r.e, alias: r.alias, serverKey: r.serverKey }));
|
|
224
|
-
}
|
|
225
|
-
async function acknowledgeEvent(db, ownerId, eventId) {
|
|
226
|
-
const rows = await db.update(mcpChangeEvents).set({ acknowledgedAt: /* @__PURE__ */ new Date() }).where(and(eq(mcpChangeEvents.id, eventId), eq(mcpChangeEvents.ownerId, ownerId))).returning({ id: mcpChangeEvents.id });
|
|
227
|
-
return rows.length > 0;
|
|
228
|
-
}
|
|
229
|
-
async function listAccountDeployments(db, ownerId) {
|
|
230
|
-
const summaries = await listDeployments(db, ownerId);
|
|
231
|
-
const hashes = [...new Set(summaries.map((s) => s.lastContentHash).filter((h) => !!h))];
|
|
232
|
-
const analyses = hashes.length ? await db.select({ hash: mcpContracts.contentHash, analysis: mcpContracts.analysis }).from(mcpContracts).where(inArray(mcpContracts.contentHash, hashes)) : [];
|
|
233
|
-
const byHash = new Map(analyses.map((a) => [a.hash, a.analysis]));
|
|
234
|
-
return summaries.map((s) => ({
|
|
235
|
-
serverKey: s.serverKey,
|
|
236
|
-
alias: s.alias,
|
|
237
|
-
lastStatus: s.lastStatus,
|
|
238
|
-
lastError: s.lastError,
|
|
239
|
-
lastContentHash: s.lastContentHash,
|
|
240
|
-
lastScannedAt: s.lastScannedAt,
|
|
241
|
-
analysis: s.lastContentHash ? byHash.get(s.lastContentHash) ?? null : null,
|
|
242
|
-
openEvents: s.openEvents,
|
|
243
|
-
openWorst: s.openWorst
|
|
244
|
-
}));
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
// src/audit/accountScans.ts
|
|
248
52
|
var STALE_AFTER_DAYS = 14;
|
|
249
53
|
var MAX_TOOL_FINDINGS = 5;
|
|
250
54
|
var DAY_MS = 864e5;
|
|
@@ -252,7 +56,8 @@ function matchDeployment(s, deployments) {
|
|
|
252
56
|
const host = s.endpoint?.toLowerCase();
|
|
253
57
|
const candidates = deployments.filter((d) => {
|
|
254
58
|
if (s.packageName) return d.serverKey === `npm:${s.packageName}`;
|
|
255
|
-
if (s.kind === "remote" && host)
|
|
59
|
+
if (s.kind === "remote" && host)
|
|
60
|
+
return d.serverKey === `remote:${host}` || d.serverKey.startsWith(`remote:${host}/`);
|
|
256
61
|
return d.alias === s.alias;
|
|
257
62
|
});
|
|
258
63
|
return candidates.sort((a, b) => b.lastScannedAt.getTime() - a.lastScannedAt.getTime())[0] ?? null;
|
|
@@ -281,7 +86,9 @@ function enrich(item, d, now) {
|
|
|
281
86
|
if (item.status !== "answered") {
|
|
282
87
|
item.status = "answered";
|
|
283
88
|
delete item.skipReason;
|
|
284
|
-
item.findings = item.findings.filter(
|
|
89
|
+
item.findings = item.findings.filter(
|
|
90
|
+
(f) => !(f.kind === "contract-drift" && f.severity === "info")
|
|
91
|
+
);
|
|
285
92
|
}
|
|
286
93
|
if (age > STALE_AFTER_DAYS) {
|
|
287
94
|
item.findings.push({
|
|
@@ -352,7 +159,7 @@ async function withAccountScans(db, ownerId, report, servers) {
|
|
|
352
159
|
// src/audit/assess.ts
|
|
353
160
|
init_esm_shims();
|
|
354
161
|
var import_semver = __toESM(require_semver(), 1);
|
|
355
|
-
import { inArray
|
|
162
|
+
import { inArray } from "drizzle-orm";
|
|
356
163
|
var NAME_CHUNK = 500;
|
|
357
164
|
async function loadIndexed(db, names) {
|
|
358
165
|
const out = /* @__PURE__ */ new Map();
|
|
@@ -363,7 +170,7 @@ async function loadIndexed(db, names) {
|
|
|
363
170
|
latestVersion: packages.latestVersion,
|
|
364
171
|
deprecated: packages.deprecated,
|
|
365
172
|
advisories: packages.advisories
|
|
366
|
-
}).from(packages).where(
|
|
173
|
+
}).from(packages).where(inArray(packages.name, chunk));
|
|
367
174
|
for (const r of rows) out.set(r.name, r);
|
|
368
175
|
}
|
|
369
176
|
return out;
|
|
@@ -669,7 +476,7 @@ async function queueUnknown(db, report, ownerId = null) {
|
|
|
669
476
|
const names = report.items.filter((i) => i.unit !== "transitive" && i.skipReason === "not-in-index").map((i) => i.name);
|
|
670
477
|
if (names.length === 0) return 0;
|
|
671
478
|
try {
|
|
672
|
-
const { enqueueIngest } = await import("./ingestQueue-
|
|
479
|
+
const { enqueueIngest } = await import("./ingestQueue-FSVJC3AA.js");
|
|
673
480
|
for (const name of names) enqueueIngest(db, name, ownerId);
|
|
674
481
|
} catch (err) {
|
|
675
482
|
logger.debug(`audit: untracked-dep enqueue failed: ${String(err)}`);
|
|
@@ -714,20 +521,16 @@ async function handleAudit(db, input, ownerId = null) {
|
|
|
714
521
|
filesRead: [],
|
|
715
522
|
notes
|
|
716
523
|
};
|
|
717
|
-
const report = await withAccountScans(
|
|
524
|
+
const report = await withAccountScans(
|
|
525
|
+
db,
|
|
526
|
+
ownerId,
|
|
527
|
+
await assessInventory(db, inv),
|
|
528
|
+
inv.mcpServers
|
|
529
|
+
);
|
|
718
530
|
await queueUnknown(db, report);
|
|
719
531
|
return { ...report, root: null };
|
|
720
532
|
}
|
|
721
533
|
|
|
722
534
|
export {
|
|
723
|
-
putContract,
|
|
724
|
-
countDeployments,
|
|
725
|
-
deploymentExists,
|
|
726
|
-
recordScan,
|
|
727
|
-
reportPublic,
|
|
728
|
-
listDeployments,
|
|
729
|
-
getDeploymentDetail,
|
|
730
|
-
listChangeEvents,
|
|
731
|
-
acknowledgeEvent,
|
|
732
535
|
handleAudit
|
|
733
536
|
};
|
|
@@ -7,17 +7,17 @@ import {
|
|
|
7
7
|
enqueueSurface,
|
|
8
8
|
mcpSurfaceRef,
|
|
9
9
|
surfaceRef
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import {
|
|
12
|
-
cached
|
|
13
|
-
} from "./chunk-HWBBVLOT.js";
|
|
10
|
+
} from "./chunk-ONDVTXUO.js";
|
|
14
11
|
import {
|
|
15
12
|
UNBOUNDED_ARITY,
|
|
16
13
|
claims,
|
|
17
14
|
entities,
|
|
18
15
|
observations,
|
|
19
16
|
symbols
|
|
20
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-4JHDSVIN.js";
|
|
18
|
+
import {
|
|
19
|
+
cached
|
|
20
|
+
} from "./chunk-6L67QMCP.js";
|
|
21
21
|
import {
|
|
22
22
|
logger
|
|
23
23
|
} from "./chunk-MYGSLK44.js";
|
|
@@ -65,7 +65,9 @@ async function drain() {
|
|
|
65
65
|
const updated = await job.fill(job.db, job.pkg, job.version, job.entityId);
|
|
66
66
|
logger.info(`surface fill ${key}: ${updated} symbol row(s) updated`);
|
|
67
67
|
} catch (err) {
|
|
68
|
-
logger.warn(
|
|
68
|
+
logger.warn(
|
|
69
|
+
`surface fill failed for ${key}: ${err instanceof Error ? err.message : String(err)}`
|
|
70
|
+
);
|
|
69
71
|
} finally {
|
|
70
72
|
pending.delete(key);
|
|
71
73
|
}
|
|
@@ -73,10 +75,12 @@ async function drain() {
|
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
async function fillOne(db, pkg, version, entityId) {
|
|
76
|
-
const { fetchAndExtract } = await import("./fetch-
|
|
78
|
+
const { fetchAndExtract } = await import("./fetch-PJ3SC32M.js");
|
|
77
79
|
const fetched = await fetchAndExtract(pkg, version);
|
|
78
80
|
if (!fetched) return 0;
|
|
79
|
-
const values = fetched.surface.symbols.filter(
|
|
81
|
+
const values = fetched.surface.symbols.filter(
|
|
82
|
+
(s) => s.tier === TIER && (s.sourceRef?.offset !== void 0 || s.maxArity !== void 0)
|
|
83
|
+
).map((s) => ({
|
|
80
84
|
path: s.path,
|
|
81
85
|
offset: s.sourceRef?.offset ?? null,
|
|
82
86
|
maxArity: s.maxArity === void 0 ? null : s.maxArity ?? UNBOUNDED_ARITY
|
|
@@ -189,7 +193,7 @@ async function resolveSurfaceUncached(db, input) {
|
|
|
189
193
|
const version = input.version ?? null;
|
|
190
194
|
let stored = await loadStored(db, input.package, version);
|
|
191
195
|
if (!stored || stored.verdict === "unknown" && stored.rows.length === 0) {
|
|
192
|
-
const { firstTouchSurface } = await import("./firstTouch-
|
|
196
|
+
const { firstTouchSurface } = await import("./firstTouch-COJCMOB3.js");
|
|
193
197
|
if (await firstTouchSurface(db, input.package, version)) {
|
|
194
198
|
stored = await loadStored(db, input.package, version);
|
|
195
199
|
}
|
|
@@ -244,7 +248,7 @@ async function diffSurfaceUncached(db, input, onFill) {
|
|
|
244
248
|
loadStored(db, input.package, input.toVersion)
|
|
245
249
|
]);
|
|
246
250
|
if (!a || !b || a.rows.length === 0 || b.rows.length === 0) {
|
|
247
|
-
const { firstTouchPair } = await import("./firstTouch-
|
|
251
|
+
const { firstTouchPair } = await import("./firstTouch-COJCMOB3.js");
|
|
248
252
|
if (await firstTouchPair(db, input.package, input.fromVersion, input.toVersion)) {
|
|
249
253
|
[a, b] = await Promise.all([
|
|
250
254
|
loadStored(db, input.package, input.fromVersion),
|
|
@@ -279,7 +283,8 @@ async function diffSurfaceUncached(db, input, onFill) {
|
|
|
279
283
|
[a, input.fromVersion],
|
|
280
284
|
[b, input.toVersion]
|
|
281
285
|
]) {
|
|
282
|
-
if (needsFill(stored.rows) && scheduleFill(db, input.package, version, stored.entityId))
|
|
286
|
+
if (needsFill(stored.rows) && scheduleFill(db, input.package, version, stored.entityId))
|
|
287
|
+
onFill();
|
|
283
288
|
}
|
|
284
289
|
const diff = diffSurfaces(
|
|
285
290
|
rowsToSurface(input.package, input.fromVersion, a.rows, a.tier ?? "shipped_js_ast"),
|