groove-dev 0.27.143 → 0.27.145

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 (251) hide show
  1. package/CLAUDE.md +0 -7
  2. package/node_modules/@groove-dev/cli/package.json +1 -1
  3. package/node_modules/@groove-dev/daemon/package.json +1 -1
  4. package/node_modules/@groove-dev/daemon/src/api.js +1086 -6532
  5. package/node_modules/@groove-dev/daemon/src/conversations.js +18 -48
  6. package/node_modules/@groove-dev/daemon/src/gateways/manager.js +35 -1
  7. package/node_modules/@groove-dev/daemon/src/index.js +3 -0
  8. package/node_modules/@groove-dev/daemon/src/journalist.js +23 -13
  9. package/node_modules/@groove-dev/daemon/src/mlx-server.js +365 -0
  10. package/node_modules/@groove-dev/daemon/src/model-lab.js +308 -12
  11. package/node_modules/@groove-dev/daemon/src/pm.js +1 -1
  12. package/node_modules/@groove-dev/daemon/src/process.js +2 -2
  13. package/node_modules/@groove-dev/daemon/src/providers/local.js +36 -8
  14. package/node_modules/@groove-dev/daemon/src/registry.js +21 -5
  15. package/node_modules/@groove-dev/daemon/src/routes/agents.js +812 -0
  16. package/node_modules/@groove-dev/daemon/src/routes/coordination.js +318 -0
  17. package/node_modules/@groove-dev/daemon/src/routes/files.js +751 -0
  18. package/node_modules/@groove-dev/daemon/src/routes/integrations.js +485 -0
  19. package/node_modules/@groove-dev/daemon/src/routes/network.js +1784 -0
  20. package/node_modules/@groove-dev/daemon/src/routes/providers.js +755 -0
  21. package/node_modules/@groove-dev/daemon/src/routes/schedules.js +110 -0
  22. package/node_modules/@groove-dev/daemon/src/routes/teams.js +650 -0
  23. package/node_modules/@groove-dev/daemon/src/scheduler.js +456 -24
  24. package/node_modules/@groove-dev/daemon/src/teams.js +1 -1
  25. package/node_modules/@groove-dev/daemon/src/validate.js +38 -1
  26. package/node_modules/@groove-dev/daemon/templates/mlx-setup.json +12 -0
  27. package/node_modules/@groove-dev/daemon/templates/tgi-setup.json +1 -1
  28. package/node_modules/@groove-dev/daemon/templates/vllm-setup.json +1 -1
  29. package/node_modules/@groove-dev/daemon/test/introducer.test.js +3 -3
  30. package/node_modules/@groove-dev/daemon/test/journalist.test.js +7 -10
  31. package/node_modules/@groove-dev/daemon/test/registry.test.js +38 -0
  32. package/node_modules/@groove-dev/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  33. package/node_modules/@groove-dev/gui/dist/assets/index-C0pztKBn.css +1 -0
  34. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  35. package/node_modules/@groove-dev/gui/package.json +1 -1
  36. package/node_modules/@groove-dev/gui/src/{app.jsx → App.jsx} +0 -2
  37. package/node_modules/@groove-dev/gui/src/app.css +35 -0
  38. package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +1 -128
  39. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +210 -112
  40. package/node_modules/@groove-dev/gui/src/components/agents/agent-node.jsx +8 -13
  41. package/node_modules/@groove-dev/gui/src/components/agents/agent-panel.jsx +2 -70
  42. package/node_modules/@groove-dev/gui/src/components/agents/code-review.jsx +159 -122
  43. package/node_modules/@groove-dev/gui/src/components/agents/diff-viewer.jsx +23 -23
  44. package/node_modules/@groove-dev/gui/src/components/agents/journalist-panel.jsx +1 -1
  45. package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +2 -135
  46. package/node_modules/@groove-dev/gui/src/components/automations/automation-card.jsx +274 -0
  47. package/node_modules/@groove-dev/gui/src/components/automations/automation-wizard.jsx +1136 -0
  48. package/node_modules/@groove-dev/gui/src/components/chat/chat-header.jsx +2 -0
  49. package/node_modules/@groove-dev/gui/src/components/chat/chat-input.jsx +68 -66
  50. package/node_modules/@groove-dev/gui/src/components/chat/chat-view.jsx +4 -8
  51. package/node_modules/@groove-dev/gui/src/components/dashboard/activity-feed.jsx +3 -3
  52. package/node_modules/@groove-dev/gui/src/components/dashboard/cache-ring.jsx +5 -5
  53. package/node_modules/@groove-dev/gui/src/components/dashboard/context-gauges.jsx +6 -8
  54. package/node_modules/@groove-dev/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  55. package/node_modules/@groove-dev/gui/src/components/dashboard/intel-panel.jsx +238 -656
  56. package/node_modules/@groove-dev/gui/src/components/dashboard/kpi-card.jsx +3 -3
  57. package/node_modules/@groove-dev/gui/src/components/dashboard/routing-chart.jsx +3 -3
  58. package/node_modules/@groove-dev/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  59. package/node_modules/@groove-dev/gui/src/components/dashboard/token-chart.jsx +4 -4
  60. package/node_modules/@groove-dev/gui/src/components/lab/chat-playground.jsx +39 -31
  61. package/node_modules/@groove-dev/gui/src/components/lab/lab-assistant.jsx +316 -82
  62. package/node_modules/@groove-dev/gui/src/components/lab/metrics-panel.jsx +187 -32
  63. package/node_modules/@groove-dev/gui/src/components/lab/parameter-panel.jsx +200 -18
  64. package/node_modules/@groove-dev/gui/src/components/lab/preset-manager.jsx +17 -14
  65. package/node_modules/@groove-dev/gui/src/components/lab/runtime-config.jsx +335 -152
  66. package/node_modules/@groove-dev/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  67. package/node_modules/@groove-dev/gui/src/components/layout/activity-bar.jsx +2 -4
  68. package/node_modules/@groove-dev/gui/src/components/layout/terminal-panel.jsx +4 -2
  69. package/node_modules/@groove-dev/gui/src/components/layout/welcome-splash.jsx +137 -108
  70. package/node_modules/@groove-dev/gui/src/components/network/network-health.jsx +2 -2
  71. package/node_modules/@groove-dev/gui/src/components/network/performance-dashboard.jsx +4 -4
  72. package/node_modules/@groove-dev/gui/src/components/settings/ssh-wizard.jsx +81 -99
  73. package/node_modules/@groove-dev/gui/src/components/ui/sheet.jsx +5 -2
  74. package/node_modules/@groove-dev/gui/src/components/ui/slider.jsx +8 -8
  75. package/node_modules/@groove-dev/gui/src/lib/cron.js +64 -0
  76. package/node_modules/@groove-dev/gui/src/lib/status.js +25 -24
  77. package/node_modules/@groove-dev/gui/src/lib/theme-hex.js +1 -0
  78. package/node_modules/@groove-dev/gui/src/stores/groove.js +51 -3144
  79. package/node_modules/@groove-dev/gui/src/stores/helpers.js +10 -0
  80. package/node_modules/@groove-dev/gui/src/stores/slices/agents-slice.js +459 -0
  81. package/node_modules/@groove-dev/gui/src/stores/slices/automations-slice.js +96 -0
  82. package/node_modules/@groove-dev/gui/src/stores/slices/chat-slice.js +226 -0
  83. package/node_modules/@groove-dev/gui/src/stores/slices/editor-slice.js +285 -0
  84. package/node_modules/@groove-dev/gui/src/stores/slices/marketplace-slice.js +461 -0
  85. package/node_modules/@groove-dev/gui/src/stores/slices/network-slice.js +361 -0
  86. package/node_modules/@groove-dev/gui/src/stores/slices/preview-slice.js +109 -0
  87. package/node_modules/@groove-dev/gui/src/stores/slices/providers-slice.js +897 -0
  88. package/node_modules/@groove-dev/gui/src/stores/slices/teams-slice.js +413 -0
  89. package/node_modules/@groove-dev/gui/src/stores/slices/ui-slice.js +98 -0
  90. package/node_modules/@groove-dev/gui/src/views/agents.jsx +5 -5
  91. package/node_modules/@groove-dev/gui/src/views/dashboard.jsx +12 -13
  92. package/node_modules/@groove-dev/gui/src/views/marketplace.jsx +191 -3
  93. package/node_modules/@groove-dev/gui/src/views/model-lab.jsx +54 -12
  94. package/node_modules/@groove-dev/gui/src/views/models.jsx +419 -496
  95. package/node_modules/@groove-dev/gui/src/views/network.jsx +3 -3
  96. package/node_modules/@groove-dev/gui/src/views/settings.jsx +81 -94
  97. package/node_modules/@groove-dev/gui/src/views/teams.jsx +40 -483
  98. package/node_modules/axios/CHANGELOG.md +260 -0
  99. package/node_modules/axios/README.md +595 -223
  100. package/node_modules/axios/dist/axios.js +1460 -1090
  101. package/node_modules/axios/dist/axios.js.map +1 -1
  102. package/node_modules/axios/dist/axios.min.js +3 -3
  103. package/node_modules/axios/dist/axios.min.js.map +1 -1
  104. package/node_modules/axios/dist/browser/axios.cjs +1560 -1132
  105. package/node_modules/axios/dist/browser/axios.cjs.map +1 -1
  106. package/node_modules/axios/dist/esm/axios.js +1557 -1128
  107. package/node_modules/axios/dist/esm/axios.js.map +1 -1
  108. package/node_modules/axios/dist/esm/axios.min.js +2 -2
  109. package/node_modules/axios/dist/esm/axios.min.js.map +1 -1
  110. package/node_modules/axios/dist/node/axios.cjs +1594 -1057
  111. package/node_modules/axios/dist/node/axios.cjs.map +1 -1
  112. package/node_modules/axios/index.d.cts +40 -41
  113. package/node_modules/axios/index.d.ts +151 -227
  114. package/node_modules/axios/index.js +2 -0
  115. package/node_modules/axios/lib/adapters/adapters.js +4 -2
  116. package/node_modules/axios/lib/adapters/fetch.js +147 -16
  117. package/node_modules/axios/lib/adapters/http.js +306 -58
  118. package/node_modules/axios/lib/adapters/xhr.js +6 -2
  119. package/node_modules/axios/lib/core/Axios.js +7 -3
  120. package/node_modules/axios/lib/core/AxiosError.js +120 -34
  121. package/node_modules/axios/lib/core/AxiosHeaders.js +27 -25
  122. package/node_modules/axios/lib/core/buildFullPath.js +1 -1
  123. package/node_modules/axios/lib/core/dispatchRequest.js +19 -7
  124. package/node_modules/axios/lib/core/mergeConfig.js +21 -4
  125. package/node_modules/axios/lib/core/settle.js +7 -11
  126. package/node_modules/axios/lib/defaults/index.js +14 -9
  127. package/node_modules/axios/lib/env/data.js +1 -1
  128. package/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +1 -2
  129. package/node_modules/axios/lib/helpers/buildURL.js +1 -1
  130. package/node_modules/axios/lib/helpers/cookies.js +14 -2
  131. package/node_modules/axios/lib/helpers/estimateDataURLDecodedBytes.js +28 -1
  132. package/node_modules/axios/lib/helpers/formDataToJSON.js +3 -1
  133. package/node_modules/axios/lib/helpers/formDataToStream.js +3 -2
  134. package/node_modules/axios/lib/helpers/parseProtocol.js +1 -1
  135. package/node_modules/axios/lib/helpers/progressEventReducer.js +5 -5
  136. package/node_modules/axios/lib/helpers/resolveConfig.js +54 -18
  137. package/node_modules/axios/lib/helpers/shouldBypassProxy.js +74 -2
  138. package/node_modules/axios/lib/helpers/toFormData.js +10 -2
  139. package/node_modules/axios/lib/helpers/validator.js +3 -1
  140. package/node_modules/axios/lib/utils.js +33 -21
  141. package/node_modules/axios/package.json +17 -24
  142. package/node_modules/follow-redirects/README.md +7 -5
  143. package/node_modules/follow-redirects/index.js +24 -1
  144. package/node_modules/follow-redirects/package.json +1 -1
  145. package/package.json +1 -1
  146. package/packages/cli/package.json +1 -1
  147. package/packages/daemon/package.json +1 -1
  148. package/packages/daemon/src/api.js +1086 -6532
  149. package/packages/daemon/src/conversations.js +18 -48
  150. package/packages/daemon/src/gateways/manager.js +35 -1
  151. package/packages/daemon/src/index.js +3 -0
  152. package/packages/daemon/src/journalist.js +23 -13
  153. package/packages/daemon/src/mlx-server.js +365 -0
  154. package/packages/daemon/src/model-lab.js +308 -12
  155. package/packages/daemon/src/pm.js +1 -1
  156. package/packages/daemon/src/process.js +2 -2
  157. package/packages/daemon/src/providers/local.js +36 -8
  158. package/packages/daemon/src/registry.js +21 -5
  159. package/packages/daemon/src/routes/agents.js +812 -0
  160. package/packages/daemon/src/routes/coordination.js +318 -0
  161. package/packages/daemon/src/routes/files.js +751 -0
  162. package/packages/daemon/src/routes/integrations.js +485 -0
  163. package/packages/daemon/src/routes/network.js +1784 -0
  164. package/packages/daemon/src/routes/providers.js +755 -0
  165. package/packages/daemon/src/routes/schedules.js +110 -0
  166. package/packages/daemon/src/routes/teams.js +650 -0
  167. package/packages/daemon/src/scheduler.js +456 -24
  168. package/packages/daemon/src/teams.js +1 -1
  169. package/packages/daemon/src/validate.js +38 -1
  170. package/packages/daemon/templates/mlx-setup.json +12 -0
  171. package/packages/daemon/templates/tgi-setup.json +1 -1
  172. package/packages/daemon/templates/vllm-setup.json +1 -1
  173. package/packages/gui/dist/assets/index-Bxc0gU06.js +1006 -0
  174. package/packages/gui/dist/assets/index-C0pztKBn.css +1 -0
  175. package/packages/gui/dist/index.html +2 -2
  176. package/packages/gui/package.json +1 -1
  177. package/packages/gui/src/{app.jsx → App.jsx} +0 -2
  178. package/packages/gui/src/app.css +35 -0
  179. package/packages/gui/src/components/agents/agent-config.jsx +1 -128
  180. package/packages/gui/src/components/agents/agent-feed.jsx +210 -112
  181. package/packages/gui/src/components/agents/agent-node.jsx +8 -13
  182. package/packages/gui/src/components/agents/agent-panel.jsx +2 -70
  183. package/packages/gui/src/components/agents/code-review.jsx +159 -122
  184. package/packages/gui/src/components/agents/diff-viewer.jsx +23 -23
  185. package/packages/gui/src/components/agents/journalist-panel.jsx +1 -1
  186. package/packages/gui/src/components/agents/spawn-wizard.jsx +2 -135
  187. package/packages/gui/src/components/automations/automation-card.jsx +274 -0
  188. package/packages/gui/src/components/automations/automation-wizard.jsx +1136 -0
  189. package/packages/gui/src/components/chat/chat-header.jsx +2 -0
  190. package/packages/gui/src/components/chat/chat-input.jsx +68 -66
  191. package/packages/gui/src/components/chat/chat-view.jsx +4 -8
  192. package/packages/gui/src/components/dashboard/activity-feed.jsx +3 -3
  193. package/packages/gui/src/components/dashboard/cache-ring.jsx +5 -5
  194. package/packages/gui/src/components/dashboard/context-gauges.jsx +6 -8
  195. package/packages/gui/src/components/dashboard/fleet-panel.jsx +8 -14
  196. package/packages/gui/src/components/dashboard/intel-panel.jsx +238 -656
  197. package/packages/gui/src/components/dashboard/kpi-card.jsx +3 -3
  198. package/packages/gui/src/components/dashboard/routing-chart.jsx +3 -3
  199. package/packages/gui/src/components/dashboard/team-burn-panel.jsx +1 -1
  200. package/packages/gui/src/components/dashboard/token-chart.jsx +4 -4
  201. package/packages/gui/src/components/lab/chat-playground.jsx +39 -31
  202. package/packages/gui/src/components/lab/lab-assistant.jsx +316 -82
  203. package/packages/gui/src/components/lab/metrics-panel.jsx +187 -32
  204. package/packages/gui/src/components/lab/parameter-panel.jsx +200 -18
  205. package/packages/gui/src/components/lab/preset-manager.jsx +17 -14
  206. package/packages/gui/src/components/lab/runtime-config.jsx +335 -152
  207. package/packages/gui/src/components/lab/system-prompt-editor.jsx +10 -8
  208. package/packages/gui/src/components/layout/activity-bar.jsx +2 -4
  209. package/packages/gui/src/components/layout/terminal-panel.jsx +4 -2
  210. package/packages/gui/src/components/layout/welcome-splash.jsx +137 -108
  211. package/packages/gui/src/components/network/network-health.jsx +2 -2
  212. package/packages/gui/src/components/network/performance-dashboard.jsx +4 -4
  213. package/packages/gui/src/components/settings/ssh-wizard.jsx +81 -99
  214. package/packages/gui/src/components/ui/sheet.jsx +5 -2
  215. package/packages/gui/src/components/ui/slider.jsx +8 -8
  216. package/packages/gui/src/lib/cron.js +64 -0
  217. package/packages/gui/src/lib/status.js +25 -24
  218. package/packages/gui/src/lib/theme-hex.js +1 -0
  219. package/packages/gui/src/stores/groove.js +51 -3144
  220. package/packages/gui/src/stores/helpers.js +10 -0
  221. package/packages/gui/src/stores/slices/agents-slice.js +459 -0
  222. package/packages/gui/src/stores/slices/automations-slice.js +96 -0
  223. package/packages/gui/src/stores/slices/chat-slice.js +226 -0
  224. package/packages/gui/src/stores/slices/editor-slice.js +285 -0
  225. package/packages/gui/src/stores/slices/marketplace-slice.js +461 -0
  226. package/packages/gui/src/stores/slices/network-slice.js +361 -0
  227. package/packages/gui/src/stores/slices/preview-slice.js +109 -0
  228. package/packages/gui/src/stores/slices/providers-slice.js +897 -0
  229. package/packages/gui/src/stores/slices/teams-slice.js +413 -0
  230. package/packages/gui/src/stores/slices/ui-slice.js +98 -0
  231. package/packages/gui/src/views/agents.jsx +5 -5
  232. package/packages/gui/src/views/dashboard.jsx +12 -13
  233. package/packages/gui/src/views/marketplace.jsx +191 -3
  234. package/packages/gui/src/views/model-lab.jsx +54 -12
  235. package/packages/gui/src/views/models.jsx +419 -496
  236. package/packages/gui/src/views/network.jsx +3 -3
  237. package/packages/gui/src/views/settings.jsx +81 -94
  238. package/packages/gui/src/views/teams.jsx +40 -483
  239. package/SECURITY_SWEEP.md +0 -228
  240. package/TRAINING_DATA_v4.md +0 -6
  241. package/node_modules/@groove-dev/gui/dist/assets/index-CCVvAoQn.css +0 -1
  242. package/node_modules/@groove-dev/gui/dist/assets/index-DGIv_TRm.js +0 -984
  243. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +0 -379
  244. package/node_modules/@groove-dev/gui/src/views/preview.jsx +0 -6
  245. package/node_modules/@groove-dev/gui/src/views/subscription-panel.jsx +0 -327
  246. package/packages/gui/dist/assets/index-CCVvAoQn.css +0 -1
  247. package/packages/gui/dist/assets/index-DGIv_TRm.js +0 -984
  248. package/packages/gui/src/components/agents/agent-chat.jsx +0 -379
  249. package/packages/gui/src/views/preview.jsx +0 -6
  250. package/packages/gui/src/views/subscription-panel.jsx +0 -327
  251. package/test.py +0 -571
@@ -0,0 +1,461 @@
1
+ // FSL-1.1-Apache-2.0 — see LICENSE
2
+
3
+ import { api } from '../../lib/api';
4
+
5
+ export const createMarketplaceSlice = (set, get) => ({
6
+ // ── Marketplace Auth ───────────────────────────────────────
7
+ marketplaceUser: null,
8
+ marketplaceAuthenticated: false,
9
+ edition: 'community',
10
+ subscription: {
11
+ plan: 'community',
12
+ status: 'none',
13
+ active: false,
14
+ features: [],
15
+ seats: 1,
16
+ periodEnd: null,
17
+ cancelAtPeriodEnd: false,
18
+ },
19
+
20
+ // ── Training Data ──────────────────────────────────────────
21
+ trainingOptIn: false,
22
+ trainingStats: null,
23
+ dataSharingDismissed: false,
24
+ dataSharingModalOpen: false,
25
+
26
+ // ── Project Directory ───────────────────────────────────────
27
+ projectDir: null,
28
+ recentProjects: [],
29
+ showProjectPicker: false,
30
+
31
+ // ── Tunnels ────────────────────────────────────────────────
32
+ savedTunnels: [],
33
+ tunnelConnectStep: null,
34
+
35
+ // ── GitHub Repo Import ────────────────────────────────────
36
+ importedRepos: [],
37
+ importInProgress: false,
38
+
39
+ // ── Gateways ──────────────────────────────────────────────
40
+ gateways: [],
41
+
42
+ // ── Onboarding ────────────────────────────────────────────
43
+ onboardingComplete: localStorage.getItem('groove:onboardingComplete') === 'true',
44
+
45
+ // ── Journalist ────────────────────────────────────────────
46
+ journalistStatus: null,
47
+
48
+ // ── Marketplace Auth Actions ──────────────────────────────
49
+
50
+ async checkMarketplaceAuth() {
51
+ try {
52
+ const data = await api.get('/auth/status');
53
+ set({
54
+ marketplaceAuthenticated: data.authenticated || false,
55
+ marketplaceUser: data.user || null,
56
+ });
57
+ try {
58
+ const edition = await api.get('/edition');
59
+ set({
60
+ edition: edition.edition || 'community',
61
+ subscription: {
62
+ plan: edition.plan || 'community',
63
+ status: edition.status || (edition.subscriptionActive ? 'active' : 'none'),
64
+ active: edition.subscriptionActive === true,
65
+ features: edition.features || [],
66
+ seats: edition.seats || 1,
67
+ periodEnd: edition.periodEnd || null,
68
+ cancelAtPeriodEnd: edition.cancelAtPeriodEnd || false,
69
+ },
70
+ });
71
+ } catch { /* edition endpoint may not exist */ }
72
+ } catch {
73
+ set({ marketplaceAuthenticated: false, marketplaceUser: null });
74
+ }
75
+ },
76
+
77
+ async marketplaceLogin() {
78
+ try {
79
+ const data = await api.get('/auth/login-url');
80
+ if (data.url) window.open(data.url, '_blank');
81
+ const poll = setInterval(async () => {
82
+ try {
83
+ const status = await api.get('/auth/status');
84
+ if (status.authenticated) {
85
+ clearInterval(poll);
86
+ set({ marketplaceAuthenticated: true, marketplaceUser: status.user });
87
+ get().addToast('success', `Signed in as ${status.user?.displayName || status.user?.id || 'user'}`);
88
+ try {
89
+ const edition = await api.get('/edition');
90
+ set({
91
+ edition: edition.edition || 'community',
92
+ subscription: {
93
+ plan: edition.plan || 'community',
94
+ status: edition.status || (edition.subscriptionActive ? 'active' : 'none'),
95
+ active: edition.subscriptionActive === true,
96
+ features: edition.features || [],
97
+ seats: edition.seats || 1,
98
+ periodEnd: edition.periodEnd || null,
99
+ cancelAtPeriodEnd: edition.cancelAtPeriodEnd || false,
100
+ },
101
+ });
102
+ } catch { /* edition endpoint may not exist */ }
103
+ setTimeout(async () => {
104
+ try {
105
+ const e = await api.get('/edition');
106
+ set({
107
+ edition: e.edition || 'community',
108
+ subscription: {
109
+ plan: e.plan || 'community',
110
+ status: e.status || (e.subscriptionActive ? 'active' : 'none'),
111
+ active: e.subscriptionActive === true,
112
+ features: e.features || [],
113
+ seats: e.seats || 1,
114
+ periodEnd: e.periodEnd || null,
115
+ cancelAtPeriodEnd: e.cancelAtPeriodEnd || false,
116
+ },
117
+ });
118
+ } catch { /* delayed re-fetch may fail */ }
119
+ }, 2000);
120
+ }
121
+ } catch { /* keep polling */ }
122
+ }, 2000);
123
+ setTimeout(() => clearInterval(poll), 300000);
124
+ } catch (err) {
125
+ get().addToast('error', 'Login failed', err.message);
126
+ }
127
+ },
128
+
129
+ async marketplaceLogout() {
130
+ try {
131
+ await api.post('/auth/logout');
132
+ set({ marketplaceAuthenticated: false, marketplaceUser: null });
133
+ get().addToast('info', 'Signed out of marketplace');
134
+ } catch (err) {
135
+ get().addToast('error', 'Logout failed', err.message);
136
+ }
137
+ },
138
+
139
+ async marketplaceCheckout(skillId) {
140
+ try {
141
+ const data = await api.post('/auth/checkout', { skillId });
142
+ if (data.url) window.open(data.url, '_blank');
143
+ return data;
144
+ } catch (err) {
145
+ get().addToast('error', 'Checkout failed', err.message);
146
+ throw err;
147
+ }
148
+ },
149
+
150
+ // ── Subscription ────────────────────────────────────────────
151
+
152
+ async fetchSubscriptionPlans() {
153
+ return api.get('/subscription/plans');
154
+ },
155
+
156
+ async startCheckout(priceId) {
157
+ try {
158
+ const data = await api.post('/subscription/checkout', { priceId });
159
+ if (data.url) {
160
+ if (window.groove?.openExternal) {
161
+ window.groove.openExternal(data.url);
162
+ } else {
163
+ window.open(data.url, '_blank');
164
+ }
165
+ }
166
+ return data;
167
+ } catch (err) {
168
+ if (err.status === 401 || err.message?.includes('Not authenticated')) {
169
+ get().addToast('info', 'Please sign in to subscribe');
170
+ get().marketplaceLogin();
171
+ } else if (err.status === 409) {
172
+ get().addToast('info', 'Already subscribed', 'Use Manage Subscription to switch plans');
173
+ } else {
174
+ get().addToast('error', 'Checkout failed', err.message);
175
+ }
176
+ throw err;
177
+ }
178
+ },
179
+
180
+ async openPortal() {
181
+ try {
182
+ const data = await api.post('/subscription/portal');
183
+ if (data.url) {
184
+ if (window.groove?.openExternal) {
185
+ window.groove.openExternal(data.url);
186
+ } else {
187
+ window.open(data.url, '_blank');
188
+ }
189
+ }
190
+ return data;
191
+ } catch (err) {
192
+ get().addToast('error', 'Portal failed', err.message);
193
+ throw err;
194
+ }
195
+ },
196
+
197
+ async updateSeats(seats) {
198
+ try {
199
+ const data = await api.patch('/subscription', { seats });
200
+ set({ subscription: { ...get().subscription, ...data } });
201
+ get().addToast('success', `Updated to ${seats} seat${seats !== 1 ? 's' : ''}`);
202
+ return data;
203
+ } catch (err) {
204
+ get().addToast('error', 'Seat update failed', err.message);
205
+ throw err;
206
+ }
207
+ },
208
+
209
+ // ── Training Data ─────────────────────────────────────────
210
+
211
+ async setTrainingOptIn(enabled) {
212
+ try {
213
+ await api.post('/training/opt-in', { enabled });
214
+ set({ trainingOptIn: enabled, dataSharingModalOpen: false });
215
+ if (!enabled) set({ trainingStats: null });
216
+ } catch (e) {
217
+ get().addToast('error', 'Failed to update training preference', e.body?.detail || e.message);
218
+ }
219
+ },
220
+
221
+ async fetchTrainingStatus() {
222
+ try {
223
+ const data = await api.get('/training/status');
224
+ set({ trainingOptIn: data.optedIn, trainingStats: data });
225
+ } catch { /* endpoint may not exist on older daemons */ }
226
+ },
227
+
228
+ async dismissDataSharingModal(permanent) {
229
+ if (permanent) {
230
+ try { await api.patch('/config', { dataSharingDismissed: true }); } catch {}
231
+ set({ dataSharingDismissed: true, dataSharingModalOpen: false });
232
+ } else {
233
+ set({ dataSharingModalOpen: false });
234
+ }
235
+ },
236
+
237
+ // ── Project Directory ────────────────────────────────────
238
+
239
+ async fetchProjectDir() {
240
+ try {
241
+ const data = await api.get('/project-dir');
242
+ const isHome = /^\/home\/[^/]+$/.test(data.projectDir) || data.projectDir === '/root';
243
+ set({
244
+ projectDir: data.projectDir,
245
+ recentProjects: data.recentProjects || [],
246
+ showProjectPicker: isHome || (data.recentProjects || []).length === 0,
247
+ editorTreeCache: {},
248
+ });
249
+ } catch {}
250
+ },
251
+
252
+ async setProjectDir(path) {
253
+ const data = await api.post('/project-dir', { path });
254
+ try { await api.post('/files/root', { root: data.projectDir }); } catch {}
255
+ set({
256
+ projectDir: data.projectDir,
257
+ recentProjects: data.recentProjects || [],
258
+ showProjectPicker: false,
259
+ editorTreeCache: {},
260
+ });
261
+ get().fetchTreeDir('');
262
+ },
263
+
264
+ async removeRecentProject(path) {
265
+ try {
266
+ await api.delete('/projects/recent', { path });
267
+ } catch {}
268
+ get().fetchProjectDir();
269
+ },
270
+
271
+ toggleProjectPicker() {
272
+ set((s) => ({ showProjectPicker: !s.showProjectPicker }));
273
+ },
274
+
275
+ // ── Tunnels ──────────────────────────────────────────────
276
+
277
+ async fetchTunnels() {
278
+ try {
279
+ const tunnels = await api.get('/tunnels');
280
+ set({ savedTunnels: Array.isArray(tunnels) ? tunnels : [] });
281
+ } catch {}
282
+ },
283
+
284
+ async saveTunnel(config) {
285
+ const result = await api.post('/tunnels', config);
286
+ get().fetchTunnels();
287
+ return result;
288
+ },
289
+
290
+ async updateTunnel(id, config) {
291
+ const result = await api.patch(`/tunnels/${encodeURIComponent(id)}`, config);
292
+ get().fetchTunnels();
293
+ return result;
294
+ },
295
+
296
+ async deleteTunnel(id) {
297
+ await api.delete(`/tunnels/${encodeURIComponent(id)}`);
298
+ get().fetchTunnels();
299
+ },
300
+
301
+ async testTunnel(id) {
302
+ return api.post(`/tunnels/${encodeURIComponent(id)}/test`);
303
+ },
304
+
305
+ async connectTunnel(id) {
306
+ try {
307
+ const result = await api.post(`/tunnels/${encodeURIComponent(id)}/connect`);
308
+ get().fetchTunnels();
309
+ if (result.localPort && result.name) {
310
+ if (window.groove?.remote?.openWindow) {
311
+ window.groove.remote.openWindow(result.localPort, result.name);
312
+ } else {
313
+ window.open(`http://localhost:${result.localPort}?instance=${encodeURIComponent(result.name)}`, '_blank');
314
+ }
315
+ }
316
+ return result;
317
+ } finally {
318
+ set({ tunnelConnectStep: null });
319
+ }
320
+ },
321
+
322
+ async upgradeTunnel(id) {
323
+ return api.post(`/tunnels/${encodeURIComponent(id)}/upgrade`);
324
+ },
325
+
326
+ async disconnectTunnel(id) {
327
+ const tunnel = get().savedTunnels.find(t => t.id === id);
328
+ await api.post(`/tunnels/${encodeURIComponent(id)}/disconnect`);
329
+ get().fetchTunnels();
330
+ if (tunnel?.localPort && window.groove?.remote?.closeByPort) {
331
+ window.groove.remote.closeByPort(tunnel.localPort);
332
+ }
333
+ },
334
+
335
+ async installTunnel(id) {
336
+ return api.post(`/tunnels/${encodeURIComponent(id)}/install`);
337
+ },
338
+
339
+ async startTunnel(id) {
340
+ return api.post(`/tunnels/${encodeURIComponent(id)}/start`);
341
+ },
342
+
343
+ // ── GitHub Repo Import ────────────────────────────────────
344
+
345
+ async fetchImportedRepos() {
346
+ try {
347
+ const repos = await api.get('/repos/imported');
348
+ set({ importedRepos: repos });
349
+ } catch { /* ignore */ }
350
+ },
351
+
352
+ async previewRepo(repoUrl) {
353
+ return api.post('/repos/preview', { repoUrl });
354
+ },
355
+
356
+ async importRepo(repoUrl, targetPath, createTeam, teamName) {
357
+ set({ importInProgress: true });
358
+ try {
359
+ const result = await api.post('/repos/import', { repoUrl, targetPath, createTeam, teamName });
360
+ get().fetchImportedRepos();
361
+ return result;
362
+ } finally {
363
+ set({ importInProgress: false });
364
+ }
365
+ },
366
+
367
+ async softRemoveRepo(importId) {
368
+ await api.delete(`/repos/${encodeURIComponent(importId)}/remove`);
369
+ get().fetchImportedRepos();
370
+ },
371
+
372
+ async hardNukeRepo(importId, deleteFiles = true) {
373
+ await api.delete(`/repos/${encodeURIComponent(importId)}/nuke?deleteFiles=${deleteFiles}`);
374
+ get().fetchImportedRepos();
375
+ },
376
+
377
+ // ── Journalist ────────────────────────────────────────────
378
+
379
+ async fetchJournalist() {
380
+ try {
381
+ const data = await api.get('/journalist');
382
+ set({ journalistStatus: data });
383
+ return data;
384
+ } catch { return null; }
385
+ },
386
+
387
+ async triggerJournalistCycle() {
388
+ try {
389
+ const data = await api.post('/journalist/cycle');
390
+ get().addToast('success', 'Synthesis cycle triggered');
391
+ set({ journalistStatus: data });
392
+ return data;
393
+ } catch (err) {
394
+ get().addToast('error', 'Synthesis failed', err.message);
395
+ throw err;
396
+ }
397
+ },
398
+
399
+ // ── Onboarding ────────────────────────────────────────────
400
+
401
+ async fetchOnboardingStatus() {
402
+ try {
403
+ const data = await api.get('/onboarding/status');
404
+ if (data?.complete) {
405
+ set({ onboardingComplete: true });
406
+ localStorage.setItem('groove:onboardingComplete', 'true');
407
+ }
408
+ return data;
409
+ } catch {
410
+ return null;
411
+ }
412
+ },
413
+
414
+ dismissOnboarding() {
415
+ set({ onboardingComplete: true });
416
+ localStorage.setItem('groove:onboardingComplete', 'true');
417
+ api.post('/onboarding/dismiss').catch(() => {});
418
+ },
419
+
420
+ // ── Integration Agent Install ────────────────────────────
421
+
422
+ async installViaExistingAgent(integration, agentId) {
423
+ const message = buildIntegrationPrompt(integration);
424
+ await get().instructAgent(agentId, message);
425
+ get().setActiveView('agents');
426
+ get().selectAgent(agentId);
427
+ },
428
+
429
+ async spawnIntegrationTeam(integration) {
430
+ const team = await get().createTeam(integration.name);
431
+ const prompt = buildIntegrationPrompt(integration);
432
+ const agent = await get().spawnAgent({ role: 'planner', prompt, teamId: team.id });
433
+ get().setActiveView('agents');
434
+ get().selectAgent(agent.id);
435
+ return agent;
436
+ },
437
+ });
438
+
439
+ function buildIntegrationPrompt(integration) {
440
+ const lines = [
441
+ `Set up the "${integration.name}" integration for this project.`,
442
+ '',
443
+ ];
444
+ if (integration.description) lines.push(`**Description:** ${integration.description}`);
445
+ if (integration.npmPackage) lines.push(`**npm package:** ${integration.npmPackage}`);
446
+ if (integration.authType) lines.push(`**Auth type:** ${integration.authType}`);
447
+ if (integration.envKeys?.length) {
448
+ lines.push('', '**Environment keys required:**');
449
+ for (const k of integration.envKeys) {
450
+ lines.push(`- \`${k.key}\` — ${k.label}${k.required ? ' (required)' : ''}`);
451
+ }
452
+ }
453
+ if (integration.setupSteps?.length) {
454
+ lines.push('', '**Setup steps:**');
455
+ integration.setupSteps.forEach((step, i) => lines.push(`${i + 1}. ${step}`));
456
+ }
457
+ if (integration.setupUrl) lines.push(``, `**Setup URL:** ${integration.setupUrl}`);
458
+ if (integration.agentInstructions) lines.push('', `**Agent instructions:** ${integration.agentInstructions}`);
459
+ lines.push('', 'Follow the setup steps, configure environment keys, and verify the integration works.');
460
+ return lines.join('\n');
461
+ }