groove-dev 0.27.110 → 0.27.111

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 (37) hide show
  1. package/EMBEDDING_SERVICE_BUILD_PLAN.md +200 -0
  2. package/TRAINING_DATA_v2.md +9 -0
  3. package/moe-training/client/domain-tagger.js +3 -1
  4. package/moe-training/client/trajectory-capture.js +3 -2
  5. package/moe-training/shared/constants.js +1 -0
  6. package/moe-training/test/client/domain-tagger.test.js +6 -4
  7. package/node_modules/@groove-dev/cli/package.json +1 -1
  8. package/node_modules/@groove-dev/daemon/package.json +1 -1
  9. package/node_modules/@groove-dev/daemon/src/api.js +16 -3
  10. package/node_modules/@groove-dev/gui/dist/assets/{index-B8JomvGM.js → index-CHu5w3i3.js} +1 -1
  11. package/node_modules/@groove-dev/gui/dist/index.html +1 -1
  12. package/node_modules/@groove-dev/gui/package.json +1 -1
  13. package/node_modules/@groove-dev/gui/src/stores/groove.js +1 -1
  14. package/node_modules/moe-training/client/domain-tagger.js +3 -1
  15. package/node_modules/moe-training/client/trajectory-capture.js +3 -2
  16. package/node_modules/moe-training/shared/constants.js +1 -0
  17. package/node_modules/moe-training/test/client/domain-tagger.test.js +6 -4
  18. package/package.json +1 -1
  19. package/packages/cli/package.json +1 -1
  20. package/packages/daemon/package.json +1 -1
  21. package/packages/daemon/src/api.js +16 -3
  22. package/packages/gui/dist/assets/{index-B8JomvGM.js → index-CHu5w3i3.js} +1 -1
  23. package/packages/gui/dist/index.html +1 -1
  24. package/packages/gui/package.json +1 -1
  25. package/packages/gui/src/stores/groove.js +1 -1
  26. package/TRAINING_DATA.md +0 -12
  27. package/codex/browser-racing-game/README.md +0 -45
  28. package/codex/browser-racing-game/dist/assets/index-D-sGTraQ.js +0 -47
  29. package/codex/browser-racing-game/dist/assets/index-S75nJv69.css +0 -1
  30. package/codex/browser-racing-game/dist/index.html +0 -14
  31. package/codex/browser-racing-game/index.html +0 -13
  32. package/codex/browser-racing-game/package-lock.json +0 -841
  33. package/codex/browser-racing-game/package.json +0 -15
  34. package/codex/browser-racing-game/src/app.css +0 -359
  35. package/codex/browser-racing-game/src/main.ts +0 -913
  36. package/codex/browser-racing-game/tsconfig.json +0 -20
  37. package/codex/browser-racing-game/vite.config.ts +0 -12
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <link rel="icon" type="image/png" href="/favicon.png" />
8
8
  <title>Groove GUI</title>
9
- <script type="module" crossorigin src="/assets/index-B8JomvGM.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-CHu5w3i3.js"></script>
10
10
  <link rel="modulepreload" crossorigin href="/assets/vendor-26L3JoZv.js">
11
11
  <link rel="modulepreload" crossorigin href="/assets/reactflow-DoBZjiHE.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/codemirror-CFF1Lrnz.js">
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/gui",
3
- "version": "0.27.110",
3
+ "version": "0.27.111",
4
4
  "description": "GROOVE GUI — visual agent control plane",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -2702,7 +2702,7 @@ export const useGrooveStore = create((set, get) => ({
2702
2702
  set({ trainingOptIn: enabled });
2703
2703
  if (!enabled) set({ trainingStats: null });
2704
2704
  } catch (e) {
2705
- get().addToast('error', 'Failed to update training preference');
2705
+ get().addToast('error', 'Failed to update training preference', e.body?.detail || e.message);
2706
2706
  }
2707
2707
  },
2708
2708
 
@@ -1,5 +1,7 @@
1
1
  // FSL-1.1-Apache-2.0 — see LICENSE
2
2
 
3
+ import { EMBEDDING_SERVICE_URL } from '../shared/constants.js';
4
+
3
5
  const DEFAULT_MODEL = 'sentence-transformers/all-MiniLM-L6-v2';
4
6
  const DEFAULT_TOP_K = 3;
5
7
 
@@ -171,7 +173,7 @@ const DOMAIN_TAXONOMY = {
171
173
 
172
174
  export class DomainTagger {
173
175
  constructor(options = {}) {
174
- this._serviceUrl = options.serviceUrl || process.env.EMBEDDING_SERVICE_URL || null;
176
+ this._serviceUrl = options.serviceUrl !== undefined ? options.serviceUrl : EMBEDDING_SERVICE_URL;
175
177
  this._registryUrl = options.registryUrl || process.env.LEAF_REGISTRY_URL || null;
176
178
  this._registry = options.registry || null;
177
179
  this._model = options.model || DEFAULT_MODEL;
@@ -298,9 +298,10 @@ export class TrajectoryCapture {
298
298
 
299
299
  if (this._domainTagger) {
300
300
  const role = ctx.metadata.agent_role || '';
301
- const firstPrompt = ctx.allSteps.find((s) => s.type === 'thought')?.content || '';
302
301
  const thoughtSteps = ctx.allSteps.filter((s) => s.type === 'thought');
303
- const routingText = DomainTagger.buildRoutingText(role, firstPrompt, thoughtSteps);
302
+ const firstPrompt = thoughtSteps[0]?.content || '';
303
+ const remainingThoughts = thoughtSteps.slice(1);
304
+ const routingText = DomainTagger.buildRoutingText(role, firstPrompt, remainingThoughts);
304
305
  ctx.metadata.domain_tags = await this._domainTagger.tag(routingText);
305
306
  ctx.metadata.session_embedding = await this._domainTagger.embed(routingText);
306
307
  }
@@ -39,3 +39,4 @@ export const TRAINING_EXCLUSION_REASONS = ['too_few_steps', 'no_actions', 'no_ob
39
39
  export const USER_MESSAGE_MAX_CHARS = 2000;
40
40
 
41
41
  export const CENTRAL_COMMAND_URL = process.env.GROOVE_CENTRAL_URL || 'https://api.groovedev.ai';
42
+ export const EMBEDDING_SERVICE_URL = process.env.EMBEDDING_SERVICE_URL || `${CENTRAL_COMMAND_URL}/v1/embed`;
@@ -8,7 +8,7 @@ describe('DomainTagger', () => {
8
8
  let tagger;
9
9
 
10
10
  beforeEach(async () => {
11
- tagger = new DomainTagger();
11
+ tagger = new DomainTagger({ serviceUrl: null });
12
12
  await tagger.init();
13
13
  });
14
14
 
@@ -176,7 +176,7 @@ describe('DomainTagger', () => {
176
176
  });
177
177
 
178
178
  it('returns null when not initialized', async () => {
179
- const uninit = new DomainTagger();
179
+ const uninit = new DomainTagger({ serviceUrl: null });
180
180
  const result = await uninit.tag('Build a Python Django app');
181
181
  assert.equal(result, null);
182
182
  });
@@ -203,6 +203,7 @@ describe('DomainTagger', () => {
203
203
 
204
204
  it('accepts registry option and falls back to keyword mode without embedding service', async () => {
205
205
  const registryTagger = new DomainTagger({
206
+ serviceUrl: null,
206
207
  registry: [
207
208
  { id: 'quantum_computing', domain_description: 'Quantum computing, qubits, quantum gates' },
208
209
  { id: 'bioinformatics', domain_description: 'Biology, genomics, DNA analysis' },
@@ -215,6 +216,7 @@ describe('DomainTagger', () => {
215
216
 
216
217
  it('accepts registryUrl option and falls back to keyword mode when unavailable', async () => {
217
218
  const registryTagger = new DomainTagger({
219
+ serviceUrl: null,
218
220
  registryUrl: 'http://localhost:99999/api/leaves',
219
221
  });
220
222
  await registryTagger.init();
@@ -223,7 +225,7 @@ describe('DomainTagger', () => {
223
225
  });
224
226
 
225
227
  it('uses expanded taxonomy — has 40 domains by default', async () => {
226
- const defaultTagger = new DomainTagger();
228
+ const defaultTagger = new DomainTagger({ serviceUrl: null });
227
229
  await defaultTagger.init();
228
230
  assert.ok(defaultTagger._domains.length >= 35, `Expected 35+ domains, got ${defaultTagger._domains.length}`);
229
231
  });
@@ -239,7 +241,7 @@ describe('DomainTagger', () => {
239
241
  });
240
242
 
241
243
  it('embed() returns null when not initialized', async () => {
242
- const uninit = new DomainTagger();
244
+ const uninit = new DomainTagger({ serviceUrl: null });
243
245
  const result = await uninit.embed('Build a Python app');
244
246
  assert.equal(result, null);
245
247
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "groove-dev",
3
- "version": "0.27.110",
3
+ "version": "0.27.111",
4
4
  "description": "Open-source agent orchestration layer — the AI company OS. Local model agent engine (GGUF/Ollama/llama-server), HuggingFace model browser, MCP integrations (Slack, Gmail, Stripe, 15+), agent scheduling (cron), business roles (CMO, CFO, EA). GUI dashboard, multi-agent coordination, zero cold-start, infinite sessions. Works with Claude Code, Codex, Gemini CLI, Ollama, any local model.",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "author": "Groove Dev <hello@groovedev.ai> (https://groovedev.ai)",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.110",
3
+ "version": "0.27.111",
4
4
  "description": "GROOVE CLI — manage AI coding agents from your terminal",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.110",
3
+ "version": "0.27.111",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -112,7 +112,7 @@ export function createApi(app, daemon) {
112
112
  res.setHeader('Content-Security-Policy', "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; frame-ancestors 'self'");
113
113
  } else {
114
114
  res.setHeader('X-Frame-Options', 'DENY');
115
- res.setHeader('Content-Security-Policy', "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self' ws://localhost:* ws://127.0.0.1:* http://localhost:* http://127.0.0.1:*; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-src 'self'; frame-ancestors 'none'");
115
+ res.setHeader('Content-Security-Policy', "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; connect-src 'self' ws://localhost:* ws://127.0.0.1:* http://localhost:* http://127.0.0.1:*; font-src 'self' data:; object-src 'none'; base-uri 'self'; frame-src 'self' http://127.0.0.1:* http://localhost:*; frame-ancestors 'none'");
116
116
  }
117
117
  next();
118
118
  });
@@ -4869,11 +4869,18 @@ Keep responses concise. Help them think, don't lecture them about the system the
4869
4869
  const { enabled } = req.body;
4870
4870
  if (typeof enabled !== 'boolean') return res.status(400).json({ error: 'enabled must be boolean' });
4871
4871
 
4872
- daemon.config.training_opt_in = enabled;
4873
4872
  const { saveConfig } = await import('./firstrun.js');
4874
- saveConfig(daemon.grooveDir, daemon.config);
4875
4873
 
4876
4874
  if (enabled) {
4875
+ try {
4876
+ await import('better-sqlite3');
4877
+ } catch (modErr) {
4878
+ console.error('[training/opt-in] Native module load failed:', modErr);
4879
+ return res.status(500).json({
4880
+ error: 'Failed to enable data sharing',
4881
+ detail: 'Native SQLite module (better-sqlite3) is not available. On remote instances, ensure build tools are installed (gcc, g++, make, python3) and run: npm rebuild better-sqlite3',
4882
+ });
4883
+ }
4877
4884
  try {
4878
4885
  const userId = ConsentManager.getOrCreateUserId();
4879
4886
  const consent = new ConsentManager();
@@ -4882,13 +4889,19 @@ Keep responses concise. Help them think, don't lecture them about the system the
4882
4889
  } finally {
4883
4890
  consent.close();
4884
4891
  }
4892
+ daemon.config.training_opt_in = true;
4893
+ saveConfig(daemon.grooveDir, daemon.config);
4885
4894
  await daemon._initTrajectoryCapture();
4886
4895
  daemon.state.set('training_enrolled_at', new Date().toISOString());
4887
4896
  } catch (e) {
4897
+ console.error('[training/opt-in] Failed to enable data sharing:', e);
4888
4898
  daemon.config.training_opt_in = false;
4899
+ saveConfig(daemon.grooveDir, daemon.config);
4889
4900
  return res.status(500).json({ error: 'Failed to enable data sharing', detail: e.message });
4890
4901
  }
4891
4902
  } else {
4903
+ daemon.config.training_opt_in = false;
4904
+ saveConfig(daemon.grooveDir, daemon.config);
4892
4905
  if (daemon.trajectoryCapture) {
4893
4906
  try { await daemon.trajectoryCapture.shutdown(); } catch (e) { /* */ }
4894
4907
  daemon.trajectoryCapture = null;