studiograph 1.3.48-next.2 → 1.3.48-next.201

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.
Files changed (1157) hide show
  1. package/README.md +26 -16
  2. package/dist/agent/agent-pool.d.ts +117 -0
  3. package/dist/agent/agent-pool.js +287 -0
  4. package/dist/agent/agent-pool.js.map +1 -0
  5. package/dist/agent/followups.d.ts +34 -0
  6. package/dist/agent/followups.js +52 -0
  7. package/dist/agent/followups.js.map +1 -0
  8. package/dist/agent/orchestrator.d.ts +113 -22
  9. package/dist/agent/orchestrator.js +574 -181
  10. package/dist/agent/orchestrator.js.map +1 -1
  11. package/dist/agent/prompts/entity-types-section.d.ts +34 -0
  12. package/dist/agent/prompts/entity-types-section.js +76 -0
  13. package/dist/agent/prompts/entity-types-section.js.map +1 -0
  14. package/dist/agent/prompts/system.md +147 -69
  15. package/dist/agent/skill-loader.d.ts +30 -17
  16. package/dist/agent/skill-loader.js +63 -30
  17. package/dist/agent/skill-loader.js.map +1 -1
  18. package/dist/agent/skills/entity-schema.md +77 -433
  19. package/dist/agent/skills/interview/entity-templates.md +193 -0
  20. package/dist/agent/skills/interview/question-domains.md +391 -0
  21. package/dist/agent/skills/interview/skill.md +204 -0
  22. package/dist/agent/skills/schema-rules.md +54 -0
  23. package/dist/agent/tools/capture-tools.d.ts +31 -0
  24. package/dist/agent/tools/capture-tools.js +40 -0
  25. package/dist/agent/tools/capture-tools.js.map +1 -0
  26. package/dist/agent/tools/folder-tools.d.ts +47 -0
  27. package/dist/agent/tools/folder-tools.js +249 -0
  28. package/dist/agent/tools/folder-tools.js.map +1 -0
  29. package/dist/agent/tools/fs-tools.d.ts +7 -6
  30. package/dist/agent/tools/fs-tools.js +5 -4
  31. package/dist/agent/tools/fs-tools.js.map +1 -1
  32. package/dist/agent/tools/graph-tools.d.ts +21 -58
  33. package/dist/agent/tools/graph-tools.js +664 -333
  34. package/dist/agent/tools/graph-tools.js.map +1 -1
  35. package/dist/agent/tools/history-tools.d.ts +95 -0
  36. package/dist/agent/tools/history-tools.js +461 -0
  37. package/dist/agent/tools/history-tools.js.map +1 -0
  38. package/dist/agent/tools/load-skill.d.ts +6 -5
  39. package/dist/agent/tools/load-skill.js +3 -3
  40. package/dist/agent/tools/load-skill.js.map +1 -1
  41. package/dist/agent/tools/ops-tools.d.ts +5 -4
  42. package/dist/agent/tools/ops-tools.js +130 -236
  43. package/dist/agent/tools/ops-tools.js.map +1 -1
  44. package/dist/agent/tools/permission-tools.d.ts +87 -17
  45. package/dist/agent/tools/permission-tools.js +233 -38
  46. package/dist/agent/tools/permission-tools.js.map +1 -1
  47. package/dist/agent/tools/tool-loader.js +5 -4
  48. package/dist/agent/tools/tool-loader.js.map +1 -1
  49. package/dist/agent/tools/web-tools.js +58 -9
  50. package/dist/agent/tools/web-tools.js.map +1 -1
  51. package/dist/cli/commands/about.d.ts +1 -0
  52. package/dist/cli/commands/about.js +55 -3
  53. package/dist/cli/commands/about.js.map +1 -1
  54. package/dist/cli/commands/admin/audit-workspace.d.ts +23 -0
  55. package/dist/cli/commands/admin/audit-workspace.js +133 -0
  56. package/dist/cli/commands/admin/audit-workspace.js.map +1 -0
  57. package/dist/cli/commands/admin/audit.d.ts +21 -0
  58. package/dist/cli/commands/admin/audit.js +174 -0
  59. package/dist/cli/commands/admin/audit.js.map +1 -0
  60. package/dist/cli/commands/admin/backup.d.ts +54 -0
  61. package/dist/cli/commands/admin/backup.js +207 -0
  62. package/dist/cli/commands/admin/backup.js.map +1 -0
  63. package/dist/cli/commands/admin/folder.d.ts +11 -0
  64. package/dist/cli/commands/admin/folder.js +186 -0
  65. package/dist/cli/commands/admin/folder.js.map +1 -0
  66. package/dist/cli/commands/admin/index.d.ts +16 -0
  67. package/dist/cli/commands/admin/index.js +46 -0
  68. package/dist/cli/commands/admin/index.js.map +1 -0
  69. package/dist/cli/commands/admin/migrate-assets.d.ts +53 -0
  70. package/dist/cli/commands/admin/migrate-assets.js +184 -0
  71. package/dist/cli/commands/admin/migrate-assets.js.map +1 -0
  72. package/dist/cli/commands/admin/migrate.d.ts +56 -0
  73. package/dist/cli/commands/admin/migrate.js +263 -0
  74. package/dist/cli/commands/admin/migrate.js.map +1 -0
  75. package/dist/cli/commands/admin/restore.d.ts +24 -0
  76. package/dist/cli/commands/admin/restore.js +228 -0
  77. package/dist/cli/commands/admin/restore.js.map +1 -0
  78. package/dist/cli/commands/admin/secrets.d.ts +23 -0
  79. package/dist/cli/commands/admin/secrets.js +256 -0
  80. package/dist/cli/commands/admin/secrets.js.map +1 -0
  81. package/dist/cli/commands/admin/settings.d.ts +28 -0
  82. package/dist/cli/commands/admin/settings.js +284 -0
  83. package/dist/cli/commands/admin/settings.js.map +1 -0
  84. package/dist/cli/commands/admin/token.d.ts +42 -0
  85. package/dist/cli/commands/admin/token.js +126 -0
  86. package/dist/cli/commands/admin/token.js.map +1 -0
  87. package/dist/cli/commands/admin/transfer-ownership.d.ts +15 -0
  88. package/dist/cli/commands/admin/transfer-ownership.js +106 -0
  89. package/dist/cli/commands/admin/transfer-ownership.js.map +1 -0
  90. package/dist/cli/commands/admin/user.d.ts +11 -0
  91. package/dist/cli/commands/admin/user.js +187 -0
  92. package/dist/cli/commands/admin/user.js.map +1 -0
  93. package/dist/cli/commands/clone.d.ts +25 -3
  94. package/dist/cli/commands/clone.js +142 -36
  95. package/dist/cli/commands/clone.js.map +1 -1
  96. package/dist/cli/commands/commit.d.ts +1 -1
  97. package/dist/cli/commands/commit.js +24 -11
  98. package/dist/cli/commands/commit.js.map +1 -1
  99. package/dist/cli/commands/config.d.ts +23 -107
  100. package/dist/cli/commands/config.js +52 -260
  101. package/dist/cli/commands/config.js.map +1 -1
  102. package/dist/cli/commands/connector.d.ts +10 -13
  103. package/dist/cli/commands/connector.js +16 -58
  104. package/dist/cli/commands/connector.js.map +1 -1
  105. package/dist/cli/commands/deploy.js +215 -68
  106. package/dist/cli/commands/deploy.js.map +1 -1
  107. package/dist/cli/commands/index.js +2 -2
  108. package/dist/cli/commands/index.js.map +1 -1
  109. package/dist/cli/commands/init.js +10 -30
  110. package/dist/cli/commands/init.js.map +1 -1
  111. package/dist/cli/commands/mcp.js +12 -4
  112. package/dist/cli/commands/mcp.js.map +1 -1
  113. package/dist/cli/commands/orphans.js +14 -30
  114. package/dist/cli/commands/orphans.js.map +1 -1
  115. package/dist/cli/commands/r2.d.ts +3 -0
  116. package/dist/cli/commands/r2.js +223 -204
  117. package/dist/cli/commands/r2.js.map +1 -1
  118. package/dist/cli/commands/redeploy.js +65 -12
  119. package/dist/cli/commands/redeploy.js.map +1 -1
  120. package/dist/cli/commands/reset.d.ts +22 -6
  121. package/dist/cli/commands/reset.js +142 -63
  122. package/dist/cli/commands/reset.js.map +1 -1
  123. package/dist/cli/commands/serve.js +218 -24
  124. package/dist/cli/commands/serve.js.map +1 -1
  125. package/dist/cli/commands/sync.d.ts +1 -1
  126. package/dist/cli/commands/sync.js +372 -202
  127. package/dist/cli/commands/sync.js.map +1 -1
  128. package/dist/cli/crypto-bundle.d.ts +39 -0
  129. package/dist/cli/crypto-bundle.js +94 -0
  130. package/dist/cli/crypto-bundle.js.map +1 -0
  131. package/dist/cli/index.js +24 -35
  132. package/dist/cli/index.js.map +1 -1
  133. package/dist/cli/railway-pin.d.ts +68 -0
  134. package/dist/cli/railway-pin.js +96 -0
  135. package/dist/cli/railway-pin.js.map +1 -0
  136. package/dist/cli/railway-provisioning.d.ts +53 -0
  137. package/dist/cli/railway-provisioning.js +85 -0
  138. package/dist/cli/railway-provisioning.js.map +1 -0
  139. package/dist/cli/setup-wizard.d.ts +33 -52
  140. package/dist/cli/setup-wizard.js +43 -68
  141. package/dist/cli/setup-wizard.js.map +1 -1
  142. package/dist/core/accent-palette.d.ts +22 -0
  143. package/dist/core/accent-palette.js +47 -0
  144. package/dist/core/accent-palette.js.map +1 -0
  145. package/dist/core/cell-anchor.d.ts +29 -0
  146. package/dist/core/cell-anchor.js +53 -0
  147. package/dist/core/cell-anchor.js.map +1 -0
  148. package/dist/core/comment-anchor.d.ts +41 -0
  149. package/dist/core/comment-anchor.js +147 -0
  150. package/dist/core/comment-anchor.js.map +1 -0
  151. package/dist/core/commit-messages.d.ts +57 -0
  152. package/dist/core/commit-messages.js +85 -0
  153. package/dist/core/commit-messages.js.map +1 -0
  154. package/dist/core/embeds.d.ts +77 -0
  155. package/dist/core/embeds.js +147 -0
  156. package/dist/core/embeds.js.map +1 -0
  157. package/dist/core/entity-body-templates.d.ts +21 -0
  158. package/dist/core/entity-body-templates.js +53 -0
  159. package/dist/core/entity-body-templates.js.map +1 -0
  160. package/dist/core/entity-types-catalog.d.ts +65 -0
  161. package/dist/core/entity-types-catalog.js +140 -0
  162. package/dist/core/entity-types-catalog.js.map +1 -0
  163. package/dist/core/folder-paths.d.ts +41 -0
  164. package/dist/core/folder-paths.js +95 -0
  165. package/dist/core/folder-paths.js.map +1 -0
  166. package/dist/core/folder-sidecar.d.ts +36 -0
  167. package/dist/core/folder-sidecar.js +91 -0
  168. package/dist/core/folder-sidecar.js.map +1 -0
  169. package/dist/core/format-registry.d.ts +170 -0
  170. package/dist/core/format-registry.js +404 -0
  171. package/dist/core/format-registry.js.map +1 -0
  172. package/dist/core/graph.d.ts +731 -14
  173. package/dist/core/graph.js +2202 -315
  174. package/dist/core/graph.js.map +1 -1
  175. package/dist/core/history-diff.d.ts +35 -0
  176. package/dist/core/history-diff.js +114 -0
  177. package/dist/core/history-diff.js.map +1 -0
  178. package/dist/core/refs.d.ts +41 -0
  179. package/dist/core/refs.js +80 -0
  180. package/dist/core/refs.js.map +1 -0
  181. package/dist/core/schema-registry.d.ts +82 -0
  182. package/dist/core/schema-registry.js +238 -0
  183. package/dist/core/schema-registry.js.map +1 -1
  184. package/dist/core/schemas/connector.d.ts +67 -0
  185. package/dist/core/schemas/connector.js +100 -0
  186. package/dist/core/schemas/connector.js.map +1 -0
  187. package/dist/core/schemas/workspace.d.ts +122 -0
  188. package/dist/core/schemas/workspace.js +211 -0
  189. package/dist/core/schemas/workspace.js.map +1 -0
  190. package/dist/core/secrets/SecretStore.d.ts +77 -0
  191. package/dist/core/secrets/SecretStore.js +13 -0
  192. package/dist/core/secrets/SecretStore.js.map +1 -0
  193. package/dist/core/secrets/SettingsResolver.d.ts +54 -0
  194. package/dist/core/secrets/SettingsResolver.js +80 -0
  195. package/dist/core/secrets/SettingsResolver.js.map +1 -0
  196. package/dist/core/secrets/SettingsStore.d.ts +30 -0
  197. package/dist/core/secrets/SettingsStore.js +9 -0
  198. package/dist/core/secrets/SettingsStore.js.map +1 -0
  199. package/dist/core/secrets/SqliteEncryptedStore.d.ts +90 -0
  200. package/dist/core/secrets/SqliteEncryptedStore.js +598 -0
  201. package/dist/core/secrets/SqliteEncryptedStore.js.map +1 -0
  202. package/dist/core/secrets/audit.d.ts +36 -0
  203. package/dist/core/secrets/audit.js +60 -0
  204. package/dist/core/secrets/audit.js.map +1 -0
  205. package/dist/core/secrets/auth-db-migration.d.ts +129 -0
  206. package/dist/core/secrets/auth-db-migration.js +653 -0
  207. package/dist/core/secrets/auth-db-migration.js.map +1 -0
  208. package/dist/core/secrets/bundle.d.ts +141 -0
  209. package/dist/core/secrets/bundle.js +435 -0
  210. package/dist/core/secrets/bundle.js.map +1 -0
  211. package/dist/core/secrets/dual-write.d.ts +81 -0
  212. package/dist/core/secrets/dual-write.js +247 -0
  213. package/dist/core/secrets/dual-write.js.map +1 -0
  214. package/dist/core/secrets/encryption.d.ts +44 -0
  215. package/dist/core/secrets/encryption.js +97 -0
  216. package/dist/core/secrets/encryption.js.map +1 -0
  217. package/dist/core/secrets/index.d.ts +49 -0
  218. package/dist/core/secrets/index.js +74 -0
  219. package/dist/core/secrets/index.js.map +1 -0
  220. package/dist/core/secrets/master-key.d.ts +38 -0
  221. package/dist/core/secrets/master-key.js +122 -0
  222. package/dist/core/secrets/master-key.js.map +1 -0
  223. package/dist/core/secrets/probes/anthropic.d.ts +98 -0
  224. package/dist/core/secrets/probes/anthropic.js +300 -0
  225. package/dist/core/secrets/probes/anthropic.js.map +1 -0
  226. package/dist/core/secrets/probes/brave.d.ts +9 -0
  227. package/dist/core/secrets/probes/brave.js +15 -0
  228. package/dist/core/secrets/probes/brave.js.map +1 -0
  229. package/dist/core/secrets/probes/r2.d.ts +15 -0
  230. package/dist/core/secrets/probes/r2.js +14 -0
  231. package/dist/core/secrets/probes/r2.js.map +1 -0
  232. package/dist/core/secrets/probes/tavily.d.ts +18 -0
  233. package/dist/core/secrets/probes/tavily.js +58 -0
  234. package/dist/core/secrets/probes/tavily.js.map +1 -0
  235. package/dist/core/secrets/probes/voyage.d.ts +13 -0
  236. package/dist/core/secrets/probes/voyage.js +52 -0
  237. package/dist/core/secrets/probes/voyage.js.map +1 -0
  238. package/dist/core/secrets/r2-structural-migration.d.ts +39 -0
  239. package/dist/core/secrets/r2-structural-migration.js +109 -0
  240. package/dist/core/secrets/r2-structural-migration.js.map +1 -0
  241. package/dist/core/secrets/read-flip.d.ts +59 -0
  242. package/dist/core/secrets/read-flip.js +87 -0
  243. package/dist/core/secrets/read-flip.js.map +1 -0
  244. package/dist/core/secrets/registry.d.ts +188 -0
  245. package/dist/core/secrets/registry.js +616 -0
  246. package/dist/core/secrets/registry.js.map +1 -0
  247. package/dist/core/types.d.ts +80 -475
  248. package/dist/core/types.js +27 -3
  249. package/dist/core/types.js.map +1 -1
  250. package/dist/core/user-config.d.ts +75 -7
  251. package/dist/core/user-config.js +155 -7
  252. package/dist/core/user-config.js.map +1 -1
  253. package/dist/core/validation.d.ts +731 -1790
  254. package/dist/core/validation.js +442 -228
  255. package/dist/core/validation.js.map +1 -1
  256. package/dist/core/workspace-manager.d.ts +89 -12
  257. package/dist/core/workspace-manager.js +225 -73
  258. package/dist/core/workspace-manager.js.map +1 -1
  259. package/dist/core/workspace.d.ts +19 -5
  260. package/dist/core/workspace.js +69 -35
  261. package/dist/core/workspace.js.map +1 -1
  262. package/dist/mcp/comment-virtual-entity.d.ts +36 -0
  263. package/dist/mcp/comment-virtual-entity.js +71 -0
  264. package/dist/mcp/comment-virtual-entity.js.map +1 -0
  265. package/dist/mcp/connector-manager.d.ts +94 -13
  266. package/dist/mcp/connector-manager.js +283 -62
  267. package/dist/mcp/connector-manager.js.map +1 -1
  268. package/dist/mcp/oauth-provider.d.ts +27 -33
  269. package/dist/mcp/oauth-provider.js +65 -134
  270. package/dist/mcp/oauth-provider.js.map +1 -1
  271. package/dist/mcp/oauth-registry.d.ts +62 -0
  272. package/dist/mcp/oauth-registry.js +85 -0
  273. package/dist/mcp/oauth-registry.js.map +1 -0
  274. package/dist/mcp/server.d.ts +11 -3
  275. package/dist/mcp/server.js +30 -5
  276. package/dist/mcp/server.js.map +1 -1
  277. package/dist/mcp/state-signer.d.ts +62 -0
  278. package/dist/mcp/state-signer.js +205 -0
  279. package/dist/mcp/state-signer.js.map +1 -0
  280. package/dist/mcp/tools.d.ts +35 -2
  281. package/dist/mcp/tools.js +1361 -112
  282. package/dist/mcp/tools.js.map +1 -1
  283. package/dist/server/__tests__/helpers/graph-api.d.ts +16 -0
  284. package/dist/server/__tests__/helpers/graph-api.js +16 -0
  285. package/dist/server/__tests__/helpers/graph-api.js.map +1 -0
  286. package/dist/server/asset-index-queue.d.ts +96 -0
  287. package/dist/server/asset-index-queue.js +191 -0
  288. package/dist/server/asset-index-queue.js.map +1 -0
  289. package/dist/server/body-write-coordinator.d.ts +151 -0
  290. package/dist/server/body-write-coordinator.js +161 -0
  291. package/dist/server/body-write-coordinator.js.map +1 -0
  292. package/dist/server/cloud-billing-flow.d.ts +32 -0
  293. package/dist/server/cloud-billing-flow.js +75 -0
  294. package/dist/server/cloud-billing-flow.js.map +1 -0
  295. package/dist/server/commit-audit.d.ts +26 -0
  296. package/dist/server/commit-audit.js +30 -0
  297. package/dist/server/commit-audit.js.map +1 -0
  298. package/dist/server/index.d.ts +22 -3
  299. package/dist/server/index.js +622 -198
  300. package/dist/server/index.js.map +1 -1
  301. package/dist/server/middleware/sanitize.d.ts +46 -0
  302. package/dist/server/middleware/sanitize.js +171 -0
  303. package/dist/server/middleware/sanitize.js.map +1 -0
  304. package/dist/server/routes/asset-api.d.ts +31 -0
  305. package/dist/server/routes/asset-api.js +593 -0
  306. package/dist/server/routes/asset-api.js.map +1 -0
  307. package/dist/server/routes/audit-api.d.ts +24 -0
  308. package/dist/server/routes/audit-api.js +117 -0
  309. package/dist/server/routes/audit-api.js.map +1 -0
  310. package/dist/server/routes/auth-api.d.ts +3 -2
  311. package/dist/server/routes/auth-api.js +573 -39
  312. package/dist/server/routes/auth-api.js.map +1 -1
  313. package/dist/server/routes/capture-api.d.ts +18 -0
  314. package/dist/server/routes/capture-api.js +257 -0
  315. package/dist/server/routes/capture-api.js.map +1 -0
  316. package/dist/server/routes/chat-sessions-api.d.ts +9 -0
  317. package/dist/server/routes/chat-sessions-api.js +121 -0
  318. package/dist/server/routes/chat-sessions-api.js.map +1 -0
  319. package/dist/server/routes/chat.d.ts +12 -1
  320. package/dist/server/routes/chat.js +318 -88
  321. package/dist/server/routes/chat.js.map +1 -1
  322. package/dist/server/routes/comments-api.d.ts +15 -0
  323. package/dist/server/routes/comments-api.js +444 -0
  324. package/dist/server/routes/comments-api.js.map +1 -0
  325. package/dist/server/routes/config-api.d.ts +21 -0
  326. package/dist/server/routes/config-api.js +256 -0
  327. package/dist/server/routes/config-api.js.map +1 -0
  328. package/dist/server/routes/connectors-api.d.ts +17 -0
  329. package/dist/server/routes/connectors-api.js +410 -0
  330. package/dist/server/routes/connectors-api.js.map +1 -0
  331. package/dist/server/routes/event-ingest-api.d.ts +15 -0
  332. package/dist/server/routes/event-ingest-api.js +125 -0
  333. package/dist/server/routes/event-ingest-api.js.map +1 -0
  334. package/dist/server/routes/git-http.d.ts +3 -3
  335. package/dist/server/routes/git-http.js +86 -38
  336. package/dist/server/routes/git-http.js.map +1 -1
  337. package/dist/server/routes/graph-api-access.d.ts +57 -0
  338. package/dist/server/routes/graph-api-access.js +112 -0
  339. package/dist/server/routes/graph-api-access.js.map +1 -0
  340. package/dist/server/routes/graph-api.d.ts +1 -1
  341. package/dist/server/routes/graph-api.js +1529 -263
  342. package/dist/server/routes/graph-api.js.map +1 -1
  343. package/dist/server/routes/health.d.ts +18 -0
  344. package/dist/server/routes/health.js +74 -0
  345. package/dist/server/routes/health.js.map +1 -0
  346. package/dist/server/routes/import-batch.d.ts +24 -0
  347. package/dist/server/routes/import-batch.js +33 -0
  348. package/dist/server/routes/import-batch.js.map +1 -0
  349. package/dist/server/routes/insights-api.d.ts +9 -2
  350. package/dist/server/routes/insights-api.js +384 -38
  351. package/dist/server/routes/insights-api.js.map +1 -1
  352. package/dist/server/routes/mcp.d.ts +7 -3
  353. package/dist/server/routes/mcp.js +22 -6
  354. package/dist/server/routes/mcp.js.map +1 -1
  355. package/dist/server/routes/oauth-api.d.ts +67 -0
  356. package/dist/server/routes/oauth-api.js +421 -0
  357. package/dist/server/routes/oauth-api.js.map +1 -0
  358. package/dist/server/routes/permissions-api.d.ts +9 -2
  359. package/dist/server/routes/permissions-api.js +87 -30
  360. package/dist/server/routes/permissions-api.js.map +1 -1
  361. package/dist/server/routes/r2-api.d.ts +25 -0
  362. package/dist/server/routes/r2-api.js +276 -0
  363. package/dist/server/routes/r2-api.js.map +1 -0
  364. package/dist/server/routes/secrets-api.d.ts +36 -0
  365. package/dist/server/routes/secrets-api.js +308 -0
  366. package/dist/server/routes/secrets-api.js.map +1 -0
  367. package/dist/server/routes/settings-api.d.ts +29 -0
  368. package/dist/server/routes/settings-api.js +180 -0
  369. package/dist/server/routes/settings-api.js.map +1 -0
  370. package/dist/server/routes/share-api.d.ts +32 -0
  371. package/dist/server/routes/share-api.js +234 -0
  372. package/dist/server/routes/share-api.js.map +1 -0
  373. package/dist/server/routes/url-api.d.ts +7 -0
  374. package/dist/server/routes/url-api.js +74 -0
  375. package/dist/server/routes/url-api.js.map +1 -0
  376. package/dist/server/routes/views-api.js +75 -7
  377. package/dist/server/routes/views-api.js.map +1 -1
  378. package/dist/server/routes/workspace-api.d.ts +2 -1
  379. package/dist/server/routes/workspace-api.js +129 -35
  380. package/dist/server/routes/workspace-api.js.map +1 -1
  381. package/dist/server/routes/ws.d.ts +2 -1
  382. package/dist/server/routes/ws.js +68 -16
  383. package/dist/server/routes/ws.js.map +1 -1
  384. package/dist/server/session-manager.d.ts +48 -5
  385. package/dist/server/session-manager.js +182 -15
  386. package/dist/server/session-manager.js.map +1 -1
  387. package/dist/server/ws-hub.d.ts +138 -14
  388. package/dist/server/ws-hub.js +0 -0
  389. package/dist/server/ws-hub.js.map +1 -1
  390. package/dist/server/yjs-manager.d.ts +285 -7
  391. package/dist/server/yjs-manager.js +907 -36
  392. package/dist/server/yjs-manager.js.map +1 -1
  393. package/dist/server/yjs-persistence.d.ts +165 -0
  394. package/dist/server/yjs-persistence.js +557 -0
  395. package/dist/server/yjs-persistence.js.map +1 -0
  396. package/dist/server/yjs-text-diff.d.ts +32 -0
  397. package/dist/server/yjs-text-diff.js +61 -0
  398. package/dist/server/yjs-text-diff.js.map +1 -0
  399. package/dist/services/access-control.d.ts +73 -0
  400. package/dist/services/access-control.js +165 -0
  401. package/dist/services/access-control.js.map +1 -0
  402. package/dist/services/asset-caption-service.d.ts +102 -0
  403. package/dist/services/asset-caption-service.js +184 -0
  404. package/dist/services/asset-caption-service.js.map +1 -0
  405. package/dist/services/asset-delete-authz.d.ts +31 -0
  406. package/dist/services/asset-delete-authz.js +61 -0
  407. package/dist/services/asset-delete-authz.js.map +1 -0
  408. package/dist/services/asset-finalize-service.d.ts +58 -0
  409. package/dist/services/asset-finalize-service.js +207 -0
  410. package/dist/services/asset-finalize-service.js.map +1 -0
  411. package/dist/services/asset-import-service.d.ts +111 -0
  412. package/dist/services/asset-import-service.js +394 -0
  413. package/dist/services/asset-import-service.js.map +1 -0
  414. package/dist/services/asset-index-sweep.d.ts +92 -0
  415. package/dist/services/asset-index-sweep.js +258 -0
  416. package/dist/services/asset-index-sweep.js.map +1 -0
  417. package/dist/services/asset-lifecycle-check.d.ts +22 -0
  418. package/dist/services/asset-lifecycle-check.js +80 -0
  419. package/dist/services/asset-lifecycle-check.js.map +1 -0
  420. package/dist/services/asset-listing.d.ts +72 -0
  421. package/dist/services/asset-listing.js +321 -0
  422. package/dist/services/asset-listing.js.map +1 -0
  423. package/dist/services/asset-presign-service.d.ts +68 -0
  424. package/dist/services/asset-presign-service.js +124 -0
  425. package/dist/services/asset-presign-service.js.map +1 -0
  426. package/dist/services/asset-sidecar-service.d.ts +30 -0
  427. package/dist/services/asset-sidecar-service.js +96 -0
  428. package/dist/services/asset-sidecar-service.js.map +1 -0
  429. package/dist/services/asset-upload-errors.d.ts +41 -0
  430. package/dist/services/asset-upload-errors.js +45 -0
  431. package/dist/services/asset-upload-errors.js.map +1 -0
  432. package/dist/services/asset-upload-service.d.ts +74 -0
  433. package/dist/services/asset-upload-service.js +244 -0
  434. package/dist/services/asset-upload-service.js.map +1 -0
  435. package/dist/services/asset-upload-token.d.ts +58 -0
  436. package/dist/services/asset-upload-token.js +75 -0
  437. package/dist/services/asset-upload-token.js.map +1 -0
  438. package/dist/services/assets/asset-index-service.d.ts +127 -0
  439. package/dist/services/assets/asset-index-service.js +227 -0
  440. package/dist/services/assets/asset-index-service.js.map +1 -0
  441. package/dist/services/assets/base.d.ts +118 -1
  442. package/dist/services/assets/base.js +77 -1
  443. package/dist/services/assets/base.js.map +1 -1
  444. package/dist/services/assets/index.d.ts +103 -1
  445. package/dist/services/assets/index.js +192 -0
  446. package/dist/services/assets/index.js.map +1 -1
  447. package/dist/services/assets/local.d.ts +16 -1
  448. package/dist/services/assets/local.js +110 -1
  449. package/dist/services/assets/local.js.map +1 -1
  450. package/dist/services/assets/r2-sync.d.ts +88 -0
  451. package/dist/services/assets/r2-sync.js +412 -0
  452. package/dist/services/assets/r2-sync.js.map +1 -0
  453. package/dist/services/assets/r2.d.ts +87 -1
  454. package/dist/services/assets/r2.js +203 -1
  455. package/dist/services/assets/r2.js.map +1 -1
  456. package/dist/services/auth-service.d.ts +350 -36
  457. package/dist/services/auth-service.js +1179 -140
  458. package/dist/services/auth-service.js.map +1 -1
  459. package/dist/services/bookmark-import-service.d.ts +49 -0
  460. package/dist/services/bookmark-import-service.js +250 -0
  461. package/dist/services/bookmark-import-service.js.map +1 -0
  462. package/dist/services/chat-session-service.d.ts +96 -0
  463. package/dist/services/chat-session-service.js +316 -0
  464. package/dist/services/chat-session-service.js.map +1 -0
  465. package/dist/services/cloud-inference-billing.d.ts +64 -0
  466. package/dist/services/cloud-inference-billing.js +313 -0
  467. package/dist/services/cloud-inference-billing.js.map +1 -0
  468. package/dist/services/comment-service.d.ts +97 -0
  469. package/dist/services/comment-service.js +341 -0
  470. package/dist/services/comment-service.js.map +1 -0
  471. package/dist/services/convert-service.d.ts +64 -0
  472. package/dist/services/convert-service.js +68 -0
  473. package/dist/services/convert-service.js.map +1 -0
  474. package/dist/services/csv-service.d.ts +22 -17
  475. package/dist/services/csv-service.js +55 -92
  476. package/dist/services/csv-service.js.map +1 -1
  477. package/dist/services/entity-mutations.d.ts +210 -0
  478. package/dist/services/entity-mutations.js +377 -0
  479. package/dist/services/entity-mutations.js.map +1 -0
  480. package/dist/services/event-processor.d.ts +104 -0
  481. package/dist/services/event-processor.js +441 -0
  482. package/dist/services/event-processor.js.map +1 -0
  483. package/dist/services/extract/docx.d.ts +1 -0
  484. package/dist/services/extract/docx.js +233 -0
  485. package/dist/services/extract/docx.js.map +1 -0
  486. package/dist/services/extract/index.d.ts +9 -0
  487. package/dist/services/extract/index.js +10 -0
  488. package/dist/services/extract/index.js.map +1 -0
  489. package/dist/services/extract/pdf.d.ts +13 -0
  490. package/dist/services/extract/pdf.js +69 -0
  491. package/dist/services/extract/pdf.js.map +1 -0
  492. package/dist/services/folder-creation.d.ts +33 -0
  493. package/dist/services/folder-creation.js +103 -0
  494. package/dist/services/folder-creation.js.map +1 -0
  495. package/dist/services/git.d.ts +54 -0
  496. package/dist/services/git.js +188 -54
  497. package/dist/services/git.js.map +1 -1
  498. package/dist/services/graph-maintenance.d.ts +42 -0
  499. package/dist/services/graph-maintenance.js +143 -0
  500. package/dist/services/graph-maintenance.js.map +1 -0
  501. package/dist/services/import-service.d.ts +58 -3
  502. package/dist/services/import-service.js +316 -100
  503. package/dist/services/import-service.js.map +1 -1
  504. package/dist/services/lint-service.js +10 -17
  505. package/dist/services/lint-service.js.map +1 -1
  506. package/dist/services/markdown.d.ts +12 -1
  507. package/dist/services/markdown.js +77 -9
  508. package/dist/services/markdown.js.map +1 -1
  509. package/dist/services/memory-service.d.ts +22 -14
  510. package/dist/services/memory-service.js +53 -35
  511. package/dist/services/memory-service.js.map +1 -1
  512. package/dist/services/mention-detector.d.ts +23 -0
  513. package/dist/services/mention-detector.js +47 -0
  514. package/dist/services/mention-detector.js.map +1 -0
  515. package/dist/services/model-capabilities.d.ts +41 -0
  516. package/dist/services/model-capabilities.js +107 -0
  517. package/dist/services/model-capabilities.js.map +1 -0
  518. package/dist/services/notification-broadcast.d.ts +32 -0
  519. package/dist/services/notification-broadcast.js +38 -0
  520. package/dist/services/notification-broadcast.js.map +1 -0
  521. package/dist/services/notification-service.d.ts +41 -0
  522. package/dist/services/notification-service.js +100 -0
  523. package/dist/services/notification-service.js.map +1 -0
  524. package/dist/services/oauth-server-store.d.ts +147 -0
  525. package/dist/services/oauth-server-store.js +319 -0
  526. package/dist/services/oauth-server-store.js.map +1 -0
  527. package/dist/services/orphan-service.js +2 -2
  528. package/dist/services/orphan-service.js.map +1 -1
  529. package/dist/services/personal-folder.d.ts +40 -0
  530. package/dist/services/personal-folder.js +101 -0
  531. package/dist/services/personal-folder.js.map +1 -0
  532. package/dist/services/share-link-service.d.ts +57 -0
  533. package/dist/services/share-link-service.js +142 -0
  534. package/dist/services/share-link-service.js.map +1 -0
  535. package/dist/services/user-person-bridge.d.ts +136 -0
  536. package/dist/services/user-person-bridge.js +340 -0
  537. package/dist/services/user-person-bridge.js.map +1 -0
  538. package/dist/services/vector-service.d.ts +260 -6
  539. package/dist/services/vector-service.js +574 -31
  540. package/dist/services/vector-service.js.map +1 -1
  541. package/dist/services/workspace-access.d.ts +108 -0
  542. package/dist/services/workspace-access.js +149 -0
  543. package/dist/services/workspace-access.js.map +1 -0
  544. package/dist/services/workspace-assets-folder.d.ts +46 -0
  545. package/dist/services/workspace-assets-folder.js +75 -0
  546. package/dist/services/workspace-assets-folder.js.map +1 -0
  547. package/dist/utils/git.d.ts +17 -2
  548. package/dist/utils/git.js +23 -7
  549. package/dist/utils/git.js.map +1 -1
  550. package/dist/utils/log.d.ts +42 -0
  551. package/dist/utils/log.js +137 -0
  552. package/dist/utils/log.js.map +1 -0
  553. package/dist/utils/preflight.js +2 -2
  554. package/dist/utils/preflight.js.map +1 -1
  555. package/dist/utils/version-checker.d.ts +12 -19
  556. package/dist/utils/version-checker.js +14 -104
  557. package/dist/utils/version-checker.js.map +1 -1
  558. package/dist/web/_app/immutable/assets/0.BZHoBJEc.css +2 -0
  559. package/dist/web/_app/immutable/assets/12.DlIf1mKh.css +1 -0
  560. package/dist/web/_app/immutable/assets/13.7d-Q37wc.css +1 -0
  561. package/dist/web/_app/immutable/assets/14.BwBFdc1D.css +1 -0
  562. package/dist/web/_app/immutable/assets/15.CmLrbzZp.css +1 -0
  563. package/dist/web/_app/immutable/assets/16.B0GwXar3.css +1 -0
  564. package/dist/web/_app/immutable/assets/2.C9Vt4JHy.css +1 -0
  565. package/dist/web/_app/immutable/assets/3.BFvgCYSk.css +1 -0
  566. package/dist/web/_app/immutable/assets/4.OmdYF47-.css +1 -0
  567. package/dist/web/_app/immutable/assets/5.C6MySjPq.css +1 -0
  568. package/dist/web/_app/immutable/assets/BulkActionsBar.Bx7nxMjH.css +1 -0
  569. package/dist/web/_app/immutable/assets/CalendarView.lBCvS3X5.css +1 -0
  570. package/dist/web/_app/immutable/assets/CodeMirrorEditor.D6hf2pNJ.css +1 -0
  571. package/dist/web/_app/immutable/assets/CopyField.DVGZtw4U.css +1 -0
  572. package/dist/web/_app/immutable/assets/FolderMembersPanel.DX1oBeF_.css +1 -0
  573. package/dist/web/_app/immutable/assets/FolderMutationDialogs.D2B7KrRn.css +1 -0
  574. package/dist/web/_app/immutable/assets/FolderPicker.B5KdvRYl.css +1 -0
  575. package/dist/web/_app/immutable/assets/GalleryView.CF48FWYQ.css +1 -0
  576. package/dist/web/_app/immutable/assets/GraphView.BJtGL9py.css +1 -0
  577. package/dist/web/_app/immutable/assets/KanbanView.BOaI5KFL.css +1 -0
  578. package/dist/web/_app/immutable/assets/Link.vV0ne105.css +1 -0
  579. package/dist/web/_app/immutable/assets/Markdown.BqgpZCv5.css +1 -0
  580. package/dist/web/_app/immutable/assets/Rail.f8lsriOT.css +1 -0
  581. package/dist/web/_app/immutable/assets/SettingsDialog.DwMus2u2.css +1 -0
  582. package/dist/web/_app/immutable/assets/Spinner.UBfl0pab.css +1 -0
  583. package/dist/web/_app/immutable/assets/StopFilledAlt.fNlDN65D.css +1 -0
  584. package/dist/web/_app/immutable/assets/TimelineView.DriOGAKB.css +1 -0
  585. package/dist/web/_app/immutable/assets/WorkspaceView.u5VdwRR6.css +1 -0
  586. package/dist/web/_app/immutable/assets/button.BlLm4Dg1.css +1 -0
  587. package/dist/web/_app/immutable/assets/checkbox.DK0MgYgb.css +1 -0
  588. package/dist/web/_app/immutable/assets/dist.DDCWxn3B.css +1 -0
  589. package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-400-normal.CvHOgSBP.woff +0 -0
  590. package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-400-normal.DMJ8VG8y.woff2 +0 -0
  591. package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-500-normal.CB9ihrfo.woff +0 -0
  592. package/dist/web/_app/immutable/assets/ibm-plex-mono-latin-500-normal.DSY6xOcd.woff2 +0 -0
  593. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-italic.CZTNEAuW.woff2 +0 -0
  594. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-italic.CsGl1sm0.woff +0 -0
  595. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-normal.CDDApCn2.woff2 +0 -0
  596. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-400-normal.CYLoc0-x.woff +0 -0
  597. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-italic.BNK2_mGO.woff2 +0 -0
  598. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-italic.DpEwFAQM.woff +0 -0
  599. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-normal.6ng42L7E.woff2 +0 -0
  600. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-500-normal.BgVn5rGT.woff +0 -0
  601. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-600-normal.Cu4Hd6ag.woff +0 -0
  602. package/dist/web/_app/immutable/assets/ibm-plex-sans-latin-600-normal.CuJfVYMP.woff2 +0 -0
  603. package/dist/web/_app/immutable/assets/inline-list.cqga56xT.css +1 -0
  604. package/dist/web/_app/immutable/assets/list-columns.DiLB0G5L.css +1 -0
  605. package/dist/web/_app/immutable/assets/select.BFL238eD.css +1 -0
  606. package/dist/web/_app/immutable/assets/sheet.4rY4hpfJ.css +1 -0
  607. package/dist/web/_app/immutable/chunks/2oYV6q4R.js +2 -0
  608. package/dist/web/_app/immutable/chunks/4XSri7g0.js +1 -0
  609. package/dist/web/_app/immutable/chunks/4iaT0dG72.js +1 -0
  610. package/dist/web/_app/immutable/chunks/5_TKU9QS2.js +1 -0
  611. package/dist/web/_app/immutable/chunks/8Yh26Z9_2.js +1 -0
  612. package/dist/web/_app/immutable/chunks/Atl8xKOm.js +2 -0
  613. package/dist/web/_app/immutable/chunks/B-Z_xZy_.js +4 -0
  614. package/dist/web/_app/immutable/chunks/B0pk0Lyx.js +1 -0
  615. package/dist/web/_app/immutable/chunks/B1RnjnNt.js +1 -0
  616. package/dist/web/_app/immutable/chunks/B2n86UNJ.js +1 -0
  617. package/dist/web/_app/immutable/chunks/B318GEUB2.js +1 -0
  618. package/dist/web/_app/immutable/chunks/B6Lt-qaJ.js +1 -0
  619. package/dist/web/_app/immutable/chunks/B8yrQWxT2.js +1 -0
  620. package/dist/web/_app/immutable/chunks/BADt8daH.js +2 -0
  621. package/dist/web/_app/immutable/chunks/BBGt-XQo.js +3 -0
  622. package/dist/web/_app/immutable/chunks/BDIUHcEz.js +1 -0
  623. package/dist/web/_app/immutable/chunks/BDSuq3KH.js +1 -0
  624. package/dist/web/_app/immutable/chunks/BGiLU5VN.js +1 -0
  625. package/dist/web/_app/immutable/chunks/BJgOZTHR.js +1 -0
  626. package/dist/web/_app/immutable/chunks/BOSiTh-42.js +1 -0
  627. package/dist/web/_app/immutable/chunks/BPxcCdjn.js +1 -0
  628. package/dist/web/_app/immutable/chunks/BVPNAzAK.js +1 -0
  629. package/dist/web/_app/immutable/chunks/BcOvJgjM.js +1 -0
  630. package/dist/web/_app/immutable/chunks/BdYQewoD.js +1 -0
  631. package/dist/web/_app/immutable/chunks/BfCWIy8t.js +8 -0
  632. package/dist/web/_app/immutable/chunks/BgRT-K6w.js +5 -0
  633. package/dist/web/_app/immutable/chunks/BibveGGd.js +1 -0
  634. package/dist/web/_app/immutable/chunks/BmM5VZ4W.js +1 -0
  635. package/dist/web/_app/immutable/chunks/BnIYzuS1.js +66 -0
  636. package/dist/web/_app/immutable/chunks/BoDmwOTJ.js +1 -0
  637. package/dist/web/_app/immutable/chunks/BoglwbZW.js +1 -0
  638. package/dist/web/_app/immutable/chunks/Bqm_YrIg2.js +23 -0
  639. package/dist/web/_app/immutable/chunks/BtMRrdc4.js +2 -0
  640. package/dist/web/_app/immutable/chunks/C-AnzvKr.js +7 -0
  641. package/dist/web/_app/immutable/chunks/C1Y3tUpz.js +1 -0
  642. package/dist/web/_app/immutable/chunks/C6VZhhwF.js +1 -0
  643. package/dist/web/_app/immutable/chunks/C8IMrD4G2.js +3 -0
  644. package/dist/web/_app/immutable/chunks/CAXXrbj52.js +1 -0
  645. package/dist/web/_app/immutable/chunks/CB-0u-Pc2.js +1 -0
  646. package/dist/web/_app/immutable/chunks/CEniyZ1Z2.js +6 -0
  647. package/dist/web/_app/immutable/chunks/CJhElIkU2.js +1 -0
  648. package/dist/web/_app/immutable/chunks/CK8tIaYT.js +1 -0
  649. package/dist/web/_app/immutable/chunks/CM8uYli8.js +1 -0
  650. package/dist/web/_app/immutable/chunks/CTzjJm_m2.js +1 -0
  651. package/dist/web/_app/immutable/chunks/CUXqa1nn2.js +1 -0
  652. package/dist/web/_app/immutable/chunks/CY0iY_WO.js +1 -0
  653. package/dist/web/_app/immutable/chunks/CbCfNNV_2.js +2692 -0
  654. package/dist/web/_app/immutable/chunks/CbuGIyDu2.js +22 -0
  655. package/dist/web/_app/immutable/chunks/CcRGXA-t.js +1 -0
  656. package/dist/web/_app/immutable/chunks/CcXmQaYs2.js +1 -0
  657. package/dist/web/_app/immutable/chunks/CcaQuaSt2.js +1 -0
  658. package/dist/web/_app/immutable/chunks/CoHaBDpN2.js +2 -0
  659. package/dist/web/_app/immutable/chunks/Cvbd3myc2.js +14 -0
  660. package/dist/web/_app/immutable/chunks/D20C1thX2.js +1 -0
  661. package/dist/web/_app/immutable/chunks/D3JoMtWC.js +7 -0
  662. package/dist/web/_app/immutable/chunks/D3ch71s_.js +1 -0
  663. package/dist/web/_app/immutable/chunks/D4xXlMEU.js +2 -0
  664. package/dist/web/_app/immutable/chunks/D5GipQqN2.js +1 -0
  665. package/dist/web/_app/immutable/chunks/D9TyJuu_.js +1 -0
  666. package/dist/web/_app/immutable/chunks/DBFijAmG.js +1 -0
  667. package/dist/web/_app/immutable/chunks/DHLjkH7T.js +1 -0
  668. package/dist/web/_app/immutable/chunks/DIfdPIt_2.js +1 -0
  669. package/dist/web/_app/immutable/chunks/DO_sw49q2.js +1 -0
  670. package/dist/web/_app/immutable/chunks/DP69PpIj.js +1 -0
  671. package/dist/web/_app/immutable/chunks/DQ3HSZMs.js +2 -0
  672. package/dist/web/_app/immutable/chunks/DQMWa2t7.js +1 -0
  673. package/dist/web/_app/immutable/chunks/DT0wzK622.js +1 -0
  674. package/dist/web/_app/immutable/chunks/DTnEJArL.js +1 -0
  675. package/dist/web/_app/immutable/chunks/DToS-G202.js +1 -0
  676. package/dist/web/_app/immutable/chunks/DZcU6mGe2.js +1 -0
  677. package/dist/web/_app/immutable/chunks/DbslMybD.js +1 -0
  678. package/dist/web/_app/immutable/chunks/DcGThsSF.js +1 -0
  679. package/dist/web/_app/immutable/chunks/DcPrzUMJ.js +1 -0
  680. package/dist/web/_app/immutable/chunks/De0g5qop2.js +1 -0
  681. package/dist/web/_app/immutable/chunks/DimS8dbZ2.js +1 -0
  682. package/dist/web/_app/immutable/chunks/DjuqhOjF.js +1 -0
  683. package/dist/web/_app/immutable/chunks/Dk6sAhpo.js +3 -0
  684. package/dist/web/_app/immutable/chunks/Dl6cnwyk.js +1 -0
  685. package/dist/web/_app/immutable/chunks/DnIQzIOz.js +1 -0
  686. package/dist/web/_app/immutable/chunks/DnXYAo60.js +1 -0
  687. package/dist/web/_app/immutable/chunks/DnrImJan.js +1 -0
  688. package/dist/web/_app/immutable/chunks/Dpuq25vu2.js +1 -0
  689. package/dist/web/_app/immutable/chunks/DrMZDWru.js +1 -0
  690. package/dist/web/_app/immutable/chunks/DsVOtl0N.js +1 -0
  691. package/dist/web/_app/immutable/chunks/DuTXsWdP.js +2 -0
  692. package/dist/web/_app/immutable/chunks/Dw-frCfE.js +1 -0
  693. package/dist/web/_app/immutable/chunks/Dz34u8Ie2.js +185 -0
  694. package/dist/web/_app/immutable/chunks/DzcFeQZU2.js +2 -0
  695. package/dist/web/_app/immutable/chunks/DzrRTvug.js +1 -0
  696. package/dist/web/_app/immutable/chunks/G5oUVQa92.js +1 -0
  697. package/dist/web/_app/immutable/chunks/HyhOhoeq2.js +2 -0
  698. package/dist/web/_app/immutable/chunks/J5nb9xxj.js +1 -0
  699. package/dist/web/_app/immutable/chunks/JCjEwqH9.js +1 -0
  700. package/dist/web/_app/immutable/chunks/JN_nsXUm2.js +1 -0
  701. package/dist/web/_app/immutable/chunks/JS2_GaB1.js +1 -0
  702. package/dist/web/_app/immutable/chunks/MtI6dyxu.js +1 -0
  703. package/dist/web/_app/immutable/chunks/N6vnY5Si2.js +1 -0
  704. package/dist/web/_app/immutable/chunks/PcEbaKam.js +2 -0
  705. package/dist/web/_app/immutable/chunks/VTYhCLh9.js +2 -0
  706. package/dist/web/_app/immutable/chunks/Wowi_89k.js +5 -0
  707. package/dist/web/_app/immutable/chunks/Y_asqJqs2.js +83 -0
  708. package/dist/web/_app/immutable/chunks/Yhg5Q4MT.js +1 -0
  709. package/dist/web/_app/immutable/chunks/f_eYccPf2.js +1 -0
  710. package/dist/web/_app/immutable/chunks/hm_8RsuL.js +1 -0
  711. package/dist/web/_app/immutable/chunks/iPCkjliu.js +3 -0
  712. package/dist/web/_app/immutable/chunks/j2AvgZGz.js +1 -0
  713. package/dist/web/_app/immutable/chunks/kNaey6uv.js +1 -0
  714. package/dist/web/_app/immutable/chunks/l1761xxj.js +1 -0
  715. package/dist/web/_app/immutable/chunks/liGRFQqV2.js +184 -0
  716. package/dist/web/_app/immutable/chunks/lq1kR86d.js +1 -0
  717. package/dist/web/_app/immutable/chunks/mIykYR4F2.js +1 -0
  718. package/dist/web/_app/immutable/chunks/rbhlO_t8.js +1 -0
  719. package/dist/web/_app/immutable/chunks/tJpAwaTl.js +1 -0
  720. package/dist/web/_app/immutable/chunks/tcegdii0.js +2 -0
  721. package/dist/web/_app/immutable/chunks/u8G2EUvz2.js +224 -0
  722. package/dist/web/_app/immutable/chunks/vgsM0KTm2.js +1 -0
  723. package/dist/web/_app/immutable/chunks/xcGI4fuV.js +1 -0
  724. package/dist/web/_app/immutable/chunks/xihTtKlq.js +1 -0
  725. package/dist/web/_app/immutable/chunks/yEYlhV9G2.js +1 -0
  726. package/dist/web/_app/immutable/entry/app.DSf_XGp8.js +2 -0
  727. package/dist/web/_app/immutable/entry/start.B7ScfxPc.js +1 -0
  728. package/dist/web/_app/immutable/nodes/0.BMSOOETY.js +2 -0
  729. package/dist/web/_app/immutable/nodes/1.B0lBUpHt.js +1 -0
  730. package/dist/web/_app/immutable/nodes/10.DmDbUH1j.js +1 -0
  731. package/dist/web/_app/immutable/nodes/11.gwY7gZdR.js +1 -0
  732. package/dist/web/_app/immutable/nodes/12.BpGHSr2y.js +1 -0
  733. package/dist/web/_app/immutable/nodes/13.Bf178QF_.js +1 -0
  734. package/dist/web/_app/immutable/nodes/14.D_x8-nk9.js +1 -0
  735. package/dist/web/_app/immutable/nodes/15.DY4XeagL.js +1 -0
  736. package/dist/web/_app/immutable/nodes/16.DPqftx8x.js +77 -0
  737. package/dist/web/_app/immutable/nodes/2.OM2LGRpi.js +109 -0
  738. package/dist/web/_app/immutable/nodes/3.e8ZoPCmC.js +6 -0
  739. package/dist/web/_app/immutable/nodes/4.BdYR1hNQ.js +11 -0
  740. package/dist/web/_app/immutable/nodes/5.B8sOFna9.js +5 -0
  741. package/dist/web/_app/immutable/nodes/6.L1BbYsmo.js +1 -0
  742. package/dist/web/_app/immutable/nodes/7.B7zoemJD.js +1 -0
  743. package/dist/web/_app/immutable/nodes/8.B1VtnfMK.js +1 -0
  744. package/dist/web/_app/immutable/nodes/9.BE3VCQzk.js +1 -0
  745. package/dist/web/_app/version.json +1 -1
  746. package/dist/web/favicon-16.png +0 -0
  747. package/dist/web/favicon-180.png +0 -0
  748. package/dist/web/favicon-32.png +0 -0
  749. package/dist/web/favicon-48.png +0 -0
  750. package/dist/web/favicon-512.png +0 -0
  751. package/dist/web/favicon.ico +0 -0
  752. package/dist/web/favicon.svg +8 -0
  753. package/dist/web/index.html +58 -19
  754. package/dist/web/studiograph-logomark.svg +29 -0
  755. package/package.json +38 -14
  756. package/dist/agent/skills/enrich-entities.md +0 -136
  757. package/dist/agent/skills/obsidian-source-setup.md +0 -246
  758. package/dist/agent/skills/skill-loader.d.ts +0 -48
  759. package/dist/agent/skills/skill-loader.js +0 -166
  760. package/dist/agent/skills/skill-loader.js.map +0 -1
  761. package/dist/agent/skills/sync-configuration.md +0 -119
  762. package/dist/agent/skills/sync-setup.md +0 -82
  763. package/dist/agent/tools/sync-tools.d.ts +0 -35
  764. package/dist/agent/tools/sync-tools.js +0 -992
  765. package/dist/agent/tools/sync-tools.js.map +0 -1
  766. package/dist/auth/github.d.ts +0 -56
  767. package/dist/auth/github.js +0 -169
  768. package/dist/auth/github.js.map +0 -1
  769. package/dist/cli/commands/access.d.ts +0 -11
  770. package/dist/cli/commands/access.js +0 -156
  771. package/dist/cli/commands/access.js.map +0 -1
  772. package/dist/cli/commands/app.d.ts +0 -7
  773. package/dist/cli/commands/app.js +0 -268
  774. package/dist/cli/commands/app.js.map +0 -1
  775. package/dist/cli/commands/auth.d.ts +0 -10
  776. package/dist/cli/commands/auth.js +0 -79
  777. package/dist/cli/commands/auth.js.map +0 -1
  778. package/dist/cli/commands/clear.d.ts +0 -5
  779. package/dist/cli/commands/clear.js +0 -36
  780. package/dist/cli/commands/clear.js.map +0 -1
  781. package/dist/cli/commands/collection.d.ts +0 -10
  782. package/dist/cli/commands/collection.js +0 -187
  783. package/dist/cli/commands/collection.js.map +0 -1
  784. package/dist/cli/commands/enrich.d.ts +0 -11
  785. package/dist/cli/commands/enrich.js +0 -135
  786. package/dist/cli/commands/enrich.js.map +0 -1
  787. package/dist/cli/commands/graphrag.d.ts +0 -12
  788. package/dist/cli/commands/graphrag.js +0 -122
  789. package/dist/cli/commands/graphrag.js.map +0 -1
  790. package/dist/cli/commands/join.d.ts +0 -9
  791. package/dist/cli/commands/join.js +0 -255
  792. package/dist/cli/commands/join.js.map +0 -1
  793. package/dist/cli/commands/members.d.ts +0 -11
  794. package/dist/cli/commands/members.js +0 -230
  795. package/dist/cli/commands/members.js.map +0 -1
  796. package/dist/cli/commands/org.d.ts +0 -10
  797. package/dist/cli/commands/org.js +0 -132
  798. package/dist/cli/commands/org.js.map +0 -1
  799. package/dist/cli/commands/provision.d.ts +0 -8
  800. package/dist/cli/commands/provision.js +0 -116
  801. package/dist/cli/commands/provision.js.map +0 -1
  802. package/dist/cli/commands/resolve.d.ts +0 -8
  803. package/dist/cli/commands/resolve.js +0 -85
  804. package/dist/cli/commands/resolve.js.map +0 -1
  805. package/dist/cli/commands/review.d.ts +0 -19
  806. package/dist/cli/commands/review.js +0 -128
  807. package/dist/cli/commands/review.js.map +0 -1
  808. package/dist/cli/commands/source.d.ts +0 -16
  809. package/dist/cli/commands/source.js +0 -159
  810. package/dist/cli/commands/source.js.map +0 -1
  811. package/dist/cli/commands/start.d.ts +0 -7
  812. package/dist/cli/commands/start.js +0 -589
  813. package/dist/cli/commands/start.js.map +0 -1
  814. package/dist/cli/commands/sync-collection.d.ts +0 -14
  815. package/dist/cli/commands/sync-collection.js +0 -355
  816. package/dist/cli/commands/sync-collection.js.map +0 -1
  817. package/dist/cli/commands/sync-entities.d.ts +0 -13
  818. package/dist/cli/commands/sync-entities.js +0 -242
  819. package/dist/cli/commands/sync-entities.js.map +0 -1
  820. package/dist/cli/commands/team.d.ts +0 -12
  821. package/dist/cli/commands/team.js +0 -185
  822. package/dist/cli/commands/team.js.map +0 -1
  823. package/dist/cli/commands/update.d.ts +0 -8
  824. package/dist/cli/commands/update.js +0 -155
  825. package/dist/cli/commands/update.js.map +0 -1
  826. package/dist/cli/commands/user.d.ts +0 -7
  827. package/dist/cli/commands/user.js +0 -153
  828. package/dist/cli/commands/user.js.map +0 -1
  829. package/dist/cli/scaffolding.d.ts +0 -12
  830. package/dist/cli/scaffolding.js +0 -397
  831. package/dist/cli/scaffolding.js.map +0 -1
  832. package/dist/cli/sync-review-interactive.d.ts +0 -31
  833. package/dist/cli/sync-review-interactive.js +0 -393
  834. package/dist/cli/sync-review-interactive.js.map +0 -1
  835. package/dist/core/migration-runner.d.ts +0 -42
  836. package/dist/core/migration-runner.js +0 -232
  837. package/dist/core/migration-runner.js.map +0 -1
  838. package/dist/core/migration-types.d.ts +0 -101
  839. package/dist/core/migration-types.js +0 -21
  840. package/dist/core/migration-types.js.map +0 -1
  841. package/dist/core/migrations/20260219-formalize-memory-location.d.ts +0 -2
  842. package/dist/core/migrations/20260219-formalize-memory-location.js +0 -35
  843. package/dist/core/migrations/20260219-formalize-memory-location.js.map +0 -1
  844. package/dist/core/migrations/20260220-add-workspace-metadata.d.ts +0 -12
  845. package/dist/core/migrations/20260220-add-workspace-metadata.js +0 -65
  846. package/dist/core/migrations/20260220-add-workspace-metadata.js.map +0 -1
  847. package/dist/core/migrations/20260220-add-workspace-readme.d.ts +0 -11
  848. package/dist/core/migrations/20260220-add-workspace-readme.js +0 -82
  849. package/dist/core/migrations/20260220-add-workspace-readme.js.map +0 -1
  850. package/dist/core/migrations/20260220-migrate-yaml-to-json.d.ts +0 -9
  851. package/dist/core/migrations/20260220-migrate-yaml-to-json.js +0 -64
  852. package/dist/core/migrations/20260220-migrate-yaml-to-json.js.map +0 -1
  853. package/dist/core/migrations/index.d.ts +0 -11
  854. package/dist/core/migrations/index.js +0 -23
  855. package/dist/core/migrations/index.js.map +0 -1
  856. package/dist/integrations/asana.d.ts +0 -26
  857. package/dist/integrations/asana.js +0 -78
  858. package/dist/integrations/asana.js.map +0 -1
  859. package/dist/integrations/figma-local.d.ts +0 -16
  860. package/dist/integrations/figma-local.js +0 -10
  861. package/dist/integrations/figma-local.js.map +0 -1
  862. package/dist/integrations/figma.d.ts +0 -17
  863. package/dist/integrations/figma.js +0 -17
  864. package/dist/integrations/figma.js.map +0 -1
  865. package/dist/integrations/granola.d.ts +0 -24
  866. package/dist/integrations/granola.js +0 -60
  867. package/dist/integrations/granola.js.map +0 -1
  868. package/dist/integrations/linear.d.ts +0 -14
  869. package/dist/integrations/linear.js +0 -80
  870. package/dist/integrations/linear.js.map +0 -1
  871. package/dist/integrations/paper-local.d.ts +0 -14
  872. package/dist/integrations/paper-local.js +0 -10
  873. package/dist/integrations/paper-local.js.map +0 -1
  874. package/dist/integrations/paper.d.ts +0 -2
  875. package/dist/integrations/paper.js +0 -10
  876. package/dist/integrations/paper.js.map +0 -1
  877. package/dist/integrations/pipedrive.d.ts +0 -26
  878. package/dist/integrations/pipedrive.js +0 -97
  879. package/dist/integrations/pipedrive.js.map +0 -1
  880. package/dist/integrations/registry.d.ts +0 -15
  881. package/dist/integrations/registry.js +0 -27
  882. package/dist/integrations/registry.js.map +0 -1
  883. package/dist/integrations/types.d.ts +0 -38
  884. package/dist/integrations/types.js +0 -9
  885. package/dist/integrations/types.js.map +0 -1
  886. package/dist/lib/lib/utils.d.ts +0 -2
  887. package/dist/lib/lib/utils.js +0 -6
  888. package/dist/lib/lib/utils.js.map +0 -1
  889. package/dist/mcp/connectors/asana.d.ts +0 -2
  890. package/dist/mcp/connectors/asana.js +0 -20
  891. package/dist/mcp/connectors/asana.js.map +0 -1
  892. package/dist/mcp/connectors/definitions.d.ts +0 -45
  893. package/dist/mcp/connectors/definitions.js +0 -32
  894. package/dist/mcp/connectors/definitions.js.map +0 -1
  895. package/dist/mcp/connectors/figma.d.ts +0 -5
  896. package/dist/mcp/connectors/figma.js +0 -21
  897. package/dist/mcp/connectors/figma.js.map +0 -1
  898. package/dist/mcp/connectors/gdrive.d.ts +0 -2
  899. package/dist/mcp/connectors/gdrive.js +0 -20
  900. package/dist/mcp/connectors/gdrive.js.map +0 -1
  901. package/dist/mcp/connectors/granola.d.ts +0 -2
  902. package/dist/mcp/connectors/granola.js +0 -12
  903. package/dist/mcp/connectors/granola.js.map +0 -1
  904. package/dist/mcp/connectors/linear.d.ts +0 -2
  905. package/dist/mcp/connectors/linear.js +0 -19
  906. package/dist/mcp/connectors/linear.js.map +0 -1
  907. package/dist/mcp/connectors/obsidian.d.ts +0 -2
  908. package/dist/mcp/connectors/obsidian.js +0 -19
  909. package/dist/mcp/connectors/obsidian.js.map +0 -1
  910. package/dist/mcp/connectors/pipedrive.d.ts +0 -2
  911. package/dist/mcp/connectors/pipedrive.js +0 -20
  912. package/dist/mcp/connectors/pipedrive.js.map +0 -1
  913. package/dist/mcp/connectors/slack.d.ts +0 -2
  914. package/dist/mcp/connectors/slack.js +0 -21
  915. package/dist/mcp/connectors/slack.js.map +0 -1
  916. package/dist/mcp/server-oauth-provider.d.ts +0 -56
  917. package/dist/mcp/server-oauth-provider.js +0 -142
  918. package/dist/mcp/server-oauth-provider.js.map +0 -1
  919. package/dist/server/chrome/chrome.css +0 -691
  920. package/dist/server/chrome/chrome.js +0 -374
  921. package/dist/server/collab-authority.d.ts +0 -70
  922. package/dist/server/collab-authority.js +0 -218
  923. package/dist/server/collab-authority.js.map +0 -1
  924. package/dist/server/collab.d.ts +0 -29
  925. package/dist/server/collab.js +0 -195
  926. package/dist/server/collab.js.map +0 -1
  927. package/dist/server/commit-scheduler.d.ts +0 -39
  928. package/dist/server/commit-scheduler.js +0 -113
  929. package/dist/server/commit-scheduler.js.map +0 -1
  930. package/dist/server/plugin-loader.d.ts +0 -53
  931. package/dist/server/plugin-loader.js +0 -155
  932. package/dist/server/plugin-loader.js.map +0 -1
  933. package/dist/server/routes/collab.d.ts +0 -6
  934. package/dist/server/routes/collab.js +0 -10
  935. package/dist/server/routes/collab.js.map +0 -1
  936. package/dist/server/routes/git-api.d.ts +0 -9
  937. package/dist/server/routes/git-api.js +0 -82
  938. package/dist/server/routes/git-api.js.map +0 -1
  939. package/dist/server/routes/meeting-ingest-api.d.ts +0 -15
  940. package/dist/server/routes/meeting-ingest-api.js +0 -323
  941. package/dist/server/routes/meeting-ingest-api.js.map +0 -1
  942. package/dist/server/routes/sync-api.d.ts +0 -26
  943. package/dist/server/routes/sync-api.js +0 -814
  944. package/dist/server/routes/sync-api.js.map +0 -1
  945. package/dist/server/routes/webhook.d.ts +0 -14
  946. package/dist/server/routes/webhook.js +0 -102
  947. package/dist/server/routes/webhook.js.map +0 -1
  948. package/dist/services/github-provisioner.d.ts +0 -36
  949. package/dist/services/github-provisioner.js +0 -126
  950. package/dist/services/github-provisioner.js.map +0 -1
  951. package/dist/services/github-service.d.ts +0 -99
  952. package/dist/services/github-service.js +0 -310
  953. package/dist/services/github-service.js.map +0 -1
  954. package/dist/services/insights.d.ts +0 -38
  955. package/dist/services/insights.js +0 -246
  956. package/dist/services/insights.js.map +0 -1
  957. package/dist/services/sync/collection-sync.d.ts +0 -60
  958. package/dist/services/sync/collection-sync.js +0 -509
  959. package/dist/services/sync/collection-sync.js.map +0 -1
  960. package/dist/services/sync/commit.d.ts +0 -60
  961. package/dist/services/sync/commit.js +0 -354
  962. package/dist/services/sync/commit.js.map +0 -1
  963. package/dist/services/sync/context-index.d.ts +0 -69
  964. package/dist/services/sync/context-index.js +0 -280
  965. package/dist/services/sync/context-index.js.map +0 -1
  966. package/dist/services/sync/data-fetcher.d.ts +0 -31
  967. package/dist/services/sync/data-fetcher.js +0 -12
  968. package/dist/services/sync/data-fetcher.js.map +0 -1
  969. package/dist/services/sync/derive.d.ts +0 -34
  970. package/dist/services/sync/derive.js +0 -164
  971. package/dist/services/sync/derive.js.map +0 -1
  972. package/dist/services/sync/enrichment-state.d.ts +0 -31
  973. package/dist/services/sync/enrichment-state.js +0 -63
  974. package/dist/services/sync/enrichment-state.js.map +0 -1
  975. package/dist/services/sync/enrichment.d.ts +0 -25
  976. package/dist/services/sync/enrichment.js +0 -121
  977. package/dist/services/sync/enrichment.js.map +0 -1
  978. package/dist/services/sync/entity-refresh.d.ts +0 -30
  979. package/dist/services/sync/entity-refresh.js +0 -275
  980. package/dist/services/sync/entity-refresh.js.map +0 -1
  981. package/dist/services/sync/frontmatter-extractor.d.ts +0 -40
  982. package/dist/services/sync/frontmatter-extractor.js +0 -279
  983. package/dist/services/sync/frontmatter-extractor.js.map +0 -1
  984. package/dist/services/sync/graph-match-state.d.ts +0 -33
  985. package/dist/services/sync/graph-match-state.js +0 -61
  986. package/dist/services/sync/graph-match-state.js.map +0 -1
  987. package/dist/services/sync/graph-match.d.ts +0 -53
  988. package/dist/services/sync/graph-match.js +0 -316
  989. package/dist/services/sync/graph-match.js.map +0 -1
  990. package/dist/services/sync/graphrag-client.d.ts +0 -43
  991. package/dist/services/sync/graphrag-client.js +0 -94
  992. package/dist/services/sync/graphrag-client.js.map +0 -1
  993. package/dist/services/sync/graphrag-config.d.ts +0 -16
  994. package/dist/services/sync/graphrag-config.js +0 -39
  995. package/dist/services/sync/graphrag-config.js.map +0 -1
  996. package/dist/services/sync/graphrag-context.d.ts +0 -14
  997. package/dist/services/sync/graphrag-context.js +0 -109
  998. package/dist/services/sync/graphrag-context.js.map +0 -1
  999. package/dist/services/sync/graphrag-indexer.d.ts +0 -30
  1000. package/dist/services/sync/graphrag-indexer.js +0 -358
  1001. package/dist/services/sync/graphrag-indexer.js.map +0 -1
  1002. package/dist/services/sync/llm.d.ts +0 -32
  1003. package/dist/services/sync/llm.js +0 -115
  1004. package/dist/services/sync/llm.js.map +0 -1
  1005. package/dist/services/sync/mcp-client.d.ts +0 -71
  1006. package/dist/services/sync/mcp-client.js +0 -299
  1007. package/dist/services/sync/mcp-client.js.map +0 -1
  1008. package/dist/services/sync/model-factory.d.ts +0 -13
  1009. package/dist/services/sync/model-factory.js +0 -38
  1010. package/dist/services/sync/model-factory.js.map +0 -1
  1011. package/dist/services/sync/name-quality.d.ts +0 -31
  1012. package/dist/services/sync/name-quality.js +0 -60
  1013. package/dist/services/sync/name-quality.js.map +0 -1
  1014. package/dist/services/sync/output-schemas.d.ts +0 -92
  1015. package/dist/services/sync/output-schemas.js +0 -43
  1016. package/dist/services/sync/output-schemas.js.map +0 -1
  1017. package/dist/services/sync/prompts.d.ts +0 -19
  1018. package/dist/services/sync/prompts.js +0 -128
  1019. package/dist/services/sync/prompts.js.map +0 -1
  1020. package/dist/services/sync/reconciler.d.ts +0 -48
  1021. package/dist/services/sync/reconciler.js +0 -294
  1022. package/dist/services/sync/reconciler.js.map +0 -1
  1023. package/dist/services/sync/rest-client.d.ts +0 -40
  1024. package/dist/services/sync/rest-client.js +0 -100
  1025. package/dist/services/sync/rest-client.js.map +0 -1
  1026. package/dist/services/sync/source-config.d.ts +0 -67
  1027. package/dist/services/sync/source-config.js +0 -304
  1028. package/dist/services/sync/source-config.js.map +0 -1
  1029. package/dist/services/sync/source-definitions/asana.d.ts +0 -14
  1030. package/dist/services/sync/source-definitions/asana.js +0 -42
  1031. package/dist/services/sync/source-definitions/asana.js.map +0 -1
  1032. package/dist/services/sync/source-definitions/definitions.d.ts +0 -8
  1033. package/dist/services/sync/source-definitions/definitions.js +0 -8
  1034. package/dist/services/sync/source-definitions/definitions.js.map +0 -1
  1035. package/dist/services/sync/source-definitions/gdrive.d.ts +0 -16
  1036. package/dist/services/sync/source-definitions/gdrive.js +0 -68
  1037. package/dist/services/sync/source-definitions/gdrive.js.map +0 -1
  1038. package/dist/services/sync/source-definitions/granola.d.ts +0 -2
  1039. package/dist/services/sync/source-definitions/granola.js +0 -21
  1040. package/dist/services/sync/source-definitions/granola.js.map +0 -1
  1041. package/dist/services/sync/source-definitions/linear.d.ts +0 -2
  1042. package/dist/services/sync/source-definitions/linear.js +0 -62
  1043. package/dist/services/sync/source-definitions/linear.js.map +0 -1
  1044. package/dist/services/sync/source-definitions/obsidian.d.ts +0 -2
  1045. package/dist/services/sync/source-definitions/obsidian.js +0 -55
  1046. package/dist/services/sync/source-definitions/obsidian.js.map +0 -1
  1047. package/dist/services/sync/source-definitions/pipedrive.d.ts +0 -2
  1048. package/dist/services/sync/source-definitions/pipedrive.js +0 -43
  1049. package/dist/services/sync/source-definitions/pipedrive.js.map +0 -1
  1050. package/dist/services/sync/staging.d.ts +0 -53
  1051. package/dist/services/sync/staging.js +0 -130
  1052. package/dist/services/sync/staging.js.map +0 -1
  1053. package/dist/services/sync/structured-extractor.d.ts +0 -57
  1054. package/dist/services/sync/structured-extractor.js +0 -584
  1055. package/dist/services/sync/structured-extractor.js.map +0 -1
  1056. package/dist/services/sync/sync-runner.d.ts +0 -32
  1057. package/dist/services/sync/sync-runner.js +0 -195
  1058. package/dist/services/sync/sync-runner.js.map +0 -1
  1059. package/dist/services/sync/sync-state.d.ts +0 -43
  1060. package/dist/services/sync/sync-state.js +0 -154
  1061. package/dist/services/sync/sync-state.js.map +0 -1
  1062. package/dist/services/sync/types.d.ts +0 -381
  1063. package/dist/services/sync/types.js +0 -8
  1064. package/dist/services/sync/types.js.map +0 -1
  1065. package/dist/services/sync/unstructured-extractor.d.ts +0 -27
  1066. package/dist/services/sync/unstructured-extractor.js +0 -185
  1067. package/dist/services/sync/unstructured-extractor.js.map +0 -1
  1068. package/dist/utils/merge-resolver.d.ts +0 -59
  1069. package/dist/utils/merge-resolver.js +0 -303
  1070. package/dist/utils/merge-resolver.js.map +0 -1
  1071. package/dist/utils/workspace-config.d.ts +0 -8
  1072. package/dist/utils/workspace-config.js +0 -22
  1073. package/dist/utils/workspace-config.js.map +0 -1
  1074. package/dist/web/_app/immutable/assets/0.DdizXOKi.css +0 -1
  1075. package/dist/web/_app/immutable/assets/10.BUrHkYry.css +0 -1
  1076. package/dist/web/_app/immutable/assets/2.n7-yW_Fs.css +0 -1
  1077. package/dist/web/_app/immutable/assets/3.BtaZagnv.css +0 -1
  1078. package/dist/web/_app/immutable/assets/4.DT7X0x5S.css +0 -1
  1079. package/dist/web/_app/immutable/assets/5.DFeGxLYf.css +0 -1
  1080. package/dist/web/_app/immutable/assets/6.CquhUpOu.css +0 -1
  1081. package/dist/web/_app/immutable/assets/7.CjbDRbuG.css +0 -1
  1082. package/dist/web/_app/immutable/assets/8.S1QdUGNM.css +0 -1
  1083. package/dist/web/_app/immutable/assets/9.CT4xL4K3.css +0 -1
  1084. package/dist/web/_app/immutable/assets/Copy.FS8bdfxr.css +0 -1
  1085. package/dist/web/_app/immutable/assets/Toaster.rN8r_Hzv.css +0 -1
  1086. package/dist/web/_app/immutable/assets/ViewToolbar.D-QW2oKe.css +0 -1
  1087. package/dist/web/_app/immutable/assets/index.D6tMDJWk.css +0 -1
  1088. package/dist/web/_app/immutable/chunks/-iaeBIWN.js +0 -1
  1089. package/dist/web/_app/immutable/chunks/37NdyH6G.js +0 -32
  1090. package/dist/web/_app/immutable/chunks/4Hhzb6pv.js +0 -1
  1091. package/dist/web/_app/immutable/chunks/72bZS3G9.js +0 -1
  1092. package/dist/web/_app/immutable/chunks/7S2LGqoP.js +0 -2
  1093. package/dist/web/_app/immutable/chunks/B340SUKR.js +0 -1
  1094. package/dist/web/_app/immutable/chunks/B3Z4_Sps.js +0 -1
  1095. package/dist/web/_app/immutable/chunks/BB_5th5W.js +0 -3383
  1096. package/dist/web/_app/immutable/chunks/BPWYOQXG.js +0 -1
  1097. package/dist/web/_app/immutable/chunks/BR77jbfR.js +0 -1
  1098. package/dist/web/_app/immutable/chunks/BS2rFAVq.js +0 -1
  1099. package/dist/web/_app/immutable/chunks/BSsDC_p4.js +0 -1
  1100. package/dist/web/_app/immutable/chunks/BTX2Jr8_.js +0 -1
  1101. package/dist/web/_app/immutable/chunks/Bq_KShUL.js +0 -4
  1102. package/dist/web/_app/immutable/chunks/Bsacq2UX.js +0 -1
  1103. package/dist/web/_app/immutable/chunks/ByunV8un.js +0 -1
  1104. package/dist/web/_app/immutable/chunks/BzPu-Eht.js +0 -1
  1105. package/dist/web/_app/immutable/chunks/C7VoTosa.js +0 -2
  1106. package/dist/web/_app/immutable/chunks/CDV5Q7RN.js +0 -1
  1107. package/dist/web/_app/immutable/chunks/CGc1sIb_.js +0 -1
  1108. package/dist/web/_app/immutable/chunks/CJ8__CWt.js +0 -1
  1109. package/dist/web/_app/immutable/chunks/CJUKmosC.js +0 -5
  1110. package/dist/web/_app/immutable/chunks/CSVbGg_b.js +0 -5
  1111. package/dist/web/_app/immutable/chunks/CT6oIU-C.js +0 -1
  1112. package/dist/web/_app/immutable/chunks/CTRxNfZk.js +0 -1
  1113. package/dist/web/_app/immutable/chunks/CWQRQXxy.js +0 -1
  1114. package/dist/web/_app/immutable/chunks/CX87mIM8.js +0 -1
  1115. package/dist/web/_app/immutable/chunks/CXH6iFbA.js +0 -1
  1116. package/dist/web/_app/immutable/chunks/CX_61fY8.js +0 -5
  1117. package/dist/web/_app/immutable/chunks/CYrVHOHA.js +0 -1
  1118. package/dist/web/_app/immutable/chunks/CdeYcEuU.js +0 -1
  1119. package/dist/web/_app/immutable/chunks/CmCtpZ1Y.js +0 -1
  1120. package/dist/web/_app/immutable/chunks/Cpsr8-Xy.js +0 -1
  1121. package/dist/web/_app/immutable/chunks/CqkleIqs.js +0 -1
  1122. package/dist/web/_app/immutable/chunks/CrdV0ttd.js +0 -1
  1123. package/dist/web/_app/immutable/chunks/CscoF-YL.js +0 -18
  1124. package/dist/web/_app/immutable/chunks/Cx4YdFMk.js +0 -1
  1125. package/dist/web/_app/immutable/chunks/D7ZqAKi9.js +0 -3
  1126. package/dist/web/_app/immutable/chunks/DGbA7IXh.js +0 -2
  1127. package/dist/web/_app/immutable/chunks/DTZE-yoq.js +0 -2
  1128. package/dist/web/_app/immutable/chunks/DbbB6Up5.js +0 -1
  1129. package/dist/web/_app/immutable/chunks/DnL9f0lc.js +0 -7
  1130. package/dist/web/_app/immutable/chunks/DtM5cEDu.js +0 -1
  1131. package/dist/web/_app/immutable/chunks/Eqahi7_S.js +0 -2
  1132. package/dist/web/_app/immutable/chunks/O9Eb9k00.js +0 -1
  1133. package/dist/web/_app/immutable/chunks/PPVm8Dsz.js +0 -1
  1134. package/dist/web/_app/immutable/chunks/QF8MAmnc.js +0 -1
  1135. package/dist/web/_app/immutable/chunks/UjzxCpxn.js +0 -1
  1136. package/dist/web/_app/immutable/chunks/WSUKABI_.js +0 -1
  1137. package/dist/web/_app/immutable/chunks/Y90OgS-9.js +0 -1
  1138. package/dist/web/_app/immutable/chunks/cLyZlkXv.js +0 -1
  1139. package/dist/web/_app/immutable/chunks/iDtAARVW.js +0 -2
  1140. package/dist/web/_app/immutable/chunks/oC_W7W7p.js +0 -1
  1141. package/dist/web/_app/immutable/chunks/rJdWIgh-.js +0 -1
  1142. package/dist/web/_app/immutable/chunks/tvOsokaa.js +0 -1
  1143. package/dist/web/_app/immutable/chunks/uLEXaPwE.js +0 -1
  1144. package/dist/web/_app/immutable/chunks/vSaooFHB.js +0 -1
  1145. package/dist/web/_app/immutable/entry/app.BeUKh4sD.js +0 -2
  1146. package/dist/web/_app/immutable/entry/start.CZJnFuQn.js +0 -1
  1147. package/dist/web/_app/immutable/nodes/0.DyF_RsLg.js +0 -2
  1148. package/dist/web/_app/immutable/nodes/1.7iDQmMPh.js +0 -1
  1149. package/dist/web/_app/immutable/nodes/10.Btl8d8HT.js +0 -1
  1150. package/dist/web/_app/immutable/nodes/2.LDRE62jN.js +0 -168
  1151. package/dist/web/_app/immutable/nodes/3.BaW1XB1x.js +0 -1
  1152. package/dist/web/_app/immutable/nodes/4.D0Q8kpkI.js +0 -12
  1153. package/dist/web/_app/immutable/nodes/5.n7j2UG9h.js +0 -4
  1154. package/dist/web/_app/immutable/nodes/6.DQYxR0iy.js +0 -2
  1155. package/dist/web/_app/immutable/nodes/7.BsURvFAp.js +0 -2
  1156. package/dist/web/_app/immutable/nodes/8.CsiErG0p.js +0 -1
  1157. package/dist/web/_app/immutable/nodes/9.CnN6OZgC.js +0 -1
@@ -7,11 +7,18 @@
7
7
  * - Manage wikilinks
8
8
  * - Upload assets
9
9
  */
10
- import { Type as T } from '@sinclair/typebox';
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 { SyncStateManager } from '../../services/sync/sync-state.js';
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, assertEntityRefs, EntityRefError, UnknownUserRefError, } 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,228 @@ function cleanData(data) {
31
38
  return rest;
32
39
  }
33
40
  /**
34
- * Per-request user context for collection access filtering.
35
- * When getCurrentUser returns a non-admin user, tools filter results
36
- * to only collections the user has been granted access to.
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
- /** Check if a user can see a private repo (only the owner can). */
39
- function canSeePrivateRepo(repoConfig, user) {
40
- if (!repoConfig?.private)
41
- return true;
42
- if (!user)
43
- return !repoConfig.owner_id; // API key / open mode — only if no owner set
44
- if (!repoConfig.owner_id)
45
- return false; // Private without owner — hidden from all users
46
- return user.id === repoConfig.owner_id;
47
- }
48
- /** Check if the current user is an admin. Returns an error result if not. */
49
- function adminOnly(getUser) {
50
- const user = getUser();
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
- const allRepos = workspaceManager.getAllRepoConfigs();
64
- if (user.role === 'admin') {
65
- // Admins see all non-private + their own private repos
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 authService.getUserCollections(user.id).includes(repoName);
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
+ const hint = isCuratedEntityType(entityType)
154
+ ? '' // shouldn't happen for any other curated type — they're all allowed
155
+ : ` Allowed types: ${agentAllowedTypes.join(', ')}.`;
156
+ return wrapToolResult({
157
+ success: false,
158
+ error: `Entry type "${entityType}" is not a known canonical or workspace custom type.${hint}`,
159
+ });
160
+ }
94
161
  return [
95
162
  // Create entity
96
163
  {
97
164
  name: 'create_entity',
98
- label: 'Create Entity',
99
- description: 'Create a new entity in a collection. Always validate required fields before calling. Collection is auto-resolved for app-defined entity types.',
165
+ label: 'Create Entry',
166
+ description: 'Create a new entry in a folder. Always validate required fields before calling. Folder is auto-resolved for app-defined entry types.',
100
167
  parameters: T.Object({
101
- repo: T.Optional(T.String({ description: 'Collection name (auto-resolved for app entity types)' })),
102
- entityType: T.String({ description: 'Entity type (project, client, decision, etc.)' }),
168
+ repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
169
+ entityType: T.Union(agentAllowedTypes.map(t => T.Literal(t)), { description: `Entity type. Must be one of: ${agentAllowedTypes.join(', ')}.` }),
103
170
  entityId: T.String({ description: 'Unique entity ID in kebab-case' }),
104
171
  data: T.Object({}, { description: 'Entity data (YAML frontmatter)', additionalProperties: true }),
105
172
  content: T.Optional(T.String({ description: 'Markdown content (optional)' })),
173
+ 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
174
  commitMessage: T.Optional(T.String({ description: 'Custom commit message (optional)' })),
107
175
  }),
108
176
  execute: async (toolCallId, params) => {
109
177
  try {
178
+ // Defense in depth: LLMs occasionally pass strings that don't match the
179
+ // enum schema. Runtime check ensures the launch allowlist is enforced
180
+ // even if the schema layer is bypassed.
181
+ const typeRejection = rejectDisallowedCreateType(params.entityType);
182
+ if (typeRejection)
183
+ return typeRejection;
110
184
  let repoName = params.repo;
111
185
  if (!repoName) {
112
- repoName = workspaceManager.getAppForEntityType(params.entityType);
113
- if (!repoName)
114
- return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
186
+ return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
115
187
  }
188
+ repoName = resolvePrivateRepo(repoName);
116
189
  if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
117
- return wrapToolResult({ success: false, error: `Collection "${repoName}" not found` });
190
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
118
191
  }
192
+ const eagerError = checkEagerSkillPermission(params.entityType, params.data, repoName);
193
+ if (eagerError)
194
+ return wrapToolResult({ success: false, error: eagerError });
119
195
  const graph = workspaceManager.getGraph(repoName);
120
196
  // Workspace-level dedup: warn if an entity with this ID already exists elsewhere
121
197
  const existing = workspaceManager.findEntityById(params.entityId);
122
198
  if (existing && existing.repoName !== repoName) {
123
- return wrapToolResult({ success: false, error: `An entity with ID "${params.entityId}" already exists in the "${existing.repoName}" collection (type: ${existing.data?.entity_type}). Use a unique ID or link to the existing entity with [[${params.entityId}]].` });
199
+ 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
200
  }
125
- // Add timestamps and user info
126
- const now = new Date().toISOString();
127
- const dataWithMeta = {
128
- ...params.data,
129
- entity_id: params.entityId,
130
- created_at: now,
131
- updated_at: now,
132
- created_by: gitUser.id,
133
- updated_by: gitUser.id,
134
- };
135
- // Sanitize double-escaped newlines from LLM JSON output
136
- const sanitizedContent = (params.content || '').replace(/\\n/g, '\n');
137
- const entity = await graph.create({
201
+ const actor = effectiveGitUser();
202
+ const sanitizedContent = sanitizeLlmContent(params.content);
203
+ // Workspace-wide uniqueness check for `user_handle` on person
204
+ // entities (one user ↔ one person, workspace-wide), plus owner-
205
+ // only authz so a non-owner agent session can't stamp a
206
+ // pre-linked person via generic create_entity.
207
+ if (params.entityType === 'person') {
208
+ try {
209
+ const incoming = params.data ?? {};
210
+ validateUserHandleInPayload(workspaceManager, incoming);
211
+ if (Object.prototype.hasOwnProperty.call(incoming, 'user_handle')) {
212
+ assertCanChangeUserHandle(getUser(), '', incoming.user_handle);
213
+ }
214
+ }
215
+ catch (err) {
216
+ if (err instanceof BridgeError) {
217
+ return wrapToolResult({ success: false, error: err.message, code: err.code, ...err.details });
218
+ }
219
+ throw err;
220
+ }
221
+ }
222
+ // Scope ref fields (today: task.assignee → person). Reject a wikilink
223
+ // that resolves to a non-person; forward references are allowed.
224
+ try {
225
+ assertEntityRefs(workspaceManager, params.entityType, params.data ?? {}, authSvc ? { userExists: (id) => !!authSvc.findUserById(Number(id)) } : undefined);
226
+ }
227
+ catch (err) {
228
+ if (err instanceof EntityRefError || err instanceof UnknownUserRefError) {
229
+ return wrapToolResult({ success: false, error: err.message, code: err.code, field: err.field });
230
+ }
231
+ throw err;
232
+ }
233
+ const options = prepareCreatePayload({
138
234
  entityType: params.entityType,
139
235
  entityId: params.entityId,
140
- data: dataWithMeta,
236
+ data: params.data ?? {},
141
237
  content: sanitizedContent,
238
+ folderPath: params.folder_path,
142
239
  commitMessage: params.commitMessage,
143
- });
144
- onMutation?.({ action: 'created', repo: repoName, entityType: params.entityType, entityId: params.entityId });
145
- return wrapToolResult({
146
- success: true,
147
- entity: {
148
- entityId: entity.id,
149
- entityType: entity.entityType,
150
- repo: repoName,
151
- path: entity.path,
152
- data: cleanData(entity.data),
153
- },
154
- message: `Created ${params.entityType}: ${params.entityId} in ${repoName}. Auto-committed — ready to push.`,
155
- });
240
+ }, actor);
241
+ // Surface a live "<user>'s agent is acting" chip in the sidebar for
242
+ // the duration of the mutation. `leave` is always emitted via the
243
+ // inner finally so a thrown error doesn't leave the chip stuck.
244
+ onAgentActivity?.('enter', repoName);
245
+ try {
246
+ const entity = await graph.create(options);
247
+ onMutation?.({ action: 'created', repo: repoName, entityType: params.entityType, entityId: params.entityId });
248
+ return wrapToolResult({
249
+ success: true,
250
+ entity: {
251
+ entityId: entity.id,
252
+ entityType: entity.entityType,
253
+ repo: repoName,
254
+ path: entity.path,
255
+ data: cleanData(entity.data),
256
+ },
257
+ message: `Created ${params.entityType}: ${params.entityId} in ${repoName}. Auto-committed — ready to push.`,
258
+ });
259
+ }
260
+ finally {
261
+ onAgentActivity?.('leave', repoName);
262
+ }
156
263
  }
157
264
  catch (error) {
158
265
  return wrapToolResult({
@@ -165,31 +272,51 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
165
272
  // Get entity
166
273
  {
167
274
  name: 'get_entity',
168
- label: 'Get Entity',
169
- description: 'Retrieve full entity details. Use repo, entityType, entityId from search/list results. entityType is optional — if omitted it is read from the file.',
275
+ label: 'Get Entry',
276
+ 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
277
  parameters: T.Object({
171
- repo: T.String({ description: 'Collection name' }),
278
+ repo: T.String({ description: 'Folder name' }),
172
279
  entityType: T.Optional(T.String({ description: 'Entity type (optional — resolved from frontmatter if omitted)' })),
173
280
  entityId: T.String({ description: 'Entity ID' }),
174
281
  }),
175
282
  execute: async (toolCallId, params) => {
176
283
  try {
177
- if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
178
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
284
+ const repo = resolvePrivateRepo(params.repo);
285
+ if (!canAccessRepo(repo, workspaceManager, getUser, authSvc)) {
286
+ return wrapToolResult({ success: false, error: `Folder "${repo}" not found` });
179
287
  }
180
- const graph = workspaceManager.getGraph(params.repo);
181
- const entity = params.entityType
182
- ? graph.get(params.entityType, params.entityId)
183
- : graph.getById(params.entityId);
288
+ const graph = workspaceManager.getGraph(repo);
289
+ // If the agent passes the wrong entityType (e.g. based on stale
290
+ // search results), graph.get computes the wrong filesystem path
291
+ // and throws. Fall back to getById, which scans all type subdirs
292
+ // under the folder and resolves the actual location.
293
+ let entity;
294
+ if (params.entityType) {
295
+ try {
296
+ entity = graph.get(params.entityType, params.entityId);
297
+ }
298
+ catch {
299
+ entity = graph.getById(params.entityId);
300
+ }
301
+ }
302
+ else {
303
+ entity = graph.getById(params.entityId);
304
+ }
305
+ // Prefer the live editor body when a seeded Y.Doc is open. graph.get
306
+ // reads disk, which lags the editor by the autosave debounce — a
307
+ // user's freshly-placed image embed lives in the Y.Doc before it's
308
+ // committed. Returning disk content is what let the agent edit then
309
+ // resend a body missing those embeds, silently dropping images.
310
+ const liveBody = graph.getLiveBody(entity.entityType, entity.id);
184
311
  return wrapToolResult({
185
312
  success: true,
186
313
  entity: {
187
314
  entityId: entity.id,
188
315
  entityType: entity.entityType,
189
- repo: params.repo,
316
+ repo,
190
317
  path: entity.path,
191
318
  data: cleanData(entity.data),
192
- content: entity.document.content,
319
+ content: liveBody ?? entity.document.content,
193
320
  wikilinks: entity.document.wikilinks,
194
321
  },
195
322
  });
@@ -205,59 +332,116 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
205
332
  // Update entity
206
333
  {
207
334
  name: 'update_entity',
208
- label: 'Update Entity',
209
- description: 'Update an existing entity. Collection is auto-resolved for app-defined types.',
335
+ label: 'Update Entry',
336
+ description: 'Update an existing entry. Folder is auto-resolved for app-defined types.',
210
337
  parameters: T.Object({
211
- repo: T.Optional(T.String({ description: 'Collection name (auto-resolved for app entity types)' })),
338
+ repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
212
339
  entityType: T.String({ description: 'Entity type' }),
213
340
  entityId: T.String({ description: 'Entity ID' }),
214
341
  data: T.Optional(T.Object({}, { description: 'Updated data fields', additionalProperties: true })),
215
- content: T.Optional(T.String({ description: 'Updated markdown content' })),
342
+ content: T.Optional(T.String({ description: 'Updated markdown body (replaces the entire body)' })),
216
343
  commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
344
+ 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
345
  }),
218
346
  execute: async (toolCallId, params) => {
219
347
  try {
220
348
  let repoName = params.repo;
221
349
  if (!repoName) {
222
- repoName = workspaceManager.getAppForEntityType(params.entityType);
223
- if (!repoName)
224
- return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
350
+ return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
225
351
  }
352
+ repoName = resolvePrivateRepo(repoName);
226
353
  if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
227
- return wrapToolResult({ success: false, error: `Collection "${repoName}" not found` });
354
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
228
355
  }
356
+ const eagerError = checkEagerSkillPermission(params.entityType, params.data, repoName);
357
+ if (eagerError)
358
+ return wrapToolResult({ success: false, error: eagerError });
229
359
  const graph = workspaceManager.getGraph(repoName);
230
- // Add update metadata
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
360
+ const actor = effectiveGitUser();
239
361
  const sanitizedContent = params.content !== undefined
240
- ? params.content.replace(/\\n/g, '\n') : params.content;
241
- const entity = await graph.update({
362
+ ? sanitizeLlmContent(params.content)
363
+ : params.content;
364
+ // Workspace-wide uniqueness check + owner-only authz for
365
+ // `user_handle` on person entities. Generic update_entity must
366
+ // not be a back door around the ownerOnly() gate on the dedicated
367
+ // link/unlink tools — otherwise a member could ask the agent to
368
+ // "set this person's user_handle to mine" and bypass the gate.
369
+ if (params.entityType === 'person' && params.data) {
370
+ try {
371
+ validateUserHandleInPayload(workspaceManager, params.data, { repo: repoName, entityId: params.entityId });
372
+ if (Object.prototype.hasOwnProperty.call(params.data, 'user_handle')) {
373
+ let currentHandle = '';
374
+ try {
375
+ const current = graph.get('person', params.entityId);
376
+ currentHandle = (current?.data?.user_handle ?? '');
377
+ }
378
+ catch { /* new entity / missing — treat as empty */ }
379
+ assertCanChangeUserHandle(getUser(), currentHandle, params.data.user_handle);
380
+ }
381
+ }
382
+ catch (err) {
383
+ if (err instanceof BridgeError) {
384
+ return wrapToolResult({ success: false, error: err.message, code: err.code, ...err.details });
385
+ }
386
+ throw err;
387
+ }
388
+ }
389
+ // Scope ref fields (today: task.assignee → person). Reject a wikilink
390
+ // that resolves to a non-person; forward references are allowed.
391
+ try {
392
+ assertEntityRefs(workspaceManager, params.entityType, params.data, authSvc ? { userExists: (id) => !!authSvc.findUserById(Number(id)) } : undefined);
393
+ }
394
+ catch (err) {
395
+ if (err instanceof EntityRefError || err instanceof UnknownUserRefError) {
396
+ return wrapToolResult({ success: false, error: err.message, code: err.code, field: err.field });
397
+ }
398
+ throw err;
399
+ }
400
+ const options = prepareUpdatePayload({
242
401
  entityType: params.entityType,
243
402
  entityId: params.entityId,
244
- data: dataWithMeta,
403
+ data: params.data,
245
404
  content: sanitizedContent,
246
405
  commitMessage: params.commitMessage,
247
- });
248
- onMutation?.({ action: 'updated', repo: repoName, entityType: params.entityType, entityId: params.entityId });
249
- return wrapToolResult({
250
- success: true,
251
- entity: {
252
- entityId: entity.id,
253
- entityType: entity.entityType,
254
- repo: repoName,
255
- data: cleanData(entity.data),
256
- },
257
- message: `Updated ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
258
- });
406
+ }, actor);
407
+ onAgentActivity?.('enter', repoName);
408
+ try {
409
+ // Shared diagnosed update (c6ef9297 contract): throws
410
+ // SilentDropError when the caller intended a change that left the
411
+ // file byte-identical, surfaced via the outer catch so the agent
412
+ // isn't misled by a success envelope.
413
+ const { entity, frontmatter_changed, content_changed, noop, broadcast } = await diagnosedUpdate(graph, options, { data: params.data, content: sanitizedContent }, { allowAssetRemoval: params.allowImageRemoval });
414
+ onMutation?.({ action: 'updated', repo: repoName, entityType: params.entityType, entityId: params.entityId });
415
+ return wrapToolResult({
416
+ success: true,
417
+ entity: {
418
+ entityId: entity.id,
419
+ entityType: entity.entityType,
420
+ repo: repoName,
421
+ data: cleanData(entity.data),
422
+ },
423
+ frontmatter_changed,
424
+ content_changed,
425
+ noop,
426
+ broadcast,
427
+ message: noop
428
+ ? `No change to ${params.entityType}: ${params.entityId} — on-disk state already matched.`
429
+ : `Updated ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
430
+ });
431
+ }
432
+ finally {
433
+ onAgentActivity?.('leave', repoName);
434
+ }
259
435
  }
260
436
  catch (error) {
437
+ if (error instanceof DroppedAssetError) {
438
+ return wrapToolResult({
439
+ success: false,
440
+ code: 'ASSET_REMOVAL_BLOCKED',
441
+ droppedAssets: error.dropped,
442
+ error: error.message,
443
+ });
444
+ }
261
445
  return wrapToolResult({
262
446
  success: false,
263
447
  error: error instanceof Error ? error.message : 'Unknown error',
@@ -265,13 +449,157 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
265
449
  }
266
450
  },
267
451
  },
452
+ // List assets already uploaded to a folder
453
+ {
454
+ name: 'list_assets',
455
+ label: 'List Assets',
456
+ description: 'List images/files already uploaded to a folder, with a ready-to-paste markdown embed for each. ' +
457
+ 'Use this to find an asset a user placed (e.g. a screenshot) so you can embed it into an entry — ' +
458
+ 'assets live in storage (R2/local), NOT on the local filesystem, so import_file cannot find them. ' +
459
+ 'Each result has an `embed` string: use it verbatim and NEVER write ![[filename]] transclusion syntax ' +
460
+ '(it does not render). Optionally filter by entityType/entityId. This tool only references existing ' +
461
+ 'assets — uploads happen via the workspace UI or import_file.',
462
+ parameters: T.Object({
463
+ repo: T.String({ description: 'Folder name' }),
464
+ entityType: T.Optional(T.String({ description: 'Filter to assets owned by entries of this type' })),
465
+ entityId: T.Optional(T.String({ description: 'Filter to assets owned by this entry id' })),
466
+ }),
467
+ execute: async (toolCallId, params) => {
468
+ try {
469
+ const repoName = resolvePrivateRepo(params.repo);
470
+ if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
471
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
472
+ }
473
+ let assets = await listRepoAssets(repoName, workspaceManager);
474
+ if (params.entityType)
475
+ assets = assets.filter(a => a.entityType === params.entityType);
476
+ if (params.entityId)
477
+ assets = assets.filter(a => a.entityId === params.entityId);
478
+ return wrapToolResult({
479
+ success: true,
480
+ repo: repoName,
481
+ count: assets.length,
482
+ assets: assets.map(a => ({
483
+ asset_id: a.assetId,
484
+ filename: a.filename,
485
+ mime_type: a.contentType,
486
+ entityType: a.entityType,
487
+ entityId: a.entityId,
488
+ entityName: a.entityName,
489
+ url: a.url,
490
+ embed: a.embed,
491
+ })),
492
+ });
493
+ }
494
+ catch (error) {
495
+ return wrapToolResult({ success: false, error: error instanceof Error ? error.message : 'Unknown error' });
496
+ }
497
+ },
498
+ },
499
+ // Embed an already-uploaded asset into an entry body
500
+ {
501
+ name: 'attach_asset_to_entity',
502
+ label: 'Attach Asset',
503
+ description: 'Embed an already-uploaded asset (from list_assets) into an entry body using its render-safe markdown, ' +
504
+ 'without rewriting the whole body. mode "append" adds it at the end; mode "replace_placeholder" swaps dead ' +
505
+ 'placeholder text (e.g. an ![[Foo.png]] written earlier) for the working embed. Drop-guarded: rejects with ' +
506
+ 'ASSET_REMOVAL_BLOCKED if it would remove other image embeds (append only — replace_placeholder is exempt ' +
507
+ 'since the placeholder it removes is the dead reference being fixed).',
508
+ parameters: T.Object({
509
+ repo: T.String({ description: 'Folder name' }),
510
+ entityType: T.String({ description: 'Entity type of the target entry' }),
511
+ entityId: T.String({ description: 'Entity ID of the target entry' }),
512
+ url: T.String({ description: 'Asset url, taken verbatim from list_assets' }),
513
+ alt: T.Optional(T.String({ description: 'Alt text / caption. Defaults to the asset filename.' })),
514
+ mode: T.Optional(T.Union([T.Literal('append'), T.Literal('replace_placeholder')], { description: 'append (default) or replace_placeholder' })),
515
+ placeholder: T.Optional(T.String({ description: 'Required for replace_placeholder: exact text to replace' })),
516
+ expectedCount: T.Optional(T.Number({ description: 'For replace_placeholder: require this many occurrences, else reject' })),
517
+ }),
518
+ execute: async (toolCallId, params) => {
519
+ try {
520
+ const repoName = resolvePrivateRepo(params.repo);
521
+ if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
522
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
523
+ }
524
+ const url = params.url ?? '';
525
+ if (!url.trim())
526
+ return wrapToolResult({ success: false, error: 'url is required' });
527
+ const mode = params.mode ?? 'append';
528
+ if (mode === 'replace_placeholder' && !params.placeholder) {
529
+ return wrapToolResult({ success: false, error: 'mode "replace_placeholder" requires a non-empty placeholder' });
530
+ }
531
+ const filename = params.alt ?? (url.split('/').pop() || 'asset').split('?')[0];
532
+ const embed = assetEmbed(filename, url);
533
+ const graph = workspaceManager.getGraph(repoName);
534
+ const entity = graph.get(params.entityType, params.entityId);
535
+ const currentBody = graph.getLiveBody(params.entityType, params.entityId) ?? entity.document.content;
536
+ let newBody;
537
+ let occurrences;
538
+ let allowAssetRemoval = false;
539
+ if (mode === 'replace_placeholder') {
540
+ const ph = params.placeholder;
541
+ let count = 0;
542
+ for (let i = currentBody.indexOf(ph); i !== -1; i = currentBody.indexOf(ph, i + ph.length))
543
+ count++;
544
+ if (count === 0) {
545
+ return wrapToolResult({ success: false, code: 'NO_MATCH', error: `placeholder not present in ${params.entityType}/${params.entityId}.` });
546
+ }
547
+ if (params.expectedCount !== undefined && count !== params.expectedCount) {
548
+ return wrapToolResult({ success: false, code: 'AMBIGUOUS_MATCH', occurrences: count, error: `Expected ${params.expectedCount} occurrence(s) of placeholder, found ${count}.` });
549
+ }
550
+ occurrences = count;
551
+ newBody = currentBody.split(ph).join(embed);
552
+ // The placeholder we're removing is itself a recognized embed
553
+ // target; swapping it for the working embed is the whole point.
554
+ allowAssetRemoval = true;
555
+ }
556
+ else {
557
+ if (currentBody.includes(embed)) {
558
+ return wrapToolResult({ success: false, code: 'ALREADY_PRESENT', error: `Asset embed already present in ${params.entityType}/${params.entityId}.` });
559
+ }
560
+ newBody = currentBody.trimEnd() + '\n\n' + embed + '\n';
561
+ }
562
+ const options = prepareUpdatePayload({
563
+ entityType: params.entityType,
564
+ entityId: params.entityId,
565
+ content: newBody,
566
+ }, effectiveGitUser());
567
+ onAgentActivity?.('enter', repoName);
568
+ try {
569
+ const { entity: updated, frontmatter_changed, content_changed, noop, broadcast } = await diagnosedUpdate(graph, options, { content: newBody }, { allowAssetRemoval });
570
+ onMutation?.({ action: 'updated', repo: repoName, entityType: params.entityType, entityId: params.entityId });
571
+ return wrapToolResult({
572
+ success: true,
573
+ entity: { entityId: updated.id, entityType: updated.entityType, repo: repoName },
574
+ embed,
575
+ mode,
576
+ occurrences,
577
+ frontmatter_changed,
578
+ content_changed,
579
+ noop,
580
+ broadcast,
581
+ message: `Embedded ${filename} into ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
582
+ });
583
+ }
584
+ finally {
585
+ onAgentActivity?.('leave', repoName);
586
+ }
587
+ }
588
+ catch (error) {
589
+ if (error instanceof DroppedAssetError) {
590
+ return wrapToolResult({ success: false, code: 'ASSET_REMOVAL_BLOCKED', droppedAssets: error.dropped, error: error.message });
591
+ }
592
+ return wrapToolResult({ success: false, error: error instanceof Error ? error.message : 'Unknown error' });
593
+ }
594
+ },
595
+ },
268
596
  // Delete entity
269
597
  {
270
598
  name: 'delete_entity',
271
- label: 'Delete Entity',
272
- description: 'Delete an entity. Use with caution! Collection is auto-resolved for app-defined types.',
599
+ label: 'Delete Entry',
600
+ description: 'Delete an entry. Use with caution! Folder is auto-resolved for app-defined types.',
273
601
  parameters: T.Object({
274
- repo: T.Optional(T.String({ description: 'Collection name (auto-resolved for app entity types)' })),
602
+ repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
275
603
  entityType: T.String({ description: 'Entity type' }),
276
604
  entityId: T.String({ description: 'Entity ID' }),
277
605
  commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
@@ -280,20 +608,39 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
280
608
  try {
281
609
  let repoName = params.repo;
282
610
  if (!repoName) {
283
- repoName = workspaceManager.getAppForEntityType(params.entityType);
284
- if (!repoName)
285
- return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
611
+ return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
286
612
  }
613
+ repoName = resolvePrivateRepo(repoName);
287
614
  if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
288
- return wrapToolResult({ success: false, error: `Collection "${repoName}" not found` });
615
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
289
616
  }
290
617
  const graph = workspaceManager.getGraph(repoName);
291
- await graph.delete(params.entityType, params.entityId, params.commitMessage);
292
- onMutation?.({ action: 'deleted', repo: repoName, entityType: params.entityType, entityId: params.entityId });
293
- return wrapToolResult({
294
- success: true,
295
- message: `Deleted ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
296
- });
618
+ // Soft bridge-awareness: deleting a person linked to an auth account
619
+ // orphans that user. Don't block surface a warning so the agent can
620
+ // tell the user, and the Profile panel catches the orphan after.
621
+ let bridgeWarning;
622
+ if (params.entityType === 'person') {
623
+ try {
624
+ const handle = graph.get('person', params.entityId)?.data?.user_handle;
625
+ if (typeof handle === 'string' && handle.length > 0) {
626
+ bridgeWarning = `Note: this record was linked to the "${handle}" user account. Deleting it unlinks them — their "My Tasks", @mentions, and assignments stop resolving until they link a new record.`;
627
+ }
628
+ }
629
+ catch { /* not found — let graph.delete surface it */ }
630
+ }
631
+ onAgentActivity?.('enter', repoName);
632
+ try {
633
+ await graph.delete(params.entityType, params.entityId, params.commitMessage);
634
+ onMutation?.({ action: 'deleted', repo: repoName, entityType: params.entityType, entityId: params.entityId });
635
+ return wrapToolResult({
636
+ success: true,
637
+ message: `Deleted ${params.entityType}: ${params.entityId}. Auto-committed — ready to push.`,
638
+ ...(bridgeWarning ? { warning: bridgeWarning } : {}),
639
+ });
640
+ }
641
+ finally {
642
+ onAgentActivity?.('leave', repoName);
643
+ }
297
644
  }
298
645
  catch (error) {
299
646
  return wrapToolResult({
@@ -307,46 +654,94 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
307
654
  {
308
655
  name: 'import_file',
309
656
  label: 'Import File',
310
- description: 'Import a local file as a Studiograph entity. Supports .md and .txt (→ note) and .csv (→ dataset). The file is read from the local filesystem and converted to an entity with appropriate frontmatter.',
657
+ description: 'Import a local file as a Studiograph entry. Text formats become typed entries (.md/.txt → note, .csv → dataset). Binary formats become typed entries that embed a free-standing asset: images/opaque files material, PDF/Word → document, spreadsheets → dataset.',
311
658
  parameters: T.Object({
312
659
  path: T.String({ description: 'Absolute path or ~/relative path to the file' }),
313
- collection: T.String({ description: 'Target collection name' }),
314
- entityType: T.Optional(T.String({ description: 'Override entity type (default: auto-detect from extension)' })),
660
+ folder: T.String({ description: 'Target folder name' }),
661
+ entityType: T.Optional(T.String({ description: 'Override entity type (default: auto-detect from extension; ignored for binary imports, which route by kind)' })),
315
662
  entityId: T.Optional(T.String({ description: 'Override entity ID (default: from filename)' })),
316
663
  }),
317
664
  execute: async (toolCallId, params) => {
318
665
  try {
319
- if (!canAccessRepo(params.collection, workspaceManager, getUser, authSvc)) {
320
- return wrapToolResult({ success: false, error: `Collection "${params.collection}" not found` });
666
+ if (!canAccessRepo(params.folder, workspaceManager, getUser, authSvc)) {
667
+ return wrapToolResult({ success: false, error: `Folder "${params.folder}" not found` });
321
668
  }
322
669
  const { readFileSync, existsSync } = await import('fs');
323
- const { resolve } = await import('path');
670
+ const { resolve, basename, sep } = await import('path');
324
671
  const { homedir } = await import('os');
325
672
  const { importFile, isSupportedFile } = await import('../../services/import-service.js');
673
+ const { isAssetUploadExtension } = await import('../../services/assets/base.js');
674
+ const { importAssetAsEntity } = await import('../../services/asset-import-service.js');
326
675
  const filePath = params.path.startsWith('~/')
327
676
  ? resolve(homedir(), params.path.slice(2))
328
677
  : resolve(params.path);
329
678
  if (!existsSync(filePath)) {
330
679
  return wrapToolResult({ success: false, error: `File not found: ${filePath}` });
331
680
  }
681
+ const graph = workspaceManager.getGraph(params.folder);
682
+ const fname = basename(filePath);
683
+ // Path-exfil guard: the agent reads bytes off disk and uploads
684
+ // them as a workspace asset, accessible via /api/assets/* by any
685
+ // folder member. Without an allowlist, an LLM prompt injection in
686
+ // an imported note can ask the agent to grab ~/.ssh/id_rsa, .env
687
+ // files, kubeconfigs, etc. by renaming them to a permitted
688
+ // extension. Restrict to roots a user would plausibly drop files
689
+ // from: the workspace itself, ~/Downloads, ~/Documents.
690
+ const home = homedir();
691
+ const workspaceRoot = graph.getWorkspaceRoot();
692
+ const allowedRoots = [
693
+ workspaceRoot,
694
+ resolve(home, 'Downloads'),
695
+ resolve(home, 'Documents'),
696
+ ].filter((r) => Boolean(r)).map(r => r.endsWith(sep) ? r : r + sep);
697
+ const isInAllowedRoot = allowedRoots.some(root => filePath === root.slice(0, -1) || filePath.startsWith(root));
698
+ if (!isInAllowedRoot) {
699
+ return wrapToolResult({
700
+ success: false,
701
+ error: `Path "${filePath}" is outside the import allowlist. Files must live under the workspace, ~/Downloads, or ~/Documents.`,
702
+ });
703
+ }
704
+ // Binary extensions → asset-as-embed import: store a free-standing
705
+ // asset + create the typed entry(ies) that embed it (image→material,
706
+ // doc/pdf→document, xlsx→dataset×N). The text-import path doesn't know
707
+ // how to handle .indd / .pptx / etc. Parity with the web import
708
+ // dispatcher (importAssetAsEntity).
709
+ if (isAssetUploadExtension(fname)) {
710
+ const buffer = readFileSync(filePath);
711
+ const result = await importAssetAsEntity({
712
+ graph,
713
+ filename: fname,
714
+ buffer,
715
+ });
716
+ for (const e of result.entities) {
717
+ onMutation?.({ action: 'created', repo: params.folder, entityType: e.entityType, entityId: e.entityId });
718
+ }
719
+ const first = result.entities[0];
720
+ return wrapToolResult({
721
+ success: true,
722
+ entityType: first?.entityType,
723
+ entityId: first?.entityId,
724
+ assetId: result.assetId,
725
+ entities: result.entities.map(e => ({ entityType: e.entityType, entityId: e.entityId })),
726
+ message: `Imported ${fname} as ${result.entities.map(e => `${e.entityType}/${e.entityId}`).join(', ')} in ${params.folder}`,
727
+ });
728
+ }
332
729
  if (!isSupportedFile(filePath)) {
333
- return wrapToolResult({ success: false, error: `Unsupported file type. Supported: .md, .txt, .csv` });
730
+ return wrapToolResult({ success: false, error: `Unsupported file type for ${fname}` });
334
731
  }
335
- const graph = workspaceManager.getGraph(params.collection);
336
732
  const content = readFileSync(filePath);
337
- const { basename } = await import('path');
338
- const result = await importFile(graph, basename(filePath), content, {
733
+ const result = await importFile(graph, fname, content, {
339
734
  entityType: params.entityType,
340
735
  entityId: params.entityId,
341
736
  });
342
737
  if (result.status === 'created') {
343
- onMutation?.({ action: 'created', repo: params.collection, entityType: result.entityType, entityId: result.entityId });
738
+ onMutation?.({ action: 'created', repo: params.folder, entityType: result.entityType, entityId: result.entityId });
344
739
  }
345
740
  return wrapToolResult({
346
741
  success: result.status === 'created',
347
742
  ...result,
348
743
  message: result.status === 'created'
349
- ? `Imported ${basename(filePath)} as ${result.entityType}/${result.entityId} in ${params.collection}`
744
+ ? `Imported ${fname} as ${result.entityType}/${result.entityId} in ${params.folder}`
350
745
  : result.error,
351
746
  });
352
747
  }
@@ -361,10 +756,10 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
361
756
  // Rename entity (change ID)
362
757
  {
363
758
  name: 'rename_entity',
364
- label: 'Rename Entity',
365
- description: 'Rename an entity by changing its ID. Preserves all data, content, and source_ref. The old ID will no longer exist. Collection is auto-resolved for app-defined types.',
759
+ label: 'Rename Entry',
760
+ 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
761
  parameters: T.Object({
367
- repo: T.Optional(T.String({ description: 'Collection name (auto-resolved for app entity types)' })),
762
+ repo: T.Optional(T.String({ description: 'Folder name (auto-resolved for app entity types)' })),
368
763
  entityType: T.String({ description: 'Entity type' }),
369
764
  oldId: T.String({ description: 'Current entity ID' }),
370
765
  newId: T.String({ description: 'New entity ID (kebab-case)' }),
@@ -373,12 +768,11 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
373
768
  try {
374
769
  let repoName = params.repo;
375
770
  if (!repoName) {
376
- repoName = workspaceManager.getAppForEntityType(params.entityType);
377
- if (!repoName)
378
- return wrapToolResult({ success: false, error: `repo is required — could not auto-resolve repo for type "${params.entityType}"` });
771
+ return wrapToolResult({ success: false, error: `repo is required — must specify which folder to use for type "${params.entityType}"` });
379
772
  }
773
+ repoName = resolvePrivateRepo(repoName);
380
774
  if (!canAccessRepo(repoName, workspaceManager, getUser, authSvc)) {
381
- return wrapToolResult({ success: false, error: `Collection "${repoName}" not found` });
775
+ return wrapToolResult({ success: false, error: `Folder "${repoName}" not found` });
382
776
  }
383
777
  const graph = workspaceManager.getGraph(repoName);
384
778
  const result = await graph.rename(params.entityType, params.oldId, params.newId);
@@ -398,41 +792,41 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
398
792
  }
399
793
  },
400
794
  },
401
- // Move entity between repos
795
+ // Transfer entity across repos (cross-repo move). Distinct from
796
+ // folder-tools' `move_entity`, which relocates within one repo.
402
797
  {
403
- name: 'move_entity',
404
- label: 'Move Entity',
405
- description: 'Move an entity from one collection to another (admin only). Preserves all data, content, and wikilinks.',
798
+ name: 'transfer_entity',
799
+ label: 'Transfer Entry',
800
+ 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
801
  parameters: T.Object({
407
- sourceRepo: T.String({ description: 'Source collection name' }),
408
- targetRepo: T.String({ description: 'Target collection name' }),
802
+ sourceRepo: T.String({ description: 'Source repo name' }),
803
+ targetRepo: T.String({ description: 'Target repo name' }),
409
804
  entityType: T.String({ description: 'Entity type' }),
410
805
  entityId: T.String({ description: 'Entity ID' }),
411
806
  commitMessage: T.Optional(T.String({ description: 'Custom commit message (optional)' })),
412
807
  }),
413
808
  execute: async (toolCallId, params) => {
414
809
  try {
415
- const denied = adminOnly(getUser);
416
- if (denied)
417
- return wrapToolResult({ success: false, error: denied });
418
810
  if (!canAccessRepo(params.sourceRepo, workspaceManager, getUser, authSvc)) {
419
- return wrapToolResult({ success: false, error: `Collection "${params.sourceRepo}" not found` });
811
+ return wrapToolResult({ success: false, error: `Folder "${params.sourceRepo}" not found` });
420
812
  }
421
813
  if (!canAccessRepo(params.targetRepo, workspaceManager, getUser, authSvc)) {
422
- return wrapToolResult({ success: false, error: `Collection "${params.targetRepo}" not found` });
814
+ return wrapToolResult({ success: false, error: `Folder "${params.targetRepo}" not found` });
423
815
  }
424
816
  const sourceGraph = workspaceManager.getGraph(params.sourceRepo);
425
817
  const targetGraph = workspaceManager.getGraph(params.targetRepo);
426
818
  // Read the full entity from source
427
819
  const entity = sourceGraph.get(params.entityType, params.entityId);
428
820
  // Create in target repo
821
+ const actor = effectiveGitUser();
429
822
  const now = new Date().toISOString();
430
823
  await targetGraph.create({
431
824
  entityType: params.entityType,
432
825
  entityId: params.entityId,
433
- data: { ...entity.data, updated_at: now, updated_by: gitUser.id },
826
+ data: { ...entity.data, updated_at: now, updated_by: actor.id },
434
827
  content: entity.document.content || '',
435
828
  commitMessage: params.commitMessage || `Move ${params.entityType} ${params.entityId} from ${params.sourceRepo} to ${params.targetRepo}`,
829
+ user: actor,
436
830
  });
437
831
  // Delete from source repo
438
832
  await sourceGraph.delete(params.entityType, params.entityId, `Move ${params.entityType} ${params.entityId} to ${params.targetRepo}`);
@@ -454,12 +848,12 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
454
848
  // Search entities
455
849
  {
456
850
  name: 'search_entities',
457
- label: 'Search Entities',
458
- description: 'Search for entities across collections with filters.',
851
+ label: 'Search Entries',
852
+ description: 'Search for entries across folders with filters.',
459
853
  parameters: T.Object({
460
854
  query: T.Optional(T.String({ description: 'Search query (full-text)' })),
461
855
  entityType: T.Optional(T.String({ description: 'Filter by entity type' })),
462
- repoNames: T.Optional(T.Array(T.String(), { description: 'Limit to specific collections' })),
856
+ repoNames: T.Optional(T.Array(T.String(), { description: 'Limit to specific folders' })),
463
857
  visibility: T.Optional(T.Array(T.String(), { description: 'Filter by visibility (public, team, admin, restricted)' })),
464
858
  tags: T.Optional(T.Array(T.String(), { description: 'Filter by tags' })),
465
859
  dateRange: T.Optional(T.Object({
@@ -471,9 +865,9 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
471
865
  }),
472
866
  execute: async (toolCallId, params) => {
473
867
  try {
474
- // Scope search to accessible collections
868
+ // Scope search to accessible folders
475
869
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
476
- let repoNames = params.repoNames;
870
+ let repoNames = params.repoNames?.map((r) => resolvePrivateRepo(r));
477
871
  if (allowed) {
478
872
  repoNames = repoNames
479
873
  ? repoNames.filter((r) => allowed.has(r))
@@ -511,8 +905,8 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
511
905
  // List entities
512
906
  {
513
907
  name: 'list_entities',
514
- label: 'List Entities',
515
- description: 'List all entities of a given type (or all types)',
908
+ label: 'List Entries',
909
+ description: 'List all entries of a given type (or all types)',
516
910
  parameters: T.Object({
517
911
  entityType: T.Optional(T.String({ description: 'Entity type to list (omit for all)' })),
518
912
  limit: T.Optional(T.Number({ description: 'Max results' })),
@@ -520,7 +914,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
520
914
  execute: async (toolCallId, params) => {
521
915
  try {
522
916
  let results = workspaceManager.list(params.entityType, params.limit);
523
- // Filter to accessible collections
917
+ // Filter to accessible folders
524
918
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
525
919
  if (allowed) {
526
920
  results = results.filter(r => allowed.has(r.repoName));
@@ -547,20 +941,21 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
547
941
  // Get related entities
548
942
  {
549
943
  name: 'get_related',
550
- label: 'Get Related Entities',
551
- description: 'Get entities related to a given entity via wikilinks (cross-collection supported). Pass repo, entityType, entityId from search/list results.',
944
+ label: 'Get Related Entries',
945
+ description: 'Get entries related to a given entry via wikilinks (cross-folder supported). Pass repo, entityType, entityId from search/list results.',
552
946
  parameters: T.Object({
553
- repo: T.String({ description: 'Collection name' }),
947
+ repo: T.String({ description: 'Folder name' }),
554
948
  entityType: T.String({ description: 'Entity type' }),
555
949
  entityId: T.String({ description: 'Entity ID' }),
556
950
  }),
557
951
  execute: async (toolCallId, params) => {
558
952
  try {
559
- if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
560
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
953
+ const repo = resolvePrivateRepo(params.repo);
954
+ if (!canAccessRepo(repo, workspaceManager, getUser, authSvc)) {
955
+ return wrapToolResult({ success: false, error: `Folder "${repo}" not found` });
561
956
  }
562
- let related = workspaceManager.getRelated(params.repo, params.entityType, params.entityId);
563
- // Filter cross-collection results to accessible repos
957
+ let related = workspaceManager.getRelated(repo, params.entityType, params.entityId);
958
+ // Filter cross-folder results to accessible repos
564
959
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
565
960
  if (allowed) {
566
961
  related = related.filter(r => allowed.has(r.repoName));
@@ -588,19 +983,19 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
588
983
  {
589
984
  name: 'get_backlinks',
590
985
  label: 'Get Backlinks',
591
- description: 'Get entities that link to a given entity (cross-collection supported). Pass repo, entityType, entityId from search/list results.',
986
+ description: 'Get entries that link to a given entry (cross-folder supported). Pass repo, entityType, entityId from search/list results.',
592
987
  parameters: T.Object({
593
- repo: T.String({ description: 'Collection name' }),
988
+ repo: T.String({ description: 'Folder name' }),
594
989
  entityType: T.String({ description: 'Entity type' }),
595
990
  entityId: T.String({ description: 'Entity ID' }),
596
991
  }),
597
992
  execute: async (toolCallId, params) => {
598
993
  try {
599
994
  if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
600
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
995
+ return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
601
996
  }
602
997
  let backlinks = workspaceManager.getBacklinks(params.repo, params.entityType, params.entityId);
603
- // Filter cross-collection results to accessible repos
998
+ // Filter cross-folder results to accessible repos
604
999
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
605
1000
  if (allowed) {
606
1001
  backlinks = backlinks.filter(r => allowed.has(r.repoName));
@@ -628,16 +1023,16 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
628
1023
  {
629
1024
  name: 'validate_wikilinks',
630
1025
  label: 'Validate Wikilinks',
631
- description: 'Validate all wikilinks in an entity (checks same collection and cross-collection)',
1026
+ description: 'Validate all wikilinks in an entry (checks same folder and cross-folder)',
632
1027
  parameters: T.Object({
633
- repo: T.String({ description: 'Collection name' }),
1028
+ repo: T.String({ description: 'Folder name' }),
634
1029
  entityType: T.String({ description: 'Entity type' }),
635
1030
  entityId: T.String({ description: 'Entity ID' }),
636
1031
  }),
637
1032
  execute: async (toolCallId, params) => {
638
1033
  try {
639
1034
  if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
640
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
1035
+ return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
641
1036
  }
642
1037
  const validation = workspaceManager.validateWikilinks(params.repo, params.entityType, params.entityId);
643
1038
  return wrapToolResult({
@@ -672,7 +1067,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
672
1067
  const summary = workspaceManager.getSummary();
673
1068
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
674
1069
  if (allowed) {
675
- // Filter summary to accessible collections only
1070
+ // Filter summary to accessible folders only
676
1071
  const filteredByRepo = {};
677
1072
  let filteredTotal = 0;
678
1073
  for (const [repo, count] of Object.entries(summary.entitiesByRepo)) {
@@ -684,19 +1079,19 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
684
1079
  return wrapToolResult({
685
1080
  success: true,
686
1081
  summary: {
687
- totalCollections: allowed.size,
1082
+ totalFolders: allowed.size,
688
1083
  totalEntities: filteredTotal,
689
- entitiesByCollection: filteredByRepo,
1084
+ entitiesByFolder: filteredByRepo,
690
1085
  },
691
1086
  });
692
1087
  }
693
1088
  return wrapToolResult({
694
1089
  success: true,
695
1090
  summary: {
696
- totalCollections: summary.totalRepos,
1091
+ totalFolders: summary.totalRepos,
697
1092
  totalEntities: summary.totalEntities,
698
1093
  entitiesByType: summary.entitiesByType,
699
- entitiesByCollection: summary.entitiesByRepo,
1094
+ entitiesByFolder: summary.entitiesByRepo,
700
1095
  },
701
1096
  });
702
1097
  }
@@ -708,15 +1103,15 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
708
1103
  }
709
1104
  },
710
1105
  },
711
- // List collections
1106
+ // List folders
712
1107
  {
713
1108
  name: 'list_repos',
714
- label: 'List Collections',
715
- description: 'List all collections in the workspace',
1109
+ label: 'List Folders',
1110
+ description: 'List all folders in the workspace',
716
1111
  parameters: T.Object({}),
717
1112
  execute: async (toolCallId, params) => {
718
1113
  try {
719
- let repos = workspaceManager.getAllRepoConfigs();
1114
+ let repos = workspaceManager.getContentRepoConfigs();
720
1115
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
721
1116
  if (allowed) {
722
1117
  repos = repos.filter(r => allowed.has(r.name));
@@ -724,12 +1119,12 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
724
1119
  return wrapToolResult({
725
1120
  success: true,
726
1121
  count: repos.length,
727
- collections: repos.map(r => ({
1122
+ folders: repos.map(r => ({
728
1123
  name: r.name,
729
1124
  type: r.type,
730
1125
  description: r.description,
731
1126
  path: r.path,
732
- private: r.private || false,
1127
+ personal: r.personal || false,
733
1128
  })),
734
1129
  });
735
1130
  }
@@ -741,40 +1136,35 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
741
1136
  }
742
1137
  },
743
1138
  },
744
- // Create a new collection
1139
+ // Create a new folder
745
1140
  {
746
- name: 'create_collection',
747
- label: 'Create Collection',
748
- description: 'Create a new collection in the workspace. A collection is a git-backed container for entities. Private collections are only visible to the creating user.',
1141
+ name: 'create_folder',
1142
+ label: 'Create Folder',
1143
+ 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
1144
  parameters: T.Object({
750
- name: T.String({ description: 'Collection name in kebab-case (e.g., "client-projects")' }),
751
- description: T.Optional(T.String({ description: 'Short description of the collection' })),
752
- private: T.Optional(T.Boolean({ description: 'If true, creates a private collection visible only to you' })),
1145
+ name: T.String({ description: 'Folder name in kebab-case (e.g., "client-projects")' }),
1146
+ description: T.Optional(T.String({ description: 'Short description of the folder' })),
753
1147
  }),
754
1148
  execute: async (toolCallId, params) => {
755
1149
  try {
756
1150
  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
1151
  if (!/^[a-z0-9][a-z0-9-]*$/.test(params.name)) {
762
- return wrapToolResult({ success: false, error: 'Collection name must be kebab-case (lowercase letters, numbers, hyphens)' });
1152
+ return wrapToolResult({ success: false, error: 'Folder name must be kebab-case (lowercase letters, numbers, hyphens)' });
763
1153
  }
764
1154
  const { Workspace } = await import('../../core/workspace.js');
765
1155
  const workspace = new Workspace(workspacePath);
766
1156
  const repo = await workspace.registerRepo({
767
1157
  name: params.name,
768
1158
  description: params.description,
769
- private: params.private,
770
- ...(params.private && user ? { owner_id: user.id } : {}),
1159
+ owner_id: user?.id,
771
1160
  });
772
- // Reload workspace manager to pick up the new collection
773
1161
  workspaceManager.reloadConfig();
774
- onMutation?.({ action: 'created', repo: repo.name, entityType: '_collection', entityId: repo.name });
1162
+ if (user && authSvc)
1163
+ authSvc.grantFolderAccess(user.id, repo.name, 'admin');
1164
+ onMutation?.({ action: 'created', repo: repo.name, entityType: '_folder', entityId: repo.name });
775
1165
  return wrapToolResult({
776
1166
  success: true,
777
- collection: { name: repo.name, path: repo.path, description: repo.description },
1167
+ folder: { name: repo.name, path: repo.path, description: repo.description },
778
1168
  });
779
1169
  }
780
1170
  catch (error) {
@@ -788,7 +1178,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
788
1178
  label: 'Query Dataset',
789
1179
  description: 'Query rows from a dataset entity with optional filtering',
790
1180
  parameters: T.Object({
791
- repo: T.String({ description: 'Collection name' }),
1181
+ repo: T.String({ description: 'Folder name' }),
792
1182
  entityId: T.String({ description: 'Dataset entity ID' }),
793
1183
  filter: T.Optional(T.Object({}, { description: 'Filter conditions (column: value or { gte, lte, contains })', additionalProperties: true })),
794
1184
  limit: T.Optional(T.Number({ description: 'Max rows to return' })),
@@ -796,21 +1186,24 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
796
1186
  execute: async (toolCallId, params) => {
797
1187
  try {
798
1188
  if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
799
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
1189
+ return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
800
1190
  }
801
1191
  const graph = workspaceManager.getGraph(params.repo);
802
- const entity = graph.get('dataset', params.entityId);
803
- const schema = entity.data.schema;
1192
+ // Validates the entity exists and is a dataset before querying.
1193
+ graph.get('dataset', params.entityId);
804
1194
  let rows = graph.getDatasetRows(params.entityId, params.filter);
805
1195
  const total = rows.length;
806
1196
  if (params.limit && params.limit > 0) {
807
1197
  rows = rows.slice(0, params.limit);
808
1198
  }
1199
+ // Columns from the header, not the result rows — so a zero-match
1200
+ // filter or header-only dataset still reports the real columns.
1201
+ const columns = graph.getDatasetColumns(params.entityId);
809
1202
  return wrapToolResult({
810
1203
  success: true,
811
1204
  rows,
812
1205
  total,
813
- schema,
1206
+ columns,
814
1207
  });
815
1208
  }
816
1209
  catch (error) {
@@ -827,7 +1220,7 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
827
1220
  label: 'Append Rows',
828
1221
  description: 'Append rows to a dataset entity',
829
1222
  parameters: T.Object({
830
- repo: T.String({ description: 'Collection name' }),
1223
+ repo: T.String({ description: 'Folder name' }),
831
1224
  entityId: T.String({ description: 'Dataset entity ID' }),
832
1225
  rows: T.Array(T.Object({}, { additionalProperties: true }), { description: 'Rows to append' }),
833
1226
  commitMessage: T.Optional(T.String({ description: 'Custom commit message' })),
@@ -835,13 +1228,14 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
835
1228
  execute: async (toolCallId, params) => {
836
1229
  try {
837
1230
  if (!canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
838
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
1231
+ return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
839
1232
  }
840
1233
  const graph = workspaceManager.getGraph(params.repo);
841
1234
  // Get current row count before appending
842
1235
  const beforeRows = graph.getDatasetRows(params.entityId);
843
1236
  await graph.appendDatasetRows(params.entityId, params.rows, params.commitMessage);
844
1237
  const afterRows = graph.getDatasetRows(params.entityId);
1238
+ onMutation?.({ action: 'updated', repo: params.repo, entityType: 'dataset', entityId: params.entityId });
845
1239
  return wrapToolResult({
846
1240
  success: true,
847
1241
  rowsAdded: afterRows.length - beforeRows.length,
@@ -860,31 +1254,23 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
860
1254
  // Get entity schema
861
1255
  {
862
1256
  name: 'get_entity_schema',
863
- label: 'Get Entity Schema',
864
- description: 'Get the schema definition for an entity type (useful for understanding required fields)',
1257
+ label: 'Get Entry Schema',
1258
+ 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
1259
  parameters: T.Object({
866
1260
  entityType: T.String({ description: 'Entity type' }),
867
1261
  }),
868
1262
  execute: async (toolCallId, params) => {
869
1263
  try {
870
- const schema = ENTITY_SCHEMAS[params.entityType];
871
- if (!schema) {
1264
+ const registry = workspaceManager.getSchemaRegistry();
1265
+ const knownTypes = new Set(registry.getAllTypes());
1266
+ if (!knownTypes.has(params.entityType)) {
872
1267
  return wrapToolResult({
873
1268
  success: false,
874
- error: `Unknown entity type: ${params.entityType}`,
1269
+ error: `Unknown entity type: ${params.entityType}. Known types: ${[...knownTypes].sort().join(', ')}`,
875
1270
  });
876
1271
  }
877
- // Extract schema shape (simplified)
878
- const shape = schema.shape || {};
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
- }
1272
+ const schema = registry.getSchema(params.entityType);
1273
+ const fields = describeZodObject(schema);
888
1274
  return wrapToolResult({
889
1275
  success: true,
890
1276
  entityType: params.entityType,
@@ -902,16 +1288,16 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
902
1288
  // Lint entities
903
1289
  {
904
1290
  name: 'lint_entities',
905
- label: 'Lint Entities',
906
- description: 'Check for missing recommended fields across entities. Returns incomplete entities with their missing fields. Use to discover entities that need enrichment. Optionally filter by collection or entity type.',
1291
+ label: 'Lint Entries',
1292
+ 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
1293
  parameters: T.Object({
908
- repo: T.Optional(T.String({ description: 'Optional: limit to specific collection' })),
1294
+ repo: T.Optional(T.String({ description: 'Optional: limit to specific folder' })),
909
1295
  entityType: T.Optional(T.String({ description: 'Optional: limit to specific entity type (e.g. "project", "deal")' })),
910
1296
  }),
911
1297
  execute: async (toolCallId, params) => {
912
1298
  try {
913
1299
  if (params.repo && !canAccessRepo(params.repo, workspaceManager, getUser, authSvc)) {
914
- return wrapToolResult({ success: false, error: `Collection "${params.repo}" not found` });
1300
+ return wrapToolResult({ success: false, error: `Folder "${params.repo}" not found` });
915
1301
  }
916
1302
  let issues = await lintWorkspace(workspaceManager, {
917
1303
  repo: params.repo,
@@ -957,16 +1343,15 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
957
1343
  {
958
1344
  name: 'find_orphans',
959
1345
  label: 'Find Orphans',
960
- description: 'Find entities with zero inbound wikilink references. Optionally tombstone them to exclude from future syncs.',
1346
+ description: 'Find entries with zero inbound wikilink references.',
961
1347
  parameters: T.Object({
962
1348
  entityTypes: T.Optional(T.Array(T.String(), { description: 'Entity types to check (e.g. ["person", "client"])' })),
963
1349
  minAgeDays: T.Optional(T.Number({ description: 'Only flag entities older than N days' })),
964
- repos: T.Optional(T.Array(T.String(), { description: 'Collection names to scan (default: all)' })),
965
- tombstone: T.Optional(T.Boolean({ description: 'Add orphans to sync-state tombstones' })),
1350
+ repos: T.Optional(T.Array(T.String(), { description: 'Folder names to scan (default: all)' })),
966
1351
  }),
967
1352
  execute: async (toolCallId, params) => {
968
1353
  try {
969
- // Scope to accessible collections
1354
+ // Scope to accessible folders
970
1355
  const allowed = getAccessibleRepoNames(workspaceManager, getUser, authSvc);
971
1356
  let repos = params.repos;
972
1357
  if (allowed) {
@@ -977,13 +1362,6 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
977
1362
  minAgeDays: params.minAgeDays,
978
1363
  repos,
979
1364
  });
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
1365
  // Group by type for summary
988
1366
  const byType = {};
989
1367
  for (const o of result.orphans) {
@@ -993,7 +1371,6 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
993
1371
  success: true,
994
1372
  totalScanned: result.totalScanned,
995
1373
  totalOrphans: result.totalOrphans,
996
- tombstoned: params.tombstone ? result.totalOrphans : 0,
997
1374
  byType,
998
1375
  orphans: result.orphans.slice(0, 50), // limit response size
999
1376
  });
@@ -1009,8 +1386,8 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
1009
1386
  // Highlight entities in graph view
1010
1387
  {
1011
1388
  name: 'highlight_entities',
1012
- label: 'Highlight Entities',
1013
- description: 'Highlight specific entities in the graph view. Pass entity IDs to highlight them (dimming all others). Pass an empty array to clear highlights.',
1389
+ label: 'Highlight Entries',
1390
+ 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
1391
  parameters: T.Object({
1015
1392
  entityIds: T.Array(T.String(), { description: 'Entity IDs to highlight in the graph' }),
1016
1393
  }),
@@ -1025,96 +1402,50 @@ export function createGraphTools(workspaceManager, gitUser, workspacePath, onHig
1025
1402
  });
1026
1403
  },
1027
1404
  },
1028
- // ── View Management Tools ──
1405
+ // Mark onboarding complete
1029
1406
  {
1030
- name: 'list_views',
1031
- label: 'List Views',
1032
- description: 'List the current user\'s saved views.',
1407
+ name: 'mark_onboarded',
1408
+ label: 'Mark Onboarded',
1409
+ description: 'Mark the current user as onboarded. Call this when the interview/onboarding flow is complete.',
1033
1410
  parameters: T.Object({}),
1034
- execute: async () => {
1411
+ execute: async (_toolCallId) => {
1035
1412
  if (!authSvc)
1036
1413
  return wrapToolResult({ success: false, error: 'Auth service not available' });
1037
1414
  const userId = getUser()?.id ?? 0;
1038
- const views = authSvc.getUserViews(userId);
1039
- return wrapToolResult({ views });
1415
+ authSvc.setOnboarded(userId, true);
1416
+ return wrapToolResult({ success: true, message: 'User marked as onboarded.' });
1040
1417
  },
1041
1418
  },
1419
+ // Update workspace description (ABOUT.md)
1042
1420
  {
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.',
1421
+ name: 'update_workspace_about',
1422
+ label: 'Update Workspace Description',
1423
+ 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.',
1046
1424
  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")' })),
1425
+ content: T.String({ description: 'The full markdown content for the workspace description' }),
1050
1426
  }),
1051
1427
  execute: async (_toolCallId, params) => {
1052
- if (!authSvc)
1053
- return wrapToolResult({ success: false, error: 'Auth service not available' });
1054
- const userId = getUser()?.id ?? 0;
1055
- const config = {
1056
- selectedType: params.selectedType ?? null,
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
- });
1068
- },
1069
- },
1070
- {
1071
- name: 'update_view',
1072
- label: 'Update View',
1073
- description: 'Update an existing saved view\'s name or configuration.',
1074
- parameters: T.Object({
1075
- id: T.Number({ description: 'View ID' }),
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)' })),
1079
- }),
1080
- execute: async (_toolCallId, params) => {
1081
- if (!authSvc)
1082
- return wrapToolResult({ success: false, error: 'Auth service not available' });
1083
- const userId = getUser()?.id ?? 0;
1084
- const existing = authSvc.getUserView(params.id, userId);
1085
- if (!existing)
1086
- return wrapToolResult({ success: false, error: `View ${params.id} not found` });
1087
- const fields = {};
1088
- if (params.name)
1089
- fields.name = params.name;
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;
1428
+ try {
1429
+ const { Workspace } = await import('../../core/workspace.js');
1430
+ const workspace = new Workspace(workspacePath);
1431
+ workspace.writeAbout(params.content);
1432
+ onMutation?.({ action: 'updated', repo: '_workspace', entityType: '_workspace', entityId: 'about' });
1433
+ return wrapToolResult({ success: true, message: 'Workspace description updated.' });
1434
+ }
1435
+ catch (err) {
1436
+ return wrapToolResult({ success: false, error: err.message || 'Failed to write ABOUT.md' });
1097
1437
  }
1098
- authSvc.updateUserView(params.id, userId, fields);
1099
- return wrapToolResult({ success: true, message: `Updated view "${existing.name}".` });
1100
1438
  },
1101
1439
  },
1440
+ // Reset conversation
1102
1441
  {
1103
- name: 'delete_view',
1104
- label: 'Delete View',
1105
- description: 'Delete a saved view.',
1106
- parameters: T.Object({
1107
- id: T.Number({ description: 'View ID to delete' }),
1108
- }),
1109
- execute: async (_toolCallId, params) => {
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}".` });
1442
+ name: 'reset_conversation',
1443
+ label: 'Reset Conversation',
1444
+ description: 'Clear the current conversation and start fresh. Use when the user asks to "start over", "reset", "clear the chat", or "new conversation".',
1445
+ parameters: T.Object({}),
1446
+ execute: async (_toolCallId) => {
1447
+ onMutation?.({ action: 'deleted', repo: '_conversation', entityType: '_conversation', entityId: 'reset' });
1448
+ return wrapToolResult({ success: true, message: 'Conversation reset.' });
1118
1449
  },
1119
1450
  },
1120
1451
  ];