studiograph 1.3.47 → 1.3.48-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -16
- package/dist/agent/agent-pool.d.ts +117 -0
- package/dist/agent/agent-pool.js +287 -0
- package/dist/agent/agent-pool.js.map +1 -0
- package/dist/agent/followups.d.ts +34 -0
- package/dist/agent/followups.js +52 -0
- package/dist/agent/followups.js.map +1 -0
- package/dist/agent/orchestrator.d.ts +113 -22
- package/dist/agent/orchestrator.js +573 -181
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/prompts/entity-types-section.d.ts +36 -0
- package/dist/agent/prompts/entity-types-section.js +90 -0
- package/dist/agent/prompts/entity-types-section.js.map +1 -0
- package/dist/agent/prompts/system.md +148 -69
- package/dist/agent/skill-loader.d.ts +30 -17
- package/dist/agent/skill-loader.js +63 -30
- package/dist/agent/skill-loader.js.map +1 -1
- package/dist/agent/skills/entity-schema.md +77 -433
- package/dist/agent/skills/interview/entity-templates.md +193 -0
- package/dist/agent/skills/interview/question-domains.md +391 -0
- package/dist/agent/skills/interview/skill.md +204 -0
- package/dist/agent/skills/schema-rules.md +54 -0
- package/dist/agent/tools/capture-tools.d.ts +31 -0
- package/dist/agent/tools/capture-tools.js +40 -0
- package/dist/agent/tools/capture-tools.js.map +1 -0
- package/dist/agent/tools/folder-tools.d.ts +47 -0
- package/dist/agent/tools/folder-tools.js +249 -0
- package/dist/agent/tools/folder-tools.js.map +1 -0
- package/dist/agent/tools/fs-tools.d.ts +7 -6
- package/dist/agent/tools/fs-tools.js +5 -4
- package/dist/agent/tools/fs-tools.js.map +1 -1
- package/dist/agent/tools/graph-tools.d.ts +21 -58
- package/dist/agent/tools/graph-tools.js +635 -332
- package/dist/agent/tools/graph-tools.js.map +1 -1
- package/dist/agent/tools/history-tools.d.ts +95 -0
- package/dist/agent/tools/history-tools.js +461 -0
- package/dist/agent/tools/history-tools.js.map +1 -0
- package/dist/agent/tools/load-skill.d.ts +6 -5
- package/dist/agent/tools/load-skill.js +3 -3
- package/dist/agent/tools/load-skill.js.map +1 -1
- package/dist/agent/tools/ops-tools.d.ts +5 -4
- package/dist/agent/tools/ops-tools.js +130 -236
- package/dist/agent/tools/ops-tools.js.map +1 -1
- package/dist/agent/tools/permission-tools.d.ts +87 -17
- package/dist/agent/tools/permission-tools.js +233 -38
- package/dist/agent/tools/permission-tools.js.map +1 -1
- package/dist/agent/tools/tool-loader.js +5 -4
- package/dist/agent/tools/tool-loader.js.map +1 -1
- package/dist/agent/tools/web-tools.d.ts +18 -0
- package/dist/agent/tools/web-tools.js +283 -0
- package/dist/agent/tools/web-tools.js.map +1 -0
- package/dist/cli/commands/about.d.ts +1 -0
- package/dist/cli/commands/about.js +55 -3
- package/dist/cli/commands/about.js.map +1 -1
- package/dist/cli/commands/admin/audit-workspace.d.ts +23 -0
- package/dist/cli/commands/admin/audit-workspace.js +133 -0
- package/dist/cli/commands/admin/audit-workspace.js.map +1 -0
- package/dist/cli/commands/admin/audit.d.ts +21 -0
- package/dist/cli/commands/admin/audit.js +174 -0
- package/dist/cli/commands/admin/audit.js.map +1 -0
- package/dist/cli/commands/admin/backup.d.ts +54 -0
- package/dist/cli/commands/admin/backup.js +207 -0
- package/dist/cli/commands/admin/backup.js.map +1 -0
- package/dist/cli/commands/admin/folder.d.ts +11 -0
- package/dist/cli/commands/admin/folder.js +186 -0
- package/dist/cli/commands/admin/folder.js.map +1 -0
- package/dist/cli/commands/admin/index.d.ts +16 -0
- package/dist/cli/commands/admin/index.js +46 -0
- package/dist/cli/commands/admin/index.js.map +1 -0
- package/dist/cli/commands/admin/migrate-assets.d.ts +53 -0
- package/dist/cli/commands/admin/migrate-assets.js +184 -0
- package/dist/cli/commands/admin/migrate-assets.js.map +1 -0
- package/dist/cli/commands/admin/migrate.d.ts +56 -0
- package/dist/cli/commands/admin/migrate.js +263 -0
- package/dist/cli/commands/admin/migrate.js.map +1 -0
- package/dist/cli/commands/admin/restore.d.ts +24 -0
- package/dist/cli/commands/admin/restore.js +228 -0
- package/dist/cli/commands/admin/restore.js.map +1 -0
- package/dist/cli/commands/admin/secrets.d.ts +23 -0
- package/dist/cli/commands/admin/secrets.js +256 -0
- package/dist/cli/commands/admin/secrets.js.map +1 -0
- package/dist/cli/commands/admin/settings.d.ts +28 -0
- package/dist/cli/commands/admin/settings.js +284 -0
- package/dist/cli/commands/admin/settings.js.map +1 -0
- package/dist/cli/commands/admin/token.d.ts +42 -0
- package/dist/cli/commands/admin/token.js +126 -0
- package/dist/cli/commands/admin/token.js.map +1 -0
- package/dist/cli/commands/admin/transfer-ownership.d.ts +15 -0
- package/dist/cli/commands/admin/transfer-ownership.js +106 -0
- package/dist/cli/commands/admin/transfer-ownership.js.map +1 -0
- package/dist/cli/commands/admin/user.d.ts +11 -0
- package/dist/cli/commands/admin/user.js +187 -0
- package/dist/cli/commands/admin/user.js.map +1 -0
- package/dist/cli/commands/clone.d.ts +25 -3
- package/dist/cli/commands/clone.js +142 -36
- package/dist/cli/commands/clone.js.map +1 -1
- package/dist/cli/commands/commit.d.ts +1 -1
- package/dist/cli/commands/commit.js +24 -11
- package/dist/cli/commands/commit.js.map +1 -1
- package/dist/cli/commands/config.d.ts +23 -107
- package/dist/cli/commands/config.js +52 -260
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/connector.d.ts +10 -13
- package/dist/cli/commands/connector.js +16 -58
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/deploy.js +215 -68
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/index.js +2 -2
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.js +10 -30
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/mcp.js +12 -4
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/orphans.js +14 -30
- package/dist/cli/commands/orphans.js.map +1 -1
- package/dist/cli/commands/r2.d.ts +3 -0
- package/dist/cli/commands/r2.js +223 -204
- package/dist/cli/commands/r2.js.map +1 -1
- package/dist/cli/commands/redeploy.js +65 -12
- package/dist/cli/commands/redeploy.js.map +1 -1
- package/dist/cli/commands/reset.d.ts +22 -6
- package/dist/cli/commands/reset.js +142 -63
- package/dist/cli/commands/reset.js.map +1 -1
- package/dist/cli/commands/serve.js +209 -24
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/sync.d.ts +1 -1
- package/dist/cli/commands/sync.js +372 -202
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/crypto-bundle.d.ts +39 -0
- package/dist/cli/crypto-bundle.js +94 -0
- package/dist/cli/crypto-bundle.js.map +1 -0
- package/dist/cli/index.js +24 -35
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/railway-pin.d.ts +68 -0
- package/dist/cli/railway-pin.js +96 -0
- package/dist/cli/railway-pin.js.map +1 -0
- package/dist/cli/railway-provisioning.d.ts +53 -0
- package/dist/cli/railway-provisioning.js +85 -0
- package/dist/cli/railway-provisioning.js.map +1 -0
- package/dist/cli/setup-wizard.d.ts +33 -52
- package/dist/cli/setup-wizard.js +43 -68
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/core/accent-palette.d.ts +22 -0
- package/dist/core/accent-palette.js +47 -0
- package/dist/core/accent-palette.js.map +1 -0
- package/dist/core/cell-anchor.d.ts +29 -0
- package/dist/core/cell-anchor.js +53 -0
- package/dist/core/cell-anchor.js.map +1 -0
- package/dist/core/comment-anchor.d.ts +41 -0
- package/dist/core/comment-anchor.js +147 -0
- package/dist/core/comment-anchor.js.map +1 -0
- package/dist/core/commit-messages.d.ts +57 -0
- package/dist/core/commit-messages.js +85 -0
- package/dist/core/commit-messages.js.map +1 -0
- package/dist/core/embeds.d.ts +56 -0
- package/dist/core/embeds.js +103 -0
- package/dist/core/embeds.js.map +1 -0
- package/dist/core/entity-body-templates.d.ts +21 -0
- package/dist/core/entity-body-templates.js +53 -0
- package/dist/core/entity-body-templates.js.map +1 -0
- package/dist/core/entity-types-catalog.d.ts +65 -0
- package/dist/core/entity-types-catalog.js +140 -0
- package/dist/core/entity-types-catalog.js.map +1 -0
- package/dist/core/folder-paths.d.ts +41 -0
- package/dist/core/folder-paths.js +95 -0
- package/dist/core/folder-paths.js.map +1 -0
- package/dist/core/folder-sidecar.d.ts +36 -0
- package/dist/core/folder-sidecar.js +91 -0
- package/dist/core/folder-sidecar.js.map +1 -0
- package/dist/core/graph.d.ts +675 -14
- package/dist/core/graph.js +2118 -314
- package/dist/core/graph.js.map +1 -1
- package/dist/core/history-diff.d.ts +35 -0
- package/dist/core/history-diff.js +114 -0
- package/dist/core/history-diff.js.map +1 -0
- package/dist/core/schema-registry.d.ts +59 -0
- package/dist/core/schema-registry.js +198 -0
- package/dist/core/schema-registry.js.map +1 -1
- package/dist/core/schemas/connector.d.ts +67 -0
- package/dist/core/schemas/connector.js +100 -0
- package/dist/core/schemas/connector.js.map +1 -0
- package/dist/core/schemas/workspace.d.ts +122 -0
- package/dist/core/schemas/workspace.js +211 -0
- package/dist/core/schemas/workspace.js.map +1 -0
- package/dist/core/secrets/SecretStore.d.ts +77 -0
- package/dist/core/secrets/SecretStore.js +13 -0
- package/dist/core/secrets/SecretStore.js.map +1 -0
- package/dist/core/secrets/SettingsResolver.d.ts +54 -0
- package/dist/core/secrets/SettingsResolver.js +80 -0
- package/dist/core/secrets/SettingsResolver.js.map +1 -0
- package/dist/core/secrets/SettingsStore.d.ts +30 -0
- package/dist/core/secrets/SettingsStore.js +9 -0
- package/dist/core/secrets/SettingsStore.js.map +1 -0
- package/dist/core/secrets/SqliteEncryptedStore.d.ts +90 -0
- package/dist/core/secrets/SqliteEncryptedStore.js +598 -0
- package/dist/core/secrets/SqliteEncryptedStore.js.map +1 -0
- package/dist/core/secrets/audit.d.ts +36 -0
- package/dist/core/secrets/audit.js +60 -0
- package/dist/core/secrets/audit.js.map +1 -0
- package/dist/core/secrets/auth-db-migration.d.ts +129 -0
- package/dist/core/secrets/auth-db-migration.js +653 -0
- package/dist/core/secrets/auth-db-migration.js.map +1 -0
- package/dist/core/secrets/bundle.d.ts +141 -0
- package/dist/core/secrets/bundle.js +435 -0
- package/dist/core/secrets/bundle.js.map +1 -0
- package/dist/core/secrets/dual-write.d.ts +81 -0
- package/dist/core/secrets/dual-write.js +247 -0
- package/dist/core/secrets/dual-write.js.map +1 -0
- package/dist/core/secrets/encryption.d.ts +44 -0
- package/dist/core/secrets/encryption.js +97 -0
- package/dist/core/secrets/encryption.js.map +1 -0
- package/dist/core/secrets/index.d.ts +49 -0
- package/dist/core/secrets/index.js +74 -0
- package/dist/core/secrets/index.js.map +1 -0
- package/dist/core/secrets/master-key.d.ts +38 -0
- package/dist/core/secrets/master-key.js +122 -0
- package/dist/core/secrets/master-key.js.map +1 -0
- package/dist/core/secrets/probes/anthropic.d.ts +98 -0
- package/dist/core/secrets/probes/anthropic.js +300 -0
- package/dist/core/secrets/probes/anthropic.js.map +1 -0
- package/dist/core/secrets/probes/brave.d.ts +9 -0
- package/dist/core/secrets/probes/brave.js +15 -0
- package/dist/core/secrets/probes/brave.js.map +1 -0
- package/dist/core/secrets/probes/r2.d.ts +15 -0
- package/dist/core/secrets/probes/r2.js +14 -0
- package/dist/core/secrets/probes/r2.js.map +1 -0
- package/dist/core/secrets/probes/voyage.d.ts +13 -0
- package/dist/core/secrets/probes/voyage.js +52 -0
- package/dist/core/secrets/probes/voyage.js.map +1 -0
- package/dist/core/secrets/r2-structural-migration.d.ts +39 -0
- package/dist/core/secrets/r2-structural-migration.js +109 -0
- package/dist/core/secrets/r2-structural-migration.js.map +1 -0
- package/dist/core/secrets/read-flip.d.ts +59 -0
- package/dist/core/secrets/read-flip.js +87 -0
- package/dist/core/secrets/read-flip.js.map +1 -0
- package/dist/core/secrets/registry.d.ts +188 -0
- package/dist/core/secrets/registry.js +598 -0
- package/dist/core/secrets/registry.js.map +1 -0
- package/dist/core/types.d.ts +77 -455
- package/dist/core/types.js +17 -3
- package/dist/core/types.js.map +1 -1
- package/dist/core/user-config.d.ts +75 -7
- package/dist/core/user-config.js +155 -7
- package/dist/core/user-config.js.map +1 -1
- package/dist/core/validation.d.ts +717 -1791
- package/dist/core/validation.js +357 -228
- package/dist/core/validation.js.map +1 -1
- package/dist/core/workspace-manager.d.ts +79 -12
- package/dist/core/workspace-manager.js +213 -73
- package/dist/core/workspace-manager.js.map +1 -1
- package/dist/core/workspace.d.ts +19 -5
- package/dist/core/workspace.js +69 -35
- package/dist/core/workspace.js.map +1 -1
- package/dist/mcp/comment-virtual-entity.d.ts +36 -0
- package/dist/mcp/comment-virtual-entity.js +71 -0
- package/dist/mcp/comment-virtual-entity.js.map +1 -0
- package/dist/mcp/connector-manager.d.ts +94 -13
- package/dist/mcp/connector-manager.js +283 -62
- package/dist/mcp/connector-manager.js.map +1 -1
- package/dist/mcp/oauth-provider.d.ts +27 -33
- package/dist/mcp/oauth-provider.js +65 -134
- package/dist/mcp/oauth-provider.js.map +1 -1
- package/dist/mcp/oauth-registry.d.ts +62 -0
- package/dist/mcp/oauth-registry.js +85 -0
- package/dist/mcp/oauth-registry.js.map +1 -0
- package/dist/mcp/server.d.ts +11 -3
- package/dist/mcp/server.js +30 -5
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/state-signer.d.ts +41 -0
- package/dist/mcp/state-signer.js +120 -0
- package/dist/mcp/state-signer.js.map +1 -0
- package/dist/mcp/tools.d.ts +35 -2
- package/dist/mcp/tools.js +1051 -117
- package/dist/mcp/tools.js.map +1 -1
- package/dist/server/__tests__/helpers/graph-api.d.ts +18 -0
- package/dist/server/__tests__/helpers/graph-api.js +16 -0
- package/dist/server/__tests__/helpers/graph-api.js.map +1 -0
- package/dist/server/body-write-coordinator.d.ts +151 -0
- package/dist/server/body-write-coordinator.js +161 -0
- package/dist/server/body-write-coordinator.js.map +1 -0
- package/dist/server/cloud-billing-flow.d.ts +32 -0
- package/dist/server/cloud-billing-flow.js +75 -0
- package/dist/server/cloud-billing-flow.js.map +1 -0
- package/dist/server/commit-audit.d.ts +26 -0
- package/dist/server/commit-audit.js +30 -0
- package/dist/server/commit-audit.js.map +1 -0
- package/dist/server/index.d.ts +14 -3
- package/dist/server/index.js +451 -193
- package/dist/server/index.js.map +1 -1
- package/dist/server/middleware/sanitize.d.ts +46 -0
- package/dist/server/middleware/sanitize.js +171 -0
- package/dist/server/middleware/sanitize.js.map +1 -0
- package/dist/server/routes/asset-api.d.ts +10 -0
- package/dist/server/routes/asset-api.js +294 -0
- package/dist/server/routes/asset-api.js.map +1 -0
- package/dist/server/routes/audit-api.d.ts +24 -0
- package/dist/server/routes/audit-api.js +117 -0
- package/dist/server/routes/audit-api.js.map +1 -0
- package/dist/server/routes/auth-api.d.ts +3 -2
- package/dist/server/routes/auth-api.js +519 -38
- package/dist/server/routes/auth-api.js.map +1 -1
- package/dist/server/routes/capture-api.d.ts +18 -0
- package/dist/server/routes/capture-api.js +257 -0
- package/dist/server/routes/capture-api.js.map +1 -0
- package/dist/server/routes/chat.d.ts +4 -1
- package/dist/server/routes/chat.js +298 -88
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/comments-api.d.ts +15 -0
- package/dist/server/routes/comments-api.js +444 -0
- package/dist/server/routes/comments-api.js.map +1 -0
- package/dist/server/routes/config-api.d.ts +21 -0
- package/dist/server/routes/config-api.js +256 -0
- package/dist/server/routes/config-api.js.map +1 -0
- package/dist/server/routes/connectors-api.d.ts +17 -0
- package/dist/server/routes/connectors-api.js +410 -0
- package/dist/server/routes/connectors-api.js.map +1 -0
- package/dist/server/routes/event-ingest-api.d.ts +15 -0
- package/dist/server/routes/event-ingest-api.js +125 -0
- package/dist/server/routes/event-ingest-api.js.map +1 -0
- package/dist/server/routes/git-http.d.ts +3 -3
- package/dist/server/routes/git-http.js +86 -38
- package/dist/server/routes/git-http.js.map +1 -1
- package/dist/server/routes/graph-api-access.d.ts +35 -0
- package/dist/server/routes/graph-api-access.js +105 -0
- package/dist/server/routes/graph-api-access.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +3 -2
- package/dist/server/routes/graph-api.js +1321 -263
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/health.d.ts +18 -0
- package/dist/server/routes/health.js +74 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/insights-api.d.ts +1 -2
- package/dist/server/routes/insights-api.js +149 -41
- package/dist/server/routes/insights-api.js.map +1 -1
- package/dist/server/routes/mcp.d.ts +7 -3
- package/dist/server/routes/mcp.js +22 -6
- package/dist/server/routes/mcp.js.map +1 -1
- package/dist/server/routes/permissions-api.d.ts +9 -2
- package/dist/server/routes/permissions-api.js +87 -30
- package/dist/server/routes/permissions-api.js.map +1 -1
- package/dist/server/routes/r2-api.d.ts +25 -0
- package/dist/server/routes/r2-api.js +276 -0
- package/dist/server/routes/r2-api.js.map +1 -0
- package/dist/server/routes/secrets-api.d.ts +36 -0
- package/dist/server/routes/secrets-api.js +308 -0
- package/dist/server/routes/secrets-api.js.map +1 -0
- package/dist/server/routes/settings-api.d.ts +29 -0
- package/dist/server/routes/settings-api.js +180 -0
- package/dist/server/routes/settings-api.js.map +1 -0
- package/dist/server/routes/url-api.d.ts +7 -0
- package/dist/server/routes/url-api.js +74 -0
- package/dist/server/routes/url-api.js.map +1 -0
- package/dist/server/routes/views-api.js +81 -7
- package/dist/server/routes/views-api.js.map +1 -1
- package/dist/server/routes/workspace-api.d.ts +2 -1
- package/dist/server/routes/workspace-api.js +124 -35
- package/dist/server/routes/workspace-api.js.map +1 -1
- package/dist/server/routes/ws.d.ts +2 -1
- package/dist/server/routes/ws.js +64 -16
- package/dist/server/routes/ws.js.map +1 -1
- package/dist/server/session-manager.d.ts +48 -5
- package/dist/server/session-manager.js +182 -15
- package/dist/server/session-manager.js.map +1 -1
- package/dist/server/ws-hub.d.ts +138 -14
- package/dist/server/ws-hub.js +0 -0
- package/dist/server/ws-hub.js.map +1 -1
- package/dist/server/yjs-manager.d.ts +285 -7
- package/dist/server/yjs-manager.js +907 -36
- package/dist/server/yjs-manager.js.map +1 -1
- package/dist/server/yjs-persistence.d.ts +165 -0
- package/dist/server/yjs-persistence.js +557 -0
- package/dist/server/yjs-persistence.js.map +1 -0
- package/dist/server/yjs-text-diff.d.ts +32 -0
- package/dist/server/yjs-text-diff.js +61 -0
- package/dist/server/yjs-text-diff.js.map +1 -0
- package/dist/services/access-control.d.ts +73 -0
- package/dist/services/access-control.js +146 -0
- package/dist/services/access-control.js.map +1 -0
- package/dist/services/asset-listing.d.ts +39 -0
- package/dist/services/asset-listing.js +125 -0
- package/dist/services/asset-listing.js.map +1 -0
- package/dist/services/asset-upload-service.d.ts +53 -0
- package/dist/services/asset-upload-service.js +201 -0
- package/dist/services/asset-upload-service.js.map +1 -0
- package/dist/services/assets/asset-index-service.d.ts +82 -0
- package/dist/services/assets/asset-index-service.js +167 -0
- package/dist/services/assets/asset-index-service.js.map +1 -0
- package/dist/services/assets/base.d.ts +44 -0
- package/dist/services/assets/base.js +55 -0
- package/dist/services/assets/base.js.map +1 -1
- package/dist/services/assets/index.d.ts +69 -1
- package/dist/services/assets/index.js +125 -0
- package/dist/services/assets/index.js.map +1 -1
- package/dist/services/assets/local.d.ts +12 -1
- package/dist/services/assets/local.js +100 -1
- package/dist/services/assets/local.js.map +1 -1
- package/dist/services/assets/r2-sync.d.ts +88 -0
- package/dist/services/assets/r2-sync.js +412 -0
- package/dist/services/assets/r2-sync.js.map +1 -0
- package/dist/services/assets/r2.d.ts +34 -1
- package/dist/services/assets/r2.js +93 -1
- package/dist/services/assets/r2.js.map +1 -1
- package/dist/services/auth-service.d.ts +314 -36
- package/dist/services/auth-service.js +1126 -139
- package/dist/services/auth-service.js.map +1 -1
- package/dist/services/bookmark-import-service.d.ts +49 -0
- package/dist/services/bookmark-import-service.js +250 -0
- package/dist/services/bookmark-import-service.js.map +1 -0
- package/dist/services/cloud-inference-billing.d.ts +64 -0
- package/dist/services/cloud-inference-billing.js +313 -0
- package/dist/services/cloud-inference-billing.js.map +1 -0
- package/dist/services/comment-service.d.ts +97 -0
- package/dist/services/comment-service.js +341 -0
- package/dist/services/comment-service.js.map +1 -0
- package/dist/services/csv-service.d.ts +22 -17
- package/dist/services/csv-service.js +55 -92
- package/dist/services/csv-service.js.map +1 -1
- package/dist/services/entity-mutations.d.ts +161 -0
- package/dist/services/entity-mutations.js +296 -0
- package/dist/services/entity-mutations.js.map +1 -0
- package/dist/services/event-processor.d.ts +104 -0
- package/dist/services/event-processor.js +441 -0
- package/dist/services/event-processor.js.map +1 -0
- package/dist/services/folder-creation.d.ts +33 -0
- package/dist/services/folder-creation.js +103 -0
- package/dist/services/folder-creation.js.map +1 -0
- package/dist/services/git.d.ts +54 -0
- package/dist/services/git.js +188 -54
- package/dist/services/git.js.map +1 -1
- package/dist/services/graph-maintenance.d.ts +42 -0
- package/dist/services/graph-maintenance.js +143 -0
- package/dist/services/graph-maintenance.js.map +1 -0
- package/dist/services/import-service.d.ts +45 -2
- package/dist/services/import-service.js +304 -100
- package/dist/services/import-service.js.map +1 -1
- package/dist/services/lint-service.js +9 -16
- package/dist/services/lint-service.js.map +1 -1
- package/dist/services/markdown.d.ts +12 -1
- package/dist/services/markdown.js +71 -6
- package/dist/services/markdown.js.map +1 -1
- package/dist/services/memory-service.d.ts +22 -14
- package/dist/services/memory-service.js +53 -35
- package/dist/services/memory-service.js.map +1 -1
- package/dist/services/mention-detector.d.ts +23 -0
- package/dist/services/mention-detector.js +47 -0
- package/dist/services/mention-detector.js.map +1 -0
- package/dist/services/notification-broadcast.d.ts +32 -0
- package/dist/services/notification-broadcast.js +38 -0
- package/dist/services/notification-broadcast.js.map +1 -0
- package/dist/services/notification-service.d.ts +41 -0
- package/dist/services/notification-service.js +100 -0
- package/dist/services/notification-service.js.map +1 -0
- package/dist/services/personal-folder.d.ts +40 -0
- package/dist/services/personal-folder.js +101 -0
- package/dist/services/personal-folder.js.map +1 -0
- package/dist/services/user-person-bridge.d.ts +118 -0
- package/dist/services/user-person-bridge.js +306 -0
- package/dist/services/user-person-bridge.js.map +1 -0
- package/dist/services/vector-service.d.ts +146 -6
- package/dist/services/vector-service.js +276 -13
- package/dist/services/vector-service.js.map +1 -1
- package/dist/services/workspace-access.d.ts +106 -0
- package/dist/services/workspace-access.js +149 -0
- package/dist/services/workspace-access.js.map +1 -0
- package/dist/utils/git.d.ts +17 -2
- package/dist/utils/git.js +23 -7
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/log.d.ts +42 -0
- package/dist/utils/log.js +137 -0
- package/dist/utils/log.js.map +1 -0
- package/dist/utils/preflight.js +2 -2
- package/dist/utils/preflight.js.map +1 -1
- package/dist/utils/version-checker.d.ts +12 -19
- package/dist/utils/version-checker.js +14 -104
- package/dist/utils/version-checker.js.map +1 -1
- package/dist/web/_app/immutable/assets/0.DDqq11xY.css +2 -0
- package/dist/web/_app/immutable/assets/12.DlIf1mKh.css +1 -0
- package/dist/web/_app/immutable/assets/13.7d-Q37wc.css +1 -0
- package/dist/web/_app/immutable/assets/14.CmLrbzZp.css +1 -0
- package/dist/web/_app/immutable/assets/2.CGK2ky-K.css +1 -0
- package/dist/web/_app/immutable/assets/3.CV0abekd.css +1 -0
- package/dist/web/_app/immutable/assets/4.fGsEpo95.css +1 -0
- package/dist/web/_app/immutable/assets/AgentOverlay.DqzjAOm4.css +1 -0
- package/dist/web/_app/immutable/assets/AssetManagerModal.BKJfPAPk.css +1 -0
- package/dist/web/_app/immutable/assets/CalendarView.bNewSxkH.css +1 -0
- package/dist/web/_app/immutable/assets/FolderMembersPanel.DX1oBeF_.css +1 -0
- package/dist/web/_app/immutable/assets/FolderMutationDialogs.BMRF6Z3z.css +1 -0
- package/dist/web/_app/immutable/assets/FolderPicker.B5KdvRYl.css +1 -0
- package/dist/web/_app/immutable/assets/GalleryView.DgvSjS0I.css +1 -0
- package/dist/web/_app/immutable/assets/GraphView.BJtGL9py.css +1 -0
- package/dist/web/_app/immutable/assets/KanbanView.D0QbZFd6.css +1 -0
- package/dist/web/_app/immutable/assets/Markdown.B4lW7Llh.css +1 -0
- package/dist/web/_app/immutable/assets/SettingsDialog.DYWYMFSO.css +1 -0
- package/dist/web/_app/immutable/assets/Spinner.UBfl0pab.css +1 -0
- package/dist/web/_app/immutable/assets/StopFilledAlt.clodJdp5.css +1 -0
- package/dist/web/_app/immutable/assets/TimelineView.DA-H6dvv.css +1 -0
- package/dist/web/_app/immutable/assets/WorkspaceView.BS1ildu7.css +1 -0
- package/dist/web/_app/immutable/assets/button.BlLm4Dg1.css +1 -0
- package/dist/web/_app/immutable/assets/formatting.B912lpdG.css +1 -0
- package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-400-normal.CvHOgSBP.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-400-normal.DMJ8VG8y.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-500-normal.CB9ihrfo.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-500-normal.DSY6xOcd.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-italic.CZTNEAuW.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-italic.CsGl1sm0.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-normal.CDDApCn2.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-normal.CYLoc0-x.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-italic.BNK2_mGO.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-italic.DpEwFAQM.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-normal.6ng42L7E.woff2 +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-normal.BgVn5rGT.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-600-normal.Cu4Hd6ag.woff +0 -0
- package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-600-normal.CuJfVYMP.woff2 +0 -0
- package/dist/web/_app/immutable/assets/inline-list.cqga56xT.css +1 -0
- package/dist/web/_app/immutable/assets/list-columns.DCMVmy_Q.css +1 -0
- package/dist/web/_app/immutable/assets/realtime.DDCWxn3B.css +1 -0
- package/dist/web/_app/immutable/assets/sheet.DJPuqnTg.css +1 -0
- package/dist/web/_app/immutable/assets/speech-dictation.C5CYFhS1.css +1 -0
- package/dist/web/_app/immutable/chunks/0iDDDyaZ.js +1 -0
- package/dist/web/_app/immutable/chunks/2LgrBrpS2.js +2 -0
- package/dist/web/_app/immutable/chunks/3EfPAYzi2.js +1 -0
- package/dist/web/_app/immutable/chunks/7Bu427my2.js +184 -0
- package/dist/web/_app/immutable/chunks/96h3ktuk.js +1 -0
- package/dist/web/_app/immutable/chunks/A6FJA1AF.js +1 -0
- package/dist/web/_app/immutable/chunks/B-FAwCqe2.js +1 -0
- package/dist/web/_app/immutable/chunks/B-V5eMSw2.js +1 -0
- package/dist/web/_app/immutable/chunks/B-i9_YVM.js +1 -0
- package/dist/web/_app/immutable/chunks/B15-kvCe2.js +1 -0
- package/dist/web/_app/immutable/chunks/B1KZ7zY32.js +2 -0
- package/dist/web/_app/immutable/chunks/B4gpzeQ2.js +1 -0
- package/dist/web/_app/immutable/chunks/B6Lt-qaJ2.js +1 -0
- package/dist/web/_app/immutable/chunks/B7tbGyiU2.js +1 -0
- package/dist/web/_app/immutable/chunks/BBxt8lpa.js +1 -0
- package/dist/web/_app/immutable/chunks/BCaRi2AF.js +1 -0
- package/dist/web/_app/immutable/chunks/BJ6Z7eAM.js +2 -0
- package/dist/web/_app/immutable/chunks/BM_vIwVC.js +83 -0
- package/dist/web/_app/immutable/chunks/BQULA6er.js +4 -0
- package/dist/web/_app/immutable/chunks/BQW-EDgP2.js +224 -0
- package/dist/web/_app/immutable/chunks/BR6jMpLB.js +1 -0
- package/dist/web/_app/immutable/chunks/BVnuLlVg.js +1 -0
- package/dist/web/_app/immutable/chunks/BddNmQ8j.js +1 -0
- package/dist/web/_app/immutable/chunks/BeuunHPO.js +1 -0
- package/dist/web/_app/immutable/chunks/BhTmSo4n2.js +1 -0
- package/dist/web/_app/immutable/chunks/BikW7mty2.js +1 -0
- package/dist/web/_app/immutable/chunks/BkyFvJvz.js +1 -0
- package/dist/web/_app/immutable/chunks/BlyFGPFV.js +22 -0
- package/dist/web/_app/immutable/chunks/Bo5dghSu.js +3 -0
- package/dist/web/_app/immutable/chunks/BpPyho8Y.js +3 -0
- package/dist/web/_app/immutable/chunks/BsuvyNDN2.js +2 -0
- package/dist/web/_app/immutable/chunks/BuKi0vpu2.js +7 -0
- package/dist/web/_app/immutable/chunks/BuuYnIjE.js +1 -0
- package/dist/web/_app/immutable/chunks/By4lVKNC.js +2 -0
- package/dist/web/_app/immutable/chunks/ByQGCIwO.js +5 -0
- package/dist/web/_app/immutable/chunks/ByidpUhu.js +1 -0
- package/dist/web/_app/immutable/chunks/C35TIzaB.js +1 -0
- package/dist/web/_app/immutable/chunks/C5dM5op-.js +1 -0
- package/dist/web/_app/immutable/chunks/C6Nx0jpM.js +1 -0
- package/dist/web/_app/immutable/chunks/C6pVyOEl2.js +1 -0
- package/dist/web/_app/immutable/chunks/C80GKPZ9.js +1 -0
- package/dist/web/_app/immutable/chunks/C94TJqPI.js +1 -0
- package/dist/web/_app/immutable/chunks/C9PETsiT.js +1 -0
- package/dist/web/_app/immutable/chunks/CAuAQ81a2.js +1 -0
- package/dist/web/_app/immutable/chunks/CBnzSITi2.js +1 -0
- package/dist/web/_app/immutable/chunks/CC9p2p6w.js +1 -0
- package/dist/web/_app/immutable/chunks/CCLR-AJL2.js +185 -0
- package/dist/web/_app/immutable/chunks/CD0X7XPW.js +6 -0
- package/dist/web/_app/immutable/chunks/CDTjuBSm.js +1 -0
- package/dist/web/_app/immutable/chunks/CH-KYFIm.js +64 -0
- package/dist/web/_app/immutable/chunks/CHj8fObQ2.js +9 -0
- package/dist/web/_app/immutable/chunks/CK-UnH-n2.js +1 -0
- package/dist/web/_app/immutable/chunks/CKH5BEAh.js +1 -0
- package/dist/web/_app/immutable/chunks/CPSupDJp2.js +2 -0
- package/dist/web/_app/immutable/chunks/CSUrYOis.js +1 -0
- package/dist/web/_app/immutable/chunks/CYTTTma0.js +3 -0
- package/dist/web/_app/immutable/chunks/Cbaut_us2.js +1 -0
- package/dist/web/_app/immutable/chunks/CiIpSx5n2.js +1 -0
- package/dist/web/_app/immutable/chunks/CkLfUXwy.js +1 -0
- package/dist/web/_app/immutable/chunks/CokE4L8B2.js +1 -0
- package/dist/web/_app/immutable/chunks/CpLdnbh3.js +1 -0
- package/dist/web/_app/immutable/chunks/CvDrXJk9.js +1 -0
- package/dist/web/_app/immutable/chunks/D00MFB9_2.js +1 -0
- package/dist/web/_app/immutable/chunks/D41CbXmM.js +1 -0
- package/dist/web/_app/immutable/chunks/D5Hj-MPO2.js +1 -0
- package/dist/web/_app/immutable/chunks/D6nLEmZy2.js +1 -0
- package/dist/web/_app/immutable/chunks/D71ZlQBM2.js +2 -0
- package/dist/web/_app/immutable/chunks/D9ql9vXU.js +1 -0
- package/dist/web/_app/immutable/chunks/DAXW5iLp.js +1 -0
- package/dist/web/_app/immutable/chunks/DBzQ8LyQ2.js +2 -0
- package/dist/web/_app/immutable/chunks/DIb5rAPU2.js +1 -0
- package/dist/web/_app/immutable/chunks/DOmH4G9o.js +14 -0
- package/dist/web/_app/immutable/chunks/DQMWa2t72.js +1 -0
- package/dist/web/_app/immutable/chunks/DRsswX8S.js +1 -0
- package/dist/web/_app/immutable/chunks/DTCHhxD5.js +1 -0
- package/dist/web/_app/immutable/chunks/DUwgGBxa.js +1 -0
- package/dist/web/_app/immutable/chunks/DVcy5Pp82.js +1 -0
- package/dist/web/_app/immutable/chunks/DWygwzcO.js +1 -0
- package/dist/web/_app/immutable/chunks/DYXDRmoo.js +1 -0
- package/dist/web/_app/immutable/chunks/DZ-YyRVM.js +1 -0
- package/dist/web/_app/immutable/chunks/D_HVOuHV.js +1 -0
- package/dist/web/_app/immutable/chunks/DaoOQFPb.js +1 -0
- package/dist/web/_app/immutable/chunks/DdLkNvPf.js +23 -0
- package/dist/web/_app/immutable/chunks/DiMQob8p.js +1 -0
- package/dist/web/_app/immutable/chunks/DiQJ9DLy.js +1 -0
- package/dist/web/_app/immutable/chunks/DlORZqfE.js +1 -0
- package/dist/web/_app/immutable/chunks/DmeYl7eL.js +2 -0
- package/dist/web/_app/immutable/chunks/Dng3OcRd2.js +1 -0
- package/dist/web/_app/immutable/chunks/DoKMFfJd.js +1 -0
- package/dist/web/_app/immutable/chunks/DpzG2mVI2.js +1 -0
- package/dist/web/_app/immutable/chunks/DvJSCDuZ2.js +1 -0
- package/dist/web/_app/immutable/chunks/DvPuaTCl2.js +5 -0
- package/dist/web/_app/immutable/chunks/ItgU4ei5.js +1 -0
- package/dist/web/_app/immutable/chunks/JJDMrjj62.js +1 -0
- package/dist/web/_app/immutable/chunks/OTTMDMTW.js +1 -0
- package/dist/web/_app/immutable/chunks/RmiWpCin2.js +1 -0
- package/dist/web/_app/immutable/chunks/ZTiqmKJy2.js +1 -0
- package/dist/web/_app/immutable/chunks/ahC5WoXX2.js +1 -0
- package/dist/web/_app/immutable/chunks/e3SY5t2O2.js +2692 -0
- package/dist/web/_app/immutable/chunks/g09ZrevW.js +1 -0
- package/dist/web/_app/immutable/chunks/go8N1nWD2.js +3 -0
- package/dist/web/_app/immutable/chunks/nTAmRNKw2.js +1 -0
- package/dist/web/_app/immutable/chunks/oBQOivfH2.js +1 -0
- package/dist/web/_app/immutable/chunks/oUTRxd0f.js +1 -0
- package/dist/web/_app/immutable/chunks/s_7BJJYy.js +2 -0
- package/dist/web/_app/immutable/chunks/uuFM-ygL.js +1 -0
- package/dist/web/_app/immutable/chunks/v7me-ydg.js +2 -0
- package/dist/web/_app/immutable/chunks/xihTtKlq.js +1 -0
- package/dist/web/_app/immutable/chunks/zl16E4yc2.js +1 -0
- package/dist/web/_app/immutable/entry/app.CbuUtkoM.js +2 -0
- package/dist/web/_app/immutable/entry/start.DeZyKwOT.js +1 -0
- package/dist/web/_app/immutable/nodes/0.C4PMtdx9.js +2 -0
- package/dist/web/_app/immutable/nodes/1.BwVfPLMn.js +1 -0
- package/dist/web/_app/immutable/nodes/10.DPr_SYan.js +1 -0
- package/dist/web/_app/immutable/nodes/11.CJAmEchE.js +1 -0
- package/dist/web/_app/immutable/nodes/12.ChMWXPMk.js +1 -0
- package/dist/web/_app/immutable/nodes/13.8vOKq8ue.js +1 -0
- package/dist/web/_app/immutable/nodes/14.BOSNmj9h.js +1 -0
- package/dist/web/_app/immutable/nodes/2.7N4BLwhX.js +109 -0
- package/dist/web/_app/immutable/nodes/3.Cd-tx8Ej.js +2 -0
- package/dist/web/_app/immutable/nodes/4.DtuT-syy.js +14 -0
- package/dist/web/_app/immutable/nodes/5.YwNHOrkt.js +1 -0
- package/dist/web/_app/immutable/nodes/6.BSPlYQuq.js +1 -0
- package/dist/web/_app/immutable/nodes/7.DPXzwW0H.js +1 -0
- package/dist/web/_app/immutable/nodes/8.Dhpk7w3X.js +1 -0
- package/dist/web/_app/immutable/nodes/9.Dd4iAQN5.js +1 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/favicon-16.png +0 -0
- package/dist/web/favicon-180.png +0 -0
- package/dist/web/favicon-32.png +0 -0
- package/dist/web/favicon-48.png +0 -0
- package/dist/web/favicon-512.png +0 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/favicon.svg +8 -0
- package/dist/web/index.html +54 -19
- package/dist/web/studiograph-logomark.svg +29 -0
- package/package.json +34 -14
- package/dist/agent/skills/enrich-entities.md +0 -136
- package/dist/agent/skills/obsidian-source-setup.md +0 -246
- package/dist/agent/skills/skill-loader.d.ts +0 -48
- package/dist/agent/skills/skill-loader.js +0 -166
- package/dist/agent/skills/skill-loader.js.map +0 -1
- package/dist/agent/skills/sync-configuration.md +0 -119
- package/dist/agent/skills/sync-setup.md +0 -82
- package/dist/agent/tools/sync-tools.d.ts +0 -35
- package/dist/agent/tools/sync-tools.js +0 -992
- package/dist/agent/tools/sync-tools.js.map +0 -1
- package/dist/auth/github.d.ts +0 -56
- package/dist/auth/github.js +0 -169
- package/dist/auth/github.js.map +0 -1
- package/dist/cli/commands/access.d.ts +0 -11
- package/dist/cli/commands/access.js +0 -156
- package/dist/cli/commands/access.js.map +0 -1
- package/dist/cli/commands/app.d.ts +0 -7
- package/dist/cli/commands/app.js +0 -268
- package/dist/cli/commands/app.js.map +0 -1
- package/dist/cli/commands/auth.d.ts +0 -10
- package/dist/cli/commands/auth.js +0 -79
- package/dist/cli/commands/auth.js.map +0 -1
- package/dist/cli/commands/clear.d.ts +0 -5
- package/dist/cli/commands/clear.js +0 -36
- package/dist/cli/commands/clear.js.map +0 -1
- package/dist/cli/commands/collection.d.ts +0 -10
- package/dist/cli/commands/collection.js +0 -187
- package/dist/cli/commands/collection.js.map +0 -1
- package/dist/cli/commands/enrich.d.ts +0 -11
- package/dist/cli/commands/enrich.js +0 -135
- package/dist/cli/commands/enrich.js.map +0 -1
- package/dist/cli/commands/graphrag.d.ts +0 -12
- package/dist/cli/commands/graphrag.js +0 -122
- package/dist/cli/commands/graphrag.js.map +0 -1
- package/dist/cli/commands/join.d.ts +0 -9
- package/dist/cli/commands/join.js +0 -255
- package/dist/cli/commands/join.js.map +0 -1
- package/dist/cli/commands/members.d.ts +0 -11
- package/dist/cli/commands/members.js +0 -230
- package/dist/cli/commands/members.js.map +0 -1
- package/dist/cli/commands/org.d.ts +0 -10
- package/dist/cli/commands/org.js +0 -132
- package/dist/cli/commands/org.js.map +0 -1
- package/dist/cli/commands/provision.d.ts +0 -8
- package/dist/cli/commands/provision.js +0 -116
- package/dist/cli/commands/provision.js.map +0 -1
- package/dist/cli/commands/resolve.d.ts +0 -8
- package/dist/cli/commands/resolve.js +0 -85
- package/dist/cli/commands/resolve.js.map +0 -1
- package/dist/cli/commands/review.d.ts +0 -19
- package/dist/cli/commands/review.js +0 -128
- package/dist/cli/commands/review.js.map +0 -1
- package/dist/cli/commands/source.d.ts +0 -16
- package/dist/cli/commands/source.js +0 -159
- package/dist/cli/commands/source.js.map +0 -1
- package/dist/cli/commands/start.d.ts +0 -7
- package/dist/cli/commands/start.js +0 -589
- package/dist/cli/commands/start.js.map +0 -1
- package/dist/cli/commands/sync-collection.d.ts +0 -14
- package/dist/cli/commands/sync-collection.js +0 -355
- package/dist/cli/commands/sync-collection.js.map +0 -1
- package/dist/cli/commands/sync-entities.d.ts +0 -13
- package/dist/cli/commands/sync-entities.js +0 -242
- package/dist/cli/commands/sync-entities.js.map +0 -1
- package/dist/cli/commands/team.d.ts +0 -12
- package/dist/cli/commands/team.js +0 -185
- package/dist/cli/commands/team.js.map +0 -1
- package/dist/cli/commands/update.d.ts +0 -8
- package/dist/cli/commands/update.js +0 -155
- package/dist/cli/commands/update.js.map +0 -1
- package/dist/cli/commands/user.d.ts +0 -7
- package/dist/cli/commands/user.js +0 -153
- package/dist/cli/commands/user.js.map +0 -1
- package/dist/cli/scaffolding.d.ts +0 -12
- package/dist/cli/scaffolding.js +0 -397
- package/dist/cli/scaffolding.js.map +0 -1
- package/dist/cli/sync-review-interactive.d.ts +0 -31
- package/dist/cli/sync-review-interactive.js +0 -393
- package/dist/cli/sync-review-interactive.js.map +0 -1
- package/dist/core/migration-runner.d.ts +0 -42
- package/dist/core/migration-runner.js +0 -232
- package/dist/core/migration-runner.js.map +0 -1
- package/dist/core/migration-types.d.ts +0 -101
- package/dist/core/migration-types.js +0 -21
- package/dist/core/migration-types.js.map +0 -1
- package/dist/core/migrations/20260219-formalize-memory-location.d.ts +0 -2
- package/dist/core/migrations/20260219-formalize-memory-location.js +0 -35
- package/dist/core/migrations/20260219-formalize-memory-location.js.map +0 -1
- package/dist/core/migrations/20260220-add-workspace-metadata.d.ts +0 -12
- package/dist/core/migrations/20260220-add-workspace-metadata.js +0 -65
- package/dist/core/migrations/20260220-add-workspace-metadata.js.map +0 -1
- package/dist/core/migrations/20260220-add-workspace-readme.d.ts +0 -11
- package/dist/core/migrations/20260220-add-workspace-readme.js +0 -82
- package/dist/core/migrations/20260220-add-workspace-readme.js.map +0 -1
- package/dist/core/migrations/20260220-migrate-yaml-to-json.d.ts +0 -9
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js +0 -64
- package/dist/core/migrations/20260220-migrate-yaml-to-json.js.map +0 -1
- package/dist/core/migrations/index.d.ts +0 -11
- package/dist/core/migrations/index.js +0 -23
- package/dist/core/migrations/index.js.map +0 -1
- package/dist/integrations/asana.d.ts +0 -26
- package/dist/integrations/asana.js +0 -78
- package/dist/integrations/asana.js.map +0 -1
- package/dist/integrations/figma-local.d.ts +0 -16
- package/dist/integrations/figma-local.js +0 -10
- package/dist/integrations/figma-local.js.map +0 -1
- package/dist/integrations/figma.d.ts +0 -17
- package/dist/integrations/figma.js +0 -17
- package/dist/integrations/figma.js.map +0 -1
- package/dist/integrations/granola.d.ts +0 -24
- package/dist/integrations/granola.js +0 -60
- package/dist/integrations/granola.js.map +0 -1
- package/dist/integrations/linear.d.ts +0 -14
- package/dist/integrations/linear.js +0 -80
- package/dist/integrations/linear.js.map +0 -1
- package/dist/integrations/paper-local.d.ts +0 -14
- package/dist/integrations/paper-local.js +0 -10
- package/dist/integrations/paper-local.js.map +0 -1
- package/dist/integrations/paper.d.ts +0 -2
- package/dist/integrations/paper.js +0 -10
- package/dist/integrations/paper.js.map +0 -1
- package/dist/integrations/pipedrive.d.ts +0 -26
- package/dist/integrations/pipedrive.js +0 -97
- package/dist/integrations/pipedrive.js.map +0 -1
- package/dist/integrations/registry.d.ts +0 -15
- package/dist/integrations/registry.js +0 -27
- package/dist/integrations/registry.js.map +0 -1
- package/dist/integrations/types.d.ts +0 -38
- package/dist/integrations/types.js +0 -9
- package/dist/integrations/types.js.map +0 -1
- package/dist/lib/lib/utils.d.ts +0 -2
- package/dist/lib/lib/utils.js +0 -6
- package/dist/lib/lib/utils.js.map +0 -1
- package/dist/mcp/connectors/asana.d.ts +0 -2
- package/dist/mcp/connectors/asana.js +0 -20
- package/dist/mcp/connectors/asana.js.map +0 -1
- package/dist/mcp/connectors/definitions.d.ts +0 -45
- package/dist/mcp/connectors/definitions.js +0 -32
- package/dist/mcp/connectors/definitions.js.map +0 -1
- package/dist/mcp/connectors/figma.d.ts +0 -5
- package/dist/mcp/connectors/figma.js +0 -21
- package/dist/mcp/connectors/figma.js.map +0 -1
- package/dist/mcp/connectors/gdrive.d.ts +0 -2
- package/dist/mcp/connectors/gdrive.js +0 -20
- package/dist/mcp/connectors/gdrive.js.map +0 -1
- package/dist/mcp/connectors/granola.d.ts +0 -2
- package/dist/mcp/connectors/granola.js +0 -12
- package/dist/mcp/connectors/granola.js.map +0 -1
- package/dist/mcp/connectors/linear.d.ts +0 -2
- package/dist/mcp/connectors/linear.js +0 -19
- package/dist/mcp/connectors/linear.js.map +0 -1
- package/dist/mcp/connectors/obsidian.d.ts +0 -2
- package/dist/mcp/connectors/obsidian.js +0 -19
- package/dist/mcp/connectors/obsidian.js.map +0 -1
- package/dist/mcp/connectors/pipedrive.d.ts +0 -2
- package/dist/mcp/connectors/pipedrive.js +0 -20
- package/dist/mcp/connectors/pipedrive.js.map +0 -1
- package/dist/mcp/connectors/slack.d.ts +0 -2
- package/dist/mcp/connectors/slack.js +0 -21
- package/dist/mcp/connectors/slack.js.map +0 -1
- package/dist/mcp/server-oauth-provider.d.ts +0 -56
- package/dist/mcp/server-oauth-provider.js +0 -142
- package/dist/mcp/server-oauth-provider.js.map +0 -1
- package/dist/server/chrome/chrome.css +0 -691
- package/dist/server/chrome/chrome.js +0 -374
- package/dist/server/collab-authority.d.ts +0 -70
- package/dist/server/collab-authority.js +0 -218
- package/dist/server/collab-authority.js.map +0 -1
- package/dist/server/collab.d.ts +0 -29
- package/dist/server/collab.js +0 -195
- package/dist/server/collab.js.map +0 -1
- package/dist/server/commit-scheduler.d.ts +0 -39
- package/dist/server/commit-scheduler.js +0 -113
- package/dist/server/commit-scheduler.js.map +0 -1
- package/dist/server/plugin-loader.d.ts +0 -53
- package/dist/server/plugin-loader.js +0 -155
- package/dist/server/plugin-loader.js.map +0 -1
- package/dist/server/routes/collab.d.ts +0 -6
- package/dist/server/routes/collab.js +0 -10
- package/dist/server/routes/collab.js.map +0 -1
- package/dist/server/routes/git-api.d.ts +0 -9
- package/dist/server/routes/git-api.js +0 -82
- package/dist/server/routes/git-api.js.map +0 -1
- package/dist/server/routes/meeting-ingest-api.d.ts +0 -15
- package/dist/server/routes/meeting-ingest-api.js +0 -323
- package/dist/server/routes/meeting-ingest-api.js.map +0 -1
- package/dist/server/routes/sync-api.d.ts +0 -26
- package/dist/server/routes/sync-api.js +0 -814
- package/dist/server/routes/sync-api.js.map +0 -1
- package/dist/server/routes/webhook.d.ts +0 -14
- package/dist/server/routes/webhook.js +0 -102
- package/dist/server/routes/webhook.js.map +0 -1
- package/dist/services/github-provisioner.d.ts +0 -36
- package/dist/services/github-provisioner.js +0 -126
- package/dist/services/github-provisioner.js.map +0 -1
- package/dist/services/github-service.d.ts +0 -99
- package/dist/services/github-service.js +0 -310
- package/dist/services/github-service.js.map +0 -1
- package/dist/services/insights.d.ts +0 -38
- package/dist/services/insights.js +0 -246
- package/dist/services/insights.js.map +0 -1
- package/dist/services/sync/collection-sync.d.ts +0 -60
- package/dist/services/sync/collection-sync.js +0 -509
- package/dist/services/sync/collection-sync.js.map +0 -1
- package/dist/services/sync/commit.d.ts +0 -60
- package/dist/services/sync/commit.js +0 -354
- package/dist/services/sync/commit.js.map +0 -1
- package/dist/services/sync/context-index.d.ts +0 -69
- package/dist/services/sync/context-index.js +0 -280
- package/dist/services/sync/context-index.js.map +0 -1
- package/dist/services/sync/data-fetcher.d.ts +0 -31
- package/dist/services/sync/data-fetcher.js +0 -12
- package/dist/services/sync/data-fetcher.js.map +0 -1
- package/dist/services/sync/derive.d.ts +0 -34
- package/dist/services/sync/derive.js +0 -164
- package/dist/services/sync/derive.js.map +0 -1
- package/dist/services/sync/enrichment-state.d.ts +0 -31
- package/dist/services/sync/enrichment-state.js +0 -63
- package/dist/services/sync/enrichment-state.js.map +0 -1
- package/dist/services/sync/enrichment.d.ts +0 -25
- package/dist/services/sync/enrichment.js +0 -121
- package/dist/services/sync/enrichment.js.map +0 -1
- package/dist/services/sync/entity-refresh.d.ts +0 -30
- package/dist/services/sync/entity-refresh.js +0 -275
- package/dist/services/sync/entity-refresh.js.map +0 -1
- package/dist/services/sync/frontmatter-extractor.d.ts +0 -40
- package/dist/services/sync/frontmatter-extractor.js +0 -279
- package/dist/services/sync/frontmatter-extractor.js.map +0 -1
- package/dist/services/sync/graph-match-state.d.ts +0 -33
- package/dist/services/sync/graph-match-state.js +0 -61
- package/dist/services/sync/graph-match-state.js.map +0 -1
- package/dist/services/sync/graph-match.d.ts +0 -53
- package/dist/services/sync/graph-match.js +0 -316
- package/dist/services/sync/graph-match.js.map +0 -1
- package/dist/services/sync/graphrag-client.d.ts +0 -43
- package/dist/services/sync/graphrag-client.js +0 -94
- package/dist/services/sync/graphrag-client.js.map +0 -1
- package/dist/services/sync/graphrag-config.d.ts +0 -16
- package/dist/services/sync/graphrag-config.js +0 -39
- package/dist/services/sync/graphrag-config.js.map +0 -1
- package/dist/services/sync/graphrag-context.d.ts +0 -14
- package/dist/services/sync/graphrag-context.js +0 -109
- package/dist/services/sync/graphrag-context.js.map +0 -1
- package/dist/services/sync/graphrag-indexer.d.ts +0 -30
- package/dist/services/sync/graphrag-indexer.js +0 -358
- package/dist/services/sync/graphrag-indexer.js.map +0 -1
- package/dist/services/sync/llm.d.ts +0 -32
- package/dist/services/sync/llm.js +0 -115
- package/dist/services/sync/llm.js.map +0 -1
- package/dist/services/sync/mcp-client.d.ts +0 -71
- package/dist/services/sync/mcp-client.js +0 -299
- package/dist/services/sync/mcp-client.js.map +0 -1
- package/dist/services/sync/model-factory.d.ts +0 -13
- package/dist/services/sync/model-factory.js +0 -38
- package/dist/services/sync/model-factory.js.map +0 -1
- package/dist/services/sync/name-quality.d.ts +0 -31
- package/dist/services/sync/name-quality.js +0 -60
- package/dist/services/sync/name-quality.js.map +0 -1
- package/dist/services/sync/output-schemas.d.ts +0 -92
- package/dist/services/sync/output-schemas.js +0 -43
- package/dist/services/sync/output-schemas.js.map +0 -1
- package/dist/services/sync/prompts.d.ts +0 -19
- package/dist/services/sync/prompts.js +0 -128
- package/dist/services/sync/prompts.js.map +0 -1
- package/dist/services/sync/reconciler.d.ts +0 -48
- package/dist/services/sync/reconciler.js +0 -294
- package/dist/services/sync/reconciler.js.map +0 -1
- package/dist/services/sync/rest-client.d.ts +0 -40
- package/dist/services/sync/rest-client.js +0 -100
- package/dist/services/sync/rest-client.js.map +0 -1
- package/dist/services/sync/source-config.d.ts +0 -67
- package/dist/services/sync/source-config.js +0 -304
- package/dist/services/sync/source-config.js.map +0 -1
- package/dist/services/sync/source-definitions/asana.d.ts +0 -14
- package/dist/services/sync/source-definitions/asana.js +0 -42
- package/dist/services/sync/source-definitions/asana.js.map +0 -1
- package/dist/services/sync/source-definitions/definitions.d.ts +0 -8
- package/dist/services/sync/source-definitions/definitions.js +0 -8
- package/dist/services/sync/source-definitions/definitions.js.map +0 -1
- package/dist/services/sync/source-definitions/gdrive.d.ts +0 -16
- package/dist/services/sync/source-definitions/gdrive.js +0 -68
- package/dist/services/sync/source-definitions/gdrive.js.map +0 -1
- package/dist/services/sync/source-definitions/granola.d.ts +0 -2
- package/dist/services/sync/source-definitions/granola.js +0 -21
- package/dist/services/sync/source-definitions/granola.js.map +0 -1
- package/dist/services/sync/source-definitions/linear.d.ts +0 -2
- package/dist/services/sync/source-definitions/linear.js +0 -62
- package/dist/services/sync/source-definitions/linear.js.map +0 -1
- package/dist/services/sync/source-definitions/obsidian.d.ts +0 -2
- package/dist/services/sync/source-definitions/obsidian.js +0 -55
- package/dist/services/sync/source-definitions/obsidian.js.map +0 -1
- package/dist/services/sync/source-definitions/pipedrive.d.ts +0 -2
- package/dist/services/sync/source-definitions/pipedrive.js +0 -43
- package/dist/services/sync/source-definitions/pipedrive.js.map +0 -1
- package/dist/services/sync/staging.d.ts +0 -53
- package/dist/services/sync/staging.js +0 -130
- package/dist/services/sync/staging.js.map +0 -1
- package/dist/services/sync/structured-extractor.d.ts +0 -57
- package/dist/services/sync/structured-extractor.js +0 -584
- package/dist/services/sync/structured-extractor.js.map +0 -1
- package/dist/services/sync/sync-runner.d.ts +0 -32
- package/dist/services/sync/sync-runner.js +0 -195
- package/dist/services/sync/sync-runner.js.map +0 -1
- package/dist/services/sync/sync-state.d.ts +0 -43
- package/dist/services/sync/sync-state.js +0 -154
- package/dist/services/sync/sync-state.js.map +0 -1
- package/dist/services/sync/types.d.ts +0 -381
- package/dist/services/sync/types.js +0 -8
- package/dist/services/sync/types.js.map +0 -1
- package/dist/services/sync/unstructured-extractor.d.ts +0 -27
- package/dist/services/sync/unstructured-extractor.js +0 -185
- package/dist/services/sync/unstructured-extractor.js.map +0 -1
- package/dist/utils/merge-resolver.d.ts +0 -59
- package/dist/utils/merge-resolver.js +0 -303
- package/dist/utils/merge-resolver.js.map +0 -1
- package/dist/utils/workspace-config.d.ts +0 -8
- package/dist/utils/workspace-config.js +0 -22
- package/dist/utils/workspace-config.js.map +0 -1
- package/dist/web/_app/immutable/assets/0.DdizXOKi.css +0 -1
- package/dist/web/_app/immutable/assets/10.BUrHkYry.css +0 -1
- package/dist/web/_app/immutable/assets/2.n7-yW_Fs.css +0 -1
- package/dist/web/_app/immutable/assets/3.BtaZagnv.css +0 -1
- package/dist/web/_app/immutable/assets/4.DT7X0x5S.css +0 -1
- package/dist/web/_app/immutable/assets/5.DFeGxLYf.css +0 -1
- package/dist/web/_app/immutable/assets/6.CquhUpOu.css +0 -1
- package/dist/web/_app/immutable/assets/7.CjbDRbuG.css +0 -1
- package/dist/web/_app/immutable/assets/8.S1QdUGNM.css +0 -1
- package/dist/web/_app/immutable/assets/9.CT4xL4K3.css +0 -1
- package/dist/web/_app/immutable/assets/Copy.FS8bdfxr.css +0 -1
- package/dist/web/_app/immutable/assets/Toaster.rN8r_Hzv.css +0 -1
- package/dist/web/_app/immutable/assets/ViewToolbar.D-QW2oKe.css +0 -1
- package/dist/web/_app/immutable/assets/index.D6tMDJWk.css +0 -1
- package/dist/web/_app/immutable/chunks/37NdyH6G.js +0 -32
- package/dist/web/_app/immutable/chunks/4Hhzb6pv.js +0 -1
- package/dist/web/_app/immutable/chunks/72bZS3G9.js +0 -1
- package/dist/web/_app/immutable/chunks/7S2LGqoP.js +0 -2
- package/dist/web/_app/immutable/chunks/B-7hHz7B.js +0 -1
- package/dist/web/_app/immutable/chunks/B340SUKR.js +0 -1
- package/dist/web/_app/immutable/chunks/BB_5th5W.js +0 -3383
- package/dist/web/_app/immutable/chunks/BDoWDZaG.js +0 -1
- package/dist/web/_app/immutable/chunks/BFyl1ZHO.js +0 -1
- package/dist/web/_app/immutable/chunks/BS2rFAVq.js +0 -1
- package/dist/web/_app/immutable/chunks/BSsDC_p4.js +0 -1
- package/dist/web/_app/immutable/chunks/BTX2Jr8_.js +0 -1
- package/dist/web/_app/immutable/chunks/BWNY8zw6.js +0 -2
- package/dist/web/_app/immutable/chunks/BdPUVvAi.js +0 -1
- package/dist/web/_app/immutable/chunks/BmsJVLyy.js +0 -1
- package/dist/web/_app/immutable/chunks/BoAosqzE.js +0 -1
- package/dist/web/_app/immutable/chunks/Bs-tL5OR.js +0 -1
- package/dist/web/_app/immutable/chunks/Bsacq2UX.js +0 -1
- package/dist/web/_app/immutable/chunks/BuewkNdS.js +0 -4
- package/dist/web/_app/immutable/chunks/ByunV8un.js +0 -1
- package/dist/web/_app/immutable/chunks/C7VoTosa.js +0 -2
- package/dist/web/_app/immutable/chunks/CDV5Q7RN.js +0 -1
- package/dist/web/_app/immutable/chunks/CJ8__CWt.js +0 -1
- package/dist/web/_app/immutable/chunks/CJUKmosC.js +0 -5
- package/dist/web/_app/immutable/chunks/CSVbGg_b.js +0 -5
- package/dist/web/_app/immutable/chunks/CT6oIU-C.js +0 -1
- package/dist/web/_app/immutable/chunks/CTRxNfZk.js +0 -1
- package/dist/web/_app/immutable/chunks/CWQRQXxy.js +0 -1
- package/dist/web/_app/immutable/chunks/CXH6iFbA.js +0 -1
- package/dist/web/_app/immutable/chunks/CX_61fY8.js +0 -5
- package/dist/web/_app/immutable/chunks/CYrVHOHA.js +0 -1
- package/dist/web/_app/immutable/chunks/CdeYcEuU.js +0 -1
- package/dist/web/_app/immutable/chunks/CmCtpZ1Y.js +0 -1
- package/dist/web/_app/immutable/chunks/CqkleIqs.js +0 -1
- package/dist/web/_app/immutable/chunks/CrdV0ttd.js +0 -1
- package/dist/web/_app/immutable/chunks/CscoF-YL.js +0 -18
- package/dist/web/_app/immutable/chunks/Cx4YdFMk.js +0 -1
- package/dist/web/_app/immutable/chunks/D7ZqAKi9.js +0 -3
- package/dist/web/_app/immutable/chunks/DGbA7IXh.js +0 -2
- package/dist/web/_app/immutable/chunks/DbbB6Up5.js +0 -1
- package/dist/web/_app/immutable/chunks/DnL9f0lc.js +0 -7
- package/dist/web/_app/immutable/chunks/DtM5cEDu.js +0 -1
- package/dist/web/_app/immutable/chunks/Eqahi7_S.js +0 -2
- package/dist/web/_app/immutable/chunks/FFlLQIiS.js +0 -1
- package/dist/web/_app/immutable/chunks/O9Eb9k00.js +0 -1
- package/dist/web/_app/immutable/chunks/PPVm8Dsz.js +0 -1
- package/dist/web/_app/immutable/chunks/QF8MAmnc.js +0 -1
- package/dist/web/_app/immutable/chunks/UjzxCpxn.js +0 -1
- package/dist/web/_app/immutable/chunks/WSUKABI_.js +0 -1
- package/dist/web/_app/immutable/chunks/Y90OgS-9.js +0 -1
- package/dist/web/_app/immutable/chunks/cLyZlkXv.js +0 -1
- package/dist/web/_app/immutable/chunks/iDtAARVW.js +0 -2
- package/dist/web/_app/immutable/chunks/oC_W7W7p.js +0 -1
- package/dist/web/_app/immutable/chunks/rJdWIgh-.js +0 -1
- package/dist/web/_app/immutable/chunks/tvOsokaa.js +0 -1
- package/dist/web/_app/immutable/chunks/uLEXaPwE.js +0 -1
- package/dist/web/_app/immutable/chunks/vSaooFHB.js +0 -1
- package/dist/web/_app/immutable/entry/app.DAR-mtfg.js +0 -2
- package/dist/web/_app/immutable/entry/start.xDnyRaR1.js +0 -1
- package/dist/web/_app/immutable/nodes/0.D0aV-Zro.js +0 -2
- package/dist/web/_app/immutable/nodes/1.C7QoM8qD.js +0 -1
- package/dist/web/_app/immutable/nodes/10.DrDOAjOD.js +0 -1
- package/dist/web/_app/immutable/nodes/2.B0OgNuKW.js +0 -168
- package/dist/web/_app/immutable/nodes/3.BZ4qHGZi.js +0 -1
- package/dist/web/_app/immutable/nodes/4.hm-mxuuj.js +0 -12
- package/dist/web/_app/immutable/nodes/5.Bdbt4fjx.js +0 -4
- package/dist/web/_app/immutable/nodes/6.BXrCI40c.js +0 -2
- package/dist/web/_app/immutable/nodes/7.Chd4i9bm.js +0 -2
- package/dist/web/_app/immutable/nodes/8.B8SF-aNs.js +0 -1
- package/dist/web/_app/immutable/nodes/9.YDeu-RnO.js +0 -1
|
@@ -7,11 +7,18 @@
|
|
|
7
7
|
* - Manage wikilinks
|
|
8
8
|
* - Upload assets
|
|
9
9
|
*/
|
|
10
|
-
import { Type as T } from '
|
|
10
|
+
import { Type as T } from 'typebox';
|
|
11
11
|
import { ENTITY_SCHEMAS } from '../../core/validation.js';
|
|
12
|
+
import { describeZodObject } from '../../core/schema-registry.js';
|
|
12
13
|
import { lintWorkspace } from '../../services/lint-service.js';
|
|
13
14
|
import { findOrphans } from '../../services/orphan-service.js';
|
|
14
|
-
import
|
|
15
|
+
import * as access from '../../services/access-control.js';
|
|
16
|
+
import { isCuratedEntityType } from '../../core/entity-types-catalog.js';
|
|
17
|
+
import { getAgentAllowedEntityTypes } from '../prompts/entity-types-section.js';
|
|
18
|
+
import { BridgeError, assertCanChangeUserHandle, validateUserHandleInPayload } from '../../services/user-person-bridge.js';
|
|
19
|
+
import { buildActor, prepareCreatePayload, prepareUpdatePayload, diagnosedUpdate, DroppedAssetError, } from '../../services/entity-mutations.js';
|
|
20
|
+
import { listRepoAssets } from '../../services/asset-listing.js';
|
|
21
|
+
import { assetEmbed } from '../../core/embeds.js';
|
|
15
22
|
/**
|
|
16
23
|
* Helper to wrap tool results in AgentToolResult format
|
|
17
24
|
*/
|
|
@@ -31,128 +38,226 @@ function cleanData(data) {
|
|
|
31
38
|
return rest;
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
41
|
+
* Undo JSON-string escapes that sometimes leak into content when the LLM
|
|
42
|
+
* serializes markdown as a quoted string instead of raw text. Handles `\n`,
|
|
43
|
+
* `\t`, `\r`, `\"`, `\\` in a single pass so escape sequences aren't
|
|
44
|
+
* re-processed. Also strips stray surrounding quotes from a fully-quoted
|
|
45
|
+
* payload.
|
|
37
46
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (!user)
|
|
52
|
-
return null; // API key / open mode → allow
|
|
53
|
-
if (user.role === 'admin')
|
|
54
|
-
return null;
|
|
55
|
-
return 'This operation requires admin access.';
|
|
47
|
+
function sanitizeLlmContent(content) {
|
|
48
|
+
if (!content)
|
|
49
|
+
return '';
|
|
50
|
+
const unescaped = content.replace(/\\([ntr"\\])/g, (_, c) => {
|
|
51
|
+
if (c === 'n')
|
|
52
|
+
return '\n';
|
|
53
|
+
if (c === 't')
|
|
54
|
+
return '\t';
|
|
55
|
+
if (c === 'r')
|
|
56
|
+
return '\r';
|
|
57
|
+
return c;
|
|
58
|
+
});
|
|
59
|
+
return unescaped.replace(/^"+|"+$/g, '');
|
|
56
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Per-request user context for folder access filtering.
|
|
63
|
+
* When getCurrentUser returns a user, tools filter results to only
|
|
64
|
+
* folders the user is a member of (via folder_access).
|
|
65
|
+
*/
|
|
57
66
|
function getAccessibleRepoNames(workspaceManager, getCurrentUser, authService) {
|
|
58
67
|
const user = getCurrentUser();
|
|
59
68
|
if (!user)
|
|
60
69
|
return null; // API key / open mode → no filtering
|
|
61
70
|
if (!authService)
|
|
62
71
|
return null;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const hidden = allRepos.filter(r => !canSeePrivateRepo(r, user)).map(r => r.name);
|
|
67
|
-
if (hidden.length === 0)
|
|
68
|
-
return null; // No filtering needed
|
|
69
|
-
const visible = new Set(allRepos.filter(r => canSeePrivateRepo(r, user)).map(r => r.name));
|
|
70
|
-
return visible;
|
|
71
|
-
}
|
|
72
|
-
const allowed = authService.getUserCollections(user.id);
|
|
73
|
-
const visible = allRepos.filter(r => canSeePrivateRepo(r, user) && (r.private && r.owner_id === user.id || allowed.includes(r.name)));
|
|
74
|
-
return new Set(visible.map(r => r.name));
|
|
72
|
+
// Delegate to the shared helper so personal-folder restrictions and
|
|
73
|
+
// owner-on-shared-folder semantics apply consistently with the HTTP layer.
|
|
74
|
+
return new Set(access.getAccessibleRepos(user, workspaceManager, authService).map(r => r.name));
|
|
75
75
|
}
|
|
76
76
|
function canAccessRepo(repoName, workspaceManager, getCurrentUser, authService) {
|
|
77
77
|
const user = getCurrentUser();
|
|
78
|
-
const repoConfig = workspaceManager.getRepoConfig(repoName);
|
|
79
|
-
if (!canSeePrivateRepo(repoConfig, user))
|
|
80
|
-
return false;
|
|
81
78
|
if (!user)
|
|
82
79
|
return true;
|
|
83
|
-
if (repoConfig?.private && repoConfig?.owner_id === user.id)
|
|
84
|
-
return true;
|
|
85
|
-
if (user.role === 'admin')
|
|
86
|
-
return true;
|
|
87
80
|
if (!authService)
|
|
88
81
|
return true;
|
|
89
|
-
return
|
|
82
|
+
return access.hasRepoAccess(user, repoName, workspaceManager, authService);
|
|
90
83
|
}
|
|
91
|
-
export function createGraphTools(workspaceManager, gitUser, workspacePath, onHighlight, onMutation, getCurrentUser, authService
|
|
84
|
+
export function createGraphTools(workspaceManager, gitUser, workspacePath, onHighlight, onMutation, getCurrentUser, authService,
|
|
85
|
+
/**
|
|
86
|
+
* Called at the start (`enter`) and end (`leave`) of any mutation tool
|
|
87
|
+
* call. Surfaces the active-agent chip in the sidebar via the WS hub. The
|
|
88
|
+
* orchestrator wires this through to wsHub.handleAgentActivity.
|
|
89
|
+
*/
|
|
90
|
+
onAgentActivity) {
|
|
92
91
|
const getUser = getCurrentUser ?? (() => null);
|
|
93
92
|
const authSvc = authService ?? null;
|
|
93
|
+
/**
|
|
94
|
+
* Resolve the identity to stamp on writes. If the tool call is running on
|
|
95
|
+
* behalf of a real user (chat / quick-capture from the web), credit them
|
|
96
|
+
* by their handle via the shared `buildActor` so MCP and agent surfaces
|
|
97
|
+
* produce byte-identical git authors for the same user. Fall back to the
|
|
98
|
+
* orchestrator-level gitUser for unauthenticated contexts (CLI, tests,
|
|
99
|
+
* server-only automations).
|
|
100
|
+
*/
|
|
101
|
+
function effectiveGitUser() {
|
|
102
|
+
const user = getUser();
|
|
103
|
+
if (user?.handle)
|
|
104
|
+
return buildActor(user);
|
|
105
|
+
return gitUser;
|
|
106
|
+
}
|
|
107
|
+
/** Resolve "private" or "entries" to the current user's actual private folder name. */
|
|
108
|
+
function resolvePrivateRepo(repoName) {
|
|
109
|
+
if (repoName !== 'private' && repoName !== 'entries')
|
|
110
|
+
return repoName;
|
|
111
|
+
const user = getUser();
|
|
112
|
+
if (!user)
|
|
113
|
+
return repoName;
|
|
114
|
+
const personalRepo = workspaceManager.getUserPersonalRepo(user.id);
|
|
115
|
+
return personalRepo?.name ?? repoName;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Eager skills are inlined into every system prompt for everyone with folder
|
|
119
|
+
* access. Creating one in a shared folder requires admin/owner so a rogue
|
|
120
|
+
* member can't bloat everyone's context. Eager skills in the user's own
|
|
121
|
+
* private folder are fine — they only bloat that user's own prompt.
|
|
122
|
+
* Returns an error string or null if the operation is allowed.
|
|
123
|
+
*/
|
|
124
|
+
function checkEagerSkillPermission(entityType, data, repoName) {
|
|
125
|
+
if (entityType !== 'skill')
|
|
126
|
+
return null;
|
|
127
|
+
if (!data || data.loading !== 'eager')
|
|
128
|
+
return null;
|
|
129
|
+
const user = getUser();
|
|
130
|
+
if (!user)
|
|
131
|
+
return null; // non-authenticated contexts (CLI, tests) bypass
|
|
132
|
+
const personalRepo = workspaceManager.getUserPersonalRepo(user.id);
|
|
133
|
+
if (personalRepo && personalRepo.name === repoName)
|
|
134
|
+
return null;
|
|
135
|
+
if (authSvc?.isFolderAdmin(user.id, repoName))
|
|
136
|
+
return null;
|
|
137
|
+
if (user.role === 'owner')
|
|
138
|
+
return null;
|
|
139
|
+
return `Creating an eager skill in a shared folder requires folder admin or workspace owner. Save this skill to your private folder (repo: "private") or set loading to "on-demand".`;
|
|
140
|
+
}
|
|
141
|
+
// Compute the set of entity types the agent is allowed to create in this
|
|
142
|
+
// workspace: the full canonical catalog plus any custom types defined via
|
|
143
|
+
// schema_extensions. The launch-time allowlist was removed — the catalog
|
|
144
|
+
// now grows with the user via the New Entry picker's progressive disclosure.
|
|
145
|
+
const builtinTypeKeys = new Set(Object.keys(ENTITY_SCHEMAS));
|
|
146
|
+
const customWorkspaceTypes = workspaceManager.getSchemaRegistry().getAllTypes()
|
|
147
|
+
.filter(t => !builtinTypeKeys.has(t));
|
|
148
|
+
const agentAllowedTypes = getAgentAllowedEntityTypes(customWorkspaceTypes);
|
|
149
|
+
const agentAllowedTypeSet = new Set(agentAllowedTypes);
|
|
150
|
+
function rejectDisallowedCreateType(entityType) {
|
|
151
|
+
if (agentAllowedTypeSet.has(entityType))
|
|
152
|
+
return null;
|
|
153
|
+
if (entityType === 'asset') {
|
|
154
|
+
// The schema enum already excludes `asset` (see
|
|
155
|
+
// getAgentAllowedEntityTypes). This is the runtime defense-in-depth
|
|
156
|
+
// path for clients that bypass the enum.
|
|
157
|
+
return wrapToolResult({
|
|
158
|
+
success: false,
|
|
159
|
+
error: 'Asset entries cannot be created via create_entity — they require a binary blob plus a sidecar text file. Use the import_file tool with a local file path, or have the user upload via the workspace import dialog.',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
const hint = isCuratedEntityType(entityType)
|
|
163
|
+
? '' // shouldn't happen for any other curated type — they're all allowed
|
|
164
|
+
: ` Allowed types: ${agentAllowedTypes.join(', ')}.`;
|
|
165
|
+
return wrapToolResult({
|
|
166
|
+
success: false,
|
|
167
|
+
error: `Entry type "${entityType}" is not a known canonical or workspace custom type.${hint}`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
94
170
|
return [
|
|
95
171
|
// Create entity
|
|
96
172
|
{
|
|
97
173
|
name: 'create_entity',
|
|
98
|
-
label: 'Create
|
|
99
|
-
description: 'Create a new
|
|
174
|
+
label: 'Create Entry',
|
|
175
|
+
description: 'Create a new entry in a folder. Always validate required fields before calling. Folder is auto-resolved for app-defined entry types.',
|
|
100
176
|
parameters: T.Object({
|
|
101
|
-
repo: T.Optional(T.String({ description: '
|
|
102
|
-
entityType: T.
|
|
177
|
+
repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
|
|
178
|
+
entityType: T.Union(agentAllowedTypes.map(t => T.Literal(t)), { description: `Entity type. Must be one of: ${agentAllowedTypes.join(', ')}.` }),
|
|
103
179
|
entityId: T.String({ description: 'Unique entity ID in kebab-case' }),
|
|
104
180
|
data: T.Object({}, { description: 'Entity data (YAML frontmatter)', additionalProperties: true }),
|
|
105
181
|
content: T.Optional(T.String({ description: 'Markdown content (optional)' })),
|
|
182
|
+
folder_path: T.Optional(T.String({ description: 'Repo-relative subfolder for the entry (e.g. "clients/acme"). Omit to land at repo root. Parent folders are auto-created.' })),
|
|
106
183
|
commitMessage: T.Optional(T.String({ description: 'Custom commit message (optional)' })),
|
|
107
184
|
}),
|
|
108
185
|
execute: async (toolCallId, params) => {
|
|
109
186
|
try {
|
|
187
|
+
// Defense in depth: LLMs occasionally pass strings that don't match the
|
|
188
|
+
// enum schema. Runtime check ensures the launch allowlist is enforced
|
|
189
|
+
// even if the schema layer is bypassed.
|
|
190
|
+
const typeRejection = rejectDisallowedCreateType(params.entityType);
|
|
191
|
+
if (typeRejection)
|
|
192
|
+
return typeRejection;
|
|
110
193
|
let repoName = params.repo;
|
|
111
194
|
if (!repoName) {
|
|
112
|
-
|
|
113
|
-
if (!repoName)
|
|
114
|
-
return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
|
|
195
|
+
return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
|
|
115
196
|
}
|
|
197
|
+
repoName = resolvePrivateRepo(repoName);
|
|
116
198
|
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
117
|
-
return wrapToolResult({ success: false, error: `
|
|
199
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
118
200
|
}
|
|
201
|
+
const eagerError = checkEagerSkillPermission(params.entityType, params.data, repoName);
|
|
202
|
+
if (eagerError)
|
|
203
|
+
return wrapToolResult({ success: false, error: eagerError });
|
|
119
204
|
const graph = workspaceManager.getGraph(repoName);
|
|
120
205
|
// Workspace-level dedup: warn if an entity with this ID already exists elsewhere
|
|
121
206
|
const existing = workspaceManager.findEntityById(params.entityId);
|
|
122
207
|
if (existing && existing.repoName !== repoName) {
|
|
123
|
-
return wrapToolResult({ success: false, error: `An entity with ID "${params.entityId}" already exists in the "${existing.repoName}"
|
|
208
|
+
return wrapToolResult({ success: false, error: `An entity with ID "${params.entityId}" already exists in the "${existing.repoName}" folder (type: ${existing.data?.entity_type}). Use a unique ID or link to the existing entity with [[${params.entityId}]].` });
|
|
124
209
|
}
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
210
|
+
const actor = effectiveGitUser();
|
|
211
|
+
const sanitizedContent = sanitizeLlmContent(params.content);
|
|
212
|
+
// Workspace-wide uniqueness check for `user_handle` on person
|
|
213
|
+
// entities (one user ↔ one person, workspace-wide), plus owner-
|
|
214
|
+
// only authz so a non-owner agent session can't stamp a
|
|
215
|
+
// pre-linked person via generic create_entity.
|
|
216
|
+
if (params.entityType === 'person') {
|
|
217
|
+
try {
|
|
218
|
+
const incoming = params.data ?? {};
|
|
219
|
+
validateUserHandleInPayload(workspaceManager, incoming);
|
|
220
|
+
if (Object.prototype.hasOwnProperty.call(incoming, 'user_handle')) {
|
|
221
|
+
assertCanChangeUserHandle(getUser(), '', incoming.user_handle);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
if (err instanceof BridgeError) {
|
|
226
|
+
return wrapToolResult({ success: false, error: err.message, code: err.code, ...err.details });
|
|
227
|
+
}
|
|
228
|
+
throw err;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const options = prepareCreatePayload({
|
|
138
232
|
entityType: params.entityType,
|
|
139
233
|
entityId: params.entityId,
|
|
140
|
-
data:
|
|
234
|
+
data: params.data ?? {},
|
|
141
235
|
content: sanitizedContent,
|
|
236
|
+
folderPath: params.folder_path,
|
|
142
237
|
commitMessage: params.commitMessage,
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
238
|
+
}, actor);
|
|
239
|
+
// Surface a live "<user>'s agent is acting" chip in the sidebar for
|
|
240
|
+
// the duration of the mutation. `leave` is always emitted via the
|
|
241
|
+
// inner finally so a thrown error doesn't leave the chip stuck.
|
|
242
|
+
onAgentActivity?.('enter', repoName);
|
|
243
|
+
try {
|
|
244
|
+
const entity = await graph.create(options);
|
|
245
|
+
onMutation?.({ action: 'created', repo: repoName, entityType: params.entityType, entityId: params.entityId });
|
|
246
|
+
return wrapToolResult({
|
|
247
|
+
success: true,
|
|
248
|
+
entity: {
|
|
249
|
+
entityId: entity.id,
|
|
250
|
+
entityType: entity.entityType,
|
|
251
|
+
repo: repoName,
|
|
252
|
+
path: entity.path,
|
|
253
|
+
data: cleanData(entity.data),
|
|
254
|
+
},
|
|
255
|
+
message: `Created ${params.entityType}: ${params.entityId} in ${repoName}. Auto-committed — ready to push.`,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
finally {
|
|
259
|
+
onAgentActivity?.('leave', repoName);
|
|
260
|
+
}
|
|
156
261
|
}
|
|
157
262
|
catch (error) {
|
|
158
263
|
return wrapToolResult({
|
|
@@ -165,31 +270,51 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
165
270
|
// Get entity
|
|
166
271
|
{
|
|
167
272
|
name: 'get_entity',
|
|
168
|
-
label: 'Get
|
|
169
|
-
description: 'Retrieve full
|
|
273
|
+
label: 'Get Entry',
|
|
274
|
+
description: 'Retrieve full entry details. Use repo, entityType, entityId from search/list results. entityType is optional — if omitted it is read from the file.',
|
|
170
275
|
parameters: T.Object({
|
|
171
|
-
repo: T.String({ description: '
|
|
276
|
+
repo: T.String({ description: 'Folder name' }),
|
|
172
277
|
entityType: T.Optional(T.String({ description: 'Entity type (optional — resolved from frontmatter if omitted)' })),
|
|
173
278
|
entityId: T.String({ description: 'Entity ID' }),
|
|
174
279
|
}),
|
|
175
280
|
execute: async (toolCallId, params) => {
|
|
176
281
|
try {
|
|
177
|
-
|
|
178
|
-
|
|
282
|
+
const repo = resolvePrivateRepo(params.repo);
|
|
283
|
+
if (!canAccessRepo(repo, workspaceManager, getUser, authSvc)) {
|
|
284
|
+
return wrapToolResult({ success: false, error: `Folder "${repo}" not found` });
|
|
179
285
|
}
|
|
180
|
-
const graph = workspaceManager.getGraph(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
286
|
+
const graph = workspaceManager.getGraph(repo);
|
|
287
|
+
// If the agent passes the wrong entityType (e.g. based on stale
|
|
288
|
+
// search results), graph.get computes the wrong filesystem path
|
|
289
|
+
// and throws. Fall back to getById, which scans all type subdirs
|
|
290
|
+
// under the folder and resolves the actual location.
|
|
291
|
+
let entity;
|
|
292
|
+
if (params.entityType) {
|
|
293
|
+
try {
|
|
294
|
+
entity = graph.get(params.entityType, params.entityId);
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
entity = graph.getById(params.entityId);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
entity = graph.getById(params.entityId);
|
|
302
|
+
}
|
|
303
|
+
// Prefer the live editor body when a seeded Y.Doc is open. graph.get
|
|
304
|
+
// reads disk, which lags the editor by the autosave debounce — a
|
|
305
|
+
// user's freshly-placed image embed lives in the Y.Doc before it's
|
|
306
|
+
// committed. Returning disk content is what let the agent edit then
|
|
307
|
+
// resend a body missing those embeds, silently dropping images.
|
|
308
|
+
const liveBody = graph.getLiveBody(entity.entityType, entity.id);
|
|
184
309
|
return wrapToolResult({
|
|
185
310
|
success: true,
|
|
186
311
|
entity: {
|
|
187
312
|
entityId: entity.id,
|
|
188
313
|
entityType: entity.entityType,
|
|
189
|
-
repo
|
|
314
|
+
repo,
|
|
190
315
|
path: entity.path,
|
|
191
316
|
data: cleanData(entity.data),
|
|
192
|
-
content: entity.document.content,
|
|
317
|
+
content: liveBody ?? entity.document.content,
|
|
193
318
|
wikilinks: entity.document.wikilinks,
|
|
194
319
|
},
|
|
195
320
|
});
|
|
@@ -205,59 +330,105 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
205
330
|
// Update entity
|
|
206
331
|
{
|
|
207
332
|
name: 'update_entity',
|
|
208
|
-
label: 'Update
|
|
209
|
-
description: 'Update an existing
|
|
333
|
+
label: 'Update Entry',
|
|
334
|
+
description: 'Update an existing entry. Folder is auto-resolved for app-defined types.',
|
|
210
335
|
parameters: T.Object({
|
|
211
|
-
repo: T.Optional(T.String({ description: '
|
|
336
|
+
repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
|
|
212
337
|
entityType: T.String({ description: 'Entity type' }),
|
|
213
338
|
entityId: T.String({ description: 'Entity ID' }),
|
|
214
339
|
data: T.Optional(T.Object({}, { description: 'Updated data fields', additionalProperties: true })),
|
|
215
|
-
content: T.Optional(T.String({ description: 'Updated markdown
|
|
340
|
+
content: T.Optional(T.String({ description: 'Updated markdown body (replaces the entire body)' })),
|
|
216
341
|
commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
|
|
342
|
+
allowImageRemoval: T.Optional(T.Boolean({ description: 'Set true only to deliberately delete image/asset embeds the document currently has; otherwise such a whole-body write is rejected (ASSET_REMOVAL_BLOCKED). Prefer get_entity then patch_entity for small edits.' })),
|
|
217
343
|
}),
|
|
218
344
|
execute: async (toolCallId, params) => {
|
|
219
345
|
try {
|
|
220
346
|
let repoName = params.repo;
|
|
221
347
|
if (!repoName) {
|
|
222
|
-
|
|
223
|
-
if (!repoName)
|
|
224
|
-
return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
|
|
348
|
+
return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
|
|
225
349
|
}
|
|
350
|
+
repoName = resolvePrivateRepo(repoName);
|
|
226
351
|
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
227
|
-
return wrapToolResult({ success: false, error: `
|
|
352
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
228
353
|
}
|
|
354
|
+
const eagerError = checkEagerSkillPermission(params.entityType, params.data, repoName);
|
|
355
|
+
if (eagerError)
|
|
356
|
+
return wrapToolResult({ success: false, error: eagerError });
|
|
229
357
|
const graph = workspaceManager.getGraph(repoName);
|
|
230
|
-
|
|
231
|
-
const dataWithMeta = params.data
|
|
232
|
-
? {
|
|
233
|
-
...params.data,
|
|
234
|
-
updated_at: new Date().toISOString(),
|
|
235
|
-
updated_by: gitUser.id,
|
|
236
|
-
}
|
|
237
|
-
: undefined;
|
|
238
|
-
// Sanitize double-escaped newlines from LLM JSON output
|
|
358
|
+
const actor = effectiveGitUser();
|
|
239
359
|
const sanitizedContent = params.content !== undefined
|
|
240
|
-
? params.content
|
|
241
|
-
|
|
360
|
+
? sanitizeLlmContent(params.content)
|
|
361
|
+
: params.content;
|
|
362
|
+
// Workspace-wide uniqueness check + owner-only authz for
|
|
363
|
+
// `user_handle` on person entities. Generic update_entity must
|
|
364
|
+
// not be a back door around the ownerOnly() gate on the dedicated
|
|
365
|
+
// link/unlink tools — otherwise a member could ask the agent to
|
|
366
|
+
// "set this person's user_handle to mine" and bypass the gate.
|
|
367
|
+
if (params.entityType === 'person' && params.data) {
|
|
368
|
+
try {
|
|
369
|
+
validateUserHandleInPayload(workspaceManager, params.data, { repo: repoName, entityId: params.entityId });
|
|
370
|
+
if (Object.prototype.hasOwnProperty.call(params.data, 'user_handle')) {
|
|
371
|
+
let currentHandle = '';
|
|
372
|
+
try {
|
|
373
|
+
const current = graph.get('person', params.entityId);
|
|
374
|
+
currentHandle = (current?.data?.user_handle ?? '');
|
|
375
|
+
}
|
|
376
|
+
catch { /* new entity / missing — treat as empty */ }
|
|
377
|
+
assertCanChangeUserHandle(getUser(), currentHandle, params.data.user_handle);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
if (err instanceof BridgeError) {
|
|
382
|
+
return wrapToolResult({ success: false, error: err.message, code: err.code, ...err.details });
|
|
383
|
+
}
|
|
384
|
+
throw err;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
const options = prepareUpdatePayload({
|
|
242
388
|
entityType: params.entityType,
|
|
243
389
|
entityId: params.entityId,
|
|
244
|
-
data:
|
|
390
|
+
data: params.data,
|
|
245
391
|
content: sanitizedContent,
|
|
246
392
|
commitMessage: params.commitMessage,
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
393
|
+
}, actor);
|
|
394
|
+
onAgentActivity?.('enter', repoName);
|
|
395
|
+
try {
|
|
396
|
+
// Shared diagnosed update (c6ef9297 contract): throws
|
|
397
|
+
// SilentDropError when the caller intended a change that left the
|
|
398
|
+
// file byte-identical, surfaced via the outer catch so the agent
|
|
399
|
+
// isn't misled by a success envelope.
|
|
400
|
+
const { entity, frontmatter_changed, content_changed, noop, broadcast } = await diagnosedUpdate(graph, options, { data: params.data, content: sanitizedContent }, { allowAssetRemoval: params.allowImageRemoval });
|
|
401
|
+
onMutation?.({ action: 'updated', repo: repoName, entityType: params.entityType, entityId: params.entityId });
|
|
402
|
+
return wrapToolResult({
|
|
403
|
+
success: true,
|
|
404
|
+
entity: {
|
|
405
|
+
entityId: entity.id,
|
|
406
|
+
entityType: entity.entityType,
|
|
407
|
+
repo: repoName,
|
|
408
|
+
data: cleanData(entity.data),
|
|
409
|
+
},
|
|
410
|
+
frontmatter_changed,
|
|
411
|
+
content_changed,
|
|
412
|
+
noop,
|
|
413
|
+
broadcast,
|
|
414
|
+
message: noop
|
|
415
|
+
? `No change to ${params.entityType}: ${params.entityId} — on-disk state already matched.`
|
|
416
|
+
: `Updated ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
finally {
|
|
420
|
+
onAgentActivity?.('leave', repoName);
|
|
421
|
+
}
|
|
259
422
|
}
|
|
260
423
|
catch (error) {
|
|
424
|
+
if (error instanceof DroppedAssetError) {
|
|
425
|
+
return wrapToolResult({
|
|
426
|
+
success: false,
|
|
427
|
+
code: 'ASSET_REMOVAL_BLOCKED',
|
|
428
|
+
droppedAssets: error.dropped,
|
|
429
|
+
error: error.message,
|
|
430
|
+
});
|
|
431
|
+
}
|
|
261
432
|
return wrapToolResult({
|
|
262
433
|
success: false,
|
|
263
434
|
error: error instanceof Error ? error.message : 'Unknown error',
|
|
@@ -265,13 +436,157 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
265
436
|
}
|
|
266
437
|
},
|
|
267
438
|
},
|
|
439
|
+
// List assets already uploaded to a folder
|
|
440
|
+
{
|
|
441
|
+
name: 'list_assets',
|
|
442
|
+
label: 'List Assets',
|
|
443
|
+
description: 'List images/files already uploaded to a folder, with a ready-to-paste markdown embed for each. ' +
|
|
444
|
+
'Use this to find an asset a user placed (e.g. a screenshot) so you can embed it into an entry — ' +
|
|
445
|
+
'assets live in storage (R2/local), NOT on the local filesystem, so import_file cannot find them. ' +
|
|
446
|
+
'Each result has an `embed` string: use it verbatim and NEVER write ![[filename]] transclusion syntax ' +
|
|
447
|
+
'(it does not render). Optionally filter by entityType/entityId. This tool only references existing ' +
|
|
448
|
+
'assets — uploads happen via the workspace UI or import_file.',
|
|
449
|
+
parameters: T.Object({
|
|
450
|
+
repo: T.String({ description: 'Folder name' }),
|
|
451
|
+
entityType: T.Optional(T.String({ description: 'Filter to assets owned by entries of this type' })),
|
|
452
|
+
entityId: T.Optional(T.String({ description: 'Filter to assets owned by this entry id' })),
|
|
453
|
+
}),
|
|
454
|
+
execute: async (toolCallId, params) => {
|
|
455
|
+
try {
|
|
456
|
+
const repoName = resolvePrivateRepo(params.repo);
|
|
457
|
+
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
458
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
459
|
+
}
|
|
460
|
+
let assets = await listRepoAssets(repoName, workspaceManager);
|
|
461
|
+
if (params.entityType)
|
|
462
|
+
assets = assets.filter(a => a.entityType === params.entityType);
|
|
463
|
+
if (params.entityId)
|
|
464
|
+
assets = assets.filter(a => a.entityId === params.entityId);
|
|
465
|
+
return wrapToolResult({
|
|
466
|
+
success: true,
|
|
467
|
+
repo: repoName,
|
|
468
|
+
count: assets.length,
|
|
469
|
+
assets: assets.map(a => ({
|
|
470
|
+
asset_id: a.assetId,
|
|
471
|
+
filename: a.filename,
|
|
472
|
+
mime_type: a.contentType,
|
|
473
|
+
entityType: a.entityType,
|
|
474
|
+
entityId: a.entityId,
|
|
475
|
+
entityName: a.entityName,
|
|
476
|
+
url: a.url,
|
|
477
|
+
embed: a.embed,
|
|
478
|
+
})),
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
return wrapToolResult({ success: false, error: error instanceof Error ? error.message : 'Unknown error' });
|
|
483
|
+
}
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
// Embed an already-uploaded asset into an entry body
|
|
487
|
+
{
|
|
488
|
+
name: 'attach_asset_to_entity',
|
|
489
|
+
label: 'Attach Asset',
|
|
490
|
+
description: 'Embed an already-uploaded asset (from list_assets) into an entry body using its render-safe markdown, ' +
|
|
491
|
+
'without rewriting the whole body. mode "append" adds it at the end; mode "replace_placeholder" swaps dead ' +
|
|
492
|
+
'placeholder text (e.g. an ![[Foo.png]] written earlier) for the working embed. Drop-guarded: rejects with ' +
|
|
493
|
+
'ASSET_REMOVAL_BLOCKED if it would remove other image embeds (append only — replace_placeholder is exempt ' +
|
|
494
|
+
'since the placeholder it removes is the dead reference being fixed).',
|
|
495
|
+
parameters: T.Object({
|
|
496
|
+
repo: T.String({ description: 'Folder name' }),
|
|
497
|
+
entityType: T.String({ description: 'Entity type of the target entry' }),
|
|
498
|
+
entityId: T.String({ description: 'Entity ID of the target entry' }),
|
|
499
|
+
url: T.String({ description: 'Asset url, taken verbatim from list_assets' }),
|
|
500
|
+
alt: T.Optional(T.String({ description: 'Alt text / caption. Defaults to the asset filename.' })),
|
|
501
|
+
mode: T.Optional(T.Union([T.Literal('append'), T.Literal('replace_placeholder')], { description: 'append (default) or replace_placeholder' })),
|
|
502
|
+
placeholder: T.Optional(T.String({ description: 'Required for replace_placeholder: exact text to replace' })),
|
|
503
|
+
expectedCount: T.Optional(T.Number({ description: 'For replace_placeholder: require this many occurrences, else reject' })),
|
|
504
|
+
}),
|
|
505
|
+
execute: async (toolCallId, params) => {
|
|
506
|
+
try {
|
|
507
|
+
const repoName = resolvePrivateRepo(params.repo);
|
|
508
|
+
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
509
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
510
|
+
}
|
|
511
|
+
const url = params.url ?? '';
|
|
512
|
+
if (!url.trim())
|
|
513
|
+
return wrapToolResult({ success: false, error: 'url is required' });
|
|
514
|
+
const mode = params.mode ?? 'append';
|
|
515
|
+
if (mode === 'replace_placeholder' && !params.placeholder) {
|
|
516
|
+
return wrapToolResult({ success: false, error: 'mode "replace_placeholder" requires a non-empty placeholder' });
|
|
517
|
+
}
|
|
518
|
+
const filename = params.alt ?? (url.split('/').pop() || 'asset').split('?')[0];
|
|
519
|
+
const embed = assetEmbed(filename, url);
|
|
520
|
+
const graph = workspaceManager.getGraph(repoName);
|
|
521
|
+
const entity = graph.get(params.entityType, params.entityId);
|
|
522
|
+
const currentBody = graph.getLiveBody(params.entityType, params.entityId) ?? entity.document.content;
|
|
523
|
+
let newBody;
|
|
524
|
+
let occurrences;
|
|
525
|
+
let allowAssetRemoval = false;
|
|
526
|
+
if (mode === 'replace_placeholder') {
|
|
527
|
+
const ph = params.placeholder;
|
|
528
|
+
let count = 0;
|
|
529
|
+
for (let i = currentBody.indexOf(ph); i !== -1; i = currentBody.indexOf(ph, i + ph.length))
|
|
530
|
+
count++;
|
|
531
|
+
if (count === 0) {
|
|
532
|
+
return wrapToolResult({ success: false, code: 'NO_MATCH', error: `placeholder not present in ${params.entityType}/${params.entityId}.` });
|
|
533
|
+
}
|
|
534
|
+
if (params.expectedCount !== undefined && count !== params.expectedCount) {
|
|
535
|
+
return wrapToolResult({ success: false, code: 'AMBIGUOUS_MATCH', occurrences: count, error: `Expected ${params.expectedCount} occurrence(s) of placeholder, found ${count}.` });
|
|
536
|
+
}
|
|
537
|
+
occurrences = count;
|
|
538
|
+
newBody = currentBody.split(ph).join(embed);
|
|
539
|
+
// The placeholder we're removing is itself a recognized embed
|
|
540
|
+
// target; swapping it for the working embed is the whole point.
|
|
541
|
+
allowAssetRemoval = true;
|
|
542
|
+
}
|
|
543
|
+
else {
|
|
544
|
+
if (currentBody.includes(embed)) {
|
|
545
|
+
return wrapToolResult({ success: false, code: 'ALREADY_PRESENT', error: `Asset embed already present in ${params.entityType}/${params.entityId}.` });
|
|
546
|
+
}
|
|
547
|
+
newBody = currentBody.trimEnd() + '\n\n' + embed + '\n';
|
|
548
|
+
}
|
|
549
|
+
const options = prepareUpdatePayload({
|
|
550
|
+
entityType: params.entityType,
|
|
551
|
+
entityId: params.entityId,
|
|
552
|
+
content: newBody,
|
|
553
|
+
}, effectiveGitUser());
|
|
554
|
+
onAgentActivity?.('enter', repoName);
|
|
555
|
+
try {
|
|
556
|
+
const { entity: updated, frontmatter_changed, content_changed, noop, broadcast } = await diagnosedUpdate(graph, options, { content: newBody }, { allowAssetRemoval });
|
|
557
|
+
onMutation?.({ action: 'updated', repo: repoName, entityType: params.entityType, entityId: params.entityId });
|
|
558
|
+
return wrapToolResult({
|
|
559
|
+
success: true,
|
|
560
|
+
entity: { entityId: updated.id, entityType: updated.entityType, repo: repoName },
|
|
561
|
+
embed,
|
|
562
|
+
mode,
|
|
563
|
+
occurrences,
|
|
564
|
+
frontmatter_changed,
|
|
565
|
+
content_changed,
|
|
566
|
+
noop,
|
|
567
|
+
broadcast,
|
|
568
|
+
message: `Embedded ${filename} into ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
finally {
|
|
572
|
+
onAgentActivity?.('leave', repoName);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
if (error instanceof DroppedAssetError) {
|
|
577
|
+
return wrapToolResult({ success: false, code: 'ASSET_REMOVAL_BLOCKED', droppedAssets: error.dropped, error: error.message });
|
|
578
|
+
}
|
|
579
|
+
return wrapToolResult({ success: false, error: error instanceof Error ? error.message : 'Unknown error' });
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
},
|
|
268
583
|
// Delete entity
|
|
269
584
|
{
|
|
270
585
|
name: 'delete_entity',
|
|
271
|
-
label: 'Delete
|
|
272
|
-
description: 'Delete an
|
|
586
|
+
label: 'Delete Entry',
|
|
587
|
+
description: 'Delete an entry. Use with caution! Folder is auto-resolved for app-defined types.',
|
|
273
588
|
parameters: T.Object({
|
|
274
|
-
repo: T.Optional(T.String({ description: '
|
|
589
|
+
repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
|
|
275
590
|
entityType: T.String({ description: 'Entity type' }),
|
|
276
591
|
entityId: T.String({ description: 'Entity ID' }),
|
|
277
592
|
commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
|
|
@@ -280,20 +595,25 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
280
595
|
try {
|
|
281
596
|
let repoName = params.repo;
|
|
282
597
|
if (!repoName) {
|
|
283
|
-
|
|
284
|
-
if (!repoName)
|
|
285
|
-
return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
|
|
598
|
+
return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
|
|
286
599
|
}
|
|
600
|
+
repoName = resolvePrivateRepo(repoName);
|
|
287
601
|
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
288
|
-
return wrapToolResult({ success: false, error: `
|
|
602
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
289
603
|
}
|
|
290
604
|
const graph = workspaceManager.getGraph(repoName);
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
605
|
+
onAgentActivity?.('enter', repoName);
|
|
606
|
+
try {
|
|
607
|
+
await graph.delete(params.entityType, params.entityId, params.commitMessage);
|
|
608
|
+
onMutation?.({ action: 'deleted', repo: repoName, entityType: params.entityType, entityId: params.entityId });
|
|
609
|
+
return wrapToolResult({
|
|
610
|
+
success: true,
|
|
611
|
+
message: `Deleted ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
finally {
|
|
615
|
+
onAgentActivity?.('leave', repoName);
|
|
616
|
+
}
|
|
297
617
|
}
|
|
298
618
|
catch (error) {
|
|
299
619
|
return wrapToolResult({
|
|
@@ -307,46 +627,93 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
307
627
|
{
|
|
308
628
|
name: 'import_file',
|
|
309
629
|
label: 'Import File',
|
|
310
|
-
description: 'Import a local file as a Studiograph
|
|
630
|
+
description: 'Import a local file as a Studiograph entry. Text formats become typed entries (.md/.txt → note, .csv → dataset). Binary formats (PDF, images, design files, video, audio, archives) become asset entries.',
|
|
311
631
|
parameters: T.Object({
|
|
312
632
|
path: T.String({ description: 'Absolute path or ~/relative path to the file' }),
|
|
313
|
-
|
|
314
|
-
entityType: T.Optional(T.String({ description: 'Override entity type (default: auto-detect from extension)' })),
|
|
633
|
+
folder: T.String({ description: 'Target folder name' }),
|
|
634
|
+
entityType: T.Optional(T.String({ description: 'Override entity type (default: auto-detect from extension; ignored for asset uploads)' })),
|
|
315
635
|
entityId: T.Optional(T.String({ description: 'Override entity ID (default: from filename)' })),
|
|
316
636
|
}),
|
|
317
637
|
execute: async (toolCallId, params) => {
|
|
318
638
|
try {
|
|
319
|
-
if (!canAccessRepo(params.
|
|
320
|
-
return wrapToolResult({ success: false, error: `
|
|
639
|
+
if (!canAccessRepo(params.folder, workspaceManager, getUser, authSvc)) {
|
|
640
|
+
return wrapToolResult({ success: false, error: `Folder "${params.folder}" not found` });
|
|
321
641
|
}
|
|
322
642
|
const { readFileSync, existsSync } = await import('fs');
|
|
323
|
-
const { resolve } = await import('path');
|
|
643
|
+
const { resolve, basename, sep } = await import('path');
|
|
324
644
|
const { homedir } = await import('os');
|
|
325
645
|
const { importFile, isSupportedFile } = await import('../../services/import-service.js');
|
|
646
|
+
const { isAssetUploadExtension } = await import('../../services/assets/base.js');
|
|
647
|
+
const { uploadAsset } = await import('../../services/asset-upload-service.js');
|
|
326
648
|
const filePath = params.path.startsWith('~/')
|
|
327
649
|
? resolve(homedir(), params.path.slice(2))
|
|
328
650
|
: resolve(params.path);
|
|
329
651
|
if (!existsSync(filePath)) {
|
|
330
652
|
return wrapToolResult({ success: false, error: `File not found: ${filePath}` });
|
|
331
653
|
}
|
|
654
|
+
const graph = workspaceManager.getGraph(params.folder);
|
|
655
|
+
const fname = basename(filePath);
|
|
656
|
+
// Path-exfil guard: the agent reads bytes off disk and uploads
|
|
657
|
+
// them as a workspace asset, accessible via /api/assets/* by any
|
|
658
|
+
// folder member. Without an allowlist, an LLM prompt injection in
|
|
659
|
+
// an imported note can ask the agent to grab ~/.ssh/id_rsa, .env
|
|
660
|
+
// files, kubeconfigs, etc. by renaming them to a permitted
|
|
661
|
+
// extension. Restrict to roots a user would plausibly drop files
|
|
662
|
+
// from: the workspace itself, ~/Downloads, ~/Documents.
|
|
663
|
+
const home = homedir();
|
|
664
|
+
const workspaceRoot = graph.getWorkspaceRoot();
|
|
665
|
+
const allowedRoots = [
|
|
666
|
+
workspaceRoot,
|
|
667
|
+
resolve(home, 'Downloads'),
|
|
668
|
+
resolve(home, 'Documents'),
|
|
669
|
+
].filter((r) => Boolean(r)).map(r => r.endsWith(sep) ? r : r + sep);
|
|
670
|
+
const isInAllowedRoot = allowedRoots.some(root => filePath === root.slice(0, -1) || filePath.startsWith(root));
|
|
671
|
+
if (!isInAllowedRoot) {
|
|
672
|
+
return wrapToolResult({
|
|
673
|
+
success: false,
|
|
674
|
+
error: `Path "${filePath}" is outside the import allowlist. Files must live under the workspace, ~/Downloads, or ~/Documents.`,
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
// Binary extensions → asset wrapper. The text-import path doesn't
|
|
678
|
+
// know how to handle .indd / .pptx / etc. and would either reject
|
|
679
|
+
// them or (for .pdf) mistakenly land them as a `note` entity with
|
|
680
|
+
// extracted body text. Route to uploadAsset for parity with the
|
|
681
|
+
// web import dispatcher.
|
|
682
|
+
if (isAssetUploadExtension(fname)) {
|
|
683
|
+
const buffer = readFileSync(filePath);
|
|
684
|
+
const result = await uploadAsset({
|
|
685
|
+
graph,
|
|
686
|
+
filename: fname,
|
|
687
|
+
buffer,
|
|
688
|
+
workspacePath: graph.getWorkspaceRoot(),
|
|
689
|
+
});
|
|
690
|
+
onMutation?.({ action: 'created', repo: params.folder, entityType: 'asset', entityId: result.entityId });
|
|
691
|
+
return wrapToolResult({
|
|
692
|
+
success: true,
|
|
693
|
+
entityType: 'asset',
|
|
694
|
+
entityId: result.entityId,
|
|
695
|
+
asset_kind: result.asset_kind,
|
|
696
|
+
asset_size: result.asset_size,
|
|
697
|
+
pages: result.pages,
|
|
698
|
+
message: `Imported ${fname} as asset/${result.entityId} in ${params.folder}`,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
332
701
|
if (!isSupportedFile(filePath)) {
|
|
333
|
-
return wrapToolResult({ success: false, error: `Unsupported file type
|
|
702
|
+
return wrapToolResult({ success: false, error: `Unsupported file type for ${fname}` });
|
|
334
703
|
}
|
|
335
|
-
const graph = workspaceManager.getGraph(params.collection);
|
|
336
704
|
const content = readFileSync(filePath);
|
|
337
|
-
const
|
|
338
|
-
const result = await importFile(graph, basename(filePath), content, {
|
|
705
|
+
const result = await importFile(graph, fname, content, {
|
|
339
706
|
entityType: params.entityType,
|
|
340
707
|
entityId: params.entityId,
|
|
341
708
|
});
|
|
342
709
|
if (result.status === 'created') {
|
|
343
|
-
onMutation?.({ action: 'created', repo: params.
|
|
710
|
+
onMutation?.({ action: 'created', repo: params.folder, entityType: result.entityType, entityId: result.entityId });
|
|
344
711
|
}
|
|
345
712
|
return wrapToolResult({
|
|
346
713
|
success: result.status === 'created',
|
|
347
714
|
...result,
|
|
348
715
|
message: result.status === 'created'
|
|
349
|
-
? `Imported ${
|
|
716
|
+
? `Imported ${fname} as ${result.entityType}/${result.entityId} in ${params.folder}`
|
|
350
717
|
: result.error,
|
|
351
718
|
});
|
|
352
719
|
}
|
|
@@ -361,10 +728,10 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
361
728
|
// Rename entity (change ID)
|
|
362
729
|
{
|
|
363
730
|
name: 'rename_entity',
|
|
364
|
-
label: 'Rename
|
|
365
|
-
description: 'Rename an
|
|
731
|
+
label: 'Rename Entry',
|
|
732
|
+
description: 'Rename an entry by changing its ID. Preserves all data, content, and source_ref. The old ID will no longer exist. Folder is auto-resolved for app-defined types.',
|
|
366
733
|
parameters: T.Object({
|
|
367
|
-
repo: T.Optional(T.String({ description: '
|
|
734
|
+
repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
|
|
368
735
|
entityType: T.String({ description: 'Entity type' }),
|
|
369
736
|
oldId: T.String({ description: 'Current entity ID' }),
|
|
370
737
|
newId: T.String({ description: 'New entity ID (kebab-case)' }),
|
|
@@ -373,12 +740,11 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
373
740
|
try {
|
|
374
741
|
let repoName = params.repo;
|
|
375
742
|
if (!repoName) {
|
|
376
|
-
|
|
377
|
-
if (!repoName)
|
|
378
|
-
return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
|
|
743
|
+
return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
|
|
379
744
|
}
|
|
745
|
+
repoName = resolvePrivateRepo(repoName);
|
|
380
746
|
if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
|
|
381
|
-
return wrapToolResult({ success: false, error: `
|
|
747
|
+
return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
|
|
382
748
|
}
|
|
383
749
|
const graph = workspaceManager.getGraph(repoName);
|
|
384
750
|
const result = await graph.rename(params.entityType, params.oldId, params.newId);
|
|
@@ -398,41 +764,41 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
398
764
|
}
|
|
399
765
|
},
|
|
400
766
|
},
|
|
401
|
-
//
|
|
767
|
+
// Transfer entity across repos (cross-repo move). Distinct from
|
|
768
|
+
// folder-tools' `move_entity`, which relocates within one repo.
|
|
402
769
|
{
|
|
403
|
-
name: '
|
|
404
|
-
label: '
|
|
405
|
-
description: 'Move an
|
|
770
|
+
name: 'transfer_entity',
|
|
771
|
+
label: 'Transfer Entry',
|
|
772
|
+
description: 'Move an entry from one repo to another. Preserves all data, content, and wikilinks. Requires access to both folders. For relocating within the same repo (folder_path change), use move_entity instead.',
|
|
406
773
|
parameters: T.Object({
|
|
407
|
-
sourceRepo: T.String({ description: 'Source
|
|
408
|
-
targetRepo: T.String({ description: 'Target
|
|
774
|
+
sourceRepo: T.String({ description: 'Source repo name' }),
|
|
775
|
+
targetRepo: T.String({ description: 'Target repo name' }),
|
|
409
776
|
entityType: T.String({ description: 'Entity type' }),
|
|
410
777
|
entityId: T.String({ description: 'Entity ID' }),
|
|
411
778
|
commitMessage: T.Optional(T.String({ description: 'Custom commit message (optional)' })),
|
|
412
779
|
}),
|
|
413
780
|
execute: async (toolCallId, params) => {
|
|
414
781
|
try {
|
|
415
|
-
const denied = adminOnly(getUser);
|
|
416
|
-
if (denied)
|
|
417
|
-
return wrapToolResult({ success: false, error: denied });
|
|
418
782
|
if (!canAccessRepo(params.sourceRepo, workspaceManager, getUser, authSvc)) {
|
|
419
|
-
return wrapToolResult({ success: false, error: `
|
|
783
|
+
return wrapToolResult({ success: false, error: `Folder "${params.sourceRepo}" not found` });
|
|
420
784
|
}
|
|
421
785
|
if (!canAccessRepo(params.targetRepo, workspaceManager, getUser, authSvc)) {
|
|
422
|
-
return wrapToolResult({ success: false, error: `
|
|
786
|
+
return wrapToolResult({ success: false, error: `Folder "${params.targetRepo}" not found` });
|
|
423
787
|
}
|
|
424
788
|
const sourceGraph = workspaceManager.getGraph(params.sourceRepo);
|
|
425
789
|
const targetGraph = workspaceManager.getGraph(params.targetRepo);
|
|
426
790
|
// Read the full entity from source
|
|
427
791
|
const entity = sourceGraph.get(params.entityType, params.entityId);
|
|
428
792
|
// Create in target repo
|
|
793
|
+
const actor = effectiveGitUser();
|
|
429
794
|
const now = new Date().toISOString();
|
|
430
795
|
await targetGraph.create({
|
|
431
796
|
entityType: params.entityType,
|
|
432
797
|
entityId: params.entityId,
|
|
433
|
-
data: { ...entity.data, updated_at: now, updated_by:
|
|
798
|
+
data: { ...entity.data, updated_at: now, updated_by: actor.id },
|
|
434
799
|
content: entity.document.content || '',
|
|
435
800
|
commitMessage: params.commitMessage || `Move ${params.entityType} ${params.entityId} from ${params.sourceRepo} to ${params.targetRepo}`,
|
|
801
|
+
user: actor,
|
|
436
802
|
});
|
|
437
803
|
// Delete from source repo
|
|
438
804
|
await sourceGraph.delete(params.entityType, params.entityId, `Move ${params.entityType} ${params.entityId} to ${params.targetRepo}`);
|
|
@@ -454,12 +820,12 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
454
820
|
// Search entities
|
|
455
821
|
{
|
|
456
822
|
name: 'search_entities',
|
|
457
|
-
label: 'Search
|
|
458
|
-
description: 'Search for
|
|
823
|
+
label: 'Search Entries',
|
|
824
|
+
description: 'Search for entries across folders with filters.',
|
|
459
825
|
parameters: T.Object({
|
|
460
826
|
query: T.Optional(T.String({ description: 'Search query (full-text)' })),
|
|
461
827
|
entityType: T.Optional(T.String({ description: 'Filter by entity type' })),
|
|
462
|
-
repoNames: T.Optional(T.Array(T.String(), { description: 'Limit to specific
|
|
828
|
+
repoNames: T.Optional(T.Array(T.String(), { description: 'Limit to specific folders' })),
|
|
463
829
|
visibility: T.Optional(T.Array(T.String(), { description: 'Filter by visibility (public, team, admin, restricted)' })),
|
|
464
830
|
tags: T.Optional(T.Array(T.String(), { description: 'Filter by tags' })),
|
|
465
831
|
dateRange: T.Optional(T.Object({
|
|
@@ -471,9 +837,9 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
471
837
|
}),
|
|
472
838
|
execute: async (toolCallId, params) => {
|
|
473
839
|
try {
|
|
474
|
-
// Scope search to accessible
|
|
840
|
+
// Scope search to accessible folders
|
|
475
841
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
476
|
-
let repoNames = params.repoNames;
|
|
842
|
+
let repoNames = params.repoNames?.map((r) => resolvePrivateRepo(r));
|
|
477
843
|
if (allowed) {
|
|
478
844
|
repoNames = repoNames
|
|
479
845
|
? repoNames.filter((r) => allowed.has(r))
|
|
@@ -511,8 +877,8 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
511
877
|
// List entities
|
|
512
878
|
{
|
|
513
879
|
name: 'list_entities',
|
|
514
|
-
label: 'List
|
|
515
|
-
description: 'List all
|
|
880
|
+
label: 'List Entries',
|
|
881
|
+
description: 'List all entries of a given type (or all types)',
|
|
516
882
|
parameters: T.Object({
|
|
517
883
|
entityType: T.Optional(T.String({ description: 'Entity type to list (omit for all)' })),
|
|
518
884
|
limit: T.Optional(T.Number({ description: 'Max results' })),
|
|
@@ -520,7 +886,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
520
886
|
execute: async (toolCallId, params) => {
|
|
521
887
|
try {
|
|
522
888
|
let results = workspaceManager.list(params.entityType, params.limit);
|
|
523
|
-
// Filter to accessible
|
|
889
|
+
// Filter to accessible folders
|
|
524
890
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
525
891
|
if (allowed) {
|
|
526
892
|
results = results.filter(r => allowed.has(r.repoName));
|
|
@@ -547,20 +913,21 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
547
913
|
// Get related entities
|
|
548
914
|
{
|
|
549
915
|
name: 'get_related',
|
|
550
|
-
label: 'Get Related
|
|
551
|
-
description: 'Get
|
|
916
|
+
label: 'Get Related Entries',
|
|
917
|
+
description: 'Get entries related to a given entry via wikilinks (cross-folder supported). Pass repo, entityType, entityId from search/list results.',
|
|
552
918
|
parameters: T.Object({
|
|
553
|
-
repo: T.String({ description: '
|
|
919
|
+
repo: T.String({ description: 'Folder name' }),
|
|
554
920
|
entityType: T.String({ description: 'Entity type' }),
|
|
555
921
|
entityId: T.String({ description: 'Entity ID' }),
|
|
556
922
|
}),
|
|
557
923
|
execute: async (toolCallId, params) => {
|
|
558
924
|
try {
|
|
559
|
-
|
|
560
|
-
|
|
925
|
+
const repo = resolvePrivateRepo(params.repo);
|
|
926
|
+
if (!canAccessRepo(repo, workspaceManager, getUser, authSvc)) {
|
|
927
|
+
return wrapToolResult({ success: false, error: `Folder "${repo}" not found` });
|
|
561
928
|
}
|
|
562
|
-
let related = workspaceManager.getRelated(
|
|
563
|
-
// Filter cross-
|
|
929
|
+
let related = workspaceManager.getRelated(repo, params.entityType, params.entityId);
|
|
930
|
+
// Filter cross-folder results to accessible repos
|
|
564
931
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
565
932
|
if (allowed) {
|
|
566
933
|
related = related.filter(r => allowed.has(r.repoName));
|
|
@@ -588,19 +955,19 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
588
955
|
{
|
|
589
956
|
name: 'get_backlinks',
|
|
590
957
|
label: 'Get Backlinks',
|
|
591
|
-
description: 'Get
|
|
958
|
+
description: 'Get entries that link to a given entry (cross-folder supported). Pass repo, entityType, entityId from search/list results.',
|
|
592
959
|
parameters: T.Object({
|
|
593
|
-
repo: T.String({ description: '
|
|
960
|
+
repo: T.String({ description: 'Folder name' }),
|
|
594
961
|
entityType: T.String({ description: 'Entity type' }),
|
|
595
962
|
entityId: T.String({ description: 'Entity ID' }),
|
|
596
963
|
}),
|
|
597
964
|
execute: async (toolCallId, params) => {
|
|
598
965
|
try {
|
|
599
966
|
if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
|
|
600
|
-
return wrapToolResult({ success: false, error: `
|
|
967
|
+
return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
|
|
601
968
|
}
|
|
602
969
|
let backlinks = workspaceManager.getBacklinks(params.repo, params.entityType, params.entityId);
|
|
603
|
-
// Filter cross-
|
|
970
|
+
// Filter cross-folder results to accessible repos
|
|
604
971
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
605
972
|
if (allowed) {
|
|
606
973
|
backlinks = backlinks.filter(r => allowed.has(r.repoName));
|
|
@@ -628,16 +995,16 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
628
995
|
{
|
|
629
996
|
name: 'validate_wikilinks',
|
|
630
997
|
label: 'Validate Wikilinks',
|
|
631
|
-
description: 'Validate all wikilinks in an
|
|
998
|
+
description: 'Validate all wikilinks in an entry (checks same folder and cross-folder)',
|
|
632
999
|
parameters: T.Object({
|
|
633
|
-
repo: T.String({ description: '
|
|
1000
|
+
repo: T.String({ description: 'Folder name' }),
|
|
634
1001
|
entityType: T.String({ description: 'Entity type' }),
|
|
635
1002
|
entityId: T.String({ description: 'Entity ID' }),
|
|
636
1003
|
}),
|
|
637
1004
|
execute: async (toolCallId, params) => {
|
|
638
1005
|
try {
|
|
639
1006
|
if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
|
|
640
|
-
return wrapToolResult({ success: false, error: `
|
|
1007
|
+
return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
|
|
641
1008
|
}
|
|
642
1009
|
const validation = workspaceManager.validateWikilinks(params.repo, params.entityType, params.entityId);
|
|
643
1010
|
return wrapToolResult({
|
|
@@ -672,7 +1039,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
672
1039
|
const summary = workspaceManager.getSummary();
|
|
673
1040
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
674
1041
|
if (allowed) {
|
|
675
|
-
// Filter summary to accessible
|
|
1042
|
+
// Filter summary to accessible folders only
|
|
676
1043
|
const filteredByRepo = {};
|
|
677
1044
|
let filteredTotal = 0;
|
|
678
1045
|
for (const [repo, count] of Object.entries(summary.entitiesByRepo)) {
|
|
@@ -684,19 +1051,19 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
684
1051
|
return wrapToolResult({
|
|
685
1052
|
success: true,
|
|
686
1053
|
summary: {
|
|
687
|
-
|
|
1054
|
+
totalFolders: allowed.size,
|
|
688
1055
|
totalEntities: filteredTotal,
|
|
689
|
-
|
|
1056
|
+
entitiesByFolder: filteredByRepo,
|
|
690
1057
|
},
|
|
691
1058
|
});
|
|
692
1059
|
}
|
|
693
1060
|
return wrapToolResult({
|
|
694
1061
|
success: true,
|
|
695
1062
|
summary: {
|
|
696
|
-
|
|
1063
|
+
totalFolders: summary.totalRepos,
|
|
697
1064
|
totalEntities: summary.totalEntities,
|
|
698
1065
|
entitiesByType: summary.entitiesByType,
|
|
699
|
-
|
|
1066
|
+
entitiesByFolder: summary.entitiesByRepo,
|
|
700
1067
|
},
|
|
701
1068
|
});
|
|
702
1069
|
}
|
|
@@ -708,11 +1075,11 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
708
1075
|
}
|
|
709
1076
|
},
|
|
710
1077
|
},
|
|
711
|
-
// List
|
|
1078
|
+
// List folders
|
|
712
1079
|
{
|
|
713
1080
|
name: 'list_repos',
|
|
714
|
-
label: 'List
|
|
715
|
-
description: 'List all
|
|
1081
|
+
label: 'List Folders',
|
|
1082
|
+
description: 'List all folders in the workspace',
|
|
716
1083
|
parameters: T.Object({}),
|
|
717
1084
|
execute: async (toolCallId, params) => {
|
|
718
1085
|
try {
|
|
@@ -724,12 +1091,12 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
724
1091
|
return wrapToolResult({
|
|
725
1092
|
success: true,
|
|
726
1093
|
count: repos.length,
|
|
727
|
-
|
|
1094
|
+
folders: repos.map(r => ({
|
|
728
1095
|
name: r.name,
|
|
729
1096
|
type: r.type,
|
|
730
1097
|
description: r.description,
|
|
731
1098
|
path: r.path,
|
|
732
|
-
|
|
1099
|
+
personal: r.personal || false,
|
|
733
1100
|
})),
|
|
734
1101
|
});
|
|
735
1102
|
}
|
|
@@ -741,40 +1108,35 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
741
1108
|
}
|
|
742
1109
|
},
|
|
743
1110
|
},
|
|
744
|
-
// Create a new
|
|
1111
|
+
// Create a new folder
|
|
745
1112
|
{
|
|
746
|
-
name: '
|
|
747
|
-
label: 'Create
|
|
748
|
-
description: 'Create a new
|
|
1113
|
+
name: 'create_folder',
|
|
1114
|
+
label: 'Create Folder',
|
|
1115
|
+
description: 'Create a new shared folder in the workspace. Folders are git-backed containers for entries. New folders are shared with teammates who have access; the creator is granted admin. Every user already has a personal "My Folder" folder auto-provisioned — do not use this tool to create another one.',
|
|
749
1116
|
parameters: T.Object({
|
|
750
|
-
name: T.String({ description: '
|
|
751
|
-
description: T.Optional(T.String({ description: 'Short description of the
|
|
752
|
-
private: T.Optional(T.Boolean({ description: 'If true, creates a private collection visible only to you' })),
|
|
1117
|
+
name: T.String({ description: 'Folder name in kebab-case (e.g., "client-projects")' }),
|
|
1118
|
+
description: T.Optional(T.String({ description: 'Short description of the folder' })),
|
|
753
1119
|
}),
|
|
754
1120
|
execute: async (toolCallId, params) => {
|
|
755
1121
|
try {
|
|
756
1122
|
const user = getUser();
|
|
757
|
-
// Non-private collections require admin; private collections can be created by anyone
|
|
758
|
-
if (!params.private && user && user.role !== 'admin') {
|
|
759
|
-
return wrapToolResult({ success: false, error: 'Only admins can create collections' });
|
|
760
|
-
}
|
|
761
1123
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(params.name)) {
|
|
762
|
-
return wrapToolResult({ success: false, error: '
|
|
1124
|
+
return wrapToolResult({ success: false, error: 'Folder name must be kebab-case (lowercase letters, numbers, hyphens)' });
|
|
763
1125
|
}
|
|
764
1126
|
const { Workspace } = await import('../../core/workspace.js');
|
|
765
1127
|
const workspace = new Workspace(workspacePath);
|
|
766
1128
|
const repo = await workspace.registerRepo({
|
|
767
1129
|
name: params.name,
|
|
768
1130
|
description: params.description,
|
|
769
|
-
|
|
770
|
-
...(params.private && user ? { owner_id: user.id } : {}),
|
|
1131
|
+
owner_id: user?.id,
|
|
771
1132
|
});
|
|
772
|
-
// Reload workspace manager to pick up the new collection
|
|
773
1133
|
workspaceManager.reloadConfig();
|
|
774
|
-
|
|
1134
|
+
if (user && authSvc)
|
|
1135
|
+
authSvc.grantFolderAccess(user.id, repo.name, 'admin');
|
|
1136
|
+
onMutation?.({ action: 'created', repo: repo.name, entityType: '_folder', entityId: repo.name });
|
|
775
1137
|
return wrapToolResult({
|
|
776
1138
|
success: true,
|
|
777
|
-
|
|
1139
|
+
folder: { name: repo.name, path: repo.path, description: repo.description },
|
|
778
1140
|
});
|
|
779
1141
|
}
|
|
780
1142
|
catch (error) {
|
|
@@ -788,7 +1150,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
788
1150
|
label: 'Query Dataset',
|
|
789
1151
|
description: 'Query rows from a dataset entity with optional filtering',
|
|
790
1152
|
parameters: T.Object({
|
|
791
|
-
repo: T.String({ description: '
|
|
1153
|
+
repo: T.String({ description: 'Folder name' }),
|
|
792
1154
|
entityId: T.String({ description: 'Dataset entity ID' }),
|
|
793
1155
|
filter: T.Optional(T.Object({}, { description: 'Filter conditions (column: value or { gte, lte, contains })', additionalProperties: true })),
|
|
794
1156
|
limit: T.Optional(T.Number({ description: 'Max rows to return' })),
|
|
@@ -796,21 +1158,24 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
796
1158
|
execute: async (toolCallId, params) => {
|
|
797
1159
|
try {
|
|
798
1160
|
if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
|
|
799
|
-
return wrapToolResult({ success: false, error: `
|
|
1161
|
+
return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
|
|
800
1162
|
}
|
|
801
1163
|
const graph = workspaceManager.getGraph(params.repo);
|
|
802
|
-
|
|
803
|
-
|
|
1164
|
+
// Validates the entity exists and is a dataset before querying.
|
|
1165
|
+
graph.get('dataset', params.entityId);
|
|
804
1166
|
let rows = graph.getDatasetRows(params.entityId, params.filter);
|
|
805
1167
|
const total = rows.length;
|
|
806
1168
|
if (params.limit && params.limit > 0) {
|
|
807
1169
|
rows = rows.slice(0, params.limit);
|
|
808
1170
|
}
|
|
1171
|
+
// Columns from the header, not the result rows — so a zero-match
|
|
1172
|
+
// filter or header-only dataset still reports the real columns.
|
|
1173
|
+
const columns = graph.getDatasetColumns(params.entityId);
|
|
809
1174
|
return wrapToolResult({
|
|
810
1175
|
success: true,
|
|
811
1176
|
rows,
|
|
812
1177
|
total,
|
|
813
|
-
|
|
1178
|
+
columns,
|
|
814
1179
|
});
|
|
815
1180
|
}
|
|
816
1181
|
catch (error) {
|
|
@@ -827,7 +1192,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
827
1192
|
label: 'Append Rows',
|
|
828
1193
|
description: 'Append rows to a dataset entity',
|
|
829
1194
|
parameters: T.Object({
|
|
830
|
-
repo: T.String({ description: '
|
|
1195
|
+
repo: T.String({ description: 'Folder name' }),
|
|
831
1196
|
entityId: T.String({ description: 'Dataset entity ID' }),
|
|
832
1197
|
rows: T.Array(T.Object({}, { additionalProperties: true }), { description: 'Rows to append' }),
|
|
833
1198
|
commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
|
|
@@ -835,13 +1200,14 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
835
1200
|
execute: async (toolCallId, params) => {
|
|
836
1201
|
try {
|
|
837
1202
|
if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
|
|
838
|
-
return wrapToolResult({ success: false, error: `
|
|
1203
|
+
return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
|
|
839
1204
|
}
|
|
840
1205
|
const graph = workspaceManager.getGraph(params.repo);
|
|
841
1206
|
// Get current row count before appending
|
|
842
1207
|
const beforeRows = graph.getDatasetRows(params.entityId);
|
|
843
1208
|
await graph.appendDatasetRows(params.entityId, params.rows, params.commitMessage);
|
|
844
1209
|
const afterRows = graph.getDatasetRows(params.entityId);
|
|
1210
|
+
onMutation?.({ action: 'updated', repo: params.repo, entityType: 'dataset', entityId: params.entityId });
|
|
845
1211
|
return wrapToolResult({
|
|
846
1212
|
success: true,
|
|
847
1213
|
rowsAdded: afterRows.length - beforeRows.length,
|
|
@@ -860,31 +1226,23 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
860
1226
|
// Get entity schema
|
|
861
1227
|
{
|
|
862
1228
|
name: 'get_entity_schema',
|
|
863
|
-
label: 'Get
|
|
864
|
-
description: 'Get the schema
|
|
1229
|
+
label: 'Get Entry Schema',
|
|
1230
|
+
description: 'Get the authoritative schema for an entry type. Returns each field with its type, whether it is optional, the description from the Zod schema, the full enum value list when applicable, and any default. Call this before writing enum-shaped fields (stage, status, category, priority, etc.) — the validator only accepts the values listed under `enum`.',
|
|
865
1231
|
parameters: T.Object({
|
|
866
1232
|
entityType: T.String({ description: 'Entity type' }),
|
|
867
1233
|
}),
|
|
868
1234
|
execute: async (toolCallId, params) => {
|
|
869
1235
|
try {
|
|
870
|
-
const
|
|
871
|
-
|
|
1236
|
+
const registry = workspaceManager.getSchemaRegistry();
|
|
1237
|
+
const knownTypes = new Set(registry.getAllTypes());
|
|
1238
|
+
if (!knownTypes.has(params.entityType)) {
|
|
872
1239
|
return wrapToolResult({
|
|
873
1240
|
success: false,
|
|
874
|
-
error: `Unknown entity type: ${params.entityType}`,
|
|
1241
|
+
error: `Unknown entity type: ${params.entityType}. Known types: ${[...knownTypes].sort().join(', ')}`,
|
|
875
1242
|
});
|
|
876
1243
|
}
|
|
877
|
-
|
|
878
|
-
const
|
|
879
|
-
const fields = {};
|
|
880
|
-
for (const [key, value] of Object.entries(shape)) {
|
|
881
|
-
const field = value;
|
|
882
|
-
fields[key] = {
|
|
883
|
-
type: field._def.typeName || 'unknown',
|
|
884
|
-
optional: field.isOptional() || false,
|
|
885
|
-
description: field._def.description || '',
|
|
886
|
-
};
|
|
887
|
-
}
|
|
1244
|
+
const schema = registry.getSchema(params.entityType);
|
|
1245
|
+
const fields = describeZodObject(schema);
|
|
888
1246
|
return wrapToolResult({
|
|
889
1247
|
success: true,
|
|
890
1248
|
entityType: params.entityType,
|
|
@@ -902,16 +1260,16 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
902
1260
|
// Lint entities
|
|
903
1261
|
{
|
|
904
1262
|
name: 'lint_entities',
|
|
905
|
-
label: 'Lint
|
|
906
|
-
description: 'Check for missing recommended fields across
|
|
1263
|
+
label: 'Lint Entries',
|
|
1264
|
+
description: 'Check for missing recommended fields across entries. Returns incomplete entries with their missing fields. Use to discover entries that need enrichment. Optionally filter by folder or entry type.',
|
|
907
1265
|
parameters: T.Object({
|
|
908
|
-
repo: T.Optional(T.String({ description: 'Optional: limit to specific
|
|
1266
|
+
repo: T.Optional(T.String({ description: 'Optional: limit to specific folder' })),
|
|
909
1267
|
entityType: T.Optional(T.String({ description: 'Optional: limit to specific entity type (e.g. "project", "deal")' })),
|
|
910
1268
|
}),
|
|
911
1269
|
execute: async (toolCallId, params) => {
|
|
912
1270
|
try {
|
|
913
1271
|
if (params.repo && !canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
|
|
914
|
-
return wrapToolResult({ success: false, error: `
|
|
1272
|
+
return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
|
|
915
1273
|
}
|
|
916
1274
|
let issues = await lintWorkspace(workspaceManager, {
|
|
917
1275
|
repo: params.repo,
|
|
@@ -957,16 +1315,15 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
957
1315
|
{
|
|
958
1316
|
name: 'find_orphans',
|
|
959
1317
|
label: 'Find Orphans',
|
|
960
|
-
description: 'Find
|
|
1318
|
+
description: 'Find entries with zero inbound wikilink references.',
|
|
961
1319
|
parameters: T.Object({
|
|
962
1320
|
entityTypes: T.Optional(T.Array(T.String(), { description: 'Entity types to check (e.g. ["person", "client"])' })),
|
|
963
1321
|
minAgeDays: T.Optional(T.Number({ description: 'Only flag entities older than N days' })),
|
|
964
|
-
repos: T.Optional(T.Array(T.String(), { description: '
|
|
965
|
-
tombstone: T.Optional(T.Boolean({ description: 'Add orphans to sync-state tombstones' })),
|
|
1322
|
+
repos: T.Optional(T.Array(T.String(), { description: 'Folder names to scan (default: all)' })),
|
|
966
1323
|
}),
|
|
967
1324
|
execute: async (toolCallId, params) => {
|
|
968
1325
|
try {
|
|
969
|
-
// Scope to accessible
|
|
1326
|
+
// Scope to accessible folders
|
|
970
1327
|
const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
|
|
971
1328
|
let repos = params.repos;
|
|
972
1329
|
if (allowed) {
|
|
@@ -977,13 +1334,6 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
977
1334
|
minAgeDays: params.minAgeDays,
|
|
978
1335
|
repos,
|
|
979
1336
|
});
|
|
980
|
-
// Tombstone if requested
|
|
981
|
-
if (params.tombstone && workspacePath && result.orphans.length > 0) {
|
|
982
|
-
const syncState = new SyncStateManager(workspacePath);
|
|
983
|
-
for (const orphan of result.orphans) {
|
|
984
|
-
syncState.addTombstone(orphan.entityId);
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
1337
|
// Group by type for summary
|
|
988
1338
|
const byType = {};
|
|
989
1339
|
for (const o of result.orphans) {
|
|
@@ -993,7 +1343,6 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
993
1343
|
success: true,
|
|
994
1344
|
totalScanned: result.totalScanned,
|
|
995
1345
|
totalOrphans: result.totalOrphans,
|
|
996
|
-
tombstoned: params.tombstone ? result.totalOrphans : 0,
|
|
997
1346
|
byType,
|
|
998
1347
|
orphans: result.orphans.slice(0, 50), // limit response size
|
|
999
1348
|
});
|
|
@@ -1009,8 +1358,8 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
1009
1358
|
// Highlight entities in graph view
|
|
1010
1359
|
{
|
|
1011
1360
|
name: 'highlight_entities',
|
|
1012
|
-
label: 'Highlight
|
|
1013
|
-
description: 'Highlight specific
|
|
1361
|
+
label: 'Highlight Entries',
|
|
1362
|
+
description: 'Highlight specific entries in the graph view. Pass entry IDs to highlight them (dimming all others). Pass an empty array to clear highlights.',
|
|
1014
1363
|
parameters: T.Object({
|
|
1015
1364
|
entityIds: T.Array(T.String(), { description: 'Entity IDs to highlight in the graph' }),
|
|
1016
1365
|
}),
|
|
@@ -1025,96 +1374,50 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
|
|
|
1025
1374
|
});
|
|
1026
1375
|
},
|
|
1027
1376
|
},
|
|
1028
|
-
//
|
|
1377
|
+
// Mark onboarding complete
|
|
1029
1378
|
{
|
|
1030
|
-
name: '
|
|
1031
|
-
label: '
|
|
1032
|
-
description: '
|
|
1379
|
+
name: 'mark_onboarded',
|
|
1380
|
+
label: 'Mark Onboarded',
|
|
1381
|
+
description: 'Mark the current user as onboarded. Call this when the interview/onboarding flow is complete.',
|
|
1033
1382
|
parameters: T.Object({}),
|
|
1034
|
-
execute: async () => {
|
|
1035
|
-
if (!authSvc)
|
|
1036
|
-
return wrapToolResult({ success: false, error: 'Auth service not available' });
|
|
1037
|
-
const userId = getUser()?.id ?? 0;
|
|
1038
|
-
const views = authSvc.getUserViews(userId);
|
|
1039
|
-
return wrapToolResult({ views });
|
|
1040
|
-
},
|
|
1041
|
-
},
|
|
1042
|
-
{
|
|
1043
|
-
name: 'create_view',
|
|
1044
|
-
label: 'Create View',
|
|
1045
|
-
description: 'Create a new saved view for the current user. Views appear as tabs in the toolbar.',
|
|
1046
|
-
parameters: T.Object({
|
|
1047
|
-
name: T.String({ description: 'View name (e.g. "My Tasks", "Open Projects")' }),
|
|
1048
|
-
selectedType: T.Optional(T.String({ description: 'Entity type filter (e.g. "task", "project"). Omit for all types.' })),
|
|
1049
|
-
groupBy: T.Optional(T.String({ description: 'Column key to group by (e.g. "status", "priority")' })),
|
|
1050
|
-
}),
|
|
1051
|
-
execute: async (_toolCallId, params) => {
|
|
1383
|
+
execute: async (_toolCallId) => {
|
|
1052
1384
|
if (!authSvc)
|
|
1053
1385
|
return wrapToolResult({ success: false, error: 'Auth service not available' });
|
|
1054
1386
|
const userId = getUser()?.id ?? 0;
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
groupBy: params.groupBy ?? null,
|
|
1058
|
-
sortKey: 'name',
|
|
1059
|
-
sortAsc: true,
|
|
1060
|
-
filters: { text: {}, enum: {}, date: {} },
|
|
1061
|
-
};
|
|
1062
|
-
const view = authSvc.createUserView(userId, params.name, 'list', config);
|
|
1063
|
-
return wrapToolResult({
|
|
1064
|
-
success: true,
|
|
1065
|
-
view: { id: view.id, name: view.name, viewType: view.viewType, config: view.config },
|
|
1066
|
-
message: `Created view "${params.name}". It will appear as a tab in the toolbar.`,
|
|
1067
|
-
});
|
|
1387
|
+
authSvc.setOnboarded(userId, true);
|
|
1388
|
+
return wrapToolResult({ success: true, message: 'User marked as onboarded.' });
|
|
1068
1389
|
},
|
|
1069
1390
|
},
|
|
1391
|
+
// Update workspace description (ABOUT.md)
|
|
1070
1392
|
{
|
|
1071
|
-
name: '
|
|
1072
|
-
label: 'Update
|
|
1073
|
-
description: '
|
|
1393
|
+
name: 'update_workspace_about',
|
|
1394
|
+
label: 'Update Workspace Description',
|
|
1395
|
+
description: 'Write or update the workspace description (ABOUT.md). Use this to synthesize a description from the knowledge graph after onboarding, or when asked to sync the workspace description. The content should be a concise narrative covering the organization\'s identity, team, capabilities, and values — written in markdown.',
|
|
1074
1396
|
parameters: T.Object({
|
|
1075
|
-
|
|
1076
|
-
name: T.Optional(T.String({ description: 'New view name' })),
|
|
1077
|
-
selectedType: T.Optional(T.String({ description: 'Entity type filter (use "all" to clear)' })),
|
|
1078
|
-
groupBy: T.Optional(T.String({ description: 'Column key to group by (use "none" to clear)' })),
|
|
1397
|
+
content: T.String({ description: 'The full markdown content for the workspace description' }),
|
|
1079
1398
|
}),
|
|
1080
1399
|
execute: async (_toolCallId, params) => {
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
return wrapToolResult({ success:
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
if (params.selectedType !== undefined || params.groupBy !== undefined) {
|
|
1091
|
-
const config = { ...existing.config };
|
|
1092
|
-
if (params.selectedType !== undefined)
|
|
1093
|
-
config.selectedType = params.selectedType === 'all' ? null : params.selectedType;
|
|
1094
|
-
if (params.groupBy !== undefined)
|
|
1095
|
-
config.groupBy = params.groupBy === 'none' ? null : params.groupBy;
|
|
1096
|
-
fields.config = config;
|
|
1400
|
+
try {
|
|
1401
|
+
const { Workspace } = await import('../../core/workspace.js');
|
|
1402
|
+
const workspace = new Workspace(workspacePath);
|
|
1403
|
+
workspace.writeAbout(params.content);
|
|
1404
|
+
onMutation?.({ action: 'updated', repo: '_workspace', entityType: '_workspace', entityId: 'about' });
|
|
1405
|
+
return wrapToolResult({ success: true, message: 'Workspace description updated.' });
|
|
1406
|
+
}
|
|
1407
|
+
catch (err) {
|
|
1408
|
+
return wrapToolResult({ success: false, error: err.message || 'Failed to write ABOUT.md' });
|
|
1097
1409
|
}
|
|
1098
|
-
authSvc.updateUserView(params.id, userId, fields);
|
|
1099
|
-
return wrapToolResult({ success: true, message: `Updated view "${existing.name}".` });
|
|
1100
1410
|
},
|
|
1101
1411
|
},
|
|
1412
|
+
// Reset conversation
|
|
1102
1413
|
{
|
|
1103
|
-
name: '
|
|
1104
|
-
label: '
|
|
1105
|
-
description: '
|
|
1106
|
-
parameters: T.Object({
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
if (!authSvc)
|
|
1111
|
-
return wrapToolResult({ success: false, error: 'Auth service not available' });
|
|
1112
|
-
const userId = getUser()?.id ?? 0;
|
|
1113
|
-
const existing = authSvc.getUserView(params.id, userId);
|
|
1114
|
-
if (!existing)
|
|
1115
|
-
return wrapToolResult({ success: false, error: `View ${params.id} not found` });
|
|
1116
|
-
authSvc.deleteUserView(params.id, userId);
|
|
1117
|
-
return wrapToolResult({ success: true, message: `Deleted view "${existing.name}".` });
|
|
1414
|
+
name: 'reset_conversation',
|
|
1415
|
+
label: 'Reset Conversation',
|
|
1416
|
+
description: 'Clear the current conversation and start fresh. Use when the user asks to "start over", "reset", "clear the chat", or "new conversation".',
|
|
1417
|
+
parameters: T.Object({}),
|
|
1418
|
+
execute: async (_toolCallId) => {
|
|
1419
|
+
onMutation?.({ action: 'deleted', repo: '_conversation', entityType: '_conversation', entityId: 'reset' });
|
|
1420
|
+
return wrapToolResult({ success: true, message: 'Conversation reset.' });
|
|
1118
1421
|
},
|
|
1119
1422
|
},
|
|
1120
1423
|
];
|