openlore 2.0.0 → 2.0.2

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 (105) hide show
  1. package/README.md +76 -0
  2. package/dist/cli/commands/decisions.d.ts.map +1 -1
  3. package/dist/cli/commands/decisions.js +21 -3
  4. package/dist/cli/commands/decisions.js.map +1 -1
  5. package/dist/cli/commands/mcp.d.ts.map +1 -1
  6. package/dist/cli/commands/mcp.js +56 -5
  7. package/dist/cli/commands/mcp.js.map +1 -1
  8. package/dist/cli/commands/telemetry.d.ts +11 -0
  9. package/dist/cli/commands/telemetry.d.ts.map +1 -0
  10. package/dist/cli/commands/telemetry.js +373 -0
  11. package/dist/cli/commands/telemetry.js.map +1 -0
  12. package/dist/cli/index.js +17 -9
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/cli/install/adapters/agents-md.d.ts +8 -0
  15. package/dist/cli/install/adapters/agents-md.d.ts.map +1 -0
  16. package/dist/cli/install/adapters/agents-md.js +21 -0
  17. package/dist/cli/install/adapters/agents-md.js.map +1 -0
  18. package/dist/cli/install/adapters/claude-code.d.ts +8 -0
  19. package/dist/cli/install/adapters/claude-code.d.ts.map +1 -0
  20. package/dist/cli/install/adapters/claude-code.js +184 -0
  21. package/dist/cli/install/adapters/claude-code.js.map +1 -0
  22. package/dist/cli/install/adapters/cline.d.ts +6 -0
  23. package/dist/cli/install/adapters/cline.d.ts.map +1 -0
  24. package/dist/cli/install/adapters/cline.js +19 -0
  25. package/dist/cli/install/adapters/cline.js.map +1 -0
  26. package/dist/cli/install/adapters/continue.d.ts +13 -0
  27. package/dist/cli/install/adapters/continue.d.ts.map +1 -0
  28. package/dist/cli/install/adapters/continue.js +119 -0
  29. package/dist/cli/install/adapters/continue.js.map +1 -0
  30. package/dist/cli/install/adapters/cursor.d.ts +8 -0
  31. package/dist/cli/install/adapters/cursor.d.ts.map +1 -0
  32. package/dist/cli/install/adapters/cursor.js +195 -0
  33. package/dist/cli/install/adapters/cursor.js.map +1 -0
  34. package/dist/cli/install/adapters/markdown-block.d.ts +20 -0
  35. package/dist/cli/install/adapters/markdown-block.d.ts.map +1 -0
  36. package/dist/cli/install/adapters/markdown-block.js +114 -0
  37. package/dist/cli/install/adapters/markdown-block.js.map +1 -0
  38. package/dist/cli/install/adapters/types.d.ts +39 -0
  39. package/dist/cli/install/adapters/types.d.ts.map +1 -0
  40. package/dist/cli/install/adapters/types.js +10 -0
  41. package/dist/cli/install/adapters/types.js.map +1 -0
  42. package/dist/cli/install/block.d.ts +53 -0
  43. package/dist/cli/install/block.d.ts.map +1 -0
  44. package/dist/cli/install/block.js +106 -0
  45. package/dist/cli/install/block.js.map +1 -0
  46. package/dist/cli/install/detect.d.ts +23 -0
  47. package/dist/cli/install/detect.d.ts.map +1 -0
  48. package/dist/cli/install/detect.js +115 -0
  49. package/dist/cli/install/detect.js.map +1 -0
  50. package/dist/cli/install/diff.d.ts +12 -0
  51. package/dist/cli/install/diff.d.ts.map +1 -0
  52. package/dist/cli/install/diff.js +51 -0
  53. package/dist/cli/install/diff.js.map +1 -0
  54. package/dist/cli/install/index.d.ts +19 -0
  55. package/dist/cli/install/index.d.ts.map +1 -0
  56. package/dist/cli/install/index.js +133 -0
  57. package/dist/cli/install/index.js.map +1 -0
  58. package/dist/cli/install/json-managed.d.ts +43 -0
  59. package/dist/cli/install/json-managed.d.ts.map +1 -0
  60. package/dist/cli/install/json-managed.js +137 -0
  61. package/dist/cli/install/json-managed.js.map +1 -0
  62. package/dist/cli/install/templates/agent-instructions.md +12 -0
  63. package/dist/cli/install/templates/cursor-openlore.mdc +7 -0
  64. package/dist/cli/preflight/diff.d.ts +42 -0
  65. package/dist/cli/preflight/diff.d.ts.map +1 -0
  66. package/dist/cli/preflight/diff.js +162 -0
  67. package/dist/cli/preflight/diff.js.map +1 -0
  68. package/dist/cli/preflight/index.d.ts +31 -0
  69. package/dist/cli/preflight/index.d.ts.map +1 -0
  70. package/dist/cli/preflight/index.js +126 -0
  71. package/dist/cli/preflight/index.js.map +1 -0
  72. package/dist/cli/preflight/report.d.ts +50 -0
  73. package/dist/cli/preflight/report.d.ts.map +1 -0
  74. package/dist/cli/preflight/report.js +174 -0
  75. package/dist/cli/preflight/report.js.map +1 -0
  76. package/dist/cli/preflight/score.d.ts +43 -0
  77. package/dist/cli/preflight/score.d.ts.map +1 -0
  78. package/dist/cli/preflight/score.js +102 -0
  79. package/dist/cli/preflight/score.js.map +1 -0
  80. package/dist/core/analyzer/file-walker.d.ts.map +1 -1
  81. package/dist/core/analyzer/file-walker.js +20 -13
  82. package/dist/core/analyzer/file-walker.js.map +1 -1
  83. package/dist/core/analyzer/vector-index.d.ts +2 -0
  84. package/dist/core/analyzer/vector-index.d.ts.map +1 -1
  85. package/dist/core/analyzer/vector-index.js +30 -20
  86. package/dist/core/analyzer/vector-index.js.map +1 -1
  87. package/dist/core/services/mcp-handlers/decisions.d.ts.map +1 -1
  88. package/dist/core/services/mcp-handlers/decisions.js +4 -0
  89. package/dist/core/services/mcp-handlers/decisions.js.map +1 -1
  90. package/dist/core/services/mcp-handlers/epistemic-lease.d.ts +67 -0
  91. package/dist/core/services/mcp-handlers/epistemic-lease.d.ts.map +1 -0
  92. package/dist/core/services/mcp-handlers/epistemic-lease.js +431 -0
  93. package/dist/core/services/mcp-handlers/epistemic-lease.js.map +1 -0
  94. package/dist/core/services/mcp-handlers/utils.d.ts +2 -0
  95. package/dist/core/services/mcp-handlers/utils.d.ts.map +1 -1
  96. package/dist/core/services/mcp-handlers/utils.js +21 -2
  97. package/dist/core/services/mcp-handlers/utils.js.map +1 -1
  98. package/dist/core/services/telemetry.d.ts +16 -0
  99. package/dist/core/services/telemetry.d.ts.map +1 -0
  100. package/dist/core/services/telemetry.js +38 -0
  101. package/dist/core/services/telemetry.js.map +1 -0
  102. package/examples/ci/openlore-preflight.gitlab.yml +16 -0
  103. package/examples/ci/openlore-preflight.sh +16 -0
  104. package/examples/ci/openlore-preflight.yml +30 -0
  105. package/package.json +4 -2
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Compute the set of source files that have changed since the graph was built.
3
+ *
4
+ * Two paths:
5
+ *
6
+ * 1. `--since <git-ref>` (CI-friendly) — `git diff --name-only <ref>...HEAD`
7
+ * plus uncommitted modifications. The merge-base form is intentional:
8
+ * it captures every file the PR touched, not just the latest commit.
9
+ *
10
+ * 2. No `--since` flag — fall back to comparing file mtimes against
11
+ * `fingerprint.json.computedAt`. Slower but works without git history.
12
+ *
13
+ * Either path returns paths relative to the repo root. Non-source files
14
+ * (anything not tracked by the analyzer's language config) are filtered out
15
+ * by the caller via the node table.
16
+ */
17
+ import { execFile } from 'node:child_process';
18
+ import { promisify } from 'node:util';
19
+ import { stat, readdir, readFile, access } from 'node:fs/promises';
20
+ import { join, relative, resolve, sep } from 'node:path';
21
+ import { OPENLORE_DIR } from '../../constants.js';
22
+ const execFileAsync = promisify(execFile);
23
+ export async function hasGitDirectory(repoRoot) {
24
+ try {
25
+ await access(join(repoRoot, '.git'));
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ async function runGit(repoRoot, args) {
33
+ const { stdout } = await execFileAsync('git', args, { cwd: repoRoot });
34
+ return stdout;
35
+ }
36
+ export async function refExists(repoRoot, ref) {
37
+ try {
38
+ await runGit(repoRoot, ['rev-parse', '--verify', '--quiet', ref]);
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ }
45
+ async function shortHead(repoRoot) {
46
+ try {
47
+ return (await runGit(repoRoot, ['rev-parse', '--short', 'HEAD'])).trim();
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ }
53
+ /** Changed files via git diff against `since`, plus uncommitted modifications. */
54
+ async function diffViaGit(repoRoot, since) {
55
+ // Use ...HEAD (merge-base) so we capture every file the PR touched relative
56
+ // to the branch point, not just the latest commit's diff.
57
+ const tracked = (await runGit(repoRoot, ['diff', '--name-only', `${since}...HEAD`]))
58
+ .split('\n')
59
+ .filter(Boolean);
60
+ // Include uncommitted modifications so a developer running locally before
61
+ // committing also gets honest feedback.
62
+ const uncommitted = (await runGit(repoRoot, ['diff', '--name-only', 'HEAD']))
63
+ .split('\n')
64
+ .filter(Boolean);
65
+ const set = new Set([...tracked, ...uncommitted]);
66
+ return Array.from(set).sort();
67
+ }
68
+ /** Changed files via mtime comparison against graphBuiltAtMs. */
69
+ async function diffViaMtime(repoRoot, graphBuiltAtMs) {
70
+ const out = [];
71
+ await walk(repoRoot, repoRoot, graphBuiltAtMs, out);
72
+ return out.sort();
73
+ }
74
+ const SKIP_DIRECTORIES = new Set([
75
+ 'node_modules',
76
+ 'dist',
77
+ 'build',
78
+ 'out',
79
+ 'coverage',
80
+ OPENLORE_DIR,
81
+ '.git',
82
+ ]);
83
+ async function walk(repoRoot, dir, cutoffMs, out) {
84
+ let entries;
85
+ try {
86
+ entries = await readdir(dir, { withFileTypes: true });
87
+ }
88
+ catch {
89
+ return;
90
+ }
91
+ for (const ent of entries) {
92
+ if (ent.name.startsWith('.') && ent.name !== '.gitignore')
93
+ continue;
94
+ if (SKIP_DIRECTORIES.has(ent.name))
95
+ continue;
96
+ const full = join(dir, ent.name);
97
+ if (ent.isDirectory()) {
98
+ await walk(repoRoot, full, cutoffMs, out);
99
+ continue;
100
+ }
101
+ if (!ent.isFile())
102
+ continue;
103
+ try {
104
+ const s = await stat(full);
105
+ if (s.mtimeMs > cutoffMs) {
106
+ out.push(relative(repoRoot, full).split(sep).join('/'));
107
+ }
108
+ }
109
+ catch {
110
+ /* unreadable file — skip */
111
+ }
112
+ }
113
+ }
114
+ export async function computeDiff(opts) {
115
+ const root = resolve(opts.repoRoot);
116
+ const warnings = [];
117
+ const workingCommit = await shortHead(root);
118
+ const gitAvailable = await hasGitDirectory(root);
119
+ if (opts.since) {
120
+ if (!gitAvailable) {
121
+ throw Object.assign(new Error(`--since requires a git repository`), { exitCode: 2 });
122
+ }
123
+ if (!(await refExists(root, opts.since))) {
124
+ throw Object.assign(new Error(`git ref not found: ${opts.since}`), { exitCode: 2 });
125
+ }
126
+ const changed = await diffViaGit(root, opts.since);
127
+ return { changed, mechanism: 'git', warnings, workingCommit };
128
+ }
129
+ if (!gitAvailable) {
130
+ warnings.push('no .git found — falling back to mtime comparison');
131
+ }
132
+ if (!opts.graphBuiltAt) {
133
+ warnings.push('graph has no build timestamp — everything will look stale');
134
+ // Treat as "everything changed since epoch" — caller can decide.
135
+ const changed = await diffViaMtime(root, 0);
136
+ return { changed, mechanism: 'mtime', warnings, workingCommit };
137
+ }
138
+ const cutoff = Date.parse(opts.graphBuiltAt);
139
+ if (Number.isNaN(cutoff)) {
140
+ warnings.push(`graph build timestamp unparseable: ${opts.graphBuiltAt}`);
141
+ const changed = await diffViaMtime(root, 0);
142
+ return { changed, mechanism: 'mtime', warnings, workingCommit };
143
+ }
144
+ const changed = await diffViaMtime(root, cutoff);
145
+ return { changed, mechanism: 'mtime', warnings, workingCommit };
146
+ }
147
+ /** Read `fingerprint.json` if present. */
148
+ export async function readGraphFingerprint(repoRoot) {
149
+ const path = join(repoRoot, OPENLORE_DIR, 'analysis', 'fingerprint.json');
150
+ try {
151
+ const raw = await readFile(path, 'utf8');
152
+ const parsed = JSON.parse(raw);
153
+ return {
154
+ computedAt: parsed.computedAt ?? null,
155
+ fileCount: typeof parsed.fileCount === 'number' ? parsed.fileCount : null,
156
+ };
157
+ }
158
+ catch {
159
+ return null;
160
+ }
161
+ }
162
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/cli/preflight/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * `openlore preflight` — CI staleness gate.
3
+ *
4
+ * Determines whether the persisted analysis graph is current relative to
5
+ * the working tree. Designed to run on every PR so out-of-date graphs
6
+ * never reach orient() / agent runtime silently.
7
+ *
8
+ * Exit codes: 0 = fresh, 1 = stale, 2 = error.
9
+ */
10
+ import { Command } from 'commander';
11
+ import { type PreflightSummary } from './report.js';
12
+ export interface PreflightOptions {
13
+ cwd?: string;
14
+ fix?: boolean;
15
+ json?: boolean;
16
+ since?: string;
17
+ maxStaleness?: number;
18
+ /**
19
+ * Test-only seam: replace the analyzer invocation used by --fix. Returns
20
+ * the exit code (0 = success). Production code spawns `openlore analyze`;
21
+ * tests pass a stub that simulates the side-effect (refreshing
22
+ * fingerprint.json) without needing the full pipeline.
23
+ */
24
+ analyzeFn?: (cwd: string) => Promise<number>;
25
+ }
26
+ export declare function runPreflight(opts: PreflightOptions): Promise<{
27
+ code: number;
28
+ summary?: PreflightSummary;
29
+ }>;
30
+ export declare const preflightCommand: Command;
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/preflight/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,OAAO,EAKL,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC9C;AAID,wBAAsB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC;IAClE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,gBAAgB,CAAC;CAC5B,CAAC,CAgGD;AAeD,eAAO,MAAM,gBAAgB,SAczB,CAAC"}
@@ -0,0 +1,126 @@
1
+ /**
2
+ * `openlore preflight` — CI staleness gate.
3
+ *
4
+ * Determines whether the persisted analysis graph is current relative to
5
+ * the working tree. Designed to run on every PR so out-of-date graphs
6
+ * never reach orient() / agent runtime silently.
7
+ *
8
+ * Exit codes: 0 = fresh, 1 = stale, 2 = error.
9
+ */
10
+ import { access } from 'node:fs/promises';
11
+ import { join, resolve } from 'node:path';
12
+ import { spawn } from 'node:child_process';
13
+ import { Command } from 'commander';
14
+ import { logger } from '../../utils/logger.js';
15
+ import { OPENLORE_DIR, OPENLORE_ANALYSIS_SUBDIR, ARTIFACT_CALL_GRAPH_DB, } from '../../constants.js';
16
+ import { computeDiff, readGraphFingerprint } from './diff.js';
17
+ import { scoreChangedFiles } from './score.js';
18
+ import { buildSummary, renderHuman, renderJson, renderGithubAnnotations, } from './report.js';
19
+ const DEFAULT_THRESHOLD = 0;
20
+ export async function runPreflight(opts) {
21
+ const cwd = resolve(opts.cwd ?? process.cwd());
22
+ const threshold = typeof opts.maxStaleness === 'number' ? opts.maxStaleness : DEFAULT_THRESHOLD;
23
+ // 1. Graph must exist.
24
+ const dbPath = join(cwd, OPENLORE_DIR, OPENLORE_ANALYSIS_SUBDIR, ARTIFACT_CALL_GRAPH_DB);
25
+ try {
26
+ await access(dbPath);
27
+ }
28
+ catch {
29
+ if (opts.json) {
30
+ process.stdout.write(JSON.stringify({
31
+ status: 'ERROR',
32
+ error: 'no graph found',
33
+ hint: 'run `openlore analyze` first',
34
+ }, null, 2) + '\n');
35
+ }
36
+ else {
37
+ logger.error('No graph found. Run `openlore analyze` first to build the analysis graph.');
38
+ }
39
+ return { code: 2 };
40
+ }
41
+ // 2. Read graph metadata.
42
+ const fp = await readGraphFingerprint(cwd);
43
+ const graphBuiltAt = fp?.computedAt ?? null;
44
+ // We don't store the build commit today — leave null. Once analyze records
45
+ // it, this is the single place to surface it. (See TODO in docs/preflight.md.)
46
+ const graphCommit = null;
47
+ // 3. Compute changed files.
48
+ let diff;
49
+ try {
50
+ diff = await computeDiff({ repoRoot: cwd, graphBuiltAt, since: opts.since });
51
+ }
52
+ catch (err) {
53
+ const e = err;
54
+ if (opts.json) {
55
+ process.stdout.write(JSON.stringify({ status: 'ERROR', error: e.message }, null, 2) + '\n');
56
+ }
57
+ else {
58
+ logger.error(e.message);
59
+ }
60
+ return { code: e.exitCode ?? 2 };
61
+ }
62
+ // 4. Score.
63
+ const score = scoreChangedFiles(cwd, diff.changed);
64
+ // 5. Build summary.
65
+ const summary = buildSummary({ diff, score, graphBuiltAt, graphCommit, threshold });
66
+ const stale = summary.stalenessScore > threshold;
67
+ // 6. --fix path runs `openlore analyze` then re-checks.
68
+ if (stale && opts.fix) {
69
+ if (!opts.json)
70
+ logger.discovery('Stale graph detected — running `openlore analyze --fix`');
71
+ const code = await (opts.analyzeFn ?? runAnalyzeFix)(cwd);
72
+ if (code !== 0) {
73
+ if (opts.json) {
74
+ process.stdout.write(JSON.stringify({ status: 'ERROR', error: 'openlore analyze --fix failed' }, null, 2) +
75
+ '\n');
76
+ }
77
+ else {
78
+ logger.error('openlore analyze failed during --fix; manual intervention required');
79
+ }
80
+ return { code: 2 };
81
+ }
82
+ // Re-run preflight WITHOUT --fix and WITHOUT --since (now everything
83
+ // should be current vs. the freshly built graph).
84
+ return runPreflight({
85
+ cwd,
86
+ json: opts.json,
87
+ maxStaleness: opts.maxStaleness,
88
+ analyzeFn: opts.analyzeFn,
89
+ });
90
+ }
91
+ // 7. Render.
92
+ if (opts.json) {
93
+ process.stdout.write(renderJson(summary) + '\n');
94
+ }
95
+ else {
96
+ process.stdout.write(renderHuman(summary) + '\n');
97
+ }
98
+ // 8. GitHub Actions inline annotations (no-op outside GHA).
99
+ const annotations = renderGithubAnnotations(summary);
100
+ if (annotations)
101
+ process.stdout.write(annotations + '\n');
102
+ return { code: stale ? 1 : 0, summary };
103
+ }
104
+ async function runAnalyzeFix(cwd) {
105
+ return new Promise((resolveProm) => {
106
+ // TODO(spec-03-followup): when `openlore analyze --incremental` exists,
107
+ // prefer that — it should be a fraction of the cost of the full re-run.
108
+ const child = spawn(process.execPath, [process.argv[1], 'analyze'], {
109
+ cwd,
110
+ stdio: 'inherit',
111
+ });
112
+ child.on('exit', (code) => resolveProm(code ?? 1));
113
+ child.on('error', () => resolveProm(1));
114
+ });
115
+ }
116
+ export const preflightCommand = new Command('preflight')
117
+ .description('CI staleness gate: check whether the analysis graph is current relative to the working tree.')
118
+ .option('--fix', 'Run `openlore analyze` if the graph is stale, then re-check', false)
119
+ .option('--json', 'Emit JSON instead of human-readable output', false)
120
+ .option('--since <ref>', 'Diff against this git ref (e.g. origin/main) instead of mtimes')
121
+ .option('--max-staleness <n>', `Maximum allowed staleness score (default ${DEFAULT_THRESHOLD})`, (v) => parseInt(v, 10), DEFAULT_THRESHOLD)
122
+ .action(async (opts) => {
123
+ const { code } = await runPreflight(opts);
124
+ process.exit(code);
125
+ });
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/preflight/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Human-readable + JSON renderers for preflight results.
3
+ */
4
+ import type { DiffResult } from './diff.js';
5
+ import type { ScoreResult } from './score.js';
6
+ export type PreflightStatus = 'FRESH' | 'STALE' | 'ERROR';
7
+ export interface PerFileEntry {
8
+ filePath: string;
9
+ weight: number;
10
+ hub: boolean;
11
+ /** Highest fan-in across nodes in the file (for "why is this a hub"). */
12
+ maxFanIn: number;
13
+ /** True if the file isn't represented in the graph at all. */
14
+ unknown: boolean;
15
+ }
16
+ export interface PreflightSummary {
17
+ status: PreflightStatus;
18
+ graphBuiltAt: string | null;
19
+ graphCommit: string | null;
20
+ workingCommit: string | null;
21
+ changedFiles: string[];
22
+ unknownFiles: string[];
23
+ /** Per-file detail with weight + hub flag. Same order as `changedFiles`. */
24
+ perFile: PerFileEntry[];
25
+ hubCount: number;
26
+ leafCount: number;
27
+ stalenessScore: number;
28
+ threshold: number;
29
+ mechanism: 'git' | 'mtime';
30
+ warnings: string[];
31
+ message: string;
32
+ }
33
+ export interface BuildSummaryInput {
34
+ diff: DiffResult;
35
+ score: ScoreResult;
36
+ graphBuiltAt: string | null;
37
+ graphCommit: string | null;
38
+ threshold: number;
39
+ }
40
+ export declare function buildSummary(input: BuildSummaryInput): PreflightSummary;
41
+ export declare function renderHuman(s: PreflightSummary): string;
42
+ /**
43
+ * Emit GitHub Actions workflow-command annotations so that stale files
44
+ * appear inline in the PR diff UI when this runs in CI. No-op outside of
45
+ * GHA. Format docs:
46
+ * https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions
47
+ */
48
+ export declare function renderGithubAnnotations(s: PreflightSummary): string;
49
+ export declare function renderJson(s: PreflightSummary): string;
50
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../../src/cli/preflight/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,eAAe,CAAC;IACxB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,4EAA4E;IAC5E,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,KAAK,GAAG,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,WAAW,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,CA8CvE;AAMD,wBAAgB,WAAW,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAmDvD;AAcD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CAmBnE;AAMD,wBAAgB,UAAU,CAAC,CAAC,EAAE,gBAAgB,GAAG,MAAM,CA4BtD"}
@@ -0,0 +1,174 @@
1
+ /**
2
+ * Human-readable + JSON renderers for preflight results.
3
+ */
4
+ export function buildSummary(input) {
5
+ const { diff, score, graphBuiltAt, graphCommit, threshold } = input;
6
+ const totalChanged = diff.changed.length;
7
+ const stale = score.totalScore > threshold;
8
+ const status = stale ? 'STALE' : 'FRESH';
9
+ let message;
10
+ if (totalChanged === 0) {
11
+ message = 'nothing to check — no changed files since graph build';
12
+ }
13
+ else if (stale) {
14
+ message = `STALE — run \`openlore analyze\` or re-run with --fix`;
15
+ }
16
+ else {
17
+ message = 'FRESH';
18
+ }
19
+ // Build per-file detail in the same order as diff.changed so renderers
20
+ // can show "why" each file matters without re-querying the graph.
21
+ const scoreByPath = new Map(score.perFile.map((f) => [f.filePath, f]));
22
+ const unknownSet = new Set(score.unknownFiles);
23
+ const perFile = diff.changed.map((p) => {
24
+ const s = scoreByPath.get(p);
25
+ return {
26
+ filePath: p,
27
+ weight: s?.weight ?? 0,
28
+ hub: s?.hub ?? false,
29
+ maxFanIn: s?.maxFanIn ?? 0,
30
+ unknown: unknownSet.has(p),
31
+ };
32
+ });
33
+ return {
34
+ status,
35
+ graphBuiltAt,
36
+ graphCommit,
37
+ workingCommit: diff.workingCommit,
38
+ changedFiles: diff.changed,
39
+ unknownFiles: score.unknownFiles,
40
+ perFile,
41
+ hubCount: score.hubCount,
42
+ leafCount: score.leafCount,
43
+ stalenessScore: score.totalScore,
44
+ threshold,
45
+ mechanism: diff.mechanism,
46
+ warnings: diff.warnings,
47
+ message,
48
+ };
49
+ }
50
+ function pad(s, n) {
51
+ return s + ' '.repeat(Math.max(0, n - s.length));
52
+ }
53
+ export function renderHuman(s) {
54
+ const lines = [];
55
+ lines.push('OpenLore preflight');
56
+ lines.push('──────────────────');
57
+ lines.push(`${pad('Graph built:', 15)}${s.graphBuiltAt ?? '(unknown)'}` +
58
+ (s.graphCommit ? ` commit ${s.graphCommit}` : ''));
59
+ lines.push(`${pad('Working tree:', 15)}${new Date().toISOString()}` +
60
+ (s.workingCommit ? ` commit ${s.workingCommit}` : ''));
61
+ if (s.changedFiles.length === 0) {
62
+ lines.push(`${pad('Changed files:', 15)}0`);
63
+ }
64
+ else {
65
+ lines.push(`${pad('Changed files:', 15)}${s.changedFiles.length} (${s.hubCount} hub, ${s.leafCount} leaf` +
66
+ (s.unknownFiles.length ? `, ${s.unknownFiles.length} new/untracked` : '') +
67
+ `)`);
68
+ }
69
+ lines.push(`${pad('Staleness:', 15)}score ${s.stalenessScore} (threshold ${s.threshold})`);
70
+ // Status line: STALE message wins; otherwise distinguish "FRESH" from the
71
+ // genuinely-empty "nothing to check" case so users can tell why CI passed.
72
+ let statusLine;
73
+ if (s.status === 'STALE') {
74
+ statusLine = 'STALE — ' + s.message.replace('STALE — ', '');
75
+ }
76
+ else if (s.changedFiles.length === 0) {
77
+ statusLine = `FRESH — ${s.message}`;
78
+ }
79
+ else {
80
+ statusLine = 'FRESH';
81
+ }
82
+ lines.push(`${pad('Status:', 15)}${statusLine}`);
83
+ if (s.warnings.length) {
84
+ lines.push('');
85
+ for (const w of s.warnings)
86
+ lines.push(` warning: ${w}`);
87
+ }
88
+ // Per-file breakdown — sorted by weight DESC so hubs surface first.
89
+ const ranked = [...s.perFile].sort((a, b) => b.weight - a.weight);
90
+ if (ranked.length > 0) {
91
+ lines.push('');
92
+ const cap = 20;
93
+ const header = ranked.length > cap ? `Changed (showing top ${cap} of ${ranked.length}, by weight):` : 'Changed:';
94
+ lines.push(header);
95
+ for (const f of ranked.slice(0, cap)) {
96
+ lines.push(` - ${formatFileLine(f)}`);
97
+ }
98
+ }
99
+ return lines.join('\n');
100
+ }
101
+ function formatFileLine(f) {
102
+ if (f.unknown) {
103
+ return `${f.filePath} (new/untracked, weight 0)`;
104
+ }
105
+ const tags = [];
106
+ if (f.hub)
107
+ tags.push('hub');
108
+ if (f.maxFanIn > 0 && !f.hub)
109
+ tags.push(`fan-in ${f.maxFanIn}`);
110
+ else if (f.hub && f.maxFanIn > 0)
111
+ tags.push(`fan-in ${f.maxFanIn}`);
112
+ const tagStr = tags.length ? tags.join(', ') + ', ' : '';
113
+ return `${f.filePath} (${tagStr}weight ${f.weight})`;
114
+ }
115
+ /**
116
+ * Emit GitHub Actions workflow-command annotations so that stale files
117
+ * appear inline in the PR diff UI when this runs in CI. No-op outside of
118
+ * GHA. Format docs:
119
+ * https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions
120
+ */
121
+ export function renderGithubAnnotations(s) {
122
+ if (s.status !== 'STALE')
123
+ return '';
124
+ if (process.env.GITHUB_ACTIONS !== 'true')
125
+ return '';
126
+ const lines = [];
127
+ // Per-file warnings — point CI users at the exact files that pushed us
128
+ // over the threshold. Only annotate files that contributed weight (i.e.
129
+ // appeared in the graph); new/untracked files have weight 0.
130
+ for (const f of s.changedFiles) {
131
+ const inGraphContributor = !s.unknownFiles.includes(f);
132
+ if (!inGraphContributor)
133
+ continue;
134
+ // Escape per GHA workflow-command escape rules.
135
+ const msg = `OpenLore graph is stale for this file — run \`openlore analyze\` to refresh`;
136
+ lines.push(`::warning file=${escapeAnnotation(f)}::${escapeAnnotation(msg)}`);
137
+ }
138
+ // Top-line error so the PR check fails visibly.
139
+ lines.push(`::error::OpenLore preflight: staleness score ${s.stalenessScore} > threshold ${s.threshold} (${s.hubCount} hub, ${s.leafCount} leaf changes). Run \`openlore analyze\`.`);
140
+ return lines.join('\n');
141
+ }
142
+ function escapeAnnotation(s) {
143
+ return s.replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
144
+ }
145
+ export function renderJson(s) {
146
+ // Schema is documented in docs/preflight.md. We deliberately ship more
147
+ // than the spec's minimum (status / graph_built_at / graph_commit /
148
+ // working_commit / changed_files / staleness_score / threshold) — the
149
+ // extras (`unknown_files`, `per_file`, `hub_count`, `leaf_count`,
150
+ // `mechanism`, `warnings`) are purely additive.
151
+ const payload = {
152
+ status: s.status,
153
+ graph_built_at: s.graphBuiltAt,
154
+ graph_commit: s.graphCommit,
155
+ working_commit: s.workingCommit,
156
+ changed_files: s.changedFiles,
157
+ unknown_files: s.unknownFiles,
158
+ per_file: s.perFile.map((f) => ({
159
+ file: f.filePath,
160
+ weight: f.weight,
161
+ hub: f.hub,
162
+ max_fan_in: f.maxFanIn,
163
+ unknown: f.unknown,
164
+ })),
165
+ hub_count: s.hubCount,
166
+ leaf_count: s.leafCount,
167
+ staleness_score: s.stalenessScore,
168
+ threshold: s.threshold,
169
+ mechanism: s.mechanism,
170
+ warnings: s.warnings,
171
+ };
172
+ return JSON.stringify(payload, null, 2);
173
+ }
174
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/cli/preflight/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Compute the staleness score for a set of changed files.
3
+ *
4
+ * Scoring model (deliberately simple, documented in docs/preflight.md):
5
+ *
6
+ * per-file weight =
7
+ * 1 base
8
+ * + 2 if any node in the file is a hub (is_hub = 1)
9
+ * + min(3, ceil(maxFanIn/5)) for the heaviest fan-in in the file
10
+ *
11
+ * staleness_score = sum(per-file weight) over files that map to nodes in
12
+ * the graph; files not in the graph are reported but do
13
+ * not contribute to the score (we cannot reason about
14
+ * them without re-analyzing).
15
+ *
16
+ * This is intentionally a heuristic — a hub change matters more than a leaf
17
+ * change, but we never claim it's a true blast-radius computation. It is the
18
+ * cheapest signal that distinguishes "noisy editor save" from "ripped out a
19
+ * central module."
20
+ */
21
+ export interface FileScore {
22
+ filePath: string;
23
+ /** Whether the file appears in the graph at all. */
24
+ inGraph: boolean;
25
+ /** Did the file contain at least one hub? */
26
+ hub: boolean;
27
+ /** Max fan-in across nodes in the file. */
28
+ maxFanIn: number;
29
+ /** Number of nodes in the file. */
30
+ nodeCount: number;
31
+ /** Weight contribution. */
32
+ weight: number;
33
+ }
34
+ export interface ScoreResult {
35
+ perFile: FileScore[];
36
+ totalScore: number;
37
+ hubCount: number;
38
+ leafCount: number;
39
+ /** Files not represented in the graph at all (e.g. new files). */
40
+ unknownFiles: string[];
41
+ }
42
+ export declare function scoreChangedFiles(repoRoot: string, changedFiles: string[]): ScoreResult;
43
+ //# sourceMappingURL=score.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score.d.ts","sourceRoot":"","sources":["../../../src/cli/preflight/score.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,6CAA6C;IAC7C,GAAG,EAAE,OAAO,CAAC;IACb,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAqDD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,WAAW,CA4BvF"}