/**
* query.js — AtomSpace queries for code intelligence
*
* Three query functions that improve Claude's responses:
* blastRadius(filePath) — what's at risk if I edit this file?
* similarLoops(editedFiles) — what past loops match this situation?
* riskAssessment(editList) — aggregate risk across all edited files
*
* All functions return null if CogServer is not running (graceful fallback).
*/
const { evalScheme, isCogServerUp } = require('./cogserver')
const S = require('./schema')
/**
* Parse a MeetLink result string into an array of atom names.
* MeetLink returns: (SetLink (ConceptNode "x") (ConceptNode "y") ...)
* or just: (ConceptNode "x") for single results
*/
function parseAtomNames (resultStr) {
if (!resultStr) return []
const names = []
// CogServer prints either "ConceptNode" or abbreviated "Concept"
const re = /(?:ConceptNode|Concept) "([^"]+)"/g
let match
while ((match = re.exec(resultStr)) !== null) {
names.push(match[1])
}
return names
}
/**
* Parse a float value result.
*/
function parseFloat_ (resultStr) {
if (!resultStr) return 0
const match = resultStr.match(/[\d.]+/)
return match ? parseFloat(match[0]) : 0
}
/**
* blastRadius(filePath) — What's at risk if I edit this file?
*
* Returns: {
* consumers: string[], // files that import from this file
* dependencies: string[], // files this file imports from
* loops: string[], // loop fingerprints involving this file
* rules: string[], // rule IDs applying to this file
* dangerLevel: string, // "low"|"medium"|"high"
* module: string, // which module this file belongs to
* }
*/
async function blastRadius (filePath) {
if (!await isCogServerUp()) return null
// Normalize path — strip leading slashes, common prefixes
const normalPath = filePath
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
const [consumers, dependencies, loops, rules, danger] = await Promise.all([
evalScheme(S.queryImporters(normalPath)),
evalScheme(S.queryDependencies(normalPath)),
evalScheme(S.queryLoopsForFile(normalPath)),
evalScheme(S.queryRulesForFile(normalPath)),
evalScheme(S.getStringValue(S.fileNode(normalPath), 'danger-level'))
])
// Sort rules by wisdom score (high-wisdom first), filter out zero-wisdom
const ruleNames = parseAtomNames(rules)
const rulesWithWisdom = await Promise.all(ruleNames.map(async r => ({
name: r,
wisdom: await getWisdom(r)
})))
// Keep rules even if wisdom is 0 — still visible, just ranked lower
const rankedRules = rulesWithWisdom
.sort((a, b) => b.wisdom - a.wisdom)
.map(r => r.name)
return {
file: normalPath,
consumers: parseAtomNames(consumers),
dependencies: parseAtomNames(dependencies),
loops: parseAtomNames(loops),
rules: rankedRules, // sorted by wisdom
rulesHighWisdom: rulesWithWisdom.filter(r => r.wisdom >= 1.0).length,
rulesLowWisdom: rulesWithWisdom.filter(r => r.wisdom < 0.3).length,
dangerLevel: (danger && danger !== '""' && danger !== '') ? danger.replace(/"/g, '') : 'unknown'
}
}
/**
* Get the wisdom score for a rule or meta atom.
* Returns 0.5 if no wisdom value stored (neutral default).
*/
async function getWisdom (atomName) {
const result = await evalScheme(
`(let ((v (cog-value (ConceptNode "${atomName.replace(/"/g, '\\"')}") (Predicate "wisdom")))) (if v (cog-value-ref v 0) 0.5))`)
return parseFloat(result) || 0.5
}
/**
* similarLoops(editedFiles) — What past loops match this situation?
*
* Finds loops that share file overlap with the currently edited files.
* Scored by overlap count.
*
* Returns: {
* matches: [{ loopId, sharedFiles, score, type, project, resolved }]
* }
*/
async function similarLoops (editedFiles) {
if (!await isCogServerUp()) return null
if (!editedFiles || !editedFiles.length) return { matches: [] }
// For each edited file, find loops
const allLoops = new Map() // loopId → { sharedFiles, type, project, resolved }
for (const file of editedFiles) {
const normalPath = file
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
const result = await evalScheme(S.queryLoopsForFile(normalPath))
const loopNames = parseAtomNames(result)
for (const loopName of loopNames) {
const id = loopName.replace('loop:', '')
if (!allLoops.has(id)) {
// Get loop metadata
const node = S.loopNode(id)
const [type, project, resolved] = await Promise.all([
evalScheme(S.getStringValue(node, 'type')),
evalScheme(S.getStringValue(node, 'project')),
evalScheme(S.getFloatValue(node, 'resolved'))
])
allLoops.set(id, {
loopId: id,
sharedFiles: [normalPath],
type: (type || '').replace(/"/g, ''),
project: (project || '').replace(/"/g, ''),
resolved: parseFloat_(resolved) > 0.5
})
} else {
allLoops.get(id).sharedFiles.push(normalPath)
}
}
}
// Score by shared file count and sort
const matches = [...allLoops.values()]
.map(m => ({ ...m, score: m.sharedFiles.length }))
.sort((a, b) => b.score - a.score)
.slice(0, 10)
return { matches }
}
/**
* riskAssessment(editList) — Aggregate risk across all edited files
*
* Returns: {
* risk: "low"|"medium"|"high",
* totalDownstream: number,
* totalLoops: number,
* totalRules: number,
* crossModuleEdits: string[],
* hotspots: [{ file, consumers, loops, danger }]
* }
*/
async function riskAssessment (editList) {
if (!await isCogServerUp()) return null
if (!editList || !editList.length) return { risk: 'low', totalDownstream: 0, totalLoops: 0, totalRules: 0, crossModuleEdits: [], hotspots: [] }
const hotspots = []
let totalDownstream = 0
let totalLoops = 0
let totalRules = 0
const modules = new Set()
const crossModuleEdits = []
for (const file of editList) {
const br = await blastRadius(file)
if (!br) continue
// Track module boundaries
const parts = br.file.split('/')
if (parts.length > 0) {
const mod = parts[0]
if (modules.size > 0 && !modules.has(mod)) {
crossModuleEdits.push(br.file)
}
modules.add(mod)
}
totalDownstream += br.consumers.length
totalLoops += br.loops.length
totalRules += br.rules.length
if (br.consumers.length > 0 || br.loops.length > 0 || br.dangerLevel !== 'unknown') {
hotspots.push({
file: br.file,
consumers: br.consumers.length,
loops: br.loops.length,
danger: br.dangerLevel
})
}
}
// Determine overall risk
let risk = 'low'
if (totalLoops > 3 || crossModuleEdits.length > 0 || hotspots.some(h => h.danger === 'high')) {
risk = 'high'
} else if (totalLoops > 0 || totalDownstream > 5 || hotspots.some(h => h.danger === 'medium')) {
risk = 'medium'
}
return {
risk,
totalDownstream,
totalLoops,
totalRules,
crossModuleEdits,
hotspots: hotspots.sort((a, b) => (b.loops + b.consumers) - (a.loops + a.consumers)).slice(0, 5)
}
}
/**
* Format a blast radius result as a human-readable briefing string.
*/
function formatBlastRadius (br) {
if (!br) return ''
const lines = []
if (br.consumers.length) lines.push(`Downstream consumers (${br.consumers.length}): ${br.consumers.slice(0, 5).map(c => c.replace('file:', '')).join(', ')}`)
if (br.loops.length) lines.push(`Past correction loops (${br.loops.length}): ${br.loops.slice(0, 3).join(', ')}`)
if (br.rules.length) lines.push(`Applicable rules: ${br.rules.length}`)
if (br.dangerLevel !== 'unknown') lines.push(`Danger level: ${br.dangerLevel}`)
return lines.join('\n')
}
/**
* fileContext(filePath) — Language/domain/role-aware context for a file
*
* Returns: {
* file, language, domain, role,
* exports: number, // count of things this file exports
* isExportedAPI: bool, // true if file has exports
* avgLoopsForLanguage: number, // correction density for this language
* dominantLoopType: string, // most common failure mode
* }
*/
async function fileContext (filePath) {
if (!await isCogServerUp()) return null
const normalPath = filePath
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
const [language, domain, role, exportStr] = await Promise.all([
evalScheme(S.getStringValue(S.fileNode(normalPath), 'language')),
evalScheme(S.getStringValue(S.fileNode(normalPath), 'domain')),
evalScheme(S.getStringValue(S.fileNode(normalPath), 'role')),
evalScheme(`(length (cog-execute! (Meet (TypedVariable (Variable "$e") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "exports") (ListLink (ConceptNode "file:${normalPath}") (Variable "$e")))))))`)
])
const cleanStr = (s) => (s || '').replace(/"/g, '').trim()
const lang = cleanStr(language) || 'unknown'
const dom = cleanStr(domain) || 'unknown'
const rl = cleanStr(role) || 'unknown'
const exports = parseInt(exportStr) || 0
return {
file: normalPath,
language: lang,
domain: dom,
role: rl,
exports,
isExportedAPI: exports > 0
}
}
/**
* findResolution(filePath, loopType) — What fixed similar past loops?
*
* Queries loops matching this file's language+domain+type. Returns
* the resolution files from those loops — "last time, the fix was in X."
*
* Returns: {
* matches: [{ loopId, project, resolutionFiles, corrections }]
* }
*/
async function findResolution (filePath, loopType) {
if (!await isCogServerUp()) return null
const ctx = await fileContext(filePath)
if (!ctx) return null
// Find loops in the same domain with similar type
// (We can't query by language/domain on loops directly — they're on files)
// So: find loops in files that share language+domain with this one
await evalScheme('(use-modules (srfi srfi-1))')
// Get all loops that touch files in the same domain
const allLoopsStr = await evalScheme(
'(string-join (map cog-name (cog-get-atoms (quote ConceptNode))) "|")')
const allAtoms = (allLoopsStr || '').replace(/^"|"$/g, '').split('|').filter(s => s.startsWith('loop:'))
const matches = []
for (const loopName of allAtoms.slice(0, 100)) { // limit for performance
// Get loop's type and project
const [type, project, resolved] = await Promise.all([
evalScheme(`(let ((v (cog-value (ConceptNode "${loopName}") (Predicate "type")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value (ConceptNode "${loopName}") (Predicate "project")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value (ConceptNode "${loopName}") (Predicate "resolved")))) (if v (cog-value-ref v 0) 0))`)
])
const cleanType = (type || '').replace(/"/g, '')
const cleanProject = (project || '').replace(/"/g, '')
const isResolved = parseFloat(resolved) > 0.5
// Match if type matches or project matches
if (!isResolved) continue
if (loopType && cleanType !== loopType) continue
// Get resolution files
const resolutionStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "resolved-by") (ListLink (ConceptNode "${loopName}") (Variable "$f"))))))`)
const resolutionFiles = parseAtomNames(resolutionStr)
if (resolutionFiles.length > 0) {
matches.push({
loopId: loopName.replace('loop:', ''),
type: cleanType,
project: cleanProject,
resolutionFiles: resolutionFiles.map(f => f.replace('file:', ''))
})
}
}
return {
context: ctx,
matches: matches.slice(0, 5)
}
}
/**
* unfamiliarityScore(filePath) — How much experience do I have with this module?
*
* Queries session-count on the parent module. Low session count + high
* correction density = unfamiliarity risk.
*/
async function unfamiliarityScore (filePath) {
if (!await isCogServerUp()) return null
const ctx = await fileContext(filePath)
if (!ctx) return null
// Extract module from path (first segment)
const modName = ctx.file.split('/')[0]
if (!modName) return null
const sessionStr = await evalScheme(
`(let ((v (cog-value (ConceptNode "mod:${modName}") (Predicate "session-count")))) (if v (cog-value-ref v 0) 0))`)
const sessions = parseFloat(sessionStr) || 0
let level = 'unknown'
if (sessions === 0) level = 'never-visited'
else if (sessions < 3) level = 'unfamiliar'
else if (sessions < 10) level = 'familiar'
else level = 'well-known'
return { module: modName, sessions, familiarity: level }
}
/**
* Enhanced blastRadius — adds export weighting
*/
async function blastRadiusEnhanced (filePath) {
const br = await blastRadius(filePath)
if (!br) return null
const ctx = await fileContext(filePath)
const unfam = await unfamiliarityScore(filePath)
// Compute weighted risk score
let riskScore = br.loops.length * 3 + br.rules.length + br.consumers.length * 2
if (ctx && ctx.isExportedAPI) riskScore += 5 // exports amplify blast radius
if (unfam && (unfam.familiarity === 'unfamiliar' || unfam.familiarity === 'never-visited')) riskScore += 3
return {
...br,
...ctx,
...unfam,
riskScore
}
}
/**
* contrastGuidance(filePath) — Contrast-derived meta-cognition for a file
*
* Finds meta-cognition atoms where this file is either in the approach-works
* or approach-fails position. Also finds cross-loop patterns for the file's
* project+language context.
*
* Returns: {
* worksFor: [{ loopId, context, correction }], // past cases where this file fixed things
* failedFor: [{ loopId, context, correction }], // past cases where editing this file was wasted
* patterns: [{ context, tryFirst: [files], avoidFirst: [files], loopCount }]
* }
*/
async function contrastGuidance (filePath) {
if (!await isCogServerUp()) return null
const normalPath = filePath
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
.replace(/^\/storage\/projects\/code\//, '')
const fileAtom = `(ConceptNode "file:${normalPath.replace(/"/g, '\\"')}")`
// Find meta-atoms where this file is a successful approach
const worksForStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$m") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "approach-works") (ListLink (Variable "$m") ${fileAtom})))))`)
// Find meta-atoms where this file was wasted effort
const failedForStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$m") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "approach-fails") (ListLink (Variable "$m") ${fileAtom})))))`)
const worksMetaIds = parseAtomNames(worksForStr).filter(n => n.startsWith('meta:loop:'))
const failedMetaIds = parseAtomNames(failedForStr).filter(n => n.startsWith('meta:loop:'))
// Get context info for each meta-atom
async function getMetaContext (metaId) {
const [project, loopType, correction] = await Promise.all([
evalScheme(`(let ((v (cog-value (ConceptNode "${metaId}") (Predicate "project")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value (ConceptNode "${metaId}") (Predicate "loop-type")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value (ConceptNode "${metaId}") (Predicate "correction-snippet")))) (if v (cog-value-ref v 0) ""))`)
])
return {
loopId: metaId.replace('meta:loop:', ''),
project: (project || '').replace(/"/g, ''),
loopType: (loopType || '').replace(/"/g, ''),
correction: (correction || '').replace(/"/g, '')
}
}
const worksFor = await Promise.all(worksMetaIds.slice(0, 5).map(getMetaContext))
const failedFor = await Promise.all(failedMetaIds.slice(0, 5).map(getMetaContext))
// Find cross-loop patterns whose context applies to this file
// Need the file's language + the project it's in
const fileCtx = await fileContext(filePath)
const patterns = []
if (fileCtx && fileCtx.language && fileCtx.language !== 'unknown') {
// Extract project from path
const parts = normalPath.split('/')
const project = parts[0]
// Query patterns matching this context
const patternKeys = [
`meta:pattern:${project}:${fileCtx.language}:*`, // broad
]
for (const key of patternKeys) {
const patternNode = `(ConceptNode "${key}")`
const existsStr = await evalScheme(`(cog-node (quote ConceptNode) "${key}")`)
if (!existsStr || existsStr === 'false' || existsStr === '#f') continue
const tryFirstStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "try-first") (ListLink ${patternNode} (Variable "$f"))))))`)
const avoidStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "avoid-first") (ListLink ${patternNode} (Variable "$f"))))))`)
const loopCountStr = await evalScheme(
`(let ((v (cog-value ${patternNode} (Predicate "loop-count")))) (if v (cog-value-ref v 0) 0))`)
const tryFirst = parseAtomNames(tryFirstStr).map(n => n.replace('file:', ''))
const avoidFirst = parseAtomNames(avoidStr).map(n => n.replace('file:', ''))
if (tryFirst.length > 0 || avoidFirst.length > 0) {
patterns.push({
context: key.replace('meta:pattern:', ''),
tryFirst,
avoidFirst,
loopCount: parseFloat(loopCountStr) || 0
})
}
}
}
return {
file: normalPath,
worksFor: worksFor.filter(Boolean),
failedFor: failedFor.filter(Boolean),
patterns
}
}
/**
* liveSessionContext(filePath) — Live events in the current session for a file
*
* Returns: {
* sessionId,
* sessionEditedFiles: number, // how many files edited this session
* editsForThisFile: number, // times this file edited this session
* correctionsNearThisFile: number, // corrections that happened near edits to this file
* recentCorrections: [{ text, turn }] // sample corrections
* }
*
* If no active session, returns null.
*/
async function liveSessionContext (filePath) {
if (!await isCogServerUp()) return null
const fs = require('fs')
let sessionId = null
try { sessionId = fs.readFileSync('/tmp/claude-atomspace-session', 'utf8').trim() } catch {}
if (!sessionId) return null
const normalPath = filePath
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
.replace(/^\/storage\/projects\/code\//, '')
const sessionNode = `(ConceptNode "session:${sessionId}")`
const fileAtom = `(ConceptNode "file:${normalPath.replace(/"/g, '\\"')}")`
// Files edited this session
const editedStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "session-edited") (ListLink ${sessionNode} (Variable "$f"))))))`)
const editedFiles = parseAtomNames(editedStr)
// Is THIS file in the session-edited set?
const isThisEdited = editedFiles.includes(`file:${normalPath}`)
const fileEdits = isThisEdited ? [fileAtom] : []
// All corrections in the session
const allCorrectionsStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$c") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "correction-in-session") (ListLink (Variable "$c") ${sessionNode})))))`)
const allCorrectionIds = parseAtomNames(allCorrectionsStr)
// Filter to corrections near edit of this specific file
const correctionIds = []
for (const cid of allCorrectionIds) {
const nearEdit = await evalScheme(
`(cog-link (quote EdgeLink) (BondNode "correction-near-edit") (ListLink (ConceptNode "${cid}") ${fileAtom}))`)
if (nearEdit && nearEdit !== 'false' && !nearEdit.includes('#f')) {
correctionIds.push(cid)
}
}
// Get text for each correction
const recentCorrections = []
for (const cid of correctionIds.slice(0, 3)) {
const [text, turn] = await Promise.all([
evalScheme(`(let ((v (cog-value (ConceptNode "${cid}") (Predicate "text")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value (ConceptNode "${cid}") (Predicate "turn")))) (if v (cog-value-ref v 0) 0))`)
])
recentCorrections.push({
text: (text || '').replace(/"/g, '').slice(0, 150),
turn: parseFloat(turn) || 0
})
}
return {
sessionId,
sessionEditedFiles: editedFiles.length,
editsForThisFile: fileEdits.length,
correctionsNearThisFile: correctionIds.length,
totalSessionCorrections: allCorrectionIds.length,
recentCorrections
}
}
/**
* relevantAtoms(context) — Top-k wisdom-ranked meta-cognition for current context
*
* context: {
* cwd?: string, // current working directory
* files?: string[], // files mentioned in prompt or recently edited
* module?: string, // module name from cwd
* language?: string, // inferred language of work area
* }
*
* Returns: {
* tier1: [{ atom, wisdom, summary }], // top 3, shown prominently
* tier2: [{ atom, wisdom, summary }], // next 2, abbreviated
* totalMatched: number, // how many matched total
* totalTokens: number // estimated tokens in all briefing
* }
*/
async function relevantAtoms (context) {
if (!await isCogServerUp()) return null
const files = context.files || []
const module = context.module
const language = context.language
const candidates = new Map() // atomName → { atom, wisdom, matchReason }
// 1. Rules and meta atoms directly for the listed files
for (const file of files) {
const normalPath = file
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
.replace(/^\/storage\/projects\/code\//, '')
if (!normalPath) continue
const fileAtom = `(ConceptNode "file:${normalPath.replace(/"/g, '\\"')}")`
// Rules for this file
const ruleResult = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$r") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "rule-for-file") (ListLink (Variable "$r") ${fileAtom})))))`)
for (const name of parseAtomNames(ruleResult)) {
if (!name.startsWith('rule:')) continue
if (!candidates.has(name)) candidates.set(name, { atom: name, matchReason: `file: ${normalPath}` })
}
// Per-loop meta atoms linked via approach-works or approach-fails
const metaResult = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$m") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "approach-works") (ListLink (Variable "$m") ${fileAtom})))))`)
for (const name of parseAtomNames(metaResult)) {
if (!name.startsWith('meta:')) continue
if (!candidates.has(name)) candidates.set(name, { atom: name, matchReason: `approach-works for ${normalPath}` })
}
}
// 2. Cross-loop patterns for the module + language
if (module && language && language !== 'unknown') {
const patternKeys = [
`meta:pattern:${module}:${language}:*`, // broad
]
for (const key of patternKeys) {
const existsStr = await evalScheme(`(cog-node (quote ConceptNode) "${key}")`)
if (!existsStr || existsStr === 'false' || existsStr === '#f' || !existsStr.includes('Concept')) continue
if (!candidates.has(key)) candidates.set(key, { atom: key, matchReason: `pattern for ${module}:${language}` })
}
}
// 3. Fetch wisdom for all candidates, sort
const scored = []
for (const [name, info] of candidates) {
const wisdom = await getWisdom(name)
scored.push({ ...info, wisdom })
}
scored.sort((a, b) => b.wisdom - a.wisdom)
// 4. Fetch human-readable summaries for top candidates
async function getSummary (atomName) {
const node = `(ConceptNode "${atomName.replace(/"/g, '\\"')}")`
if (atomName.startsWith('rule:')) {
const [symptom, fix] = await Promise.all([
evalScheme(`(let ((v (cog-value ${node} (Predicate "symptom")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value ${node} (Predicate "fix")))) (if v (cog-value-ref v 0) ""))`)
])
const s = (symptom || '').replace(/"/g, '').trim()
const f = (fix || '').replace(/"/g, '').trim()
if (f && s) return `When: ${s.slice(0, 100)} → fix: ${f.slice(0, 100)}`
if (f) return `Fix pattern: ${f.slice(0, 150)}`
return 'Rule (no description)'
}
if (atomName.startsWith('meta:loop:')) {
const correction = await evalScheme(`(let ((v (cog-value ${node} (Predicate "correction-snippet")))) (if v (cog-value-ref v 0) ""))`)
return `Past correction: "${(correction || '').replace(/"/g, '').slice(0, 100)}..."`
}
if (atomName.startsWith('meta:pattern:')) {
// Get try-first and avoid-first files
const tryStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "try-first") (ListLink ${node} (Variable "$f"))))))`)
const tryFiles = parseAtomNames(tryStr).map(n => n.replace('file:', '').split('/').pop()).slice(0, 2)
const avoidStr = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$f") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "avoid-first") (ListLink ${node} (Variable "$f"))))))`)
const avoidFiles = parseAtomNames(avoidStr).map(n => n.replace('file:', '').split('/').pop()).slice(0, 2)
const ctx = atomName.replace('meta:pattern:', '')
let parts = []
if (tryFiles.length) parts.push(`try ${tryFiles.join(', ')}`)
if (avoidFiles.length) parts.push(`avoid ${avoidFiles.join(', ')}`)
return `[${ctx}] ${parts.join('; ')}`
}
return atomName
}
const totalMatched = scored.length
// Tier 1: top 3 by wisdom
const tier1 = []
for (const c of scored.slice(0, 3)) {
tier1.push({ ...c, summary: await getSummary(c.atom) })
}
// Tier 2: next 2
const tier2 = []
for (const c of scored.slice(3, 5)) {
tier2.push({ ...c, summary: await getSummary(c.atom) })
}
// Estimate tokens (rough: 1 token ≈ 4 chars)
const totalChars = [...tier1, ...tier2].reduce((acc, c) => acc + (c.summary || '').length, 0)
const totalTokens = Math.ceil(totalChars / 4)
return { tier1, tier2, totalMatched, totalTokens }
}
/**
* preferredApproachFor(filePath) — Find preferred approach rules for editing this file
*
* Returns: [{ id, shape, successCount, sessionCount, avgScore, secondaryFiles, sampleApproval }]
* Sorted by successCount desc.
*/
async function preferredApproachFor (filePath) {
if (!await isCogServerUp()) return null
const normalPath = filePath
.replace(/^\/storage\/projects\/code\/hypercore-kb\/hyper-fleeky\//, '')
.replace(/^\/storage\/projects\/code\/hypercore-kb\//, '')
.replace(/^\/storage\/projects\/code\//, '')
const fileAtom = `(ConceptNode "file:${normalPath.replace(/"/g, '\\"')}")`
const result = await evalScheme(
`(cog-execute! (Meet (TypedVariable (Variable "$p") (Type (quote ConceptNode))) (Present (EdgeLink (BondNode "preferred-for-file") (ListLink (Variable "$p") ${fileAtom})))))`)
const approachIds = parseAtomNames(result).filter(n => n.startsWith('preferred:'))
const approaches = []
for (const pid of approachIds.slice(0, 5)) {
const node = `(ConceptNode "${pid.replace(/"/g, '\\"')}")`
const [shape, count, avgScore, sample] = await Promise.all([
evalScheme(`(let ((v (cog-value ${node} (Predicate "shape")))) (if v (cog-value-ref v 0) ""))`),
evalScheme(`(let ((v (cog-value ${node} (Predicate "success-count")))) (if v (cog-value-ref v 0) 0))`),
evalScheme(`(let ((v (cog-value ${node} (Predicate "avg-score")))) (if v (cog-value-ref v 0) 0))`),
evalScheme(`(let ((v (cog-value ${node} (Predicate "sample-approval")))) (if v (cog-value-ref v 0) ""))`)
])
approaches.push({
id: pid,
shape: (shape || '').replace(/"/g, ''),
successCount: parseFloat(count) || 0,
avgScore: parseFloat(avgScore) || 0,
sampleApproval: (sample || '').replace(/"/g, '').slice(0, 100)
})
}
approaches.sort((a, b) => b.successCount - a.successCount)
return approaches
}
module.exports = {
blastRadius,
blastRadiusEnhanced,
similarLoops,
riskAssessment,
formatBlastRadius,
fileContext,
findResolution,
unfamiliarityScore,
contrastGuidance,
liveSessionContext,
relevantAtoms,
getWisdom,
preferredApproachFor
}