crewly 1.20.20 → 1.20.21
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/config/roles/generalist/prompt.md +8 -2
- package/config/roles/team-leader/prompt.md +2 -1
- package/config/skills/agent/core/wiki-query/SKILL.md +11 -0
- package/config/skills/agent/core/wiki-query/execute.sh +22 -3
- package/config/skills/orchestrator/wiki-ingest/SKILL.md +19 -0
- package/config/skills/orchestrator/wiki-ingest/execute.sh +36 -1
- package/config/skills/team-leader/wiki-review-proposals/SKILL.md +35 -0
- package/config/skills/team-leader/wiki-review-proposals/execute.sh +40 -0
- package/config/skills/team-leader/wiki-supersede/SKILL.md +38 -0
- package/config/skills/team-leader/wiki-supersede/execute.sh +44 -0
- package/dist/backend/backend/src/constants.d.ts +32 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +30 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts +29 -0
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js +196 -4
- package/dist/backend/backend/src/controllers/wiki/wiki.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js +9 -1
- package/dist/backend/backend/src/controllers/wiki/wiki.routes.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +3 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.d.ts +2 -0
- package/dist/backend/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/memory/memory.service.js +16 -4
- package/dist/backend/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts +9 -0
- package/dist/backend/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js +40 -1
- package/dist/backend/backend/src/services/wiki/schema-loader.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts +32 -0
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js +63 -1
- package/dist/backend/backend/src/services/wiki/wiki-bookkeep.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts +2 -0
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js +9 -2
- package/dist/backend/backend/src/services/wiki/wiki-cleanup.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-curation.service.d.ts +106 -0
- package/dist/backend/backend/src/services/wiki/wiki-curation.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-curation.service.js +211 -0
- package/dist/backend/backend/src/services/wiki/wiki-curation.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-history.service.d.ts +63 -0
- package/dist/backend/backend/src/services/wiki/wiki-history.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-history.service.js +124 -0
- package/dist/backend/backend/src/services/wiki/wiki-history.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-index.service.d.ts +119 -0
- package/dist/backend/backend/src/services/wiki/wiki-index.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-index.service.js +263 -0
- package/dist/backend/backend/src/services/wiki/wiki-index.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts +66 -11
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js +162 -44
- package/dist/backend/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-lint.service.d.ts +31 -0
- package/dist/backend/backend/src/services/wiki/wiki-lint.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-lint.service.js +69 -0
- package/dist/backend/backend/src/services/wiki/wiki-lint.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-owner.resolver.d.ts +29 -0
- package/dist/backend/backend/src/services/wiki/wiki-owner.resolver.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-owner.resolver.js +55 -0
- package/dist/backend/backend/src/services/wiki/wiki-owner.resolver.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-page.d.ts +101 -0
- package/dist/backend/backend/src/services/wiki/wiki-page.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-page.js +130 -0
- package/dist/backend/backend/src/services/wiki/wiki-page.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-policy.d.ts +35 -0
- package/dist/backend/backend/src/services/wiki/wiki-policy.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-policy.js +44 -0
- package/dist/backend/backend/src/services/wiki/wiki-policy.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-process.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js +5 -2
- package/dist/backend/backend/src/services/wiki/wiki-process.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts +57 -13
- package/dist/backend/backend/src/services/wiki/wiki-query.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js +91 -54
- package/dist/backend/backend/src/services/wiki/wiki-query.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-redaction.d.ts +74 -0
- package/dist/backend/backend/src/services/wiki/wiki-redaction.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-redaction.js +94 -0
- package/dist/backend/backend/src/services/wiki/wiki-redaction.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts +12 -3
- package/dist/backend/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js +19 -9
- package/dist/backend/backend/src/services/wiki/wiki-search.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-usage.service.d.ts +96 -0
- package/dist/backend/backend/src/services/wiki/wiki-usage.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-usage.service.js +147 -0
- package/dist/backend/backend/src/services/wiki/wiki-usage.service.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-vault-walk.d.ts +25 -0
- package/dist/backend/backend/src/services/wiki/wiki-vault-walk.d.ts.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-vault-walk.js +52 -0
- package/dist/backend/backend/src/services/wiki/wiki-vault-walk.js.map +1 -0
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts +19 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js +47 -6
- package/dist/backend/backend/src/services/wiki/wiki-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts +24 -0
- package/dist/backend/backend/src/services/wiki/wiki.types.d.ts.map +1 -1
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +32 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +30 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.d.ts +2 -0
- package/dist/cli/backend/src/services/memory/memory.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/memory/memory.service.js +16 -4
- package/dist/cli/backend/src/services/memory/memory.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts +9 -0
- package/dist/cli/backend/src/services/wiki/schema-loader.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/schema-loader.service.js +40 -1
- package/dist/cli/backend/src/services/wiki/schema-loader.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-history.service.d.ts +63 -0
- package/dist/cli/backend/src/services/wiki/wiki-history.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-history.service.js +124 -0
- package/dist/cli/backend/src/services/wiki/wiki-history.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-index.service.d.ts +119 -0
- package/dist/cli/backend/src/services/wiki/wiki-index.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-index.service.js +263 -0
- package/dist/cli/backend/src/services/wiki/wiki-index.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts +66 -11
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js +162 -44
- package/dist/cli/backend/src/services/wiki/wiki-ingest.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-page.d.ts +101 -0
- package/dist/cli/backend/src/services/wiki/wiki-page.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-page.js +130 -0
- package/dist/cli/backend/src/services/wiki/wiki-page.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-policy.d.ts +35 -0
- package/dist/cli/backend/src/services/wiki/wiki-policy.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-policy.js +44 -0
- package/dist/cli/backend/src/services/wiki/wiki-policy.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-redaction.d.ts +74 -0
- package/dist/cli/backend/src/services/wiki/wiki-redaction.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-redaction.js +94 -0
- package/dist/cli/backend/src/services/wiki/wiki-redaction.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts +12 -3
- package/dist/cli/backend/src/services/wiki/wiki-search.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-search.service.js +19 -9
- package/dist/cli/backend/src/services/wiki/wiki-search.service.js.map +1 -1
- package/dist/cli/backend/src/services/wiki/wiki-usage.service.d.ts +96 -0
- package/dist/cli/backend/src/services/wiki/wiki-usage.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-usage.service.js +147 -0
- package/dist/cli/backend/src/services/wiki/wiki-usage.service.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-vault-walk.d.ts +25 -0
- package/dist/cli/backend/src/services/wiki/wiki-vault-walk.d.ts.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki-vault-walk.js +52 -0
- package/dist/cli/backend/src/services/wiki/wiki-vault-walk.js.map +1 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.d.ts +24 -0
- package/dist/cli/backend/src/services/wiki/wiki.types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WikiIndexService — the one-line-per-page index that makes retrieval a
|
|
3
|
+
* two-step read: read the whole index → pick 3–5 pages → read them in
|
|
4
|
+
* full. No embeddings, no vector store; the index IS the retrieval.
|
|
5
|
+
*
|
|
6
|
+
* `llm-curated/index.md` is owned by the system: every page write updates
|
|
7
|
+
* its line, every delete removes it, and `rebuild()` regenerates it from
|
|
8
|
+
* the pages' frontmatter (also the migration path for vaults whose index
|
|
9
|
+
* nobody maintained). Pages are grouped by their top-level curated folder.
|
|
10
|
+
*
|
|
11
|
+
* @module services/wiki/wiki-index.service
|
|
12
|
+
*/
|
|
13
|
+
import { type WikiPageFrontmatter } from './wiki-page.js';
|
|
14
|
+
/** One entry of the parsed index. */
|
|
15
|
+
export interface WikiIndexEntry {
|
|
16
|
+
relativePath: string;
|
|
17
|
+
title: string;
|
|
18
|
+
summary: string;
|
|
19
|
+
supersededBy?: string;
|
|
20
|
+
/** Top-level folder under llm-curated (e.g. `decisions`), or `_root`. */
|
|
21
|
+
group: string;
|
|
22
|
+
}
|
|
23
|
+
/** Parsed index + raw text. */
|
|
24
|
+
export interface WikiIndex {
|
|
25
|
+
entries: WikiIndexEntry[];
|
|
26
|
+
raw: string;
|
|
27
|
+
bytes: number;
|
|
28
|
+
}
|
|
29
|
+
/** Coverage report: pages the index does not know and vice versa. */
|
|
30
|
+
export interface WikiIndexCoverage {
|
|
31
|
+
pages: number;
|
|
32
|
+
indexed: number;
|
|
33
|
+
missingFromIndex: string[];
|
|
34
|
+
indexedButMissing: string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Maintains `llm-curated/index.md` per vault.
|
|
38
|
+
*/
|
|
39
|
+
export declare class WikiIndexService {
|
|
40
|
+
private static instance;
|
|
41
|
+
private readonly logger;
|
|
42
|
+
/** Per-vault write serialisation (index edits are read-modify-write). */
|
|
43
|
+
private readonly locks;
|
|
44
|
+
constructor();
|
|
45
|
+
static getInstance(): WikiIndexService;
|
|
46
|
+
/** Test-only reset. */
|
|
47
|
+
static _resetForTesting(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Absolute path of a vault's index file.
|
|
50
|
+
*
|
|
51
|
+
* @param vaultPath - Vault root
|
|
52
|
+
* @returns `<vault>/llm-curated/index.md`
|
|
53
|
+
*/
|
|
54
|
+
indexPath(vaultPath: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Read and parse the index (empty when absent).
|
|
57
|
+
*
|
|
58
|
+
* @param vaultPath - Vault root
|
|
59
|
+
* @returns Parsed entries + raw text
|
|
60
|
+
*/
|
|
61
|
+
read(vaultPath: string): Promise<WikiIndex>;
|
|
62
|
+
/**
|
|
63
|
+
* Insert or replace the line for one page.
|
|
64
|
+
*
|
|
65
|
+
* @param vaultPath - Vault root
|
|
66
|
+
* @param relativePath - Vault-relative page path
|
|
67
|
+
* @param fm - The page's frontmatter (title/summary/superseded_by are used)
|
|
68
|
+
*/
|
|
69
|
+
upsert(vaultPath: string, relativePath: string, fm: Partial<WikiPageFrontmatter>): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Remove a page's line (no-op when absent).
|
|
72
|
+
*
|
|
73
|
+
* @param vaultPath - Vault root
|
|
74
|
+
* @param relativePath - Vault-relative page path
|
|
75
|
+
*/
|
|
76
|
+
remove(vaultPath: string, relativePath: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Regenerate the whole index from the pages on disk. Pages without a
|
|
79
|
+
* `summary` still get a line (title only) so nothing is invisible, and
|
|
80
|
+
* they show up in {@link coverage} as work for the bookkeeping agent.
|
|
81
|
+
*
|
|
82
|
+
* @param vaultPath - Vault root
|
|
83
|
+
* @returns Number of entries written
|
|
84
|
+
*/
|
|
85
|
+
rebuild(vaultPath: string): Promise<number>;
|
|
86
|
+
/**
|
|
87
|
+
* Compare the index against the pages on disk.
|
|
88
|
+
*
|
|
89
|
+
* @param vaultPath - Vault root
|
|
90
|
+
* @returns Coverage report
|
|
91
|
+
*/
|
|
92
|
+
coverage(vaultPath: string): Promise<WikiIndexCoverage>;
|
|
93
|
+
/**
|
|
94
|
+
* The index text an agent should read first, cut to the folders most
|
|
95
|
+
* relevant to a query when the full index would not fit the budget.
|
|
96
|
+
*
|
|
97
|
+
* @param vaultPath - Vault root
|
|
98
|
+
* @param queryTokens - Lower-cased query terms (for folder selection when trimming)
|
|
99
|
+
* @param maxBytes - Budget (default {@link WIKI_KB_CONSTANTS.INDEX_MAX_BYTES})
|
|
100
|
+
* @returns Text plus whether it was trimmed
|
|
101
|
+
*/
|
|
102
|
+
readForQuery(vaultPath: string, queryTokens: string[], maxBytes?: number): Promise<{
|
|
103
|
+
text: string;
|
|
104
|
+
truncated: boolean;
|
|
105
|
+
entries: number;
|
|
106
|
+
}>;
|
|
107
|
+
private write;
|
|
108
|
+
private withLock;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Parse index lines back into entries.
|
|
112
|
+
*
|
|
113
|
+
* @param raw - index.md text
|
|
114
|
+
* @returns Entries in file order
|
|
115
|
+
*/
|
|
116
|
+
export declare function parseIndex(raw: string): WikiIndexEntry[];
|
|
117
|
+
/** Whether a vault has an index file at all. */
|
|
118
|
+
export declare function hasIndex(vaultPath: string): boolean;
|
|
119
|
+
//# sourceMappingURL=wiki-index.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-index.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-index.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAA2B,KAAK,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAGnF,qCAAqC;AACrC,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,+BAA+B;AAC/B,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qEAAqE;AACrE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAKD;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAoC;;IAM1D,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAKtC,uBAAuB;IACvB,MAAM,CAAC,gBAAgB,IAAI,IAAI;IAI/B;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAIpC;;;;;OAKG;IACG,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAUjD;;;;;;OAMG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAUtG;;;;;OAKG;IACG,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASpE;;;;;;;OAOG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAsBjD;;;;;OAKG;IACG,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAc7D;;;;;;;;OAQG;IACG,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAoC,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;YAwB5J,KAAK;YAQL,QAAQ;CAavB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,EAAE,CAexD;AAoCD,gDAAgD;AAChD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WikiIndexService — the one-line-per-page index that makes retrieval a
|
|
3
|
+
* two-step read: read the whole index → pick 3–5 pages → read them in
|
|
4
|
+
* full. No embeddings, no vector store; the index IS the retrieval.
|
|
5
|
+
*
|
|
6
|
+
* `llm-curated/index.md` is owned by the system: every page write updates
|
|
7
|
+
* its line, every delete removes it, and `rebuild()` regenerates it from
|
|
8
|
+
* the pages' frontmatter (also the migration path for vaults whose index
|
|
9
|
+
* nobody maintained). Pages are grouped by their top-level curated folder.
|
|
10
|
+
*
|
|
11
|
+
* @module services/wiki/wiki-index.service
|
|
12
|
+
*/
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import * as fs from 'fs/promises';
|
|
15
|
+
import { existsSync } from 'fs';
|
|
16
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
17
|
+
import { WIKI_KB_CONSTANTS } from '../../constants.js';
|
|
18
|
+
import { parsePage, indexLineFor } from './wiki-page.js';
|
|
19
|
+
import { walkCuratedPages, isSeedFile } from './wiki-vault-walk.js';
|
|
20
|
+
const HEADER = '# Index\n\nOne line per page — read this first, then open 3–5 pages. `⟶ superseded by` marks a page whose conclusion has been replaced.\n';
|
|
21
|
+
const LINE_RE = /^- \[(.+?)\]\(([^)]+)\)(?: — (.*?))?(?: ⟶ superseded by (\S+))?$/;
|
|
22
|
+
/**
|
|
23
|
+
* Maintains `llm-curated/index.md` per vault.
|
|
24
|
+
*/
|
|
25
|
+
export class WikiIndexService {
|
|
26
|
+
static instance = null;
|
|
27
|
+
logger;
|
|
28
|
+
/** Per-vault write serialisation (index edits are read-modify-write). */
|
|
29
|
+
locks = new Map();
|
|
30
|
+
constructor() {
|
|
31
|
+
this.logger = LoggerService.getInstance().createComponentLogger('WikiIndex');
|
|
32
|
+
}
|
|
33
|
+
static getInstance() {
|
|
34
|
+
if (!this.instance)
|
|
35
|
+
this.instance = new WikiIndexService();
|
|
36
|
+
return this.instance;
|
|
37
|
+
}
|
|
38
|
+
/** Test-only reset. */
|
|
39
|
+
static _resetForTesting() {
|
|
40
|
+
this.instance = null;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Absolute path of a vault's index file.
|
|
44
|
+
*
|
|
45
|
+
* @param vaultPath - Vault root
|
|
46
|
+
* @returns `<vault>/llm-curated/index.md`
|
|
47
|
+
*/
|
|
48
|
+
indexPath(vaultPath) {
|
|
49
|
+
return path.join(vaultPath, 'llm-curated', WIKI_KB_CONSTANTS.INDEX_FILENAME);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Read and parse the index (empty when absent).
|
|
53
|
+
*
|
|
54
|
+
* @param vaultPath - Vault root
|
|
55
|
+
* @returns Parsed entries + raw text
|
|
56
|
+
*/
|
|
57
|
+
async read(vaultPath) {
|
|
58
|
+
let raw = '';
|
|
59
|
+
try {
|
|
60
|
+
raw = await fs.readFile(this.indexPath(vaultPath), 'utf8');
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return { entries: [], raw: '', bytes: 0 };
|
|
64
|
+
}
|
|
65
|
+
return { entries: parseIndex(raw), raw, bytes: Buffer.byteLength(raw, 'utf8') };
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Insert or replace the line for one page.
|
|
69
|
+
*
|
|
70
|
+
* @param vaultPath - Vault root
|
|
71
|
+
* @param relativePath - Vault-relative page path
|
|
72
|
+
* @param fm - The page's frontmatter (title/summary/superseded_by are used)
|
|
73
|
+
*/
|
|
74
|
+
async upsert(vaultPath, relativePath, fm) {
|
|
75
|
+
await this.withLock(vaultPath, async () => {
|
|
76
|
+
const index = await this.read(vaultPath);
|
|
77
|
+
const rel = relativePath.replace(/\\/g, '/');
|
|
78
|
+
const entries = index.entries.filter((e) => e.relativePath !== rel);
|
|
79
|
+
entries.push(entryFrom(rel, fm));
|
|
80
|
+
await this.write(vaultPath, entries);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Remove a page's line (no-op when absent).
|
|
85
|
+
*
|
|
86
|
+
* @param vaultPath - Vault root
|
|
87
|
+
* @param relativePath - Vault-relative page path
|
|
88
|
+
*/
|
|
89
|
+
async remove(vaultPath, relativePath) {
|
|
90
|
+
await this.withLock(vaultPath, async () => {
|
|
91
|
+
const index = await this.read(vaultPath);
|
|
92
|
+
const rel = relativePath.replace(/\\/g, '/');
|
|
93
|
+
const entries = index.entries.filter((e) => e.relativePath !== rel);
|
|
94
|
+
if (entries.length !== index.entries.length)
|
|
95
|
+
await this.write(vaultPath, entries);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Regenerate the whole index from the pages on disk. Pages without a
|
|
100
|
+
* `summary` still get a line (title only) so nothing is invisible, and
|
|
101
|
+
* they show up in {@link coverage} as work for the bookkeeping agent.
|
|
102
|
+
*
|
|
103
|
+
* @param vaultPath - Vault root
|
|
104
|
+
* @returns Number of entries written
|
|
105
|
+
*/
|
|
106
|
+
async rebuild(vaultPath) {
|
|
107
|
+
return this.withLock(vaultPath, async () => {
|
|
108
|
+
const entries = [];
|
|
109
|
+
for (const page of await walkCuratedPages(vaultPath)) {
|
|
110
|
+
if (isSeedFile(page.relativePath))
|
|
111
|
+
continue;
|
|
112
|
+
let raw;
|
|
113
|
+
try {
|
|
114
|
+
raw = await fs.readFile(page.absPath, 'utf8');
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const { frontmatter, body } = parsePage(raw);
|
|
120
|
+
const fm = { ...frontmatter };
|
|
121
|
+
if (!fm.title)
|
|
122
|
+
fm.title = firstHeading(body) ?? path.basename(page.relativePath, '.md');
|
|
123
|
+
entries.push(entryFrom(page.relativePath, fm));
|
|
124
|
+
}
|
|
125
|
+
await this.write(vaultPath, entries);
|
|
126
|
+
this.logger.info('Wiki index rebuilt', { vaultPath, entries: entries.length });
|
|
127
|
+
return entries.length;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Compare the index against the pages on disk.
|
|
132
|
+
*
|
|
133
|
+
* @param vaultPath - Vault root
|
|
134
|
+
* @returns Coverage report
|
|
135
|
+
*/
|
|
136
|
+
async coverage(vaultPath) {
|
|
137
|
+
const index = await this.read(vaultPath);
|
|
138
|
+
const indexed = new Set(index.entries.map((e) => e.relativePath));
|
|
139
|
+
const onDisk = new Set((await walkCuratedPages(vaultPath)).map((p) => p.relativePath).filter((p) => !isSeedFile(p)));
|
|
140
|
+
return {
|
|
141
|
+
pages: onDisk.size,
|
|
142
|
+
indexed: indexed.size,
|
|
143
|
+
missingFromIndex: [...onDisk].filter((p) => !indexed.has(p)).sort(),
|
|
144
|
+
indexedButMissing: [...indexed].filter((p) => !onDisk.has(p)).sort(),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The index text an agent should read first, cut to the folders most
|
|
149
|
+
* relevant to a query when the full index would not fit the budget.
|
|
150
|
+
*
|
|
151
|
+
* @param vaultPath - Vault root
|
|
152
|
+
* @param queryTokens - Lower-cased query terms (for folder selection when trimming)
|
|
153
|
+
* @param maxBytes - Budget (default {@link WIKI_KB_CONSTANTS.INDEX_MAX_BYTES})
|
|
154
|
+
* @returns Text plus whether it was trimmed
|
|
155
|
+
*/
|
|
156
|
+
async readForQuery(vaultPath, queryTokens, maxBytes = WIKI_KB_CONSTANTS.INDEX_MAX_BYTES) {
|
|
157
|
+
const index = await this.read(vaultPath);
|
|
158
|
+
if (index.bytes <= maxBytes)
|
|
159
|
+
return { text: index.raw, truncated: false, entries: index.entries.length };
|
|
160
|
+
// Trim: keep groups whose lines mention a query term first, then fill.
|
|
161
|
+
const terms = new Set(queryTokens.map((t) => t.toLowerCase()).filter((t) => t.length > 1));
|
|
162
|
+
const score = (e) => {
|
|
163
|
+
const hay = `${e.title} ${e.summary} ${e.relativePath}`.toLowerCase();
|
|
164
|
+
let n = 0;
|
|
165
|
+
for (const t of terms)
|
|
166
|
+
if (hay.includes(t))
|
|
167
|
+
n++;
|
|
168
|
+
return n;
|
|
169
|
+
};
|
|
170
|
+
const ranked = [...index.entries].sort((a, b) => score(b) - score(a) || a.relativePath.localeCompare(b.relativePath));
|
|
171
|
+
const kept = [];
|
|
172
|
+
let bytes = Buffer.byteLength(HEADER, 'utf8');
|
|
173
|
+
for (const e of ranked) {
|
|
174
|
+
const line = indexLineFor(e.relativePath, { title: e.title, summary: e.summary, superseded_by: e.supersededBy }) + '\n';
|
|
175
|
+
const b = Buffer.byteLength(line, 'utf8');
|
|
176
|
+
if (bytes + b > maxBytes)
|
|
177
|
+
break;
|
|
178
|
+
bytes += b;
|
|
179
|
+
kept.push(e);
|
|
180
|
+
}
|
|
181
|
+
return { text: render(kept) + `\n_(index trimmed to ${kept.length} of ${index.entries.length} entries for this query)_\n`, truncated: true, entries: kept.length };
|
|
182
|
+
}
|
|
183
|
+
async write(vaultPath, entries) {
|
|
184
|
+
const file = this.indexPath(vaultPath);
|
|
185
|
+
await fs.mkdir(path.dirname(file), { recursive: true });
|
|
186
|
+
const tmp = `${file}.tmp`;
|
|
187
|
+
await fs.writeFile(tmp, render(entries), 'utf8');
|
|
188
|
+
await fs.rename(tmp, file);
|
|
189
|
+
}
|
|
190
|
+
async withLock(vaultPath, fn) {
|
|
191
|
+
const prev = this.locks.get(vaultPath) ?? Promise.resolve();
|
|
192
|
+
let release;
|
|
193
|
+
const gate = new Promise((r) => { release = r; });
|
|
194
|
+
this.locks.set(vaultPath, prev.then(() => gate));
|
|
195
|
+
await prev;
|
|
196
|
+
try {
|
|
197
|
+
return await fn();
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
release();
|
|
201
|
+
if (this.locks.get(vaultPath) === gate)
|
|
202
|
+
this.locks.delete(vaultPath);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Parse index lines back into entries.
|
|
208
|
+
*
|
|
209
|
+
* @param raw - index.md text
|
|
210
|
+
* @returns Entries in file order
|
|
211
|
+
*/
|
|
212
|
+
export function parseIndex(raw) {
|
|
213
|
+
const entries = [];
|
|
214
|
+
for (const line of raw.split('\n')) {
|
|
215
|
+
const m = line.match(LINE_RE);
|
|
216
|
+
if (!m)
|
|
217
|
+
continue;
|
|
218
|
+
const relativePath = m[2];
|
|
219
|
+
entries.push({
|
|
220
|
+
relativePath,
|
|
221
|
+
title: m[1],
|
|
222
|
+
summary: m[3] ?? '',
|
|
223
|
+
...(m[4] ? { supersededBy: m[4] } : {}),
|
|
224
|
+
group: groupOf(relativePath),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return entries;
|
|
228
|
+
}
|
|
229
|
+
function entryFrom(relativePath, fm) {
|
|
230
|
+
const line = indexLineFor(relativePath, fm);
|
|
231
|
+
const parsed = parseIndex(line)[0];
|
|
232
|
+
return parsed ?? { relativePath, title: relativePath, summary: '', group: groupOf(relativePath) };
|
|
233
|
+
}
|
|
234
|
+
function groupOf(relativePath) {
|
|
235
|
+
const parts = relativePath.replace(/^llm-curated\//, '').split('/');
|
|
236
|
+
return parts.length > 1 ? parts[0] : '_root';
|
|
237
|
+
}
|
|
238
|
+
function render(entries) {
|
|
239
|
+
const groups = new Map();
|
|
240
|
+
for (const e of entries) {
|
|
241
|
+
const g = groups.get(e.group) ?? [];
|
|
242
|
+
g.push(e);
|
|
243
|
+
groups.set(e.group, g);
|
|
244
|
+
}
|
|
245
|
+
const names = [...groups.keys()].sort((a, b) => (a === '_root' ? 1 : b === '_root' ? -1 : a.localeCompare(b)));
|
|
246
|
+
const out = [HEADER];
|
|
247
|
+
for (const name of names) {
|
|
248
|
+
out.push(`\n## ${name === '_root' ? 'Other' : name}\n`);
|
|
249
|
+
for (const e of groups.get(name).sort((a, b) => a.relativePath.localeCompare(b.relativePath))) {
|
|
250
|
+
out.push(indexLineFor(e.relativePath, { title: e.title, summary: e.summary, superseded_by: e.supersededBy }));
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return out.join('\n') + '\n';
|
|
254
|
+
}
|
|
255
|
+
function firstHeading(body) {
|
|
256
|
+
const m = body.match(/^#\s+(.+)$/m);
|
|
257
|
+
return m ? m[1].trim() : null;
|
|
258
|
+
}
|
|
259
|
+
/** Whether a vault has an index file at all. */
|
|
260
|
+
export function hasIndex(vaultPath) {
|
|
261
|
+
return existsSync(path.join(vaultPath, 'llm-curated', WIKI_KB_CONSTANTS.INDEX_FILENAME));
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=wiki-index.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wiki-index.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-index.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WikiIngestService — write
|
|
2
|
+
* WikiIngestService — write into a vault's `llm-curated/`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Two kinds of write:
|
|
5
|
+
* - **log entry** (default): append to `llm-curated/log.md`. Cheap,
|
|
6
|
+
* append-only, no gate beyond confidentiality. This is where "maybe
|
|
7
|
+
* useful" goes — the default is NOT to keep.
|
|
8
|
+
* - **page** (`targetRelativePath` under llm-curated/): a piece of
|
|
9
|
+
* knowledge. Passes the retention gate (title + one-line summary +
|
|
10
|
+
* keep_because), the vault's write policy (a `proposed_only` role's
|
|
11
|
+
* page lands in `_proposed/` until a canonical role accepts), the
|
|
12
|
+
* confidentiality gate (secrets never; PII per vault), gets YAML
|
|
13
|
+
* frontmatter, an index line, and a history snapshot of what it
|
|
14
|
+
* replaced.
|
|
8
15
|
*
|
|
9
16
|
* Frozen-path contract (§2): refuses ANY write whose target lives under a
|
|
10
17
|
* `hardcoded:` folder. SchemaLoaderService.isFrozenPath() is the gate.
|
|
@@ -12,6 +19,9 @@
|
|
|
12
19
|
* @module services/wiki/wiki-ingest.service
|
|
13
20
|
*/
|
|
14
21
|
import { SchemaLoaderService } from './schema-loader.service.js';
|
|
22
|
+
import { type WikiKeepBecause } from '../../constants.js';
|
|
23
|
+
import { WikiIndexService } from './wiki-index.service.js';
|
|
24
|
+
import { WikiHistoryService } from './wiki-history.service.js';
|
|
15
25
|
/**
|
|
16
26
|
* Categories of sources that trigger ingest. Mirrors §4 (ingest trigger
|
|
17
27
|
* taxonomy) plus `user_chat` for the demo path.
|
|
@@ -28,14 +38,39 @@ export interface WikiIngestInput {
|
|
|
28
38
|
sourceBody: string;
|
|
29
39
|
/** Session/user that authored the source — appears in the log header. */
|
|
30
40
|
callerSession?: string;
|
|
41
|
+
/** Writer's role as resolved by the server (undefined = owner/UI). Drives write_policy. */
|
|
42
|
+
callerRole?: string;
|
|
31
43
|
/** Optional override of the relative target path; defaults to `llm-curated/log.md`. */
|
|
32
44
|
targetRelativePath?: string;
|
|
45
|
+
/** Page writes only: the page's name. */
|
|
46
|
+
title?: string;
|
|
47
|
+
/** Page writes only: the one-line conclusion — what this means for us. */
|
|
48
|
+
summary?: string;
|
|
49
|
+
/** Page writes only: why it earns a page. */
|
|
50
|
+
keepBecause?: WikiKeepBecause | string;
|
|
51
|
+
tags?: string[];
|
|
52
|
+
/** Page writes only: roles that may read it (default: the vault's default_visibility). */
|
|
53
|
+
visibility?: string[];
|
|
54
|
+
/** Page writes only: replace the page instead of appending to it (default: append). */
|
|
55
|
+
replace?: boolean;
|
|
33
56
|
}
|
|
34
57
|
export interface WikiIngestResult {
|
|
35
58
|
ok: true;
|
|
36
59
|
pagesWritten: string[];
|
|
37
60
|
logEntry: string;
|
|
38
61
|
frozenPathsTouched: string[];
|
|
62
|
+
/** True when the page landed in `_proposed/` (writer is a proposed_only role). */
|
|
63
|
+
proposed?: boolean;
|
|
64
|
+
/** PII pattern names that were masked (vault privacy `mask`). */
|
|
65
|
+
masked?: string[];
|
|
66
|
+
indexUpdated?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface WikiIngestRefusedGate {
|
|
69
|
+
ok: false;
|
|
70
|
+
reason: 'retention_gate' | 'secret_detected' | 'pii_refused';
|
|
71
|
+
message: string;
|
|
72
|
+
/** retention_gate: missing fields; privacy: matched pattern names. */
|
|
73
|
+
details: string[];
|
|
39
74
|
}
|
|
40
75
|
export interface WikiIngestRefusedFrozen {
|
|
41
76
|
ok: false;
|
|
@@ -48,7 +83,7 @@ export interface WikiIngestRefusedInvalid {
|
|
|
48
83
|
reason: 'invalid_input' | 'schema_missing' | 'empty_body';
|
|
49
84
|
message: string;
|
|
50
85
|
}
|
|
51
|
-
export type WikiIngestOutcome = WikiIngestResult | WikiIngestRefusedFrozen | WikiIngestRefusedInvalid;
|
|
86
|
+
export type WikiIngestOutcome = WikiIngestResult | WikiIngestRefusedFrozen | WikiIngestRefusedInvalid | WikiIngestRefusedGate;
|
|
52
87
|
/**
|
|
53
88
|
* Writes ingest pages to a vault. Construct one per process; stateless.
|
|
54
89
|
*/
|
|
@@ -56,7 +91,9 @@ export declare class WikiIngestService {
|
|
|
56
91
|
private static instance;
|
|
57
92
|
private readonly logger;
|
|
58
93
|
private readonly schemaLoader;
|
|
59
|
-
|
|
94
|
+
private readonly index;
|
|
95
|
+
private readonly history;
|
|
96
|
+
constructor(schemaLoader?: SchemaLoaderService, index?: WikiIndexService, history?: WikiHistoryService);
|
|
60
97
|
static getInstance(): WikiIngestService;
|
|
61
98
|
/** Test-only reset. */
|
|
62
99
|
static _resetForTesting(): void;
|
|
@@ -68,6 +105,25 @@ export declare class WikiIngestService {
|
|
|
68
105
|
* callers can fold the result into their normal control flow.
|
|
69
106
|
*/
|
|
70
107
|
ingest(input: WikiIngestInput): Promise<WikiIngestOutcome>;
|
|
108
|
+
/**
|
|
109
|
+
* Write (create, append to, or replace) a knowledge page. See the module
|
|
110
|
+
* header for the gates it passes.
|
|
111
|
+
*
|
|
112
|
+
* @param schema - Vault schema
|
|
113
|
+
* @param target - Vault-relative page path (validated, not frozen)
|
|
114
|
+
* @param input - Ingest input with a body that already passed the privacy gate
|
|
115
|
+
* @param masked - PII pattern names masked in the body
|
|
116
|
+
* @returns Outcome
|
|
117
|
+
*/
|
|
118
|
+
private writePage;
|
|
119
|
+
/**
|
|
120
|
+
* The provenance block appended to a page for each ingest.
|
|
121
|
+
*
|
|
122
|
+
* @param input - Ingest input
|
|
123
|
+
* @returns Markdown block
|
|
124
|
+
*/
|
|
125
|
+
private formatPageEntry;
|
|
126
|
+
private titleFromBody;
|
|
71
127
|
private validateInput;
|
|
72
128
|
/**
|
|
73
129
|
* Build the markdown entry. Format is chosen to be safely append-only
|
|
@@ -82,10 +138,9 @@ export declare class WikiIngestService {
|
|
|
82
138
|
private formatLogEntry;
|
|
83
139
|
private appendOrCreate;
|
|
84
140
|
/**
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
* - anything else → minimal title block from the source ref
|
|
141
|
+
* Header for a freshly-created `log.md` (pages are built by {@link writePage}).
|
|
142
|
+
*
|
|
143
|
+
* @returns The activity-log preamble
|
|
89
144
|
*/
|
|
90
145
|
private buildPageHeader;
|
|
91
146
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wiki-ingest.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-ingest.service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wiki-ingest.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/wiki/wiki-ingest.service.ts"],"names":[],"mappings":"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"}
|