studiograph 1.1.2 → 1.2.0-beta.1
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 +191 -0
- package/README.md +301 -10
- package/dist/agent/orchestrator.d.ts +17 -9
- package/dist/agent/orchestrator.js +142 -97
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/prompts/system.md +186 -0
- package/dist/agent/skill-loader.d.ts +48 -0
- package/dist/agent/skill-loader.js +166 -0
- package/dist/agent/skill-loader.js.map +1 -0
- package/dist/agent/skills/enrich-entities.md +136 -0
- package/dist/agent/skills/entity-schema.md +502 -0
- package/dist/agent/skills/gather-context.md +46 -0
- package/dist/agent/skills/obsidian-source-setup.md +246 -0
- package/dist/agent/skills/skill-loader.d.ts +48 -0
- package/dist/agent/skills/skill-loader.js +166 -0
- package/dist/agent/skills/skill-loader.js.map +1 -0
- package/dist/agent/skills/sync-configuration.md +144 -0
- package/dist/agent/skills/sync-setup.md +68 -0
- package/dist/agent/tools/connector-tools.d.ts +37 -0
- package/dist/agent/tools/connector-tools.js +132 -0
- package/dist/agent/tools/connector-tools.js.map +1 -0
- package/dist/agent/tools/fs-tools.d.ts +39 -0
- package/dist/agent/tools/fs-tools.js +106 -0
- package/dist/agent/tools/fs-tools.js.map +1 -0
- package/dist/agent/tools/graph-tools.d.ts +30 -2
- package/dist/agent/tools/graph-tools.js +154 -37
- package/dist/agent/tools/graph-tools.js.map +1 -1
- package/dist/agent/tools/load-skill.d.ts +42 -0
- package/dist/agent/tools/load-skill.js +45 -0
- package/dist/agent/tools/load-skill.js.map +1 -0
- package/dist/agent/tools/sync-tools.d.ts +25 -0
- package/dist/agent/tools/sync-tools.js +691 -0
- package/dist/agent/tools/sync-tools.js.map +1 -0
- package/dist/agent/tools/tool-loader.d.ts +25 -0
- package/dist/agent/tools/tool-loader.js +73 -0
- package/dist/agent/tools/tool-loader.js.map +1 -0
- package/dist/auth/github.d.ts +11 -8
- package/dist/auth/github.js +56 -75
- package/dist/auth/github.js.map +1 -1
- package/dist/cli/colors.d.ts +54 -0
- package/dist/cli/colors.js +133 -0
- package/dist/cli/colors.js.map +1 -0
- package/dist/cli/commands/app.d.ts +7 -0
- package/dist/cli/commands/app.js +167 -0
- package/dist/cli/commands/app.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +1 -1
- package/dist/cli/commands/auth.js +26 -10
- package/dist/cli/commands/auth.js.map +1 -1
- package/dist/cli/commands/clone.d.ts +9 -0
- package/dist/cli/commands/clone.js +167 -0
- package/dist/cli/commands/clone.js.map +1 -0
- package/dist/cli/commands/commit.d.ts +8 -0
- package/dist/cli/commands/commit.js +43 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/config.d.ts +13 -0
- package/dist/cli/commands/config.js +276 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/connector.d.ts +33 -0
- package/dist/cli/commands/connector.js +178 -0
- package/dist/cli/commands/connector.js.map +1 -0
- package/dist/cli/commands/deploy.d.ts +11 -0
- package/dist/cli/commands/deploy.js +153 -0
- package/dist/cli/commands/deploy.js.map +1 -0
- package/dist/cli/commands/enrich.d.ts +11 -0
- package/dist/cli/commands/enrich.js +135 -0
- package/dist/cli/commands/enrich.js.map +1 -0
- package/dist/cli/commands/graphrag.d.ts +12 -0
- package/dist/cli/commands/graphrag.js +122 -0
- package/dist/cli/commands/graphrag.js.map +1 -0
- package/dist/cli/commands/index.d.ts +15 -0
- package/dist/cli/commands/index.js +117 -0
- package/dist/cli/commands/index.js.map +1 -0
- package/dist/cli/commands/init.js +110 -210
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/join.js +89 -24
- package/dist/cli/commands/join.js.map +1 -1
- package/dist/cli/commands/lint.d.ts +8 -0
- package/dist/cli/commands/lint.js +70 -0
- package/dist/cli/commands/lint.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +27 -0
- package/dist/cli/commands/mcp.js +56 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/orphans.d.ts +8 -0
- package/dist/cli/commands/orphans.js +125 -0
- package/dist/cli/commands/orphans.js.map +1 -0
- package/dist/cli/commands/provision.d.ts +8 -0
- package/dist/cli/commands/provision.js +116 -0
- package/dist/cli/commands/provision.js.map +1 -0
- package/dist/cli/commands/r2.d.ts +2 -0
- package/dist/cli/commands/r2.js +87 -6
- package/dist/cli/commands/r2.js.map +1 -1
- package/dist/cli/commands/reset.d.ts +12 -0
- package/dist/cli/commands/reset.js +137 -0
- package/dist/cli/commands/reset.js.map +1 -0
- package/dist/cli/commands/review.d.ts +19 -0
- package/dist/cli/commands/review.js +128 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/commands/serve.js +47 -2
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/source.d.ts +16 -0
- package/dist/cli/commands/source.js +159 -0
- package/dist/cli/commands/source.js.map +1 -0
- package/dist/cli/commands/start.js +472 -103
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/sync-entities.d.ts +13 -0
- package/dist/cli/commands/sync-entities.js +242 -0
- package/dist/cli/commands/sync-entities.js.map +1 -0
- package/dist/cli/commands/sync.js +40 -9
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/commands/update.d.ts +8 -0
- package/dist/cli/commands/update.js +155 -0
- package/dist/cli/commands/update.js.map +1 -0
- package/dist/cli/index.js +114 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/scaffolding.d.ts +10 -0
- package/dist/cli/scaffolding.js +302 -0
- package/dist/cli/scaffolding.js.map +1 -0
- package/dist/cli/setup-wizard.d.ts +30 -0
- package/dist/cli/setup-wizard.js +244 -0
- package/dist/cli/setup-wizard.js.map +1 -0
- package/dist/cli/sync-review-interactive.d.ts +31 -0
- package/dist/cli/sync-review-interactive.js +393 -0
- package/dist/cli/sync-review-interactive.js.map +1 -0
- package/dist/cli/theme.d.ts +31 -0
- package/dist/cli/theme.js +116 -0
- package/dist/cli/theme.js.map +1 -0
- package/dist/core/graph.d.ts +16 -9
- package/dist/core/graph.js +263 -145
- package/dist/core/graph.js.map +1 -1
- package/dist/core/migration-runner.d.ts +42 -0
- package/dist/core/migration-runner.js +232 -0
- package/dist/core/migration-runner.js.map +1 -0
- package/dist/core/migration-types.d.ts +101 -0
- package/dist/core/migration-types.js +21 -0
- package/dist/core/migration-types.js.map +1 -0
- package/dist/core/migrations/20260219-formalize-memory-location.d.ts +2 -0
- package/dist/core/migrations/20260219-formalize-memory-location.js +35 -0
- package/dist/core/migrations/20260219-formalize-memory-location.js.map +1 -0
- package/dist/core/migrations/20260220-add-workspace-metadata.d.ts +12 -0
- package/dist/core/migrations/20260220-add-workspace-metadata.js +65 -0
- package/dist/core/migrations/20260220-add-workspace-metadata.js.map +1 -0
- package/dist/core/migrations/20260220-add-workspace-readme.d.ts +11 -0
- package/dist/core/migrations/20260220-add-workspace-readme.js +82 -0
- package/dist/core/migrations/20260220-add-workspace-readme.js.map +1 -0
- package/dist/core/migrations/20260220-migrate-yaml-to-json.d.ts +9 -0
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js +64 -0
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js.map +1 -0
- package/dist/core/migrations/index.d.ts +11 -0
- package/dist/core/migrations/index.js +23 -0
- package/dist/core/migrations/index.js.map +1 -0
- package/dist/core/schema-registry.d.ts +36 -0
- package/dist/core/schema-registry.js +161 -0
- package/dist/core/schema-registry.js.map +1 -0
- package/dist/core/types.d.ts +242 -3
- package/dist/core/types.js +21 -2
- package/dist/core/types.js.map +1 -1
- package/dist/core/user-config.d.ts +16 -0
- package/dist/core/user-config.js +8 -0
- package/dist/core/user-config.js.map +1 -1
- package/dist/core/validation.d.ts +973 -32
- package/dist/core/validation.js +163 -4
- package/dist/core/validation.js.map +1 -1
- package/dist/core/workspace-manager.d.ts +26 -2
- package/dist/core/workspace-manager.js +113 -15
- package/dist/core/workspace-manager.js.map +1 -1
- package/dist/core/workspace.d.ts +20 -11
- package/dist/core/workspace.js +123 -34
- package/dist/core/workspace.js.map +1 -1
- package/dist/mcp/connector-manager.d.ts +65 -0
- package/dist/mcp/connector-manager.js +223 -0
- package/dist/mcp/connector-manager.js.map +1 -0
- package/dist/mcp/connectors/asana.d.ts +2 -0
- package/dist/mcp/connectors/asana.js +20 -0
- package/dist/mcp/connectors/asana.js.map +1 -0
- package/dist/mcp/connectors/definitions.d.ts +45 -0
- package/dist/mcp/connectors/definitions.js +32 -0
- package/dist/mcp/connectors/definitions.js.map +1 -0
- package/dist/mcp/connectors/figma.d.ts +5 -0
- package/dist/mcp/connectors/figma.js +21 -0
- package/dist/mcp/connectors/figma.js.map +1 -0
- package/dist/mcp/connectors/gdrive.d.ts +2 -0
- package/dist/mcp/connectors/gdrive.js +20 -0
- package/dist/mcp/connectors/gdrive.js.map +1 -0
- package/dist/mcp/connectors/granola.d.ts +2 -0
- package/dist/mcp/connectors/granola.js +12 -0
- package/dist/mcp/connectors/granola.js.map +1 -0
- package/dist/mcp/connectors/linear.d.ts +2 -0
- package/dist/mcp/connectors/linear.js +19 -0
- package/dist/mcp/connectors/linear.js.map +1 -0
- package/dist/mcp/connectors/obsidian.d.ts +2 -0
- package/dist/mcp/connectors/obsidian.js +19 -0
- package/dist/mcp/connectors/obsidian.js.map +1 -0
- package/dist/mcp/connectors/pipedrive.d.ts +2 -0
- package/dist/mcp/connectors/pipedrive.js +20 -0
- package/dist/mcp/connectors/pipedrive.js.map +1 -0
- package/dist/mcp/connectors/slack.d.ts +2 -0
- package/dist/mcp/connectors/slack.js +21 -0
- package/dist/mcp/connectors/slack.js.map +1 -0
- package/dist/mcp/oauth-provider.d.ts +41 -0
- package/dist/mcp/oauth-provider.js +160 -0
- package/dist/mcp/oauth-provider.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -0
- package/dist/mcp/server.js +28 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +14 -0
- package/dist/mcp/tools.js +172 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/server/index.js +17 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/plugin-loader.d.ts +15 -0
- package/dist/server/plugin-loader.js +68 -2
- package/dist/server/plugin-loader.js.map +1 -1
- package/dist/server/routes/graph-api.js +1 -1
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/webhook.js +33 -0
- package/dist/server/routes/webhook.js.map +1 -1
- package/dist/services/github-provisioner.d.ts +9 -3
- package/dist/services/github-provisioner.js +46 -8
- package/dist/services/github-provisioner.js.map +1 -1
- package/dist/services/lint-service.d.ts +27 -0
- package/dist/services/lint-service.js +83 -0
- package/dist/services/lint-service.js.map +1 -0
- package/dist/services/markdown.d.ts +9 -0
- package/dist/services/markdown.js +26 -5
- package/dist/services/markdown.js.map +1 -1
- package/dist/services/memory-service.d.ts +1 -2
- package/dist/services/memory-service.js +5 -4
- package/dist/services/memory-service.js.map +1 -1
- package/dist/services/orphan-service.d.ts +31 -0
- package/dist/services/orphan-service.js +100 -0
- package/dist/services/orphan-service.js.map +1 -0
- package/dist/services/sync/commit.d.ts +58 -0
- package/dist/services/sync/commit.js +350 -0
- package/dist/services/sync/commit.js.map +1 -0
- package/dist/services/sync/context-index.d.ts +69 -0
- package/dist/services/sync/context-index.js +280 -0
- package/dist/services/sync/context-index.js.map +1 -0
- package/dist/services/sync/derive.d.ts +34 -0
- package/dist/services/sync/derive.js +164 -0
- package/dist/services/sync/derive.js.map +1 -0
- package/dist/services/sync/enrichment-state.d.ts +31 -0
- package/dist/services/sync/enrichment-state.js +63 -0
- package/dist/services/sync/enrichment-state.js.map +1 -0
- package/dist/services/sync/enrichment.d.ts +25 -0
- package/dist/services/sync/enrichment.js +121 -0
- package/dist/services/sync/enrichment.js.map +1 -0
- package/dist/services/sync/frontmatter-extractor.d.ts +40 -0
- package/dist/services/sync/frontmatter-extractor.js +273 -0
- package/dist/services/sync/frontmatter-extractor.js.map +1 -0
- package/dist/services/sync/graph-match-state.d.ts +33 -0
- package/dist/services/sync/graph-match-state.js +61 -0
- package/dist/services/sync/graph-match-state.js.map +1 -0
- package/dist/services/sync/graph-match.d.ts +53 -0
- package/dist/services/sync/graph-match.js +316 -0
- package/dist/services/sync/graph-match.js.map +1 -0
- package/dist/services/sync/graphrag-client.d.ts +43 -0
- package/dist/services/sync/graphrag-client.js +94 -0
- package/dist/services/sync/graphrag-client.js.map +1 -0
- package/dist/services/sync/graphrag-config.d.ts +16 -0
- package/dist/services/sync/graphrag-config.js +39 -0
- package/dist/services/sync/graphrag-config.js.map +1 -0
- package/dist/services/sync/graphrag-context.d.ts +14 -0
- package/dist/services/sync/graphrag-context.js +109 -0
- package/dist/services/sync/graphrag-context.js.map +1 -0
- package/dist/services/sync/graphrag-indexer.d.ts +30 -0
- package/dist/services/sync/graphrag-indexer.js +358 -0
- package/dist/services/sync/graphrag-indexer.js.map +1 -0
- package/dist/services/sync/llm.d.ts +32 -0
- package/dist/services/sync/llm.js +115 -0
- package/dist/services/sync/llm.js.map +1 -0
- package/dist/services/sync/mcp-client.d.ts +59 -0
- package/dist/services/sync/mcp-client.js +285 -0
- package/dist/services/sync/mcp-client.js.map +1 -0
- package/dist/services/sync/model-factory.d.ts +10 -0
- package/dist/services/sync/model-factory.js +24 -0
- package/dist/services/sync/model-factory.js.map +1 -0
- package/dist/services/sync/name-quality.d.ts +31 -0
- package/dist/services/sync/name-quality.js +60 -0
- package/dist/services/sync/name-quality.js.map +1 -0
- package/dist/services/sync/output-schemas.d.ts +92 -0
- package/dist/services/sync/output-schemas.js +43 -0
- package/dist/services/sync/output-schemas.js.map +1 -0
- package/dist/services/sync/prompts.d.ts +19 -0
- package/dist/services/sync/prompts.js +128 -0
- package/dist/services/sync/prompts.js.map +1 -0
- package/dist/services/sync/reconciler.d.ts +48 -0
- package/dist/services/sync/reconciler.js +295 -0
- package/dist/services/sync/reconciler.js.map +1 -0
- package/dist/services/sync/source-config.d.ts +45 -0
- package/dist/services/sync/source-config.js +208 -0
- package/dist/services/sync/source-config.js.map +1 -0
- package/dist/services/sync/source-definitions/asana.d.ts +15 -0
- package/dist/services/sync/source-definitions/asana.js +48 -0
- package/dist/services/sync/source-definitions/asana.js.map +1 -0
- package/dist/services/sync/source-definitions/definitions.d.ts +21 -0
- package/dist/services/sync/source-definitions/definitions.js +26 -0
- package/dist/services/sync/source-definitions/definitions.js.map +1 -0
- package/dist/services/sync/source-definitions/gdrive.d.ts +16 -0
- package/dist/services/sync/source-definitions/gdrive.js +68 -0
- package/dist/services/sync/source-definitions/gdrive.js.map +1 -0
- package/dist/services/sync/source-definitions/granola.d.ts +2 -0
- package/dist/services/sync/source-definitions/granola.js +28 -0
- package/dist/services/sync/source-definitions/granola.js.map +1 -0
- package/dist/services/sync/source-definitions/linear.d.ts +2 -0
- package/dist/services/sync/source-definitions/linear.js +60 -0
- package/dist/services/sync/source-definitions/linear.js.map +1 -0
- package/dist/services/sync/source-definitions/obsidian.d.ts +2 -0
- package/dist/services/sync/source-definitions/obsidian.js +55 -0
- package/dist/services/sync/source-definitions/obsidian.js.map +1 -0
- package/dist/services/sync/source-definitions/pipedrive.d.ts +2 -0
- package/dist/services/sync/source-definitions/pipedrive.js +52 -0
- package/dist/services/sync/source-definitions/pipedrive.js.map +1 -0
- package/dist/services/sync/staging.d.ts +53 -0
- package/dist/services/sync/staging.js +131 -0
- package/dist/services/sync/staging.js.map +1 -0
- package/dist/services/sync/structured-extractor.d.ts +49 -0
- package/dist/services/sync/structured-extractor.js +344 -0
- package/dist/services/sync/structured-extractor.js.map +1 -0
- package/dist/services/sync/sync-runner.d.ts +32 -0
- package/dist/services/sync/sync-runner.js +195 -0
- package/dist/services/sync/sync-runner.js.map +1 -0
- package/dist/services/sync/sync-state.d.ts +43 -0
- package/dist/services/sync/sync-state.js +154 -0
- package/dist/services/sync/sync-state.js.map +1 -0
- package/dist/services/sync/types.d.ts +203 -0
- package/dist/services/sync/types.js +8 -0
- package/dist/services/sync/types.js.map +1 -0
- package/dist/services/sync/unstructured-extractor.d.ts +29 -0
- package/dist/services/sync/unstructured-extractor.js +197 -0
- package/dist/services/sync/unstructured-extractor.js.map +1 -0
- package/dist/services/vector-service.d.ts +88 -0
- package/dist/services/vector-service.js +322 -0
- package/dist/services/vector-service.js.map +1 -0
- package/dist/utils/git.d.ts +26 -4
- package/dist/utils/git.js +55 -7
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/merge-resolver.d.ts +34 -0
- package/dist/utils/merge-resolver.js +201 -0
- package/dist/utils/merge-resolver.js.map +1 -0
- package/dist/utils/preflight.d.ts +2 -1
- package/dist/utils/preflight.js +8 -1
- package/dist/utils/preflight.js.map +1 -1
- package/dist/utils/version-checker.d.ts +23 -0
- package/dist/utils/version-checker.js +116 -0
- package/dist/utils/version-checker.js.map +1 -0
- package/dist/utils/workspace-config.d.ts +8 -0
- package/dist/utils/workspace-config.js +22 -0
- package/dist/utils/workspace-config.js.map +1 -0
- package/package.json +24 -11
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnstructuredExtractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts entities from file-based sources (e.g. Obsidian) where field
|
|
5
|
+
* mapping isn't possible. Uses LLM for extraction.
|
|
6
|
+
*/
|
|
7
|
+
import { SyncMCPClient } from './mcp-client.js';
|
|
8
|
+
import type { SchemaRegistry } from '../../core/schema-registry.js';
|
|
9
|
+
import type { GraphRAGClient } from './graphrag-client.js';
|
|
10
|
+
import type { SourceConfig, EntityMapping, ExtractedRecord, SourceFile } from './types.js';
|
|
11
|
+
export declare class UnstructuredExtractor {
|
|
12
|
+
private client;
|
|
13
|
+
private sourceConfig;
|
|
14
|
+
private schemaRegistry;
|
|
15
|
+
private graphrag?;
|
|
16
|
+
constructor(client: SyncMCPClient, sourceConfig: SourceConfig, schemaRegistry: SchemaRegistry, graphrag?: GraphRAGClient);
|
|
17
|
+
/**
|
|
18
|
+
* Discover files matching directory patterns.
|
|
19
|
+
*/
|
|
20
|
+
discover(mapping: EntityMapping): Promise<SourceFile[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Extract one file via LLM.
|
|
23
|
+
*/
|
|
24
|
+
extractOne(file: SourceFile, mapping: EntityMapping, onProgress?: (msg: string) => void): Promise<ExtractedRecord | null>;
|
|
25
|
+
/**
|
|
26
|
+
* Extract all files for one mapping (with concurrency limit).
|
|
27
|
+
*/
|
|
28
|
+
extract(mapping: EntityMapping, onProgress?: (msg: string) => void): Promise<ExtractedRecord[]>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UnstructuredExtractor
|
|
3
|
+
*
|
|
4
|
+
* Extracts entities from file-based sources (e.g. Obsidian) where field
|
|
5
|
+
* mapping isn't possible. Uses LLM for extraction.
|
|
6
|
+
*/
|
|
7
|
+
import { llmExtract } from './llm.js';
|
|
8
|
+
import { slugify } from './structured-extractor.js';
|
|
9
|
+
import { matchGlob } from './frontmatter-extractor.js';
|
|
10
|
+
const CONCURRENCY_LIMIT = 3;
|
|
11
|
+
export class UnstructuredExtractor {
|
|
12
|
+
client;
|
|
13
|
+
sourceConfig;
|
|
14
|
+
schemaRegistry;
|
|
15
|
+
graphrag;
|
|
16
|
+
constructor(client, sourceConfig, schemaRegistry, graphrag) {
|
|
17
|
+
this.client = client;
|
|
18
|
+
this.sourceConfig = sourceConfig;
|
|
19
|
+
this.schemaRegistry = schemaRegistry;
|
|
20
|
+
this.graphrag = graphrag;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Discover files matching directory patterns.
|
|
24
|
+
*/
|
|
25
|
+
async discover(mapping) {
|
|
26
|
+
// Use explicit tool name from mapping, or fall back to heuristic matching
|
|
27
|
+
const tools = this.client.getTools();
|
|
28
|
+
const listTool = mapping.list_tool
|
|
29
|
+
? tools.find(t => t.name === mapping.list_tool)
|
|
30
|
+
: tools.find(t => t.name.includes('list') && (t.name.includes('file') || t.name.includes('vault')));
|
|
31
|
+
if (!listTool) {
|
|
32
|
+
throw new Error(mapping.list_tool
|
|
33
|
+
? `Configured list_tool "${mapping.list_tool}" not found on the MCP server`
|
|
34
|
+
: 'No file listing tool found on the MCP server');
|
|
35
|
+
}
|
|
36
|
+
const files = [];
|
|
37
|
+
const patterns = mapping.directory_patterns ?? [];
|
|
38
|
+
if (patterns.length === 0) {
|
|
39
|
+
// List all files
|
|
40
|
+
const raw = await this.client.callTool(listTool.name);
|
|
41
|
+
const items = parseFileList(raw);
|
|
42
|
+
for (const item of items) {
|
|
43
|
+
const path = typeof item === 'string' ? item : (item.path ?? item.filename ?? item.name);
|
|
44
|
+
if (path && path.endsWith('.md')) {
|
|
45
|
+
if (mapping.file_pattern) {
|
|
46
|
+
const basename = (path.split('/').pop() ?? path).replace(/\.md$/, '');
|
|
47
|
+
if (!matchGlob(mapping.file_pattern, basename))
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (mapping.name_match === 'folder') {
|
|
51
|
+
const parts = path.split('/');
|
|
52
|
+
const basename = (parts[parts.length - 1] ?? path).replace(/\.md$/, '');
|
|
53
|
+
const parentFolder = parts.length >= 2 ? parts[parts.length - 2] : '';
|
|
54
|
+
if (basename.toLowerCase() !== parentFolder.toLowerCase())
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
files.push({ path, name: path.split('/').pop() ?? path });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
for (const pattern of patterns) {
|
|
63
|
+
const dir = pattern.replace(/\/$/, '');
|
|
64
|
+
try {
|
|
65
|
+
const raw = await this.client.callTool(listTool.name, { directory: dir });
|
|
66
|
+
const items = parseFileList(raw);
|
|
67
|
+
for (const item of items) {
|
|
68
|
+
const entry = typeof item === 'string' ? item : (item.path ?? item.filename ?? item.name);
|
|
69
|
+
if (entry && entry.endsWith('.md')) {
|
|
70
|
+
if (mapping.file_pattern) {
|
|
71
|
+
const basename = (entry.split('/').pop() ?? entry).replace(/\.md$/, '');
|
|
72
|
+
if (!matchGlob(mapping.file_pattern, basename))
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
if (mapping.name_match === 'folder') {
|
|
76
|
+
const basename = (entry.split('/').pop() ?? entry).replace(/\.md$/, '');
|
|
77
|
+
const parentFolder = dir.split('/').pop() ?? dir;
|
|
78
|
+
if (basename.toLowerCase() !== parentFolder.toLowerCase())
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const filename = entry.split('/').pop() ?? entry;
|
|
82
|
+
files.push({ path: `${dir}/${filename}`, name: filename });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// skip inaccessible directories
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return files;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Extract one file via LLM.
|
|
95
|
+
*/
|
|
96
|
+
async extractOne(file, mapping, onProgress) {
|
|
97
|
+
// Use explicit tool name from mapping, or fall back to heuristic matching
|
|
98
|
+
const tools = this.client.getTools();
|
|
99
|
+
const readTool = mapping.read_tool
|
|
100
|
+
? tools.find(t => t.name === mapping.read_tool)
|
|
101
|
+
: tools.find(t => (t.name.includes('get') || t.name.includes('read')) &&
|
|
102
|
+
(t.name.includes('vault') || t.name.includes('note'))) ?? tools.find(t => (t.name.includes('get') || t.name.includes('read')) &&
|
|
103
|
+
t.name.includes('file') &&
|
|
104
|
+
!t.name.includes('active'));
|
|
105
|
+
if (!readTool) {
|
|
106
|
+
onProgress?.(` Skip ${file.name}: no read tool found`);
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
let content;
|
|
110
|
+
try {
|
|
111
|
+
content = await this.client.callTool(readTool.name, { filename: file.path });
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
115
|
+
onProgress?.(` Read error on ${file.name}: ${msg}`);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
if (!content || content.length < 10) {
|
|
119
|
+
onProgress?.(` Skip ${file.name}: empty or too short (${content?.length ?? 0} chars)`);
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
// Get schema for extraction
|
|
123
|
+
const schema = this.schemaRegistry.getSchema(mapping.entity_type);
|
|
124
|
+
try {
|
|
125
|
+
// Get cross-document context from GraphRAG if available
|
|
126
|
+
let graphragContext;
|
|
127
|
+
if (this.graphrag) {
|
|
128
|
+
const entityName = file.name.replace(/\.md$/, '');
|
|
129
|
+
const ctx = this.graphrag.getEntityContext(entityName, mapping.entity_type, content);
|
|
130
|
+
if (ctx.formattedContext) {
|
|
131
|
+
graphragContext = ctx.formattedContext;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const frontmatter = await llmExtract(content, mapping.entity_type, schema, graphragContext);
|
|
135
|
+
// Generate entity_id from extracted name/title or filename
|
|
136
|
+
const nameField = frontmatter.name ?? frontmatter.title ?? file.name.replace(/\.md$/, '');
|
|
137
|
+
const entityId = slugify(String(nameField));
|
|
138
|
+
frontmatter.entity_type = mapping.entity_type;
|
|
139
|
+
frontmatter.entity_id = entityId;
|
|
140
|
+
return {
|
|
141
|
+
entity_type: mapping.entity_type,
|
|
142
|
+
entity_id: entityId,
|
|
143
|
+
target_repo: mapping.target_repo,
|
|
144
|
+
frontmatter,
|
|
145
|
+
content: '',
|
|
146
|
+
source_name: this.sourceConfig.name,
|
|
147
|
+
source_ref: `${this.sourceConfig.name}:${file.path}`,
|
|
148
|
+
confidence: 0.7,
|
|
149
|
+
...(mapping.write_mode ? { write_mode: mapping.write_mode } : {}),
|
|
150
|
+
...(mapping.co_locate ? { co_locate: mapping.co_locate } : {}),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
155
|
+
onProgress?.(` LLM error on ${file.name}: ${msg}`);
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Extract all files for one mapping (with concurrency limit).
|
|
161
|
+
*/
|
|
162
|
+
async extract(mapping, onProgress) {
|
|
163
|
+
if (mapping.extraction_mode !== 'unstructured')
|
|
164
|
+
return [];
|
|
165
|
+
const log = onProgress ?? (() => { });
|
|
166
|
+
const files = await this.discover(mapping);
|
|
167
|
+
log(` Found ${files.length} files for LLM extraction`);
|
|
168
|
+
const results = [];
|
|
169
|
+
// Process in batches
|
|
170
|
+
for (let i = 0; i < files.length; i += CONCURRENCY_LIMIT) {
|
|
171
|
+
const batch = files.slice(i, i + CONCURRENCY_LIMIT);
|
|
172
|
+
const batchResults = await Promise.all(batch.map(file => this.extractOne(file, mapping, onProgress)));
|
|
173
|
+
for (const result of batchResults) {
|
|
174
|
+
if (result)
|
|
175
|
+
results.push(result);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return results;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function tryParseJSON(raw) {
|
|
182
|
+
try {
|
|
183
|
+
return JSON.parse(raw);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return raw;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/** Parse an MCP file list response, handling both arrays and wrapped objects. */
|
|
190
|
+
function parseFileList(raw) {
|
|
191
|
+
const parsed = tryParseJSON(raw);
|
|
192
|
+
if (Array.isArray(parsed))
|
|
193
|
+
return parsed;
|
|
194
|
+
const items = parsed?.files ?? parsed?.data ?? parsed?.results ?? parsed?.items;
|
|
195
|
+
return Array.isArray(items) ? items : [];
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=unstructured-extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unstructured-extractor.js","sourceRoot":"","sources":["../../../src/services/sync/unstructured-extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VectorService
|
|
3
|
+
*
|
|
4
|
+
* Manages semantic and full-text search using LanceDB.
|
|
5
|
+
*
|
|
6
|
+
* Tier 1 — FTS only (no API key required):
|
|
7
|
+
* All entities are indexed in LanceDB with a BM25 full-text search index on
|
|
8
|
+
* the `text` column. This is a significant upgrade over substring matching.
|
|
9
|
+
*
|
|
10
|
+
* Tier 2 — Hybrid semantic search (requires Voyage AI API key):
|
|
11
|
+
* When a voyage_api_key is configured, embeddings are generated via Voyage AI
|
|
12
|
+
* (voyage-3, 1024 dimensions) and stored alongside the FTS index. Searches
|
|
13
|
+
* use LanceDB hybrid mode (vector + FTS re-ranked).
|
|
14
|
+
*
|
|
15
|
+
* Storage: ~/.studiograph/vector/ (configurable via user.json vector_db_path)
|
|
16
|
+
* Last-index timestamps: ~/.studiograph/vector/last-indexed.json
|
|
17
|
+
*/
|
|
18
|
+
import type { EntityFile } from '../core/graph.js';
|
|
19
|
+
export interface VectorSearchResult {
|
|
20
|
+
repoName: string;
|
|
21
|
+
entityType: string;
|
|
22
|
+
entityId: string;
|
|
23
|
+
score: number;
|
|
24
|
+
}
|
|
25
|
+
export declare class VectorService {
|
|
26
|
+
private dbPath;
|
|
27
|
+
private voyageApiKey?;
|
|
28
|
+
private db?;
|
|
29
|
+
private table?;
|
|
30
|
+
private lastIndexedPath;
|
|
31
|
+
private initialized;
|
|
32
|
+
constructor(dbPath: string, voyageApiKey?: string);
|
|
33
|
+
/**
|
|
34
|
+
* Open/create the LanceDB table and ensure the FTS index exists.
|
|
35
|
+
* Call once before using the service.
|
|
36
|
+
*/
|
|
37
|
+
init(): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Index or re-index a single entity.
|
|
40
|
+
* Safe to call on create, update, or as part of bulk indexing.
|
|
41
|
+
*/
|
|
42
|
+
upsert(repoName: string, entity: EntityFile): Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Bulk upsert — used by `studiograph index`. Batches Voyage API calls.
|
|
45
|
+
*/
|
|
46
|
+
upsertMany(repoName: string, entities: EntityFile[]): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Remove an entity from the index.
|
|
49
|
+
*/
|
|
50
|
+
delete(repoName: string, entityType: string, entityId: string): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Search the index.
|
|
53
|
+
* Uses hybrid search (vector + FTS) when Voyage key is configured, FTS only otherwise.
|
|
54
|
+
*/
|
|
55
|
+
search(query: string, options?: {
|
|
56
|
+
limit?: number;
|
|
57
|
+
repos?: string[];
|
|
58
|
+
}): Promise<VectorSearchResult[]>;
|
|
59
|
+
/**
|
|
60
|
+
* Get the last time a repo's entities were indexed.
|
|
61
|
+
*/
|
|
62
|
+
getLastIndexedTime(repoName: string): string | undefined;
|
|
63
|
+
/**
|
|
64
|
+
* Record the current time as the last index time for a repo.
|
|
65
|
+
*/
|
|
66
|
+
setLastIndexedTime(repoName: string): void;
|
|
67
|
+
/** Whether Voyage AI embeddings are enabled (Tier 2). */
|
|
68
|
+
get hasEmbeddings(): boolean;
|
|
69
|
+
private generateEmbedding;
|
|
70
|
+
private generateEmbeddingsBatch;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Index (or re-index) all entities across workspace repos into LanceDB.
|
|
74
|
+
* Standalone function — does not require a WorkspaceManager instance.
|
|
75
|
+
* Used by `join`, `commit`, and other CLI commands that land entities on disk.
|
|
76
|
+
*
|
|
77
|
+
* @returns Total number of entities indexed.
|
|
78
|
+
*/
|
|
79
|
+
export declare function reindexWorkspace(workspacePath: string, repos: Array<{
|
|
80
|
+
name: string;
|
|
81
|
+
path: string;
|
|
82
|
+
}>, onProgress?: (msg: string) => void): Promise<number>;
|
|
83
|
+
/**
|
|
84
|
+
* Build a text representation of an entity for FTS/embedding.
|
|
85
|
+
* Combines entity type, key frontmatter fields, and markdown body.
|
|
86
|
+
* Exported for testing.
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildEntityText(entity: EntityFile): string;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* VectorService
|
|
3
|
+
*
|
|
4
|
+
* Manages semantic and full-text search using LanceDB.
|
|
5
|
+
*
|
|
6
|
+
* Tier 1 — FTS only (no API key required):
|
|
7
|
+
* All entities are indexed in LanceDB with a BM25 full-text search index on
|
|
8
|
+
* the `text` column. This is a significant upgrade over substring matching.
|
|
9
|
+
*
|
|
10
|
+
* Tier 2 — Hybrid semantic search (requires Voyage AI API key):
|
|
11
|
+
* When a voyage_api_key is configured, embeddings are generated via Voyage AI
|
|
12
|
+
* (voyage-3, 1024 dimensions) and stored alongside the FTS index. Searches
|
|
13
|
+
* use LanceDB hybrid mode (vector + FTS re-ranked).
|
|
14
|
+
*
|
|
15
|
+
* Storage: ~/.studiograph/vector/ (configurable via user.json vector_db_path)
|
|
16
|
+
* Last-index timestamps: ~/.studiograph/vector/last-indexed.json
|
|
17
|
+
*/
|
|
18
|
+
import { join } from 'path';
|
|
19
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
20
|
+
import * as lancedb from '@lancedb/lancedb';
|
|
21
|
+
const VOYAGE_API_URL = 'https://api.voyageai.com/v1/embeddings';
|
|
22
|
+
const VOYAGE_MODEL = 'voyage-3';
|
|
23
|
+
const VECTOR_DIM = 1024;
|
|
24
|
+
const TABLE_NAME = 'entities';
|
|
25
|
+
export class VectorService {
|
|
26
|
+
dbPath;
|
|
27
|
+
voyageApiKey;
|
|
28
|
+
db;
|
|
29
|
+
table;
|
|
30
|
+
lastIndexedPath;
|
|
31
|
+
initialized = false;
|
|
32
|
+
constructor(dbPath, voyageApiKey) {
|
|
33
|
+
this.dbPath = dbPath;
|
|
34
|
+
this.voyageApiKey = voyageApiKey;
|
|
35
|
+
this.lastIndexedPath = join(dbPath, 'last-indexed.json');
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Open/create the LanceDB table and ensure the FTS index exists.
|
|
39
|
+
* Call once before using the service.
|
|
40
|
+
*/
|
|
41
|
+
async init() {
|
|
42
|
+
if (this.initialized)
|
|
43
|
+
return;
|
|
44
|
+
mkdirSync(this.dbPath, { recursive: true });
|
|
45
|
+
this.db = await lancedb.connect(this.dbPath);
|
|
46
|
+
const tableNames = await this.db.tableNames();
|
|
47
|
+
if (tableNames.includes(TABLE_NAME)) {
|
|
48
|
+
this.table = await this.db.openTable(TABLE_NAME);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Create table with a seed record (LanceDB infers schema from first batch)
|
|
52
|
+
const seed = {
|
|
53
|
+
id: '__seed__',
|
|
54
|
+
repo: '',
|
|
55
|
+
entity_type: '',
|
|
56
|
+
entity_id: '',
|
|
57
|
+
text: 'seed',
|
|
58
|
+
vector: new Array(VECTOR_DIM).fill(0),
|
|
59
|
+
updated_at: new Date().toISOString(),
|
|
60
|
+
};
|
|
61
|
+
this.table = await this.db.createTable(TABLE_NAME, [seed]);
|
|
62
|
+
// Create FTS index on text column
|
|
63
|
+
await this.table.createIndex('text', {
|
|
64
|
+
config: lancedb.Index.fts(),
|
|
65
|
+
});
|
|
66
|
+
// Delete the seed record
|
|
67
|
+
await this.table.delete(`id = '__seed__'`);
|
|
68
|
+
}
|
|
69
|
+
this.initialized = true;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Index or re-index a single entity.
|
|
73
|
+
* Safe to call on create, update, or as part of bulk indexing.
|
|
74
|
+
*/
|
|
75
|
+
async upsert(repoName, entity) {
|
|
76
|
+
await this.init();
|
|
77
|
+
const id = `${repoName}/${entity.entityType}/${entity.id}`;
|
|
78
|
+
const text = buildEntityText(entity);
|
|
79
|
+
const vector = this.voyageApiKey
|
|
80
|
+
? await this.generateEmbedding(text)
|
|
81
|
+
: null;
|
|
82
|
+
const record = {
|
|
83
|
+
id,
|
|
84
|
+
repo: repoName,
|
|
85
|
+
entity_type: entity.entityType,
|
|
86
|
+
entity_id: entity.id,
|
|
87
|
+
text,
|
|
88
|
+
// Only include vector when we actually have one — avoids LanceDB schema inference issues
|
|
89
|
+
vector: vector ?? new Array(VECTOR_DIM).fill(0),
|
|
90
|
+
updated_at: new Date().toISOString(),
|
|
91
|
+
};
|
|
92
|
+
await this.table
|
|
93
|
+
.mergeInsert('id')
|
|
94
|
+
.whenMatchedUpdateAll()
|
|
95
|
+
.whenNotMatchedInsertAll()
|
|
96
|
+
.execute([record]);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Bulk upsert — used by `studiograph index`. Batches Voyage API calls.
|
|
100
|
+
*/
|
|
101
|
+
async upsertMany(repoName, entities) {
|
|
102
|
+
await this.init();
|
|
103
|
+
if (entities.length === 0)
|
|
104
|
+
return;
|
|
105
|
+
const texts = entities.map(e => buildEntityText(e));
|
|
106
|
+
// Batch embeddings (Voyage supports up to 128 per request)
|
|
107
|
+
let vectors = new Array(entities.length).fill(null);
|
|
108
|
+
if (this.voyageApiKey) {
|
|
109
|
+
vectors = await this.generateEmbeddingsBatch(texts);
|
|
110
|
+
}
|
|
111
|
+
const records = entities.map((entity, i) => ({
|
|
112
|
+
id: `${repoName}/${entity.entityType}/${entity.id}`,
|
|
113
|
+
repo: repoName,
|
|
114
|
+
entity_type: entity.entityType,
|
|
115
|
+
entity_id: entity.id,
|
|
116
|
+
text: texts[i],
|
|
117
|
+
vector: vectors[i] ?? new Array(VECTOR_DIM).fill(0),
|
|
118
|
+
updated_at: new Date().toISOString(),
|
|
119
|
+
}));
|
|
120
|
+
await this.table
|
|
121
|
+
.mergeInsert('id')
|
|
122
|
+
.whenMatchedUpdateAll()
|
|
123
|
+
.whenNotMatchedInsertAll()
|
|
124
|
+
.execute(records);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Remove an entity from the index.
|
|
128
|
+
*/
|
|
129
|
+
async delete(repoName, entityType, entityId) {
|
|
130
|
+
await this.init();
|
|
131
|
+
const id = `${repoName}/${entityType}/${entityId}`;
|
|
132
|
+
await this.table.delete(`id = '${id.replace(/'/g, "''")}'`);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Search the index.
|
|
136
|
+
* Uses hybrid search (vector + FTS) when Voyage key is configured, FTS only otherwise.
|
|
137
|
+
*/
|
|
138
|
+
async search(query, options = {}) {
|
|
139
|
+
await this.init();
|
|
140
|
+
const limit = options.limit ?? 10;
|
|
141
|
+
try {
|
|
142
|
+
let rows;
|
|
143
|
+
if (this.voyageApiKey) {
|
|
144
|
+
// Tier 2: hybrid search
|
|
145
|
+
const queryVector = await this.generateEmbedding(query);
|
|
146
|
+
rows = await this.table
|
|
147
|
+
.search(queryVector)
|
|
148
|
+
.limit(limit * 2) // fetch extra for re-ranking
|
|
149
|
+
.toArray();
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Tier 1: FTS only
|
|
153
|
+
rows = await this.table
|
|
154
|
+
.search(query, 'text')
|
|
155
|
+
.limit(limit)
|
|
156
|
+
.toArray();
|
|
157
|
+
}
|
|
158
|
+
let results = rows
|
|
159
|
+
.filter((r) => r.id !== '__seed__' && r.entity_id !== '')
|
|
160
|
+
.map((r, i) => ({
|
|
161
|
+
repoName: r.repo,
|
|
162
|
+
entityType: r.entity_type,
|
|
163
|
+
entityId: r.entity_id,
|
|
164
|
+
score: r._distance != null ? 1 / (1 + r._distance) : 1 - i * 0.01,
|
|
165
|
+
}));
|
|
166
|
+
if (options.repos && options.repos.length > 0) {
|
|
167
|
+
results = results.filter(r => options.repos.includes(r.repoName));
|
|
168
|
+
}
|
|
169
|
+
return results.slice(0, limit);
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// FTS index may not be built yet — return empty
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get the last time a repo's entities were indexed.
|
|
178
|
+
*/
|
|
179
|
+
getLastIndexedTime(repoName) {
|
|
180
|
+
if (!existsSync(this.lastIndexedPath))
|
|
181
|
+
return undefined;
|
|
182
|
+
try {
|
|
183
|
+
const data = JSON.parse(readFileSync(this.lastIndexedPath, 'utf-8'));
|
|
184
|
+
return data[repoName];
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Record the current time as the last index time for a repo.
|
|
192
|
+
*/
|
|
193
|
+
setLastIndexedTime(repoName) {
|
|
194
|
+
mkdirSync(this.dbPath, { recursive: true });
|
|
195
|
+
let data = {};
|
|
196
|
+
if (existsSync(this.lastIndexedPath)) {
|
|
197
|
+
try {
|
|
198
|
+
data = JSON.parse(readFileSync(this.lastIndexedPath, 'utf-8'));
|
|
199
|
+
}
|
|
200
|
+
catch { /* ignore */ }
|
|
201
|
+
}
|
|
202
|
+
data[repoName] = new Date().toISOString();
|
|
203
|
+
writeFileSync(this.lastIndexedPath, JSON.stringify(data, null, 2) + '\n');
|
|
204
|
+
}
|
|
205
|
+
/** Whether Voyage AI embeddings are enabled (Tier 2). */
|
|
206
|
+
get hasEmbeddings() {
|
|
207
|
+
return !!this.voyageApiKey;
|
|
208
|
+
}
|
|
209
|
+
// ─── Private: Voyage AI ──────────────────────────────────────────────────────
|
|
210
|
+
async generateEmbedding(text) {
|
|
211
|
+
const results = await this.generateEmbeddingsBatch([text]);
|
|
212
|
+
return results[0] ?? new Array(VECTOR_DIM).fill(0);
|
|
213
|
+
}
|
|
214
|
+
async generateEmbeddingsBatch(texts) {
|
|
215
|
+
// Voyage supports up to 128 inputs per request
|
|
216
|
+
const BATCH_SIZE = 128;
|
|
217
|
+
const all = [];
|
|
218
|
+
for (let i = 0; i < texts.length; i += BATCH_SIZE) {
|
|
219
|
+
const batch = texts.slice(i, i + BATCH_SIZE);
|
|
220
|
+
const response = await fetch(VOYAGE_API_URL, {
|
|
221
|
+
method: 'POST',
|
|
222
|
+
headers: {
|
|
223
|
+
'Authorization': `Bearer ${this.voyageApiKey}`,
|
|
224
|
+
'Content-Type': 'application/json',
|
|
225
|
+
},
|
|
226
|
+
body: JSON.stringify({ model: VOYAGE_MODEL, input: batch }),
|
|
227
|
+
});
|
|
228
|
+
if (!response.ok) {
|
|
229
|
+
const body = await response.text();
|
|
230
|
+
throw new Error(`Voyage AI error ${response.status}: ${body}`);
|
|
231
|
+
}
|
|
232
|
+
const json = await response.json();
|
|
233
|
+
all.push(...json.data.map(d => d.embedding));
|
|
234
|
+
}
|
|
235
|
+
return all;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
// ─── Standalone reindex ──────────────────────────────────────────────────────
|
|
239
|
+
/**
|
|
240
|
+
* Index (or re-index) all entities across workspace repos into LanceDB.
|
|
241
|
+
* Standalone function — does not require a WorkspaceManager instance.
|
|
242
|
+
* Used by `join`, `commit`, and other CLI commands that land entities on disk.
|
|
243
|
+
*
|
|
244
|
+
* @returns Total number of entities indexed.
|
|
245
|
+
*/
|
|
246
|
+
export async function reindexWorkspace(workspacePath, repos, onProgress) {
|
|
247
|
+
const { loadUserConfig } = await import('../core/user-config.js');
|
|
248
|
+
const { BaseGraphManager } = await import('../core/graph.js');
|
|
249
|
+
const { homedir } = await import('os');
|
|
250
|
+
const userConfig = loadUserConfig();
|
|
251
|
+
const dbPath = userConfig.vector_db_path || join(homedir(), '.studiograph', 'vector');
|
|
252
|
+
const vectorService = new VectorService(dbPath, userConfig.voyage_api_key);
|
|
253
|
+
await vectorService.init();
|
|
254
|
+
const log = onProgress ?? (() => { });
|
|
255
|
+
let total = 0;
|
|
256
|
+
for (const repo of repos) {
|
|
257
|
+
const repoPath = join(workspacePath, repo.path);
|
|
258
|
+
if (!existsSync(repoPath))
|
|
259
|
+
continue;
|
|
260
|
+
try {
|
|
261
|
+
const graph = new BaseGraphManager({
|
|
262
|
+
repoPath,
|
|
263
|
+
repoName: repo.name,
|
|
264
|
+
gitUser: { id: 'reindex', name: 'reindex', email: 'reindex@studiograph.local' },
|
|
265
|
+
});
|
|
266
|
+
const entities = graph.list();
|
|
267
|
+
if (entities.length > 0) {
|
|
268
|
+
await vectorService.upsertMany(repo.name, entities);
|
|
269
|
+
total += entities.length;
|
|
270
|
+
}
|
|
271
|
+
vectorService.setLastIndexedTime(repo.name);
|
|
272
|
+
log(` Indexed ${repo.name}: ${entities.length} entities`);
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
log(` Failed to index ${repo.name}: ${err instanceof Error ? err.message : 'unknown'}`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return total;
|
|
279
|
+
}
|
|
280
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
281
|
+
/**
|
|
282
|
+
* Build a text representation of an entity for FTS/embedding.
|
|
283
|
+
* Combines entity type, key frontmatter fields, and markdown body.
|
|
284
|
+
* Exported for testing.
|
|
285
|
+
*/
|
|
286
|
+
export function buildEntityText(entity) {
|
|
287
|
+
const parts = [];
|
|
288
|
+
// Entity type and ID as context
|
|
289
|
+
parts.push(`${entity.entityType}: ${entity.data.name || entity.id}`);
|
|
290
|
+
// Key frontmatter fields (skip system fields and empty values)
|
|
291
|
+
const systemFields = new Set([
|
|
292
|
+
'entity_type', 'entity_id', 'created_at', 'updated_at',
|
|
293
|
+
'created_by', 'updated_by', 'visibility', 'restricted_to',
|
|
294
|
+
'sensitive_fields',
|
|
295
|
+
]);
|
|
296
|
+
for (const [key, value] of Object.entries(entity.data)) {
|
|
297
|
+
if (systemFields.has(key) || value == null || value === '')
|
|
298
|
+
continue;
|
|
299
|
+
if (Array.isArray(value)) {
|
|
300
|
+
if (value.length > 0)
|
|
301
|
+
parts.push(`${key}: ${value.join(', ')}`);
|
|
302
|
+
}
|
|
303
|
+
else {
|
|
304
|
+
parts.push(`${key}: ${String(value)}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Markdown body
|
|
308
|
+
if (entity.document.content) {
|
|
309
|
+
// Strip markdown syntax for cleaner FTS/embedding input
|
|
310
|
+
const plainText = entity.document.content
|
|
311
|
+
.replace(/^#{1,6}\s+/gm, '') // headings
|
|
312
|
+
.replace(/\*\*(.+?)\*\*/g, '$1') // bold
|
|
313
|
+
.replace(/\*(.+?)\*/g, '$1') // italic
|
|
314
|
+
.replace(/`(.+?)`/g, '$1') // inline code
|
|
315
|
+
.replace(/\[\[(.+?)\]\]/g, '$1') // wikilinks
|
|
316
|
+
.trim();
|
|
317
|
+
if (plainText)
|
|
318
|
+
parts.push(plainText);
|
|
319
|
+
}
|
|
320
|
+
return parts.join('\n');
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=vector-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector-service.js","sourceRoot":"","sources":["../../src/services/vector-service.ts"],"names":[],"mappings":"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"}
|