gitnexus 1.6.13-rc.6 → 1.6.13-rc.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/README.md +1 -1
- package/dist/cli/ai-context.js +1 -0
- package/dist/core/ingestion/languages/rust/cargo-module-files.d.ts +9 -0
- package/dist/core/ingestion/languages/rust/cargo-module-files.js +319 -0
- package/dist/core/ingestion/languages/rust/cargo-targets.d.ts +21 -0
- package/dist/core/ingestion/languages/rust/cargo-targets.js +473 -0
- package/dist/core/ingestion/languages/rust/import-decomposer.js +10 -5
- package/dist/core/ingestion/languages/rust/name-fallback-visibility.d.ts +2 -0
- package/dist/core/ingestion/languages/rust/name-fallback-visibility.js +152 -13
- package/dist/core/ingestion/languages/rust/scope-resolver.js +2 -0
- package/dist/core/ingestion/scope-resolution/contract/scope-resolver.d.ts +2 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.d.ts +1 -0
- package/dist/core/ingestion/scope-resolution/passes/free-call-fallback.js +1 -0
- package/dist/core/ingestion/scope-resolution/pipeline/run.js +1 -0
- package/dist/core/staleness-status.d.ts +43 -6
- package/dist/core/staleness-status.js +26 -8
- package/dist/mcp/local/local-backend.d.ts +28 -11
- package/dist/mcp/local/local-backend.js +33 -12
- package/dist/mcp/tools.js +14 -4
- package/dist/server/repo-projection.d.ts +12 -7
- package/dist/server/repo-projection.js +12 -7
- package/dist/storage/parse-cache.js +7 -1
- package/package.json +2 -1
- package/scripts/cross-platform-tests.ts +3 -0
- package/skills/gitnexus-debugging.md +1 -0
- package/skills/gitnexus-exploring.md +1 -0
- package/skills/gitnexus-guide.md +49 -0
- package/skills/gitnexus-impact-analysis.md +1 -0
- package/skills/gitnexus-refactoring.md +1 -0
package/README.md
CHANGED
|
@@ -431,7 +431,7 @@ TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust, PHP, Kotlin, Swift,
|
|
|
431
431
|
| Kotlin | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | — | ✓ | ✓ |
|
|
432
432
|
| C# | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
433
433
|
| Go | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
434
|
-
| Rust | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
434
|
+
| Rust | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
435
435
|
| PHP | ✓ | ✓ | ✓ | — | ✓ | ✓ | ✓ | ✓ | ✓ |
|
|
436
436
|
| Ruby | ✓ | — | ✓ | ✓ | — | ✓ | — | ✓ | ✓ |
|
|
437
437
|
| Swift | — | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -137,6 +137,7 @@ ${tableBody}`
|
|
|
137
137
|
This project is indexed by GitNexus as **${projectName}**${noStats ? '' : ` (${stats.nodes || 0} symbols, ${stats.edges || 0} relationships, ${stats.processes || 0} execution flows)`}.
|
|
138
138
|
|
|
139
139
|
> Index stale? Run \`${runner} analyze --index-only\` from the project root — it auto-selects an available runner. ${bootstrapNote}
|
|
140
|
+
> On query/context/impact/cypher object results, read staleness.status and branch/lastCommit. Re-analyze only for behind or diverged — current is clone HEAD, not main.
|
|
140
141
|
|
|
141
142
|
## Always Do
|
|
142
143
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type Parser from 'tree-sitter';
|
|
2
|
+
/** Public use evidence from the same AST used for membership. Keeps restricted
|
|
3
|
+
* and private globs distinct without changing the shared import/cache shape. */
|
|
4
|
+
export declare function rustPublicUses(root: Parser.SyntaxNode): ReadonlySet<string>;
|
|
5
|
+
/** External modules reachable from one source file; undefined is incomplete. */
|
|
6
|
+
export declare function rustModuleFiles(root: Parser.SyntaxNode, file: string, ownsDirectory: boolean, files: ReadonlySet<string>, missingFiles?: Set<string>, isCrateRoot?: boolean): readonly {
|
|
7
|
+
file: string;
|
|
8
|
+
ownsDirectory: boolean;
|
|
9
|
+
}[] | undefined;
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { splitRustUseDeclaration } from './import-decomposer.js';
|
|
3
|
+
// Built-in attributes cannot expand to new module declarations. cfg is a union:
|
|
4
|
+
// visiting both alternatives is conservative; cfg_attr may change a path.
|
|
5
|
+
const NON_EXPANDING_ATTRIBUTES = new Set([
|
|
6
|
+
'cfg',
|
|
7
|
+
'path',
|
|
8
|
+
'allow',
|
|
9
|
+
'warn',
|
|
10
|
+
'deny',
|
|
11
|
+
'forbid',
|
|
12
|
+
'expect',
|
|
13
|
+
'doc',
|
|
14
|
+
'test',
|
|
15
|
+
'should_panic',
|
|
16
|
+
'ignore',
|
|
17
|
+
'automatically_derived',
|
|
18
|
+
'proc_macro',
|
|
19
|
+
'proc_macro_derive',
|
|
20
|
+
'proc_macro_attribute',
|
|
21
|
+
'inline',
|
|
22
|
+
'cold',
|
|
23
|
+
'no_mangle',
|
|
24
|
+
'export_name',
|
|
25
|
+
'repr',
|
|
26
|
+
'non_exhaustive',
|
|
27
|
+
'must_use',
|
|
28
|
+
'deprecated',
|
|
29
|
+
'no_std',
|
|
30
|
+
'no_main',
|
|
31
|
+
'feature',
|
|
32
|
+
'crate_type',
|
|
33
|
+
'crate_name',
|
|
34
|
+
'recursion_limit',
|
|
35
|
+
'type_length_limit',
|
|
36
|
+
]);
|
|
37
|
+
const BUILTIN_DERIVES = new Set([
|
|
38
|
+
'Clone',
|
|
39
|
+
'Copy',
|
|
40
|
+
'Debug',
|
|
41
|
+
'Default',
|
|
42
|
+
'Eq',
|
|
43
|
+
'Hash',
|
|
44
|
+
'Ord',
|
|
45
|
+
'PartialEq',
|
|
46
|
+
'PartialOrd',
|
|
47
|
+
]);
|
|
48
|
+
const EXPRESSION_MACROS = new Set([
|
|
49
|
+
'print',
|
|
50
|
+
'println',
|
|
51
|
+
'eprint',
|
|
52
|
+
'eprintln',
|
|
53
|
+
'assert',
|
|
54
|
+
'assert_eq',
|
|
55
|
+
'assert_ne',
|
|
56
|
+
'debug_assert',
|
|
57
|
+
'debug_assert_eq',
|
|
58
|
+
'debug_assert_ne',
|
|
59
|
+
'vec',
|
|
60
|
+
'format',
|
|
61
|
+
'format_args',
|
|
62
|
+
'write',
|
|
63
|
+
'writeln',
|
|
64
|
+
'panic',
|
|
65
|
+
'todo',
|
|
66
|
+
'unimplemented',
|
|
67
|
+
'unreachable',
|
|
68
|
+
'dbg',
|
|
69
|
+
'matches',
|
|
70
|
+
]);
|
|
71
|
+
/** Token arguments can contain blocks/modules or further macro expansion.
|
|
72
|
+
* Inspect token nodes, never strings/comments that merely mention those words. */
|
|
73
|
+
function hasExpandingArguments(tokens) {
|
|
74
|
+
for (let i = 0; i < tokens.childCount; i++) {
|
|
75
|
+
const child = tokens.child(i);
|
|
76
|
+
if (child.type === 'mod' || child.type === '#')
|
|
77
|
+
return true;
|
|
78
|
+
if (child.type === '!' && tokens.child(i - 1)?.type === 'identifier')
|
|
79
|
+
return true;
|
|
80
|
+
if (child.type === 'token_tree' && hasExpandingArguments(child))
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
/** Public use evidence from the same AST used for membership. Keeps restricted
|
|
86
|
+
* and private globs distinct without changing the shared import/cache shape. */
|
|
87
|
+
export function rustPublicUses(root) {
|
|
88
|
+
const uses = new Set();
|
|
89
|
+
const pending = [{ node: root, module: '' }];
|
|
90
|
+
while (pending.length > 0) {
|
|
91
|
+
const { node, module } = pending.pop();
|
|
92
|
+
for (const child of node.namedChildren) {
|
|
93
|
+
if (child.type === 'mod_item') {
|
|
94
|
+
const body = child.childForFieldName('body');
|
|
95
|
+
const name = child.childForFieldName('name')?.text;
|
|
96
|
+
if (body && name)
|
|
97
|
+
pending.push({ node: body, module: [module, name].filter(Boolean).join('::') });
|
|
98
|
+
}
|
|
99
|
+
else if (child.type === 'use_declaration' &&
|
|
100
|
+
child.namedChildren.some((part) => part.type === 'visibility_modifier' && part.text === 'pub')) {
|
|
101
|
+
for (const capture of splitRustUseDeclaration(child)) {
|
|
102
|
+
uses.add(JSON.stringify([
|
|
103
|
+
module,
|
|
104
|
+
capture['@import.source']?.text,
|
|
105
|
+
capture['@import.kind']?.text,
|
|
106
|
+
capture['@import.name']?.text,
|
|
107
|
+
]));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return uses;
|
|
113
|
+
}
|
|
114
|
+
/** Decode a literal path without mistaking strings/comments for Rust syntax. */
|
|
115
|
+
function literalPath(text) {
|
|
116
|
+
const raw = /^r(#+)?"([\s\S]*)"\1$/.exec(text);
|
|
117
|
+
if (raw)
|
|
118
|
+
return raw[2];
|
|
119
|
+
// Escape forms beyond JSON's subset remain unknown, never a guessed path.
|
|
120
|
+
try {
|
|
121
|
+
const value = JSON.parse(text);
|
|
122
|
+
return typeof value === 'string' ? value : undefined;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** External modules reachable from one source file; undefined is incomplete. */
|
|
129
|
+
export function rustModuleFiles(root, file, ownsDirectory, files, missingFiles, isCrateRoot = false) {
|
|
130
|
+
if (root.hasError)
|
|
131
|
+
return undefined;
|
|
132
|
+
// Built-in spellings are not proof when an import/local macro can shadow
|
|
133
|
+
// them. Cross-file macro_use/macro_export remain unknown attributes below.
|
|
134
|
+
const shadowed = new Set();
|
|
135
|
+
const globs = [];
|
|
136
|
+
const scan = [root];
|
|
137
|
+
while (scan.length) {
|
|
138
|
+
const node = scan.pop();
|
|
139
|
+
if (node.type === 'macro_definition' || node.type === 'mod_item') {
|
|
140
|
+
const name = node.childForFieldName('name')?.text;
|
|
141
|
+
if (name)
|
|
142
|
+
shadowed.add(name);
|
|
143
|
+
// macro_rules textual scope can extend into child module files. Without
|
|
144
|
+
// expansion/scope receipts, do not assume their same-named calls are std.
|
|
145
|
+
if (node.type === 'macro_definition' && name && EXPRESSION_MACROS.has(name))
|
|
146
|
+
return undefined;
|
|
147
|
+
}
|
|
148
|
+
if (node.type === 'use_declaration') {
|
|
149
|
+
for (const capture of splitRustUseDeclaration(node)) {
|
|
150
|
+
if (capture['@import.kind']?.text === 'wildcard')
|
|
151
|
+
globs.push({ node, path: capture['@import.source']?.text ?? '' });
|
|
152
|
+
const name = capture['@import.name']?.text;
|
|
153
|
+
if (name)
|
|
154
|
+
shadowed.add(name);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (node.type !== 'macro_definition' && node.type !== 'token_tree')
|
|
158
|
+
scan.push(...node.namedChildren);
|
|
159
|
+
}
|
|
160
|
+
const wildcard = globs.some(({ node, path: imported }) => {
|
|
161
|
+
const parts = imported.split('::').filter(Boolean);
|
|
162
|
+
// Cargo aliases for these names are rejected by the loader. A local
|
|
163
|
+
// module/import can still shadow a standard-library path in this file.
|
|
164
|
+
if (['std', 'core', 'alloc'].includes(parts[0] ?? '') && !shadowed.has(parts[0]))
|
|
165
|
+
return false;
|
|
166
|
+
let depth = 0;
|
|
167
|
+
let localModuleScope = true;
|
|
168
|
+
for (let parent = node.parent; parent && parent !== root; parent = parent.parent) {
|
|
169
|
+
if (parent.type === 'mod_item')
|
|
170
|
+
depth++;
|
|
171
|
+
if (parent.type === 'function_item' ||
|
|
172
|
+
parent.type === 'block' ||
|
|
173
|
+
parent.type === 'closure_expression')
|
|
174
|
+
localModuleScope = false;
|
|
175
|
+
}
|
|
176
|
+
// The common inline unit-test `use super::*` stays within this AST.
|
|
177
|
+
// A file-level super glob has an external parent and remains unknown.
|
|
178
|
+
if (localModuleScope &&
|
|
179
|
+
parts.length > 0 &&
|
|
180
|
+
parts.every((part) => part === 'super') &&
|
|
181
|
+
parts.length <= depth)
|
|
182
|
+
return false;
|
|
183
|
+
// At a Cargo root, bare/self/crate paths to inline modules have the same
|
|
184
|
+
// meaning across editions. Do not extend this assumption to file modules.
|
|
185
|
+
if (isCrateRoot && node.parent === root) {
|
|
186
|
+
if (parts[0] === 'self' || parts[0] === 'crate')
|
|
187
|
+
parts.shift();
|
|
188
|
+
let body = root;
|
|
189
|
+
for (const part of parts) {
|
|
190
|
+
body =
|
|
191
|
+
body?.namedChildren
|
|
192
|
+
.find((child) => child.type === 'mod_item' && child.childForFieldName('name')?.text === part)
|
|
193
|
+
?.childForFieldName('body') ?? undefined;
|
|
194
|
+
}
|
|
195
|
+
if (parts.length > 0 && body !== undefined)
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
return true;
|
|
199
|
+
});
|
|
200
|
+
const builtin = (name) => !wildcard && !shadowed.has(name);
|
|
201
|
+
const fileDir = path.posix.dirname(file);
|
|
202
|
+
const moduleDir = ownsDirectory || path.posix.basename(file) === 'mod.rs'
|
|
203
|
+
? fileDir
|
|
204
|
+
: file.slice(0, -'.rs'.length);
|
|
205
|
+
const pending = [{ node: root, moduleDir, attributeDir: fileDir }];
|
|
206
|
+
const result = [];
|
|
207
|
+
let unresolved = false;
|
|
208
|
+
while (pending.length) {
|
|
209
|
+
const context = pending.pop();
|
|
210
|
+
let attributes = [];
|
|
211
|
+
for (const node of context.node.namedChildren) {
|
|
212
|
+
if (node.type === 'line_comment' || node.type === 'block_comment')
|
|
213
|
+
continue;
|
|
214
|
+
if (node.type === 'attribute_item' || node.type === 'inner_attribute_item') {
|
|
215
|
+
const attribute = node.namedChildren[0];
|
|
216
|
+
const name = attribute?.namedChildren[0]?.text;
|
|
217
|
+
if (name === 'derive') {
|
|
218
|
+
const argumentsNode = attribute?.childForFieldName('arguments');
|
|
219
|
+
if (!argumentsNode ||
|
|
220
|
+
!builtin('derive') ||
|
|
221
|
+
argumentsNode.namedChildren.length === 0 ||
|
|
222
|
+
argumentsNode.namedChildren.some((item) => item.type !== 'identifier' ||
|
|
223
|
+
!BUILTIN_DERIVES.has(item.text) ||
|
|
224
|
+
!builtin(item.text)) ||
|
|
225
|
+
argumentsNode.children.some((item) => !['(', ')', ',', 'identifier', 'line_comment', 'block_comment'].includes(item.type)))
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
else if (!name || !NON_EXPANDING_ATTRIBUTES.has(name))
|
|
229
|
+
return undefined;
|
|
230
|
+
if (node.type === 'attribute_item')
|
|
231
|
+
attributes.push(node);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const attrs = attributes;
|
|
235
|
+
attributes = [];
|
|
236
|
+
// The current scope captures do not carry extern-crate aliases. Do not
|
|
237
|
+
// certify a negative import-root proof from an incomplete namespace view.
|
|
238
|
+
if (node.type === 'extern_crate_declaration' && node.childForFieldName('alias') !== null) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
const macro = node.type === 'macro_invocation'
|
|
242
|
+
? node
|
|
243
|
+
: node.type === 'expression_statement' &&
|
|
244
|
+
node.namedChildren[0]?.type === 'macro_invocation'
|
|
245
|
+
? node.namedChildren[0]
|
|
246
|
+
: undefined;
|
|
247
|
+
if (macro) {
|
|
248
|
+
const name = macro.childForFieldName('macro')?.text;
|
|
249
|
+
const tokens = macro.namedChildren.find((child) => child.type === 'token_tree');
|
|
250
|
+
const parts = name?.split('::').filter(Boolean) ?? [];
|
|
251
|
+
const standard = parts.length === 1 ||
|
|
252
|
+
(parts.length === 2 && ['std', 'core', 'alloc'].includes(parts[0]));
|
|
253
|
+
if (!standard ||
|
|
254
|
+
!EXPRESSION_MACROS.has(parts.at(-1) ?? '') ||
|
|
255
|
+
!parts.every(builtin) ||
|
|
256
|
+
!tokens ||
|
|
257
|
+
hasExpandingArguments(tokens) ||
|
|
258
|
+
context.node.type === 'source_file' ||
|
|
259
|
+
context.node.type === 'declaration_list')
|
|
260
|
+
return undefined;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (node.type !== 'mod_item') {
|
|
264
|
+
// Items (including external #[path] modules) can also occur in blocks.
|
|
265
|
+
// Inspect them too; a macro expansion there can add shared membership.
|
|
266
|
+
// Macro definitions/token trees and literal contents are not expansions.
|
|
267
|
+
if (node.type !== 'macro_definition' &&
|
|
268
|
+
node.type !== 'token_tree' &&
|
|
269
|
+
node.namedChildCount > 0) {
|
|
270
|
+
pending.push({ ...context, node });
|
|
271
|
+
}
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const name = node.childForFieldName('name')?.text;
|
|
275
|
+
if (!name)
|
|
276
|
+
return undefined;
|
|
277
|
+
let override;
|
|
278
|
+
for (const attr of attrs) {
|
|
279
|
+
const attribute = attr.namedChildren[0];
|
|
280
|
+
if (attribute.namedChildren[0]?.text !== 'path')
|
|
281
|
+
continue;
|
|
282
|
+
const value = attribute.childForFieldName('value');
|
|
283
|
+
if (!value || override !== undefined)
|
|
284
|
+
return undefined;
|
|
285
|
+
override = literalPath(value.text);
|
|
286
|
+
if (override === undefined || path.posix.isAbsolute(override) || override.includes('\\'))
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
const body = node.childForFieldName('body');
|
|
290
|
+
if (body) {
|
|
291
|
+
const dir = override === undefined
|
|
292
|
+
? path.posix.join(context.moduleDir, name)
|
|
293
|
+
: path.posix.join(context.attributeDir, override);
|
|
294
|
+
pending.push({ node: body, moduleDir: dir, attributeDir: dir });
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
const candidates = override !== undefined
|
|
298
|
+
? [path.posix.normalize(path.posix.join(context.attributeDir, override))]
|
|
299
|
+
: [
|
|
300
|
+
path.posix.join(context.moduleDir, `${name}.rs`),
|
|
301
|
+
path.posix.join(context.moduleDir, name, 'mod.rs'),
|
|
302
|
+
];
|
|
303
|
+
const existing = candidates.filter((candidate) => files.has(candidate));
|
|
304
|
+
if (existing.length === 0) {
|
|
305
|
+
if (!missingFiles)
|
|
306
|
+
return undefined;
|
|
307
|
+
for (const candidate of candidates)
|
|
308
|
+
missingFiles.add(candidate);
|
|
309
|
+
unresolved = true;
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// Union conditional alternatives; shared membership must never be erased.
|
|
313
|
+
// #[path] makes the loaded file own its containing directory, just like
|
|
314
|
+
// a crate root; its children do NOT acquire the file stem as a prefix.
|
|
315
|
+
result.push(...existing.map((file) => ({ file, ownsDirectory: override !== undefined })));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return unresolved ? undefined : result;
|
|
319
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** A target is identified by its entry file, not its package directory. */
|
|
2
|
+
export declare function cargoTargetRoots(manifest: string, content: string, files: ReadonlySet<string>, workspaceEditions?: ReadonlyMap<string, string>): readonly string[] | undefined;
|
|
3
|
+
/** Exact public-use evidence, independent of the capture's coarse reexport kind. */
|
|
4
|
+
export declare function rustCargoPubliclyReexports(config: unknown, file: string, module: string, target: string, kind: string, name: string): boolean;
|
|
5
|
+
/** Positive evidence that this import names this library's ROOT, not a module
|
|
6
|
+
* elsewhere (or a binary/test entry point that cannot be imported as a lib). */
|
|
7
|
+
export declare function rustImportNamesCargoRoot(config: unknown, caller: string, candidate: string, importedModule: string): boolean;
|
|
8
|
+
/** Every known membership must identify this file as the entry point. A file
|
|
9
|
+
* shared as a module in another target does not have a single root role. */
|
|
10
|
+
export declare function rustIsExclusiveCargoRoot(config: unknown, file: string): boolean;
|
|
11
|
+
/** Establish crate identity before the existing module-path plausibility test. */
|
|
12
|
+
export declare function rustImportReachesCargoTarget(config: unknown, caller: string, candidate: string, importedModule: string): boolean;
|
|
13
|
+
/** Undefined means no complete membership proof; never interpret it as disjoint. */
|
|
14
|
+
export declare function rustFilesShareCargoTarget(config: unknown, caller: string, candidate: string): boolean | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Static, bounded, one-shot provider loader. No cargo/rustc, build scripts,
|
|
17
|
+
* repository wrappers, or network. Parse only files reachable from Cargo roots.
|
|
18
|
+
* Unknown expansion anywhere can add shared membership, so it invalidates the
|
|
19
|
+
* negative proof for this snapshot rather than producing a partial veto.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadRustCargoTargets(repoPath: string): Promise<unknown>;
|