@colbymchenry/codegraph 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -51
- package/dist/bin/fatal-handler.d.ts +20 -0
- package/dist/db/index.d.ts +22 -1
- package/dist/db/queries.d.ts +14 -0
- package/dist/directory.d.ts +58 -0
- package/dist/extraction/grammars.d.ts +11 -3
- package/dist/extraction/tree-sitter-types.d.ts +13 -0
- package/dist/extraction/tree-sitter.d.ts +119 -0
- package/dist/index.d.ts +33 -0
- package/dist/installer/instructions-template.d.ts +3 -3
- package/dist/installer/targets/claude.d.ts +18 -12
- package/dist/installer/targets/shared.d.ts +12 -2
- package/dist/installer/targets/types.d.ts +7 -0
- package/dist/mcp/daemon-manager.d.ts +42 -0
- package/dist/mcp/daemon-registry.d.ts +47 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/liveness-watchdog.d.ts +18 -0
- package/dist/mcp/server-instructions.d.ts +18 -14
- package/dist/mcp/tools.d.ts +51 -1
- package/dist/project-config.d.ts +19 -0
- package/dist/reasoning/config.d.ts +45 -0
- package/dist/reasoning/credentials.d.ts +5 -0
- package/dist/reasoning/login.d.ts +21 -0
- package/dist/reasoning/reasoner.d.ts +43 -0
- package/dist/resolution/c-fnptr-synthesizer.d.ts +33 -0
- package/dist/resolution/callback-synthesizer.d.ts +6 -1
- package/dist/resolution/frameworks/goframe.d.ts +41 -0
- package/dist/resolution/frameworks/index.d.ts +1 -0
- package/dist/resolution/goframe-synthesizer.d.ts +28 -0
- package/dist/resolution/strip-comments.d.ts +1 -1
- package/dist/sync/watcher.d.ts +68 -1
- package/dist/telemetry/index.d.ts +0 -3
- package/dist/utils.d.ts +14 -1
- package/package.json +7 -7
|
@@ -16,12 +16,19 @@ export declare class TreeSitterExtractor {
|
|
|
16
16
|
private nodes;
|
|
17
17
|
private edges;
|
|
18
18
|
private unresolvedReferences;
|
|
19
|
+
private static readonly VALUE_REF_LANGS;
|
|
20
|
+
private static readonly MAX_VALUE_REF_NODES;
|
|
21
|
+
private readonly valueRefsEnabled;
|
|
22
|
+
private fileScopeValues;
|
|
23
|
+
private fileScopeValueCounts;
|
|
24
|
+
private valueRefScopes;
|
|
19
25
|
private errors;
|
|
20
26
|
private extractor;
|
|
21
27
|
private nodeStack;
|
|
22
28
|
private methodIndex;
|
|
23
29
|
private fnRefSpec;
|
|
24
30
|
private fnRefCandidates;
|
|
31
|
+
private vueStoreFile;
|
|
25
32
|
constructor(filePath: string, source: string, language?: Language);
|
|
26
33
|
/**
|
|
27
34
|
* Parse and extract from the source code
|
|
@@ -59,6 +66,21 @@ export declare class TreeSitterExtractor {
|
|
|
59
66
|
* callback + same-file ops struct) — is.
|
|
60
67
|
*/
|
|
61
68
|
private flushFnRefCandidates;
|
|
69
|
+
/**
|
|
70
|
+
* Record value-reference bookkeeping as nodes are created: file-scope const/var symbols with
|
|
71
|
+
* distinctive names become reference targets; function/method/const/var symbols become reader
|
|
72
|
+
* scopes whose bodies flushValueRefs scans.
|
|
73
|
+
*/
|
|
74
|
+
private captureValueRefScope;
|
|
75
|
+
/**
|
|
76
|
+
* Emit same-file `references` edges from a symbol to the file-scope const/var it reads (TS/JS).
|
|
77
|
+
* The engine doesn't edge const→consumer, so impact analysis misses "change this table, affect
|
|
78
|
+
* its readers" (the ReScript-PR false positive). Same-file only (resolution is unambiguous),
|
|
79
|
+
* distinctive target names only (dodges the local-shadowing precision trap documented on
|
|
80
|
+
* function_ref), deduped per (reader, target). Default on (CODEGRAPH_VALUE_REFS=0 disables) +
|
|
81
|
+
* additive. Shadowed targets are pruned — see below.
|
|
82
|
+
*/
|
|
83
|
+
private flushValueRefs;
|
|
62
84
|
/**
|
|
63
85
|
* Visit a node and extract information
|
|
64
86
|
*/
|
|
@@ -92,10 +114,41 @@ export declare class TreeSitterExtractor {
|
|
|
92
114
|
* (class, struct, interface, trait). File nodes do not count as class-like.
|
|
93
115
|
*/
|
|
94
116
|
private isInsideClassLikeNode;
|
|
117
|
+
/**
|
|
118
|
+
* Ruby `CONST = …` assignment whose LHS is a `constant` node — a class/module
|
|
119
|
+
* (or top-level) constant worth extracting as a symbol even inside a class.
|
|
120
|
+
* Other languages don't give an assignment a `constant`-typed LHS, so this
|
|
121
|
+
* gate is effectively Ruby-only.
|
|
122
|
+
*/
|
|
123
|
+
private isClassScopeConstantAssignment;
|
|
95
124
|
/**
|
|
96
125
|
* Extract a function
|
|
97
126
|
*/
|
|
98
127
|
private extractFunction;
|
|
128
|
+
/**
|
|
129
|
+
* Detect a React component declared via an HOC wrapper whose result is itself a
|
|
130
|
+
* component: `forwardRef(...)`, `memo(...)`, `React.forwardRef/memo(...)`, and
|
|
131
|
+
* styled-components / emotion `styled.tag\`…\`` / `styled(Base)\`…\``. These
|
|
132
|
+
* initializers are a call / tagged-template (not a bare arrow), so the const is
|
|
133
|
+
* otherwise classified `constant` — and a constant is skipped by both the
|
|
134
|
+
* JSX-render edge synthesizer and component resolution, so `<Button/>` usages
|
|
135
|
+
* get no edge and callers/impact silently return empty (#841).
|
|
136
|
+
*
|
|
137
|
+
* Returns `{ inner }` — the inline render function to extract as the component
|
|
138
|
+
* body, or `null` when the wrapper has no inline function (`memo(Imported)`,
|
|
139
|
+
* `styled.button\`…\``) and only a bodyless component node is minted — or
|
|
140
|
+
* `undefined` when this initializer is not a recognized component wrapper.
|
|
141
|
+
*/
|
|
142
|
+
private reactComponentHoc;
|
|
143
|
+
/**
|
|
144
|
+
* Emit a `component` node for an HOC-wrapped React component declaration (see
|
|
145
|
+
* reactComponentHoc). Named by the declarator (`Button`) and located at it so
|
|
146
|
+
* the node range spans the body. When the wrapper has an inline render
|
|
147
|
+
* function, its body is walked so the component's callees (hooks, helpers) are
|
|
148
|
+
* captured under the component node — matching how a plain
|
|
149
|
+
* `const Foo = () => …` arrow component already behaves.
|
|
150
|
+
*/
|
|
151
|
+
private extractReactComponentNode;
|
|
99
152
|
/**
|
|
100
153
|
* Extract a class
|
|
101
154
|
*/
|
|
@@ -157,6 +210,72 @@ export declare class TreeSitterExtractor {
|
|
|
157
210
|
* `=> { return {...} }` block. Returns null for any other body shape.
|
|
158
211
|
*/
|
|
159
212
|
private functionReturnedObject;
|
|
213
|
+
/**
|
|
214
|
+
* RTK Query: from a `createApi({ ..., endpoints: build => ({...}) })` or a
|
|
215
|
+
* `baseApi.injectEndpoints({ endpoints: build => ({...}) })` call initializer,
|
|
216
|
+
* return the object literal of endpoint definitions (the object the `endpoints`
|
|
217
|
+
* arrow returns). Returns null for any other call — the common case — so this
|
|
218
|
+
* stays cheap and silent. Keyed on the RTK entry-point names (`createApi` /
|
|
219
|
+
* `injectEndpoints`) like the framework extractors key on their library APIs.
|
|
220
|
+
*/
|
|
221
|
+
private findRtkEndpointsObject;
|
|
222
|
+
/**
|
|
223
|
+
* Extract each RTK Query endpoint (`getX: build.query({...})` / `build.mutation`)
|
|
224
|
+
* as a function node named by the endpoint key, spanning its primary handler
|
|
225
|
+
* (the `queryFn`/`query` arrow) so the fetch logic's calls attribute to the
|
|
226
|
+
* endpoint. Without this an endpoint exists only as an object-literal property —
|
|
227
|
+
* never a node — so the generated `useXQuery` hook can't be bridged to it.
|
|
228
|
+
*/
|
|
229
|
+
private extractRtkEndpoints;
|
|
230
|
+
/**
|
|
231
|
+
* The primary handler arrow of a `build.query({ queryFn|query: (…) => … })`
|
|
232
|
+
* endpoint — prefers `queryFn`, then `query`, else the first function-valued
|
|
233
|
+
* property. Returns null when the endpoint is config-only (no handler arrow).
|
|
234
|
+
*/
|
|
235
|
+
private rtkEndpointHandler;
|
|
236
|
+
/**
|
|
237
|
+
* RTK Query generated-hook bindings. `export const { useGetXQuery,
|
|
238
|
+
* useUpdateYMutation } = someApi` destructures the hooks RTK generates per
|
|
239
|
+
* endpoint off a createApi result. They are real exported symbols that
|
|
240
|
+
* components import, but destructured bindings aren't otherwise extracted —
|
|
241
|
+
* mint a function node per binding matching the RTK hook convention so the hook
|
|
242
|
+
* resolves and the synthesizer can bridge it to its endpoint. Gated tight by the
|
|
243
|
+
* caller (object-pattern off a bare identifier) + the name convention here, so
|
|
244
|
+
* ordinary destructures stay unextracted.
|
|
245
|
+
*/
|
|
246
|
+
private extractRtkHookBindings;
|
|
247
|
+
/** Cheap per-file heuristic: the file carries ≥2 distinct Vue-store signals
|
|
248
|
+
* (defineStore/createStore/Vuex, or the actions/mutations/getters/namespaced
|
|
249
|
+
* vocabulary). Gates the non-exported `const actions = {…}` Vuex-module form so
|
|
250
|
+
* a stray `const actions` in unrelated code is never mistaken for a store. */
|
|
251
|
+
private looksLikeVueStoreFile;
|
|
252
|
+
/** True if an object literal has ≥1 inline function member (`key: () => …` /
|
|
253
|
+
* `method(){}`) — distinguishes an inline action map (zustand/SvelteKit form
|
|
254
|
+
* actions) from a Pinia SETUP store's all-shorthand `return { foo, bar }`
|
|
255
|
+
* (whose functions are body-local consts, walked normally instead). */
|
|
256
|
+
private objectHasInlineFunctions;
|
|
257
|
+
/** Vue store action/mutation/getter collections defined INLINE in a store call:
|
|
258
|
+
* `defineStore({ actions: {…}, getters: {…} })` (Pinia options form),
|
|
259
|
+
* `defineStore('id', { actions: {…} })`, `createStore({ mutations: {…} })`,
|
|
260
|
+
* `new Vuex.Store({ actions: {…} })`. Returns the object literals under those
|
|
261
|
+
* keys so their methods become nodes. Gated on the store-factory callee. */
|
|
262
|
+
private findVueStoreCollectionObjects;
|
|
263
|
+
/** Extract the methods of a store-config object's `actions`/`mutations`/`getters`
|
|
264
|
+
* properties. Used for the canonical Vuex MODULE shape `export default {
|
|
265
|
+
* namespaced, actions: {…}, mutations: {…} }` — object-literal methods aren't
|
|
266
|
+
* otherwise extracted, so the actions/mutations would never be nodes. */
|
|
267
|
+
private extractStoreCollectionMethods;
|
|
268
|
+
/** The SETUP function of a Pinia setup store (`defineStore('id', () => {…})`)
|
|
269
|
+
* — an arrow/function arg with a block body. Returns null for the options form
|
|
270
|
+
* (`defineStore({…})`) and for any non-defineStore call. The setup body's local
|
|
271
|
+
* function consts are the store's actions; the generic body walk doesn't reach
|
|
272
|
+
* them (nested functions are separate scopes), so they're extracted explicitly. */
|
|
273
|
+
private findPiniaSetupFn;
|
|
274
|
+
/** Extract a Pinia setup store's actions: the body-local `const foo = () => …`
|
|
275
|
+
* / `function foo(){}` declarations, named by the binding. (State refs and other
|
|
276
|
+
* consts are left to the normal value-extraction; only the functions matter as
|
|
277
|
+
* the store's callable surface.) */
|
|
278
|
+
private extractPiniaSetupBody;
|
|
160
279
|
/**
|
|
161
280
|
* Extract a variable declaration (const, let, var, etc.)
|
|
162
281
|
*
|
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`
|
|
21
|
-
*
|
|
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
|
|
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
|
|
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.
|
|
23
|
-
*
|
|
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. */
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { DaemonRecord, StopResult } from './daemon-registry';
|
|
2
|
+
/** Sentinel option values (not real roots, so they can't collide with a project path). */
|
|
3
|
+
export declare const STOP_ALL = "__stop_all__";
|
|
4
|
+
export declare const CANCEL = "__cancel__";
|
|
5
|
+
export interface PickItem {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
hint?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Compact uptime: `45s`, `12m`, `3h 5m`. */
|
|
11
|
+
export declare function formatUptime(ms: number): string;
|
|
12
|
+
/**
|
|
13
|
+
* Build the ordered, UI-ready option list: the current project's daemon first
|
|
14
|
+
* (so it's the auto-selected default), the rest newest-first, then "Stop all"
|
|
15
|
+
* (only when there's more than one) and "Cancel".
|
|
16
|
+
*/
|
|
17
|
+
export declare function buildPickItems(daemons: DaemonRecord[], cwdRoot: string | null, now: number): PickItem[];
|
|
18
|
+
export interface PickerDeps {
|
|
19
|
+
list: () => DaemonRecord[];
|
|
20
|
+
stop: (root: string) => Promise<StopResult>;
|
|
21
|
+
stopAll: () => Promise<StopResult[]>;
|
|
22
|
+
/** Realpath'd root of the current project's daemon, or null. */
|
|
23
|
+
cwdRoot: string | null;
|
|
24
|
+
now: () => number;
|
|
25
|
+
/** Render the picker; returns the chosen value or a cancel sentinel. */
|
|
26
|
+
select: (opts: {
|
|
27
|
+
message: string;
|
|
28
|
+
options: PickItem[];
|
|
29
|
+
initialValue: string;
|
|
30
|
+
}) => Promise<unknown>;
|
|
31
|
+
isCancel: (v: unknown) => boolean;
|
|
32
|
+
/** Per-action note (e.g. "Stopped daemon …"). */
|
|
33
|
+
note: (msg: string) => void;
|
|
34
|
+
/** Final line + teardown (clack outro). */
|
|
35
|
+
done: (msg: string) => void;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Pick a daemon → stop it → re-prompt with what's left, until the user cancels
|
|
39
|
+
* (Esc / Ctrl-C / "Cancel"), picks "Stop all", or nothing remains.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runDaemonPicker(deps: PickerDeps): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=daemon-manager.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface DaemonRecord {
|
|
2
|
+
/** Realpath'd project root the daemon serves. */
|
|
3
|
+
root: string;
|
|
4
|
+
pid: number;
|
|
5
|
+
version: string;
|
|
6
|
+
socketPath: string;
|
|
7
|
+
/** Epoch ms when the daemon bound its socket. */
|
|
8
|
+
startedAt: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `~/.codegraph/daemons` — GLOBAL, keyed off the home install dir. (The
|
|
12
|
+
* `CODEGRAPH_DIR` env var only renames the per-project index dir, not this.)
|
|
13
|
+
*/
|
|
14
|
+
export declare function getRegistryDir(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Is `pid` a live process? `kill(pid, 0)` sends no signal — it just probes:
|
|
17
|
+
* ESRCH ⇒ dead, EPERM ⇒ alive but not ours (still alive). Same liveness check
|
|
18
|
+
* the PPID watchdog (#277) and daemon lock arbitration use.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isProcessAlive(pid: number): boolean;
|
|
21
|
+
/** Best-effort: record this daemon so `list`/`stop --all` can find it. */
|
|
22
|
+
export declare function registerDaemon(rec: DaemonRecord): void;
|
|
23
|
+
/** Best-effort: drop this daemon's record on graceful shutdown. */
|
|
24
|
+
export declare function deregisterDaemon(root: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* All registered daemons whose process is still alive, newest first. Dead/garbage
|
|
27
|
+
* records are deleted as a side effect (self-healing) unless `prune` is false.
|
|
28
|
+
*/
|
|
29
|
+
export declare function listDaemons(opts?: {
|
|
30
|
+
prune?: boolean;
|
|
31
|
+
}): DaemonRecord[];
|
|
32
|
+
export interface StopResult {
|
|
33
|
+
root: string;
|
|
34
|
+
pid: number | null;
|
|
35
|
+
/** 'term' graceful, 'kill' force, 'not-running' stale lock, 'no-daemon' none found. */
|
|
36
|
+
outcome: 'term' | 'kill' | 'not-running' | 'no-daemon';
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Stop the daemon serving `root`: SIGTERM, wait, then SIGKILL if it won't go,
|
|
40
|
+
* then sweep its artifacts. `root` must be realpath'd (match how the daemon
|
|
41
|
+
* keys its socket/lockfile). Resolves the pid from the authoritative lockfile,
|
|
42
|
+
* falling back to the registry.
|
|
43
|
+
*/
|
|
44
|
+
export declare function stopDaemonAt(root: string): Promise<StopResult>;
|
|
45
|
+
/** Stop every registered, live daemon. */
|
|
46
|
+
export declare function stopAllDaemons(): Promise<StopResult[]>;
|
|
47
|
+
//# sourceMappingURL=daemon-registry.d.ts.map
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Default: 60s — ~300× shorter than the 5h #850 wedge, far longer than any real main-thread block. */
|
|
2
|
+
export declare const DEFAULT_WATCHDOG_TIMEOUT_MS = 60000;
|
|
3
|
+
/** Parse the timeout env, falling back to the default for missing/invalid values. */
|
|
4
|
+
export declare function parseWatchdogTimeoutMs(raw: string | undefined, fallback?: number): number;
|
|
5
|
+
/** Derive a heartbeat cadence that emits several beats inside the timeout window. */
|
|
6
|
+
export declare function deriveCheckIntervalMs(timeoutMs: number): number;
|
|
7
|
+
export interface WatchdogHandle {
|
|
8
|
+
/** Stop heartbeating and shut the watchdog child down. Idempotent. */
|
|
9
|
+
stop(): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Install the main-thread liveness watchdog for a long-lived process. Returns a
|
|
13
|
+
* handle to stop it, or `null` when disabled or when the child can't be spawned
|
|
14
|
+
* (degraded, never throws — a missing watchdog must never keep a process from
|
|
15
|
+
* starting).
|
|
16
|
+
*/
|
|
17
|
+
export declare function installMainThreadWatchdog(): WatchdogHandle | null;
|
|
18
|
+
//# sourceMappingURL=liveness-watchdog.d.ts.map
|
|
@@ -7,24 +7,28 @@
|
|
|
7
7
|
* before it sees individual tool descriptions.
|
|
8
8
|
*
|
|
9
9
|
* Goals when editing this:
|
|
10
|
-
* -
|
|
11
|
-
* -
|
|
12
|
-
* - Anti-patterns (don't grep
|
|
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.
|
|
16
|
-
*
|
|
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##
|
|
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
|
|
22
|
+
* Instructions variant sent when the server's own root has NO codegraph index.
|
|
21
23
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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
|
|
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
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -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 (
|
|
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,19 @@
|
|
|
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
|
+
/**
|
|
9
|
+
* Load the validated extension overrides for a project, mtime-cached.
|
|
10
|
+
*
|
|
11
|
+
* Returns a map of `.ext` → supported language id. The result merges on top of
|
|
12
|
+
* the built-in extension map at the point of use (see `detectLanguage` /
|
|
13
|
+
* `isSourceFile`), with these user mappings taking precedence. Returns an empty
|
|
14
|
+
* map when there is no `codegraph.json` (the zero-config default).
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadExtensionOverrides(rootDir: string): Record<string, Language>;
|
|
17
|
+
/** Test/maintenance hook: forget cached config (e.g. after rewriting it in a test). */
|
|
18
|
+
export declare function clearProjectConfigCache(): void;
|
|
19
|
+
//# sourceMappingURL=project-config.d.ts.map
|