circle-ir-ai 4.5.0 → 4.6.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 (46) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/bom/assemble.d.ts +29 -0
  3. package/dist/bom/assemble.d.ts.map +1 -0
  4. package/dist/bom/assemble.js +81 -0
  5. package/dist/bom/assemble.js.map +1 -0
  6. package/dist/bom/classify.d.ts +37 -0
  7. package/dist/bom/classify.d.ts.map +1 -0
  8. package/dist/bom/classify.js +82 -0
  9. package/dist/bom/classify.js.map +1 -0
  10. package/dist/bom/index.d.ts +40 -0
  11. package/dist/bom/index.d.ts.map +1 -0
  12. package/dist/bom/index.js +245 -0
  13. package/dist/bom/index.js.map +1 -0
  14. package/dist/bom/types.d.ts +75 -0
  15. package/dist/bom/types.d.ts.map +1 -0
  16. package/dist/bom/types.js +25 -0
  17. package/dist/bom/types.js.map +1 -0
  18. package/dist/bom/usage.d.ts +17 -0
  19. package/dist/bom/usage.d.ts.map +1 -0
  20. package/dist/bom/usage.js +112 -0
  21. package/dist/bom/usage.js.map +1 -0
  22. package/dist/coverage/index.d.ts +50 -0
  23. package/dist/coverage/index.d.ts.map +1 -0
  24. package/dist/coverage/index.js +73 -0
  25. package/dist/coverage/index.js.map +1 -0
  26. package/dist/coverage-map/index.d.ts +50 -0
  27. package/dist/coverage-map/index.d.ts.map +1 -0
  28. package/dist/coverage-map/index.js +73 -0
  29. package/dist/coverage-map/index.js.map +1 -0
  30. package/dist/coverage-map/kb-join.d.ts +46 -0
  31. package/dist/coverage-map/kb-join.d.ts.map +1 -0
  32. package/dist/coverage-map/kb-join.js +52 -0
  33. package/dist/coverage-map/kb-join.js.map +1 -0
  34. package/dist/coverage-map/kb.d.ts +50 -0
  35. package/dist/coverage-map/kb.d.ts.map +1 -0
  36. package/dist/coverage-map/kb.js +31 -0
  37. package/dist/coverage-map/kb.js.map +1 -0
  38. package/dist/index.d.ts +8 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +6 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/llm/verification.d.ts +15 -0
  43. package/dist/llm/verification.d.ts.map +1 -1
  44. package/dist/llm/verification.js +32 -9
  45. package/dist/llm/verification.js.map +1 -1
  46. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,48 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.6.0] - 2026-08-23
9
+
10
+ ### Fixed — cognium-ai#334 (P1): window-growth must not shrink the verify chunk
11
+
12
+ Successor to #332. #332 fixed the token ceiling; the OTHER chunk limiter — the
13
+ window↔chunk coupling (#244) — was directionally backwards: `windowScale =
14
+ baseWindow / currentWindow`, so when the AIMD window GROWS above its start
15
+ (80→120, which happens on healthy/fast endpoints where AIMD ramps the window up
16
+ on success streaks), `coupledMax` SHRANK 20→13, splitting every file with >13
17
+ pairs into extra LLM calls — a 20–40× slowdown on exactly the fast endpoints AIMD
18
+ was rewarding (h2database: 313/313 coupling events at `coupledMax`, window pinned
19
+ at 120, ~732 verify calls, 0 HTTP 429s). Fix: clamp the scale to ≥ 1 (new pure
20
+ `computeCoupledMax`) — a growing window never reduces the chunk below the AIMD
21
+ base; the shrink-boost (window < base → more pairs) is preserved. The token
22
+ ceiling (#332) already bounds pairs-per-call by real token cost, so window growth
23
+ carries no token argument for a smaller chunk. window=120 → `coupledMax` 20 (was
24
+ 13); files with ≤20 pairs do ONE call again. Test: `tests/verify-coupled-max-334.test.ts`
25
+ (+5). **#332 + #334 together are the complete verify-slowdown fix.**
26
+
27
+ ### Added — Conformis layer-BOM engine op (9-layer detect + usage index) + coverage map
28
+
29
+ The inventory + receipt spine of the Conformis loop (conformis-execution-plan.md
30
+ §7, A3-S2 "Join"), all in `src/bom/` + `src/coverage-map/`:
31
+ - **BOM** (`generateBom`): dependencies across all ecosystems (composes circle-ir's
32
+ npm/pypi/pyproject/maven/gradle/go/cargo parsers) with **transitive resolution**
33
+ from lockfiles (`direct` flag from the sibling manifest); a curated deterministic
34
+ **classifier** sorting the dependency BOM into L3 Protocols / L5 Framework / L7
35
+ Data usage layers; L2 runtime; L6/L8 from file detection; and a **usage index**
36
+ (which of the repo's own files import each classified component, via circle-ir
37
+ `parse` + `extractImports`).
38
+ - **Coverage map** (`computeCoverage`): the architect-view *receipt* — per component,
39
+ `settles_now` / `signal_until_harness` / `not_diffable` / `uncovered`, grounded in
40
+ the canon §3 per-layer inherited/extracted split. Emits counts + a
41
+ `declaredCoverablePct` explicitly labelled **PROJECTED** — never a settled-%.
42
+ - **BOM×KB join** (`joinCoverageWithKb`): fleet-memory skeleton — a `KnowledgeBase`
43
+ contract (the service plane implements it against the anchor store) + an
44
+ in-memory stub. A `settles_now` component with a fleet witness → `witnessed`; a
45
+ real `witnessedCount` distinct from the projected %.
46
+
47
+ Exposed via the cognium-ai `bom` CLI (`--coverage`), circle-pack `POST /api/bom`,
48
+ and the `layer_bom` MCP tool. Additive — no existing behaviour changed. +23 tests.
49
+
8
50
  ## [4.5.0] - 2026-08-22
9
51
 
10
52
  ### Changed — bump `circle-ir` 4.8.2 → 4.9.7
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pure BOM assembly: dependencies + detected files → {@link RepoBom}.
3
+ *
4
+ * Kept pure (no fs, no circle-ir) so the layer mapping is unit-testable without
5
+ * a repo. `generateBom(repoPath)` (index.ts) does the IO — collect deps via
6
+ * circle-ir, walk for L6/L8 files — then calls this.
7
+ */
8
+ import { type ClassifiableDependency } from './classify.js';
9
+ import { type BomLayer, type RepoBom } from './types.js';
10
+ /** A dependency as fed to the assembler (adds scope/direct over the classifier shape). */
11
+ export interface BomInputDependency extends ClassifiableDependency {
12
+ scope?: 'required' | 'optional' | 'dev';
13
+ direct?: boolean;
14
+ }
15
+ /** A non-dependency component found by walking the repo (L6 config, L8 spec). */
16
+ export interface DetectedFile {
17
+ layer: Extract<BomLayer, 'L6' | 'L8'>;
18
+ /** e.g. `container`, `ci`, `k8s` (L6); `openapi-spec`, `graphql-schema`, `proto` (L8). */
19
+ kind: string;
20
+ path: string;
21
+ name?: string;
22
+ }
23
+ export interface AssembleBomParams {
24
+ target: string;
25
+ dependencies: BomInputDependency[];
26
+ files?: DetectedFile[];
27
+ }
28
+ export declare function assembleBom(params: AssembleBomParams): RepoBom;
29
+ //# sourceMappingURL=assemble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.d.ts","sourceRoot":"","sources":["../../src/bom/assemble.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAGL,KAAK,sBAAsB,EAE5B,MAAM,eAAe,CAAC;AACvB,OAAO,EAGL,KAAK,QAAQ,EAEb,KAAK,OAAO,EACb,MAAM,YAAY,CAAC;AAIpB,0FAA0F;AAC1F,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAChE,KAAK,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,KAAK,CAAC;IACxC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,iFAAiF;AACjF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;IACtC,0FAA0F;IAC1F,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,kBAAkB,EAAE,CAAC;IACnC,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;CACxB;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CA+E9D"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Pure BOM assembly: dependencies + detected files → {@link RepoBom}.
3
+ *
4
+ * Kept pure (no fs, no circle-ir) so the layer mapping is unit-testable without
5
+ * a repo. `generateBom(repoPath)` (index.ts) does the IO — collect deps via
6
+ * circle-ir, walk for L6/L8 files — then calls this.
7
+ */
8
+ import { classifyDependency, runtimeForEcosystem, } from './classify.js';
9
+ import { BOM_LAYER_TITLES, } from './types.js';
10
+ const ALL_LAYERS = ['L2', 'L3', 'L4', 'L5', 'L6', 'L7', 'L8', 'L9'];
11
+ export function assembleBom(params) {
12
+ const { target, dependencies, files = [] } = params;
13
+ const buckets = {
14
+ L2: [], L3: [], L4: [], L5: [], L6: [], L7: [], L8: [], L9: [],
15
+ };
16
+ const ecosystems = new Set();
17
+ for (const dep of dependencies) {
18
+ ecosystems.add(dep.ecosystem);
19
+ // Every dependency is L4 supply chain (the recursive dependency BOM).
20
+ buckets.L4.push({
21
+ name: dep.name,
22
+ version: dep.version,
23
+ layer: 'L4',
24
+ kind: dep.scope === 'dev' ? 'dependency:dev' : 'dependency',
25
+ ecosystem: dep.ecosystem,
26
+ source: 'dependency',
27
+ direct: dep.direct,
28
+ });
29
+ // …and, if it is a protocol/framework/data library, its usage layer too.
30
+ const cls = classifyDependency(dep);
31
+ if (cls) {
32
+ buckets[cls.layer].push({
33
+ name: dep.name,
34
+ version: dep.version,
35
+ layer: cls.layer,
36
+ kind: cls.kind,
37
+ ecosystem: dep.ecosystem,
38
+ source: 'dependency',
39
+ direct: dep.direct,
40
+ });
41
+ }
42
+ }
43
+ // L2 Runtime — one component per distinct ecosystem present.
44
+ for (const eco of ecosystems) {
45
+ buckets.L2.push({
46
+ name: runtimeForEcosystem(eco),
47
+ layer: 'L2',
48
+ kind: runtimeForEcosystem(eco),
49
+ ecosystem: eco,
50
+ source: 'runtime',
51
+ });
52
+ }
53
+ // L6 / L8 — file-detected components.
54
+ for (const f of files) {
55
+ buckets[f.layer].push({
56
+ name: f.name ?? f.path,
57
+ layer: f.layer,
58
+ kind: f.kind,
59
+ source: 'file',
60
+ path: f.path,
61
+ });
62
+ }
63
+ const layers = {};
64
+ for (const layer of ALL_LAYERS) {
65
+ layers[layer] = { layer, title: BOM_LAYER_TITLES[layer], components: buckets[layer] };
66
+ }
67
+ const totalComponents = ALL_LAYERS.reduce((n, l) => n + buckets[l].length, 0);
68
+ const populatedLayers = ALL_LAYERS.filter((l) => buckets[l].length > 0);
69
+ return {
70
+ target,
71
+ languages: [...ecosystems].sort(),
72
+ layers,
73
+ meta: {
74
+ generatedAt: new Date().toISOString(),
75
+ totalDependencies: dependencies.length,
76
+ totalComponents,
77
+ populatedLayers,
78
+ },
79
+ };
80
+ }
81
+ //# sourceMappingURL=assemble.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assemble.js","sourceRoot":"","sources":["../../src/bom/assemble.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Dependency → layer classifier (the BOM's core intelligence).
3
+ *
4
+ * The insight behind the 9-layer inventory: **L3 (Protocols), L5 (Framework),
5
+ * and L7 (Data) are, at the component level, the L4 dependency BOM sorted into
6
+ * buckets.** A JWT library is an L3 protocol component; React is an L5 framework
7
+ * component; Prisma is an L7 data component — all of them are also L4 supply
8
+ * chain. So the classifier maps a dependency to its *usage* layer (L3/L5/L7),
9
+ * and the assembler always also lists it under L4. Unclassified deps are L4-only.
10
+ *
11
+ * The map is deterministic + curated (no LLM) and seeded from the conformis lane
12
+ * targets (conformis-execution-plan.md §2–3b): OpenAPI/GraphQL/gRPC + JWT/OAuth
13
+ * (Lane A/D), React/Expo (Lane B), Spring/Django, ORMs (Lane C data). Extend by
14
+ * adding rows — it is intentionally a plain table, not a heuristic.
15
+ */
16
+ import type { BomLayer } from './types.js';
17
+ /** Package ecosystem, aligned with circle-ir's `Ecosystem` (purl `pkg:<type>`). */
18
+ export type Ecosystem = 'npm' | 'pypi' | 'maven' | 'cargo' | 'golang';
19
+ /** The minimal dependency shape the classifier needs (decoupled from circle-ir's union). */
20
+ export interface ClassifiableDependency {
21
+ name: string;
22
+ version?: string;
23
+ ecosystem: Ecosystem;
24
+ }
25
+ export interface Classification {
26
+ layer: Extract<BomLayer, 'L3' | 'L5' | 'L7'>;
27
+ /** Sub-kind, e.g. `jwt`, `framework:react`, `orm:prisma`. */
28
+ kind: string;
29
+ }
30
+ /**
31
+ * Classify a dependency into its usage layer (L3/L5/L7), or `null` if it is
32
+ * plain supply chain (L4-only). First matching rule wins.
33
+ */
34
+ export declare function classifyDependency(dep: ClassifiableDependency): Classification | null;
35
+ /** Ecosystem → L2 runtime component name (JLS/ECMA/CPython families). */
36
+ export declare function runtimeForEcosystem(ecosystem: Ecosystem): string;
37
+ //# sourceMappingURL=classify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/bom/classify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,mFAAmF;AACnF,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEtE,4FAA4F;AAC5F,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAC7C,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;CACd;AA4DD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,sBAAsB,GAAG,cAAc,GAAG,IAAI,CAOrF;AAED,yEAAyE;AACzE,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAQhE"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Dependency → layer classifier (the BOM's core intelligence).
3
+ *
4
+ * The insight behind the 9-layer inventory: **L3 (Protocols), L5 (Framework),
5
+ * and L7 (Data) are, at the component level, the L4 dependency BOM sorted into
6
+ * buckets.** A JWT library is an L3 protocol component; React is an L5 framework
7
+ * component; Prisma is an L7 data component — all of them are also L4 supply
8
+ * chain. So the classifier maps a dependency to its *usage* layer (L3/L5/L7),
9
+ * and the assembler always also lists it under L4. Unclassified deps are L4-only.
10
+ *
11
+ * The map is deterministic + curated (no LLM) and seeded from the conformis lane
12
+ * targets (conformis-execution-plan.md §2–3b): OpenAPI/GraphQL/gRPC + JWT/OAuth
13
+ * (Lane A/D), React/Expo (Lane B), Spring/Django, ORMs (Lane C data). Extend by
14
+ * adding rows — it is intentionally a plain table, not a heuristic.
15
+ */
16
+ // Ordered: first matching rule wins. Keep specific before generic.
17
+ const RULES = [
18
+ // ── L3 Protocols ───────────────────────────────────────────────────────────
19
+ { layer: 'L3', kind: 'jwt', names: ['jsonwebtoken', 'jose', 'jwt-decode', 'fast-jwt', 'pyjwt', 'jjwt'], prefixes: ['@panva/jose', 'com.auth0:java-jwt', 'io.jsonwebtoken'] },
20
+ { layer: 'L3', kind: 'oauth', names: ['passport', 'oauth', 'openid-client', 'simple-oauth2', 'authlib', 'oauthlib'], prefixes: ['passport-', '@node-oauth', 'next-auth', '@auth/'] },
21
+ { layer: 'L3', kind: 'grpc', names: ['grpc', '@grpc/grpc-js', 'grpcio', 'nice-grpc'], prefixes: ['@grpc/', 'io.grpc:'] },
22
+ { layer: 'L3', kind: 'graphql-transport', names: ['graphql', 'graphql-ws', 'subscriptions-transport-ws'] },
23
+ { layer: 'L3', kind: 'websocket', names: ['ws', 'socket.io', 'socket.io-client', 'websockets'] },
24
+ { layer: 'L3', kind: 'http-client', names: ['axios', 'node-fetch', 'got', 'undici', 'superagent', 'requests', 'httpx', 'aiohttp'], prefixes: ['okhttp', 'org.apache.httpcomponents'] },
25
+ { layer: 'L3', kind: 'tls', names: ['node-forge', 'pyopenssl', 'cryptography'] },
26
+ // ── L5 Framework ───────────────────────────────────────────────────────────
27
+ { layer: 'L5', kind: 'framework:expo', names: ['expo'], prefixes: ['expo-', '@expo/'] },
28
+ { layer: 'L5', kind: 'framework:react-native', names: ['react-native'], prefixes: ['react-native-', '@react-native'] },
29
+ { layer: 'L5', kind: 'framework:react', names: ['react', 'react-dom', 'next'], prefixes: ['@remix-run', 'gatsby'] },
30
+ { layer: 'L5', kind: 'framework:vue', names: ['vue', 'nuxt'], prefixes: ['@vue/'] },
31
+ { layer: 'L5', kind: 'framework:angular', prefixes: ['@angular/'] },
32
+ { layer: 'L5', kind: 'framework:svelte', names: ['svelte', '@sveltejs/kit'] },
33
+ { layer: 'L5', kind: 'framework:node-http', names: ['express', 'koa', 'fastify', 'hapi', 'hono'], prefixes: ['@nestjs/'] },
34
+ { layer: 'L5', kind: 'framework:spring', ecosystem: 'maven', prefixes: ['org.springframework'] },
35
+ { layer: 'L5', kind: 'framework:python-web', ecosystem: 'pypi', names: ['django', 'flask', 'fastapi', 'starlette', 'tornado'] },
36
+ // ── L7 Data ────────────────────────────────────────────────────────────────
37
+ { layer: 'L7', kind: 'orm:prisma', names: ['prisma', '@prisma/client'], prefixes: ['@prisma/'] },
38
+ { layer: 'L7', kind: 'orm:sequelize', names: ['sequelize'] },
39
+ { layer: 'L7', kind: 'orm:typeorm', names: ['typeorm'] },
40
+ { layer: 'L7', kind: 'orm:mongoose', names: ['mongoose'] },
41
+ { layer: 'L7', kind: 'orm:drizzle', names: ['drizzle-orm'] },
42
+ { layer: 'L7', kind: 'query-builder', names: ['knex', 'kysely'] },
43
+ { layer: 'L7', kind: 'orm:python', ecosystem: 'pypi', names: ['sqlalchemy', 'alembic', 'django-orm', 'peewee', 'tortoise-orm'] },
44
+ { layer: 'L7', kind: 'orm:jpa', ecosystem: 'maven', prefixes: ['org.hibernate', 'jakarta.persistence', 'javax.persistence', 'org.mybatis'] },
45
+ { layer: 'L7', kind: 'db-driver', names: ['pg', 'mysql', 'mysql2', 'sqlite3', 'better-sqlite3', 'ioredis', 'redis', 'mongodb', 'psycopg2', 'psycopg2-binary', 'asyncpg', 'pymysql'] },
46
+ ];
47
+ const lc = (s) => s.toLowerCase();
48
+ function matches(rule, name, ecosystem) {
49
+ if (rule.ecosystem && rule.ecosystem !== ecosystem)
50
+ return false;
51
+ const n = lc(name);
52
+ if (rule.names?.some((x) => n === lc(x)))
53
+ return true;
54
+ if (rule.prefixes?.some((x) => n.startsWith(lc(x))))
55
+ return true;
56
+ if (rule.contains?.some((x) => n.includes(lc(x))))
57
+ return true;
58
+ return false;
59
+ }
60
+ /**
61
+ * Classify a dependency into its usage layer (L3/L5/L7), or `null` if it is
62
+ * plain supply chain (L4-only). First matching rule wins.
63
+ */
64
+ export function classifyDependency(dep) {
65
+ for (const rule of RULES) {
66
+ if (matches(rule, dep.name, dep.ecosystem)) {
67
+ return { layer: rule.layer, kind: rule.kind };
68
+ }
69
+ }
70
+ return null;
71
+ }
72
+ /** Ecosystem → L2 runtime component name (JLS/ECMA/CPython families). */
73
+ export function runtimeForEcosystem(ecosystem) {
74
+ switch (ecosystem) {
75
+ case 'npm': return 'runtime:node';
76
+ case 'pypi': return 'runtime:python';
77
+ case 'maven': return 'runtime:jvm';
78
+ case 'cargo': return 'runtime:rust';
79
+ case 'golang': return 'runtime:go';
80
+ }
81
+ }
82
+ //# sourceMappingURL=classify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"classify.js","sourceRoot":"","sources":["../../src/bom/classify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Layer-BOM engine op — `generateBom(repoPath)` (Conformis inventory step).
3
+ *
4
+ * Composes: (a) dependencies (all ecosystems, via circle-ir's manifest parsers)
5
+ * → L4 + classified L3/L5/L7; (b) L2 runtime from ecosystems; (c) L6/L8 file
6
+ * detection (config + API specs); (d) the usage index (import sites per
7
+ * classified component, via circle-ir `parse` + `extractImports`). The
8
+ * classification/assembly is pure (assemble.ts); this module does the IO.
9
+ */
10
+ import { type BomInputDependency, type DetectedFile } from './assemble.js';
11
+ import type { RepoBom } from './types.js';
12
+ export * from './types.js';
13
+ export * from './classify.js';
14
+ export { assembleBom } from './assemble.js';
15
+ export type { BomInputDependency, DetectedFile } from './assemble.js';
16
+ export { buildUsageIndex } from './usage.js';
17
+ /** Read npm dependencies from a single package.json (kept for direct callers). */
18
+ export declare function readNpmDependencies(repoPath: string): BomInputDependency[];
19
+ /**
20
+ * Collect the dependency set across all ecosystems. Per directory: a lockfile,
21
+ * when present, gives the full direct+transitive graph (and `direct` is set from
22
+ * the sibling manifest's declared names); otherwise the manifest gives the
23
+ * direct set. Aggregated across the repo (monorepo-aware) and deduped by
24
+ * `(ecosystem, name)` — a dep declared direct anywhere stays direct; a resolved
25
+ * version wins over an `unknown`.
26
+ */
27
+ export declare function readDependencies(repoPath: string): BomInputDependency[];
28
+ /** Walk the repo (bounded) for L6 (config) + L8 (API spec) file components. */
29
+ export declare function detectFiles(repoPath: string): DetectedFile[];
30
+ export interface GenerateBomOptions {
31
+ /** Override the detected dependency set (e.g. inject a pre-collected list). */
32
+ dependencies?: BomInputDependency[];
33
+ /** Skip the L6/L8 file walk. */
34
+ skipFiles?: boolean;
35
+ /** Build the usage index (import sites per classified component). Default true. */
36
+ usage?: boolean;
37
+ }
38
+ /** Generate the layer-BOM for a repo (async: the usage index parses source). */
39
+ export declare function generateBom(repoPath: string, opts?: GenerateBomOptions): Promise<RepoBom>;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bom/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgBH,OAAO,EAAe,KAAK,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAExF,OAAO,KAAK,EAAY,OAAO,EAAE,MAAM,YAAY,CAAC;AAEpD,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAgC7C,kFAAkF;AAClF,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAQ1E;AAYD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAuDvE;AAED,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAuC5D;AAMD,MAAM,WAAW,kBAAkB;IACjC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,gFAAgF;AAChF,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBnG"}
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Layer-BOM engine op — `generateBom(repoPath)` (Conformis inventory step).
3
+ *
4
+ * Composes: (a) dependencies (all ecosystems, via circle-ir's manifest parsers)
5
+ * → L4 + classified L3/L5/L7; (b) L2 runtime from ecosystems; (c) L6/L8 file
6
+ * detection (config + API specs); (d) the usage index (import sites per
7
+ * classified component, via circle-ir `parse` + `extractImports`). The
8
+ * classification/assembly is pure (assemble.ts); this module does the IO.
9
+ */
10
+ import * as fs from 'fs';
11
+ import * as path from 'path';
12
+ import { parseNpmDependencies, parsePypiDependencies, parsePyprojectDependencies, parseMavenDependencies, parseGradleDependencies, parseGoDependencies, parseCargoDependencies, parseNpmLockDependencies, parseCargoLockDependencies, parsePoetryLockDependencies, } from 'circle-ir';
13
+ import { assembleBom } from './assemble.js';
14
+ import { buildUsageIndex } from './usage.js';
15
+ export * from './types.js';
16
+ export * from './classify.js';
17
+ export { assembleBom } from './assemble.js';
18
+ export { buildUsageIndex } from './usage.js';
19
+ const IGNORE_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage', '.next', 'vendor', 'target', '__pycache__']);
20
+ const MAX_WALK_DEPTH = 6;
21
+ /** Manifest filename → circle-ir parser (each takes the file *content*). */
22
+ const MANIFEST_PARSERS = [
23
+ { file: 'package.json', parse: parseNpmDependencies },
24
+ { file: 'requirements.txt', parse: parsePypiDependencies },
25
+ { file: 'pyproject.toml', parse: parsePyprojectDependencies },
26
+ { file: 'pom.xml', parse: parseMavenDependencies },
27
+ { file: 'build.gradle', parse: parseGradleDependencies },
28
+ { file: 'build.gradle.kts', parse: parseGradleDependencies },
29
+ { file: 'go.mod', parse: parseGoDependencies },
30
+ { file: 'Cargo.toml', parse: parseCargoDependencies },
31
+ ];
32
+ const MANIFEST_NAMES = new Set(MANIFEST_PARSERS.map((m) => m.file));
33
+ /**
34
+ * Lockfile parsers — the *complete resolved* graph (direct + transitive, exact
35
+ * versions). When a lockfile is present it supersedes its sibling manifest for
36
+ * that ecosystem; `direct` is then set by whether the dep is declared in the
37
+ * manifest. Java (Maven/Gradle) + Go have no statically-parseable lock graph
38
+ * here, so they stay direct-from-manifest (best-effort).
39
+ */
40
+ const LOCK_PARSERS = [
41
+ { file: 'package-lock.json', parse: parseNpmLockDependencies },
42
+ { file: 'Cargo.lock', parse: parseCargoLockDependencies },
43
+ { file: 'poetry.lock', parse: parsePoetryLockDependencies },
44
+ ];
45
+ const LOCK_NAMES = new Set(LOCK_PARSERS.map((m) => m.file));
46
+ /** Read npm dependencies from a single package.json (kept for direct callers). */
47
+ export function readNpmDependencies(repoPath) {
48
+ const pkgPath = path.join(repoPath, 'package.json');
49
+ if (!fs.existsSync(pkgPath))
50
+ return [];
51
+ try {
52
+ return parseNpmDependencies(fs.readFileSync(pkgPath, 'utf-8')).map(toInputDep);
53
+ }
54
+ catch {
55
+ return [];
56
+ }
57
+ }
58
+ function toInputDep(d) {
59
+ return {
60
+ name: d.name,
61
+ version: d.version,
62
+ ecosystem: d.ecosystem,
63
+ scope: d.scope ?? 'required',
64
+ direct: true,
65
+ };
66
+ }
67
+ /**
68
+ * Collect the dependency set across all ecosystems. Per directory: a lockfile,
69
+ * when present, gives the full direct+transitive graph (and `direct` is set from
70
+ * the sibling manifest's declared names); otherwise the manifest gives the
71
+ * direct set. Aggregated across the repo (monorepo-aware) and deduped by
72
+ * `(ecosystem, name)` — a dep declared direct anywhere stays direct; a resolved
73
+ * version wins over an `unknown`.
74
+ */
75
+ export function readDependencies(repoPath) {
76
+ // Per-directory: manifest-declared names + parsed manifest/lock deps.
77
+ const perDir = new Map();
78
+ const dirOf = (d) => {
79
+ let v = perDir.get(d);
80
+ if (!v) {
81
+ v = { manifestNames: new Set(), fromManifest: [], fromLock: [] };
82
+ perDir.set(d, v);
83
+ }
84
+ return v;
85
+ };
86
+ const walk = (dir, depth) => {
87
+ if (depth > MAX_WALK_DEPTH)
88
+ return;
89
+ let entries;
90
+ try {
91
+ entries = fs.readdirSync(dir, { withFileTypes: true });
92
+ }
93
+ catch {
94
+ return;
95
+ }
96
+ for (const e of entries) {
97
+ const abs = path.join(dir, e.name);
98
+ if (e.isDirectory()) {
99
+ if (IGNORE_DIRS.has(e.name) || e.name.startsWith('.'))
100
+ continue;
101
+ walk(abs, depth + 1);
102
+ }
103
+ else if (e.isFile() && MANIFEST_NAMES.has(e.name)) {
104
+ const parser = MANIFEST_PARSERS.find((m) => m.file === e.name);
105
+ if (!parser)
106
+ continue;
107
+ try {
108
+ const deps = parser.parse(fs.readFileSync(abs, 'utf-8')).map(toInputDep);
109
+ const d = dirOf(dir);
110
+ for (const dep of deps) {
111
+ d.fromManifest.push(dep);
112
+ d.manifestNames.add(dep.name);
113
+ }
114
+ }
115
+ catch { /* skip unparseable manifest */ }
116
+ }
117
+ else if (e.isFile() && LOCK_NAMES.has(e.name)) {
118
+ const parser = LOCK_PARSERS.find((m) => m.file === e.name);
119
+ if (!parser)
120
+ continue;
121
+ try {
122
+ dirOf(dir).fromLock.push(...parser.parse(fs.readFileSync(abs, 'utf-8')).map(toInputDep));
123
+ }
124
+ catch { /* skip unparseable lockfile */ }
125
+ }
126
+ }
127
+ };
128
+ walk(repoPath, 0);
129
+ const byKey = new Map();
130
+ const upsert = (dep) => {
131
+ const key = `${dep.ecosystem}:${dep.name}`;
132
+ const existing = byKey.get(key);
133
+ if (!existing) {
134
+ byKey.set(key, dep);
135
+ return;
136
+ }
137
+ if (dep.direct && !existing.direct)
138
+ existing.direct = true;
139
+ if ((!existing.version || existing.version === 'unknown') && dep.version && dep.version !== 'unknown')
140
+ existing.version = dep.version;
141
+ };
142
+ for (const info of perDir.values()) {
143
+ if (info.fromLock.length > 0) {
144
+ // Lockfile wins: full graph, `direct` = declared in the sibling manifest.
145
+ for (const dep of info.fromLock) {
146
+ dep.direct = info.manifestNames.has(dep.name);
147
+ upsert(dep);
148
+ }
149
+ }
150
+ else {
151
+ for (const dep of info.fromManifest)
152
+ upsert(dep);
153
+ }
154
+ }
155
+ return [...byKey.values()];
156
+ }
157
+ /** Walk the repo (bounded) for L6 (config) + L8 (API spec) file components. */
158
+ export function detectFiles(repoPath) {
159
+ const found = [];
160
+ const rel = (p) => path.relative(repoPath, p) || path.basename(p);
161
+ const classifyFile = (abs, base) => {
162
+ const lower = base.toLowerCase();
163
+ if (lower === 'dockerfile' || lower.startsWith('dockerfile.'))
164
+ return { layer: 'L6', kind: 'container', path: rel(abs), name: base };
165
+ if (lower === 'docker-compose.yml' || lower === 'docker-compose.yaml')
166
+ return { layer: 'L6', kind: 'compose', path: rel(abs), name: base };
167
+ if (lower.endsWith('.graphql') || lower.endsWith('.graphqls'))
168
+ return { layer: 'L8', kind: 'graphql-schema', path: rel(abs), name: base };
169
+ if (lower.endsWith('.proto'))
170
+ return { layer: 'L8', kind: 'proto', path: rel(abs), name: base };
171
+ if (/^(openapi|swagger)\.(ya?ml|json)$/.test(lower))
172
+ return { layer: 'L8', kind: 'openapi-spec', path: rel(abs), name: base };
173
+ return null;
174
+ };
175
+ const walk = (dir, depth) => {
176
+ if (depth > MAX_WALK_DEPTH)
177
+ return;
178
+ let entries;
179
+ try {
180
+ entries = fs.readdirSync(dir, { withFileTypes: true });
181
+ }
182
+ catch {
183
+ return;
184
+ }
185
+ for (const e of entries) {
186
+ const abs = path.join(dir, e.name);
187
+ if (e.isDirectory()) {
188
+ if (e.name === '.github') {
189
+ const wf = path.join(abs, 'workflows');
190
+ for (const f of safeReaddir(wf)) {
191
+ if (/\.ya?ml$/i.test(f))
192
+ found.push({ layer: 'L6', kind: 'ci', path: rel(path.join(wf, f)), name: f });
193
+ }
194
+ continue;
195
+ }
196
+ if (IGNORE_DIRS.has(e.name) || e.name.startsWith('.'))
197
+ continue;
198
+ walk(abs, depth + 1);
199
+ }
200
+ else if (e.isFile()) {
201
+ const hit = classifyFile(abs, e.name);
202
+ if (hit)
203
+ found.push(hit);
204
+ }
205
+ }
206
+ };
207
+ walk(repoPath, 0);
208
+ return found;
209
+ }
210
+ function safeReaddir(dir) {
211
+ try {
212
+ return fs.readdirSync(dir);
213
+ }
214
+ catch {
215
+ return [];
216
+ }
217
+ }
218
+ /** Generate the layer-BOM for a repo (async: the usage index parses source). */
219
+ export async function generateBom(repoPath, opts = {}) {
220
+ const dependencies = opts.dependencies ?? readDependencies(repoPath);
221
+ const files = opts.skipFiles ? [] : detectFiles(repoPath);
222
+ const bom = assembleBom({ target: repoPath, dependencies, files });
223
+ if (opts.usage === false)
224
+ return bom;
225
+ // Usage index over the classified (L3/L5/L7) component names — the "which of
226
+ // your call-sites" set. L4-only supply-chain isn't usage-indexed (noise).
227
+ const classifiedLayers = ['L3', 'L5', 'L7'];
228
+ const names = [...new Set(classifiedLayers.flatMap((l) => bom.layers[l].components.map((c) => c.name)))];
229
+ const usageIndex = await buildUsageIndex(repoPath, names);
230
+ for (const layer of classifiedLayers) {
231
+ for (const c of bom.layers[layer].components) {
232
+ const sites = usageIndex[c.name];
233
+ if (sites) {
234
+ c.usageSites = sites;
235
+ c.usageCount = sites.length;
236
+ }
237
+ else {
238
+ c.usageCount = 0;
239
+ }
240
+ }
241
+ }
242
+ bom.usageIndex = usageIndex;
243
+ return bom;
244
+ }
245
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/bom/index.ts"],"names":[],"mappings":"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"}