mewkit 1.11.2 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/commands/index-command.d.ts.map +1 -1
  2. package/dist/commands/index-command.js +2 -1
  3. package/dist/commands/index-command.js.map +1 -1
  4. package/dist/core/derived-index.d.ts +12 -3
  5. package/dist/core/derived-index.d.ts.map +1 -1
  6. package/dist/core/derived-index.js +42 -13
  7. package/dist/core/derived-index.js.map +1 -1
  8. package/dist/index.js +9 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/wiki/application/ports.d.ts +111 -0
  11. package/dist/wiki/application/ports.d.ts.map +1 -0
  12. package/dist/wiki/application/ports.js +33 -0
  13. package/dist/wiki/application/ports.js.map +1 -0
  14. package/dist/wiki/application/queries.d.ts +5 -0
  15. package/dist/wiki/application/queries.d.ts.map +1 -0
  16. package/dist/wiki/application/queries.js +10 -0
  17. package/dist/wiki/application/queries.js.map +1 -0
  18. package/dist/wiki/application/research.d.ts +16 -0
  19. package/dist/wiki/application/research.d.ts.map +1 -0
  20. package/dist/wiki/application/research.js +48 -0
  21. package/dist/wiki/application/research.js.map +1 -0
  22. package/dist/wiki/application/service.d.ts +27 -0
  23. package/dist/wiki/application/service.d.ts.map +1 -0
  24. package/dist/wiki/application/service.js +153 -0
  25. package/dist/wiki/application/service.js.map +1 -0
  26. package/dist/wiki/domain/index.d.ts +5 -0
  27. package/dist/wiki/domain/index.d.ts.map +1 -0
  28. package/dist/wiki/domain/index.js +6 -0
  29. package/dist/wiki/domain/index.js.map +1 -0
  30. package/dist/wiki/domain/invariants.d.ts +28 -0
  31. package/dist/wiki/domain/invariants.d.ts.map +1 -0
  32. package/dist/wiki/domain/invariants.js +84 -0
  33. package/dist/wiki/domain/invariants.js.map +1 -0
  34. package/dist/wiki/domain/salience.d.ts +11 -0
  35. package/dist/wiki/domain/salience.d.ts.map +1 -0
  36. package/dist/wiki/domain/salience.js +40 -0
  37. package/dist/wiki/domain/salience.js.map +1 -0
  38. package/dist/wiki/domain/types.d.ts +151 -0
  39. package/dist/wiki/domain/types.d.ts.map +1 -0
  40. package/dist/wiki/domain/types.js +27 -0
  41. package/dist/wiki/domain/types.js.map +1 -0
  42. package/dist/wiki/domain/write-decision.d.ts +25 -0
  43. package/dist/wiki/domain/write-decision.d.ts.map +1 -0
  44. package/dist/wiki/domain/write-decision.js +71 -0
  45. package/dist/wiki/domain/write-decision.js.map +1 -0
  46. package/dist/wiki/infrastructure/fetcher-adapter.d.ts +45 -0
  47. package/dist/wiki/infrastructure/fetcher-adapter.d.ts.map +1 -0
  48. package/dist/wiki/infrastructure/fetcher-adapter.js +99 -0
  49. package/dist/wiki/infrastructure/fetcher-adapter.js.map +1 -0
  50. package/dist/wiki/infrastructure/inventory-adapter.d.ts +13 -0
  51. package/dist/wiki/infrastructure/inventory-adapter.d.ts.map +1 -0
  52. package/dist/wiki/infrastructure/inventory-adapter.js +46 -0
  53. package/dist/wiki/infrastructure/inventory-adapter.js.map +1 -0
  54. package/dist/wiki/infrastructure/markdown-repository.d.ts +23 -0
  55. package/dist/wiki/infrastructure/markdown-repository.d.ts.map +1 -0
  56. package/dist/wiki/infrastructure/markdown-repository.js +168 -0
  57. package/dist/wiki/infrastructure/markdown-repository.js.map +1 -0
  58. package/dist/wiki/infrastructure/scan-patterns.d.ts +20 -0
  59. package/dist/wiki/infrastructure/scan-patterns.d.ts.map +1 -0
  60. package/dist/wiki/infrastructure/scan-patterns.js +106 -0
  61. package/dist/wiki/infrastructure/scan-patterns.js.map +1 -0
  62. package/dist/wiki/infrastructure/scanner-adapter.d.ts +10 -0
  63. package/dist/wiki/infrastructure/scanner-adapter.d.ts.map +1 -0
  64. package/dist/wiki/infrastructure/scanner-adapter.js +147 -0
  65. package/dist/wiki/infrastructure/scanner-adapter.js.map +1 -0
  66. package/dist/wiki/infrastructure/sqlite-index.d.ts +9 -0
  67. package/dist/wiki/infrastructure/sqlite-index.d.ts.map +1 -0
  68. package/dist/wiki/infrastructure/sqlite-index.js +43 -0
  69. package/dist/wiki/infrastructure/sqlite-index.js.map +1 -0
  70. package/dist/wiki/infrastructure/trace-adapter.d.ts +7 -0
  71. package/dist/wiki/infrastructure/trace-adapter.d.ts.map +1 -0
  72. package/dist/wiki/infrastructure/trace-adapter.js +42 -0
  73. package/dist/wiki/infrastructure/trace-adapter.js.map +1 -0
  74. package/dist/wiki/infrastructure/wiki-ingest.d.ts +14 -0
  75. package/dist/wiki/infrastructure/wiki-ingest.d.ts.map +1 -0
  76. package/dist/wiki/infrastructure/wiki-ingest.js +138 -0
  77. package/dist/wiki/infrastructure/wiki-ingest.js.map +1 -0
  78. package/dist/wiki/infrastructure/wiki-query.d.ts +15 -0
  79. package/dist/wiki/infrastructure/wiki-query.d.ts.map +1 -0
  80. package/dist/wiki/infrastructure/wiki-query.js +58 -0
  81. package/dist/wiki/infrastructure/wiki-query.js.map +1 -0
  82. package/dist/wiki/infrastructure/wiki-schema.d.ts +3 -0
  83. package/dist/wiki/infrastructure/wiki-schema.d.ts.map +1 -0
  84. package/dist/wiki/infrastructure/wiki-schema.js +43 -0
  85. package/dist/wiki/infrastructure/wiki-schema.js.map +1 -0
  86. package/dist/wiki/interface/cli.d.ts +7 -0
  87. package/dist/wiki/interface/cli.d.ts.map +1 -0
  88. package/dist/wiki/interface/cli.js +160 -0
  89. package/dist/wiki/interface/cli.js.map +1 -0
  90. package/dist/wiki/render.d.ts +3 -0
  91. package/dist/wiki/render.d.ts.map +1 -0
  92. package/dist/wiki/render.js +58 -0
  93. package/dist/wiki/render.js.map +1 -0
  94. package/package.json +1 -1
@@ -0,0 +1,106 @@
1
+ // TS port of the MeowKit scanners so the wiki gate ships in dist/ (the repo-root
2
+ // .cjs files live outside this package's rootDir and would NOT be emitted).
3
+ // MIRROR these sources pattern-for-pattern when they change:
4
+ // - plugin/hooks/lib/validate-content.cjs → INJECTION_PATTERNS + validateContent
5
+ // - plugin/hooks/lib/secret-scrub.cjs → SECRET_PATTERNS + scrubSecrets
6
+ // Local additions cite web-to-markdown security.md Layer 5 (injection) / Layer 7 (secrets).
7
+ // A parity test (scanner-adapter.test.ts) asserts a shared payload set behaves identically
8
+ // in the .cjs source and this port.
9
+ /** Injection patterns. First 8 are verbatim from validate-content.cjs; the rest are the
10
+ * web-to-markdown Layer 5 local additions (tool-call hijack, memory poisoning, role-play). */
11
+ export const INJECTION_PATTERNS = [
12
+ /ignore\s+(?:previous|all)\s+instructions/i,
13
+ /disregard\s+(?:rules|instructions|safety)/i,
14
+ /you\s+are\s+now/i,
15
+ /forget\s+your/i,
16
+ /new\s+system\s+prompt/i,
17
+ /<\/?memory-data[^>]*>/i,
18
+ /pretend\s+you\s+are/i,
19
+ /act\s+as\s+if/i,
20
+ // web-to-markdown Layer 5 local additions:
21
+ /your\s+(?:previous\s+)?instructions\s+(?:have\s+been\s+)?updated/i,
22
+ /call\s+the\s+\w+\s+tool/i,
23
+ /use\s+the\s+(?:bash|write|edit|read)\s+tool/i,
24
+ /add\s+this\s+to\s+your\s+memory/i,
25
+ /\bDAN\s+mode\b/i,
26
+ /you'?re\s+an?\s+uncensored/i,
27
+ // Security-audit additions (instruction-override / exfil / jailbreak / role-play):
28
+ /\bjailbreak\b/i,
29
+ /(?:reveal|print|repeat|show)\s+(?:your|the)\s+(?:system\s+)?(?:prompt|instructions)/i,
30
+ /(?:override|bypass|ignore)\s+(?:the\s+)?(?:safety|security|content)\s+(?:filter|policy|guidelines)/i,
31
+ /without\s+(?:any\s+)?restrictions?/i,
32
+ /exfiltrat/i,
33
+ /(?:send|post|upload|leak)\s+(?:the\s+)?(?:secret|token|password|api[_-]?key|env|credentials?)/i,
34
+ /do\s+not\s+(?:tell|inform|alert|warn)\s+(?:the\s+)?(?:user|human)/i,
35
+ /system\s*:\s*you\s+(?:are|must)/i,
36
+ /developer\s+mode\s+(?:enabled|on)/i,
37
+ // Expansion toward web-to-markdown Layer-5 parity. Scoped to ASSISTANT-DIRECTED
38
+ // phrasings only — generic shell/code terms (curl, rm -rf, execute) are intentionally NOT
39
+ // here, since a dev-knowledge wiki carries legitimate shell examples (avoid false-positive
40
+ // quarantine of real content).
41
+ /from\s+now\s+on[, ]+you\s+(?:are|will|must|should)/i,
42
+ /stay\s+in\s+character/i,
43
+ /roleplay\s+as/i,
44
+ /act\s+as\s+(?:an?\s+)?(?:dan|jailbroken|unfiltered|uncensored)/i,
45
+ /this\s+is\s+(?:just\s+)?a\s+test\s+of\s+your/i,
46
+ /decode\s+the\s+following\s+(?:base64|rot13|text|string)/i,
47
+ /\bsudo\s+mode\b/i,
48
+ /disable\s+(?:your\s+)?(?:safety|guardrails?|filters?)/i,
49
+ /turn\s+off\s+(?:your\s+)?safety/i,
50
+ /send\s+(?:it|this|them|the\s+\w+)\s+to\s+https?:\/\//i,
51
+ /(?:post|upload)\s+(?:the\s+)?(?:secret|token|key|data|env|file)\s+to\b/i,
52
+ /what\s+(?:is|are)\s+your\s+(?:initial\s+|original\s+)?instructions/i,
53
+ /repeat\s+the\s+(?:words|text|content)\s+above/i,
54
+ /ignore\s+(?:the\s+)?(?:above|preceding|prior)\b/i,
55
+ /override\s+(?:your\s+)?(?:prior|previous)\s+(?:directives|rules|instructions)/i,
56
+ /new\s+persona\b/i,
57
+ ];
58
+ /** Mirror of validate-content.cjs: {valid:true} on pass (no pattern/match);
59
+ * {valid:false, pattern, match} on the first hit. */
60
+ export function validateContent(text) {
61
+ if (!text)
62
+ return { valid: true };
63
+ for (const pattern of INJECTION_PATTERNS) {
64
+ const match = text.match(pattern);
65
+ if (match)
66
+ return { valid: false, pattern: pattern.source, match: match[0] };
67
+ }
68
+ return { valid: true };
69
+ }
70
+ /** Secret patterns, ported verbatim from secret-scrub.cjs. Conservative: false positives
71
+ * accepted, missed secrets are not. Each entry is [matcher, replacement]. */
72
+ export const SECRET_PATTERNS = [
73
+ [/sk-ant-[A-Za-z0-9_-]{20,}/g, "[REDACTED-ANTHROPIC-KEY]"],
74
+ [/sk-[A-Za-z0-9_-]{20,}/g, "[REDACTED-OPENAI-KEY]"],
75
+ [/sk_(live|test)_[A-Za-z0-9]{16,}/g, "[REDACTED-STRIPE-KEY]"],
76
+ [/rk_(live|test)_[A-Za-z0-9]{16,}/g, "[REDACTED-STRIPE-RESTRICTED-KEY]"],
77
+ [/pk_(live|test)_[A-Za-z0-9]{16,}/g, "[REDACTED-STRIPE-PUB-KEY]"],
78
+ [/AKIA[0-9A-Z]{16}/g, "[REDACTED-AWS-KEY]"],
79
+ [/ghp_[A-Za-z0-9]{30,}/g, "[REDACTED-GH-TOKEN]"],
80
+ [/gho_[A-Za-z0-9]{30,}/g, "[REDACTED-GH-OAUTH]"],
81
+ [/glpat-[A-Za-z0-9_-]{20,}/g, "[REDACTED-GITLAB-PAT]"],
82
+ [/xox[bpars]-[0-9]+-[0-9]+-[0-9]+-[A-Za-z0-9]{24,}/g, "[REDACTED-SLACK-TOKEN]"],
83
+ [/https:\/\/hooks\.slack\.com\/services\/[A-Z0-9/]+/g, "[REDACTED-SLACK-WEBHOOK]"],
84
+ [/eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]{20,}/g, "[REDACTED-JWT]"],
85
+ [/-----BEGIN [A-Z ]*PRIVATE KEY-----[^-]*-----END [A-Z ]*PRIVATE KEY-----/g, "[REDACTED-PRIVATE-KEY]"],
86
+ [/(api[_-]?key|apikey|password|passwd|secret|token)(\s*[:=]\s*)["']?[A-Za-z0-9_/+=.-]{16,}["']?/gi, "$1$2[REDACTED]"],
87
+ [/Bearer [A-Za-z0-9_/+=.-]{20,}/g, "Bearer [REDACTED]"],
88
+ [/(mysql|postgres|postgresql|mongodb|redis):\/\/[^\s"']+/gi, "$1://[REDACTED-DB-URL]"],
89
+ [/[A-Za-z0-9._%+-]{3,}@[A-Za-z0-9.-]{3,}\.[A-Za-z]{2,}/g, "[REDACTED-EMAIL]"],
90
+ [/(MEOWKIT_[A-Z_]*(?:KEY|SECRET|TOKEN|PASSWORD))(\s*=\s*)\S{8,}/g, "$1$2[REDACTED]"],
91
+ ];
92
+ /** Mirror of secret-scrub.cjs scrubSecrets. */
93
+ export function scrubSecrets(input) {
94
+ if (typeof input !== "string" || !input)
95
+ return "";
96
+ let out = input;
97
+ for (const [re, replacement] of SECRET_PATTERNS)
98
+ out = out.replace(re, replacement);
99
+ return out;
100
+ }
101
+ /** Strip zero-width chars and apply NFKC (catches homoglyph/zero-width obfuscation),
102
+ * per web-to-markdown Layer 5 pass 1. */
103
+ export function normalizeForScan(text) {
104
+ return text.replace(/[​‌‍]/g, "").normalize("NFKC");
105
+ }
106
+ //# sourceMappingURL=scan-patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan-patterns.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/scan-patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { Scanner, ScanInput, ScanOutput } from "../application/ports.js";
2
+ /** Wiki draft size ceiling (bytes). Smaller than the 10MB web-fetch cap — a single page draft. */
3
+ export declare const MAX_CONTENT_BYTES = 1000000;
4
+ /** Port of web-to-markdown Layer 2 `_safe_url`: http(s) only, no credentials-in-URL, no
5
+ * private/loopback/link-local/metadata hosts (IPv4, IPv6, IPv4-mapped, bare-decimal, octal). */
6
+ export declare function isSafeSourceUrl(raw: string): boolean;
7
+ export declare class ScannerAdapter implements Scanner {
8
+ scan(input: ScanInput): ScanOutput;
9
+ }
10
+ //# sourceMappingURL=scanner-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner-adapter.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/scanner-adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAU9E,kGAAkG;AAClG,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAkC3C;gGACgG;AAChG,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAcpD;AAqDD,qBAAa,cAAe,YAAW,OAAO;IAC7C,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU;CAyBlC"}
@@ -0,0 +1,147 @@
1
+ import { normalizeForScan, scrubSecrets, validateContent } from "./scan-patterns.js";
2
+ // The security gate (web-to-markdown layers): URL-guard → size cap → normalize
3
+ // → multi-pass injection scan (plaintext + base64 + ROT13 + percent-decode) → flood check
4
+ // → secret scrub. Detection only — quarantine IO and the write-token mint happen in the
5
+ // repository/application so this stays pure and unit-testable. External + agent content is DATA.
6
+ // Carry-forward to the fetcher re-audit: hex IP encodings, redirect re-validation, and
7
+ // full web-to-markdown Layer-5 pattern parity (this layer has no live network egress yet).
8
+ /** Wiki draft size ceiling (bytes). Smaller than the 10MB web-fetch cap — a single page draft. */
9
+ export const MAX_CONTENT_BYTES = 1_000_000;
10
+ /** Scan passes performed on clean content — satisfies the domain MIN_SCAN_PASSES floor. */
11
+ const SCAN_PASSES = 4;
12
+ const BLOCKED_V4 = /^(10\.|127\.|169\.254\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.|198\.1[89]\.)/;
13
+ function isBlockedIpv4(host) {
14
+ if (/^0x/i.test(host))
15
+ return true; // hex IP encoding (e.g. 0x7f000001) — no legit host starts 0x
16
+ if (/^\d+$/.test(host))
17
+ return true; // bare-decimal IP encoding (e.g. 2130706433 = 127.0.0.1)
18
+ if (/^0[0-9.]/.test(host))
19
+ return true; // octal leading-zero encoding (e.g. 0177.0.0.1)
20
+ if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host))
21
+ return host === "0.0.0.0" || BLOCKED_V4.test(host);
22
+ return false;
23
+ }
24
+ function isBlockedIpv6(addr) {
25
+ const a = addr.toLowerCase();
26
+ if (a === "::1")
27
+ return true; // loopback
28
+ if (a.startsWith("fe80:"))
29
+ return true; // link-local
30
+ if (/^f[cd][0-9a-f]{0,2}:/.test(a))
31
+ return true; // ULA fc00::/7 (colon-anchored — no longer matches fcc.com)
32
+ // IPv4-mapped, dotted form: ::ffff:169.254.169.254
33
+ const dotted = a.match(/::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/);
34
+ if (dotted)
35
+ return isBlockedIpv4(dotted[1]);
36
+ // IPv4-mapped, hex-compressed form the URL parser emits: ::ffff:a9fe:a9fe
37
+ const hex = a.match(/::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/);
38
+ if (hex) {
39
+ const hi = parseInt(hex[1], 16);
40
+ const lo = parseInt(hex[2], 16);
41
+ const v4 = ((hi >> 8) & 0xff) + "." + (hi & 0xff) + "." + ((lo >> 8) & 0xff) + "." + (lo & 0xff);
42
+ return isBlockedIpv4(v4);
43
+ }
44
+ return false;
45
+ }
46
+ /** Port of web-to-markdown Layer 2 `_safe_url`: http(s) only, no credentials-in-URL, no
47
+ * private/loopback/link-local/metadata hosts (IPv4, IPv6, IPv4-mapped, bare-decimal, octal). */
48
+ export function isSafeSourceUrl(raw) {
49
+ let url;
50
+ try {
51
+ url = new URL(raw);
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ if (url.protocol !== "http:" && url.protocol !== "https:")
57
+ return false;
58
+ if (url.username || url.password)
59
+ return false;
60
+ const host = url.hostname.toLowerCase();
61
+ if (host.startsWith("[") && host.endsWith("]"))
62
+ return !isBlockedIpv6(host.slice(1, -1));
63
+ if (host === "localhost" || host.endsWith(".localhost"))
64
+ return false;
65
+ if (host === "metadata.google.internal" || /^metadata\./.test(host))
66
+ return false;
67
+ return !isBlockedIpv4(host);
68
+ }
69
+ function rot13(text) {
70
+ return text.replace(/[a-zA-Z]/g, (c) => {
71
+ const base = c <= "Z" ? 65 : 97;
72
+ return String.fromCharCode(((c.charCodeAt(0) - base + 13) % 26) + base);
73
+ });
74
+ }
75
+ function percentDecode(text) {
76
+ try {
77
+ return decodeURIComponent(text);
78
+ }
79
+ catch {
80
+ return text; // malformed %-sequence — scan the raw form instead
81
+ }
82
+ }
83
+ /** Extract HTML-comment bodies so injection hidden in <!-- ... --> is scanned, not skipped. */
84
+ function extractHtmlComments(text) {
85
+ return [...text.matchAll(/<!--([\s\S]*?)-->/g)].map((m) => m[1]);
86
+ }
87
+ /** Decode base64 blocks (≥16 chars catches short payloads) and return decoded strings to re-scan. */
88
+ function decodeBase64Blocks(text) {
89
+ const out = [];
90
+ for (const m of text.matchAll(/[A-Za-z0-9+/]{16,}={0,2}/g)) {
91
+ try {
92
+ const decoded = Buffer.from(m[0], "base64").toString("utf-8");
93
+ if (decoded && /[ -~]/.test(decoded))
94
+ out.push(decoded);
95
+ }
96
+ catch {
97
+ // not valid base64 — ignore
98
+ }
99
+ }
100
+ return out;
101
+ }
102
+ /** Context-flooding heuristic (injection-rules R9): large + highly repetitive content. */
103
+ function isFlood(text) {
104
+ if (text.length <= 5000)
105
+ return false;
106
+ const lines = text.split("\n");
107
+ if (lines.length >= 10)
108
+ return 1 - new Set(lines).size / lines.length > 0.3;
109
+ return new Set(text).size / text.length < 0.05;
110
+ }
111
+ function findInjection(passes) {
112
+ const findings = [];
113
+ for (const text of passes) {
114
+ const result = validateContent(text);
115
+ if (!result.valid && result.pattern)
116
+ findings.push(result.pattern);
117
+ }
118
+ return findings;
119
+ }
120
+ export class ScannerAdapter {
121
+ scan(input) {
122
+ const fail = (finding) => ({
123
+ verdict: { status: "injection", passes: SCAN_PASSES, findings: [finding] },
124
+ scrubbed: "",
125
+ secretsFound: false,
126
+ });
127
+ if (input.sourceUrl && !isSafeSourceUrl(input.sourceUrl))
128
+ return fail("unsafe-source-url");
129
+ if (Buffer.byteLength(input.content, "utf-8") > MAX_CONTENT_BYTES)
130
+ return fail("size-cap-exceeded");
131
+ const normalized = normalizeForScan(input.content);
132
+ const findings = findInjection([
133
+ normalized,
134
+ percentDecode(normalized),
135
+ rot13(normalized),
136
+ ...decodeBase64Blocks(normalized),
137
+ ...extractHtmlComments(normalized),
138
+ ]);
139
+ if (isFlood(normalized))
140
+ findings.push("context-flood");
141
+ const status = findings.length > 0 ? "injection" : "clean";
142
+ const scrubbed = scrubSecrets(normalized);
143
+ const verdict = { status, passes: SCAN_PASSES, findings };
144
+ return { verdict, scrubbed, secretsFound: scrubbed !== normalized };
145
+ }
146
+ }
147
+ //# sourceMappingURL=scanner-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner-adapter.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/scanner-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { WikiPage } from "../domain/index.js";
2
+ import type { WikiIndex, WikiSearchHit } from "../application/ports.js";
3
+ export declare class SqliteWikiIndex implements WikiIndex {
4
+ private readonly dbFile;
5
+ constructor(dbFile: string);
6
+ upsertPage(page: WikiPage): void;
7
+ searchFts(query: string, limit?: number): WikiSearchHit[];
8
+ }
9
+ //# sourceMappingURL=sqlite-index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-index.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/sqlite-index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAUxE,qBAAa,eAAgB,YAAW,SAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,MAAM;IAE3C,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAoChC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,aAAa,EAAE;CAGrD"}
@@ -0,0 +1,43 @@
1
+ import { DatabaseSync } from "node:sqlite";
2
+ import { searchWiki } from "./wiki-query.js";
3
+ import { ensureIndexSchema } from "../../core/derived-index.js";
4
+ // Live read/upsert adapter over the consolidated wiki-index.db. Reads go
5
+ // through the read-only searchWiki helper; the single live mutation is page upsert. Upsert is
6
+ // an explicit DELETE then INSERT (not INSERT OR REPLACE): the explicit DELETE always fires the
7
+ // wiki_page AFTER DELETE trigger, keeping wiki_fts in sync — REPLACE's implicit delete would
8
+ // not fire it under the default recursive_triggers=off and would strand a duplicate FTS row.
9
+ export class SqliteWikiIndex {
10
+ dbFile;
11
+ constructor(dbFile) {
12
+ this.dbFile = dbFile;
13
+ }
14
+ upsertPage(page) {
15
+ const db = new DatabaseSync(this.dbFile);
16
+ try {
17
+ db.exec("PRAGMA journal_mode = WAL");
18
+ // The derived index is opt-in: nothing builds it before the first canonical write.
19
+ // Opening it here with a raw DatabaseSync also CREATES an empty file, so without this
20
+ // the very first `approve` on a fresh wiki throws `no such table: wiki_page`. Migrate
21
+ // (idempotent) so upsert self-heals a never-built index instead of requiring a prior
22
+ // `mewkit index` / `wiki reindex`.
23
+ ensureIndexSchema(db);
24
+ db.exec("BEGIN IMMEDIATE");
25
+ try {
26
+ db.prepare("DELETE FROM wiki_page WHERE id = ?").run(page.id);
27
+ db.prepare("INSERT INTO wiki_page (id, slug, title, path, content, state, origin, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)").run(page.id, page.slug, page.title, page.path, page.content, page.state, page.provenance.origin, page.createdAt, page.updatedAt);
28
+ db.exec("COMMIT");
29
+ }
30
+ catch (err) {
31
+ db.exec("ROLLBACK");
32
+ throw err;
33
+ }
34
+ }
35
+ finally {
36
+ db.close();
37
+ }
38
+ }
39
+ searchFts(query, limit = 10) {
40
+ return searchWiki(this.dbFile, query, limit);
41
+ }
42
+ }
43
+ //# sourceMappingURL=sqlite-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sqlite-index.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/sqlite-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAEhE,yEAAyE;AACzE,8FAA8F;AAC9F,+FAA+F;AAC/F,6FAA6F;AAC7F,6FAA6F;AAE7F,MAAM,OAAO,eAAe;IACE;IAA7B,YAA6B,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAE/C,UAAU,CAAC,IAAc;QACxB,MAAM,EAAE,GAAG,IAAI,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,CAAC;YACJ,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YACrC,mFAAmF;YACnF,sFAAsF;YACtF,sFAAsF;YACtF,qFAAqF;YACrF,mCAAmC;YACnC,iBAAiB,CAAC,EAAE,CAAC,CAAC;YACtB,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC3B,IAAI,CAAC;gBACJ,EAAE,CAAC,OAAO,CAAC,oCAAoC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC9D,EAAE,CAAC,OAAO,CACT,kIAAkI,CAClI,CAAC,GAAG,CACJ,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,IAAI,EACT,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,UAAU,CAAC,MAAM,EACtB,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,SAAS,CACd,CAAC;gBACF,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACd,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBACpB,MAAM,GAAG,CAAC;YACX,CAAC;QACF,CAAC;gBAAS,CAAC;YACV,EAAE,CAAC,KAAK,EAAE,CAAC;QACZ,CAAC;IACF,CAAC;IAED,SAAS,CAAC,KAAa,EAAE,KAAK,GAAG,EAAE;QAClC,OAAO,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9C,CAAC;CACD"}
@@ -0,0 +1,7 @@
1
+ import type { Tracer } from "../application/ports.js";
2
+ export declare class TraceAdapter implements Tracer {
3
+ private readonly claudeDir;
4
+ constructor(claudeDir: string);
5
+ recordWikiTrace(event: string, data: Record<string, unknown>): void;
6
+ }
7
+ //# sourceMappingURL=trace-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-adapter.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/trace-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAoBtD,qBAAa,YAAa,YAAW,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAAT,SAAS,EAAE,MAAM;IAE9C,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;CAcnE"}
@@ -0,0 +1,42 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { scrubSecrets } from "./scan-patterns.js";
4
+ // Appends wiki trace events to .claude/memory/trace-log.jsonl. Re-implements the JSONL
5
+ // append + redaction because the only existing writer (commands/trace.ts recordFriction)
6
+ // is private and hardcodes event:"friction". Fixed line shape:
7
+ // {schema_version:"1.0", ts, event, run_id, model, density, data:{...}}
8
+ // Every string value in `data` is secret-scrubbed before it is written.
9
+ function scrubDeep(value) {
10
+ if (typeof value === "string")
11
+ return scrubSecrets(value);
12
+ if (Array.isArray(value))
13
+ return value.map(scrubDeep);
14
+ if (value && typeof value === "object") {
15
+ const out = {};
16
+ for (const [k, v] of Object.entries(value))
17
+ out[k] = scrubDeep(v);
18
+ return out;
19
+ }
20
+ return value;
21
+ }
22
+ export class TraceAdapter {
23
+ claudeDir;
24
+ constructor(claudeDir) {
25
+ this.claudeDir = claudeDir;
26
+ }
27
+ recordWikiTrace(event, data) {
28
+ const line = {
29
+ schema_version: "1.0",
30
+ ts: new Date().toISOString(),
31
+ event,
32
+ run_id: process.env["MEOWKIT_RUN_ID"] ?? "",
33
+ model: process.env["MEOWKIT_MODEL_HINT"] ?? "",
34
+ density: process.env["MEOWKIT_AUTOBUILD_MODE"] ?? "",
35
+ data: scrubDeep(data),
36
+ };
37
+ const logPath = path.join(this.claudeDir, "memory", "trace-log.jsonl");
38
+ fs.mkdirSync(path.dirname(logPath), { recursive: true });
39
+ fs.appendFileSync(logPath, JSON.stringify(line) + "\n", "utf-8");
40
+ }
41
+ }
42
+ //# sourceMappingURL=trace-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-adapter.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/trace-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,uFAAuF;AACvF,yFAAyF;AACzF,+DAA+D;AAC/D,0EAA0E;AAC1E,wEAAwE;AAExE,SAAS,SAAS,CAAC,KAAc;IAChC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACtD,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,GAAG,GAA4B,EAAE,CAAC;QACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAClE,OAAO,GAAG,CAAC;IACZ,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,MAAM,OAAO,YAAY;IACK;IAA7B,YAA6B,SAAiB;QAAjB,cAAS,GAAT,SAAS,CAAQ;IAAG,CAAC;IAElD,eAAe,CAAC,KAAa,EAAE,IAA6B;QAC3D,MAAM,IAAI,GAAG;YACZ,cAAc,EAAE,KAAK;YACrB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,KAAK;YACL,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE;YAC3C,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,EAAE;YAC9C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,IAAI,EAAE;YACpD,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC;SACrB,CAAC;QACF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,iBAAiB,CAAC,CAAC;QACvE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzD,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;IAClE,CAAC;CACD"}
@@ -0,0 +1,14 @@
1
+ import type { DatabaseSync } from "node:sqlite";
2
+ export interface WikiIngestCounts {
3
+ wikis: number;
4
+ pages: number;
5
+ sources: number;
6
+ claims: number;
7
+ candidates: number;
8
+ seeds: number;
9
+ interventions: number;
10
+ links: number;
11
+ }
12
+ /** Clear and rebuild every wiki table from the canonical tree. Returns row counts. */
13
+ export declare function ingestWiki(db: DatabaseSync, projectRoot: string): WikiIngestCounts;
14
+ //# sourceMappingURL=wiki-ingest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-ingest.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/wiki-ingest.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAShD,MAAM,WAAW,gBAAgB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACd;AA0JD,sFAAsF;AACtF,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAUlF"}
@@ -0,0 +1,138 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import yaml from "js-yaml";
4
+ import { WIKI_TABLES } from "./wiki-schema.js";
5
+ function s(v) {
6
+ if (v === null || v === undefined)
7
+ return null;
8
+ return typeof v === "string" ? v : String(v);
9
+ }
10
+ function n(v) {
11
+ return typeof v === "number" && Number.isFinite(v) ? v : null;
12
+ }
13
+ function readJsonl(file) {
14
+ if (!fs.existsSync(file))
15
+ return [];
16
+ const out = [];
17
+ for (const line of fs.readFileSync(file, "utf-8").split("\n")) {
18
+ const trimmed = line.trim();
19
+ if (!trimmed)
20
+ continue;
21
+ try {
22
+ const parsed = JSON.parse(trimmed);
23
+ if (parsed && typeof parsed === "object")
24
+ out.push(parsed);
25
+ }
26
+ catch {
27
+ // tolerant: skip a malformed line, keep ingesting the rest
28
+ }
29
+ }
30
+ return out;
31
+ }
32
+ function parseFrontmatter(raw) {
33
+ if (!raw.startsWith("---"))
34
+ return { meta: {}, body: raw };
35
+ const end = raw.indexOf("\n---", 3);
36
+ if (end === -1)
37
+ return { meta: {}, body: raw };
38
+ const loaded = yaml.load(raw.slice(3, end).trim());
39
+ const meta = loaded && typeof loaded === "object" ? loaded : {};
40
+ return { meta, body: raw.slice(end + 4).replace(/^\r?\n/, "") };
41
+ }
42
+ function listDirs(root) {
43
+ if (!fs.existsSync(root))
44
+ return [];
45
+ return fs
46
+ .readdirSync(root, { withFileTypes: true })
47
+ .filter((e) => e.isDirectory())
48
+ .map((e) => e.name)
49
+ .sort();
50
+ }
51
+ function ingestSlug(db, root, slug, c) {
52
+ const dir = path.join(root, slug);
53
+ const wikiMeta = (() => {
54
+ const f = path.join(dir, "wiki.json");
55
+ if (!fs.existsSync(f))
56
+ return { slug };
57
+ try {
58
+ const parsed = JSON.parse(fs.readFileSync(f, "utf-8"));
59
+ return parsed && typeof parsed === "object" ? parsed : { slug };
60
+ }
61
+ catch {
62
+ return { slug };
63
+ }
64
+ })();
65
+ db.prepare("INSERT OR REPLACE INTO wiki (slug, title, created_at, updated_at) VALUES (?, ?, ?, ?)").run(slug, s(wikiMeta["title"]) ?? slug, s(wikiMeta["createdAt"]), s(wikiMeta["updatedAt"]));
66
+ c.wikis += 1;
67
+ // OR IGNORE (not OR REPLACE): two files claiming the same id is malformed input;
68
+ // ignoring the later one keeps ingest crash-free AND keeps wiki_fts consistent —
69
+ // REPLACE's implicit delete does NOT fire the AFTER DELETE trigger under the default
70
+ // recursive_triggers=off, which would strand a duplicate FTS row. First file wins
71
+ // (files are read in sorted order, so the choice is deterministic).
72
+ const pageStmt = db.prepare("INSERT OR IGNORE INTO wiki_page (id, slug, title, path, content, state, origin, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
73
+ const linkStmt = db.prepare("INSERT OR IGNORE INTO wiki_link (from_page_id, to_page_id) VALUES (?, ?)");
74
+ const pagesDir = path.join(dir, "pages");
75
+ if (fs.existsSync(pagesDir)) {
76
+ for (const file of fs.readdirSync(pagesDir).filter((f) => f.endsWith(".md")).sort()) {
77
+ const { meta, body } = parseFrontmatter(fs.readFileSync(path.join(pagesDir, file), "utf-8"));
78
+ const id = s(meta["id"]) ?? `${slug}/${file}`;
79
+ const inserted = pageStmt.run(id, s(meta["slug"]) ?? slug, s(meta["title"]) ?? file.replace(/\.md$/, ""), `pages/${file}`, body, s(meta["state"]) ?? "committed", s(meta["origin"]) ?? "human", s(meta["createdAt"]), s(meta["updatedAt"])).changes > 0;
80
+ if (!inserted)
81
+ continue; // duplicate id ignored — skip the page and its links
82
+ c.pages += 1;
83
+ const links = Array.isArray(meta["links"]) ? meta["links"] : [];
84
+ for (const to of links) {
85
+ const toId = s(to);
86
+ if (toId) {
87
+ linkStmt.run(id, toId);
88
+ c.links += 1;
89
+ }
90
+ }
91
+ }
92
+ }
93
+ const srcStmt = db.prepare("INSERT OR REPLACE INTO wiki_source (id, kind, url, title, fetched_at, content_hash) VALUES (?, ?, ?, ?, ?, ?)");
94
+ for (const o of readJsonl(path.join(dir, "sources.jsonl"))) {
95
+ srcStmt.run(s(o["id"]), s(o["kind"]), s(o["url"]), s(o["title"]), s(o["fetchedAt"]), s(o["contentHash"]));
96
+ c.sources += 1;
97
+ }
98
+ const claimStmt = db.prepare("INSERT OR REPLACE INTO wiki_claim (id, text, external, source_id, page_id) VALUES (?, ?, ?, ?, ?)");
99
+ for (const o of readJsonl(path.join(dir, "claims.jsonl"))) {
100
+ claimStmt.run(s(o["id"]), s(o["text"]), o["external"] ? 1 : 0, s(o["sourceId"]), s(o["pageId"]));
101
+ c.claims += 1;
102
+ }
103
+ const seedStmt = db.prepare("INSERT OR REPLACE INTO wiki_seed (id, query, kind, status, created_at) VALUES (?, ?, ?, ?, ?)");
104
+ for (const o of readJsonl(path.join(dir, "seeds.jsonl"))) {
105
+ seedStmt.run(s(o["id"]), s(o["query"]), s(o["kind"]), s(o["status"]), s(o["createdAt"]));
106
+ c.seeds += 1;
107
+ }
108
+ const candStmt = db.prepare("INSERT OR REPLACE INTO wiki_candidate (id, slug, origin, title, content, why_save, evidence, novelty_delta, reuse_scope, verification_state, risk_score, salience_total, state, created_at, review_after) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
109
+ const salStmt = db.prepare("INSERT OR REPLACE INTO wiki_salience (candidate_id, explicit_user_intent, verified_outcome, recurrence_or_friction, novelty_vs_existing_wiki, future_reuse_likelihood, source_quality, blast_radius, security_risk_penalty, staleness_penalty, total) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
110
+ for (const o of readJsonl(path.join(dir, "candidates.jsonl"))) {
111
+ const id = s(o["id"]);
112
+ const sal = (o["salience"] && typeof o["salience"] === "object" ? o["salience"] : {});
113
+ const comp = (sal["components"] && typeof sal["components"] === "object" ? sal["components"] : {});
114
+ candStmt.run(id, s(o["slug"]) ?? slug, s(o["origin"]) ?? "agent", s(o["title"]) ?? "", s(o["content"]) ?? "", s(o["whySave"]), s(o["evidence"]), n(o["noveltyDelta"]), s(o["reuseScope"]), s(o["verificationState"]), n(o["riskScore"]), n(sal["total"]), s(o["state"]) ?? "proposed", s(o["createdAt"]), s(o["reviewAfter"]));
115
+ if (id) {
116
+ salStmt.run(id, n(comp["explicit_user_intent"]), n(comp["verified_outcome"]), n(comp["recurrence_or_friction"]), n(comp["novelty_vs_existing_wiki"]), n(comp["future_reuse_likelihood"]), n(comp["source_quality"]), n(comp["blast_radius"]), n(comp["security_risk_penalty"]), n(comp["staleness_penalty"]), n(sal["total"]));
117
+ }
118
+ c.candidates += 1;
119
+ }
120
+ const intStmt = db.prepare("INSERT OR REPLACE INTO wiki_intervention (id, kind, candidate_id, reason, actor, created_at) VALUES (?, ?, ?, ?, ?, ?)");
121
+ for (const o of readJsonl(path.join(dir, "interventions.jsonl"))) {
122
+ intStmt.run(s(o["id"]), s(o["kind"]), s(o["candidateId"]), s(o["reason"]), s(o["actor"]), s(o["createdAt"]));
123
+ c.interventions += 1;
124
+ }
125
+ }
126
+ /** Clear and rebuild every wiki table from the canonical tree. Returns row counts. */
127
+ export function ingestWiki(db, projectRoot) {
128
+ const counts = { wikis: 0, pages: 0, sources: 0, claims: 0, candidates: 0, seeds: 0, interventions: 0, links: 0 };
129
+ for (const table of WIKI_TABLES) {
130
+ db.exec("DELETE FROM " + table); // table is a constant from WIKI_TABLES, never user input
131
+ }
132
+ const root = path.join(projectRoot, "tasks", "wikis");
133
+ for (const slug of listDirs(root)) {
134
+ ingestSlug(db, root, slug, counts);
135
+ }
136
+ return counts;
137
+ }
138
+ //# sourceMappingURL=wiki-ingest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-ingest.js","sourceRoot":"","sources":["../../../src/wiki/infrastructure/wiki-ingest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { WikiSearchHit } from "../application/ports.js";
2
+ export type { WikiSearchHit };
3
+ export type WikiPageRow = {
4
+ id: string;
5
+ slug: string;
6
+ title: string;
7
+ path: string;
8
+ state: string;
9
+ };
10
+ /** Full-text search over page title + body. Returns provenance (slug/path via the
11
+ * page id) and a snippet with a token-budget estimate. */
12
+ export declare function searchWiki(dbFile: string, query: string, limit?: number): WikiSearchHit[];
13
+ /** List committed/approved pages for a slug (or all slugs when omitted). */
14
+ export declare function listWikiPages(dbFile: string, slug?: string): WikiPageRow[];
15
+ //# sourceMappingURL=wiki-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wiki-query.d.ts","sourceRoot":"","sources":["../../../src/wiki/infrastructure/wiki-query.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAM7D,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B,MAAM,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACd,CAAC;AAgBF;0DAC0D;AAC1D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,aAAa,EAAE,CAoBrF;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,WAAW,EAAE,CAe1E"}