@balpal4495/quorum 3.0.3 → 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/bin/commands/compass.js +4 -4
- package/bin/shared/llm.js +2 -2
- 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 @@
|
|
|
1
|
+
{"version":3,"file":"bm25.d.ts","sourceRoot":"","sources":["../../modules/oracle/bm25.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAcH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAsCtE;AAWD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAY/D"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight BM25 implementation for Pass 2 re-ranking.
|
|
3
|
+
*
|
|
4
|
+
* k1 = 1.5 (term frequency saturation)
|
|
5
|
+
* b = 0.75 (length normalization)
|
|
6
|
+
*
|
|
7
|
+
* Formula: score(q, d) = Σ IDF(qi) * f(qi, d) * (k1 + 1) / (f(qi, d) + k1 * (1 − b + b * |d| / avgdl))
|
|
8
|
+
*/
|
|
9
|
+
const K1 = 1.5;
|
|
10
|
+
const B = 0.75;
|
|
11
|
+
function tokenize(text) {
|
|
12
|
+
return text.toLowerCase().match(/\b\w+\b/g) ?? [];
|
|
13
|
+
}
|
|
14
|
+
/** Robertson–Sparck Jones IDF with smoothing. */
|
|
15
|
+
function computeIdf(N, df) {
|
|
16
|
+
return Math.log(1 + (N - df + 0.5) / (df + 0.5));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Score each document string against the query using BM25.
|
|
20
|
+
* Returns a score array parallel to `documents`.
|
|
21
|
+
*/
|
|
22
|
+
export function bm25Score(query, documents) {
|
|
23
|
+
if (documents.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
const queryTokens = tokenize(query);
|
|
26
|
+
const docTokenLists = documents.map(tokenize);
|
|
27
|
+
const totalLength = docTokenLists.reduce((sum, d) => sum + d.length, 0);
|
|
28
|
+
const avgdl = totalLength / docTokenLists.length;
|
|
29
|
+
const N = documents.length;
|
|
30
|
+
// Precompute document frequency for each unique query token
|
|
31
|
+
const df = new Map();
|
|
32
|
+
for (const token of queryTokens) {
|
|
33
|
+
if (!df.has(token)) {
|
|
34
|
+
df.set(token, docTokenLists.filter(doc => doc.includes(token)).length);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return docTokenLists.map(docTokenList => {
|
|
38
|
+
const docLength = docTokenList.length;
|
|
39
|
+
const tf = new Map();
|
|
40
|
+
for (const token of docTokenList) {
|
|
41
|
+
tf.set(token, (tf.get(token) ?? 0) + 1);
|
|
42
|
+
}
|
|
43
|
+
let score = 0;
|
|
44
|
+
for (const token of queryTokens) {
|
|
45
|
+
const termFreq = tf.get(token) ?? 0;
|
|
46
|
+
if (termFreq === 0)
|
|
47
|
+
continue;
|
|
48
|
+
const idfScore = computeIdf(N, df.get(token) ?? 0);
|
|
49
|
+
const normTf = (termFreq * (K1 + 1)) /
|
|
50
|
+
(termFreq + K1 * (1 - B + B * (docLength / avgdl)));
|
|
51
|
+
score += idfScore * normTf;
|
|
52
|
+
}
|
|
53
|
+
return score;
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const BM25_STOP_WORDS = new Set([
|
|
57
|
+
"a", "an", "the", "is", "are", "was", "were", "be", "been", "being",
|
|
58
|
+
"have", "has", "had", "do", "does", "did", "will", "would", "should",
|
|
59
|
+
"could", "may", "might", "shall", "can", "to", "of", "in", "for", "on",
|
|
60
|
+
"with", "at", "by", "from", "as", "into", "through", "and", "or", "but",
|
|
61
|
+
"if", "then", "this", "that", "these", "those", "it", "its", "we", "they",
|
|
62
|
+
"their", "there", "when", "where", "what", "which", "who", "how", "not", "no",
|
|
63
|
+
]);
|
|
64
|
+
/**
|
|
65
|
+
* Extract domain terms from Chronicle key insights for Pass 2 query enrichment.
|
|
66
|
+
* Bridges the vocabulary gap between natural language queries and technical identifiers.
|
|
67
|
+
* Strips stop words, returns the most frequent distinctive tokens.
|
|
68
|
+
*/
|
|
69
|
+
export function extractDomainTerms(insights) {
|
|
70
|
+
const allTokens = insights.flatMap(s => tokenize(s));
|
|
71
|
+
const freq = new Map();
|
|
72
|
+
for (const token of allTokens) {
|
|
73
|
+
if (!BM25_STOP_WORDS.has(token) && token.length > 2) {
|
|
74
|
+
freq.set(token, (freq.get(token) ?? 0) + 1);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return [...freq.entries()]
|
|
78
|
+
.sort((a, b) => b[1] - a[1])
|
|
79
|
+
.slice(0, 10)
|
|
80
|
+
.map(([token]) => token);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=bm25.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bm25.js","sourceRoot":"","sources":["../../modules/oracle/bm25.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { query } from "./query.js";
|
|
2
|
+
export { propose, commit } from "./propose.js";
|
|
3
|
+
export type { OracleDeps, VectorStore } from "./types.js";
|
|
4
|
+
export type { OracleResult, QueryOptions, ChronicleEntry, OracleClient, } from "../shared/types.js";
|
|
5
|
+
export { createLanceDBStore } from "./adapters/lance-db.js";
|
|
6
|
+
export { xenovaEmbed, warmEmbedder } from "./adapters/xenova-embedder.js";
|
|
7
|
+
import type { OracleClient } from "../shared/types.js";
|
|
8
|
+
import type { OracleDeps } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* Create a bound OracleClient from injected deps.
|
|
11
|
+
* Pass this to Jury and Council — they only need the OracleClient interface,
|
|
12
|
+
* not the raw Oracle functions.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* const oracle = createOracleClient({
|
|
16
|
+
* embedder: xenovaEmbed,
|
|
17
|
+
* vectorStore: await createLanceDBStore(".chronicle"),
|
|
18
|
+
* })
|
|
19
|
+
*/
|
|
20
|
+
export declare function createOracleClient(deps: OracleDeps): OracleClient;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../modules/oracle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAC9C,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACzD,YAAY,EACV,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,YAAY,GACb,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAI5C;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,CAMjE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export { query } from "./query.js";
|
|
2
|
+
export { propose, commit } from "./propose.js";
|
|
3
|
+
export { createLanceDBStore } from "./adapters/lance-db.js";
|
|
4
|
+
export { xenovaEmbed, warmEmbedder } from "./adapters/xenova-embedder.js";
|
|
5
|
+
import { query } from "./query.js";
|
|
6
|
+
import { propose, commit } from "./propose.js";
|
|
7
|
+
/**
|
|
8
|
+
* Create a bound OracleClient from injected deps.
|
|
9
|
+
* Pass this to Jury and Council — they only need the OracleClient interface,
|
|
10
|
+
* not the raw Oracle functions.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* const oracle = createOracleClient({
|
|
14
|
+
* embedder: xenovaEmbed,
|
|
15
|
+
* vectorStore: await createLanceDBStore(".chronicle"),
|
|
16
|
+
* })
|
|
17
|
+
*/
|
|
18
|
+
export function createOracleClient(deps) {
|
|
19
|
+
return {
|
|
20
|
+
query: (text, options) => query(text, options ?? {}, deps),
|
|
21
|
+
propose: entry => propose(entry, deps),
|
|
22
|
+
commit: proposalId => commit(proposalId, deps),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../modules/oracle/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAS9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAA;AAIzE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAE9C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAgB;IACjD,OAAO;QACL,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,EAAE,IAAI,CAAC;QAC1D,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC;QACtC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC;KAC/C,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append a query log entry to .chronicle/query-log.jsonl.
|
|
3
|
+
* Best-effort — callers should swallow errors from this.
|
|
4
|
+
*/
|
|
5
|
+
export declare function appendQueryLog(entry: Record<string, unknown>, chronicleDir: string): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../modules/oracle/log.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Append a query log entry to .chronicle/query-log.jsonl.
|
|
5
|
+
* Best-effort — callers should swallow errors from this.
|
|
6
|
+
*/
|
|
7
|
+
export async function appendQueryLog(entry, chronicleDir) {
|
|
8
|
+
await fs.mkdir(chronicleDir, { recursive: true });
|
|
9
|
+
const logPath = path.join(chronicleDir, "query-log.jsonl");
|
|
10
|
+
await fs.appendFile(logPath, JSON.stringify(entry) + "\n", "utf8");
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../modules/oracle/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,IAAI,MAAM,MAAM,CAAA;AAEvB;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAA8B,EAC9B,YAAoB;IAEpB,MAAM,EAAE,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,CAAA;IAC1D,MAAM,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACpE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ChronicleEntry, SimilarityWarning } from "../shared/types.js";
|
|
2
|
+
import type { OracleDeps } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Propose a new Chronicle entry for human review.
|
|
5
|
+
* Validates entry quality and checks for similar existing entries before writing.
|
|
6
|
+
* Writes the entry to .chronicle/proposals/<id>.json — NOT yet indexed.
|
|
7
|
+
* The proposal sits pending until a human calls commit() to approve it.
|
|
8
|
+
*
|
|
9
|
+
* Throws if key_insight is too short/long or affected_areas is empty.
|
|
10
|
+
* Returns a SimilarityWarning if a near-identical entry already exists —
|
|
11
|
+
* the human gate should surface this before approving the commit.
|
|
12
|
+
*/
|
|
13
|
+
export declare function propose(entry: Omit<ChronicleEntry, "id" | "timestamp">, deps: OracleDeps): Promise<{
|
|
14
|
+
proposalId: string;
|
|
15
|
+
similarity?: SimilarityWarning;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Commit a pending proposal after human approval.
|
|
19
|
+
* Reads the proposal file, assigns an ID and timestamp, embeds the entry,
|
|
20
|
+
* upserts it into the vector store, and deletes the proposal file.
|
|
21
|
+
*
|
|
22
|
+
* Throws if the proposal does not exist.
|
|
23
|
+
*/
|
|
24
|
+
export declare function commit(proposalId: string, deps: OracleDeps): Promise<ChronicleEntry>;
|
|
25
|
+
//# sourceMappingURL=propose.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../modules/oracle/propose.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AAE3E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAqE5C;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,IAAI,GAAG,WAAW,CAAC,EAC/C,IAAI,EAAE,UAAU,GACf,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAcjE;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAC1B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,cAAc,CAAC,CAgDzB"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { randomUUID } from "crypto";
|
|
4
|
+
import { exec } from "child_process";
|
|
5
|
+
import { promisify } from "util";
|
|
6
|
+
import { entryText } from "../shared/types.js";
|
|
7
|
+
import { updateSummary } from "./summary.js";
|
|
8
|
+
const execAsync = promisify(exec);
|
|
9
|
+
const INSIGHT_MIN_LENGTH = 20;
|
|
10
|
+
const INSIGHT_MAX_LENGTH = 200;
|
|
11
|
+
const SIMILARITY_WARNING_THRESHOLD = 0.85;
|
|
12
|
+
function validateEntry(entry) {
|
|
13
|
+
const insight = entry.key_insight?.trim() ?? "";
|
|
14
|
+
if (insight.length < INSIGHT_MIN_LENGTH) {
|
|
15
|
+
throw new Error(`key_insight too short (${insight.length} chars, min ${INSIGHT_MIN_LENGTH}). ` +
|
|
16
|
+
`Write a specific, complete sentence naming the module or area affected.`);
|
|
17
|
+
}
|
|
18
|
+
if (insight.length > INSIGHT_MAX_LENGTH) {
|
|
19
|
+
throw new Error(`key_insight too long (${insight.length} chars, max ${INSIGHT_MAX_LENGTH}). ` +
|
|
20
|
+
`Distil to a single clear sentence.`);
|
|
21
|
+
}
|
|
22
|
+
if (entry.decision !== undefined) {
|
|
23
|
+
const d = entry.decision.trim();
|
|
24
|
+
if (d.length < INSIGHT_MIN_LENGTH) {
|
|
25
|
+
throw new Error(`decision too short (${d.length} chars, min ${INSIGHT_MIN_LENGTH}). ` +
|
|
26
|
+
`Write a specific, complete sentence describing the decision.`);
|
|
27
|
+
}
|
|
28
|
+
if (d.length > INSIGHT_MAX_LENGTH) {
|
|
29
|
+
throw new Error(`decision too long (${d.length} chars, max ${INSIGHT_MAX_LENGTH}). ` +
|
|
30
|
+
`Distil to a single clear sentence.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (!entry.affected_areas || entry.affected_areas.filter(a => a.trim()).length === 0) {
|
|
34
|
+
throw new Error(`affected_areas must contain at least one non-empty entry.`);
|
|
35
|
+
}
|
|
36
|
+
if (entry.confidence < 0 || entry.confidence > 1) {
|
|
37
|
+
throw new Error(`confidence must be between 0 and 1, got ${entry.confidence}.`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function checkSimilarity(entry, deps) {
|
|
41
|
+
try {
|
|
42
|
+
const text = [entryText(entry), ...entry.affected_areas, ...(entry.scope ?? [])].join(" ");
|
|
43
|
+
const vector = await deps.embedder(text);
|
|
44
|
+
const results = await deps.vectorStore.search(vector, 3);
|
|
45
|
+
if (results.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
const top = results[0];
|
|
48
|
+
if (top.score < SIMILARITY_WARNING_THRESHOLD)
|
|
49
|
+
return undefined;
|
|
50
|
+
return {
|
|
51
|
+
entry: top.entry,
|
|
52
|
+
score: top.score,
|
|
53
|
+
// If the existing entry is validated, a near-duplicate is likely a correction
|
|
54
|
+
warning: top.entry.status === "validated" ? "potential-supersession" : "potential-duplicate",
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Similarity check is best-effort — never block a proposal because of it
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Propose a new Chronicle entry for human review.
|
|
64
|
+
* Validates entry quality and checks for similar existing entries before writing.
|
|
65
|
+
* Writes the entry to .chronicle/proposals/<id>.json — NOT yet indexed.
|
|
66
|
+
* The proposal sits pending until a human calls commit() to approve it.
|
|
67
|
+
*
|
|
68
|
+
* Throws if key_insight is too short/long or affected_areas is empty.
|
|
69
|
+
* Returns a SimilarityWarning if a near-identical entry already exists —
|
|
70
|
+
* the human gate should surface this before approving the commit.
|
|
71
|
+
*/
|
|
72
|
+
export async function propose(entry, deps) {
|
|
73
|
+
validateEntry(entry);
|
|
74
|
+
const similarity = await checkSimilarity(entry, deps);
|
|
75
|
+
const chronicleDir = deps.chronicleDir ?? ".chronicle";
|
|
76
|
+
const proposalsDir = path.join(chronicleDir, "proposals");
|
|
77
|
+
await fs.mkdir(proposalsDir, { recursive: true });
|
|
78
|
+
const proposalId = randomUUID();
|
|
79
|
+
const proposalPath = path.join(proposalsDir, `${proposalId}.json`);
|
|
80
|
+
await fs.writeFile(proposalPath, JSON.stringify(entry, null, 2), "utf8");
|
|
81
|
+
return { proposalId, ...(similarity ? { similarity } : {}) };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Commit a pending proposal after human approval.
|
|
85
|
+
* Reads the proposal file, assigns an ID and timestamp, embeds the entry,
|
|
86
|
+
* upserts it into the vector store, and deletes the proposal file.
|
|
87
|
+
*
|
|
88
|
+
* Throws if the proposal does not exist.
|
|
89
|
+
*/
|
|
90
|
+
export async function commit(proposalId, deps) {
|
|
91
|
+
const chronicleDir = deps.chronicleDir ?? ".chronicle";
|
|
92
|
+
const proposalPath = path.join(chronicleDir, "proposals", `${proposalId}.json`);
|
|
93
|
+
let raw;
|
|
94
|
+
try {
|
|
95
|
+
raw = await fs.readFile(proposalPath, "utf8");
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
throw new Error(`Proposal not found: ${proposalId}`);
|
|
99
|
+
}
|
|
100
|
+
const partial = JSON.parse(raw);
|
|
101
|
+
const entry = {
|
|
102
|
+
...partial,
|
|
103
|
+
id: randomUUID(),
|
|
104
|
+
timestamp: new Date().toISOString(),
|
|
105
|
+
};
|
|
106
|
+
// Embed the primary text + areas + scope tags for richer retrieval
|
|
107
|
+
const embeddingText = [entryText(entry), ...entry.affected_areas, ...(entry.scope ?? [])].join(" ");
|
|
108
|
+
const vector = await deps.embedder(embeddingText);
|
|
109
|
+
await deps.vectorStore.upsert(entry.id, vector, entry);
|
|
110
|
+
// Write to committed/ — the git-tracked source of truth shared across the team
|
|
111
|
+
const committedDir = path.join(chronicleDir, "committed");
|
|
112
|
+
await fs.mkdir(committedDir, { recursive: true });
|
|
113
|
+
const committedPath = path.join(committedDir, `${entry.id}.json`);
|
|
114
|
+
await fs.writeFile(committedPath, JSON.stringify(entry, null, 2), "utf8");
|
|
115
|
+
// Stage the committed entry for the next git commit — best-effort
|
|
116
|
+
try {
|
|
117
|
+
await execAsync(`git add "${committedPath}"`);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
// Not in a git repo, or git is unavailable — silently continue
|
|
121
|
+
}
|
|
122
|
+
// Rebuild SUMMARY.md — best-effort, never fail a commit
|
|
123
|
+
try {
|
|
124
|
+
await updateSummary(chronicleDir);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Summary generation failure must not fail a commit
|
|
128
|
+
}
|
|
129
|
+
// Remove the proposal — it has been committed
|
|
130
|
+
await fs.unlink(proposalPath);
|
|
131
|
+
return entry;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=propose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"propose.js","sourceRoot":"","sources":["../../modules/oracle/propose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OracleResult, QueryOptions } from "../shared/types.js";
|
|
2
|
+
import type { OracleDeps } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Two-pass retrieval with Reciprocal Rank Fusion.
|
|
5
|
+
*
|
|
6
|
+
* Pass 1 — vector similarity:
|
|
7
|
+
* Embed the query, retrieve top (limit × CANDIDATE_MULTIPLIER) candidates.
|
|
8
|
+
*
|
|
9
|
+
* Pass 2 — BM25 re-ranking with query enrichment:
|
|
10
|
+
* Extract domain terms from Pass 1 key insights, enrich the query,
|
|
11
|
+
* score candidates with BM25, fuse ranks via RRF.
|
|
12
|
+
*
|
|
13
|
+
* Results below scoreThreshold are dropped entirely.
|
|
14
|
+
* All queries are appended to .chronicle/query-log.jsonl.
|
|
15
|
+
*/
|
|
16
|
+
export declare function query(text: string, options: QueryOptions | undefined, deps: OracleDeps): Promise<OracleResult[]>;
|
|
17
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../modules/oracle/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEpF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAmB5C;;;;;;;;;;;;GAYG;AACH,wBAAsB,KAAK,CACzB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,YAAY,YAAK,EAC1B,IAAI,EAAE,UAAU,GACf,OAAO,CAAC,YAAY,EAAE,CAAC,CAgEzB"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { entryText } from "../shared/types.js";
|
|
2
|
+
import { bm25Score, extractDomainTerms } from "./bm25.js";
|
|
3
|
+
import { appendQueryLog } from "./log.js";
|
|
4
|
+
const DEFAULT_LIMIT = 10;
|
|
5
|
+
const DEFAULT_SCORE_THRESHOLD = 0.031;
|
|
6
|
+
const RRF_K = 60;
|
|
7
|
+
/** Retrieve this many vector candidates before BM25 re-ranking. */
|
|
8
|
+
const CANDIDATE_MULTIPLIER = 3;
|
|
9
|
+
/**
|
|
10
|
+
* Reciprocal Rank Fusion score.
|
|
11
|
+
* score = Σ 1 / (k + rank_i) summed across all rank lists.
|
|
12
|
+
* k = 60 (standard constant).
|
|
13
|
+
*/
|
|
14
|
+
function rrfScore(ranks) {
|
|
15
|
+
return ranks.reduce((sum, rank) => sum + 1 / (RRF_K + rank), 0);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Two-pass retrieval with Reciprocal Rank Fusion.
|
|
19
|
+
*
|
|
20
|
+
* Pass 1 — vector similarity:
|
|
21
|
+
* Embed the query, retrieve top (limit × CANDIDATE_MULTIPLIER) candidates.
|
|
22
|
+
*
|
|
23
|
+
* Pass 2 — BM25 re-ranking with query enrichment:
|
|
24
|
+
* Extract domain terms from Pass 1 key insights, enrich the query,
|
|
25
|
+
* score candidates with BM25, fuse ranks via RRF.
|
|
26
|
+
*
|
|
27
|
+
* Results below scoreThreshold are dropped entirely.
|
|
28
|
+
* All queries are appended to .chronicle/query-log.jsonl.
|
|
29
|
+
*/
|
|
30
|
+
export async function query(text, options = {}, deps) {
|
|
31
|
+
const { statusFilter, limit = DEFAULT_LIMIT, scoreThreshold = DEFAULT_SCORE_THRESHOLD, } = options;
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
// ── Pass 1: vector similarity ──────────────────────────────────────────────
|
|
34
|
+
const queryVector = await deps.embedder(text);
|
|
35
|
+
const candidateLimit = limit * CANDIDATE_MULTIPLIER;
|
|
36
|
+
let candidates = await deps.vectorStore.search(queryVector, candidateLimit);
|
|
37
|
+
// Status filter applied before BM25 to avoid scoring irrelevant entries
|
|
38
|
+
if (statusFilter && statusFilter.length > 0) {
|
|
39
|
+
candidates = candidates.filter(c => statusFilter.includes(c.entry.status));
|
|
40
|
+
}
|
|
41
|
+
if (candidates.length === 0) {
|
|
42
|
+
await tryLogQuery(text, [], startTime, deps);
|
|
43
|
+
return [];
|
|
44
|
+
}
|
|
45
|
+
// ── Pass 2: BM25 re-ranking with query enrichment ─────────────────────────
|
|
46
|
+
const topInsights = candidates
|
|
47
|
+
.slice(0, Math.min(5, candidates.length))
|
|
48
|
+
.map(c => entryText(c.entry));
|
|
49
|
+
const domainTerms = extractDomainTerms(topInsights);
|
|
50
|
+
const enrichedQuery = domainTerms.length > 0 ? `${text} ${domainTerms.join(" ")}` : text;
|
|
51
|
+
const documents = candidates.map(c => [entryText(c.entry), ...c.entry.affected_areas, ...(c.entry.scope ?? [])].join(" "));
|
|
52
|
+
const bm25Scores = bm25Score(enrichedQuery, documents);
|
|
53
|
+
// Build BM25 rank lookup (index → rank)
|
|
54
|
+
const bm25RankOf = new Array(candidates.length);
|
|
55
|
+
bm25Scores
|
|
56
|
+
.map((score, i) => ({ i, score }))
|
|
57
|
+
.sort((a, b) => b.score - a.score)
|
|
58
|
+
.forEach(({ i }, rank) => {
|
|
59
|
+
bm25RankOf[i] = rank;
|
|
60
|
+
});
|
|
61
|
+
// ── RRF fusion ─────────────────────────────────────────────────────────────
|
|
62
|
+
const fused = candidates.map((candidate, vectorRank) => ({
|
|
63
|
+
...candidate.entry,
|
|
64
|
+
score: rrfScore([vectorRank, bm25RankOf[vectorRank]]),
|
|
65
|
+
}));
|
|
66
|
+
fused.sort((a, b) => b.score - a.score);
|
|
67
|
+
const filtered = fused
|
|
68
|
+
.filter(r => r.score >= scoreThreshold)
|
|
69
|
+
.slice(0, limit);
|
|
70
|
+
const results = assignTiers(filtered);
|
|
71
|
+
await tryLogQuery(text, results, startTime, deps);
|
|
72
|
+
return results;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Assign relevance tiers within the result set using relative rank.
|
|
76
|
+
* Top ~30% → primary, next ~40% → supporting, remainder → background.
|
|
77
|
+
* Thresholds are relative so they self-calibrate as Chronicle grows.
|
|
78
|
+
*/
|
|
79
|
+
function assignTiers(results) {
|
|
80
|
+
const n = results.length;
|
|
81
|
+
if (n === 0)
|
|
82
|
+
return [];
|
|
83
|
+
const primaryCount = Math.max(1, Math.ceil(n * 0.3));
|
|
84
|
+
const supportingCount = Math.max(1, Math.ceil(n * 0.4));
|
|
85
|
+
return results.map((r, i) => ({
|
|
86
|
+
...r,
|
|
87
|
+
tier: i < primaryCount ? "primary"
|
|
88
|
+
: i < primaryCount + supportingCount ? "supporting"
|
|
89
|
+
: "background",
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
async function tryLogQuery(text, results, startTime, deps) {
|
|
93
|
+
try {
|
|
94
|
+
await appendQueryLog({
|
|
95
|
+
query: text,
|
|
96
|
+
results: results.map(r => ({ id: r.id, score: r.score, status: r.status })),
|
|
97
|
+
resultCount: results.length,
|
|
98
|
+
durationMs: Date.now() - startTime,
|
|
99
|
+
timestamp: new Date().toISOString(),
|
|
100
|
+
}, deps.chronicleDir ?? ".chronicle");
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Query logging is best-effort — never fail a query because of a log write failure
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../modules/oracle/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuild .chronicle/SUMMARY.md from all committed entries.
|
|
3
|
+
*
|
|
4
|
+
* Groups entries by ISO week (most-recent first), then by work_ref within
|
|
5
|
+
* each week. Shows the last SUMMARY_WEEKS weeks; older entries are omitted
|
|
6
|
+
* (still fully queryable via Oracle).
|
|
7
|
+
*
|
|
8
|
+
* Called by commit() as a best-effort side-effect — never throws.
|
|
9
|
+
*/
|
|
10
|
+
export declare function updateSummary(chronicleDir: string): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../modules/oracle/summary.ts"],"names":[],"mappings":"AAmCA;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuEvE"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { entryText } from "../shared/types.js";
|
|
4
|
+
const SUMMARY_WEEKS = 12;
|
|
5
|
+
const DIRECTIVE = "<!-- Chronicle Summary v1 — temporal orientation for agents. " +
|
|
6
|
+
"Use for sequence context; query Oracle by entry ID for full reasoning. -->";
|
|
7
|
+
/**
|
|
8
|
+
* Returns the ISO week string (YYYY-Www) for a given date.
|
|
9
|
+
* Uses the ISO 8601 definition: week 1 is the week containing the first Thursday.
|
|
10
|
+
*/
|
|
11
|
+
function isoWeekKey(date) {
|
|
12
|
+
const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
13
|
+
const day = d.getUTCDay() || 7;
|
|
14
|
+
d.setUTCDate(d.getUTCDate() + 4 - day);
|
|
15
|
+
const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
|
|
16
|
+
const week = Math.ceil(((d.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);
|
|
17
|
+
return `${d.getUTCFullYear()}-W${String(week).padStart(2, "0")}`;
|
|
18
|
+
}
|
|
19
|
+
function workRefLabel(entry) {
|
|
20
|
+
if (!entry.work_ref)
|
|
21
|
+
return "__none__";
|
|
22
|
+
const { type, ref } = entry.work_ref;
|
|
23
|
+
return ref ? `[${type} ${ref}]` : `[${type}]`;
|
|
24
|
+
}
|
|
25
|
+
function renderEntry(entry) {
|
|
26
|
+
const areas = entry.affected_areas.join(", ");
|
|
27
|
+
const id = entry.id.slice(0, 8);
|
|
28
|
+
return `- **[${id}]** ${areas} — \`${entry.status}\` (${entry.confidence.toFixed(2)}) — ${entryText(entry)}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Rebuild .chronicle/SUMMARY.md from all committed entries.
|
|
32
|
+
*
|
|
33
|
+
* Groups entries by ISO week (most-recent first), then by work_ref within
|
|
34
|
+
* each week. Shows the last SUMMARY_WEEKS weeks; older entries are omitted
|
|
35
|
+
* (still fully queryable via Oracle).
|
|
36
|
+
*
|
|
37
|
+
* Called by commit() as a best-effort side-effect — never throws.
|
|
38
|
+
*/
|
|
39
|
+
export async function updateSummary(chronicleDir) {
|
|
40
|
+
const committedDir = path.join(chronicleDir, "committed");
|
|
41
|
+
let files;
|
|
42
|
+
try {
|
|
43
|
+
files = await fs.readdir(committedDir);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const entries = [];
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
if (!file.endsWith(".json"))
|
|
51
|
+
continue;
|
|
52
|
+
try {
|
|
53
|
+
const raw = await fs.readFile(path.join(committedDir, file), "utf8");
|
|
54
|
+
entries.push(JSON.parse(raw));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Skip malformed entries
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (entries.length === 0)
|
|
61
|
+
return;
|
|
62
|
+
entries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));
|
|
63
|
+
// Group by ISO week
|
|
64
|
+
const byWeek = new Map();
|
|
65
|
+
for (const entry of entries) {
|
|
66
|
+
const week = isoWeekKey(new Date(entry.timestamp));
|
|
67
|
+
const bucket = byWeek.get(week) ?? [];
|
|
68
|
+
bucket.push(entry);
|
|
69
|
+
byWeek.set(week, bucket);
|
|
70
|
+
}
|
|
71
|
+
const weeks = [...byWeek.keys()].sort().reverse().slice(0, SUMMARY_WEEKS);
|
|
72
|
+
const lines = [DIRECTIVE, ""];
|
|
73
|
+
for (const week of weeks) {
|
|
74
|
+
lines.push(`## Week ${week}`, "");
|
|
75
|
+
// Group entries within week by work_ref label
|
|
76
|
+
const weekEntries = byWeek.get(week);
|
|
77
|
+
const byWork = new Map();
|
|
78
|
+
for (const entry of weekEntries) {
|
|
79
|
+
const key = workRefLabel(entry);
|
|
80
|
+
const bucket = byWork.get(key) ?? [];
|
|
81
|
+
bucket.push(entry);
|
|
82
|
+
byWork.set(key, bucket);
|
|
83
|
+
}
|
|
84
|
+
// Labelled work groups first, then ungrouped
|
|
85
|
+
const workKeys = [...byWork.keys()].sort((a, b) => a === "__none__" ? 1 : b === "__none__" ? -1 : a.localeCompare(b));
|
|
86
|
+
for (const key of workKeys) {
|
|
87
|
+
if (key === "__none__") {
|
|
88
|
+
lines.push(`### (no work context — query Oracle by entry ID for details)`);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
lines.push(`### ${key}`);
|
|
92
|
+
}
|
|
93
|
+
for (const entry of byWork.get(key)) {
|
|
94
|
+
lines.push(renderEntry(entry));
|
|
95
|
+
}
|
|
96
|
+
lines.push("");
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const summaryPath = path.join(chronicleDir, "SUMMARY.md");
|
|
100
|
+
await fs.writeFile(summaryPath, lines.join("\n"), "utf8");
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../modules/oracle/summary.ts"],"names":[],"mappings":"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"}
|