autonomous-flow-daemon 1.1.0 → 1.9.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/CHANGELOG.md +85 -46
- package/LICENSE +21 -21
- package/README-ko.md +282 -0
- package/README.md +282 -337
- package/mcp-config.json +10 -10
- package/package.json +14 -6
- package/src/adapters/index.ts +370 -159
- package/src/cli.ts +162 -57
- package/src/commands/benchmark.ts +187 -0
- package/src/commands/correlate.ts +180 -0
- package/src/commands/dashboard.ts +404 -0
- package/src/commands/diagnose.ts +56 -14
- package/src/commands/doctor.ts +243 -0
- package/src/commands/evolution.ts +190 -0
- package/src/commands/fix.ts +158 -138
- package/src/commands/hooks.ts +136 -0
- package/src/commands/lang.ts +41 -41
- package/src/commands/mcp.ts +129 -0
- package/src/commands/plugin.ts +110 -0
- package/src/commands/restart.ts +14 -0
- package/src/commands/score.ts +276 -208
- package/src/commands/start.ts +155 -96
- package/src/commands/stats.ts +103 -0
- package/src/commands/status.ts +157 -0
- package/src/commands/stop.ts +68 -49
- package/src/commands/suggest.ts +211 -0
- package/src/commands/sync.ts +567 -21
- package/src/commands/vaccine.ts +177 -0
- package/src/constants.ts +32 -8
- package/src/core/boast.ts +280 -265
- package/src/core/config.ts +49 -49
- package/src/core/correlation-engine.ts +265 -0
- package/src/core/db.ts +145 -46
- package/src/core/discovery.ts +65 -65
- package/src/core/evolution.ts +215 -0
- package/src/core/federation.ts +129 -0
- package/src/core/hologram/engine.ts +71 -0
- package/src/core/hologram/fallback.ts +11 -0
- package/src/core/hologram/go-extractor.ts +203 -0
- package/src/core/hologram/incremental.ts +227 -0
- package/src/core/hologram/py-extractor.ts +132 -0
- package/src/core/hologram/rust-extractor.ts +244 -0
- package/src/core/hologram/ts-extractor.ts +406 -0
- package/src/core/hologram/types.ts +27 -0
- package/src/core/hologram.ts +73 -243
- package/src/core/hook-manager.ts +259 -0
- package/src/core/i18n/messages.ts +309 -266
- package/src/core/immune.ts +8 -123
- package/src/core/locale.ts +88 -88
- package/src/core/log-rotate.ts +33 -0
- package/src/core/log-utils.ts +38 -0
- package/src/core/lru-map.ts +61 -0
- package/src/core/notify.ts +74 -66
- package/src/core/plugin-manager.ts +225 -0
- package/src/core/rule-engine.ts +287 -0
- package/src/core/rule-suggestion.ts +127 -0
- package/src/core/semantic-diff.ts +432 -0
- package/src/core/telemetry.ts +94 -0
- package/src/core/vaccine-registry.ts +212 -0
- package/src/core/validator-generator.ts +224 -0
- package/src/core/workspace.ts +28 -0
- package/src/core/yaml-minimal.ts +176 -0
- package/src/daemon/client.ts +78 -37
- package/src/daemon/event-batcher.ts +108 -0
- package/src/daemon/guards.ts +13 -0
- package/src/daemon/http-routes.ts +376 -0
- package/src/daemon/mcp-handler.ts +575 -0
- package/src/daemon/mcp-subscriptions.ts +81 -0
- package/src/daemon/mesh.ts +51 -0
- package/src/daemon/server.ts +655 -504
- package/src/daemon/types.ts +121 -0
- package/src/daemon/workspace-map.ts +104 -0
- package/src/platform.ts +60 -39
- package/src/version.ts +15 -0
- package/README.ko.md +0 -306
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import type { Node, Tree } from "web-tree-sitter";
|
|
2
|
+
import type { LanguageExtractor, HologramOptions } from "./types";
|
|
3
|
+
import { readFileSync } from "fs";
|
|
4
|
+
|
|
5
|
+
/** Extract imported symbols from a context file using regex (L1 filtering) */
|
|
6
|
+
function extractImportedSymbols(contextSource: string, targetPath: string): Set<string> | "all" {
|
|
7
|
+
const symbols = new Set<string>();
|
|
8
|
+
const targetBase = targetPath.replace(/\.[tj]sx?$/, "").replace(/\\/g, "/");
|
|
9
|
+
const targetName = targetBase.split("/").pop() ?? targetBase;
|
|
10
|
+
|
|
11
|
+
function matchesTarget(from: string): boolean {
|
|
12
|
+
const normalized = from.replace(/\.[tj]sx?$/, "").replace(/\\/g, "/");
|
|
13
|
+
return normalized.endsWith(targetName) || normalized.endsWith(targetBase);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Namespace import
|
|
17
|
+
const nsRe = /import\s+\*\s+as\s+\w+\s+from\s+["']([^"']+)["']/g;
|
|
18
|
+
for (const m of contextSource.matchAll(nsRe)) {
|
|
19
|
+
if (matchesTarget(m[1])) return "all";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Named imports
|
|
23
|
+
const namedRe = /import\s+\{([^}]+)\}\s+from\s+["']([^"']+)["']/g;
|
|
24
|
+
for (const m of contextSource.matchAll(namedRe)) {
|
|
25
|
+
if (matchesTarget(m[2])) {
|
|
26
|
+
m[1].split(",").forEach(s => {
|
|
27
|
+
const name = s.trim().split(/\s+as\s+/)[0].trim();
|
|
28
|
+
if (name) symbols.add(name);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Default import
|
|
34
|
+
const defaultRe = /import\s+(\w+)\s+from\s+["']([^"']+)["']/g;
|
|
35
|
+
for (const m of contextSource.matchAll(defaultRe)) {
|
|
36
|
+
if (matchesTarget(m[2])) symbols.add("default");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Combined: import X, { A, B } from "./target"
|
|
40
|
+
const combinedRe = /import\s+(\w+)\s*,\s*\{([^}]+)\}\s+from\s+["']([^"']+)["']/g;
|
|
41
|
+
for (const m of contextSource.matchAll(combinedRe)) {
|
|
42
|
+
if (matchesTarget(m[3])) {
|
|
43
|
+
symbols.add("default");
|
|
44
|
+
m[2].split(",").forEach(s => {
|
|
45
|
+
const name = s.trim().split(/\s+as\s+/)[0].trim();
|
|
46
|
+
if (name) symbols.add(name);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return symbols;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Node types that contain implementation bodies (NOT pure type declarations) */
|
|
55
|
+
const IMPL_NODE_TYPES = new Set([
|
|
56
|
+
"function_declaration",
|
|
57
|
+
"generator_function_declaration",
|
|
58
|
+
"class_declaration",
|
|
59
|
+
"lexical_declaration",
|
|
60
|
+
"variable_declaration",
|
|
61
|
+
"expression_statement",
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Fast pure-type file check: scans only root-level node types (O(n), no deep traversal).
|
|
66
|
+
* Returns true if every top-level statement is a pure type declaration with no implementation body.
|
|
67
|
+
*/
|
|
68
|
+
function isPureTypeFile(rootChildren: Node[]): boolean {
|
|
69
|
+
for (const node of rootChildren) {
|
|
70
|
+
if (IMPL_NODE_TYPES.has(node.type)) return false;
|
|
71
|
+
|
|
72
|
+
if (node.type === "export_statement") {
|
|
73
|
+
// Check what's being exported — if it has an implementation node, it's not pure
|
|
74
|
+
const inner = node.namedChildren.find(c =>
|
|
75
|
+
c.type !== "export_clause" && c.type !== "string" && c.type !== "identifier"
|
|
76
|
+
);
|
|
77
|
+
if (inner && IMPL_NODE_TYPES.has(inner.type)) return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get the declared name from any top-level node (exported or not).
|
|
85
|
+
* Used for L1 symbol filtering.
|
|
86
|
+
*/
|
|
87
|
+
function getDeclarationName(node: Node): string | null {
|
|
88
|
+
let target = node;
|
|
89
|
+
|
|
90
|
+
// Unwrap export_statement
|
|
91
|
+
if (node.type === "export_statement") {
|
|
92
|
+
const inner = node.namedChildren.find(c =>
|
|
93
|
+
c.type === "function_declaration" ||
|
|
94
|
+
c.type === "generator_function_declaration" ||
|
|
95
|
+
c.type === "class_declaration" ||
|
|
96
|
+
c.type === "interface_declaration" ||
|
|
97
|
+
c.type === "type_alias_declaration" ||
|
|
98
|
+
c.type === "enum_declaration" ||
|
|
99
|
+
c.type === "lexical_declaration"
|
|
100
|
+
);
|
|
101
|
+
if (!inner) return null;
|
|
102
|
+
target = inner;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const nameNode = target.childForFieldName("name");
|
|
106
|
+
if (nameNode) return nameNode.text;
|
|
107
|
+
|
|
108
|
+
if (target.type === "lexical_declaration") {
|
|
109
|
+
const declarator = target.namedChildren.find(c => c.type === "variable_declarator");
|
|
110
|
+
return declarator?.childForFieldName("name")?.text ?? null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Get the exported name from a top-level declaration node */
|
|
117
|
+
function getExportedName(node: Node): string | null {
|
|
118
|
+
// Check if wrapped in export_statement
|
|
119
|
+
const parent = node.parent;
|
|
120
|
+
const isExported = parent?.type === "export_statement" || node.type === "export_statement";
|
|
121
|
+
if (!isExported && parent?.type !== "program") return null;
|
|
122
|
+
if (!isExported) return null;
|
|
123
|
+
|
|
124
|
+
const decl = node.type === "export_statement"
|
|
125
|
+
? node.namedChildren.find(c =>
|
|
126
|
+
c.type === "function_declaration" ||
|
|
127
|
+
c.type === "class_declaration" ||
|
|
128
|
+
c.type === "interface_declaration" ||
|
|
129
|
+
c.type === "type_alias_declaration" ||
|
|
130
|
+
c.type === "enum_declaration" ||
|
|
131
|
+
c.type === "lexical_declaration")
|
|
132
|
+
: node;
|
|
133
|
+
|
|
134
|
+
if (!decl) return null;
|
|
135
|
+
|
|
136
|
+
const nameNode = decl.childForFieldName("name");
|
|
137
|
+
if (nameNode) return nameNode.text;
|
|
138
|
+
|
|
139
|
+
// Variable declarations
|
|
140
|
+
if (decl.type === "lexical_declaration") {
|
|
141
|
+
const declarator = decl.namedChildren.find(c => c.type === "variable_declarator");
|
|
142
|
+
return declarator?.childForFieldName("name")?.text ?? null;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Stub a node's body, keeping only the signature */
|
|
149
|
+
function stubBody(node: Node, source: string): string {
|
|
150
|
+
const body = node.childForFieldName("body");
|
|
151
|
+
if (!body) return collapseWhitespace(node.text);
|
|
152
|
+
return collapseWhitespace(source.slice(node.startIndex, body.startIndex).trimEnd()) + " {…}";
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Extract function signature */
|
|
156
|
+
function extractFunction(node: Node, source: string): string {
|
|
157
|
+
return stubBody(node, source);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Extract class with member signatures */
|
|
161
|
+
function extractClass(node: Node, source: string): string {
|
|
162
|
+
const nameNode = node.childForFieldName("name");
|
|
163
|
+
const name = nameNode?.text ?? "Anonymous";
|
|
164
|
+
const body = node.childForFieldName("body");
|
|
165
|
+
|
|
166
|
+
// Heritage (extends/implements)
|
|
167
|
+
let heritage = "";
|
|
168
|
+
const heritageNodes = node.children.filter(c =>
|
|
169
|
+
c.type === "extends_clause" || c.type === "implements_clause" ||
|
|
170
|
+
c.type === "class_heritage");
|
|
171
|
+
if (heritageNodes.length > 0) {
|
|
172
|
+
heritage = " " + heritageNodes.map(h => collapseWhitespace(h.text)).join(" ");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Prefix (export, abstract, etc.)
|
|
176
|
+
const prefix = collapseWhitespace(
|
|
177
|
+
source.slice(node.startIndex, (nameNode ?? body ?? node).startIndex).trimEnd()
|
|
178
|
+
).replace(name, "").trimEnd();
|
|
179
|
+
const classPrefix = prefix ? `${prefix} ${name}` : `class ${name}`;
|
|
180
|
+
|
|
181
|
+
if (!body) return `${classPrefix}${heritage} {}`;
|
|
182
|
+
|
|
183
|
+
const members: string[] = [];
|
|
184
|
+
for (const member of body.namedChildren) {
|
|
185
|
+
switch (member.type) {
|
|
186
|
+
case "public_field_definition":
|
|
187
|
+
case "property_definition": {
|
|
188
|
+
members.push(" " + collapseWhitespace(member.text).replace(/;$/, "") + ";");
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
case "method_definition": {
|
|
192
|
+
const methodBody = member.childForFieldName("body");
|
|
193
|
+
if (methodBody) {
|
|
194
|
+
const sig = collapseWhitespace(source.slice(member.startIndex, methodBody.startIndex).trimEnd());
|
|
195
|
+
members.push(" " + sig + ";");
|
|
196
|
+
} else {
|
|
197
|
+
members.push(" " + collapseWhitespace(member.text) + ";");
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return `${classPrefix}${heritage} {\n${members.join("\n")}\n}`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Extract interface with all members */
|
|
208
|
+
function extractInterface(node: Node, source: string): string {
|
|
209
|
+
const nameNode = node.childForFieldName("name");
|
|
210
|
+
const name = nameNode?.text ?? "Anonymous";
|
|
211
|
+
const body = node.childForFieldName("body");
|
|
212
|
+
|
|
213
|
+
// Heritage (extends)
|
|
214
|
+
const extendsClause = node.children.find(c => c.type === "extends_type_clause");
|
|
215
|
+
const ext = extendsClause ? " " + collapseWhitespace(extendsClause.text) : "";
|
|
216
|
+
|
|
217
|
+
// Prefix
|
|
218
|
+
const prefixEnd = (nameNode ?? body ?? node).startIndex;
|
|
219
|
+
const rawPrefix = source.slice(node.startIndex, prefixEnd).trimEnd();
|
|
220
|
+
const prefix = collapseWhitespace(rawPrefix).replace(name, "").trimEnd();
|
|
221
|
+
const ifacePrefix = prefix ? `${prefix} ${name}` : `interface ${name}`;
|
|
222
|
+
|
|
223
|
+
if (!body) return `${ifacePrefix}${ext} {}`;
|
|
224
|
+
|
|
225
|
+
const members = body.namedChildren.map(m => {
|
|
226
|
+
const text = collapseWhitespace(m.text).replace(/;$/, "");
|
|
227
|
+
return " " + text + ";";
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
return `${ifacePrefix}${ext} {\n${members.join("\n")}\n}`;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Extract enum */
|
|
234
|
+
function extractEnum(node: Node): string {
|
|
235
|
+
const nameNode = node.childForFieldName("name");
|
|
236
|
+
const name = nameNode?.text ?? "Anonymous";
|
|
237
|
+
const body = node.childForFieldName("body");
|
|
238
|
+
|
|
239
|
+
const isExport = node.parent?.type === "export_statement" ? "export " : "";
|
|
240
|
+
const isConst = node.children.some(c => c.text === "const") ? "const " : "";
|
|
241
|
+
|
|
242
|
+
if (!body) return `${isExport}${isConst}enum ${name} {}`;
|
|
243
|
+
|
|
244
|
+
const members = body.namedChildren
|
|
245
|
+
.filter(m => m.type === "enum_member" || m.type === "property_identifier")
|
|
246
|
+
.map(m => collapseWhitespace(m.text));
|
|
247
|
+
|
|
248
|
+
return `${isExport}${isConst}enum ${name} { ${members.join(", ")} }`;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/** Extract variable statement (const/let/var with possible arrow functions) */
|
|
252
|
+
function extractVariable(node: Node, source: string): string {
|
|
253
|
+
const keyword = node.children[0]?.text ?? "const";
|
|
254
|
+
const isExport = node.parent?.type === "export_statement" ? "export " : "";
|
|
255
|
+
|
|
256
|
+
const declarators = node.namedChildren.filter(c => c.type === "variable_declarator");
|
|
257
|
+
const parts = declarators.map(d => {
|
|
258
|
+
const name = d.childForFieldName("name")?.text ?? "?";
|
|
259
|
+
const typeAnn = d.childForFieldName("type")
|
|
260
|
+
? ": " + collapseWhitespace(d.childForFieldName("type")!.text)
|
|
261
|
+
: "";
|
|
262
|
+
const value = d.childForFieldName("value");
|
|
263
|
+
|
|
264
|
+
if (value && (value.type === "arrow_function" || value.type === "function_expression" || value.type === "function")) {
|
|
265
|
+
return `${name} = ${stubBody(value, source)}`;
|
|
266
|
+
}
|
|
267
|
+
if (typeAnn) return `${name}${typeAnn}`;
|
|
268
|
+
if (value) return `${name} = …`;
|
|
269
|
+
return name;
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return `${isExport}${keyword} ${parts.join(", ")};`;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Extract type alias */
|
|
276
|
+
function extractTypeAlias(node: Node): string {
|
|
277
|
+
const isExport = node.parent?.type === "export_statement" ? "export " : "";
|
|
278
|
+
return isExport + collapseWhitespace(node.text);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function collapseWhitespace(s: string): string {
|
|
282
|
+
return s.replace(/\s+/g, " ").trim();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/** Process a single top-level statement */
|
|
286
|
+
function extractTopLevel(node: Node, source: string): string | null {
|
|
287
|
+
// Unwrap export_statement to get the inner declaration
|
|
288
|
+
if (node.type === "export_statement") {
|
|
289
|
+
// Re-export: export { ... } from "..."
|
|
290
|
+
const exportClause = node.namedChildren.find(c => c.type === "export_clause");
|
|
291
|
+
if (exportClause) return collapseWhitespace(node.text);
|
|
292
|
+
|
|
293
|
+
// export default expression
|
|
294
|
+
const defaultKw = node.children.find(c => c.text === "default");
|
|
295
|
+
if (defaultKw) {
|
|
296
|
+
const inner = node.namedChildren.find(c => c.type !== "export_clause");
|
|
297
|
+
if (inner && (inner.type === "function_declaration" || inner.type === "class_declaration")) {
|
|
298
|
+
return "export default " + extractTopLevel(inner, source);
|
|
299
|
+
}
|
|
300
|
+
return `export default …;`;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// export <declaration>
|
|
304
|
+
const inner = node.namedChildren[0];
|
|
305
|
+
if (inner) {
|
|
306
|
+
const result = extractTopLevel(inner, source);
|
|
307
|
+
if (result) {
|
|
308
|
+
const alreadyHasExport = result.startsWith("export ");
|
|
309
|
+
return alreadyHasExport ? result : "export " + result;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return collapseWhitespace(node.text);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
switch (node.type) {
|
|
316
|
+
case "import_statement":
|
|
317
|
+
return collapseWhitespace(node.text);
|
|
318
|
+
case "function_declaration":
|
|
319
|
+
case "generator_function_declaration":
|
|
320
|
+
return extractFunction(node, source);
|
|
321
|
+
case "class_declaration":
|
|
322
|
+
return extractClass(node, source);
|
|
323
|
+
case "interface_declaration":
|
|
324
|
+
return extractInterface(node, source);
|
|
325
|
+
case "type_alias_declaration":
|
|
326
|
+
return extractTypeAlias(node);
|
|
327
|
+
case "enum_declaration":
|
|
328
|
+
return extractEnum(node);
|
|
329
|
+
case "lexical_declaration":
|
|
330
|
+
case "variable_declaration":
|
|
331
|
+
return extractVariable(node, source);
|
|
332
|
+
case "export_statement":
|
|
333
|
+
return collapseWhitespace(node.text);
|
|
334
|
+
default:
|
|
335
|
+
return null;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export const tsExtractor: LanguageExtractor = {
|
|
340
|
+
extensions: ["ts", "tsx", "js", "jsx", "mts", "cts"],
|
|
341
|
+
grammarName: "typescript",
|
|
342
|
+
|
|
343
|
+
extract(tree: Tree, source: string, options?: HologramOptions): string[] {
|
|
344
|
+
const rootChildren = tree.rootNode.namedChildren;
|
|
345
|
+
|
|
346
|
+
// === Pure Type File Bypass ===
|
|
347
|
+
// If all top-level nodes are type declarations (no implementation bodies),
|
|
348
|
+
// skip extraction entirely and return the original source as-is.
|
|
349
|
+
if (!options?.symbols && !options?.contextFile && isPureTypeFile(rootChildren)) {
|
|
350
|
+
return [source];
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// === L1 Symbol Extraction ===
|
|
354
|
+
// If specific symbols are requested, pinpoint-extract only those nodes.
|
|
355
|
+
if (options?.symbols && options.symbols.length > 0) {
|
|
356
|
+
const symbolSet = new Set(options.symbols);
|
|
357
|
+
const matched: string[] = [];
|
|
358
|
+
for (const stmt of rootChildren) {
|
|
359
|
+
const name = getDeclarationName(stmt);
|
|
360
|
+
if (name && symbolSet.has(name)) {
|
|
361
|
+
const line = extractTopLevel(stmt, source);
|
|
362
|
+
if (line) matched.push(line);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return matched;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const lines: string[] = [];
|
|
369
|
+
|
|
370
|
+
// L1 filtering setup
|
|
371
|
+
let importedSymbols: Set<string> | "all" | null = null;
|
|
372
|
+
if (options?.contextFile) {
|
|
373
|
+
try {
|
|
374
|
+
const contextSource = readFileSync(options.contextFile, "utf-8");
|
|
375
|
+
importedSymbols = extractImportedSymbols(contextSource, "");
|
|
376
|
+
if (importedSymbols !== "all" && importedSymbols.size === 0) importedSymbols = null;
|
|
377
|
+
} catch {
|
|
378
|
+
importedSymbols = null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
for (const stmt of rootChildren) {
|
|
383
|
+
// L1: filter non-imported exports
|
|
384
|
+
if (importedSymbols && importedSymbols !== "all") {
|
|
385
|
+
const exportedName = getExportedName(stmt);
|
|
386
|
+
if (exportedName !== null && !importedSymbols.has(exportedName)) {
|
|
387
|
+
const line = extractTopLevel(stmt, source);
|
|
388
|
+
if (line) {
|
|
389
|
+
const stub = line.split("\n")[0].replace(/\{[^}]*\}?\s*$/, "").trimEnd();
|
|
390
|
+
lines.push(`${stub} // details omitted — read directly if needed`);
|
|
391
|
+
}
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const line = extractTopLevel(stmt, source);
|
|
397
|
+
if (line) lines.push(line);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (importedSymbols && importedSymbols !== "all") {
|
|
401
|
+
lines.push("\n// [afd L1] Non-imported exports are shown as stubs. Use afd_read for full details.");
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return lines;
|
|
405
|
+
},
|
|
406
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Tree } from "web-tree-sitter";
|
|
2
|
+
|
|
3
|
+
export interface HologramResult {
|
|
4
|
+
hologram: string;
|
|
5
|
+
originalLength: number;
|
|
6
|
+
hologramLength: number;
|
|
7
|
+
savings: number; // percentage 0-100
|
|
8
|
+
language?: string;
|
|
9
|
+
isDiff?: boolean;
|
|
10
|
+
changedNodes?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface HologramOptions {
|
|
14
|
+
contextFile?: string;
|
|
15
|
+
diffOnly?: boolean;
|
|
16
|
+
/** L1: Extract only these named symbols (interfaces, types, classes, functions) */
|
|
17
|
+
symbols?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface LanguageExtractor {
|
|
21
|
+
/** Supported file extensions (without dot) */
|
|
22
|
+
extensions: string[];
|
|
23
|
+
/** Tree-sitter grammar name for WASM resolution */
|
|
24
|
+
grammarName: string;
|
|
25
|
+
/** Extract type signatures from AST */
|
|
26
|
+
extract(tree: Tree, source: string, options?: HologramOptions): string[];
|
|
27
|
+
}
|