gnosys 4.0.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/LICENSE +21 -0
- package/README.md +1387 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +3753 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2267 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/archive.d.ts +95 -0
- package/dist/lib/archive.d.ts.map +1 -0
- package/dist/lib/archive.js +311 -0
- package/dist/lib/archive.js.map +1 -0
- package/dist/lib/ask.d.ts +77 -0
- package/dist/lib/ask.d.ts.map +1 -0
- package/dist/lib/ask.js +316 -0
- package/dist/lib/ask.js.map +1 -0
- package/dist/lib/audit.d.ts +47 -0
- package/dist/lib/audit.d.ts.map +1 -0
- package/dist/lib/audit.js +136 -0
- package/dist/lib/audit.js.map +1 -0
- package/dist/lib/bootstrap.d.ts +56 -0
- package/dist/lib/bootstrap.d.ts.map +1 -0
- package/dist/lib/bootstrap.js +163 -0
- package/dist/lib/bootstrap.js.map +1 -0
- package/dist/lib/config.d.ts +239 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +371 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/dashboard.d.ts +81 -0
- package/dist/lib/dashboard.d.ts.map +1 -0
- package/dist/lib/dashboard.js +314 -0
- package/dist/lib/dashboard.js.map +1 -0
- package/dist/lib/db.d.ts +182 -0
- package/dist/lib/db.d.ts.map +1 -0
- package/dist/lib/db.js +620 -0
- package/dist/lib/db.js.map +1 -0
- package/dist/lib/dbSearch.d.ts +65 -0
- package/dist/lib/dbSearch.d.ts.map +1 -0
- package/dist/lib/dbSearch.js +239 -0
- package/dist/lib/dbSearch.js.map +1 -0
- package/dist/lib/dbWrite.d.ts +56 -0
- package/dist/lib/dbWrite.d.ts.map +1 -0
- package/dist/lib/dbWrite.js +171 -0
- package/dist/lib/dbWrite.js.map +1 -0
- package/dist/lib/dream.d.ts +170 -0
- package/dist/lib/dream.d.ts.map +1 -0
- package/dist/lib/dream.js +706 -0
- package/dist/lib/dream.js.map +1 -0
- package/dist/lib/embeddings.d.ts +84 -0
- package/dist/lib/embeddings.d.ts.map +1 -0
- package/dist/lib/embeddings.js +226 -0
- package/dist/lib/embeddings.js.map +1 -0
- package/dist/lib/export.d.ts +92 -0
- package/dist/lib/export.d.ts.map +1 -0
- package/dist/lib/export.js +362 -0
- package/dist/lib/export.js.map +1 -0
- package/dist/lib/federated.d.ts +113 -0
- package/dist/lib/federated.d.ts.map +1 -0
- package/dist/lib/federated.js +346 -0
- package/dist/lib/federated.js.map +1 -0
- package/dist/lib/graph.d.ts +50 -0
- package/dist/lib/graph.d.ts.map +1 -0
- package/dist/lib/graph.js +118 -0
- package/dist/lib/graph.js.map +1 -0
- package/dist/lib/history.d.ts +39 -0
- package/dist/lib/history.d.ts.map +1 -0
- package/dist/lib/history.js +112 -0
- package/dist/lib/history.js.map +1 -0
- package/dist/lib/hybridSearch.d.ts +80 -0
- package/dist/lib/hybridSearch.d.ts.map +1 -0
- package/dist/lib/hybridSearch.js +296 -0
- package/dist/lib/hybridSearch.js.map +1 -0
- package/dist/lib/import.d.ts +52 -0
- package/dist/lib/import.d.ts.map +1 -0
- package/dist/lib/import.js +365 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/ingest.d.ts +51 -0
- package/dist/lib/ingest.d.ts.map +1 -0
- package/dist/lib/ingest.js +144 -0
- package/dist/lib/ingest.js.map +1 -0
- package/dist/lib/lensing.d.ts +35 -0
- package/dist/lib/lensing.d.ts.map +1 -0
- package/dist/lib/lensing.js +85 -0
- package/dist/lib/lensing.js.map +1 -0
- package/dist/lib/llm.d.ts +84 -0
- package/dist/lib/llm.d.ts.map +1 -0
- package/dist/lib/llm.js +386 -0
- package/dist/lib/llm.js.map +1 -0
- package/dist/lib/lock.d.ts +28 -0
- package/dist/lib/lock.d.ts.map +1 -0
- package/dist/lib/lock.js +145 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/maintenance.d.ts +124 -0
- package/dist/lib/maintenance.d.ts.map +1 -0
- package/dist/lib/maintenance.js +587 -0
- package/dist/lib/maintenance.js.map +1 -0
- package/dist/lib/migrate.d.ts +19 -0
- package/dist/lib/migrate.d.ts.map +1 -0
- package/dist/lib/migrate.js +260 -0
- package/dist/lib/migrate.js.map +1 -0
- package/dist/lib/preferences.d.ts +49 -0
- package/dist/lib/preferences.d.ts.map +1 -0
- package/dist/lib/preferences.js +149 -0
- package/dist/lib/preferences.js.map +1 -0
- package/dist/lib/projectIdentity.d.ts +66 -0
- package/dist/lib/projectIdentity.d.ts.map +1 -0
- package/dist/lib/projectIdentity.js +148 -0
- package/dist/lib/projectIdentity.js.map +1 -0
- package/dist/lib/recall.d.ts +82 -0
- package/dist/lib/recall.d.ts.map +1 -0
- package/dist/lib/recall.js +289 -0
- package/dist/lib/recall.js.map +1 -0
- package/dist/lib/resolver.d.ts +116 -0
- package/dist/lib/resolver.d.ts.map +1 -0
- package/dist/lib/resolver.js +372 -0
- package/dist/lib/resolver.js.map +1 -0
- package/dist/lib/retry.d.ts +24 -0
- package/dist/lib/retry.d.ts.map +1 -0
- package/dist/lib/retry.js +60 -0
- package/dist/lib/retry.js.map +1 -0
- package/dist/lib/rulesGen.d.ts +51 -0
- package/dist/lib/rulesGen.d.ts.map +1 -0
- package/dist/lib/rulesGen.js +167 -0
- package/dist/lib/rulesGen.js.map +1 -0
- package/dist/lib/search.d.ts +51 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +190 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/staticSearch.d.ts +70 -0
- package/dist/lib/staticSearch.d.ts.map +1 -0
- package/dist/lib/staticSearch.js +162 -0
- package/dist/lib/staticSearch.js.map +1 -0
- package/dist/lib/store.d.ts +79 -0
- package/dist/lib/store.d.ts.map +1 -0
- package/dist/lib/store.js +227 -0
- package/dist/lib/store.js.map +1 -0
- package/dist/lib/structuredIngest.d.ts +37 -0
- package/dist/lib/structuredIngest.d.ts.map +1 -0
- package/dist/lib/structuredIngest.js +208 -0
- package/dist/lib/structuredIngest.js.map +1 -0
- package/dist/lib/tags.d.ts +26 -0
- package/dist/lib/tags.d.ts.map +1 -0
- package/dist/lib/tags.js +109 -0
- package/dist/lib/tags.js.map +1 -0
- package/dist/lib/timeline.d.ts +34 -0
- package/dist/lib/timeline.d.ts.map +1 -0
- package/dist/lib/timeline.js +116 -0
- package/dist/lib/timeline.js.map +1 -0
- package/dist/lib/trace.d.ts +42 -0
- package/dist/lib/trace.d.ts.map +1 -0
- package/dist/lib/trace.js +338 -0
- package/dist/lib/trace.js.map +1 -0
- package/dist/lib/webIndex.d.ts +28 -0
- package/dist/lib/webIndex.d.ts.map +1 -0
- package/dist/lib/webIndex.js +208 -0
- package/dist/lib/webIndex.js.map +1 -0
- package/dist/lib/webIngest.d.ts +51 -0
- package/dist/lib/webIngest.d.ts.map +1 -0
- package/dist/lib/webIngest.js +533 -0
- package/dist/lib/webIngest.js.map +1 -0
- package/dist/lib/wikilinks.d.ts +63 -0
- package/dist/lib/wikilinks.d.ts.map +1 -0
- package/dist/lib/wikilinks.js +146 -0
- package/dist/lib/wikilinks.js.map +1 -0
- package/dist/sandbox/client.d.ts +82 -0
- package/dist/sandbox/client.d.ts.map +1 -0
- package/dist/sandbox/client.js +128 -0
- package/dist/sandbox/client.js.map +1 -0
- package/dist/sandbox/helper-template.d.ts +14 -0
- package/dist/sandbox/helper-template.d.ts.map +1 -0
- package/dist/sandbox/helper-template.js +285 -0
- package/dist/sandbox/helper-template.js.map +1 -0
- package/dist/sandbox/index.d.ts +10 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +10 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +40 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +220 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/server.d.ts +44 -0
- package/dist/sandbox/server.d.ts.map +1 -0
- package/dist/sandbox/server.js +661 -0
- package/dist/sandbox/server.js.map +1 -0
- package/package.json +103 -0
- package/prompts/synthesize.md +21 -0
package/dist/lib/tags.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnosys Tag Registry — Categorized controlled vocabulary for tags.
|
|
3
|
+
* Stored in .config/tags.json. The ingestion LLM must use existing tags
|
|
4
|
+
* but can propose new ones for approval.
|
|
5
|
+
*/
|
|
6
|
+
import fs from "fs/promises";
|
|
7
|
+
import path from "path";
|
|
8
|
+
const DEFAULT_REGISTRY = {
|
|
9
|
+
domain: [
|
|
10
|
+
"auth",
|
|
11
|
+
"database",
|
|
12
|
+
"frontend",
|
|
13
|
+
"backend",
|
|
14
|
+
"deployment",
|
|
15
|
+
"api",
|
|
16
|
+
"cli",
|
|
17
|
+
"mcp",
|
|
18
|
+
"wiki",
|
|
19
|
+
"obsidian",
|
|
20
|
+
"architecture",
|
|
21
|
+
"retrieval",
|
|
22
|
+
"search",
|
|
23
|
+
"ingestion",
|
|
24
|
+
"memory",
|
|
25
|
+
"lensing",
|
|
26
|
+
"decay",
|
|
27
|
+
"reinforcement",
|
|
28
|
+
"contradiction",
|
|
29
|
+
"tags",
|
|
30
|
+
"git",
|
|
31
|
+
"typescript",
|
|
32
|
+
"tooling",
|
|
33
|
+
"roadmap",
|
|
34
|
+
"scope",
|
|
35
|
+
],
|
|
36
|
+
type: [
|
|
37
|
+
"decision",
|
|
38
|
+
"convention",
|
|
39
|
+
"architecture",
|
|
40
|
+
"concept",
|
|
41
|
+
"requirement",
|
|
42
|
+
"landscape",
|
|
43
|
+
"open-question",
|
|
44
|
+
],
|
|
45
|
+
concern: [
|
|
46
|
+
"security",
|
|
47
|
+
"performance",
|
|
48
|
+
"scalability",
|
|
49
|
+
"dx",
|
|
50
|
+
"adoption",
|
|
51
|
+
"community",
|
|
52
|
+
"portability",
|
|
53
|
+
],
|
|
54
|
+
status_tag: ["core", "experimental", "deprecated", "phased"],
|
|
55
|
+
};
|
|
56
|
+
export class GnosysTagRegistry {
|
|
57
|
+
registryPath;
|
|
58
|
+
registry;
|
|
59
|
+
constructor(storePath) {
|
|
60
|
+
this.registryPath = path.join(storePath, ".config", "tags.json");
|
|
61
|
+
this.registry = { ...DEFAULT_REGISTRY };
|
|
62
|
+
}
|
|
63
|
+
async load() {
|
|
64
|
+
try {
|
|
65
|
+
const raw = await fs.readFile(this.registryPath, "utf-8");
|
|
66
|
+
this.registry = JSON.parse(raw);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// File doesn't exist yet — use defaults and create it
|
|
70
|
+
await this.save();
|
|
71
|
+
}
|
|
72
|
+
return this.registry;
|
|
73
|
+
}
|
|
74
|
+
async save() {
|
|
75
|
+
const dir = path.dirname(this.registryPath);
|
|
76
|
+
await fs.mkdir(dir, { recursive: true });
|
|
77
|
+
await fs.writeFile(this.registryPath, JSON.stringify(this.registry, null, 2), "utf-8");
|
|
78
|
+
}
|
|
79
|
+
getRegistry() {
|
|
80
|
+
return this.registry;
|
|
81
|
+
}
|
|
82
|
+
getAllTags() {
|
|
83
|
+
return [...new Set(Object.values(this.registry).flat())].sort();
|
|
84
|
+
}
|
|
85
|
+
getTagsByCategory(category) {
|
|
86
|
+
return this.registry[category] || [];
|
|
87
|
+
}
|
|
88
|
+
hasTag(tag) {
|
|
89
|
+
return Object.values(this.registry).some((tags) => tags.includes(tag));
|
|
90
|
+
}
|
|
91
|
+
findTagCategory(tag) {
|
|
92
|
+
for (const [category, tags] of Object.entries(this.registry)) {
|
|
93
|
+
if (tags.includes(tag))
|
|
94
|
+
return category;
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
async addTag(category, tag) {
|
|
99
|
+
if (!this.registry[category]) {
|
|
100
|
+
this.registry[category] = [];
|
|
101
|
+
}
|
|
102
|
+
if (this.registry[category].includes(tag))
|
|
103
|
+
return false;
|
|
104
|
+
this.registry[category].push(tag);
|
|
105
|
+
await this.save();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/lib/tags.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnosys Timeline — Temporal views and statistics for memory stores.
|
|
3
|
+
*
|
|
4
|
+
* Group memories by time period to see knowledge evolution.
|
|
5
|
+
* Compute summary statistics across the store.
|
|
6
|
+
*/
|
|
7
|
+
import { Memory } from "./store.js";
|
|
8
|
+
export type TimePeriod = "day" | "week" | "month" | "year";
|
|
9
|
+
export interface TimelineEntry {
|
|
10
|
+
period: string;
|
|
11
|
+
created: number;
|
|
12
|
+
modified: number;
|
|
13
|
+
titles: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface MemoryStats {
|
|
16
|
+
totalCount: number;
|
|
17
|
+
byCategory: Record<string, number>;
|
|
18
|
+
byStatus: Record<string, number>;
|
|
19
|
+
byAuthor: Record<string, number>;
|
|
20
|
+
byAuthority: Record<string, number>;
|
|
21
|
+
averageConfidence: number;
|
|
22
|
+
oldestCreated: string | null;
|
|
23
|
+
newestCreated: string | null;
|
|
24
|
+
lastModified: string | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Group memories by time period based on their created/modified dates.
|
|
28
|
+
*/
|
|
29
|
+
export declare function groupByPeriod(memories: Memory[], period: TimePeriod): TimelineEntry[];
|
|
30
|
+
/**
|
|
31
|
+
* Compute summary statistics across all memories.
|
|
32
|
+
*/
|
|
33
|
+
export declare function computeStats(memories: Memory[]): MemoryStats;
|
|
34
|
+
//# sourceMappingURL=timeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.d.ts","sourceRoot":"","sources":["../../src/lib/timeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,UAAU,GAAG,aAAa,EAAE,CAkCrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAmC5D"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnosys Timeline — Temporal views and statistics for memory stores.
|
|
3
|
+
*
|
|
4
|
+
* Group memories by time period to see knowledge evolution.
|
|
5
|
+
* Compute summary statistics across the store.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Group memories by time period based on their created/modified dates.
|
|
9
|
+
*/
|
|
10
|
+
export function groupByPeriod(memories, period) {
|
|
11
|
+
const createdMap = new Map();
|
|
12
|
+
const modifiedMap = new Map();
|
|
13
|
+
for (const m of memories) {
|
|
14
|
+
const createdKey = toPeriodKey(m.frontmatter.created, period);
|
|
15
|
+
if (createdKey) {
|
|
16
|
+
const entry = createdMap.get(createdKey) || { count: 0, titles: [] };
|
|
17
|
+
entry.count++;
|
|
18
|
+
entry.titles.push(m.frontmatter.title);
|
|
19
|
+
createdMap.set(createdKey, entry);
|
|
20
|
+
}
|
|
21
|
+
const modifiedKey = toPeriodKey(m.frontmatter.modified, period);
|
|
22
|
+
if (modifiedKey && modifiedKey !== createdKey) {
|
|
23
|
+
modifiedMap.set(modifiedKey, (modifiedMap.get(modifiedKey) || 0) + 1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// Merge all period keys
|
|
27
|
+
const allKeys = new Set([...createdMap.keys(), ...modifiedMap.keys()]);
|
|
28
|
+
const entries = [];
|
|
29
|
+
for (const key of allKeys) {
|
|
30
|
+
const created = createdMap.get(key);
|
|
31
|
+
entries.push({
|
|
32
|
+
period: key,
|
|
33
|
+
created: created?.count || 0,
|
|
34
|
+
modified: modifiedMap.get(key) || 0,
|
|
35
|
+
titles: created?.titles || [],
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return entries.sort((a, b) => a.period.localeCompare(b.period));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Compute summary statistics across all memories.
|
|
42
|
+
*/
|
|
43
|
+
export function computeStats(memories) {
|
|
44
|
+
const byCategory = {};
|
|
45
|
+
const byStatus = {};
|
|
46
|
+
const byAuthor = {};
|
|
47
|
+
const byAuthority = {};
|
|
48
|
+
let totalConfidence = 0;
|
|
49
|
+
let oldest = null;
|
|
50
|
+
let newest = null;
|
|
51
|
+
let lastMod = null;
|
|
52
|
+
for (const m of memories) {
|
|
53
|
+
const fm = m.frontmatter;
|
|
54
|
+
byCategory[fm.category] = (byCategory[fm.category] || 0) + 1;
|
|
55
|
+
byStatus[fm.status] = (byStatus[fm.status] || 0) + 1;
|
|
56
|
+
byAuthor[fm.author] = (byAuthor[fm.author] || 0) + 1;
|
|
57
|
+
byAuthority[fm.authority] = (byAuthority[fm.authority] || 0) + 1;
|
|
58
|
+
totalConfidence += fm.confidence;
|
|
59
|
+
if (!oldest || fm.created < oldest)
|
|
60
|
+
oldest = fm.created;
|
|
61
|
+
if (!newest || fm.created > newest)
|
|
62
|
+
newest = fm.created;
|
|
63
|
+
if (!lastMod || fm.modified > lastMod)
|
|
64
|
+
lastMod = fm.modified;
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
totalCount: memories.length,
|
|
68
|
+
byCategory,
|
|
69
|
+
byStatus,
|
|
70
|
+
byAuthor,
|
|
71
|
+
byAuthority,
|
|
72
|
+
averageConfidence: memories.length > 0 ? Math.round((totalConfidence / memories.length) * 100) / 100 : 0,
|
|
73
|
+
oldestCreated: oldest,
|
|
74
|
+
newestCreated: newest,
|
|
75
|
+
lastModified: lastMod,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Convert an ISO date string to a period key.
|
|
80
|
+
*/
|
|
81
|
+
function toPeriodKey(dateStr, period) {
|
|
82
|
+
if (!dateStr)
|
|
83
|
+
return null;
|
|
84
|
+
// Parse the date string (YYYY-MM-DD format)
|
|
85
|
+
const parts = dateStr.split("-");
|
|
86
|
+
if (parts.length < 3)
|
|
87
|
+
return null;
|
|
88
|
+
const year = parseInt(parts[0]);
|
|
89
|
+
const month = parseInt(parts[1]);
|
|
90
|
+
const day = parseInt(parts[2]);
|
|
91
|
+
switch (period) {
|
|
92
|
+
case "day":
|
|
93
|
+
return dateStr; // Already YYYY-MM-DD
|
|
94
|
+
case "week": {
|
|
95
|
+
const d = new Date(year, month - 1, day);
|
|
96
|
+
const weekNum = getISOWeek(d);
|
|
97
|
+
return `${year}-W${String(weekNum).padStart(2, "0")}`;
|
|
98
|
+
}
|
|
99
|
+
case "month":
|
|
100
|
+
return `${year}-${String(month).padStart(2, "0")}`;
|
|
101
|
+
case "year":
|
|
102
|
+
return `${year}`;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Get ISO week number for a date.
|
|
107
|
+
*/
|
|
108
|
+
function getISOWeek(d) {
|
|
109
|
+
const date = new Date(d.getTime());
|
|
110
|
+
date.setHours(0, 0, 0, 0);
|
|
111
|
+
date.setDate(date.getDate() + 3 - ((date.getDay() + 6) % 7));
|
|
112
|
+
const week1 = new Date(date.getFullYear(), 0, 4);
|
|
113
|
+
return (1 +
|
|
114
|
+
Math.round(((date.getTime() - week1.getTime()) / 86400000 - 3 + ((week1.getDay() + 6) % 7)) / 7));
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=timeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/lib/timeline.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyBH;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,QAAkB,EAAE,MAAkB;IAClE,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+C,CAAC;IAC1E,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE9C,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,UAAU,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC9D,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;YACrE,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACvC,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAChE,IAAI,WAAW,IAAI,WAAW,KAAK,UAAU,EAAE,CAAC;YAC9C,WAAW,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,CAAC;IAED,wBAAwB;IACxB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,EAAE,GAAG,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IACvE,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,CAAC,IAAI,CAAC;YACX,MAAM,EAAE,GAAG;YACX,OAAO,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;YAC5B,QAAQ,EAAE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI,EAAE;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,QAAkB;IAC7C,MAAM,UAAU,GAA2B,EAAE,CAAC;IAC9C,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,OAAO,GAAkB,IAAI,CAAC;IAElC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,CAAC;QAEzB,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QAC7D,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACrD,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACrD,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACjE,eAAe,IAAI,EAAE,CAAC,UAAU,CAAC;QAEjC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,OAAO,GAAG,MAAM;YAAE,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC;QACxD,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,OAAO,GAAG,MAAM;YAAE,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC;QACxD,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,QAAQ,GAAG,OAAO;YAAE,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,UAAU,EAAE,QAAQ,CAAC,MAAM;QAC3B,UAAU;QACV,QAAQ;QACR,QAAQ;QACR,WAAW;QACX,iBAAiB,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QACxG,aAAa,EAAE,MAAM;QACrB,aAAa,EAAE,MAAM;QACrB,YAAY,EAAE,OAAO;KACtB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,OAAkC,EAAE,MAAkB;IACzE,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,4CAA4C;IAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/B,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,OAAO,OAAO,CAAC,CAAC,qBAAqB;QACvC,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;YACzC,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;YAC9B,OAAO,GAAG,IAAI,KAAK,MAAM,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACxD,CAAC;QACD,KAAK,OAAO;YACV,OAAO,GAAG,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;QACrD,KAAK,MAAM;YACT,OAAO,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,CAAO;IACzB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1B,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,CACL,CAAC;QACD,IAAI,CAAC,KAAK,CACR,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CACrF,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnosys Process Tracing — Phase 10
|
|
3
|
+
*
|
|
4
|
+
* Builds call chains from TypeScript/JavaScript source files and stores them
|
|
5
|
+
* as procedural "how" memories with relationship chaining:
|
|
6
|
+
* - follows_from: sequential call order
|
|
7
|
+
* - requires: dependency / import relationships
|
|
8
|
+
* - leads_to: what this function calls
|
|
9
|
+
*
|
|
10
|
+
* No external dependencies beyond Node built-ins and the Gnosys DB.
|
|
11
|
+
*/
|
|
12
|
+
import { GnosysDB } from "./db.js";
|
|
13
|
+
export interface TraceNode {
|
|
14
|
+
name: string;
|
|
15
|
+
file: string;
|
|
16
|
+
kind: "function" | "class" | "method" | "export";
|
|
17
|
+
line: number;
|
|
18
|
+
calls: string[];
|
|
19
|
+
calledBy: string[];
|
|
20
|
+
imports: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface TraceGraph {
|
|
23
|
+
nodes: Map<string, TraceNode>;
|
|
24
|
+
files: string[];
|
|
25
|
+
rootDir: string;
|
|
26
|
+
}
|
|
27
|
+
export interface TraceResult {
|
|
28
|
+
memoriesCreated: number;
|
|
29
|
+
relationshipsCreated: number;
|
|
30
|
+
functionsFound: number;
|
|
31
|
+
filesScanned: number;
|
|
32
|
+
memoryIds: string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Trace a codebase directory: discover source files, parse function declarations
|
|
36
|
+
* and call relationships, then store as procedural "how" memories in the DB.
|
|
37
|
+
*/
|
|
38
|
+
export declare function traceCodebase(db: GnosysDB, rootDir: string, opts?: {
|
|
39
|
+
projectId?: string;
|
|
40
|
+
maxFiles?: number;
|
|
41
|
+
}): TraceResult;
|
|
42
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../src/lib/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,EAAE,QAAQ,EAAY,MAAM,SAAS,CAAC;AAI7C,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAwLD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,QAAQ,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,GAAE;IACJ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACd,GACL,WAAW,CAkKb"}
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gnosys Process Tracing — Phase 10
|
|
3
|
+
*
|
|
4
|
+
* Builds call chains from TypeScript/JavaScript source files and stores them
|
|
5
|
+
* as procedural "how" memories with relationship chaining:
|
|
6
|
+
* - follows_from: sequential call order
|
|
7
|
+
* - requires: dependency / import relationships
|
|
8
|
+
* - leads_to: what this function calls
|
|
9
|
+
*
|
|
10
|
+
* No external dependencies beyond Node built-ins and the Gnosys DB.
|
|
11
|
+
*/
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
// ─── Source Parsing (Regex-based, no TS compiler dependency) ─────────
|
|
15
|
+
/**
|
|
16
|
+
* Extract function declarations, class methods, exports, and call sites
|
|
17
|
+
* from a TypeScript/JavaScript source file using regex patterns.
|
|
18
|
+
*
|
|
19
|
+
* This is intentionally lightweight — no AST parsing dependency needed.
|
|
20
|
+
*/
|
|
21
|
+
function parseSourceFile(filePath, rootDir) {
|
|
22
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
23
|
+
const lines = content.split("\n");
|
|
24
|
+
const relPath = path.relative(rootDir, filePath);
|
|
25
|
+
const nodes = [];
|
|
26
|
+
// Track imports for the file
|
|
27
|
+
const fileImports = [];
|
|
28
|
+
const importRegex = /import\s+(?:{[^}]*}|\*\s+as\s+\w+|\w+)\s+from\s+["']([^"']+)["']/g;
|
|
29
|
+
let importMatch;
|
|
30
|
+
while ((importMatch = importRegex.exec(content))) {
|
|
31
|
+
fileImports.push(importMatch[1]);
|
|
32
|
+
}
|
|
33
|
+
// Pattern: function declarations (named functions, arrow functions assigned to const/let/var)
|
|
34
|
+
const funcPatterns = [
|
|
35
|
+
// export function foo(...) or function foo(...)
|
|
36
|
+
/(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/g,
|
|
37
|
+
// const foo = (...) => or const foo = function(...)
|
|
38
|
+
/(?:export\s+)?(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)\s*=>|function\s*\()/g,
|
|
39
|
+
// class methods: foo(...) { or async foo(...) {
|
|
40
|
+
/^\s+(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*[^{]+)?\s*\{/gm,
|
|
41
|
+
];
|
|
42
|
+
// Pattern: class declarations
|
|
43
|
+
const classRegex = /(?:export\s+)?class\s+(\w+)(?:\s+(?:extends|implements)\s+\w+)?\s*\{/g;
|
|
44
|
+
// Extract function call sites: identifier followed by (
|
|
45
|
+
const callRegex = /\b(\w+)\s*\(/g;
|
|
46
|
+
// Common built-ins to exclude from call detection
|
|
47
|
+
const builtins = new Set([
|
|
48
|
+
"if", "for", "while", "switch", "catch", "return", "throw", "new", "typeof",
|
|
49
|
+
"instanceof", "delete", "void", "yield", "await", "import", "export",
|
|
50
|
+
"require", "console", "process", "JSON", "Object", "Array", "String",
|
|
51
|
+
"Number", "Boolean", "Map", "Set", "Promise", "Error", "Math", "Date",
|
|
52
|
+
"parseInt", "parseFloat", "setTimeout", "setInterval", "clearTimeout",
|
|
53
|
+
"clearInterval", "Buffer", "Symbol", "RegExp", "Proxy", "Reflect",
|
|
54
|
+
"describe", "it", "expect", "test", "beforeEach", "afterEach",
|
|
55
|
+
]);
|
|
56
|
+
// First pass: find all function/class/method declarations
|
|
57
|
+
const declaredNames = new Set();
|
|
58
|
+
for (const pattern of funcPatterns) {
|
|
59
|
+
pattern.lastIndex = 0;
|
|
60
|
+
let match;
|
|
61
|
+
while ((match = pattern.exec(content))) {
|
|
62
|
+
const name = match[1];
|
|
63
|
+
if (builtins.has(name) || declaredNames.has(name))
|
|
64
|
+
continue;
|
|
65
|
+
declaredNames.add(name);
|
|
66
|
+
// Find line number
|
|
67
|
+
const lineNum = content.slice(0, match.index).split("\n").length;
|
|
68
|
+
nodes.push({
|
|
69
|
+
name,
|
|
70
|
+
file: relPath,
|
|
71
|
+
kind: "function",
|
|
72
|
+
line: lineNum,
|
|
73
|
+
calls: [],
|
|
74
|
+
calledBy: [],
|
|
75
|
+
imports: fileImports,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Extract classes
|
|
80
|
+
{
|
|
81
|
+
classRegex.lastIndex = 0;
|
|
82
|
+
let match;
|
|
83
|
+
while ((match = classRegex.exec(content))) {
|
|
84
|
+
const name = match[1];
|
|
85
|
+
if (declaredNames.has(name))
|
|
86
|
+
continue;
|
|
87
|
+
declaredNames.add(name);
|
|
88
|
+
const lineNum = content.slice(0, match.index).split("\n").length;
|
|
89
|
+
nodes.push({
|
|
90
|
+
name,
|
|
91
|
+
file: relPath,
|
|
92
|
+
kind: "class",
|
|
93
|
+
line: lineNum,
|
|
94
|
+
calls: [],
|
|
95
|
+
calledBy: [],
|
|
96
|
+
imports: fileImports,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Second pass: for each declared function, find what it calls
|
|
101
|
+
// This is an approximation — we scan the function body for call sites
|
|
102
|
+
for (const node of nodes) {
|
|
103
|
+
// Find the function body (from declaration to next top-level declaration or EOF)
|
|
104
|
+
const startLine = node.line - 1;
|
|
105
|
+
let endLine = lines.length;
|
|
106
|
+
// Simple heuristic: scan forward until we find the closing brace at the same indent level
|
|
107
|
+
let braceDepth = 0;
|
|
108
|
+
let foundOpen = false;
|
|
109
|
+
for (let i = startLine; i < lines.length; i++) {
|
|
110
|
+
for (const ch of lines[i]) {
|
|
111
|
+
if (ch === "{") {
|
|
112
|
+
braceDepth++;
|
|
113
|
+
foundOpen = true;
|
|
114
|
+
}
|
|
115
|
+
if (ch === "}") {
|
|
116
|
+
braceDepth--;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (foundOpen && braceDepth <= 0) {
|
|
120
|
+
endLine = i + 1;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const body = lines.slice(startLine, endLine).join("\n");
|
|
125
|
+
callRegex.lastIndex = 0;
|
|
126
|
+
let callMatch;
|
|
127
|
+
const callSet = new Set();
|
|
128
|
+
while ((callMatch = callRegex.exec(body))) {
|
|
129
|
+
const callee = callMatch[1];
|
|
130
|
+
if (callee !== node.name && !builtins.has(callee) && declaredNames.has(callee)) {
|
|
131
|
+
callSet.add(callee);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
node.calls = [...callSet];
|
|
135
|
+
}
|
|
136
|
+
// Back-fill calledBy
|
|
137
|
+
const nodeMap = new Map(nodes.map((n) => [n.name, n]));
|
|
138
|
+
for (const node of nodes) {
|
|
139
|
+
for (const callee of node.calls) {
|
|
140
|
+
const target = nodeMap.get(callee);
|
|
141
|
+
if (target) {
|
|
142
|
+
target.calledBy.push(node.name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return nodes;
|
|
147
|
+
}
|
|
148
|
+
// ─── File Discovery ─────────────────────────────────────────────────────
|
|
149
|
+
function discoverSourceFiles(rootDir) {
|
|
150
|
+
const files = [];
|
|
151
|
+
const extensions = new Set([".ts", ".js", ".tsx", ".jsx"]);
|
|
152
|
+
const ignoreDirs = new Set(["node_modules", "dist", "build", ".git", "coverage", ".gnosys"]);
|
|
153
|
+
function walk(dir) {
|
|
154
|
+
let entries;
|
|
155
|
+
try {
|
|
156
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return; // Permission denied or other error
|
|
160
|
+
}
|
|
161
|
+
for (const entry of entries) {
|
|
162
|
+
if (entry.name.startsWith(".") && entry.isDirectory())
|
|
163
|
+
continue;
|
|
164
|
+
if (ignoreDirs.has(entry.name) && entry.isDirectory())
|
|
165
|
+
continue;
|
|
166
|
+
const fullPath = path.join(dir, entry.name);
|
|
167
|
+
if (entry.isDirectory()) {
|
|
168
|
+
walk(fullPath);
|
|
169
|
+
}
|
|
170
|
+
else if (entry.isFile() && extensions.has(path.extname(entry.name))) {
|
|
171
|
+
// Skip test files and declaration files
|
|
172
|
+
if (entry.name.endsWith(".test.ts") || entry.name.endsWith(".test.js"))
|
|
173
|
+
continue;
|
|
174
|
+
if (entry.name.endsWith(".d.ts"))
|
|
175
|
+
continue;
|
|
176
|
+
files.push(fullPath);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
walk(rootDir);
|
|
181
|
+
return files;
|
|
182
|
+
}
|
|
183
|
+
// ─── Trace Codebase ─────────────────────────────────────────────────────
|
|
184
|
+
/**
|
|
185
|
+
* Trace a codebase directory: discover source files, parse function declarations
|
|
186
|
+
* and call relationships, then store as procedural "how" memories in the DB.
|
|
187
|
+
*/
|
|
188
|
+
export function traceCodebase(db, rootDir, opts = {}) {
|
|
189
|
+
const absRoot = path.resolve(rootDir);
|
|
190
|
+
const sourceFiles = discoverSourceFiles(absRoot);
|
|
191
|
+
const filesToScan = opts.maxFiles
|
|
192
|
+
? sourceFiles.slice(0, opts.maxFiles)
|
|
193
|
+
: sourceFiles;
|
|
194
|
+
// Parse all files
|
|
195
|
+
const allNodes = [];
|
|
196
|
+
for (const file of filesToScan) {
|
|
197
|
+
try {
|
|
198
|
+
const nodes = parseSourceFile(file, absRoot);
|
|
199
|
+
allNodes.push(...nodes);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// Skip unparseable files
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (allNodes.length === 0) {
|
|
206
|
+
return {
|
|
207
|
+
memoriesCreated: 0,
|
|
208
|
+
relationshipsCreated: 0,
|
|
209
|
+
functionsFound: 0,
|
|
210
|
+
filesScanned: filesToScan.length,
|
|
211
|
+
memoryIds: [],
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// Build a global name→node map (deduplicate by file:name)
|
|
215
|
+
const globalMap = new Map();
|
|
216
|
+
for (const node of allNodes) {
|
|
217
|
+
const key = `${node.file}:${node.name}`;
|
|
218
|
+
globalMap.set(key, node);
|
|
219
|
+
}
|
|
220
|
+
// Cross-file: resolve calls to any declared function across files
|
|
221
|
+
const nameToKeys = new Map();
|
|
222
|
+
for (const [key, node] of globalMap) {
|
|
223
|
+
if (!nameToKeys.has(node.name))
|
|
224
|
+
nameToKeys.set(node.name, []);
|
|
225
|
+
nameToKeys.get(node.name).push(key);
|
|
226
|
+
}
|
|
227
|
+
const now = new Date().toISOString();
|
|
228
|
+
const memoryIds = [];
|
|
229
|
+
let relationshipsCreated = 0;
|
|
230
|
+
// Create a procedural memory for each function/class
|
|
231
|
+
const keyToMemId = new Map();
|
|
232
|
+
for (const [key, node] of globalMap) {
|
|
233
|
+
const memId = `mem-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
234
|
+
keyToMemId.set(key, memId);
|
|
235
|
+
const content = [
|
|
236
|
+
`## ${node.kind}: ${node.name}`,
|
|
237
|
+
"",
|
|
238
|
+
`**File:** \`${node.file}\` (line ${node.line})`,
|
|
239
|
+
"",
|
|
240
|
+
node.calls.length > 0
|
|
241
|
+
? `**Calls:** ${node.calls.map((c) => `\`${c}\``).join(", ")}`
|
|
242
|
+
: "**Calls:** (none)",
|
|
243
|
+
node.calledBy.length > 0
|
|
244
|
+
? `**Called by:** ${node.calledBy.map((c) => `\`${c}\``).join(", ")}`
|
|
245
|
+
: "**Called by:** (none)",
|
|
246
|
+
node.imports.length > 0
|
|
247
|
+
? `\n**Imports:** ${node.imports.map((i) => `\`${i}\``).join(", ")}`
|
|
248
|
+
: "",
|
|
249
|
+
].filter(Boolean).join("\n");
|
|
250
|
+
db.insertMemory({
|
|
251
|
+
id: memId,
|
|
252
|
+
title: `How: ${node.name} (${node.file})`,
|
|
253
|
+
category: "how",
|
|
254
|
+
content,
|
|
255
|
+
summary: null,
|
|
256
|
+
tags: JSON.stringify(["procedural", node.kind, path.basename(node.file, path.extname(node.file))]),
|
|
257
|
+
relevance: `how procedural ${node.name} ${node.file} ${node.kind}`,
|
|
258
|
+
author: "ai",
|
|
259
|
+
authority: "observed",
|
|
260
|
+
confidence: 0.85,
|
|
261
|
+
reinforcement_count: 0,
|
|
262
|
+
content_hash: "",
|
|
263
|
+
status: "active",
|
|
264
|
+
tier: "active",
|
|
265
|
+
supersedes: null,
|
|
266
|
+
superseded_by: null,
|
|
267
|
+
last_reinforced: null,
|
|
268
|
+
created: now,
|
|
269
|
+
modified: now,
|
|
270
|
+
embedding: null,
|
|
271
|
+
source_path: node.file,
|
|
272
|
+
project_id: opts.projectId || null,
|
|
273
|
+
scope: "project",
|
|
274
|
+
});
|
|
275
|
+
memoryIds.push(memId);
|
|
276
|
+
}
|
|
277
|
+
// Create relationships: leads_to, follows_from, requires
|
|
278
|
+
for (const [key, node] of globalMap) {
|
|
279
|
+
const sourceMemId = keyToMemId.get(key);
|
|
280
|
+
for (const callee of node.calls) {
|
|
281
|
+
// Find target memory IDs for this callee name
|
|
282
|
+
const targetKeys = nameToKeys.get(callee) || [];
|
|
283
|
+
for (const targetKey of targetKeys) {
|
|
284
|
+
const targetMemId = keyToMemId.get(targetKey);
|
|
285
|
+
if (!targetMemId || targetMemId === sourceMemId)
|
|
286
|
+
continue;
|
|
287
|
+
// leads_to: this function leads to the callee
|
|
288
|
+
db.insertRelationship({
|
|
289
|
+
source_id: sourceMemId,
|
|
290
|
+
target_id: targetMemId,
|
|
291
|
+
rel_type: "leads_to",
|
|
292
|
+
label: `${node.name} calls ${callee}`,
|
|
293
|
+
confidence: 0.9,
|
|
294
|
+
created: now,
|
|
295
|
+
});
|
|
296
|
+
relationshipsCreated++;
|
|
297
|
+
// follows_from: the callee follows from this function
|
|
298
|
+
db.insertRelationship({
|
|
299
|
+
source_id: targetMemId,
|
|
300
|
+
target_id: sourceMemId,
|
|
301
|
+
rel_type: "follows_from",
|
|
302
|
+
label: `${callee} is called by ${node.name}`,
|
|
303
|
+
confidence: 0.9,
|
|
304
|
+
created: now,
|
|
305
|
+
});
|
|
306
|
+
relationshipsCreated++;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
// requires: import relationships (module-level)
|
|
310
|
+
for (const imp of node.imports) {
|
|
311
|
+
// Find any nodes from the imported module
|
|
312
|
+
for (const [targetKey, targetNode] of globalMap) {
|
|
313
|
+
if (targetNode.file.includes(imp.replace(/^\.\//, "").replace(/\.\w+$/, ""))) {
|
|
314
|
+
const targetMemId = keyToMemId.get(targetKey);
|
|
315
|
+
if (!targetMemId || targetMemId === sourceMemId)
|
|
316
|
+
continue;
|
|
317
|
+
db.insertRelationship({
|
|
318
|
+
source_id: sourceMemId,
|
|
319
|
+
target_id: targetMemId,
|
|
320
|
+
rel_type: "requires",
|
|
321
|
+
label: `${node.file} imports from ${targetNode.file}`,
|
|
322
|
+
confidence: 0.7,
|
|
323
|
+
created: now,
|
|
324
|
+
});
|
|
325
|
+
relationshipsCreated++;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return {
|
|
331
|
+
memoriesCreated: memoryIds.length,
|
|
332
|
+
relationshipsCreated,
|
|
333
|
+
functionsFound: allNodes.length,
|
|
334
|
+
filesScanned: filesToScan.length,
|
|
335
|
+
memoryIds,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
//# sourceMappingURL=trace.js.map
|