brainclaw 1.16.0 → 1.18.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.
Files changed (85) hide show
  1. package/README.md +22 -8
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli/register-review.js +2 -2
  4. package/dist/commands/code-map.js +4 -1
  5. package/dist/commands/codev.js +61 -30
  6. package/dist/commands/doctor.js +14 -1
  7. package/dist/commands/harvest.js +241 -25
  8. package/dist/commands/inbox.js +10 -4
  9. package/dist/commands/loop.js +2 -2
  10. package/dist/commands/loops-handlers.js +82 -1
  11. package/dist/commands/mcp-catalog.js +12 -4
  12. package/dist/commands/mcp-read-handlers.js +90 -7
  13. package/dist/commands/mcp-schemas.generated.js +3 -0
  14. package/dist/commands/mcp-write-coordination.js +159 -40
  15. package/dist/commands/mcp.js +11 -2
  16. package/dist/core/agent-capability.js +7 -2
  17. package/dist/core/agent-files.js +53 -2
  18. package/dist/core/agent-integrations.js +1 -0
  19. package/dist/core/agentrun-reconciler.js +171 -7
  20. package/dist/core/agentruns.js +6 -1
  21. package/dist/core/code-map/aggregate.js +473 -0
  22. package/dist/core/code-map/backend.js +36 -10
  23. package/dist/core/code-map/freshness.js +36 -1
  24. package/dist/core/code-map/lang/c/imports.scm +12 -0
  25. package/dist/core/code-map/lang/c/index.js +150 -0
  26. package/dist/core/code-map/lang/c/tags.scm +68 -0
  27. package/dist/core/code-map/lang/cpp/imports.scm +14 -0
  28. package/dist/core/code-map/lang/cpp/index.js +149 -0
  29. package/dist/core/code-map/lang/cpp/tags.scm +87 -0
  30. package/dist/core/code-map/lang/csharp/imports.scm +20 -0
  31. package/dist/core/code-map/lang/csharp/index.js +224 -0
  32. package/dist/core/code-map/lang/csharp/tags.scm +63 -0
  33. package/dist/core/code-map/lang/go/imports.scm +13 -0
  34. package/dist/core/code-map/lang/go/index.js +139 -0
  35. package/dist/core/code-map/lang/go/tags.scm +36 -0
  36. package/dist/core/code-map/lang/providers.js +12 -1
  37. package/dist/core/code-map/lang/ruby/imports.scm +24 -0
  38. package/dist/core/code-map/lang/ruby/index.js +198 -0
  39. package/dist/core/code-map/lang/ruby/tags.scm +49 -0
  40. package/dist/core/code-map/lang/rust/imports.scm +44 -0
  41. package/dist/core/code-map/lang/rust/index.js +136 -0
  42. package/dist/core/code-map/lang/rust/tags.scm +47 -0
  43. package/dist/core/code-map/query.js +229 -80
  44. package/dist/core/code-map/types.js +18 -0
  45. package/dist/core/code-map/work-section.js +8 -7
  46. package/dist/core/codev-responses.js +16 -0
  47. package/dist/core/dispatcher.js +209 -29
  48. package/dist/core/execution-adapters.js +29 -3
  49. package/dist/core/ideation-loop-close.js +124 -0
  50. package/dist/core/loops/artifact-resolver.js +197 -0
  51. package/dist/core/loops/attempt-reservation.js +576 -0
  52. package/dist/core/loops/commit-intent.js +494 -0
  53. package/dist/core/loops/facade-schema.js +48 -0
  54. package/dist/core/loops/impl-bind.js +144 -0
  55. package/dist/core/loops/index.js +1 -1
  56. package/dist/core/loops/iteration-engine.js +29 -0
  57. package/dist/core/loops/lock.js +14 -0
  58. package/dist/core/loops/project-resolution.js +157 -0
  59. package/dist/core/loops/reconcile-turn.js +369 -0
  60. package/dist/core/loops/result-reducers.js +88 -0
  61. package/dist/core/loops/store.js +46 -7
  62. package/dist/core/loops/types.js +139 -11
  63. package/dist/core/loops/verbs.js +9 -3
  64. package/dist/core/loops/verify-command.js +209 -0
  65. package/dist/core/messaging.js +58 -5
  66. package/dist/core/review-loop-close.js +106 -34
  67. package/dist/core/review-loop-turn-dispatch.js +445 -0
  68. package/dist/core/runtime-signals.js +68 -0
  69. package/dist/core/schema.js +34 -0
  70. package/dist/core/worktree.js +240 -22
  71. package/dist/facts.js +10 -10
  72. package/dist/facts.json +9 -9
  73. package/dist/wasm/tree-sitter-c.wasm +0 -0
  74. package/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
  75. package/dist/wasm/tree-sitter-cpp.wasm +0 -0
  76. package/dist/wasm/tree-sitter-go.wasm +0 -0
  77. package/dist/wasm/tree-sitter-ruby.wasm +0 -0
  78. package/dist/wasm/tree-sitter-rust.wasm +0 -0
  79. package/docs/cli.md +1 -1
  80. package/docs/code-map.md +22 -6
  81. package/docs/concepts/loop-engine.md +28 -2
  82. package/docs/concepts/observer-protocol.md +22 -0
  83. package/docs/integrations/codex.md +19 -3
  84. package/docs/mcp-schema-changelog.md +43 -1
  85. package/package.json +1 -1
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Code Map langs batch 2 — RubyProvider (provider #6).
3
+ *
4
+ * Owns `.rb` (runtime lang `ruby`). `extractDraft` delegates to the generic
5
+ * query-runtime; the curated `tags.scm`/`imports.scm` (this dir) drive extraction.
6
+ *
7
+ * Definitions (verified via dogfood against tree-sitter-ruby):
8
+ * - `class` -> class (name: a `constant`)
9
+ * - `module` -> namespace (name: a `constant`; Ruby modules are namespaces/mixins)
10
+ * - `method` (def) -> method (uniform capture)
11
+ * - `singleton_method` (def self.x) -> method (always a member method)
12
+ * - constant assignment (`FOO = ...`, left is a bare `constant`) -> constant
13
+ *
14
+ * refine() carries what the structural query CANNOT express (mirrors Python's
15
+ * dynamic-language refine):
16
+ * - a `method` whose enclosing scope is NOT a class/module (a TOP-LEVEL `def`, or a
17
+ * def nested inside another def/block) -> reclassified `function` (Ruby's
18
+ * module-level-function analog). A `method` directly in a class/module body stays
19
+ * `method`. `singleton_method` stays `method` regardless of location.
20
+ * - import sources: strip the surrounding quotes from the required string
21
+ * (`'sinatra'` -> `sinatra`). Defensive/idempotent — the query-runtime already
22
+ * strips quotes; kept to match the Go provider's documented pattern.
23
+ *
24
+ * Imports: Ruby has NO static import statement — `require`/`require_relative` are
25
+ * method CALLS. imports.scm captures those calls (a `#any-of?` predicate limits the
26
+ * match to the require family) and the module node `name` is the required string.
27
+ * Best-effort T2 only: no path resolution (T3 = none). NO exports edges — Ruby has
28
+ * no export statement (capabilities: T1.definitions + T2.imports).
29
+ *
30
+ * Identity is owned by the CORE finalizer — this provider mints NO ids. The grammar
31
+ * loads through the SHARED engine glue (`loadGrammarWasm`), never a fresh
32
+ * `web-tree-sitter` import (trp_8df65ab7).
33
+ */
34
+ import crypto from 'node:crypto';
35
+ import fs from 'node:fs';
36
+ import path from 'node:path';
37
+ import { fileURLToPath } from 'node:url';
38
+ import { loadGrammarWasm, grammarHashForWasm } from '../../wasm-loader.js';
39
+ import { extractWithQueries } from '../query-runtime.js';
40
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
41
+ const RUBY_WASM_BASENAME = 'tree-sitter-ruby.wasm';
42
+ const RUBY_WASM_NODE_MODULES_SPEC = 'tree-sitter-wasms/out/tree-sitter-ruby.wasm';
43
+ const RUBY_GRAMMAR_NAME = 'tree-sitter-ruby';
44
+ /** Resolve a vendored `.scm` next to this module (dist) or from the source tree. */
45
+ function readScm(basename) {
46
+ const local = path.join(HERE, basename);
47
+ if (fs.existsSync(local))
48
+ return fs.readFileSync(local, 'utf-8');
49
+ let dir = HERE;
50
+ for (let i = 0; i < 12; i++) {
51
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
52
+ const fromSrc = path.join(dir, 'src', 'core', 'code-map', 'lang', 'ruby', basename);
53
+ if (fs.existsSync(fromSrc))
54
+ return fs.readFileSync(fromSrc, 'utf-8');
55
+ break;
56
+ }
57
+ const parent = path.dirname(dir);
58
+ if (parent === dir)
59
+ break;
60
+ dir = parent;
61
+ }
62
+ throw new Error(`code-map: could not locate query asset ${basename} (from ${HERE})`);
63
+ }
64
+ function sha256(s) {
65
+ return `sha256:${crypto.createHash('sha256').update(s, 'utf-8').digest('hex')}`;
66
+ }
67
+ const TAGS = readScm('tags.scm');
68
+ const IMPORTS = readScm('imports.scm');
69
+ const TAGS_HASH = sha256(TAGS);
70
+ const IMPORTS_HASH = sha256(IMPORTS);
71
+ const parser = {
72
+ grammarForLang: () => loadGrammarWasm(RUBY_WASM_BASENAME, RUBY_WASM_NODE_MODULES_SPEC),
73
+ grammarNameForLang: () => RUBY_GRAMMAR_NAME,
74
+ grammarHashForLang: () => grammarHashForWasm(RUBY_WASM_BASENAME, RUBY_WASM_NODE_MODULES_SPEC),
75
+ };
76
+ const queries = {
77
+ tags: { name: 'tags', sourceForLang: () => TAGS, hashForLang: () => TAGS_HASH },
78
+ imports: { name: 'imports', sourceForLang: () => IMPORTS, hashForLang: () => IMPORTS_HASH },
79
+ // Ruby has no import statement — the require CALL is the span/ordinal anchor.
80
+ enclosingStatementNodeTypes: ['call'],
81
+ captureMap: [
82
+ { capture: 'definition.class.node', field: 'node', subtype: 'class' },
83
+ { capture: 'definition.class.name', field: 'name' },
84
+ { capture: 'definition.namespace.node', field: 'node', subtype: 'namespace' },
85
+ { capture: 'definition.namespace.name', field: 'name' },
86
+ { capture: 'definition.method.node', field: 'node', subtype: 'method' },
87
+ { capture: 'definition.method.name', field: 'name' },
88
+ { capture: 'definition.constant.node', field: 'node', subtype: 'constant' },
89
+ { capture: 'definition.constant.name', field: 'name' },
90
+ { capture: 'import.source', field: 'source' },
91
+ ],
92
+ };
93
+ const vocabulary = {
94
+ nodeSubtypes: ['class', 'namespace', 'method', 'function', 'constant'],
95
+ edgeKinds: ['contains', 'defines', 'imports'],
96
+ captureMap: queries.captureMap,
97
+ };
98
+ const capabilities = {
99
+ tiers: ['T1.definitions', 'T2.imports'],
100
+ proven: {
101
+ 'T1.definitions': true,
102
+ 'T2.imports': true,
103
+ 'T3.import_resolution': false,
104
+ 'T4.tests_for': false,
105
+ },
106
+ };
107
+ /** Strip the surrounding quotes from a required-string import path. */
108
+ function stripQuotes(s) {
109
+ return s.replace(/^['"`]/, '').replace(/['"`]$/, '');
110
+ }
111
+ function isDefSourceNode(v) {
112
+ return (typeof v === 'object' &&
113
+ v !== null &&
114
+ 'node' in v &&
115
+ typeof v.node === 'object');
116
+ }
117
+ /**
118
+ * True iff `defNode` (a `method`) is a member of a class/module — i.e. directly owned
119
+ * by a class/module body. tree-sitter-ruby nests a def's statements under a
120
+ * `body_statement` whose parent is the enclosing `class`/`module`/`singleton_class`;
121
+ * a TOP-LEVEL def's parent is `program` (no body_statement wrapper), and a def nested
122
+ * in another def/block has a `body_statement` whose parent is that def/block (not a
123
+ * class/module). So a member method is exactly: parent `body_statement` whose parent
124
+ * is `class` | `module` | `singleton_class`.
125
+ */
126
+ function isClassOrModuleMember(defNode) {
127
+ const owner = defNode.parent;
128
+ if (!owner || owner.type !== 'body_statement')
129
+ return false;
130
+ const container = owner.parent;
131
+ if (!container)
132
+ return false;
133
+ return (container.type === 'class' ||
134
+ container.type === 'module' ||
135
+ container.type === 'singleton_class');
136
+ }
137
+ export class RubyProvider {
138
+ id = 'ruby';
139
+ displayName = 'Ruby';
140
+ languages = ['ruby'];
141
+ extensions = ['.rb'];
142
+ priority = 0;
143
+ version = '0.1.0';
144
+ parser = parser;
145
+ queries = queries;
146
+ vocabulary = vocabulary;
147
+ capabilities = capabilities;
148
+ langForPath(_p) {
149
+ return 'ruby';
150
+ }
151
+ async extractDraft(input, _services) {
152
+ return extractWithQueries({
153
+ providerId: this.id,
154
+ lang: input.lang,
155
+ source: input.source,
156
+ sizeBytes: input.sizeBytes,
157
+ maxParseFileBytes: input.maxParseFileBytes,
158
+ maxQueryWaitMs: input.maxQueryWaitMs,
159
+ path: input.path,
160
+ grammarForLang: this.parser.grammarForLang,
161
+ tagsSource: TAGS,
162
+ tagsHash: TAGS_HASH,
163
+ importsSource: IMPORTS,
164
+ importsHash: IMPORTS_HASH,
165
+ enclosingStatementNodeTypes: queries.enclosingStatementNodeTypes,
166
+ });
167
+ }
168
+ /**
169
+ * Drafts-only refinement:
170
+ * - a `method` def whose enclosing scope is NOT a class/module body -> `function`
171
+ * (top-level defs + defs nested in another def/block); `singleton_method` and
172
+ * class/module-body `method`s stay `method`.
173
+ * - strip the surrounding quotes from each import source (defensive/idempotent).
174
+ */
175
+ refine(draft, _ctx) {
176
+ const definitions = draft.definitions.map((d) => {
177
+ if (d.subtype !== 'method')
178
+ return d;
179
+ const src = isDefSourceNode(d.sourceNode) ? d.sourceNode : null;
180
+ if (!src)
181
+ return d;
182
+ // singleton_method (def self.x) is always a member method.
183
+ if (src.node.type === 'singleton_method')
184
+ return d;
185
+ // A plain `method` (def) is a `function` unless it is a class/module member.
186
+ return isClassOrModuleMember(src.node) ? d : setSubtype(d, 'function');
187
+ });
188
+ const imports = draft.imports.length === 0
189
+ ? draft.imports
190
+ : draft.imports.map((im) => ({ ...im, source: stripQuotes(im.source) }));
191
+ return { ...draft, definitions, imports };
192
+ }
193
+ }
194
+ function setSubtype(d, subtype) {
195
+ return d.subtype === subtype ? d : { ...d, subtype };
196
+ }
197
+ export const rubyProvider = new RubyProvider();
198
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,49 @@
1
+ ; Code Map — Ruby definitions (tags.scm). Provider #6 (langs batch 2).
2
+ ;
3
+ ; Capture-name convention (query-runtime.ts is the contract):
4
+ ; @definition.<subtype>.node = identity-span anchor (the declaration)
5
+ ; @definition.<subtype>.name = the symbol name node
6
+ ;
7
+ ; Subtype mapping (verified against tree-sitter-ruby via dogfood):
8
+ ; class -> class (name: a (constant))
9
+ ; module -> namespace (name: a (constant); Ruby modules are namespaces/mixins)
10
+ ; method (def ...) -> method (name: any node — identifier/operator/setter)
11
+ ; singleton_method (def self.x) -> method (always a member method)
12
+ ; constant assignment (FOO = ...) -> constant (left is a bare (constant))
13
+ ;
14
+ ; TOP-LEVEL vs CLASS/MODULE def: `method` is captured UNIFORMLY as
15
+ ; @definition.method (like Python captures every function_definition as function).
16
+ ; The provider's refine() reclassifies a `method` whose enclosing scope is NOT a
17
+ ; class/module body (i.e. a top-level `def`, or a def nested in another def/block)
18
+ ; to `function` — mirroring Python's module-level-function analog. `singleton_method`
19
+ ; stays `method` regardless of location (def self.x is a member method by intent).
20
+ ; refine() must do this because the structural query cannot inspect the enclosing
21
+ ; scope chain (query-runtime nests every def under a `body_statement`).
22
+ ;
23
+ ; The method `name:` field is captured with `(_)` (any node) so operator/setter
24
+ ; methods (`def <=>`, `def []`, `def foo=`) are captured too, not just identifiers.
25
+ ;
26
+ ; NAMESPACED constant assignments (`Foo::BAR = 1`, left is a `scope_resolution`,
27
+ ; NOT a bare `constant`) are intentionally NOT captured in v1 — low value and the
28
+ ; bare-constant pattern below deliberately does not match them.
29
+
30
+ (class
31
+ name: (constant) @definition.class.name) @definition.class.node
32
+
33
+ (module
34
+ name: (constant) @definition.namespace.name) @definition.namespace.node
35
+
36
+ ; def foo / def <=> / def foo= — captured uniformly; refine() may narrow a
37
+ ; non-class/module-body method to `function`.
38
+ (method
39
+ name: (_) @definition.method.name) @definition.method.node
40
+
41
+ ; def self.foo — a singleton (class-level) method; always `method`.
42
+ (singleton_method
43
+ name: (_) @definition.method.name) @definition.method.node
44
+
45
+ ; FOO = ... — a constant assignment (left is a bare constant). Captured at ANY depth
46
+ ; (top-level, class body, module body) — a Ruby constant is a meaningful symbol
47
+ ; wherever it is declared (parity with Go's const capture).
48
+ (assignment
49
+ left: (constant) @definition.constant.name) @definition.constant.node
@@ -0,0 +1,44 @@
1
+ ; Code Map — Rust imports (imports.scm). Provider #6 (langs batch 2).
2
+ ;
3
+ ; enclosingStatementNodeTypes = [use_declaration] (the import span/ordinal anchor).
4
+ ; Rust `use` paths are bare `a::b::c` (NO quotes) so — unlike Go — nothing to strip,
5
+ ; and the common use-tree shapes expand STRUCTURALLY in the query (no refine()):
6
+ ; use a::b::c; -> module a::b::c
7
+ ; use foo; -> module foo
8
+ ; use a::b::{c, d}; -> module a::b + imported names c, d (group-use)
9
+ ; use a::b as c; -> module a::b + imported name c (alias)
10
+ ; use a::b::*; -> module a::b + imported name '*' (wildcard)
11
+ ; Grouping is keyed by the captured @import.source NODE (query-runtime), so the two
12
+ ; matches a `{c, d}` list produces share one source node -> one module with names
13
+ ; [c, d].
14
+ ;
15
+ ; v1 limitations (documented, not bugs): NESTED use-trees `use a::{b, c::{d}}` capture
16
+ ; only the top path `a` + the direct-identifier members (the nested `c::{…}` subtree
17
+ ; is dropped); `use a::{self, b}` drops the `self`; `pub use` re-exports are treated
18
+ ; as plain imports (NO exports edge — Rust re-export modelling deferred, capabilities
19
+ ; declare T2 imports only).
20
+
21
+ ; use a::b::c; / use foo; (direct scoped/plain path is the module source)
22
+ (use_declaration
23
+ argument: [
24
+ (scoped_identifier)
25
+ (identifier)
26
+ ] @import.source)
27
+
28
+ ; use a::b::{c, d}; -> source a::b, imported names c, d
29
+ (use_declaration
30
+ argument: (scoped_use_list
31
+ path: [(scoped_identifier) (identifier)] @import.source
32
+ list: (use_list (identifier) @import.named.name)))
33
+
34
+ ; use a::b as c; -> source a::b, imported name c
35
+ (use_declaration
36
+ argument: (use_as_clause
37
+ path: [(scoped_identifier) (identifier)] @import.source
38
+ alias: (identifier) @import.named.name))
39
+
40
+ ; use a::b::*; -> source a::b, imported name '*'
41
+ (use_declaration
42
+ argument: (use_wildcard
43
+ [(scoped_identifier) (identifier)] @import.source
44
+ "*" @import.namespace.name))
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Code Map langs batch 2 — RustProvider (provider #6).
3
+ *
4
+ * Owns `.rs` (runtime lang `rust`). `extractDraft` delegates to the generic
5
+ * query-runtime; the curated `tags.scm`/`imports.scm` (this dir) drive extraction.
6
+ * Definition subtypes are fixed by the query (struct→class, enum/function/constant/
7
+ * type/macro/namespace universal, `trait`→namespaced `rust.trait`). Rust methods are
8
+ * `function_item` nodes nested in an impl/trait body — the SAME node type as a free
9
+ * `fn` — so v1 maps ALL `function_item`→function (no `method` subtype; tree-sitter
10
+ * can't express "not inside an impl").
11
+ *
12
+ * NO `refine()` — Rust `use` paths are bare `a::b::c` (no quotes to strip), and the
13
+ * common use-tree shapes (group `{a,b}`, `as` alias, `*` wildcard) expand
14
+ * STRUCTURALLY in imports.scm via the runtime's per-`@import.source`-node grouping.
15
+ *
16
+ * NO exports edges — `pub use` re-export modelling is deferred (capabilities: T2 =
17
+ * imports). Identity is owned by the CORE finalizer — this provider mints NO ids.
18
+ * The grammar loads through the SHARED engine glue (`loadGrammarWasm`), never a
19
+ * fresh `web-tree-sitter` import (trp_8df65ab7).
20
+ */
21
+ import crypto from 'node:crypto';
22
+ import fs from 'node:fs';
23
+ import path from 'node:path';
24
+ import { fileURLToPath } from 'node:url';
25
+ import { loadGrammarWasm, grammarHashForWasm } from '../../wasm-loader.js';
26
+ import { extractWithQueries } from '../query-runtime.js';
27
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
28
+ const RUST_WASM_BASENAME = 'tree-sitter-rust.wasm';
29
+ const RUST_WASM_NODE_MODULES_SPEC = 'tree-sitter-wasms/out/tree-sitter-rust.wasm';
30
+ const RUST_GRAMMAR_NAME = 'tree-sitter-rust';
31
+ /** Resolve a vendored `.scm` next to this module (dist) or from the source tree. */
32
+ function readScm(basename) {
33
+ const local = path.join(HERE, basename);
34
+ if (fs.existsSync(local))
35
+ return fs.readFileSync(local, 'utf-8');
36
+ let dir = HERE;
37
+ for (let i = 0; i < 12; i++) {
38
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
39
+ const fromSrc = path.join(dir, 'src', 'core', 'code-map', 'lang', 'rust', basename);
40
+ if (fs.existsSync(fromSrc))
41
+ return fs.readFileSync(fromSrc, 'utf-8');
42
+ break;
43
+ }
44
+ const parent = path.dirname(dir);
45
+ if (parent === dir)
46
+ break;
47
+ dir = parent;
48
+ }
49
+ throw new Error(`code-map: could not locate query asset ${basename} (from ${HERE})`);
50
+ }
51
+ function sha256(s) {
52
+ return `sha256:${crypto.createHash('sha256').update(s, 'utf-8').digest('hex')}`;
53
+ }
54
+ const TAGS = readScm('tags.scm');
55
+ const IMPORTS = readScm('imports.scm');
56
+ const TAGS_HASH = sha256(TAGS);
57
+ const IMPORTS_HASH = sha256(IMPORTS);
58
+ const parser = {
59
+ grammarForLang: () => loadGrammarWasm(RUST_WASM_BASENAME, RUST_WASM_NODE_MODULES_SPEC),
60
+ grammarNameForLang: () => RUST_GRAMMAR_NAME,
61
+ grammarHashForLang: () => grammarHashForWasm(RUST_WASM_BASENAME, RUST_WASM_NODE_MODULES_SPEC),
62
+ };
63
+ const queries = {
64
+ tags: { name: 'tags', sourceForLang: () => TAGS, hashForLang: () => TAGS_HASH },
65
+ imports: { name: 'imports', sourceForLang: () => IMPORTS, hashForLang: () => IMPORTS_HASH },
66
+ enclosingStatementNodeTypes: ['use_declaration'],
67
+ captureMap: [
68
+ { capture: 'definition.function.node', field: 'node', subtype: 'function' },
69
+ { capture: 'definition.function.name', field: 'name' },
70
+ { capture: 'definition.class.node', field: 'node', subtype: 'class' },
71
+ { capture: 'definition.class.name', field: 'name' },
72
+ { capture: 'definition.enum.node', field: 'node', subtype: 'enum' },
73
+ { capture: 'definition.enum.name', field: 'name' },
74
+ { capture: 'definition.rust.trait.node', field: 'node', subtype: 'rust.trait' },
75
+ { capture: 'definition.rust.trait.name', field: 'name' },
76
+ { capture: 'definition.namespace.node', field: 'node', subtype: 'namespace' },
77
+ { capture: 'definition.namespace.name', field: 'name' },
78
+ { capture: 'definition.constant.node', field: 'node', subtype: 'constant' },
79
+ { capture: 'definition.constant.name', field: 'name' },
80
+ { capture: 'definition.type.node', field: 'node', subtype: 'type' },
81
+ { capture: 'definition.type.name', field: 'name' },
82
+ { capture: 'definition.macro.node', field: 'node', subtype: 'macro' },
83
+ { capture: 'definition.macro.name', field: 'name' },
84
+ { capture: 'import.source', field: 'source' },
85
+ { capture: 'import.named.name', field: 'name' },
86
+ { capture: 'import.namespace.name', field: 'name' },
87
+ ],
88
+ };
89
+ const vocabulary = {
90
+ nodeSubtypes: ['function', 'class', 'enum', 'rust.trait', 'namespace', 'constant', 'type', 'macro'],
91
+ edgeKinds: ['contains', 'defines', 'imports'],
92
+ captureMap: queries.captureMap,
93
+ };
94
+ const capabilities = {
95
+ tiers: ['T1.definitions', 'T2.imports'],
96
+ proven: {
97
+ 'T1.definitions': true,
98
+ 'T2.imports': true,
99
+ 'T3.import_resolution': false,
100
+ 'T4.tests_for': false,
101
+ },
102
+ };
103
+ export class RustProvider {
104
+ id = 'rust';
105
+ displayName = 'Rust';
106
+ languages = ['rust'];
107
+ extensions = ['.rs'];
108
+ priority = 0;
109
+ version = '0.1.0';
110
+ parser = parser;
111
+ queries = queries;
112
+ vocabulary = vocabulary;
113
+ capabilities = capabilities;
114
+ langForPath(_p) {
115
+ return 'rust';
116
+ }
117
+ async extractDraft(input, _services) {
118
+ return extractWithQueries({
119
+ providerId: this.id,
120
+ lang: input.lang,
121
+ source: input.source,
122
+ sizeBytes: input.sizeBytes,
123
+ maxParseFileBytes: input.maxParseFileBytes,
124
+ maxQueryWaitMs: input.maxQueryWaitMs,
125
+ path: input.path,
126
+ grammarForLang: this.parser.grammarForLang,
127
+ tagsSource: TAGS,
128
+ tagsHash: TAGS_HASH,
129
+ importsSource: IMPORTS,
130
+ importsHash: IMPORTS_HASH,
131
+ enclosingStatementNodeTypes: queries.enclosingStatementNodeTypes,
132
+ });
133
+ }
134
+ }
135
+ export const rustProvider = new RustProvider();
136
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,47 @@
1
+ ; Code Map — Rust definitions (tags.scm). Provider #6 (langs batch 2).
2
+ ;
3
+ ; Capture-name convention (query-runtime.ts is the contract):
4
+ ; @definition.<subtype>.node = identity-span anchor (the whole declaration)
5
+ ; @definition.<subtype>.name = the symbol name node
6
+ ; Subtypes: function/enum/namespace/constant/type/macro are universal; a Rust
7
+ ; struct maps to `class` (the named aggregate devs search for like a class), and a
8
+ ; `trait` has no clean universal equal (it carries default methods + associated
9
+ ; types/consts, unlike a plain interface) so it is NAMESPACED as `rust.trait`
10
+ ; (guide §"when to namespace" cites this exact case).
11
+ ;
12
+ ; METHOD caveat (v1): Rust methods are `function_item` nodes nested in an
13
+ ; `impl_item` (or `trait_item`) body — the SAME node type as a free `fn`. Tree-sitter
14
+ ; queries can't express "function_item NOT inside an impl", so a single generic
15
+ ; pattern maps ALL `function_item` -> `function` (no distinct `method` subtype in
16
+ ; v1). Trait method *signatures* (`function_signature_item`, no body) are a distinct
17
+ ; node type and are intentionally NOT captured in v1.
18
+ ;
19
+ ; const + static both map to `constant`; associated const/type inside impl/trait
20
+ ; reuse the const_item/type_item patterns (captured as constant/type — acceptable).
21
+
22
+ (function_item
23
+ name: (identifier) @definition.function.name) @definition.function.node
24
+
25
+ (struct_item
26
+ name: (type_identifier) @definition.class.name) @definition.class.node
27
+
28
+ (enum_item
29
+ name: (type_identifier) @definition.enum.name) @definition.enum.node
30
+
31
+ (trait_item
32
+ name: (type_identifier) @definition.rust.trait.name) @definition.rust.trait.node
33
+
34
+ (mod_item
35
+ name: (identifier) @definition.namespace.name) @definition.namespace.node
36
+
37
+ (const_item
38
+ name: (identifier) @definition.constant.name) @definition.constant.node
39
+
40
+ (static_item
41
+ name: (identifier) @definition.constant.name) @definition.constant.node
42
+
43
+ (type_item
44
+ name: (type_identifier) @definition.type.name) @definition.type.node
45
+
46
+ (macro_definition
47
+ name: (identifier) @definition.macro.name) @definition.macro.node