@colbymchenry/codegraph 1.0.1 → 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/dist/index.d.ts CHANGED
@@ -66,6 +66,28 @@ export declare class CodeGraph {
66
66
  private fileLock;
67
67
  private watcher;
68
68
  private constructor();
69
+ /**
70
+ * (Re)build the query/extraction/graph layers over the current `this.queries`
71
+ * (which wraps `this.db`). Factored out of the constructor so `reopenIfReplaced`
72
+ * can rebuild them against a fresh connection without duplicating the wiring.
73
+ * The path-based `fileLock` is independent of the DB handle, so it stays put.
74
+ */
75
+ private wireLayers;
76
+ /**
77
+ * Heal a stale database handle in place. If `.codegraph/` was removed and
78
+ * recreated at the SAME path while this instance held the DB open — a git
79
+ * worktree removed and re-added, or `rm -rf .codegraph` + `codegraph init` —
80
+ * our open fd points at the now-unlinked inode and can never see the new
81
+ * index, so every query returns the pre-removal snapshot until the process
82
+ * restarts (#925). When that's detected, open the live file at the same path,
83
+ * rebuild the query layers, and swap them IN PLACE, so every holder of this
84
+ * instance (the MCP daemon's default project, cached projectPath connections)
85
+ * heals without a restart. Returns true iff it reopened.
86
+ *
87
+ * POSIX-only in practice: `isReplacedOnDisk` never fires on Windows (an open
88
+ * file can't be unlinked there, and st_ino is unreliable).
89
+ */
90
+ reopenIfReplaced(): boolean;
69
91
  /**
70
92
  * Initialize a new CodeGraph project
71
93
  *
@@ -144,6 +166,17 @@ export declare class CodeGraph {
144
166
  * Check if the file watcher is active.
145
167
  */
146
168
  isWatching(): boolean;
169
+ /**
170
+ * True once live watching has permanently degraded (OS watch-resource
171
+ * exhaustion, or a write lock held past the retry budget) and auto-sync is
172
+ * disabled until the next {@link watch} call. Distinct from `!isWatching()`:
173
+ * a stopped/never-started watcher is inactive but NOT degraded. MCP tools use
174
+ * this to surface a whole-index "results may be stale" notice, since
175
+ * `getPendingFiles()` goes empty once watching stops (#876).
176
+ */
177
+ isWatcherDegraded(): boolean;
178
+ /** The reason live watching degraded, or null if it is healthy (#876). */
179
+ getWatcherDegradedReason(): string | null;
147
180
  /**
148
181
  * Files seen by the file watcher since the last successful sync —
149
182
  * the per-file "stale" signal MCP tools attach to responses so an agent
@@ -17,8 +17,8 @@
17
17
  * runs without this block, and consistently with it — including runs
18
18
  * with zero Read/grep fallback.
19
19
  * - **Non-MCP harnesses** — agents with no MCP client at all can still
20
- * run the `codegraph explore` / `codegraph node` CLI, which prints the
21
- * same output as the MCP tools.
20
+ * run the `codegraph explore` CLI, which prints the same output as the
21
+ * MCP tool.
22
22
  *
23
23
  * Keep this block SHORT. The main agent reads it every turn on top of the
24
24
  * server instructions — the #529 duplication-cost argument still bounds
@@ -37,5 +37,5 @@ export declare const CODEGRAPH_SECTION_END = "<!-- CODEGRAPH_END -->";
37
37
  * indexed" claim would send subagents into failing codegraph calls (the
38
38
  * noise the unindexed-session policy exists to prevent).
39
39
  */
40
- export declare const CODEGRAPH_INSTRUCTIONS_BLOCK = "<!-- CODEGRAPH_START -->\n## CodeGraph\n\nIn repositories indexed by CodeGraph (a `.codegraph/` directory exists at the repo root), reach for it BEFORE grep/find or reading files when you need to understand or locate code:\n\n- **MCP tools** (when available): `codegraph_explore` answers most code questions in one call \u2014 the relevant symbols' verbatim source plus the call paths between them. `codegraph_node` returns one symbol's source + callers, or reads a whole file with line numbers. If the tools are listed but deferred, load them by name via tool search.\n- **Shell** (always works): `codegraph explore \"<symbol names or question>\"` and `codegraph node <symbol-or-file>` print the same output.\n\nIf there is no `.codegraph/` directory, skip CodeGraph entirely \u2014 indexing is the user's decision.\n<!-- CODEGRAPH_END -->";
40
+ export declare const CODEGRAPH_INSTRUCTIONS_BLOCK = "<!-- CODEGRAPH_START -->\n## CodeGraph\n\nIn repositories indexed by CodeGraph (a `.codegraph/` directory exists at the repo root), reach for it BEFORE grep/find or reading files when you need to understand or locate code:\n\n- **MCP tool** (when available): `codegraph_explore` answers most code questions in one call \u2014 the relevant symbols' verbatim source plus the call paths between them, including dynamic-dispatch hops grep can't follow. Name a file or symbol in the query to read its current line-numbered source. If it's listed but deferred, load it by name via tool search.\n- **Shell** (always works): `codegraph explore \"<symbol names or question>\"` prints the same output.\n\nIf there is no `.codegraph/` directory, skip CodeGraph entirely \u2014 indexing is the user's decision.\n<!-- CODEGRAPH_END -->";
41
41
  //# sourceMappingURL=instructions-template.d.ts.map
@@ -26,22 +26,28 @@ import { AgentTarget, Location, WriteResult } from './types';
26
26
  */
27
27
  export declare function writeMcpEntry(loc: Location): WriteResult['files'][number];
28
28
  /**
29
- * Remove stale codegraph auto-sync hooks from Claude `settings.json`.
30
- *
31
- * Surgical at the individual-command level: only entries matching
32
- * `isLegacyCodegraphHookCommand` are dropped, so a sibling hook sharing
33
- * a matcher group (or the Stop event) with ours survives. We prune a
34
- * matcher group only once its `hooks` array is empty, an event only
35
- * once it has no groups left, and `hooks` itself only once every event
36
- * is gone — and none of that runs unless we actually removed a
37
- * codegraph command, so a settings.json with no legacy hooks is left
38
- * byte-for-byte untouched and reported `unchanged`.
39
- *
40
- * Exported so it can be unit-tested directly and reused by both
29
+ * Remove stale codegraph auto-sync hooks (`mark-dirty` / `sync-if-dirty`) that a
30
+ * pre-0.8 install wrote. Exported for direct unit-testing; reused by both
41
31
  * `install` (an upgrade self-heals) and `uninstall`.
42
32
  */
43
33
  export declare function cleanupLegacyHooks(loc: Location): WriteResult['files'][number];
34
+ /**
35
+ * Remove the front-load `UserPromptSubmit` hook this installer writes (see
36
+ * writePromptHookEntry). Used by `uninstall`, and by `install` when the user
37
+ * opts out, so the choice round-trips.
38
+ */
39
+ export declare function removePromptHookEntry(loc: Location): WriteResult['files'][number];
44
40
  export declare function writePermissionsEntry(loc: Location): WriteResult['files'][number];
41
+ /**
42
+ * Write the front-load `UserPromptSubmit` hook into Claude `settings.json` —
43
+ * a `command` hook that runs `codegraph prompt-hook`, which injects
44
+ * codegraph_explore context for structural prompts so the agent reliably uses
45
+ * the graph. Idempotent: if our command is already wired under UserPromptSubmit
46
+ * the file is left byte-for-byte untouched and reported `unchanged`. Sibling
47
+ * hooks (the user's own, or other events) are preserved. Opt-in — the installer
48
+ * only calls this when the user accepts the prompt (default-yes).
49
+ */
50
+ export declare function writePromptHookEntry(loc: Location): WriteResult['files'][number];
45
51
  /**
46
52
  * Strip the marker-delimited CodeGraph block from CLAUDE.md if a prior
47
53
  * install wrote one. Codegraph no longer maintains an instructions file
@@ -19,8 +19,18 @@ export declare function getMcpServerConfig(): {
19
19
  };
20
20
  /**
21
21
  * Permissions list for Claude `settings.json`. Other targets that
22
- * have a permissions concept can compose this list directly. The
23
- * permission strings follow Claude's `mcp__<server>__<tool>` format.
22
+ * have a permissions concept can compose this list directly.
23
+ *
24
+ * One server-scoped wildcard rather than a per-tool list. By default only
25
+ * `codegraph_explore` is even LISTED to the agent (see DEFAULT_MCP_TOOLS in
26
+ * mcp/tools.ts), so in practice explore is the only tool this auto-approves —
27
+ * but the wildcard means that if a user re-enables another tool via
28
+ * CODEGRAPH_MCP_TOOLS, it's already pre-approved (no permission prompt, no
29
+ * hand-editing settings.json), and future tools are covered too. Claude only
30
+ * honors globs after a literal `mcp__<server>__` prefix, so this exact string
31
+ * is the way to allow-all for one server; a bare `mcp__codegraph` or `*` is
32
+ * ignored. The allowlist gates PROMPTING, not visibility, so a superset here
33
+ * never makes a hidden tool appear.
24
34
  */
25
35
  export declare function getCodeGraphPermissions(): string[];
26
36
  /**
@@ -63,6 +63,13 @@ export interface InstallOptions {
63
63
  * target has no permissions concept this option is a no-op.
64
64
  */
65
65
  autoAllow: boolean;
66
+ /**
67
+ * Front-load prompt hook (Claude `UserPromptSubmit`) that injects
68
+ * codegraph_explore context for structural prompts. `true` installs it,
69
+ * `false` removes any prior install (so opt-out round-trips), `undefined`
70
+ * leaves it untouched. Targets without a prompt-hook concept ignore it.
71
+ */
72
+ promptHook?: boolean;
66
73
  }
67
74
  export interface AgentTarget {
68
75
  /** Stable id; matches the `TargetId` union. */
@@ -7,24 +7,28 @@
7
7
  * before it sees individual tool descriptions.
8
8
  *
9
9
  * Goals when editing this:
10
- * - Tool selection by intent (which tool for which question)
11
- * - Common chains (refactor planning = X then Y)
12
- * - Anti-patterns (don't grep when codegraph_search is faster)
10
+ * - Lead the agent to codegraph_explore for any structural/flow question
11
+ * - Reinforce "explore instead of Read/Grep" for indexed code
12
+ * - Anti-patterns (don't re-verify with grep; don't hand-reconstruct flows)
13
13
  *
14
14
  * Keep it tight. The agent reads this every session — long instructions
15
- * burn tokens. Reference only tools that exist on `main`; gate any
16
- * conditional tools behind feature checks if/when they ship.
15
+ * burn tokens. The DEFAULT MCP surface is `codegraph_explore` ALONE (see
16
+ * DEFAULT_MCP_TOOLS in tools.ts) reference only that tool here. The other
17
+ * tools (node/search/callers/…) stay defined and are re-enablable via
18
+ * CODEGRAPH_MCP_TOOLS, but they are NOT listed to agents, so don't name them.
17
19
  */
18
- export declare const SERVER_INSTRUCTIONS = "# Codegraph \u2014 code intelligence over an indexed knowledge graph\n\nCodegraph is a SQLite knowledge graph of every symbol, edge, and file in\nthe workspace \u2014 pre-computed structure you would otherwise re-derive by\nreading files (cached intelligence: thousands of parse/trace decisions you\ndon't pay to re-reason each run). Reads are sub-millisecond; the index lags\nwrites by ~1s through the file watcher. Reach for it BEFORE *and* while\nwriting or editing code \u2014 not just for questions: one call returns the\nverbatim source PLUS who calls it and what it affects, so you edit with the\nblast radius in view. More accurate context, in far fewer tokens and\nround-trips than reading files yourself.\n\n## Use codegraph instead of reading files \u2014 for questions AND edits\n\nWhether you're answering \"how does X work\" or implementing a change (fixing\na bug, adding a feature), reach for codegraph before you Read. For\nunderstanding, answer DIRECTLY \u2014 usually with ONE `codegraph_explore` call.\n`codegraph_explore` takes either a natural-language question or a bag of\nsymbol/file names and returns the verbatim source of the relevant symbols\ngrouped by file, so it is Read-equivalent and most often the ONLY\ncodegraph call you need. Codegraph IS the pre-built search index \u2014 so\ndelegating the lookup to a separate file-reading sub-task/agent, or\nrunning your own grep + read loop, repeats work codegraph already did and\ncosts more for the same answer. Reach for raw Read/Grep only to confirm a\nspecific detail codegraph didn't cover. A direct codegraph answer is\ntypically one to a few calls; a grep/read exploration is dozens.\n\n## Tool selection by intent\n\n- **Almost any question \u2014 \"how does X work\", architecture, a bug, \"what/where is X\", or surveying an area** \u2192 `codegraph_explore` (PRIMARY \u2014 call FIRST; ONE capped call returns the verbatim source of the relevant symbols grouped by file; most often the ONLY call you need)\n- **\"How does X reach/become Y? / the flow / the path from X to Y\"** \u2192 `codegraph_explore`, naming the symbols that span the flow (e.g. `mutateElement renderScene`) \u2014 it surfaces the call path among them, including dynamic-dispatch hops (callbacks, React re-render, JSX children) grep can't follow\n- **\"What is the symbol named X?\" (just its location)** \u2192 `codegraph_search`\n- **\"What calls this?\" / \"What would changing this break?\"** \u2192 `codegraph_callers` \u2014 EVERY call site with file:line, including where a function is **registered as a callback** (passed as an argument, assigned to a function pointer/field, listed in a handler table) \u2014 labeled \"via callback registration\" \u2014 so a function with no direct calls is NOT dead if it's wired up somewhere. When several UNRELATED symbols share a name (one `UserService` per monorepo app), it reports **one section per definition** (never a merged list) \u2014 pass `file` to focus the definition you mean. The wider blast radius arrives automatically on `codegraph_explore` (its \"Blast radius\" section) and `codegraph_node` (the dependents note)\n- **\"What does this call?\"** \u2192 `codegraph_node` with that symbol and `includeCode: true` \u2014 the body IS the callee list, and the caller/callee trail comes with it\n- **Reading a source FILE (any time you'd use the `Read` tool)** \u2192 `codegraph_node` with a `file` path and no `symbol`. It returns the file's **current source with line numbers \u2014 the same `<n>\\t<line>` shape `Read` gives you, safe to `Edit` from** \u2014 narrowable with `offset`/`limit` exactly like `Read`, PLUS a one-line note of which files depend on it. Same bytes as `Read`, faster (served from the index), with the blast radius attached. Use it **instead of `Read`** for indexed source files; fall back to `Read` only for what codegraph doesn't index (configs, docs). Pass `symbolsOnly: true` for just the file's structure.\n- **About to read or edit a symbol you can name** \u2192 `codegraph_node` with that `symbol` (SECONDARY \u2014 the after-explore depth tool): the verbatim source (`includeCode: true`) PLUS its caller/callee trail, so before changing it you see what calls it and what your edit would break. For an OVERLOADED name it returns EVERY matching definition's body in one call, so you never Read a file to find the right overload\n\n## Common chains\n\n- **Flow / \"how does X reach Y\"**: ONE `codegraph_explore` with the symbol names spanning the flow \u2014 it surfaces the call path among them (riding dynamic-dispatch hops) AND returns their source. No need to reconstruct the path with `codegraph_search` + `codegraph_callers`.\n- **Onboarding / understanding any area**: ONE `codegraph_explore` is usually the whole answer. Only follow up \u2014 `codegraph_node` for a specific symbol \u2014 if something is still unclear.\n- **Refactor planning**: `codegraph_callers` for the complete call-site list to update; the wider blast radius is already attached to `codegraph_explore` / `codegraph_node` output.\n- **Debugging a regression**: `codegraph_callers` of the suspected symbol; `codegraph_node` on anything unexpected that appears.\n\n## Anti-patterns\n\n- **Trust codegraph's results \u2014 don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.\n- **Don't grep first** when looking up a symbol by name \u2014 `codegraph_search` is faster and returns kind + location + signature.\n- **Don't chain `codegraph_search` + `codegraph_node`** to understand an area \u2014 ONE `codegraph_explore` returns the relevant symbols' source together in a single round-trip.\n- **Don't loop `codegraph_node` over many symbols** \u2014 one `codegraph_explore` call returns them all grouped by file, while each separate call re-reads the whole context and costs far more. Use `codegraph_node` for a single symbol.\n- **Don't reach for the `Read` tool on an indexed source file** \u2014 `codegraph_node` with a `file` reads it for you (same `<n>\\t<line>` source, `offset`/`limit` like Read, faster, with its blast radius), and with a `symbol` it returns the source plus the caller/callee trail. Reach for raw `Read` only for what codegraph doesn't index (configs, docs) or when the staleness banner flags a file as pending re-index.\n- **After editing, check the staleness banner.** When a tool response starts with \"\u26A0\uFE0F Some files referenced below were edited since the last index sync\u2026\", the listed files are pending re-index \u2014 Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust codegraph.\n\n## Limitations\n\n- If a tool reports a project isn't indexed (no `.codegraph/`), stop calling codegraph tools for that project for the rest of the session and use your built-in tools there instead. Indexing is the user's decision \u2014 mention they can run `codegraph init` if it comes up, but don't run it yourself.\n- Index lags file writes by ~1 second.\n- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.\n- No live correctness validation \u2014 that's still the TypeScript compiler / test suite / linter's job. Codegraph supplements those with structural context they don't have.\n";
20
+ export declare const SERVER_INSTRUCTIONS = "# Codegraph \u2014 code intelligence over an indexed knowledge graph\n\nCodegraph is a SQLite knowledge graph of every symbol, edge, and file in\nthe workspace \u2014 pre-computed structure you would otherwise re-derive by\nreading files (cached intelligence: thousands of parse/trace decisions you\ndon't pay to re-reason each run). Reads are sub-millisecond; the index lags\nwrites by ~1s through the file watcher. Reach for it BEFORE *and* while\nwriting or editing code \u2014 not just for questions: one call returns the\nverbatim source PLUS who calls it and what it affects, so you edit with the\nblast radius in view. More accurate context, in far fewer tokens and\nround-trips than reading files yourself.\n\n## One tool: codegraph_explore \u2014 use it instead of reading files\n\nThere is a single tool, `codegraph_explore`, and it is Read-equivalent. It\ntakes either a natural-language question or a bag of symbol/file names and\nreturns the **verbatim, line-numbered source** of the relevant symbols\ngrouped by file \u2014 the same `<n>\\t<line>` shape `Read` gives you, safe to\n`Edit` from \u2014 PLUS the call path among them (including dynamic-dispatch hops\nlike callbacks, React re-render, and JSX children that grep can't follow) and\na blast-radius summary of what depends on them.\n\nWhether you're answering \"how does X work\" or implementing a change (fixing a\nbug, adding a feature), call `codegraph_explore` before you Read. ONE call\nusually answers the whole question. Codegraph IS the pre-built search index \u2014\nso running your own grep + read loop, or delegating the lookup to a separate\nfile-reading sub-task/agent, repeats work codegraph already did and costs more\nfor the same answer. A direct codegraph answer is typically one to a few\ncalls; a grep/read exploration is dozens.\n\n## How to query\n\n- **Almost any question \u2014 \"how does X work\", architecture, a bug, \"what/where is X\", or surveying an area** \u2192 `codegraph_explore` with a natural-language question or the relevant names. ONE capped call returns the verbatim source grouped by file; most often the ONLY call you need.\n- **\"How does X reach/become Y? / the flow / the path from X to Y\"** \u2192 `codegraph_explore`, naming the symbols that span the flow (e.g. `mutateElement renderScene`) \u2014 it surfaces the call path among them, riding dynamic-dispatch hops, and returns their source.\n- **Reading or editing a file/symbol you can name** \u2192 put its name or file path in the `codegraph_explore` query \u2014 it returns that current line-numbered source (safe to `Edit` from) with the call path and blast radius attached, so you don't Read it separately. For an overloaded name it returns every matching definition's body in one call.\n- **Need more?** Call `codegraph_explore` again with more specific names \u2014 treat the source it returns as already Read.\n\n## Anti-patterns\n\n- **Trust codegraph's results \u2014 don't re-verify them with grep.** They come from a full AST parse; re-checking with grep is slower, less accurate, and wastes context.\n- **Don't grep or Read first** to find or understand indexed code \u2014 ONE `codegraph_explore` returns the relevant symbols' source together in a single round-trip. Reach for raw `Read`/`Grep` only to confirm a specific detail codegraph didn't cover, or for what codegraph doesn't index (configs, docs).\n- **Don't reconstruct a flow by hand** \u2014 name the endpoints in one `codegraph_explore` and it surfaces the path between them, dynamic-dispatch hops included.\n- **After editing, check the staleness banner.** When a tool response starts with \"\u26A0\uFE0F Some files referenced below were edited since the last index sync\u2026\", the listed files are pending re-index \u2014 Read those specific files for accurate content. Every file NOT in that banner is fresh, so still trust codegraph. A different, rarer banner \u2014 \"\u26A0\uFE0F CodeGraph auto-sync is DISABLED\u2026\" \u2014 means live watching stopped entirely (the whole index is frozen, not just a few files); until it's resolved, Read files directly to confirm anything that may have changed.\n\n## Limitations\n\n- If a tool reports a project isn't indexed (no `.codegraph/`), stop calling codegraph tools for that project for the rest of the session and use your built-in tools there instead. Indexing is the user's decision \u2014 mention they can run `codegraph init` if it comes up, but don't run it yourself.\n- Index lags file writes by ~1 second.\n- Cross-file resolution is best-effort name matching; ambiguous calls may return multiple candidates.\n- No live correctness validation \u2014 that's still the TypeScript compiler / test suite / linter's job. Codegraph supplements those with structural context they don't have.\n";
19
21
  /**
20
- * Instructions variant sent when the workspace has NO codegraph index.
22
+ * Instructions variant sent when the server's own root has NO codegraph index.
21
23
  *
22
- * Sending the full playbook ("lean on codegraph for everything") into a
23
- * session where every call would fail wastes the agent's calls and worse —
24
- * the failures teach it codegraph is broken. The unindexed variant is a
25
- * short, unambiguous "inactive this session" note; `tools/list` is gated to
26
- * empty in the same state, so the agent has nothing to mis-call. Indexing is
27
- * deliberately left to the user: the agent is told NOT to run init itself.
24
+ * The tools are still exposed (gating tool availability on whether `./` has an
25
+ * index is the bug behind #964: it breaks monorepos where only sub-projects are
26
+ * indexed, and a server that started before `codegraph init` never surfaces the
27
+ * tools afterward). Instead of an "inactive" note, this variant tells the agent
28
+ * codegraph works **per project**: there's no default project to query, so pass
29
+ * a `projectPath` to any project that HAS a `.codegraph/`. The full single-
30
+ * project playbook ({@link SERVER_INSTRUCTIONS}) is sent instead when the root
31
+ * IS indexed, so the common case stays tight.
28
32
  */
29
- export declare const SERVER_INSTRUCTIONS_UNINDEXED = "# Codegraph \u2014 inactive (workspace not indexed)\n\nThis workspace has no codegraph index (no `.codegraph/` directory), so no\ncodegraph tools are available this session. Work with your built-in tools as\nusual.\n\nIndexing is the user's decision \u2014 do not run it yourself. If the user asks\nabout codegraph, they can enable it by running `codegraph init` in the\nproject root and starting a new session.\n";
33
+ export declare const SERVER_INSTRUCTIONS_NO_ROOT_INDEX = "# Codegraph \u2014 available (per-project; pass projectPath)\n\nCodegraph is a SQLite knowledge graph of a codebase's symbols, edges, and\nfiles: one `codegraph_explore` call returns the verbatim, line-numbered source\nof the relevant symbols PLUS the call paths between them and a blast-radius\nsummary \u2014 replacing a grep + Read loop with one round-trip.\n\nThis server started somewhere with no `.codegraph/` of its own, so there is no\ndefault project \u2014 but the tools are available and work **per project**:\n\n- To query a project that HAS a `.codegraph/` index (e.g. a service inside a\n monorepo, or a second repo), pass its path as `projectPath` to\n `codegraph_explore` (and any other codegraph tool). Codegraph resolves the\n nearest `.codegraph/` at or above that path and answers from it \u2014 for as many\n projects as you like in one session.\n- For a project with no `.codegraph/`, use your built-in tools (Read/Grep/Glob)\n for that project. Indexing is the user's decision \u2014 don't run it yourself, but\n if it comes up they can run `codegraph init` in a project to enable codegraph\n there (a new index is picked up live, no restart).\n";
30
34
  //# sourceMappingURL=server-instructions.d.ts.map
@@ -57,7 +57,7 @@ export interface ExploreOutputBudget {
57
57
  maxCharsPerFile: number;
58
58
  /** Cluster gap threshold in lines — tighter clustering on small projects. */
59
59
  gapThreshold: number;
60
- /** Max symbols listed in the per-file header (`#### path — sym(kind), ...`). */
60
+ /** Max symbols listed in the per-file header (``**`path`** — sym(kind), ...``). */
61
61
  maxSymbolsInFileHeader: number;
62
62
  /** Max edges shown per relationship kind in the Relationships section. */
63
63
  maxEdgesPerRelationshipKind: number;
@@ -93,6 +93,15 @@ export declare function formatStaleBanner(stale: PendingFile[]): string;
93
93
  * without bloating the main banner.
94
94
  */
95
95
  export declare function formatStaleFooter(stale: PendingFile[]): string;
96
+ /**
97
+ * Whole-index degradation banner (issue #876). Emitted at the top of a read
98
+ * tool response when live watching has permanently stopped — at which point
99
+ * `getPendingFiles()` is empty, so the per-file banner above can't fire even
100
+ * though the index is now FROZEN and silently drifting stale. Leads with the
101
+ * agent-actionable instruction (Read directly) and carries the reason, which
102
+ * already names the operator remedy (`codegraph sync` / git hooks).
103
+ */
104
+ export declare function formatDegradedBanner(reason: string | null): string;
96
105
  /**
97
106
  * MCP Tool definition
98
107
  */
@@ -163,6 +172,16 @@ export declare class ToolHandler {
163
172
  * stale data, which is what would have happened without the gate.
164
173
  */
165
174
  setCatchUpGate(p: Promise<void> | null): void;
175
+ /**
176
+ * Await the catch-up gate, but no longer than the configured timeout (#905).
177
+ * If the reconcile settles first, we got the fully-reconciled answer. If the
178
+ * timeout wins, we serve the call now and let the reconcile finish in the
179
+ * background — it yields to the event loop (see SYNC_RECONCILE_YIELD_INTERVAL),
180
+ * so a concurrent read still runs against the same connection. Never throws:
181
+ * a failed reconcile is logged by the engine, and we serve best-effort over
182
+ * the same potentially-stale data the un-gated path would have.
183
+ */
184
+ private awaitCatchUpGate;
166
185
  /**
167
186
  * Record the directory the server tried to resolve the default project from.
168
187
  * Used only to make the "no default project" error actionable.
@@ -200,6 +219,17 @@ export declare class ToolHandler {
200
219
  * similar to how git finds .git/ directories.
201
220
  */
202
221
  private getCodeGraph;
222
+ /**
223
+ * Heal a long-lived connection whose `.codegraph/` was removed and recreated
224
+ * at the same path (a worktree recreated, or `rm -rf .codegraph` + re-init)
225
+ * before handing it to a tool. Otherwise the daemon keeps serving the
226
+ * pre-removal snapshot from its now-unlinked file handle until restart — and
227
+ * because the daemon registry is keyed by path, a same-path recreate routes
228
+ * new clients straight back to this same stale daemon (#925). The check is one
229
+ * stat() and a no-op unless the inode actually changed; it never throws into a
230
+ * tool call.
231
+ */
232
+ private freshen;
203
233
  /**
204
234
  * Close all cached project connections
205
235
  */
@@ -316,6 +346,26 @@ export declare class ToolHandler {
316
346
  * connected flow never reaches this method.
317
347
  */
318
348
  private buildDynamicBoundaries;
349
+ /**
350
+ * Interface/registry-dispatch announcement — #687 extended to GRAPH-visible
351
+ * polymorphism (the body-scan can't see it: `nodeType.execute()` is textually
352
+ * an ordinary call; the polymorphism lives in the `implements`/`extends` edges).
353
+ *
354
+ * A method the agent named that resolves to a large same-name family whose
355
+ * definers overwhelmingly implement/extend ONE supertype is a runtime dispatch:
356
+ * the concrete target is chosen at runtime from N implementations, so no single
357
+ * static edge is "the answer" — the implementations ARE the continuations. We
358
+ * announce the supertype, its TRUE implementer count, and a few concrete targets,
359
+ * then steer to codegraph_explore. Graph-only, query-time, zero mutation; the
360
+ * caller fires it ONLY for an UNCOVERED named token, so a connected flow is silent.
361
+ *
362
+ * Robust to FTS sampling bias: the same-name family is a capped FTS sample that
363
+ * over-represents whatever FTS ranks first (n8n: DB `TableOperation.execute`
364
+ * outnumbered `INodeType.execute` in the sample 7:6 even though INodeType has
365
+ * 611 implementers vs a handful). So candidate supertypes are ranked by their
366
+ * TRUE graph-wide implementer count, NOT their frequency in the sample.
367
+ */
368
+ private buildPolymorphicBoundaries;
319
369
  /**
320
370
  * Shortlist candidate runtime targets for a dispatch key surfaced by
321
371
  * {@link buildDynamicBoundaries}. Exact conventional names first (`save` →
@@ -0,0 +1,36 @@
1
+ import { Language } from './types';
2
+ /** Filename of the project-scoped config, resolved relative to the project root. */
3
+ export declare const PROJECT_CONFIG_FILENAME = "codegraph.json";
4
+ export interface ProjectConfig {
5
+ /** Map of custom file extension (`.foo`) to a supported language id. */
6
+ extensions?: Record<string, string>;
7
+ /**
8
+ * Gitignore-style patterns naming gitignored directories whose embedded git
9
+ * repositories should be indexed anyway — the explicit opt-in to override
10
+ * `.gitignore` for nested-repo discovery (#622, #699). Absent/empty (the
11
+ * default) means `.gitignore` is fully respected: gitignored embedded repos
12
+ * are never discovered or indexed (#970, #976).
13
+ */
14
+ includeIgnored?: string[];
15
+ }
16
+ /**
17
+ * Load the validated extension overrides for a project, mtime-cached.
18
+ *
19
+ * Returns a map of `.ext` → supported language id. The result merges on top of
20
+ * the built-in extension map at the point of use (see `detectLanguage` /
21
+ * `isSourceFile`), with these user mappings taking precedence. Returns an empty
22
+ * map when there is no `codegraph.json` (the zero-config default).
23
+ */
24
+ export declare function loadExtensionOverrides(rootDir: string): Record<string, Language>;
25
+ /**
26
+ * Load the validated `includeIgnored` patterns for a project, mtime-cached.
27
+ *
28
+ * These name gitignored directories whose embedded git repositories should be
29
+ * indexed despite `.gitignore` (#622, #699). An empty result — the zero-config
30
+ * default — means `.gitignore` is fully respected: gitignored embedded repos
31
+ * are never discovered or indexed (#970, #976).
32
+ */
33
+ export declare function loadIncludeIgnoredPatterns(rootDir: string): string[];
34
+ /** Test/maintenance hook: forget cached config (e.g. after rewriting it in a test). */
35
+ export declare function clearProjectConfigCache(): void;
36
+ //# sourceMappingURL=project-config.d.ts.map
@@ -0,0 +1,45 @@
1
+ /** Managed tier ("CodeGraph AI") — the metered gateway used when logged in. */
2
+ export declare const MANAGED_DEFAULT_URL = "https://ai.getcodegraph.com/v1";
3
+ /** The gateway's public model id (it translates this to the upstream provider id). */
4
+ export declare const MANAGED_DEFAULT_MODEL = "openai/gpt-oss-120b";
5
+ export interface OffloadConfig {
6
+ /** Managed tier: route through CodeGraph AI (metered) with the logged-in org token. */
7
+ managed?: boolean;
8
+ /** OpenAI-compatible base URL ending in `/v1` (e.g. https://api.cerebras.ai/v1). */
9
+ url?: string;
10
+ /** Model id to request (default `gpt-oss-120b` BYO, `openai/gpt-oss-120b` managed). */
11
+ model?: string;
12
+ /** Name of the env var holding the provider API key (never persisted). BYO only. */
13
+ keyEnv?: string;
14
+ /** reasoning_effort: low | medium | high (default `low`). */
15
+ effort?: string;
16
+ /** Output style: plain | report (default `plain`). */
17
+ style?: string;
18
+ }
19
+ export interface ResolvedOffload {
20
+ /** True when the offload is usable (endpoint present; for managed, a token too). */
21
+ enabled: boolean;
22
+ /** Managed tier (CodeGraph AI, metered) vs BYO endpoint. */
23
+ managed: boolean;
24
+ url?: string;
25
+ model: string;
26
+ /** Resolved API key / org token (from env, the configured `keyEnv`, or login), if any. */
27
+ apiKey?: string;
28
+ /** Where the key/token came from (for `status` display) — never the secret itself. */
29
+ keySource?: string;
30
+ effort: string;
31
+ style: string;
32
+ timeoutMs: number;
33
+ maxTokens: number;
34
+ strip: boolean;
35
+ debug: boolean;
36
+ /** Where the endpoint came from — drives `codegraph offload status`. */
37
+ origin: 'env' | 'config' | 'none';
38
+ }
39
+ /** The persisted offload block (empty object if none). */
40
+ export declare function readOffloadConfig(): OffloadConfig;
41
+ /** Persist (or, with `null`, clear) the offload block, leaving other config keys intact. */
42
+ export declare function writeOffloadConfig(offload: OffloadConfig | null): void;
43
+ /** Merge the persisted config with `CODEGRAPH_OFFLOAD_*` env overrides (env wins). */
44
+ export declare function resolveOffload(env?: NodeJS.ProcessEnv): ResolvedOffload;
45
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1,5 @@
1
+ /** The stored managed-offload org token, if the machine is logged in. */
2
+ export declare function readOffloadToken(): string | undefined;
3
+ /** Persist (or, with `null`, clear) the managed-offload org token at `0600`. */
4
+ export declare function writeOffloadToken(token: string | null): void;
5
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1,21 @@
1
+ /** Dashboard base for the device-login endpoints; override for testing via CODEGRAPH_LOGIN_URL. */
2
+ export declare function loginBaseUrl(): string;
3
+ /** The dashboard's response to a device-authorization start request. */
4
+ export interface DeviceStart {
5
+ device_code: string;
6
+ user_code: string;
7
+ verification_uri: string;
8
+ /** Same URL with the code prefilled, for one-click open. */
9
+ verification_uri_complete?: string;
10
+ /** Seconds the CLI should wait between polls. */
11
+ interval?: number;
12
+ /** Seconds until the request expires. */
13
+ expires_in?: number;
14
+ }
15
+ /** Begin a device-authorization request. */
16
+ export declare function startDeviceLogin(): Promise<DeviceStart>;
17
+ /** Poll until the user approves in the browser; resolves with the org token. */
18
+ export declare function pollForToken(deviceCode: string, intervalSec: number, expiresInSec: number): Promise<string>;
19
+ /** Best-effort: open a URL in the default browser. Never throws — the URL is also printed. */
20
+ export declare function openBrowser(url: string): Promise<void>;
21
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1,43 @@
1
+ interface SynthArgs {
2
+ query: string;
3
+ context: string;
4
+ }
5
+ /** True when a reasoning offload endpoint is configured (env or `~/.codegraph/config.json`). */
6
+ export declare function isOffloadEnabled(): boolean;
7
+ export interface OffloadUsage {
8
+ plan?: string;
9
+ allowance?: number;
10
+ used?: number;
11
+ overage?: number;
12
+ remaining?: number;
13
+ periodEnd?: number;
14
+ unlimited?: boolean;
15
+ banned?: boolean;
16
+ tokensLast30?: number;
17
+ callsLast30?: number;
18
+ creditsLast30?: number;
19
+ models?: string[];
20
+ }
21
+ /**
22
+ * GET `/v1/usage` from the configured (managed) endpoint → the org's credit
23
+ * balance/usage, or null on any failure. Drives `codegraph offload status`.
24
+ */
25
+ export declare function fetchUsage(): Promise<OffloadUsage | null>;
26
+ /**
27
+ * Strip sections of the explore output addressed to the AGENT (not useful to a
28
+ * reasoning model): the "Not shown above" pointer list, the completeness signal,
29
+ * the explore-budget note, the trimmed/truncation notices, and the redundant
30
+ * "## Exploration:/Found N symbols" header (the query is sent separately). Left
31
+ * in, some models regurgitate them ("We have 2 explore calls. Let's explore…")
32
+ * and they add noise. Source code, blast radius, relationships, and flow stay.
33
+ * Opt-in (`CODEGRAPH_OFFLOAD_STRIP=1`) — default off (it also removes the "Not
34
+ * shown above" pointers, which can be useful navigation).
35
+ */
36
+ export declare function stripAgentDirectives(context: string): string;
37
+ /**
38
+ * Offload reasoning over the retrieved `context` to the configured model and
39
+ * return its synthesized answer, or null to signal "fall back to local source".
40
+ */
41
+ export declare function synthesizeOffload({ query, context }: SynthArgs): Promise<string | null>;
42
+ export {};
43
+ //# sourceMappingURL=reasoner.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * C/C++ function-pointer dispatch synthesis (#932).
3
+ *
4
+ * C/C++ polymorphism is the function pointer: a struct carries a fn-pointer
5
+ * field (`int (*fn)(int)`, or a fn-pointer-typedef field `hook_func func`),
6
+ * concrete functions are *registered* into it through a table
7
+ * (`static struct cmd cmds[] = {{"add", cmd_add}, …}`, a designated
8
+ * `.fn = cmd_add`, or `x->fn = cmd_add`), and the dispatcher calls through it
9
+ * indirectly (`p->fn(argv)`). Static extraction captures neither the
10
+ * registration→field binding nor the indirect call, so the dispatcher→handler
11
+ * edge is missing and `git`'s `run_builtin` looks like it calls nothing, the
12
+ * hooks in `hook_demo.c` are unreachable, etc.
13
+ *
14
+ * This bridges it, keyed by **(struct type, fn-pointer field)**:
15
+ * • registrations — a function bound to `S.field` via a positional
16
+ * initializer (matched by field index), a designated `.field = fn`, or a
17
+ * direct `x.field = fn` / `x->field = fn` assignment;
18
+ * • dispatch — `recv->field(…)` / `recv.field(…)` where `recv` resolves to a
19
+ * value of struct type `S` (from the enclosing function's params / locals),
20
+ * falling back to the field name when it is unique to one struct;
21
+ * • field←field propagation — `a->f = b->g` merges `B.g`'s handlers into
22
+ * `A.f`, so a generic single-slot hook that is reassigned from a registry
23
+ * (the `hook_demo.c` shape: `h->func = found->fn`) still resolves.
24
+ *
25
+ * Whole-graph pass after base resolution; all edges are `provenance:'heuristic'`
26
+ * (`synthesizedBy:'fn-pointer-dispatch'`). High precision via the (type, field)
27
+ * key + a real-function gate; a project with no fn-pointer dispatch is a no-op.
28
+ */
29
+ import type { Edge } from '../types';
30
+ import type { QueryBuilder } from '../db/queries';
31
+ import type { ResolutionContext } from './types';
32
+ export declare function cFnPointerDispatchEdges(queries: QueryBuilder, ctx: ResolutionContext): Edge[];
33
+ //# sourceMappingURL=c-fnptr-synthesizer.d.ts.map
@@ -3,7 +3,12 @@ import type { ResolutionContext } from './types';
3
3
  /**
4
4
  * Synthesize dispatcher→callback edges (field observers + EventEmitters +
5
5
  * React re-render + JSX children + Vue templates + SvelteKit load + RN event
6
- * channel + Fabric native-impl + MyBatis Java↔XML + Gin middleware chain).
6
+ * channel + Fabric native-impl + MyBatis Java↔XML + Gin middleware chain +
7
+ * Redux-thunk dispatch chain + object-literal registry dispatch + RTK Query
8
+ * generated-hook → endpoint + Pinia useStore().action() + Vuex string dispatch +
9
+ * Celery task .delay()/.apply_async() → task body + Spring publishEvent → @EventListener +
10
+ * MediatR Send/Publish → IRequestHandler/INotificationHandler +
11
+ * Sidekiq Worker.perform_async → #perform + Laravel event(new X) → listener handle).
7
12
  * Returns the count added. Never throws into indexing — callers wrap in try/catch.
8
13
  */
9
14
  export declare function synthesizeCallbackEdges(queries: QueryBuilder, ctx: ResolutionContext): number;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * GoFrame Framework Resolver (route metadata) — issue #747.
3
+ *
4
+ * GoFrame's "standard router" binds routes reflectively, so there is no literal
5
+ * path string at a `.GET("/x", handler)` call site and no static edge from a
6
+ * route to the controller method that serves it. The structural facts live in
7
+ * two places, joined only at runtime by GoFrame:
8
+ *
9
+ * // api/user/v1/user_sign_in.go — the route lives in a struct tag on the request type
10
+ * type SignInReq struct {
11
+ * g.Meta `path:"/user/sign-in" method:"post" tags:"UserService" summary:"…"`
12
+ * …
13
+ * }
14
+ * // internal/controller/user/user_v1_sign_in.go — the handler takes *that* request type
15
+ * func (c *ControllerV1) SignIn(ctx context.Context, req *v1.SignInReq) (res *v1.SignInRes, err error)
16
+ * // internal/cmd/cmd.go — reflective binding (no path, no handler name)
17
+ * group.Bind(user.NewV1())
18
+ *
19
+ * This resolver handles the FIRST half: it reads the `g.Meta` struct tag on a
20
+ * request type into a `route` node (`POST /user/sign-in`). The route → handler
21
+ * EDGE is the genuinely reflective part — the method name is NOT derivable from
22
+ * the request type (`DeptSearchReq` is served by `List`, `DeptAddReq` by `Add`),
23
+ * so the only reliable join is the request type appearing in the method's
24
+ * parameter signature. That whole-graph join is done by the companion
25
+ * `goframeRouteEdges` synthesizer, which reads the request type back out of the
26
+ * route node's qualifiedName.
27
+ *
28
+ * Honesty note: the route node carries the `g.Meta` path verbatim. The group
29
+ * prefix from `s.Group("/api", …)` / nested `group.Group("/v1", …)` is applied
30
+ * by reflective `Bind` at runtime and is deliberately NOT reconstructed here —
31
+ * the discriminating, structural part is the per-route path + method.
32
+ */
33
+ import { FrameworkResolver } from '../types';
34
+ /** Marker embedded in a route node's qualifiedName so the synthesizer can read
35
+ * back the request type to join on. The value after it is the package-qualified
36
+ * request type (`cash.ListReq`) — the package disambiguates the many identical
37
+ * bare names (`ListReq`, `GetReq`) a large app defines, one per module. Falls
38
+ * back to the bare type when no `package` declaration is found. */
39
+ export declare const GOFRAME_ROUTE_MARKER = "::goframe-route:";
40
+ export declare const goframeResolver: FrameworkResolver;
41
+ //# sourceMappingURL=goframe.d.ts.map
@@ -39,6 +39,7 @@ export { railsResolver } from './ruby';
39
39
  export { springResolver } from './java';
40
40
  export { playResolver } from './play';
41
41
  export { goResolver } from './go';
42
+ export { goframeResolver } from './goframe';
42
43
  export { rustResolver } from './rust';
43
44
  export { aspnetResolver } from './csharp';
44
45
  export { swiftUIResolver, uikitResolver, vaporResolver } from './swift';
@@ -0,0 +1,28 @@
1
+ /**
2
+ * GoFrame route → controller-method dispatch synthesis (#747).
3
+ *
4
+ * GoFrame binds routes reflectively (`group.Bind(user.NewV1())`), so the route
5
+ * declared in a request type's `g.Meta` tag has no static edge to the method
6
+ * that serves it. The `goframeResolver` extract pass turns each `g.Meta` into a
7
+ * `route` node carrying its request type in the qualifiedName; this whole-graph
8
+ * pass closes the loop by joining each route to its handler.
9
+ *
10
+ * The join key is the REQUEST TYPE, not the method name — GoFrame method names
11
+ * are free (`DeptSearchReq` is served by `List`, `DeptAddReq` by `Add`), so the
12
+ * only reliable link is the request type appearing in the handler's parameter
13
+ * signature:
14
+ *
15
+ * func (c *sysDeptController) Add(ctx context.Context, req *system.DeptAddReq) (…)
16
+ * ^^^^^^^^^^^^^^^^ the join
17
+ *
18
+ * Go method nodes already carry that signature, so no source re-read is needed.
19
+ * Each synthesized edge is `kind:'calls'`, `provenance:'heuristic'`,
20
+ * `metadata.synthesizedBy:'goframe-route'` — a reflective-dispatch bridge, so
21
+ * `codegraph_explore` surfaces it as a dynamic hop rather than a literal call,
22
+ * and the handler's callers list the route that reaches it. A project with no
23
+ * GoFrame routes is a no-op.
24
+ */
25
+ import type { Edge } from '../types';
26
+ import type { ResolutionContext } from './types';
27
+ export declare function goframeRouteEdges(ctx: ResolutionContext): Edge[];
28
+ //# sourceMappingURL=goframe-synthesizer.d.ts.map
@@ -22,6 +22,6 @@
22
22
  * `path(...)`, `Route::get(...)`, `app.get(...)` style patterns that
23
23
  * framework extractors scan for.
24
24
  */
25
- export type CommentLang = 'python' | 'javascript' | 'typescript' | 'php' | 'ruby' | 'java' | 'csharp' | 'swift' | 'go' | 'rust';
25
+ export type CommentLang = 'python' | 'javascript' | 'typescript' | 'php' | 'ruby' | 'java' | 'csharp' | 'swift' | 'go' | 'rust' | 'c' | 'cpp';
26
26
  export declare function stripCommentsForRegex(content: string, lang: CommentLang): string;
27
27
  //# sourceMappingURL=strip-comments.d.ts.map