@tangle-network/agent-app 0.45.38 → 0.45.39
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/dist/{agent-session-controls-CCeu5QLS.d.ts → agent-session-controls-BGNNTeJ5.d.ts} +49 -2
- package/dist/assistant/index.d.ts +1 -1
- package/dist/assistant/index.js +2 -2
- package/dist/chat-react/index.d.ts +1 -1
- package/dist/chat-react/index.js +1 -1
- package/dist/{chunk-HNVAASAO.js → chunk-4TZZXCLF.js} +2 -2
- package/dist/chunk-4TZZXCLF.js.map +1 -0
- package/dist/{chunk-3AXSERRK.js → chunk-JRPXENLF.js} +25 -7
- package/dist/chunk-JRPXENLF.js.map +1 -0
- package/dist/chunk-QL7HXXXL.js +609 -0
- package/dist/chunk-QL7HXXXL.js.map +1 -0
- package/dist/peer-floors/check.d.ts +188 -1
- package/dist/peer-floors/check.js +13 -1
- package/dist/peer-floors/cli.d.ts +7 -0
- package/dist/peer-floors/cli.js +40 -5
- package/dist/peer-floors/cli.js.map +1 -1
- package/dist/web-react/index.d.ts +1 -1
- package/dist/web-react/index.js +8 -2
- package/package.json +1 -1
- package/dist/chunk-3AXSERRK.js.map +0 -1
- package/dist/chunk-HNVAASAO.js.map +0 -1
- package/dist/chunk-S24VVLKV.js +0 -130
- package/dist/chunk-S24VVLKV.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/peer-floors/check.ts","../src/peer-floors/dependency-source.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join } from 'node:path'\n\n/**\n * The second half of this gate lives in `./dependency-source` and ships on the\n * SAME subpath and the SAME `agent-app-peer-check` bin, because it answers the\n * question underneath this one: a floor comparison reads a version, and a\n * version is not an identity — a vendored `pnpm pack` of an unmerged branch\n * carries the same `0.45.33` a real release does.\n */\nexport * from './dependency-source'\n\n/**\n * Audit a consumer's installed tree against the peer floors this package\n * declares.\n *\n * A peer floor is not documentation — it encodes a WIRE CONTRACT, and breaking\n * one is invisible to every other gate. `pnpm` only WARNS on an unmet peer when\n * the package is also a direct dependency, and says nothing at all for an unmet\n * OPTIONAL peer, which is how most of the substrate is declared here. So a\n * product can sit below a floor with a clean install, a clean typecheck, a green\n * suite and a successful deploy, and fail only on a live wire call:\n *\n * `@tangle-network/sandbox` 0.15.0 → 0.15.1 changed the sidecar spawn body\n * from `{ command }` to `{ executable, args }`. Below the floor, every\n * `box.exec()` on a live sandbox returns 400 `Unrecognized key: \"command\"`.\n *\n * `@tangle-network/agent-interface` 0.38.0 changed MCP config values from\n * plain strings to tagged public/secret-ref objects. Below the floor, this\n * package fails at MODULE LOAD with \"does not provide an export named\n * defineAgentProfilePublicConfig\" — while `tsc` reports zero errors, because\n * the types resolve and only the runtime export is missing.\n *\n * That second shape is why this exists as its own gate: typecheck cannot see it,\n * and a suite only sees it as dozens of unrelated-looking import failures.\n */\n\n/** Installed, and inside the declared range. */\nexport type PeerFloorVerdict =\n | 'satisfied'\n /** Installed and BELOW the floor — the silent case this module exists for. */\n | 'below-floor'\n /** Not installed and never asked for. A legitimate answer for an optional peer. */\n | 'absent-unused'\n /** Declared by the app, yet no version could be read, so the floor went\n * UNCHECKED. Reported as a failure rather than a pass this did not earn. */\n | 'absent-but-declared'\n\nexport interface PeerFloorRow {\n readonly name: string\n readonly range: string\n readonly installed: string | null\n readonly verdict: PeerFloorVerdict\n}\n\nexport interface PeerFloorReport {\n readonly shellVersion: string\n readonly rows: readonly PeerFloorRow[]\n readonly violations: readonly PeerFloorRow[]\n readonly ok: boolean\n}\n\nexport interface CheckPeerFloorsOptions {\n /** Directory of the app under audit — the one whose `package.json` and\n * installed tree are read. */\n appDir: string\n /** Package whose peer floors are the contract. Defaults to this shell. */\n shell?: string\n /** Only audit peers under this scope. Third-party peers (react, drizzle) are\n * the app's own business, not part of the Tangle wire contract. Pass `''` to\n * audit every peer. */\n scope?: string\n /** Floors to audit against, when the shell is not resolvable from `appDir` —\n * the package auditing ITSELF, which has no copy of itself in its own\n * `node_modules`. Without this a package cannot check that the contract it\n * publishes is one its own dev install satisfies. */\n shellManifest?: { version?: string; peerDependencies?: Record<string, string> }\n /** Directory name to walk for installed packages. Overridable so a test can\n * point at a committed fixture tree — `node_modules` is gitignored\n * everywhere, so a fixture using that name could not be committed, and a\n * calibration proof that is not committed is a proof that stops running. */\n modulesDir?: string\n}\n\n/**\n * Read a package's manifest off disk, walking `modulesDir` up from `fromDir`.\n *\n * Deliberately NOT `require.resolve('<name>/package.json')`: most of these\n * packages omit `./package.json` from their `exports` map, so that throws\n * ERR_PACKAGE_PATH_NOT_EXPORTED — and a try/catch around it reports an INSTALLED\n * package as absent, turning the whole audit into a silent no-op. Walking the\n * tree is exports-map-independent and mirrors Node's own resolution order, so\n * the version reported is the version that would actually load.\n *\n * The walk STOPS at the repository root — a directory containing `.git` — and\n * never climbs past it. Node itself would keep going, but a `node_modules`\n * above a checkout belongs to something else entirely, and letting it answer\n * silently changes the verdict: a stray `/tmp/node_modules` shadowing one\n * package produced a confident FAIL for a repo that was above every floor. A\n * check that reports the wrong tree is worse than no check.\n *\n * Returns null only when no directory for the package exists inside the repo,\n * which is the genuine not-installed case.\n */\nfunction readInstalledManifest(\n name: string,\n fromDir: string,\n modulesDir: string,\n): { version?: string; peerDependencies?: Record<string, string> } | null {\n let dir = fromDir\n for (;;) {\n const manifest = join(dir, modulesDir, name, 'package.json')\n if (existsSync(manifest)) {\n return JSON.parse(readFileSync(manifest, 'utf8')) as {\n version?: string\n peerDependencies?: Record<string, string>\n }\n }\n // Repo boundary: stop here rather than inheriting an unrelated tree.\n if (existsSync(join(dir, '.git'))) return null\n const parent = dirname(dir)\n if (parent === dir) return null\n dir = parent\n }\n}\n\n/**\n * Minimal range satisfaction for the ranges peer floors actually use:\n * `>=x <y`, `^x.y.z`, `~x.y.z`, `x.y.z`, and `*`/`x`.\n *\n * Hand-rolled rather than taking a `semver` dependency, because this package\n * ships zero runtime dependencies and a checker that forces one on every\n * consumer is a worse trade than 40 lines of comparison. Prerelease versions\n * compare by their release part — a floor is about the wire contract, and a\n * prerelease of a satisfying version speaks it.\n */\nfunction parseVersion(version: string): [number, number, number] {\n const [core] = version.split(/[-+]/)\n const parts = (core ?? '').split('.').map((p) => Number.parseInt(p, 10))\n return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0]\n}\n\nfunction compare(a: string, b: string): number {\n const va = parseVersion(a)\n const vb = parseVersion(b)\n for (let i = 0; i < 3; i += 1) {\n if (va[i]! !== vb[i]!) return va[i]! < vb[i]! ? -1 : 1\n }\n return 0\n}\n\nfunction satisfiesComparator(version: string, comparator: string): boolean {\n const trimmed = comparator.trim()\n if (!trimmed || trimmed === '*' || trimmed === 'x') return true\n const match = /^(>=|<=|>|<|=|\\^|~)?\\s*v?(.+)$/.exec(trimmed)\n if (!match) return false\n const [, op = '=', target = ''] = match\n const cmp = compare(version, target)\n switch (op) {\n case '>=': return cmp >= 0\n case '<=': return cmp <= 0\n case '>': return cmp > 0\n case '<': return cmp < 0\n case '=': return cmp === 0\n case '~': {\n // ~1.2.3 allows patch bumps; ~1.2 allows minor.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n return cmp >= 0 && vMajor === major && vMinor === minor\n }\n case '^': {\n // A caret on a 0.x version is MINOR-locked: ^0.36.0 can never resolve to\n // 0.38.0. That is the single most common reason a floor cannot be met by\n // reinstalling, so it is modelled exactly rather than approximated.\n const [major, minor] = parseVersion(target)\n const [vMajor, vMinor] = parseVersion(version)\n if (cmp < 0) return false\n if (major > 0) return vMajor === major\n if (minor > 0) return vMajor === 0 && vMinor === minor\n return vMajor === 0 && vMinor === 0\n }\n default: return false\n }\n}\n\nexport function satisfiesRange(version: string, range: string): boolean {\n // `||` is alternation; whitespace inside an alternative is conjunction.\n return range.split('||').some((alternative) =>\n alternative.trim().split(/\\s+/).filter(Boolean).every((c) => satisfiesComparator(version, c)),\n )\n}\n\n/** Audit one app directory against the shell's declared peer floors. */\nexport function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorReport {\n const {\n appDir,\n shell = '@tangle-network/agent-app',\n scope = '@tangle-network/',\n modulesDir = 'node_modules',\n } = options\n\n const shellManifest = options.shellManifest ?? readInstalledManifest(shell, appDir, modulesDir)\n if (!shellManifest) throw new Error(`${shell} is not installed under ${appDir}`)\n\n const appManifest = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf8')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n optionalDependencies?: Record<string, string>\n }\n const declared = {\n ...appManifest.dependencies,\n ...appManifest.devDependencies,\n ...appManifest.optionalDependencies,\n }\n\n const floors = Object.entries(shellManifest.peerDependencies ?? {})\n .filter(([name]) => name.startsWith(scope))\n\n const rows = floors.map(([name, range]): PeerFloorRow => {\n const installed = readInstalledManifest(name, appDir, modulesDir)?.version ?? null\n if (installed === null) {\n return { name, range, installed, verdict: declared[name] ? 'absent-but-declared' : 'absent-unused' }\n }\n return {\n name,\n range,\n installed,\n verdict: satisfiesRange(installed, range) ? 'satisfied' : 'below-floor',\n }\n })\n\n const violations = rows.filter((row) => row.verdict === 'below-floor' || row.verdict === 'absent-but-declared')\n return {\n shellVersion: shellManifest.version ?? 'unknown',\n rows,\n violations,\n ok: violations.length === 0,\n }\n}\n\n/** The failure message for one violating row. Split out so a caller can raise\n * it from a test and a CLI can print it identically. */\nexport function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell = '@tangle-network/agent-app'): string {\n if (row.verdict === 'below-floor') {\n return `PEER FLOOR VIOLATED: ${shell}@${shellVersion} requires ${row.name}@${row.range}, `\n + `but ${row.installed} is installed. A peer floor encodes a wire contract — bump the `\n + `dependency, do not widen the floor. A caret on a 0.x version is minor-locked `\n + `(^0.36.0 can never resolve to 0.38.0), so reinstalling alone will not fix this: `\n + `change the pin, in EVERY place it appears including pnpm.overrides.`\n }\n return `${row.name} is a declared dependency of this app, but no installed version could be `\n + `read, so its peer floor ${row.range} went UNCHECKED. Failing loudly rather than `\n + `reporting a pass this guard did not earn.`\n}\n\nexport function formatPeerFloorReport(report: PeerFloorReport, shell = '@tangle-network/agent-app'): string {\n const width = Math.max(...report.rows.map((r) => r.name.length), 4)\n const lines = [\n `${shell}@${report.shellVersion} — peer floors`,\n '',\n ...report.rows.map((row) =>\n ` ${row.verdict === 'satisfied' ? 'ok ' : row.verdict.startsWith('absent') ? '-- ' : 'FAIL'} `\n + `${row.name.padEnd(width)} installed ${(row.installed ?? '(none)').padEnd(10)} floor ${row.range}`),\n '',\n report.ok\n ? `all ${report.rows.length} floors satisfied`\n : report.violations.map((row) => describePeerFloorViolation(row, report.shellVersion, shell)).join('\\n\\n'),\n ]\n return lines.join('\\n')\n}\n","import { createHash } from 'node:crypto'\nimport { existsSync, lstatSync, readFileSync, readdirSync, statSync } from 'node:fs'\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'\n\n/**\n * Audit where a repository's dependencies COME FROM.\n *\n * `/peer-floors` already answers \"is the installed version inside the declared\n * range\". This answers the question underneath it — \"is the installed package\n * the one the registry publishes at all\" — because a version number is not an\n * identity. Two artifacts can carry `0.45.33` and ship different APIs, and every\n * gate that reads a version reads the same number for both.\n *\n * THE MEASURED DEFECT. insurance-agent's `pnpm-workspace.yaml` carried\n *\n * overrides:\n * '@tangle-network/agent-app': file:./vendor/agent-app/tangle-network-agent-app-0.45.33.tgz\n *\n * — a 2.6 MB `pnpm pack` of an UNMERGED pull request, committed into the\n * product repo (`insurance-agent` f7d0f51 removed it). It installed cleanly,\n * typechecked green and passed sign-off while the product ran code that existed\n * in no published release. Note where it was NOT: `package.json` still read\n * `\"@tangle-network/agent-app\": \"^0.45.33\"`, a perfectly ordinary registry\n * range. A check that reads only the root manifest's `dependencies` sees\n * nothing. The override lane is the one that shipped, so the override lane —\n * `pnpm-workspace.yaml`, `pnpm.overrides`, `resolutions` — is audited first.\n *\n * The second shape is worse because nothing declares it at all: a worktree was\n * found whose installed `agent-app@0.45.29` had `dist/spend/index.d.ts`\n * replaced with a newer version's content by hand. The manifest, the lockfile\n * and the version on disk all agreed; only the bytes disagreed, and the product\n * typechecked green against an API its declared dependency does not ship. See\n * `checkInstalledIntegrity` below for exactly how much of that class is\n * catchable cheaply and exactly how much is not.\n */\n\n/** How a specifier says a dependency should be obtained. */\nexport type DependencySourceProtocol =\n /** Resolvable from the registry by anyone: `^1.2.3`, `1.2.3`, `npm:x@1`. */\n | 'registry'\n /** `workspace:` — another package in this same repo. Reviewable in one diff. */\n | 'workspace'\n /** `catalog:` — indirection into `pnpm-workspace.yaml`, which is itself audited. */\n | 'catalog'\n /** A local path. Whether it is legitimate depends on WHERE it points. */\n | 'file'\n | 'link'\n | 'portal'\n /** A path or URL ending in a packed tarball. Opaque bytes; never legitimate. */\n | 'tarball'\n /** A git ref or a remote URL that is not the registry. */\n | 'git'\n | 'remote'\n\nconst TARBALL = /\\.(?:tgz|tar\\.gz)$/i\n\n/**\n * Classify one dependency specifier by the SOURCE it names.\n *\n * Pure and exported so a consumer can reuse the vocabulary, and so the rule can\n * be tested without a filesystem. Nothing here decides legitimacy — `file:` on\n * a directory inside the repo is correct and `file:` on a tarball never is, and\n * that distinction needs the disk (`resolveLocalPathSource`).\n */\nexport function classifyDependencySpecifier(specifier: string): DependencySourceProtocol {\n const spec = specifier.trim()\n if (spec.startsWith('workspace:')) return 'workspace'\n if (spec.startsWith('catalog:')) return 'catalog'\n for (const protocol of ['file:', 'link:', 'portal:'] as const) {\n if (spec.startsWith(protocol)) {\n const path = spec.slice(protocol.length)\n if (TARBALL.test(path)) return 'tarball'\n return protocol.slice(0, -1) as 'file' | 'link' | 'portal'\n }\n }\n if (/^(?:git|git\\+ssh|git\\+https?|git\\+file|ssh):/.test(spec)) return 'git'\n if (/^(?:github|gitlab|bitbucket):/.test(spec)) return 'git'\n if (/^https?:\\/\\//.test(spec)) return TARBALL.test(spec.split(/[?#]/)[0] ?? '') ? 'tarball' : 'remote'\n // `owner/repo` and `owner/repo#ref` are npm's GitHub shorthand. A scoped\n // package name (`@scope/name`) also contains a slash, hence the leading-@ guard.\n if (/^[\\w.-]+\\/[\\w.-]+(?:#.+)?$/.test(spec) && !spec.startsWith('@')) return 'git'\n return 'registry'\n}\n\n/** A protocol that resolves from the registry, or from this repo's own sources. */\nfunction isReproducible(protocol: DependencySourceProtocol): boolean {\n return protocol === 'registry' || protocol === 'workspace' || protocol === 'catalog'\n}\n\n/**\n * The legitimate-exception rule, stated once so it is not a path allowlist.\n *\n * agent-app's own `playground/package.json` declares\n * `\"@tangle-network/agent-app\": \"file:..\"` and that is CORRECT: the playground\n * depends on the package it lives inside. The property that makes it correct is\n * not its path — it is that the dependency is satisfied by SOURCE ALREADY IN\n * THIS REPOSITORY, under version control, changing only in a diff a reviewer\n * sees. So the rule is:\n *\n * A `file:` / `link:` / `portal:` specifier is exempt when it resolves to a\n * DIRECTORY inside this repository holding a `package.json` whose `name` is\n * the dependency being declared.\n *\n * Every clause is load-bearing. A DIRECTORY, because a `.tgz` is opaque bytes\n * that no diff shows — a packed tarball is never exempt, wherever it sits.\n * INSIDE THIS REPOSITORY, because `file:../../agent-app` is a path on one\n * machine: it resolves for its author and for nobody else, and a sign-off gate\n * that installs into a clean export dies at install. NAME MATCHES, because a\n * path pointing at some other package's source is a mis-wire, not a\n * self-reference.\n */\nexport type LocalPathSource =\n /** In-repo directory whose package.json names this dependency. Legitimate. */\n | 'in-repo-source'\n /** Points outside the repository — reproducible on one machine only. */\n | 'outside-repo'\n /** Nothing there, or not a directory (a packed tarball lands here too). */\n | 'not-a-directory'\n /** An in-repo directory, but it is a different package. */\n | 'name-mismatch'\n\nexport function resolveLocalPathSource(args: {\n /** Directory of the manifest that made the declaration. */\n fromDir: string\n /** Root of the repository the declaration must stay inside. */\n repoDir: string\n /** The path part of the specifier, protocol already stripped. */\n path: string\n /** The dependency name the path is claimed to satisfy. */\n name: string\n}): LocalPathSource {\n const root = resolve(args.repoDir)\n const target = isAbsolute(args.path) ? resolve(args.path) : resolve(args.fromDir, args.path)\n if (target !== root && !target.startsWith(root + sep)) return 'outside-repo'\n const manifest = join(target, 'package.json')\n if (!existsSync(manifest) || !statSync(target).isDirectory()) return 'not-a-directory'\n let declared: string | undefined\n try {\n declared = (JSON.parse(readFileSync(manifest, 'utf8')) as { name?: string }).name\n } catch {\n return 'not-a-directory'\n }\n return declared === args.name ? 'in-repo-source' : 'name-mismatch'\n}\n\n/** Which of the five scans produced a finding. Kept on the row because the fix\n * differs: a declaration is edited, an installed tree is reinstalled. */\nexport type DependencySourceCheck =\n /** A `dependencies`-family field in some `package.json`. */\n | 'declared'\n /** `pnpm.overrides` / `resolutions` / `pnpm-workspace.yaml` — the lane that shipped. */\n | 'override'\n /** `pnpm-lock.yaml` — what actually resolved, whatever the manifests now say. */\n | 'lockfile'\n /** A packed tarball sitting in the source tree. */\n | 'vendored-tarball'\n /** The installed tree on disk. */\n | 'installed'\n\nexport interface DependencySourceFinding {\n readonly check: DependencySourceCheck\n /** Dependency name, or `null` for a stray tarball that names no dependency. */\n readonly name: string | null\n readonly specifier: string | null\n readonly protocol: DependencySourceProtocol | null\n /** Repo-relative location, with the key or line that carries it. */\n readonly where: string\n /** Why this is a finding, and what to do about it. */\n readonly detail: string\n}\n\n/**\n * What the on-disk integrity pass was able to examine — reported on EVERY run,\n * clean or not, because \"checked nothing\" and \"checked everything and found\n * nothing\" render identically otherwise. This module's own doctrine: an\n * unchecked contract is never a pass it did not earn.\n */\nexport interface InstalledIntegrityCoverage {\n /** The only basis implemented. See `checkInstalledIntegrity`'s limits. */\n readonly basis: 'store-cas'\n /** False for npm, yarn, a pruned CI cache, or a store on another machine.\n * Nothing was verified, and the report says so rather than reading clean. */\n readonly storeLocated: boolean\n readonly packagesExamined: number\n readonly filesExamined: number\n /** Files settled by reading their bytes rather than by a shared inode. */\n readonly filesHashed: number\n}\n\nexport interface DependencySourceReport {\n readonly repoDir: string\n readonly manifestsScanned: number\n readonly lockfileScanned: boolean\n readonly integrity: InstalledIntegrityCoverage\n readonly findings: readonly DependencySourceFinding[]\n readonly ok: boolean\n}\n\nexport interface CheckDependencySourcesOptions {\n /** Repository root to audit. */\n repoDir: string\n /** Scope filter for the on-disk integrity pass. `''` examines every package. */\n scope?: string\n /** Directory name holding the installed tree. Overridable so a committed\n * fixture can use `fixture_modules` — `node_modules` is gitignored\n * everywhere, and a calibration proof that is not committed stops running. */\n modulesDir?: string\n /** Repo-relative path prefixes the source-tree walk skips. The escape hatch\n * for a repo that genuinely carries a tarball as test data — and for this\n * package's own calibration fixtures, whose purpose is to CONTAIN the\n * violation. */\n exclude?: readonly string[]\n}\n\n/** Directories a source-tree walk must never descend into: build output and\n * installed packages are not declarations, and walking them turns a\n * sub-second scan into a minute. */\nconst SKIP_DIRS = new Set([\n 'node_modules', '.git', 'dist', 'build', 'out', 'coverage',\n '.wrangler', '.react-router', '.next', '.turbo', '.cache', 'storybook-static',\n])\n\nfunction walkSourceTree(\n dir: string,\n repoDir: string,\n exclude: readonly string[],\n seen: { manifests: string[]; tarballs: string[] },\n): void {\n let entries: import('node:fs').Dirent[]\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n } catch {\n return\n }\n for (const entry of entries) {\n const full = join(dir, entry.name)\n const rel = relative(repoDir, full).split(sep).join('/')\n if (exclude.some((prefix) => rel === prefix || rel.startsWith(`${prefix}/`))) continue\n if (entry.isDirectory()) {\n if (SKIP_DIRS.has(entry.name)) continue\n walkSourceTree(full, repoDir, exclude, seen)\n } else if (entry.isFile()) {\n if (entry.name === 'package.json') seen.manifests.push(full)\n else if (TARBALL.test(entry.name)) seen.tarballs.push(full)\n }\n }\n}\n\n/* ---------------------------------------------------------------------------\n * A line reader for the two YAML files that matter.\n *\n * Deliberately not a YAML dependency: this package ships zero runtime deps and\n * forcing one on every consumer to read four block mappings is the worse trade\n * — the same call `/peer-floors` made about `semver`. The shapes read here are\n * `pnpm-workspace.yaml`'s `overrides`/`catalog`/`catalogs` and\n * `pnpm-lock.yaml`'s `overrides`/`importers`/`packages`/`snapshots`, all of\n * which pnpm emits as plain two-space block mappings of scalars.\n * ------------------------------------------------------------------------ */\n\ninterface YamlLine {\n readonly indent: number\n readonly key: string\n readonly value: string\n /** Enclosing keys, outermost first, excluding this line's own key. */\n readonly path: readonly string[]\n readonly lineNumber: number\n}\n\nfunction unquote(text: string): string {\n const t = text.trim()\n if ((t.startsWith(\"'\") && t.endsWith(\"'\")) || (t.startsWith('\"') && t.endsWith('\"'))) {\n return t.slice(1, -1)\n }\n return t\n}\n\nfunction readYamlLines(text: string): YamlLine[] {\n const out: YamlLine[] = []\n // Innermost key seen at each indent level, so a `specifier:` line can name\n // the dependency it belongs to.\n const stack: string[] = []\n text.split('\\n').forEach((raw, index) => {\n if (!raw.trim() || raw.trimStart().startsWith('#')) return\n const indent = raw.length - raw.trimStart().length\n const match = /^\\s*(?:'((?:[^']|'')*)'|\"([^\"]*)\"|([^\\s:#][^:]*?))\\s*:(?:\\s+(.*))?$/.exec(raw)\n if (!match) return\n const key = (match[1] ?? match[2] ?? match[3] ?? '').replace(/''/g, \"'\")\n // A trailing ` # comment` is a comment only outside quotes; every value pnpm\n // writes here is unquoted or fully quoted, so splitting on ` #` is exact.\n const rawValue = (match[4] ?? '').split(' #')[0] ?? ''\n const depth = Math.floor(indent / 2)\n stack.length = depth\n const path = [...stack]\n stack[depth] = key\n out.push({ indent, key, value: unquote(rawValue), path, lineNumber: index + 1 })\n })\n return out\n}\n\n/** The top-level section a nested line sits under. */\nfunction sectionOf(line: YamlLine): string | undefined {\n return line.indent === 0 ? line.key : line.path[0]\n}\n\n/* ------------------------------------------------------------------------ */\n\nconst DEP_FIELDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'] as const\n\n/**\n * Judge one declaration and produce a finding, or `null` when it is fine.\n *\n * One function so the manifest lane, the override lane and the lockfile lane\n * cannot drift into three different opinions about the same specifier.\n */\nfunction judge(args: {\n check: DependencySourceCheck\n name: string\n specifier: string\n where: string\n fromDir: string\n repoDir: string\n}): DependencySourceFinding | null {\n const protocol = classifyDependencySpecifier(args.specifier)\n if (isReproducible(protocol)) return null\n\n const base = { check: args.check, name: args.name, specifier: args.specifier, protocol, where: args.where }\n\n if (protocol === 'tarball') {\n return {\n ...base,\n detail: 'resolves a PACKED TARBALL, not a published release. A .tgz is opaque bytes that no '\n + 'diff shows and no registry can reproduce: the version inside it can collide with a real '\n + 'release and ship a different API. Publish the change and pin the published range.',\n }\n }\n if (protocol === 'git' || protocol === 'remote') {\n return {\n ...base,\n detail: `resolves from ${protocol === 'git' ? 'a git ref' : 'a remote URL'} rather than the `\n + 'registry, so what installs depends on what that ref points at today. Publish the change '\n + 'and pin the published range.',\n }\n }\n\n const path = args.specifier.slice(args.specifier.indexOf(':') + 1)\n const source = resolveLocalPathSource({ fromDir: args.fromDir, repoDir: args.repoDir, path, name: args.name })\n if (source === 'in-repo-source') return null\n const why: Record<Exclude<LocalPathSource, 'in-repo-source'>, string> = {\n 'outside-repo': 'points OUTSIDE this repository, so it resolves on one machine and nowhere else — '\n + 'a clean checkout, a CI runner and a sign-off gate that installs into an exported tree all '\n + 'get a different answer or fail at install.',\n 'not-a-directory': 'does not resolve to a package directory in this repository. A local specifier '\n + 'is only legitimate when it points at in-repo SOURCE a reviewer sees in the diff.',\n 'name-mismatch': `resolves to an in-repo directory that declares a DIFFERENT package name, so the `\n + `dependency ${args.name} is being satisfied by something else entirely.`,\n }\n return { ...base, detail: `${why[source]} (${source})` }\n}\n\nfunction scanManifest(file: string, repoDir: string): DependencySourceFinding[] {\n let manifest: Record<string, unknown>\n try {\n manifest = JSON.parse(readFileSync(file, 'utf8')) as Record<string, unknown>\n } catch {\n return []\n }\n const fromDir = dirname(file)\n const where = relative(repoDir, file).split(sep).join('/') || 'package.json'\n const findings: DependencySourceFinding[] = []\n\n for (const field of DEP_FIELDS) {\n const block = manifest[field]\n if (!block || typeof block !== 'object') continue\n for (const [name, specifier] of Object.entries(block as Record<string, unknown>)) {\n if (typeof specifier !== 'string') continue\n const finding = judge({ check: 'declared', name, specifier, where: `${where} → ${field}`, fromDir, repoDir })\n if (finding) findings.push(finding)\n }\n }\n\n // The lane insurance's defect actually used. `resolutions` is yarn/npm's\n // spelling of the same authority; both silently outrank every range above.\n const overrideBlocks: Array<[string, unknown]> = [\n ['pnpm.overrides', (manifest.pnpm as { overrides?: unknown } | undefined)?.overrides],\n ['resolutions', manifest.resolutions],\n ]\n for (const [label, block] of overrideBlocks) {\n if (!block || typeof block !== 'object') continue\n for (const [name, specifier] of Object.entries(block as Record<string, unknown>)) {\n if (typeof specifier !== 'string') continue\n const finding = judge({\n check: 'override',\n // An override key can carry a range suffix (`foo@1 > bar`); the package\n // name is the leading segment.\n name: overrideKeyName(name),\n specifier,\n where: `${where} → ${label}['${name}']`,\n fromDir,\n repoDir,\n })\n if (finding) findings.push(finding)\n }\n }\n return findings\n}\n\n/** `@scope/pkg@^1 > dep` and `pkg@1` both name `pkg` / `@scope/pkg`. */\nfunction overrideKeyName(key: string): string {\n const head = (key.split('>').pop() ?? key).trim()\n const at = head.lastIndexOf('@')\n return at > 0 ? head.slice(0, at) : head\n}\n\nfunction scanWorkspaceYaml(file: string, repoDir: string): DependencySourceFinding[] {\n const findings: DependencySourceFinding[] = []\n const where = relative(repoDir, file).split(sep).join('/')\n for (const line of readYamlLines(readFileSync(file, 'utf8'))) {\n const section = sectionOf(line)\n if (section !== 'overrides' && section !== 'catalog' && section !== 'catalogs') continue\n if (line.indent === 0 || !line.value) continue\n const finding = judge({\n check: 'override',\n name: overrideKeyName(line.key),\n specifier: line.value,\n where: `${where}:${line.lineNumber} → ${[...line.path, line.key].join('.')}`,\n fromDir: dirname(file),\n repoDir,\n })\n if (finding) findings.push(finding)\n }\n return findings\n}\n\n/**\n * The lockfile is the only file that reports what ACTUALLY resolved. A manifest\n * can be cleaned up while `pnpm-lock.yaml` still resolves a tarball, and the\n * install follows the lockfile.\n *\n * Three shapes carry it, all present in the real insurance-agent lockfile:\n * overrides: '@tangle-network/agent-app': file:./vendor/…-0.45.33.tgz\n * importers: specifier: file:vendor/…-0.45.33.tgz\n * packages: '@tangle-network/agent-app@file:vendor/…-0.45.33.tgz':\n */\nfunction scanLockfile(file: string, repoDir: string): DependencySourceFinding[] {\n const findings: DependencySourceFinding[] = []\n const where = relative(repoDir, file).split(sep).join('/')\n const fromDir = dirname(file)\n const seen = new Set<string>()\n const push = (finding: DependencySourceFinding | null): void => {\n if (!finding) return\n const key = `${finding.name}|${finding.specifier}`\n if (seen.has(key)) return\n seen.add(key)\n findings.push(finding)\n }\n\n for (const line of readYamlLines(readFileSync(file, 'utf8'))) {\n const section = sectionOf(line)\n if (section === 'overrides' && line.indent > 0 && line.value) {\n push(judge({\n check: 'lockfile',\n name: overrideKeyName(line.key),\n specifier: line.value,\n where: `${where}:${line.lineNumber} → overrides`,\n fromDir,\n repoDir,\n }))\n continue\n }\n if (section === 'importers' && line.key === 'specifier' && line.value) {\n push(judge({\n check: 'lockfile',\n name: line.path[line.path.length - 1] ?? '(unknown)',\n specifier: line.value,\n where: `${where}:${line.lineNumber} → importers`,\n fromDir,\n repoDir,\n }))\n continue\n }\n if ((section === 'packages' || section === 'snapshots') && line.indent === 2 && !line.value) {\n const parsed = parsePackageKey(line.key)\n if (!parsed) continue\n push(judge({\n check: 'lockfile',\n name: parsed.name,\n specifier: parsed.reference,\n where: `${where}:${line.lineNumber} → ${section}`,\n fromDir,\n repoDir,\n }))\n }\n }\n return findings\n}\n\n/**\n * `'@scope/name@file:vendor/x.tgz'` → name + reference.\n *\n * The peer-suffix is stripped FIRST: a snapshot key looks like\n * `@radix-ui/react-dialog@1.1.23(@types/react@19.2.17)`, and the last `@` in\n * that string sits inside the suffix, not at the version boundary.\n */\nfunction parsePackageKey(key: string): { name: string; reference: string } | null {\n const withoutPeers = key.replace(/\\(.*\\)$/, '')\n const at = withoutPeers.lastIndexOf('@')\n if (at <= 0) return null\n return { name: withoutPeers.slice(0, at), reference: withoutPeers.slice(at + 1) }\n}\n\n/**\n * pnpm's virtual store encodes a dependency's SOURCE in the directory name:\n * a registry package is `@tangle-network+agent-app@0.45.33`, while the\n * vendored one installed as\n * `file+vendor+agent-app+tangle-network-agent-app-0.45.33.tgz`.\n *\n * This is install evidence that survives a tidied manifest and a regenerated\n * lockfile, which is why it is scanned separately rather than trusted to follow\n * from them.\n */\nfunction scanVirtualStore(\n repoDir: string,\n modulesDir: string,\n): DependencySourceFinding[] {\n const store = join(repoDir, modulesDir, '.pnpm')\n if (!existsSync(store)) return []\n const findings: DependencySourceFinding[] = []\n for (const entry of readdirSync(store, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === modulesDir) continue\n const protocolMatch = /^(file|link|portal|git|https?)\\+/.exec(entry.name)\n if (!protocolMatch) continue\n const protocol = protocolMatch[1] as string\n // pnpm encodes `/` as `+` for the whole remainder of a path-protocol key.\n const encoded = entry.name.slice(protocol.length + 1)\n const name = installedPackageName(join(store, entry.name), modulesDir)\n const where = `${modulesDir}/.pnpm/${entry.name}`\n\n if (protocol === 'file' || protocol === 'link' || protocol === 'portal') {\n const path = encoded.split('+').join('/')\n const specifier = `${protocol}:${path}`\n const finding = judge({\n check: 'installed',\n name: name ?? path,\n specifier,\n where,\n // A virtual-store path is written relative to the install root.\n fromDir: repoDir,\n repoDir,\n })\n if (finding) findings.push(finding)\n continue\n }\n findings.push({\n check: 'installed',\n name,\n specifier: encoded.split('+++').join('://').split('+').join('/'),\n protocol: protocol === 'git' ? 'git' : 'remote',\n where,\n detail: 'is INSTALLED from a git ref or remote URL rather than the registry. The manifests may '\n + 'read clean — this is what the tree on disk actually holds. Reinstall from a published range.',\n })\n }\n return findings\n}\n\n/**\n * The package a virtual-store entry belongs to: the one REAL directory under\n * its nested module dir (its dependencies are all symlinks).\n *\n * The nested level takes `modulesDir` too, not a hardcoded `node_modules`.\n * In a real install both levels ARE `node_modules`, so nothing changes there —\n * but a COMMITTED fixture cannot carry a `node_modules` path segment at any\n * depth, because every repo gitignores that name. Hardcoding it here made this\n * module's own calibration tree un-committable, which is the failure the\n * `fixture_modules` convention exists to prevent, reintroduced one level down.\n */\nfunction installedPackageName(entryDir: string, modulesDir: string): string | null {\n const nested = join(entryDir, modulesDir)\n if (!existsSync(nested)) return null\n for (const child of readdirSync(nested, { withFileTypes: true })) {\n if (child.name === '.bin' || child.isSymbolicLink()) continue\n if (!child.isDirectory()) continue\n if (child.name.startsWith('@')) {\n const scopeDir = join(nested, child.name)\n for (const scoped of readdirSync(scopeDir, { withFileTypes: true })) {\n if (scoped.isSymbolicLink() || !scoped.isDirectory()) continue\n if (existsSync(join(scopeDir, scoped.name, 'package.json'))) return `${child.name}/${scoped.name}`\n }\n continue\n }\n if (existsSync(join(nested, child.name, 'package.json'))) return child.name\n }\n return null\n}\n\n/* ---------------------------------------------------------------------------\n * On-disk integrity — and an honest account of its ceiling.\n *\n * WHAT WAS CONSIDERED AND REJECTED. Full verification means comparing the\n * installed bytes against the PUBLISHED tarball. `pnpm-lock.yaml` records that\n * tarball's `integrity` (`sha512-…`) and nothing about its contents, and the\n * tarball is not on disk: pnpm unpacks into a content-addressed store and keeps\n * the per-file digests in an INDEX whose location and format change between\n * pnpm majors — pnpm 10 writes JSON under `store/v10/index/`, pnpm 11 writes one\n * SQLite database (measured: `~/.local/share/pnpm/store/v11/index.db`, 57 MB).\n * Reading it means a SQLite dependency plus a coupling to store internals, in a\n * package that ships zero runtime dependencies; re-fetching the tarball means\n * network access inside a gate that must run offline in seconds. So full\n * verification is NOT affordable and is not attempted.\n *\n * WHAT IS AFFORDABLE. The store is CONTENT-ADDRESSED: a file's bytes live at\n * `<store>/files/<first 2 hex>/<rest>` of their own sha512, a layout that has\n * survived v3 → v10 → v11 while the index format changed twice. So a file's\n * bytes can be asked one question with no dependency and no network — \"has this\n * store ever held these bytes?\" Bytes that came out of a package pnpm installed\n * are in there by construction. Bytes typed in afterwards are not.\n *\n * Two steps, because hashing 30,000 files per run would not be cheap:\n * 1. `nlink > 1` — the file shares an inode, so it IS a store blob. No hash.\n * This settles ~99% of files at the cost of one `lstat`.\n * 2. Everything else is hashed and looked up in the store CAS.\n *\n * THE HARD-LINK COUNT ALONE IS NOT THE SIGNAL, and believing it was is the\n * mistake this design corrects. An earlier cut reported any package holding\n * both linked and unlinked files as tampered. Measured across five real fleet\n * repos it fired once — on legal-agent's `@tangle-network/agent-interface@0.32.0`,\n * whose `dist/environment-provider.js` is `nlink == 1` — and that finding was\n * FALSE: `npm pack @tangle-network/agent-interface@0.32.0` yields the identical\n * 11-byte `export {};`. pnpm simply wrote that copy instead of linking it. A\n * 1-in-5-repos false alarm is a gate people switch off, and the CAS lookup is\n * what tells the two apart: those bytes ARE in the store.\n *\n * MEASURED after adding the lookup: 5 fleet repos, 0 findings, 0 false alarms.\n *\n * WHAT IT CANNOT CATCH, precisely — do not read a clean integrity line as more:\n * 1. A patch whose content came from ANOTHER package or version ALREADY in\n * this store. CAS membership proves \"this store has held these bytes\", not\n * \"these bytes belong to this package at this version\". The measured\n * defect — a `dist/spend/index.d.ts` overwritten with a NEWER version's\n * copy — is caught only when that newer version was never installed on the\n * machine. This is the real ceiling; closing it needs the per-file index.\n * 2. An edit that PRESERVES the inode (`> file`, `cp onto`). The link\n * survives and the STORE copy is corrupted with it, so both agree.\n * 3. A tampered store: everything resolves, everything agrees, all wrong.\n * 4. Anything at all when the store cannot be located — npm, yarn, a store on\n * another machine, a pruned CI cache. That is reported as NOT VERIFIED\n * rather than as a pass, and it is never a finding, because failing every\n * non-pnpm consumer forever is how a gate gets deleted.\n * ------------------------------------------------------------------------ */\n\n/**\n * Every content-addressed `files/` directory this install could have linked\n * from, read out of `node_modules/.modules.yaml` — pure `fs`, no `pnpm store\n * path` subprocess.\n *\n * More than one, because a long-lived machine has several store majors side by\n * side and an existing tree can be linked from an older one: measured on\n * legal-agent, `dist/index.js` resolves in `store/v10/files` while\n * `dist/environment-provider.js` resolves in `store/v10/v11/files`. Checking\n * only the configured one reports a linked file as unknown.\n */\nfunction locateStoreCas(repoDir: string, modulesDir: string): string[] {\n const modulesState = join(repoDir, modulesDir, '.modules.yaml')\n if (!existsSync(modulesState)) return []\n let configured: string | undefined\n try {\n const text = readFileSync(modulesState, 'utf8')\n // pnpm 11 writes JSON under the .yaml name; older versions write YAML.\n configured = (/\"storeDir\"\\s*:\\s*\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(text)?.[1]\n ?? /^storeDir:\\s*(.+)$/m.exec(text)?.[1])?.trim()\n } catch {\n return []\n }\n if (!configured) return []\n const root = unquote(configured.replace(/\\\\\\\\/g, '\\\\'))\n const candidates = new Set<string>([root, dirname(root)])\n for (const base of [root, dirname(root)]) {\n try {\n for (const entry of readdirSync(base, { withFileTypes: true })) {\n if (entry.isDirectory() && /^v\\d+$/.test(entry.name)) candidates.add(join(base, entry.name))\n }\n } catch { /* an unreadable store is simply not a candidate */ }\n }\n return [...candidates].map((dir) => join(dir, 'files')).filter((dir) => existsSync(dir))\n}\n\nfunction collectFiles(dir: string, modulesDir: string, out: string[] = []): string[] {\n let entries: import('node:fs').Dirent[]\n try {\n entries = readdirSync(dir, { withFileTypes: true })\n } catch {\n return out\n }\n for (const entry of entries) {\n // A package's own nested `node_modules` holds pnpm-GENERATED `.bin` shims\n // and symlinks, never store content. Including it made 3 of this repo's 8\n // installed @tangle-network packages look partially replaced.\n if (entry.name === modulesDir) continue\n const full = join(dir, entry.name)\n if (entry.isSymbolicLink()) continue\n if (entry.isDirectory()) collectFiles(full, modulesDir, out)\n else if (entry.isFile()) out.push(full)\n }\n return out\n}\n\n/** Does any reachable store hold these exact bytes? `-exec` is pnpm's suffix\n * for the executable-mode copy of the same content. */\nfunction storeHolds(casDirs: readonly string[], bytes: Buffer): boolean {\n const hex = createHash('sha512').update(bytes).digest('hex')\n const tail = join(hex.slice(0, 2), hex.slice(2))\n return casDirs.some((dir) => existsSync(join(dir, tail)) || existsSync(join(dir, `${tail}-exec`)))\n}\n\n/**\n * Check each installed package under `scope` against the content-addressed\n * store it was installed from. Returns coverage alongside findings, because a\n * pass that verified nothing must not render like a pass that verified\n * everything.\n */\nexport function checkInstalledIntegrity(args: {\n repoDir: string\n modulesDir: string\n scope: string\n}): { coverage: InstalledIntegrityCoverage; findings: DependencySourceFinding[] } {\n const virtualStore = join(args.repoDir, args.modulesDir, '.pnpm')\n const casDirs = locateStoreCas(args.repoDir, args.modulesDir)\n const findings: DependencySourceFinding[] = []\n let packagesExamined = 0\n let filesExamined = 0\n let filesHashed = 0\n\n if (casDirs.length > 0 && existsSync(virtualStore)) {\n for (const entry of readdirSync(virtualStore, { withFileTypes: true })) {\n if (!entry.isDirectory() || entry.name === args.modulesDir) continue\n const entryDir = join(virtualStore, entry.name)\n const name = installedPackageName(entryDir, args.modulesDir)\n if (!name || !name.startsWith(args.scope)) continue\n const packageDir = join(entryDir, args.modulesDir, name)\n if (!existsSync(packageDir)) continue\n\n const files = collectFiles(packageDir, args.modulesDir)\n if (files.length === 0) continue\n packagesExamined += 1\n filesExamined += files.length\n\n const foreign: string[] = []\n for (const file of files) {\n try {\n // A shared inode IS a store blob — settled without reading the file.\n if (lstatSync(file).nlink > 1) continue\n filesHashed += 1\n if (storeHolds(casDirs, readFileSync(file))) continue\n foreign.push(relative(packageDir, file).split(sep).join('/'))\n } catch { /* a file that vanished mid-walk is not evidence */ }\n }\n if (foreign.length === 0) continue\n\n const shown = foreign.slice(0, 5)\n findings.push({\n check: 'installed',\n name,\n specifier: null,\n protocol: null,\n where: `${args.modulesDir}/.pnpm/${entry.name} → ${shown.join(', ')}`\n + `${foreign.length > shown.length ? ` (+${foreign.length - shown.length} more)` : ''}`,\n detail: `holds ${foreign.length} file(s) whose bytes this pnpm store has never contained — the `\n + 'shape of a package HAND-PATCHED after install. The version on disk, the manifest and the '\n + 'lockfile all still agree; only the bytes do not, which is how a product typechecks green '\n + 'against an API its declared dependency does not ship. Delete the tree and reinstall '\n + `(\\`rm -rf ${args.modulesDir} && pnpm install --frozen-lockfile\\`), then publish whatever `\n + 'change made the patch look necessary.',\n })\n }\n }\n\n return {\n coverage: {\n basis: 'store-cas',\n storeLocated: casDirs.length > 0,\n packagesExamined,\n filesExamined,\n filesHashed,\n },\n findings,\n }\n}\n\n/** Audit one repository for dependencies whose source is not the registry. */\nexport function checkDependencySources(options: CheckDependencySourcesOptions): DependencySourceReport {\n const repoDir = resolve(options.repoDir)\n const { scope = '@tangle-network/', modulesDir = 'node_modules', exclude = [] } = options\n\n const seen = { manifests: [] as string[], tarballs: [] as string[] }\n walkSourceTree(repoDir, repoDir, exclude, seen)\n\n const findings: DependencySourceFinding[] = []\n for (const manifest of seen.manifests) findings.push(...scanManifest(manifest, repoDir))\n\n const workspaceYaml = join(repoDir, 'pnpm-workspace.yaml')\n if (existsSync(workspaceYaml)) findings.push(...scanWorkspaceYaml(workspaceYaml, repoDir))\n\n const lockfile = join(repoDir, 'pnpm-lock.yaml')\n const lockfileScanned = existsSync(lockfile)\n if (lockfileScanned) findings.push(...scanLockfile(lockfile, repoDir))\n\n for (const tarball of seen.tarballs) {\n findings.push({\n check: 'vendored-tarball',\n name: null,\n specifier: null,\n protocol: 'tarball',\n where: relative(repoDir, tarball).split(sep).join('/'),\n detail: 'is a PACKED TARBALL committed into the source tree. Even when nothing points at it today, '\n + 'it is a build nobody can reproduce from the registry sitting one `file:` line away from '\n + `shipping. Delete it; if ${basename(tarball)} is genuinely test data, move it under a path `\n + 'passed to `--exclude`.',\n })\n }\n\n findings.push(...scanVirtualStore(repoDir, modulesDir))\n const integrity = checkInstalledIntegrity({ repoDir, modulesDir, scope })\n findings.push(...integrity.findings)\n\n return {\n repoDir,\n manifestsScanned: seen.manifests.length,\n lockfileScanned,\n integrity: integrity.coverage,\n findings,\n ok: findings.length === 0,\n }\n}\n\nconst CHECK_LABEL: Record<DependencySourceCheck, string> = {\n declared: 'DECLARED',\n override: 'OVERRIDE',\n lockfile: 'LOCKFILE',\n 'vendored-tarball': 'TARBALL',\n installed: 'INSTALLED',\n}\n\n/** One finding rendered as the failure a reader has to act on. */\nexport function describeDependencySourceFinding(finding: DependencySourceFinding): string {\n const subject = finding.name\n ? `${finding.name}${finding.specifier ? ` (${finding.specifier})` : ''}`\n : finding.where\n return `DEPENDENCY SOURCE: ${subject} ${finding.detail}\\n at ${finding.where}`\n}\n\nexport function formatDependencySourceReport(report: DependencySourceReport): string {\n const { integrity } = report\n // Printed on EVERY report, clean or not: \"verified nothing\" and \"verified\n // everything and found nothing\" are otherwise the same green line, which is\n // this gate's own failure class turned on itself.\n const integrityLine = integrity.storeLocated\n ? ` integrity (${integrity.basis}): ${integrity.packagesExamined} package(s), `\n + `${integrity.filesExamined} file(s), ${integrity.filesHashed} hashed against the store`\n : ` integrity (${integrity.basis}): NOT VERIFIED — no pnpm content-addressed store is reachable `\n + 'from this tree, so no installed bytes were checked against anything'\n const lines = [\n 'dependency sources',\n '',\n ` scanned ${report.manifestsScanned} manifest(s), `\n + `${report.lockfileScanned ? 'pnpm-lock.yaml' : 'no lockfile'}`,\n integrityLine,\n '',\n ]\n if (report.ok) {\n lines.push(\n integrity.storeLocated && integrity.packagesExamined > 0\n ? ' ok every declared source is the registry, and every installed byte came from the store'\n : ' ok every declared source is the registry — installed bytes UNVERIFIED (see above)',\n )\n } else {\n for (const finding of report.findings) {\n lines.push(` FAIL [${CHECK_LABEL[finding.check]}] ${describeDependencySourceFinding(finding)}`, '')\n }\n }\n return lines.join('\\n')\n}\n"],"mappings":";AAAA,SAAS,cAAAA,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,WAAAC,UAAS,QAAAC,aAAY;;;ACD9B,SAAS,kBAAkB;AAC3B,SAAS,YAAY,WAAW,cAAc,aAAa,gBAAgB;AAC3E,SAAS,UAAU,SAAS,YAAY,MAAM,UAAU,SAAS,WAAW;AAoD5E,IAAM,UAAU;AAUT,SAAS,4BAA4B,WAA6C;AACvF,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,KAAK,WAAW,YAAY,EAAG,QAAO;AAC1C,MAAI,KAAK,WAAW,UAAU,EAAG,QAAO;AACxC,aAAW,YAAY,CAAC,SAAS,SAAS,SAAS,GAAY;AAC7D,QAAI,KAAK,WAAW,QAAQ,GAAG;AAC7B,YAAM,OAAO,KAAK,MAAM,SAAS,MAAM;AACvC,UAAI,QAAQ,KAAK,IAAI,EAAG,QAAO;AAC/B,aAAO,SAAS,MAAM,GAAG,EAAE;AAAA,IAC7B;AAAA,EACF;AACA,MAAI,+CAA+C,KAAK,IAAI,EAAG,QAAO;AACtE,MAAI,gCAAgC,KAAK,IAAI,EAAG,QAAO;AACvD,MAAI,eAAe,KAAK,IAAI,EAAG,QAAO,QAAQ,KAAK,KAAK,MAAM,MAAM,EAAE,CAAC,KAAK,EAAE,IAAI,YAAY;AAG9F,MAAI,6BAA6B,KAAK,IAAI,KAAK,CAAC,KAAK,WAAW,GAAG,EAAG,QAAO;AAC7E,SAAO;AACT;AAGA,SAAS,eAAe,UAA6C;AACnE,SAAO,aAAa,cAAc,aAAa,eAAe,aAAa;AAC7E;AAkCO,SAAS,uBAAuB,MASnB;AAClB,QAAM,OAAO,QAAQ,KAAK,OAAO;AACjC,QAAM,SAAS,WAAW,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,SAAS,KAAK,IAAI;AAC3F,MAAI,WAAW,QAAQ,CAAC,OAAO,WAAW,OAAO,GAAG,EAAG,QAAO;AAC9D,QAAM,WAAW,KAAK,QAAQ,cAAc;AAC5C,MAAI,CAAC,WAAW,QAAQ,KAAK,CAAC,SAAS,MAAM,EAAE,YAAY,EAAG,QAAO;AACrE,MAAI;AACJ,MAAI;AACF,eAAY,KAAK,MAAM,aAAa,UAAU,MAAM,CAAC,EAAwB;AAAA,EAC/E,QAAQ;AACN,WAAO;AAAA,EACT;AACA,SAAO,aAAa,KAAK,OAAO,mBAAmB;AACrD;AA0EA,IAAM,YAAY,oBAAI,IAAI;AAAA,EACxB;AAAA,EAAgB;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAO;AAAA,EAChD;AAAA,EAAa;AAAA,EAAiB;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAC7D,CAAC;AAED,SAAS,eACP,KACA,SACA,SACA,MACM;AACN,MAAI;AACJ,MAAI;AACF,cAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,QAAQ;AACN;AAAA,EACF;AACA,aAAW,SAAS,SAAS;AAC3B,UAAM,OAAO,KAAK,KAAK,MAAM,IAAI;AACjC,UAAM,MAAM,SAAS,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AACvD,QAAI,QAAQ,KAAK,CAAC,WAAW,QAAQ,UAAU,IAAI,WAAW,GAAG,MAAM,GAAG,CAAC,EAAG;AAC9E,QAAI,MAAM,YAAY,GAAG;AACvB,UAAI,UAAU,IAAI,MAAM,IAAI,EAAG;AAC/B,qBAAe,MAAM,SAAS,SAAS,IAAI;AAAA,IAC7C,WAAW,MAAM,OAAO,GAAG;AACzB,UAAI,MAAM,SAAS,eAAgB,MAAK,UAAU,KAAK,IAAI;AAAA,eAClD,QAAQ,KAAK,MAAM,IAAI,EAAG,MAAK,SAAS,KAAK,IAAI;AAAA,IAC5D;AAAA,EACF;AACF;AAsBA,SAAS,QAAQ,MAAsB;AACrC,QAAM,IAAI,KAAK,KAAK;AACpB,MAAK,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,KAAO,EAAE,WAAW,GAAG,KAAK,EAAE,SAAS,GAAG,GAAI;AACpF,WAAO,EAAE,MAAM,GAAG,EAAE;AAAA,EACtB;AACA,SAAO;AACT;AAEA,SAAS,cAAc,MAA0B;AAC/C,QAAM,MAAkB,CAAC;AAGzB,QAAM,QAAkB,CAAC;AACzB,OAAK,MAAM,IAAI,EAAE,QAAQ,CAAC,KAAK,UAAU;AACvC,QAAI,CAAC,IAAI,KAAK,KAAK,IAAI,UAAU,EAAE,WAAW,GAAG,EAAG;AACpD,UAAM,SAAS,IAAI,SAAS,IAAI,UAAU,EAAE;AAC5C,UAAM,QAAQ,sEAAsE,KAAK,GAAG;AAC5F,QAAI,CAAC,MAAO;AACZ,UAAM,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,MAAM,CAAC,KAAK,IAAI,QAAQ,OAAO,GAAG;AAGvE,UAAM,YAAY,MAAM,CAAC,KAAK,IAAI,MAAM,IAAI,EAAE,CAAC,KAAK;AACpD,UAAM,QAAQ,KAAK,MAAM,SAAS,CAAC;AACnC,UAAM,SAAS;AACf,UAAM,OAAO,CAAC,GAAG,KAAK;AACtB,UAAM,KAAK,IAAI;AACf,QAAI,KAAK,EAAE,QAAQ,KAAK,OAAO,QAAQ,QAAQ,GAAG,MAAM,YAAY,QAAQ,EAAE,CAAC;AAAA,EACjF,CAAC;AACD,SAAO;AACT;AAGA,SAAS,UAAU,MAAoC;AACrD,SAAO,KAAK,WAAW,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC;AACnD;AAIA,IAAM,aAAa,CAAC,gBAAgB,mBAAmB,wBAAwB,kBAAkB;AAQjG,SAAS,MAAM,MAOoB;AACjC,QAAM,WAAW,4BAA4B,KAAK,SAAS;AAC3D,MAAI,eAAe,QAAQ,EAAG,QAAO;AAErC,QAAM,OAAO,EAAE,OAAO,KAAK,OAAO,MAAM,KAAK,MAAM,WAAW,KAAK,WAAW,UAAU,OAAO,KAAK,MAAM;AAE1G,MAAI,aAAa,WAAW;AAC1B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ;AAAA,IAGV;AAAA,EACF;AACA,MAAI,aAAa,SAAS,aAAa,UAAU;AAC/C,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,iBAAiB,aAAa,QAAQ,cAAc,cAAc;AAAA,IAG5E;AAAA,EACF;AAEA,QAAM,OAAO,KAAK,UAAU,MAAM,KAAK,UAAU,QAAQ,GAAG,IAAI,CAAC;AACjE,QAAM,SAAS,uBAAuB,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK,SAAS,MAAM,MAAM,KAAK,KAAK,CAAC;AAC7G,MAAI,WAAW,iBAAkB,QAAO;AACxC,QAAM,MAAkE;AAAA,IACtE,gBAAgB;AAAA,IAGhB,mBAAmB;AAAA,IAEnB,iBAAiB,8FACC,KAAK,IAAI;AAAA,EAC7B;AACA,SAAO,EAAE,GAAG,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,KAAK,MAAM,IAAI;AACzD;AAEA,SAAS,aAAa,MAAc,SAA4C;AAC9E,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,MAAM,aAAa,MAAM,MAAM,CAAC;AAAA,EAClD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,UAAU,QAAQ,IAAI;AAC5B,QAAM,QAAQ,SAAS,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG,KAAK;AAC9D,QAAM,WAAsC,CAAC;AAE7C,aAAW,SAAS,YAAY;AAC9B,UAAM,QAAQ,SAAS,KAAK;AAC5B,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU;AACzC,eAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAChF,UAAI,OAAO,cAAc,SAAU;AACnC,YAAM,UAAU,MAAM,EAAE,OAAO,YAAY,MAAM,WAAW,OAAO,GAAG,KAAK,WAAM,KAAK,IAAI,SAAS,QAAQ,CAAC;AAC5G,UAAI,QAAS,UAAS,KAAK,OAAO;AAAA,IACpC;AAAA,EACF;AAIA,QAAM,iBAA2C;AAAA,IAC/C,CAAC,kBAAmB,SAAS,MAA8C,SAAS;AAAA,IACpF,CAAC,eAAe,SAAS,WAAW;AAAA,EACtC;AACA,aAAW,CAAC,OAAO,KAAK,KAAK,gBAAgB;AAC3C,QAAI,CAAC,SAAS,OAAO,UAAU,SAAU;AACzC,eAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAChF,UAAI,OAAO,cAAc,SAAU;AACnC,YAAM,UAAU,MAAM;AAAA,QACpB,OAAO;AAAA;AAAA;AAAA,QAGP,MAAM,gBAAgB,IAAI;AAAA,QAC1B;AAAA,QACA,OAAO,GAAG,KAAK,WAAM,KAAK,KAAK,IAAI;AAAA,QACnC;AAAA,QACA;AAAA,MACF,CAAC;AACD,UAAI,QAAS,UAAS,KAAK,OAAO;AAAA,IACpC;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,QAAQ,IAAI,MAAM,GAAG,EAAE,IAAI,KAAK,KAAK,KAAK;AAChD,QAAM,KAAK,KAAK,YAAY,GAAG;AAC/B,SAAO,KAAK,IAAI,KAAK,MAAM,GAAG,EAAE,IAAI;AACtC;AAEA,SAAS,kBAAkB,MAAc,SAA4C;AACnF,QAAM,WAAsC,CAAC;AAC7C,QAAM,QAAQ,SAAS,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AACzD,aAAW,QAAQ,cAAc,aAAa,MAAM,MAAM,CAAC,GAAG;AAC5D,UAAM,UAAU,UAAU,IAAI;AAC9B,QAAI,YAAY,eAAe,YAAY,aAAa,YAAY,WAAY;AAChF,QAAI,KAAK,WAAW,KAAK,CAAC,KAAK,MAAO;AACtC,UAAM,UAAU,MAAM;AAAA,MACpB,OAAO;AAAA,MACP,MAAM,gBAAgB,KAAK,GAAG;AAAA,MAC9B,WAAW,KAAK;AAAA,MAChB,OAAO,GAAG,KAAK,IAAI,KAAK,UAAU,WAAM,CAAC,GAAG,KAAK,MAAM,KAAK,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,MAC1E,SAAS,QAAQ,IAAI;AAAA,MACrB;AAAA,IACF,CAAC;AACD,QAAI,QAAS,UAAS,KAAK,OAAO;AAAA,EACpC;AACA,SAAO;AACT;AAYA,SAAS,aAAa,MAAc,SAA4C;AAC9E,QAAM,WAAsC,CAAC;AAC7C,QAAM,QAAQ,SAAS,SAAS,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AACzD,QAAM,UAAU,QAAQ,IAAI;AAC5B,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,OAAO,CAAC,YAAkD;AAC9D,QAAI,CAAC,QAAS;AACd,UAAM,MAAM,GAAG,QAAQ,IAAI,IAAI,QAAQ,SAAS;AAChD,QAAI,KAAK,IAAI,GAAG,EAAG;AACnB,SAAK,IAAI,GAAG;AACZ,aAAS,KAAK,OAAO;AAAA,EACvB;AAEA,aAAW,QAAQ,cAAc,aAAa,MAAM,MAAM,CAAC,GAAG;AAC5D,UAAM,UAAU,UAAU,IAAI;AAC9B,QAAI,YAAY,eAAe,KAAK,SAAS,KAAK,KAAK,OAAO;AAC5D,WAAK,MAAM;AAAA,QACT,OAAO;AAAA,QACP,MAAM,gBAAgB,KAAK,GAAG;AAAA,QAC9B,WAAW,KAAK;AAAA,QAChB,OAAO,GAAG,KAAK,IAAI,KAAK,UAAU;AAAA,QAClC;AAAA,QACA;AAAA,MACF,CAAC,CAAC;AACF;AAAA,IACF;AACA,QAAI,YAAY,eAAe,KAAK,QAAQ,eAAe,KAAK,OAAO;AACrE,WAAK,MAAM;AAAA,QACT,OAAO;AAAA,QACP,MAAM,KAAK,KAAK,KAAK,KAAK,SAAS,CAAC,KAAK;AAAA,QACzC,WAAW,KAAK;AAAA,QAChB,OAAO,GAAG,KAAK,IAAI,KAAK,UAAU;AAAA,QAClC;AAAA,QACA;AAAA,MACF,CAAC,CAAC;AACF;AAAA,IACF;AACA,SAAK,YAAY,cAAc,YAAY,gBAAgB,KAAK,WAAW,KAAK,CAAC,KAAK,OAAO;AAC3F,YAAM,SAAS,gBAAgB,KAAK,GAAG;AACvC,UAAI,CAAC,OAAQ;AACb,WAAK,MAAM;AAAA,QACT,OAAO;AAAA,QACP,MAAM,OAAO;AAAA,QACb,WAAW,OAAO;AAAA,QAClB,OAAO,GAAG,KAAK,IAAI,KAAK,UAAU,WAAM,OAAO;AAAA,QAC/C;AAAA,QACA;AAAA,MACF,CAAC,CAAC;AAAA,IACJ;AAAA,EACF;AACA,SAAO;AACT;AASA,SAAS,gBAAgB,KAAyD;AAChF,QAAM,eAAe,IAAI,QAAQ,WAAW,EAAE;AAC9C,QAAM,KAAK,aAAa,YAAY,GAAG;AACvC,MAAI,MAAM,EAAG,QAAO;AACpB,SAAO,EAAE,MAAM,aAAa,MAAM,GAAG,EAAE,GAAG,WAAW,aAAa,MAAM,KAAK,CAAC,EAAE;AAClF;AAYA,SAAS,iBACP,SACA,YAC2B;AAC3B,QAAM,QAAQ,KAAK,SAAS,YAAY,OAAO;AAC/C,MAAI,CAAC,WAAW,KAAK,EAAG,QAAO,CAAC;AAChC,QAAM,WAAsC,CAAC;AAC7C,aAAW,SAAS,YAAY,OAAO,EAAE,eAAe,KAAK,CAAC,GAAG;AAC/D,QAAI,CAAC,MAAM,YAAY,KAAK,MAAM,SAAS,WAAY;AACvD,UAAM,gBAAgB,mCAAmC,KAAK,MAAM,IAAI;AACxE,QAAI,CAAC,cAAe;AACpB,UAAM,WAAW,cAAc,CAAC;AAEhC,UAAM,UAAU,MAAM,KAAK,MAAM,SAAS,SAAS,CAAC;AACpD,UAAM,OAAO,qBAAqB,KAAK,OAAO,MAAM,IAAI,GAAG,UAAU;AACrE,UAAM,QAAQ,GAAG,UAAU,UAAU,MAAM,IAAI;AAE/C,QAAI,aAAa,UAAU,aAAa,UAAU,aAAa,UAAU;AACvE,YAAM,OAAO,QAAQ,MAAM,GAAG,EAAE,KAAK,GAAG;AACxC,YAAM,YAAY,GAAG,QAAQ,IAAI,IAAI;AACrC,YAAM,UAAU,MAAM;AAAA,QACpB,OAAO;AAAA,QACP,MAAM,QAAQ;AAAA,QACd;AAAA,QACA;AAAA;AAAA,QAEA,SAAS;AAAA,QACT;AAAA,MACF,CAAC;AACD,UAAI,QAAS,UAAS,KAAK,OAAO;AAClC;AAAA,IACF;AACA,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP;AAAA,MACA,WAAW,QAAQ,MAAM,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAAA,MAC/D,UAAU,aAAa,QAAQ,QAAQ;AAAA,MACvC;AAAA,MACA,QAAQ;AAAA,IAEV,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAaA,SAAS,qBAAqB,UAAkB,YAAmC;AACjF,QAAM,SAAS,KAAK,UAAU,UAAU;AACxC,MAAI,CAAC,WAAW,MAAM,EAAG,QAAO;AAChC,aAAW,SAAS,YAAY,QAAQ,EAAE,eAAe,KAAK,CAAC,GAAG;AAChE,QAAI,MAAM,SAAS,UAAU,MAAM,eAAe,EAAG;AACrD,QAAI,CAAC,MAAM,YAAY,EAAG;AAC1B,QAAI,MAAM,KAAK,WAAW,GAAG,GAAG;AAC9B,YAAM,WAAW,KAAK,QAAQ,MAAM,IAAI;AACxC,iBAAW,UAAU,YAAY,UAAU,EAAE,eAAe,KAAK,CAAC,GAAG;AACnE,YAAI,OAAO,eAAe,KAAK,CAAC,OAAO,YAAY,EAAG;AACtD,YAAI,WAAW,KAAK,UAAU,OAAO,MAAM,cAAc,CAAC,EAAG,QAAO,GAAG,MAAM,IAAI,IAAI,OAAO,IAAI;AAAA,MAClG;AACA;AAAA,IACF;AACA,QAAI,WAAW,KAAK,QAAQ,MAAM,MAAM,cAAc,CAAC,EAAG,QAAO,MAAM;AAAA,EACzE;AACA,SAAO;AACT;AAoEA,SAAS,eAAe,SAAiB,YAA8B;AACrE,QAAM,eAAe,KAAK,SAAS,YAAY,eAAe;AAC9D,MAAI,CAAC,WAAW,YAAY,EAAG,QAAO,CAAC;AACvC,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,aAAa,cAAc,MAAM;AAE9C,kBAAc,uCAAuC,KAAK,IAAI,IAAI,CAAC,KAC9D,sBAAsB,KAAK,IAAI,IAAI,CAAC,IAAI,KAAK;AAAA,EACpD,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,MAAI,CAAC,WAAY,QAAO,CAAC;AACzB,QAAM,OAAO,QAAQ,WAAW,QAAQ,SAAS,IAAI,CAAC;AACtD,QAAM,aAAa,oBAAI,IAAY,CAAC,MAAM,QAAQ,IAAI,CAAC,CAAC;AACxD,aAAW,QAAQ,CAAC,MAAM,QAAQ,IAAI,CAAC,GAAG;AACxC,QAAI;AACF,iBAAW,SAAS,YAAY,MAAM,EAAE,eAAe,KAAK,CAAC,GAAG;AAC9D,YAAI,MAAM,YAAY,KAAK,SAAS,KAAK,MAAM,IAAI,EAAG,YAAW,IAAI,KAAK,MAAM,MAAM,IAAI,CAAC;AAAA,MAC7F;AAAA,IACF,QAAQ;AAAA,IAAsD;AAAA,EAChE;AACA,SAAO,CAAC,GAAG,UAAU,EAAE,IAAI,CAAC,QAAQ,KAAK,KAAK,OAAO,CAAC,EAAE,OAAO,CAAC,QAAQ,WAAW,GAAG,CAAC;AACzF;AAEA,SAAS,aAAa,KAAa,YAAoB,MAAgB,CAAC,GAAa;AACnF,MAAI;AACJ,MAAI;AACF,cAAU,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AACA,aAAW,SAAS,SAAS;AAI3B,QAAI,MAAM,SAAS,WAAY;AAC/B,UAAM,OAAO,KAAK,KAAK,MAAM,IAAI;AACjC,QAAI,MAAM,eAAe,EAAG;AAC5B,QAAI,MAAM,YAAY,EAAG,cAAa,MAAM,YAAY,GAAG;AAAA,aAClD,MAAM,OAAO,EAAG,KAAI,KAAK,IAAI;AAAA,EACxC;AACA,SAAO;AACT;AAIA,SAAS,WAAW,SAA4B,OAAwB;AACtE,QAAM,MAAM,WAAW,QAAQ,EAAE,OAAO,KAAK,EAAE,OAAO,KAAK;AAC3D,QAAM,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC;AAC/C,SAAO,QAAQ,KAAK,CAAC,QAAQ,WAAW,KAAK,KAAK,IAAI,CAAC,KAAK,WAAW,KAAK,KAAK,GAAG,IAAI,OAAO,CAAC,CAAC;AACnG;AAQO,SAAS,wBAAwB,MAI0C;AAChF,QAAM,eAAe,KAAK,KAAK,SAAS,KAAK,YAAY,OAAO;AAChE,QAAM,UAAU,eAAe,KAAK,SAAS,KAAK,UAAU;AAC5D,QAAM,WAAsC,CAAC;AAC7C,MAAI,mBAAmB;AACvB,MAAI,gBAAgB;AACpB,MAAI,cAAc;AAElB,MAAI,QAAQ,SAAS,KAAK,WAAW,YAAY,GAAG;AAClD,eAAW,SAAS,YAAY,cAAc,EAAE,eAAe,KAAK,CAAC,GAAG;AACtE,UAAI,CAAC,MAAM,YAAY,KAAK,MAAM,SAAS,KAAK,WAAY;AAC5D,YAAM,WAAW,KAAK,cAAc,MAAM,IAAI;AAC9C,YAAM,OAAO,qBAAqB,UAAU,KAAK,UAAU;AAC3D,UAAI,CAAC,QAAQ,CAAC,KAAK,WAAW,KAAK,KAAK,EAAG;AAC3C,YAAM,aAAa,KAAK,UAAU,KAAK,YAAY,IAAI;AACvD,UAAI,CAAC,WAAW,UAAU,EAAG;AAE7B,YAAM,QAAQ,aAAa,YAAY,KAAK,UAAU;AACtD,UAAI,MAAM,WAAW,EAAG;AACxB,0BAAoB;AACpB,uBAAiB,MAAM;AAEvB,YAAM,UAAoB,CAAC;AAC3B,iBAAW,QAAQ,OAAO;AACxB,YAAI;AAEF,cAAI,UAAU,IAAI,EAAE,QAAQ,EAAG;AAC/B,yBAAe;AACf,cAAI,WAAW,SAAS,aAAa,IAAI,CAAC,EAAG;AAC7C,kBAAQ,KAAK,SAAS,YAAY,IAAI,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;AAAA,QAC9D,QAAQ;AAAA,QAAsD;AAAA,MAChE;AACA,UAAI,QAAQ,WAAW,EAAG;AAE1B,YAAM,QAAQ,QAAQ,MAAM,GAAG,CAAC;AAChC,eAAS,KAAK;AAAA,QACZ,OAAO;AAAA,QACP;AAAA,QACA,WAAW;AAAA,QACX,UAAU;AAAA,QACV,OAAO,GAAG,KAAK,UAAU,UAAU,MAAM,IAAI,WAAM,MAAM,KAAK,IAAI,CAAC,GAC5D,QAAQ,SAAS,MAAM,SAAS,MAAM,QAAQ,SAAS,MAAM,MAAM,WAAW,EAAE;AAAA,QACvF,QAAQ,SAAS,QAAQ,MAAM,uVAId,KAAK,UAAU;AAAA,MAElC,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU;AAAA,MACR,OAAO;AAAA,MACP,cAAc,QAAQ,SAAS;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AACF;AAGO,SAAS,uBAAuB,SAAgE;AACrG,QAAM,UAAU,QAAQ,QAAQ,OAAO;AACvC,QAAM,EAAE,QAAQ,oBAAoB,aAAa,gBAAgB,UAAU,CAAC,EAAE,IAAI;AAElF,QAAM,OAAO,EAAE,WAAW,CAAC,GAAe,UAAU,CAAC,EAAc;AACnE,iBAAe,SAAS,SAAS,SAAS,IAAI;AAE9C,QAAM,WAAsC,CAAC;AAC7C,aAAW,YAAY,KAAK,UAAW,UAAS,KAAK,GAAG,aAAa,UAAU,OAAO,CAAC;AAEvF,QAAM,gBAAgB,KAAK,SAAS,qBAAqB;AACzD,MAAI,WAAW,aAAa,EAAG,UAAS,KAAK,GAAG,kBAAkB,eAAe,OAAO,CAAC;AAEzF,QAAM,WAAW,KAAK,SAAS,gBAAgB;AAC/C,QAAM,kBAAkB,WAAW,QAAQ;AAC3C,MAAI,gBAAiB,UAAS,KAAK,GAAG,aAAa,UAAU,OAAO,CAAC;AAErE,aAAW,WAAW,KAAK,UAAU;AACnC,aAAS,KAAK;AAAA,MACZ,OAAO;AAAA,MACP,MAAM;AAAA,MACN,WAAW;AAAA,MACX,UAAU;AAAA,MACV,OAAO,SAAS,SAAS,OAAO,EAAE,MAAM,GAAG,EAAE,KAAK,GAAG;AAAA,MACrD,QAAQ,+MAEuB,SAAS,OAAO,CAAC;AAAA,IAElD,CAAC;AAAA,EACH;AAEA,WAAS,KAAK,GAAG,iBAAiB,SAAS,UAAU,CAAC;AACtD,QAAM,YAAY,wBAAwB,EAAE,SAAS,YAAY,MAAM,CAAC;AACxE,WAAS,KAAK,GAAG,UAAU,QAAQ;AAEnC,SAAO;AAAA,IACL;AAAA,IACA,kBAAkB,KAAK,UAAU;AAAA,IACjC;AAAA,IACA,WAAW,UAAU;AAAA,IACrB;AAAA,IACA,IAAI,SAAS,WAAW;AAAA,EAC1B;AACF;AAEA,IAAM,cAAqD;AAAA,EACzD,UAAU;AAAA,EACV,UAAU;AAAA,EACV,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,WAAW;AACb;AAGO,SAAS,gCAAgC,SAA0C;AACxF,QAAM,UAAU,QAAQ,OACpB,GAAG,QAAQ,IAAI,GAAG,QAAQ,YAAY,KAAK,QAAQ,SAAS,MAAM,EAAE,KACpE,QAAQ;AACZ,SAAO,sBAAsB,OAAO,IAAI,QAAQ,MAAM;AAAA,SAAY,QAAQ,KAAK;AACjF;AAEO,SAAS,6BAA6B,QAAwC;AACnF,QAAM,EAAE,UAAU,IAAI;AAItB,QAAM,gBAAgB,UAAU,eAC5B,gBAAgB,UAAU,KAAK,MAAM,UAAU,gBAAgB,gBAC1D,UAAU,aAAa,aAAa,UAAU,WAAW,8BAC9D,gBAAgB,UAAU,KAAK;AAEnC,QAAM,QAAQ;AAAA,IACZ;AAAA,IACA;AAAA,IACA,aAAa,OAAO,gBAAgB,iBAC/B,OAAO,kBAAkB,mBAAmB,aAAa;AAAA,IAC9D;AAAA,IACA;AAAA,EACF;AACA,MAAI,OAAO,IAAI;AACb,UAAM;AAAA,MACJ,UAAU,gBAAgB,UAAU,mBAAmB,IACnD,8FACA;AAAA,IACN;AAAA,EACF,OAAO;AACL,eAAW,WAAW,OAAO,UAAU;AACrC,YAAM,KAAK,WAAW,YAAY,QAAQ,KAAK,CAAC,KAAK,gCAAgC,OAAO,CAAC,IAAI,EAAE;AAAA,IACrG;AAAA,EACF;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;;;ADxwBA,SAAS,sBACP,MACA,SACA,YACwE;AACxE,MAAI,MAAM;AACV,aAAS;AACP,UAAM,WAAWC,MAAK,KAAK,YAAY,MAAM,cAAc;AAC3D,QAAIC,YAAW,QAAQ,GAAG;AACxB,aAAO,KAAK,MAAMC,cAAa,UAAU,MAAM,CAAC;AAAA,IAIlD;AAEA,QAAID,YAAWD,MAAK,KAAK,MAAM,CAAC,EAAG,QAAO;AAC1C,UAAM,SAASG,SAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAYA,SAAS,aAAa,SAA2C;AAC/D,QAAM,CAAC,IAAI,IAAI,QAAQ,MAAM,MAAM;AACnC,QAAM,SAAS,QAAQ,IAAI,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM,OAAO,SAAS,GAAG,EAAE,CAAC;AACvE,SAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AACrD;AAEA,SAAS,QAAQ,GAAW,GAAmB;AAC7C,QAAM,KAAK,aAAa,CAAC;AACzB,QAAM,KAAK,aAAa,CAAC;AACzB,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG;AAC7B,QAAI,GAAG,CAAC,MAAO,GAAG,CAAC,EAAI,QAAO,GAAG,CAAC,IAAK,GAAG,CAAC,IAAK,KAAK;AAAA,EACvD;AACA,SAAO;AACT;AAEA,SAAS,oBAAoB,SAAiB,YAA6B;AACzE,QAAM,UAAU,WAAW,KAAK;AAChC,MAAI,CAAC,WAAW,YAAY,OAAO,YAAY,IAAK,QAAO;AAC3D,QAAM,QAAQ,iCAAiC,KAAK,OAAO;AAC3D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,CAAC,EAAE,KAAK,KAAK,SAAS,EAAE,IAAI;AAClC,QAAM,MAAM,QAAQ,SAAS,MAAM;AACnC,UAAQ,IAAI;AAAA,IACV,KAAK;AAAM,aAAO,OAAO;AAAA,IACzB,KAAK;AAAM,aAAO,OAAO;AAAA,IACzB,KAAK;AAAK,aAAO,MAAM;AAAA,IACvB,KAAK;AAAK,aAAO,MAAM;AAAA,IACvB,KAAK;AAAK,aAAO,QAAQ;AAAA,IACzB,KAAK,KAAK;AAER,YAAM,CAAC,OAAO,KAAK,IAAI,aAAa,MAAM;AAC1C,YAAM,CAAC,QAAQ,MAAM,IAAI,aAAa,OAAO;AAC7C,aAAO,OAAO,KAAK,WAAW,SAAS,WAAW;AAAA,IACpD;AAAA,IACA,KAAK,KAAK;AAIR,YAAM,CAAC,OAAO,KAAK,IAAI,aAAa,MAAM;AAC1C,YAAM,CAAC,QAAQ,MAAM,IAAI,aAAa,OAAO;AAC7C,UAAI,MAAM,EAAG,QAAO;AACpB,UAAI,QAAQ,EAAG,QAAO,WAAW;AACjC,UAAI,QAAQ,EAAG,QAAO,WAAW,KAAK,WAAW;AACjD,aAAO,WAAW,KAAK,WAAW;AAAA,IACpC;AAAA,IACA;AAAS,aAAO;AAAA,EAClB;AACF;AAEO,SAAS,eAAe,SAAiB,OAAwB;AAEtE,SAAO,MAAM,MAAM,IAAI,EAAE;AAAA,IAAK,CAAC,gBAC7B,YAAY,KAAK,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO,EAAE,MAAM,CAAC,MAAM,oBAAoB,SAAS,CAAC,CAAC;AAAA,EAC9F;AACF;AAGO,SAAS,gBAAgB,SAAkD;AAChF,QAAM;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,aAAa;AAAA,EACf,IAAI;AAEJ,QAAM,gBAAgB,QAAQ,iBAAiB,sBAAsB,OAAO,QAAQ,UAAU;AAC9F,MAAI,CAAC,cAAe,OAAM,IAAI,MAAM,GAAG,KAAK,2BAA2B,MAAM,EAAE;AAE/E,QAAM,cAAc,KAAK,MAAMD,cAAaF,MAAK,QAAQ,cAAc,GAAG,MAAM,CAAC;AAKjF,QAAM,WAAW;AAAA,IACf,GAAG,YAAY;AAAA,IACf,GAAG,YAAY;AAAA,IACf,GAAG,YAAY;AAAA,EACjB;AAEA,QAAM,SAAS,OAAO,QAAQ,cAAc,oBAAoB,CAAC,CAAC,EAC/D,OAAO,CAAC,CAAC,IAAI,MAAM,KAAK,WAAW,KAAK,CAAC;AAE5C,QAAM,OAAO,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,MAAoB;AACvD,UAAM,YAAY,sBAAsB,MAAM,QAAQ,UAAU,GAAG,WAAW;AAC9E,QAAI,cAAc,MAAM;AACtB,aAAO,EAAE,MAAM,OAAO,WAAW,SAAS,SAAS,IAAI,IAAI,wBAAwB,gBAAgB;AAAA,IACrG;AACA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA,SAAS,eAAe,WAAW,KAAK,IAAI,cAAc;AAAA,IAC5D;AAAA,EACF,CAAC;AAED,QAAM,aAAa,KAAK,OAAO,CAAC,QAAQ,IAAI,YAAY,iBAAiB,IAAI,YAAY,qBAAqB;AAC9G,SAAO;AAAA,IACL,cAAc,cAAc,WAAW;AAAA,IACvC;AAAA,IACA;AAAA,IACA,IAAI,WAAW,WAAW;AAAA,EAC5B;AACF;AAIO,SAAS,2BAA2B,KAAmB,cAAsB,QAAQ,6BAAqC;AAC/H,MAAI,IAAI,YAAY,eAAe;AACjC,WAAO,wBAAwB,KAAK,IAAI,YAAY,aAAa,IAAI,IAAI,IAAI,IAAI,KAAK,SAC3E,IAAI,SAAS;AAAA,EAI1B;AACA,SAAO,GAAG,IAAI,IAAI,oGACa,IAAI,KAAK;AAE1C;AAEO,SAAS,sBAAsB,QAAyB,QAAQ,6BAAqC;AAC1G,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM,GAAG,CAAC;AAClE,QAAM,QAAQ;AAAA,IACZ,GAAG,KAAK,IAAI,OAAO,YAAY;AAAA,IAC/B;AAAA,IACA,GAAG,OAAO,KAAK,IAAI,CAAC,QAClB,KAAK,IAAI,YAAY,cAAc,SAAS,IAAI,QAAQ,WAAW,QAAQ,IAAI,SAAS,MAAM,IACzF,IAAI,KAAK,OAAO,KAAK,CAAC,gBAAgB,IAAI,aAAa,UAAU,OAAO,EAAE,CAAC,UAAU,IAAI,KAAK,EAAE;AAAA,IACvG;AAAA,IACA,OAAO,KACH,OAAO,OAAO,KAAK,MAAM,sBACzB,OAAO,WAAW,IAAI,CAAC,QAAQ,2BAA2B,KAAK,OAAO,cAAc,KAAK,CAAC,EAAE,KAAK,MAAM;AAAA,EAC7G;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;","names":["existsSync","readFileSync","dirname","join","join","existsSync","readFileSync","dirname"]}
|
|
@@ -1,3 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit where a repository's dependencies COME FROM.
|
|
3
|
+
*
|
|
4
|
+
* `/peer-floors` already answers "is the installed version inside the declared
|
|
5
|
+
* range". This answers the question underneath it — "is the installed package
|
|
6
|
+
* the one the registry publishes at all" — because a version number is not an
|
|
7
|
+
* identity. Two artifacts can carry `0.45.33` and ship different APIs, and every
|
|
8
|
+
* gate that reads a version reads the same number for both.
|
|
9
|
+
*
|
|
10
|
+
* THE MEASURED DEFECT. insurance-agent's `pnpm-workspace.yaml` carried
|
|
11
|
+
*
|
|
12
|
+
* overrides:
|
|
13
|
+
* '@tangle-network/agent-app': file:./vendor/agent-app/tangle-network-agent-app-0.45.33.tgz
|
|
14
|
+
*
|
|
15
|
+
* — a 2.6 MB `pnpm pack` of an UNMERGED pull request, committed into the
|
|
16
|
+
* product repo (`insurance-agent` f7d0f51 removed it). It installed cleanly,
|
|
17
|
+
* typechecked green and passed sign-off while the product ran code that existed
|
|
18
|
+
* in no published release. Note where it was NOT: `package.json` still read
|
|
19
|
+
* `"@tangle-network/agent-app": "^0.45.33"`, a perfectly ordinary registry
|
|
20
|
+
* range. A check that reads only the root manifest's `dependencies` sees
|
|
21
|
+
* nothing. The override lane is the one that shipped, so the override lane —
|
|
22
|
+
* `pnpm-workspace.yaml`, `pnpm.overrides`, `resolutions` — is audited first.
|
|
23
|
+
*
|
|
24
|
+
* The second shape is worse because nothing declares it at all: a worktree was
|
|
25
|
+
* found whose installed `agent-app@0.45.29` had `dist/spend/index.d.ts`
|
|
26
|
+
* replaced with a newer version's content by hand. The manifest, the lockfile
|
|
27
|
+
* and the version on disk all agreed; only the bytes disagreed, and the product
|
|
28
|
+
* typechecked green against an API its declared dependency does not ship. See
|
|
29
|
+
* `checkInstalledIntegrity` below for exactly how much of that class is
|
|
30
|
+
* catchable cheaply and exactly how much is not.
|
|
31
|
+
*/
|
|
32
|
+
/** How a specifier says a dependency should be obtained. */
|
|
33
|
+
type DependencySourceProtocol =
|
|
34
|
+
/** Resolvable from the registry by anyone: `^1.2.3`, `1.2.3`, `npm:x@1`. */
|
|
35
|
+
'registry'
|
|
36
|
+
/** `workspace:` — another package in this same repo. Reviewable in one diff. */
|
|
37
|
+
| 'workspace'
|
|
38
|
+
/** `catalog:` — indirection into `pnpm-workspace.yaml`, which is itself audited. */
|
|
39
|
+
| 'catalog'
|
|
40
|
+
/** A local path. Whether it is legitimate depends on WHERE it points. */
|
|
41
|
+
| 'file' | 'link' | 'portal'
|
|
42
|
+
/** A path or URL ending in a packed tarball. Opaque bytes; never legitimate. */
|
|
43
|
+
| 'tarball'
|
|
44
|
+
/** A git ref or a remote URL that is not the registry. */
|
|
45
|
+
| 'git' | 'remote';
|
|
46
|
+
/**
|
|
47
|
+
* Classify one dependency specifier by the SOURCE it names.
|
|
48
|
+
*
|
|
49
|
+
* Pure and exported so a consumer can reuse the vocabulary, and so the rule can
|
|
50
|
+
* be tested without a filesystem. Nothing here decides legitimacy — `file:` on
|
|
51
|
+
* a directory inside the repo is correct and `file:` on a tarball never is, and
|
|
52
|
+
* that distinction needs the disk (`resolveLocalPathSource`).
|
|
53
|
+
*/
|
|
54
|
+
declare function classifyDependencySpecifier(specifier: string): DependencySourceProtocol;
|
|
55
|
+
/**
|
|
56
|
+
* The legitimate-exception rule, stated once so it is not a path allowlist.
|
|
57
|
+
*
|
|
58
|
+
* agent-app's own `playground/package.json` declares
|
|
59
|
+
* `"@tangle-network/agent-app": "file:.."` and that is CORRECT: the playground
|
|
60
|
+
* depends on the package it lives inside. The property that makes it correct is
|
|
61
|
+
* not its path — it is that the dependency is satisfied by SOURCE ALREADY IN
|
|
62
|
+
* THIS REPOSITORY, under version control, changing only in a diff a reviewer
|
|
63
|
+
* sees. So the rule is:
|
|
64
|
+
*
|
|
65
|
+
* A `file:` / `link:` / `portal:` specifier is exempt when it resolves to a
|
|
66
|
+
* DIRECTORY inside this repository holding a `package.json` whose `name` is
|
|
67
|
+
* the dependency being declared.
|
|
68
|
+
*
|
|
69
|
+
* Every clause is load-bearing. A DIRECTORY, because a `.tgz` is opaque bytes
|
|
70
|
+
* that no diff shows — a packed tarball is never exempt, wherever it sits.
|
|
71
|
+
* INSIDE THIS REPOSITORY, because `file:../../agent-app` is a path on one
|
|
72
|
+
* machine: it resolves for its author and for nobody else, and a sign-off gate
|
|
73
|
+
* that installs into a clean export dies at install. NAME MATCHES, because a
|
|
74
|
+
* path pointing at some other package's source is a mis-wire, not a
|
|
75
|
+
* self-reference.
|
|
76
|
+
*/
|
|
77
|
+
type LocalPathSource =
|
|
78
|
+
/** In-repo directory whose package.json names this dependency. Legitimate. */
|
|
79
|
+
'in-repo-source'
|
|
80
|
+
/** Points outside the repository — reproducible on one machine only. */
|
|
81
|
+
| 'outside-repo'
|
|
82
|
+
/** Nothing there, or not a directory (a packed tarball lands here too). */
|
|
83
|
+
| 'not-a-directory'
|
|
84
|
+
/** An in-repo directory, but it is a different package. */
|
|
85
|
+
| 'name-mismatch';
|
|
86
|
+
declare function resolveLocalPathSource(args: {
|
|
87
|
+
/** Directory of the manifest that made the declaration. */
|
|
88
|
+
fromDir: string;
|
|
89
|
+
/** Root of the repository the declaration must stay inside. */
|
|
90
|
+
repoDir: string;
|
|
91
|
+
/** The path part of the specifier, protocol already stripped. */
|
|
92
|
+
path: string;
|
|
93
|
+
/** The dependency name the path is claimed to satisfy. */
|
|
94
|
+
name: string;
|
|
95
|
+
}): LocalPathSource;
|
|
96
|
+
/** Which of the five scans produced a finding. Kept on the row because the fix
|
|
97
|
+
* differs: a declaration is edited, an installed tree is reinstalled. */
|
|
98
|
+
type DependencySourceCheck =
|
|
99
|
+
/** A `dependencies`-family field in some `package.json`. */
|
|
100
|
+
'declared'
|
|
101
|
+
/** `pnpm.overrides` / `resolutions` / `pnpm-workspace.yaml` — the lane that shipped. */
|
|
102
|
+
| 'override'
|
|
103
|
+
/** `pnpm-lock.yaml` — what actually resolved, whatever the manifests now say. */
|
|
104
|
+
| 'lockfile'
|
|
105
|
+
/** A packed tarball sitting in the source tree. */
|
|
106
|
+
| 'vendored-tarball'
|
|
107
|
+
/** The installed tree on disk. */
|
|
108
|
+
| 'installed';
|
|
109
|
+
interface DependencySourceFinding {
|
|
110
|
+
readonly check: DependencySourceCheck;
|
|
111
|
+
/** Dependency name, or `null` for a stray tarball that names no dependency. */
|
|
112
|
+
readonly name: string | null;
|
|
113
|
+
readonly specifier: string | null;
|
|
114
|
+
readonly protocol: DependencySourceProtocol | null;
|
|
115
|
+
/** Repo-relative location, with the key or line that carries it. */
|
|
116
|
+
readonly where: string;
|
|
117
|
+
/** Why this is a finding, and what to do about it. */
|
|
118
|
+
readonly detail: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* What the on-disk integrity pass was able to examine — reported on EVERY run,
|
|
122
|
+
* clean or not, because "checked nothing" and "checked everything and found
|
|
123
|
+
* nothing" render identically otherwise. This module's own doctrine: an
|
|
124
|
+
* unchecked contract is never a pass it did not earn.
|
|
125
|
+
*/
|
|
126
|
+
interface InstalledIntegrityCoverage {
|
|
127
|
+
/** The only basis implemented. See `checkInstalledIntegrity`'s limits. */
|
|
128
|
+
readonly basis: 'store-cas';
|
|
129
|
+
/** False for npm, yarn, a pruned CI cache, or a store on another machine.
|
|
130
|
+
* Nothing was verified, and the report says so rather than reading clean. */
|
|
131
|
+
readonly storeLocated: boolean;
|
|
132
|
+
readonly packagesExamined: number;
|
|
133
|
+
readonly filesExamined: number;
|
|
134
|
+
/** Files settled by reading their bytes rather than by a shared inode. */
|
|
135
|
+
readonly filesHashed: number;
|
|
136
|
+
}
|
|
137
|
+
interface DependencySourceReport {
|
|
138
|
+
readonly repoDir: string;
|
|
139
|
+
readonly manifestsScanned: number;
|
|
140
|
+
readonly lockfileScanned: boolean;
|
|
141
|
+
readonly integrity: InstalledIntegrityCoverage;
|
|
142
|
+
readonly findings: readonly DependencySourceFinding[];
|
|
143
|
+
readonly ok: boolean;
|
|
144
|
+
}
|
|
145
|
+
interface CheckDependencySourcesOptions {
|
|
146
|
+
/** Repository root to audit. */
|
|
147
|
+
repoDir: string;
|
|
148
|
+
/** Scope filter for the on-disk integrity pass. `''` examines every package. */
|
|
149
|
+
scope?: string;
|
|
150
|
+
/** Directory name holding the installed tree. Overridable so a committed
|
|
151
|
+
* fixture can use `fixture_modules` — `node_modules` is gitignored
|
|
152
|
+
* everywhere, and a calibration proof that is not committed stops running. */
|
|
153
|
+
modulesDir?: string;
|
|
154
|
+
/** Repo-relative path prefixes the source-tree walk skips. The escape hatch
|
|
155
|
+
* for a repo that genuinely carries a tarball as test data — and for this
|
|
156
|
+
* package's own calibration fixtures, whose purpose is to CONTAIN the
|
|
157
|
+
* violation. */
|
|
158
|
+
exclude?: readonly string[];
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check each installed package under `scope` against the content-addressed
|
|
162
|
+
* store it was installed from. Returns coverage alongside findings, because a
|
|
163
|
+
* pass that verified nothing must not render like a pass that verified
|
|
164
|
+
* everything.
|
|
165
|
+
*/
|
|
166
|
+
declare function checkInstalledIntegrity(args: {
|
|
167
|
+
repoDir: string;
|
|
168
|
+
modulesDir: string;
|
|
169
|
+
scope: string;
|
|
170
|
+
}): {
|
|
171
|
+
coverage: InstalledIntegrityCoverage;
|
|
172
|
+
findings: DependencySourceFinding[];
|
|
173
|
+
};
|
|
174
|
+
/** Audit one repository for dependencies whose source is not the registry. */
|
|
175
|
+
declare function checkDependencySources(options: CheckDependencySourcesOptions): DependencySourceReport;
|
|
176
|
+
/** One finding rendered as the failure a reader has to act on. */
|
|
177
|
+
declare function describeDependencySourceFinding(finding: DependencySourceFinding): string;
|
|
178
|
+
declare function formatDependencySourceReport(report: DependencySourceReport): string;
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The second half of this gate lives in `./dependency-source` and ships on the
|
|
182
|
+
* SAME subpath and the SAME `agent-app-peer-check` bin, because it answers the
|
|
183
|
+
* question underneath this one: a floor comparison reads a version, and a
|
|
184
|
+
* version is not an identity — a vendored `pnpm pack` of an unmerged branch
|
|
185
|
+
* carries the same `0.45.33` a real release does.
|
|
186
|
+
*/
|
|
187
|
+
|
|
1
188
|
/**
|
|
2
189
|
* Audit a consumer's installed tree against the peer floors this package
|
|
3
190
|
* declares.
|
|
@@ -75,4 +262,4 @@ declare function checkPeerFloors(options: CheckPeerFloorsOptions): PeerFloorRepo
|
|
|
75
262
|
declare function describePeerFloorViolation(row: PeerFloorRow, shellVersion: string, shell?: string): string;
|
|
76
263
|
declare function formatPeerFloorReport(report: PeerFloorReport, shell?: string): string;
|
|
77
264
|
|
|
78
|
-
export { type CheckPeerFloorsOptions, type PeerFloorReport, type PeerFloorRow, type PeerFloorVerdict, checkPeerFloors, describePeerFloorViolation, formatPeerFloorReport, satisfiesRange };
|
|
265
|
+
export { type CheckDependencySourcesOptions, type CheckPeerFloorsOptions, type DependencySourceCheck, type DependencySourceFinding, type DependencySourceProtocol, type DependencySourceReport, type InstalledIntegrityCoverage, type LocalPathSource, type PeerFloorReport, type PeerFloorRow, type PeerFloorVerdict, checkDependencySources, checkInstalledIntegrity, checkPeerFloors, classifyDependencySpecifier, describeDependencySourceFinding, describePeerFloorViolation, formatDependencySourceReport, formatPeerFloorReport, resolveLocalPathSource, satisfiesRange };
|
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
|
+
checkDependencySources,
|
|
3
|
+
checkInstalledIntegrity,
|
|
2
4
|
checkPeerFloors,
|
|
5
|
+
classifyDependencySpecifier,
|
|
6
|
+
describeDependencySourceFinding,
|
|
3
7
|
describePeerFloorViolation,
|
|
8
|
+
formatDependencySourceReport,
|
|
4
9
|
formatPeerFloorReport,
|
|
10
|
+
resolveLocalPathSource,
|
|
5
11
|
satisfiesRange
|
|
6
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-QL7HXXXL.js";
|
|
7
13
|
export {
|
|
14
|
+
checkDependencySources,
|
|
15
|
+
checkInstalledIntegrity,
|
|
8
16
|
checkPeerFloors,
|
|
17
|
+
classifyDependencySpecifier,
|
|
18
|
+
describeDependencySourceFinding,
|
|
9
19
|
describePeerFloorViolation,
|
|
20
|
+
formatDependencySourceReport,
|
|
10
21
|
formatPeerFloorReport,
|
|
22
|
+
resolveLocalPathSource,
|
|
11
23
|
satisfiesRange
|
|
12
24
|
};
|
|
13
25
|
//# sourceMappingURL=check.js.map
|
package/dist/peer-floors/cli.js
CHANGED
|
@@ -3,23 +3,58 @@ import {
|
|
|
3
3
|
invokedAsScript
|
|
4
4
|
} from "../chunk-C3CAYGGQ.js";
|
|
5
5
|
import {
|
|
6
|
+
checkDependencySources,
|
|
6
7
|
checkPeerFloors,
|
|
8
|
+
formatDependencySourceReport,
|
|
7
9
|
formatPeerFloorReport
|
|
8
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-QL7HXXXL.js";
|
|
9
11
|
|
|
10
12
|
// src/peer-floors/cli.ts
|
|
13
|
+
function parsePeerCheckArgs(argv) {
|
|
14
|
+
const exclude = [];
|
|
15
|
+
let appDir;
|
|
16
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === "--exclude") {
|
|
19
|
+
const value = argv[i + 1];
|
|
20
|
+
if (value) exclude.push(value);
|
|
21
|
+
i += 1;
|
|
22
|
+
} else if (arg.startsWith("--exclude=")) {
|
|
23
|
+
exclude.push(arg.slice("--exclude=".length));
|
|
24
|
+
} else if (!arg.startsWith("-") && appDir === void 0) {
|
|
25
|
+
appDir = arg;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { appDir: appDir ?? process.cwd(), exclude };
|
|
29
|
+
}
|
|
11
30
|
function main() {
|
|
12
|
-
const appDir = process.argv
|
|
31
|
+
const { appDir, exclude } = parsePeerCheckArgs(process.argv.slice(2));
|
|
32
|
+
let failed = false;
|
|
33
|
+
try {
|
|
34
|
+
const sources = checkDependencySources({ repoDir: appDir, exclude });
|
|
35
|
+
process.stdout.write(`${formatDependencySourceReport(sources)}
|
|
36
|
+
|
|
37
|
+
`);
|
|
38
|
+
if (!sources.ok) failed = true;
|
|
39
|
+
} catch (err) {
|
|
40
|
+
process.stderr.write(`agent-app-peer-check (dependency sources) failed: ${err instanceof Error ? err.message : String(err)}
|
|
41
|
+
`);
|
|
42
|
+
failed = true;
|
|
43
|
+
}
|
|
13
44
|
try {
|
|
14
45
|
const report = checkPeerFloors({ appDir });
|
|
15
46
|
process.stdout.write(`${formatPeerFloorReport(report)}
|
|
16
47
|
`);
|
|
17
|
-
|
|
48
|
+
if (!report.ok) failed = true;
|
|
18
49
|
} catch (err) {
|
|
19
|
-
process.stderr.write(`agent-app-peer-check failed: ${err instanceof Error ? err.message : String(err)}
|
|
50
|
+
process.stderr.write(`agent-app-peer-check (peer floors) failed: ${err instanceof Error ? err.message : String(err)}
|
|
20
51
|
`);
|
|
21
|
-
|
|
52
|
+
failed = true;
|
|
22
53
|
}
|
|
54
|
+
process.exit(failed ? 1 : 0);
|
|
23
55
|
}
|
|
24
56
|
if (invokedAsScript(import.meta.url, process.argv[1])) main();
|
|
57
|
+
export {
|
|
58
|
+
parsePeerCheckArgs
|
|
59
|
+
};
|
|
25
60
|
//# sourceMappingURL=cli.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/peer-floors/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-peer-check` — fail a consumer's CI when its
|
|
1
|
+
{"version":3,"sources":["../../src/peer-floors/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `agent-app-peer-check` — fail a consumer's CI when its dependencies are wrong\n * in either of the two ways a version number cannot show.\n *\n * Runs in the CONSUMER's repo, over the consumer's own tree, because both\n * questions only mean anything against a real install. Add it next to\n * typecheck:\n *\n * \"scripts\": { \"peer-check\": \"agent-app-peer-check\" }\n *\n * Two gates, one report, one exit code:\n *\n * PEER FLOORS — is the installed version inside the range the shell\n * declares. `pnpm` only WARNS on an unmet peer that is\n * also a direct dependency and says nothing at all for an\n * unmet optional one.\n * DEPENDENCY SOURCE — is the installed package the one the registry\n * publishes at all. A `file:` tarball, a `link:` out of\n * the repo, or a hand-patched `node_modules` all report\n * the same version as the real release and ship different\n * bytes.\n *\n * The source gate runs FIRST and independently: it needs no installed shell, so\n * a repo whose install is broken still gets the answer that explains why.\n *\n * Usage: agent-app-peer-check [repoDir] [--exclude <path>]...\n * `--exclude` takes a repo-relative path prefix the source-tree walk skips —\n * the escape hatch for a repo that genuinely carries a tarball as test data.\n * Exits 1 on any violation, 0 otherwise.\n */\nimport { checkPeerFloors, formatPeerFloorReport } from './check'\nimport { checkDependencySources, formatDependencySourceReport } from './dependency-source'\nimport { invokedAsScript } from '../signoff/invoked-as-script'\n\ninterface CliArgs {\n readonly appDir: string\n readonly exclude: readonly string[]\n}\n\nexport function parsePeerCheckArgs(argv: readonly string[]): CliArgs {\n const exclude: string[] = []\n let appDir: string | undefined\n for (let i = 0; i < argv.length; i += 1) {\n const arg = argv[i] as string\n if (arg === '--exclude') {\n const value = argv[i + 1]\n if (value) exclude.push(value)\n i += 1\n } else if (arg.startsWith('--exclude=')) {\n exclude.push(arg.slice('--exclude='.length))\n } else if (!arg.startsWith('-') && appDir === undefined) {\n appDir = arg\n }\n }\n return { appDir: appDir ?? process.cwd(), exclude }\n}\n\nfunction main(): void {\n const { appDir, exclude } = parsePeerCheckArgs(process.argv.slice(2))\n let failed = false\n\n try {\n const sources = checkDependencySources({ repoDir: appDir, exclude })\n process.stdout.write(`${formatDependencySourceReport(sources)}\\n\\n`)\n if (!sources.ok) failed = true\n } catch (err) {\n process.stderr.write(`agent-app-peer-check (dependency sources) failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n failed = true\n }\n\n try {\n const report = checkPeerFloors({ appDir })\n process.stdout.write(`${formatPeerFloorReport(report)}\\n`)\n if (!report.ok) failed = true\n } catch (err) {\n process.stderr.write(`agent-app-peer-check (peer floors) failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n failed = true\n }\n\n process.exit(failed ? 1 : 0)\n}\n\n/* c8 ignore start — process wiring, exercised by the bin itself */\nif (invokedAsScript(import.meta.url, process.argv[1])) main()\n/* c8 ignore stop */\n"],"mappings":";;;;;;;;;;;;AAwCO,SAAS,mBAAmB,MAAkC;AACnE,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACJ,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,QAAQ,aAAa;AACvB,YAAM,QAAQ,KAAK,IAAI,CAAC;AACxB,UAAI,MAAO,SAAQ,KAAK,KAAK;AAC7B,WAAK;AAAA,IACP,WAAW,IAAI,WAAW,YAAY,GAAG;AACvC,cAAQ,KAAK,IAAI,MAAM,aAAa,MAAM,CAAC;AAAA,IAC7C,WAAW,CAAC,IAAI,WAAW,GAAG,KAAK,WAAW,QAAW;AACvD,eAAS;AAAA,IACX;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,UAAU,QAAQ,IAAI,GAAG,QAAQ;AACpD;AAEA,SAAS,OAAa;AACpB,QAAM,EAAE,QAAQ,QAAQ,IAAI,mBAAmB,QAAQ,KAAK,MAAM,CAAC,CAAC;AACpE,MAAI,SAAS;AAEb,MAAI;AACF,UAAM,UAAU,uBAAuB,EAAE,SAAS,QAAQ,QAAQ,CAAC;AACnE,YAAQ,OAAO,MAAM,GAAG,6BAA6B,OAAO,CAAC;AAAA;AAAA,CAAM;AACnE,QAAI,CAAC,QAAQ,GAAI,UAAS;AAAA,EAC5B,SAAS,KAAK;AACZ,YAAQ,OAAO,MAAM,qDAAqD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AAC9H,aAAS;AAAA,EACX;AAEA,MAAI;AACF,UAAM,SAAS,gBAAgB,EAAE,OAAO,CAAC;AACzC,YAAQ,OAAO,MAAM,GAAG,sBAAsB,MAAM,CAAC;AAAA,CAAI;AACzD,QAAI,CAAC,OAAO,GAAI,UAAS;AAAA,EAC3B,SAAS,KAAK;AACZ,YAAQ,OAAO,MAAM,8CAA8C,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,CAAI;AACvH,aAAS;AAAA,EACX;AAEA,UAAQ,KAAK,SAAS,IAAI,CAAC;AAC7B;AAGA,IAAI,gBAAgB,YAAY,KAAK,QAAQ,KAAK,CAAC,CAAC,EAAG,MAAK;","names":[]}
|
|
@@ -9,7 +9,7 @@ export { InteractionData, InteractionOutcome, InteractionRequest } from '@tangle
|
|
|
9
9
|
import { e as ChatMentionPart, a as ChatAttachmentPart } from '../parts-BqIHMdyu.js';
|
|
10
10
|
export { s as attachmentInputToPart, t as attachmentKindForMime, u as attachmentPartsFromMessageParts, x as isChatAttachmentPart, H as mentionInputToPart, I as mentionPartsFromMessageParts } from '../parts-BqIHMdyu.js';
|
|
11
11
|
import { E as EvidenceEntry, g as ExceptionEntry, b as WorkProductProvenance, P as ProfileBacktestSummary, Q as QualityCheck, W as WorkProductPersistedPart, h as WorkProductStatus } from '../types-CCeYywdS.js';
|
|
12
|
-
export { a as AgentSessionControls, A as AgentSessionControlsProps, C as ComposerMentionProp, D as DEFAULT_EFFORT_LEVELS, b as DEFAULT_MENTION_EMPTY_TEXT, c as DEFAULT_MENTION_LIMIT, E as EFFORT_METER_SEGMENTS, d as EffortLevel, e as EffortMeter, f as EffortPicker, g as EffortPickerProps, I as INDEX_REFRESH_AFTER_MS, M as MentionItem, h as ModelPicker, i as ModelPickerProps, O as OVERLAY_SHADOW, P as POPOVER_SURFACE_ATTR, j as PopoverSurface, k as PopoverSurfaceProps, l as UseFileMentionsOptions, U as UseFileMentionsResult, m as effortMeterFill, r as rankFileMentions, u as useFileMentions,
|
|
12
|
+
export { a as AgentSessionControls, A as AgentSessionControlsProps, C as ComposerMentionProp, D as DEFAULT_EFFORT_LEVELS, b as DEFAULT_MENTION_EMPTY_TEXT, c as DEFAULT_MENTION_LIMIT, E as EFFORT_METER_SEGMENTS, d as EffortLevel, e as EffortMeter, f as EffortPicker, g as EffortPickerProps, I as INDEX_REFRESH_AFTER_MS, M as MentionItem, h as ModelPicker, i as ModelPickerProps, O as OVERLAY_SHADOW, P as POPOVER_SURFACE_ATTR, j as PopoverSurface, k as PopoverSurfaceProps, l as UseFileMentionsOptions, U as UseFileMentionsResult, m as effortLevelLabel, n as effortLevelsFromIds, o as effortMeterFill, r as rankFileMentions, p as reconcileEffortLevels, u as useFileMentions, q as usePending, s as usePopover } from '../agent-session-controls-BGNNTeJ5.js';
|
|
13
13
|
import { a as ChatAttachmentKind, b as ChatAttachmentInput } from '../wire-DOZ-O6hD.js';
|
|
14
14
|
export { C as ChatMentionKind, e as ChatTurnFilePartInput, d as ChatTurnPartInput, c as ChatTurnRequestPayload, D as DISPATCH_MAX_MEDIA_PARTS, i as DISPATCH_MAX_PARTS, j as DISPATCH_REQUEST_MAX_BYTES, k as DISPATCH_STRUCTURAL_RESERVE_BYTES, F as FileMention, P as ProducerErrorEvent, m as ProducerNoticeEvent, n as ProducerPassthroughEvent, o as ProducerPassthroughEventType, p as ProducerReasoningEvent, q as ProducerTextEvent, r as ProducerToolCallEvent, s as ProducerToolResultEvent, t as ProducerUsageEvent, u as ProducerWireEvent, w as base64WireLen, x as buildMentionPromptBlock, y as chatTurnRequestInit, z as fileMentionsToParts, B as mediaTypeForMentionPath, E as mentionKindForPath } from '../wire-DOZ-O6hD.js';
|
|
15
15
|
import { Harness } from '../harness/index.js';
|
package/dist/web-react/index.js
CHANGED
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
withoutRecordGridCreated,
|
|
112
112
|
withoutRecordGridRemoved,
|
|
113
113
|
withoutRecordGridUpdate
|
|
114
|
-
} from "../chunk-
|
|
114
|
+
} from "../chunk-4TZZXCLF.js";
|
|
115
115
|
import "../chunk-FBVLEGEG.js";
|
|
116
116
|
import {
|
|
117
117
|
EvidenceLineageTable,
|
|
@@ -140,11 +140,14 @@ import {
|
|
|
140
140
|
POPOVER_SURFACE_ATTR,
|
|
141
141
|
PopoverSurface,
|
|
142
142
|
ProviderLogo,
|
|
143
|
+
effortLevelLabel,
|
|
144
|
+
effortLevelsFromIds,
|
|
143
145
|
effortMeterFill,
|
|
146
|
+
reconcileEffortLevels,
|
|
144
147
|
useComposerAttachments,
|
|
145
148
|
usePending,
|
|
146
149
|
usePopover
|
|
147
|
-
} from "../chunk-
|
|
150
|
+
} from "../chunk-JRPXENLF.js";
|
|
148
151
|
import {
|
|
149
152
|
tabTerminalConnectionId,
|
|
150
153
|
useSandboxTerminalConnection
|
|
@@ -287,6 +290,8 @@ export {
|
|
|
287
290
|
describeProvenanceSourceStatus,
|
|
288
291
|
dispatchChatStreamLine,
|
|
289
292
|
durableChatCardsFromParts,
|
|
293
|
+
effortLevelLabel,
|
|
294
|
+
effortLevelsFromIds,
|
|
290
295
|
effortMeterFill,
|
|
291
296
|
fieldAcceptsFreeText,
|
|
292
297
|
fieldAnswer,
|
|
@@ -341,6 +346,7 @@ export {
|
|
|
341
346
|
questionInteractionContentSignature,
|
|
342
347
|
rankFileMentions,
|
|
343
348
|
readRecordGridCell,
|
|
349
|
+
reconcileEffortLevels,
|
|
344
350
|
recordGridEditorText,
|
|
345
351
|
recordGridFail,
|
|
346
352
|
recordGridOk,
|
package/package.json
CHANGED