studiograph 1.3.3 → 1.3.4
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/dist/agent/orchestrator.d.ts +10 -0
- package/dist/agent/orchestrator.js +26 -7
- package/dist/agent/orchestrator.js.map +1 -1
- package/dist/agent/skills/sync-configuration.md +4 -29
- package/dist/agent/skills/sync-setup.md +2 -4
- package/dist/agent/tools/graph-tools.d.ts +5 -1
- package/dist/agent/tools/graph-tools.js +161 -9
- package/dist/agent/tools/graph-tools.js.map +1 -1
- package/dist/agent/tools/ops-tools.js +15 -126
- package/dist/agent/tools/ops-tools.js.map +1 -1
- package/dist/agent/tools/permission-tools.d.ts +15 -14
- package/dist/agent/tools/permission-tools.js +65 -128
- package/dist/agent/tools/permission-tools.js.map +1 -1
- package/dist/agent/tools/sync-tools.d.ts +7 -6
- package/dist/agent/tools/sync-tools.js +205 -178
- package/dist/agent/tools/sync-tools.js.map +1 -1
- package/dist/cli/commands/about.d.ts +13 -0
- package/dist/cli/commands/about.js +97 -0
- package/dist/cli/commands/about.js.map +1 -0
- package/dist/cli/commands/clone.d.ts +5 -2
- package/dist/cli/commands/clone.js +131 -62
- package/dist/cli/commands/clone.js.map +1 -1
- package/dist/cli/commands/connector.d.ts +2 -16
- package/dist/cli/commands/connector.js +32 -109
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/deploy.d.ts +0 -1
- package/dist/cli/commands/deploy.js +13 -103
- package/dist/cli/commands/deploy.js.map +1 -1
- package/dist/cli/commands/init.js +6 -93
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/join.d.ts +3 -2
- package/dist/cli/commands/join.js +142 -97
- package/dist/cli/commands/join.js.map +1 -1
- package/dist/cli/commands/redeploy.js +1 -2
- package/dist/cli/commands/redeploy.js.map +1 -1
- package/dist/cli/commands/serve.d.ts +1 -3
- package/dist/cli/commands/serve.js +29 -109
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/start.js +1 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/sync-collection.d.ts +14 -0
- package/dist/cli/commands/sync-collection.js +366 -0
- package/dist/cli/commands/sync-collection.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +4 -2
- package/dist/cli/commands/sync.js +529 -94
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/cli/index.js +15 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/setup-wizard.d.ts +0 -13
- package/dist/cli/setup-wizard.js +6 -81
- package/dist/cli/setup-wizard.js.map +1 -1
- package/dist/core/graph.d.ts +8 -2
- package/dist/core/graph.js +11 -7
- package/dist/core/graph.js.map +1 -1
- package/dist/core/types.d.ts +149 -21
- package/dist/core/types.js +16 -4
- package/dist/core/types.js.map +1 -1
- package/dist/core/workspace-manager.js +1 -5
- package/dist/core/workspace-manager.js.map +1 -1
- package/dist/core/workspace.d.ts +11 -4
- package/dist/core/workspace.js +61 -26
- package/dist/core/workspace.js.map +1 -1
- package/dist/integrations/asana.d.ts +26 -0
- package/dist/integrations/asana.js +77 -0
- package/dist/integrations/asana.js.map +1 -0
- package/dist/integrations/figma-local.d.ts +16 -0
- package/dist/integrations/figma-local.js +10 -0
- package/dist/integrations/figma-local.js.map +1 -0
- package/dist/integrations/figma.d.ts +17 -0
- package/dist/integrations/figma.js +16 -0
- package/dist/integrations/figma.js.map +1 -0
- package/dist/integrations/granola.d.ts +24 -0
- package/dist/integrations/granola.js +59 -0
- package/dist/integrations/granola.js.map +1 -0
- package/dist/integrations/linear.d.ts +14 -0
- package/dist/integrations/linear.js +70 -0
- package/dist/integrations/linear.js.map +1 -0
- package/dist/integrations/paper-local.d.ts +14 -0
- package/dist/integrations/paper-local.js +10 -0
- package/dist/integrations/paper-local.js.map +1 -0
- package/dist/integrations/paper.d.ts +2 -0
- package/dist/integrations/paper.js +10 -0
- package/dist/integrations/paper.js.map +1 -0
- package/dist/integrations/pipedrive.d.ts +26 -0
- package/dist/integrations/pipedrive.js +97 -0
- package/dist/integrations/pipedrive.js.map +1 -0
- package/dist/integrations/registry.d.ts +15 -0
- package/dist/integrations/registry.js +27 -0
- package/dist/integrations/registry.js.map +1 -0
- package/dist/integrations/types.d.ts +34 -0
- package/dist/integrations/types.js +9 -0
- package/dist/integrations/types.js.map +1 -0
- package/dist/mcp/connector-manager.d.ts +45 -31
- package/dist/mcp/connector-manager.js +164 -116
- package/dist/mcp/connector-manager.js.map +1 -1
- package/dist/mcp/server-oauth-provider.d.ts +56 -0
- package/dist/mcp/server-oauth-provider.js +138 -0
- package/dist/mcp/server-oauth-provider.js.map +1 -0
- package/dist/server/chrome/chrome.css +142 -28
- package/dist/server/chrome/chrome.js +46 -220
- package/dist/server/collab-authority.d.ts +70 -0
- package/dist/server/collab-authority.js +218 -0
- package/dist/server/collab-authority.js.map +1 -0
- package/dist/server/collab.d.ts +29 -0
- package/dist/server/collab.js +195 -0
- package/dist/server/collab.js.map +1 -0
- package/dist/server/commit-scheduler.d.ts +39 -0
- package/dist/server/commit-scheduler.js +113 -0
- package/dist/server/commit-scheduler.js.map +1 -0
- package/dist/server/index.d.ts +0 -2
- package/dist/server/index.js +166 -55
- package/dist/server/index.js.map +1 -1
- package/dist/server/routes/auth-api.d.ts +6 -0
- package/dist/server/routes/auth-api.js +78 -0
- package/dist/server/routes/auth-api.js.map +1 -1
- package/dist/server/routes/chat.js +4 -0
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/collab.d.ts +6 -0
- package/dist/server/routes/collab.js +10 -0
- package/dist/server/routes/collab.js.map +1 -0
- package/dist/server/routes/git-http.d.ts +23 -0
- package/dist/server/routes/git-http.js +251 -0
- package/dist/server/routes/git-http.js.map +1 -0
- package/dist/server/routes/graph-api.d.ts +6 -2
- package/dist/server/routes/graph-api.js +266 -82
- package/dist/server/routes/graph-api.js.map +1 -1
- package/dist/server/routes/mcp.d.ts +12 -0
- package/dist/server/routes/mcp.js +35 -0
- package/dist/server/routes/mcp.js.map +1 -0
- package/dist/server/routes/permissions-api.d.ts +6 -4
- package/dist/server/routes/permissions-api.js +53 -167
- package/dist/server/routes/permissions-api.js.map +1 -1
- package/dist/server/routes/sync-api.d.ts +26 -0
- package/dist/server/routes/sync-api.js +757 -0
- package/dist/server/routes/sync-api.js.map +1 -0
- package/dist/server/routes/ws.d.ts +9 -0
- package/dist/server/routes/ws.js +131 -0
- package/dist/server/routes/ws.js.map +1 -0
- package/dist/server/session-manager.d.ts +40 -0
- package/dist/server/session-manager.js +132 -0
- package/dist/server/session-manager.js.map +1 -0
- package/dist/server/ws-hub.d.ts +130 -0
- package/dist/server/ws-hub.js +250 -0
- package/dist/server/ws-hub.js.map +1 -0
- package/dist/server/yjs-manager.d.ts +59 -0
- package/dist/server/yjs-manager.js +194 -0
- package/dist/server/yjs-manager.js.map +1 -0
- package/dist/services/auth-service.d.ts +74 -0
- package/dist/services/auth-service.js +286 -6
- package/dist/services/auth-service.js.map +1 -1
- package/dist/services/git.d.ts +6 -0
- package/dist/services/git.js +32 -2
- package/dist/services/git.js.map +1 -1
- package/dist/services/sync/collection-sync.d.ts +73 -0
- package/dist/services/sync/collection-sync.js +726 -0
- package/dist/services/sync/collection-sync.js.map +1 -0
- package/dist/services/sync/commit.js +5 -20
- package/dist/services/sync/commit.js.map +1 -1
- package/dist/services/sync/data-fetcher.d.ts +31 -0
- package/dist/services/sync/data-fetcher.js +12 -0
- package/dist/services/sync/data-fetcher.js.map +1 -0
- package/dist/services/sync/entity-refresh.d.ts +30 -0
- package/dist/services/sync/entity-refresh.js +275 -0
- package/dist/services/sync/entity-refresh.js.map +1 -0
- package/dist/services/sync/frontmatter-extractor.d.ts +2 -2
- package/dist/services/sync/frontmatter-extractor.js +1 -2
- package/dist/services/sync/frontmatter-extractor.js.map +1 -1
- package/dist/services/sync/graph-match.js +1 -1
- package/dist/services/sync/graph-match.js.map +1 -1
- package/dist/services/sync/mcp-client.d.ts +16 -4
- package/dist/services/sync/mcp-client.js +34 -20
- package/dist/services/sync/mcp-client.js.map +1 -1
- package/dist/services/sync/prompts.js +1 -1
- package/dist/services/sync/reconciler.js +1 -2
- package/dist/services/sync/reconciler.js.map +1 -1
- package/dist/services/sync/rest-client.d.ts +40 -0
- package/dist/services/sync/rest-client.js +100 -0
- package/dist/services/sync/rest-client.js.map +1 -0
- package/dist/services/sync/source-config.d.ts +23 -1
- package/dist/services/sync/source-config.js +112 -16
- package/dist/services/sync/source-config.js.map +1 -1
- package/dist/services/sync/source-definitions/asana.d.ts +3 -4
- package/dist/services/sync/source-definitions/asana.js +7 -13
- package/dist/services/sync/source-definitions/asana.js.map +1 -1
- package/dist/services/sync/source-definitions/definitions.d.ts +5 -18
- package/dist/services/sync/source-definitions/definitions.js +4 -22
- package/dist/services/sync/source-definitions/definitions.js.map +1 -1
- package/dist/services/sync/source-definitions/granola.d.ts +1 -1
- package/dist/services/sync/source-definitions/granola.js +11 -18
- package/dist/services/sync/source-definitions/granola.js.map +1 -1
- package/dist/services/sync/source-definitions/linear.d.ts +1 -1
- package/dist/services/sync/source-definitions/linear.js +17 -15
- package/dist/services/sync/source-definitions/linear.js.map +1 -1
- package/dist/services/sync/source-definitions/pipedrive.d.ts +1 -1
- package/dist/services/sync/source-definitions/pipedrive.js +6 -15
- package/dist/services/sync/source-definitions/pipedrive.js.map +1 -1
- package/dist/services/sync/staging.js +1 -2
- package/dist/services/sync/staging.js.map +1 -1
- package/dist/services/sync/structured-extractor.d.ts +8 -2
- package/dist/services/sync/structured-extractor.js +243 -35
- package/dist/services/sync/structured-extractor.js.map +1 -1
- package/dist/services/sync/types.d.ts +192 -23
- package/dist/services/sync/unstructured-extractor.d.ts +1 -3
- package/dist/services/sync/unstructured-extractor.js +2 -14
- package/dist/services/sync/unstructured-extractor.js.map +1 -1
- package/dist/utils/git.d.ts +33 -20
- package/dist/utils/git.js +119 -62
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/preflight.d.ts +1 -15
- package/dist/utils/preflight.js +1 -35
- package/dist/utils/preflight.js.map +1 -1
- package/dist/web/_app/immutable/assets/0.CupILLQs.css +1 -0
- package/dist/web/_app/immutable/assets/3.CtJi4Cy9.css +1 -0
- package/dist/web/_app/immutable/assets/5.CydFyZSu.css +1 -0
- package/dist/web/_app/immutable/assets/6.kqeOo0OW.css +1 -0
- package/dist/web/_app/immutable/assets/7.CseIx7qQ.css +1 -0
- package/dist/web/_app/immutable/assets/8.BYpFDZHK.css +1 -0
- package/dist/web/_app/immutable/assets/AppShell.Ch_ef9hJ.css +1 -0
- package/dist/web/_app/immutable/assets/ChatPanel.CP-_8txt.css +1 -0
- package/dist/web/_app/immutable/chunks/0oxpWEgM.js +1 -0
- package/dist/web/_app/immutable/chunks/B1y7Wy5O.js +18 -0
- package/dist/web/_app/immutable/chunks/B7eduG_j.js +64 -0
- package/dist/web/_app/immutable/chunks/BBLgaWN8.js +1 -0
- package/dist/web/_app/immutable/chunks/BCB5cYCz.js +2 -0
- package/dist/web/_app/immutable/chunks/{aosHekRC.js → BPUy9_sS.js} +1 -1
- package/dist/web/_app/immutable/chunks/BVBRzmeQ.js +7 -0
- package/dist/web/_app/immutable/chunks/{CUzqHQY_.js → BXuvR8Ks.js} +2 -1
- package/dist/web/_app/immutable/chunks/BeBar3OL.js +1 -0
- package/dist/web/_app/immutable/chunks/BuOTIbJu.js +1 -0
- package/dist/web/_app/immutable/chunks/CLFba8FK.js +5 -0
- package/dist/web/_app/immutable/chunks/CQCkXCml.js +1 -0
- package/dist/web/_app/immutable/chunks/CXuhHL4d.js +1 -0
- package/dist/web/_app/immutable/chunks/Cg9NOuOl.js +27 -0
- package/dist/web/_app/immutable/chunks/Cs5oz2oJ.js +5 -0
- package/dist/web/_app/immutable/chunks/Cs_ROD7H.js +2 -0
- package/dist/web/_app/immutable/chunks/D2aTbzFm.js +3 -0
- package/dist/web/_app/immutable/chunks/D4FXhiC2.js +1 -0
- package/dist/web/_app/immutable/chunks/D4VHRYeB.js +1 -0
- package/dist/web/_app/immutable/chunks/DCGSm8Hl.js +1 -0
- package/dist/web/_app/immutable/chunks/DP09rP34.js +2 -0
- package/dist/web/_app/immutable/chunks/DiP47fAp.js +1 -0
- package/dist/web/_app/immutable/chunks/DptGlK8O.js +1 -0
- package/dist/web/_app/immutable/chunks/O0fx2ss6.js +1 -0
- package/dist/web/_app/immutable/chunks/xBRYfpah.js +1 -0
- package/dist/web/_app/immutable/entry/app.FgnywZP_.js +2 -0
- package/dist/web/_app/immutable/entry/start.Bsa-zlPf.js +1 -0
- package/dist/web/_app/immutable/nodes/0.D3SW-LMc.js +10 -0
- package/dist/web/_app/immutable/nodes/1.y0c5TQTP.js +1 -0
- package/dist/web/_app/immutable/nodes/2.BQfSep9-.js +1 -0
- package/dist/web/_app/immutable/nodes/3.CC4Y-xMM.js +11 -0
- package/dist/web/_app/immutable/nodes/{5.BBpmYkAu.js → 4.Dp0Z-oPW.js} +2 -2
- package/dist/web/_app/immutable/nodes/5.gjZ03DON.js +2 -0
- package/dist/web/_app/immutable/nodes/6.dRNIwcJQ.js +1 -0
- package/dist/web/_app/immutable/nodes/7.I4Gjes3o.js +2 -0
- package/dist/web/_app/immutable/nodes/8.Dj14D7uH.js +1 -0
- package/dist/web/_app/version.json +1 -1
- package/dist/web/index.html +10 -12
- package/package.json +12 -2
- package/dist/web/_app/immutable/assets/0.CDbX4Cwz.css +0 -1
- package/dist/web/_app/immutable/assets/3.BJy7pVXi.css +0 -1
- package/dist/web/_app/immutable/assets/4.Ad16uh9o.css +0 -1
- package/dist/web/_app/immutable/assets/6.Bm2i7O0j.css +0 -1
- package/dist/web/_app/immutable/assets/AppShell.D0rmbdqF.css +0 -1
- package/dist/web/_app/immutable/assets/ChatPanel.RFD5GGYI.css +0 -1
- package/dist/web/_app/immutable/assets/editor.CPAf2SRV.css +0 -1
- package/dist/web/_app/immutable/chunks/479TgXB4.js +0 -1
- package/dist/web/_app/immutable/chunks/4QY4j-jX.js +0 -1
- package/dist/web/_app/immutable/chunks/BFb0g4TQ.js +0 -64
- package/dist/web/_app/immutable/chunks/Bopa-Ask.js +0 -1
- package/dist/web/_app/immutable/chunks/COwytaCP.js +0 -1
- package/dist/web/_app/immutable/chunks/DEJSHbC3.js +0 -1
- package/dist/web/_app/immutable/chunks/DNywhIex.js +0 -23
- package/dist/web/_app/immutable/chunks/DTUXhwEY.js +0 -1
- package/dist/web/_app/immutable/chunks/DThXpa0U.js +0 -6
- package/dist/web/_app/immutable/chunks/Dh_H7Owr.js +0 -18
- package/dist/web/_app/immutable/chunks/Dml-u95b.js +0 -2
- package/dist/web/_app/immutable/chunks/DnlgZ_Tk.js +0 -5
- package/dist/web/_app/immutable/chunks/DtVH--hH.js +0 -6
- package/dist/web/_app/immutable/chunks/DvKVaE7M.js +0 -1
- package/dist/web/_app/immutable/chunks/MbiSz-iW.js +0 -2
- package/dist/web/_app/immutable/chunks/bSAC733J.js +0 -1
- package/dist/web/_app/immutable/entry/app.BvodXQQ0.js +0 -2
- package/dist/web/_app/immutable/entry/start.Bkui3Kyw.js +0 -1
- package/dist/web/_app/immutable/nodes/0.DfbCOBhn.js +0 -2
- package/dist/web/_app/immutable/nodes/1.vtxUGpe6.js +0 -1
- package/dist/web/_app/immutable/nodes/2.Cq29oW4h.js +0 -1
- package/dist/web/_app/immutable/nodes/3.SquslPZy.js +0 -1
- package/dist/web/_app/immutable/nodes/4.COV8FR8b.js +0 -16
- package/dist/web/_app/immutable/nodes/6.BBbh6z9I.js +0 -2
- /package/dist/web/_app/immutable/assets/{5.BhKgiXd2.css → 4.BhKgiXd2.css} +0 -0
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Sync &
|
|
2
|
+
* Sync & Workspace Tools for Studiograph Agent
|
|
3
3
|
*
|
|
4
|
-
* These tools allow the agent to
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
7
|
-
* - Manage
|
|
4
|
+
* These tools allow the agent to:
|
|
5
|
+
* - Sync external data into collections (collection-scoped sync)
|
|
6
|
+
* - Refresh individual synced entities from their source
|
|
7
|
+
* - Manage workspace git operations (commit, push, pull, status)
|
|
8
|
+
* - Inspect MCP connectors for sync configuration
|
|
8
9
|
*/
|
|
9
10
|
import { Type as T } from '@sinclair/typebox';
|
|
10
11
|
import { spawnSync } from 'child_process';
|
|
@@ -12,13 +13,13 @@ import { gitPush, gitPull } from '../../utils/git.js';
|
|
|
12
13
|
import { existsSync } from 'fs';
|
|
13
14
|
import { join } from 'path';
|
|
14
15
|
import { homedir } from 'os';
|
|
15
|
-
import {
|
|
16
|
-
import { commitStaging, applyStaging, commitRepos } from '../../services/sync/commit.js';
|
|
17
|
-
import { runEnrichment } from '../../services/sync/enrichment.js';
|
|
16
|
+
import { commitRepos } from '../../services/sync/commit.js';
|
|
18
17
|
import { StagingManager } from '../../services/sync/staging.js';
|
|
19
18
|
import { SourceConfigManager } from '../../services/sync/source-config.js';
|
|
20
19
|
import { ConnectorManager } from '../../mcp/connector-manager.js';
|
|
21
20
|
import { SOURCE_DEFINITIONS } from '../../services/sync/source-definitions/definitions.js';
|
|
21
|
+
import { syncRepo, syncWorkspaceRule } from '../../services/sync/collection-sync.js';
|
|
22
|
+
import { refreshEntity } from '../../services/sync/entity-refresh.js';
|
|
22
23
|
import { wrapToolResult } from './graph-tools.js';
|
|
23
24
|
import { VectorService } from '../../services/vector-service.js';
|
|
24
25
|
import { BaseGraphManager } from '../../core/graph.js';
|
|
@@ -29,30 +30,36 @@ import { loadUserConfig } from '../../core/user-config.js';
|
|
|
29
30
|
export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
30
31
|
const getRegistry = () => registryRef?.registry ?? null;
|
|
31
32
|
return [
|
|
32
|
-
//
|
|
33
|
+
// ── Collection-scoped sync tools ─────────────────────────────────────────
|
|
34
|
+
// Sync a collection — runs collection-level rules AND workspace-level rules targeting it
|
|
33
35
|
{
|
|
34
|
-
name: '
|
|
35
|
-
label: '
|
|
36
|
-
description: '
|
|
36
|
+
name: 'sync_collection',
|
|
37
|
+
label: 'Sync Collection',
|
|
38
|
+
description: 'Pull new entities from external sources into a collection. Runs both collection-level sync rules and any workspace-level sync rules that target this collection. Creates new entities only — existing entities (matched by source_ref) are never updated. Always confirm with the user before calling.',
|
|
37
39
|
parameters: T.Object({
|
|
38
|
-
|
|
39
|
-
dryRun: T.Optional(T.Boolean({ description: 'Preview without writing staging files' })),
|
|
40
|
-
incremental: T.Optional(T.Boolean({ description: 'Only sync records updated since last sync' })),
|
|
40
|
+
collection: T.String({ description: 'Collection name to sync' }),
|
|
41
41
|
}),
|
|
42
42
|
execute: async (toolCallId, params) => {
|
|
43
43
|
try {
|
|
44
44
|
const progress = [];
|
|
45
|
-
const
|
|
45
|
+
const { collectionResults, workspaceResults } = await syncRepo({
|
|
46
46
|
workspacePath,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
incremental: params.incremental,
|
|
47
|
+
collectionName: params.collection,
|
|
48
|
+
workspaceConfig,
|
|
50
49
|
schemaExtensions: workspaceConfig.schema_extensions,
|
|
51
|
-
|
|
50
|
+
onProgress: (msg) => progress.push(msg),
|
|
51
|
+
});
|
|
52
|
+
const totalCreated = collectionResults.reduce((s, r) => s + r.created + r.derived, 0) +
|
|
53
|
+
workspaceResults.reduce((s, r) => r.targets.reduce((ts, t) => ts + t.created + t.derived, 0) + s, 0);
|
|
54
|
+
const totalSkipped = collectionResults.reduce((s, r) => s + r.skipped, 0) +
|
|
55
|
+
workspaceResults.reduce((s, r) => r.targets.reduce((ts, t) => ts + t.skipped, 0) + s, 0);
|
|
52
56
|
return wrapToolResult({
|
|
53
57
|
success: true,
|
|
54
|
-
|
|
58
|
+
collectionResults,
|
|
59
|
+
workspaceResults,
|
|
60
|
+
summary: `Created ${totalCreated}, skipped ${totalSkipped}`,
|
|
55
61
|
progress: progress.join('\n'),
|
|
62
|
+
nextSteps: totalCreated > 0 ? 'Commit changes with workspace_commit' : undefined,
|
|
56
63
|
});
|
|
57
64
|
}
|
|
58
65
|
catch (error) {
|
|
@@ -63,20 +70,37 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
63
70
|
}
|
|
64
71
|
},
|
|
65
72
|
},
|
|
66
|
-
//
|
|
73
|
+
// Run all workspace-level sync rules
|
|
67
74
|
{
|
|
68
|
-
name: '
|
|
69
|
-
label: 'Sync
|
|
70
|
-
description: '
|
|
75
|
+
name: 'sync_workspace',
|
|
76
|
+
label: 'Sync Workspace',
|
|
77
|
+
description: 'Run all workspace-level sync rules defined in workspace.json. Each rule fetches from its source once and distributes records to multiple target collections. Use this instead of sync_collection when multiple collections share the same source. Always confirm with the user before calling.',
|
|
71
78
|
parameters: T.Object({}),
|
|
72
|
-
execute: async (toolCallId,
|
|
79
|
+
execute: async (toolCallId, _params) => {
|
|
73
80
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
81
|
+
const rules = workspaceConfig.sync ?? [];
|
|
82
|
+
if (rules.length === 0) {
|
|
83
|
+
return wrapToolResult({ success: true, results: [], summary: 'No workspace-level sync rules configured' });
|
|
84
|
+
}
|
|
85
|
+
const progress = [];
|
|
86
|
+
const results = [];
|
|
87
|
+
for (const rule of rules) {
|
|
88
|
+
const result = await syncWorkspaceRule({
|
|
89
|
+
workspacePath,
|
|
90
|
+
rule,
|
|
91
|
+
workspaceConfig,
|
|
92
|
+
schemaExtensions: workspaceConfig.schema_extensions,
|
|
93
|
+
onProgress: (msg) => progress.push(msg),
|
|
94
|
+
});
|
|
95
|
+
results.push(result);
|
|
96
|
+
}
|
|
97
|
+
const totalCreated = results.reduce((s, r) => r.targets.reduce((ts, t) => ts + t.created + t.derived, 0) + s, 0);
|
|
76
98
|
return wrapToolResult({
|
|
77
99
|
success: true,
|
|
78
|
-
|
|
79
|
-
summary,
|
|
100
|
+
results,
|
|
101
|
+
summary: `Ran ${rules.length} workspace rule(s), created ${totalCreated} entities`,
|
|
102
|
+
progress: progress.join('\n'),
|
|
103
|
+
nextSteps: totalCreated > 0 ? 'Commit changes with workspace_commit' : undefined,
|
|
80
104
|
});
|
|
81
105
|
}
|
|
82
106
|
catch (error) {
|
|
@@ -87,23 +111,80 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
87
111
|
}
|
|
88
112
|
},
|
|
89
113
|
},
|
|
90
|
-
//
|
|
114
|
+
// Refresh a single synced entity
|
|
91
115
|
{
|
|
92
|
-
name: '
|
|
93
|
-
label: '
|
|
94
|
-
description: '
|
|
116
|
+
name: 'sync_refresh',
|
|
117
|
+
label: 'Refresh Synced Entity',
|
|
118
|
+
description: 'Refresh a single entity from its external source. Shows what fields have changed. Does NOT apply changes automatically — use the apply parameter or tell the user about the changes.',
|
|
95
119
|
parameters: T.Object({
|
|
96
|
-
|
|
120
|
+
entity_id: T.String({ description: 'Entity ID to refresh' }),
|
|
121
|
+
collection: T.Optional(T.String({ description: 'Collection name (auto-detected if omitted)' })),
|
|
122
|
+
entity_type: T.Optional(T.String({ description: 'Entity type (auto-detected if omitted)' })),
|
|
123
|
+
apply: T.Optional(T.Boolean({ description: 'Apply changes immediately (default: false, just show diff)' })),
|
|
97
124
|
}),
|
|
98
125
|
execute: async (toolCallId, params) => {
|
|
99
126
|
try {
|
|
100
|
-
|
|
101
|
-
|
|
127
|
+
let { collection, entity_type, entity_id, apply } = params;
|
|
128
|
+
// Auto-detect collection and entity_type if not provided
|
|
129
|
+
if (!collection || !entity_type) {
|
|
130
|
+
for (const repo of workspaceConfig.repos) {
|
|
131
|
+
try {
|
|
132
|
+
const repoPath = join(workspacePath, repo.path);
|
|
133
|
+
if (!existsSync(repoPath))
|
|
134
|
+
continue;
|
|
135
|
+
const graph = new BaseGraphManager({
|
|
136
|
+
repoPath,
|
|
137
|
+
repoName: repo.name,
|
|
138
|
+
gitUser: { id: 'agent', name: 'Agent', email: 'agent@studiograph.local' },
|
|
139
|
+
});
|
|
140
|
+
const entities = graph.list();
|
|
141
|
+
const match = entities.find(e => e.data?.entity_id === entity_id);
|
|
142
|
+
if (match) {
|
|
143
|
+
collection = repo.name;
|
|
144
|
+
entity_type = match.entityType;
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch { /* skip */ }
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!collection || !entity_type) {
|
|
152
|
+
return wrapToolResult({
|
|
153
|
+
success: false,
|
|
154
|
+
error: `Entity "${entity_id}" not found in any collection`,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
const result = await refreshEntity({
|
|
158
|
+
workspacePath,
|
|
159
|
+
collectionName: collection,
|
|
160
|
+
entityType: entity_type,
|
|
161
|
+
entityId: entity_id,
|
|
162
|
+
workspaceConfig: workspaceConfig,
|
|
163
|
+
schemaExtensions: workspaceConfig.schema_extensions,
|
|
164
|
+
apply: apply ?? false,
|
|
165
|
+
});
|
|
166
|
+
if (result.diffs.length === 0 && !result.body_changed) {
|
|
167
|
+
return wrapToolResult({
|
|
168
|
+
success: true,
|
|
169
|
+
message: 'Entity is already up to date with the source.',
|
|
170
|
+
entity_id,
|
|
171
|
+
source_ref: result.source_ref,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
102
174
|
return wrapToolResult({
|
|
103
175
|
success: true,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
entity_id,
|
|
177
|
+
source_ref: result.source_ref,
|
|
178
|
+
applied: result.applied,
|
|
179
|
+
changes: result.diffs.map(d => ({
|
|
180
|
+
field: d.field,
|
|
181
|
+
from: d.old_value,
|
|
182
|
+
to: d.new_value,
|
|
183
|
+
})),
|
|
184
|
+
body_changed: result.body_changed,
|
|
185
|
+
nextSteps: result.applied
|
|
186
|
+
? 'Changes applied. Commit with workspace_commit.'
|
|
187
|
+
: 'Review the changes above and call sync_refresh with apply: true to apply them.',
|
|
107
188
|
});
|
|
108
189
|
}
|
|
109
190
|
catch (error) {
|
|
@@ -114,21 +195,72 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
114
195
|
}
|
|
115
196
|
},
|
|
116
197
|
},
|
|
117
|
-
//
|
|
198
|
+
// Show sync status across collections
|
|
118
199
|
{
|
|
119
|
-
name: '
|
|
120
|
-
label: '
|
|
121
|
-
description: '
|
|
200
|
+
name: 'sync_status',
|
|
201
|
+
label: 'Sync Status',
|
|
202
|
+
description: 'Show which collections have sync rules configured, their sources, and last sync time. Use this when users ask about sync configuration or what has been synced.',
|
|
122
203
|
parameters: T.Object({
|
|
123
|
-
|
|
204
|
+
collection: T.Optional(T.String({ description: 'Filter to a specific collection' })),
|
|
124
205
|
}),
|
|
125
206
|
execute: async (toolCallId, params) => {
|
|
126
207
|
try {
|
|
127
|
-
const
|
|
128
|
-
|
|
208
|
+
const repos = params.collection
|
|
209
|
+
? workspaceConfig.repos.filter(r => r.name === params.collection)
|
|
210
|
+
: workspaceConfig.repos;
|
|
211
|
+
const collections = [];
|
|
212
|
+
for (const repo of repos) {
|
|
213
|
+
const syncRules = repo.sync;
|
|
214
|
+
if (!syncRules || syncRules.length === 0)
|
|
215
|
+
continue;
|
|
216
|
+
let syncedCount = 0;
|
|
217
|
+
let lastSync = null;
|
|
218
|
+
try {
|
|
219
|
+
const repoPath = join(workspacePath, repo.path);
|
|
220
|
+
if (!existsSync(repoPath))
|
|
221
|
+
continue;
|
|
222
|
+
const graph = new BaseGraphManager({
|
|
223
|
+
repoPath,
|
|
224
|
+
repoName: repo.name,
|
|
225
|
+
gitUser: { id: 'agent', name: 'Agent', email: 'agent@studiograph.local' },
|
|
226
|
+
});
|
|
227
|
+
for (const entity of graph.list()) {
|
|
228
|
+
const syncedAt = entity.data?.synced_at;
|
|
229
|
+
if (syncedAt) {
|
|
230
|
+
syncedCount++;
|
|
231
|
+
if (!lastSync || syncedAt > lastSync)
|
|
232
|
+
lastSync = syncedAt;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch { /* skip */ }
|
|
237
|
+
collections.push({ name: repo.name, syncRules, syncedCount, lastSync });
|
|
238
|
+
}
|
|
239
|
+
// Also list available source definitions
|
|
240
|
+
const configMgr = new SourceConfigManager(workspacePath);
|
|
241
|
+
const sources = configMgr.getAll().map(s => s.name);
|
|
242
|
+
// Check for new-format too
|
|
243
|
+
const { readdirSync } = await import('fs');
|
|
244
|
+
const sourcesDir = join(workspacePath, '.studiograph', 'sources');
|
|
245
|
+
if (existsSync(sourcesDir)) {
|
|
246
|
+
for (const file of readdirSync(sourcesDir)) {
|
|
247
|
+
if (!file.endsWith('.json'))
|
|
248
|
+
continue;
|
|
249
|
+
const name = file.replace('.json', '');
|
|
250
|
+
if (!sources.includes(name)) {
|
|
251
|
+
const def = configMgr.getDefinition(name);
|
|
252
|
+
if (def)
|
|
253
|
+
sources.push(name);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
129
257
|
return wrapToolResult({
|
|
130
258
|
success: true,
|
|
131
|
-
|
|
259
|
+
collections,
|
|
260
|
+
availableSources: sources,
|
|
261
|
+
message: collections.length > 0
|
|
262
|
+
? `${collections.length} collection(s) with sync rules`
|
|
263
|
+
: 'No collections have sync rules configured.',
|
|
132
264
|
});
|
|
133
265
|
}
|
|
134
266
|
catch (error) {
|
|
@@ -139,22 +271,20 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
139
271
|
}
|
|
140
272
|
},
|
|
141
273
|
},
|
|
142
|
-
//
|
|
274
|
+
// Git commit across workspace repos
|
|
143
275
|
{
|
|
144
|
-
name: '
|
|
145
|
-
label: 'Commit
|
|
146
|
-
description: '
|
|
276
|
+
name: 'workspace_commit',
|
|
277
|
+
label: 'Commit Changes',
|
|
278
|
+
description: 'Git commit entity changes across all workspace repos. Works after sync_apply, enrich_run, or manual edits. Always confirm with the user before calling this.',
|
|
147
279
|
parameters: T.Object({
|
|
148
|
-
|
|
280
|
+
messagePrefix: T.Optional(T.String({ description: 'Commit message prefix (default: "update")' })),
|
|
149
281
|
}),
|
|
150
282
|
execute: async (toolCallId, params) => {
|
|
151
283
|
try {
|
|
152
284
|
const progress = [];
|
|
153
|
-
progress.push(
|
|
154
|
-
const result = await commitStaging(workspacePath, (msg) => progress.push(msg), { force: params.force, noGit: false });
|
|
285
|
+
await commitRepos(workspacePath, (msg) => progress.push(msg), { messagePrefix: params.messagePrefix ?? 'update' });
|
|
155
286
|
return wrapToolResult({
|
|
156
287
|
success: true,
|
|
157
|
-
result,
|
|
158
288
|
progress: progress.join('\n'),
|
|
159
289
|
});
|
|
160
290
|
}
|
|
@@ -166,31 +296,6 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
166
296
|
}
|
|
167
297
|
},
|
|
168
298
|
},
|
|
169
|
-
// Abort staging
|
|
170
|
-
{
|
|
171
|
-
name: 'sync_abort',
|
|
172
|
-
label: 'Abort Staging',
|
|
173
|
-
description: 'Discard all staging files without committing.',
|
|
174
|
-
parameters: T.Object({}),
|
|
175
|
-
execute: async (toolCallId, params) => {
|
|
176
|
-
try {
|
|
177
|
-
const staging = new StagingManager(workspacePath);
|
|
178
|
-
const hadStaging = staging.hasStaging();
|
|
179
|
-
staging.clear();
|
|
180
|
-
return wrapToolResult({
|
|
181
|
-
success: true,
|
|
182
|
-
hadStaging,
|
|
183
|
-
message: hadStaging ? 'Staging cleared.' : 'No staging files to clear.',
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
catch (error) {
|
|
187
|
-
return wrapToolResult({
|
|
188
|
-
success: false,
|
|
189
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
299
|
// List sources and connectors
|
|
195
300
|
{
|
|
196
301
|
name: 'sync_list_sources',
|
|
@@ -202,9 +307,9 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
202
307
|
const configMgr = new SourceConfigManager(workspacePath);
|
|
203
308
|
const sources = configMgr.getAll();
|
|
204
309
|
// Load connectors but strip sensitive fields
|
|
205
|
-
const connectors = ConnectorManager.loadConfigs().map(c => ({
|
|
310
|
+
const connectors = ConnectorManager.loadConfigs(workspacePath).map(c => ({
|
|
206
311
|
name: c.name,
|
|
207
|
-
|
|
312
|
+
url: c.url,
|
|
208
313
|
description: c.description,
|
|
209
314
|
}));
|
|
210
315
|
const availableDefinitions = Object.keys(SOURCE_DEFINITIONS);
|
|
@@ -227,11 +332,10 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
227
332
|
{
|
|
228
333
|
name: 'sync_setup_source',
|
|
229
334
|
label: 'Setup Sync Source',
|
|
230
|
-
description: 'Add or reconfigure a sync source.
|
|
335
|
+
description: 'Add or reconfigure a sync source using built-in source definitions. The collection assignment is managed via sync rules in collection settings, not here.',
|
|
231
336
|
parameters: T.Object({
|
|
232
|
-
name: T.String({ description: 'Source name (
|
|
337
|
+
name: T.String({ description: 'Source name — must match a built-in source definition (e.g. "linear", "pipedrive", "granola", "asana")' }),
|
|
233
338
|
connector: T.Optional(T.String({ description: 'Connector name (defaults to source name)' })),
|
|
234
|
-
entity_mappings: T.Optional(T.Array(T.Object({}, { additionalProperties: true }), { description: 'Entity mappings (overrides defaults from source definition)' })),
|
|
235
339
|
force: T.Optional(T.Boolean({ description: 'Overwrite existing source config' })),
|
|
236
340
|
}),
|
|
237
341
|
execute: async (toolCallId, params) => {
|
|
@@ -247,7 +351,7 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
247
351
|
});
|
|
248
352
|
}
|
|
249
353
|
// Verify connector exists
|
|
250
|
-
const connectors = ConnectorManager.loadConfigs();
|
|
354
|
+
const connectors = ConnectorManager.loadConfigs(workspacePath);
|
|
251
355
|
const connector = connectors.find(c => c.name === connectorName);
|
|
252
356
|
if (!connector) {
|
|
253
357
|
return wrapToolResult({
|
|
@@ -256,30 +360,27 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
256
360
|
availableConnectors: connectors.map(c => c.name),
|
|
257
361
|
});
|
|
258
362
|
}
|
|
259
|
-
//
|
|
363
|
+
// Built-in definition required — don't allow custom configs
|
|
260
364
|
const definition = SOURCE_DEFINITIONS[params.name] ?? SOURCE_DEFINITIONS[connectorName];
|
|
261
|
-
|
|
262
|
-
const config = {
|
|
263
|
-
name: params.name,
|
|
264
|
-
connector: connectorName,
|
|
265
|
-
enabled: true,
|
|
266
|
-
added_at: new Date().toISOString(),
|
|
267
|
-
entity_mappings: mappings,
|
|
268
|
-
};
|
|
269
|
-
// Validate
|
|
270
|
-
const validation = configMgr.validate(config);
|
|
271
|
-
if (!validation.valid) {
|
|
365
|
+
if (!definition || !definition.entities || Object.keys(definition.entities).length === 0) {
|
|
272
366
|
return wrapToolResult({
|
|
273
367
|
success: false,
|
|
274
|
-
error:
|
|
275
|
-
validationErrors: validation.errors,
|
|
368
|
+
error: `No built-in source definition for "${params.name}". Available sources: ${Object.keys(SOURCE_DEFINITIONS).join(', ')}`,
|
|
276
369
|
});
|
|
277
370
|
}
|
|
278
|
-
|
|
371
|
+
// Save as new-format source definition
|
|
372
|
+
const savedDef = {
|
|
373
|
+
...definition,
|
|
374
|
+
name: params.name,
|
|
375
|
+
enabled: true,
|
|
376
|
+
added_at: new Date().toISOString(),
|
|
377
|
+
};
|
|
378
|
+
configMgr.saveDefinition(params.name, savedDef);
|
|
379
|
+
const entityTypes = Object.keys(definition.entities);
|
|
279
380
|
return wrapToolResult({
|
|
280
381
|
success: true,
|
|
281
|
-
message: `Source "${params.name}" configured with ${
|
|
282
|
-
|
|
382
|
+
message: `Source "${params.name}" configured with ${entityTypes.length} entity type(s): ${entityTypes.join(', ')}. Assign it to a collection via sync rules in collection settings.`,
|
|
383
|
+
definition: savedDef,
|
|
283
384
|
});
|
|
284
385
|
}
|
|
285
386
|
catch (error) {
|
|
@@ -573,80 +674,6 @@ export function createSyncTools(workspacePath, workspaceConfig, registryRef) {
|
|
|
573
674
|
}
|
|
574
675
|
},
|
|
575
676
|
},
|
|
576
|
-
// ── Enrich tools ──────────────────────────────────────────────────────────
|
|
577
|
-
// Run enrichment
|
|
578
|
-
{
|
|
579
|
-
name: 'enrich_run',
|
|
580
|
-
label: 'Enrich Entities',
|
|
581
|
-
description: 'Enrich entities with cross-source context via LLM. Writes changes in-place (no staging). Review with workspace_review, then commit with workspace_commit. Always confirm with the user before calling this.',
|
|
582
|
-
parameters: T.Object({
|
|
583
|
-
entityTypes: T.Optional(T.Array(T.String(), { description: 'Only enrich specific entity types' })),
|
|
584
|
-
dryRun: T.Optional(T.Boolean({ description: 'Preview without writing changes' })),
|
|
585
|
-
minRefs: T.Optional(T.Number({ description: 'Minimum context references required (default: 2)' })),
|
|
586
|
-
maxCompleteness: T.Optional(T.Number({ description: 'Maximum completeness to qualify (default: 0.6)' })),
|
|
587
|
-
}),
|
|
588
|
-
execute: async (toolCallId, params) => {
|
|
589
|
-
try {
|
|
590
|
-
const progress = [];
|
|
591
|
-
const result = await runEnrichment({
|
|
592
|
-
workspacePath,
|
|
593
|
-
entityTypes: params.entityTypes,
|
|
594
|
-
dryRun: params.dryRun,
|
|
595
|
-
minRefs: params.minRefs,
|
|
596
|
-
maxCompleteness: params.maxCompleteness,
|
|
597
|
-
schemaExtensions: workspaceConfig.schema_extensions,
|
|
598
|
-
}, (msg) => progress.push(msg));
|
|
599
|
-
return wrapToolResult({
|
|
600
|
-
success: true,
|
|
601
|
-
result,
|
|
602
|
-
progress: progress.join('\n'),
|
|
603
|
-
nextSteps: result.enriched > 0 && !params.dryRun
|
|
604
|
-
? 'Review changes with workspace_review, then commit with workspace_commit or studiograph commit'
|
|
605
|
-
: undefined,
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
catch (error) {
|
|
609
|
-
return wrapToolResult({
|
|
610
|
-
success: false,
|
|
611
|
-
error: error instanceof Error ? error.message : 'Unknown error',
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
},
|
|
615
|
-
},
|
|
616
|
-
// Abort enrichment (revert uncommitted changes)
|
|
617
|
-
{
|
|
618
|
-
name: 'enrich_abort',
|
|
619
|
-
label: 'Abort Enrichment',
|
|
620
|
-
description: 'Discard uncommitted enrichment changes by reverting all entity files (git checkout + git clean).',
|
|
621
|
-
parameters: T.Object({}),
|
|
622
|
-
execute: async (toolCallId, _params) => {
|
|
623
|
-
try {
|
|
624
|
-
const repos = workspaceConfig.repos ?? [];
|
|
625
|
-
const reverted = [];
|
|
626
|
-
for (const repo of repos) {
|
|
627
|
-
const repoPath = join(workspacePath, repo.path);
|
|
628
|
-
if (!existsSync(repoPath))
|
|
629
|
-
continue;
|
|
630
|
-
spawnSync('git', ['checkout', '--', '.'], { cwd: repoPath, encoding: 'utf-8' });
|
|
631
|
-
spawnSync('git', ['clean', '-fd'], { cwd: repoPath, encoding: 'utf-8' });
|
|
632
|
-
reverted.push(repo.name);
|
|
633
|
-
}
|
|
634
|
-
return wrapToolResult({
|
|
635
|
-
success: true,
|
|
636
|
-
reverted,
|
|
637
|
-
message: reverted.length > 0
|
|
638
|
-
? `Reverted changes in: ${reverted.join(', ')}`
|
|
639
|
-
: 'No changes to revert.',
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
catch (error) {
|
|
643
|
-
return wrapToolResult({
|
|
644
|
-
success: false,
|
|
645
|
-
error: String(error instanceof Error ? error.message : error),
|
|
646
|
-
});
|
|
647
|
-
}
|
|
648
|
-
},
|
|
649
|
-
},
|
|
650
677
|
// Reset workspace (discard uncommitted changes)
|
|
651
678
|
{
|
|
652
679
|
name: 'workspace_reset',
|