kirograph 0.22.0 → 0.26.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.
Files changed (62) hide show
  1. package/README.md +19 -5
  2. package/dist/bin/commands/configure-mcp.js +104 -0
  3. package/dist/bin/commands/configure-mcp.js.map +7 -0
  4. package/dist/bin/commands/memory.js +334 -2
  5. package/dist/bin/commands/memory.js.map +2 -2
  6. package/dist/bin/commands/wiki.js +307 -0
  7. package/dist/bin/commands/wiki.js.map +7 -0
  8. package/dist/bin/installer/common.js +9 -0
  9. package/dist/bin/installer/common.js.map +2 -2
  10. package/dist/bin/installer/config-prompt.js +96 -5
  11. package/dist/bin/installer/config-prompt.js.map +2 -2
  12. package/dist/bin/installer/hooks.js +40 -0
  13. package/dist/bin/installer/hooks.js.map +2 -2
  14. package/dist/bin/installer/index.js +22 -11
  15. package/dist/bin/installer/index.js.map +2 -2
  16. package/dist/bin/installer/instructions.js +27 -1
  17. package/dist/bin/installer/instructions.js.map +2 -2
  18. package/dist/bin/installer/mcp.js +37 -4
  19. package/dist/bin/installer/mcp.js.map +2 -2
  20. package/dist/bin/installer/prompts.js +3 -3
  21. package/dist/bin/installer/prompts.js.map +2 -2
  22. package/dist/bin/installer/steering.js +633 -291
  23. package/dist/bin/installer/steering.js.map +2 -2
  24. package/dist/bin/installer/targets/index.js.map +1 -1
  25. package/dist/bin/installer/targets/kiro.js +5 -4
  26. package/dist/bin/installer/targets/kiro.js.map +2 -2
  27. package/dist/bin/kirograph.js +3 -1
  28. package/dist/bin/kirograph.js.map +3 -3
  29. package/dist/config.js +52 -5
  30. package/dist/config.js.map +2 -2
  31. package/dist/db/database.js +11 -0
  32. package/dist/db/database.js.map +2 -2
  33. package/dist/db/memory-schema.sql +34 -1
  34. package/dist/db/wiki-schema.sql +40 -0
  35. package/dist/mcp/server.js +35 -11
  36. package/dist/mcp/server.js.map +2 -2
  37. package/dist/mcp/tool-names.js +112 -1
  38. package/dist/mcp/tool-names.js.map +2 -2
  39. package/dist/mcp/tools.js +458 -3
  40. package/dist/mcp/tools.js.map +2 -2
  41. package/dist/memory/database.js +131 -7
  42. package/dist/memory/database.js.map +2 -2
  43. package/dist/memory/index.js +130 -4
  44. package/dist/memory/index.js.map +3 -3
  45. package/dist/memory/types.js.map +1 -1
  46. package/dist/watchmen/synthesize.js +2 -0
  47. package/dist/watchmen/synthesize.js.map +2 -2
  48. package/dist/wiki/database.js +143 -0
  49. package/dist/wiki/database.js.map +7 -0
  50. package/dist/wiki/index.js +149 -0
  51. package/dist/wiki/index.js.map +7 -0
  52. package/dist/wiki/ingest.js +259 -0
  53. package/dist/wiki/ingest.js.map +7 -0
  54. package/dist/wiki/lint.js +93 -0
  55. package/dist/wiki/lint.js.map +7 -0
  56. package/dist/wiki/schema.js +148 -0
  57. package/dist/wiki/schema.js.map +7 -0
  58. package/dist/wiki/synthesize.js +104 -0
  59. package/dist/wiki/synthesize.js.map +7 -0
  60. package/dist/wiki/types.js +17 -0
  61. package/dist/wiki/types.js.map +7 -0
  62. package/package.json +5 -3
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var wiki_exports = {};
30
+ __export(wiki_exports, {
31
+ KiroGraphWiki: () => KiroGraphWiki
32
+ });
33
+ module.exports = __toCommonJS(wiki_exports);
34
+ var fs = __toESM(require("fs"));
35
+ var path = __toESM(require("path"));
36
+ var import_database = require("./database");
37
+ var import_schema = require("./schema");
38
+ var import_schema2 = require("./schema");
39
+ var import_ingest = require("./ingest");
40
+ var import_lint = require("./lint");
41
+ class KiroGraphWiki {
42
+ constructor(db, kirographDir, opts = {}) {
43
+ this.wikiDb = new import_database.WikiDatabase(db);
44
+ this.wikiDir = path.join(kirographDir, "wiki");
45
+ this.autoResolveConflicts = opts.autoResolveConflicts ?? false;
46
+ }
47
+ initialize() {
48
+ this.wikiDb.initialize();
49
+ fs.mkdirSync(this.wikiDir, { recursive: true });
50
+ }
51
+ // ── Init ───────────────────────────────────────────────────────────────────
52
+ initWiki() {
53
+ this.initialize();
54
+ const schemaPath = path.join(this.wikiDir, "SCHEMA.md");
55
+ if (!fs.existsSync(schemaPath)) {
56
+ fs.writeFileSync(schemaPath, import_schema.DEFAULT_SCHEMA, "utf8");
57
+ }
58
+ const manifestPath = path.join(this.wikiDir, "MANIFEST.md");
59
+ if (!fs.existsSync(manifestPath)) {
60
+ fs.writeFileSync(manifestPath, "# Wiki Manifest\n\n(empty)\n", "utf8");
61
+ }
62
+ }
63
+ // ── Ingest ─────────────────────────────────────────────────────────────────
64
+ /**
65
+ * Returns the ingest prompt for the LLM (agent mode).
66
+ * The agent uses this to produce a WIKI_DIFF, then calls applyDiff.
67
+ */
68
+ getIngestPrompt(source, sourceName = "source") {
69
+ this.initialize();
70
+ return (0, import_ingest.buildIngestPrompt)(this.wikiDir, source, sourceName);
71
+ }
72
+ // ── Queue (local synthesis mode) ──────────────────────────────────────────
73
+ queueSource(sourceText, sourceName) {
74
+ this.initialize();
75
+ this.wikiDb.queueSource(sourceName, sourceText);
76
+ }
77
+ getPendingQueue() {
78
+ this.initialize();
79
+ return this.wikiDb.getPendingQueue();
80
+ }
81
+ clearQueue() {
82
+ this.initialize();
83
+ this.wikiDb.clearQueue();
84
+ }
85
+ getQueueCount() {
86
+ this.initialize();
87
+ return this.wikiDb.getQueueCount();
88
+ }
89
+ async synthesize(modelName, quiet = false) {
90
+ this.initialize();
91
+ const { runWikiLocalSynthesis } = await Promise.resolve().then(() => require("./synthesize.js"));
92
+ return runWikiLocalSynthesis(this, modelName, quiet);
93
+ }
94
+ /**
95
+ * Parse and apply a WIKI_DIFF string produced by the LLM.
96
+ */
97
+ applyDiff(rawDiff) {
98
+ this.initialize();
99
+ const diff = (0, import_schema2.parseWikiDiff)(rawDiff);
100
+ return (0, import_ingest.applyDiff)(diff, this.wikiDir, this.wikiDb, {
101
+ autoResolveConflicts: this.autoResolveConflicts
102
+ });
103
+ }
104
+ // ── Search & Read ──────────────────────────────────────────────────────────
105
+ search(query, limit = 10) {
106
+ this.initialize();
107
+ return this.wikiDb.search(query, limit);
108
+ }
109
+ getPage(slug) {
110
+ this.initialize();
111
+ return this.wikiDb.getPage(slug);
112
+ }
113
+ listPages() {
114
+ this.initialize();
115
+ return this.wikiDb.listPages();
116
+ }
117
+ // ── Lint ───────────────────────────────────────────────────────────────────
118
+ lint() {
119
+ this.initialize();
120
+ return (0, import_lint.lintWiki)(this.wikiDb);
121
+ }
122
+ // ── Reindex ────────────────────────────────────────────────────────────────
123
+ reindex() {
124
+ this.initialize();
125
+ return (0, import_ingest.reindexFromDisk)(this.wikiDir, this.wikiDb);
126
+ }
127
+ // ── Stats ──────────────────────────────────────────────────────────────────
128
+ getStats() {
129
+ this.initialize();
130
+ return this.wikiDb.getStats();
131
+ }
132
+ // ── Context enrichment ────────────────────────────────────────────────────
133
+ /**
134
+ * Returns wiki pages relevant to a query, for inclusion in kirograph_context.
135
+ * Returns up to `limit` pages with score >= threshold.
136
+ */
137
+ getContextPages(query, limit = 3, threshold = 0.4) {
138
+ this.initialize();
139
+ return this.wikiDb.search(query, limit * 2).filter((r) => r.score >= threshold).slice(0, limit).map((r) => r.page);
140
+ }
141
+ get dir() {
142
+ return this.wikiDir;
143
+ }
144
+ }
145
+ // Annotate the CommonJS export names for ESM import in node:
146
+ 0 && (module.exports = {
147
+ KiroGraphWiki
148
+ });
149
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/wiki/index.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph Wiki \u2014 Public API\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { WikiDatabase } from './database';\nimport { DEFAULT_SCHEMA } from './schema';\nimport { parseWikiDiff } from './schema';\nimport { buildIngestPrompt, applyDiff, reindexFromDisk, updateManifest } from './ingest';\nimport { lintWiki } from './lint';\nimport type {\n WikiPage,\n ScoredWikiPage,\n WikiDiff,\n WikiLintIssue,\n WikiStats,\n} from './types';\n\nexport type { WikiPage, ScoredWikiPage, WikiDiff, WikiLintIssue, WikiStats };\n\nexport class KiroGraphWiki {\n private wikiDb: WikiDatabase;\n private wikiDir: string;\n private autoResolveConflicts: boolean;\n\n constructor(\n db: any,\n kirographDir: string,\n opts: { autoResolveConflicts?: boolean } = {}\n ) {\n this.wikiDb = new WikiDatabase(db);\n this.wikiDir = path.join(kirographDir, 'wiki');\n this.autoResolveConflicts = opts.autoResolveConflicts ?? false;\n }\n\n initialize(): void {\n this.wikiDb.initialize();\n fs.mkdirSync(this.wikiDir, { recursive: true });\n }\n\n // \u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n initWiki(): void {\n this.initialize();\n const schemaPath = path.join(this.wikiDir, 'SCHEMA.md');\n if (!fs.existsSync(schemaPath)) {\n fs.writeFileSync(schemaPath, DEFAULT_SCHEMA, 'utf8');\n }\n const manifestPath = path.join(this.wikiDir, 'MANIFEST.md');\n if (!fs.existsSync(manifestPath)) {\n fs.writeFileSync(manifestPath, '# Wiki Manifest\\n\\n(empty)\\n', 'utf8');\n }\n }\n\n // \u2500\u2500 Ingest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Returns the ingest prompt for the LLM (agent mode).\n * The agent uses this to produce a WIKI_DIFF, then calls applyDiff.\n */\n getIngestPrompt(source: string, sourceName = 'source'): string {\n this.initialize();\n return buildIngestPrompt(this.wikiDir, source, sourceName);\n }\n\n // \u2500\u2500 Queue (local synthesis mode) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n queueSource(sourceText: string, sourceName: string): void {\n this.initialize();\n this.wikiDb.queueSource(sourceName, sourceText);\n }\n\n getPendingQueue(): Array<{ id: number; sourceName: string; sourceText: string }> {\n this.initialize();\n return this.wikiDb.getPendingQueue();\n }\n\n clearQueue(): void {\n this.initialize();\n this.wikiDb.clearQueue();\n }\n\n getQueueCount(): number {\n this.initialize();\n return this.wikiDb.getQueueCount();\n }\n\n async synthesize(modelName: string, quiet = false) {\n this.initialize();\n const { runWikiLocalSynthesis } = await Promise.resolve().then(() => require('./synthesize.js'));\n return runWikiLocalSynthesis(this, modelName, quiet);\n }\n\n /**\n * Parse and apply a WIKI_DIFF string produced by the LLM.\n */\n applyDiff(rawDiff: string) {\n this.initialize();\n const diff = parseWikiDiff(rawDiff);\n return applyDiff(diff, this.wikiDir, this.wikiDb, {\n autoResolveConflicts: this.autoResolveConflicts,\n });\n }\n\n // \u2500\u2500 Search & Read \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n search(query: string, limit = 10): ScoredWikiPage[] {\n this.initialize();\n return this.wikiDb.search(query, limit);\n }\n\n getPage(slug: string): WikiPage | null {\n this.initialize();\n return this.wikiDb.getPage(slug);\n }\n\n listPages(): WikiPage[] {\n this.initialize();\n return this.wikiDb.listPages();\n }\n\n // \u2500\u2500 Lint \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n lint(): WikiLintIssue[] {\n this.initialize();\n return lintWiki(this.wikiDb);\n }\n\n // \u2500\u2500 Reindex \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n reindex(): number {\n this.initialize();\n return reindexFromDisk(this.wikiDir, this.wikiDb);\n }\n\n // \u2500\u2500 Stats \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n getStats(): WikiStats {\n this.initialize();\n return this.wikiDb.getStats();\n }\n\n // \u2500\u2500 Context enrichment \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n /**\n * Returns wiki pages relevant to a query, for inclusion in kirograph_context.\n * Returns up to `limit` pages with score >= threshold.\n */\n getContextPages(query: string, limit = 3, threshold = 0.4): WikiPage[] {\n this.initialize();\n return this.wikiDb\n .search(query, limit * 2)\n .filter(r => r.score >= threshold)\n .slice(0, limit)\n .map(r => r.page);\n }\n\n get dir(): string {\n return this.wikiDir;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["import_schema"]
7
+ }
@@ -0,0 +1,259 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var ingest_exports = {};
30
+ __export(ingest_exports, {
31
+ applyDiff: () => applyDiff,
32
+ buildIngestPrompt: () => buildIngestPrompt,
33
+ reindexFromDisk: () => reindexFromDisk,
34
+ updateManifest: () => updateManifest
35
+ });
36
+ module.exports = __toCommonJS(ingest_exports);
37
+ var fs = __toESM(require("fs"));
38
+ var path = __toESM(require("path"));
39
+ function slugToFilePath(slug) {
40
+ return slug.replace(/\//g, path.sep) + ".md";
41
+ }
42
+ function ensureDir(p) {
43
+ fs.mkdirSync(path.dirname(p), { recursive: true });
44
+ }
45
+ function upsertSection(content, section, newContent, mode) {
46
+ const heading = `## ${section}`;
47
+ const idx = content.indexOf(heading);
48
+ if (idx === -1) {
49
+ return content.trimEnd() + `
50
+
51
+ ${heading}
52
+ ${newContent.trimEnd()}
53
+ `;
54
+ }
55
+ const afterHeading = idx + heading.length;
56
+ const nextHeading = content.indexOf("\n## ", afterHeading);
57
+ const sectionEnd = nextHeading === -1 ? content.length : nextHeading;
58
+ if (mode === "replace") {
59
+ return content.slice(0, idx) + heading + "\n" + newContent.trimEnd() + "\n" + content.slice(sectionEnd);
60
+ } else {
61
+ const sectionContent = content.slice(afterHeading, sectionEnd).trimEnd();
62
+ return content.slice(0, idx) + heading + sectionContent + "\n" + newContent.trimEnd() + "\n" + content.slice(sectionEnd);
63
+ }
64
+ }
65
+ function buildIngestPrompt(wikiDir, sourceContent, sourceName) {
66
+ const schemaPath = path.join(wikiDir, "SCHEMA.md");
67
+ const manifestPath = path.join(wikiDir, "MANIFEST.md");
68
+ const schema = fs.existsSync(schemaPath) ? fs.readFileSync(schemaPath, "utf8") : "(no SCHEMA.md found \u2014 use default wiki page structure)";
69
+ const manifest = fs.existsSync(manifestPath) ? fs.readFileSync(manifestPath, "utf8") : "(wiki is empty \u2014 no pages yet)";
70
+ return `You are maintaining a project wiki following the schema below.
71
+
72
+ ## SCHEMA
73
+ ${schema}
74
+
75
+ ## MANIFEST (existing pages)
76
+ ${manifest}
77
+
78
+ ## SOURCE TO INGEST
79
+ Source name: ${sourceName}
80
+ ${sourceContent}
81
+
82
+ ## INSTRUCTIONS
83
+
84
+ Read the source above. Following the schema:
85
+ 1. Identify entities, decisions, and patterns mentioned
86
+ 2. For existing pages (listed in MANIFEST): update relevant sections
87
+ 3. For new entities: create pages using the standard structure
88
+ 4. Emit one WIKI_DIFF block per page operation
89
+ 5. If incoming info contradicts existing content, emit a WIKI_DIFF_CONFLICTS block
90
+
91
+ Produce ONLY the WIKI_DIFF blocks and WIKI_DIFF_CONFLICTS blocks. No other output.`;
92
+ }
93
+ function applyDiff(diff, wikiDir, wikiDb, opts = {}) {
94
+ const result = {
95
+ created: [],
96
+ updated: [],
97
+ conflictsResolved: [],
98
+ conflictsPending: []
99
+ };
100
+ for (const entry of diff.entries) {
101
+ if (!entry.page) continue;
102
+ const relPath = slugToFilePath(entry.page);
103
+ const absPath = path.join(wikiDir, relPath);
104
+ if (entry.action === "create") {
105
+ ensureDir(absPath);
106
+ const title = entry.title ?? entry.page;
107
+ const fileContent = `# ${title}
108
+
109
+ ${entry.content.trimEnd()}
110
+ `;
111
+ fs.writeFileSync(absPath, fileContent, "utf8");
112
+ wikiDb.upsertPage({
113
+ slug: entry.page,
114
+ title,
115
+ content: fileContent,
116
+ filePath: relPath,
117
+ sourceCount: 1
118
+ });
119
+ result.created.push(entry.page);
120
+ } else if (entry.action === "upsert") {
121
+ let current = "";
122
+ let isNew = false;
123
+ if (fs.existsSync(absPath)) {
124
+ current = fs.readFileSync(absPath, "utf8");
125
+ } else {
126
+ ensureDir(absPath);
127
+ current = `# ${entry.page}
128
+
129
+ `;
130
+ isNew = true;
131
+ }
132
+ const updated = entry.section ? upsertSection(current, entry.section, entry.content, entry.mode ?? "append") : current.trimEnd() + "\n\n" + entry.content.trimEnd() + "\n";
133
+ fs.writeFileSync(absPath, updated, "utf8");
134
+ const titleMatch = updated.match(/^#\s+(.+)$/m);
135
+ wikiDb.upsertPage({
136
+ slug: entry.page,
137
+ title: titleMatch?.[1] ?? entry.page,
138
+ content: updated,
139
+ filePath: relPath,
140
+ sourceCount: 1
141
+ });
142
+ if (isNew) {
143
+ result.created.push(entry.page);
144
+ } else {
145
+ result.updated.push(entry.page);
146
+ }
147
+ } else if (entry.action === "append") {
148
+ let current = "";
149
+ if (fs.existsSync(absPath)) {
150
+ current = fs.readFileSync(absPath, "utf8");
151
+ } else {
152
+ ensureDir(absPath);
153
+ current = `# ${entry.page}
154
+
155
+ `;
156
+ }
157
+ const appended = current.trimEnd() + "\n\n" + entry.content.trimEnd() + "\n";
158
+ fs.writeFileSync(absPath, appended, "utf8");
159
+ const titleMatch = appended.match(/^#\s+(.+)$/m);
160
+ wikiDb.upsertPage({
161
+ slug: entry.page,
162
+ title: titleMatch?.[1] ?? entry.page,
163
+ content: appended,
164
+ filePath: relPath,
165
+ sourceCount: 1
166
+ });
167
+ result.updated.push(entry.page);
168
+ }
169
+ }
170
+ for (const conflict of diff.conflicts) {
171
+ if (opts.autoResolveConflicts) {
172
+ const resolved = resolveConflictByDate(conflict, wikiDir, wikiDb);
173
+ if (resolved) {
174
+ result.conflictsResolved.push(conflict.page);
175
+ continue;
176
+ }
177
+ }
178
+ result.conflictsPending.push(conflict);
179
+ }
180
+ updateManifest(wikiDir, wikiDb);
181
+ return result;
182
+ }
183
+ function resolveConflictByDate(conflict, wikiDir, wikiDb) {
184
+ const existingDate = conflict.existingDate ? new Date(conflict.existingDate).getTime() : 0;
185
+ const incomingDate = conflict.incomingDate ? new Date(conflict.incomingDate).getTime() : 0;
186
+ if (incomingDate >= existingDate && conflict.page && conflict.section) {
187
+ const relPath = slugToFilePath(conflict.page);
188
+ const absPath = path.join(wikiDir, relPath);
189
+ if (!fs.existsSync(absPath)) return false;
190
+ let content = fs.readFileSync(absPath, "utf8");
191
+ const supersededNote = `
192
+ > \u26A0 Superseded by ${conflict.source} on ${conflict.incomingDate ?? "unknown date"}
193
+ `;
194
+ const oldClaim = conflict.existing;
195
+ content = content.replace(oldClaim, conflict.incoming + supersededNote);
196
+ fs.writeFileSync(absPath, content, "utf8");
197
+ const titleMatch = content.match(/^#\s+(.+)$/m);
198
+ wikiDb.upsertPage({
199
+ slug: conflict.page,
200
+ title: titleMatch?.[1] ?? conflict.page,
201
+ content,
202
+ filePath: relPath,
203
+ sourceCount: 0
204
+ });
205
+ return true;
206
+ }
207
+ return false;
208
+ }
209
+ function updateManifest(wikiDir, wikiDb) {
210
+ const pages = wikiDb.listPages();
211
+ if (pages.length === 0) return;
212
+ const rows = pages.map((p) => `| [${p.slug}](${p.filePath}) | ${p.title} | ${p.sourceCount} | ${new Date(p.updatedAt).toISOString().slice(0, 10)} |`).join("\n");
213
+ const manifest = `# Wiki Manifest
214
+
215
+ | Slug | Title | Sources | Updated |
216
+ |------|-------|---------|----------|
217
+ ${rows}
218
+ `;
219
+ fs.writeFileSync(path.join(wikiDir, "MANIFEST.md"), manifest, "utf8");
220
+ }
221
+ function reindexFromDisk(wikiDir, wikiDb) {
222
+ wikiDb.clearAll();
223
+ let count = 0;
224
+ function walkDir(dir) {
225
+ if (!fs.existsSync(dir)) return;
226
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
227
+ const abs = path.join(dir, entry.name);
228
+ if (entry.isDirectory()) {
229
+ walkDir(abs);
230
+ } else if (entry.name.endsWith(".md") && entry.name !== "SCHEMA.md" && entry.name !== "MANIFEST.md") {
231
+ const rel = path.relative(wikiDir, abs);
232
+ const slug = rel.replace(/\.md$/, "").replace(/\\/g, "/");
233
+ const content = fs.readFileSync(abs, "utf8");
234
+ const titleMatch = content.match(/^#\s+(.+)$/m);
235
+ const stat = fs.statSync(abs);
236
+ wikiDb.upsertPage({
237
+ slug,
238
+ title: titleMatch?.[1] ?? slug,
239
+ content,
240
+ filePath: rel,
241
+ updatedAt: stat.mtimeMs,
242
+ sourceCount: 0
243
+ });
244
+ count++;
245
+ }
246
+ }
247
+ }
248
+ walkDir(wikiDir);
249
+ updateManifest(wikiDir, wikiDb);
250
+ return count;
251
+ }
252
+ // Annotate the CommonJS export names for ESM import in node:
253
+ 0 && (module.exports = {
254
+ applyDiff,
255
+ buildIngestPrompt,
256
+ reindexFromDisk,
257
+ updateManifest
258
+ });
259
+ //# sourceMappingURL=ingest.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/wiki/ingest.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph Wiki \u2014 Ingest & apply-diff logic\n *\n * applyDiff: writes markdown files + updates SQLite from a parsed WIKI_DIFF\n * buildIngestPrompt: returns the prompt for the LLM (SCHEMA + MANIFEST + source)\n * resolveConflicts: deterministic auto-resolve by source date\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport type { WikiDiff, WikiDiffEntry, WikiDiffConflict, WikiPage } from './types';\nimport type { WikiDatabase } from './database';\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction slugToFilePath(slug: string): string {\n return slug.replace(/\\//g, path.sep) + '.md';\n}\n\nfunction ensureDir(p: string): void {\n fs.mkdirSync(path.dirname(p), { recursive: true });\n}\n\nfunction upsertSection(content: string, section: string, newContent: string, mode: 'replace' | 'append'): string {\n const heading = `## ${section}`;\n const idx = content.indexOf(heading);\n\n if (idx === -1) {\n // Section doesn't exist \u2014 append at end\n return content.trimEnd() + `\\n\\n${heading}\\n${newContent.trimEnd()}\\n`;\n }\n\n // Find end of section (next ## heading or EOF)\n const afterHeading = idx + heading.length;\n const nextHeading = content.indexOf('\\n## ', afterHeading);\n const sectionEnd = nextHeading === -1 ? content.length : nextHeading;\n\n if (mode === 'replace') {\n return content.slice(0, idx) + heading + '\\n' + newContent.trimEnd() + '\\n' + content.slice(sectionEnd);\n } else {\n // append: insert before next heading\n const sectionContent = content.slice(afterHeading, sectionEnd).trimEnd();\n return content.slice(0, idx) + heading + sectionContent + '\\n' + newContent.trimEnd() + '\\n' + content.slice(sectionEnd);\n }\n}\n\n// \u2500\u2500 buildIngestPrompt \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function buildIngestPrompt(\n wikiDir: string,\n sourceContent: string,\n sourceName: string,\n): string {\n const schemaPath = path.join(wikiDir, 'SCHEMA.md');\n const manifestPath = path.join(wikiDir, 'MANIFEST.md');\n\n const schema = fs.existsSync(schemaPath)\n ? fs.readFileSync(schemaPath, 'utf8')\n : '(no SCHEMA.md found \u2014 use default wiki page structure)';\n\n const manifest = fs.existsSync(manifestPath)\n ? fs.readFileSync(manifestPath, 'utf8')\n : '(wiki is empty \u2014 no pages yet)';\n\n return `You are maintaining a project wiki following the schema below.\n\n## SCHEMA\n${schema}\n\n## MANIFEST (existing pages)\n${manifest}\n\n## SOURCE TO INGEST\nSource name: ${sourceName}\n${sourceContent}\n\n## INSTRUCTIONS\n\nRead the source above. Following the schema:\n1. Identify entities, decisions, and patterns mentioned\n2. For existing pages (listed in MANIFEST): update relevant sections\n3. For new entities: create pages using the standard structure\n4. Emit one WIKI_DIFF block per page operation\n5. If incoming info contradicts existing content, emit a WIKI_DIFF_CONFLICTS block\n\nProduce ONLY the WIKI_DIFF blocks and WIKI_DIFF_CONFLICTS blocks. No other output.`;\n}\n\n// \u2500\u2500 applyDiff \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface ApplyDiffResult {\n created: string[];\n updated: string[];\n conflictsResolved: string[];\n conflictsPending: WikiDiffConflict[];\n}\n\nexport function applyDiff(\n diff: WikiDiff,\n wikiDir: string,\n wikiDb: WikiDatabase,\n opts: { autoResolveConflicts?: boolean } = {}\n): ApplyDiffResult {\n const result: ApplyDiffResult = {\n created: [],\n updated: [],\n conflictsResolved: [],\n conflictsPending: [],\n };\n\n for (const entry of diff.entries) {\n if (!entry.page) continue;\n\n const relPath = slugToFilePath(entry.page);\n const absPath = path.join(wikiDir, relPath);\n\n if (entry.action === 'create') {\n ensureDir(absPath);\n const title = entry.title ?? entry.page;\n const fileContent = `# ${title}\\n\\n${entry.content.trimEnd()}\\n`;\n fs.writeFileSync(absPath, fileContent, 'utf8');\n wikiDb.upsertPage({\n slug: entry.page,\n title,\n content: fileContent,\n filePath: relPath,\n sourceCount: 1,\n });\n result.created.push(entry.page);\n\n } else if (entry.action === 'upsert') {\n let current = '';\n let isNew = false;\n if (fs.existsSync(absPath)) {\n current = fs.readFileSync(absPath, 'utf8');\n } else {\n ensureDir(absPath);\n current = `# ${entry.page}\\n\\n`;\n isNew = true;\n }\n\n const updated = entry.section\n ? upsertSection(current, entry.section, entry.content, entry.mode ?? 'append')\n : current.trimEnd() + '\\n\\n' + entry.content.trimEnd() + '\\n';\n\n fs.writeFileSync(absPath, updated, 'utf8');\n const titleMatch = updated.match(/^#\\s+(.+)$/m);\n wikiDb.upsertPage({\n slug: entry.page,\n title: titleMatch?.[1] ?? entry.page,\n content: updated,\n filePath: relPath,\n sourceCount: 1,\n });\n if (isNew) {\n result.created.push(entry.page);\n } else {\n result.updated.push(entry.page);\n }\n\n } else if (entry.action === 'append') {\n let current = '';\n if (fs.existsSync(absPath)) {\n current = fs.readFileSync(absPath, 'utf8');\n } else {\n ensureDir(absPath);\n current = `# ${entry.page}\\n\\n`;\n }\n const appended = current.trimEnd() + '\\n\\n' + entry.content.trimEnd() + '\\n';\n fs.writeFileSync(absPath, appended, 'utf8');\n const titleMatch = appended.match(/^#\\s+(.+)$/m);\n wikiDb.upsertPage({\n slug: entry.page,\n title: titleMatch?.[1] ?? entry.page,\n content: appended,\n filePath: relPath,\n sourceCount: 1,\n });\n result.updated.push(entry.page);\n }\n }\n\n // Handle conflicts\n for (const conflict of diff.conflicts) {\n if (opts.autoResolveConflicts) {\n const resolved = resolveConflictByDate(conflict, wikiDir, wikiDb);\n if (resolved) {\n result.conflictsResolved.push(conflict.page);\n continue;\n }\n }\n result.conflictsPending.push(conflict);\n }\n\n updateManifest(wikiDir, wikiDb);\n\n return result;\n}\n\n// \u2500\u2500 resolveConflictByDate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction resolveConflictByDate(\n conflict: WikiDiffConflict,\n wikiDir: string,\n wikiDb: WikiDatabase,\n): boolean {\n const existingDate = conflict.existingDate ? new Date(conflict.existingDate).getTime() : 0;\n const incomingDate = conflict.incomingDate ? new Date(conflict.incomingDate).getTime() : 0;\n\n // Incoming is newer \u2014 replace existing claim and add superseded note\n if (incomingDate >= existingDate && conflict.page && conflict.section) {\n const relPath = slugToFilePath(conflict.page);\n const absPath = path.join(wikiDir, relPath);\n if (!fs.existsSync(absPath)) return false;\n\n let content = fs.readFileSync(absPath, 'utf8');\n const supersededNote = `\\n> \u26A0 Superseded by ${conflict.source} on ${conflict.incomingDate ?? 'unknown date'}\\n`;\n const oldClaim = conflict.existing;\n content = content.replace(oldClaim, conflict.incoming + supersededNote);\n fs.writeFileSync(absPath, content, 'utf8');\n\n const titleMatch = content.match(/^#\\s+(.+)$/m);\n wikiDb.upsertPage({\n slug: conflict.page,\n title: titleMatch?.[1] ?? conflict.page,\n content,\n filePath: relPath,\n sourceCount: 0,\n });\n return true;\n }\n\n return false;\n}\n\n// \u2500\u2500 updateManifest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function updateManifest(wikiDir: string, wikiDb: WikiDatabase): void {\n const pages = wikiDb.listPages();\n if (pages.length === 0) return;\n\n const rows = pages\n .map(p => `| [${p.slug}](${p.filePath}) | ${p.title} | ${p.sourceCount} | ${new Date(p.updatedAt).toISOString().slice(0, 10)} |`)\n .join('\\n');\n\n const manifest = `# Wiki Manifest\\n\\n| Slug | Title | Sources | Updated |\\n|------|-------|---------|----------|\\n${rows}\\n`;\n fs.writeFileSync(path.join(wikiDir, 'MANIFEST.md'), manifest, 'utf8');\n}\n\n// \u2500\u2500 reindex \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport function reindexFromDisk(wikiDir: string, wikiDb: WikiDatabase): number {\n wikiDb.clearAll();\n\n let count = 0;\n\n function walkDir(dir: string): void {\n if (!fs.existsSync(dir)) return;\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const abs = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n walkDir(abs);\n } else if (entry.name.endsWith('.md') && entry.name !== 'SCHEMA.md' && entry.name !== 'MANIFEST.md') {\n const rel = path.relative(wikiDir, abs);\n const slug = rel.replace(/\\.md$/, '').replace(/\\\\/g, '/');\n const content = fs.readFileSync(abs, 'utf8');\n const titleMatch = content.match(/^#\\s+(.+)$/m);\n const stat = fs.statSync(abs);\n wikiDb.upsertPage({\n slug,\n title: titleMatch?.[1] ?? slug,\n content,\n filePath: rel,\n updatedAt: stat.mtimeMs,\n sourceCount: 0,\n });\n count++;\n }\n }\n }\n\n walkDir(wikiDir);\n updateManifest(wikiDir, wikiDb);\n return count;\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var lint_exports = {};
20
+ __export(lint_exports, {
21
+ lintWiki: () => lintWiki
22
+ });
23
+ module.exports = __toCommonJS(lint_exports);
24
+ const LINK_RE = /\[\[([^\]]+)\]\]/g;
25
+ function lintWiki(wikiDb) {
26
+ const issues = [];
27
+ const pages = wikiDb.listPages();
28
+ const slugSet = new Set(pages.map((p) => p.slug));
29
+ for (const page of pages) {
30
+ let m;
31
+ const re = new RegExp(LINK_RE.source, "g");
32
+ while ((m = re.exec(page.content)) !== null) {
33
+ const linked = m[1].trim();
34
+ if (!slugSet.has(linked)) {
35
+ issues.push({
36
+ kind: "broken_link",
37
+ slug: page.slug,
38
+ detail: `Broken link to [[${linked}]] \u2014 page does not exist`,
39
+ relatedSlug: linked
40
+ });
41
+ }
42
+ }
43
+ const hasRelated = /^## Related/m.test(page.content);
44
+ const hasIncoming = pages.some((p) => p.slug !== page.slug && p.content.includes(`[[${page.slug}]]`));
45
+ if (!hasRelated && !hasIncoming && pages.length > 1) {
46
+ issues.push({
47
+ kind: "orphan",
48
+ slug: page.slug,
49
+ detail: "Page has no ## Related section and no incoming links from other pages"
50
+ });
51
+ }
52
+ const sourcesMatch = page.content.match(/## Sources\n([\s\S]*?)(?=\n## |\n*$)/);
53
+ if (sourcesMatch) {
54
+ const sourcesBlock = sourcesMatch[1];
55
+ const hasDates = /\d{4}-\d{2}-\d{2}/.test(sourcesBlock);
56
+ if (!hasDates) {
57
+ issues.push({
58
+ kind: "stale",
59
+ slug: page.slug,
60
+ detail: "## Sources section has no dates \u2014 cannot verify freshness"
61
+ });
62
+ }
63
+ }
64
+ const similar = wikiDb.search(page.title, 5);
65
+ for (const { page: other } of similar) {
66
+ if (other.slug === page.slug) continue;
67
+ const contradictionSignals = ["instead of", "not", "replaced by", "superseded", "deprecated"];
68
+ const bothMentionSignal = contradictionSignals.some(
69
+ (sig) => page.content.toLowerCase().includes(sig) && other.content.toLowerCase().includes(sig)
70
+ );
71
+ if (bothMentionSignal) {
72
+ const key = [page.slug, other.slug].sort().join("|");
73
+ const alreadyReported = issues.some(
74
+ (i) => i.kind === "contradiction" && i.detail.includes(other.slug)
75
+ );
76
+ if (!alreadyReported) {
77
+ issues.push({
78
+ kind: "contradiction",
79
+ slug: page.slug,
80
+ detail: `Possible contradiction with [[${other.slug}]] \u2014 both pages contain negation signals on shared topics`,
81
+ relatedSlug: other.slug
82
+ });
83
+ }
84
+ }
85
+ }
86
+ }
87
+ return issues;
88
+ }
89
+ // Annotate the CommonJS export names for ESM import in node:
90
+ 0 && (module.exports = {
91
+ lintWiki
92
+ });
93
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/wiki/lint.ts"],
4
+ "sourcesContent": ["/**\n * KiroGraph Wiki \u2014 Lint\n *\n * Health checks: contradictions (FTS similarity), orphan pages,\n * broken [[slug]] cross-references.\n */\n\nimport * as path from 'path';\nimport type { WikiLintIssue } from './types';\nimport type { WikiDatabase } from './database';\n\nconst LINK_RE = /\\[\\[([^\\]]+)\\]\\]/g;\n\nexport function lintWiki(wikiDb: WikiDatabase): WikiLintIssue[] {\n const issues: WikiLintIssue[] = [];\n const pages = wikiDb.listPages();\n const slugSet = new Set(pages.map(p => p.slug));\n\n for (const page of pages) {\n // Broken [[slug]] links\n let m: RegExpExecArray | null;\n const re = new RegExp(LINK_RE.source, 'g');\n while ((m = re.exec(page.content)) !== null) {\n const linked = m[1].trim();\n if (!slugSet.has(linked)) {\n issues.push({\n kind: 'broken_link',\n slug: page.slug,\n detail: `Broken link to [[${linked}]] \u2014 page does not exist`,\n relatedSlug: linked,\n });\n }\n }\n\n // Orphan: no ## Related section and no incoming links from other pages\n const hasRelated = /^## Related/m.test(page.content);\n const hasIncoming = pages.some(p => p.slug !== page.slug && p.content.includes(`[[${page.slug}]]`));\n if (!hasRelated && !hasIncoming && pages.length > 1) {\n issues.push({\n kind: 'orphan',\n slug: page.slug,\n detail: 'Page has no ## Related section and no incoming links from other pages',\n });\n }\n\n // Stale: ## Sources section present but no date found (can't verify freshness)\n const sourcesMatch = page.content.match(/## Sources\\n([\\s\\S]*?)(?=\\n## |\\n*$)/);\n if (sourcesMatch) {\n const sourcesBlock = sourcesMatch[1];\n const hasDates = /\\d{4}-\\d{2}-\\d{2}/.test(sourcesBlock);\n if (!hasDates) {\n issues.push({\n kind: 'stale',\n slug: page.slug,\n detail: '## Sources section has no dates \u2014 cannot verify freshness',\n });\n }\n }\n\n // Contradictions: FTS similarity with other pages on the same topic\n // Simple heuristic: search for the page title and flag pages with conflicting signals\n const similar = wikiDb.search(page.title, 5);\n for (const { page: other } of similar) {\n if (other.slug === page.slug) continue;\n // Check for negation keywords close to shared terms\n const contradictionSignals = ['instead of', 'not', 'replaced by', 'superseded', 'deprecated'];\n const bothMentionSignal = contradictionSignals.some(\n sig => page.content.toLowerCase().includes(sig) && other.content.toLowerCase().includes(sig)\n );\n if (bothMentionSignal) {\n const key = [page.slug, other.slug].sort().join('|');\n const alreadyReported = issues.some(\n i => i.kind === 'contradiction' && i.detail.includes(other.slug)\n );\n if (!alreadyReported) {\n issues.push({\n kind: 'contradiction',\n slug: page.slug,\n detail: `Possible contradiction with [[${other.slug}]] \u2014 both pages contain negation signals on shared topics`,\n relatedSlug: other.slug,\n });\n }\n }\n }\n }\n\n return issues;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAWA,MAAM,UAAU;AAET,SAAS,SAAS,QAAuC;AAC9D,QAAM,SAA0B,CAAC;AACjC,QAAM,QAAQ,OAAO,UAAU;AAC/B,QAAM,UAAU,IAAI,IAAI,MAAM,IAAI,OAAK,EAAE,IAAI,CAAC;AAE9C,aAAW,QAAQ,OAAO;AAExB,QAAI;AACJ,UAAM,KAAK,IAAI,OAAO,QAAQ,QAAQ,GAAG;AACzC,YAAQ,IAAI,GAAG,KAAK,KAAK,OAAO,OAAO,MAAM;AAC3C,YAAM,SAAS,EAAE,CAAC,EAAE,KAAK;AACzB,UAAI,CAAC,QAAQ,IAAI,MAAM,GAAG;AACxB,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,UACX,QAAQ,oBAAoB,MAAM;AAAA,UAClC,aAAa;AAAA,QACf,CAAC;AAAA,MACH;AAAA,IACF;AAGA,UAAM,aAAa,eAAe,KAAK,KAAK,OAAO;AACnD,UAAM,cAAc,MAAM,KAAK,OAAK,EAAE,SAAS,KAAK,QAAQ,EAAE,QAAQ,SAAS,KAAK,KAAK,IAAI,IAAI,CAAC;AAClG,QAAI,CAAC,cAAc,CAAC,eAAe,MAAM,SAAS,GAAG;AACnD,aAAO,KAAK;AAAA,QACV,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,QACX,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAGA,UAAM,eAAe,KAAK,QAAQ,MAAM,sCAAsC;AAC9E,QAAI,cAAc;AAChB,YAAM,eAAe,aAAa,CAAC;AACnC,YAAM,WAAW,oBAAoB,KAAK,YAAY;AACtD,UAAI,CAAC,UAAU;AACb,eAAO,KAAK;AAAA,UACV,MAAM;AAAA,UACN,MAAM,KAAK;AAAA,UACX,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF;AAIA,UAAM,UAAU,OAAO,OAAO,KAAK,OAAO,CAAC;AAC3C,eAAW,EAAE,MAAM,MAAM,KAAK,SAAS;AACrC,UAAI,MAAM,SAAS,KAAK,KAAM;AAE9B,YAAM,uBAAuB,CAAC,cAAc,OAAO,eAAe,cAAc,YAAY;AAC5F,YAAM,oBAAoB,qBAAqB;AAAA,QAC7C,SAAO,KAAK,QAAQ,YAAY,EAAE,SAAS,GAAG,KAAK,MAAM,QAAQ,YAAY,EAAE,SAAS,GAAG;AAAA,MAC7F;AACA,UAAI,mBAAmB;AACrB,cAAM,MAAM,CAAC,KAAK,MAAM,MAAM,IAAI,EAAE,KAAK,EAAE,KAAK,GAAG;AACnD,cAAM,kBAAkB,OAAO;AAAA,UAC7B,OAAK,EAAE,SAAS,mBAAmB,EAAE,OAAO,SAAS,MAAM,IAAI;AAAA,QACjE;AACA,YAAI,CAAC,iBAAiB;AACpB,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,YACX,QAAQ,iCAAiC,MAAM,IAAI;AAAA,YACnD,aAAa,MAAM;AAAA,UACrB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;",
6
+ "names": []
7
+ }