@aionlabsai/aion 0.2.10 → 0.2.12
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/dist/cli/commands/churn.js +2 -3
- package/dist/cli/commands/churn.js.map +1 -1
- package/dist/cli/commands/explain.js +2 -3
- package/dist/cli/commands/explain.js.map +1 -1
- package/dist/cli/commands/graph.js +2 -3
- package/dist/cli/commands/graph.js.map +1 -1
- package/dist/cli/commands/health.js +2 -3
- package/dist/cli/commands/health.js.map +1 -1
- package/dist/cli/commands/memory.d.ts.map +1 -1
- package/dist/cli/commands/memory.js +79 -26
- package/dist/cli/commands/memory.js.map +1 -1
- package/dist/cli/commands/patterns.js +2 -3
- package/dist/cli/commands/patterns.js.map +1 -1
- package/dist/core/pipelines/audit-pipeline.d.ts.map +1 -1
- package/dist/core/pipelines/audit-pipeline.js +2 -5
- package/dist/core/pipelines/audit-pipeline.js.map +1 -1
- package/dist/infra/bm25.d.ts +13 -0
- package/dist/infra/bm25.d.ts.map +1 -1
- package/dist/infra/bm25.js +18 -0
- package/dist/infra/bm25.js.map +1 -1
- package/dist/infra/dep-graph.d.ts +2 -0
- package/dist/infra/dep-graph.d.ts.map +1 -1
- package/dist/infra/dep-graph.js +111 -31
- package/dist/infra/dep-graph.js.map +1 -1
- package/dist/infra/embeddings.d.ts +4 -0
- package/dist/infra/embeddings.d.ts.map +1 -1
- package/dist/infra/embeddings.js +80 -7
- package/dist/infra/embeddings.js.map +1 -1
- package/dist/infra/knowledge.js +3 -3
- package/dist/infra/knowledge.js.map +1 -1
- package/dist/infra/project-report.js +2 -3
- package/dist/infra/project-report.js.map +1 -1
- package/dist/infra/vector-store.d.ts +37 -0
- package/dist/infra/vector-store.d.ts.map +1 -0
- package/dist/infra/vector-store.js +126 -0
- package/dist/infra/vector-store.js.map +1 -0
- package/package.json +1 -1
- package/dist/infra/dep-graph-python.d.ts +0 -3
- package/dist/infra/dep-graph-python.d.ts.map +0 -1
- package/dist/infra/dep-graph-python.js +0 -154
- package/dist/infra/dep-graph-python.js.map +0 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface VectorResult {
|
|
2
|
+
id: string;
|
|
3
|
+
score: number;
|
|
4
|
+
payload: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export interface VectorStore {
|
|
7
|
+
upsert(id: string, vector: number[], payload: Record<string, unknown>): Promise<void>;
|
|
8
|
+
search(vector: number[], topK: number): Promise<VectorResult[]>;
|
|
9
|
+
clear(): Promise<void>;
|
|
10
|
+
size(): number;
|
|
11
|
+
}
|
|
12
|
+
export declare class JsonFileStore implements VectorStore {
|
|
13
|
+
private readonly filePath;
|
|
14
|
+
private entries;
|
|
15
|
+
constructor(filePath: string);
|
|
16
|
+
private load;
|
|
17
|
+
private save;
|
|
18
|
+
upsert(id: string, vector: number[], payload: Record<string, unknown>): Promise<void>;
|
|
19
|
+
search(queryVec: number[], topK: number): Promise<VectorResult[]>;
|
|
20
|
+
clear(): Promise<void>;
|
|
21
|
+
size(): number;
|
|
22
|
+
}
|
|
23
|
+
export declare class QdrantStore implements VectorStore {
|
|
24
|
+
private readonly url;
|
|
25
|
+
private readonly collection;
|
|
26
|
+
private _size;
|
|
27
|
+
private initialized;
|
|
28
|
+
constructor(url: string, collection: string);
|
|
29
|
+
private ensureCollection;
|
|
30
|
+
upsert(id: string, vector: number[], payload: Record<string, unknown>): Promise<void>;
|
|
31
|
+
search(vector: number[], topK: number): Promise<VectorResult[]>;
|
|
32
|
+
clear(): Promise<void>;
|
|
33
|
+
size(): number;
|
|
34
|
+
}
|
|
35
|
+
export declare function createVectorStore(cwd: string): VectorStore;
|
|
36
|
+
export declare function vectorStoreBackend(): string;
|
|
37
|
+
//# sourceMappingURL=vector-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store.d.ts","sourceRoot":"","sources":["../../src/infra/vector-store.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAChE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,MAAM,CAAC;CAChB;AAUD,qBAAa,aAAc,YAAW,WAAW;IAGnC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAFrC,OAAO,CAAC,OAAO,CAAqF;gBAEvE,QAAQ,EAAE,MAAM;IAI7C,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,IAAI;IAQN,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrF,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAQjE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAK5B,IAAI,IAAI,MAAM;CACf;AAMD,qBAAa,WAAY,YAAW,WAAW;IAK3C,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAL7B,OAAO,CAAC,KAAK,CAAK;IAClB,OAAO,CAAC,WAAW,CAAS;gBAGT,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM;YAGvB,gBAAgB;IAgBxB,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAarF,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB/D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,IAAI,IAAI,MAAM;CACf;AAID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAO1D;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { cosineSimilarity, stringToUUID } from './embeddings.js';
|
|
4
|
+
export class JsonFileStore {
|
|
5
|
+
filePath;
|
|
6
|
+
entries = [];
|
|
7
|
+
constructor(filePath) {
|
|
8
|
+
this.filePath = filePath;
|
|
9
|
+
this.load();
|
|
10
|
+
}
|
|
11
|
+
load() {
|
|
12
|
+
try {
|
|
13
|
+
const raw = JSON.parse(readFileSync(this.filePath, 'utf8'));
|
|
14
|
+
this.entries = raw.map((e) => ({ id: e.id, vector: new Float32Array(e.vector), payload: e.payload }));
|
|
15
|
+
}
|
|
16
|
+
catch { /* fresh store */ }
|
|
17
|
+
}
|
|
18
|
+
save() {
|
|
19
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
20
|
+
const raw = this.entries.map((e) => ({
|
|
21
|
+
id: e.id, vector: Array.from(e.vector), payload: e.payload,
|
|
22
|
+
}));
|
|
23
|
+
writeFileSync(this.filePath, JSON.stringify(raw), 'utf8');
|
|
24
|
+
}
|
|
25
|
+
async upsert(id, vector, payload) {
|
|
26
|
+
const idx = this.entries.findIndex((e) => e.id === id);
|
|
27
|
+
const entry = { id, vector: new Float32Array(vector), payload };
|
|
28
|
+
if (idx >= 0)
|
|
29
|
+
this.entries[idx] = entry;
|
|
30
|
+
else
|
|
31
|
+
this.entries.push(entry);
|
|
32
|
+
this.save();
|
|
33
|
+
}
|
|
34
|
+
async search(queryVec, topK) {
|
|
35
|
+
const q = new Float32Array(queryVec);
|
|
36
|
+
return this.entries
|
|
37
|
+
.map((e) => ({ id: e.id, score: cosineSimilarity(q, e.vector), payload: e.payload }))
|
|
38
|
+
.sort((a, b) => b.score - a.score)
|
|
39
|
+
.slice(0, topK);
|
|
40
|
+
}
|
|
41
|
+
async clear() {
|
|
42
|
+
this.entries = [];
|
|
43
|
+
this.save();
|
|
44
|
+
}
|
|
45
|
+
size() { return this.entries.length; }
|
|
46
|
+
}
|
|
47
|
+
// ── QdrantStore — production-ready, requires Qdrant instance ─────────────────
|
|
48
|
+
// Start locally: docker run -p 6333:6333 qdrant/qdrant
|
|
49
|
+
// Or use Qdrant Cloud (free tier available at cloud.qdrant.io)
|
|
50
|
+
export class QdrantStore {
|
|
51
|
+
url;
|
|
52
|
+
collection;
|
|
53
|
+
_size = 0;
|
|
54
|
+
initialized = false;
|
|
55
|
+
constructor(url, collection) {
|
|
56
|
+
this.url = url;
|
|
57
|
+
this.collection = collection;
|
|
58
|
+
}
|
|
59
|
+
async ensureCollection(dimension) {
|
|
60
|
+
if (this.initialized)
|
|
61
|
+
return;
|
|
62
|
+
// Check if collection exists
|
|
63
|
+
const check = await fetch(`${this.url}/collections/${this.collection}`);
|
|
64
|
+
if (check.ok) {
|
|
65
|
+
this.initialized = true;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
// Create collection with cosine distance
|
|
69
|
+
const res = await fetch(`${this.url}/collections/${this.collection}`, {
|
|
70
|
+
method: 'PUT',
|
|
71
|
+
headers: { 'Content-Type': 'application/json' },
|
|
72
|
+
body: JSON.stringify({ vectors: { size: dimension, distance: 'Cosine' } }),
|
|
73
|
+
});
|
|
74
|
+
if (!res.ok)
|
|
75
|
+
throw new Error(`Qdrant create collection: ${res.status} ${await res.text()}`);
|
|
76
|
+
this.initialized = true;
|
|
77
|
+
}
|
|
78
|
+
async upsert(id, vector, payload) {
|
|
79
|
+
await this.ensureCollection(vector.length);
|
|
80
|
+
const res = await fetch(`${this.url}/collections/${this.collection}/points`, {
|
|
81
|
+
method: 'PUT',
|
|
82
|
+
headers: { 'Content-Type': 'application/json' },
|
|
83
|
+
body: JSON.stringify({
|
|
84
|
+
points: [{ id: stringToUUID(id), vector, payload: { ...payload, _id: id } }],
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
if (!res.ok)
|
|
88
|
+
throw new Error(`Qdrant upsert: ${res.status} ${await res.text()}`);
|
|
89
|
+
this._size++;
|
|
90
|
+
}
|
|
91
|
+
async search(vector, topK) {
|
|
92
|
+
await this.ensureCollection(vector.length);
|
|
93
|
+
const res = await fetch(`${this.url}/collections/${this.collection}/points/search`, {
|
|
94
|
+
method: 'POST',
|
|
95
|
+
headers: { 'Content-Type': 'application/json' },
|
|
96
|
+
body: JSON.stringify({ vector, limit: topK, with_payload: true }),
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok)
|
|
99
|
+
throw new Error(`Qdrant search: ${res.status} ${await res.text()}`);
|
|
100
|
+
const json = await res.json();
|
|
101
|
+
return json.result.map((r) => ({
|
|
102
|
+
id: String(r.payload['_id'] ?? ''),
|
|
103
|
+
score: r.score,
|
|
104
|
+
payload: r.payload,
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
async clear() {
|
|
108
|
+
await fetch(`${this.url}/collections/${this.collection}`, { method: 'DELETE' });
|
|
109
|
+
this.initialized = false;
|
|
110
|
+
this._size = 0;
|
|
111
|
+
}
|
|
112
|
+
size() { return this._size; }
|
|
113
|
+
}
|
|
114
|
+
// ── Factory ───────────────────────────────────────────────────────────────────
|
|
115
|
+
export function createVectorStore(cwd) {
|
|
116
|
+
if (process.env.QDRANT_URL) {
|
|
117
|
+
// Derive collection name from project path (last segment, safe chars)
|
|
118
|
+
const projectSlug = cwd.split('/').filter(Boolean).pop()?.replace(/[^a-z0-9-]/gi, '-').toLowerCase() ?? 'project';
|
|
119
|
+
return new QdrantStore(process.env.QDRANT_URL, `aion-${projectSlug}`);
|
|
120
|
+
}
|
|
121
|
+
return new JsonFileStore(join(cwd, '.ai-runtime', 'vectors.json'));
|
|
122
|
+
}
|
|
123
|
+
export function vectorStoreBackend() {
|
|
124
|
+
return process.env.QDRANT_URL ? `Qdrant (${process.env.QDRANT_URL})` : 'JSON file (.ai-runtime/vectors.json)';
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=vector-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-store.js","sourceRoot":"","sources":["../../src/infra/vector-store.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dep-graph-python.d.ts","sourceRoot":"","sources":["../../src/infra/dep-graph-python.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAW,MAAM,gBAAgB,CAAC;AAoFxD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAuCzD"}
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { readdirSync, readFileSync, statSync } from 'fs';
|
|
2
|
-
import { join, relative, dirname } from 'path';
|
|
3
|
-
const IGNORE_DIRS = new Set([
|
|
4
|
-
'__pycache__', '.git', 'node_modules', 'dist', 'build',
|
|
5
|
-
'.venv', 'venv', 'env', '.env', 'site-packages',
|
|
6
|
-
]);
|
|
7
|
-
function collectPyFiles(cwd) {
|
|
8
|
-
const files = [];
|
|
9
|
-
const walk = (dir) => {
|
|
10
|
-
let entries;
|
|
11
|
-
try {
|
|
12
|
-
entries = readdirSync(dir);
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
|
-
for (const entry of entries) {
|
|
18
|
-
if (IGNORE_DIRS.has(entry) || entry.startsWith('.'))
|
|
19
|
-
continue;
|
|
20
|
-
const full = join(dir, entry);
|
|
21
|
-
let st;
|
|
22
|
-
try {
|
|
23
|
-
st = statSync(full);
|
|
24
|
-
}
|
|
25
|
-
catch {
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
if (st.isDirectory()) {
|
|
29
|
-
walk(full);
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
if (entry.endsWith('.py'))
|
|
33
|
-
files.push(relative(cwd, full));
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
walk(cwd);
|
|
37
|
-
return files;
|
|
38
|
-
}
|
|
39
|
-
function parseImports(content, fromFile, allFiles, cwd) {
|
|
40
|
-
const resolved = [];
|
|
41
|
-
const lines = content.split('\n');
|
|
42
|
-
for (const line of lines) {
|
|
43
|
-
const trimmed = line.trim();
|
|
44
|
-
// import foo.bar or from foo.bar import baz
|
|
45
|
-
const fromMatch = /^from\s+([\w.]+)\s+import/.exec(trimmed);
|
|
46
|
-
const importMatch = /^import\s+([\w.]+)/.exec(trimmed);
|
|
47
|
-
const spec = fromMatch?.[1] ?? importMatch?.[1];
|
|
48
|
-
if (!spec)
|
|
49
|
-
continue;
|
|
50
|
-
// Convert dot-notation to path
|
|
51
|
-
const parts = spec.split('.');
|
|
52
|
-
const candidates = [
|
|
53
|
-
parts.join('/') + '.py',
|
|
54
|
-
parts.join('/') + '/__init__.py',
|
|
55
|
-
];
|
|
56
|
-
// Relative resolution from file's directory
|
|
57
|
-
const fileDir = dirname(fromFile);
|
|
58
|
-
for (const candidate of candidates) {
|
|
59
|
-
const relFromFile = join(fileDir, candidate);
|
|
60
|
-
const relFromRoot = candidate;
|
|
61
|
-
if (allFiles.has(relFromFile)) {
|
|
62
|
-
resolved.push(relFromFile);
|
|
63
|
-
break;
|
|
64
|
-
}
|
|
65
|
-
if (allFiles.has(relFromRoot)) {
|
|
66
|
-
resolved.push(relFromRoot);
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return [...new Set(resolved)];
|
|
72
|
-
}
|
|
73
|
-
function countLines(content) {
|
|
74
|
-
return content.split('\n').length;
|
|
75
|
-
}
|
|
76
|
-
function detectCyclesPy(nodes) {
|
|
77
|
-
const visited = new Set();
|
|
78
|
-
const inStack = new Set();
|
|
79
|
-
const cycles = [];
|
|
80
|
-
function dfs(node, path) {
|
|
81
|
-
if (inStack.has(node)) {
|
|
82
|
-
const start = path.indexOf(node);
|
|
83
|
-
if (start !== -1)
|
|
84
|
-
cycles.push(path.slice(start));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
if (visited.has(node))
|
|
88
|
-
return;
|
|
89
|
-
visited.add(node);
|
|
90
|
-
inStack.add(node);
|
|
91
|
-
for (const imp of nodes.get(node)?.imports ?? [])
|
|
92
|
-
dfs(imp, [...path, node]);
|
|
93
|
-
inStack.delete(node);
|
|
94
|
-
}
|
|
95
|
-
for (const file of nodes.keys())
|
|
96
|
-
dfs(file, []);
|
|
97
|
-
return cycles.slice(0, 20);
|
|
98
|
-
}
|
|
99
|
-
export function buildPythonDepGraph(cwd) {
|
|
100
|
-
const files = collectPyFiles(cwd);
|
|
101
|
-
const fileSet = new Set(files);
|
|
102
|
-
const nodes = new Map();
|
|
103
|
-
for (const file of files) {
|
|
104
|
-
let content = '';
|
|
105
|
-
try {
|
|
106
|
-
content = readFileSync(join(cwd, file), 'utf8');
|
|
107
|
-
}
|
|
108
|
-
catch {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
nodes.set(file, {
|
|
112
|
-
file,
|
|
113
|
-
imports: [],
|
|
114
|
-
importedBy: [],
|
|
115
|
-
exports: extractExports(content),
|
|
116
|
-
loc: countLines(content),
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
for (const file of files) {
|
|
120
|
-
let content = '';
|
|
121
|
-
try {
|
|
122
|
-
content = readFileSync(join(cwd, file), 'utf8');
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
continue;
|
|
126
|
-
}
|
|
127
|
-
const imports = parseImports(content, file, fileSet, cwd);
|
|
128
|
-
nodes.get(file).imports = imports;
|
|
129
|
-
for (const imp of imports) {
|
|
130
|
-
nodes.get(imp)?.importedBy.push(file);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
const cycles = detectCyclesPy(nodes);
|
|
134
|
-
const hotspots = [...nodes.values()]
|
|
135
|
-
.map((n) => ({
|
|
136
|
-
file: n.file,
|
|
137
|
-
fanIn: n.importedBy.length,
|
|
138
|
-
fanOut: n.imports.length,
|
|
139
|
-
score: n.importedBy.length * 2 + n.imports.length + Math.floor(n.loc / 100),
|
|
140
|
-
}))
|
|
141
|
-
.sort((a, b) => b.score - a.score)
|
|
142
|
-
.slice(0, 15);
|
|
143
|
-
return { nodes, cycles, hotspots };
|
|
144
|
-
}
|
|
145
|
-
function extractExports(content) {
|
|
146
|
-
const exports = [];
|
|
147
|
-
for (const line of content.split('\n')) {
|
|
148
|
-
const m = /^(?:def|class|async def)\s+([A-Za-z_]\w*)/.exec(line.trim());
|
|
149
|
-
if (m?.[1] && !m[1].startsWith('_'))
|
|
150
|
-
exports.push(m[1]);
|
|
151
|
-
}
|
|
152
|
-
return exports.slice(0, 50);
|
|
153
|
-
}
|
|
154
|
-
//# sourceMappingURL=dep-graph-python.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dep-graph-python.js","sourceRoot":"","sources":["../../src/infra/dep-graph-python.ts"],"names":[],"mappings":"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"}
|