studiograph 1.1.3 → 1.2.0-beta.10
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/README.md +2 -8
- package/dist/agent/orchestrator.d.ts +53 -0
- package/dist/agent/orchestrator.js +197 -12
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/prompts/system.md +43 -11
- 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/{bundled/enrich-entities.md → enrich-entities.md} +12 -0
- package/dist/agent/skills/entity-schema.md +502 -0
- package/dist/agent/skills/obsidian-source-setup.md +246 -0
- package/dist/agent/skills/sync-configuration.md +144 -0
- package/dist/agent/skills/sync-setup.md +84 -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 +33 -1
- package/dist/agent/tools/graph-tools.js +192 -44
- package/dist/agent/tools/graph-tools.js.map +1 -1
- package/dist/agent/tools/load-skill.d.ts +1 -1
- package/dist/agent/tools/load-skill.js +1 -1
- package/dist/agent/tools/load-skill.js.map +1 -1
- package/dist/agent/tools/ops-tools.d.ts +24 -0
- package/dist/agent/tools/ops-tools.js +542 -0
- package/dist/agent/tools/ops-tools.js.map +1 -0
- package/dist/agent/tools/sync-tools.d.ts +33 -0
- package/dist/agent/tools/sync-tools.js +947 -0
- package/dist/agent/tools/sync-tools.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.js +121 -18
- package/dist/cli/commands/app.js.map +1 -1
- 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 +44 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/connector.js +10 -2
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts +4 -6
- package/dist/cli/commands/deploy.js +292 -115
- package/dist/cli/commands/deploy.js.map +1 -1
- 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/init.js +29 -196
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/join.js +23 -3
- package/dist/cli/commands/join.js.map +1 -1
- 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.js +11 -7
- package/dist/cli/commands/provision.js.map +1 -1
- package/dist/cli/commands/r2.js +8 -2
- package/dist/cli/commands/r2.js.map +1 -1
- package/dist/cli/commands/redeploy.d.ts +9 -0
- package/dist/cli/commands/redeploy.js +203 -0
- package/dist/cli/commands/redeploy.js.map +1 -0
- 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/resolve.d.ts +8 -0
- package/dist/cli/commands/resolve.js +85 -0
- package/dist/cli/commands/resolve.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 +55 -8
- 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 +307 -55
- 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 +81 -5
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/index.js +45 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/scaffolding.d.ts +2 -1
- package/dist/cli/scaffolding.js +38 -23
- package/dist/cli/scaffolding.js.map +1 -1
- 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 +40 -12
- package/dist/core/graph.js +344 -104
- package/dist/core/graph.js.map +1 -1
- package/dist/core/migration-runner.d.ts +4 -1
- package/dist/core/migration-runner.js +14 -3
- package/dist/core/migration-runner.js.map +1 -1
- package/dist/core/types.d.ts +2 -4
- package/dist/core/types.js +1 -2
- package/dist/core/types.js.map +1 -1
- package/dist/core/user-config.d.ts +12 -0
- package/dist/core/user-config.js.map +1 -1
- package/dist/core/workspace-manager.d.ts +6 -1
- package/dist/core/workspace-manager.js +29 -4
- package/dist/core/workspace-manager.js.map +1 -1
- package/dist/core/workspace.d.ts +13 -5
- package/dist/core/workspace.js +115 -33
- package/dist/core/workspace.js.map +1 -1
- package/dist/lib/lib/utils.d.ts +2 -0
- package/dist/lib/lib/utils.js +6 -0
- package/dist/lib/lib/utils.js.map +1 -0
- package/dist/mcp/connector-manager.d.ts +7 -3
- package/dist/mcp/connector-manager.js +61 -16
- package/dist/mcp/connector-manager.js.map +1 -1
- 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 +3 -1
- package/dist/mcp/connectors/definitions.js +19 -127
- package/dist/mcp/connectors/definitions.js.map +1 -1
- 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/server/index.js +97 -11
- package/dist/server/index.js.map +1 -1
- package/dist/server/plugin-loader.d.ts +8 -0
- package/dist/server/plugin-loader.js +54 -2
- package/dist/server/plugin-loader.js.map +1 -1
- package/dist/server/routes/chat.d.ts +3 -2
- package/dist/server/routes/chat.js +67 -16
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/git-api.d.ts +9 -0
- package/dist/server/routes/git-api.js +82 -0
- package/dist/server/routes/git-api.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +2 -2
- package/dist/server/routes/graph-api.js +164 -3
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/workspace-api.d.ts +9 -0
- package/dist/server/routes/workspace-api.js +170 -0
- package/dist/server/routes/workspace-api.js.map +1 -0
- package/dist/services/assets/base.d.ts +2 -2
- package/dist/services/assets/base.js +4 -4
- package/dist/services/assets/base.js.map +1 -1
- package/dist/services/assets/index.d.ts +6 -6
- package/dist/services/assets/index.js +12 -12
- package/dist/services/assets/index.js.map +1 -1
- package/dist/services/git.d.ts +31 -0
- package/dist/services/git.js +92 -3
- package/dist/services/git.js.map +1 -1
- package/dist/services/github-provisioner.d.ts +8 -3
- package/dist/services/github-provisioner.js +35 -8
- package/dist/services/github-provisioner.js.map +1 -1
- package/dist/services/lint-service.js +8 -1
- package/dist/services/lint-service.js.map +1 -1
- package/dist/services/markdown.js +3 -3
- package/dist/services/markdown.js.map +1 -1
- package/dist/services/memory-service.d.ts +1 -1
- package/dist/services/memory-service.js +2 -3
- 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 +60 -0
- package/dist/services/sync/commit.js +370 -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 +11 -0
- package/dist/services/vector-service.js +42 -0
- package/dist/services/vector-service.js.map +1 -1
- package/dist/utils/git.d.ts +31 -4
- package/dist/utils/git.js +65 -7
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/merge-resolver.d.ts +60 -0
- package/dist/utils/merge-resolver.js +304 -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/workspace-config.d.ts +8 -0
- package/dist/utils/workspace-config.js +22 -0
- package/dist/utils/workspace-config.js.map +1 -0
- package/dist/web/_app/env.js +1 -0
- package/dist/web/_app/immutable/assets/0.BwJV4fvl.css +1 -0
- package/dist/web/_app/immutable/assets/2.DRHi7ABa.css +1 -0
- package/dist/web/_app/immutable/assets/3.CnAQdPKU.css +1 -0
- package/dist/web/_app/immutable/assets/4.BG92MufE.css +1 -0
- package/dist/web/_app/immutable/assets/5.CfrQIPYs.css +1 -0
- package/dist/web/_app/immutable/assets/ChatPanel.BNzaCFTL.css +1 -0
- package/dist/web/_app/immutable/assets/editor.D6Rjo7RE.css +1 -0
- package/dist/web/_app/immutable/chunks/4QY4j-jX.js +1 -0
- package/dist/web/_app/immutable/chunks/B4G4uWkV.js +1 -0
- package/dist/web/_app/immutable/chunks/BB_5th5W.js +3383 -0
- package/dist/web/_app/immutable/chunks/CUzqHQY_.js +1 -0
- package/dist/web/_app/immutable/chunks/CYrVHOHA.js +1 -0
- package/dist/web/_app/immutable/chunks/CksE5s8n.js +1 -0
- package/dist/web/_app/immutable/chunks/CqkleIqs.js +1 -0
- package/dist/web/_app/immutable/chunks/D0JBkEPE.js +86 -0
- package/dist/web/_app/immutable/chunks/D2K5GzLj.js +1 -0
- package/dist/web/_app/immutable/chunks/DEkoussQ.js +2 -0
- package/dist/web/_app/immutable/chunks/DW-KmHRi.js +1 -0
- package/dist/web/_app/immutable/chunks/DcCr4z9k.js +1 -0
- package/dist/web/_app/immutable/chunks/Dg2wWwJu.js +2 -0
- package/dist/web/_app/immutable/chunks/Dh_H7Owr.js +18 -0
- package/dist/web/_app/immutable/chunks/DnlgZ_Tk.js +5 -0
- package/dist/web/_app/immutable/chunks/DtVH--hH.js +6 -0
- package/dist/web/_app/immutable/chunks/PPVm8Dsz.js +1 -0
- package/dist/web/_app/immutable/chunks/SBEriEQR.js +1 -0
- package/dist/web/_app/immutable/chunks/WSUKABI_.js +1 -0
- package/dist/web/_app/immutable/chunks/YTERt3Ul.js +6 -0
- package/dist/web/_app/immutable/chunks/m_R7HatS.js +1 -0
- package/dist/web/_app/immutable/chunks/vlmEnjfO.js +1 -0
- package/dist/web/_app/immutable/entry/app.B9pwpU_x.js +2 -0
- package/dist/web/_app/immutable/entry/start.CDuNCEco.js +1 -0
- package/dist/web/_app/immutable/nodes/0.YEQhw1us.js +1 -0
- package/dist/web/_app/immutable/nodes/1.CvmHhpRy.js +1 -0
- package/dist/web/_app/immutable/nodes/2.c5k1r7dq.js +1 -0
- package/dist/web/_app/immutable/nodes/3.B24tcdLK.js +1 -0
- package/dist/web/_app/immutable/nodes/4.kX2m5Pp9.js +16 -0
- package/dist/web/_app/immutable/nodes/5.DELt6wTD.js +2 -0
- package/dist/web/_app/version.json +1 -0
- package/dist/web/index.html +41 -0
- package/package.json +21 -7
- /package/dist/agent/skills/{bundled/gather-context.md → gather-context.md} +0 -0
package/dist/core/graph.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* Provides unified entity management across any repo type.
|
|
5
5
|
* Integrates Git, Markdown, and Asset services.
|
|
6
6
|
*/
|
|
7
|
-
import { join,
|
|
8
|
-
import { existsSync, readdirSync, statSync } from 'fs';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, statSync, writeFileSync, mkdirSync } from 'fs';
|
|
9
9
|
import { GitService } from '../services/git.js';
|
|
10
10
|
import { MarkdownService } from '../services/markdown.js';
|
|
11
11
|
import { AssetService } from '../services/assets/index.js';
|
|
@@ -54,33 +54,43 @@ export class BaseGraphManager {
|
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Get entity file path
|
|
57
|
+
*
|
|
58
|
+
* Checks three layouts:
|
|
59
|
+
* 1. Flat folder: {repo}/{entityId}/main.md
|
|
60
|
+
* 2. Type subfolder: {repo}/{entityType}/{entityId}/main.md
|
|
61
|
+
* 3. Collection (flat): {repo}/{entityId}.md
|
|
57
62
|
*/
|
|
58
63
|
getEntityPath(entityType, entityId) {
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
64
|
+
// 1. Flat folder layout (most common)
|
|
65
|
+
const folderPath = join(this.repoPath, entityId, 'main.md');
|
|
66
|
+
if (existsSync(folderPath))
|
|
67
|
+
return folderPath;
|
|
68
|
+
// 2. Type-based subfolder layout (e.g. projects/deck/sample-deck/main.md)
|
|
69
|
+
if (entityType) {
|
|
70
|
+
const typeFolderPath = join(this.repoPath, entityType, entityId, 'main.md');
|
|
71
|
+
if (existsSync(typeFolderPath))
|
|
72
|
+
return typeFolderPath;
|
|
73
|
+
}
|
|
74
|
+
// 3. Collection mode (flat file)
|
|
75
|
+
const flatPath = join(this.repoPath, `${entityId}.md`);
|
|
76
|
+
if (existsSync(flatPath))
|
|
77
|
+
return flatPath;
|
|
78
|
+
return folderPath; // default to folder layout for new entities
|
|
73
79
|
}
|
|
74
80
|
/**
|
|
75
81
|
* Validate entity data against schema
|
|
76
82
|
*/
|
|
77
|
-
validateEntity(entityType, data) {
|
|
83
|
+
validateEntity(entityType, data, lenient) {
|
|
78
84
|
// Use schemaRegistry when available (supports extended built-in schemas and
|
|
79
85
|
// custom entity types). Fall back to ENTITY_SCHEMAS, then EntityBaseSchema
|
|
80
86
|
// for unregistered workspace-specific types.
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
87
|
+
// In lenient mode, only validate base fields so entities missing type-specific
|
|
88
|
+
// required fields (e.g. name) are still discoverable.
|
|
89
|
+
const schema = lenient
|
|
90
|
+
? EntityBaseSchema
|
|
91
|
+
: (this.schemaRegistry?.getSchema(entityType)
|
|
92
|
+
?? ENTITY_SCHEMAS[entityType]
|
|
93
|
+
?? EntityBaseSchema);
|
|
84
94
|
try {
|
|
85
95
|
// Add entity_type and preprocess YAML parsing artefacts:
|
|
86
96
|
// - null → undefined (Zod .optional() doesn't accept null)
|
|
@@ -125,7 +135,7 @@ export class BaseGraphManager {
|
|
|
125
135
|
* Create a new entity
|
|
126
136
|
*/
|
|
127
137
|
async create(options) {
|
|
128
|
-
const { entityType, entityId, data, content = '', commitMessage } = options;
|
|
138
|
+
const { entityType, entityId, data, content = '', commitMessage, skipCommit } = options;
|
|
129
139
|
// Validate data
|
|
130
140
|
const validatedData = this.validateEntity(entityType, data);
|
|
131
141
|
// Check if entity already exists
|
|
@@ -139,7 +149,7 @@ export class BaseGraphManager {
|
|
|
139
149
|
content,
|
|
140
150
|
wikilinks: this.markdownService.extractWikilinks(content, validatedData),
|
|
141
151
|
});
|
|
142
|
-
if (this.gitService) {
|
|
152
|
+
if (this.gitService && !skipCommit) {
|
|
143
153
|
const transaction = this.gitService.createTransaction();
|
|
144
154
|
transaction.add({
|
|
145
155
|
operation: 'create',
|
|
@@ -165,8 +175,46 @@ export class BaseGraphManager {
|
|
|
165
175
|
throw new Error(`Entity not found: ${entityType}/${entityId}`);
|
|
166
176
|
}
|
|
167
177
|
const document = this.markdownService.parseFile(entityPath);
|
|
168
|
-
// Validate frontmatter
|
|
169
|
-
|
|
178
|
+
// Validate frontmatter — fall back to base schema, then raw data
|
|
179
|
+
// so app-defined entity types missing base fields are still readable
|
|
180
|
+
let validatedData;
|
|
181
|
+
try {
|
|
182
|
+
validatedData = this.validateEntity(entityType, document.frontmatter);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
try {
|
|
186
|
+
validatedData = this.validateEntity(entityType, document.frontmatter, true);
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
// Last resort: use raw frontmatter (e.g. app-defined types without created_by)
|
|
190
|
+
validatedData = document.frontmatter;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
id: entityId,
|
|
195
|
+
path: entityPath,
|
|
196
|
+
entityType,
|
|
197
|
+
data: validatedData,
|
|
198
|
+
document,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get an entity by ID only (type resolved from frontmatter)
|
|
203
|
+
*/
|
|
204
|
+
getById(entityId) {
|
|
205
|
+
const entityPath = this.getEntityPath('', entityId);
|
|
206
|
+
if (!existsSync(entityPath)) {
|
|
207
|
+
throw new Error(`Entity not found: ${entityId}`);
|
|
208
|
+
}
|
|
209
|
+
const document = this.markdownService.parseFile(entityPath);
|
|
210
|
+
const entityType = document.frontmatter.entity_type ?? this.repoName;
|
|
211
|
+
let validatedData;
|
|
212
|
+
try {
|
|
213
|
+
validatedData = this.validateEntity(entityType, document.frontmatter);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
validatedData = this.validateEntity(entityType, document.frontmatter, true);
|
|
217
|
+
}
|
|
170
218
|
return {
|
|
171
219
|
id: entityId,
|
|
172
220
|
path: entityPath,
|
|
@@ -175,11 +223,98 @@ export class BaseGraphManager {
|
|
|
175
223
|
document,
|
|
176
224
|
};
|
|
177
225
|
}
|
|
226
|
+
/**
|
|
227
|
+
* List files and folders alongside main.md in an entity folder.
|
|
228
|
+
* Returns a recursive tree. Collection-mode entities return [].
|
|
229
|
+
*/
|
|
230
|
+
listEntityContents(entityType, entityId) {
|
|
231
|
+
const entityPath = this.getEntityPath(entityType, entityId);
|
|
232
|
+
if (!existsSync(entityPath))
|
|
233
|
+
return [];
|
|
234
|
+
// Collection-mode entities (flat .md files) have no sub-content
|
|
235
|
+
if (!entityPath.endsWith('main.md'))
|
|
236
|
+
return [];
|
|
237
|
+
const entityDir = dirname(entityPath);
|
|
238
|
+
const readDir = (dirPath) => {
|
|
239
|
+
const entries = [];
|
|
240
|
+
for (const name of readdirSync(dirPath)) {
|
|
241
|
+
if (name.startsWith('.') || name === 'main.md')
|
|
242
|
+
continue;
|
|
243
|
+
const fullPath = join(dirPath, name);
|
|
244
|
+
try {
|
|
245
|
+
const stat = statSync(fullPath);
|
|
246
|
+
if (stat.isDirectory()) {
|
|
247
|
+
const children = readDir(fullPath);
|
|
248
|
+
// Count all files recursively in this directory
|
|
249
|
+
const countFiles = (items) => items.reduce((n, item) => n + (item.type === 'file' ? 1 : countFiles(item.children ?? [])), 0);
|
|
250
|
+
entries.push({ name, type: 'directory', count: countFiles(children), children });
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
entries.push({ name, type: 'file' });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch { /* skip unreadable */ }
|
|
257
|
+
}
|
|
258
|
+
return entries.sort((a, b) => {
|
|
259
|
+
// Directories first, then alphabetical
|
|
260
|
+
if (a.type !== b.type)
|
|
261
|
+
return a.type === 'directory' ? -1 : 1;
|
|
262
|
+
return a.name.localeCompare(b.name);
|
|
263
|
+
});
|
|
264
|
+
};
|
|
265
|
+
return readDir(entityDir);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Read a sub-content file from within an entity folder.
|
|
269
|
+
* Returns the raw file content as a string, or null if not found.
|
|
270
|
+
*/
|
|
271
|
+
readEntityContent(entityType, entityId, filePath) {
|
|
272
|
+
const entityPath = this.getEntityPath(entityType, entityId);
|
|
273
|
+
if (!existsSync(entityPath) || !entityPath.endsWith('main.md'))
|
|
274
|
+
return null;
|
|
275
|
+
const entityDir = dirname(entityPath);
|
|
276
|
+
const resolved = join(entityDir, filePath);
|
|
277
|
+
// Prevent path traversal
|
|
278
|
+
if (!resolved.startsWith(entityDir))
|
|
279
|
+
return null;
|
|
280
|
+
if (!existsSync(resolved))
|
|
281
|
+
return null;
|
|
282
|
+
try {
|
|
283
|
+
const stat = statSync(resolved);
|
|
284
|
+
if (!stat.isFile())
|
|
285
|
+
return null;
|
|
286
|
+
return readFileSync(resolved, 'utf-8');
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Write a sub-content file inside an entity folder.
|
|
294
|
+
* Creates parent directories as needed. Prevents path traversal.
|
|
295
|
+
*/
|
|
296
|
+
writeEntityContent(entityType, entityId, filePath, content) {
|
|
297
|
+
const entityPath = this.getEntityPath(entityType, entityId);
|
|
298
|
+
if (!existsSync(entityPath) || !entityPath.endsWith('main.md')) {
|
|
299
|
+
throw new Error(`Entity not found or is collection-mode: ${entityType}/${entityId}`);
|
|
300
|
+
}
|
|
301
|
+
const entityDir = dirname(entityPath);
|
|
302
|
+
const resolved = join(entityDir, filePath);
|
|
303
|
+
// Prevent path traversal
|
|
304
|
+
if (!resolved.startsWith(entityDir)) {
|
|
305
|
+
throw new Error('Invalid file path: traversal not allowed');
|
|
306
|
+
}
|
|
307
|
+
const dir = dirname(resolved);
|
|
308
|
+
if (!existsSync(dir)) {
|
|
309
|
+
mkdirSync(dir, { recursive: true });
|
|
310
|
+
}
|
|
311
|
+
writeFileSync(resolved, content, 'utf-8');
|
|
312
|
+
}
|
|
178
313
|
/**
|
|
179
314
|
* Update an existing entity
|
|
180
315
|
*/
|
|
181
316
|
async update(options) {
|
|
182
|
-
const { entityType, entityId, data, content, commitMessage } = options;
|
|
317
|
+
const { entityType, entityId, data, content, commitMessage, skipCommit } = options;
|
|
183
318
|
// Get existing entity
|
|
184
319
|
const existing = this.get(entityType, entityId);
|
|
185
320
|
// Merge data (if provided) and add update metadata
|
|
@@ -192,8 +327,33 @@ export class BaseGraphManager {
|
|
|
192
327
|
updated_by: this.gitUser.id,
|
|
193
328
|
}
|
|
194
329
|
: existing.data;
|
|
195
|
-
// Validate merged data
|
|
196
|
-
|
|
330
|
+
// Validate merged data — use lenient validation when no new data is provided,
|
|
331
|
+
// since the existing entity may have been stored without all required fields.
|
|
332
|
+
// Raw fallback coerces Date objects to YYYY-MM-DD so gray-matter doesn't
|
|
333
|
+
// serialize them as full ISO timestamps.
|
|
334
|
+
let validatedData;
|
|
335
|
+
if (data) {
|
|
336
|
+
validatedData = this.validateEntity(entityType, mergedData);
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
try {
|
|
340
|
+
validatedData = this.validateEntity(entityType, mergedData);
|
|
341
|
+
}
|
|
342
|
+
catch {
|
|
343
|
+
try {
|
|
344
|
+
validatedData = this.validateEntity(entityType, mergedData, true);
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
const coerced = Object.fromEntries(Object.entries(mergedData).map(([k, v]) => {
|
|
348
|
+
if (v !== null && typeof v === 'object' && Object.prototype.toString.call(v) === '[object Date]') {
|
|
349
|
+
return [k, v.toISOString().split('T')[0]];
|
|
350
|
+
}
|
|
351
|
+
return [k, v];
|
|
352
|
+
}));
|
|
353
|
+
validatedData = coerced;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
197
357
|
// Merge content (if provided)
|
|
198
358
|
const mergedContent = content !== undefined ? content : existing.document.content;
|
|
199
359
|
// Write updated markdown file
|
|
@@ -203,7 +363,7 @@ export class BaseGraphManager {
|
|
|
203
363
|
content: mergedContent,
|
|
204
364
|
wikilinks: this.markdownService.extractWikilinks(mergedContent, validatedData),
|
|
205
365
|
});
|
|
206
|
-
if (this.gitService) {
|
|
366
|
+
if (this.gitService && !skipCommit) {
|
|
207
367
|
const transaction = this.gitService.createTransaction();
|
|
208
368
|
transaction.add({
|
|
209
369
|
operation: 'update',
|
|
@@ -226,9 +386,14 @@ export class BaseGraphManager {
|
|
|
226
386
|
async delete(entityType, entityId, commitMessage) {
|
|
227
387
|
// Verify entity exists
|
|
228
388
|
const existing = this.get(entityType, entityId);
|
|
229
|
-
// Delete the
|
|
230
|
-
const {
|
|
231
|
-
|
|
389
|
+
// Delete the entity directory (derive from resolved path, not hardcoded layout)
|
|
390
|
+
const { rmSync } = await import('fs');
|
|
391
|
+
const entityDir = existing.path.endsWith('.md') && !existing.path.endsWith(`${entityId}.md`)
|
|
392
|
+
? dirname(existing.path) // folder-mode: main.md → parent dir
|
|
393
|
+
: existing.path.endsWith(`${entityId}.md`)
|
|
394
|
+
? existing.path // collection-mode: delete the single file
|
|
395
|
+
: join(this.repoPath, entityId);
|
|
396
|
+
rmSync(entityDir, { recursive: true, force: true });
|
|
232
397
|
if (this.gitService) {
|
|
233
398
|
const transaction = this.gitService.createTransaction();
|
|
234
399
|
transaction.add({
|
|
@@ -247,73 +412,145 @@ export class BaseGraphManager {
|
|
|
247
412
|
* List entities of a given type
|
|
248
413
|
*/
|
|
249
414
|
list(entityType, limit) {
|
|
415
|
+
if (!existsSync(this.repoPath))
|
|
416
|
+
return [];
|
|
250
417
|
const results = [];
|
|
251
|
-
//
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
return
|
|
418
|
+
// Lenient validation for list(): try strict schema first, fall back to
|
|
419
|
+
// EntityBaseSchema, then raw data so app-defined types are still discovered.
|
|
420
|
+
const validateLenient = (type, data) => {
|
|
421
|
+
try {
|
|
422
|
+
return this.validateEntity(type, data);
|
|
256
423
|
}
|
|
257
|
-
|
|
258
|
-
.filter(f => f.endsWith('.md'))
|
|
259
|
-
.map(f => {
|
|
260
|
-
const entityId = basename(f, '.md');
|
|
424
|
+
catch {
|
|
261
425
|
try {
|
|
262
|
-
return this.
|
|
426
|
+
return this.validateEntity(type, { ...data, entity_type: type }, true);
|
|
263
427
|
}
|
|
264
428
|
catch {
|
|
265
|
-
return
|
|
429
|
+
return data;
|
|
266
430
|
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
const seenIds = new Set();
|
|
434
|
+
// Helper to process a directory entry as a potential entity
|
|
435
|
+
const tryAddEntity = (dirPath, entry) => {
|
|
436
|
+
const mainPath = join(dirPath, entry, 'main.md');
|
|
437
|
+
if (!existsSync(mainPath))
|
|
438
|
+
return;
|
|
439
|
+
if (seenIds.has(entry))
|
|
440
|
+
return;
|
|
441
|
+
try {
|
|
442
|
+
const doc = this.markdownService.parseFile(mainPath);
|
|
443
|
+
const fmType = doc.frontmatter.entity_type;
|
|
444
|
+
const resolvedType = entityType ?? fmType ?? this.repoName;
|
|
445
|
+
if (entityType && fmType && fmType !== entityType)
|
|
446
|
+
return;
|
|
447
|
+
const validatedData = validateLenient(resolvedType, doc.frontmatter);
|
|
448
|
+
// Count all sub-content files recursively (excluding main.md and dotfiles)
|
|
449
|
+
const entityDir = join(dirPath, entry);
|
|
450
|
+
const countFiles = (dir) => {
|
|
451
|
+
let n = 0;
|
|
452
|
+
for (const f of readdirSync(dir)) {
|
|
453
|
+
if (f.startsWith('.'))
|
|
454
|
+
continue;
|
|
455
|
+
if (dir === entityDir && f === 'main.md')
|
|
456
|
+
continue;
|
|
457
|
+
const full = join(dir, f);
|
|
458
|
+
try {
|
|
459
|
+
if (statSync(full).isDirectory())
|
|
460
|
+
n += countFiles(full);
|
|
461
|
+
else
|
|
462
|
+
n++;
|
|
463
|
+
}
|
|
464
|
+
catch { /* skip */ }
|
|
289
465
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
466
|
+
return n;
|
|
467
|
+
};
|
|
468
|
+
const fileCount = countFiles(entityDir);
|
|
469
|
+
seenIds.add(entry);
|
|
470
|
+
results.push({
|
|
471
|
+
id: entry,
|
|
472
|
+
path: mainPath,
|
|
473
|
+
entityType: resolvedType,
|
|
474
|
+
data: validatedData,
|
|
475
|
+
document: doc,
|
|
476
|
+
hasSubContent: fileCount > 0,
|
|
477
|
+
subContentCount: fileCount,
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
catch { /* skip invalid */ }
|
|
481
|
+
};
|
|
482
|
+
for (const entry of readdirSync(this.repoPath)) {
|
|
483
|
+
if (entry.startsWith('.'))
|
|
484
|
+
continue;
|
|
485
|
+
const fullPath = join(this.repoPath, entry);
|
|
486
|
+
try {
|
|
487
|
+
if (!statSync(fullPath).isDirectory())
|
|
296
488
|
continue;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
489
|
+
}
|
|
490
|
+
catch {
|
|
491
|
+
continue;
|
|
492
|
+
}
|
|
493
|
+
const mainPath = join(fullPath, 'main.md');
|
|
494
|
+
if (existsSync(mainPath)) {
|
|
495
|
+
// Direct entity folder (e.g. projects/acme-corp/main.md)
|
|
496
|
+
tryAddEntity(this.repoPath, entry);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
// Subfolder containing entities (e.g. projects/deck/ containing sample-deck/main.md)
|
|
500
|
+
try {
|
|
501
|
+
for (const sub of readdirSync(fullPath)) {
|
|
502
|
+
if (sub.startsWith('.'))
|
|
503
|
+
continue;
|
|
504
|
+
try {
|
|
505
|
+
if (!statSync(join(fullPath, sub)).isDirectory())
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
catch {
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
tryAddEntity(fullPath, sub);
|
|
307
512
|
}
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
results.push(...files);
|
|
513
|
+
}
|
|
514
|
+
catch { /* skip unreadable */ }
|
|
311
515
|
}
|
|
312
516
|
}
|
|
313
|
-
//
|
|
314
|
-
|
|
315
|
-
|
|
517
|
+
// Also discover collection-mode entities (flat .md files at repo root)
|
|
518
|
+
for (const entry of readdirSync(this.repoPath)) {
|
|
519
|
+
if (entry.startsWith('.'))
|
|
520
|
+
continue;
|
|
521
|
+
if (!entry.endsWith('.md'))
|
|
522
|
+
continue;
|
|
523
|
+
const fullPath = join(this.repoPath, entry);
|
|
524
|
+
try {
|
|
525
|
+
if (!statSync(fullPath).isFile())
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
continue;
|
|
530
|
+
}
|
|
531
|
+
const id = entry.replace(/\.md$/, '');
|
|
532
|
+
if (seenIds.has(id))
|
|
533
|
+
continue; // folder-mode entity takes precedence
|
|
534
|
+
try {
|
|
535
|
+
const doc = this.markdownService.parseFile(fullPath);
|
|
536
|
+
const fmType = doc.frontmatter.entity_type;
|
|
537
|
+
const resolvedType = entityType ?? fmType ?? this.repoName;
|
|
538
|
+
if (entityType && fmType && fmType !== entityType)
|
|
539
|
+
continue;
|
|
540
|
+
const validatedData = validateLenient(resolvedType, doc.frontmatter);
|
|
541
|
+
seenIds.add(id);
|
|
542
|
+
results.push({
|
|
543
|
+
id,
|
|
544
|
+
path: fullPath,
|
|
545
|
+
entityType: resolvedType,
|
|
546
|
+
data: validatedData,
|
|
547
|
+
document: doc,
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
catch { /* skip invalid */ }
|
|
316
551
|
}
|
|
552
|
+
if (limit && limit > 0)
|
|
553
|
+
return results.slice(0, limit);
|
|
317
554
|
return results;
|
|
318
555
|
}
|
|
319
556
|
/**
|
|
@@ -435,10 +672,11 @@ export class BaseGraphManager {
|
|
|
435
672
|
// Determine entity type from path
|
|
436
673
|
const relPath = found.replace(this.repoPath + '/', '');
|
|
437
674
|
const parts = relPath.split('/');
|
|
438
|
-
if (parts.length >= 2) {
|
|
439
|
-
const
|
|
440
|
-
const linkedId = basename(parts[1], '.md');
|
|
675
|
+
if (parts.length >= 2 && parts[parts.length - 1] === 'main.md') {
|
|
676
|
+
const linkedId = parts[0];
|
|
441
677
|
try {
|
|
678
|
+
const doc = this.markdownService.parseFile(found);
|
|
679
|
+
const linkedType = doc.frontmatter.entity_type ?? this.repoName;
|
|
442
680
|
const linkedEntity = this.get(linkedType, linkedId);
|
|
443
681
|
related.push(linkedEntity);
|
|
444
682
|
}
|
|
@@ -460,10 +698,11 @@ export class BaseGraphManager {
|
|
|
460
698
|
// Determine entity type from path
|
|
461
699
|
const relPath = file.replace(this.repoPath + '/', '');
|
|
462
700
|
const parts = relPath.split('/');
|
|
463
|
-
if (parts.length >= 2) {
|
|
464
|
-
const
|
|
465
|
-
const linkedId = basename(parts[1], '.md');
|
|
701
|
+
if (parts.length >= 2 && parts[parts.length - 1] === 'main.md') {
|
|
702
|
+
const linkedId = parts[0];
|
|
466
703
|
try {
|
|
704
|
+
const doc = this.markdownService.parseFile(file);
|
|
705
|
+
const linkedType = doc.frontmatter.entity_type ?? this.repoName;
|
|
467
706
|
const linkedEntity = this.get(linkedType, linkedId);
|
|
468
707
|
results.push(linkedEntity);
|
|
469
708
|
}
|
|
@@ -494,11 +733,12 @@ export class BaseGraphManager {
|
|
|
494
733
|
this.markdownService.updateWikilinks(file, oldId, newId);
|
|
495
734
|
const relPath = file.replace(this.repoPath + '/', '');
|
|
496
735
|
const parts = relPath.split('/');
|
|
497
|
-
if (parts.length >= 2) {
|
|
736
|
+
if (parts.length >= 2 && parts[parts.length - 1] === 'main.md') {
|
|
737
|
+
const doc = this.markdownService.parseFile(file);
|
|
498
738
|
transaction.add({
|
|
499
739
|
operation: 'update',
|
|
500
|
-
entityType: parts[0],
|
|
501
|
-
entityId:
|
|
740
|
+
entityType: doc.frontmatter.entity_type ?? parts[0],
|
|
741
|
+
entityId: parts[0],
|
|
502
742
|
filePath: file,
|
|
503
743
|
});
|
|
504
744
|
}
|
|
@@ -516,38 +756,38 @@ export class BaseGraphManager {
|
|
|
516
756
|
/**
|
|
517
757
|
* Upload asset for an entity
|
|
518
758
|
*/
|
|
519
|
-
async uploadAsset(
|
|
759
|
+
async uploadAsset(entityType, entityId, filename, buffer, keyPrefix) {
|
|
520
760
|
if (!this.assetService) {
|
|
521
761
|
throw new Error('Asset service is not configured for this graph');
|
|
522
762
|
}
|
|
523
|
-
return await this.assetService.upload(
|
|
763
|
+
return await this.assetService.upload(entityType, entityId, filename, buffer, keyPrefix);
|
|
524
764
|
}
|
|
525
765
|
/**
|
|
526
766
|
* List assets for an entity
|
|
527
767
|
*/
|
|
528
|
-
async listAssets(
|
|
768
|
+
async listAssets(entityType, entityId, keyPrefix) {
|
|
529
769
|
if (!this.assetService) {
|
|
530
770
|
throw new Error('Asset service is not configured for this graph');
|
|
531
771
|
}
|
|
532
|
-
return await this.assetService.list(
|
|
772
|
+
return await this.assetService.list(entityType, entityId, keyPrefix);
|
|
533
773
|
}
|
|
534
774
|
/**
|
|
535
775
|
* Delete an asset
|
|
536
776
|
*/
|
|
537
|
-
async deleteAsset(
|
|
777
|
+
async deleteAsset(entityType, entityId, filename, keyPrefix) {
|
|
538
778
|
if (!this.assetService) {
|
|
539
779
|
throw new Error('Asset service is not configured for this graph');
|
|
540
780
|
}
|
|
541
|
-
return await this.assetService.delete(
|
|
781
|
+
return await this.assetService.delete(entityType, entityId, filename, keyPrefix);
|
|
542
782
|
}
|
|
543
783
|
/**
|
|
544
784
|
* Delete all assets for an entity (when entity is deleted)
|
|
545
785
|
*/
|
|
546
|
-
async deleteAllAssets(
|
|
786
|
+
async deleteAllAssets(entityType, entityId, keyPrefix) {
|
|
547
787
|
if (!this.assetService) {
|
|
548
788
|
throw new Error('Asset service is not configured for this graph');
|
|
549
789
|
}
|
|
550
|
-
return await this.assetService.deleteAll(
|
|
790
|
+
return await this.assetService.deleteAll(entityType, entityId, keyPrefix);
|
|
551
791
|
}
|
|
552
792
|
/**
|
|
553
793
|
* Get dataset rows, optionally filtered
|
|
@@ -587,7 +827,7 @@ export class BaseGraphManager {
|
|
|
587
827
|
// Stringify back to CSV
|
|
588
828
|
const newContent = this.csvService.stringifyRows(allRows, schema);
|
|
589
829
|
// Update the entity file (update content, bump updated_at)
|
|
590
|
-
const entityPath = this.
|
|
830
|
+
const entityPath = this.getEntityPath('dataset', entityId);
|
|
591
831
|
const updatedData = {
|
|
592
832
|
...entity.data,
|
|
593
833
|
updated_at: new Date().toISOString(),
|