groove-dev 0.27.113 → 0.27.116

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 (70) hide show
  1. package/CENTRAL_COMMAND_REBUILD.md +689 -0
  2. package/EMBEDDING_DIAGNOSTIC.md +197 -0
  3. package/TRAINING_DATA_v4.md +6 -0
  4. package/node_modules/@groove-dev/cli/package.json +1 -1
  5. package/node_modules/@groove-dev/cli/src/commands/team.js +59 -2
  6. package/node_modules/@groove-dev/daemon/package.json +1 -1
  7. package/node_modules/@groove-dev/daemon/src/api.js +27 -2
  8. package/node_modules/@groove-dev/daemon/src/filewatcher.js +45 -0
  9. package/node_modules/@groove-dev/daemon/src/index.js +14 -2
  10. package/node_modules/@groove-dev/daemon/src/process.js +254 -208
  11. package/node_modules/@groove-dev/daemon/src/teams.js +143 -20
  12. package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +78 -45
  13. package/node_modules/@groove-dev/gui/dist/assets/index-DdN9RVnC.css +1 -0
  14. package/node_modules/@groove-dev/gui/dist/assets/{index-BYh6iHqL.js → index-fq--PD7_.js} +1731 -1731
  15. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  16. package/node_modules/@groove-dev/gui/package.json +1 -1
  17. package/node_modules/@groove-dev/gui/src/components/agents/workspace-mode.jsx +0 -22
  18. package/node_modules/@groove-dev/gui/src/components/layout/status-bar.jsx +43 -45
  19. package/node_modules/@groove-dev/gui/src/components/settings/quick-connect.jsx +2 -1
  20. package/node_modules/@groove-dev/gui/src/components/teams/team-removal-dialog.jsx +156 -0
  21. package/node_modules/@groove-dev/gui/src/stores/groove.js +57 -12
  22. package/node_modules/@groove-dev/gui/src/views/agents.jsx +23 -4
  23. package/node_modules/@groove-dev/gui/src/views/editor.jsx +1 -20
  24. package/node_modules/@groove-dev/gui/src/views/teams.jsx +84 -5
  25. package/package.json +1 -1
  26. package/packages/cli/package.json +1 -1
  27. package/packages/cli/src/commands/team.js +59 -2
  28. package/packages/daemon/package.json +1 -1
  29. package/packages/daemon/src/api.js +27 -2
  30. package/packages/daemon/src/filewatcher.js +45 -0
  31. package/packages/daemon/src/index.js +14 -2
  32. package/packages/daemon/src/process.js +254 -208
  33. package/packages/daemon/src/teams.js +143 -20
  34. package/packages/daemon/src/tunnel-manager.js +78 -45
  35. package/packages/gui/dist/assets/index-DdN9RVnC.css +1 -0
  36. package/packages/gui/dist/assets/{index-BYh6iHqL.js → index-fq--PD7_.js} +1731 -1731
  37. package/packages/gui/dist/index.html +2 -2
  38. package/packages/gui/package.json +1 -1
  39. package/packages/gui/src/components/agents/workspace-mode.jsx +0 -22
  40. package/packages/gui/src/components/layout/status-bar.jsx +43 -45
  41. package/packages/gui/src/components/settings/quick-connect.jsx +2 -1
  42. package/packages/gui/src/components/teams/team-removal-dialog.jsx +156 -0
  43. package/packages/gui/src/stores/groove.js +57 -12
  44. package/packages/gui/src/views/agents.jsx +23 -4
  45. package/packages/gui/src/views/editor.jsx +1 -20
  46. package/packages/gui/src/views/teams.jsx +84 -5
  47. package/TRAINING_DATA_v3.md +0 -11
  48. package/codex-test/offroad-nitro-racer/dist/assets/index-CuvdKK6U.js +0 -44
  49. package/codex-test/offroad-nitro-racer/dist/assets/index-DvHn2Thu.css +0 -1
  50. package/codex-test/offroad-nitro-racer/dist/index.html +0 -23
  51. package/codex-test/offroad-nitro-racer/index.html +0 -21
  52. package/codex-test/offroad-nitro-racer/package-lock.json +0 -841
  53. package/codex-test/offroad-nitro-racer/package.json +0 -15
  54. package/codex-test/offroad-nitro-racer/src/game/AI.ts +0 -28
  55. package/codex-test/offroad-nitro-racer/src/game/Audio.ts +0 -63
  56. package/codex-test/offroad-nitro-racer/src/game/Car.ts +0 -247
  57. package/codex-test/offroad-nitro-racer/src/game/Effects.ts +0 -62
  58. package/codex-test/offroad-nitro-racer/src/game/Game.ts +0 -229
  59. package/codex-test/offroad-nitro-racer/src/game/Input.ts +0 -45
  60. package/codex-test/offroad-nitro-racer/src/game/Renderer.ts +0 -224
  61. package/codex-test/offroad-nitro-racer/src/game/Track.ts +0 -158
  62. package/codex-test/offroad-nitro-racer/src/game/UI.ts +0 -96
  63. package/codex-test/offroad-nitro-racer/src/game/math.ts +0 -42
  64. package/codex-test/offroad-nitro-racer/src/main.ts +0 -24
  65. package/codex-test/offroad-nitro-racer/src/style.css +0 -291
  66. package/codex-test/offroad-nitro-racer/src/vite-env.d.ts +0 -1
  67. package/codex-test/offroad-nitro-racer/tsconfig.json +0 -18
  68. package/codex-test/offroad-nitro-racer/vite.config.ts +0 -7
  69. package/node_modules/@groove-dev/gui/dist/assets/index-DAlSbVyK.css +0 -1
  70. package/packages/gui/dist/assets/index-DAlSbVyK.css +0 -1
@@ -0,0 +1,197 @@
1
+ # Embedding Service Diagnostic — Central Command Rebuild
2
+
3
+ ## Problem
4
+
5
+ After the Central Command rebuild, `session_embedding` is `null` on all SESSION_CLOSE envelopes and `domain_tags` show keyword-mode confidence (~0.067) instead of embedding-mode confidence (~0.3-0.5). Embeddings were working correctly before the rebuild (TRAINING_DATA_v3 had full 384-dim vectors on every session).
6
+
7
+ The endpoint responds to direct curl tests from a developer machine, but the Groove client is falling back to keyword mode during live sessions.
8
+
9
+ ## What "working" looked like (v3 data)
10
+
11
+ ```
12
+ domain_tags: primary=react_frontend (0.4932)
13
+ session_embedding: 384d, model=sentence-transformers/all-MiniLM-L6-v2, nonzero=377/384
14
+ ```
15
+
16
+ ## What's happening now (v4 data)
17
+
18
+ ```
19
+ domain_tags: primary=nlp_llm (0.0769) ← keyword mode
20
+ session_embedding: null ← embed() returns null in keyword mode
21
+ ```
22
+
23
+ ## How the client decides between keyword and embedding mode
24
+
25
+ On every agent spawn, the `DomainTagger.init()` runs this sequence:
26
+
27
+ ```
28
+ 1. POST to EMBEDDING_SERVICE_URL with {"input": "health check", "model": "sentence-transformers/all-MiniLM-L6-v2"}
29
+ 2. If response is 200 OK:
30
+ a. Switch to "http" mode
31
+ b. Call _buildCentroids() — embeds all 40 domain descriptions (40 sequential POST calls)
32
+ c. If all succeeds → ready, embedding mode active
33
+ 3. If ANYTHING fails (network error, non-200, timeout, _buildCentroids() error):
34
+ → Fall back to "keyword" mode silently
35
+ ```
36
+
37
+ The client **never logs** why it fell back — it catches all errors silently. So the failure is invisible.
38
+
39
+ ## Likely failure points (in order of probability)
40
+
41
+ ### 1. `_buildCentroids()` is failing
42
+
43
+ Even if the health probe succeeds, `init()` then makes **40 sequential embed calls** to build domain centroids. If any single one fails, the whole init throws and falls back to keyword mode. The entire block is wrapped in a try/catch:
44
+
45
+ ```javascript
46
+ try {
47
+ const res = await fetch(this._serviceUrl, { ... }); // health probe
48
+ if (res.ok) {
49
+ this._mode = this._leafRegistry?.length ? 'registry' : 'http';
50
+ await this._buildCentroids(); // ← 40 more calls, if this throws → keyword mode
51
+ this._ready = true;
52
+ return;
53
+ }
54
+ } catch {
55
+ // silently falls through to keyword mode
56
+ }
57
+ ```
58
+
59
+ **To check:** Look at Central Command logs during a Groove session. You should see ~41 POST requests to `/v1/embed` in quick succession (1 health probe + 40 centroid builds). If you see fewer, one is failing.
60
+
61
+ ### 2. Timeout under load
62
+
63
+ The health probe has a **5-second timeout**. The centroid embed calls have a **10-second timeout** each. If the ONNX model is cold or the server is under load, individual calls might be timing out.
64
+
65
+ **To check:** Add timing logs to the `/v1/embed` endpoint:
66
+ ```javascript
67
+ const start = Date.now();
68
+ const vector = await embed(text);
69
+ console.log(`[embed] ${Date.now() - start}ms "${text.slice(0, 50)}..."`);
70
+ ```
71
+
72
+ ### 3. Response format mismatch
73
+
74
+ The client parses the response as:
75
+ ```javascript
76
+ const data = await res.json();
77
+ const embedding = data?.data?.[0]?.embedding;
78
+ if (!Array.isArray(embedding)) {
79
+ // returns null — "Invalid embedding response format"
80
+ }
81
+ ```
82
+
83
+ The expected response is **exactly**:
84
+ ```json
85
+ {
86
+ "data": [
87
+ {
88
+ "embedding": [0.0123, -0.0456, ...384 floats],
89
+ "index": 0
90
+ }
91
+ ],
92
+ "model": "sentence-transformers/all-MiniLM-L6-v2"
93
+ }
94
+ ```
95
+
96
+ **To check:** Verify the response structure. Common mistakes:
97
+ - Returning `{ "embedding": [...] }` instead of `{ "data": [{ "embedding": [...] }] }`
98
+ - Returning the vector as a nested array `[[0.01, ...]]` instead of flat `[0.01, ...]`
99
+ - Returning Float32Array or typed array instead of plain JSON numbers
100
+
101
+ ### 4. CORS or request rejection
102
+
103
+ The Groove daemon makes requests from `localhost` (or wherever it runs). If the rebuilt server has stricter CORS, different firewall rules, or middleware that rejects requests without a specific User-Agent or Origin header, the fetch would fail.
104
+
105
+ **To check:** The original Central Command had `Access-Control-Allow-Origin: *`. Verify the rebuild has the same.
106
+
107
+ ### 5. URL path mismatch
108
+
109
+ The client hits exactly: `POST https://api.groovedev.ai/v1/embed`
110
+
111
+ **To check:** Verify the route is mounted at `/v1/embed`, not `/embed` or `/v1/embeddings` or `/api/v1/embed`.
112
+
113
+ ## Quick diagnostic commands
114
+
115
+ Run these on the Central Command server:
116
+
117
+ ```bash
118
+ # 1. Verify endpoint exists and responds correctly
119
+ curl -s -X POST http://localhost:8443/v1/embed \
120
+ -H "Content-Type: application/json" \
121
+ -d '{"input": "Python programming debugging testing"}' \
122
+ | python3 -c "
123
+ import sys, json
124
+ d = json.load(sys.stdin)
125
+ v = d.get('data', [{}])[0].get('embedding')
126
+ if v and isinstance(v, list):
127
+ print(f'OK: {len(v)}-dim vector, type={type(v[0]).__name__}')
128
+ else:
129
+ print(f'BROKEN: response structure = {json.dumps(d)[:200]}')"
130
+
131
+ # 2. Simulate the full init sequence (health probe + 40 centroids)
132
+ python3 -c "
133
+ import requests, time
134
+ url = 'http://localhost:8443/v1/embed'
135
+ domains = [
136
+ 'Python programming, debugging, testing with pytest',
137
+ 'TypeScript and Node.js backend, Express frameworks',
138
+ 'React frontend development, JSX components, hooks',
139
+ # ...add all 40 domain descriptions from domain-tagger.js
140
+ ]
141
+
142
+ # Health probe
143
+ start = time.time()
144
+ r = requests.post(url, json={'input': 'health check', 'model': 'sentence-transformers/all-MiniLM-L6-v2'}, timeout=5)
145
+ print(f'Health probe: {r.status_code} in {time.time()-start:.1f}s')
146
+
147
+ # Centroid batch
148
+ fails = 0
149
+ for i, desc in enumerate(domains):
150
+ try:
151
+ r = requests.post(url, json={'input': desc}, timeout=10)
152
+ d = r.json()
153
+ v = d.get('data', [{}])[0].get('embedding')
154
+ if not v or not isinstance(v, list) or len(v) != 384:
155
+ print(f' Domain {i}: BAD RESPONSE')
156
+ fails += 1
157
+ except Exception as e:
158
+ print(f' Domain {i}: FAILED - {e}')
159
+ fails += 1
160
+
161
+ print(f'Centroid build: {len(domains)-fails}/{len(domains)} succeeded, {fails} failed')
162
+ if fails > 0:
163
+ print('THIS IS WHY EMBEDDINGS ARE NULL - any failure causes full fallback to keyword mode')
164
+ "
165
+
166
+ # 3. Check response time under sequential load
167
+ for i in $(seq 1 10); do
168
+ time curl -s -X POST http://localhost:8443/v1/embed \
169
+ -H "Content-Type: application/json" \
170
+ -d "{\"input\": \"test embedding call $i\"}" > /dev/null
171
+ done
172
+
173
+ # 4. Check server logs during a live Groove session
174
+ # Start a Groove agent and watch for /v1/embed requests in the Central Command logs
175
+ ```
176
+
177
+ ## What success looks like
178
+
179
+ After fix, a SESSION_CLOSE envelope should show:
180
+ ```json
181
+ {
182
+ "metadata": {
183
+ "domain_tags": {
184
+ "primary": { "domain": "react_frontend", "confidence": 0.49 },
185
+ "secondary": { "domain": "vue_frontend", "confidence": 0.47 },
186
+ "tertiary": { "domain": "typescript_node", "confidence": 0.40 }
187
+ },
188
+ "session_embedding": {
189
+ "model": "sentence-transformers/all-MiniLM-L6-v2",
190
+ "vector": [0.0123, -0.0456, "...384 floats"],
191
+ "source_text": "frontend\nI'll scaffold the project..."
192
+ }
193
+ }
194
+ }
195
+ ```
196
+
197
+ Confidence scores in the 0.25-0.55 range (cosine similarity), NOT 0.06-0.08 (keyword hit ratio).
@@ -0,0 +1,6 @@
1
+ {"envelope_id":"env_f93f9a50-bda7-453f-ac14-5fdaf7e4b9f0","session_id":"sess_a3717729-38ba-4b17-bc7b-ee6de297819c","chunk_sequence":0,"contributor_id":"23e6dd8c4a884836bf78cafda9fbe57d","attestation":{"session_hmac":"54323779fa5dd41968d8a3a47bd224c14904de2105d80c0f019fc3bce2b2242a","sequence":0,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"metadata":{"model_engine":"gpt-5.5","provider":"codex","agent_role":"planner","agent_id":"0f8f9413","task_complexity":"medium","team_size":1,"session_quality":0,"groove_version":"0.27.115","leaf_context":null},"trajectory_log":[{"step":1,"type":"thought","timestamp":1777357867.668,"content":"I’m planner-15, ready to create a team plan and route work for this project; what would you like the team to work on?","token_count":30},{"step":2,"type":"resolution","timestamp":1777357867.736,"content":"","token_count":1}]}
2
+ {"envelope_id":"env_b87816e2-78a0-49a7-a752-a1e4d2e254ac","session_id":"sess_a3717729-38ba-4b17-bc7b-ee6de297819c","type":"SESSION_CLOSE","attestation":{"session_hmac":"c14d57b241931c303d012250d705ac684846bb2e1ca0f54b763f0836431057cf","sequence":1,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"metadata":{"model_engine":"gpt-5.5","provider":"codex","agent_role":"planner","agent_id":"0f8f9413","task_complexity":"medium","team_size":1,"session_quality":50,"groove_version":"0.27.115","leaf_context":null,"domain_tags":{"primary":{"domain":"game_dev","confidence":0.3195},"secondary":{"domain":"terraform_iac","confidence":0.2711},"tertiary":{"domain":"data_engineering","confidence":0.2643}},"session_embedding":{"model":"sentence-transformers/all-MiniLM-L6-v2","vector":[-0.06693711876869202,0.03756159171462059,0.010457690805196762,0.04468412324786186,0.002729380503296852,-0.029737668111920357,-0.06678873300552368,0.004431950394064188,-0.029793797060847282,0.03199131786823273,-0.05346382036805153,-0.052542418241500854,-0.0896829217672348,0.06104477867484093,0.0013839079765602946,-0.0016345101175829768,-0.003324210410937667,-0.11078022420406342,-0.003062125528231263,-0.04880036041140556,-0.048932887613773346,-0.051840100437402725,0.02568761073052883,0.039964400231838226,0.001537518692202866,0.040539808571338654,0.030761633068323135,0.0491737462580204,-0.07218410819768906,-0.029797852039337158,-0.0066963909193873405,0.038294192403554916,0.015140545554459095,-0.04978591948747635,0.0278309416025877,0.06458312273025513,0.006800215691328049,-0.01994621753692627,0.059406038373708725,-0.03646699711680412,-0.01317537296563387,0.006807025521993637,-0.012372791767120361,0.007981612347066402,-0.047996290028095245,-0.06941527128219604,-0.021287590265274048,0.0697072371840477,-0.0012229934800416231,0.006396177690476179,-0.017981786280870438,-0.09368792921304703,-0.021155012771487236,-0.045693740248680115,-0.006683778017759323,0.017966078594326973,-0.05211588740348816,-0.0267979484051466,0.025201359763741493,-0.12047793716192245,-0.0361454002559185,-0.025392761453986168,-0.03815518692135811,-0.018638024106621742,-0.06582809239625931,0.0019236942753195763,0.029014267027378082,0.13426721096038818,-0.0005220572929829359,-0.05717352777719498,-0.024502145126461983,-0.04326274245977402,-0.03909342736005783,-0.009473098441958427,0.0497124008834362,0.023660186678171158,0.054812654852867126,-0.054756440222263336,0.05391204357147217,-0.04714641720056534,0.028515657410025597,0.04642858728766441,-0.04145672917366028,0.10116692632436752,-0.03991951793432236,-0.04286665841937065,0.017647257074713707,0.09745117276906967,0.03830735757946968,-0.008003407157957554,-0.014752407558262348,0.04168744012713432,0.04748523607850075,-0.02546866610646248,-0.10061267018318176,0.12033362686634064,-0.027015231549739838,-0.14085499942302704,-0.005614984314888716,0.00886533036828041,0.015765583142638206,-0.0006136206211522222,0.05842571333050728,0.016121435910463333,-0.04278235509991646,-0.0030503568705171347,0.0036935152020305395,-0.028376350179314613,-0.014532533474266529,0.04114052280783653,0.0011675329878926277,-0.021999606862664223,-0.017133478075265884,0.005161401350051165,0.0396900437772274,-0.0035789432004094124,-0.09314292669296265,0.06771265715360641,0.00790176261216402,0.07370912283658981,-0.006244460120797157,0.025356663390994072,0.03252163529396057,0.038172513246536255,0.0009429815108887851,0.026619913056492805,-0.006710680201649666,-4.834445698393237e-33,0.0317494161427021,0.07065433263778687,0.008340931497514248,0.1201411709189415,0.09289234131574631,-0.020369000732898712,0.023603154346346855,0.030785277485847473,-0.06636367738246918,0.043442901223897934,0.004750489257276058,-0.042186837643384933,0.00009028187923831865,0.05069036781787872,0.07535631954669952,-0.10499453544616699,0.014247747138142586,0.0270184725522995,-0.09973820298910141,-0.011029377579689026,-0.032685618847608566,-0.006465937942266464,0.010154122486710548,-0.02717854641377926,0.12462681531906128,0.011647133156657219,0.003071556566283107,-0.008692835457623005,0.07693301141262054,0.01446034386754036,0.024890810251235962,0.06814736872911453,-0.07334719598293304,0.002170490799471736,-0.029263827949762344,0.09250277280807495,-0.06061100587248802,-0.11188185214996338,0.03905009478330612,0.0033079206477850676,-0.03201739862561226,0.005462287459522486,-0.031173614785075188,-0.020481854677200317,0.04092852398753166,0.019254270941019058,0.03622661158442497,0.0007735321414656937,0.034228887408971786,-0.041223932057619095,-0.07547527551651001,-0.00144545070361346,-0.043760668486356735,-0.04899723082780838,0.0038046231493353844,-0.020684348419308662,0.06484944373369217,-0.05336824804544449,-0.01875849813222885,0.024013284593820572,0.04057905077934265,0.054865285754203796,-0.04459976777434349,-0.019519207999110222,0.0027556102722883224,0.020701291039586067,-0.04129016026854515,0.03876744210720062,0.18292708694934845,-0.1101064383983612,-0.01986405998468399,-0.015210955403745174,0.13115163147449493,0.05985547602176666,0.006015945225954056,0.04702761769294739,-0.016290070489048958,0.03228021785616875,-0.024850063025951385,0.026119623333215714,-0.05488264933228493,-0.006398380734026432,-0.006747493054717779,-0.005061847157776356,0.0892919972538948,0.05025973916053772,0.02357408031821251,0.09547967463731766,-0.07367022335529327,0.053491003811359406,0.006920004729181528,0.015010586939752102,0.01579098030924797,0.12157966941595078,-0.06020873785018921,1.3929382141923558e-33,0.016278034076094627,-0.014178301207721233,0.04308824986219406,-0.010197533294558525,0.11034440249204636,-0.06756774336099625,0.005605938378721476,-0.12820777297019958,0.11364550143480301,0.023939447477459908,-0.13100779056549072,-0.038116730749607086,0.02452114038169384,-0.007561508100479841,-0.04172280430793762,-0.04998759552836418,0.0445985421538353,-0.11505752056837082,0.0316021703183651,-0.007184158079326153,-0.03980126231908798,-0.007068125531077385,-0.13575677573680878,0.0429917648434639,0.023145517334342003,0.04615885391831398,0.035206861793994904,-0.13508564233779907,-0.011482535861432552,0.004406603053212166,-0.019343743100762367,-0.09097670018672943,0.02864338457584381,-0.06782244145870209,0.01546765211969614,0.019078753888607025,-0.06060025095939636,0.010488520376384258,-0.031113414093852043,0.009230522438883781,0.08841842412948608,-0.04379266873002052,0.05899025499820709,0.016347873955965042,-0.026219137012958527,0.02038387954235077,-0.014200525358319283,0.009894083254039288,-0.06384336203336716,0.0022446049842983484,0.01027018390595913,0.047613710165023804,-0.0830245241522789,-0.07711603492498398,0.017686014994978905,0.026766380295157433,0.02611905336380005,-0.07114812731742859,0.06848011165857315,0.04019796475768089,-0.0353044793009758,0.04928945004940033,0.04998962581157684,0.10279839485883713,-0.01383902132511139,0.01666494645178318,-0.027739690616726875,-0.05444987118244171,0.007934018038213253,-0.00008676606375956908,-0.036469899117946625,0.04313051328063011,0.01788181997835636,-0.0031711673364043236,0.011032620444893837,-0.08506286889314651,0.0029793395660817623,0.009692475199699402,0.012268202379345894,0.052996765822172165,-0.021802926436066628,0.04182073846459389,-0.040531259030103683,0.03108423575758934,-0.00071404327172786,0.02872210554778576,-0.02999175526201725,0.051085226237773895,0.00921647995710373,0.06241995841264725,-0.020895760506391525,-0.038975074887275696,0.04905983433127403,-0.03376005217432976,0.03695639967918396,-2.4303401957581627e-8,0.03082858957350254,0.06290039420127869,-0.005677367560565472,-0.03198196366429329,0.02765379473567009,-0.08999671041965485,-0.04596478492021561,-0.012033313512802124,0.10859999060630798,0.04584134370088577,0.041828371584415436,0.029676562175154686,-0.07500626891851425,0.010680696927011013,-0.011483248323202133,-0.010828768834471703,0.006966833490878344,0.07397440075874329,-0.027604015544056892,-0.06020504608750343,-0.021679310128092766,0.01734982803463936,-0.09294107556343079,-0.015492177568376064,0.022490480914711952,-0.016370315104722977,-0.11188998073339462,0.023930232971906662,-0.008641882799565792,0.042171284556388855,-0.01778116449713707,0.0352688692510128,0.0006121583865024149,0.05162434279918671,0.00946846418082714,-0.058817308396101,-0.06093035265803337,-0.05471249669790268,0.03433128818869591,0.024074459448456764,0.021978890523314476,0.07237174361944199,-0.05034384876489639,0.014771189540624619,-0.029563160613179207,-0.04772720858454704,-0.06582613289356232,-0.08140838891267776,-0.07585163414478302,-0.058470383286476135,-0.05282985046505928,-0.01877354271709919,0.04150386527180672,0.03611302003264427,0.12656284868717194,0.07502514123916626,-0.012954971753060818,-0.04893255606293678,0.024131637066602707,0.013823425397276878,0.022045692428946495,-0.009787112474441528,-0.10270018875598907,0.05586628243327141],"source_text":"planner\nI’m planner-15, ready to create a team plan and route work for this project; what would you like the team to work on?"}},"outcome":{"status":"SUCCESS","session_quality":50,"quality_tier":"TIER_B","quality_tier_reason":"moderate_quality","user_interventions":0,"total_steps":2,"total_chunks":1,"total_tokens":31,"duration_seconds":3,"files_modified":0,"errors_encountered":0,"errors_recovered":0,"coordination_events":0,"training_eligible":false,"training_exclusion_reason":"too_few_steps"}}
3
+ {"envelope_id":"env_09a682fb-de06-420a-9164-e44aa67a3520","session_id":"sess_a3717729-38ba-4b17-bc7b-ee6de297819c","type":"USER_FEEDBACK","attestation":{"session_hmac":"b3ce4560438facbc7a2719ea53aca69cd135a3edda800a692ae424fcdda33367","sequence":2,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"feedback":{"signal":"accepted","timestamp":1777357868.451,"context":"session completed successfully with no user interventions","target_step":2,"revision_rounds":0,"delta_summary":null}}
4
+ {"envelope_id":"env_1317b05c-9986-4d33-b386-4020575623cb","session_id":"sess_2bcbe7fe-a1b0-488e-bf66-a20381bb57ea","chunk_sequence":0,"contributor_id":"23e6dd8c4a884836bf78cafda9fbe57d","attestation":{"session_hmac":"1ff8b76c0044294d19713e0bc4b36ef76f7eae2daf6eafd0d00d11b1ed2c227c","sequence":0,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"metadata":{"model_engine":"gpt-5.5","provider":"codex","agent_role":"planner","agent_id":"c7f1a11c","task_complexity":"medium","team_size":1,"session_quality":0,"groove_version":"0.27.115","leaf_context":null},"trajectory_log":[{"step":1,"type":"thought","timestamp":1777357911.75,"content":"I’ll quickly check the team registry and the relevant app entry points, then route the work without implementing it.","token_count":29},{"step":2,"type":"action","timestamp":1777357912.464,"tool":"command_execution","arguments":{"command":"/bin/zsh -lc 'pwd && ls && (test -f AGENTS_REGISTRY.md && cat AGENTS_REGISTRY.md || true) && (test -f .groove/recommended-team.json && cat .groove/recommended-team.json || true)'"},"content":"Executing: /bin/zsh -lc 'pwd && ls && (test -f AGENTS_REGISTRY.md && cat AGENTS_REGISTRY.md || true) && (test -f .groove/recommended-team.json && cat .groove/recommended-team.json || true)'","token_count":96},{"step":3,"type":"observation","timestamp":1777357912.512,"is_error":false,"content":"~/Desktop/groove-project/groove/codex\n","truncated":false,"original_token_count":12,"token_count":10},{"step":4,"type":"thought","timestamp":1777357919.886,"content":"No registry surfaced in the current folder, so I’m checking hidden project metadata and nearby package hints.","token_count":28},{"step":5,"type":"action","timestamp":1777357920.233,"tool":"command_execution","arguments":{"command":"/bin/zsh -lc \"ls -la && find . -maxdepth 3 -type f \\\\( -name 'AGENTS_REGISTRY.md' -o -name 'recommended-team.json' -o -name 'package.json' -o -name 'README.md' \\\\) -print\""},"content":"Executing: /bin/zsh -lc \"ls -la && find . -maxdepth 3 -type f \\\\( -name 'AGENTS_REGISTRY.md' -o -name 'recommended-team.json' -o -name 'package.json' -o -name 'README.md' \\\\) -print\"","token_count":94},{"step":6,"type":"observation","timestamp":1777357920.285,"is_error":false,"content":"total 0\ndrwxr-xr-x@ 2 rok staff 64 Apr 27 23:30 .\ndrwxr-xr-x@ 52 rok staff 1664 Apr 27 23:31 ..\n","truncated":false,"original_token_count":26,"token_count":26},{"step":7,"type":"thought","timestamp":1777357941.242,"content":"I’ll create the routing config for a new static landing-page project in this empty workspace.","token_count":24},{"step":8,"type":"action","timestamp":1777357947.238,"tool":"command_execution","arguments":{"command":"/bin/zsh -lc \"mkdir -p .groove && cat > .groove/recommended-team.json <<'EOF'\n{\n \\\"projectDir\\\": \\\"coming-soon-landing\\\",\n \\\"agents\\\": [\n {\n \\\"role\\\": \\\"frontend\\\",\n \\\"phase\\\": 1,\n \\\"scope\\\": [\n \\\"**/*\\\"\n ],\n \\\"prompt\\\": \\\"Build a basic static coming-soon landing page with a 5-day countdown. Create a small self-contained site in this project directory with an index.html entry point plus any needed CSS/JS assets. The page should include a clear product/brand placeholder headline, short supporting copy, email signup UI as a non-submitting visual form or safe mailto-free placeholder, and a responsive countdown showing days, hours, minutes, and seconds. The countdown should start at 5 days for a first-time visitor and persist the target timestamp in localStorage so refreshing does not reset it. Keep the design polished but lightweight, mobile-friendly, accessible, and dependency-free unless a minimal toolchain is already created by you. Do not delete unrelated files.\\\"\n },\n {\n \\\"role\\\": \\\"fullstack\\\",\n \\\"phase\\\": 2,\n \\\"scope\\\": [],\n \\\"prompt\\\": \\\"QC Senior Dev: Audit the frontend landing page for correctness, accessibility, responsiveness, and countdown behavior. Verify the countdown persists across refreshes via localStorage and handles expiry cleanly. Run any available validation/build commands if the frontend agent added a toolchain; otherwise inspect the static files directly. Do NOT start long-running dev servers. Do NOT open files in a browser with an 'open' command. Commit all changes.\\\"\n }\n ],\n \\\"preview\\\": {\n \\\"kind\\\": \\\"static-html\\\",\n \\\"command\\\": \\\"\\\",\n \\\"openPath\\\": \\\"index.html\\\"\n }\n}\nEOF\ncat .groove/recommended-team.json\""},"content":"Executing: /bin/zsh -lc \"mkdir -p .groove && cat > .groove/recommended-team.json <<'EOF'\n{\n \\\"projectDir\\\": \\\"coming-soon-landing\\\",\n \\\"agents\\\": [\n {\n \\\"role\\\": \\\"frontend\\\",\n \\\"phase\\\": 1,\n \\\"scope\\\": [\n \\\"**/*\\\"\n ],\n \\\"prompt\\\": \\\"Build a basic static coming-soon landing page with a 5-day countdown. Create a small self-contained site in this project directory with an index.html entry point plus any needed CSS/JS assets. The page should include a clear product/brand placeholder headline, short supporting copy, email signup UI as a non-submitting visual form or safe mailto-free placeholder, and a responsive countdown showing days, hours, minutes, and seconds. The countdown should start at 5 days for a first-time visitor and persist the target timestamp in localStorage so refreshing does not reset it. Keep the design polished but lightweight, mobile-friendly, accessible, and dependency-free unless a minimal toolchain is already created by you. Do not delete unrelated files.\\\"\n },\n {\n \\\"role\\\": \\\"fullstack\\\",\n \\\"phase\\\": 2,\n \\\"scope\\\": [],\n \\\"prompt\\\": \\\"QC Senior Dev: Audit the frontend landing page for correctness, accessibility, responsiveness, and countdown behavior. Verify the countdown persists across refreshes via localStorage and handles expiry cleanly. Run any available validation/build commands if the frontend agent added a toolchain; otherwise inspect the static files directly. Do NOT start long-running dev servers. Do NOT open files in a browser with an 'open' command. Commit all changes.\\\"\n }\n ],\n \\\"preview\\\": {\n \\\"kind\\\": \\\"static-html\\\",\n \\\"command\\\": \\\"\\\",\n \\\"openPath\\\": \\\"index.html\\\"\n }\n}\nEOF\ncat .groove/recommended-team.json\"","token_count":906},{"step":9,"type":"observation","timestamp":1777357947.29,"is_error":false,"content":"{\n \"projectDir\": \"coming-soon-landing\",\n \"agents\": [\n {\n \"role\": \"frontend\",\n \"phase\": 1,\n \"scope\": [\n \"**/*\"\n ],\n \"prompt\": \"Build a basic static coming-soon landing page with a 5-day countdown. Create a small self-contained site in this project directory with an index.html entry point plus any needed CSS/JS assets. The page should include a clear product/brand placeholder headline, short supporting copy, email signup UI as a non-submitting visual form or safe mailto-free placeholder, and a responsive countdown showing days, hours, minutes, and seconds. The countdown should start at 5 days for a first-time visitor and persist the target timestamp in localStorage so refreshing does not reset it. Keep the design polished but lightweight, mobile-friendly, accessible, and dependency-free unless a minimal toolchain is already created by you. Do not delete unrelated files.\"\n },\n {\n \"role\": \"fullstack\",\n \"phase\": 2,\n \"scope\": [],\n \"prompt\": \"QC Senior Dev: Audit the frontend landing page for correctness, accessibility, responsiveness, and countdown behavior. Verify the countdown persists across refreshes via localStorage and handles expiry cleanly. Run any available validation/build commands if the frontend agent added a toolchain; otherwise inspect the static files directly. Do NOT start long-running dev servers. Do NOT open files in a browser with an 'open' command. Commit all changes.\"\n }\n ],\n \"preview\": {\n \"kind\": \"static-html\",\n \"command\": \"\",\n \"openPath\": \"index.html\"\n }\n}\n","truncated":false,"original_token_count":394,"token_count":394},{"step":10,"type":"thought","timestamp":1777357951.62,"content":"Routing plan written to `.groove/recommended-team.json:1`.\n\n- Created a new-project team plan for `coming-soon-landing`.\n- Assigned `frontend` to build a static `index.html` coming-soon page with a persisted 5-day countdown.\n- Assigned `fullstack` as phase 2 QC to verify responsiveness, accessibility, countdown persistence, and expiry behavior.\n- Configured preview as `static-html` opening `index.html`.\n\nNo source code was implemented by me.","token_count":112},{"step":11,"type":"resolution","timestamp":1777357951.695,"content":"","token_count":1}]}
5
+ {"envelope_id":"env_35478843-ef60-461d-b3ce-422d07270005","session_id":"sess_2bcbe7fe-a1b0-488e-bf66-a20381bb57ea","type":"SESSION_CLOSE","attestation":{"session_hmac":"47fb2e06056a87f6491a6ac83f84e2f169090d33732da961f2ad2fd2a81393eb","sequence":1,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"metadata":{"model_engine":"gpt-5.5","provider":"codex","agent_role":"planner","agent_id":"c7f1a11c","task_complexity":"medium","team_size":1,"session_quality":60,"groove_version":"0.27.115","leaf_context":null,"domain_tags":{"primary":{"domain":"ci_cd","confidence":0.2656},"secondary":{"domain":"terraform_iac","confidence":0.2173},"tertiary":{"domain":"csharp_dotnet","confidence":0.1886}},"session_embedding":{"model":"sentence-transformers/all-MiniLM-L6-v2","vector":[-0.02388685755431652,-0.060105498880147934,-0.023632973432540894,0.0032994654029607773,0.01703188754618168,-0.027073629200458527,-0.06481088697910309,-0.017189089208841324,-0.05652660131454468,0.014533017762005329,-0.01777762547135353,0.02002338506281376,-0.05209732800722122,0.04445069283246994,-0.007964960299432278,0.04861873760819435,-0.012648002244532108,-0.08211388438940048,0.051421307027339935,-0.029105566442012787,0.0005955102969892323,0.022396843880414963,0.022131549194455147,0.04424780607223511,-0.01220770739018917,0.004836526699364185,0.028830472379922867,0.041462864726781845,0.026998143643140793,-0.000980757991783321,0.012424197047948837,0.11313086003065109,-0.07381390035152435,-0.01920468732714653,0.13104867935180664,0.07106650620698929,0.03553297743201256,0.010054200887680054,0.023640574887394905,-0.026549845933914185,0.0605519637465477,0.015304633416235447,0.03918188437819481,0.04107779636979103,-0.01577165350317955,-0.06581766158342361,0.0033992244862020016,-0.0348748154938221,0.005415500141680241,-0.0031897486187517643,0.03264386206865311,-0.09864047169685364,0.02709083817899227,-0.08861556649208069,-0.000052495539421215653,0.06640173494815826,0.04121771827340126,0.0004893096629530191,-0.00977682787925005,-0.07920201122760773,0.13322006165981293,-0.043157704174518585,-0.016540568321943283,-0.054678160697221756,-0.095985047519207,0.05884283408522606,0.0032373068388551474,0.009309493005275726,0.08217776566743851,-0.05484403297305107,-0.07754853367805481,-0.019648581743240356,-0.027543600648641586,-0.027237258851528168,0.02558710239827633,0.00013364652113523334,0.023264585062861443,0.0011471020989120007,0.06965775042772293,-0.13843274116516113,0.08088801056146622,0.013594448566436768,0.029804017394781113,0.12125246226787567,0.033591799437999725,-0.05364574119448662,0.018196476623415947,0.009922769851982594,0.09473657608032227,0.07483018189668655,-0.03030695952475071,-0.048255182802677155,0.0418412871658802,-0.07262617349624634,-0.11693336069583893,0.05892452597618103,-0.038537364453077316,-0.03292952477931976,-0.030068717896938324,0.08499839156866074,-0.05652804300189018,-0.02501920610666275,0.03261302784085274,0.021289926022291183,0.028933417052030563,0.022540424019098282,0.04930088669061661,-0.011273123323917389,-0.0009935525013133883,0.0701846033334732,-0.01747896708548069,-0.01582796312868595,0.007453564554452896,0.0068029495887458324,-0.07404918223619461,-0.00664112251251936,-0.023154813796281815,0.001421975321136415,-0.055900655686855316,0.021410414949059486,-0.03479393199086189,0.0009077505674213171,0.0983644649386406,0.031113509088754654,-0.02366735227406025,-0.017292210832238197,-0.05703660100698471,9.485468911323095e-34,0.049997519701719284,0.08261831104755402,-0.015507739037275314,0.027001556009054184,0.04633799567818642,-0.09600644558668137,0.03635014221072197,0.010093399323523045,-0.003712594276294112,-0.00631878525018692,-0.026720624417066574,0.010993762873113155,0.07502569258213043,-0.00509985676035285,-0.01989608444273472,-0.05150638148188591,0.0054930527694523335,0.03485715761780739,-0.001701683853752911,-0.06095350533723831,-0.05227480083703995,-0.04240967705845833,-0.03602784126996994,-0.07175292074680328,0.12459434568881989,0.054003290832042694,-0.027733396738767624,0.022252900525927544,0.049904536455869675,0.019711073487997055,0.04208594188094139,0.0926598459482193,0.011147594079375267,0.03464190661907196,-0.059706829488277435,0.0705917552113533,-0.06051686778664589,-0.09401654452085495,0.05709428712725639,0.1019669696688652,-0.005356642417609692,-0.036960046738386154,-0.039272770285606384,-0.04939410835504532,0.014264113269746304,-0.03555767238140106,-0.013013712130486965,-0.051901645958423615,0.17037756741046906,-0.03869776427745819,-0.017398767173290253,-0.020863287150859833,-0.0091478256508708,0.030313894152641296,-0.009502967819571495,-0.10463112592697144,-0.034701697528362274,-0.029594063758850098,0.08568678051233292,0.028067853301763535,0.00702727772295475,-0.020609155297279358,-0.0953810065984726,0.04143253341317177,-0.027815813198685646,0.02031555026769638,-0.06704629212617874,0.044165097177028656,0.08477029949426651,-0.09975844621658325,0.01727958954870701,0.000894423050340265,0.08260852843523026,0.0006351986667141318,-0.02283228561282158,0.028247075155377388,-0.05774255469441414,0.05414297804236412,-0.0931570902466774,0.013774513266980648,0.013258248567581177,0.009294215589761734,0.004645416978746653,0.025863856077194214,0.03964362293481827,-0.02484980970621109,0.029589718207716942,0.03249607980251312,-0.035005245357751846,0.08652828633785248,-0.035142406821250916,-0.00884088221937418,-0.029139533638954163,0.12507598102092743,0.02195696160197258,-3.289483573169272e-37,0.018034616485238075,0.019557246938347816,-0.033867284655570984,0.002278698608279228,0.03126790374517441,-0.02864532545208931,0.06274496018886566,-0.05692826583981514,0.04448181763291359,0.0591057650744915,-0.04386522248387337,0.02608109451830387,0.01508491113781929,-0.041225191205739975,-0.002441790420562029,-0.035356178879737854,0.0071209389716386795,-0.054987628012895584,0.04377412423491478,0.04183093085885048,-0.00621685478836298,-0.031353116035461426,-0.10444547981023788,-0.0833139568567276,0.05675416439771652,0.0362086184322834,0.04481751471757889,-0.04107509180903435,-0.07948796451091766,0.003126996336504817,-0.010310756973922253,-0.003558435710147023,-0.048596419394016266,-0.11138182133436203,0.02340853400528431,0.06813378632068634,-0.13512185215950012,0.01128294039517641,-0.024462617933750153,-0.06024760380387306,0.06362652033567429,-0.004108428955078125,-0.020379841327667236,0.09104712307453156,0.009642861783504486,0.0021345391869544983,0.07418365031480789,-0.033214300870895386,-0.02716899663209915,-0.029562801122665405,0.04602033272385597,0.01990636996924877,-0.04943450540304184,-0.038352664560079575,0.005142817273736,0.16565272212028503,0.008641287684440613,-0.03526175022125244,-0.01924167387187481,0.010664568282663822,0.054390184581279755,-0.008514161221683025,-0.0618470199406147,0.10752137005329132,0.014099428430199623,-0.00508504081517458,-0.009550908580422401,0.08488281816244125,-0.037636417895555496,0.03946157544851303,-0.10607825964689255,0.042513005435466766,0.025197044014930725,0.013312465511262417,0.010461016558110714,-0.053037941455841064,0.08911341428756714,0.016598965972661972,0.025846417993307114,0.01968512125313282,-0.061517030000686646,0.02003258280456066,-0.042076341807842255,-0.057019345462322235,0.005304405931383371,0.021328125149011612,-0.05654192343354225,0.06762088090181351,-0.03129829466342926,0.07132996618747711,-0.01712295040488243,-0.03540065884590149,0.06953057646751404,-0.034674271941185,0.0068288929760456085,-4.765118788441214e-8,0.021352697163820267,0.1262984275817871,-0.006307561881840229,-0.03768131881952286,0.04515105113387108,0.030682465061545372,0.022922370582818985,0.03771546110510826,0.06148586794734001,0.05424340069293976,-0.05243263766169548,-0.008472433313727379,-0.0981537327170372,0.07113897800445557,-0.054021935909986496,-0.013147328980267048,-0.003634627675637603,0.0749971941113472,-0.08111397922039032,-0.08387390524148941,-0.08342036604881287,0.01695854775607586,-0.026544621214270592,0.0368790365755558,-0.016829654574394226,0.035303663462400436,-0.03214229643344879,-0.01911233365535736,0.043698012828826904,0.0414605550467968,-0.03473788499832153,0.06389732658863068,-0.045386821031570435,0.04035051539540291,-0.026537632569670677,0.040752001106739044,-0.0030007059685885906,0.008067303337156773,0.00835010688751936,0.0029566672164946795,0.029438525438308716,0.04444463551044464,0.006823315285146236,-0.0028545972891151905,-0.01422444824129343,0.0022671471815556288,-0.027213815599679947,-0.047464873641729355,0.0025221756659448147,-0.06314513832330704,-0.090935617685318,-0.010546295903623104,-0.012237844057381153,0.06477628648281097,0.0828094407916069,0.08613219857215881,-0.03376612439751625,-0.11163280159235,0.018945032730698586,0.02491677738726139,-0.03860095888376236,-0.04143964871764183,-0.048489443957805634,-0.021546607837080956],"source_text":"planner\nI’ll quickly check the team registry and the relevant app entry points, then route the work without implementing it.\nNo registry surfaced in the current folder, so I’m checking hidden project metadata and nearby package hints.\nI’ll create the routing config for a new static landing-page project in this empty workspace."}},"outcome":{"status":"SUCCESS","session_quality":60,"quality_tier":"TIER_B","quality_tier_reason":"moderate_quality","user_interventions":0,"total_steps":11,"total_chunks":1,"total_tokens":1720,"duration_seconds":45,"files_modified":0,"errors_encountered":0,"errors_recovered":0,"coordination_events":0,"training_eligible":true,"training_exclusion_reason":null}}
6
+ {"envelope_id":"env_14658ff7-104e-4448-b50c-36cdd70103fb","session_id":"sess_2bcbe7fe-a1b0-488e-bf66-a20381bb57ea","type":"USER_FEEDBACK","attestation":{"session_hmac":"3df52d98395ea0b79e95f8bf90e821057b8fc1879d96d41448584faaf99caa19","sequence":2,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"feedback":{"signal":"accepted","timestamp":1777357952.417,"context":"session completed successfully with no user interventions","target_step":11,"revision_rounds":0,"delta_summary":null}}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/cli",
3
- "version": "0.27.113",
3
+ "version": "0.27.116",
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,9 +1,17 @@
1
1
  // GROOVE CLI — team commands
2
2
  // FSL-1.1-Apache-2.0 — see LICENSE
3
3
 
4
+ import { createInterface } from 'readline';
4
5
  import chalk from 'chalk';
5
6
  import { apiCall } from '../client.js';
6
7
 
8
+ function prompt(question) {
9
+ return new Promise((resolve) => {
10
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
11
+ rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); });
12
+ });
13
+ }
14
+
7
15
  export async function teamCreate(name) {
8
16
  try {
9
17
  const team = await apiCall('POST', '/api/teams', { name });
@@ -37,9 +45,58 @@ export async function teamList() {
37
45
  }
38
46
 
39
47
  export async function teamDelete(id) {
48
+ const choice = await prompt(` Archive or permanently delete? [${chalk.bold('a')}rchive / ${chalk.bold('D')}elete] `);
49
+ const normalized = choice.toLowerCase();
50
+
51
+ if (normalized === 'd' || normalized === 'delete') {
52
+ const teamName = await prompt(chalk.yellow(' WARNING: All files in this team will be permanently lost.\n') + ` Type the team name to confirm: `);
53
+ if (!teamName) {
54
+ console.log(chalk.dim(' Cancelled.'));
55
+ return;
56
+ }
57
+ try {
58
+ await apiCall('DELETE', `/api/teams/${encodeURIComponent(id)}?permanent=true`);
59
+ console.log(chalk.green(` Permanently deleted team "${id}".`));
60
+ } catch (err) {
61
+ console.error(chalk.red(' Failed:'), err.message);
62
+ process.exit(1);
63
+ }
64
+ } else if (normalized === 'a' || normalized === 'archive' || normalized === '') {
65
+ try {
66
+ await apiCall('DELETE', `/api/teams/${encodeURIComponent(id)}`);
67
+ console.log(chalk.green(` Archived team "${id}"`) + chalk.dim(' — restore with `groove team restore <id>`'));
68
+ } catch (err) {
69
+ console.error(chalk.red(' Failed:'), err.message);
70
+ process.exit(1);
71
+ }
72
+ } else {
73
+ console.log(chalk.dim(' Cancelled.'));
74
+ }
75
+ }
76
+
77
+ export async function teamArchived() {
78
+ try {
79
+ const { archived } = await apiCall('GET', '/api/teams/archived');
80
+ if (archived.length === 0) {
81
+ console.log(chalk.dim(' No archived teams.'));
82
+ return;
83
+ }
84
+ console.log(chalk.bold(`\n Archived Teams (${archived.length})\n`));
85
+ for (const t of archived) {
86
+ const date = t.deletedAt ? new Date(t.deletedAt).toLocaleDateString() : 'unknown';
87
+ console.log(` ${chalk.bold(t.originalName || t.id)} — archive-id: ${t.id} — deleted ${date} — ${t.agentCount} agent(s)`);
88
+ }
89
+ console.log('');
90
+ } catch {
91
+ console.error(chalk.red(' Cannot connect to daemon.'));
92
+ process.exit(1);
93
+ }
94
+ }
95
+
96
+ export async function teamRestore(id) {
40
97
  try {
41
- await apiCall('DELETE', `/api/teams/${encodeURIComponent(id)}`);
42
- console.log(chalk.green(` Deleted team "${id}"`));
98
+ const team = await apiCall('POST', `/api/teams/archived/${encodeURIComponent(id)}/restore`);
99
+ console.log(chalk.green(` Restored team "${team.name}"`) + ` (new id: ${team.id})`);
43
100
  } catch (err) {
44
101
  console.error(chalk.red(' Failed:'), err.message);
45
102
  process.exit(1);
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@groove-dev/daemon",
3
- "version": "0.27.113",
3
+ "version": "0.27.116",
4
4
  "description": "GROOVE daemon — agent orchestration engine",
5
5
  "license": "FSL-1.1-Apache-2.0",
6
6
  "type": "module",
@@ -1100,6 +1100,30 @@ export function createApi(app, daemon) {
1100
1100
  }
1101
1101
  });
1102
1102
 
1103
+ app.get('/api/teams/archived', (req, res) => {
1104
+ res.json({ archived: daemon.teams.listArchived() });
1105
+ });
1106
+
1107
+ app.post('/api/teams/archived/:id/restore', (req, res) => {
1108
+ try {
1109
+ const team = daemon.teams.restore(req.params.id);
1110
+ daemon.audit.log('team.restore', { archivedId: req.params.id, newId: team.id, name: team.name });
1111
+ res.json(team);
1112
+ } catch (err) {
1113
+ res.status(400).json({ error: err.message });
1114
+ }
1115
+ });
1116
+
1117
+ app.delete('/api/teams/archived/:id', (req, res) => {
1118
+ try {
1119
+ daemon.teams.purge(req.params.id);
1120
+ daemon.audit.log('team.purge', { archivedId: req.params.id });
1121
+ res.json({ ok: true });
1122
+ } catch (err) {
1123
+ res.status(400).json({ error: err.message });
1124
+ }
1125
+ });
1126
+
1103
1127
  app.patch('/api/teams/:id', (req, res) => {
1104
1128
  try {
1105
1129
  if (req.body.name) daemon.teams.rename(req.params.id, req.body.name);
@@ -1114,8 +1138,9 @@ export function createApi(app, daemon) {
1114
1138
 
1115
1139
  app.delete('/api/teams/:id', (req, res) => {
1116
1140
  try {
1117
- daemon.teams.delete(req.params.id);
1118
- daemon.audit.log('team.delete', { id: req.params.id });
1141
+ const permanent = req.query.permanent === 'true';
1142
+ daemon.teams.delete(req.params.id, { permanent });
1143
+ daemon.audit.log(permanent ? 'team.delete' : 'team.archive', { id: req.params.id, permanent });
1119
1144
  res.json({ ok: true });
1120
1145
  } catch (err) {
1121
1146
  res.status(400).json({ error: err.message });
@@ -8,6 +8,7 @@ export class FileWatcher {
8
8
  constructor(daemon) {
9
9
  this.daemon = daemon;
10
10
  this.watchers = new Map(); // relPath → { watcher, timer }
11
+ this.dirWatchers = new Map(); // relPath → { watcher, timer }
11
12
  }
12
13
 
13
14
  watch(relPath) {
@@ -51,9 +52,53 @@ export class FileWatcher {
51
52
  this.watchers.delete(relPath);
52
53
  }
53
54
 
55
+ watchDir(relPath) {
56
+ if (typeof relPath !== 'string') return;
57
+ if (relPath && relPath.includes('..')) return;
58
+ if (this.dirWatchers.has(relPath)) return;
59
+
60
+ const fullPath = relPath ? resolve(this.daemon.projectDir, relPath) : this.daemon.projectDir;
61
+
62
+ try {
63
+ const watcher = watch(fullPath, () => {
64
+ const entry = this.dirWatchers.get(relPath);
65
+ if (!entry) return;
66
+
67
+ if (entry.timer) clearTimeout(entry.timer);
68
+ entry.timer = setTimeout(() => {
69
+ this.daemon.broadcast({
70
+ type: 'file:tree-changed',
71
+ path: relPath,
72
+ timestamp: Date.now(),
73
+ });
74
+ }, 300);
75
+ });
76
+
77
+ watcher.on('error', () => {
78
+ this.unwatchDir(relPath);
79
+ });
80
+
81
+ this.dirWatchers.set(relPath, { watcher, timer: null });
82
+ } catch {
83
+ // Directory doesn't exist or not watchable — ignore
84
+ }
85
+ }
86
+
87
+ unwatchDir(relPath) {
88
+ const entry = this.dirWatchers.get(relPath);
89
+ if (!entry) return;
90
+
91
+ if (entry.timer) clearTimeout(entry.timer);
92
+ try { entry.watcher.close(); } catch { /* already closed */ }
93
+ this.dirWatchers.delete(relPath);
94
+ }
95
+
54
96
  unwatchAll() {
55
97
  for (const [relPath] of this.watchers) {
56
98
  this.unwatch(relPath);
57
99
  }
100
+ for (const [relPath] of this.dirWatchers) {
101
+ this.unwatchDir(relPath);
102
+ }
58
103
  }
59
104
  }
@@ -325,8 +325,9 @@ export class Daemon {
325
325
  data: enrichAgents(this.registry.getAll()),
326
326
  }));
327
327
 
328
- // Track which files this client is watching (for cleanup on disconnect)
328
+ // Track which files/dirs this client is watching (for cleanup on disconnect)
329
329
  const watchedFiles = new Set();
330
+ const watchedDirs = new Set();
330
331
 
331
332
  ws.on('message', (raw) => {
332
333
  try {
@@ -335,7 +336,7 @@ export class Daemon {
335
336
  // Validate message type against whitelist
336
337
  const VALID_WS_TYPES = new Set([
337
338
  'terminal:spawn', 'terminal:resize', 'terminal:input', 'terminal:close', 'terminal:kill', 'terminal:rename',
338
- 'editor:watch', 'editor:unwatch', 'editor:save',
339
+ 'editor:watch', 'editor:unwatch', 'editor:save', 'editor:watchdir', 'editor:unwatchdir',
339
340
  'ping'
340
341
  ]);
341
342
  if (!msg || typeof msg !== 'object' || !VALID_WS_TYPES.has(msg.type)) return;
@@ -351,6 +352,14 @@ export class Daemon {
351
352
  case 'editor:unwatch':
352
353
  if (msg.path) { this.fileWatcher.unwatch(msg.path); watchedFiles.delete(msg.path); }
353
354
  break;
355
+ case 'editor:watchdir':
356
+ if (typeof msg.path === 'string' && !msg.path.includes('..')) {
357
+ this.fileWatcher.watchDir(msg.path); watchedDirs.add(msg.path);
358
+ }
359
+ break;
360
+ case 'editor:unwatchdir':
361
+ if (typeof msg.path === 'string') { this.fileWatcher.unwatchDir(msg.path); watchedDirs.delete(msg.path); }
362
+ break;
354
363
  // Terminal
355
364
  case 'terminal:spawn': {
356
365
  if (msg.cwd !== undefined && (typeof msg.cwd !== 'string' || msg.cwd.includes('..'))) break;
@@ -389,6 +398,9 @@ export class Daemon {
389
398
  for (const path of watchedFiles) {
390
399
  this.fileWatcher.unwatch(path);
391
400
  }
401
+ for (const path of watchedDirs) {
402
+ this.fileWatcher.unwatchDir(path);
403
+ }
392
404
  this.terminalManager.cleanupClient(ws);
393
405
  });
394
406
  });