@4da/mcp-server 6.2.3 → 6.2.5

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.
Files changed (123) hide show
  1. package/CHANGELOG.md +520 -0
  2. package/README.md +22 -6
  3. package/dist/db.d.ts +38 -0
  4. package/dist/db.js +78 -23
  5. package/dist/doctor.js +6 -3
  6. package/dist/embeddings.d.ts +1 -1
  7. package/dist/embeddings.js +16 -14
  8. package/dist/index.js +73 -103
  9. package/dist/live/advisory-groups.d.ts +68 -0
  10. package/dist/live/advisory-groups.js +131 -0
  11. package/dist/live/cache.js +11 -3
  12. package/dist/live/cargo-platform.d.ts +6 -0
  13. package/dist/live/cargo-platform.js +8 -2
  14. package/dist/live/changelog.js +38 -6
  15. package/dist/live/dependency-set.d.ts +9 -1
  16. package/dist/live/dependency-set.js +10 -2
  17. package/dist/live/fix-paths.d.ts +289 -16
  18. package/dist/live/fix-paths.js +876 -93
  19. package/dist/live/github-releases.js +3 -0
  20. package/dist/live/held-dependencies.d.ts +93 -0
  21. package/dist/live/held-dependencies.js +212 -0
  22. package/dist/live/held-targets.d.ts +30 -0
  23. package/dist/live/held-targets.js +107 -0
  24. package/dist/live/http-utils.js +13 -3
  25. package/dist/live/index.d.ts +7 -4
  26. package/dist/live/index.js +24 -19
  27. package/dist/live/install-state.js +6 -2
  28. package/dist/live/js-lockfile-readers.d.ts +8 -1
  29. package/dist/live/js-lockfile-readers.js +43 -6
  30. package/dist/live/lockfile-parents.d.ts +15 -0
  31. package/dist/live/lockfile-parents.js +85 -10
  32. package/dist/live/lockfile-parsers-pygo.d.ts +47 -2
  33. package/dist/live/lockfile-parsers-pygo.js +230 -12
  34. package/dist/live/lockfile-parsers-rbphp.d.ts +38 -0
  35. package/dist/live/lockfile-parsers-rbphp.js +123 -0
  36. package/dist/live/lockfile-parsers.d.ts +6 -0
  37. package/dist/live/lockfile-parsers.js +116 -4
  38. package/dist/live/lockfile-types.d.ts +28 -1
  39. package/dist/live/maintenance.d.ts +20 -4
  40. package/dist/live/maintenance.js +31 -2
  41. package/dist/live/malware.d.ts +20 -0
  42. package/dist/live/malware.js +31 -0
  43. package/dist/live/npm-packument.d.ts +4 -1
  44. package/dist/live/npm-packument.js +5 -2
  45. package/dist/live/offered-release.d.ts +53 -0
  46. package/dist/live/offered-release.js +117 -0
  47. package/dist/live/osv-ranges.d.ts +111 -0
  48. package/dist/live/osv-ranges.js +173 -14
  49. package/dist/live/osv-scanner.d.ts +87 -5
  50. package/dist/live/osv-scanner.js +310 -59
  51. package/dist/live/pinned-advisories.d.ts +2 -2
  52. package/dist/live/pinned-advisories.js +3 -3
  53. package/dist/live/pypi-advice.d.ts +36 -0
  54. package/dist/live/pypi-advice.js +158 -0
  55. package/dist/live/range-satisfies.d.ts +4 -2
  56. package/dist/live/range-satisfies.js +7 -5
  57. package/dist/live/rate-limiter.d.ts +7 -0
  58. package/dist/live/rate-limiter.js +22 -1
  59. package/dist/live/refresh-rule.d.ts +36 -0
  60. package/dist/live/refresh-rule.js +49 -0
  61. package/dist/live/release-metadata.d.ts +5 -0
  62. package/dist/live/resolution.d.ts +3 -0
  63. package/dist/live/resolution.js +6 -3
  64. package/dist/live/scan-coverage.d.ts +26 -0
  65. package/dist/live/scan-coverage.js +70 -0
  66. package/dist/live/semver-utils.d.ts +8 -0
  67. package/dist/live/semver-utils.js +26 -3
  68. package/dist/live/severity-scope.d.ts +26 -1
  69. package/dist/live/severity-scope.js +32 -0
  70. package/dist/live/shell-safe.d.ts +19 -0
  71. package/dist/live/shell-safe.js +36 -0
  72. package/dist/live/types.d.ts +134 -8
  73. package/dist/live/version-compare.d.ts +51 -0
  74. package/dist/live/version-compare.js +152 -1
  75. package/dist/live/withdrawn-releases.d.ts +50 -0
  76. package/dist/live/withdrawn-releases.js +125 -0
  77. package/dist/project-manifests.d.ts +7 -0
  78. package/dist/project-manifests.js +45 -5
  79. package/dist/project-scanner.js +6 -4
  80. package/dist/project-tree.d.ts +56 -0
  81. package/dist/project-tree.js +174 -5
  82. package/dist/schema-registry.d.ts +47 -4
  83. package/dist/schema-registry.js +76 -9
  84. package/dist/server-instructions.js +4 -2
  85. package/dist/setup.d.ts +8 -0
  86. package/dist/setup.js +21 -2
  87. package/dist/tool-dispatch.js +3 -3
  88. package/dist/tools/agent-memory.d.ts +5 -0
  89. package/dist/tools/agent-memory.js +9 -0
  90. package/dist/tools/briefing-task-scope.js +5 -2
  91. package/dist/tools/decision-memory.js +2 -0
  92. package/dist/tools/dependency-check-held.d.ts +44 -0
  93. package/dist/tools/dependency-check-held.js +98 -0
  94. package/dist/tools/dependency-check-signals.d.ts +19 -2
  95. package/dist/tools/dependency-check-signals.js +84 -13
  96. package/dist/tools/dependency-check-versions.d.ts +37 -4
  97. package/dist/tools/dependency-check-versions.js +48 -13
  98. package/dist/tools/dependency-check.d.ts +11 -1
  99. package/dist/tools/dependency-check.js +81 -29
  100. package/dist/tools/dependency-health.js +209 -45
  101. package/dist/tools/get-context.d.ts +3 -0
  102. package/dist/tools/get-context.js +4 -0
  103. package/dist/tools/project-scope.d.ts +8 -0
  104. package/dist/tools/project-scope.js +21 -0
  105. package/dist/tools/upgrade-impact-features.d.ts +37 -0
  106. package/dist/tools/upgrade-impact-features.js +176 -0
  107. package/dist/tools/upgrade-impact-literals.js +26 -4
  108. package/dist/tools/upgrade-impact-report.d.ts +5 -1
  109. package/dist/tools/upgrade-impact-report.js +26 -5
  110. package/dist/tools/upgrade-impact.js +10 -3
  111. package/dist/tools/upgrade-planner-fixpaths.d.ts +164 -5
  112. package/dist/tools/upgrade-planner-fixpaths.js +0 -0
  113. package/dist/tools/upgrade-planner.d.ts +70 -7
  114. package/dist/tools/upgrade-planner.js +237 -61
  115. package/dist/tools/vulnerability-scan-concise.d.ts +47 -2
  116. package/dist/tools/vulnerability-scan-concise.js +37 -3
  117. package/dist/tools/vulnerability-scan-format.d.ts +126 -24
  118. package/dist/tools/vulnerability-scan-format.js +193 -26
  119. package/dist/tools/vulnerability-scan.d.ts +224 -63
  120. package/dist/tools/vulnerability-scan.js +50 -15
  121. package/dist/tools/what-should-i-know.d.ts +6 -1
  122. package/dist/tools/what-should-i-know.js +72 -15
  123. package/package.json +2 -2
@@ -26,7 +26,38 @@ import type { LiveCache } from "./cache.js";
26
26
  import type { RateLimiter } from "./rate-limiter.js";
27
27
  import { type AdvisoryRanges, type CleanTarget } from "./osv-ranges.js";
28
28
  import { type LockfileFormat } from "./lockfile-parents.js";
29
+ import { type AdvisoryQuery, type HeldDependency } from "./held-dependencies.js";
29
30
  import type { OsvEcosystem } from "./types.js";
31
+ /** What a registry says about one package's releases, for fix targets and parent advice. */
32
+ export interface PackageReleaseFacts {
33
+ /** Published, installable versions: every release except the `withdrawn` ones. */
34
+ versions: string[];
35
+ /**
36
+ * Releases the registry withdrew, never a fix target (withdrawn-releases.ts, the 4DA app's
37
+ * rule): yanked (crates.io; PyPI: every file), and npm `deprecated` only where a later,
38
+ * non-deprecated stable release exists on the same caret line and `latest` is not deprecated.
39
+ */
40
+ withdrawn: string[];
41
+ /** Per withdrawn release, the registry's words ("4.18.0 is deprecated on npm ("Bad release...")"). */
42
+ withdrawnWhy: Record<string, string>;
43
+ /** The registry's latest release (npm `latest` tag; crates.io the highest non-yanked), or null. */
44
+ latest: string | null;
45
+ /** The package-level deprecation of the newest release (npm), or null. */
46
+ deprecatedLatest: string | null;
47
+ /**
48
+ * npm: releases that carry a `deprecated` message the withdrawal rule does NOT withdraw (a
49
+ * notice on a whole line, such as glob's "Old versions of glob are not supported"), with the
50
+ * message. Still candidates; a tool that offers one says it is deprecated (final release audit
51
+ * of 6.2.5: the plan targeted glob 10.5.0 while dependency_check said review on it).
52
+ */
53
+ lineNotices?: Record<string, string>;
54
+ /**
55
+ * npm: per release, the dependencies it holds (exact pins and narrow ranges, held-dependencies.ts):
56
+ * name -> spec. A release that holds none is absent. Its advisories come with the release
57
+ * (audit 6.2.5 D-4: express 4.20.0 exact-pins qs 6.11.0).
58
+ */
59
+ heldSpecs?: Record<string, Record<string, string>>;
60
+ }
30
61
  export interface CrateDepReq {
31
62
  req: string;
32
63
  optional: boolean;
@@ -34,12 +65,20 @@ export interface CrateDepReq {
34
65
  export interface CratesSparse {
35
66
  /** Versions not yanked. */
36
67
  versions: string[];
68
+ /** Yanked versions. */
69
+ yanked?: string[];
37
70
  /** version -> dependency crate name -> requirements (one per target/kind entry; dev-dependencies left out). */
38
71
  reqs: Record<string, Record<string, CrateDepReq[]>>;
39
72
  }
73
+ /** Per published release of a parent: its requirements on one package, and whether it declares it only as a peer. */
74
+ export type RequirementHistory = Record<string, {
75
+ reqs: string[];
76
+ peer: boolean;
77
+ }>;
40
78
  export declare class FixPathSources {
41
79
  private cache;
42
80
  private rateLimiter;
81
+ private npmDocs;
43
82
  constructor(cache: LiveCache, rateLimiter: RateLimiter);
44
83
  /** Every non-withdrawn OSV advisory for a package, as ranges; null when OSV could not be read. */
45
84
  packageAdvisories(ecosystem: OsvEcosystem, name: string): Promise<AdvisoryRanges[] | null>;
@@ -51,15 +90,138 @@ export declare class FixPathSources {
51
90
  * records none). Null when unknown; [] when the parent declares none.
52
91
  */
53
92
  parentRequirements(ecosystem: OsvEcosystem, parent: string, parentVersion: string, dep: string): Promise<string[] | null>;
54
- private npmVersions;
93
+ /**
94
+ * What every published release of `parent` requires of `dep`, from the
95
+ * registry: version -> requirements (`reqs: []` when that release does not
96
+ * depend on it). npm reads dependencies and optionalDependencies of the
97
+ * abbreviated document (as `parentRequirements`), and, when neither holds
98
+ * it, peerDependencies, flagged `peer`: npm 7+ installs a missing peer, so
99
+ * moving a package into peerDependencies is not dropping it (readiness
100
+ * review 2026-10-17, finding 10). crates.io: the sparse index. Null when
101
+ * unknown or unsupported. Used to find the smallest parent release that
102
+ * admits a clean version (audit H1).
103
+ */
104
+ requirementHistory(ecosystem: OsvEcosystem, parent: string, dep: string): Promise<RequirementHistory | null>;
105
+ /**
106
+ * One npm abbreviated document per package, shared by the release facts and the requirement
107
+ * history of a plan (a parent's document was downloaded twice: NodeGoat's mongodb, ~600
108
+ * releases). Kept in memory for a short while, at most a few at a time; a failure is not kept.
109
+ */
110
+ private npmDocument;
111
+ /**
112
+ * Release facts for a parent or a fix target: what is installable, what is
113
+ * deprecated or yanked, and the latest release. Null when the registry
114
+ * could not be read or is not supported.
115
+ */
116
+ releaseFacts(ecosystem: OsvEcosystem, name: string): Promise<PackageReleaseFacts | null>;
117
+ /**
118
+ * npm's abbreviated document: versions without READMEs, with each
119
+ * version's `deprecated` message. A withdrawn release is never offered as a
120
+ * fix target: lodash 4.18.0 ("Bad release. Please use lodash@4.17.21
121
+ * instead.") was recommended by vulnerability_scan (audit B-8, 2026-10-12).
122
+ * Withdrawn means the app's rule (withdrawn-releases.ts): a deprecated
123
+ * release with a later clean one on its caret line. A whole-major notice
124
+ * (glob, tar 6.x) withdraws nothing, or glob 10.4.5 is sent to 12.0.0.
125
+ */
126
+ private npmFacts;
55
127
  /** A crate's sparse-index record: versions and per-version dependency requirements. */
56
128
  cratesSparse(name: string): Promise<CratesSparse | null>;
57
- private pypiVersions;
129
+ /**
130
+ * PyPI's JSON API: every release with files; one whose every file is yanked is withdrawn
131
+ * (PEP 592, the app's `parse_pypi`). A release with no files cannot be installed and is not listed.
132
+ */
133
+ private pypiFacts;
58
134
  private goVersions;
59
135
  }
60
- export type FixTargetResult = CleanTarget;
61
- /** The minimal clean target for one installed copy, or null when the advisories could not be read. */
62
- export declare function cleanFixTarget(sources: FixPathSources, ecosystem: OsvEcosystem, name: string, perAdvisoryFixes: string[]): Promise<FixTargetResult | null>;
136
+ export type FixTargetResult = CleanTarget & {
137
+ /** No target and a malicious landing: "<pkg> is flagged malicious (<id>): remove or replace <pkg>" (#994 review). */
138
+ landingNote?: string;
139
+ /**
140
+ * True when the package's advisories could not be read (OSV /v1/query
141
+ * failed) but the registry could: `target` is then only the smallest
142
+ * installable release at or above the highest per-advisory fix, which is
143
+ * deprecated, yanked or unpublished (`floorWithdrawn` says which). It is
144
+ * NOT checked against the package's other advisories; callers report the
145
+ * fix as checked against the installed version's advisories only.
146
+ */
147
+ advisoriesUnread?: boolean;
148
+ /**
149
+ * True when the package's registry could not be read: withdrawn (yanked, deprecated) releases
150
+ * were not checked, and the target comes from the advisory data alone, as before FX-H5.
151
+ */
152
+ registryUnread?: boolean;
153
+ /** The registry's words for each `withheld` release and each withdrawn line fix. */
154
+ withheldWhy?: Record<string, string>;
155
+ /**
156
+ * Per-advisory fixes the registry withdrew, keyed by that fix: the release to take instead
157
+ * (`fix: null` when none past it is known) and the withdrawn ones passed (installableFix).
158
+ */
159
+ lineFixes?: Record<string, {
160
+ fix: string | null;
161
+ withheld: string[];
162
+ }>;
163
+ /**
164
+ * npm: the target carries a deprecation notice the withdrawal rule keeps (one on its whole line,
165
+ * no later release on the line free of it: glob 10.5.0, "Old versions of glob are not
166
+ * supported"). It stays the target, the smallest fix without a major upgrade, and every tool
167
+ * says it is deprecated, as dependency_check does with `review` (final release audit 7f).
168
+ */
169
+ targetNotice?: string;
170
+ /** The package's malware advisories (#981 rule a): a release one affects is never the target. */
171
+ malware?: string[];
172
+ /**
173
+ * npm (audit 6.2.5 D-4): the release the package's own advisories pointed at, passed because a
174
+ * dependency it holds (an exact pin, or a narrow range whose newest release is affected) brings
175
+ * an advisory in; `heldPast` names each release passed and why. `target` is then the smallest
176
+ * later release on that line whose own advisories AND held dependencies are clean.
177
+ */
178
+ heldFrom?: string;
179
+ heldPast?: Array<{
180
+ version: string;
181
+ affected: HeldDependency[];
182
+ }>;
183
+ /** The target holds an affected dependency and no later release searched (`searched`) clears it: not a clean fix. */
184
+ heldBlocked?: {
185
+ affected: HeldDependency[];
186
+ searched: string[];
187
+ };
188
+ /** Whether the target's held dependencies are affected could not be checked, and why: not a clean fix either. */
189
+ heldUnchecked?: string;
190
+ };
191
+ /**
192
+ * Whether a checked target may be reported as checked against every advisory (fix_checked
193
+ * `all_advisories`): its own advisories were read, and, for npm, what it installs at a fixed
194
+ * version was judged clean (audit 6.2.5 D-4).
195
+ */
196
+ export declare function targetCheckedAll(clean: FixTargetResult): boolean;
197
+ /** The words for a target's held dependencies (FixTargetResult.heldFrom / heldBlocked / heldUnchecked), or null when there is nothing to say. */
198
+ export declare function heldNote(clean: FixTargetResult): string | null;
199
+ /**
200
+ * The minimal clean target for one installed copy, or null when neither the
201
+ * advisories nor anything that changes the answer could be read.
202
+ *
203
+ * Advisories unreadable, registry readable (audit H5: OSV /v1/query down):
204
+ * a deprecated or yanked release is still never the target. lodash 4.17.20
205
+ * went to 4.18.0 ("Bad release") because the whole check was skipped; the
206
+ * registry facts alone move it to 4.18.1, flagged `advisoriesUnread`.
207
+ *
208
+ * With no per-advisory fix at all (advisories that give only `last_affected`,
209
+ * audit A6), and the installed version known, the registry is asked for the
210
+ * first published release above the installed one that no known advisory
211
+ * affects: a fix candidate the advisories never named, flagged
212
+ * `noAdvisoryFix`, instead of "no fix".
213
+ */
214
+ export declare function cleanFixTarget(sources: FixPathSources, ecosystem: OsvEcosystem, name: string, perAdvisoryFixes: string[], installed?: string | null): Promise<FixTargetResult | null>;
215
+ /** #981 (b): an advisory whose ranges cannot be read leaves the release unknown, never skipped silently. */
216
+ export declare function unreadableText(ids: string[]): string;
217
+ /** The 4DA lead's rule (2026-10-18): no release is offered that brings in an advisory the installed version does not have. */
218
+ export declare function introducesText(ids: string[]): string;
219
+ /** #981 round 3: an installed copy a malicious advisory affects names no release; the advice is to remove or replace it. */
220
+ export declare function malwareText(name: string, ids: string[]): string;
221
+ /** The words for a target that carries a line-wide deprecation notice (FixTargetResult.targetNotice). */
222
+ export declare function lineNoticeText(version: string, message: string): string;
223
+ /** `withheldNote` for a checked target: the withdrawn releases passed, in plain words; null when none. */
224
+ export declare function withheldText(clean: FixTargetResult, ecosystem: string): string | null;
63
225
  /**
64
226
  * Verified targets for many installed copies at once, within a time budget:
65
227
  * the copies that could not be checked in time (or offline) are simply
@@ -70,31 +232,141 @@ export declare function verifyFixTargets(sources: FixPathSources | null, items:
70
232
  ecosystem: OsvEcosystem;
71
233
  name: string;
72
234
  fixes: string[];
73
- }>, budgetMs: number, concurrency?: number): Promise<Map<string, CleanTarget>>;
74
- /** One clause for a target that is not the highest per-advisory fix, or null when it is. */
75
- export declare function targetNote(clean: CleanTarget): string | null;
235
+ installed?: string;
236
+ }>, budgetMs: number, concurrency?: number, options?: {
237
+ heldQuery?: AdvisoryQuery;
238
+ }): Promise<Map<string, FixTargetResult>>;
239
+ /** Said whenever the registry could not be read: withdrawn releases are then not ruled out, never silently. */
240
+ export declare const REGISTRY_UNREAD_NOTE = "the registry could not be read, so whether it yanked or deprecated this release was not checked";
241
+ /**
242
+ * One clause for a target that is not the highest per-advisory fix, or null when it is.
243
+ * Withdrawn releases passed on the way are named in the registry's own words (FX-H5).
244
+ */
245
+ export declare function targetNote(clean: FixTargetResult, ecosystem?: string): string | null;
246
+ /**
247
+ * A finding's own fix as the registry still offers it (the app's `installable_fix`): the
248
+ * advisory's fixed version, or, when the registry withdrew it, the release to take instead
249
+ * (null: none past it is known), with the withdrawn ones and the plain-words note.
250
+ */
251
+ export declare function rowFix(fixed: string | null, clean: FixTargetResult | undefined, ecosystem: string): {
252
+ fixed: string | null;
253
+ withheld: string[];
254
+ note: string | null;
255
+ };
76
256
  export interface RefreshVerdict {
77
- /** True when every parent's requirement already admits a clean version. */
257
+ /** True when a lockfile refresh reaches a clean version (read, or inferred: see `inferred`). */
78
258
  refreshFixes: boolean;
259
+ /**
260
+ * True when no parent's requirement could be read (or not every one) and none
261
+ * excludes the target, so the verdict comes from semver compatibility
262
+ * (4DA AD-055 ¶1): a refresh when the target is caret-compatible with the
263
+ * installed version, the parent otherwise.
264
+ */
265
+ inferred: boolean;
79
266
  format: LockfileFormat;
80
- /** The command, run in the lockfile's directory. */
267
+ /** The command, run in the lockfile's directory; for yarn 1 and bun, the manual steps (no command moves one copy in place). */
81
268
  command: string;
82
- /** Parent requirements that do NOT admit a clean version (why it is waiting on upstream). */
269
+ /**
270
+ * Parent requirements that do NOT admit a clean version (why it is waiting on upstream).
271
+ * `bundled`: the copy ships inside that parent's tarball, so neither a refresh nor an override reaches it (audit E8).
272
+ */
83
273
  blocking: Array<{
84
274
  parent: string;
85
275
  parentVersion: string | null;
86
276
  requirement: string;
277
+ bundled?: boolean;
87
278
  }>;
88
279
  /** The version a refresh resolves to, when the registry's version list was read. */
89
280
  resolvesTo: string | null;
90
281
  }
91
- /** The refresh command for one lockfile format. */
92
- export declare function refreshCommand(format: LockfileFormat, name: string, installed: string, target: string): string;
282
+ /**
283
+ * The command that refreshes one transitive copy in place, for the tools it
284
+ * can be named for (4DA AD-055 ¶4); null for yarn 1 and bun, which have none
285
+ * (see `manualRefreshSteps`).
286
+ *
287
+ * pnpm: at a workspace root (`pnpm-workspace.yaml`), `pnpm update <pkg>`
288
+ * touches only the root project's tree, so a member's transitive copy stayed
289
+ * where it was; `-r` reaches every member (measured with pnpm 10.34.6: a
290
+ * member's mkdirp -> minimist 1.2.5 moved to 1.2.8 only with `-r`). `--depth
291
+ * Infinity` is the form the fix-path oracle applied (2026-10-10, U04/U10);
292
+ * pnpm 8.15 to 10.34 also moved a root project's transitive copy without it.
293
+ */
294
+ export declare function refreshCommand(format: LockfileFormat, name: string, installed: string, target: string, workspaceRoot?: boolean): string | null;
295
+ /**
296
+ * Whether an override (npm `overrides`, pnpm `pnpm.overrides`, yarn `resolutions`) can reach the copy
297
+ * these blocking parents hold: never when one of them ships it bundled (rule vectors rv-066..rv-068).
298
+ */
299
+ export declare function overrideReaches(blocking: Array<{
300
+ bundled?: boolean;
301
+ }>): boolean;
302
+ /**
303
+ * How a DIRECT dependency moves to its fix target, worded for the tool and the manifest that
304
+ * declares it: a port of the 4DA app's `osv/direct_upgrade.rs` (rule vectors fc-028..fc-053),
305
+ * read from the declaring project's own manifest. A command is named only where it was run
306
+ * against the tool (2026-10-15/16: npm 10.9.2, pnpm 10.34.6, yarn 1.22.22, yarn 4.9.1, cargo
307
+ * 1.95, go 1.24) and moved the dependency while keeping it as declared. Plain `npm install x@v`
308
+ * wrote `^v` over an exact pin and over `~` (readiness review 2026-10-17, finding 4).
309
+ *
310
+ * Null, and the plan keeps its plain "bump it where it is declared", for anything this cannot
311
+ * read with certainty: a dependency declared in two sections; a declared spec that does not
312
+ * admit the installed copy; `>=`, `||`, x-range, tag, git, `workspace:` or alias specs; a git,
313
+ * path or alternate-registry crate; a yarn workspace member (`yarn up` is project-wide); a Go
314
+ * `replace`; hashed or compiled (pip-compile, uv) requirements; bun or an unknown tool.
315
+ */
316
+ export type DirectFix = {
317
+ command: string;
318
+ refresh?: false;
319
+ }
320
+ /**
321
+ * The declaration ALREADY admits the target (navcal: sharp, next and vite under `^`): the minimal
322
+ * advice is the tool's in-range lockfile refresh, which leaves the manifest untouched, not a bump
323
+ * of the declaration (the 4DA app's DirectFix::Refresh). Each was run on a project declaring
324
+ * `ms ^2.1.1` locked at 2.1.1 (2026-10-18): it moved the lock to 2.1.3 and left package.json
325
+ * unchanged; plain `pnpm update ms` rewrote `^2.1.1` to `^2.1.3`, hence `--no-save`. Cargo:
326
+ * `itoa = "1.0.5"` locked 1.0.11 with Cargo.toml unchanged. Any readable range qualifies,
327
+ * `>=` and `||` included: no operator needs carrying.
328
+ */
329
+ | {
330
+ command: string;
331
+ refresh: true;
332
+ } | {
333
+ instruction: string;
334
+ };
335
+ type NpmManager = "npm" | "pnpm" | "yarn1" | "yarn-berry";
336
+ /** The spec `name` is declared with, when exactly one of dependencies / devDependencies / optionalDependencies holds it. */
337
+ export declare function npmDeclared(packageJson: string, name: string): string | null;
338
+ /** The command that moves a declared npm-family dependency, keeping its operator (quoted: `^` is cmd.exe's escape). */
339
+ export declare function npmDirectCommand(manager: NpmManager, declared: string, name: string, target: string): string | null;
340
+ interface CargoDecl {
341
+ kind: "normal" | "dev" | "build";
342
+ target: string | null;
343
+ key: string;
344
+ req: string | null;
345
+ workspace: boolean;
346
+ otherSource: boolean;
347
+ }
348
+ /** Every declaration of `crate` in a Cargo.toml (by crate name, so a renamed dependency is found through `package = ...`). */
349
+ export declare function cargoDeclarations(manifest: string, crate: string): CargoDecl[];
350
+ /** `go get <module>@v<target>` when go.mod requires the module directly at `installed` and no `replace` points it elsewhere. */
351
+ export declare function goDirectCommand(goMod: string, module: string, installed: string, target: string): string | null;
352
+ /** The edit of the requirements line that pins the package with `==` at `installed` (markers, extras kept). */
353
+ export declare function pypiDirectInstruction(requirements: string, file: string, name: string, installed: string, target: string): string | null;
354
+ /**
355
+ * The fix for `name` at `installed`, declared in the project at `projectDir`, read from its own
356
+ * manifest; null when it cannot be named with certainty (see DirectFix).
357
+ */
358
+ export declare function directFix(projectDir: string, ecosystem: string, name: string, installed: string, target: string): DirectFix | null;
359
+ /** For a lockfile with no in-place refresh command (yarn 1, bun): the steps that move the copy. */
360
+ export declare function manualRefreshSteps(format: "yarn" | "bun", name: string): string;
361
+ /** The refresh command for the project whose lockfile is `lockfile`; null when no command is named for it. */
362
+ export declare function refreshCommandFor(lockfile: string, name: string, installed: string, target: string): string | null;
93
363
  /**
94
364
  * Whether refreshing `lockfile` moves `name@installed` to a clean version
95
- * without any parent changing its declared requirement. Null when the
96
- * lockfile or a requirement cannot be read (the caller keeps "waiting on
97
- * upstream", the conservative answer).
365
+ * without any parent changing its declared requirement: `refreshRule` over
366
+ * every requirement the parents declare (read from the lockfile, else the
367
+ * parent's registry metadata). Null when the lockfile cannot be read or no
368
+ * verdict is possible (the caller keeps "waiting on upstream", the
369
+ * conservative answer).
98
370
  */
99
371
  export declare function refreshVerdict(sources: FixPathSources, ecosystem: OsvEcosystem, lockfile: string, name: string, installed: string, target: string, advisories: AdvisoryRanges[] | null, published: string[] | null): Promise<RefreshVerdict | null>;
100
372
  /**
@@ -116,3 +388,4 @@ export declare function refreshVerdict(sources: FixPathSources, ecosystem: OsvEc
116
388
  * at its newest matching version.
117
389
  */
118
390
  export declare function cargoPrecisePrerequisites(sources: FixPathSources, lockContent: string, name: string, installed: string, target: string): Promise<string[] | null>;
391
+ export {};