kirograph 1.0.0 → 1.1.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.
- package/README.md +3 -2
- package/dist/architecture/manifest/python.js +2 -2
- package/dist/architecture/manifest/python.js.map +2 -2
- package/dist/bin/commands/help.js +3 -1
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/memory.js +18 -8
- package/dist/bin/commands/memory.js.map +2 -2
- package/dist/bin/commands/reachability.js +7 -2
- package/dist/bin/commands/reachability.js.map +2 -2
- package/dist/bin/commands/vulns.js +16 -1
- package/dist/bin/commands/vulns.js.map +2 -2
- package/dist/bin/commands/wiki.js +56 -0
- package/dist/bin/commands/wiki.js.map +2 -2
- package/dist/bin/installer/steering.js +9 -0
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/kirograph.js +1 -1
- package/dist/config.js +4 -0
- package/dist/config.js.map +2 -2
- package/dist/extraction/extractor.js +46 -41
- package/dist/extraction/extractor.js.map +2 -2
- package/dist/extraction/notebook.js +15 -7
- package/dist/extraction/notebook.js.map +2 -2
- package/dist/jev/client.js +99 -0
- package/dist/jev/client.js.map +7 -0
- package/dist/jev/types.js +17 -0
- package/dist/jev/types.js.map +7 -0
- package/dist/mcp/handlers/memory.js +14 -8
- package/dist/mcp/handlers/memory.js.map +2 -2
- package/dist/mcp/handlers/security.js +5 -3
- package/dist/mcp/handlers/security.js.map +2 -2
- package/dist/mcp/tools.js +1 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/memory/index.js +13 -1
- package/dist/memory/index.js.map +3 -3
- package/dist/memory/relation-jev.js +59 -0
- package/dist/memory/relation-jev.js.map +7 -0
- package/dist/memory/schema.js +57 -0
- package/dist/memory/schema.js.map +7 -0
- package/dist/security/auth-detection-jev.js +47 -0
- package/dist/security/auth-detection-jev.js.map +7 -0
- package/dist/security/manifest/adapter.js +17 -3
- package/dist/security/manifest/adapter.js.map +3 -3
- package/dist/security/manifest/plugins/cargo.js +23 -0
- package/dist/security/manifest/plugins/cargo.js.map +2 -2
- package/dist/security/manifest/plugins/composer.js +12 -0
- package/dist/security/manifest/plugins/composer.js.map +2 -2
- package/dist/security/manifest/plugins/gradle.js +12 -0
- package/dist/security/manifest/plugins/gradle.js.map +2 -2
- package/dist/security/manifest/plugins/hex.js +12 -0
- package/dist/security/manifest/plugins/hex.js.map +2 -2
- package/dist/security/manifest/plugins/maven.js +68 -1
- package/dist/security/manifest/plugins/maven.js.map +2 -2
- package/dist/security/manifest/plugins/npm.js +86 -0
- package/dist/security/manifest/plugins/npm.js.map +2 -2
- package/dist/security/manifest/plugins/nuget.js +13 -0
- package/dist/security/manifest/plugins/nuget.js.map +2 -2
- package/dist/security/manifest/plugins/pubspec.js +12 -0
- package/dist/security/manifest/plugins/pubspec.js.map +2 -2
- package/dist/security/manifest/plugins/pyproject.js +12 -0
- package/dist/security/manifest/plugins/pyproject.js.map +2 -2
- package/dist/security/manifest/plugins/rubygems.js +12 -0
- package/dist/security/manifest/plugins/rubygems.js.map +2 -2
- package/dist/security/pipeline.js +1 -1
- package/dist/security/pipeline.js.map +2 -2
- package/dist/security/reachability.js +54 -5
- package/dist/security/reachability.js.map +3 -3
- package/dist/security/types.js.map +1 -1
- package/dist/security/vuln/client.js +45 -1
- package/dist/security/vuln/client.js.map +2 -2
- package/dist/security/vuln/osv-adapter.js +45 -1
- package/dist/security/vuln/osv-adapter.js.map +2 -2
- package/dist/wiki/contradiction-jev.js +49 -0
- package/dist/wiki/contradiction-jev.js.map +7 -0
- package/dist/wiki/index.js +13 -0
- package/dist/wiki/index.js.map +2 -2
- package/dist/wiki/ingest.js +2 -0
- package/dist/wiki/ingest.js.map +2 -2
- package/dist/wiki/links.js +53 -0
- package/dist/wiki/links.js.map +7 -0
- package/dist/wiki/lint.js +3 -6
- package/dist/wiki/lint.js.map +2 -2
- package/dist/wiki/rename.js +103 -0
- package/dist/wiki/rename.js.map +7 -0
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/bin/commands/vulns.ts"],
|
|
4
|
-
"sourcesContent": ["import { Command } from 'commander';\nimport * as path from 'path';\nimport { loadConfig } from '../../config';\nimport { dim, reset, violet, bold, green } from '../ui';\nimport { formatFixSuggestion } from '../../security/export/fix-suggestions';\nimport { SuppressionManager } from '../../security/suppressions';\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\n/** Parse an `epss=N` fail-on value and return the threshold, or null if not an epss condition. */\nfunction parseEpssFailOn(failOn: string): number | null {\n const m = failOn.match(/^epss=(.+)$/);\n if (!m) return null;\n const n = parseFloat(m[1]);\n return isNaN(n) ? null : n;\n}\n\n/** Extract workspace label from a source_manifests JSON string. */\nfunction workspaceFromManifests(sourceManifests: string | null): string {\n if (!sourceManifests) return 'root';\n try {\n const manifests: string[] = JSON.parse(sourceManifests);\n if (!manifests.length) return 'root';\n const dir = path.dirname(manifests[0]);\n return dir === '.' ? 'root' : dir;\n } catch {\n return 'root';\n }\n}\n\nexport function register(program: Command): void {\n program\n .command('vulns [projectPath]')\n .description('List vulnerabilities with reachability verdicts and severity')\n .option('--severity <level>', 'Filter by severity: critical, high, medium, low')\n .option('--verdict <verdict>', 'Filter by verdict: affected, not_affected, under_investigation')\n .option('--refresh', 'Trigger fresh vulnerability enrichment before listing')\n .option('--epss <threshold>', 'Filter by EPSS score (e.g. 0.5 shows only vulns with EPSS >= 0.5)')\n .option('--stale', 'Show staleness score of the affected dependency alongside each CVE')\n .option('--sort <key>', 'Sort results by: risk (default), cvss, epss, name')\n .option('--add <cveId>', 'Manually register a CVE')\n .option('--package <name>', 'Package name for --add')\n .option('--version <ver>', 'Package version for --add')\n .option('--fail-on <condition>', 'Exit 1 if condition is met: affected, any, critical, high, epss=N')\n .option('--group-by <key>', 'Group output by: workspace')\n .action(async (projectPath: string | undefined, opts: {\n severity?: string;\n verdict?: string;\n refresh?: boolean;\n epss?: string;\n stale?: boolean;\n sort?: string;\n add?: string;\n package?: string;\n version?: string;\n failOn?: string;\n groupBy?: string;\n }) => {\n const target = path.resolve(projectPath ?? process.cwd());\n const config = await loadConfig(target);\n\n if (!config.enableSecurity) {\n console.error(`\\n ${'\\x1b[33m'}\u26A0 Security analysis is disabled.${reset}`);\n console.error(` ${dim}Enable it in .kirograph/config.json:${reset} ${violet}${bold}\"enableSecurity\": true${reset}`);\n console.error(` ${dim}Then re-run:${reset} ${violet}${bold}kirograph index${reset}\\n`);\n process.exit(1);\n }\n\n // Validate --fail-on early\n if (opts.failOn !== undefined) {\n const validFailOns = ['affected', 'any', 'critical', 'high'];\n const isEpss = parseEpssFailOn(opts.failOn) !== null;\n if (!validFailOns.includes(opts.failOn) && !isEpss) {\n console.error(` \u2716 Invalid --fail-on value: ${opts.failOn}. Use: affected, any, critical, high, epss=N`);\n process.exit(1);\n }\n }\n\n // Validate --group-by early\n if (opts.groupBy !== undefined && opts.groupBy !== 'workspace') {\n console.error(` \u2716 Invalid --group-by value: ${opts.groupBy}. Supported: workspace`);\n process.exit(1);\n }\n\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n if (!KiroGraph.isInitialized(target)) {\n console.error(' \u2716 KiroGraph not initialized. Run: kirograph init');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(target);\n const db = cg.getDatabase();\n db.applySecuritySchema();\n const rawDb = db.getRawDb();\n\n // Handle --add: manually register a CVE\n if (opts.add) {\n if (!opts.package || !opts.version) {\n console.error(` \u2716 --add requires --package <name> and --version <ver>`);\n cg.close(); process.exit(1);\n }\n\n const cveId = opts.add;\n const pkgName = opts.package;\n const pkgVersion = opts.version;\n\n // Find the matching dependency node\n const depRow: { node_id: string; ecosystem: string } | undefined = rawDb.get(\n `SELECT node_id, ecosystem FROM sec_dependencies\n WHERE package_name = ? AND (resolved_version = ? OR declared_constraint = ?)`,\n [pkgName, pkgVersion, pkgVersion],\n );\n\n if (!depRow) {\n console.error(` \u2716 No dependency found matching ${violet}${pkgName}@${pkgVersion}${reset}`);\n console.error(` ${dim}Run${reset} ${violet}${bold}kirograph index${reset} ${dim}first to discover dependencies.${reset}`);\n cg.close(); process.exit(1);\n }\n\n // Create the vulnerability node\n const vulnNodeId = `vuln:${cveId}`;\n const now = Date.now();\n\n rawDb.run(\n `INSERT OR REPLACE INTO nodes\n (id, kind, name, qualified_name, file_path, language,\n start_line, end_line, start_column, end_column,\n is_exported, is_async, is_static, is_abstract, updated_at)\n VALUES (?, 'vulnerability', ?, ?, '', 'unknown', 0, 0, 0, 0, 0, 0, 0, 0, ?)`,\n [vulnNodeId, cveId, cveId, now],\n );\n\n rawDb.run(\n `INSERT OR REPLACE INTO sec_vulnerabilities\n (node_id, cve_id, severity_score, affected_ranges, fixed_version, summary, source_database)\n VALUES (?, ?, NULL, '[]', NULL, 'Manually registered', 'manual')`,\n [vulnNodeId, cveId],\n );\n\n // Create has_vulnerability edge\n rawDb.run(\n `INSERT OR IGNORE INTO edges (source, target, kind, confidence, confidence_score)\n VALUES (?, ?, 'has_vulnerability', 'extracted', 1.0)`,\n [depRow.node_id, vulnNodeId],\n );\n\n console.log(` ${green}\u2713${reset} Registered ${violet}${bold}${cveId}${reset} against ${violet}${pkgName}@${pkgVersion}${reset}`);\n cg.close();\n return;\n }\n\n // Handle --refresh: trigger fresh vulnerability enrichment\n if (opts.refresh) {\n console.error(` ${dim}Refreshing vulnerability data from configured databases...${reset}`);\n const { OsvAdapter } = await Promise.resolve().then(() => require('../../security/vuln/osv-adapter.js'));\n const { VulnerabilityDatabaseClient } = await Promise.resolve().then(() => require('../../security/vuln/client.js'));\n\n const adapters = config.securityDatabases.map((dbName: string) => {\n if (dbName.toUpperCase() === 'OSV') return new OsvAdapter();\n return null;\n }).filter(Boolean) as any[];\n\n const client = new VulnerabilityDatabaseClient(adapters, db);\n const result = await client.enrichAll();\n\n console.error(` ${green}\u2713${reset} Checked ${bold}${result.dependenciesChecked}${reset} dependencies, found ${bold}${result.vulnerabilitiesFound}${reset} vulnerabilities`);\n if (result.errors.length > 0) {\n console.error(` ${'\\x1b[33m'}\u26A0${reset} ${result.errors.length} error(s) during enrichment`);\n }\n console.error();\n }\n\n // Build query for listing vulnerabilities\n // Include source_manifests when group-by workspace is requested\n const selectSourceManifests = opts.groupBy === 'workspace' ? `,\\n d.source_manifests` : '';\n let query = `\n SELECT\n v.node_id, v.cve_id, v.severity_score, v.fixed_version, v.summary, v.source_database,\n v.epss_score, v.epss_percentile, v.risk_score,\n d.package_name, d.ecosystem, d.resolved_version, d.declared_constraint,\n d.staleness_score,\n r.verdict${selectSourceManifests}\n FROM sec_vulnerabilities v\n LEFT JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n LEFT JOIN sec_dependencies d ON d.node_id = e.source\n LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id\n WHERE 1=1\n `;\n const params: any[] = [];\n\n // Apply severity filter.\n // Bounds are half-open [min, max) and MUST mirror the display buckets in\n // printVulnRow() so the filter and the rendered label never disagree:\n // CRITICAL >= 9.0, HIGH >= 7.0, MEDIUM >= 4.0, LOW < 4.0 (incl. 0.0).\n if (opts.severity) {\n const severityRanges: Record<string, [number, number]> = {\n critical: [9.0, 10.01],\n high: [7.0, 9.0],\n medium: [4.0, 7.0],\n low: [0.0, 4.0],\n };\n const range = severityRanges[opts.severity.toLowerCase()];\n if (!range) {\n console.error(` \u2716 Invalid severity: ${opts.severity}. Use: critical, high, medium, low`);\n cg.close(); process.exit(1);\n }\n // severity_score IS NULL means \"unknown\" \u2014 excluded from every band.\n query += ` AND v.severity_score IS NOT NULL AND v.severity_score >= ? AND v.severity_score < ?`;\n params.push(range[0], range[1]);\n }\n\n // Apply verdict filter\n if (opts.verdict) {\n const validVerdicts = ['affected', 'not_affected', 'under_investigation'];\n if (!validVerdicts.includes(opts.verdict)) {\n console.error(` \u2716 Invalid verdict: ${opts.verdict}. Use: affected, not_affected, under_investigation`);\n cg.close(); process.exit(1);\n }\n query += ` AND r.verdict = ?`;\n params.push(opts.verdict);\n }\n\n // Apply EPSS threshold filter\n if (opts.epss !== undefined) {\n const epssThreshold = parseFloat(opts.epss);\n if (isNaN(epssThreshold) || epssThreshold < 0 || epssThreshold > 1) {\n console.error(` \u2716 Invalid EPSS threshold: ${opts.epss}. Use a number between 0 and 1 (e.g. 0.5)`);\n cg.close(); process.exit(1);\n }\n query += ` AND v.epss_score >= ?`;\n params.push(epssThreshold);\n }\n\n // Resolve sort order\n const sortKey = opts.sort?.toLowerCase() ?? 'risk';\n const validSortKeys = ['risk', 'cvss', 'epss', 'name'];\n if (!validSortKeys.includes(sortKey)) {\n console.error(` \u2716 Invalid sort key: ${opts.sort}. Use: risk, cvss, epss, name`);\n cg.close(); process.exit(1);\n }\n const sortClause =\n sortKey === 'risk' ? `v.risk_score DESC NULLS LAST` :\n sortKey === 'cvss' ? `v.severity_score DESC NULLS LAST` :\n sortKey === 'epss' ? `v.epss_score DESC NULLS LAST` :\n `v.cve_id ASC`;\n query += ` ORDER BY ${sortClause}`;\n\n const rows: Array<{\n node_id: string;\n cve_id: string;\n severity_score: number | null;\n fixed_version: string | null;\n summary: string | null;\n source_database: string;\n epss_score: number | null;\n epss_percentile: number | null;\n risk_score: number | null;\n package_name: string | null;\n ecosystem: string | null;\n resolved_version: string | null;\n declared_constraint: string | null;\n staleness_score: number | null;\n verdict: string | null;\n source_manifests?: string | null;\n }> = rawDb.all(query, params);\n\n // Deduplicate by (cve_id, package_name, ecosystem) \u2014 same CVE can appear multiple\n // times if a package is declared in multiple manifests (monorepo) or has multiple\n // dep nodes. Keep the row with the worst verdict (affected > under_investigation > not_affected > null).\n const verdictRank = (v: string | null) =>\n v === 'affected' ? 3 : v === 'under_investigation' ? 2 : v === 'not_affected' ? 1 : 0;\n const deduped = new Map<string, typeof rows[0]>();\n for (const row of rows) {\n const key = `${row.cve_id}::${row.package_name ?? ''}::${row.ecosystem ?? ''}`;\n const existing = deduped.get(key);\n if (!existing || verdictRank(row.verdict) > verdictRank(existing.verdict)) {\n deduped.set(key, row);\n }\n }\n const dedupedRows = [...deduped.values()];\n\n // Filter out suppressed CVEs\n const suppressions = new SuppressionManager(target);\n const suppressedRows = dedupedRows.filter(row => suppressions.isSuppressed(row.cve_id));\n const filteredRows = dedupedRows.filter(row => !suppressions.isSuppressed(row.cve_id));\n\n if (filteredRows.length === 0) {\n const filterNote = (opts.severity || opts.verdict)\n ? ` matching filters`\n : '';\n console.log(`\\n ${dim}No vulnerabilities found${filterNote}.${reset}\\n`);\n if (suppressedRows.length > 0) {\n console.log(` ${dim}${suppressedRows.length} CVE(s) suppressed \u2014 kirograph vuln suppressions to review${reset}\\n`);\n }\n cg.close();\n return;\n }\n\n // \u2500\u2500 Render a single vulnerability row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 function printVulnRow(row: (typeof filteredRows)[0], indent = ' '): void {\n // Severity badge\n const score = row.severity_score;\n let severityLabel: string;\n let severityColor: string;\n if (score == null) {\n severityLabel = 'unknown';\n severityColor = dim;\n } else if (score >= 9.0) {\n severityLabel = 'CRITICAL';\n severityColor = '\\x1b[31m';\n } else if (score >= 7.0) {\n severityLabel = 'HIGH';\n severityColor = '\\x1b[31m';\n } else if (score >= 4.0) {\n severityLabel = 'MEDIUM';\n severityColor = '\\x1b[33m';\n } else {\n severityLabel = 'LOW';\n severityColor = dim;\n }\n\n // Verdict badge\n let verdictLabel: string;\n let verdictColor: string;\n if (!row.verdict) {\n verdictLabel = 'pending';\n verdictColor = dim;\n } else if (row.verdict === 'affected') {\n verdictLabel = 'affected';\n verdictColor = '\\x1b[31m';\n } else if (row.verdict === 'not_affected') {\n verdictLabel = 'not affected';\n verdictColor = green;\n } else {\n verdictLabel = 'investigating';\n verdictColor = '\\x1b[33m';\n }\n\n const pkg = row.package_name\n ? `${row.package_name}@${row.resolved_version || row.declared_constraint || '?'}`\n : 'unknown package';\n\n // EPSS badge\n let epssBadge = '';\n if (row.epss_score != null && row.epss_percentile != null) {\n const epssColor = row.epss_score >= 0.3 ? '\\x1b[33m' : dim;\n const scoreStr = row.epss_score.toFixed(2);\n const pctStr = `${Math.round(row.epss_percentile * 100)}th%`;\n epssBadge = ` ${epssColor}${dim}[EPSS: ${scoreStr} / ${pctStr}]${reset}`;\n }\n\n // Risk score badge\n let riskBadge = '';\n if (row.risk_score != null) {\n const riskColor = row.risk_score >= 7 ? '\\x1b[31m' : row.risk_score >= 4 ? '\\x1b[33m' : dim;\n riskBadge = ` ${riskColor}[Risk: ${row.risk_score.toFixed(1)}]${reset}`;\n }\n\n console.log(`${indent}${severityColor}${severityLabel}${reset} ${violet}${bold}${row.cve_id}${reset} ${dim}${pkg}${reset} [${verdictColor}${verdictLabel}${reset}]${epssBadge}${riskBadge}`);\n\n if (row.summary && row.summary !== 'Manually registered') {\n const truncated = row.summary.length > 100 ? row.summary.slice(0, 100) + '\u2026' : row.summary;\n console.log(`${indent} ${dim}${truncated}${reset}`);\n }\n\n // Staleness badge (when --stale flag is set)\n if (opts.stale && row.staleness_score != null) {\n const s = row.staleness_score;\n const staleColor = s >= 0.7 ? '\\x1b[31m' : s >= 0.4 ? '\\x1b[33m' : dim;\n console.log(`${indent} ${staleColor}${dim}[staleness: ${s.toFixed(2)}]${reset}`);\n }\n\n // Fix suggestion\n if (row.fixed_version && row.ecosystem && row.package_name) {\n const fix = formatFixSuggestion(row.ecosystem, row.package_name, row.fixed_version);\n if (fix) {\n console.log(`${indent} ${fix}`);\n }\n }\n\n console.log();\n }\n\n // \u2500\u2500 Output: grouped or flat \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 if (opts.groupBy === 'workspace') {\n // Group by workspace (directory of first source manifest)\n const groups = new Map<string, Array<(typeof filteredRows)[0]>>();\n for (const row of filteredRows) {\n const ws = workspaceFromManifests(row.source_manifests ?? null);\n if (!groups.has(ws)) groups.set(ws, []);\n groups.get(ws)!.push(row);\n }\n\n // Only apply workspace grouping when there are multiple distinct workspaces\n const workspaces = Array.from(groups.keys());\n if (workspaces.length <= 1) {\n // Single workspace \u2014 fall through to flat output\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const row of filteredRows) {\n printVulnRow(row);\n }\n } else {\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const ws of workspaces) {\n const wsRows = groups.get(ws)!;\n const count = wsRows.length;\n const header = `Workspace: ${ws} (${count} vulnerabilit${count === 1 ? 'y' : 'ies'})`;\n const line = '\u2500'.repeat(header.length);\n console.log(` ${bold}${header}${reset}`);\n console.log(` ${dim}${line}${reset}`);\n for (const row of wsRows) {\n printVulnRow(row);\n }\n }\n }\n } else {\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const row of filteredRows) {\n printVulnRow(row);\n }\n }\n\n if (suppressedRows.length > 0) {\n console.log(` ${dim}${suppressedRows.length} CVE(s) suppressed \u2014 kirograph vuln suppressions to review${reset}\\n`);\n }\n\n // Hint when reachability hasn't been computed yet (verdict is pending).\n // vulns --refresh only re-queries vulnerability data; the call-graph\n // reachability analysis that resolves [pending] \u2192 [affected]/[not affected]\n // runs during `kirograph index`.\n const pendingCount = filteredRows.filter(r => !r.verdict).length;\n if (pendingCount > 0) {\n console.log(` ${dim}${pendingCount} vulnerabilit${pendingCount === 1 ? 'y is' : 'ies are'} [pending] reachability analysis \u2014 run ${reset}kirograph index${dim} to compute call-graph verdicts.${reset}\\n`);\n }\n\n // \u2500\u2500 CI exit codes: --fail-on \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 if (opts.failOn !== undefined) {\n const failOn = opts.failOn;\n\n let failCount = 0;\n let failReason = '';\n\n if (failOn === 'affected') {\n failCount = filteredRows.filter(r => r.verdict === 'affected').length;\n failReason = `affected`;\n } else if (failOn === 'any') {\n failCount = filteredRows.length;\n failReason = `any`;\n } else if (failOn === 'critical') {\n failCount = filteredRows.filter(r => r.severity_score != null && r.severity_score >= 9.0).length;\n failReason = `critical`;\n } else if (failOn === 'high') {\n failCount = filteredRows.filter(r => r.severity_score != null && r.severity_score >= 7.0).length;\n failReason = `high`;\n } else {\n const epssThreshold = parseEpssFailOn(failOn);\n if (epssThreshold !== null) {\n failCount = filteredRows.filter(r => r.epss_score != null && r.epss_score >= epssThreshold).length;\n failReason = `epss=${epssThreshold}`;\n }\n }\n\n if (failCount > 0) {\n console.log(` \\x1b[31m\u2716\\x1b[0m --fail-on ${failReason}: ${failCount} ${failReason === 'any' ? '' : `${failReason} `}vulnerabilit${failCount === 1 ? 'y' : 'ies'} found. Exiting with code 1.`);\n cg.close();\n process.exit(1);\n }\n }\n\n cg.close();\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { Command } from 'commander';\nimport * as path from 'path';\nimport { loadConfig } from '../../config';\nimport { dim, reset, violet, bold, green } from '../ui';\nimport { formatFixSuggestion } from '../../security/export/fix-suggestions';\nimport { SuppressionManager } from '../../security/suppressions';\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\n/** Parse an `epss=N` fail-on value and return the threshold, or null if not an epss condition. */\nfunction parseEpssFailOn(failOn: string): number | null {\n const m = failOn.match(/^epss=(.+)$/);\n if (!m) return null;\n const n = parseFloat(m[1]);\n return isNaN(n) ? null : n;\n}\n\n/** Extract workspace label from a source_manifests JSON string. */\nfunction workspaceFromManifests(sourceManifests: string | null): string {\n if (!sourceManifests) return 'root';\n try {\n const manifests: string[] = JSON.parse(sourceManifests);\n if (!manifests.length) return 'root';\n const dir = path.dirname(manifests[0]);\n return dir === '.' ? 'root' : dir;\n } catch {\n return 'root';\n }\n}\n\nexport function register(program: Command): void {\n program\n .command('vulns [projectPath]')\n .description('List vulnerabilities with reachability verdicts and severity')\n .option('--severity <level>', 'Filter by severity: critical, high, medium, low')\n .option('--verdict <verdict>', 'Filter by verdict: affected, not_affected, under_investigation')\n .option('--refresh', 'Trigger fresh vulnerability enrichment before listing')\n .option('--epss <threshold>', 'Filter by EPSS score (e.g. 0.5 shows only vulns with EPSS >= 0.5)')\n .option('--stale', 'Show staleness score of the affected dependency alongside each CVE')\n .option('--sort <key>', 'Sort results by: risk (default), cvss, epss, name')\n .option('--add <cveId>', 'Manually register a CVE')\n .option('--package <name>', 'Package name for --add')\n .option('--version <ver>', 'Package version for --add')\n .option('--fail-on <condition>', 'Exit 1 if condition is met: affected, any, critical, high, epss=N')\n .option('--group-by <key>', 'Group output by: workspace')\n .action(async (projectPath: string | undefined, opts: {\n severity?: string;\n verdict?: string;\n refresh?: boolean;\n epss?: string;\n stale?: boolean;\n sort?: string;\n add?: string;\n package?: string;\n version?: string;\n failOn?: string;\n groupBy?: string;\n }) => {\n const target = path.resolve(projectPath ?? process.cwd());\n const config = await loadConfig(target);\n\n if (!config.enableSecurity) {\n console.error(`\\n ${'\\x1b[33m'}\u26A0 Security analysis is disabled.${reset}`);\n console.error(` ${dim}Enable it in .kirograph/config.json:${reset} ${violet}${bold}\"enableSecurity\": true${reset}`);\n console.error(` ${dim}Then re-run:${reset} ${violet}${bold}kirograph index${reset}\\n`);\n process.exit(1);\n }\n\n // Validate --fail-on early\n if (opts.failOn !== undefined) {\n const validFailOns = ['affected', 'any', 'critical', 'high'];\n const isEpss = parseEpssFailOn(opts.failOn) !== null;\n if (!validFailOns.includes(opts.failOn) && !isEpss) {\n console.error(` \u2716 Invalid --fail-on value: ${opts.failOn}. Use: affected, any, critical, high, epss=N`);\n process.exit(1);\n }\n }\n\n // Validate --group-by early\n if (opts.groupBy !== undefined && opts.groupBy !== 'workspace') {\n console.error(` \u2716 Invalid --group-by value: ${opts.groupBy}. Supported: workspace`);\n process.exit(1);\n }\n\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n if (!KiroGraph.isInitialized(target)) {\n console.error(' \u2716 KiroGraph not initialized. Run: kirograph init');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(target);\n const db = cg.getDatabase();\n db.applySecuritySchema();\n const rawDb = db.getRawDb();\n\n // Handle --add: manually register a CVE\n if (opts.add) {\n if (!opts.package || !opts.version) {\n console.error(` \u2716 --add requires --package <name> and --version <ver>`);\n cg.close(); process.exit(1);\n }\n\n const cveId = opts.add;\n const pkgName = opts.package;\n const pkgVersion = opts.version;\n\n // Find the matching dependency node\n const depRow: { node_id: string; ecosystem: string } | undefined = rawDb.get(\n `SELECT node_id, ecosystem FROM sec_dependencies\n WHERE package_name = ? AND (resolved_version = ? OR declared_constraint = ?)`,\n [pkgName, pkgVersion, pkgVersion],\n );\n\n if (!depRow) {\n console.error(` \u2716 No dependency found matching ${violet}${pkgName}@${pkgVersion}${reset}`);\n console.error(` ${dim}Run${reset} ${violet}${bold}kirograph index${reset} ${dim}first to discover dependencies.${reset}`);\n cg.close(); process.exit(1);\n }\n\n // Create the vulnerability node\n const vulnNodeId = `vuln:${cveId}`;\n const now = Date.now();\n\n rawDb.run(\n `INSERT OR REPLACE INTO nodes\n (id, kind, name, qualified_name, file_path, language,\n start_line, end_line, start_column, end_column,\n is_exported, is_async, is_static, is_abstract, updated_at)\n VALUES (?, 'vulnerability', ?, ?, '', 'unknown', 0, 0, 0, 0, 0, 0, 0, 0, ?)`,\n [vulnNodeId, cveId, cveId, now],\n );\n\n rawDb.run(\n `INSERT OR REPLACE INTO sec_vulnerabilities\n (node_id, cve_id, severity_score, affected_ranges, fixed_version, summary, source_database)\n VALUES (?, ?, NULL, '[]', NULL, 'Manually registered', 'manual')`,\n [vulnNodeId, cveId],\n );\n\n // Create has_vulnerability edge\n rawDb.run(\n `INSERT OR IGNORE INTO edges (source, target, kind, confidence, confidence_score)\n VALUES (?, ?, 'has_vulnerability', 'extracted', 1.0)`,\n [depRow.node_id, vulnNodeId],\n );\n\n console.log(` ${green}\u2713${reset} Registered ${violet}${bold}${cveId}${reset} against ${violet}${pkgName}@${pkgVersion}${reset}`);\n cg.close();\n return;\n }\n\n // Handle --refresh: trigger fresh vulnerability enrichment\n if (opts.refresh) {\n console.error(` ${dim}Refreshing vulnerability data from configured databases...${reset}`);\n const { OsvAdapter } = await Promise.resolve().then(() => require('../../security/vuln/osv-adapter.js'));\n const { VulnerabilityDatabaseClient } = await Promise.resolve().then(() => require('../../security/vuln/client.js'));\n\n const adapters = config.securityDatabases.map((dbName: string) => {\n if (dbName.toUpperCase() === 'OSV') return new OsvAdapter();\n return null;\n }).filter(Boolean) as any[];\n\n const client = new VulnerabilityDatabaseClient(adapters, db, undefined, target);\n const result = await client.enrichAll();\n\n console.error(` ${green}\u2713${reset} Checked ${bold}${result.dependenciesChecked}${reset} dependencies, found ${bold}${result.vulnerabilitiesFound}${reset} vulnerabilities`);\n if (result.errors.length > 0) {\n console.error(` ${'\\x1b[33m'}\u26A0${reset} ${result.errors.length} error(s) during enrichment`);\n }\n console.error();\n }\n\n // Build query for listing vulnerabilities\n // Include source_manifests when group-by workspace is requested\n const selectSourceManifests = opts.groupBy === 'workspace' ? `,\\n d.source_manifests` : '';\n let query = `\n SELECT\n v.node_id, v.cve_id, v.severity_score, v.fixed_version, v.summary, v.source_database,\n v.epss_score, v.epss_percentile, v.risk_score,\n d.package_name, d.ecosystem, d.resolved_version, d.declared_constraint,\n d.staleness_score,\n r.verdict${selectSourceManifests}\n FROM sec_vulnerabilities v\n LEFT JOIN edges e ON e.target = v.node_id AND e.kind = 'has_vulnerability'\n LEFT JOIN sec_dependencies d ON d.node_id = e.source\n LEFT JOIN sec_reachability r ON r.vulnerability_node_id = v.node_id\n WHERE 1=1\n `;\n const params: any[] = [];\n\n // Apply severity filter.\n // Bounds are half-open [min, max) and MUST mirror the display buckets in\n // printVulnRow() so the filter and the rendered label never disagree:\n // CRITICAL >= 9.0, HIGH >= 7.0, MEDIUM >= 4.0, LOW < 4.0 (incl. 0.0).\n if (opts.severity) {\n const severityRanges: Record<string, [number, number]> = {\n critical: [9.0, 10.01],\n high: [7.0, 9.0],\n medium: [4.0, 7.0],\n low: [0.0, 4.0],\n };\n const range = severityRanges[opts.severity.toLowerCase()];\n if (!range) {\n console.error(` \u2716 Invalid severity: ${opts.severity}. Use: critical, high, medium, low`);\n cg.close(); process.exit(1);\n }\n // severity_score IS NULL means \"unknown\" \u2014 excluded from every band.\n query += ` AND v.severity_score IS NOT NULL AND v.severity_score >= ? AND v.severity_score < ?`;\n params.push(range[0], range[1]);\n }\n\n // Apply verdict filter\n if (opts.verdict) {\n const validVerdicts = ['affected', 'not_affected', 'under_investigation'];\n if (!validVerdicts.includes(opts.verdict)) {\n console.error(` \u2716 Invalid verdict: ${opts.verdict}. Use: affected, not_affected, under_investigation`);\n cg.close(); process.exit(1);\n }\n query += ` AND r.verdict = ?`;\n params.push(opts.verdict);\n }\n\n // Apply EPSS threshold filter\n if (opts.epss !== undefined) {\n const epssThreshold = parseFloat(opts.epss);\n if (isNaN(epssThreshold) || epssThreshold < 0 || epssThreshold > 1) {\n console.error(` \u2716 Invalid EPSS threshold: ${opts.epss}. Use a number between 0 and 1 (e.g. 0.5)`);\n cg.close(); process.exit(1);\n }\n query += ` AND v.epss_score >= ?`;\n params.push(epssThreshold);\n }\n\n // Resolve sort order\n const sortKey = opts.sort?.toLowerCase() ?? 'risk';\n const validSortKeys = ['risk', 'cvss', 'epss', 'name'];\n if (!validSortKeys.includes(sortKey)) {\n console.error(` \u2716 Invalid sort key: ${opts.sort}. Use: risk, cvss, epss, name`);\n cg.close(); process.exit(1);\n }\n const sortClause =\n sortKey === 'risk' ? `v.risk_score DESC NULLS LAST` :\n sortKey === 'cvss' ? `v.severity_score DESC NULLS LAST` :\n sortKey === 'epss' ? `v.epss_score DESC NULLS LAST` :\n `v.cve_id ASC`;\n query += ` ORDER BY ${sortClause}`;\n\n const rows: Array<{\n node_id: string;\n cve_id: string;\n severity_score: number | null;\n fixed_version: string | null;\n summary: string | null;\n source_database: string;\n epss_score: number | null;\n epss_percentile: number | null;\n risk_score: number | null;\n package_name: string | null;\n ecosystem: string | null;\n resolved_version: string | null;\n declared_constraint: string | null;\n staleness_score: number | null;\n verdict: string | null;\n source_manifests?: string | null;\n }> = rawDb.all(query, params);\n\n // Deduplicate by (cve_id, package_name, ecosystem) \u2014 same CVE can appear multiple\n // times if a package is declared in multiple manifests (monorepo) or has multiple\n // dep nodes. Keep the row with the worst verdict (affected > under_investigation > not_affected > null).\n const verdictRank = (v: string | null) =>\n v === 'affected' ? 3 : v === 'under_investigation' ? 2 : v === 'not_affected' ? 1 : 0;\n const deduped = new Map<string, typeof rows[0]>();\n for (const row of rows) {\n const key = `${row.cve_id}::${row.package_name ?? ''}::${row.ecosystem ?? ''}`;\n const existing = deduped.get(key);\n if (!existing || verdictRank(row.verdict) > verdictRank(existing.verdict)) {\n deduped.set(key, row);\n }\n }\n const dedupedRows = [...deduped.values()];\n\n // Filter out suppressed CVEs\n const suppressions = new SuppressionManager(target);\n const suppressedRows = dedupedRows.filter(row => suppressions.isSuppressed(row.cve_id));\n const filteredRows = dedupedRows.filter(row => !suppressions.isSuppressed(row.cve_id));\n\n // Maven has no lock file: a <dependency> with no explicit <version> (the\n // common case under a BOM parent like spring-boot-starter-parent) never\n // gets a resolved version, so it's silently skipped during vulnerability\n // enrichment. Hint at the fix when that's likely hiding results.\n const unresolvedMavenCount = (rawDb.get(\n `SELECT COUNT(*) as count FROM sec_dependencies\n WHERE ecosystem = 'maven' AND (resolved_version IS NULL OR resolved_version = '')\n AND (declared_constraint IS NULL OR declared_constraint = '')`,\n ) as { count: number } | undefined)?.count ?? 0;\n\n if (filteredRows.length === 0) {\n const filterNote = (opts.severity || opts.verdict)\n ? ` matching filters`\n : '';\n console.log(`\\n ${dim}No vulnerabilities found${filterNote}.${reset}\\n`);\n if (suppressedRows.length > 0) {\n console.log(` ${dim}${suppressedRows.length} CVE(s) suppressed \u2014 kirograph vuln suppressions to review${reset}\\n`);\n }\n if (unresolvedMavenCount > 0) {\n console.log(` ${dim}${unresolvedMavenCount} Maven dependenc${unresolvedMavenCount === 1 ? 'y has' : 'ies have'} no resolved version (BOM-managed, e.g. via spring-boot-starter-parent) and were skipped.${reset}`);\n console.log(` ${dim}Run${reset} ${violet}${bold}mvn dependency:tree -DoutputFile=dependency-tree.txt${reset}${dim} next to pom.xml, then${reset} ${violet}${bold}kirograph index${dim} again to resolve them.${reset}\\n`);\n }\n cg.close();\n return;\n }\n\n // \u2500\u2500 Render a single vulnerability row \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 function printVulnRow(row: (typeof filteredRows)[0], indent = ' '): void {\n // Severity badge\n const score = row.severity_score;\n let severityLabel: string;\n let severityColor: string;\n if (score == null) {\n severityLabel = 'unknown';\n severityColor = dim;\n } else if (score >= 9.0) {\n severityLabel = 'CRITICAL';\n severityColor = '\\x1b[31m';\n } else if (score >= 7.0) {\n severityLabel = 'HIGH';\n severityColor = '\\x1b[31m';\n } else if (score >= 4.0) {\n severityLabel = 'MEDIUM';\n severityColor = '\\x1b[33m';\n } else {\n severityLabel = 'LOW';\n severityColor = dim;\n }\n\n // Verdict badge\n let verdictLabel: string;\n let verdictColor: string;\n if (!row.verdict) {\n verdictLabel = 'pending';\n verdictColor = dim;\n } else if (row.verdict === 'affected') {\n verdictLabel = 'affected';\n verdictColor = '\\x1b[31m';\n } else if (row.verdict === 'not_affected') {\n verdictLabel = 'not affected';\n verdictColor = green;\n } else {\n verdictLabel = 'investigating';\n verdictColor = '\\x1b[33m';\n }\n\n const pkg = row.package_name\n ? `${row.package_name}@${row.resolved_version || row.declared_constraint || '?'}`\n : 'unknown package';\n\n // EPSS badge\n let epssBadge = '';\n if (row.epss_score != null && row.epss_percentile != null) {\n const epssColor = row.epss_score >= 0.3 ? '\\x1b[33m' : dim;\n const scoreStr = row.epss_score.toFixed(2);\n const pctStr = `${Math.round(row.epss_percentile * 100)}th%`;\n epssBadge = ` ${epssColor}${dim}[EPSS: ${scoreStr} / ${pctStr}]${reset}`;\n }\n\n // Risk score badge\n let riskBadge = '';\n if (row.risk_score != null) {\n const riskColor = row.risk_score >= 7 ? '\\x1b[31m' : row.risk_score >= 4 ? '\\x1b[33m' : dim;\n riskBadge = ` ${riskColor}[Risk: ${row.risk_score.toFixed(1)}]${reset}`;\n }\n\n console.log(`${indent}${severityColor}${severityLabel}${reset} ${violet}${bold}${row.cve_id}${reset} ${dim}${pkg}${reset} [${verdictColor}${verdictLabel}${reset}]${epssBadge}${riskBadge}`);\n\n if (row.summary && row.summary !== 'Manually registered') {\n const truncated = row.summary.length > 100 ? row.summary.slice(0, 100) + '\u2026' : row.summary;\n console.log(`${indent} ${dim}${truncated}${reset}`);\n }\n\n // Staleness badge (when --stale flag is set)\n if (opts.stale && row.staleness_score != null) {\n const s = row.staleness_score;\n const staleColor = s >= 0.7 ? '\\x1b[31m' : s >= 0.4 ? '\\x1b[33m' : dim;\n console.log(`${indent} ${staleColor}${dim}[staleness: ${s.toFixed(2)}]${reset}`);\n }\n\n // Fix suggestion\n if (row.fixed_version && row.ecosystem && row.package_name) {\n const fix = formatFixSuggestion(row.ecosystem, row.package_name, row.fixed_version);\n if (fix) {\n console.log(`${indent} ${fix}`);\n }\n }\n\n console.log();\n }\n\n // \u2500\u2500 Output: grouped or flat \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 if (opts.groupBy === 'workspace') {\n // Group by workspace (directory of first source manifest)\n const groups = new Map<string, Array<(typeof filteredRows)[0]>>();\n for (const row of filteredRows) {\n const ws = workspaceFromManifests(row.source_manifests ?? null);\n if (!groups.has(ws)) groups.set(ws, []);\n groups.get(ws)!.push(row);\n }\n\n // Only apply workspace grouping when there are multiple distinct workspaces\n const workspaces = Array.from(groups.keys());\n if (workspaces.length <= 1) {\n // Single workspace \u2014 fall through to flat output\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const row of filteredRows) {\n printVulnRow(row);\n }\n } else {\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const ws of workspaces) {\n const wsRows = groups.get(ws)!;\n const count = wsRows.length;\n const header = `Workspace: ${ws} (${count} vulnerabilit${count === 1 ? 'y' : 'ies'})`;\n const line = '\u2500'.repeat(header.length);\n console.log(` ${bold}${header}${reset}`);\n console.log(` ${dim}${line}${reset}`);\n for (const row of wsRows) {\n printVulnRow(row);\n }\n }\n }\n } else {\n console.log(`\\n ${bold}Vulnerabilities${reset} (${filteredRows.length})\\n`);\n for (const row of filteredRows) {\n printVulnRow(row);\n }\n }\n\n if (suppressedRows.length > 0) {\n console.log(` ${dim}${suppressedRows.length} CVE(s) suppressed \u2014 kirograph vuln suppressions to review${reset}\\n`);\n }\n\n // Hint when reachability hasn't been computed yet (verdict is pending).\n // vulns --refresh only re-queries vulnerability data; the call-graph\n // reachability analysis that resolves [pending] \u2192 [affected]/[not affected]\n // runs during `kirograph index`.\n const pendingCount = filteredRows.filter(r => !r.verdict).length;\n if (pendingCount > 0) {\n console.log(` ${dim}${pendingCount} vulnerabilit${pendingCount === 1 ? 'y is' : 'ies are'} [pending] reachability analysis \u2014 run ${reset}kirograph index${dim} to compute call-graph verdicts.${reset}\\n`);\n }\n\n if (unresolvedMavenCount > 0) {\n console.log(` ${dim}${unresolvedMavenCount} Maven dependenc${unresolvedMavenCount === 1 ? 'y has' : 'ies have'} no resolved version (BOM-managed, e.g. via spring-boot-starter-parent) and were skipped.${reset}`);\n console.log(` ${dim}Run${reset} ${violet}${bold}mvn dependency:tree -DoutputFile=dependency-tree.txt${reset}${dim} next to pom.xml, then${reset} ${violet}${bold}kirograph index${dim} again to resolve them.${reset}\\n`);\n }\n\n // \u2500\u2500 CI exit codes: --fail-on \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 if (opts.failOn !== undefined) {\n const failOn = opts.failOn;\n\n let failCount = 0;\n let failReason = '';\n\n if (failOn === 'affected') {\n failCount = filteredRows.filter(r => r.verdict === 'affected').length;\n failReason = `affected`;\n } else if (failOn === 'any') {\n failCount = filteredRows.length;\n failReason = `any`;\n } else if (failOn === 'critical') {\n failCount = filteredRows.filter(r => r.severity_score != null && r.severity_score >= 9.0).length;\n failReason = `critical`;\n } else if (failOn === 'high') {\n failCount = filteredRows.filter(r => r.severity_score != null && r.severity_score >= 7.0).length;\n failReason = `high`;\n } else {\n const epssThreshold = parseEpssFailOn(failOn);\n if (epssThreshold !== null) {\n failCount = filteredRows.filter(r => r.epss_score != null && r.epss_score >= epssThreshold).length;\n failReason = `epss=${epssThreshold}`;\n }\n }\n\n if (failCount > 0) {\n console.log(` \\x1b[31m\u2716\\x1b[0m --fail-on ${failReason}: ${failCount} ${failReason === 'any' ? '' : `${failReason} `}vulnerabilit${failCount === 1 ? 'y' : 'ies'} found. Exiting with code 1.`);\n cg.close();\n process.exit(1);\n }\n }\n\n cg.close();\n });\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,WAAsB;AACtB,oBAA2B;AAC3B,gBAAgD;AAChD,6BAAoC;AACpC,0BAAmC;AAKnC,SAAS,gBAAgB,QAA+B;AACtD,QAAM,IAAI,OAAO,MAAM,aAAa;AACpC,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,WAAW,EAAE,CAAC,CAAC;AACzB,SAAO,MAAM,CAAC,IAAI,OAAO;AAC3B;AAGA,SAAS,uBAAuB,iBAAwC;AACtE,MAAI,CAAC,gBAAiB,QAAO;AAC7B,MAAI;AACF,UAAM,YAAsB,KAAK,MAAM,eAAe;AACtD,QAAI,CAAC,UAAU,OAAQ,QAAO;AAC9B,UAAM,MAAM,KAAK,QAAQ,UAAU,CAAC,CAAC;AACrC,WAAO,QAAQ,MAAM,SAAS;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,SAAwB;AAC/C,UACG,QAAQ,qBAAqB,EAC7B,YAAY,8DAA8D,EAC1E,OAAO,sBAAsB,iDAAiD,EAC9E,OAAO,uBAAuB,gEAAgE,EAC9F,OAAO,aAAa,uDAAuD,EAC3E,OAAO,sBAAsB,mEAAmE,EAChG,OAAO,WAAW,oEAAoE,EACtF,OAAO,gBAAgB,mDAAmD,EAC1E,OAAO,iBAAiB,yBAAyB,EACjD,OAAO,oBAAoB,wBAAwB,EACnD,OAAO,mBAAmB,2BAA2B,EACrD,OAAO,yBAAyB,mEAAmE,EACnG,OAAO,oBAAoB,4BAA4B,EACvD,OAAO,OAAO,aAAiC,SAY1C;AACJ,UAAM,SAAS,KAAK,QAAQ,eAAe,QAAQ,IAAI,CAAC;AACxD,UAAM,SAAS,UAAM,0BAAW,MAAM;AAEtC,QAAI,CAAC,OAAO,gBAAgB;AAC1B,cAAQ,MAAM;AAAA,IAAO,UAAU,wCAAmC,eAAK,EAAE;AACzE,cAAQ,MAAM,KAAK,aAAG,uCAAuC,eAAK,IAAI,gBAAM,GAAG,cAAI,yBAAyB,eAAK,EAAE;AACnH,cAAQ,MAAM,KAAK,aAAG,eAAe,eAAK,IAAI,gBAAM,GAAG,cAAI,kBAAkB,eAAK;AAAA,CAAI;AACtF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAGA,QAAI,KAAK,WAAW,QAAW;AAC7B,YAAM,eAAe,CAAC,YAAY,OAAO,YAAY,MAAM;AAC3D,YAAM,SAAS,gBAAgB,KAAK,MAAM,MAAM;AAChD,UAAI,CAAC,aAAa,SAAS,KAAK,MAAM,KAAK,CAAC,QAAQ;AAClD,gBAAQ,MAAM,qCAAgC,KAAK,MAAM,8CAA8C;AACvG,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAGA,QAAI,KAAK,YAAY,UAAa,KAAK,YAAY,aAAa;AAC9D,cAAQ,MAAM,sCAAiC,KAAK,OAAO,wBAAwB;AACnF,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,aAAa,MAAM,QAAQ,QAAQ,EAAE,KAAK,MAAM,QAAQ,gBAAgB,CAAC,GAAG;AAClF,QAAI,CAAC,UAAU,cAAc,MAAM,GAAG;AACpC,cAAQ,MAAM,yDAAoD;AAClE,cAAQ,KAAK,CAAC;AAAA,IAChB;AAEA,UAAM,KAAK,MAAM,UAAU,KAAK,MAAM;AACtC,UAAM,KAAK,GAAG,YAAY;AAC1B,OAAG,oBAAoB;AACvB,UAAM,QAAQ,GAAG,SAAS;AAG1B,QAAI,KAAK,KAAK;AACZ,UAAI,CAAC,KAAK,WAAW,CAAC,KAAK,SAAS;AAClC,gBAAQ,MAAM,8DAAyD;AACvE,WAAG,MAAM;AAAG,gBAAQ,KAAK,CAAC;AAAA,MAC5B;AAEA,YAAM,QAAQ,KAAK;AACnB,YAAM,UAAU,KAAK;AACrB,YAAM,aAAa,KAAK;AAGxB,YAAM,SAA6D,MAAM;AAAA,QACvE;AAAA;AAAA,QAEA,CAAC,SAAS,YAAY,UAAU;AAAA,MAClC;AAEA,UAAI,CAAC,QAAQ;AACX,gBAAQ,MAAM,yCAAoC,gBAAM,GAAG,OAAO,IAAI,UAAU,GAAG,eAAK,EAAE;AAC1F,gBAAQ,MAAM,KAAK,aAAG,MAAM,eAAK,IAAI,gBAAM,GAAG,cAAI,kBAAkB,eAAK,IAAI,aAAG,kCAAkC,eAAK,EAAE;AACzH,WAAG,MAAM;AAAG,gBAAQ,KAAK,CAAC;AAAA,MAC5B;AAGA,YAAM,aAAa,QAAQ,KAAK;AAChC,YAAM,MAAM,KAAK,IAAI;AAErB,YAAM;AAAA,QACJ;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA,CAAC,YAAY,OAAO,OAAO,GAAG;AAAA,MAChC;AAEA,YAAM;AAAA,QACJ;AAAA;AAAA;AAAA,QAGA,CAAC,YAAY,KAAK;AAAA,MACpB;AAGA,YAAM;AAAA,QACJ;AAAA;AAAA,QAEA,CAAC,OAAO,SAAS,UAAU;AAAA,MAC7B;AAEA,cAAQ,IAAI,KAAK,eAAK,SAAI,eAAK,eAAe,gBAAM,GAAG,cAAI,GAAG,KAAK,GAAG,eAAK,YAAY,gBAAM,GAAG,OAAO,IAAI,UAAU,GAAG,eAAK,EAAE;AAC/H,SAAG,MAAM;AACT;AAAA,IACF;AAGA,QAAI,KAAK,SAAS;AAChB,cAAQ,MAAM,KAAK,aAAG,6DAA6D,eAAK,EAAE;AAC1F,YAAM,EAAE,WAAW,IAAI,MAAM,QAAQ,QAAQ,EAAE,KAAK,MAAM,QAAQ,oCAAoC,CAAC;AACvG,YAAM,EAAE,4BAA4B,IAAI,MAAM,QAAQ,QAAQ,EAAE,KAAK,MAAM,QAAQ,+BAA+B,CAAC;AAEnH,YAAM,WAAW,OAAO,kBAAkB,IAAI,CAAC,WAAmB;AAChE,YAAI,OAAO,YAAY,MAAM,MAAO,QAAO,IAAI,WAAW;AAC1D,eAAO;AAAA,MACT,CAAC,EAAE,OAAO,OAAO;AAEjB,YAAM,SAAS,IAAI,4BAA4B,UAAU,IAAI,QAAW,MAAM;AAC9E,YAAM,SAAS,MAAM,OAAO,UAAU;AAEtC,cAAQ,MAAM,KAAK,eAAK,SAAI,eAAK,YAAY,cAAI,GAAG,OAAO,mBAAmB,GAAG,eAAK,wBAAwB,cAAI,GAAG,OAAO,oBAAoB,GAAG,eAAK,kBAAkB;AAC1K,UAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,gBAAQ,MAAM,KAAK,UAAU,SAAI,eAAK,IAAI,OAAO,OAAO,MAAM,6BAA6B;AAAA,MAC7F;AACA,cAAQ,MAAM;AAAA,IAChB;AAIA,UAAM,wBAAwB,KAAK,YAAY,cAAc;AAAA,gCAAoC;AACjG,QAAI,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAMG,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOpC,UAAM,SAAgB,CAAC;AAMvB,QAAI,KAAK,UAAU;AACjB,YAAM,iBAAmD;AAAA,QACvD,UAAU,CAAC,GAAK,KAAK;AAAA,QACrB,MAAM,CAAC,GAAK,CAAG;AAAA,QACf,QAAQ,CAAC,GAAK,CAAG;AAAA,QACjB,KAAK,CAAC,GAAK,CAAG;AAAA,MAChB;AACA,YAAM,QAAQ,eAAe,KAAK,SAAS,YAAY,CAAC;AACxD,UAAI,CAAC,OAAO;AACV,gBAAQ,MAAM,8BAAyB,KAAK,QAAQ,oCAAoC;AACxF,WAAG,MAAM;AAAG,gBAAQ,KAAK,CAAC;AAAA,MAC5B;AAEA,eAAS;AACT,aAAO,KAAK,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAAA,IAChC;AAGA,QAAI,KAAK,SAAS;AAChB,YAAM,gBAAgB,CAAC,YAAY,gBAAgB,qBAAqB;AACxE,UAAI,CAAC,cAAc,SAAS,KAAK,OAAO,GAAG;AACzC,gBAAQ,MAAM,6BAAwB,KAAK,OAAO,oDAAoD;AACtG,WAAG,MAAM;AAAG,gBAAQ,KAAK,CAAC;AAAA,MAC5B;AACA,eAAS;AACT,aAAO,KAAK,KAAK,OAAO;AAAA,IAC1B;AAGA,QAAI,KAAK,SAAS,QAAW;AAC3B,YAAM,gBAAgB,WAAW,KAAK,IAAI;AAC1C,UAAI,MAAM,aAAa,KAAK,gBAAgB,KAAK,gBAAgB,GAAG;AAClE,gBAAQ,MAAM,oCAA+B,KAAK,IAAI,2CAA2C;AACjG,WAAG,MAAM;AAAG,gBAAQ,KAAK,CAAC;AAAA,MAC5B;AACA,eAAS;AACT,aAAO,KAAK,aAAa;AAAA,IAC3B;AAGA,UAAM,UAAU,KAAK,MAAM,YAAY,KAAK;AAC5C,UAAM,gBAAgB,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AACrD,QAAI,CAAC,cAAc,SAAS,OAAO,GAAG;AACpC,cAAQ,MAAM,8BAAyB,KAAK,IAAI,+BAA+B;AAC/E,SAAG,MAAM;AAAG,cAAQ,KAAK,CAAC;AAAA,IAC5B;AACA,UAAM,aACJ,YAAY,SAAS,iCACrB,YAAY,SAAS,qCACrB,YAAY,SAAS,iCACrB;AACF,aAAS,aAAa,UAAU;AAEhC,UAAM,OAiBD,MAAM,IAAI,OAAO,MAAM;AAK5B,UAAM,cAAc,CAAC,MACnB,MAAM,aAAa,IAAI,MAAM,wBAAwB,IAAI,MAAM,iBAAiB,IAAI;AACtF,UAAM,UAAU,oBAAI,IAA4B;AAChD,eAAW,OAAO,MAAM;AACtB,YAAM,MAAM,GAAG,IAAI,MAAM,KAAK,IAAI,gBAAgB,EAAE,KAAK,IAAI,aAAa,EAAE;AAC5E,YAAM,WAAW,QAAQ,IAAI,GAAG;AAChC,UAAI,CAAC,YAAY,YAAY,IAAI,OAAO,IAAI,YAAY,SAAS,OAAO,GAAG;AACzE,gBAAQ,IAAI,KAAK,GAAG;AAAA,MACtB;AAAA,IACF;AACA,UAAM,cAAc,CAAC,GAAG,QAAQ,OAAO,CAAC;AAGxC,UAAM,eAAe,IAAI,uCAAmB,MAAM;AAClD,UAAM,iBAAiB,YAAY,OAAO,SAAO,aAAa,aAAa,IAAI,MAAM,CAAC;AACtF,UAAM,eAAe,YAAY,OAAO,SAAO,CAAC,aAAa,aAAa,IAAI,MAAM,CAAC;AAMrF,UAAM,uBAAwB,MAAM;AAAA,MAClC;AAAA;AAAA;AAAA,IAGF,GAAqC,SAAS;AAE9C,QAAI,aAAa,WAAW,GAAG;AAC7B,YAAM,aAAc,KAAK,YAAY,KAAK,UACtC,sBACA;AACJ,cAAQ,IAAI;AAAA,IAAO,aAAG,2BAA2B,UAAU,IAAI,eAAK;AAAA,CAAI;AACxE,UAAI,eAAe,SAAS,GAAG;AAC7B,gBAAQ,IAAI,KAAK,aAAG,GAAG,eAAe,MAAM,kEAA6D,eAAK;AAAA,CAAI;AAAA,MACpH;AACA,UAAI,uBAAuB,GAAG;AAC5B,gBAAQ,IAAI,KAAK,aAAG,GAAG,oBAAoB,mBAAmB,yBAAyB,IAAI,UAAU,UAAU,4FAA4F,eAAK,EAAE;AAClN,gBAAQ,IAAI,KAAK,aAAG,MAAM,eAAK,IAAI,gBAAM,GAAG,cAAI,uDAAuD,eAAK,GAAG,aAAG,yBAAyB,eAAK,IAAI,gBAAM,GAAG,cAAI,kBAAkB,aAAG,0BAA0B,eAAK;AAAA,CAAI;AAAA,MAC3N;AACA,SAAG,MAAM;AACT;AAAA,IACF;AAIA,aAAS,aAAa,KAA+B,SAAS,MAAY;AAExE,YAAM,QAAQ,IAAI;AAClB,UAAI;AACJ,UAAI;AACJ,UAAI,SAAS,MAAM;AACjB,wBAAgB;AAChB,wBAAgB;AAAA,MAClB,WAAW,SAAS,GAAK;AACvB,wBAAgB;AAChB,wBAAgB;AAAA,MAClB,WAAW,SAAS,GAAK;AACvB,wBAAgB;AAChB,wBAAgB;AAAA,MAClB,WAAW,SAAS,GAAK;AACvB,wBAAgB;AAChB,wBAAgB;AAAA,MAClB,OAAO;AACL,wBAAgB;AAChB,wBAAgB;AAAA,MAClB;AAGA,UAAI;AACJ,UAAI;AACJ,UAAI,CAAC,IAAI,SAAS;AAChB,uBAAe;AACf,uBAAe;AAAA,MACjB,WAAW,IAAI,YAAY,YAAY;AACrC,uBAAe;AACf,uBAAe;AAAA,MACjB,WAAW,IAAI,YAAY,gBAAgB;AACzC,uBAAe;AACf,uBAAe;AAAA,MACjB,OAAO;AACL,uBAAe;AACf,uBAAe;AAAA,MACjB;AAEA,YAAM,MAAM,IAAI,eACZ,GAAG,IAAI,YAAY,IAAI,IAAI,oBAAoB,IAAI,uBAAuB,GAAG,KAC7E;AAGJ,UAAI,YAAY;AAChB,UAAI,IAAI,cAAc,QAAQ,IAAI,mBAAmB,MAAM;AACzD,cAAM,YAAY,IAAI,cAAc,MAAM,aAAa;AACvD,cAAM,WAAW,IAAI,WAAW,QAAQ,CAAC;AACzC,cAAM,SAAS,GAAG,KAAK,MAAM,IAAI,kBAAkB,GAAG,CAAC;AACvD,oBAAY,KAAK,SAAS,GAAG,aAAG,UAAU,QAAQ,MAAM,MAAM,IAAI,eAAK;AAAA,MACzE;AAGA,UAAI,YAAY;AAChB,UAAI,IAAI,cAAc,MAAM;AAC1B,cAAM,YAAY,IAAI,cAAc,IAAI,aAAa,IAAI,cAAc,IAAI,aAAa;AACxF,oBAAY,KAAK,SAAS,UAAU,IAAI,WAAW,QAAQ,CAAC,CAAC,IAAI,eAAK;AAAA,MACxE;AAEA,cAAQ,IAAI,GAAG,MAAM,GAAG,aAAa,GAAG,aAAa,GAAG,eAAK,KAAK,gBAAM,GAAG,cAAI,GAAG,IAAI,MAAM,GAAG,eAAK,KAAK,aAAG,GAAG,GAAG,GAAG,eAAK,MAAM,YAAY,GAAG,YAAY,GAAG,eAAK,IAAI,SAAS,GAAG,SAAS,EAAE;AAE9L,UAAI,IAAI,WAAW,IAAI,YAAY,uBAAuB;AACxD,cAAM,YAAY,IAAI,QAAQ,SAAS,MAAM,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI,WAAM,IAAI;AACnF,gBAAQ,IAAI,GAAG,MAAM,KAAK,aAAG,GAAG,SAAS,GAAG,eAAK,EAAE;AAAA,MACrD;AAGA,UAAI,KAAK,SAAS,IAAI,mBAAmB,MAAM;AAC7C,cAAM,IAAI,IAAI;AACd,cAAM,aAAa,KAAK,MAAM,aAAa,KAAK,MAAM,aAAa;AACnE,gBAAQ,IAAI,GAAG,MAAM,KAAK,UAAU,GAAG,aAAG,eAAe,EAAE,QAAQ,CAAC,CAAC,IAAI,eAAK,EAAE;AAAA,MAClF;AAGA,UAAI,IAAI,iBAAiB,IAAI,aAAa,IAAI,cAAc;AAC1D,cAAM,UAAM,4CAAoB,IAAI,WAAW,IAAI,cAAc,IAAI,aAAa;AAClF,YAAI,KAAK;AACP,kBAAQ,IAAI,GAAG,MAAM,KAAK,GAAG,EAAE;AAAA,QACjC;AAAA,MACF;AAEA,cAAQ,IAAI;AAAA,IACd;AAIA,QAAI,KAAK,YAAY,aAAa;AAEhC,YAAM,SAAS,oBAAI,IAA6C;AAChE,iBAAW,OAAO,cAAc;AAC9B,cAAM,KAAK,uBAAuB,IAAI,oBAAoB,IAAI;AAC9D,YAAI,CAAC,OAAO,IAAI,EAAE,EAAG,QAAO,IAAI,IAAI,CAAC,CAAC;AACtC,eAAO,IAAI,EAAE,EAAG,KAAK,GAAG;AAAA,MAC1B;AAGA,YAAM,aAAa,MAAM,KAAK,OAAO,KAAK,CAAC;AAC3C,UAAI,WAAW,UAAU,GAAG;AAE1B,gBAAQ,IAAI;AAAA,IAAO,cAAI,kBAAkB,eAAK,KAAK,aAAa,MAAM;AAAA,CAAK;AAC3E,mBAAW,OAAO,cAAc;AAC9B,uBAAa,GAAG;AAAA,QAClB;AAAA,MACF,OAAO;AACL,gBAAQ,IAAI;AAAA,IAAO,cAAI,kBAAkB,eAAK,KAAK,aAAa,MAAM;AAAA,CAAK;AAC3E,mBAAW,MAAM,YAAY;AAC3B,gBAAM,SAAS,OAAO,IAAI,EAAE;AAC5B,gBAAM,QAAQ,OAAO;AACrB,gBAAM,SAAS,cAAc,EAAE,KAAK,KAAK,gBAAgB,UAAU,IAAI,MAAM,KAAK;AAClF,gBAAM,OAAO,SAAI,OAAO,OAAO,MAAM;AACrC,kBAAQ,IAAI,KAAK,cAAI,GAAG,MAAM,GAAG,eAAK,EAAE;AACxC,kBAAQ,IAAI,KAAK,aAAG,GAAG,IAAI,GAAG,eAAK,EAAE;AACrC,qBAAW,OAAO,QAAQ;AACxB,yBAAa,GAAG;AAAA,UAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ,IAAI;AAAA,IAAO,cAAI,kBAAkB,eAAK,KAAK,aAAa,MAAM;AAAA,CAAK;AAC3E,iBAAW,OAAO,cAAc;AAC9B,qBAAa,GAAG;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,eAAe,SAAS,GAAG;AAC7B,cAAQ,IAAI,KAAK,aAAG,GAAG,eAAe,MAAM,kEAA6D,eAAK;AAAA,CAAI;AAAA,IACpH;AAMA,UAAM,eAAe,aAAa,OAAO,OAAK,CAAC,EAAE,OAAO,EAAE;AAC1D,QAAI,eAAe,GAAG;AACpB,cAAQ,IAAI,KAAK,aAAG,GAAG,YAAY,gBAAgB,iBAAiB,IAAI,SAAS,SAAS,+CAA0C,eAAK,kBAAkB,aAAG,mCAAmC,eAAK;AAAA,CAAI;AAAA,IAC5M;AAEA,QAAI,uBAAuB,GAAG;AAC5B,cAAQ,IAAI,KAAK,aAAG,GAAG,oBAAoB,mBAAmB,yBAAyB,IAAI,UAAU,UAAU,4FAA4F,eAAK,EAAE;AAClN,cAAQ,IAAI,KAAK,aAAG,MAAM,eAAK,IAAI,gBAAM,GAAG,cAAI,uDAAuD,eAAK,GAAG,aAAG,yBAAyB,eAAK,IAAI,gBAAM,GAAG,cAAI,kBAAkB,aAAG,0BAA0B,eAAK;AAAA,CAAI;AAAA,IAC3N;AAIA,QAAI,KAAK,WAAW,QAAW;AAC7B,YAAM,SAAS,KAAK;AAEpB,UAAI,YAAY;AAChB,UAAI,aAAa;AAEjB,UAAI,WAAW,YAAY;AACzB,oBAAY,aAAa,OAAO,OAAK,EAAE,YAAY,UAAU,EAAE;AAC/D,qBAAa;AAAA,MACf,WAAW,WAAW,OAAO;AAC3B,oBAAY,aAAa;AACzB,qBAAa;AAAA,MACf,WAAW,WAAW,YAAY;AAChC,oBAAY,aAAa,OAAO,OAAK,EAAE,kBAAkB,QAAQ,EAAE,kBAAkB,CAAG,EAAE;AAC1F,qBAAa;AAAA,MACf,WAAW,WAAW,QAAQ;AAC5B,oBAAY,aAAa,OAAO,OAAK,EAAE,kBAAkB,QAAQ,EAAE,kBAAkB,CAAG,EAAE;AAC1F,qBAAa;AAAA,MACf,OAAO;AACL,cAAM,gBAAgB,gBAAgB,MAAM;AAC5C,YAAI,kBAAkB,MAAM;AAC1B,sBAAY,aAAa,OAAO,OAAK,EAAE,cAAc,QAAQ,EAAE,cAAc,aAAa,EAAE;AAC5F,uBAAa,QAAQ,aAAa;AAAA,QACpC;AAAA,MACF;AAEA,UAAI,YAAY,GAAG;AACjB,gBAAQ,IAAI,qCAAgC,UAAU,KAAK,SAAS,IAAI,eAAe,QAAQ,KAAK,GAAG,UAAU,GAAG,eAAe,cAAc,IAAI,MAAM,KAAK,8BAA8B;AAC9L,WAAG,MAAM;AACT,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,OAAG,MAAM;AAAA,EACX,CAAC;AACL;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -227,6 +227,62 @@ function register(program) {
|
|
|
227
227
|
console.log();
|
|
228
228
|
}
|
|
229
229
|
});
|
|
230
|
+
wiki.command("links <slug>").description("Show outgoing, broken, and incoming [[slug]] links for a page").option("--format <fmt>", "Output format: text, json", "text").action(async (slug, opts) => {
|
|
231
|
+
const cwd = process.cwd();
|
|
232
|
+
const w = await getWiki(cwd);
|
|
233
|
+
const links = w.getLinks(slug);
|
|
234
|
+
if (!links) {
|
|
235
|
+
console.error(` \u2716 Wiki page "${slug}" not found. Run \`kirograph wiki list\` to see available pages.`);
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
if (opts.format === "json") {
|
|
239
|
+
console.log(JSON.stringify(links, null, 2));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
console.log(`
|
|
243
|
+
${(0, import_ui.section)("Wiki Links:")} ${import_ui.violet}${import_ui.bold}${slug}${import_ui.reset}
|
|
244
|
+
`);
|
|
245
|
+
console.log(` ${import_ui.bold}Outgoing${import_ui.reset} ${import_ui.dim}(${links.outgoing.length})${import_ui.reset}`);
|
|
246
|
+
if (links.outgoing.length === 0) {
|
|
247
|
+
console.log(` ${import_ui.dim}(none)${import_ui.reset}`);
|
|
248
|
+
} else {
|
|
249
|
+
for (const s of links.outgoing) console.log(` ${import_ui.violet}\u2192${import_ui.reset} [[${s}]]`);
|
|
250
|
+
}
|
|
251
|
+
if (links.broken.length > 0) {
|
|
252
|
+
console.log(`
|
|
253
|
+
${yellow}Broken${import_ui.reset} ${import_ui.dim}(${links.broken.length})${import_ui.reset}`);
|
|
254
|
+
for (const s of links.broken) console.log(` ${yellow}\u26A0${import_ui.reset} [[${s}]] ${import_ui.dim}\u2014 page does not exist${import_ui.reset}`);
|
|
255
|
+
}
|
|
256
|
+
console.log(`
|
|
257
|
+
${import_ui.bold}Incoming${import_ui.reset} ${import_ui.dim}(${links.incoming.length}) \u2014 pages that link here${import_ui.reset}`);
|
|
258
|
+
if (links.incoming.length === 0) {
|
|
259
|
+
console.log(` ${import_ui.dim}(none)${import_ui.reset}`);
|
|
260
|
+
} else {
|
|
261
|
+
for (const s of links.incoming) console.log(` ${import_ui.violet}\u2190${import_ui.reset} [[${s}]]`);
|
|
262
|
+
}
|
|
263
|
+
console.log();
|
|
264
|
+
});
|
|
265
|
+
wiki.command("rename <from> <to>").description("Rename a page slug, moving its file and updating every [[slug]] reference to it").action(async (from, to) => {
|
|
266
|
+
const cwd = process.cwd();
|
|
267
|
+
const w = await getWiki(cwd);
|
|
268
|
+
let result;
|
|
269
|
+
try {
|
|
270
|
+
result = w.rename(from, to);
|
|
271
|
+
} catch (err) {
|
|
272
|
+
console.error(` \u2716 ${err instanceof Error ? err.message : String(err)}`);
|
|
273
|
+
process.exit(1);
|
|
274
|
+
}
|
|
275
|
+
console.log(`
|
|
276
|
+
${import_ui.green}\u2713${import_ui.reset} Renamed ${import_ui.violet}[[${result.from}]]${import_ui.reset} \u2192 ${import_ui.violet}[[${result.to}]]${import_ui.reset}
|
|
277
|
+
`);
|
|
278
|
+
if (result.linksUpdated.length > 0) {
|
|
279
|
+
console.log(` ${import_ui.bold}Links updated in ${result.linksUpdated.length} page(s):${import_ui.reset}`);
|
|
280
|
+
for (const s of result.linksUpdated) console.log(` ${import_ui.dim}\xB7${import_ui.reset} ${s}`);
|
|
281
|
+
} else {
|
|
282
|
+
console.log(` ${import_ui.dim}No other pages referenced [[${result.from}]].${import_ui.reset}`);
|
|
283
|
+
}
|
|
284
|
+
console.log();
|
|
285
|
+
});
|
|
230
286
|
wiki.command("reindex").description("Rebuild SQLite index from .kirograph/wiki/*.md files").action(async () => {
|
|
231
287
|
const cwd = process.cwd();
|
|
232
288
|
const w = await getWiki(cwd);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/bin/commands/wiki.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * KiroGraph Wiki CLI\n *\n * kirograph wiki init\n * kirograph wiki ingest [source-file]\n * kirograph wiki apply-diff [diff-file]\n * kirograph wiki search <query>\n * kirograph wiki page <slug>\n * kirograph wiki list\n * kirograph wiki lint\n * kirograph wiki reindex\n * kirograph wiki status\n */\n\nimport { Command } from 'commander';\nimport * as fs from 'fs';\nimport { dim, reset, violet, bold, section, green } from '../ui';\n\nconst yellow = '\\x1b[33m';\n\nasync function getWiki(cwd: string) {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const config = await loadConfig(cwd);\n if (!config.enableWiki) {\n console.error(' \u2716 Wiki is not enabled. Set enableWiki: true in .kirograph/config.json');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n\n const kirographDir = `${cwd}/.kirograph`;\n const wiki = new KiroGraphWiki(db.getRawDb(), kirographDir, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n wiki.initialize();\n return wiki;\n}\n\nfunction readStdinSync(): string {\n return fs.readFileSync('/dev/stdin', 'utf8');\n}\n\nexport function register(program: Command): void {\n const wiki = program\n .command('wiki')\n .description('LLM-maintained structured wiki (requires enableWiki: true)');\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 wiki\n .command('init')\n .description('Initialize wiki: create SCHEMA.md and MANIFEST.md in .kirograph/wiki/')\n .action(async () => {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n const cwd = process.cwd();\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const config = await loadConfig(cwd);\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n const w = new KiroGraphWiki(db.getRawDb(), `${cwd}/.kirograph`, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n w.initWiki();\n console.log(`\\n ${green}\u2713${reset} Wiki initialized in ${dim}.kirograph/wiki/${reset}`);\n console.log(` ${dim}Edit .kirograph/wiki/SCHEMA.md to customize naming and page structure.${reset}\\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 wiki\n .command('ingest [source]')\n .description('Print the ingest prompt for the LLM (reads file or stdin)')\n .option('--name <name>', 'Source name to include in the prompt')\n .action(async (source: string | undefined, opts: { name?: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n\n let content: string;\n let sourceName = opts.name ?? source ?? 'source';\n\n if (source && fs.existsSync(source)) {\n content = fs.readFileSync(source, 'utf8');\n sourceName = opts.name ?? source;\n } else if (source) {\n content = source;\n } else {\n content = readStdinSync();\n }\n\n const prompt = w.getIngestPrompt(content, sourceName);\n console.log(`\\n ${section('Wiki Ingest Prompt')} ${dim}(pass to LLM, then run wiki apply-diff)${reset}\\n`);\n console.log(prompt);\n console.log();\n });\n\n // \u2500\u2500 apply-diff \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('apply-diff [diff]')\n .description('Apply a WIKI_DIFF string to the wiki (reads file or stdin)')\n .action(async (diff: string | undefined) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n\n let rawDiff: string;\n if (diff && fs.existsSync(diff)) {\n rawDiff = fs.readFileSync(diff, 'utf8');\n } else if (diff) {\n rawDiff = diff;\n } else {\n rawDiff = readStdinSync();\n }\n\n const result = w.applyDiff(rawDiff);\n\n console.log(`\\n ${green}\u2713${reset} Wiki diff applied\\n`);\n if (result.created.length) {\n console.log(` ${violet}Created:${reset} ${result.created.join(', ')}`);\n }\n if (result.updated.length) {\n console.log(` ${violet}Updated:${reset} ${result.updated.join(', ')}`);\n }\n if (result.conflictsResolved.length) {\n console.log(` ${green}Conflicts resolved:${reset} ${result.conflictsResolved.join(', ')}`);\n }\n if (result.conflictsPending.length) {\n console.log(`\\n ${yellow}\u26A1 Conflicts pending (${result.conflictsPending.length}):${reset}`);\n for (const c of result.conflictsPending) {\n console.log(` ${dim} ${c.page} \u00A7${c.section}${reset}`);\n console.log(` existing: \"${c.existing}\"`);\n console.log(` incoming: \"${c.incoming}\" (source: ${c.source})`);\n }\n }\n console.log();\n });\n\n // \u2500\u2500 search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('search <query>')\n .description('Full-text search over wiki pages')\n .option('--limit <n>', 'Max results', '5')\n .option('--format <fmt>', 'Output format: text, json', 'text')\n .action(async (query: string, opts: { limit: string; format: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const results = w.search(query, parseInt(opts.limit));\n\n if (opts.format === 'json') {\n console.log(JSON.stringify(results.map(r => ({\n slug: r.page.slug,\n title: r.page.title,\n score: r.score,\n updatedAt: r.page.updatedAt,\n })), null, 2));\n return;\n }\n\n if (results.length === 0) {\n console.log(`\\n ${dim}No wiki pages found for \"${query}\"${reset}\\n`);\n return;\n }\n\n console.log(`\\n ${section('Wiki Search:')} ${violet}${bold}${query}${reset}\\n`);\n for (const { page, score } of results) {\n console.log(` ${violet}[${page.slug}]${reset} ${bold}${page.title}${reset} ${dim}score: ${score.toFixed(3)}${reset}`);\n const preview = page.content.split('\\n').find(l => l.trim() && !l.startsWith('#'));\n if (preview) console.log(` ${dim}${preview.trim().slice(0, 120)}${reset}`);\n console.log();\n }\n });\n\n // \u2500\u2500 page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('page <slug>')\n .description('Print the full content of a wiki page')\n .action(async (slug: string) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const page = w.getPage(slug);\n if (!page) {\n console.error(` \u2716 Wiki page \"${slug}\" not found. Run \\`kirograph wiki list\\` to see available pages.`);\n process.exit(1);\n }\n console.log();\n console.log(page.content);\n });\n\n // \u2500\u2500 list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('list')\n .description('List all wiki pages')\n .option('--format <fmt>', 'Output format: text, json', 'text')\n .action(async (opts: { format: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const pages = w.listPages();\n\n if (opts.format === 'json') {\n console.log(JSON.stringify(pages.map(p => ({\n slug: p.slug,\n title: p.title,\n sourceCount: p.sourceCount,\n updatedAt: p.updatedAt,\n })), null, 2));\n return;\n }\n\n const stats = w.getStats();\n console.log(`\\n ${section('Wiki')} ${dim}${stats.pageCount} page(s)${reset}\\n`);\n if (pages.length === 0) {\n console.log(` ${dim}No pages yet. Run \\`kirograph wiki ingest\\` to add pages.${reset}\\n`);\n return;\n }\n for (const p of pages) {\n const date = new Date(p.updatedAt).toISOString().slice(0, 10);\n console.log(` ${violet}${p.slug.padEnd(32)}${reset} ${p.title} ${dim}(${p.sourceCount} src, ${date})${reset}`);\n }\n console.log();\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 wiki\n .command('lint')\n .description('Health check the wiki for issues')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const issues = w.lint();\n\n if (issues.length === 0) {\n console.log(`\\n ${green}\u2713${reset} Wiki lint passed \u2014 no issues found.\\n`);\n return;\n }\n\n console.log(`\\n ${section('Wiki Lint')} ${yellow}${issues.length} issue(s)${reset}\\n`);\n for (const issue of issues) {\n const icon = issue.kind === 'contradiction' ? '\u26A1' : issue.kind === 'orphan' ? '\u25CB' : issue.kind === 'broken_link' ? '\uD83D\uDD17' : '\u26A0';\n console.log(` ${icon} ${dim}[${issue.kind}]${reset} ${violet}${issue.slug}${reset}`);\n console.log(` ${issue.detail}`);\n console.log();\n }\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 wiki\n .command('reindex')\n .description('Rebuild SQLite index from .kirograph/wiki/*.md files')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const count = w.reindex();\n console.log(`\\n ${green}\u2713${reset} Reindexed ${bold}${count}${reset} wiki page(s)\\n`);\n });\n\n // \u2500\u2500 status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('status')\n .description('Wiki subsystem stats')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const stats = w.getStats();\n const oldest = stats.oldestPage ? new Date(stats.oldestPage).toISOString().slice(0, 10) : 'n/a';\n const newest = stats.newestPage ? new Date(stats.newestPage).toISOString().slice(0, 10) : 'n/a';\n console.log(`\\n ${section('Wiki Status')}\\n`);\n console.log(` Pages: ${bold}${stats.pageCount}${reset}`);\n console.log(` Total sources: ${bold}${stats.totalSources}${reset}`);\n console.log(` Oldest page: ${dim}${oldest}${reset}`);\n console.log(` Newest page: ${dim}${newest}${reset}`);\n console.log(` Wiki dir: ${dim}.kirograph/wiki/${reset}\\n`);\n });\n\n // \u2500\u2500 synthesize (local model) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('synthesize')\n .description('Run local-model wiki synthesis: process the pending source queue (wikiSynthesisMode: local)')\n .option('--quiet', 'suppress progress output')\n .action(async (opts) => {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n const cwd = process.cwd();\n\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const config = await loadConfig(cwd);\n if (!config.enableWiki) {\n console.error(' \u2716 Wiki is not enabled.');\n process.exit(1);\n }\n if (config.wikiSynthesisMode !== 'local') {\n console.error(' \u2716 wikiSynthesisMode is not \"local\". This command is for local-model synthesis only.');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n const w = new KiroGraphWiki(db.getRawDb(), `${cwd}/.kirograph`, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n w.initialize();\n\n const queueCount = w.getQueueCount();\n if (queueCount === 0) {\n if (!opts.quiet) console.log(`\\n ${dim}Wiki queue is empty \u2014 nothing to synthesize.${reset}\\n`);\n process.exit(0);\n }\n\n if (!opts.quiet) console.log(`\\n ${yellow}\u27F3${reset} Synthesizing ${bold}${queueCount}${reset} queued source(s) with local model...\\n`);\n\n const result = await w.synthesize(config.wikiLocalModel, !!opts.quiet);\n\n if (!opts.quiet) {\n if (result.processed > 0) {\n console.log(` ${green}\u2713${reset} Processed: ${bold}${result.processed}${reset} source(s)`);\n if (result.created.length) console.log(` ${green}\u2713${reset} Created: ${result.created.join(', ')}`);\n if (result.updated.length) console.log(` ${green}\u2713${reset} Updated: ${result.updated.join(', ')}`);\n }\n if (result.errors.length) {\n for (const e of result.errors) console.error(` ${yellow}\u26A0${reset} ${e}`);\n }\n console.log('');\n }\n });\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * KiroGraph Wiki CLI\n *\n * kirograph wiki init\n * kirograph wiki ingest [source-file]\n * kirograph wiki apply-diff [diff-file]\n * kirograph wiki search <query>\n * kirograph wiki page <slug>\n * kirograph wiki list\n * kirograph wiki lint\n * kirograph wiki links <slug>\n * kirograph wiki rename <from> <to>\n * kirograph wiki reindex\n * kirograph wiki status\n */\n\nimport { Command } from 'commander';\nimport * as fs from 'fs';\nimport { dim, reset, violet, bold, section, green } from '../ui';\n\nconst yellow = '\\x1b[33m';\n\nasync function getWiki(cwd: string) {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const config = await loadConfig(cwd);\n if (!config.enableWiki) {\n console.error(' \u2716 Wiki is not enabled. Set enableWiki: true in .kirograph/config.json');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n\n const kirographDir = `${cwd}/.kirograph`;\n const wiki = new KiroGraphWiki(db.getRawDb(), kirographDir, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n wiki.initialize();\n return wiki;\n}\n\nfunction readStdinSync(): string {\n return fs.readFileSync('/dev/stdin', 'utf8');\n}\n\nexport function register(program: Command): void {\n const wiki = program\n .command('wiki')\n .description('LLM-maintained structured wiki (requires enableWiki: true)');\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 wiki\n .command('init')\n .description('Initialize wiki: create SCHEMA.md and MANIFEST.md in .kirograph/wiki/')\n .action(async () => {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n const cwd = process.cwd();\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const config = await loadConfig(cwd);\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n const w = new KiroGraphWiki(db.getRawDb(), `${cwd}/.kirograph`, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n w.initWiki();\n console.log(`\\n ${green}\u2713${reset} Wiki initialized in ${dim}.kirograph/wiki/${reset}`);\n console.log(` ${dim}Edit .kirograph/wiki/SCHEMA.md to customize naming and page structure.${reset}\\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 wiki\n .command('ingest [source]')\n .description('Print the ingest prompt for the LLM (reads file or stdin)')\n .option('--name <name>', 'Source name to include in the prompt')\n .action(async (source: string | undefined, opts: { name?: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n\n let content: string;\n let sourceName = opts.name ?? source ?? 'source';\n\n if (source && fs.existsSync(source)) {\n content = fs.readFileSync(source, 'utf8');\n sourceName = opts.name ?? source;\n } else if (source) {\n content = source;\n } else {\n content = readStdinSync();\n }\n\n const prompt = w.getIngestPrompt(content, sourceName);\n console.log(`\\n ${section('Wiki Ingest Prompt')} ${dim}(pass to LLM, then run wiki apply-diff)${reset}\\n`);\n console.log(prompt);\n console.log();\n });\n\n // \u2500\u2500 apply-diff \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('apply-diff [diff]')\n .description('Apply a WIKI_DIFF string to the wiki (reads file or stdin)')\n .action(async (diff: string | undefined) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n\n let rawDiff: string;\n if (diff && fs.existsSync(diff)) {\n rawDiff = fs.readFileSync(diff, 'utf8');\n } else if (diff) {\n rawDiff = diff;\n } else {\n rawDiff = readStdinSync();\n }\n\n const result = w.applyDiff(rawDiff);\n\n console.log(`\\n ${green}\u2713${reset} Wiki diff applied\\n`);\n if (result.created.length) {\n console.log(` ${violet}Created:${reset} ${result.created.join(', ')}`);\n }\n if (result.updated.length) {\n console.log(` ${violet}Updated:${reset} ${result.updated.join(', ')}`);\n }\n if (result.conflictsResolved.length) {\n console.log(` ${green}Conflicts resolved:${reset} ${result.conflictsResolved.join(', ')}`);\n }\n if (result.conflictsPending.length) {\n console.log(`\\n ${yellow}\u26A1 Conflicts pending (${result.conflictsPending.length}):${reset}`);\n for (const c of result.conflictsPending) {\n console.log(` ${dim} ${c.page} \u00A7${c.section}${reset}`);\n console.log(` existing: \"${c.existing}\"`);\n console.log(` incoming: \"${c.incoming}\" (source: ${c.source})`);\n }\n }\n console.log();\n });\n\n // \u2500\u2500 search \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('search <query>')\n .description('Full-text search over wiki pages')\n .option('--limit <n>', 'Max results', '5')\n .option('--format <fmt>', 'Output format: text, json', 'text')\n .action(async (query: string, opts: { limit: string; format: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const results = w.search(query, parseInt(opts.limit));\n\n if (opts.format === 'json') {\n console.log(JSON.stringify(results.map(r => ({\n slug: r.page.slug,\n title: r.page.title,\n score: r.score,\n updatedAt: r.page.updatedAt,\n })), null, 2));\n return;\n }\n\n if (results.length === 0) {\n console.log(`\\n ${dim}No wiki pages found for \"${query}\"${reset}\\n`);\n return;\n }\n\n console.log(`\\n ${section('Wiki Search:')} ${violet}${bold}${query}${reset}\\n`);\n for (const { page, score } of results) {\n console.log(` ${violet}[${page.slug}]${reset} ${bold}${page.title}${reset} ${dim}score: ${score.toFixed(3)}${reset}`);\n const preview = page.content.split('\\n').find(l => l.trim() && !l.startsWith('#'));\n if (preview) console.log(` ${dim}${preview.trim().slice(0, 120)}${reset}`);\n console.log();\n }\n });\n\n // \u2500\u2500 page \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('page <slug>')\n .description('Print the full content of a wiki page')\n .action(async (slug: string) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const page = w.getPage(slug);\n if (!page) {\n console.error(` \u2716 Wiki page \"${slug}\" not found. Run \\`kirograph wiki list\\` to see available pages.`);\n process.exit(1);\n }\n console.log();\n console.log(page.content);\n });\n\n // \u2500\u2500 list \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('list')\n .description('List all wiki pages')\n .option('--format <fmt>', 'Output format: text, json', 'text')\n .action(async (opts: { format: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const pages = w.listPages();\n\n if (opts.format === 'json') {\n console.log(JSON.stringify(pages.map(p => ({\n slug: p.slug,\n title: p.title,\n sourceCount: p.sourceCount,\n updatedAt: p.updatedAt,\n })), null, 2));\n return;\n }\n\n const stats = w.getStats();\n console.log(`\\n ${section('Wiki')} ${dim}${stats.pageCount} page(s)${reset}\\n`);\n if (pages.length === 0) {\n console.log(` ${dim}No pages yet. Run \\`kirograph wiki ingest\\` to add pages.${reset}\\n`);\n return;\n }\n for (const p of pages) {\n const date = new Date(p.updatedAt).toISOString().slice(0, 10);\n console.log(` ${violet}${p.slug.padEnd(32)}${reset} ${p.title} ${dim}(${p.sourceCount} src, ${date})${reset}`);\n }\n console.log();\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 wiki\n .command('lint')\n .description('Health check the wiki for issues')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const issues = w.lint();\n\n if (issues.length === 0) {\n console.log(`\\n ${green}\u2713${reset} Wiki lint passed \u2014 no issues found.\\n`);\n return;\n }\n\n console.log(`\\n ${section('Wiki Lint')} ${yellow}${issues.length} issue(s)${reset}\\n`);\n for (const issue of issues) {\n const icon = issue.kind === 'contradiction' ? '\u26A1' : issue.kind === 'orphan' ? '\u25CB' : issue.kind === 'broken_link' ? '\uD83D\uDD17' : '\u26A0';\n console.log(` ${icon} ${dim}[${issue.kind}]${reset} ${violet}${issue.slug}${reset}`);\n console.log(` ${issue.detail}`);\n console.log();\n }\n });\n\n // \u2500\u2500 links \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('links <slug>')\n .description('Show outgoing, broken, and incoming [[slug]] links for a page')\n .option('--format <fmt>', 'Output format: text, json', 'text')\n .action(async (slug: string, opts: { format: string }) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const links = w.getLinks(slug);\n\n if (!links) {\n console.error(` \u2716 Wiki page \"${slug}\" not found. Run \\`kirograph wiki list\\` to see available pages.`);\n process.exit(1);\n }\n\n if (opts.format === 'json') {\n console.log(JSON.stringify(links, null, 2));\n return;\n }\n\n console.log(`\\n ${section('Wiki Links:')} ${violet}${bold}${slug}${reset}\\n`);\n\n console.log(` ${bold}Outgoing${reset} ${dim}(${links.outgoing.length})${reset}`);\n if (links.outgoing.length === 0) {\n console.log(` ${dim}(none)${reset}`);\n } else {\n for (const s of links.outgoing) console.log(` ${violet}\u2192${reset} [[${s}]]`);\n }\n\n if (links.broken.length > 0) {\n console.log(`\\n ${yellow}Broken${reset} ${dim}(${links.broken.length})${reset}`);\n for (const s of links.broken) console.log(` ${yellow}\u26A0${reset} [[${s}]] ${dim}\u2014 page does not exist${reset}`);\n }\n\n console.log(`\\n ${bold}Incoming${reset} ${dim}(${links.incoming.length}) \u2014 pages that link here${reset}`);\n if (links.incoming.length === 0) {\n console.log(` ${dim}(none)${reset}`);\n } else {\n for (const s of links.incoming) console.log(` ${violet}\u2190${reset} [[${s}]]`);\n }\n console.log();\n });\n\n // \u2500\u2500 rename \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('rename <from> <to>')\n .description('Rename a page slug, moving its file and updating every [[slug]] reference to it')\n .action(async (from: string, to: string) => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n\n let result;\n try {\n result = w.rename(from, to);\n } catch (err) {\n console.error(` \u2716 ${err instanceof Error ? err.message : String(err)}`);\n process.exit(1);\n }\n\n console.log(`\\n ${green}\u2713${reset} Renamed ${violet}[[${result.from}]]${reset} \u2192 ${violet}[[${result.to}]]${reset}\\n`);\n if (result.linksUpdated.length > 0) {\n console.log(` ${bold}Links updated in ${result.linksUpdated.length} page(s):${reset}`);\n for (const s of result.linksUpdated) console.log(` ${dim}\u00B7${reset} ${s}`);\n } else {\n console.log(` ${dim}No other pages referenced [[${result.from}]].${reset}`);\n }\n console.log();\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 wiki\n .command('reindex')\n .description('Rebuild SQLite index from .kirograph/wiki/*.md files')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const count = w.reindex();\n console.log(`\\n ${green}\u2713${reset} Reindexed ${bold}${count}${reset} wiki page(s)\\n`);\n });\n\n // \u2500\u2500 status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('status')\n .description('Wiki subsystem stats')\n .action(async () => {\n const cwd = process.cwd();\n const w = await getWiki(cwd);\n const stats = w.getStats();\n const oldest = stats.oldestPage ? new Date(stats.oldestPage).toISOString().slice(0, 10) : 'n/a';\n const newest = stats.newestPage ? new Date(stats.newestPage).toISOString().slice(0, 10) : 'n/a';\n console.log(`\\n ${section('Wiki Status')}\\n`);\n console.log(` Pages: ${bold}${stats.pageCount}${reset}`);\n console.log(` Total sources: ${bold}${stats.totalSources}${reset}`);\n console.log(` Oldest page: ${dim}${oldest}${reset}`);\n console.log(` Newest page: ${dim}${newest}${reset}`);\n console.log(` Wiki dir: ${dim}.kirograph/wiki/${reset}\\n`);\n });\n\n // \u2500\u2500 synthesize (local model) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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 wiki\n .command('synthesize')\n .description('Run local-model wiki synthesis: process the pending source queue (wikiSynthesisMode: local)')\n .option('--quiet', 'suppress progress output')\n .action(async (opts) => {\n const { KiroGraphWiki } = await Promise.resolve().then(() => require('../../wiki/index.js'));\n const { loadConfig } = await Promise.resolve().then(() => require('../../config.js'));\n const KiroGraph = (await Promise.resolve().then(() => require('../../index.js'))).default;\n const cwd = process.cwd();\n\n if (!KiroGraph.isInitialized(cwd)) {\n console.error(' \u2716 KiroGraph is not initialized. Run `kirograph init` first.');\n process.exit(1);\n }\n const config = await loadConfig(cwd);\n if (!config.enableWiki) {\n console.error(' \u2716 Wiki is not enabled.');\n process.exit(1);\n }\n if (config.wikiSynthesisMode !== 'local') {\n console.error(' \u2716 wikiSynthesisMode is not \"local\". This command is for local-model synthesis only.');\n process.exit(1);\n }\n\n const cg = await KiroGraph.open(cwd);\n const db = cg.getDatabase();\n db.applyWikiSchema();\n const w = new KiroGraphWiki(db.getRawDb(), `${cwd}/.kirograph`, {\n autoResolveConflicts: config.wikiAutoResolveConflicts,\n });\n w.initialize();\n\n const queueCount = w.getQueueCount();\n if (queueCount === 0) {\n if (!opts.quiet) console.log(`\\n ${dim}Wiki queue is empty \u2014 nothing to synthesize.${reset}\\n`);\n process.exit(0);\n }\n\n if (!opts.quiet) console.log(`\\n ${yellow}\u27F3${reset} Synthesizing ${bold}${queueCount}${reset} queued source(s) with local model...\\n`);\n\n const result = await w.synthesize(config.wikiLocalModel, !!opts.quiet);\n\n if (!opts.quiet) {\n if (result.processed > 0) {\n console.log(` ${green}\u2713${reset} Processed: ${bold}${result.processed}${reset} source(s)`);\n if (result.created.length) console.log(` ${green}\u2713${reset} Created: ${result.created.join(', ')}`);\n if (result.updated.length) console.log(` ${green}\u2713${reset} Updated: ${result.updated.join(', ')}`);\n }\n if (result.errors.length) {\n for (const e of result.errors) console.error(` ${yellow}\u26A0${reset} ${e}`);\n }\n console.log('');\n }\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1471,9 +1471,14 @@ kirograph wiki search "<query>"
|
|
|
1471
1471
|
kirograph wiki page <slug>
|
|
1472
1472
|
kirograph wiki list
|
|
1473
1473
|
kirograph wiki lint
|
|
1474
|
+
kirograph wiki links <slug> # outgoing/broken/incoming [[slug]] links for a page
|
|
1475
|
+
kirograph wiki rename <from> <to> # move a page + rewrite every [[from]] reference to [[to]]
|
|
1474
1476
|
kirograph wiki status
|
|
1475
1477
|
kirograph wiki reindex
|
|
1476
1478
|
\`\`\`
|
|
1479
|
+
|
|
1480
|
+
Use \`wiki links\` before a \`rename\` to see what else references the page \u2014 \`rename\` rewrites
|
|
1481
|
+
those references automatically, but it's still a file move, not an MCP tool call.
|
|
1477
1482
|
`);
|
|
1478
1483
|
console.log(` \u2713 Wiki workflow steering file written`);
|
|
1479
1484
|
}
|
|
@@ -1513,6 +1518,10 @@ kirograph_mem_store(
|
|
|
1513
1518
|
|
|
1514
1519
|
**topicKey examples:** \`"architecture/auth-model"\`, \`"infra/db-choice"\`, \`"pattern/error-handling"\`
|
|
1515
1520
|
|
|
1521
|
+
Always use a \`kind\` from the list above. If \`memoryStrictWrites: true\` is set, an unrecognized
|
|
1522
|
+
\`kind\` or a blank tag is rejected with the violation named \u2014 fix the call and retry, it isn't
|
|
1523
|
+
silently dropped.
|
|
1524
|
+
|
|
1516
1525
|
## 3. Capture observations from structured text
|
|
1517
1526
|
|
|
1518
1527
|
If you have a markdown block with bullet points under headings like \`## Key Learnings\` or
|