@huanlin/dsh-plugin-codegraph-service 0.1.8
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/LICENSE +21 -0
- package/README.md +17 -0
- package/lib/brand.d.ts +41 -0
- package/lib/brand.js +36 -0
- package/lib/index.d.ts +86 -0
- package/lib/index.js +214 -0
- package/lib/invariant.d.ts +16 -0
- package/lib/invariant.js +22 -0
- package/lib/types.d.ts +449 -0
- package/lib/types.js +16 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CC ZHAO
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @huanlin/dsh-plugin-codegraph-service
|
|
2
|
+
|
|
3
|
+
Service Definition for the code-graph capability seam: publishes `ctx.codegraph`, the store and indexer provider registries, and the eight normalized structural queries. Carries no store, no indexer, and no filesystem access of its own.
|
|
4
|
+
|
|
5
|
+
Part of **[dsh-plugin-codegraph](https://github.com/CC19990113/dsh-plugin-codegraph)** — structural code intelligence for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).
|
|
6
|
+
|
|
7
|
+
Most users should install the bundle instead, which mounts this package and its siblings in one layer:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
dsh plugin --profile <name> add dsh-plugin-codegraph
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
See the [project README](https://github.com/CC19990113/dsh-plugin-codegraph#readme) for setup, configuration, and the full tool reference.
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
[MIT](LICENSE)
|
package/lib/brand.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-codegraph's owned branded ids: {@link CodegraphNodeId}, the opaque symbol identity carried by
|
|
3
|
+
* every graph node and edge endpoint; {@link CodegraphStoreId}, the identity a store provider
|
|
4
|
+
* reserves on `ctx.codegraph`; and {@link CodegraphIndexerId}, the identity an indexer provider
|
|
5
|
+
* reserves. The `Branded<B>` primitive lives in `@deepseek-ai/dsh-brand`; keeping each type with its
|
|
6
|
+
* factory here lets `index.ts` re-export all three under one name.
|
|
7
|
+
* @module @huanlin/dsh-plugin-codegraph-service/brand
|
|
8
|
+
*/
|
|
9
|
+
import type { Branded } from '@deepseek-ai/dsh-brand';
|
|
10
|
+
/**
|
|
11
|
+
* Opaque identity of one graph node. The store assigns it; callers pass it back verbatim to follow
|
|
12
|
+
* an edge. Its derivation (a hash of file path and qualified name in the reference format) is a
|
|
13
|
+
* store-private detail no consumer may reconstruct or parse.
|
|
14
|
+
*/
|
|
15
|
+
export type CodegraphNodeId = Branded<'CodegraphNodeId'>;
|
|
16
|
+
/**
|
|
17
|
+
* Brand a string as a {@link CodegraphNodeId}. No validation — a node id is only ever minted by the
|
|
18
|
+
* store that owns the graph it indexes.
|
|
19
|
+
* @param id - the store-assigned node identity.
|
|
20
|
+
* @returns the same string, branded.
|
|
21
|
+
*/
|
|
22
|
+
export declare function CodegraphNodeId(id: string): CodegraphNodeId;
|
|
23
|
+
/** Opaque store-provider identity, reserved at registration and released by the disposer. */
|
|
24
|
+
export type CodegraphStoreId = Branded<'CodegraphStoreId'>;
|
|
25
|
+
/**
|
|
26
|
+
* Brand a string as a {@link CodegraphStoreId}. No validation — the registry rejects an empty id at
|
|
27
|
+
* registration.
|
|
28
|
+
* @param id - the provider's stable identifier.
|
|
29
|
+
* @returns the same string, branded.
|
|
30
|
+
*/
|
|
31
|
+
export declare function CodegraphStoreId(id: string): CodegraphStoreId;
|
|
32
|
+
/** Opaque indexer-provider identity, reserved at registration and released by the disposer. */
|
|
33
|
+
export type CodegraphIndexerId = Branded<'CodegraphIndexerId'>;
|
|
34
|
+
/**
|
|
35
|
+
* Brand a string as a {@link CodegraphIndexerId}. No validation — the registry rejects an empty id at
|
|
36
|
+
* registration.
|
|
37
|
+
* @param id - the provider's stable identifier.
|
|
38
|
+
* @returns the same string, branded.
|
|
39
|
+
*/
|
|
40
|
+
export declare function CodegraphIndexerId(id: string): CodegraphIndexerId;
|
|
41
|
+
//# sourceMappingURL=brand.d.ts.map
|
package/lib/brand.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dsh-codegraph's owned branded ids: {@link CodegraphNodeId}, the opaque symbol identity carried by
|
|
3
|
+
* every graph node and edge endpoint; {@link CodegraphStoreId}, the identity a store provider
|
|
4
|
+
* reserves on `ctx.codegraph`; and {@link CodegraphIndexerId}, the identity an indexer provider
|
|
5
|
+
* reserves. The `Branded<B>` primitive lives in `@deepseek-ai/dsh-brand`; keeping each type with its
|
|
6
|
+
* factory here lets `index.ts` re-export all three under one name.
|
|
7
|
+
* @module @huanlin/dsh-plugin-codegraph-service/brand
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Brand a string as a {@link CodegraphNodeId}. No validation — a node id is only ever minted by the
|
|
11
|
+
* store that owns the graph it indexes.
|
|
12
|
+
* @param id - the store-assigned node identity.
|
|
13
|
+
* @returns the same string, branded.
|
|
14
|
+
*/
|
|
15
|
+
export function CodegraphNodeId(id) {
|
|
16
|
+
return id;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Brand a string as a {@link CodegraphStoreId}. No validation — the registry rejects an empty id at
|
|
20
|
+
* registration.
|
|
21
|
+
* @param id - the provider's stable identifier.
|
|
22
|
+
* @returns the same string, branded.
|
|
23
|
+
*/
|
|
24
|
+
export function CodegraphStoreId(id) {
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Brand a string as a {@link CodegraphIndexerId}. No validation — the registry rejects an empty id at
|
|
29
|
+
* registration.
|
|
30
|
+
* @param id - the provider's stable identifier.
|
|
31
|
+
* @returns the same string, branded.
|
|
32
|
+
*/
|
|
33
|
+
export function CodegraphIndexerId(id) {
|
|
34
|
+
return id;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=brand.js.map
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Definition for the code-graph capability seam (`ctx.codegraph`): a graph-store provider
|
|
3
|
+
* registry and per-query, order-independent selection over eight normalized graph queries —
|
|
4
|
+
* search, node, callers, callees, impact, trace, files, and status — plus a separate graph-indexer
|
|
5
|
+
* provider registry that builds or refreshes a graph on explicit request.
|
|
6
|
+
*
|
|
7
|
+
* A store reserves a branded id at registration and declares which project roots it can serve
|
|
8
|
+
* through {@link CodegraphStoreProvider.indexes}. Selection asks every registered store per query
|
|
9
|
+
* and requires exactly one claimant, so registration and hot-reload order never change routing;
|
|
10
|
+
* zero claimants and several claimants are both loud failures rather than a silent pick. The seam
|
|
11
|
+
* carries no source text and performs no filesystem access: retrieving a declaration's code composes
|
|
12
|
+
* a graph query with a `ctx.fs` read in the consumer, which is the only role that can reach a remote
|
|
13
|
+
* workspace's files.
|
|
14
|
+
*
|
|
15
|
+
* An indexer follows the same one-claimant reservation rule, but {@link CodegraphService.index} is
|
|
16
|
+
* never called from {@link CodegraphService.query}: indexing is a caller-initiated, potentially
|
|
17
|
+
* multi-minute operation, and `query` stays read-only so a store never hides a build behind a call the
|
|
18
|
+
* model expects to return quickly.
|
|
19
|
+
* @module @huanlin/dsh-plugin-codegraph-service
|
|
20
|
+
*/
|
|
21
|
+
import { Context, Service } from '@deepseek-ai/cordis';
|
|
22
|
+
import { HarnessError } from '@deepseek-ai/dsh-llm';
|
|
23
|
+
import type { CodegraphIndexer, CodegraphIndexReport, CodegraphRequest, CodegraphResultFor, CodegraphService, CodegraphStoreProvider } from './types.ts';
|
|
24
|
+
export { CodegraphIndexerId, CodegraphNodeId, CodegraphStoreId } from './brand.ts';
|
|
25
|
+
export type { CodegraphCalleesRequest, CodegraphCallersRequest, CodegraphEdge, CodegraphFile, CodegraphFilesRequest, CodegraphFilesResult, CodegraphImpactEntry, CodegraphImpactRequest, CodegraphImpactResult, CodegraphIndexer, CodegraphIndexReport, CodegraphNode, CodegraphNodeRequest, CodegraphNodeResult, CodegraphOperation, CodegraphRelation, CodegraphRelationsResult, CodegraphRequest, CodegraphRequestBase, CodegraphResult, CodegraphResultFor, CodegraphSearchRequest, CodegraphSearchResult, CodegraphService, CodegraphStatusRequest, CodegraphStatusResult, CodegraphStoreProvider, CodegraphTraceHop, CodegraphTraceRequest, CodegraphTraceResult, } from './types.ts';
|
|
26
|
+
declare module '@deepseek-ai/cordis' {
|
|
27
|
+
interface Context {
|
|
28
|
+
codegraph: CodegraphService;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Structured code-graph failure. Extends {@link HarnessError} with a stable `code`
|
|
33
|
+
* (`CODEGRAPH_INVALID_PROVIDER`, `CODEGRAPH_CONFLICT`, `CODEGRAPH_UNAVAILABLE`,
|
|
34
|
+
* `CODEGRAPH_UNSUPPORTED_FORMAT`, `CODEGRAPH_MALFORMED_INDEX`, `CODEGRAPH_DISPOSED`,
|
|
35
|
+
* `CODEGRAPH_NO_INDEXER`, …) that callers route on instead of parsing `message`.
|
|
36
|
+
*/
|
|
37
|
+
export declare class CodegraphError extends HarnessError {
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The declaration categories the on-disk graph format defines. A store may return a kind absent from
|
|
41
|
+
* this list when a newer indexer wrote the graph; consumers treat `kind` as data and use this array
|
|
42
|
+
* only to describe or filter the known vocabulary.
|
|
43
|
+
*/
|
|
44
|
+
export declare const NODE_KINDS: readonly ["file", "module", "class", "struct", "interface", "trait", "protocol", "function", "method", "property", "field", "variable", "constant", "enum", "enum_member", "type_alias", "namespace", "parameter", "import", "export", "route", "component"];
|
|
45
|
+
/**
|
|
46
|
+
* The relationship categories the on-disk graph format defines. Open for the same reason as
|
|
47
|
+
* {@link NODE_KINDS}.
|
|
48
|
+
*/
|
|
49
|
+
export declare const EDGE_KINDS: readonly ["contains", "calls", "imports", "exports", "extends", "implements", "references", "type_of", "returns", "instantiates", "overrides", "decorates"];
|
|
50
|
+
/**
|
|
51
|
+
* The source languages the on-disk graph format labels files with. Open for the same reason as
|
|
52
|
+
* {@link NODE_KINDS}.
|
|
53
|
+
*/
|
|
54
|
+
export declare const LANGUAGES: readonly ["typescript", "javascript", "tsx", "jsx", "python", "go", "rust", "java", "c", "cpp", "csharp", "php", "ruby", "swift", "kotlin", "dart", "svelte", "vue", "liquid", "pascal", "scala", "lua", "luau", "objc", "yaml", "twig", "xml", "properties", "unknown"];
|
|
55
|
+
/**
|
|
56
|
+
* `ctx.codegraph`. Holds the store reservations; selection reads them per query so a store that
|
|
57
|
+
* unloads mid-session stops serving without leaving a stale route behind.
|
|
58
|
+
*/
|
|
59
|
+
export declare class Codegraph extends Service implements CodegraphService {
|
|
60
|
+
private readonly stores;
|
|
61
|
+
private readonly indexers;
|
|
62
|
+
constructor(ctx: Context);
|
|
63
|
+
registerStore(provider: CodegraphStoreProvider): () => void;
|
|
64
|
+
registerIndexer(provider: CodegraphIndexer): () => void;
|
|
65
|
+
available(projectRoot: string, signal?: AbortSignal): Promise<boolean>;
|
|
66
|
+
index(projectRoot: string, signal?: AbortSignal): Promise<CodegraphIndexReport>;
|
|
67
|
+
query<R extends CodegraphRequest>(request: R, signal?: AbortSignal): Promise<CodegraphResultFor<R>>;
|
|
68
|
+
/**
|
|
69
|
+
* The one store that indexes `projectRoot`. Every registered store is asked concurrently, so the
|
|
70
|
+
* answer does not depend on registration order; zero and several claimants both throw.
|
|
71
|
+
* @param projectRoot - absolute path of the project root to route to.
|
|
72
|
+
* @param signal - aborts the availability checks.
|
|
73
|
+
* @returns the single claiming store.
|
|
74
|
+
*/
|
|
75
|
+
private select;
|
|
76
|
+
/**
|
|
77
|
+
* The one indexer that claims `projectRoot`. Every registered indexer is asked concurrently, so the
|
|
78
|
+
* answer does not depend on registration order; zero and several claimants both throw.
|
|
79
|
+
* @param projectRoot - absolute path of the project root to index.
|
|
80
|
+
* @param signal - aborts the availability checks.
|
|
81
|
+
* @returns the single claiming indexer.
|
|
82
|
+
*/
|
|
83
|
+
private selectIndexer;
|
|
84
|
+
}
|
|
85
|
+
export default Codegraph;
|
|
86
|
+
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Service Definition for the code-graph capability seam (`ctx.codegraph`): a graph-store provider
|
|
3
|
+
* registry and per-query, order-independent selection over eight normalized graph queries —
|
|
4
|
+
* search, node, callers, callees, impact, trace, files, and status — plus a separate graph-indexer
|
|
5
|
+
* provider registry that builds or refreshes a graph on explicit request.
|
|
6
|
+
*
|
|
7
|
+
* A store reserves a branded id at registration and declares which project roots it can serve
|
|
8
|
+
* through {@link CodegraphStoreProvider.indexes}. Selection asks every registered store per query
|
|
9
|
+
* and requires exactly one claimant, so registration and hot-reload order never change routing;
|
|
10
|
+
* zero claimants and several claimants are both loud failures rather than a silent pick. The seam
|
|
11
|
+
* carries no source text and performs no filesystem access: retrieving a declaration's code composes
|
|
12
|
+
* a graph query with a `ctx.fs` read in the consumer, which is the only role that can reach a remote
|
|
13
|
+
* workspace's files.
|
|
14
|
+
*
|
|
15
|
+
* An indexer follows the same one-claimant reservation rule, but {@link CodegraphService.index} is
|
|
16
|
+
* never called from {@link CodegraphService.query}: indexing is a caller-initiated, potentially
|
|
17
|
+
* multi-minute operation, and `query` stays read-only so a store never hides a build behind a call the
|
|
18
|
+
* model expects to return quickly.
|
|
19
|
+
* @module @huanlin/dsh-plugin-codegraph-service
|
|
20
|
+
*/
|
|
21
|
+
import { Service } from '@deepseek-ai/cordis';
|
|
22
|
+
import { HarnessError } from '@deepseek-ai/dsh-llm';
|
|
23
|
+
export { CodegraphIndexerId, CodegraphNodeId, CodegraphStoreId } from "./brand.js";
|
|
24
|
+
/**
|
|
25
|
+
* Structured code-graph failure. Extends {@link HarnessError} with a stable `code`
|
|
26
|
+
* (`CODEGRAPH_INVALID_PROVIDER`, `CODEGRAPH_CONFLICT`, `CODEGRAPH_UNAVAILABLE`,
|
|
27
|
+
* `CODEGRAPH_UNSUPPORTED_FORMAT`, `CODEGRAPH_MALFORMED_INDEX`, `CODEGRAPH_DISPOSED`,
|
|
28
|
+
* `CODEGRAPH_NO_INDEXER`, …) that callers route on instead of parsing `message`.
|
|
29
|
+
*/
|
|
30
|
+
export class CodegraphError extends HarnessError {
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The declaration categories the on-disk graph format defines. A store may return a kind absent from
|
|
34
|
+
* this list when a newer indexer wrote the graph; consumers treat `kind` as data and use this array
|
|
35
|
+
* only to describe or filter the known vocabulary.
|
|
36
|
+
*/
|
|
37
|
+
export const NODE_KINDS = [
|
|
38
|
+
'file',
|
|
39
|
+
'module',
|
|
40
|
+
'class',
|
|
41
|
+
'struct',
|
|
42
|
+
'interface',
|
|
43
|
+
'trait',
|
|
44
|
+
'protocol',
|
|
45
|
+
'function',
|
|
46
|
+
'method',
|
|
47
|
+
'property',
|
|
48
|
+
'field',
|
|
49
|
+
'variable',
|
|
50
|
+
'constant',
|
|
51
|
+
'enum',
|
|
52
|
+
'enum_member',
|
|
53
|
+
'type_alias',
|
|
54
|
+
'namespace',
|
|
55
|
+
'parameter',
|
|
56
|
+
'import',
|
|
57
|
+
'export',
|
|
58
|
+
'route',
|
|
59
|
+
'component',
|
|
60
|
+
];
|
|
61
|
+
/**
|
|
62
|
+
* The relationship categories the on-disk graph format defines. Open for the same reason as
|
|
63
|
+
* {@link NODE_KINDS}.
|
|
64
|
+
*/
|
|
65
|
+
export const EDGE_KINDS = [
|
|
66
|
+
'contains',
|
|
67
|
+
'calls',
|
|
68
|
+
'imports',
|
|
69
|
+
'exports',
|
|
70
|
+
'extends',
|
|
71
|
+
'implements',
|
|
72
|
+
'references',
|
|
73
|
+
'type_of',
|
|
74
|
+
'returns',
|
|
75
|
+
'instantiates',
|
|
76
|
+
'overrides',
|
|
77
|
+
'decorates',
|
|
78
|
+
];
|
|
79
|
+
/**
|
|
80
|
+
* The source languages the on-disk graph format labels files with. Open for the same reason as
|
|
81
|
+
* {@link NODE_KINDS}.
|
|
82
|
+
*/
|
|
83
|
+
export const LANGUAGES = [
|
|
84
|
+
'typescript',
|
|
85
|
+
'javascript',
|
|
86
|
+
'tsx',
|
|
87
|
+
'jsx',
|
|
88
|
+
'python',
|
|
89
|
+
'go',
|
|
90
|
+
'rust',
|
|
91
|
+
'java',
|
|
92
|
+
'c',
|
|
93
|
+
'cpp',
|
|
94
|
+
'csharp',
|
|
95
|
+
'php',
|
|
96
|
+
'ruby',
|
|
97
|
+
'swift',
|
|
98
|
+
'kotlin',
|
|
99
|
+
'dart',
|
|
100
|
+
'svelte',
|
|
101
|
+
'vue',
|
|
102
|
+
'liquid',
|
|
103
|
+
'pascal',
|
|
104
|
+
'scala',
|
|
105
|
+
'lua',
|
|
106
|
+
'luau',
|
|
107
|
+
'objc',
|
|
108
|
+
'yaml',
|
|
109
|
+
'twig',
|
|
110
|
+
'xml',
|
|
111
|
+
'properties',
|
|
112
|
+
'unknown',
|
|
113
|
+
];
|
|
114
|
+
/**
|
|
115
|
+
* `ctx.codegraph`. Holds the store reservations; selection reads them per query so a store that
|
|
116
|
+
* unloads mid-session stops serving without leaving a stale route behind.
|
|
117
|
+
*/
|
|
118
|
+
export class Codegraph extends Service {
|
|
119
|
+
stores = new Map();
|
|
120
|
+
indexers = new Map();
|
|
121
|
+
constructor(ctx) {
|
|
122
|
+
super(ctx, 'codegraph');
|
|
123
|
+
}
|
|
124
|
+
registerStore(provider) {
|
|
125
|
+
const id = provider.id;
|
|
126
|
+
if (id.trim() === '') {
|
|
127
|
+
throw new CodegraphError('a code-graph store id must be a non-empty string', 'CODEGRAPH_INVALID_PROVIDER');
|
|
128
|
+
}
|
|
129
|
+
if (this.stores.has(id)) {
|
|
130
|
+
throw new CodegraphError(`a code-graph store with id "${id}" is already registered`, 'CODEGRAPH_CONFLICT');
|
|
131
|
+
}
|
|
132
|
+
const dispose = this.ctx.effect(function* () {
|
|
133
|
+
this.stores.set(id, provider);
|
|
134
|
+
yield () => {
|
|
135
|
+
this.stores.delete(id);
|
|
136
|
+
};
|
|
137
|
+
}.bind(this), 'codegraph.registerStore()');
|
|
138
|
+
// ctx.effect's disposer returns Promise<void>; our disposer API is synchronous
|
|
139
|
+
// fire-and-forget — discard the (always-resolved) promise.
|
|
140
|
+
return () => void dispose();
|
|
141
|
+
}
|
|
142
|
+
registerIndexer(provider) {
|
|
143
|
+
const id = provider.id;
|
|
144
|
+
if (id.trim() === '') {
|
|
145
|
+
throw new CodegraphError('a code-graph indexer id must be a non-empty string', 'CODEGRAPH_INVALID_PROVIDER');
|
|
146
|
+
}
|
|
147
|
+
if (this.indexers.has(id)) {
|
|
148
|
+
throw new CodegraphError(`a code-graph indexer with id "${id}" is already registered`, 'CODEGRAPH_CONFLICT');
|
|
149
|
+
}
|
|
150
|
+
const dispose = this.ctx.effect(function* () {
|
|
151
|
+
this.indexers.set(id, provider);
|
|
152
|
+
yield () => {
|
|
153
|
+
this.indexers.delete(id);
|
|
154
|
+
};
|
|
155
|
+
}.bind(this), 'codegraph.registerIndexer()');
|
|
156
|
+
return () => void dispose();
|
|
157
|
+
}
|
|
158
|
+
async available(projectRoot, signal) {
|
|
159
|
+
const candidates = [...this.stores.values()];
|
|
160
|
+
const claims = await Promise.all(candidates.map(store => store.indexes(projectRoot, signal)));
|
|
161
|
+
return claims.some(Boolean);
|
|
162
|
+
}
|
|
163
|
+
async index(projectRoot, signal) {
|
|
164
|
+
const indexer = await this.selectIndexer(projectRoot, signal);
|
|
165
|
+
return indexer.index(projectRoot, signal);
|
|
166
|
+
}
|
|
167
|
+
async query(request, signal) {
|
|
168
|
+
return (await this.select(request.projectRoot, signal)).query(request, signal);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The one store that indexes `projectRoot`. Every registered store is asked concurrently, so the
|
|
172
|
+
* answer does not depend on registration order; zero and several claimants both throw.
|
|
173
|
+
* @param projectRoot - absolute path of the project root to route to.
|
|
174
|
+
* @param signal - aborts the availability checks.
|
|
175
|
+
* @returns the single claiming store.
|
|
176
|
+
*/
|
|
177
|
+
async select(projectRoot, signal) {
|
|
178
|
+
const candidates = [...this.stores.values()];
|
|
179
|
+
const claims = await Promise.all(candidates.map(store => store.indexes(projectRoot, signal)));
|
|
180
|
+
const claimants = candidates.filter((_, index) => claims[index]);
|
|
181
|
+
const [only, rival] = claimants;
|
|
182
|
+
if (only === undefined) {
|
|
183
|
+
throw new CodegraphError(`no code-graph store indexes "${projectRoot}"`, 'CODEGRAPH_UNAVAILABLE');
|
|
184
|
+
}
|
|
185
|
+
if (rival !== undefined) {
|
|
186
|
+
const ids = claimants.map(store => store.id).join(', ');
|
|
187
|
+
throw new CodegraphError(`several code-graph stores index "${projectRoot}": ${ids}`, 'CODEGRAPH_CONFLICT');
|
|
188
|
+
}
|
|
189
|
+
return only;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The one indexer that claims `projectRoot`. Every registered indexer is asked concurrently, so the
|
|
193
|
+
* answer does not depend on registration order; zero and several claimants both throw.
|
|
194
|
+
* @param projectRoot - absolute path of the project root to index.
|
|
195
|
+
* @param signal - aborts the availability checks.
|
|
196
|
+
* @returns the single claiming indexer.
|
|
197
|
+
*/
|
|
198
|
+
async selectIndexer(projectRoot, signal) {
|
|
199
|
+
const candidates = [...this.indexers.values()];
|
|
200
|
+
const claims = await Promise.all(candidates.map(indexer => indexer.canIndex(projectRoot, signal)));
|
|
201
|
+
const claimants = candidates.filter((_, index) => claims[index]);
|
|
202
|
+
const [only, rival] = claimants;
|
|
203
|
+
if (only === undefined) {
|
|
204
|
+
throw new CodegraphError(`no code-graph indexer can index "${projectRoot}"`, 'CODEGRAPH_NO_INDEXER');
|
|
205
|
+
}
|
|
206
|
+
if (rival !== undefined) {
|
|
207
|
+
const ids = claimants.map(indexer => indexer.id).join(', ');
|
|
208
|
+
throw new CodegraphError(`several code-graph indexers can index "${projectRoot}": ${ids}`, 'CODEGRAPH_CONFLICT');
|
|
209
|
+
}
|
|
210
|
+
return only;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
export default Codegraph;
|
|
214
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `dsh-plugin-codegraph-service`.
|
|
3
|
+
* @module dsh-plugin-codegraph-service/invariant
|
|
4
|
+
*/
|
|
5
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export declare const name = "codegraph-invariant";
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export declare const inject: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Register this package's invariant companion.
|
|
12
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
13
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
14
|
+
*/
|
|
15
|
+
export declare const apply: (ctx: Context) => Promise<() => void>;
|
|
16
|
+
//# sourceMappingURL=invariant.d.ts.map
|
package/lib/invariant.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package-owned invariant companion for `dsh-plugin-codegraph-service`.
|
|
3
|
+
* @module dsh-plugin-codegraph-service/invariant
|
|
4
|
+
*/
|
|
5
|
+
const PACKAGE_NAME = 'dsh-plugin-codegraph-service';
|
|
6
|
+
/** Cordis companion plugin name. */
|
|
7
|
+
export const name = 'codegraph-invariant';
|
|
8
|
+
/** Service required before the companion can reserve package ownership. */
|
|
9
|
+
export const inject = ['invariants'];
|
|
10
|
+
/**
|
|
11
|
+
* No runtime invariant: store reservations are private state resolved per query, and the seam emits
|
|
12
|
+
* no lifecycle event and exposes no enumerable snapshot to compare an owned relation against.
|
|
13
|
+
*/
|
|
14
|
+
const install = () => { };
|
|
15
|
+
/**
|
|
16
|
+
* Register this package's invariant companion.
|
|
17
|
+
* @param ctx - Cordis context carrying the invariant service.
|
|
18
|
+
* @returns the installed registration's disposer after setup succeeds.
|
|
19
|
+
*/
|
|
20
|
+
export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
21
|
+
/* jscpd:ignore-end */
|
|
22
|
+
//# sourceMappingURL=invariant.js.map
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegraph seam vocabulary: the graph records, the normalized request and result unions, and the
|
|
3
|
+
* store-provider contract. Types only — the {@link CodegraphError} taxonomy, the branded-id
|
|
4
|
+
* factories, and the `NODE_KINDS` / `EDGE_KINDS` / `LANGUAGES` vocabulary arrays are runtime and
|
|
5
|
+
* live in `index.ts`.
|
|
6
|
+
*
|
|
7
|
+
* Line numbers are one-based and column numbers zero-based, matching the on-disk graph the reference
|
|
8
|
+
* indexer writes; the model-facing tool owns any other display convention. `kind` and `language` are
|
|
9
|
+
* plain strings rather than closed unions because the graph is read from a durable file written by
|
|
10
|
+
* an independently versioned indexer: a record whose kind this build does not know must still reach
|
|
11
|
+
* the model as data, not fail the query. `NODE_KINDS`, `EDGE_KINDS`, and `LANGUAGES` document the
|
|
12
|
+
* values that format defines today.
|
|
13
|
+
* @module @huanlin/dsh-plugin-codegraph-service/types
|
|
14
|
+
*/
|
|
15
|
+
import type { CodegraphIndexerId, CodegraphNodeId, CodegraphStoreId } from './brand.ts';
|
|
16
|
+
/**
|
|
17
|
+
* One symbol in the graph: a declaration site with its position, modifiers, and documentation. Every
|
|
18
|
+
* field except the optional ones is present for every node the store returns; a store normalizes a
|
|
19
|
+
* missing durable value to the empty array or `false` rather than surfacing null.
|
|
20
|
+
*/
|
|
21
|
+
export interface CodegraphNode {
|
|
22
|
+
/** Opaque store-assigned identity; pass it back verbatim to follow an edge. */
|
|
23
|
+
readonly id: CodegraphNodeId;
|
|
24
|
+
/** Declaration category, e.g. `function`, `class`, `interface`. See `NODE_KINDS`. */
|
|
25
|
+
readonly kind: string;
|
|
26
|
+
/** Simple declared name, e.g. `calculateTotal`. */
|
|
27
|
+
readonly name: string;
|
|
28
|
+
/** Disambiguated name including its container, e.g. `src/utils.ts::MathHelper.calculateTotal`. */
|
|
29
|
+
readonly qualifiedName: string;
|
|
30
|
+
/** Declaring file, relative to the project root the store indexed. */
|
|
31
|
+
readonly filePath: string;
|
|
32
|
+
/** Source language of the declaring file. See `LANGUAGES`. */
|
|
33
|
+
readonly language: string;
|
|
34
|
+
/** One-based first line of the declaration. */
|
|
35
|
+
readonly startLine: number;
|
|
36
|
+
/** One-based last line of the declaration. */
|
|
37
|
+
readonly endLine: number;
|
|
38
|
+
/** Zero-based column the declaration starts at. */
|
|
39
|
+
readonly startColumn: number;
|
|
40
|
+
/** Zero-based column the declaration ends at. */
|
|
41
|
+
readonly endColumn: number;
|
|
42
|
+
/** Attached documentation comment, when the indexer captured one. */
|
|
43
|
+
readonly docstring?: string;
|
|
44
|
+
/** Declared signature, when the indexer captured one. */
|
|
45
|
+
readonly signature?: string;
|
|
46
|
+
/** Declared visibility, when the language expresses one (`public`, `private`, …). */
|
|
47
|
+
readonly visibility?: string;
|
|
48
|
+
/** Whether the declaration is exported from its module. */
|
|
49
|
+
readonly isExported: boolean;
|
|
50
|
+
/** Whether the declaration is asynchronous. */
|
|
51
|
+
readonly isAsync: boolean;
|
|
52
|
+
/** Whether the declaration is static. */
|
|
53
|
+
readonly isStatic: boolean;
|
|
54
|
+
/** Whether the declaration is abstract. */
|
|
55
|
+
readonly isAbstract: boolean;
|
|
56
|
+
/** Decorators or annotations applied to the declaration; empty when none. */
|
|
57
|
+
readonly decorators: readonly string[];
|
|
58
|
+
/** Generic type parameters declared on the symbol; empty when none. */
|
|
59
|
+
readonly typeParameters: readonly string[];
|
|
60
|
+
/** Epoch milliseconds when the indexer last wrote this node. */
|
|
61
|
+
readonly updatedAt: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* One directed relationship between two nodes. `line` and `column` locate the relationship's site
|
|
65
|
+
* (the call site for a `calls` edge), which differs from either endpoint's declaration position.
|
|
66
|
+
*/
|
|
67
|
+
export interface CodegraphEdge {
|
|
68
|
+
/** Node the relationship originates from. */
|
|
69
|
+
readonly source: CodegraphNodeId;
|
|
70
|
+
/** Node the relationship points at. */
|
|
71
|
+
readonly target: CodegraphNodeId;
|
|
72
|
+
/** Relationship category, e.g. `calls`, `contains`, `imports`. See `EDGE_KINDS`. */
|
|
73
|
+
readonly kind: string;
|
|
74
|
+
/** One-based line of the relationship's site, when the indexer recorded one. */
|
|
75
|
+
readonly line?: number;
|
|
76
|
+
/** Zero-based column of the relationship's site, when the indexer recorded one. */
|
|
77
|
+
readonly column?: number;
|
|
78
|
+
/** How the indexer derived the edge, e.g. `tree-sitter`, `heuristic`. */
|
|
79
|
+
readonly provenance?: string;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* One related node paired with the edge that reached it. `callers` and `callees` return these so a
|
|
83
|
+
* caller has both the related declaration and a site linking them, without a second query.
|
|
84
|
+
*
|
|
85
|
+
* Relations are DISTINCT per related node and relationship kind: a function that calls another five
|
|
86
|
+
* times is one relation with `siteCount: 5`, not five relations. "Which declarations are involved"
|
|
87
|
+
* is the question these operations answer, and counting sites instead would let one repetitive
|
|
88
|
+
* caller consume the whole result limit while other callers went unreported.
|
|
89
|
+
*/
|
|
90
|
+
export interface CodegraphRelation {
|
|
91
|
+
/** The node at the far end of {@link edge}. */
|
|
92
|
+
readonly node: CodegraphNode;
|
|
93
|
+
/** The earliest-positioned relationship of its kind reaching {@link node}. */
|
|
94
|
+
readonly edge: CodegraphEdge;
|
|
95
|
+
/** How many relationships of this kind connect the two nodes; at least 1. */
|
|
96
|
+
readonly siteCount: number;
|
|
97
|
+
}
|
|
98
|
+
/** One indexed file and the extraction outcome recorded for it. */
|
|
99
|
+
export interface CodegraphFile {
|
|
100
|
+
/** File path relative to the project root. */
|
|
101
|
+
readonly path: string;
|
|
102
|
+
/** Detected source language. See `LANGUAGES`. */
|
|
103
|
+
readonly language: string;
|
|
104
|
+
/** File size in bytes at index time. */
|
|
105
|
+
readonly size: number;
|
|
106
|
+
/** Number of nodes the indexer extracted from the file. */
|
|
107
|
+
readonly nodeCount: number;
|
|
108
|
+
/** Epoch milliseconds of the file's modification time at index time. */
|
|
109
|
+
readonly modifiedAt: number;
|
|
110
|
+
/** Epoch milliseconds when the indexer last processed the file. */
|
|
111
|
+
readonly indexedAt: number;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* One hop of a {@link CodegraphTraceResult} path: the node reached and the edge that reached it. The
|
|
115
|
+
* first hop of every path carries the path's origin node and no edge.
|
|
116
|
+
*/
|
|
117
|
+
export interface CodegraphTraceHop {
|
|
118
|
+
/** The node this hop reaches. */
|
|
119
|
+
readonly node: CodegraphNode;
|
|
120
|
+
/** The edge traversed to reach {@link node}; absent on a path's first hop. */
|
|
121
|
+
readonly edge?: CodegraphEdge;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* The eight primitive graph queries the seam exposes. A closed union: adding an operation is a
|
|
125
|
+
* compile-enforced change across the seam, its stores, and every consumer. Source-text retrieval and
|
|
126
|
+
* task-level aggregation are deliberately absent — they compose these primitives with a filesystem
|
|
127
|
+
* read, which a graph store neither owns nor can perform for a remote workspace.
|
|
128
|
+
*/
|
|
129
|
+
export type CodegraphOperation = 'search' | 'node' | 'callers' | 'callees' | 'impact' | 'trace' | 'files' | 'status';
|
|
130
|
+
/**
|
|
131
|
+
* Fields every request carries. `projectRoot` selects which indexed project the query runs against
|
|
132
|
+
* and is always caller-supplied: a store never falls back to a process working directory.
|
|
133
|
+
*/
|
|
134
|
+
export interface CodegraphRequestBase {
|
|
135
|
+
/** Absolute path of the indexed project root to query. */
|
|
136
|
+
readonly projectRoot: string;
|
|
137
|
+
}
|
|
138
|
+
/** Find declarations whose name, qualified name, documentation, or signature matches `query`. */
|
|
139
|
+
export interface CodegraphSearchRequest extends CodegraphRequestBase {
|
|
140
|
+
readonly operation: 'search';
|
|
141
|
+
/** The symbol name or partial name to match. */
|
|
142
|
+
readonly query: string;
|
|
143
|
+
/** Restrict results to this node kind when set. See `NODE_KINDS`. */
|
|
144
|
+
readonly kind?: string;
|
|
145
|
+
/** Restrict results to this language when set. See `LANGUAGES`. */
|
|
146
|
+
readonly language?: string;
|
|
147
|
+
/** Largest number of nodes to return; the store reports whether it truncated. */
|
|
148
|
+
readonly limit: number;
|
|
149
|
+
}
|
|
150
|
+
/** Resolve one symbol by name and return it with its immediate incoming and outgoing edges. */
|
|
151
|
+
export interface CodegraphNodeRequest extends CodegraphRequestBase {
|
|
152
|
+
readonly operation: 'node';
|
|
153
|
+
/** Simple or qualified name to resolve. */
|
|
154
|
+
readonly symbol: string;
|
|
155
|
+
/** Largest number of related nodes to return on each side of the resolved symbol. */
|
|
156
|
+
readonly limit: number;
|
|
157
|
+
}
|
|
158
|
+
/** Find the declarations that call `symbol`. */
|
|
159
|
+
export interface CodegraphCallersRequest extends CodegraphRequestBase {
|
|
160
|
+
readonly operation: 'callers';
|
|
161
|
+
/** Simple or qualified name of the called symbol. */
|
|
162
|
+
readonly symbol: string;
|
|
163
|
+
/** Largest number of callers to return; the store reports whether it truncated. */
|
|
164
|
+
readonly limit: number;
|
|
165
|
+
}
|
|
166
|
+
/** Find the declarations `symbol` calls. */
|
|
167
|
+
export interface CodegraphCalleesRequest extends CodegraphRequestBase {
|
|
168
|
+
readonly operation: 'callees';
|
|
169
|
+
/** Simple or qualified name of the calling symbol. */
|
|
170
|
+
readonly symbol: string;
|
|
171
|
+
/** Largest number of callees to return; the store reports whether it truncated. */
|
|
172
|
+
readonly limit: number;
|
|
173
|
+
}
|
|
174
|
+
/** Walk incoming edges transitively to enumerate what a change to `symbol` can reach. */
|
|
175
|
+
export interface CodegraphImpactRequest extends CodegraphRequestBase {
|
|
176
|
+
readonly operation: 'impact';
|
|
177
|
+
/** Simple or qualified name of the symbol being changed. */
|
|
178
|
+
readonly symbol: string;
|
|
179
|
+
/** Largest number of edge hops to traverse outward from the symbol. */
|
|
180
|
+
readonly depth: number;
|
|
181
|
+
/** Largest number of affected nodes to return; the store reports whether it truncated. */
|
|
182
|
+
readonly limit: number;
|
|
183
|
+
}
|
|
184
|
+
/** Find directed paths from one symbol to another through the call and containment graph. */
|
|
185
|
+
export interface CodegraphTraceRequest extends CodegraphRequestBase {
|
|
186
|
+
readonly operation: 'trace';
|
|
187
|
+
/** Simple or qualified name the flow starts at. */
|
|
188
|
+
readonly from: string;
|
|
189
|
+
/** Simple or qualified name the flow should reach. */
|
|
190
|
+
readonly to: string;
|
|
191
|
+
/** Largest number of hops a returned path may contain. */
|
|
192
|
+
readonly maxDepth: number;
|
|
193
|
+
/** Largest number of distinct paths to return. */
|
|
194
|
+
readonly maxPaths: number;
|
|
195
|
+
}
|
|
196
|
+
/** List indexed files, optionally restricted to a subtree or glob pattern. */
|
|
197
|
+
export interface CodegraphFilesRequest extends CodegraphRequestBase {
|
|
198
|
+
readonly operation: 'files';
|
|
199
|
+
/** Restrict results to files under this project-relative directory when set. */
|
|
200
|
+
readonly path?: string;
|
|
201
|
+
/** Restrict results to paths matching this glob pattern when set. */
|
|
202
|
+
readonly pattern?: string;
|
|
203
|
+
/** Largest number of files to return; the store reports whether it truncated. */
|
|
204
|
+
readonly limit: number;
|
|
205
|
+
}
|
|
206
|
+
/** Report index size, coverage, and freshness. */
|
|
207
|
+
export interface CodegraphStatusRequest extends CodegraphRequestBase {
|
|
208
|
+
readonly operation: 'status';
|
|
209
|
+
}
|
|
210
|
+
/** A caller's normalized query: one member per {@link CodegraphOperation}. */
|
|
211
|
+
export type CodegraphRequest = CodegraphSearchRequest | CodegraphNodeRequest | CodegraphCallersRequest | CodegraphCalleesRequest | CodegraphImpactRequest | CodegraphTraceRequest | CodegraphFilesRequest | CodegraphStatusRequest;
|
|
212
|
+
/** Matching declarations, ordered by the store's relevance ranking. */
|
|
213
|
+
export interface CodegraphSearchResult {
|
|
214
|
+
readonly kind: 'search';
|
|
215
|
+
/** Matching nodes, most relevant first. */
|
|
216
|
+
readonly nodes: readonly CodegraphNode[];
|
|
217
|
+
/** Matches the store found before applying the request's limit. */
|
|
218
|
+
readonly total: number;
|
|
219
|
+
/** Whether {@link total} exceeded the request's limit. */
|
|
220
|
+
readonly truncated: boolean;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* One resolved symbol with its immediate neighbourhood. `node` is `null` when no declaration
|
|
224
|
+
* matches, which is an ordinary answer rather than a failure.
|
|
225
|
+
*/
|
|
226
|
+
export interface CodegraphNodeResult {
|
|
227
|
+
readonly kind: 'node';
|
|
228
|
+
/** The resolved declaration, or `null` when the name matches nothing. */
|
|
229
|
+
readonly node: CodegraphNode | null;
|
|
230
|
+
/** Declarations that reach {@link node} by one edge. */
|
|
231
|
+
readonly incoming: readonly CodegraphRelation[];
|
|
232
|
+
/** Declarations {@link node} reaches by one edge. */
|
|
233
|
+
readonly outgoing: readonly CodegraphRelation[];
|
|
234
|
+
/** Other declarations sharing the requested name, when the name was ambiguous. */
|
|
235
|
+
readonly alternatives: readonly CodegraphNode[];
|
|
236
|
+
}
|
|
237
|
+
/** Callers or callees of one symbol, discriminated by which direction was queried. */
|
|
238
|
+
export interface CodegraphRelationsResult {
|
|
239
|
+
readonly kind: 'callers' | 'callees';
|
|
240
|
+
/** The symbol the relations were resolved against, or `null` when the name matches nothing. */
|
|
241
|
+
readonly subject: CodegraphNode | null;
|
|
242
|
+
/** The related declarations with their call sites. */
|
|
243
|
+
readonly relations: readonly CodegraphRelation[];
|
|
244
|
+
/** Relations the store found before applying the request's limit. */
|
|
245
|
+
readonly total: number;
|
|
246
|
+
/** Whether {@link total} exceeded the request's limit. */
|
|
247
|
+
readonly truncated: boolean;
|
|
248
|
+
}
|
|
249
|
+
/** One node reached by an impact walk, with the hop distance that reached it. */
|
|
250
|
+
export interface CodegraphImpactEntry {
|
|
251
|
+
/** The affected declaration. */
|
|
252
|
+
readonly node: CodegraphNode;
|
|
253
|
+
/** Number of hops from the queried symbol; `1` is a direct dependent. */
|
|
254
|
+
readonly distance: number;
|
|
255
|
+
/** The relationship kind that reached this node on the shortest walk found. */
|
|
256
|
+
readonly via: string;
|
|
257
|
+
}
|
|
258
|
+
/** Everything a change to one symbol can reach, ordered by increasing hop distance. */
|
|
259
|
+
export interface CodegraphImpactResult {
|
|
260
|
+
readonly kind: 'impact';
|
|
261
|
+
/** The symbol the walk started from, or `null` when the name matches nothing. */
|
|
262
|
+
readonly subject: CodegraphNode | null;
|
|
263
|
+
/** Affected declarations, nearest first. */
|
|
264
|
+
readonly entries: readonly CodegraphImpactEntry[];
|
|
265
|
+
/** Affected declarations found before applying the request's limit. */
|
|
266
|
+
readonly total: number;
|
|
267
|
+
/** Whether {@link total} exceeded the request's limit. */
|
|
268
|
+
readonly truncated: boolean;
|
|
269
|
+
}
|
|
270
|
+
/** Directed paths between two symbols; an empty `paths` means no static path was found. */
|
|
271
|
+
export interface CodegraphTraceResult {
|
|
272
|
+
readonly kind: 'trace';
|
|
273
|
+
/** The origin declaration, or `null` when the name matches nothing. */
|
|
274
|
+
readonly from: CodegraphNode | null;
|
|
275
|
+
/** The destination declaration, or `null` when the name matches nothing. */
|
|
276
|
+
readonly to: CodegraphNode | null;
|
|
277
|
+
/** Each path from origin to destination, shortest first. */
|
|
278
|
+
readonly paths: readonly (readonly CodegraphTraceHop[])[];
|
|
279
|
+
}
|
|
280
|
+
/** Indexed files matching the request's filters. */
|
|
281
|
+
export interface CodegraphFilesResult {
|
|
282
|
+
readonly kind: 'files';
|
|
283
|
+
/** Matching files, ordered by path. */
|
|
284
|
+
readonly files: readonly CodegraphFile[];
|
|
285
|
+
/** Matching files found before applying the request's limit. */
|
|
286
|
+
readonly total: number;
|
|
287
|
+
/** Whether {@link total} exceeded the request's limit. */
|
|
288
|
+
readonly truncated: boolean;
|
|
289
|
+
}
|
|
290
|
+
/** Index size, language coverage, and the format version the store read. */
|
|
291
|
+
export interface CodegraphStatusResult {
|
|
292
|
+
readonly kind: 'status';
|
|
293
|
+
/** Absolute path of the indexed project root. */
|
|
294
|
+
readonly projectRoot: string;
|
|
295
|
+
/** Number of indexed files. */
|
|
296
|
+
readonly fileCount: number;
|
|
297
|
+
/** Number of graph nodes. */
|
|
298
|
+
readonly nodeCount: number;
|
|
299
|
+
/** Number of graph edges. */
|
|
300
|
+
readonly edgeCount: number;
|
|
301
|
+
/** Node counts per language, most files first. */
|
|
302
|
+
readonly languages: readonly {
|
|
303
|
+
readonly language: string;
|
|
304
|
+
readonly fileCount: number;
|
|
305
|
+
}[];
|
|
306
|
+
/** The on-disk graph format version the store read. */
|
|
307
|
+
readonly formatVersion: number;
|
|
308
|
+
/** Epoch milliseconds of the most recent index write, or `null` when nothing is indexed. */
|
|
309
|
+
readonly indexedAt: number | null;
|
|
310
|
+
/**
|
|
311
|
+
* Number of indexed files a direct filesystem check found stale since the index was built: modified
|
|
312
|
+
* more recently than the mtime the index recorded for them, or missing entirely. This is what makes
|
|
313
|
+
* an index's age actionable rather than merely displayed — `indexedAt` alone tells a caller how old
|
|
314
|
+
* the graph is, not whether anything has actually drifted from it. A store with no way to check the
|
|
315
|
+
* relevant filesystem reports `0` rather than guessing.
|
|
316
|
+
*/
|
|
317
|
+
readonly staleFileCount: number;
|
|
318
|
+
/**
|
|
319
|
+
* Whether {@link staleFileCount} stopped short of checking every indexed file and is therefore a
|
|
320
|
+
* lower bound rather than an exact count. A store enforces some such cap so a `status` call against
|
|
321
|
+
* a repository with a very large index stays cheap instead of statting every file it indexed.
|
|
322
|
+
*/
|
|
323
|
+
readonly staleFileCountTruncated: boolean;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* A store's answer: a CLOSED discriminated union whose `kind` matches the requested operation, so
|
|
327
|
+
* consumers `switch` to exhaustiveness and a new operation breaks compilation until handled.
|
|
328
|
+
*/
|
|
329
|
+
export type CodegraphResult = CodegraphSearchResult | CodegraphNodeResult | CodegraphRelationsResult | CodegraphImpactResult | CodegraphTraceResult | CodegraphFilesResult | CodegraphStatusResult;
|
|
330
|
+
/** The result member a given request produces, so `query()` narrows without a caller-side cast. */
|
|
331
|
+
export type CodegraphResultFor<R extends CodegraphRequest> = R extends CodegraphSearchRequest ? CodegraphSearchResult : R extends CodegraphNodeRequest ? CodegraphNodeResult : R extends CodegraphCallersRequest | CodegraphCalleesRequest ? CodegraphRelationsResult : R extends CodegraphImpactRequest ? CodegraphImpactResult : R extends CodegraphTraceRequest ? CodegraphTraceResult : R extends CodegraphFilesRequest ? CodegraphFilesResult : CodegraphStatusResult;
|
|
332
|
+
/**
|
|
333
|
+
* A graph store: it owns one on-disk or in-memory index format and answers every operation over it.
|
|
334
|
+
* A store is registered once and serves any project root it recognizes; {@link indexes} reports
|
|
335
|
+
* whether a root is available WITHOUT opening the graph, so the seam can fail a query loudly instead
|
|
336
|
+
* of routing it into a store that has nothing to read.
|
|
337
|
+
*/
|
|
338
|
+
export interface CodegraphStoreProvider {
|
|
339
|
+
/** Opaque identity reserved at registration; releasing it is the disposer's job. */
|
|
340
|
+
readonly id: CodegraphStoreId;
|
|
341
|
+
/**
|
|
342
|
+
* Whether this store has an index for `projectRoot`.
|
|
343
|
+
* @param projectRoot - absolute path of the project root to test.
|
|
344
|
+
* @param signal - aborts the availability check.
|
|
345
|
+
* @returns true when {@link query} can serve this root.
|
|
346
|
+
*/
|
|
347
|
+
indexes(projectRoot: string, signal?: AbortSignal): Promise<boolean>;
|
|
348
|
+
/**
|
|
349
|
+
* Answer one query against the store's index.
|
|
350
|
+
* @param request - the normalized query, with every bound already resolved by the caller.
|
|
351
|
+
* @param signal - aborts the query.
|
|
352
|
+
* @returns the result member matching `request.operation`.
|
|
353
|
+
*/
|
|
354
|
+
query<R extends CodegraphRequest>(request: R, signal?: AbortSignal): Promise<CodegraphResultFor<R>>;
|
|
355
|
+
}
|
|
356
|
+
/** What one indexing run produced, returned to the caller that requested it. */
|
|
357
|
+
export interface CodegraphIndexReport {
|
|
358
|
+
/** Absolute path of the project root that was indexed. */
|
|
359
|
+
readonly projectRoot: string;
|
|
360
|
+
/** Files parsed and written to the graph. */
|
|
361
|
+
readonly filesIndexed: number;
|
|
362
|
+
/** Files skipped (too large, over the file-count ceiling, or excluded). */
|
|
363
|
+
readonly filesSkipped: number;
|
|
364
|
+
/** Declaration nodes written. */
|
|
365
|
+
readonly nodeCount: number;
|
|
366
|
+
/** Relationship edges written. */
|
|
367
|
+
readonly edgeCount: number;
|
|
368
|
+
/**
|
|
369
|
+
* Call sites whose callee could not be resolved to exactly one declaration. This total is dominated,
|
|
370
|
+
* in a typical workspace, by calls that were never real candidates for a workspace edge — a member
|
|
371
|
+
* access with no type information behind its receiver, or a name the calling file imports from
|
|
372
|
+
* somewhere this run's resolution could not follow — alongside genuine gaps. See
|
|
373
|
+
* {@link unresolvedLikelyInternalCount} for the subset worth treating as a gap in the graph.
|
|
374
|
+
*/
|
|
375
|
+
readonly unresolvedCount: number;
|
|
376
|
+
/**
|
|
377
|
+
* Of {@link unresolvedCount}, the calls that were structurally plausible workspace-internal
|
|
378
|
+
* candidates: a bare, undeclared name, not a member access or an already-imported one. This is the
|
|
379
|
+
* number worth judging index completeness by; {@link unresolvedCount} alone is dominated by noise a
|
|
380
|
+
* type-free resolver was never going to settle.
|
|
381
|
+
*/
|
|
382
|
+
readonly unresolvedLikelyInternalCount: number;
|
|
383
|
+
/** Node counts per language, most files first. */
|
|
384
|
+
readonly languages: readonly {
|
|
385
|
+
readonly language: string;
|
|
386
|
+
readonly fileCount: number;
|
|
387
|
+
}[];
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* A graph indexer: it builds or refreshes an on-disk graph for a project root. Indexing is explicit
|
|
391
|
+
* and caller-initiated — a provider never runs itself from {@link CodegraphService.query}, because a
|
|
392
|
+
* multi-minute build does not belong inside a call the model expects to return quickly.
|
|
393
|
+
*/
|
|
394
|
+
export interface CodegraphIndexer {
|
|
395
|
+
/** Opaque identity reserved at registration; releasing it is the disposer's job. */
|
|
396
|
+
readonly id: CodegraphIndexerId;
|
|
397
|
+
/**
|
|
398
|
+
* Whether this indexer can build a graph for `projectRoot`.
|
|
399
|
+
* @param projectRoot - absolute path of the project root to test.
|
|
400
|
+
* @param signal - aborts the check.
|
|
401
|
+
* @returns true when {@link index} can run against this root.
|
|
402
|
+
*/
|
|
403
|
+
canIndex(projectRoot: string, signal?: AbortSignal): Promise<boolean>;
|
|
404
|
+
/**
|
|
405
|
+
* Build or refresh the graph, replacing whatever was there.
|
|
406
|
+
* @param projectRoot - absolute path of the project root to index.
|
|
407
|
+
* @param signal - aborts the run.
|
|
408
|
+
* @returns a summary of what the run produced.
|
|
409
|
+
*/
|
|
410
|
+
index(projectRoot: string, signal?: AbortSignal): Promise<CodegraphIndexReport>;
|
|
411
|
+
}
|
|
412
|
+
/** `ctx.codegraph`: the store registry, the indexer registry, and the query entry point. */
|
|
413
|
+
export interface CodegraphService {
|
|
414
|
+
/**
|
|
415
|
+
* Register a graph store.
|
|
416
|
+
* @param provider - the store to publish, carrying an unused branded id.
|
|
417
|
+
* @returns a disposer releasing the reservation; disposed with the calling fiber.
|
|
418
|
+
*/
|
|
419
|
+
registerStore(provider: CodegraphStoreProvider): () => void;
|
|
420
|
+
/**
|
|
421
|
+
* Register a graph indexer.
|
|
422
|
+
* @param provider - the indexer to publish, carrying an unused branded id.
|
|
423
|
+
* @returns a disposer releasing the reservation; disposed with the calling fiber.
|
|
424
|
+
*/
|
|
425
|
+
registerIndexer(provider: CodegraphIndexer): () => void;
|
|
426
|
+
/**
|
|
427
|
+
* Whether any registered store already claims `projectRoot`, without opening it. Lets a caller
|
|
428
|
+
* distinguish "not indexed" from "query failed" without catching {@link query}'s error.
|
|
429
|
+
* @param projectRoot - absolute path of the project root to check.
|
|
430
|
+
* @param signal - aborts the check.
|
|
431
|
+
* @returns true when {@link query} can serve this root right now.
|
|
432
|
+
*/
|
|
433
|
+
available(projectRoot: string, signal?: AbortSignal): Promise<boolean>;
|
|
434
|
+
/**
|
|
435
|
+
* Run the single indexer that claims `projectRoot`.
|
|
436
|
+
* @param projectRoot - absolute path of the project root to index.
|
|
437
|
+
* @param signal - aborts the run.
|
|
438
|
+
* @returns the report the indexer produced.
|
|
439
|
+
*/
|
|
440
|
+
index(projectRoot: string, signal?: AbortSignal): Promise<CodegraphIndexReport>;
|
|
441
|
+
/**
|
|
442
|
+
* Route one query to the store that indexes `request.projectRoot`.
|
|
443
|
+
* @param request - the normalized query.
|
|
444
|
+
* @param signal - aborts store selection and the query.
|
|
445
|
+
* @returns the result member matching `request.operation`.
|
|
446
|
+
*/
|
|
447
|
+
query<R extends CodegraphRequest>(request: R, signal?: AbortSignal): Promise<CodegraphResultFor<R>>;
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=types.d.ts.map
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegraph seam vocabulary: the graph records, the normalized request and result unions, and the
|
|
3
|
+
* store-provider contract. Types only — the {@link CodegraphError} taxonomy, the branded-id
|
|
4
|
+
* factories, and the `NODE_KINDS` / `EDGE_KINDS` / `LANGUAGES` vocabulary arrays are runtime and
|
|
5
|
+
* live in `index.ts`.
|
|
6
|
+
*
|
|
7
|
+
* Line numbers are one-based and column numbers zero-based, matching the on-disk graph the reference
|
|
8
|
+
* indexer writes; the model-facing tool owns any other display convention. `kind` and `language` are
|
|
9
|
+
* plain strings rather than closed unions because the graph is read from a durable file written by
|
|
10
|
+
* an independently versioned indexer: a record whose kind this build does not know must still reach
|
|
11
|
+
* the model as data, not fail the query. `NODE_KINDS`, `EDGE_KINDS`, and `LANGUAGES` document the
|
|
12
|
+
* values that format defines today.
|
|
13
|
+
* @module @huanlin/dsh-plugin-codegraph-service/types
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@huanlin/dsh-plugin-codegraph-service",
|
|
3
|
+
"version": "0.1.8",
|
|
4
|
+
"description": "Service Definition for the DeepSeek Harness code-graph capability seam (ctx.codegraph): a graph-store and graph-indexer provider registry with per-query, order-independent selection over eight normalized structural queries",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dsh",
|
|
7
|
+
"dsh-plugin",
|
|
8
|
+
"deepseek-harness",
|
|
9
|
+
"cordis",
|
|
10
|
+
"cordis-plugin",
|
|
11
|
+
"codegraph",
|
|
12
|
+
"code-graph",
|
|
13
|
+
"code-intelligence",
|
|
14
|
+
"ai-agent",
|
|
15
|
+
"llm-tools"
|
|
16
|
+
],
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"author": "CC ZHAO",
|
|
19
|
+
"repository": {
|
|
20
|
+
"type": "git",
|
|
21
|
+
"url": "git+https://github.com/HuanLinOTO/dsh-plugin-codegraph.git",
|
|
22
|
+
"directory": "packages/service"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/HuanLinOTO/dsh-plugin-codegraph#readme",
|
|
25
|
+
"bugs": "https://github.com/HuanLinOTO/dsh-plugin-codegraph/issues",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"main": "lib/index.js",
|
|
28
|
+
"types": "lib/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./lib/index.d.ts",
|
|
32
|
+
"default": "./lib/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"lib/**/*.js",
|
|
38
|
+
"lib/**/*.d.ts"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"@deepseek-ai/cordis": ">=4.0.1",
|
|
45
|
+
"@deepseek-ai/dsh-brand": ">=0.1.0-rc.6",
|
|
46
|
+
"@deepseek-ai/dsh-llm": ">=0.1.2-rc.1"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
50
|
+
"@deepseek-ai/dsh-brand": "0.1.2-rc.1",
|
|
51
|
+
"@deepseek-ai/dsh-llm": "0.1.2-rc.1"
|
|
52
|
+
}
|
|
53
|
+
}
|