kirograph 1.2.2 → 1.3.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 (45) hide show
  1. package/README.md +4 -3
  2. package/dist/bin/commands/attack-surface.js +15 -2
  3. package/dist/bin/commands/attack-surface.js.map +2 -2
  4. package/dist/bin/commands/help.js +4 -2
  5. package/dist/bin/commands/help.js.map +2 -2
  6. package/dist/bin/commands/memory.js +23 -3
  7. package/dist/bin/commands/memory.js.map +2 -2
  8. package/dist/bin/commands/security-export.js +7 -1
  9. package/dist/bin/commands/security-export.js.map +2 -2
  10. package/dist/bin/commands/wiki.js +12 -1
  11. package/dist/bin/commands/wiki.js.map +2 -2
  12. package/dist/bin/installer/common.js +25 -0
  13. package/dist/bin/installer/common.js.map +2 -2
  14. package/dist/bin/installer/config-prompt.js +25 -1
  15. package/dist/bin/installer/config-prompt.js.map +2 -2
  16. package/dist/bin/installer/index.js +23 -0
  17. package/dist/bin/installer/index.js.map +2 -2
  18. package/dist/bin/installer/steering.js +5 -1
  19. package/dist/bin/installer/steering.js.map +2 -2
  20. package/dist/bin/kirograph.js +1 -1
  21. package/dist/config.js +63 -2
  22. package/dist/config.js.map +2 -2
  23. package/dist/mcp/handlers/memory.js +17 -5
  24. package/dist/mcp/handlers/memory.js.map +2 -2
  25. package/dist/mcp/handlers/security.js +13 -2
  26. package/dist/mcp/handlers/security.js.map +2 -2
  27. package/dist/mcp/handlers/wiki.js +11 -1
  28. package/dist/mcp/handlers/wiki.js.map +2 -2
  29. package/dist/mcp/tools.js +4 -4
  30. package/dist/mcp/tools.js.map +2 -2
  31. package/dist/memory/index.js +40 -10
  32. package/dist/memory/index.js.map +2 -2
  33. package/dist/memory/relation-display.js +37 -0
  34. package/dist/memory/relation-display.js.map +7 -0
  35. package/dist/patterns/library/sql-injection-concat-js.yaml +3 -0
  36. package/dist/patterns/library/sql-injection-template-js.yaml +4 -0
  37. package/dist/security/attack-surface.js +20 -2
  38. package/dist/security/attack-surface.js.map +2 -2
  39. package/dist/security/data-flows.js +0 -10
  40. package/dist/security/data-flows.js.map +2 -2
  41. package/dist/wiki/index.js +15 -2
  42. package/dist/wiki/index.js.map +2 -2
  43. package/dist/wiki/lint.js +23 -11
  44. package/dist/wiki/lint.js.map +2 -2
  45. package/package.json +1 -1
package/dist/wiki/lint.js CHANGED
@@ -23,7 +23,7 @@ __export(lint_exports, {
23
23
  module.exports = __toCommonJS(lint_exports);
24
24
  var import_links = require("./links");
25
25
  var import_typed_pages = require("./typed-pages");
26
- function lintWiki(wikiDb, opts = {}) {
26
+ async function lintWiki(wikiDb, opts = {}) {
27
27
  const issues = [];
28
28
  const pages = wikiDb.listPages();
29
29
  const slugSet = new Set(pages.map((p) => p.slug));
@@ -74,23 +74,35 @@ function lintWiki(wikiDb, opts = {}) {
74
74
  const similar = wikiDb.search(page.title, 5);
75
75
  for (const { page: other } of similar) {
76
76
  if (other.slug === page.slug) continue;
77
- const contradictionSignals = ["instead of", "not", "replaced by", "superseded", "deprecated"];
78
- const bothMentionSignal = contradictionSignals.some(
79
- (sig) => page.content.toLowerCase().includes(sig) && other.content.toLowerCase().includes(sig)
77
+ const alreadyReported = issues.some(
78
+ (i) => i.kind === "contradiction" && i.detail.includes(other.slug)
80
79
  );
81
- if (bothMentionSignal) {
82
- const key = [page.slug, other.slug].sort().join("|");
83
- const alreadyReported = issues.some(
84
- (i) => i.kind === "contradiction" && i.detail.includes(other.slug)
85
- );
86
- if (!alreadyReported) {
80
+ if (alreadyReported) continue;
81
+ if (opts.contradictionMode === "jev" && opts.jevClient) {
82
+ const { checkContradictionWithJev } = await Promise.resolve().then(() => require("./contradiction-jev.js"));
83
+ const result = await checkContradictionWithJev(opts.jevClient, page.content, other.content);
84
+ const threshold = opts.contradictionConfidenceThreshold ?? 0.7;
85
+ if (result.contradicts && result.confidence >= threshold) {
87
86
  issues.push({
88
87
  kind: "contradiction",
89
88
  slug: page.slug,
90
- detail: `Possible contradiction with [[${other.slug}]] \u2014 both pages contain negation signals on shared topics`,
89
+ detail: `Possible contradiction with [[${other.slug}]] \u2014 jev confidence: ${result.confidence.toFixed(2)}`,
91
90
  relatedSlug: other.slug
92
91
  });
93
92
  }
93
+ continue;
94
+ }
95
+ const contradictionSignals = ["instead of", "not", "replaced by", "superseded", "deprecated"];
96
+ const bothMentionSignal = contradictionSignals.some(
97
+ (sig) => page.content.toLowerCase().includes(sig) && other.content.toLowerCase().includes(sig)
98
+ );
99
+ if (bothMentionSignal) {
100
+ issues.push({
101
+ kind: "contradiction",
102
+ slug: page.slug,
103
+ detail: `Possible contradiction with [[${other.slug}]] \u2014 both pages contain negation signals on shared topics`,
104
+ relatedSlug: other.slug
105
+ });
94
106
  }
95
107
  }
96
108
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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';\nimport { extractLinks } from './links';\nimport { parseFrontmatter, validatePageSchema } from './typed-pages';\n\nexport interface LintWikiOptions {\n /**\n * When set, pages declaring `_type` in their frontmatter are validated\n * against `.kirograph/wiki-schemas/<type>.schema.json` (wikiTypedPages).\n */\n wikiSchemasDir?: string;\n}\n\nexport function lintWiki(wikiDb: WikiDatabase, opts: LintWikiOptions = {}): 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 // Typed-page schema validation (opt-in via wikiTypedPages)\n if (opts.wikiSchemasDir) {\n const { type, fields } = parseFrontmatter(page.content);\n if (type) {\n for (const violation of validatePageSchema(fields, type, opts.wikiSchemasDir)) {\n issues.push({\n kind: 'schema_error',\n slug: page.slug,\n detail: `[${type}] ${violation}`,\n });\n }\n }\n }\n\n // Broken [[slug]] links\n for (const linked of extractLinks(page.content)) {\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 && extractLinks(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;AAUA,mBAA6B;AAC7B,yBAAqD;AAU9C,SAAS,SAAS,QAAsB,OAAwB,CAAC,GAAoB;AAC1F,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,KAAK,gBAAgB;AACvB,YAAM,EAAE,MAAM,OAAO,QAAI,qCAAiB,KAAK,OAAO;AACtD,UAAI,MAAM;AACR,mBAAW,iBAAa,uCAAmB,QAAQ,MAAM,KAAK,cAAc,GAAG;AAC7E,iBAAO,KAAK;AAAA,YACV,MAAM;AAAA,YACN,MAAM,KAAK;AAAA,YACX,QAAQ,IAAI,IAAI,KAAK,SAAS;AAAA,UAChC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,eAAW,cAAU,2BAAa,KAAK,OAAO,GAAG;AAC/C,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,YAAQ,2BAAa,EAAE,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;AACvG,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;",
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';\nimport type { JevClient } from '../jev/client';\nimport { extractLinks } from './links';\nimport { parseFrontmatter, validatePageSchema } from './typed-pages';\n\nexport interface LintWikiOptions {\n /** 'heuristic' (default): keyword co-occurrence. 'jev': ask jev to judge each FTS-similar pair. */\n contradictionMode?: 'heuristic' | 'jev';\n /** Confidence (0.0\u20131.0) above which a jev contradiction judgment is reported. Default: 0.7. */\n contradictionConfidenceThreshold?: number;\n /** Required when contradictionMode is 'jev'. */\n jevClient?: JevClient;\n /**\n * When set, pages declaring `_type` in their frontmatter are validated\n * against `.kirograph/wiki-schemas/<type>.schema.json` (wikiTypedPages).\n */\n wikiSchemasDir?: string;\n}\n\nexport async function lintWiki(wikiDb: WikiDatabase, opts: LintWikiOptions = {}): Promise<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 // Typed-page schema validation (opt-in via wikiTypedPages)\n if (opts.wikiSchemasDir) {\n const { type, fields } = parseFrontmatter(page.content);\n if (type) {\n for (const violation of validatePageSchema(fields, type, opts.wikiSchemasDir)) {\n issues.push({\n kind: 'schema_error',\n slug: page.slug,\n detail: `[${type}] ${violation}`,\n });\n }\n }\n }\n\n // Broken [[slug]] links\n for (const linked of extractLinks(page.content)) {\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 && extractLinks(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 const similar = wikiDb.search(page.title, 5);\n for (const { page: other } of similar) {\n if (other.slug === page.slug) continue;\n const alreadyReported = issues.some(\n i => i.kind === 'contradiction' && i.detail.includes(other.slug)\n );\n if (alreadyReported) continue;\n\n if (opts.contradictionMode === 'jev' && opts.jevClient) {\n const { checkContradictionWithJev } = await Promise.resolve().then(() => require('./contradiction-jev.js'));\n const result = await checkContradictionWithJev(opts.jevClient, page.content, other.content);\n const threshold = opts.contradictionConfidenceThreshold ?? 0.7;\n if (result.contradicts && result.confidence >= threshold) {\n issues.push({\n kind: 'contradiction',\n slug: page.slug,\n detail: `Possible contradiction with [[${other.slug}]] \u2014 jev confidence: ${result.confidence.toFixed(2)}`,\n relatedSlug: other.slug,\n });\n }\n continue;\n }\n\n // Heuristic (default): co-occurring negation keywords on both pages\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 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 return issues;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kirograph",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "Semantic code knowledge graph for Kiro: fewer tool calls, instant symbol lookups, 100% local.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",