@codyswann/lisa 4.73.1 → 4.73.3
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 +20 -0
- package/all/copy-overwrite/scripts/lib/history-secret-git.mjs +158 -5
- package/all/copy-overwrite/scripts/lib/npm-update-contract.mjs +25 -1
- package/all/copy-overwrite/scripts/lisa-enforcement-fallback.sh +137 -163
- package/all/copy-overwrite/scripts/lisa-enforcement-freshness.mjs +180 -0
- package/all/copy-overwrite/scripts/lisa-history-secrets.mjs +17 -3
- package/all/copy-overwrite/scripts/lisa-hooks/block-blind-automerge.sh +86 -7
- package/all/copy-overwrite/scripts/lisa-hooks/block-managed-file-edits.sh +7 -1
- package/all/copy-overwrite/scripts/lisa-hooks/block-no-verify.sh +62 -7
- package/all/copy-overwrite/scripts/lisa-rails-prepush.mjs +4 -1
- package/all/copy-overwrite/scripts/lisa-work-item.mjs +191 -5
- package/all/copy-overwrite/scripts/npm-updater-helper-graph.json +5 -5
- package/all/deletions.json +19 -2
- package/dist/codex/scripts/block-no-verify.sh +62 -7
- package/dist/core/config.d.ts +16 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +88 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/lisa.d.ts +31 -0
- package/dist/core/lisa.d.ts.map +1 -1
- package/dist/core/lisa.js +69 -4
- package/dist/core/lisa.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/retire-unmodified.d.ts +66 -0
- package/dist/core/retire-unmodified.d.ts.map +1 -0
- package/dist/core/retire-unmodified.js +244 -0
- package/dist/core/retire-unmodified.js.map +1 -0
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +39 -21
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/opencode/plugin-templates/block-managed-file-edits.sh +7 -1
- package/dist/opencode/plugin-templates/block-no-verify.sh +62 -7
- package/package.json +4 -4
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/auto-update.mjs +69 -1
- package/plugins/lisa/hooks/block-blind-automerge.sh +86 -7
- package/plugins/lisa/hooks/block-managed-file-edits.sh +7 -1
- package/plugins/lisa/hooks/block-no-verify.agy.sh +62 -7
- package/plugins/lisa/hooks/block-no-verify.sh +62 -7
- package/plugins/lisa-agy/hooks/block-blind-automerge.sh +86 -7
- package/plugins/lisa-agy/hooks/block-managed-file-edits.sh +7 -1
- package/plugins/lisa-agy/hooks/block-no-verify.agy.sh +62 -7
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/auto-update.mjs +69 -1
- package/plugins/lisa-copilot/hooks/block-blind-automerge.sh +86 -7
- package/plugins/lisa-copilot/hooks/block-managed-file-edits.sh +7 -1
- package/plugins/lisa-copilot/hooks/block-no-verify.sh +62 -7
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/auto-update.mjs +69 -1
- package/plugins/lisa-cursor/hooks/block-blind-automerge.sh +86 -7
- package/plugins/lisa-cursor/hooks/block-managed-file-edits.sh +7 -1
- package/plugins/lisa-cursor/hooks/block-no-verify.sh +62 -7
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/materialized-artifacts.json +1 -0
- package/plugins/src/base/hooks/auto-update.mjs +69 -1
- package/plugins/src/base/hooks/block-blind-automerge.sh +86 -7
- package/plugins/src/base/hooks/block-managed-file-edits.sh +7 -1
- package/plugins/src/base/hooks/block-no-verify.agy.sh +62 -7
- package/plugins/src/base/hooks/block-no-verify.sh +62 -7
- package/scripts/build-plugins.sh +7 -0
- package/scripts/check-shipped-surface-removals.mjs +22 -2
- package/scripts/lisa-enforcement-fallback.sh +137 -163
- package/scripts/lisa-enforcement-freshness.mjs +177 -0
- package/scripts/two-channel-couplings.json +1 -1
- package/typescript/copy-overwrite/.prettierignore +1 -0
package/README.md
CHANGED
|
@@ -333,6 +333,26 @@ agent configuration changes. This retirement
|
|
|
333
333
|
boundary belongs to the Codex project overlay. The other supported agents do
|
|
334
334
|
not delete this shell-command layout during apply.
|
|
335
335
|
|
|
336
|
+
Fallback diagnostics compare each selected host guard entry file with the
|
|
337
|
+
installed package's template, separately from its historical apply receipt.
|
|
338
|
+
Matching bytes need no apply repair; differing bytes and unknown evidence are
|
|
339
|
+
reported separately. Installed plugin channel versions remain independent
|
|
340
|
+
evidence and do not prove those hooks are live. The optional Node helper ships
|
|
341
|
+
beside the fallback; without it, enforcement still runs and freshness is unknown.
|
|
342
|
+
Diagnostics are offline and lazy: at most eight guard/template pairs (1 MiB per
|
|
343
|
+
file), four 64 KiB manifests/receipts and one 4 MiB plugin registry, with one
|
|
344
|
+
additional byte per read to detect overflow. After the session notice, permitted
|
|
345
|
+
calls invoke no freshness helper. Later refusals re-evaluate their own evidence.
|
|
346
|
+
|
|
347
|
+
| Agent | Fallback diagnostic surface |
|
|
348
|
+
| --- | --- |
|
|
349
|
+
| Claude Code | Repository PreToolUse fallback; independent plugin guards remain registered. |
|
|
350
|
+
| Codex | Tagged project hook dispatches the same delivered fallback after project trust. |
|
|
351
|
+
| Cursor | Native individual guard registrations; the common host fallback is delivered, but its aggregate diagnostic is not registered natively. |
|
|
352
|
+
| OpenCode | Native TypeScript guard adapters; the common host fallback is delivered, but its aggregate diagnostic is not represented by those adapters. |
|
|
353
|
+
| Antigravity | Native adapted guard commands; the common host fallback is delivered, but its aggregate diagnostic is not registered natively. |
|
|
354
|
+
| Copilot | Native individual guard registrations; the common host fallback is delivered, but its aggregate diagnostic is not registered natively. |
|
|
355
|
+
|
|
336
356
|
Remote coding environments use one vendor-neutral AWS bootstrap rather than
|
|
337
357
|
repository-specific or agent-specific IAM users. Run `/lisa:setup-remote-aws`
|
|
338
358
|
to install the common setup script and native Cursor/Copilot adapters; Claude,
|
|
@@ -44,12 +44,15 @@ export const gitEnvironment = () => {
|
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
+
/** Replacement refs must never redirect which objects a proof reads. */
|
|
48
|
+
const NO_REPLACE_OBJECTS = "--no-replace-objects";
|
|
49
|
+
|
|
47
50
|
/** Git errors can contain arbitrary payloads; only authored guidance leaves here. */
|
|
48
|
-
export const gitRead = (args, cwd) => {
|
|
51
|
+
export const gitRead = (args, cwd, input) => {
|
|
49
52
|
const result = spawnSync(
|
|
50
53
|
"git",
|
|
51
54
|
[
|
|
52
|
-
|
|
55
|
+
NO_REPLACE_OBJECTS,
|
|
53
56
|
"-c",
|
|
54
57
|
"diff.external=",
|
|
55
58
|
"-c",
|
|
@@ -60,6 +63,7 @@ export const gitRead = (args, cwd) => {
|
|
|
60
63
|
cwd,
|
|
61
64
|
env: gitEnvironment(),
|
|
62
65
|
encoding: "utf8",
|
|
66
|
+
input,
|
|
63
67
|
timeout: 120000,
|
|
64
68
|
maxBuffer: 64 * 1024 * 1024,
|
|
65
69
|
}
|
|
@@ -151,8 +155,143 @@ export const eventPairs = (event, name, width) => {
|
|
|
151
155
|
);
|
|
152
156
|
};
|
|
153
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Git configuration exactly as the push itself sees it.
|
|
160
|
+
*
|
|
161
|
+
* gitEnvironment pins configuration so history reads cannot be steered, which
|
|
162
|
+
* is right for walking objects and wrong for naming a destination: the push
|
|
163
|
+
* resolved its URL, `pushurl`, `pushInsteadOf` and credentials through user,
|
|
164
|
+
* system and environment configuration, and a destination resolved under any
|
|
165
|
+
* other configuration may be a different repository.
|
|
166
|
+
*/
|
|
167
|
+
const remoteEnvironment = () => {
|
|
168
|
+
const environment = gitEnvironment();
|
|
169
|
+
for (const key of Object.keys(environment))
|
|
170
|
+
if (key.startsWith("GIT_CONFIG")) delete environment[key];
|
|
171
|
+
for (const [key, value] of Object.entries(process.env))
|
|
172
|
+
if (key.startsWith("GIT_CONFIG") && value !== undefined)
|
|
173
|
+
environment[key] = value;
|
|
174
|
+
// Never wait on a person: no terminal prompt and no askpass program, so a
|
|
175
|
+
// destination that needs an unavailable credential fails at once.
|
|
176
|
+
return { ...environment, GIT_TERMINAL_PROMPT: "0", GIT_ASKPASS: "" };
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Run one destination-resolution read under the push's own configuration.
|
|
181
|
+
* @param {string[]} args Git arguments.
|
|
182
|
+
* @param {string} cwd Repository directory.
|
|
183
|
+
* @returns {string | null} Trimmed stdout, or null when Git refused or failed.
|
|
184
|
+
*/
|
|
185
|
+
const remoteRead = (args, cwd) => {
|
|
186
|
+
const result = spawnSync("git", [NO_REPLACE_OBJECTS, ...args], {
|
|
187
|
+
cwd,
|
|
188
|
+
env: remoteEnvironment(),
|
|
189
|
+
encoding: "utf8",
|
|
190
|
+
timeout: 60000,
|
|
191
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
192
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
193
|
+
});
|
|
194
|
+
// probe-direction: fail-closed — every caller treats null as "the
|
|
195
|
+
// destination is unproved", which subtracts nothing from the scan.
|
|
196
|
+
if (result.error || result.signal || result.status !== 0) return null;
|
|
197
|
+
return result.stdout.trim();
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The repository a push is actually going to, from Git's pre-push arguments.
|
|
202
|
+
*
|
|
203
|
+
* Git calls the hook with the remote's name (or the URL, when the push named
|
|
204
|
+
* no remote) and the URL it pushes to, already rewritten by `pushInsteadOf`.
|
|
205
|
+
* That URL is the destination, so it wins when present. A wrapper that
|
|
206
|
+
* forwards only a remote NAME gets that remote's push URL, resolved under the
|
|
207
|
+
* push's own configuration; a remote with several push URLs, or a bare URL
|
|
208
|
+
* with no `$2`, cannot be pinned to one destination and returns null. A value
|
|
209
|
+
* that looks like an option is never used.
|
|
210
|
+
* @param {string[]} remoteArgs Git's pre-push `$1` and `$2`, as forwarded.
|
|
211
|
+
* @param {string} cwd Repository directory.
|
|
212
|
+
* @returns {string | null} The destination, or null when it cannot be proved.
|
|
213
|
+
*/
|
|
214
|
+
export const pushDestination = (remoteArgs, cwd) => {
|
|
215
|
+
const [remote, url] = remoteArgs ?? [];
|
|
216
|
+
const usable = value =>
|
|
217
|
+
typeof value === "string" && value !== "" && !value.startsWith("-");
|
|
218
|
+
if (usable(url)) return url;
|
|
219
|
+
if (!usable(remote)) return null;
|
|
220
|
+
const names = (remoteRead(["remote"], cwd) ?? "").split("\n");
|
|
221
|
+
if (!names.includes(remote)) return null;
|
|
222
|
+
const urls = (
|
|
223
|
+
remoteRead(["remote", "get-url", "--push", "--all", "--", remote], cwd) ??
|
|
224
|
+
""
|
|
225
|
+
)
|
|
226
|
+
.split("\n")
|
|
227
|
+
.filter(Boolean);
|
|
228
|
+
return urls.length === 1 ? urls[0] : null;
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Commit IDs the push destination advertises right now that exist locally.
|
|
233
|
+
*
|
|
234
|
+
* Asked of the destination itself (`git ls-remote`), not read from local
|
|
235
|
+
* tracking refs: a tracking ref can outlive a branch deleted or reset on the
|
|
236
|
+
* remote, and with a separate pushurl it describes a different repository, so
|
|
237
|
+
* either would exclude commits the destination lacks. An advertised ID this
|
|
238
|
+
* repository does not have cannot bound a local walk and is dropped, which
|
|
239
|
+
* only ever widens the scan.
|
|
240
|
+
* @param {string | null} destination The push destination from pushDestination.
|
|
241
|
+
* @param {string} cwd Repository directory.
|
|
242
|
+
* @returns {string[]} IDs to exclude; empty when nothing could be proved.
|
|
243
|
+
*/
|
|
244
|
+
export const advertisedTips = (destination, cwd) => {
|
|
245
|
+
if (destination === null) return [];
|
|
246
|
+
// An `insteadOf` rule can rewrite even a URL Git already rewrote for the
|
|
247
|
+
// push, and then the probe would describe another repository. Trust the
|
|
248
|
+
// advertisement only when ls-remote would contact the destination itself.
|
|
249
|
+
// probe-direction: fail-closed — a URL that cannot be confirmed subtracts
|
|
250
|
+
// nothing.
|
|
251
|
+
if (
|
|
252
|
+
remoteRead(["ls-remote", "--get-url", "--", destination], cwd) !==
|
|
253
|
+
destination
|
|
254
|
+
)
|
|
255
|
+
return [];
|
|
256
|
+
const listed = spawnSync(
|
|
257
|
+
"git",
|
|
258
|
+
[NO_REPLACE_OBJECTS, "ls-remote", "--", destination],
|
|
259
|
+
{
|
|
260
|
+
cwd,
|
|
261
|
+
env: remoteEnvironment(),
|
|
262
|
+
encoding: "utf8",
|
|
263
|
+
timeout: 60000,
|
|
264
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
265
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
// probe-direction: fail-closed — a destination that cannot be asked
|
|
269
|
+
// advertises nothing, so nothing is subtracted and the complete history is
|
|
270
|
+
// scanned.
|
|
271
|
+
if (listed.error || listed.signal || listed.status !== 0) return [];
|
|
272
|
+
const advertised = [
|
|
273
|
+
...new Set(
|
|
274
|
+
listed.stdout
|
|
275
|
+
.split("\n")
|
|
276
|
+
.map(line => line.split("\t")[0])
|
|
277
|
+
.filter(id => /^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(id))
|
|
278
|
+
),
|
|
279
|
+
];
|
|
280
|
+
if (advertised.length === 0) return [];
|
|
281
|
+
const present = gitRead(
|
|
282
|
+
["cat-file", "--batch-check=%(objectname) %(objecttype)"],
|
|
283
|
+
cwd,
|
|
284
|
+
advertised.map(id => `${id}\n`).join("")
|
|
285
|
+
);
|
|
286
|
+
return present
|
|
287
|
+
.split("\n")
|
|
288
|
+
.map(line => line.split(" "))
|
|
289
|
+
.filter(([, type]) => type === "commit" || type === "tag")
|
|
290
|
+
.map(([id]) => id);
|
|
291
|
+
};
|
|
292
|
+
|
|
154
293
|
/** Pairwise subtraction prevents one ref's old tip from hiding another update. */
|
|
155
|
-
export const introducedCommits = (pairs, cwd, width) => {
|
|
294
|
+
export const introducedCommits = (pairs, cwd, width, remoteArgs = []) => {
|
|
156
295
|
const oid = new RegExp(`^[a-f0-9]{${width}}$`, "u");
|
|
157
296
|
for (const pair of pairs) {
|
|
158
297
|
if (!oid.test(pair.before ?? "") || !oid.test(pair.after ?? ""))
|
|
@@ -175,6 +314,16 @@ export const introducedCommits = (pairs, cwd, width) => {
|
|
|
175
314
|
"Legacy Git grafts prevent complete history proof. Use an unmodified complete repository checkout."
|
|
176
315
|
);
|
|
177
316
|
const commits = new Set();
|
|
317
|
+
// A new remote ref (zero `before`) has no old tip to subtract, and scanning
|
|
318
|
+
// everything reachable from it counts the remote's own published history as
|
|
319
|
+
// introduced: every new branch of an old repository then re-litigates its
|
|
320
|
+
// root commit. What a push introduces is what the destination does not
|
|
321
|
+
// already hold, so a new ref subtracts what the push destination advertises.
|
|
322
|
+
// Without a destination, or one that cannot be asked, nothing is subtracted
|
|
323
|
+
// and the complete reachable history is scanned as before.
|
|
324
|
+
const published = updates.some(pair => /^0+$/u.test(pair.before))
|
|
325
|
+
? advertisedTips(pushDestination(remoteArgs, cwd), cwd)
|
|
326
|
+
: [];
|
|
178
327
|
for (const { before, after } of updates) {
|
|
179
328
|
const next = gitRead(["rev-parse", "--verify", `${after}^{commit}`], cwd);
|
|
180
329
|
const previous = /^0+$/u.test(before)
|
|
@@ -190,9 +339,13 @@ export const introducedCommits = (pairs, cwd, width) => {
|
|
|
190
339
|
"Required Git trees or blobs are missing. Fetch complete objects, repair the checkout and retry."
|
|
191
340
|
);
|
|
192
341
|
}
|
|
342
|
+
// Exclusions go through stdin: a remote can hold more refs than one
|
|
343
|
+
// command line carries.
|
|
344
|
+
const exclusions = previous ? [previous] : published;
|
|
193
345
|
const list = gitRead(
|
|
194
|
-
["rev-list",
|
|
195
|
-
cwd
|
|
346
|
+
["rev-list", "--stdin", next],
|
|
347
|
+
cwd,
|
|
348
|
+
exclusions.map(oid => `^${oid}\n`).join("")
|
|
196
349
|
);
|
|
197
350
|
for (const commit of list.split("\n").filter(Boolean)) commits.add(commit);
|
|
198
351
|
}
|
|
@@ -109,7 +109,31 @@ export function validateLock(lock, manifest, updates) {
|
|
|
109
109
|
!item.link,
|
|
110
110
|
"unsupported lock node"
|
|
111
111
|
);
|
|
112
|
-
|
|
112
|
+
// A bundled dependency ships inside its parent's tarball, so npm records
|
|
113
|
+
// no source or integrity of its own: the parent's registry integrity is
|
|
114
|
+
// what covers its bytes. Accept it only nested under a parent this loop
|
|
115
|
+
// also validates, and never when it claims a source of its own.
|
|
116
|
+
if (item.inBundle === true) {
|
|
117
|
+
required(
|
|
118
|
+
item.resolved === undefined && item.integrity === undefined,
|
|
119
|
+
"bundled lock node declares its own source"
|
|
120
|
+
);
|
|
121
|
+
const boundary = name.lastIndexOf("/node_modules/");
|
|
122
|
+
const parent = boundary < 0 ? "" : name.slice(0, boundary);
|
|
123
|
+
required(
|
|
124
|
+
parent.startsWith("node_modules/") &&
|
|
125
|
+
Object.hasOwn(lock.packages, parent),
|
|
126
|
+
"bundled lock node has no registry parent"
|
|
127
|
+
);
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
required(typeof item.resolved === "string", "registry source missing");
|
|
131
|
+
let url;
|
|
132
|
+
try {
|
|
133
|
+
url = new URL(item.resolved);
|
|
134
|
+
} catch {
|
|
135
|
+
required(false, "registry source unparseable");
|
|
136
|
+
}
|
|
113
137
|
required(
|
|
114
138
|
url.protocol === "https:" &&
|
|
115
139
|
url.hostname === "registry.npmjs.org" &&
|