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.
- package/README.md +22 -8
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli/register-review.js +2 -2
- package/dist/commands/code-map.js +4 -1
- package/dist/commands/codev.js +61 -30
- package/dist/commands/doctor.js +14 -1
- package/dist/commands/harvest.js +241 -25
- package/dist/commands/inbox.js +10 -4
- package/dist/commands/loop.js +2 -2
- package/dist/commands/loops-handlers.js +82 -1
- package/dist/commands/mcp-catalog.js +12 -4
- package/dist/commands/mcp-read-handlers.js +90 -7
- package/dist/commands/mcp-schemas.generated.js +3 -0
- package/dist/commands/mcp-write-coordination.js +159 -40
- package/dist/commands/mcp.js +11 -2
- package/dist/core/agent-capability.js +7 -2
- package/dist/core/agent-files.js +53 -2
- package/dist/core/agent-integrations.js +1 -0
- package/dist/core/agentrun-reconciler.js +171 -7
- package/dist/core/agentruns.js +6 -1
- package/dist/core/code-map/aggregate.js +473 -0
- package/dist/core/code-map/backend.js +36 -10
- package/dist/core/code-map/freshness.js +36 -1
- package/dist/core/code-map/lang/c/imports.scm +12 -0
- package/dist/core/code-map/lang/c/index.js +150 -0
- package/dist/core/code-map/lang/c/tags.scm +68 -0
- package/dist/core/code-map/lang/cpp/imports.scm +14 -0
- package/dist/core/code-map/lang/cpp/index.js +149 -0
- package/dist/core/code-map/lang/cpp/tags.scm +87 -0
- package/dist/core/code-map/lang/csharp/imports.scm +20 -0
- package/dist/core/code-map/lang/csharp/index.js +224 -0
- package/dist/core/code-map/lang/csharp/tags.scm +63 -0
- package/dist/core/code-map/lang/go/imports.scm +13 -0
- package/dist/core/code-map/lang/go/index.js +139 -0
- package/dist/core/code-map/lang/go/tags.scm +36 -0
- package/dist/core/code-map/lang/providers.js +12 -1
- package/dist/core/code-map/lang/ruby/imports.scm +24 -0
- package/dist/core/code-map/lang/ruby/index.js +198 -0
- package/dist/core/code-map/lang/ruby/tags.scm +49 -0
- package/dist/core/code-map/lang/rust/imports.scm +44 -0
- package/dist/core/code-map/lang/rust/index.js +136 -0
- package/dist/core/code-map/lang/rust/tags.scm +47 -0
- package/dist/core/code-map/query.js +229 -80
- package/dist/core/code-map/types.js +18 -0
- package/dist/core/code-map/work-section.js +8 -7
- package/dist/core/codev-responses.js +16 -0
- package/dist/core/dispatcher.js +209 -29
- package/dist/core/execution-adapters.js +29 -3
- package/dist/core/ideation-loop-close.js +124 -0
- package/dist/core/loops/artifact-resolver.js +197 -0
- package/dist/core/loops/attempt-reservation.js +576 -0
- package/dist/core/loops/commit-intent.js +494 -0
- package/dist/core/loops/facade-schema.js +48 -0
- package/dist/core/loops/impl-bind.js +144 -0
- package/dist/core/loops/index.js +1 -1
- package/dist/core/loops/iteration-engine.js +29 -0
- package/dist/core/loops/lock.js +14 -0
- package/dist/core/loops/project-resolution.js +157 -0
- package/dist/core/loops/reconcile-turn.js +369 -0
- package/dist/core/loops/result-reducers.js +88 -0
- package/dist/core/loops/store.js +46 -7
- package/dist/core/loops/types.js +139 -11
- package/dist/core/loops/verbs.js +9 -3
- package/dist/core/loops/verify-command.js +209 -0
- package/dist/core/messaging.js +58 -5
- package/dist/core/review-loop-close.js +106 -34
- package/dist/core/review-loop-turn-dispatch.js +445 -0
- package/dist/core/runtime-signals.js +68 -0
- package/dist/core/schema.js +34 -0
- package/dist/core/worktree.js +240 -22
- package/dist/facts.js +10 -10
- package/dist/facts.json +9 -9
- package/dist/wasm/tree-sitter-c.wasm +0 -0
- package/dist/wasm/tree-sitter-c_sharp.wasm +0 -0
- package/dist/wasm/tree-sitter-cpp.wasm +0 -0
- package/dist/wasm/tree-sitter-go.wasm +0 -0
- package/dist/wasm/tree-sitter-ruby.wasm +0 -0
- package/dist/wasm/tree-sitter-rust.wasm +0 -0
- package/docs/cli.md +1 -1
- package/docs/code-map.md +22 -6
- package/docs/concepts/loop-engine.md +28 -2
- package/docs/concepts/observer-protocol.md +22 -0
- package/docs/integrations/codex.md +19 -3
- package/docs/mcp-schema-changelog.md +43 -1
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Map langs batch 2 — CProvider (provider #6).
|
|
3
|
+
*
|
|
4
|
+
* Owns `.c` / `.h` (runtime lang `c`). `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: a named C struct maps to `class`
|
|
7
|
+
* (the named aggregate devs search for like a class), a union → `c.union`
|
|
8
|
+
* (provider-namespaced — no universal peer), enum/typedef(→type)/`#define`(→macro)
|
|
9
|
+
* are universal, and `function_definition` → function. The function NAME is nested
|
|
10
|
+
* inside `function_declarator declarator: (identifier)`, wrapped in a
|
|
11
|
+
* `pointer_declarator` per `*` on the return type — the tags query enumerates the
|
|
12
|
+
* 0..3 pointer-depth alternatives (see tags.scm).
|
|
13
|
+
*
|
|
14
|
+
* `refine()` carries only what the import query cannot express structurally: a C
|
|
15
|
+
* `#include` path is either a `<...>` system-lib token or a `"..."` string literal,
|
|
16
|
+
* so the captured @import.source keeps its angle brackets / quotes — strip them to
|
|
17
|
+
* the bare header path. NO exports edges — C has no export statement (capabilities:
|
|
18
|
+
* T2 = imports). Identity is owned by the CORE finalizer — this provider mints NO
|
|
19
|
+
* ids. The grammar loads through the SHARED engine glue (`loadGrammarWasm`), never
|
|
20
|
+
* a fresh `web-tree-sitter` import (trp_8df65ab7).
|
|
21
|
+
*/
|
|
22
|
+
import crypto from 'node:crypto';
|
|
23
|
+
import fs from 'node:fs';
|
|
24
|
+
import path from 'node:path';
|
|
25
|
+
import { fileURLToPath } from 'node:url';
|
|
26
|
+
import { loadGrammarWasm, grammarHashForWasm } from '../../wasm-loader.js';
|
|
27
|
+
import { extractWithQueries } from '../query-runtime.js';
|
|
28
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
const C_WASM_BASENAME = 'tree-sitter-c.wasm';
|
|
30
|
+
const C_WASM_NODE_MODULES_SPEC = 'tree-sitter-wasms/out/tree-sitter-c.wasm';
|
|
31
|
+
const C_GRAMMAR_NAME = 'tree-sitter-c';
|
|
32
|
+
/** Resolve a vendored `.scm` next to this module (dist) or from the source tree. */
|
|
33
|
+
function readScm(basename) {
|
|
34
|
+
const local = path.join(HERE, basename);
|
|
35
|
+
if (fs.existsSync(local))
|
|
36
|
+
return fs.readFileSync(local, 'utf-8');
|
|
37
|
+
let dir = HERE;
|
|
38
|
+
for (let i = 0; i < 12; i++) {
|
|
39
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
40
|
+
const fromSrc = path.join(dir, 'src', 'core', 'code-map', 'lang', 'c', basename);
|
|
41
|
+
if (fs.existsSync(fromSrc))
|
|
42
|
+
return fs.readFileSync(fromSrc, 'utf-8');
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
const parent = path.dirname(dir);
|
|
46
|
+
if (parent === dir)
|
|
47
|
+
break;
|
|
48
|
+
dir = parent;
|
|
49
|
+
}
|
|
50
|
+
throw new Error(`code-map: could not locate query asset ${basename} (from ${HERE})`);
|
|
51
|
+
}
|
|
52
|
+
function sha256(s) {
|
|
53
|
+
return `sha256:${crypto.createHash('sha256').update(s, 'utf-8').digest('hex')}`;
|
|
54
|
+
}
|
|
55
|
+
const TAGS = readScm('tags.scm');
|
|
56
|
+
const IMPORTS = readScm('imports.scm');
|
|
57
|
+
const TAGS_HASH = sha256(TAGS);
|
|
58
|
+
const IMPORTS_HASH = sha256(IMPORTS);
|
|
59
|
+
const parser = {
|
|
60
|
+
grammarForLang: () => loadGrammarWasm(C_WASM_BASENAME, C_WASM_NODE_MODULES_SPEC),
|
|
61
|
+
grammarNameForLang: () => C_GRAMMAR_NAME,
|
|
62
|
+
grammarHashForLang: () => grammarHashForWasm(C_WASM_BASENAME, C_WASM_NODE_MODULES_SPEC),
|
|
63
|
+
};
|
|
64
|
+
const queries = {
|
|
65
|
+
tags: { name: 'tags', sourceForLang: () => TAGS, hashForLang: () => TAGS_HASH },
|
|
66
|
+
imports: { name: 'imports', sourceForLang: () => IMPORTS, hashForLang: () => IMPORTS_HASH },
|
|
67
|
+
enclosingStatementNodeTypes: ['preproc_include'],
|
|
68
|
+
captureMap: [
|
|
69
|
+
{ capture: 'definition.function.node', field: 'node', subtype: 'function' },
|
|
70
|
+
{ capture: 'definition.function.name', field: 'name' },
|
|
71
|
+
{ capture: 'definition.class.node', field: 'node', subtype: 'class' },
|
|
72
|
+
{ capture: 'definition.class.name', field: 'name' },
|
|
73
|
+
{ capture: 'definition.c.union.node', field: 'node', subtype: 'c.union' },
|
|
74
|
+
{ capture: 'definition.c.union.name', field: 'name' },
|
|
75
|
+
{ capture: 'definition.enum.node', field: 'node', subtype: 'enum' },
|
|
76
|
+
{ capture: 'definition.enum.name', field: 'name' },
|
|
77
|
+
{ capture: 'definition.type.node', field: 'node', subtype: 'type' },
|
|
78
|
+
{ capture: 'definition.type.name', field: 'name' },
|
|
79
|
+
{ capture: 'definition.macro.node', field: 'node', subtype: 'macro' },
|
|
80
|
+
{ capture: 'definition.macro.name', field: 'name' },
|
|
81
|
+
{ capture: 'import.source', field: 'source' },
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
const vocabulary = {
|
|
85
|
+
nodeSubtypes: ['function', 'class', 'c.union', 'enum', 'type', 'macro'],
|
|
86
|
+
edgeKinds: ['contains', 'defines', 'imports'],
|
|
87
|
+
captureMap: queries.captureMap,
|
|
88
|
+
};
|
|
89
|
+
const capabilities = {
|
|
90
|
+
tiers: ['T1.definitions', 'T2.imports'],
|
|
91
|
+
proven: {
|
|
92
|
+
'T1.definitions': true,
|
|
93
|
+
'T2.imports': true,
|
|
94
|
+
'T3.import_resolution': false,
|
|
95
|
+
'T4.tests_for': false,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* Strip the wrapping from a C `#include` path token: `<stdio.h>` → `stdio.h`
|
|
100
|
+
* (angle brackets) or `"config.h"` → `config.h` (double quotes). Leaves an
|
|
101
|
+
* already-bare path untouched.
|
|
102
|
+
*/
|
|
103
|
+
function stripIncludeWrapping(s) {
|
|
104
|
+
if (s.length >= 2 && s.startsWith('<') && s.endsWith('>'))
|
|
105
|
+
return s.slice(1, -1);
|
|
106
|
+
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"'))
|
|
107
|
+
return s.slice(1, -1);
|
|
108
|
+
return s;
|
|
109
|
+
}
|
|
110
|
+
export class CProvider {
|
|
111
|
+
id = 'c';
|
|
112
|
+
displayName = 'C';
|
|
113
|
+
languages = ['c'];
|
|
114
|
+
extensions = ['.c', '.h'];
|
|
115
|
+
priority = 0;
|
|
116
|
+
version = '0.1.0';
|
|
117
|
+
parser = parser;
|
|
118
|
+
queries = queries;
|
|
119
|
+
vocabulary = vocabulary;
|
|
120
|
+
capabilities = capabilities;
|
|
121
|
+
langForPath(_p) {
|
|
122
|
+
return 'c';
|
|
123
|
+
}
|
|
124
|
+
async extractDraft(input, _services) {
|
|
125
|
+
return extractWithQueries({
|
|
126
|
+
providerId: this.id,
|
|
127
|
+
lang: input.lang,
|
|
128
|
+
source: input.source,
|
|
129
|
+
sizeBytes: input.sizeBytes,
|
|
130
|
+
maxParseFileBytes: input.maxParseFileBytes,
|
|
131
|
+
maxQueryWaitMs: input.maxQueryWaitMs,
|
|
132
|
+
path: input.path,
|
|
133
|
+
grammarForLang: this.parser.grammarForLang,
|
|
134
|
+
tagsSource: TAGS,
|
|
135
|
+
tagsHash: TAGS_HASH,
|
|
136
|
+
importsSource: IMPORTS,
|
|
137
|
+
importsHash: IMPORTS_HASH,
|
|
138
|
+
enclosingStatementNodeTypes: queries.enclosingStatementNodeTypes,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/** Drafts-only: strip the `<...>`/`"..."` wrapping from each include path. */
|
|
142
|
+
refine(draft, _ctx) {
|
|
143
|
+
if (draft.imports.length === 0)
|
|
144
|
+
return draft;
|
|
145
|
+
const imports = draft.imports.map((im) => ({ ...im, source: stripIncludeWrapping(im.source) }));
|
|
146
|
+
return { ...draft, imports };
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export const cProvider = new CProvider();
|
|
150
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
; Code Map — C 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/type/enum/macro are universal; a named C struct maps to
|
|
7
|
+
; `class` (the named aggregate devs search for like a class); a union has no
|
|
8
|
+
; universal peer so it is provider-namespaced → `c.union`.
|
|
9
|
+
;
|
|
10
|
+
; C's function grammar is NESTED: a function_definition's name lives inside a
|
|
11
|
+
; `function_declarator declarator: (identifier)`, and that function_declarator is
|
|
12
|
+
; wrapped in one `pointer_declarator` PER `*` on the return type
|
|
13
|
+
; (`char *f()` → 1 level, `char **f()` → 2). Tree-sitter queries can't express
|
|
14
|
+
; arbitrary depth, so the `declarator:` field is an alternation covering 0..3
|
|
15
|
+
; pointer levels (covers all real C; 3 stars on a return type is already exotic).
|
|
16
|
+
;
|
|
17
|
+
; struct/union/enum REQUIRE a `body:` so only real DEFINITIONS are captured, never
|
|
18
|
+
; references. Without it, `typedef struct Point PointT;` (an aggregate REFERENCE)
|
|
19
|
+
; would double-capture a phantom `class:Point` at a second span. The named-aggregate
|
|
20
|
+
; struct DEFINITION inside a `typedef struct Foo {..} Bar;` still matches (it has a
|
|
21
|
+
; body) and coexists with the typedef's `type:Bar` — genuinely two named entities.
|
|
22
|
+
|
|
23
|
+
(function_definition
|
|
24
|
+
declarator: [
|
|
25
|
+
(function_declarator
|
|
26
|
+
declarator: (identifier) @definition.function.name)
|
|
27
|
+
(pointer_declarator
|
|
28
|
+
(function_declarator
|
|
29
|
+
declarator: (identifier) @definition.function.name))
|
|
30
|
+
(pointer_declarator
|
|
31
|
+
(pointer_declarator
|
|
32
|
+
(function_declarator
|
|
33
|
+
declarator: (identifier) @definition.function.name)))
|
|
34
|
+
(pointer_declarator
|
|
35
|
+
(pointer_declarator
|
|
36
|
+
(pointer_declarator
|
|
37
|
+
(function_declarator
|
|
38
|
+
declarator: (identifier) @definition.function.name))))
|
|
39
|
+
]) @definition.function.node
|
|
40
|
+
|
|
41
|
+
(struct_specifier
|
|
42
|
+
name: (type_identifier) @definition.class.name
|
|
43
|
+
body: (field_declaration_list)) @definition.class.node
|
|
44
|
+
|
|
45
|
+
(union_specifier
|
|
46
|
+
name: (type_identifier) @definition.c.union.name
|
|
47
|
+
body: (field_declaration_list)) @definition.c.union.node
|
|
48
|
+
|
|
49
|
+
(enum_specifier
|
|
50
|
+
name: (type_identifier) @definition.enum.name
|
|
51
|
+
body: (enumerator_list)) @definition.enum.node
|
|
52
|
+
|
|
53
|
+
; typedefs are structurally varied; capture the declared name best-effort — the
|
|
54
|
+
; bare declared type_identifier and the `typedef char *Str;` pointer wrapping.
|
|
55
|
+
(type_definition
|
|
56
|
+
declarator: (type_identifier) @definition.type.name) @definition.type.node
|
|
57
|
+
|
|
58
|
+
(type_definition
|
|
59
|
+
declarator: (pointer_declarator
|
|
60
|
+
declarator: (type_identifier) @definition.type.name)) @definition.type.node
|
|
61
|
+
|
|
62
|
+
; `#define NAME value` and `#define NAME(x) ...` are both macros (object-like and
|
|
63
|
+
; function-like); the name is the identifier in either case.
|
|
64
|
+
(preproc_def
|
|
65
|
+
name: (identifier) @definition.macro.name) @definition.macro.node
|
|
66
|
+
|
|
67
|
+
(preproc_function_def
|
|
68
|
+
name: (identifier) @definition.macro.name) @definition.macro.node
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
; Code Map — C++ imports (imports.scm). Provider #? (langs batch 2).
|
|
2
|
+
;
|
|
3
|
+
; enclosingStatementNodeTypes = [preproc_include] (the include span/ordinal anchor).
|
|
4
|
+
; A C++ `#include` path is either a `system_lib_string` (`<vector>`, `<sys/types.h>`)
|
|
5
|
+
; or a `string_literal` (`"config.h"`). Both carry their surrounding delimiters in
|
|
6
|
+
; the captured text, so the provider's refine() strips the `<>`/`"` to the bare path
|
|
7
|
+
; (the runtime's stripQuotes handles the quote case; refine also strips the angle
|
|
8
|
+
; brackets the runtime leaves in place). One preproc_include = one module node.
|
|
9
|
+
;
|
|
10
|
+
; C++20 `import` modules (`import std;`) are intentionally NOT captured in v1 — rare
|
|
11
|
+
; in practice and grammar-version-dependent.
|
|
12
|
+
|
|
13
|
+
(preproc_include
|
|
14
|
+
path: [(system_lib_string) (string_literal)] @import.source)
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Map langs batch 2 — CppProvider (C++).
|
|
3
|
+
*
|
|
4
|
+
* Owns `.cpp`/`.cc`/`.cxx`/`.hpp`/`.hh`/`.h` (runtime lang `cpp`). tree-sitter-cpp
|
|
5
|
+
* is a superset of tree-sitter-c, so the C `#include`/function shapes apply and the
|
|
6
|
+
* curated `tags.scm`/`imports.scm` (this dir) add the C++-only constructs. Definition
|
|
7
|
+
* subtypes are fixed by the query (class_specifier/struct_specifier→class,
|
|
8
|
+
* enum_specifier→enum, namespace_definition→namespace, function_declarator→
|
|
9
|
+
* function/method, preproc_def(_function)→macro, typedef/using→type — all universal).
|
|
10
|
+
* `refine()` carries only what the import query cannot express structurally: a C++
|
|
11
|
+
* include path is a delimited literal (`<vector>` / `"config.h"`), so strip the
|
|
12
|
+
* surrounding `<>`/`"` to the bare path.
|
|
13
|
+
*
|
|
14
|
+
* `.h` is AMBIGUOUS C/C++: this provider claims `.h` at priority 0, and the C
|
|
15
|
+
* provider may claim it too — the registry's deterministic collision order decides
|
|
16
|
+
* the winner; core is NOT special-cased here.
|
|
17
|
+
*
|
|
18
|
+
* NO exports edges — C++ has no export statement (visibility is
|
|
19
|
+
* access-specifiers/headers; capabilities: T2 = imports). Identity is owned by the
|
|
20
|
+
* CORE finalizer — this provider mints NO ids. The grammar loads through the SHARED
|
|
21
|
+
* engine glue (`loadGrammarWasm`), never a fresh `web-tree-sitter` import (trp_8df65ab7).
|
|
22
|
+
*/
|
|
23
|
+
import crypto from 'node:crypto';
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
import path from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
import { loadGrammarWasm, grammarHashForWasm } from '../../wasm-loader.js';
|
|
28
|
+
import { extractWithQueries } from '../query-runtime.js';
|
|
29
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
const CPP_WASM_BASENAME = 'tree-sitter-cpp.wasm';
|
|
31
|
+
const CPP_WASM_NODE_MODULES_SPEC = 'tree-sitter-wasms/out/tree-sitter-cpp.wasm';
|
|
32
|
+
const CPP_GRAMMAR_NAME = 'tree-sitter-cpp';
|
|
33
|
+
/** Resolve a vendored `.scm` next to this module (dist) or from the source tree. */
|
|
34
|
+
function readScm(basename) {
|
|
35
|
+
const local = path.join(HERE, basename);
|
|
36
|
+
if (fs.existsSync(local))
|
|
37
|
+
return fs.readFileSync(local, 'utf-8');
|
|
38
|
+
let dir = HERE;
|
|
39
|
+
for (let i = 0; i < 12; i++) {
|
|
40
|
+
if (fs.existsSync(path.join(dir, 'package.json'))) {
|
|
41
|
+
const fromSrc = path.join(dir, 'src', 'core', 'code-map', 'lang', 'cpp', basename);
|
|
42
|
+
if (fs.existsSync(fromSrc))
|
|
43
|
+
return fs.readFileSync(fromSrc, 'utf-8');
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
const parent = path.dirname(dir);
|
|
47
|
+
if (parent === dir)
|
|
48
|
+
break;
|
|
49
|
+
dir = parent;
|
|
50
|
+
}
|
|
51
|
+
throw new Error(`code-map: could not locate query asset ${basename} (from ${HERE})`);
|
|
52
|
+
}
|
|
53
|
+
function sha256(s) {
|
|
54
|
+
return `sha256:${crypto.createHash('sha256').update(s, 'utf-8').digest('hex')}`;
|
|
55
|
+
}
|
|
56
|
+
const TAGS = readScm('tags.scm');
|
|
57
|
+
const IMPORTS = readScm('imports.scm');
|
|
58
|
+
const TAGS_HASH = sha256(TAGS);
|
|
59
|
+
const IMPORTS_HASH = sha256(IMPORTS);
|
|
60
|
+
const parser = {
|
|
61
|
+
grammarForLang: () => loadGrammarWasm(CPP_WASM_BASENAME, CPP_WASM_NODE_MODULES_SPEC),
|
|
62
|
+
grammarNameForLang: () => CPP_GRAMMAR_NAME,
|
|
63
|
+
grammarHashForLang: () => grammarHashForWasm(CPP_WASM_BASENAME, CPP_WASM_NODE_MODULES_SPEC),
|
|
64
|
+
};
|
|
65
|
+
const queries = {
|
|
66
|
+
tags: { name: 'tags', sourceForLang: () => TAGS, hashForLang: () => TAGS_HASH },
|
|
67
|
+
imports: { name: 'imports', sourceForLang: () => IMPORTS, hashForLang: () => IMPORTS_HASH },
|
|
68
|
+
enclosingStatementNodeTypes: ['preproc_include'],
|
|
69
|
+
captureMap: [
|
|
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.cpp.union.node', field: 'node', subtype: 'cpp.union' },
|
|
75
|
+
{ capture: 'definition.cpp.union.name', field: 'name' },
|
|
76
|
+
{ capture: 'definition.namespace.node', field: 'node', subtype: 'namespace' },
|
|
77
|
+
{ capture: 'definition.namespace.name', field: 'name' },
|
|
78
|
+
{ capture: 'definition.function.node', field: 'node', subtype: 'function' },
|
|
79
|
+
{ capture: 'definition.function.name', field: 'name' },
|
|
80
|
+
{ capture: 'definition.method.node', field: 'node', subtype: 'method' },
|
|
81
|
+
{ capture: 'definition.method.name', field: 'name' },
|
|
82
|
+
{ capture: 'definition.macro.node', field: 'node', subtype: 'macro' },
|
|
83
|
+
{ capture: 'definition.macro.name', field: 'name' },
|
|
84
|
+
{ capture: 'definition.type.node', field: 'node', subtype: 'type' },
|
|
85
|
+
{ capture: 'definition.type.name', field: 'name' },
|
|
86
|
+
{ capture: 'import.source', field: 'source' },
|
|
87
|
+
],
|
|
88
|
+
};
|
|
89
|
+
const vocabulary = {
|
|
90
|
+
nodeSubtypes: ['class', 'enum', 'cpp.union', 'namespace', 'function', 'method', 'macro', 'type'],
|
|
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
|
+
/** Strip the surrounding delimiters from a C++ include path (`<vector>`/`"a.h"`). */
|
|
104
|
+
function stripIncludeDelimiters(s) {
|
|
105
|
+
return s.replace(/^[<"]/, '').replace(/[>"]$/, '');
|
|
106
|
+
}
|
|
107
|
+
export class CppProvider {
|
|
108
|
+
id = 'cpp';
|
|
109
|
+
displayName = 'C++';
|
|
110
|
+
languages = ['cpp'];
|
|
111
|
+
// `.h` is ambiguous C/C++; claimed at priority 0 and resolved by the registry's
|
|
112
|
+
// deterministic collision order if the C provider also claims it (no core special-case).
|
|
113
|
+
extensions = ['.cpp', '.cc', '.cxx', '.hpp', '.hh', '.h'];
|
|
114
|
+
priority = 0;
|
|
115
|
+
version = '0.1.0';
|
|
116
|
+
parser = parser;
|
|
117
|
+
queries = queries;
|
|
118
|
+
vocabulary = vocabulary;
|
|
119
|
+
capabilities = capabilities;
|
|
120
|
+
langForPath(_p) {
|
|
121
|
+
return 'cpp';
|
|
122
|
+
}
|
|
123
|
+
async extractDraft(input, _services) {
|
|
124
|
+
return extractWithQueries({
|
|
125
|
+
providerId: this.id,
|
|
126
|
+
lang: input.lang,
|
|
127
|
+
source: input.source,
|
|
128
|
+
sizeBytes: input.sizeBytes,
|
|
129
|
+
maxParseFileBytes: input.maxParseFileBytes,
|
|
130
|
+
maxQueryWaitMs: input.maxQueryWaitMs,
|
|
131
|
+
path: input.path,
|
|
132
|
+
grammarForLang: this.parser.grammarForLang,
|
|
133
|
+
tagsSource: TAGS,
|
|
134
|
+
tagsHash: TAGS_HASH,
|
|
135
|
+
importsSource: IMPORTS,
|
|
136
|
+
importsHash: IMPORTS_HASH,
|
|
137
|
+
enclosingStatementNodeTypes: queries.enclosingStatementNodeTypes,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/** Drafts-only: strip the delimiters from each include path (`<vector>` → `vector`). */
|
|
141
|
+
refine(draft, _ctx) {
|
|
142
|
+
if (draft.imports.length === 0)
|
|
143
|
+
return draft;
|
|
144
|
+
const imports = draft.imports.map((im) => ({ ...im, source: stripIncludeDelimiters(im.source) }));
|
|
145
|
+
return { ...draft, imports };
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export const cppProvider = new CppProvider();
|
|
149
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
; Code Map — C++ definitions (tags.scm). Provider #? (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
|
+
; Subtypes are all UNIVERSAL: class/enum/namespace/function/method/macro/type
|
|
7
|
+
; (a C++ struct maps to `class` — the named aggregate devs search for like a class;
|
|
8
|
+
; `enum` and `enum class` both map to `enum`).
|
|
9
|
+
;
|
|
10
|
+
; DOUBLE-MATCH avoidance (the CRITICAL rule): a `*_specifier` node is emitted by
|
|
11
|
+
; tree-sitter-cpp BOTH where a type is DEFINED and where it is merely USED as a
|
|
12
|
+
; type (`struct Point p;`, `friend class Bar;`, `enum Color c;`). Requiring
|
|
13
|
+
; `body: (_)` restricts each class/struct/enum pattern to the DEFINITION site, so a
|
|
14
|
+
; type is captured exactly once (and use-sites/forward-decls are never mis-emitted).
|
|
15
|
+
; struct→class and class→class share the `class` subtype but are distinct grammar
|
|
16
|
+
; nodes, so they never co-match the same node.
|
|
17
|
+
;
|
|
18
|
+
; TEMPLATES are transparent: `template <...> class/struct/function` wraps the inner
|
|
19
|
+
; specifier/definition, which the same patterns below capture directly (the
|
|
20
|
+
; template_declaration wrapper carries no name of its own).
|
|
21
|
+
;
|
|
22
|
+
; FUNCTIONS anchor on `function_declarator` (the canonical tree-sitter-cpp shape),
|
|
23
|
+
; NOT `function_definition`: this makes name capture immune to return-type
|
|
24
|
+
; declarator wrapping (`int* f()`, `int& f()`, trailing-return `auto f() -> T`) and
|
|
25
|
+
; keeps @node/@name in one match. The declarator's inner name node is mutually
|
|
26
|
+
; exclusive per function_declarator, so the three function/method patterns can never
|
|
27
|
+
; co-match the same node:
|
|
28
|
+
; identifier -> function (free functions; also file-scope prototypes)
|
|
29
|
+
; field_identifier -> method (in-class method decls / inline defs)
|
|
30
|
+
; qualified_identifier -> method (out-of-line member defs `Foo::bar`, name text
|
|
31
|
+
; is the fully-qualified path)
|
|
32
|
+
; This means a member declared in-class AND defined out-of-line surfaces as TWO
|
|
33
|
+
; method symbols (`bar` + `Foo::bar`) at distinct spans — accepted for v1 (aids
|
|
34
|
+
; discovery, never a duplicate id). SCOPED OUT of v1: fields/member variables, enum
|
|
35
|
+
; constants (enumerators), constructors/destructors/operators (their names are not
|
|
36
|
+
; plain identifier/field_identifier/qualified_identifier nodes), and pointer-wrapped
|
|
37
|
+
; typedefs — documented, low value, and kept out to avoid noise.
|
|
38
|
+
|
|
39
|
+
; --- Aggregates (require `body:` = DEFINITION site only) ---
|
|
40
|
+
(class_specifier
|
|
41
|
+
name: (type_identifier) @definition.class.name
|
|
42
|
+
body: (_)) @definition.class.node
|
|
43
|
+
|
|
44
|
+
(struct_specifier
|
|
45
|
+
name: (type_identifier) @definition.class.name
|
|
46
|
+
body: (_)) @definition.class.node
|
|
47
|
+
|
|
48
|
+
(enum_specifier
|
|
49
|
+
name: (type_identifier) @definition.enum.name
|
|
50
|
+
body: (_)) @definition.enum.node
|
|
51
|
+
|
|
52
|
+
; union → cpp.union (namespaced, mirrors the C provider's c.union). body-guarded
|
|
53
|
+
; so a union type reference / forward decl is not captured. Added because C++ wins
|
|
54
|
+
; the shared `.h` extension, so header unions must be covered here too.
|
|
55
|
+
(union_specifier
|
|
56
|
+
name: (type_identifier) @definition.cpp.union.name
|
|
57
|
+
body: (_)) @definition.cpp.union.node
|
|
58
|
+
|
|
59
|
+
; Named namespaces only (anonymous namespaces have no `name:` and are skipped). The
|
|
60
|
+
; name is a single `namespace_identifier` or, for `namespace a::b { }`, a
|
|
61
|
+
; `nested_namespace_specifier` whose text is the joined path `a::b`.
|
|
62
|
+
(namespace_definition
|
|
63
|
+
name: [(namespace_identifier) (nested_namespace_specifier)] @definition.namespace.name) @definition.namespace.node
|
|
64
|
+
|
|
65
|
+
; --- Functions / methods (anchor on function_declarator; see header) ---
|
|
66
|
+
(function_declarator
|
|
67
|
+
declarator: (identifier) @definition.function.name) @definition.function.node
|
|
68
|
+
|
|
69
|
+
(function_declarator
|
|
70
|
+
declarator: (field_identifier) @definition.method.name) @definition.method.node
|
|
71
|
+
|
|
72
|
+
(function_declarator
|
|
73
|
+
declarator: (qualified_identifier) @definition.method.name) @definition.method.node
|
|
74
|
+
|
|
75
|
+
; --- Macros ---
|
|
76
|
+
(preproc_def
|
|
77
|
+
name: (identifier) @definition.macro.name) @definition.macro.node
|
|
78
|
+
|
|
79
|
+
(preproc_function_def
|
|
80
|
+
name: (identifier) @definition.macro.name) @definition.macro.node
|
|
81
|
+
|
|
82
|
+
; --- Type aliases: `typedef T Name;` and `using Name = T;` ---
|
|
83
|
+
(type_definition
|
|
84
|
+
declarator: (type_identifier) @definition.type.name) @definition.type.node
|
|
85
|
+
|
|
86
|
+
(alias_declaration
|
|
87
|
+
name: (type_identifier) @definition.type.name) @definition.type.node
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
; Code Map — C# imports (imports.scm). Provider #6 (langs batch 2).
|
|
2
|
+
;
|
|
3
|
+
; enclosingStatementNodeTypes = [using_directive] (the import span/ordinal anchor).
|
|
4
|
+
; C# using shapes:
|
|
5
|
+
; using System.Text; -> module System.Text
|
|
6
|
+
; using static System.Math; -> module System.Math (imports the type's static
|
|
7
|
+
; members; the whole qualified name IS the module —
|
|
8
|
+
; no member split like Java `import static`)
|
|
9
|
+
; using Json = Newtonsoft.Json; -> module Newtonsoft.Json + alias name `Json`
|
|
10
|
+
;
|
|
11
|
+
; The module reference is ALWAYS a direct qualified_name / identifier child of the
|
|
12
|
+
; using_directive. An alias binding lives inside a sibling `name_equals` node (never
|
|
13
|
+
; a direct qualified_name/identifier), so this single capture takes ONLY the module
|
|
14
|
+
; path in every shape (plain / static / alias) — the static keyword and the alias
|
|
15
|
+
; are not captured here. C# has no wildcard using and no string-literal module (so
|
|
16
|
+
; nothing to quote-strip). The provider's refine() lifts an alias's binding name
|
|
17
|
+
; (from the `name_equals` sibling) onto the module node's imported names.
|
|
18
|
+
|
|
19
|
+
(using_directive
|
|
20
|
+
[(qualified_name) (identifier)] @import.source)
|