@event4u/agent-config 17.0.0 → 17.2.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 (164) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +157 -468
  5. package/README.md +4 -3
  6. package/dist/agent-src/commands/project/analyze.md +9 -6
  7. package/dist/agent-src/commands/project/map.md +58 -0
  8. package/dist/agent-src/commands/project.md +5 -3
  9. package/dist/agent-src/contexts/execution/host-capability-manifest.md +5 -3
  10. package/dist/agent-src/skills/code-intelligence/SKILL.md +6 -0
  11. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  12. package/dist/agent-src/templates/roadmaps.md +5 -1
  13. package/dist/cli/registry.js +1 -1
  14. package/dist/cli-delegate/{chunk-IROAQ77A.js → chunk-3PK3VZHB.js} +107 -9
  15. package/dist/cli-delegate/{chunk-2SFOOFJJ.js → chunk-BZJ4Y3CI.js} +1 -1
  16. package/dist/cli-delegate/{chunk-CAL76ADI.js → chunk-CMZEKSNN.js} +52 -10
  17. package/dist/cli-delegate/{chunk-ESUNQ5XR.js → chunk-E3CFULNX.js} +22 -4
  18. package/dist/cli-delegate/{chunk-GOMILC3O.js → chunk-QBHEI5N4.js} +4 -3
  19. package/dist/cli-delegate/{chunk-SIOMDAKL.js → chunk-VYZGJLCA.js} +29 -39
  20. package/dist/cli-delegate/chunk-W5JXMF2T.js +77 -0
  21. package/dist/cli-delegate/{chunk-4SHNERBL.js → chunk-XIAPY44N.js} +1 -1
  22. package/dist/cli-delegate/{chunk-JHMMWNJ2.js → chunk-YHAPONWV.js} +1 -1
  23. package/dist/cli-delegate/cmd_conformance.js +32 -47
  24. package/dist/cli-delegate/cmd_doctor.js +4 -4
  25. package/dist/cli-delegate/cmd_doctor_neighbours.js +2 -2
  26. package/dist/cli-delegate/cmd_explain.js +1 -1
  27. package/dist/cli-delegate/cmd_export.js +6 -6
  28. package/dist/cli-delegate/cmd_fleet.js +3 -3
  29. package/dist/cli-delegate/cmd_preflight.js +3 -3
  30. package/dist/cli-delegate/cmd_prune.js +6 -6
  31. package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
  32. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  33. package/dist/cli-delegate/cmd_sync.js +6 -6
  34. package/dist/cli-delegate/cmd_uninstall.js +6 -6
  35. package/dist/cli-delegate/cmd_update.js +9 -13
  36. package/dist/cli-delegate/cmd_validate.js +6 -6
  37. package/dist/discovery/deprecation-report.md +1 -1
  38. package/dist/discovery/discovery-manifest.json +41 -15
  39. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  40. package/dist/discovery/discovery-manifest.summary.md +3 -3
  41. package/dist/discovery/dormancy-report.md +1 -1
  42. package/dist/discovery/orphan-report.md +1 -1
  43. package/dist/discovery/packs.json +6 -5
  44. package/dist/discovery/trust-report.md +2 -2
  45. package/dist/discovery/workspaces.json +5 -4
  46. package/dist/hooks/dispatch.js +163 -148
  47. package/dist/hooks/dispatch.sha256 +1 -1
  48. package/dist/hooks/instructions_observer.chunk.cjs +301 -0
  49. package/dist/hooks/instructions_observer.chunk.cjs.sha256 +1 -0
  50. package/dist/install/claudeRuleRewrite.js +10 -3
  51. package/dist/install/conflict.js +24 -2
  52. package/dist/install/conflictTracker.js +14 -3
  53. package/dist/install/install.mjs +222 -117
  54. package/dist/install/installThinLayer.js +1 -0
  55. package/dist/install/loggedWrites.js +142 -0
  56. package/dist/install/paths.js +12 -2
  57. package/dist/install/preserve.js +25 -4
  58. package/dist/install/txlog.js +10 -6
  59. package/dist/mcp/registry-manifest.json +3 -3
  60. package/dist/mcp/server.json +2 -2
  61. package/dist/mcp/server.mjs +33595 -22916
  62. package/dist/scripts/_lib/egress_rules.js +4 -1
  63. package/dist/scripts/_lib/identifier_redaction.js +35 -2
  64. package/dist/scripts/ai_council/seat_policy.js +7 -1
  65. package/dist/server/schemas/settings.js +1 -1
  66. package/package.json +4 -1
  67. package/src/config/ci-local-parity.yml +1 -1
  68. package/src/config/continuity-surface.json +7 -0
  69. package/src/config/evaluator-budgets.json +4 -4
  70. package/src/config/gate-coverage.yml +27 -7
  71. package/src/config/gate-violation-baselines.json +9 -3
  72. package/src/config/gitignore-block.txt +6 -0
  73. package/src/config/hook-bundle-budget.json +19 -4
  74. package/src/config/hook-token-budget.json +1 -1
  75. package/src/config/packed-binary-manifest.json +27 -0
  76. package/src/config/production-entries.json +18 -0
  77. package/src/config/release-gate-locality.yml +0 -7
  78. package/src/config/skill-body-budget.json +7 -1
  79. package/src/install/claudeRuleRewrite.ts +10 -1
  80. package/src/install/conflict.ts +24 -1
  81. package/src/install/conflictTracker.ts +18 -2
  82. package/src/install/installThinLayer.ts +6 -0
  83. package/src/install/loggedWrites.ts +148 -0
  84. package/src/install/paths.ts +11 -2
  85. package/src/install/preserve.ts +40 -4
  86. package/src/install/txlog.ts +10 -6
  87. package/src/scripts/_cli/cmd_conformance.ts +3 -2
  88. package/src/scripts/_cli/cmd_update.ts +15 -17
  89. package/src/scripts/_lib/bench_ab_complexity.ts +14 -2
  90. package/src/scripts/_lib/collector_record.ts +1 -0
  91. package/src/scripts/_lib/council_settings_block.ts +9 -2
  92. package/src/scripts/_lib/egress_rules.ts +4 -1
  93. package/src/scripts/_lib/host_capability.ts +10 -5
  94. package/src/scripts/_lib/identifier_redaction.ts +38 -2
  95. package/src/scripts/_lib/price_freshness.ts +112 -0
  96. package/src/scripts/_lib/production_reach.ts +194 -0
  97. package/src/scripts/_lib/quota_parked.ts +17 -28
  98. package/src/scripts/_lib/release_findings_ingest.ts +13 -335
  99. package/src/scripts/_lib/runtime_journal.ts +7 -7
  100. package/src/scripts/_lib/tier_downshift_verdict.ts +81 -35
  101. package/src/scripts/ai_council/chairman.ts +5 -2
  102. package/src/scripts/ai_council/clients.ts +4 -3
  103. package/src/scripts/ai_council/free_hand_shadow.ts +24 -12
  104. package/src/scripts/ai_council/free_route_catalog.ts +142 -5
  105. package/src/scripts/ai_council/free_route_client.ts +4 -0
  106. package/src/scripts/ai_council/hand_payload.ts +115 -7
  107. package/src/scripts/ai_council/orchestrator.ts +7 -10
  108. package/src/scripts/ai_council/route_chooser.ts +1 -1
  109. package/src/scripts/ai_council/route_member.ts +66 -4
  110. package/src/scripts/ai_council/seat_policy.ts +8 -1
  111. package/src/scripts/ai_council/self_hosted_probe.ts +327 -0
  112. package/src/scripts/ai_council/status_surface.ts +2 -0
  113. package/src/scripts/ask_transport.ts +137 -15
  114. package/src/scripts/check_finding_dispositions.ts +25 -71
  115. package/src/scripts/check_release_pr_shape.ts +3 -3
  116. package/src/scripts/check_step_production_reach.ts +257 -0
  117. package/src/scripts/code_graph/build.ts +210 -10
  118. package/src/scripts/code_graph/cli.ts +168 -46
  119. package/src/scripts/code_graph/detect.ts +5 -4
  120. package/src/scripts/code_graph/docs_layer.ts +57 -0
  121. package/src/scripts/code_graph/extract.ts +58 -13
  122. package/src/scripts/code_graph/extract_more.ts +314 -0
  123. package/src/scripts/code_graph/laravel_overlay.ts +454 -0
  124. package/src/scripts/code_graph/map.ts +846 -0
  125. package/src/scripts/code_graph/map_model.ts +977 -0
  126. package/src/scripts/code_graph/map_verify.ts +140 -0
  127. package/src/scripts/code_graph/map_viewer/viewer.css +278 -0
  128. package/src/scripts/code_graph/map_viewer/viewer.js +756 -0
  129. package/src/scripts/code_graph/scip_reader.ts +201 -0
  130. package/src/scripts/code_graph/sqlite_store.ts +8 -1
  131. package/src/scripts/code_graph/types.ts +81 -15
  132. package/src/scripts/code_graph/validate.ts +16 -26
  133. package/src/scripts/code_graph/verbs.ts +7 -0
  134. package/src/scripts/council_cli.ts +10 -8
  135. package/src/scripts/hook_chunks.mjs +7 -0
  136. package/src/scripts/hook_manifest.json +1 -1
  137. package/src/scripts/hook_manifest.yaml +23 -0
  138. package/src/scripts/hooks/dispatch_hook.ts +4 -4
  139. package/src/scripts/hooks/instructions_observer_hook.ts +25 -6
  140. package/src/scripts/hooks/lazy_concern.ts +4 -0
  141. package/src/scripts/hooks/payload_stub.ts +27 -0
  142. package/src/scripts/hooks/spawn_guard_shadow_hook.ts +29 -70
  143. package/src/scripts/hooks/subagent_ledger_hook.ts +80 -0
  144. package/src/scripts/install-hooks.sh +5 -0
  145. package/src/scripts/install.ts +2 -2
  146. package/src/scripts/lint_agents_layout.ts +2 -0
  147. package/src/scripts/lint_decision_classes.ts +34 -0
  148. package/src/scripts/lint_hook_manifest.ts +25 -0
  149. package/src/scripts/lint_roadmap_blockers.ts +52 -3
  150. package/src/scripts/mcp_server/consumer_tool_catalog.json +53 -6
  151. package/src/scripts/mcp_server/graph_tools.ts +73 -1
  152. package/src/scripts/mcp_server/tools.ts +19 -36
  153. package/src/scripts/release.ts +5 -9
  154. package/src/scripts/release_drill.ts +11 -165
  155. package/src/scripts/release_publication.ts +0 -9
  156. package/src/scripts/report_production_reach.ts +35 -0
  157. package/src/scripts/worker_reuse_shadow_report.ts +399 -1
  158. package/src/server/schemas/settings.ts +1 -1
  159. package/src/vendor/grammars/README.md +10 -5
  160. package/src/vendor/grammars/tree-sitter-go.wasm +0 -0
  161. package/src/vendor/grammars/tree-sitter-java.wasm +0 -0
  162. package/src/vendor/grammars/tree-sitter-python.wasm +0 -0
  163. package/dist/cli-delegate/chunk-A4QJ6ENT.js +0 -50
  164. /package/dist/cli-delegate/{chunk-E6XNBVE4.js → chunk-KR5ZIFPO.js} +0 -0
@@ -0,0 +1,314 @@
1
+ /**
2
+ * Python, Go and Java extraction — the same shape `extract.ts` emits for
3
+ * PHP / TS / JS, so the build pass resolves them with no language branch
4
+ * beyond module lookup.
5
+ *
6
+ * definitions classes / interfaces / structs, functions, methods
7
+ * imports with the module as written, for `build.ts` to map to a file
8
+ * inherits superclasses, implemented interfaces
9
+ * calls free calls, `self.` / `this.` calls on the enclosing class,
10
+ * `X.m()` scoped calls, `new X()`, and dynamic member calls
11
+ */
12
+ import { type FileExtract, loc, namedChildren, nameField, uniq } from './extract.js';
13
+ import type { TsNode } from './loader.js';
14
+
15
+ function text(n: TsNode | null | undefined): string {
16
+ return n ? n.text : '';
17
+ }
18
+
19
+ /** Every descendant of `type`, document order. */
20
+ function descendants(n: TsNode, type: string): TsNode[] {
21
+ const out: TsNode[] = [];
22
+ const visit = (x: TsNode): void => {
23
+ for (const c of namedChildren(x)) {
24
+ if (c.type === type) out.push(c);
25
+ visit(c);
26
+ }
27
+ };
28
+ visit(n);
29
+ return out;
30
+ }
31
+
32
+ /** Node identity: the runtime hands out a fresh wrapper per access. */
33
+ function same(a: TsNode | null, b: TsNode | null): boolean {
34
+ return (
35
+ a !== null &&
36
+ b !== null &&
37
+ a.type === b.type &&
38
+ a.startPosition.row === b.startPosition.row &&
39
+ a.startPosition.column === b.startPosition.column
40
+ );
41
+ }
42
+
43
+ function lastSegment(dotted: string): string {
44
+ const parts = dotted.split(/[./]/);
45
+ return parts[parts.length - 1] ?? dotted;
46
+ }
47
+
48
+ export function extractPython(root: TsNode, file: string, out: FileExtract): void {
49
+ out.nodes.push({ id: file, label: file, kind: 'file', source_file: file, source_location: [] });
50
+ const walk = (n: TsNode, classId: string | null, scopeId: string): void => {
51
+ switch (n.type) {
52
+ case 'import_statement': {
53
+ for (const c of namedChildren(n)) {
54
+ const dotted = c.type === 'aliased_import' ? c.childForFieldName('name') : c;
55
+ const alias = c.type === 'aliased_import' ? text(c.childForFieldName('alias')) : '';
56
+ const spec = text(dotted);
57
+ if (!spec) continue;
58
+ out.rawEdges.push({
59
+ sourceId: file,
60
+ relation: 'imports',
61
+ targetName: lastSegment(spec),
62
+ confidenceHint: 'EXTRACTED',
63
+ moduleSpecifier: spec,
64
+ importKind: 'namespace',
65
+ localName: alias || (spec.split('.')[0] as string),
66
+ });
67
+ }
68
+ return;
69
+ }
70
+ case 'import_from_statement': {
71
+ const mod = text(n.childForFieldName('module_name'));
72
+ for (const c of namedChildren(n)) {
73
+ if (same(c, n.childForFieldName('module_name'))) continue;
74
+ if (c.type !== 'dotted_name' && c.type !== 'aliased_import') continue;
75
+ const name = c.type === 'aliased_import' ? text(c.childForFieldName('name')) : text(c);
76
+ const alias = c.type === 'aliased_import' ? text(c.childForFieldName('alias')) : '';
77
+ out.rawEdges.push({
78
+ sourceId: file,
79
+ relation: 'imports',
80
+ targetName: name,
81
+ confidenceHint: 'EXTRACTED',
82
+ moduleSpecifier: mod,
83
+ importKind: 'named',
84
+ ...(alias ? { localName: alias } : {}),
85
+ });
86
+ }
87
+ return;
88
+ }
89
+ case 'class_definition': {
90
+ const nm = nameField(n) ?? '<anon>';
91
+ const id = uniq(out, `${file}#${nm}`);
92
+ out.nodes.push({ id, label: nm, kind: 'class', source_file: file, source_location: loc(n) });
93
+ out.rawEdges.push({ sourceId: file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
94
+ const supers = n.childForFieldName('superclasses');
95
+ if (supers)
96
+ for (const s of namedChildren(supers))
97
+ if (s.type === 'identifier' || s.type === 'attribute') out.inherits.push({ classId: id, parentName: lastSegment(s.text) });
98
+ const body = n.childForFieldName('body');
99
+ if (body) for (const c of namedChildren(body)) walk(c, id, id);
100
+ return;
101
+ }
102
+ case 'function_definition': {
103
+ const nm = nameField(n) ?? '<anon>';
104
+ const id = uniq(out, classId ? `${classId}::${nm}` : `${file}#${nm}`);
105
+ out.nodes.push({ id, label: nm, kind: classId ? 'method' : 'function', source_file: file, source_location: loc(n) });
106
+ out.rawEdges.push({ sourceId: classId ?? file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
107
+ const body = n.childForFieldName('body');
108
+ // A nested def is a local helper: its calls belong to it, and it
109
+ // no longer sees the class as `self`.
110
+ if (body) for (const c of namedChildren(body)) walk(c, null, id);
111
+ return;
112
+ }
113
+ case 'call': {
114
+ const fn = n.childForFieldName('function');
115
+ if (fn?.type === 'identifier') {
116
+ out.rawEdges.push({ sourceId: scopeId, relation: 'calls', targetName: fn.text, confidenceHint: 'EXTRACTED', callStyle: 'free' });
117
+ } else if (fn?.type === 'attribute') {
118
+ const obj = fn.childForFieldName('object');
119
+ const attr = text(fn.childForFieldName('attribute'));
120
+ const isSelf = obj?.type === 'identifier' && (obj.text === 'self' || obj.text === 'cls');
121
+ out.rawEdges.push({
122
+ sourceId: scopeId,
123
+ relation: 'calls',
124
+ targetName: attr,
125
+ confidenceHint: isSelf && classId ? 'INFERRED' : 'AMBIGUOUS',
126
+ callStyle: isSelf ? 'this' : 'dynamic',
127
+ ...(classId ? { enclosingClassId: classId } : {}),
128
+ });
129
+ }
130
+ break;
131
+ }
132
+ default:
133
+ break;
134
+ }
135
+ for (const c of namedChildren(n)) walk(c, classId, scopeId);
136
+ };
137
+ walk(root, null, file);
138
+ }
139
+
140
+ export function extractJava(root: TsNode, file: string, out: FileExtract): void {
141
+ out.nodes.push({ id: file, label: file, kind: 'file', source_file: file, source_location: [] });
142
+ const TYPES: Record<string, 'class' | 'interface' | 'enum'> = {
143
+ class_declaration: 'class',
144
+ record_declaration: 'class',
145
+ interface_declaration: 'interface',
146
+ enum_declaration: 'enum',
147
+ };
148
+ const walk = (n: TsNode, classId: string | null, scopeId: string): void => {
149
+ const kind = TYPES[n.type];
150
+ if (kind) {
151
+ const nm = nameField(n) ?? '<anon>';
152
+ const id = uniq(out, classId ? `${classId}::${nm}` : `${file}#${nm}`);
153
+ out.nodes.push({ id, label: nm, kind, source_file: file, source_location: loc(n) });
154
+ out.rawEdges.push({ sourceId: classId ?? file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
155
+ for (const c of namedChildren(n)) {
156
+ if (c.type === 'superclass' || c.type === 'super_interfaces' || c.type === 'extends_interfaces') {
157
+ for (const t of descendants(c, 'type_identifier')) out.inherits.push({ classId: id, parentName: t.text });
158
+ }
159
+ }
160
+ const body = n.childForFieldName('body');
161
+ if (body) for (const c of namedChildren(body)) walk(c, id, id);
162
+ return;
163
+ }
164
+ switch (n.type) {
165
+ case 'import_declaration': {
166
+ const spec = namedChildren(n).find((c) => c.type === 'scoped_identifier' || c.type === 'identifier');
167
+ if (spec && !n.text.includes('*')) {
168
+ out.rawEdges.push({
169
+ sourceId: file,
170
+ relation: 'imports',
171
+ targetName: lastSegment(spec.text),
172
+ confidenceHint: 'EXTRACTED',
173
+ moduleSpecifier: spec.text,
174
+ importKind: 'named',
175
+ });
176
+ }
177
+ return;
178
+ }
179
+ case 'method_declaration':
180
+ case 'constructor_declaration': {
181
+ const nm = nameField(n) ?? '<anon>';
182
+ const id = uniq(out, classId ? `${classId}::${nm}` : `${file}#${nm}`);
183
+ out.nodes.push({ id, label: nm, kind: 'method', source_file: file, source_location: loc(n) });
184
+ out.rawEdges.push({ sourceId: classId ?? file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
185
+ const body = n.childForFieldName('body');
186
+ if (body) for (const c of namedChildren(body)) walk(c, classId, id);
187
+ return;
188
+ }
189
+ case 'method_invocation': {
190
+ const obj = n.childForFieldName('object');
191
+ const nm = text(n.childForFieldName('name'));
192
+ if (!obj || obj.type === 'this') {
193
+ out.rawEdges.push({
194
+ sourceId: scopeId,
195
+ relation: 'calls',
196
+ targetName: nm,
197
+ confidenceHint: classId ? 'INFERRED' : 'AMBIGUOUS',
198
+ callStyle: 'this',
199
+ ...(classId ? { enclosingClassId: classId } : {}),
200
+ });
201
+ } else if (obj.type === 'identifier' && /^[A-Z]/.test(obj.text)) {
202
+ out.rawEdges.push({
203
+ sourceId: scopeId,
204
+ relation: 'calls',
205
+ targetName: nm,
206
+ confidenceHint: 'AMBIGUOUS',
207
+ callStyle: 'scoped',
208
+ scopeName: obj.text,
209
+ ...(classId ? { enclosingClassId: classId } : {}),
210
+ });
211
+ } else {
212
+ out.rawEdges.push({
213
+ sourceId: scopeId,
214
+ relation: 'calls',
215
+ targetName: nm,
216
+ confidenceHint: 'AMBIGUOUS',
217
+ callStyle: 'dynamic',
218
+ ...(classId ? { enclosingClassId: classId } : {}),
219
+ });
220
+ }
221
+ break;
222
+ }
223
+ case 'object_creation_expression': {
224
+ const t = n.childForFieldName('type');
225
+ if (t) out.rawEdges.push({ sourceId: scopeId, relation: 'calls', targetName: lastSegment(t.text.replace(/<.*$/, '')), confidenceHint: 'EXTRACTED', callStyle: 'new' });
226
+ break;
227
+ }
228
+ default:
229
+ break;
230
+ }
231
+ for (const c of namedChildren(n)) walk(c, classId, scopeId);
232
+ };
233
+ walk(root, null, file);
234
+ }
235
+
236
+ export function extractGo(root: TsNode, file: string, out: FileExtract): void {
237
+ out.nodes.push({ id: file, label: file, kind: 'file', source_file: file, source_location: [] });
238
+ const walk = (n: TsNode, scopeId: string): void => {
239
+ switch (n.type) {
240
+ case 'import_spec': {
241
+ const spec = text(n.childForFieldName('path')).replace(/^["`]|["`]$/g, '');
242
+ const alias = text(n.childForFieldName('name'));
243
+ if (spec && alias !== '_') {
244
+ out.rawEdges.push({
245
+ sourceId: file,
246
+ relation: 'imports',
247
+ targetName: lastSegment(spec),
248
+ confidenceHint: 'EXTRACTED',
249
+ moduleSpecifier: spec,
250
+ importKind: 'namespace',
251
+ ...(alias && alias !== '.' ? { localName: alias } : {}),
252
+ });
253
+ }
254
+ return;
255
+ }
256
+ case 'type_spec': {
257
+ const nm = text(n.childForFieldName('name'));
258
+ const t = n.childForFieldName('type');
259
+ const kind = t?.type === 'interface_type' ? 'interface' : t?.type === 'struct_type' ? 'class' : 'type';
260
+ const id = uniq(out, `${file}#${nm}`);
261
+ out.nodes.push({ id, label: nm, kind, source_file: file, source_location: loc(n) });
262
+ out.rawEdges.push({ sourceId: file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
263
+ return;
264
+ }
265
+ case 'function_declaration': {
266
+ const nm = nameField(n) ?? '<anon>';
267
+ const id = uniq(out, `${file}#${nm}`);
268
+ out.nodes.push({ id, label: nm, kind: 'function', source_file: file, source_location: loc(n) });
269
+ out.rawEdges.push({ sourceId: file, relation: 'member', targetName: nm, confidenceHint: 'EXTRACTED' });
270
+ const body = n.childForFieldName('body');
271
+ if (body) walk(body, id);
272
+ return;
273
+ }
274
+ case 'method_declaration': {
275
+ const nm = nameField(n) ?? '<anon>';
276
+ const recv = n.childForFieldName('receiver');
277
+ const typeName = recv ? (descendants(recv, 'type_identifier')[0]?.text ?? '') : '';
278
+ const id = uniq(out, typeName ? `${file}#${typeName}::${nm}` : `${file}#${nm}`);
279
+ out.nodes.push({ id, label: nm, kind: 'method', source_file: file, source_location: loc(n) });
280
+ // The receiver type may be declared in another file of the
281
+ // package, so the member link hangs off the file, named so the
282
+ // build pass derives this method's own id from it.
283
+ out.rawEdges.push({
284
+ sourceId: file,
285
+ relation: 'member',
286
+ targetName: id.slice(file.length + 1),
287
+ confidenceHint: 'EXTRACTED',
288
+ });
289
+ const body = n.childForFieldName('body');
290
+ if (body) walk(body, id);
291
+ return;
292
+ }
293
+ case 'call_expression': {
294
+ const fn = n.childForFieldName('function');
295
+ if (fn?.type === 'identifier') {
296
+ out.rawEdges.push({ sourceId: scopeId, relation: 'calls', targetName: fn.text, confidenceHint: 'EXTRACTED', callStyle: 'free' });
297
+ } else if (fn?.type === 'selector_expression') {
298
+ out.rawEdges.push({
299
+ sourceId: scopeId,
300
+ relation: 'calls',
301
+ targetName: text(fn.childForFieldName('field')),
302
+ confidenceHint: 'AMBIGUOUS',
303
+ callStyle: 'dynamic',
304
+ });
305
+ }
306
+ break;
307
+ }
308
+ default:
309
+ break;
310
+ }
311
+ for (const c of namedChildren(n)) walk(c, scopeId);
312
+ };
313
+ walk(root, file);
314
+ }