@codeledger/aggregations 0.8.9

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 (50) hide show
  1. package/LICENSE +27 -0
  2. package/dist/engine.d.ts +4 -0
  3. package/dist/engine.d.ts.map +1 -0
  4. package/dist/engine.js +184 -0
  5. package/dist/engine.js.map +1 -0
  6. package/dist/hotspots.d.ts +7 -0
  7. package/dist/hotspots.d.ts.map +1 -0
  8. package/dist/hotspots.js +107 -0
  9. package/dist/hotspots.js.map +1 -0
  10. package/dist/index.d.ts +10 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +10 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/insights.d.ts +6 -0
  15. package/dist/insights.d.ts.map +1 -0
  16. package/dist/insights.js +89 -0
  17. package/dist/insights.js.map +1 -0
  18. package/dist/job.d.ts +9 -0
  19. package/dist/job.d.ts.map +1 -0
  20. package/dist/job.js +360 -0
  21. package/dist/job.js.map +1 -0
  22. package/dist/ownership.d.ts +4 -0
  23. package/dist/ownership.d.ts.map +1 -0
  24. package/dist/ownership.js +52 -0
  25. package/dist/ownership.js.map +1 -0
  26. package/dist/patterns.d.ts +3 -0
  27. package/dist/patterns.d.ts.map +1 -0
  28. package/dist/patterns.js +55 -0
  29. package/dist/patterns.js.map +1 -0
  30. package/dist/recommendations.d.ts +3 -0
  31. package/dist/recommendations.d.ts.map +1 -0
  32. package/dist/recommendations.js +33 -0
  33. package/dist/recommendations.js.map +1 -0
  34. package/dist/scheduler.d.ts +9 -0
  35. package/dist/scheduler.d.ts.map +1 -0
  36. package/dist/scheduler.js +19 -0
  37. package/dist/scheduler.js.map +1 -0
  38. package/dist/store.d.ts +6 -0
  39. package/dist/store.d.ts.map +1 -0
  40. package/dist/store.js +125 -0
  41. package/dist/store.js.map +1 -0
  42. package/dist/team-attribution.d.ts +9 -0
  43. package/dist/team-attribution.d.ts.map +1 -0
  44. package/dist/team-attribution.js +73 -0
  45. package/dist/team-attribution.js.map +1 -0
  46. package/dist/value.d.ts +11 -0
  47. package/dist/value.d.ts.map +1 -0
  48. package/dist/value.js +113 -0
  49. package/dist/value.js.map +1 -0
  50. package/package.json +39 -0
package/dist/store.js ADDED
@@ -0,0 +1,125 @@
1
+ import Database from 'better-sqlite3';
2
+ import { existsSync, mkdirSync, readFileSync } from 'node:fs';
3
+ import { join, dirname } from 'node:path';
4
+ const DB_NAME = 'insight.db';
5
+ const DB_CACHE = new Map();
6
+ function dbPath(repoRoot) {
7
+ return join(repoRoot, '.codeledger', 'insight', DB_NAME);
8
+ }
9
+ function ensureDb(repoRoot) {
10
+ if (DB_CACHE.has(repoRoot)) {
11
+ return DB_CACHE.get(repoRoot);
12
+ }
13
+ const path = dbPath(repoRoot);
14
+ mkdirSync(dirname(path), { recursive: true });
15
+ const db = new Database(path);
16
+ db.exec(`
17
+ CREATE TABLE IF NOT EXISTS events (
18
+ id TEXT PRIMARY KEY,
19
+ type TEXT,
20
+ timestamp TEXT,
21
+ repo TEXT,
22
+ team TEXT,
23
+ payload TEXT
24
+ );
25
+ CREATE TABLE IF NOT EXISTS snapshots (
26
+ generated_at TEXT PRIMARY KEY,
27
+ metrics TEXT,
28
+ value TEXT,
29
+ recommendations TEXT,
30
+ event_count INTEGER,
31
+ team TEXT,
32
+ filters TEXT
33
+ );
34
+ `);
35
+ DB_CACHE.set(repoRoot, db);
36
+ return db;
37
+ }
38
+ export function persistEvent(repoRoot, event) {
39
+ const db = ensureDb(repoRoot);
40
+ try {
41
+ const stmt = db.prepare(`
42
+ INSERT OR IGNORE INTO events (id, type, timestamp, repo, team, payload)
43
+ VALUES (?, ?, ?, ?, ?, ?)
44
+ `);
45
+ stmt.run(event.id, event.type, event.timestamp, event.repo, event.team ?? null, JSON.stringify(event));
46
+ }
47
+ catch {
48
+ // Non-fatal: telemetry should stay resilient
49
+ }
50
+ }
51
+ export function readEvents(repoRoot) {
52
+ const db = ensureDb(repoRoot);
53
+ const rows = db.prepare('SELECT payload FROM events ORDER BY timestamp').all();
54
+ const parsed = rows
55
+ .map((row) => {
56
+ try {
57
+ return JSON.parse(row.payload);
58
+ }
59
+ catch {
60
+ return undefined;
61
+ }
62
+ })
63
+ .filter((event) => Boolean(event));
64
+ if (parsed.length === 0) {
65
+ const legacy = readLegacyEvents(repoRoot);
66
+ for (const event of legacy) {
67
+ persistEvent(repoRoot, event);
68
+ }
69
+ return legacy;
70
+ }
71
+ return parsed;
72
+ }
73
+ function readLegacyEvents(repoRoot) {
74
+ const path = join(repoRoot, '.codeledger', 'insight', 'events.jsonl');
75
+ if (!existsSync(path))
76
+ return [];
77
+ return readFileSync(path, 'utf-8')
78
+ .split('\n')
79
+ .filter(Boolean)
80
+ .flatMap((line) => {
81
+ try {
82
+ return [JSON.parse(line)];
83
+ }
84
+ catch {
85
+ return [];
86
+ }
87
+ });
88
+ }
89
+ export function persistSnapshot(repoRoot, snapshot) {
90
+ const db = ensureDb(repoRoot);
91
+ try {
92
+ const stmt = db.prepare(`
93
+ INSERT OR REPLACE INTO snapshots
94
+ (generated_at, metrics, value, recommendations, event_count, team, filters)
95
+ VALUES (?, ?, ?, ?, ?, ?, ?)
96
+ `);
97
+ stmt.run(snapshot.generatedAt, JSON.stringify(snapshot.metrics), JSON.stringify(snapshot.value), JSON.stringify(snapshot.recommendations), snapshot.eventCount, snapshot.team ?? 'unattributed', JSON.stringify(snapshot.filters));
98
+ }
99
+ catch {
100
+ // non-fatal
101
+ }
102
+ }
103
+ export function readLatestSnapshot(repoRoot) {
104
+ const db = ensureDb(repoRoot);
105
+ const row = db
106
+ .prepare('SELECT * FROM snapshots ORDER BY generated_at DESC LIMIT 1')
107
+ .get();
108
+ if (!row)
109
+ return null;
110
+ try {
111
+ return {
112
+ generatedAt: row.generated_at,
113
+ eventCount: row.event_count,
114
+ filters: JSON.parse(row.filters),
115
+ metrics: JSON.parse(row.metrics),
116
+ value: JSON.parse(row.value),
117
+ recommendations: JSON.parse(row.recommendations),
118
+ team: row.team,
119
+ };
120
+ }
121
+ catch {
122
+ return null;
123
+ }
124
+ }
125
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { InsightEvent, AttributionSource } from '@codeledger/types';
2
+ interface AttributionResult {
3
+ team?: string;
4
+ source: AttributionSource;
5
+ }
6
+ export declare function resolveTeamAttribution(repoRoot: string, event: InsightEvent): AttributionResult;
7
+ export declare function determineTeam(repoRoot: string, event: InsightEvent): string | undefined;
8
+ export {};
9
+ //# sourceMappingURL=team-attribution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-attribution.d.ts","sourceRoot":"","sources":["../src/team-attribution.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAuDhG,UAAU,iBAAiB;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,iBAAiB,CAAC;CAC3B;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,iBAAiB,CAgB/F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAEvF"}
@@ -0,0 +1,73 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { matchOwnershipTeam, loadOwnershipMap } from './ownership.js';
4
+ const CONFIG_CACHE = new Map();
5
+ function loadConfig(repoRoot) {
6
+ if (CONFIG_CACHE.has(repoRoot)) {
7
+ return CONFIG_CACHE.get(repoRoot);
8
+ }
9
+ const configPath = join(repoRoot, '.codeledger', 'config.json');
10
+ let config = {};
11
+ if (existsSync(configPath)) {
12
+ try {
13
+ const raw = JSON.parse(readFileSync(configPath, 'utf-8'));
14
+ if (raw?.attribution) {
15
+ config = raw.attribution;
16
+ }
17
+ }
18
+ catch {
19
+ // ignore malformed config; attribution stays empty
20
+ }
21
+ }
22
+ CONFIG_CACHE.set(repoRoot, config);
23
+ return config;
24
+ }
25
+ function matchPath(paths, mapping) {
26
+ if (!paths.length)
27
+ return undefined;
28
+ const prefixes = Object.keys(mapping).sort((a, b) => b.length - a.length);
29
+ for (const path of paths) {
30
+ for (const prefix of prefixes) {
31
+ if (path.startsWith(prefix)) {
32
+ return mapping[prefix];
33
+ }
34
+ }
35
+ }
36
+ return undefined;
37
+ }
38
+ function eventPaths(event) {
39
+ switch (event.type) {
40
+ case 'CONTEXT_EVALUATION':
41
+ return event.files;
42
+ case 'PATTERN_REUSE':
43
+ return [...event.sourceFiles, ...event.targetFiles];
44
+ case 'GOLDEN_PATH_ADHERENCE':
45
+ return [event.path];
46
+ case 'SHADOW_KNOWLEDGE_SIGNAL':
47
+ return event.files;
48
+ default:
49
+ return [];
50
+ }
51
+ }
52
+ export function resolveTeamAttribution(repoRoot, event) {
53
+ if (event.team)
54
+ return { team: event.team, source: 'explicit' };
55
+ const attribution = loadConfig(repoRoot);
56
+ if (attribution.repo_team)
57
+ return { team: attribution.repo_team, source: 'repoConfig' };
58
+ const paths = eventPaths(event);
59
+ if (attribution.path_map) {
60
+ const matched = matchPath(paths, attribution.path_map);
61
+ if (matched)
62
+ return { team: matched, source: 'pathMap' };
63
+ }
64
+ const ownershipMap = loadOwnershipMap(repoRoot, attribution);
65
+ const fromOwnership = matchOwnershipTeam(paths, ownershipMap);
66
+ if (fromOwnership)
67
+ return { team: fromOwnership, source: 'ownershipFile' };
68
+ return { source: 'fallback' };
69
+ }
70
+ export function determineTeam(repoRoot, event) {
71
+ return resolveTeamAttribution(repoRoot, event).team;
72
+ }
73
+ //# sourceMappingURL=team-attribution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"team-attribution.js","sourceRoot":"","sources":["../src/team-attribution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { InsightMetrics, ValueAssumptions, ValueConfidence, ValueSummary } from '@codeledger/types';
2
+ /**
3
+ * computeValue captures the value model:
4
+ * estimatedSavings = cost_per_hour × (Rework avoided hours + Context recovery hours + Pattern leverage hours)
5
+ */
6
+ export declare function computeValue(metrics: InsightMetrics, assumptions?: ValueAssumptions): ValueSummary;
7
+ export declare function computeReworkAvoidedHours(base: number, reworkRatio: number, multiplier: number): number;
8
+ export declare function computeContextRecoveryHours(base: number, timeToContext: number): number;
9
+ export declare function computePatternLeverageHours(base: number, patternReuseRate: number): number;
10
+ export declare function deriveValueConfidence(eventCount: number): ValueConfidence;
11
+ //# sourceMappingURL=value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value.d.ts","sourceRoot":"","sources":["../src/value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,gBAAgB,EAEhB,eAAe,EAEf,YAAY,EACb,MAAM,mBAAmB,CAAC;AA4B3B;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,cAAc,EACvB,WAAW,GAAE,gBAAsC,GAClD,YAAY,CAwDd;AAED,wBAAgB,yBAAyB,CACvC,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAGvF;AAED,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAIzE"}
package/dist/value.js ADDED
@@ -0,0 +1,113 @@
1
+ const DEFAULT_ASSUMPTIONS = {
2
+ cost_per_hour: 150,
3
+ rework_multiplier: 1.2,
4
+ };
5
+ /**
6
+ * Component multipliers convert base executions into estimated developer-hours saved.
7
+ *
8
+ * REWORK_HOURS_MULTIPLIER (0.20):
9
+ * Each non-reworked execution saves ~12 minutes (0.2h) of developer time on average.
10
+ * Derived from empirical rework cost studies: a rework cycle consumes 20-30% of
11
+ * original effort. We use the conservative lower bound after applying the rework_multiplier.
12
+ *
13
+ * CONTEXT_HOURS_MULTIPLIER (0.08):
14
+ * Each execution with fast context recovery saves ~5 minutes (0.08h). Represents
15
+ * the reduction in context-switching overhead when timeToContext is low relative
16
+ * to the 10-minute baseline (a full manual context rebuild).
17
+ *
18
+ * PATTERN_HOURS_MULTIPLIER (0.12):
19
+ * Each execution leveraging an existing pattern saves ~7 minutes (0.12h). Captures
20
+ * the value of not re-inventing solutions: lookup + adapt vs. design + implement.
21
+ */
22
+ const REWORK_HOURS_MULTIPLIER = 0.2;
23
+ const CONTEXT_HOURS_MULTIPLIER = 0.08;
24
+ const PATTERN_HOURS_MULTIPLIER = 0.12;
25
+ /**
26
+ * computeValue captures the value model:
27
+ * estimatedSavings = cost_per_hour × (Rework avoided hours + Context recovery hours + Pattern leverage hours)
28
+ */
29
+ export function computeValue(metrics, assumptions = DEFAULT_ASSUMPTIONS) {
30
+ const baseExecutions = Math.max(1, metrics.quality.executionReliability.denominator);
31
+ const reworkAvoidedHours = computeReworkAvoidedHours(baseExecutions, metrics.quality.reworkRatio.value, assumptions.rework_multiplier);
32
+ const contextRecoveryHours = computeContextRecoveryHours(baseExecutions, metrics.knowledge.timeToContext.value);
33
+ const patternLeverageHours = computePatternLeverageHours(baseExecutions, metrics.knowledge.patternReuseRate.value);
34
+ const estimatedSavings = (reworkAvoidedHours + contextRecoveryHours + patternLeverageHours) * assumptions.cost_per_hour;
35
+ const derivation = [
36
+ {
37
+ label: 'Rework reduction',
38
+ hours: reworkAvoidedHours,
39
+ formula: 'executions × (1 - reworkRatio) × rework_multiplier × 0.20',
40
+ inputs: {
41
+ executions: baseExecutions,
42
+ reworkRatio: metrics.quality.reworkRatio.value,
43
+ rework_multiplier: assumptions.rework_multiplier,
44
+ multiplier: REWORK_HOURS_MULTIPLIER,
45
+ },
46
+ },
47
+ {
48
+ label: 'Context recovery',
49
+ hours: contextRecoveryHours,
50
+ formula: 'executions × max(0, 1 - timeToContext / 10) × 0.08',
51
+ inputs: {
52
+ executions: baseExecutions,
53
+ timeToContext: metrics.knowledge.timeToContext.value,
54
+ baseline_minutes: 10,
55
+ multiplier: CONTEXT_HOURS_MULTIPLIER,
56
+ },
57
+ },
58
+ {
59
+ label: 'Pattern leverage',
60
+ hours: patternLeverageHours,
61
+ formula: 'executions × patternReuseRate × 0.12',
62
+ inputs: {
63
+ executions: baseExecutions,
64
+ patternReuseRate: metrics.knowledge.patternReuseRate.value,
65
+ multiplier: PATTERN_HOURS_MULTIPLIER,
66
+ },
67
+ },
68
+ ];
69
+ return {
70
+ estimatedSavings,
71
+ reworkAvoidedHours,
72
+ contextRecoveryHours,
73
+ patternLeverageHours,
74
+ assumptions,
75
+ confidence: deriveValueConfidence(metrics.overview.eventCount),
76
+ scope: buildScopeContext(metrics.overview),
77
+ derivation,
78
+ };
79
+ }
80
+ export function computeReworkAvoidedHours(base, reworkRatio, multiplier) {
81
+ return base * (1 - reworkRatio) * multiplier * REWORK_HOURS_MULTIPLIER;
82
+ }
83
+ export function computeContextRecoveryHours(base, timeToContext) {
84
+ const contextFactor = Math.max(0, 1 - timeToContext / 10);
85
+ return base * contextFactor * CONTEXT_HOURS_MULTIPLIER;
86
+ }
87
+ export function computePatternLeverageHours(base, patternReuseRate) {
88
+ return base * patternReuseRate * PATTERN_HOURS_MULTIPLIER;
89
+ }
90
+ export function deriveValueConfidence(eventCount) {
91
+ if (eventCount >= 40)
92
+ return 'high';
93
+ if (eventCount >= 15)
94
+ return 'medium';
95
+ return 'low';
96
+ }
97
+ function buildScopeContext(overview) {
98
+ let range = 'Rolling 30-day window';
99
+ if (overview.trend.length > 1) {
100
+ const first = overview.trend[0];
101
+ const last = overview.trend[overview.trend.length - 1];
102
+ if (first && last) {
103
+ range = `${first.date} ↔ ${last.date}`;
104
+ }
105
+ }
106
+ return {
107
+ windowLabel: range,
108
+ executions: overview.eventCount,
109
+ repos: overview.repos.length,
110
+ teams: overview.teams,
111
+ };
112
+ }
113
+ //# sourceMappingURL=value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value.js","sourceRoot":"","sources":["../src/value.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@codeledger/aggregations",
3
+ "version": "0.8.9",
4
+ "type": "module",
5
+ "description": "Insight aggregation engine for CodeLedger",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/codeledgerECF/codeledger.git",
10
+ "directory": "packages/aggregations"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "main": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ }
25
+ },
26
+ "dependencies": {
27
+ "better-sqlite3": "^11.10.0",
28
+ "@codeledger/types": "0.8.9"
29
+ },
30
+ "devDependencies": {
31
+ "@types/better-sqlite3": "^7.6.0",
32
+ "typescript": "^5.4.0"
33
+ },
34
+ "scripts": {
35
+ "build": "tsc",
36
+ "typecheck": "tsc --noEmit",
37
+ "clean": "rm -rf dist"
38
+ }
39
+ }