@wrongstack/techstack 0.319.0 → 0.319.1

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 (2) hide show
  1. package/dist/index.js +198 -59
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -66,8 +66,8 @@ function parsePurl(purl) {
66
66
  const eqIdx = pair.indexOf("=");
67
67
  if (eqIdx > 0) {
68
68
  qualifiers.set(
69
- decodeURIComponent(pair.slice(0, eqIdx)),
70
- decodeURIComponent(pair.slice(eqIdx + 1))
69
+ decodePurlSegment(pair.slice(0, eqIdx)),
70
+ decodePurlSegment(pair.slice(eqIdx + 1))
71
71
  );
72
72
  }
73
73
  }
@@ -2224,7 +2224,13 @@ var TrendStore = class {
2224
2224
  active.add(key);
2225
2225
  const vulnerable = dependency.status === "vulnerable";
2226
2226
  const history = versionHistory.get(key) ?? [];
2227
- history.push({ at, version: dependency.locked ?? dependency.installed ?? dependency.requested, vulnerable, name: dependency.name, ecosystem: dependency.ecosystem });
2227
+ history.push({
2228
+ at,
2229
+ version: dependency.locked ?? dependency.installed ?? dependency.requested,
2230
+ vulnerable,
2231
+ name: dependency.name,
2232
+ ecosystem: dependency.ecosystem
2233
+ });
2228
2234
  versionHistory.set(key, history);
2229
2235
  if (vulnerable && !openVulnerabilities.has(key)) openVulnerabilities.set(key, at);
2230
2236
  if (!vulnerable && openVulnerabilities.has(key)) {
@@ -2281,7 +2287,9 @@ var TrendStore = class {
2281
2287
  snapshotId: snapshot.id,
2282
2288
  createdAt: snapshot.createdAt,
2283
2289
  dependencies: snapshot.dependencies.length,
2284
- outdated: snapshot.dependencies.filter((dependency) => dependency.status.startsWith("update_available")).length,
2290
+ outdated: snapshot.dependencies.filter(
2291
+ (dependency) => dependency.status.startsWith("update_available")
2292
+ ).length,
2285
2293
  vulnerable: snapshot.dependencies.filter((dependency) => dependency.status === "vulnerable").length
2286
2294
  }))
2287
2295
  };
@@ -2289,10 +2297,19 @@ var TrendStore = class {
2289
2297
  };
2290
2298
  function renderTrendMarkdown(report) {
2291
2299
  const lines = ["# TechStack Trend", "", `**Snapshots:** ${report.snapshots}`];
2292
- if (report.vulnerabilityHalfLifeMs !== void 0) lines.push(`**Vulnerability half-life:** ${(report.vulnerabilityHalfLifeMs / 864e5).toFixed(1)} days`);
2293
- lines.push("", "| Dependency | Version | Age (days) | Changes | Velocity/day |", "|---|---|---:|---:|---:|");
2300
+ if (report.vulnerabilityHalfLifeMs !== void 0)
2301
+ lines.push(
2302
+ `**Vulnerability half-life:** ${(report.vulnerabilityHalfLifeMs / 864e5).toFixed(1)} days`
2303
+ );
2304
+ lines.push(
2305
+ "",
2306
+ "| Dependency | Version | Age (days) | Changes | Velocity/day |",
2307
+ "|---|---|---:|---:|---:|"
2308
+ );
2294
2309
  for (const dependency of report.dependencies) {
2295
- lines.push(`| ${dependency.ecosystem}:${dependency.name} | ${dependency.currentVersion ?? "\u2014"} | ${(dependency.lockedVersionAgeMs / 864e5).toFixed(1)} | ${dependency.versionChanges} | ${dependency.upgradeVelocityPerDay.toFixed(3)} |`);
2310
+ lines.push(
2311
+ `| ${dependency.ecosystem}:${dependency.name} | ${dependency.currentVersion ?? "\u2014"} | ${(dependency.lockedVersionAgeMs / 864e5).toFixed(1)} | ${dependency.versionChanges} | ${dependency.upgradeVelocityPerDay.toFixed(3)} |`
2312
+ );
2296
2313
  }
2297
2314
  return lines.join("\n");
2298
2315
  }
@@ -2601,11 +2618,14 @@ function requestOnce(options) {
2601
2618
  );
2602
2619
  }
2603
2620
  });
2604
- response.on("end", () => resolve3({
2605
- statusCode: response.statusCode ?? 0,
2606
- headers: response.headers,
2607
- body
2608
- }));
2621
+ response.on(
2622
+ "end",
2623
+ () => resolve3({
2624
+ statusCode: response.statusCode ?? 0,
2625
+ headers: response.headers,
2626
+ body
2627
+ })
2628
+ );
2609
2629
  };
2610
2630
  const request = method === "GET" ? (isHttp ? httpGet : httpsGet)(requestOptions, callback) : (isHttp ? httpRequest : httpsRequest)(requestOptions, callback);
2611
2631
  request.on("error", reject);
@@ -2629,7 +2649,8 @@ async function requestWithRetry(options) {
2629
2649
  const exponential = (options.baseBackoffMs ?? 1e3) * 2 ** attempt;
2630
2650
  await delay(serverDelay ?? exponential, options.signal);
2631
2651
  } catch (error) {
2632
- if (options.signal?.aborted || error instanceof DOMException && error.name === "AbortError") throw error;
2652
+ if (options.signal?.aborted || error instanceof DOMException && error.name === "AbortError")
2653
+ throw error;
2633
2654
  lastError = error instanceof Error ? error : new Error(String(error));
2634
2655
  if (attempt < maxAttempts - 1) {
2635
2656
  await delay((options.baseBackoffMs ?? 1e3) * 2 ** attempt, options.signal);
@@ -2955,10 +2976,14 @@ async function lookupRegistry(ecosystem, name, options = {}) {
2955
2976
  throw new RegistryRateLimitError(response.statusCode, fetcher.host);
2956
2977
  }
2957
2978
  if (response.statusCode >= 500) {
2958
- throw new RegistryNetworkError(`Registry ${fetcher.host} returned ${response.statusCode} after 3 attempts`);
2979
+ throw new RegistryNetworkError(
2980
+ `Registry ${fetcher.host} returned ${response.statusCode} after 3 attempts`
2981
+ );
2959
2982
  }
2960
2983
  if (response.statusCode < 200 || response.statusCode >= 300) {
2961
- throw new RegistryNetworkError(`Unexpected registry response ${response.statusCode} from ${fetcher.host}`);
2984
+ throw new RegistryNetworkError(
2985
+ `Unexpected registry response ${response.statusCode} from ${fetcher.host}`
2986
+ );
2962
2987
  }
2963
2988
  const json = parseJsonResponse(response, `${fetcher.host}${path}`);
2964
2989
  const parsed = fetcher.parser(json, name, ecosystem);
@@ -3071,15 +3096,18 @@ async function queryOsvBatch(purls, options = {}) {
3071
3096
  if (!purl) continue;
3072
3097
  const vulns = result.results[i]?.vulns;
3073
3098
  if (!vulns || vulns.length === 0) continue;
3074
- advisories.set(purl, vulns.map((vuln) => ({
3075
- id: vuln.id,
3076
- summary: vuln.summary ?? vuln.details ?? "No summary available",
3077
- severity: mapSeverity(
3078
- vuln.severity,
3079
- vuln.database_specific?.severity ?? vuln.affected?.[0]?.database_specific?.severity
3080
- ),
3081
- aliases: vuln.aliases ?? []
3082
- })));
3099
+ advisories.set(
3100
+ purl,
3101
+ vulns.map((vuln) => ({
3102
+ id: vuln.id,
3103
+ summary: vuln.summary ?? vuln.details ?? "No summary available",
3104
+ severity: mapSeverity(
3105
+ vuln.severity,
3106
+ vuln.database_specific?.severity ?? vuln.affected?.[0]?.database_specific?.severity
3107
+ ),
3108
+ aliases: vuln.aliases ?? []
3109
+ }))
3110
+ );
3083
3111
  }
3084
3112
  }
3085
3113
  const evidence = {
@@ -3149,7 +3177,7 @@ async function runNpmAudit(workspaceRoot2, runner = defaultAuditCommandRunner) {
3149
3177
  id: advisory.cve ?? advisory.ghsa ?? `npm-${pkg}-${name ?? "unknown"}`,
3150
3178
  packageName: pkg,
3151
3179
  severity: npmSeverity(info.severity ?? "info"),
3152
- summary: advisory.title ?? (name ?? "No summary"),
3180
+ summary: advisory.title ?? name ?? "No summary",
3153
3181
  fixVersion: info.fixAvailable ?? void 0,
3154
3182
  url: advisory.url ?? void 0,
3155
3183
  aliases: advisory.cve ? [advisory.cve] : []
@@ -3858,7 +3886,9 @@ import { randomUUID as randomUUID2 } from "node:crypto";
3858
3886
 
3859
3887
  // src/service/finding-factory.ts
3860
3888
  function computeDependencyFingerprint(dependencies) {
3861
- const parts = dependencies.map((dependency) => `${dependency.name}@${dependency.locked ?? dependency.requested ?? "unknown"}`).sort().join(",");
3889
+ const parts = dependencies.map(
3890
+ (dependency) => `${dependency.name}@${dependency.locked ?? dependency.requested ?? "unknown"}`
3891
+ ).sort().join(",");
3862
3892
  let hash = 0;
3863
3893
  for (let index = 0; index < parts.length; index++) {
3864
3894
  hash = (hash << 5) - hash + parts.charCodeAt(index);
@@ -3870,17 +3900,60 @@ function createFindingForStatus(dependencyId, status) {
3870
3900
  const common = { dependencyId, confidence: 1, evidence: [] };
3871
3901
  switch (status) {
3872
3902
  case "vulnerable":
3873
- return { ...common, id: `finding-${dependencyId}-vuln`, type: "vulnerability", severity: "high", action: "upgrade_patch", rationale: "Known security advisory found for this package" };
3903
+ return {
3904
+ ...common,
3905
+ id: `finding-${dependencyId}-vuln`,
3906
+ type: "vulnerability",
3907
+ severity: "high",
3908
+ action: "upgrade_patch",
3909
+ rationale: "Known security advisory found for this package"
3910
+ };
3874
3911
  case "deprecated":
3875
- return { ...common, id: `finding-${dependencyId}-dep`, type: "deprecated", severity: "medium", action: "replace", rationale: "Package is deprecated in the registry" };
3912
+ return {
3913
+ ...common,
3914
+ id: `finding-${dependencyId}-dep`,
3915
+ type: "deprecated",
3916
+ severity: "medium",
3917
+ action: "replace",
3918
+ rationale: "Package is deprecated in the registry"
3919
+ };
3876
3920
  case "yanked":
3877
- return { ...common, id: `finding-${dependencyId}-yank`, type: "deprecated", severity: "high", action: "replace", rationale: "Package version has been yanked from the registry" };
3921
+ return {
3922
+ ...common,
3923
+ id: `finding-${dependencyId}-yank`,
3924
+ type: "deprecated",
3925
+ severity: "high",
3926
+ action: "replace",
3927
+ rationale: "Package version has been yanked from the registry"
3928
+ };
3878
3929
  case "update_available_safe":
3879
- return { ...common, id: `finding-${dependencyId}-update`, type: "upgrade", severity: "info", action: "upgrade_minor", rationale: "A newer compatible version is available" };
3930
+ return {
3931
+ ...common,
3932
+ id: `finding-${dependencyId}-update`,
3933
+ type: "upgrade",
3934
+ severity: "info",
3935
+ action: "upgrade_minor",
3936
+ rationale: "A newer compatible version is available"
3937
+ };
3880
3938
  case "update_available_breaking":
3881
- return { ...common, id: `finding-${dependencyId}-major`, type: "upgrade", severity: "low", action: "upgrade_major", rationale: "A newer version is available that may require breaking changes" };
3939
+ return {
3940
+ ...common,
3941
+ id: `finding-${dependencyId}-major`,
3942
+ type: "upgrade",
3943
+ severity: "low",
3944
+ action: "upgrade_major",
3945
+ rationale: "A newer version is available that may require breaking changes"
3946
+ };
3882
3947
  default:
3883
- return { ...common, confidence: 0.5, id: `finding-${dependencyId}-investigate`, type: "investigate", severity: "info", action: "investigate", rationale: `Package status is "${status}" \u2014 may need investigation` };
3948
+ return {
3949
+ ...common,
3950
+ confidence: 0.5,
3951
+ id: `finding-${dependencyId}-investigate`,
3952
+ type: "investigate",
3953
+ severity: "info",
3954
+ action: "investigate",
3955
+ rationale: `Package status is "${status}" \u2014 may need investigation`
3956
+ };
3884
3957
  }
3885
3958
  }
3886
3959
 
@@ -3889,7 +3962,8 @@ async function runEnrichPhase(snapshot, options = {}) {
3889
3962
  if (options.online === false || options.signal?.aborted) return snapshot;
3890
3963
  const grouped = /* @__PURE__ */ new Map();
3891
3964
  for (const dependency of snapshot.dependencies) {
3892
- if (!dependency.purl || dependency.sourceType === "path" || dependency.sourceType === "git") continue;
3965
+ if (!dependency.purl || dependency.sourceType === "path" || dependency.sourceType === "git")
3966
+ continue;
3893
3967
  grouped.set(dependency.ecosystem, [...grouped.get(dependency.ecosystem) ?? [], dependency]);
3894
3968
  }
3895
3969
  const enriched = /* @__PURE__ */ new Map();
@@ -3909,16 +3983,37 @@ async function runEnrichPhase(snapshot, options = {}) {
3909
3983
  latestStable: registryEntry.latestStable,
3910
3984
  deprecated: registryEntry.deprecated,
3911
3985
  yanked: registryEntry.yanked,
3912
- evidence: [{ kind: "registry", source: registryEntry.source, retrievedAt: registryEntry.retrievedAt, detail: `latestStable: ${registryEntry.latestStable ?? "N/A"}, license: ${registryEntry.license ?? "N/A"}` }]
3986
+ evidence: [
3987
+ {
3988
+ kind: "registry",
3989
+ source: registryEntry.source,
3990
+ retrievedAt: registryEntry.retrievedAt,
3991
+ detail: `latestStable: ${registryEntry.latestStable ?? "N/A"}, license: ${registryEntry.license ?? "N/A"}`
3992
+ }
3993
+ ]
3913
3994
  } : { privateOrUnresolved: true };
3914
3995
  } catch (error) {
3915
3996
  const unresolved = error instanceof RegistryNotFoundError || error instanceof RegistryAuthError;
3916
3997
  registryStatus = unresolved ? {
3917
3998
  privateOrUnresolved: true,
3918
- evidence: [{ kind: "registry", source: `${ecosystem} registry for ${name}`, retrievedAt: (/* @__PURE__ */ new Date()).toISOString(), detail: error.message }]
3999
+ evidence: [
4000
+ {
4001
+ kind: "registry",
4002
+ source: `${ecosystem} registry for ${name}`,
4003
+ retrievedAt: (/* @__PURE__ */ new Date()).toISOString(),
4004
+ detail: error.message
4005
+ }
4006
+ ]
3919
4007
  } : {
3920
4008
  lookupFailed: true,
3921
- evidence: [{ kind: "registry", source: `${ecosystem} registry for ${name}`, retrievedAt: (/* @__PURE__ */ new Date()).toISOString(), detail: error instanceof Error ? error.message : "Registry lookup failed" }]
4009
+ evidence: [
4010
+ {
4011
+ kind: "registry",
4012
+ source: `${ecosystem} registry for ${name}`,
4013
+ retrievedAt: (/* @__PURE__ */ new Date()).toISOString(),
4014
+ detail: error instanceof Error ? error.message : "Registry lookup failed"
4015
+ }
4016
+ ]
3922
4017
  };
3923
4018
  }
3924
4019
  let advisoryStatus;
@@ -3935,7 +4030,11 @@ async function runEnrichPhase(snapshot, options = {}) {
3935
4030
  for (const dependency of dependencies) {
3936
4031
  if (dependency.name !== name) continue;
3937
4032
  const status = classifyStatus(dependency, registryStatus, advisoryStatus);
3938
- const evidence = [...dependency.evidence, ...registryStatus?.evidence ?? [], ...advisoryStatus?.evidence ?? []];
4033
+ const evidence = [
4034
+ ...dependency.evidence,
4035
+ ...registryStatus?.evidence ?? [],
4036
+ ...advisoryStatus?.evidence ?? []
4037
+ ];
3939
4038
  const license = registryEntry?.license ?? dependency.license;
3940
4039
  enriched.set(dependency.id, {
3941
4040
  ...dependency,
@@ -3946,13 +4045,16 @@ async function runEnrichPhase(snapshot, options = {}) {
3946
4045
  status,
3947
4046
  evidence
3948
4047
  });
3949
- if (status !== "current" && status !== "local_path" && status !== "git_dependency") findings.push(createFindingForStatus(dependency.id, status));
4048
+ if (status !== "current" && status !== "local_path" && status !== "git_dependency")
4049
+ findings.push(createFindingForStatus(dependency.id, status));
3950
4050
  const licenseFinding = createLicenseFinding(dependency.id, dependency.name, license);
3951
4051
  if (licenseFinding) findings.push(licenseFinding);
3952
4052
  }
3953
4053
  }
3954
4054
  }
3955
- const enrichedDeps = snapshot.dependencies.map((dependency) => enriched.get(dependency.id) ?? dependency);
4055
+ const enrichedDeps = snapshot.dependencies.map(
4056
+ (dependency) => enriched.get(dependency.id) ?? dependency
4057
+ );
3956
4058
  const misalignmentFindings = detectWorkspaceMisalignments(enrichedDeps, snapshot.workspaces);
3957
4059
  findings.push(...misalignmentFindings);
3958
4060
  return { ...snapshot, dependencies: enrichedDeps, findings };
@@ -3986,11 +4088,13 @@ async function runInventoryPhase(store, projectId, targetRoot, options = {}) {
3986
4088
  for (const workspace of workspaces) {
3987
4089
  if (options.signal?.aborted) throw new DOMException("TechStack job cancelled", "AbortError");
3988
4090
  try {
3989
- dependencies.push(...await ADAPTERS[workspace.ecosystem].inventory(workspace, {
3990
- projectRoot: targetRoot,
3991
- includeTransitive: options.includeTransitive,
3992
- signal: options.signal
3993
- }));
4091
+ dependencies.push(
4092
+ ...await ADAPTERS[workspace.ecosystem].inventory(workspace, {
4093
+ projectRoot: targetRoot,
4094
+ includeTransitive: options.includeTransitive,
4095
+ signal: options.signal
4096
+ })
4097
+ );
3994
4098
  } catch {
3995
4099
  }
3996
4100
  if (workspace.coverage === "unsupported") coverage = "partial";
@@ -4031,32 +4135,56 @@ function generateReport(snapshot, format = "md") {
4031
4135
  ""
4032
4136
  ];
4033
4137
  if (snapshot.workspaces.length > 0) {
4034
- lines.push("## Workspaces", "", "| Workspace | Ecosystem | Coverage | Deps |", "|---|---|---|---|");
4138
+ lines.push(
4139
+ "## Workspaces",
4140
+ "",
4141
+ "| Workspace | Ecosystem | Coverage | Deps |",
4142
+ "|---|---|---|---|"
4143
+ );
4035
4144
  for (const workspace of snapshot.workspaces) {
4036
- const count = snapshot.dependencies.filter((dependency) => dependency.workspaceId === workspace.id).length;
4037
- lines.push(`| ${workspace.relativeRoot} | ${workspace.ecosystem} | ${workspace.coverage} | ${count} |`);
4145
+ const count = snapshot.dependencies.filter(
4146
+ (dependency) => dependency.workspaceId === workspace.id
4147
+ ).length;
4148
+ lines.push(
4149
+ `| ${workspace.relativeRoot} | ${workspace.ecosystem} | ${workspace.coverage} | ${count} |`
4150
+ );
4038
4151
  }
4039
4152
  lines.push("");
4040
4153
  }
4041
4154
  if (snapshot.findings.length > 0) {
4042
4155
  lines.push("## Findings", "");
4043
4156
  const bySeverity = /* @__PURE__ */ new Map();
4044
- for (const finding of snapshot.findings) bySeverity.set(finding.severity, [...bySeverity.get(finding.severity) ?? [], finding]);
4157
+ for (const finding of snapshot.findings)
4158
+ bySeverity.set(finding.severity, [...bySeverity.get(finding.severity) ?? [], finding]);
4045
4159
  for (const severity of ["critical", "high", "medium", "low", "info"]) {
4046
4160
  const findings = bySeverity.get(severity);
4047
4161
  if (!findings?.length) continue;
4048
- lines.push(`### ${severity.charAt(0).toUpperCase() + severity.slice(1)} (${findings.length})`, "");
4162
+ lines.push(
4163
+ `### ${severity.charAt(0).toUpperCase() + severity.slice(1)} (${findings.length})`,
4164
+ ""
4165
+ );
4049
4166
  for (const finding of findings) {
4050
- const dependency = snapshot.dependencies.find((candidate) => candidate.id === finding.dependencyId);
4051
- lines.push(`- **${dependency?.name ?? finding.dependencyId}** \u2014 ${finding.type} \u2014 ${finding.rationale}`);
4167
+ const dependency = snapshot.dependencies.find(
4168
+ (candidate) => candidate.id === finding.dependencyId
4169
+ );
4170
+ lines.push(
4171
+ `- **${dependency?.name ?? finding.dependencyId}** \u2014 ${finding.type} \u2014 ${finding.rationale}`
4172
+ );
4052
4173
  }
4053
4174
  lines.push("");
4054
4175
  }
4055
4176
  }
4056
4177
  if (snapshot.dependencies.length > 0) {
4057
- lines.push("## Dependencies", "", "| Name | Ecosystem | Status | Locked | Latest |", "|---|---|---|---|---|");
4178
+ lines.push(
4179
+ "## Dependencies",
4180
+ "",
4181
+ "| Name | Ecosystem | Status | Locked | Latest |",
4182
+ "|---|---|---|---|---|"
4183
+ );
4058
4184
  for (const dependency of snapshot.dependencies) {
4059
- lines.push(`| ${dependency.name} | ${dependency.ecosystem} | ${dependency.status} | ${dependency.locked ?? "\u2014"} | ${dependency.latestStable ?? "\u2014"} |`);
4185
+ lines.push(
4186
+ `| ${dependency.name} | ${dependency.ecosystem} | ${dependency.status} | ${dependency.locked ?? "\u2014"} | ${dependency.latestStable ?? "\u2014"} |`
4187
+ );
4060
4188
  }
4061
4189
  }
4062
4190
  return lines.join("\n");
@@ -4184,10 +4312,16 @@ var TechStackEngine = class {
4184
4312
  try {
4185
4313
  throwIfAborted();
4186
4314
  updateJob("discovering", { phase: "discovering", completed: 0, total: 1 });
4187
- let snapshot = await this.inventory(projectId, options.targetRoot, jobId, (phase, completed, total) => {
4188
- throwIfAborted();
4189
- updateJob(phase, { phase, completed, total });
4190
- }, { includeTransitive: options.includeTransitive, signal: options.signal });
4315
+ let snapshot = await this.inventory(
4316
+ projectId,
4317
+ options.targetRoot,
4318
+ jobId,
4319
+ (phase, completed, total) => {
4320
+ throwIfAborted();
4321
+ updateJob(phase, { phase, completed, total });
4322
+ },
4323
+ { includeTransitive: options.includeTransitive, signal: options.signal }
4324
+ );
4191
4325
  throwIfAborted();
4192
4326
  if (options.online !== false) {
4193
4327
  updateJob("enriching", { phase: "enriching", completed: 0, total: 1 });
@@ -4203,9 +4337,14 @@ var TechStackEngine = class {
4203
4337
  }
4204
4338
  this.store.saveSnapshot(snapshot);
4205
4339
  updateJob("completed", { phase: "completed", completed: 1, total: 1 });
4206
- return { snapshot, job: { ...job, status: "completed", completedAt: (/* @__PURE__ */ new Date()).toISOString() } };
4340
+ return {
4341
+ snapshot,
4342
+ job: { ...job, status: "completed", completedAt: (/* @__PURE__ */ new Date()).toISOString() }
4343
+ };
4207
4344
  } catch (error) {
4208
- updateJob(options.signal?.aborted || error instanceof DOMException && error.name === "AbortError" ? "cancelled" : "failed");
4345
+ updateJob(
4346
+ options.signal?.aborted || error instanceof DOMException && error.name === "AbortError" ? "cancelled" : "failed"
4347
+ );
4209
4348
  throw error;
4210
4349
  }
4211
4350
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/techstack",
3
- "version": "0.319.0",
3
+ "version": "0.319.1",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack TechStack — cross-language dependency intelligence for the active target project: discover, inventory, enrich, analyze, and report.",
6
6
  "repository": {
@@ -26,9 +26,9 @@
26
26
  "!dist/**/*.map"
27
27
  ],
28
28
  "dependencies": {
29
- "@wrongstack/core": "0.319.0",
30
- "@wrongstack/persistence": "0.319.0",
31
- "@wrongstack/tools": "0.319.0"
29
+ "@wrongstack/core": "0.319.1",
30
+ "@wrongstack/persistence": "0.319.1",
31
+ "@wrongstack/tools": "0.319.1"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@types/node": "^26.2.0",