@wrongstack/techstack 0.289.0

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 (74) hide show
  1. package/LICENSE +21 -0
  2. package/dist/adapters/cpp.d.ts +16 -0
  3. package/dist/adapters/cpp.d.ts.map +1 -0
  4. package/dist/adapters/dart.d.ts +20 -0
  5. package/dist/adapters/dart.d.ts.map +1 -0
  6. package/dist/adapters/dotnet.d.ts +19 -0
  7. package/dist/adapters/dotnet.d.ts.map +1 -0
  8. package/dist/adapters/elixir.d.ts +16 -0
  9. package/dist/adapters/elixir.d.ts.map +1 -0
  10. package/dist/adapters/go.d.ts +20 -0
  11. package/dist/adapters/go.d.ts.map +1 -0
  12. package/dist/adapters/interface.d.ts +104 -0
  13. package/dist/adapters/interface.d.ts.map +1 -0
  14. package/dist/adapters/maven.d.ts +17 -0
  15. package/dist/adapters/maven.d.ts.map +1 -0
  16. package/dist/adapters/npm.d.ts +21 -0
  17. package/dist/adapters/npm.d.ts.map +1 -0
  18. package/dist/adapters/paths.d.ts +37 -0
  19. package/dist/adapters/paths.d.ts.map +1 -0
  20. package/dist/adapters/php.d.ts +20 -0
  21. package/dist/adapters/php.d.ts.map +1 -0
  22. package/dist/adapters/python.d.ts +26 -0
  23. package/dist/adapters/python.d.ts.map +1 -0
  24. package/dist/adapters/ruby.d.ts +16 -0
  25. package/dist/adapters/ruby.d.ts.map +1 -0
  26. package/dist/adapters/rust.d.ts +20 -0
  27. package/dist/adapters/rust.d.ts.map +1 -0
  28. package/dist/advisory/native-audit.d.ts +61 -0
  29. package/dist/advisory/native-audit.d.ts.map +1 -0
  30. package/dist/advisory/osv.d.ts +41 -0
  31. package/dist/advisory/osv.d.ts.map +1 -0
  32. package/dist/delivery/coordinator.d.ts +46 -0
  33. package/dist/delivery/coordinator.d.ts.map +1 -0
  34. package/dist/discovery/index.d.ts +58 -0
  35. package/dist/discovery/index.d.ts.map +1 -0
  36. package/dist/discovery/workspace.d.ts +49 -0
  37. package/dist/discovery/workspace.d.ts.map +1 -0
  38. package/dist/index.d.ts +49 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +4287 -0
  41. package/dist/index.js.map +7 -0
  42. package/dist/policy/status.d.ts +60 -0
  43. package/dist/policy/status.d.ts.map +1 -0
  44. package/dist/registry/client.d.ts +61 -0
  45. package/dist/registry/client.d.ts.map +1 -0
  46. package/dist/registry/purl.d.ts +106 -0
  47. package/dist/registry/purl.d.ts.map +1 -0
  48. package/dist/remediation.d.ts +54 -0
  49. package/dist/remediation.d.ts.map +1 -0
  50. package/dist/research/index.d.ts +11 -0
  51. package/dist/research/index.d.ts.map +1 -0
  52. package/dist/research/llm.d.ts +37 -0
  53. package/dist/research/llm.d.ts.map +1 -0
  54. package/dist/research/researcher.d.ts +31 -0
  55. package/dist/research/researcher.d.ts.map +1 -0
  56. package/dist/research/search.d.ts +19 -0
  57. package/dist/research/search.d.ts.map +1 -0
  58. package/dist/research/triage.d.ts +33 -0
  59. package/dist/research/triage.d.ts.map +1 -0
  60. package/dist/research/types.d.ts +77 -0
  61. package/dist/research/types.d.ts.map +1 -0
  62. package/dist/sbom.d.ts +52 -0
  63. package/dist/sbom.d.ts.map +1 -0
  64. package/dist/service.d.ts +110 -0
  65. package/dist/service.d.ts.map +1 -0
  66. package/dist/snapshot-diff.d.ts +27 -0
  67. package/dist/snapshot-diff.d.ts.map +1 -0
  68. package/dist/store/schema.d.ts +20 -0
  69. package/dist/store/schema.d.ts.map +1 -0
  70. package/dist/store/sqlite.d.ts +57 -0
  71. package/dist/store/sqlite.d.ts.map +1 -0
  72. package/dist/types.d.ts +123 -0
  73. package/dist/types.d.ts.map +1 -0
  74. package/package.json +45 -0
@@ -0,0 +1,60 @@
1
+ /**
2
+ * TechStack — Status classification policy.
3
+ *
4
+ * Classifies a DependencyObservation's status based on registry metadata,
5
+ * advisory data, and version comparison rules.
6
+ *
7
+ * Key contracts (per SDD R8/R9):
8
+ * - Private/unresolved (404/401) → `private_or_unresolved` (never `dead` or `deprecated`)
9
+ * - Offline/failed lookup → `unknown` (never `current`)
10
+ * - Registry says deprecated → `deprecated`
11
+ * - Registry says yanked → `yanked`
12
+ * - Advisory found → `vulnerable`
13
+ *
14
+ * @see docs/specs/techstack-sdd.md §7, R8, R9
15
+ */
16
+ import type { DependencyObservation, DependencyStatus, Evidence } from '../types.js';
17
+ /** Registry metadata used for status classification. */
18
+ export interface RegistryStatusData {
19
+ readonly latestStable?: string | undefined;
20
+ readonly deprecated?: boolean | undefined;
21
+ readonly yanked?: boolean | undefined;
22
+ /** Whether the registry lookup resulted in a 404/401 (private/unresolved). */
23
+ readonly privateOrUnresolved?: boolean | undefined;
24
+ /** Whether the registry lookup failed due to network error / timeout / offline. */
25
+ readonly lookupFailed?: boolean | undefined;
26
+ /** The evidence from the registry lookup. */
27
+ readonly evidence?: readonly Evidence[] | undefined;
28
+ }
29
+ /** Advisory data used for status classification. */
30
+ export interface AdvisoryStatusData {
31
+ /** Whether any advisory was found for this dependency. */
32
+ readonly hasAdvisory: boolean;
33
+ /** The evidence from the advisory lookup. */
34
+ readonly evidence?: readonly Evidence[] | undefined;
35
+ }
36
+ /**
37
+ * Compare two semver-like version strings.
38
+ * Returns -1 if a < b, 0 if a == b, 1 if a > b.
39
+ * Handles prerelease tags per semver: `1.0.0-alpha < 1.0.0`.
40
+ */
41
+ export declare function compareVersions(a: string, b: string): number;
42
+ /**
43
+ * Classify a dependency's status based on its current data plus optional
44
+ * registry metadata and advisory information.
45
+ *
46
+ * @param dep - The dependency observation from the inventory pass.
47
+ * @param registryData - Optional registry metadata (from lookupRegistry).
48
+ * @param advisoryData - Optional advisory data (from OSV or native audit).
49
+ * @returns The classified DependencyStatus.
50
+ */
51
+ export declare function classifyStatus(dep: Pick<DependencyObservation, 'name' | 'sourceType' | 'status' | 'locked' | 'requested'>, registryData?: RegistryStatusData, advisoryData?: AdvisoryStatusData): DependencyStatus;
52
+ /**
53
+ * Create a registry status data object indicating a private/unresolved package.
54
+ */
55
+ export declare function privateOrUnresolvedStatus(source: string, detail?: string): RegistryStatusData;
56
+ /**
57
+ * Create a registry status data object indicating a failed/offline lookup.
58
+ */
59
+ export declare function failedLookupStatus(source: string, error?: string): RegistryStatusData;
60
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/policy/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIrF,wDAAwD;AACxD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,8EAA8E;IAC9E,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnD,mFAAmF;IACnF,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5C,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;CACrD;AAED,oDAAoD;AACpD,MAAM,WAAW,kBAAkB;IACjC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,6CAA6C;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,QAAQ,EAAE,GAAG,SAAS,CAAC;CACrD;AAWD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA6C5D;AAqED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC,EAC3F,YAAY,CAAC,EAAE,kBAAkB,EACjC,YAAY,CAAC,EAAE,kBAAkB,GAChC,gBAAgB,CAkFlB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,MAAM,EACd,MAAM,CAAC,EAAE,MAAM,GACd,kBAAkB,CAYpB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,kBAAkB,CAYpB"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * TechStack — Registry metadata HTTP client.
3
+ *
4
+ * Per-ecosystem registry API clients built on Node's built-in https module.
5
+ * Features: in-memory cache with ETag/TTL, per-host concurrency limit (max 3),
6
+ * exponential backoff on 429/5xx responses.
7
+ *
8
+ * @see docs/specs/techstack-sdd.md §5, §6
9
+ */
10
+ export interface RegistryEntry {
11
+ readonly latestStable?: string | undefined;
12
+ readonly license?: string | undefined;
13
+ readonly deprecated?: boolean | undefined;
14
+ readonly yanked?: boolean | undefined;
15
+ readonly retrievedAt: string;
16
+ readonly source: string;
17
+ }
18
+ export interface CacheEntry {
19
+ readonly data: RegistryEntry;
20
+ readonly etag?: string | undefined;
21
+ readonly expiresAt: number;
22
+ }
23
+ export interface HostConcurrency {
24
+ active: number;
25
+ readonly queue: Array<() => void>;
26
+ }
27
+ /**
28
+ * Parse an npm packument into a {@link RegistryEntry}.
29
+ *
30
+ * Exported so the deprecation rule is unit-testable without a network round
31
+ * trip — it was untested, and drifted into flagging most of the ecosystem dead.
32
+ */
33
+ export declare function parseNpmPackument(json: Record<string, unknown>, name: string): RegistryEntry;
34
+ export interface RegistryLookupOptions {
35
+ /** Abort signal for cancellation. */
36
+ readonly signal?: AbortSignal | undefined;
37
+ /** Bypass cache and force a fresh lookup. */
38
+ readonly force?: boolean | undefined;
39
+ }
40
+ /**
41
+ * Look up registry metadata for a package in a given ecosystem.
42
+ *
43
+ * Returns `undefined` on 404/401 (private/unresolved package).
44
+ * Throws on network errors (timeout, DNS failure).
45
+ */
46
+ export declare function lookupRegistry(ecosystem: string, name: string, options?: RegistryLookupOptions): Promise<RegistryEntry | undefined>;
47
+ /**
48
+ * Look up registry metadata for multiple packages in the same ecosystem.
49
+ * Uses the same per-host concurrency limit for the batch.
50
+ */
51
+ export declare function lookupRegistryBatch(ecosystem: string, names: readonly string[], options?: RegistryLookupOptions): Promise<Map<string, RegistryEntry | undefined>>;
52
+ /**
53
+ * Get the list of supported ecosystem IDs for registry lookups.
54
+ */
55
+ export declare function supportedRegistryEcosystems(): string[];
56
+ /**
57
+ * Clear the in-memory registry cache.
58
+ * Useful for testing and when force-refreshing.
59
+ */
60
+ export declare function clearRegistryCache(): void;
61
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/registry/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC;CACnC;AA8JD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CA0B5F;AAgKD,MAAM,WAAW,qBAAqB;IACpC,qCAAqC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACtC;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAiFpC;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC,CAAC,CAoBjD;AAED;;GAEG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAGzC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * TechStack — Package URL (PURL) construction and parsing.
3
+ *
4
+ * PURL spec: https://github.com/package-url/purl-spec
5
+ *
6
+ * Every dependency that comes from a registry gets a PURL identifier
7
+ * so it can be matched across ecosystems, deduplicated in aggregate views,
8
+ * and queried against OSV's /v1/querybatch endpoint.
9
+ *
10
+ * @see docs/specs/techstack-sdd.md §4.1, §5
11
+ */
12
+ import type { EcosystemId } from '../types.js';
13
+ /**
14
+ * Parsed PURL components.
15
+ */
16
+ export interface PurlParts {
17
+ readonly type: string;
18
+ readonly namespace?: string | undefined;
19
+ readonly name: string;
20
+ readonly version?: string | undefined;
21
+ readonly qualifiers?: ReadonlyMap<string, string> | undefined;
22
+ readonly subpath?: string | undefined;
23
+ }
24
+ /**
25
+ * Build a PURL string from components.
26
+ *
27
+ * @example
28
+ * buildPurl({ type: 'npm', name: 'react', version: '19.1.0' })
29
+ * // → 'pkg:npm/react@19.1.0'
30
+ *
31
+ * buildPurl({ type: 'npm', namespace: '@types', name: 'node', version: '22.0.0' })
32
+ * // → 'pkg:npm/%40types/node@22.0.0'
33
+ *
34
+ * buildPurl({ type: 'maven', namespace: 'org.springframework', name: 'spring-core', version: '6.2.7' })
35
+ * // → 'pkg:maven/org.springframework/spring-core@6.2.7'
36
+ *
37
+ * buildPurl({ type: 'pypi', name: 'django', version: '5.2' })
38
+ * // → 'pkg:pypi/django@5.2'
39
+ */
40
+ export declare function buildPurl(parts: PurlParts): string;
41
+ /**
42
+ * Parse a PURL string into its components.
43
+ * Returns undefined for malformed PURLs.
44
+ *
45
+ * @example
46
+ * parsePurl('pkg:npm/react@19.1.0')
47
+ * // → { type: 'npm', name: 'react', version: '19.1.0' }
48
+ *
49
+ * parsePurl('pkg:maven/org.springframework/spring-core@6.2.7')
50
+ * // → { type: 'maven', namespace: 'org.springframework', name: 'spring-core', version: '6.2.7' }
51
+ */
52
+ export declare function parsePurl(purl: string): PurlParts | undefined;
53
+ /**
54
+ * Get the PURL type string for an ecosystem.
55
+ */
56
+ export declare function purlTypeForEcosystem(ecosystem: EcosystemId): string;
57
+ /**
58
+ * Get the ecosystem id for a PURL type string.
59
+ * Returns undefined for unknown types.
60
+ */
61
+ export declare function ecosystemForPurlType(type: string): EcosystemId | undefined;
62
+ /**
63
+ * Construct a PURL string for a dependency in a given ecosystem.
64
+ *
65
+ * This is the spec-required convenience constructor. It composes the richer
66
+ * `buildPurl` primitive with per-ecosystem namespace splitting so callers can
67
+ * pass `name` in the ecosystem-native form (e.g. `"@types/node"` for npm
68
+ * scoped packages, or `"org.springframework/spring-core"` for Maven groupId).
69
+ *
70
+ * Special-case: Go module paths (`github.com/gorilla/mux`) are written as a
71
+ * single un-encoded name — the PURL spec treats `/` as the namespace
72
+ * separator for most ecosystems but Go module paths use literal `/`s.
73
+ *
74
+ * @example
75
+ * constructPurl('npm', 'react', '19.1.0') // → 'pkg:npm/react@19.1.0'
76
+ * constructPurl('npm', '@types/node', '22.0.0') // → 'pkg:npm/%40types/node@22.0.0'
77
+ * constructPurl('pypi', 'django', '5.2') // → 'pkg:pypi/django@5.2'
78
+ * constructPurl('maven', 'org.springframework/spring-core', '6.2.7')
79
+ * // → 'pkg:maven/org.springframework/spring-core@6.2.7'
80
+ * constructPurl('go', 'github.com/gorilla/mux', '1.8.1')
81
+ * // → 'pkg:golang/github.com/gorilla/mux@1.8.1'
82
+ */
83
+ export declare function constructPurl(ecosystem: EcosystemId, name: string, version?: string): string;
84
+ /**
85
+ * Parse a PURL string back into the ecosystem-shaped parts used by the
86
+ * TechStack dependency model: ecosystem id, package name, and optional version.
87
+ *
88
+ * The npm scope and Maven groupId are folded back into `name` so the returned
89
+ * shape matches `constructPurl`'s inputs (round-trippable).
90
+ *
91
+ * Returns `undefined` for malformed PURLs or PURL types that don't map to a
92
+ * TechStack ecosystem.
93
+ *
94
+ * @example
95
+ * parsePurl('pkg:npm/%40types/node@22.0.0') // → { ecosystem:'npm', name:'@types/node', version:'22.0.0' }
96
+ * parsePurl('pkg:pypi/django@5.2') // → { ecosystem:'python', name:'django', version:'5.2' }
97
+ * parsePurl('pkg:npm/react') // → { ecosystem:'npm', name:'react' }
98
+ * parsePurl('not-a-purl') // → undefined
99
+ */
100
+ export interface ParsedEcosystemPurl {
101
+ readonly ecosystem: EcosystemId;
102
+ readonly name: string;
103
+ readonly version?: string | undefined;
104
+ }
105
+ export declare function parsePurlEcosystem(purl: string): ParsedEcosystemPurl | undefined;
106
+ //# sourceMappingURL=purl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"purl.d.ts","sourceRoot":"","sources":["../../src/registry/purl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;IAC9D,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAwCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAyBlD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAyE7D;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,WAAW,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAE1E;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,WAAW,EACtB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CA+BR;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,GAAG,SAAS,CAYhF"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TechStack — Remediation planning.
3
+ *
4
+ * Generates dry-run upgrade plans from a snapshot's findings. NEVER mutates
5
+ * dependency files — the plan is read-only output that the user must
6
+ * explicitly approve before any `language_package` or `install` tool runs.
7
+ *
8
+ * @see docs/specs/techstack-sdd.md §2 (R25), §9
9
+ */
10
+ import type { Finding, Snapshot } from './types.js';
11
+ export interface UpgradePlanItem {
12
+ readonly dependencyName: string;
13
+ readonly ecosystem: string;
14
+ readonly workspaceId: string;
15
+ readonly currentVersion: string | undefined;
16
+ readonly targetVersion: string | undefined;
17
+ readonly action: Finding['action'];
18
+ readonly severity: Finding['severity'];
19
+ readonly rationale: string;
20
+ readonly breakingRisk: string | undefined;
21
+ /** Command suggestion (informational only — never auto-executed). */
22
+ readonly suggestedCommand: string | undefined;
23
+ }
24
+ export interface UpgradePlan {
25
+ readonly snapshotId: string;
26
+ readonly generatedAt: string;
27
+ readonly items: readonly UpgradePlanItem[];
28
+ readonly summary: {
29
+ readonly total: number;
30
+ readonly patch: number;
31
+ readonly minor: number;
32
+ readonly major: number;
33
+ readonly replace: number;
34
+ readonly remove: number;
35
+ readonly investigate: number;
36
+ };
37
+ readonly warning: string;
38
+ }
39
+ /**
40
+ * Generate a dry-run upgrade plan from a snapshot.
41
+ *
42
+ * This function is **read-only** — it never touches manifests, lockfiles,
43
+ * or the filesystem. It only reads the snapshot's findings and produces
44
+ * a structured plan the user can review.
45
+ *
46
+ * @param snapshot The enriched snapshot to plan from.
47
+ * @returns A structured upgrade plan.
48
+ */
49
+ export declare function generateUpgradePlan(snapshot: Snapshot): UpgradePlan;
50
+ /**
51
+ * Render an upgrade plan as Markdown for the report endpoint or CLI display.
52
+ */
53
+ export declare function renderPlanMarkdown(plan: UpgradePlan): string;
54
+ //# sourceMappingURL=remediation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remediation.d.ts","sourceRoot":"","sources":["../src/remediation.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAyB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,eAAe,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;KAC9B,CAAC;IACF,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAsCD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,CA4DnE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAoD5D"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * TechStack — research stage barrel.
3
+ *
4
+ * @see docs/specs/techstack-sdd.md §31, §557
5
+ */
6
+ export { createResearcher, type CreateResearcherOptions } from './researcher.js';
7
+ export { createProviderLlm, parseResearchJson, type LlmAccessor } from './llm.js';
8
+ export { createToolSearch, type SearchToolOptions } from './search.js';
9
+ export { clusterCandidates, triageCandidates, DEFAULT_TRIAGE_LIMIT, type TriageOptions, } from './triage.js';
10
+ export type { ResearchCluster, ResearchLlm, ResearchLlmRequest, ResearchOptions, ResearchSearch, ResearchSearchResult, TechStackResearcher, TriageCandidate, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/research/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,KAAK,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EACV,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * TechStack — `Provider` → {@link ResearchLlm} adapter.
3
+ *
4
+ * Mirrors the capability-probing pattern established by the WebUI completion
5
+ * handler (`packages/webui-server/src/server/completion-handlers.ts`,
6
+ * `loadLlmSuggestions`): prefer strict structured output, fall back to JSON
7
+ * mode, fall back again to prompt-only discipline. Providers differ, and a
8
+ * research pass must not be exclusive to the ones with schema support.
9
+ *
10
+ * @see docs/specs/techstack-sdd.md §4.2
11
+ */
12
+ import type { Provider } from '@wrongstack/core';
13
+ import type { ResearchLlm } from './types.js';
14
+ /** How the caller reaches a live provider. A getter, not a captured value —
15
+ * the user can switch model or rotate credentials mid-session, and a snapshot
16
+ * of the provider would silently go stale. */
17
+ export type LlmAccessor = () => {
18
+ provider: Provider;
19
+ model: string;
20
+ } | undefined;
21
+ /**
22
+ * Build a {@link ResearchLlm} from a provider accessor, or `undefined` when no
23
+ * provider is currently wired — which is the signal `TechStackEngine` uses to
24
+ * skip the research stage entirely and stay a deterministic tool.
25
+ */
26
+ export declare function createProviderLlm(accessor: LlmAccessor, options?: {
27
+ readonly timeoutMs?: number | undefined;
28
+ }): ResearchLlm | undefined;
29
+ /**
30
+ * Parse a research response into a plain object, or `null` when the model
31
+ * returned something unusable.
32
+ *
33
+ * Never throws: an unparseable research response degrades that cluster to zero
34
+ * findings, it does not fail the analyze job.
35
+ */
36
+ export declare function parseResearchJson(text: string): Record<string, unknown> | null;
37
+ //# sourceMappingURL=llm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../../src/research/llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,WAAW,EAAsB,MAAM,YAAY,CAAC;AAElE;;8CAE8C;AAC9C,MAAM,MAAM,WAAW,GAAG,MAAM;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC;AAIlF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,EACrB,OAAO,GAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,GACxD,WAAW,GAAG,SAAS,CAgDzB;AA2BD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAU9E"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * TechStack — the research stage.
3
+ *
4
+ * Takes the deterministic snapshot's problem cases (see `triage.ts`), gathers
5
+ * public context for them via web search, and asks the LLM the one question
6
+ * the registry cannot answer: *what should I actually do about this?*
7
+ *
8
+ * Structure follows SDD §557 — one pass per finding-type cluster
9
+ * (breaking-change / replacement / CVE-applicability), not one per package and
10
+ * not one per ecosystem. That keeps the call count at ≤3 per analyze while
11
+ * still letting each prompt be a focused specialist.
12
+ *
13
+ * @see docs/specs/techstack-sdd.md §31, §472, §557
14
+ */
15
+ import type { ResearchLlm, ResearchSearch, TechStackResearcher } from './types.js';
16
+ export interface CreateResearcherOptions {
17
+ readonly llm: ResearchLlm;
18
+ readonly search: ResearchSearch;
19
+ /** Injectable clock — keeps evidence timestamps deterministic in tests. */
20
+ readonly now?: (() => Date) | undefined;
21
+ }
22
+ /**
23
+ * Build a {@link TechStackResearcher} over the injected LLM and search ports.
24
+ *
25
+ * Failure policy throughout: a cluster that throws contributes zero findings
26
+ * and does not disturb its siblings. Research is enrichment — a provider
27
+ * outage or a dry search must degrade the report, never fail the analyze job
28
+ * that already produced a complete deterministic inventory.
29
+ */
30
+ export declare function createResearcher(options: CreateResearcherOptions): TechStackResearcher;
31
+ //# sourceMappingURL=researcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"researcher.d.ts","sourceRoot":"","sources":["../../src/research/researcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAKH,OAAO,KAAK,EAEV,WAAW,EAEX,cAAc,EAEd,mBAAmB,EAEpB,MAAM,YAAY,CAAC;AA0SpB,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,WAAW,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,2EAA2E;IAC3E,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,mBAAmB,CAmDtF"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * TechStack — `searchTool` → {@link ResearchSearch} adapter.
3
+ *
4
+ * Wraps the built-in web search (`packages/tools/src/search.ts`) so the
5
+ * researcher depends on a one-function port rather than the tool contract.
6
+ *
7
+ * Note on reliability: that tool scrapes DuckDuckGo/Google/Bing through
8
+ * `guardedFetch` — there is no API key and no SLA. It can and does return
9
+ * nothing. Every failure here resolves to `[]` so a dry search degrades a
10
+ * finding to registry-only evidence instead of failing the analyze job.
11
+ */
12
+ import type { ResearchSearch } from './types.js';
13
+ export interface SearchToolOptions {
14
+ readonly numResults?: number | undefined;
15
+ readonly source?: 'duckduckgo' | 'google' | 'bing' | undefined;
16
+ }
17
+ /** Build a {@link ResearchSearch} backed by the built-in `search` tool. */
18
+ export declare function createToolSearch(options?: SearchToolOptions): ResearchSearch;
19
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/research/search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,YAAY,CAAC;AAavE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;CAChE;AAED,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,cAAc,CA2BhF"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * TechStack — Deterministic research triage.
3
+ *
4
+ * Decides *which* dependencies are worth an LLM call. No LLM, no network.
5
+ *
6
+ * This is the stage that makes research affordable: a monorepo resolves
7
+ * thousands of dependencies, the overwhelming majority of which are `current`
8
+ * and need no interpretation at all. Only statuses where the registry has
9
+ * already told us something is wrong — but not what to do about it — earn a
10
+ * research slot.
11
+ *
12
+ * @see docs/specs/techstack-sdd.md §31, §557
13
+ */
14
+ import type { DependencyObservation } from '../types.js';
15
+ import type { ResearchCluster, TriageCandidate } from './types.js';
16
+ /** Default cap on researched packages. Keeps a full analyze bounded. */
17
+ export declare const DEFAULT_TRIAGE_LIMIT = 40;
18
+ export interface TriageOptions {
19
+ /** Max candidates returned. Defaults to {@link DEFAULT_TRIAGE_LIMIT}. */
20
+ readonly limit?: number | undefined;
21
+ }
22
+ /**
23
+ * Select and rank the dependencies worth researching.
24
+ *
25
+ * Ordering is fully deterministic — priority, then name, then version — so the
26
+ * same snapshot always triages identically. Ties resolve by name rather than
27
+ * by input order because adapter output order is not itself guaranteed stable
28
+ * across platforms, and a wobbling triage would make the cap non-reproducible.
29
+ */
30
+ export declare function triageCandidates(dependencies: readonly DependencyObservation[], options?: TriageOptions): readonly TriageCandidate[];
31
+ /** Group triaged candidates by cluster, preserving triage order within each. */
32
+ export declare function clusterCandidates(candidates: readonly TriageCandidate[]): ReadonlyMap<ResearchCluster, readonly TriageCandidate[]>;
33
+ //# sourceMappingURL=triage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/research/triage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAoB,MAAM,aAAa,CAAC;AAC3E,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAsDvC,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,SAAS,qBAAqB,EAAE,EAC9C,OAAO,GAAE,aAAkB,GAC1B,SAAS,eAAe,EAAE,CAoC5B;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,SAAS,eAAe,EAAE,GACrC,WAAW,CAAC,eAAe,EAAE,SAAS,eAAe,EAAE,CAAC,CAQ1D"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * TechStack — Research stage contracts.
3
+ *
4
+ * The research stage is the "agents for interpretation" half of the SDD's
5
+ * guiding principle (§31): the inventory, version comparison, and advisory
6
+ * matching are deterministic; the LLM only answers contextual questions the
7
+ * registry cannot ("is this major bump breaking?", "what replaces this dead
8
+ * package?", "does this CVE apply to how we use it?").
9
+ *
10
+ * Everything here is expressed as a narrow injected port so the engine stays
11
+ * unit-testable with fakes and `packages/techstack` never reaches for a live
12
+ * provider or the network on its own.
13
+ *
14
+ * @see docs/specs/techstack-sdd.md §4.2, §31, §472, §557
15
+ */
16
+ import type { DependencyObservation, Finding } from '../types.js';
17
+ /**
18
+ * Research clusters, per SDD §557 — group by finding-type rather than by
19
+ * ecosystem so one prompt can answer one kind of question well, and the agent
20
+ * count stays bounded regardless of how many ecosystems the repo mixes.
21
+ */
22
+ export type ResearchCluster = 'breaking_change' | 'replacement' | 'vulnerability';
23
+ /** A dependency selected by triage, with the question it needs answered. */
24
+ export interface TriageCandidate {
25
+ readonly dependency: DependencyObservation;
26
+ readonly cluster: ResearchCluster;
27
+ /** Higher runs first and survives the cap. Deterministic — see `triage.ts`. */
28
+ readonly priority: number;
29
+ }
30
+ /** One web-search hit. Mirrors the shape `searchTool` returns. */
31
+ export interface ResearchSearchResult {
32
+ readonly title: string;
33
+ readonly url: string;
34
+ readonly snippet: string;
35
+ }
36
+ /**
37
+ * Web search port. Implementations must resolve to `[]` rather than throw —
38
+ * search is scraped best-effort (`packages/tools/src/search.ts` has no API
39
+ * key and can legitimately return nothing), and a dry search must degrade the
40
+ * finding, never fail the job.
41
+ */
42
+ export type ResearchSearch = (query: string, opts: {
43
+ readonly signal?: AbortSignal | undefined;
44
+ }) => Promise<readonly ResearchSearchResult[]>;
45
+ /** A single structured LLM request. */
46
+ export interface ResearchLlmRequest {
47
+ readonly system: string;
48
+ readonly prompt: string;
49
+ /** JSON Schema the response should conform to, when the provider supports it. */
50
+ readonly schema: Record<string, unknown>;
51
+ readonly schemaName: string;
52
+ readonly maxTokens: number;
53
+ readonly signal?: AbortSignal | undefined;
54
+ }
55
+ /**
56
+ * LLM port. Returns the raw response text (JSON, possibly fenced) — parsing
57
+ * lives in `llm.ts` so fakes stay trivial to write.
58
+ */
59
+ export type ResearchLlm = (req: ResearchLlmRequest) => Promise<string>;
60
+ export interface ResearchOptions {
61
+ readonly signal?: AbortSignal | undefined;
62
+ readonly onProgress?: ((completed: number, total: number) => void) | undefined;
63
+ }
64
+ /**
65
+ * The seam `TechStackEngine.analyze()` calls during the `researching` /
66
+ * `synthesizing` phases.
67
+ *
68
+ * Contract: returns *only* `Finding`s. `Finding` structurally cannot carry
69
+ * `latestStable` / `locked` / `requested`, which is how SDD §472 ("LLM
70
+ * fabricating version numbers") is enforced by the type system rather than by
71
+ * review. The engine appends these to `snapshot.findings` and never lets them
72
+ * touch `snapshot.dependencies`.
73
+ */
74
+ export interface TechStackResearcher {
75
+ research(candidates: readonly TriageCandidate[], opts?: ResearchOptions): Promise<readonly Finding[]>;
76
+ }
77
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/research/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAIlE;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,iBAAiB,GAAG,aAAa,GAAG,eAAe,CAAC;AAElF,4EAA4E;AAC5E,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,qBAAqB,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAID,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,CAC3B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE;IAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CAAE,KAChD,OAAO,CAAC,SAAS,oBAAoB,EAAE,CAAC,CAAC;AAE9C,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CAC3C;AAED;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAIvE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAChF;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CACN,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,SAAS,OAAO,EAAE,CAAC,CAAC;CAChC"}
package/dist/sbom.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * TechStack — SBOM (Software Bill of Materials) export.
3
+ *
4
+ * Converts a Snapshot into SPDX or CycloneDX JSON format.
5
+ *
6
+ * @see docs/specs/techstack-sdd.md §9
7
+ */
8
+ import type { Snapshot } from './types.js';
9
+ export interface SpdxDocument {
10
+ spdxVersion: string;
11
+ dataLicense: string;
12
+ SPDXID: string;
13
+ name: string;
14
+ documentNamespace: string;
15
+ creationInfo: {
16
+ created: string;
17
+ creators: string[];
18
+ };
19
+ packages: Array<{
20
+ name: string;
21
+ SPDXID: string;
22
+ versionInfo?: string | undefined;
23
+ downloadLocation?: string | undefined;
24
+ licenseConcluded?: string | undefined;
25
+ }>;
26
+ }
27
+ export declare function toSpdx(snapshot: Snapshot): SpdxDocument;
28
+ export interface CycloneDXBom {
29
+ bomFormat: string;
30
+ specVersion: string;
31
+ version: number;
32
+ metadata: {
33
+ timestamp: string;
34
+ tools: Array<{
35
+ name: string;
36
+ version: string;
37
+ }>;
38
+ };
39
+ components: Array<{
40
+ type: string;
41
+ name: string;
42
+ version?: string | undefined;
43
+ purl?: string | undefined;
44
+ licenses?: Array<{
45
+ license: {
46
+ id: string;
47
+ };
48
+ }> | undefined;
49
+ }>;
50
+ }
51
+ export declare function toCycloneDX(snapshot: Snapshot): CycloneDXBom;
52
+ //# sourceMappingURL=sbom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sbom.d.ts","sourceRoot":"","sources":["../src/sbom.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE;QACZ,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACjC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QACtC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACvC,CAAC,CAAC;CACJ;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAoBvD;AAID,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACjD,CAAC;IACF,UAAU,EAAE,KAAK,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC1B,QAAQ,CAAC,EAAE,KAAK,CAAC;YAAE,OAAO,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,CAAC,GAAG,SAAS,CAAC;KAC3D,CAAC,CAAC;CACJ;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,QAAQ,GAAG,YAAY,CAmB5D"}