studiograph 1.3.3-next.9 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. package/dist/agent/orchestrator.d.ts +2 -0
  2. package/dist/agent/orchestrator.js +13 -5
  3. package/dist/agent/orchestrator.js.map +1 -1
  4. package/dist/agent/skills/sync-configuration.md +4 -29
  5. package/dist/agent/skills/sync-setup.md +2 -4
  6. package/dist/agent/tools/ops-tools.js +15 -126
  7. package/dist/agent/tools/ops-tools.js.map +1 -1
  8. package/dist/agent/tools/sync-tools.d.ts +7 -6
  9. package/dist/agent/tools/sync-tools.js +205 -178
  10. package/dist/agent/tools/sync-tools.js.map +1 -1
  11. package/dist/cli/commands/about.d.ts +13 -0
  12. package/dist/cli/commands/about.js +97 -0
  13. package/dist/cli/commands/about.js.map +1 -0
  14. package/dist/cli/commands/clone.d.ts +5 -2
  15. package/dist/cli/commands/clone.js +131 -62
  16. package/dist/cli/commands/clone.js.map +1 -1
  17. package/dist/cli/commands/connector.d.ts +2 -16
  18. package/dist/cli/commands/connector.js +32 -109
  19. package/dist/cli/commands/connector.js.map +1 -1
  20. package/dist/cli/commands/deploy.d.ts +0 -1
  21. package/dist/cli/commands/deploy.js +13 -103
  22. package/dist/cli/commands/deploy.js.map +1 -1
  23. package/dist/cli/commands/init.js +6 -93
  24. package/dist/cli/commands/init.js.map +1 -1
  25. package/dist/cli/commands/join.js +51 -1
  26. package/dist/cli/commands/join.js.map +1 -1
  27. package/dist/cli/commands/redeploy.js +1 -2
  28. package/dist/cli/commands/redeploy.js.map +1 -1
  29. package/dist/cli/commands/serve.d.ts +1 -3
  30. package/dist/cli/commands/serve.js +29 -109
  31. package/dist/cli/commands/serve.js.map +1 -1
  32. package/dist/cli/commands/start.js +1 -1
  33. package/dist/cli/commands/start.js.map +1 -1
  34. package/dist/cli/commands/sync-collection.d.ts +14 -0
  35. package/dist/cli/commands/sync-collection.js +366 -0
  36. package/dist/cli/commands/sync-collection.js.map +1 -0
  37. package/dist/cli/commands/sync.js +518 -82
  38. package/dist/cli/commands/sync.js.map +1 -1
  39. package/dist/cli/index.js +12 -30
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/cli/setup-wizard.d.ts +0 -13
  42. package/dist/cli/setup-wizard.js +6 -81
  43. package/dist/cli/setup-wizard.js.map +1 -1
  44. package/dist/core/types.d.ts +140 -21
  45. package/dist/core/types.js +15 -4
  46. package/dist/core/types.js.map +1 -1
  47. package/dist/core/workspace.d.ts +11 -4
  48. package/dist/core/workspace.js +61 -26
  49. package/dist/core/workspace.js.map +1 -1
  50. package/dist/integrations/asana.d.ts +26 -0
  51. package/dist/integrations/asana.js +77 -0
  52. package/dist/integrations/asana.js.map +1 -0
  53. package/dist/integrations/figma-local.d.ts +16 -0
  54. package/dist/integrations/figma-local.js +10 -0
  55. package/dist/integrations/figma-local.js.map +1 -0
  56. package/dist/integrations/figma.d.ts +17 -0
  57. package/dist/integrations/figma.js +16 -0
  58. package/dist/integrations/figma.js.map +1 -0
  59. package/dist/integrations/granola.d.ts +24 -0
  60. package/dist/integrations/granola.js +59 -0
  61. package/dist/integrations/granola.js.map +1 -0
  62. package/dist/integrations/linear.d.ts +14 -0
  63. package/dist/integrations/linear.js +70 -0
  64. package/dist/integrations/linear.js.map +1 -0
  65. package/dist/integrations/paper-local.d.ts +14 -0
  66. package/dist/integrations/paper-local.js +10 -0
  67. package/dist/integrations/paper-local.js.map +1 -0
  68. package/dist/integrations/paper.d.ts +2 -0
  69. package/dist/integrations/paper.js +10 -0
  70. package/dist/integrations/paper.js.map +1 -0
  71. package/dist/integrations/pipedrive.d.ts +26 -0
  72. package/dist/integrations/pipedrive.js +97 -0
  73. package/dist/integrations/pipedrive.js.map +1 -0
  74. package/dist/integrations/registry.d.ts +15 -0
  75. package/dist/integrations/registry.js +27 -0
  76. package/dist/integrations/registry.js.map +1 -0
  77. package/dist/integrations/types.d.ts +34 -0
  78. package/dist/integrations/types.js +9 -0
  79. package/dist/integrations/types.js.map +1 -0
  80. package/dist/mcp/connector-manager.d.ts +45 -31
  81. package/dist/mcp/connector-manager.js +164 -116
  82. package/dist/mcp/connector-manager.js.map +1 -1
  83. package/dist/mcp/server-oauth-provider.d.ts +56 -0
  84. package/dist/mcp/server-oauth-provider.js +138 -0
  85. package/dist/mcp/server-oauth-provider.js.map +1 -0
  86. package/dist/server/chrome/chrome.css +142 -28
  87. package/dist/server/chrome/chrome.js +51 -25
  88. package/dist/server/collab-authority.d.ts +70 -0
  89. package/dist/server/collab-authority.js +218 -0
  90. package/dist/server/collab-authority.js.map +1 -0
  91. package/dist/server/collab.d.ts +29 -0
  92. package/dist/server/collab.js +195 -0
  93. package/dist/server/collab.js.map +1 -0
  94. package/dist/server/commit-scheduler.d.ts +1 -1
  95. package/dist/server/commit-scheduler.js +18 -4
  96. package/dist/server/commit-scheduler.js.map +1 -1
  97. package/dist/server/index.d.ts +0 -2
  98. package/dist/server/index.js +89 -18
  99. package/dist/server/index.js.map +1 -1
  100. package/dist/server/routes/auth-api.d.ts +6 -0
  101. package/dist/server/routes/auth-api.js +55 -0
  102. package/dist/server/routes/auth-api.js.map +1 -1
  103. package/dist/server/routes/collab.d.ts +6 -0
  104. package/dist/server/routes/collab.js +10 -0
  105. package/dist/server/routes/collab.js.map +1 -0
  106. package/dist/server/routes/git-http.d.ts +1 -1
  107. package/dist/server/routes/git-http.js +53 -15
  108. package/dist/server/routes/git-http.js.map +1 -1
  109. package/dist/server/routes/graph-api.d.ts +2 -2
  110. package/dist/server/routes/graph-api.js +59 -55
  111. package/dist/server/routes/graph-api.js.map +1 -1
  112. package/dist/server/routes/mcp.d.ts +12 -0
  113. package/dist/server/routes/mcp.js +35 -0
  114. package/dist/server/routes/mcp.js.map +1 -0
  115. package/dist/server/routes/permissions-api.d.ts +2 -1
  116. package/dist/server/routes/permissions-api.js +16 -2
  117. package/dist/server/routes/permissions-api.js.map +1 -1
  118. package/dist/server/routes/sync-api.d.ts +26 -0
  119. package/dist/server/routes/sync-api.js +757 -0
  120. package/dist/server/routes/sync-api.js.map +1 -0
  121. package/dist/server/routes/ws.d.ts +4 -2
  122. package/dist/server/routes/ws.js +100 -4
  123. package/dist/server/routes/ws.js.map +1 -1
  124. package/dist/server/session-manager.d.ts +40 -0
  125. package/dist/server/session-manager.js +132 -0
  126. package/dist/server/session-manager.js.map +1 -0
  127. package/dist/server/ws-hub.d.ts +95 -1
  128. package/dist/server/ws-hub.js +192 -5
  129. package/dist/server/ws-hub.js.map +1 -1
  130. package/dist/server/yjs-manager.d.ts +59 -0
  131. package/dist/server/yjs-manager.js +194 -0
  132. package/dist/server/yjs-manager.js.map +1 -0
  133. package/dist/services/auth-service.d.ts +30 -2
  134. package/dist/services/auth-service.js +116 -11
  135. package/dist/services/auth-service.js.map +1 -1
  136. package/dist/services/git.d.ts +6 -0
  137. package/dist/services/git.js +32 -2
  138. package/dist/services/git.js.map +1 -1
  139. package/dist/services/sync/collection-sync.d.ts +73 -0
  140. package/dist/services/sync/collection-sync.js +726 -0
  141. package/dist/services/sync/collection-sync.js.map +1 -0
  142. package/dist/services/sync/commit.js +5 -20
  143. package/dist/services/sync/commit.js.map +1 -1
  144. package/dist/services/sync/data-fetcher.d.ts +31 -0
  145. package/dist/services/sync/data-fetcher.js +12 -0
  146. package/dist/services/sync/data-fetcher.js.map +1 -0
  147. package/dist/services/sync/entity-refresh.d.ts +30 -0
  148. package/dist/services/sync/entity-refresh.js +275 -0
  149. package/dist/services/sync/entity-refresh.js.map +1 -0
  150. package/dist/services/sync/frontmatter-extractor.d.ts +2 -2
  151. package/dist/services/sync/frontmatter-extractor.js +1 -2
  152. package/dist/services/sync/frontmatter-extractor.js.map +1 -1
  153. package/dist/services/sync/graph-match.js +1 -1
  154. package/dist/services/sync/graph-match.js.map +1 -1
  155. package/dist/services/sync/mcp-client.d.ts +16 -4
  156. package/dist/services/sync/mcp-client.js +34 -20
  157. package/dist/services/sync/mcp-client.js.map +1 -1
  158. package/dist/services/sync/prompts.js +1 -1
  159. package/dist/services/sync/reconciler.js +1 -2
  160. package/dist/services/sync/reconciler.js.map +1 -1
  161. package/dist/services/sync/rest-client.d.ts +40 -0
  162. package/dist/services/sync/rest-client.js +100 -0
  163. package/dist/services/sync/rest-client.js.map +1 -0
  164. package/dist/services/sync/source-config.d.ts +23 -1
  165. package/dist/services/sync/source-config.js +112 -16
  166. package/dist/services/sync/source-config.js.map +1 -1
  167. package/dist/services/sync/source-definitions/asana.d.ts +3 -4
  168. package/dist/services/sync/source-definitions/asana.js +7 -13
  169. package/dist/services/sync/source-definitions/asana.js.map +1 -1
  170. package/dist/services/sync/source-definitions/definitions.d.ts +5 -18
  171. package/dist/services/sync/source-definitions/definitions.js +4 -22
  172. package/dist/services/sync/source-definitions/definitions.js.map +1 -1
  173. package/dist/services/sync/source-definitions/granola.d.ts +1 -1
  174. package/dist/services/sync/source-definitions/granola.js +11 -18
  175. package/dist/services/sync/source-definitions/granola.js.map +1 -1
  176. package/dist/services/sync/source-definitions/linear.d.ts +1 -1
  177. package/dist/services/sync/source-definitions/linear.js +17 -15
  178. package/dist/services/sync/source-definitions/linear.js.map +1 -1
  179. package/dist/services/sync/source-definitions/pipedrive.d.ts +1 -1
  180. package/dist/services/sync/source-definitions/pipedrive.js +6 -15
  181. package/dist/services/sync/source-definitions/pipedrive.js.map +1 -1
  182. package/dist/services/sync/staging.js +1 -2
  183. package/dist/services/sync/staging.js.map +1 -1
  184. package/dist/services/sync/structured-extractor.d.ts +8 -2
  185. package/dist/services/sync/structured-extractor.js +243 -35
  186. package/dist/services/sync/structured-extractor.js.map +1 -1
  187. package/dist/services/sync/types.d.ts +192 -23
  188. package/dist/services/sync/unstructured-extractor.d.ts +1 -3
  189. package/dist/services/sync/unstructured-extractor.js +2 -14
  190. package/dist/services/sync/unstructured-extractor.js.map +1 -1
  191. package/dist/utils/git.d.ts +24 -20
  192. package/dist/utils/git.js +99 -65
  193. package/dist/utils/git.js.map +1 -1
  194. package/dist/utils/preflight.d.ts +1 -15
  195. package/dist/utils/preflight.js +1 -35
  196. package/dist/utils/preflight.js.map +1 -1
  197. package/dist/web/_app/immutable/assets/0.CupILLQs.css +1 -0
  198. package/dist/web/_app/immutable/assets/3.CtJi4Cy9.css +1 -0
  199. package/dist/web/_app/immutable/assets/5.CydFyZSu.css +1 -0
  200. package/dist/web/_app/immutable/assets/6.kqeOo0OW.css +1 -0
  201. package/dist/web/_app/immutable/assets/7.CseIx7qQ.css +1 -0
  202. package/dist/web/_app/immutable/assets/{8.Sm6jB3a0.css → 8.BYpFDZHK.css} +1 -1
  203. package/dist/web/_app/immutable/assets/AppShell.Ch_ef9hJ.css +1 -0
  204. package/dist/web/_app/immutable/assets/ChatPanel.CP-_8txt.css +1 -0
  205. package/dist/web/_app/immutable/chunks/0oxpWEgM.js +1 -0
  206. package/dist/web/_app/immutable/chunks/B1y7Wy5O.js +18 -0
  207. package/dist/web/_app/immutable/chunks/B7eduG_j.js +64 -0
  208. package/dist/web/_app/immutable/chunks/BBLgaWN8.js +1 -0
  209. package/dist/web/_app/immutable/chunks/BCB5cYCz.js +2 -0
  210. package/dist/web/_app/immutable/chunks/{aosHekRC.js → BPUy9_sS.js} +1 -1
  211. package/dist/web/_app/immutable/chunks/BVBRzmeQ.js +7 -0
  212. package/dist/web/_app/immutable/chunks/{CUzqHQY_.js → BXuvR8Ks.js} +2 -1
  213. package/dist/web/_app/immutable/chunks/BeBar3OL.js +1 -0
  214. package/dist/web/_app/immutable/chunks/BuOTIbJu.js +1 -0
  215. package/dist/web/_app/immutable/chunks/CLFba8FK.js +5 -0
  216. package/dist/web/_app/immutable/chunks/CQCkXCml.js +1 -0
  217. package/dist/web/_app/immutable/chunks/CXuhHL4d.js +1 -0
  218. package/dist/web/_app/immutable/chunks/Cg9NOuOl.js +27 -0
  219. package/dist/web/_app/immutable/chunks/Cs5oz2oJ.js +5 -0
  220. package/dist/web/_app/immutable/chunks/Cs_ROD7H.js +2 -0
  221. package/dist/web/_app/immutable/chunks/D2aTbzFm.js +3 -0
  222. package/dist/web/_app/immutable/chunks/D4FXhiC2.js +1 -0
  223. package/dist/web/_app/immutable/chunks/D4VHRYeB.js +1 -0
  224. package/dist/web/_app/immutable/chunks/DCGSm8Hl.js +1 -0
  225. package/dist/web/_app/immutable/chunks/DP09rP34.js +2 -0
  226. package/dist/web/_app/immutable/chunks/DiP47fAp.js +1 -0
  227. package/dist/web/_app/immutable/chunks/DptGlK8O.js +1 -0
  228. package/dist/web/_app/immutable/chunks/O0fx2ss6.js +1 -0
  229. package/dist/web/_app/immutable/chunks/xBRYfpah.js +1 -0
  230. package/dist/web/_app/immutable/entry/app.FgnywZP_.js +2 -0
  231. package/dist/web/_app/immutable/entry/start.Bsa-zlPf.js +1 -0
  232. package/dist/web/_app/immutable/nodes/0.D3SW-LMc.js +10 -0
  233. package/dist/web/_app/immutable/nodes/1.y0c5TQTP.js +1 -0
  234. package/dist/web/_app/immutable/nodes/2.BQfSep9-.js +1 -0
  235. package/dist/web/_app/immutable/nodes/3.CC4Y-xMM.js +11 -0
  236. package/dist/web/_app/immutable/nodes/4.Dp0Z-oPW.js +4 -0
  237. package/dist/web/_app/immutable/nodes/5.gjZ03DON.js +2 -0
  238. package/dist/web/_app/immutable/nodes/6.dRNIwcJQ.js +1 -0
  239. package/dist/web/_app/immutable/nodes/7.I4Gjes3o.js +2 -0
  240. package/dist/web/_app/immutable/nodes/8.Dj14D7uH.js +1 -0
  241. package/dist/web/_app/version.json +1 -1
  242. package/dist/web/index.html +10 -12
  243. package/package.json +4 -2
  244. package/dist/web/_app/immutable/assets/0.CF0XhAap.css +0 -1
  245. package/dist/web/_app/immutable/assets/3.BJy7pVXi.css +0 -1
  246. package/dist/web/_app/immutable/assets/4.Ad16uh9o.css +0 -1
  247. package/dist/web/_app/immutable/assets/6.Bm2i7O0j.css +0 -1
  248. package/dist/web/_app/immutable/assets/7.Cn2DG-J6.css +0 -1
  249. package/dist/web/_app/immutable/assets/AppShell.CztjTuKY.css +0 -1
  250. package/dist/web/_app/immutable/assets/ChatPanel.RFD5GGYI.css +0 -1
  251. package/dist/web/_app/immutable/assets/editor.CPAf2SRV.css +0 -1
  252. package/dist/web/_app/immutable/chunks/4QY4j-jX.js +0 -1
  253. package/dist/web/_app/immutable/chunks/B3Kdf1r4.js +0 -6
  254. package/dist/web/_app/immutable/chunks/BIo3H1KR.js +0 -2
  255. package/dist/web/_app/immutable/chunks/BJLM1w2L.js +0 -23
  256. package/dist/web/_app/immutable/chunks/BLCwEMdm.js +0 -1
  257. package/dist/web/_app/immutable/chunks/BSYvCVJt.js +0 -1
  258. package/dist/web/_app/immutable/chunks/Ba5JX1o9.js +0 -1
  259. package/dist/web/_app/immutable/chunks/Bj34y868.js +0 -64
  260. package/dist/web/_app/immutable/chunks/BrWpHgBJ.js +0 -1
  261. package/dist/web/_app/immutable/chunks/C3g_lwol.js +0 -1
  262. package/dist/web/_app/immutable/chunks/CXnPm09s.js +0 -1
  263. package/dist/web/_app/immutable/chunks/ClOTom10.js +0 -1
  264. package/dist/web/_app/immutable/chunks/CtT4aw_G.js +0 -1
  265. package/dist/web/_app/immutable/chunks/Dh_H7Owr.js +0 -18
  266. package/dist/web/_app/immutable/chunks/DnlgZ_Tk.js +0 -5
  267. package/dist/web/_app/immutable/chunks/DtVH--hH.js +0 -6
  268. package/dist/web/_app/immutable/chunks/Dzd9kdLj.js +0 -2
  269. package/dist/web/_app/immutable/chunks/L91a_BGe.js +0 -1
  270. package/dist/web/_app/immutable/chunks/bHAllEMt.js +0 -1
  271. package/dist/web/_app/immutable/entry/app.CdrgaaFb.js +0 -2
  272. package/dist/web/_app/immutable/entry/start.t9LMjt48.js +0 -1
  273. package/dist/web/_app/immutable/nodes/0.P-Xfebn4.js +0 -2
  274. package/dist/web/_app/immutable/nodes/1.DiZlq1e6.js +0 -1
  275. package/dist/web/_app/immutable/nodes/2.ByIZ5J2p.js +0 -1
  276. package/dist/web/_app/immutable/nodes/3.D7JhktsZ.js +0 -1
  277. package/dist/web/_app/immutable/nodes/4.BtMeWbPx.js +0 -16
  278. package/dist/web/_app/immutable/nodes/5.CCYG1pbQ.js +0 -4
  279. package/dist/web/_app/immutable/nodes/6.CL_Ah04j.js +0 -2
  280. package/dist/web/_app/immutable/nodes/7.BMTaosAj.js +0 -1
  281. package/dist/web/_app/immutable/nodes/8.mrPg67cz.js +0 -1
  282. /package/dist/web/_app/immutable/assets/{5.BhKgiXd2.css → 4.BhKgiXd2.css} +0 -0
@@ -412,46 +412,122 @@ body.sg-dragging iframe { pointer-events: none; }
412
412
  color: var(--color-text-secondary);
413
413
  }
414
414
 
415
- /* ── Hover tooltips ───────────────────────────────────── */
416
- .sg-chrome-tooltip-anchor {
417
- position: relative;
418
- }
419
- .sg-chrome-tooltip-popup {
415
+ /* ── Commit Confirmation Modal ────────────────────────── */
416
+ /* Matches shared Dialog component tokens (dialog-content.svelte) */
417
+ .sg-chrome-modal-overlay {
420
418
  display: none;
421
- position: absolute;
422
- bottom: calc(100% + 8px);
423
- left: 50%;
424
- transform: translateX(-50%);
425
- background: var(--color-bg-surface);
426
- border: 1px solid var(--color-border);
419
+ position: fixed;
420
+ inset: 0;
421
+ background: rgba(0, 0, 0, 0.6);
422
+ z-index: 1000;
423
+ align-items: flex-start;
424
+ justify-content: center;
425
+ padding-top: 80px;
426
+ }
427
+ .sg-chrome-modal-overlay.open {
428
+ display: flex;
429
+ }
430
+ .sg-chrome-modal {
431
+ background: var(--color-bg-surface, var(--surface));
432
+ border: 1px solid var(--color-border-strong, var(--border));
433
+ border-radius: 12px;
434
+ width: fit-content;
435
+ min-width: 320px;
436
+ max-width: min(640px, 90vw);
437
+ max-height: calc(100vh - 120px);
438
+ display: flex;
439
+ flex-direction: column;
440
+ overflow: hidden;
441
+ box-shadow: 0 24px 80px rgba(0, 0, 0, 0.5);
442
+ }
443
+ .sg-chrome-modal-header {
444
+ display: flex;
445
+ align-items: center;
446
+ justify-content: space-between;
447
+ padding: 20px 24px 0;
448
+ flex-shrink: 0;
449
+ }
450
+ .sg-chrome-modal-title {
451
+ font-size: 16px;
452
+ font-weight: 500;
453
+ color: var(--color-text, var(--text));
454
+ }
455
+ .sg-chrome-modal-close {
456
+ display: flex;
457
+ align-items: center;
458
+ justify-content: center;
459
+ width: 28px;
460
+ height: 28px;
461
+ border: none;
427
462
  border-radius: 6px;
428
- padding: 8px 12px;
429
- min-width: 200px;
430
- max-width: 420px;
431
- max-height: 240px;
463
+ background: transparent;
464
+ color: var(--color-text-tertiary);
465
+ font-size: 16px;
466
+ cursor: pointer;
467
+ transition: color 0.15s, background 0.15s;
468
+ }
469
+ .sg-chrome-modal-close:hover {
470
+ color: var(--color-text, var(--text));
471
+ background: var(--color-bg-hover, var(--bg-hover));
472
+ }
473
+ .sg-chrome-modal-body {
474
+ padding: 12px 24px 20px;
432
475
  overflow-y: auto;
433
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
434
- z-index: 100;
435
- font-size: 11px;
476
+ flex: 1;
477
+ min-height: 0;
478
+ font-size: 12px;
479
+ line-height: 1.6;
480
+ }
481
+ .sg-chrome-modal-footer {
482
+ display: flex;
483
+ align-items: center;
484
+ justify-content: flex-end;
485
+ gap: 8px;
486
+ padding: 16px 24px;
487
+ border-top: 1px solid var(--color-border, var(--border));
488
+ flex-shrink: 0;
489
+ }
490
+
491
+ /* Small modal variant (revert confirmation) */
492
+ .sg-chrome-modal-sm {
493
+ width: 420px;
494
+ min-width: 0;
495
+ }
496
+ .sg-chrome-modal-message {
497
+ font-size: 13px;
498
+ color: var(--color-text-secondary);
436
499
  line-height: 1.5;
500
+ margin: 0;
437
501
  }
438
- .sg-chrome-tooltip-anchor:hover .sg-chrome-tooltip-popup:not(:empty) {
439
- display: block;
502
+
503
+ /* Destructive button (used in revert modal) */
504
+ .sg-chrome-btn-destructive {
505
+ display: inline-flex;
506
+ align-items: center;
507
+ height: 24px;
508
+ padding: 0 12px;
509
+ border: none;
510
+ background: var(--color-destructive, #ea4335);
511
+ color: white;
512
+ font-family: inherit;
513
+ font-size: 12px;
514
+ font-weight: 500;
515
+ cursor: pointer;
516
+ border-radius: 4px;
517
+ transition: background 0.15s;
440
518
  }
441
- .sg-chrome-tooltip-popup-right {
442
- left: auto;
443
- right: 0;
444
- transform: none;
445
- min-width: auto;
446
- width: max-content;
519
+ .sg-chrome-btn-destructive:hover:not(:disabled) {
520
+ background: color-mix(in srgb, var(--color-destructive, #ea4335) 85%, black);
447
521
  }
522
+ .sg-chrome-btn-destructive:disabled { opacity: 0.7; cursor: default; }
523
+
524
+ /* ── File list items (used in commit modal) ──────────── */
448
525
  .sg-chrome-tooltip-file {
449
526
  color: var(--color-text-secondary);
450
- white-space: nowrap;
451
- overflow: hidden;
452
527
  display: flex;
453
528
  align-items: center;
454
529
  gap: 0;
530
+ white-space: nowrap;
455
531
  }
456
532
  .sg-chrome-tooltip-file .sg-path-sep {
457
533
  flex-shrink: 0;
@@ -550,6 +626,44 @@ body.sg-dragging iframe { pointer-events: none; }
550
626
  margin: 0 4px;
551
627
  }
552
628
 
629
+ /* ── Collaborator pills (footer right) ─────────────────── */
630
+ .sg-chrome-collaborators {
631
+ display: flex;
632
+ align-items: center;
633
+ gap: 6px;
634
+ }
635
+
636
+ .sg-chrome-collaborator {
637
+ display: inline-flex;
638
+ align-items: center;
639
+ gap: 5px;
640
+ height: 20px;
641
+ padding: 0 7px 0 3px;
642
+ border-radius: 10px;
643
+ background: var(--color-surface);
644
+ border: 1px solid var(--color-border);
645
+ }
646
+
647
+ .sg-chrome-collaborator-avatar {
648
+ display: inline-flex;
649
+ align-items: center;
650
+ justify-content: center;
651
+ width: 14px;
652
+ height: 14px;
653
+ border-radius: 50%;
654
+ background: var(--color-accent);
655
+ color: #fff;
656
+ font-size: 9px;
657
+ font-weight: 600;
658
+ flex-shrink: 0;
659
+ }
660
+
661
+ .sg-chrome-collaborator-name {
662
+ font-size: 11px;
663
+ color: var(--color-text-secondary);
664
+ white-space: nowrap;
665
+ }
666
+
553
667
  /* ── Focus rings ───────────────────────────────────────── */
554
668
  .sg-chrome-btn:focus-visible,
555
669
  .sg-chrome-theme-toggle:focus-visible,
@@ -44,6 +44,10 @@
44
44
  return e;
45
45
  }
46
46
 
47
+ function titleCase(str) {
48
+ return str.replace(/-/g, ' ').replace(/\b\w/g, function (c) { return c.toUpperCase(); });
49
+ }
50
+
47
51
  // ── Theme ───────────────────────────────────────────────
48
52
  function getTheme() {
49
53
  return document.documentElement.dataset.theme || localStorage.getItem('theme') || 'dark';
@@ -144,7 +148,7 @@
144
148
  if (e.key === 'Escape') overflowMenu.classList.remove('open');
145
149
  });
146
150
 
147
- // ── Build Footer (matches StatusBar.svelte) ────────────
151
+ // ── Build Footer ────────────────────────────────────────
148
152
  var footer = el('footer', 'sg-chrome-footer');
149
153
 
150
154
  // Left: theme toggle + workspace stats
@@ -160,7 +164,11 @@
160
164
  footerLeft.appendChild(statsEl);
161
165
  footer.appendChild(footerLeft);
162
166
 
163
- // Git commit/push/pull buttons removed — saves auto-commit on the server
167
+ // Right: collaborators
168
+ var footerRight = el('div', 'sg-chrome-footer-right');
169
+ var collaboratorsEl = el('span', 'sg-chrome-collaborators');
170
+ footerRight.appendChild(collaboratorsEl);
171
+ footer.appendChild(footerRight);
164
172
 
165
173
  // ── Inject into DOM ─────────────────────────────────────
166
174
  if (!workspaceMode) {
@@ -183,36 +191,23 @@
183
191
  body.appendChild(footer);
184
192
  }
185
193
 
186
- // ── Stats ───────────────────────────────────────────────
187
- var stats = { entities: 0, links: 0 };
188
-
189
- function updateStatsUI() {
190
- if (stats.entities > 0) {
191
- var e = stats.entities;
192
- var l = stats.links;
193
- statsEl.innerHTML =
194
- '<span class="sg-chrome-stat">' + e.toLocaleString() + (e === 1 ? ' entity' : ' entities') + '</span>' +
195
- '<span class="sg-chrome-stat-sep">|</span>' +
196
- '<span class="sg-chrome-stat">' + l.toLocaleString() + (l === 1 ? ' link' : ' links') + '</span>';
197
- }
198
- }
199
-
194
+ // ── Stats ────────────────────────────────────────────────
200
195
  function fetchStats() {
201
196
  fetch('/api/stats').then(function (r) { return r.json(); }).then(function (data) {
202
- stats = data;
203
- updateStatsUI();
197
+ if (data.entities > 0) {
198
+ var e = data.entities;
199
+ var l = data.links;
200
+ statsEl.innerHTML =
201
+ '<span class="sg-chrome-stat">' + e.toLocaleString() + (e === 1 ? ' entity' : ' entities') + '</span>' +
202
+ '<span class="sg-chrome-stat-sep">|</span>' +
203
+ '<span class="sg-chrome-stat">' + l.toLocaleString() + (l === 1 ? ' link' : ' links') + '</span>';
204
+ }
204
205
  }).catch(function () { /* silently fail */ });
205
206
  }
206
207
 
207
- // Initial fetch + poll every 60s
208
208
  fetchStats();
209
209
  setInterval(fetchStats, 60000);
210
210
 
211
- // Refresh stats when Svelte store signals a save
212
- window.addEventListener('studiograph:git-refresh', function () {
213
- fetchStats();
214
- });
215
-
216
211
  // ── Event System ────────────────────────────────────────
217
212
  var listeners = {};
218
213
 
@@ -222,6 +217,9 @@
222
217
  });
223
218
  }
224
219
 
220
+ // ── Save Status Auto-clear ───────────────────────────────
221
+ var saveStatusTimer = null;
222
+
225
223
  // ── Public API ──────────────────────────────────────────
226
224
  window.StudioChrome = {
227
225
  on: function (event, fn) {
@@ -255,11 +253,20 @@
255
253
  * Set save status indicator.
256
254
  * @param {string} text - Status text to display
257
255
  * @param {string} [type] - 'saving'|'saved'|'error'|'' — controls styling
256
+ * @param {number} [clearAfterMs] - auto-clear after this many ms (default 2000 for 'saved')
258
257
  */
259
- setSaveStatus: function (text, type) {
258
+ setSaveStatus: function (text, type, clearAfterMs) {
260
259
  type = type || '';
261
260
  saveStatusEl.textContent = text || '';
262
261
  saveStatusEl.className = 'sg-chrome-save-status' + (type === 'error' ? ' sg-chrome-save-error' : '');
262
+ if (saveStatusTimer) clearTimeout(saveStatusTimer);
263
+ var ms = clearAfterMs != null ? clearAfterMs : (type === 'saved' ? 2000 : 0);
264
+ if (ms > 0) {
265
+ saveStatusTimer = setTimeout(function () {
266
+ saveStatusEl.textContent = '';
267
+ saveStatusEl.className = 'sg-chrome-save-status';
268
+ }, ms);
269
+ }
263
270
  },
264
271
 
265
272
  refreshStatus: function () {
@@ -270,6 +277,25 @@
270
277
  fetchStats();
271
278
  },
272
279
 
280
+ /**
281
+ * Update the collaborators list in the footer right.
282
+ * @param {Array<{id: string, name: string, color?: string}>} users
283
+ */
284
+ setCollaborators: function (users) {
285
+ collaboratorsEl.innerHTML = '';
286
+ if (!users || users.length === 0) return;
287
+ users.forEach(function (u) {
288
+ var pill = el('span', 'sg-chrome-collaborator');
289
+ var avatar = el('span', 'sg-chrome-collaborator-avatar');
290
+ avatar.textContent = u.name[0].toUpperCase();
291
+ pill.appendChild(avatar);
292
+ var name = el('span', 'sg-chrome-collaborator-name');
293
+ name.textContent = u.name;
294
+ pill.appendChild(name);
295
+ collaboratorsEl.appendChild(pill);
296
+ });
297
+ },
298
+
273
299
  addMenuItem: function (opts) {
274
300
  var btn = el('button', 'sg-chrome-menu-item' + (opts.danger ? ' sg-chrome-danger' : ''),
275
301
  (opts.icon || '') + ' ' + esc(opts.label));
@@ -0,0 +1,70 @@
1
+ /**
2
+ * OT Collab Authority — central document authority for @codemirror/collab.
3
+ *
4
+ * Manages one document per entity. Each document tracks:
5
+ * - doc: the current document text (string)
6
+ * - updates: array of serialized ChangeSet + clientID pairs
7
+ * - version: current version number (= updates.length)
8
+ * - pending: debounce timer for disk persistence
9
+ *
10
+ * Lifecycle:
11
+ * Created when first client connects to an entity.
12
+ * Seeded from disk content via graph.get().
13
+ * Updated when clients push changes.
14
+ * Persisted to disk via graph.update() on debounce.
15
+ * Evicted after all clients disconnect + idle timeout.
16
+ *
17
+ * No binary state files, no vector clocks, no CRDT — just a version counter.
18
+ * If a client reconnects after eviction, it fetches the current doc fresh.
19
+ */
20
+ import type { WorkspaceManager } from '../core/workspace-manager.js';
21
+ import type { SessionManager } from './session-manager.js';
22
+ interface Update {
23
+ changes: any;
24
+ clientID: string;
25
+ }
26
+ export declare class CollabAuthority {
27
+ private workspaceManager;
28
+ private sessionManager;
29
+ private docs;
30
+ constructor(workspaceManager: WorkspaceManager, sessionManager: SessionManager);
31
+ /**
32
+ * Get or create a document for the given entity.
33
+ * Returns the current document text and version.
34
+ */
35
+ getDocument(docName: string): {
36
+ version: number;
37
+ doc: string;
38
+ };
39
+ /**
40
+ * Pull updates since clientVersion.
41
+ * Returns serialized updates the client hasn't seen yet.
42
+ */
43
+ pullUpdates(docName: string, clientVersion: number): Update[];
44
+ /**
45
+ * Push updates from a client.
46
+ * Returns true if accepted, false if version mismatch (client must pull first).
47
+ */
48
+ pushUpdates(docName: string, clientVersion: number, updates: Array<{
49
+ changes: any;
50
+ clientID: string;
51
+ }>, gitUser?: {
52
+ id: string;
53
+ name: string;
54
+ email: string;
55
+ }): boolean;
56
+ /** Track a client joining a document. */
57
+ clientJoin(docName: string, clientId: string): void;
58
+ /** Track a client leaving a document. Persist immediately and schedule eviction if no clients remain. */
59
+ clientLeave(docName: string, clientId: string): void;
60
+ /** Persist all dirty documents immediately (for server shutdown). */
61
+ flushAll(): Promise<void>;
62
+ /** Notify the authority that an entity was updated externally (e.g., refresh from source). */
63
+ externalUpdate(docName: string, newContent: string): void;
64
+ destroy(): void;
65
+ private getOrCreate;
66
+ private schedulePersist;
67
+ private persistToDisk;
68
+ private scheduleEvict;
69
+ }
70
+ export {};
@@ -0,0 +1,218 @@
1
+ /**
2
+ * OT Collab Authority — central document authority for @codemirror/collab.
3
+ *
4
+ * Manages one document per entity. Each document tracks:
5
+ * - doc: the current document text (string)
6
+ * - updates: array of serialized ChangeSet + clientID pairs
7
+ * - version: current version number (= updates.length)
8
+ * - pending: debounce timer for disk persistence
9
+ *
10
+ * Lifecycle:
11
+ * Created when first client connects to an entity.
12
+ * Seeded from disk content via graph.get().
13
+ * Updated when clients push changes.
14
+ * Persisted to disk via graph.update() on debounce.
15
+ * Evicted after all clients disconnect + idle timeout.
16
+ *
17
+ * No binary state files, no vector clocks, no CRDT — just a version counter.
18
+ * If a client reconnects after eviction, it fetches the current doc fresh.
19
+ */
20
+ import { ChangeSet, Text } from '@codemirror/state';
21
+ const PERSIST_DEBOUNCE_MS = 2000;
22
+ const EVICT_AFTER_MS = 30_000; // 30s after last client disconnects
23
+ export class CollabAuthority {
24
+ workspaceManager;
25
+ sessionManager;
26
+ docs = new Map();
27
+ constructor(workspaceManager, sessionManager) {
28
+ this.workspaceManager = workspaceManager;
29
+ this.sessionManager = sessionManager;
30
+ }
31
+ /**
32
+ * Get or create a document for the given entity.
33
+ * Returns the current document text and version.
34
+ */
35
+ getDocument(docName) {
36
+ const authority = this.getOrCreate(docName);
37
+ const result = { version: authority.updates.length, doc: authority.doc.toString() };
38
+ console.log(`[collab-authority] getDocument ${docName}: v${result.version}, ${result.doc.length} chars`);
39
+ return result;
40
+ }
41
+ /**
42
+ * Pull updates since clientVersion.
43
+ * Returns serialized updates the client hasn't seen yet.
44
+ */
45
+ pullUpdates(docName, clientVersion) {
46
+ const authority = this.docs.get(docName);
47
+ if (!authority)
48
+ return [];
49
+ if (clientVersion > authority.updates.length)
50
+ return [];
51
+ return authority.updates.slice(clientVersion);
52
+ }
53
+ /**
54
+ * Push updates from a client.
55
+ * Returns true if accepted, false if version mismatch (client must pull first).
56
+ */
57
+ pushUpdates(docName, clientVersion, updates, gitUser) {
58
+ const authority = this.getOrCreate(docName);
59
+ if (clientVersion !== authority.updates.length)
60
+ return false;
61
+ for (const update of updates) {
62
+ const changes = ChangeSet.fromJSON(update.changes);
63
+ authority.updates.push({ changes: update.changes, clientID: update.clientID });
64
+ authority.doc = changes.apply(authority.doc);
65
+ }
66
+ authority.dirty = true;
67
+ console.log(`[collab-authority] pushUpdates ${docName}: accepted ${updates.length} update(s), now v${authority.updates.length}, doc ${authority.doc.length} chars`);
68
+ this.schedulePersist(docName, gitUser);
69
+ return true;
70
+ }
71
+ /** Track a client joining a document. */
72
+ clientJoin(docName, clientId) {
73
+ const authority = this.getOrCreate(docName);
74
+ authority.clients.add(clientId);
75
+ // Cancel eviction if a client reconnects
76
+ if (authority.evictTimer) {
77
+ clearTimeout(authority.evictTimer);
78
+ authority.evictTimer = null;
79
+ }
80
+ }
81
+ /** Track a client leaving a document. Persist immediately and schedule eviction if no clients remain. */
82
+ clientLeave(docName, clientId) {
83
+ const authority = this.docs.get(docName);
84
+ if (!authority)
85
+ return;
86
+ authority.clients.delete(clientId);
87
+ console.log(`[collab-authority] clientLeave ${docName}: client=${clientId}, remaining=${authority.clients.size}, dirty=${authority.dirty}`);
88
+ // Persist immediately on client leave so navigating back reads fresh content from disk
89
+ if (authority.dirty) {
90
+ if (authority.persistTimer) {
91
+ clearTimeout(authority.persistTimer);
92
+ authority.persistTimer = null;
93
+ }
94
+ this.persistToDisk(docName, authority);
95
+ console.log(`[collab-authority] clientLeave ${docName}: persisted to disk (${authority.doc.length} chars)`);
96
+ }
97
+ if (authority.clients.size === 0) {
98
+ this.scheduleEvict(docName);
99
+ }
100
+ }
101
+ /** Persist all dirty documents immediately (for server shutdown). */
102
+ async flushAll() {
103
+ for (const [docName, authority] of this.docs) {
104
+ if (authority.persistTimer) {
105
+ clearTimeout(authority.persistTimer);
106
+ authority.persistTimer = null;
107
+ }
108
+ if (authority.dirty) {
109
+ this.persistToDisk(docName, authority);
110
+ }
111
+ }
112
+ }
113
+ /** Notify the authority that an entity was updated externally (e.g., refresh from source). */
114
+ externalUpdate(docName, newContent) {
115
+ const authority = this.docs.get(docName);
116
+ if (!authority)
117
+ return; // not loaded — next getOrCreate will read from disk
118
+ // Replace the authority doc. Connected clients will get the new content
119
+ // via an entity_change event → invalidateAll() on the client side.
120
+ authority.doc = Text.of(newContent.split('\n'));
121
+ authority.updates = []; // reset history — clients must re-fetch
122
+ authority.dirty = false; // already written to disk by the caller
123
+ }
124
+ destroy() {
125
+ for (const [, authority] of this.docs) {
126
+ if (authority.persistTimer)
127
+ clearTimeout(authority.persistTimer);
128
+ if (authority.evictTimer)
129
+ clearTimeout(authority.evictTimer);
130
+ }
131
+ this.docs.clear();
132
+ }
133
+ // ── Internal ──────────────────────────────────────────────────────────────
134
+ getOrCreate(docName) {
135
+ const existing = this.docs.get(docName);
136
+ if (existing)
137
+ return existing;
138
+ // Seed from disk
139
+ const [repo, entityType, entityId] = docName.split('/');
140
+ let content = '';
141
+ try {
142
+ const graph = this.workspaceManager.getGraph(repo);
143
+ const entity = graph.get(entityType, entityId);
144
+ content = entity?.document?.content ?? '';
145
+ }
146
+ catch {
147
+ // Entity not found — start with empty doc
148
+ }
149
+ const authority = {
150
+ doc: Text.of(content.split('\n')),
151
+ updates: [],
152
+ clients: new Set(),
153
+ dirty: false,
154
+ persistTimer: null,
155
+ evictTimer: null,
156
+ };
157
+ this.docs.set(docName, authority);
158
+ console.log(`[collab-authority] getOrCreate ${docName}: seeded from disk, ${content.length} chars`);
159
+ return authority;
160
+ }
161
+ schedulePersist(docName, gitUser) {
162
+ const authority = this.docs.get(docName);
163
+ if (!authority)
164
+ return;
165
+ if (authority.persistTimer)
166
+ clearTimeout(authority.persistTimer);
167
+ authority.persistTimer = setTimeout(() => {
168
+ authority.persistTimer = null;
169
+ this.persistToDisk(docName, authority, gitUser);
170
+ }, PERSIST_DEBOUNCE_MS);
171
+ }
172
+ persistToDisk(docName, authority, gitUser) {
173
+ if (!authority.dirty)
174
+ return;
175
+ const [repo, entityType, entityId] = docName.split('/');
176
+ try {
177
+ const graph = this.workspaceManager.getGraph(repo);
178
+ // Check if content actually changed
179
+ const existing = graph.get(entityType, entityId);
180
+ const existingBody = existing?.document?.content ?? '';
181
+ const newBody = authority.doc.toString();
182
+ console.log(`[collab-authority] persistToDisk ${docName}: disk=${existingBody.length} chars, authority=${newBody.length} chars, same=${newBody === existingBody}`);
183
+ if (newBody === existingBody) {
184
+ authority.dirty = false;
185
+ return;
186
+ }
187
+ graph.update({
188
+ entityType: entityType,
189
+ entityId,
190
+ content: newBody,
191
+ skipCommit: true,
192
+ });
193
+ const user = gitUser ?? { id: 'collab', name: 'Collab', email: 'collab@studiograph' };
194
+ this.sessionManager.markDirty(repo, user, entityType, entityId, existing?.path);
195
+ authority.dirty = false;
196
+ }
197
+ catch (err) {
198
+ console.warn(`[collab-authority] Failed to persist ${docName}:`, err.message);
199
+ }
200
+ }
201
+ scheduleEvict(docName) {
202
+ const authority = this.docs.get(docName);
203
+ if (!authority)
204
+ return;
205
+ if (authority.evictTimer)
206
+ clearTimeout(authority.evictTimer);
207
+ authority.evictTimer = setTimeout(() => {
208
+ // Persist any remaining changes before evicting
209
+ if (authority.dirty) {
210
+ this.persistToDisk(docName, authority);
211
+ }
212
+ if (authority.persistTimer)
213
+ clearTimeout(authority.persistTimer);
214
+ this.docs.delete(docName);
215
+ }, EVICT_AFTER_MS);
216
+ }
217
+ }
218
+ //# sourceMappingURL=collab-authority.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collab-authority.js","sourceRoot":"","sources":["../../src/server/collab-authority.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * CollabServer — real-time co-editing via Hocuspocus (Yjs CRDT).
3
+ *
4
+ * Each entity body is a shared Y.Text document named "{repo}/{entityType}/{entityId}".
5
+ * Frontmatter is NOT part of the shared document (edited via property inputs separately).
6
+ *
7
+ * - onAuthenticate: verifies __sg_token cookie or Hocuspocus token param
8
+ * - onLoadDocument: seeds Y.Text from the entity's body on disk (first connect only)
9
+ * - onStoreDocument: persists the merged body back to disk after debounce (2s idle)
10
+ */
11
+ import type { IncomingMessage } from 'node:http';
12
+ import type { WebSocket } from 'ws';
13
+ import type { WorkspaceManager } from '../core/workspace-manager.js';
14
+ import type { SessionManager } from './session-manager.js';
15
+ import type { AuthService } from '../services/auth-service.js';
16
+ export declare class CollabServer {
17
+ private workspacePath;
18
+ private workspaceManager;
19
+ private sessionManager;
20
+ private authService;
21
+ private hocus;
22
+ constructor(workspacePath: string, workspaceManager: WorkspaceManager, sessionManager: SessionManager, authService: AuthService);
23
+ private onAuthenticate;
24
+ private yjsStatePath;
25
+ private onLoadDocument;
26
+ private onStoreDocument;
27
+ handleConnection(socket: WebSocket, req: IncomingMessage): void;
28
+ destroy(): void;
29
+ }