Skip to content

Commit 13c62ac

Browse files
committed
Fix index command saving empty knowledge/task graphs for workspace projects
Rewrote `index` CLI command to use ProjectManager (like `serve`), so workspace-aware save logic is centralized — shared graphs are only persisted at the workspace level, not duplicated into per-project .graph-memory directories.
1 parent ab9bce6 commit 13c62ac

2 files changed

Lines changed: 46 additions & 42 deletions

File tree

demo-projects/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Workspace shared graphs + mirror files
2-
.workspace-*/
2+
.workspace-*
33

44
# Per-project persisted graphs
55
*/.graph-memory/

src/cli/index.ts

Lines changed: 45 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,26 @@ program
9090
.action((opts: { config: string; project?: string; reindex?: boolean }) => {
9191
(async () => {
9292
const mc = loadMultiConfig(opts.config);
93-
const ids = opts.project ? [opts.project] : Array.from(mc.projects.keys());
93+
const reindex = !!opts.reindex;
94+
if (reindex) process.stderr.write('[index] Re-indexing from scratch\n');
95+
96+
const manager = new ProjectManager(mc.server);
97+
98+
// Build workspace membership lookup
99+
const projectWorkspace = new Map<string, string>();
100+
for (const [wsId, wsConfig] of mc.workspaces) {
101+
for (const projId of wsConfig.projects) {
102+
projectWorkspace.set(projId, wsId);
103+
}
104+
}
105+
106+
// Add workspaces first
107+
for (const [wsId, wsConfig] of mc.workspaces) {
108+
await manager.addWorkspace(wsId, wsConfig, reindex);
109+
}
94110

111+
// Add projects (workspace projects share knowledge/task/skill graphs)
112+
const ids = opts.project ? [opts.project] : Array.from(mc.projects.keys());
95113
if (ids.length === 0) {
96114
process.stderr.write('[index] No projects defined in config\n');
97115
process.exit(1);
@@ -103,52 +121,38 @@ program
103121
process.stderr.write(`[index] Project "${id}" not found in config. Available: ${Array.from(mc.projects.keys()).join(', ')}\n`);
104122
process.exit(1);
105123
}
124+
await manager.addProject(id, project, reindex, projectWorkspace.get(id));
125+
}
106126

107-
const fresh = !!opts.reindex;
108-
if (fresh) process.stderr.write(`[index] Re-indexing project "${id}" from scratch...\n`);
109-
else process.stderr.write(`[index] Indexing project "${id}"...\n`);
110-
const projectDir = path.resolve(project.projectDir);
111-
await loadAllModels(id, project, mc.server.modelsDir);
112-
113-
const models = resolveModels(id, project);
114-
const docGraph = project.docsPattern ? loadGraph(project.graphMemory, fresh, models[`${id}:docs`]) : undefined;
115-
const codeGraph = project.codePattern ? loadCodeGraph(project.graphMemory, fresh, models[`${id}:code`]) : undefined;
116-
const knowledgeGraph = loadKnowledgeGraph(project.graphMemory, fresh, models[`${id}:knowledge`]);
117-
const fileIndexGraph = loadFileIndexGraph(project.graphMemory, fresh, models[`${id}:files`]);
118-
const taskGraph = loadTaskGraph(project.graphMemory, fresh, models[`${id}:tasks`]);
119-
const skillGraph = loadSkillGraph(project.graphMemory, fresh, models[`${id}:skills`]);
120-
121-
const indexer = createProjectIndexer(docGraph, codeGraph, {
122-
projectDir,
123-
docsPattern: project.docsPattern || undefined,
124-
codePattern: project.codePattern || undefined,
125-
excludePattern: project.excludePattern || undefined,
126-
chunkDepth: project.chunkDepth,
127-
tsconfig: project.tsconfig,
128-
docsModelName: `${id}:docs`,
129-
codeModelName: `${id}:code`,
130-
filesModelName: `${id}:files`,
131-
}, knowledgeGraph, fileIndexGraph, taskGraph, skillGraph);
132-
133-
indexer.scan();
134-
await indexer.drain();
135-
136-
if (docGraph) {
137-
saveGraph(docGraph, project.graphMemory, models[`${id}:docs`]);
138-
process.stderr.write(`[index] "${id}" docs: ${docGraph.order} nodes, ${docGraph.size} edges\n`);
139-
}
127+
// Load models (workspaces first, then projects)
128+
for (const wsId of manager.listWorkspaces()) {
129+
await manager.loadWorkspaceModels(wsId);
130+
}
131+
for (const id of ids) {
132+
await manager.loadModels(id);
133+
}
140134

141-
if (codeGraph) {
142-
saveCodeGraph(codeGraph, project.graphMemory, models[`${id}:code`]);
143-
process.stderr.write(`[index] "${id}" code: ${codeGraph.order} nodes, ${codeGraph.size} edges\n`);
135+
// Index all projects
136+
for (const id of ids) {
137+
process.stderr.write(`[index] Indexing project "${id}"...\n`);
138+
await manager.startIndexing(id);
139+
const instance = manager.getProject(id)!;
140+
if (instance.docGraph) {
141+
process.stderr.write(`[index] "${id}" docs: ${instance.docGraph.order} nodes, ${instance.docGraph.size} edges\n`);
142+
}
143+
if (instance.codeGraph) {
144+
process.stderr.write(`[index] "${id}" code: ${instance.codeGraph.order} nodes, ${instance.codeGraph.size} edges\n`);
144145
}
146+
process.stderr.write(`[index] "${id}" files: ${instance.fileIndexGraph.order} nodes, ${instance.fileIndexGraph.size} edges\n`);
147+
}
145148

146-
saveKnowledgeGraph(knowledgeGraph, project.graphMemory, models[`${id}:knowledge`]);
147-
saveFileIndexGraph(fileIndexGraph, project.graphMemory, models[`${id}:files`]);
148-
saveTaskGraph(taskGraph, project.graphMemory, models[`${id}:tasks`]);
149-
process.stderr.write(`[index] "${id}" files: ${fileIndexGraph.order} nodes, ${fileIndexGraph.size} edges\n`);
149+
// Save workspaces
150+
for (const wsId of manager.listWorkspaces()) {
151+
const ws = manager.getWorkspace(wsId)!;
152+
process.stderr.write(`[index] Workspace "${wsId}" knowledge: ${ws.knowledgeGraph.order} nodes, tasks: ${ws.taskGraph.order} nodes, skills: ${ws.skillGraph.order} nodes\n`);
150153
}
151154

155+
await manager.shutdown();
152156
process.stderr.write(`[index] Done. Indexed ${ids.length} project${ids.length > 1 ? 's' : ''}.\n`);
153157
})().catch((err: unknown) => {
154158
process.stderr.write(`[index] Fatal: ${err}\n`);

0 commit comments

Comments
 (0)