* One explore call, reduced to what the allocation assertions need — plus the * CG-4 per-file diagnostic, which is where the SCORE and the RESERVATION live. * The instrument is observational (byte-identical output either way), so reading * it here measures the same response the agent would have r
(project: Project, query: string)
| 82 | * it here measures the same response the agent would have received. |
| 83 | */ |
| 84 | async function explore(project: Project, query: string) { |
| 85 | // Outside the project root on purpose: a sidecar written INTO the indexed tree |
| 86 | // is a new file the watcher can pick up mid-suite. |
| 87 | const sidecar = path.join(fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-alloc-diag-')), 'report.jsonl'); |
| 88 | const previous = process.env[DEBUG_ENV]; |
| 89 | process.env[DEBUG_ENV] = sidecar; |
| 90 | let result; |
| 91 | try { |
| 92 | result = await project.handler.execute('codegraph_explore', { query }); |
| 93 | } finally { |
| 94 | if (previous === undefined) delete process.env[DEBUG_ENV]; |
| 95 | else process.env[DEBUG_ENV] = previous; |
| 96 | } |
| 97 | const text = result.content?.[0]?.text ?? ''; |
| 98 | const bytes = attributeSourceBytes(text); |
| 99 | const lines = fs.existsSync(sidecar) |
| 100 | ? fs.readFileSync(sidecar, 'utf-8').trim().split('\n').filter(Boolean) |
| 101 | : []; |
| 102 | const report = JSON.parse(lines[lines.length - 1]!) as ExploreDiagnosticReport; |
| 103 | fs.rmSync(path.dirname(sidecar), { recursive: true, force: true }); |
| 104 | const fileOf = (file: string) => report.files.find((f) => f.path === file); |
| 105 | return { |
| 106 | text, |
| 107 | bytes, |
| 108 | report, |
| 109 | isError: result.isError === true, |
| 110 | /** Relevance score the ranking pass gave this file. */ |
| 111 | score: (file: string) => fileOf(file)?.score ?? 0, |
| 112 | /** Chars of source the allocator RESERVED for it, before anything rendered. */ |
| 113 | allowance: (file: string) => fileOf(file)?.allowance ?? 0, |
| 114 | /** Which render path the loop took: `whole`, `clusters`, `focused`, `skeleton`. */ |
| 115 | render: (file: string) => fileOf(file)?.render ?? null, |
| 116 | /** |
| 117 | * Rank the ranking pass gave it (1 = the file the response leads with, and |
| 118 | * the first the render loop reaches). Read off the record rather than from |
| 119 | * the position in `report.files`, which the report re-sorts by delivered |
| 120 | * bytes for legibility. |
| 121 | */ |
| 122 | rank: (file: string) => fileOf(file)?.rank ?? -1, |
| 123 | /** Total source bytes delivered across every rendered file. */ |
| 124 | sourceTotal: () => [...bytes.values()].reduce((sum, n) => sum + n, 0), |
| 125 | /** Fraction of the WHOLE response this file's source occupies. */ |
| 126 | share: (file: string) => (bytes.get(file) ?? 0) / (text.length || 1), |
| 127 | shareUnder: (prefix: string) => { |
| 128 | let total = 0; |
| 129 | for (const [file, n] of bytes) if (file.startsWith(prefix)) total += n; |
| 130 | return total / (text.length || 1); |
| 131 | }, |
| 132 | }; |
| 133 | } |
| 134 | |
| 135 | // ── 1. The self-query fixture's shape ─────────────────────────────────────── |
| 136 |
no test coverage detected