@balpal4495/quorum 3.0.4 → 3.1.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.
- package/dist/advisor/ask.d.ts +13 -0
- package/dist/advisor/ask.d.ts.map +1 -0
- package/dist/advisor/ask.js +67 -0
- package/dist/advisor/ask.js.map +1 -0
- package/dist/advisor/index.d.ts +3 -0
- package/dist/advisor/index.d.ts.map +1 -0
- package/dist/advisor/index.js +2 -0
- package/dist/advisor/index.js.map +1 -0
- package/dist/advisor/prompt.d.ts +5 -0
- package/dist/advisor/prompt.d.ts.map +1 -0
- package/{modules/advisor/prompt.ts → dist/advisor/prompt.js} +22 -26
- package/dist/advisor/prompt.js.map +1 -0
- package/dist/advisor/types.d.ts +23 -0
- package/dist/advisor/types.d.ts.map +1 -0
- package/dist/advisor/types.js +2 -0
- package/dist/advisor/types.js.map +1 -0
- package/dist/compass/behavior.d.ts +4 -0
- package/dist/compass/behavior.d.ts.map +1 -0
- package/dist/compass/behavior.js +138 -0
- package/dist/compass/behavior.js.map +1 -0
- package/dist/compass/create.d.ts +3 -0
- package/dist/compass/create.d.ts.map +1 -0
- package/dist/compass/create.js +289 -0
- package/dist/compass/create.js.map +1 -0
- package/dist/compass/evidence/collect.d.ts +11 -0
- package/dist/compass/evidence/collect.d.ts.map +1 -0
- package/dist/compass/evidence/collect.js +86 -0
- package/dist/compass/evidence/collect.js.map +1 -0
- package/dist/compass/index.d.ts +8 -0
- package/dist/compass/index.d.ts.map +1 -0
- package/dist/compass/index.js +8 -0
- package/dist/compass/index.js.map +1 -0
- package/dist/compass/prompts/index.d.ts +28 -0
- package/dist/compass/prompts/index.d.ts.map +1 -0
- package/{modules/compass/prompts/index.ts → dist/compass/prompts/index.js} +13 -38
- package/dist/compass/prompts/index.js.map +1 -0
- package/dist/compass/prompts/system.d.ts +2 -0
- package/dist/compass/prompts/system.d.ts.map +1 -0
- package/{modules/compass/prompts/system.ts → dist/compass/prompts/system.js} +2 -1
- package/dist/compass/prompts/system.js.map +1 -0
- package/dist/compass/propose.d.ts +15 -0
- package/dist/compass/propose.d.ts.map +1 -0
- package/dist/compass/propose.js +128 -0
- package/dist/compass/propose.js.map +1 -0
- package/dist/compass/schemas.d.ts +1271 -0
- package/dist/compass/schemas.d.ts.map +1 -0
- package/dist/compass/schemas.js +113 -0
- package/dist/compass/schemas.js.map +1 -0
- package/dist/compass/score.d.ts +25 -0
- package/dist/compass/score.d.ts.map +1 -0
- package/dist/compass/score.js +89 -0
- package/dist/compass/score.js.map +1 -0
- package/dist/compass/sources/index.d.ts +9 -0
- package/dist/compass/sources/index.d.ts.map +1 -0
- package/dist/compass/sources/index.js +408 -0
- package/dist/compass/sources/index.js.map +1 -0
- package/dist/compass/types.d.ts +334 -0
- package/dist/compass/types.d.ts.map +1 -0
- package/dist/compass/types.js +2 -0
- package/dist/compass/types.js.map +1 -0
- package/dist/council/advisors.d.ts +15 -0
- package/dist/council/advisors.d.ts.map +1 -0
- package/dist/council/advisors.js +46 -0
- package/dist/council/advisors.js.map +1 -0
- package/dist/council/chairman.d.ts +13 -0
- package/dist/council/chairman.d.ts.map +1 -0
- package/dist/council/chairman.js +145 -0
- package/dist/council/chairman.js.map +1 -0
- package/dist/council/deliberate.d.ts +22 -0
- package/dist/council/deliberate.d.ts.map +1 -0
- package/dist/council/deliberate.js +99 -0
- package/dist/council/deliberate.js.map +1 -0
- package/dist/council/frame.d.ts +8 -0
- package/dist/council/frame.d.ts.map +1 -0
- package/dist/council/frame.js +40 -0
- package/dist/council/frame.js.map +1 -0
- package/dist/council/index.d.ts +6 -0
- package/dist/council/index.d.ts.map +1 -0
- package/dist/council/index.js +4 -0
- package/dist/council/index.js.map +1 -0
- package/dist/council/personas.d.ts +18 -0
- package/dist/council/personas.d.ts.map +1 -0
- package/dist/council/personas.js +44 -0
- package/dist/council/personas.js.map +1 -0
- package/dist/council/reviewers.d.ts +13 -0
- package/dist/council/reviewers.d.ts.map +1 -0
- package/dist/council/reviewers.js +59 -0
- package/dist/council/reviewers.js.map +1 -0
- package/dist/council/risk.d.ts +16 -0
- package/dist/council/risk.d.ts.map +1 -0
- package/dist/council/risk.js +74 -0
- package/dist/council/risk.js.map +1 -0
- package/dist/council/types.d.ts +95 -0
- package/dist/council/types.d.ts.map +1 -0
- package/dist/council/types.js +2 -0
- package/dist/council/types.js.map +1 -0
- package/dist/jury/evaluate.d.ts +13 -0
- package/dist/jury/evaluate.d.ts.map +1 -0
- package/{modules/jury/evaluate.ts → dist/jury/evaluate.js} +60 -84
- package/dist/jury/evaluate.js.map +1 -0
- package/dist/jury/index.d.ts +6 -0
- package/dist/jury/index.d.ts.map +1 -0
- package/dist/jury/index.js +4 -0
- package/dist/jury/index.js.map +1 -0
- package/dist/jury/preflight.d.ts +26 -0
- package/dist/jury/preflight.d.ts.map +1 -0
- package/dist/jury/preflight.js +71 -0
- package/dist/jury/preflight.js.map +1 -0
- package/dist/jury/schema.d.ts +57 -0
- package/dist/jury/schema.d.ts.map +1 -0
- package/dist/jury/schema.js +21 -0
- package/dist/jury/schema.js.map +1 -0
- package/dist/jury/types.d.ts +47 -0
- package/dist/jury/types.d.ts.map +1 -0
- package/dist/jury/types.js +2 -0
- package/dist/jury/types.js.map +1 -0
- package/dist/oracle/adapters/lance-db.d.ts +15 -0
- package/dist/oracle/adapters/lance-db.d.ts.map +1 -0
- package/dist/oracle/adapters/lance-db.js +68 -0
- package/dist/oracle/adapters/lance-db.js.map +1 -0
- package/dist/oracle/adapters/xenova-embedder.d.ts +21 -0
- package/dist/oracle/adapters/xenova-embedder.d.ts.map +1 -0
- package/dist/oracle/adapters/xenova-embedder.js +36 -0
- package/dist/oracle/adapters/xenova-embedder.js.map +1 -0
- package/dist/oracle/bm25.d.ts +20 -0
- package/dist/oracle/bm25.d.ts.map +1 -0
- package/dist/oracle/bm25.js +82 -0
- package/dist/oracle/bm25.js.map +1 -0
- package/dist/oracle/index.d.ts +21 -0
- package/dist/oracle/index.d.ts.map +1 -0
- package/dist/oracle/index.js +25 -0
- package/dist/oracle/index.js.map +1 -0
- package/dist/oracle/log.d.ts +6 -0
- package/dist/oracle/log.d.ts.map +1 -0
- package/dist/oracle/log.js +12 -0
- package/dist/oracle/log.js.map +1 -0
- package/dist/oracle/propose.d.ts +25 -0
- package/dist/oracle/propose.d.ts.map +1 -0
- package/dist/oracle/propose.js +133 -0
- package/dist/oracle/propose.js.map +1 -0
- package/dist/oracle/query.d.ts +17 -0
- package/dist/oracle/query.d.ts.map +1 -0
- package/dist/oracle/query.js +106 -0
- package/dist/oracle/query.js.map +1 -0
- package/dist/oracle/summary.d.ts +11 -0
- package/dist/oracle/summary.d.ts.map +1 -0
- package/dist/oracle/summary.js +102 -0
- package/dist/oracle/summary.js.map +1 -0
- package/dist/oracle/types.d.ts +31 -0
- package/dist/oracle/types.d.ts.map +1 -0
- package/dist/oracle/types.js +2 -0
- package/dist/oracle/types.js.map +1 -0
- package/dist/sentinel/assert.d.ts +28 -0
- package/dist/sentinel/assert.d.ts.map +1 -0
- package/dist/sentinel/assert.js +63 -0
- package/dist/sentinel/assert.js.map +1 -0
- package/dist/sentinel/coverage.d.ts +14 -0
- package/dist/sentinel/coverage.d.ts.map +1 -0
- package/dist/sentinel/coverage.js +96 -0
- package/dist/sentinel/coverage.js.map +1 -0
- package/dist/sentinel/drift.d.ts +12 -0
- package/dist/sentinel/drift.d.ts.map +1 -0
- package/dist/sentinel/drift.js +149 -0
- package/dist/sentinel/drift.js.map +1 -0
- package/dist/sentinel/index.d.ts +7 -0
- package/dist/sentinel/index.d.ts.map +1 -0
- package/dist/sentinel/index.js +5 -0
- package/dist/sentinel/index.js.map +1 -0
- package/dist/sentinel/review.d.ts +15 -0
- package/dist/sentinel/review.d.ts.map +1 -0
- package/dist/sentinel/review.js +177 -0
- package/dist/sentinel/review.js.map +1 -0
- package/dist/setup.d.ts +103 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +87 -0
- package/dist/setup.js.map +1 -0
- package/dist/shared/types.d.ts +173 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +16 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +13 -8
- package/.github/copilot-instructions.md +0 -117
- package/CLAUDE.md +0 -146
- package/GEMINI.md +0 -73
- package/SETUP.md +0 -264
- package/evals/__tests__/eval.test.ts +0 -31
- package/evals/cases/auth_hs256_rejected.json +0 -46
- package/evals/cases/auth_rs256_valid.json +0 -30
- package/evals/cases/cache_missing_lock.json +0 -31
- package/evals/cases/db_naive_not_null.json +0 -32
- package/evals/cases/logging_pii_leak.json +0 -32
- package/evals/cases/migration_with_rollback.json +0 -43
- package/evals/cases/no_evidence_novel_design.json +0 -16
- package/evals/cases/payment_no_idempotency.json +0 -33
- package/evals/cases/redis_session_rejected.json +0 -32
- package/evals/cases/safe_refactor.json +0 -17
- package/evals/runner.ts +0 -226
- package/modules/AGENTS.md +0 -78
- package/modules/CLAUDE.md +0 -93
- package/modules/README.md +0 -504
- package/modules/advisor/ask.ts +0 -87
- package/modules/advisor/index.ts +0 -2
- package/modules/advisor/types.ts +0 -26
- package/modules/compass/behavior.ts +0 -161
- package/modules/compass/create.ts +0 -365
- package/modules/compass/evidence/collect.ts +0 -109
- package/modules/compass/index.ts +0 -7
- package/modules/compass/propose.ts +0 -152
- package/modules/compass/schemas.ts +0 -121
- package/modules/compass/score.ts +0 -77
- package/modules/compass/sources/index.ts +0 -413
- package/modules/compass/types.ts +0 -431
- package/modules/council/advisors.ts +0 -71
- package/modules/council/chairman.ts +0 -183
- package/modules/council/deliberate.ts +0 -141
- package/modules/council/frame.ts +0 -54
- package/modules/council/index.ts +0 -9
- package/modules/council/personas.ts +0 -57
- package/modules/council/reviewers.ts +0 -82
- package/modules/council/risk.ts +0 -89
- package/modules/council/types.ts +0 -107
- package/modules/jury/index.ts +0 -5
- package/modules/jury/preflight.ts +0 -101
- package/modules/jury/schema.ts +0 -24
- package/modules/jury/types.ts +0 -50
- package/modules/oracle/adapters/lance-db.ts +0 -81
- package/modules/oracle/adapters/xenova-embedder.ts +0 -43
- package/modules/oracle/bm25.ts +0 -92
- package/modules/oracle/index.ts +0 -36
- package/modules/oracle/log.ts +0 -15
- package/modules/oracle/propose.ts +0 -164
- package/modules/oracle/query.ts +0 -146
- package/modules/oracle/summary.ts +0 -116
- package/modules/oracle/types.ts +0 -32
- package/modules/sentinel/assert.ts +0 -95
- package/modules/sentinel/coverage.ts +0 -106
- package/modules/sentinel/drift.ts +0 -163
- package/modules/sentinel/index.ts +0 -6
- package/modules/sentinel/review.ts +0 -208
- package/modules/setup.ts +0 -202
- package/modules/shared/types.ts +0 -193
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { ChronicleEntry } from "../shared/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Abstract vector store interface.
|
|
4
|
+
* Swap implementations without changing Oracle logic.
|
|
5
|
+
* Default implementation: LanceDB (see adapters/lance-db.ts).
|
|
6
|
+
*/
|
|
7
|
+
export interface VectorStore {
|
|
8
|
+
/**
|
|
9
|
+
* Upsert a Chronicle entry with its embedding vector.
|
|
10
|
+
* If an entry with this ID already exists, it is replaced.
|
|
11
|
+
*/
|
|
12
|
+
upsert: (id: string, vector: number[], metadata: ChronicleEntry) => Promise<void>;
|
|
13
|
+
/**
|
|
14
|
+
* Return the top-K most similar entries to the given query vector.
|
|
15
|
+
* Scores should be in [0, 1] (higher = more similar).
|
|
16
|
+
*/
|
|
17
|
+
search: (vector: number[], limit: number) => Promise<Array<{
|
|
18
|
+
entry: ChronicleEntry;
|
|
19
|
+
score: number;
|
|
20
|
+
}>>;
|
|
21
|
+
/** Return all stored entries (used for full-corpus BM25 if needed). */
|
|
22
|
+
getAll: () => Promise<ChronicleEntry[]>;
|
|
23
|
+
}
|
|
24
|
+
export interface OracleDeps {
|
|
25
|
+
/** Converts text to a numeric embedding vector. */
|
|
26
|
+
embedder: (text: string) => Promise<number[]>;
|
|
27
|
+
vectorStore: VectorStore;
|
|
28
|
+
/** Root directory for Chronicle data. Default: ".chronicle" */
|
|
29
|
+
chronicleDir?: string;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../modules/oracle/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjF;;;OAGG;IACH,MAAM,EAAE,CACN,MAAM,EAAE,MAAM,EAAE,EAChB,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,cAAc,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAA;IAC7D,uEAAuE;IACvE,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,EAAE,CAAC,CAAA;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7C,WAAW,EAAE,WAAW,CAAA;IACxB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../modules/oracle/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { LLMProvider } from "../shared/types.js";
|
|
2
|
+
export interface SentinelAssertOptions {
|
|
3
|
+
chronicleDir?: string;
|
|
4
|
+
codebasePath?: string;
|
|
5
|
+
/** When provided, drift detection runs. When absent, drift tests are skipped. */
|
|
6
|
+
llm?: LLMProvider;
|
|
7
|
+
extensions?: string[];
|
|
8
|
+
/**
|
|
9
|
+
* Chronicle coverage must reach this percentage for the CI test to pass.
|
|
10
|
+
* Default 0 = report gaps as advisory output without failing the build.
|
|
11
|
+
* Raise this as the project matures (e.g. 50 for an established codebase).
|
|
12
|
+
*/
|
|
13
|
+
minCoveragePercent?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Returns a set of named assertions designed to be called inside a Vitest
|
|
17
|
+
* describe block. Coverage assertions are deterministic and always run.
|
|
18
|
+
* Drift assertions skip gracefully when no LLM is provided.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* import { describe } from "vitest"
|
|
22
|
+
* import { sentinelAssertions } from "../modules/sentinel/assert.js"
|
|
23
|
+
*
|
|
24
|
+
* const assertions = sentinelAssertions({ chronicleDir: ".chronicle", codebasePath: "modules" })
|
|
25
|
+
* describe("sentinel", () => { assertions.forEach(a => a()) })
|
|
26
|
+
*/
|
|
27
|
+
export declare function sentinelAssertions(options?: SentinelAssertOptions): Array<() => void>;
|
|
28
|
+
//# sourceMappingURL=assert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../modules/sentinel/assert.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,WAAW,qBAAqB;IACpC,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,GAAG,CAAC,EAAE,WAAW,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAA;IACrB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,qBAA0B,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,CAgEzF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { coverage } from "./coverage.js";
|
|
2
|
+
import { detectDrift } from "./drift.js";
|
|
3
|
+
/**
|
|
4
|
+
* Returns a set of named assertions designed to be called inside a Vitest
|
|
5
|
+
* describe block. Coverage assertions are deterministic and always run.
|
|
6
|
+
* Drift assertions skip gracefully when no LLM is provided.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { describe } from "vitest"
|
|
10
|
+
* import { sentinelAssertions } from "../modules/sentinel/assert.js"
|
|
11
|
+
*
|
|
12
|
+
* const assertions = sentinelAssertions({ chronicleDir: ".chronicle", codebasePath: "modules" })
|
|
13
|
+
* describe("sentinel", () => { assertions.forEach(a => a()) })
|
|
14
|
+
*/
|
|
15
|
+
export function sentinelAssertions(options = {}) {
|
|
16
|
+
const { chronicleDir = ".chronicle", codebasePath = ".", llm, extensions, minCoveragePercent = 0, } = options;
|
|
17
|
+
// Import vitest lazily so this file is usable outside of a test context too
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
|
+
const { it, expect, describe: _describe } = require("vitest");
|
|
20
|
+
const assertions = [];
|
|
21
|
+
// ── Coverage (deterministic, always run) ──────────────────────────────────
|
|
22
|
+
assertions.push(() => {
|
|
23
|
+
const label = minCoveragePercent > 0
|
|
24
|
+
? `coverage: Chronicle coverage ≥ ${minCoveragePercent}%`
|
|
25
|
+
: "coverage: Chronicle coverage report [advisory]";
|
|
26
|
+
it(label, async () => {
|
|
27
|
+
const report = await coverage(chronicleDir, codebasePath, { extensions });
|
|
28
|
+
if (report.uncoveredFiles.length > 0) {
|
|
29
|
+
const list = report.uncoveredFiles.slice(0, 10).join("\n ");
|
|
30
|
+
const msg = `${report.uncoveredFiles.length} source file(s) have no Chronicle coverage (${report.percentage}% covered):\n ${list}`;
|
|
31
|
+
if (minCoveragePercent > 0) {
|
|
32
|
+
expect(report.percentage, msg).toBeGreaterThanOrEqual(minCoveragePercent);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
// New project or no threshold set — surface gaps without failing the build
|
|
36
|
+
console.info(`[sentinel] ${msg}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
assertions.push(() => {
|
|
42
|
+
it("coverage: report is readable and well-formed", async () => {
|
|
43
|
+
const report = await coverage(chronicleDir, codebasePath, { extensions });
|
|
44
|
+
expect(report.totalFiles).toBeGreaterThanOrEqual(0);
|
|
45
|
+
expect(report.percentage).toBeGreaterThanOrEqual(0);
|
|
46
|
+
expect(report.percentage).toBeLessThanOrEqual(100);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
// ── Drift (advisory, skips when no LLM configured) ────────────────────────
|
|
50
|
+
assertions.push(() => {
|
|
51
|
+
it.skipIf(!llm)("drift: no Chronicle entries flagged as potentially stale [advisory]", async () => {
|
|
52
|
+
const report = await detectDrift(chronicleDir, codebasePath, llm);
|
|
53
|
+
if (report.flags.length > 0) {
|
|
54
|
+
const detail = report.flags
|
|
55
|
+
.map(f => ` [${f.entryId.slice(0, 8)}] ${f.keyInsight}\n → ${f.reasoning}`)
|
|
56
|
+
.join("\n");
|
|
57
|
+
expect(report.flags, `${report.flags.length} Chronicle entry/entries may have drifted (advisory — review before marking refuted):\n${detail}`).toHaveLength(0);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
return assertions;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=assert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../../modules/sentinel/assert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { CoverageReport } from "../shared/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Scan the codebase and report which files have Chronicle entries referencing
|
|
4
|
+
* them in affected_areas and which do not.
|
|
5
|
+
*
|
|
6
|
+
* Matching is substring-based — "oracle/propose.ts" in affected_areas covers
|
|
7
|
+
* "modules/oracle/propose.ts" in the codebase. Treat percentage as directional
|
|
8
|
+
* signal, not a precision metric.
|
|
9
|
+
*/
|
|
10
|
+
export declare function coverage(chronicleDir: string, codebasePath: string, options?: {
|
|
11
|
+
extensions?: string[];
|
|
12
|
+
excludeTestFiles?: boolean;
|
|
13
|
+
}): Promise<CoverageReport>;
|
|
14
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../modules/sentinel/coverage.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,cAAc,EAAgB,MAAM,oBAAoB,CAAA;AAmEtF;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAAO,GAClE,OAAO,CAAC,cAAc,CAAC,CAwBzB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
const IGNORED_DIRS = new Set(["node_modules", "dist", ".git", ".chronicle", "coverage", "__tests__"]);
|
|
4
|
+
const TEST_SUFFIXES = [".test.ts", ".spec.ts", ".test.js", ".spec.js"];
|
|
5
|
+
async function walkFiles(dir, extensions, excludeTestFiles) {
|
|
6
|
+
const results = [];
|
|
7
|
+
async function recurse(current) {
|
|
8
|
+
let entries;
|
|
9
|
+
try {
|
|
10
|
+
entries = await fs.readdir(current, { withFileTypes: true, encoding: "utf8" });
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (const entry of entries) {
|
|
16
|
+
if (entry.isDirectory()) {
|
|
17
|
+
if (!IGNORED_DIRS.has(entry.name))
|
|
18
|
+
await recurse(path.join(current, entry.name));
|
|
19
|
+
}
|
|
20
|
+
else if (extensions.some(ext => entry.name.endsWith(ext))) {
|
|
21
|
+
if (excludeTestFiles && TEST_SUFFIXES.some(s => entry.name.endsWith(s)))
|
|
22
|
+
continue;
|
|
23
|
+
results.push(path.join(current, entry.name));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
await recurse(dir);
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
async function readCommittedEntries(chronicleDir) {
|
|
31
|
+
const committedDir = path.join(chronicleDir, "committed");
|
|
32
|
+
let files;
|
|
33
|
+
try {
|
|
34
|
+
files = await fs.readdir(committedDir);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return [];
|
|
38
|
+
}
|
|
39
|
+
const entries = [];
|
|
40
|
+
for (const file of files) {
|
|
41
|
+
if (!file.endsWith(".json"))
|
|
42
|
+
continue;
|
|
43
|
+
try {
|
|
44
|
+
const raw = await fs.readFile(path.join(committedDir, file), "utf8");
|
|
45
|
+
entries.push(JSON.parse(raw));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// skip malformed
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return entries;
|
|
52
|
+
}
|
|
53
|
+
function isCovered(relativePath, entries) {
|
|
54
|
+
const matched = [];
|
|
55
|
+
const normalised = relativePath.replace(/\\/g, "/");
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const hits = entry.affected_areas.some(area => {
|
|
58
|
+
const normArea = area.replace(/\\/g, "/");
|
|
59
|
+
return normalised.includes(normArea) || normArea.includes(normalised);
|
|
60
|
+
});
|
|
61
|
+
if (hits)
|
|
62
|
+
matched.push(entry.id);
|
|
63
|
+
}
|
|
64
|
+
return { covered: matched.length > 0, entryIds: matched };
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Scan the codebase and report which files have Chronicle entries referencing
|
|
68
|
+
* them in affected_areas and which do not.
|
|
69
|
+
*
|
|
70
|
+
* Matching is substring-based — "oracle/propose.ts" in affected_areas covers
|
|
71
|
+
* "modules/oracle/propose.ts" in the codebase. Treat percentage as directional
|
|
72
|
+
* signal, not a precision metric.
|
|
73
|
+
*/
|
|
74
|
+
export async function coverage(chronicleDir, codebasePath, options = {}) {
|
|
75
|
+
const extensions = options.extensions ?? [".ts"];
|
|
76
|
+
const excludeTestFiles = options.excludeTestFiles ?? true;
|
|
77
|
+
const [entries, files] = await Promise.all([
|
|
78
|
+
readCommittedEntries(chronicleDir),
|
|
79
|
+
walkFiles(codebasePath, extensions, excludeTestFiles),
|
|
80
|
+
]);
|
|
81
|
+
const coverageByFile = files.map(absolute => {
|
|
82
|
+
const relative = path.relative(codebasePath, absolute).replace(/\\/g, "/");
|
|
83
|
+
const { covered, entryIds } = isCovered(relative, entries);
|
|
84
|
+
return { file: relative, covered, entryIds };
|
|
85
|
+
});
|
|
86
|
+
const covered = coverageByFile.filter(f => f.covered);
|
|
87
|
+
const uncovered = coverageByFile.filter(f => !f.covered);
|
|
88
|
+
return {
|
|
89
|
+
totalFiles: files.length,
|
|
90
|
+
coveredFiles: covered.length,
|
|
91
|
+
uncoveredFiles: uncovered.map(f => f.file),
|
|
92
|
+
coverageByFile,
|
|
93
|
+
percentage: files.length === 0 ? 0 : Math.round((covered.length / files.length) * 100),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.js","sourceRoot":"","sources":["../../modules/sentinel/coverage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { DriftReport, LLMProvider } from "../shared/types.js";
|
|
2
|
+
/**
|
|
3
|
+
* For each Chronicle entry whose affected_areas resolves to at least one local
|
|
4
|
+
* source file, ask the LLM whether the key_insight still accurately describes
|
|
5
|
+
* the current code.
|
|
6
|
+
*
|
|
7
|
+
* Output is strictly advisory — entries are never updated autonomously.
|
|
8
|
+
* Entries where no affected_areas value resolves to a local file are skipped
|
|
9
|
+
* (e.g. entries about external tools, workflows, or conceptual areas).
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectDrift(chronicleDir: string, codebasePath: string, llm: LLMProvider): Promise<DriftReport>;
|
|
12
|
+
//# sourceMappingURL=drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.d.ts","sourceRoot":"","sources":["../../modules/sentinel/drift.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAA6B,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AA6G7F;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CAsCtB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { entryText } from "../shared/types.js";
|
|
4
|
+
const FILE_CONTENT_LIMIT = 3000;
|
|
5
|
+
async function readCommittedEntries(chronicleDir) {
|
|
6
|
+
const committedDir = path.join(chronicleDir, "committed");
|
|
7
|
+
let files;
|
|
8
|
+
try {
|
|
9
|
+
files = await fs.readdir(committedDir);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
const entries = [];
|
|
15
|
+
for (const file of files) {
|
|
16
|
+
if (!file.endsWith(".json"))
|
|
17
|
+
continue;
|
|
18
|
+
try {
|
|
19
|
+
const raw = await fs.readFile(path.join(committedDir, file), "utf8");
|
|
20
|
+
entries.push(JSON.parse(raw));
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// skip malformed
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return entries;
|
|
27
|
+
}
|
|
28
|
+
async function resolveLocalFiles(areas, codebasePath) {
|
|
29
|
+
const resolved = [];
|
|
30
|
+
for (const area of areas) {
|
|
31
|
+
// Try as a direct relative path first
|
|
32
|
+
const candidate = path.join(codebasePath, area);
|
|
33
|
+
try {
|
|
34
|
+
await fs.access(candidate);
|
|
35
|
+
resolved.push(candidate);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// not a direct path — try substring search
|
|
40
|
+
}
|
|
41
|
+
// Walk up to two levels to find files whose relative path contains the area string
|
|
42
|
+
try {
|
|
43
|
+
const all = await fs.readdir(codebasePath, { recursive: true, encoding: "utf8" });
|
|
44
|
+
for (const f of all) {
|
|
45
|
+
const normalised = f.replace(/\\/g, "/");
|
|
46
|
+
if (normalised.includes(area.replace(/\\/g, "/")) && normalised.endsWith(".ts")) {
|
|
47
|
+
resolved.push(path.join(codebasePath, f));
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// ignore
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...new Set(resolved)];
|
|
57
|
+
}
|
|
58
|
+
async function evaluateDrift(entry, files, llm) {
|
|
59
|
+
const fileSection = files
|
|
60
|
+
.map(f => `### ${path.basename(f.filePath)}\n\`\`\`\n${f.content.slice(0, FILE_CONTENT_LIMIT)}\n\`\`\``)
|
|
61
|
+
.join("\n\n");
|
|
62
|
+
const response = await llm([
|
|
63
|
+
{
|
|
64
|
+
role: "system",
|
|
65
|
+
content: "You are a code reviewer checking whether a documented insight still accurately describes the current source code. " +
|
|
66
|
+
"Reply with a JSON object only — no markdown, no explanation outside the object.",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
role: "user",
|
|
70
|
+
content: `Documented insight:
|
|
71
|
+
"${entryText(entry)}"
|
|
72
|
+
|
|
73
|
+
` +
|
|
74
|
+
`Current source:\n${fileSection}\n\n` +
|
|
75
|
+
`Does this insight still accurately describe the code above?\n` +
|
|
76
|
+
`{"stillValid": boolean, "confidence": number, "reasoning": "one sentence"}`,
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
try {
|
|
80
|
+
const match = response.match(/\{[\s\S]*?\}/);
|
|
81
|
+
if (!match)
|
|
82
|
+
throw new Error("no JSON");
|
|
83
|
+
const parsed = JSON.parse(match[0]);
|
|
84
|
+
return {
|
|
85
|
+
entryId: entry.id,
|
|
86
|
+
keyInsight: entryText(entry),
|
|
87
|
+
affectedFiles: files.map(f => f.filePath),
|
|
88
|
+
stillValid: Boolean(parsed.stillValid),
|
|
89
|
+
confidence: typeof parsed.confidence === "number" ? Math.max(0, Math.min(1, parsed.confidence)) : 0.5,
|
|
90
|
+
reasoning: typeof parsed.reasoning === "string" ? parsed.reasoning : "no reasoning provided",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Parse failure → conservative: flag for human review
|
|
95
|
+
return {
|
|
96
|
+
entryId: entry.id,
|
|
97
|
+
keyInsight: entryText(entry),
|
|
98
|
+
affectedFiles: files.map(f => f.filePath),
|
|
99
|
+
stillValid: false,
|
|
100
|
+
confidence: 0,
|
|
101
|
+
reasoning: "LLM response could not be parsed — manual review recommended",
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* For each Chronicle entry whose affected_areas resolves to at least one local
|
|
107
|
+
* source file, ask the LLM whether the key_insight still accurately describes
|
|
108
|
+
* the current code.
|
|
109
|
+
*
|
|
110
|
+
* Output is strictly advisory — entries are never updated autonomously.
|
|
111
|
+
* Entries where no affected_areas value resolves to a local file are skipped
|
|
112
|
+
* (e.g. entries about external tools, workflows, or conceptual areas).
|
|
113
|
+
*/
|
|
114
|
+
export async function detectDrift(chronicleDir, codebasePath, llm) {
|
|
115
|
+
const entries = await readCommittedEntries(chronicleDir);
|
|
116
|
+
const flags = [];
|
|
117
|
+
const confirmed = [];
|
|
118
|
+
const skipped = [];
|
|
119
|
+
for (const entry of entries) {
|
|
120
|
+
const localPaths = await resolveLocalFiles(entry.affected_areas, codebasePath);
|
|
121
|
+
if (localPaths.length === 0) {
|
|
122
|
+
skipped.push(entry.id);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
const files = [];
|
|
126
|
+
for (const p of localPaths) {
|
|
127
|
+
try {
|
|
128
|
+
const content = await fs.readFile(p, "utf8");
|
|
129
|
+
files.push({ filePath: p, content });
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// file unreadable — skip this path
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (files.length === 0) {
|
|
136
|
+
skipped.push(entry.id);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
const result = await evaluateDrift(entry, files, llm);
|
|
140
|
+
if (result.stillValid) {
|
|
141
|
+
confirmed.push(result);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
flags.push(result);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { checkedAt: new Date().toISOString(), flags, confirmed, skipped };
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=drift.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drift.js","sourceRoot":"","sources":["../../modules/sentinel/drift.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { coverage } from "./coverage.js";
|
|
2
|
+
export { detectDrift } from "./drift.js";
|
|
3
|
+
export { reviewContext } from "./review.js";
|
|
4
|
+
export { sentinelAssertions } from "./assert.js";
|
|
5
|
+
export type { CoverageReport, FileCoverage, DriftReport, DriftFlag } from "../shared/types.js";
|
|
6
|
+
export type { SentinelAssertOptions } from "./assert.js";
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../modules/sentinel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAChD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9F,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../modules/sentinel/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a PR-level Chronicle coverage map as a markdown string ready to
|
|
3
|
+
* post as a PR comment.
|
|
4
|
+
*
|
|
5
|
+
* Produces three zones:
|
|
6
|
+
* 1. Coverage table — all modules with coverage %, entry count, file count,
|
|
7
|
+
* PR delta, and risk. Changed modules are bolded.
|
|
8
|
+
* 2. Heatmap diagram — Chronicle → modules, nodes coloured by risk level,
|
|
9
|
+
* labels show coverage % and change count in one visual.
|
|
10
|
+
* 3. Chronicle context — entries for touched modules only.
|
|
11
|
+
*
|
|
12
|
+
* Deterministic — no LLM required. Pass changedFiles from `git diff --name-only`.
|
|
13
|
+
*/
|
|
14
|
+
export declare function reviewContext(changedFiles: string[], chronicleDir: string, codebasePath: string): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.d.ts","sourceRoot":"","sources":["../../modules/sentinel/review.ts"],"names":[],"mappings":"AAoEA;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CA0HjB"}
|