groove-dev 0.27.115 → 0.27.117
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.
- package/TRAINING_DATA_v4.md +6 -3
- package/moe-training/client/domain-tagger.js +20 -0
- package/moe-training/client/trajectory-capture.js +36 -7
- package/moe-training/test/client/trajectory-capture.test.js +182 -1
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/cli/src/commands/team.js +27 -12
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +3 -2
- package/node_modules/@groove-dev/daemon/src/process.js +283 -211
- package/node_modules/@groove-dev/daemon/src/teams.js +53 -24
- package/node_modules/@groove-dev/daemon/src/tunnel-manager.js +21 -3
- package/node_modules/@groove-dev/gui/dist/assets/{index-D4Q72afD.css → index-DdN9RVnC.css} +1 -1
- package/node_modules/@groove-dev/gui/dist/assets/{index-BKCiOUDb.js → index-fq--PD7_.js} +1724 -1724
- package/node_modules/@groove-dev/gui/dist/index.html +2 -2
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/teams/team-removal-dialog.jsx +156 -0
- package/node_modules/@groove-dev/gui/src/stores/groove.js +15 -4
- package/node_modules/@groove-dev/gui/src/views/agents.jsx +10 -19
- package/node_modules/@groove-dev/gui/src/views/teams.jsx +17 -41
- package/node_modules/moe-training/client/domain-tagger.js +20 -0
- package/node_modules/moe-training/client/trajectory-capture.js +36 -7
- package/node_modules/moe-training/test/client/trajectory-capture.test.js +182 -1
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/cli/src/commands/team.js +27 -12
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +3 -2
- package/packages/daemon/src/process.js +283 -211
- package/packages/daemon/src/teams.js +53 -24
- package/packages/daemon/src/tunnel-manager.js +21 -3
- package/packages/gui/dist/assets/{index-D4Q72afD.css → index-DdN9RVnC.css} +1 -1
- package/packages/gui/dist/assets/{index-BKCiOUDb.js → index-fq--PD7_.js} +1724 -1724
- package/packages/gui/dist/index.html +2 -2
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/teams/team-removal-dialog.jsx +156 -0
- package/packages/gui/src/stores/groove.js +15 -4
- package/packages/gui/src/views/agents.jsx +10 -19
- package/packages/gui/src/views/teams.jsx +17 -41
package/TRAINING_DATA_v4.md
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
-
{"envelope_id":"env_70dfa132-575b-48a3-becc-a2ea8a75aecc","session_id":"sess_54e35697-302f-45bc-bc3e-c4282b5f6034","chunk_sequence":0,"contributor_id":"23e6dd8c4a884836bf78cafda9fbe57d","attestation":{"session_hmac":"9f2d5a6369edcb2545181101574e61e02c65e939e253c068d398d2cbf8f20cd4","sequence":0,"app_version_hash":"4a527565d85cc601d3c47c376e4f361d5af987de58f60cf71dbc263a0de91247"},"metadata":{"model_engine":"claude-opus-4-6","provider":"claude-code","agent_role":"fullstack","agent_id":"e18a8fa4","task_complexity":"medium","team_size":2,"session_quality":0,"groove_version":"0.27.113","leaf_context":null},"trajectory_log":[{"step":1,"type":"thought","timestamp":1777354900.276,"content":"Let me trace the exact URL the client is using.","token_count":12},{"step":2,"type":"action","timestamp":1777354901.244,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && grep -n 'EMBEDDING_SERVICE_URL\\|CENTRAL_COMMAND_URL' moe-training/shared/constants.js"},"content":"Using Bash","token_count":37},{"step":3,"type":"observation","timestamp":1777354901.808,"content":"41:export const CENTRAL_COMMAND_URL = process.env.GROOVE_CENTRAL_URL || 'https://api.groovedev.ai';\n42:export const EMBEDDING_SERVICE_URL = process.env.EMBEDDING_SERVICE_URL || `${CENTRAL_COMMAND_URL}/v1/embed`;\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":71,"is_error":false,"tool":"Bash","token_count":69},{"step":4,"type":"action","timestamp":1777354905.484,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && grep -n 'serviceUrl\\|EMBEDDING' moe-training/client/domain-tagger.js | head -10"},"content":"Using Bash","token_count":36},{"step":5,"type":"observation","timestamp":1777354905.528,"content":"3:import { EMBEDDING_SERVICE_URL } from '../shared/constants.js';\n176: this._serviceUrl = options.serviceUrl !== undefined ? options.serviceUrl : EMBEDDING_SERVICE_URL;\n208: if (this._serviceUrl) {\n210: const res = await fetch(this._serviceUrl, {\n361: const res = await fetch(this._serviceUrl, {\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":97,"is_error":false,"tool":"Bash","token_count":95},{"step":6,"type":"thought","timestamp":1777354911.293,"content":"The constant looks correct — `https://api.groovedev.ai/v1/embed`, no trailing slash. But let me check what the DomainTagger actually receives at runtime. The `TrajectoryCapture` creates the DomainTagger — let me see if it passes any options.","token_count":61},{"step":7,"type":"action","timestamp":1777354911.644,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && grep -n 'DomainTagger\\|domainTagger\\|_domainTagger' moe-training/client/trajectory-capture.js"},"content":"Using Bash","token_count":40},{"step":8,"type":"observation","timestamp":1777354911.695,"content":"11:import { DomainTagger } from './domain-tagger.js';\n48: this._domainTagger = new DomainTagger();\n49: await this._domainTagger.init();\n299: if (this._domainTagger) {\n304: const routingText = DomainTagger.buildRoutingText(role, firstPrompt, remainingThoughts);\n305: ctx.metadata.domain_tags = await this._domainTagger.tag(routingText);\n306: ctx.metadata.session_embedding = await this._domainTagger.embed(routingText);\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":129,"is_error":false,"tool":"Bash","token_count":127},{"step":9,"type":"thought","timestamp":1777354916.313,"content":"`new DomainTagger()` — no options passed, so it uses the default `EMBEDDING_SERVICE_URL`. Now let me check where the daemon actually imports and uses this. The `moe-training` module is consumed by the daemon.","token_count":52},{"step":10,"type":"action","timestamp":1777354916.852,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && grep -rn 'TrajectoryCapture\\|trajectory-capture\\|moe-training' packages/daemon/src/ | grep -v node_modules"},"content":"Using Bash","token_count":43},{"step":11,"type":"observation","timestamp":1777354916.946,"content":"packages/daemon/src/index.js:46:import { TrajectoryCapture, ConsentManager } from '../../../moe-training/client/index.js';\npackages/daemon/src/index.js:594: this._initTrajectoryCapture().catch(() => {});\npackages/daemon/src/index.js:680: async _initTrajectoryCapture() {\npackages/daemon/src/index.js:685: this.trajectoryCapture = new TrajectoryCapture({\npackages/daemon/src/api.js:18:import { ConsentManager } from '../../../moe-training/client/index.js';\npackages/daemon/src/api.js:4939: await daemon._initTrajectoryCapture();\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":155,"is_error":false,"tool":"Bash","token_count":153},{"step":12,"type":"action","timestamp":1777354920.727,"tool":"Read","arguments":{"file_path":"~/Desktop/groove-project/groove/packages/daemon/src/index.js","offset":678,"limit":25},"content":"Using Read","token_count":28},{"step":13,"type":"observation","timestamp":1777354920.728,"content":"678\t }\n679\t\n680\t async _initTrajectoryCapture() {\n681\t try {\n682\t if (!ConsentManager.isCaptureEnabled()) return;\n683\t const pkgPath = new URL('../package.json', import.meta.url);\n684\t const version = JSON.parse(readFileSync(pkgPath, 'utf8')).version;\n685\t this.trajectoryCapture = new TrajectoryCapture({\n686\t centralCommandUrl: process.env.GROOVE_CENTRAL_URL || 'https://api.groovedev.ai',\n687\t grooveVersion: version,\n688\t });\n689\t this.trajectoryCapture.init();\n690\t } catch (e) {\n691\t // Training capture is never critical\n692\t }\n693\t }\n694\t\n695\t _startGarbageCollector() {\n696\t // Run once on startup, then every 24 hours\n697\t this._gc();\n698\t this._gcInterval = setInterval(() => this._gc(), 24 * 60 * 60 * 1000);\n699\t\n700\t // Periodic state save — crash protection (every 30s)\n701\t this._stateSaveInterval = setInterval(async () => {\n702\t try { this.state.set('agents', this.registry.getAll()); await this.state.save(); } catch {}","truncated":false,"original_token_count":255,"is_error":false,"tool":"Read","token_count":255},{"step":14,"type":"thought","timestamp":1777354925.525,"content":"Line 689 — `this.trajectoryCapture.init()` — no `await`. That's not the bug here though. Let me look at what `TrajectoryCapture.init()` does with the DomainTagger.","token_count":41},{"step":15,"type":"action","timestamp":1777354926.407,"tool":"Read","arguments":{"file_path":"~/Desktop/groove-project/groove/moe-training/client/trajectory-capture.js","offset":38,"limit":16},"content":"Using Read","token_count":31},{"step":16,"type":"observation","timestamp":1777354926.407,"content":"38\t async init() {\n39\t if (!ConsentManager.isCaptureEnabled()) {\n40\t this._enabled = false;\n41\t return;\n42\t }\n43\t this._enabled = true;\n44\t this._scrubber = new PIIScrubber();\n45\t this._attestation = new SessionAttestation(this._centralCommandUrl);\n46\t this._transmissionQueue = new TransmissionQueue(this._centralCommandUrl);\n47\t this._transmissionQueue.start();\n48\t this._domainTagger = new DomainTagger();\n49\t await this._domainTagger.init();\n50\t this._offlineRetryTimer = setInterval(() => {\n51\t this._retryOfflineQueue();\n52\t }, OFFLINE_RETRY_INTERVAL_MS);\n53\t }","truncated":false,"original_token_count":155,"is_error":false,"tool":"Read","token_count":155},{"step":17,"type":"thought","timestamp":1777354935.764,"content":"Wait — line 689 in `index.js`: `this.trajectoryCapture.init()` — **no await**. That means `init()` runs as a fire-and-forget promise. The DomainTagger's `init()` calls `await this._domainTagger.init()` which does 41 HTTP requests. But the daemon doesn't await the TrajectoryCapture's init.\n\nThat's fine in theory — the DomainTagger should still eventually resolve. But let me check: if `init()` isn't awaited and an agent spawns before the DomainTagger finishes its 41 embed calls, the `_domainTagger` might be set but not yet `_ready`. Let me look at the timing.\n\nActually, that's not the issue either — `onAgentSpawn` doesn't check `_domainTagger.ready`. The domain tagging only happens in `_closeAgent`, by which point init would have long completed.\n\nLet me look at this from another angle — is the `EMBEDDING_SERVICE_URL` constant actually making it into the published npm package?","token_count":222},{"step":18,"type":"action","timestamp":1777354936.676,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && node -e \"\nimport { EMBEDDING_SERVICE_URL, CENTRAL_COMMAND_URL } from './moe-training/shared/constants.js';\nconsole.log('CENTRAL_COMMAND_URL:', CENTRAL_COMMAND_URL);\nconsole.log('EMBEDDING_SERVICE_URL:', EMBEDDING_SERVICE_URL);\n\""},"content":"Using Bash","token_count":74},{"step":19,"type":"observation","timestamp":1777354936.764,"content":"CENTRAL_COMMAND_URL: https://api.groovedev.ai\nEMBEDDING_SERVICE_URL: https://api.groovedev.ai/v1/embed\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":44,"is_error":false,"tool":"Bash","token_count":42},{"step":20,"type":"action","timestamp":1777354948.816,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && node -e \"\nimport { DomainTagger } from './moe-training/client/domain-tagger.js';\nconst t = new DomainTagger();\nconsole.log('serviceUrl:', t._serviceUrl);\nconsole.log('mode:', t._mode);\nconsole.log('ready:', t._ready);\n\""},"content":"Using Bash","token_count":73},{"step":21,"type":"observation","timestamp":1777354948.897,"content":"serviceUrl: https://api.groovedev.ai/v1/embed\nmode: null\nready: false\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":36,"is_error":false,"tool":"Bash","token_count":34},{"step":22,"type":"thought","timestamp":1777354952.865,"content":"URL is correct. Let me test the full init flow.","token_count":12},{"step":23,"type":"action","timestamp":1777354956.383,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && node -e \"\nimport { DomainTagger } from './moe-training/client/domain-tagger.js';\nconst t = new DomainTagger();\nconsole.log('serviceUrl:', t._serviceUrl);\nconsole.time('init');\ntry {\n await t.init();\n console.timeEnd('init');\n console.log('mode:', t.mode);\n console.log('ready:', t.ready);\n console.log('lastError:', t.lastError);\n if (t._centroids) {\n console.log('centroids:', Object.keys(t._centroids).length);\n }\n const result = await t.tag('Build a React frontend with TypeScript and Tailwind CSS');\n console.log('tag result:', JSON.stringify(result));\n const emb = await t.embed('Build a React frontend with TypeScript');\n console.log('embed:', emb ? emb.vector.length + 'd' : 'null');\n} catch (e) {\n console.error('ERROR:', e.message);\n}\n\" 2>&1","timeout":60000},"content":"Using Bash","token_count":217},{"step":24,"type":"observation","timestamp":1777354961.386,"content":"serviceUrl: https://api.groovedev.ai/v1/embed\ninit: 4.706s\nmode: http\nready: true\nlastError: null\ncentroids: 40\ntag result: {\"primary\":{\"domain\":\"react_frontend\",\"confidence\":0.685},\"secondary\":{\"domain\":\"typescript_node\",\"confidence\":0.4633},\"tertiary\":{\"domain\":\"vue_frontend\",\"confidence\":0.3264}}\nembed: 384d\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":97,"is_error":false,"tool":"Bash","token_count":94},{"step":25,"type":"thought","timestamp":1777354969.631,"content":"It works perfectly from this machine — `http` mode, 40 centroids, 0.685 confidence on React, 384d embedding. The code is correct.\n\nThe issue is that the **running daemon** was started before these changes were committed. The daemon process has the old code in memory where `DomainTagger` didn't import `EMBEDDING_SERVICE_URL` and defaulted `serviceUrl` to `null`.\n\nYou need to restart the Groove daemon to pick up the new code. The changes are in the files but the running Node process is still using the old version.","token_count":130},{"step":26,"type":"action","timestamp":1777354971.472,"tool":"Bash","arguments":{"command":"cd ~/Desktop/groove-project/groove && node -e \"\nimport { DomainTagger } from './moe-training/client/domain-tagger.js';\nconst t = new DomainTagger();\nconsole.log('Confirmed: serviceUrl =', t._serviceUrl);\nconsole.log('This proves the code is correct.');\nconsole.log('If live sessions show keyword mode, the running daemon has stale code in memory.');\nconsole.log('Fix: restart the daemon (groove stop && groove start)');\n\""},"content":"Using Bash","token_count":114},{"step":27,"type":"observation","timestamp":1777354971.549,"content":"Confirmed: serviceUrl = https://api.groovedev.ai/v1/embed\nThis proves the code is correct.\nIf live sessions show keyword mode, the running daemon has stale code in memory.\nFix: restart the daemon (groove stop && groove start)\nShell cwd was reset to ~/Desktop/groove-project/groove/training","truncated":false,"original_token_count":75,"is_error":false,"tool":"Bash","token_count":73},{"step":28,"type":"thought","timestamp":1777354976.411,"content":"Mystery solved. The code works — `http` mode, 40 centroids built in 4.7s, 0.685 confidence, 384d embeddings. The running daemon just needs a restart to pick up the new `EMBEDDING_SERVICE_URL` default. Run `groove stop && groove start` and the next session will have full embeddings.","token_count":71},{"step":29,"type":"resolution","timestamp":1777354976.457,"content":"Mystery solved. The code works — `http` mode, 40 centroids built in 4.7s, 0.685 confidence, 384d embeddings. The running daemon just needs a restart to pick up the new `EMBEDDING_SERVICE_URL` default. Run `groove stop && groove start` and the next session will have full embeddings.","token_count":71}]}
|
|
2
|
-
{"envelope_id":"
|
|
3
|
-
{"envelope_id":"
|
|
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}}
|
|
@@ -169,6 +169,26 @@ const DOMAIN_TAXONOMY = {
|
|
|
169
169
|
keywords: ['scientific', 'simulation', 'matlab', 'scipy', 'julia', 'fortran', 'numerical', 'differential equation', 'finite element', 'linear algebra'],
|
|
170
170
|
description: 'Scientific computing, numerical methods, MATLAB/SciPy/Julia, simulations, optimization, statistics',
|
|
171
171
|
},
|
|
172
|
+
planning_strategy: {
|
|
173
|
+
keywords: ['plan', 'strategy', 'architect', 'design doc', 'breakdown', 'scope', 'roadmap', 'milestone', 'prioritize', 'tradeoff', 'approach', 'recommend', 'team', 'coordinate', 'delegate', 'assign'],
|
|
174
|
+
description: 'Project planning, task breakdown, architecture decisions, team coordination, strategy, roadmaps, scoping, prioritization',
|
|
175
|
+
},
|
|
176
|
+
conversational_reasoning: {
|
|
177
|
+
keywords: ['explain', 'why', 'how does', 'what is', 'clarify', 'understand', 'reason', 'think through', 'analyze', 'compare', 'evaluate', 'brainstorm', 'discuss', 'opinion', 'advice'],
|
|
178
|
+
description: 'Conversational reasoning, explanation, analysis, brainstorming, Q&A, decision-making, advice, evaluation',
|
|
179
|
+
},
|
|
180
|
+
documentation_writing: {
|
|
181
|
+
keywords: ['readme', 'documentation', 'docs', 'markdown', 'api docs', 'changelog', 'tutorial', 'guide', 'specification', 'wiki', 'jsdoc', 'docstring', 'technical writing'],
|
|
182
|
+
description: 'Documentation writing, READMEs, API docs, changelogs, tutorials, guides, technical writing, specifications',
|
|
183
|
+
},
|
|
184
|
+
product_design: {
|
|
185
|
+
keywords: ['product', 'feature', 'user story', 'requirements', 'ux', 'wireframe', 'prototype', 'feedback', 'iteration', 'mvp', 'spec', 'acceptance criteria', 'stakeholder'],
|
|
186
|
+
description: 'Product design, feature planning, user stories, requirements gathering, UX, prototyping, MVPs, stakeholder communication',
|
|
187
|
+
},
|
|
188
|
+
devops_general: {
|
|
189
|
+
keywords: ['deploy', 'deployment', 'release', 'rollback', 'staging', 'production', 'environment', 'migration', 'upgrade', 'maintenance', 'incident', 'postmortem', 'runbook'],
|
|
190
|
+
description: 'DevOps operations, deployments, releases, rollbacks, environment management, incident response, runbooks',
|
|
191
|
+
},
|
|
172
192
|
};
|
|
173
193
|
|
|
174
194
|
export class DomainTagger {
|
|
@@ -33,9 +33,11 @@ export class TrajectoryCapture {
|
|
|
33
33
|
this._transmissionQueue = null;
|
|
34
34
|
this._offlineRetryTimer = null;
|
|
35
35
|
this._contexts = new Map();
|
|
36
|
+
this._shutdown = false;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
async init() {
|
|
40
|
+
if (this._shutdown) return;
|
|
39
41
|
if (!ConsentManager.isCaptureEnabled()) {
|
|
40
42
|
this._enabled = false;
|
|
41
43
|
return;
|
|
@@ -47,12 +49,16 @@ export class TrajectoryCapture {
|
|
|
47
49
|
this._transmissionQueue.start();
|
|
48
50
|
this._domainTagger = new DomainTagger();
|
|
49
51
|
await this._domainTagger.init();
|
|
52
|
+
if (this._shutdown) return;
|
|
50
53
|
this._offlineRetryTimer = setInterval(() => {
|
|
51
54
|
this._retryOfflineQueue();
|
|
52
55
|
}, OFFLINE_RETRY_INTERVAL_MS);
|
|
56
|
+
if (typeof this._offlineRetryTimer.unref === 'function') {
|
|
57
|
+
this._offlineRetryTimer.unref();
|
|
58
|
+
}
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
async onAgentSpawn(agentId, provider, model, role, teamSize) {
|
|
61
|
+
async onAgentSpawn(agentId, provider, model, role, teamSize, prompt) {
|
|
56
62
|
if (!this._enabled) return;
|
|
57
63
|
|
|
58
64
|
const parser = getParser(provider);
|
|
@@ -98,9 +104,20 @@ export class TrajectoryCapture {
|
|
|
98
104
|
ctx.chunkTimer = setInterval(() => {
|
|
99
105
|
this._flushContext(agentId);
|
|
100
106
|
}, CHUNK_TIMEOUT_MS);
|
|
107
|
+
if (typeof ctx.chunkTimer.unref === 'function') {
|
|
108
|
+
ctx.chunkTimer.unref();
|
|
109
|
+
}
|
|
101
110
|
|
|
102
111
|
this._contexts.set(agentId, ctx);
|
|
103
112
|
|
|
113
|
+
if (prompt && typeof prompt === 'string' && prompt.trim()) {
|
|
114
|
+
this._processStep(agentId, ctx, {
|
|
115
|
+
type: 'instruction',
|
|
116
|
+
content: prompt.slice(0, USER_MESSAGE_MAX_CHARS),
|
|
117
|
+
source: 'user',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
await this._attestation.openSession(sessionId, metadata);
|
|
105
122
|
}
|
|
106
123
|
|
|
@@ -205,6 +222,7 @@ export class TrajectoryCapture {
|
|
|
205
222
|
}
|
|
206
223
|
|
|
207
224
|
async shutdown() {
|
|
225
|
+
this._shutdown = true;
|
|
208
226
|
if (this._offlineRetryTimer) clearInterval(this._offlineRetryTimer);
|
|
209
227
|
for (const agentId of this._contexts.keys()) {
|
|
210
228
|
await this._closeAgent(agentId, 'SHUTDOWN');
|
|
@@ -368,6 +386,23 @@ export class TrajectoryCapture {
|
|
|
368
386
|
}
|
|
369
387
|
|
|
370
388
|
_computeTrainingEligibility(ctx, durationSeconds) {
|
|
389
|
+
const role = ctx.metadata.agent_role || '';
|
|
390
|
+
const isConversational = role === 'planner' || role === 'chat' || role === 'advisor';
|
|
391
|
+
|
|
392
|
+
if (ctx.totalTokens < TRAINING_MIN_TOKENS) {
|
|
393
|
+
return { eligible: false, exclusionReason: 'insufficient_tokens' };
|
|
394
|
+
}
|
|
395
|
+
if (durationSeconds < TRAINING_MIN_DURATION) {
|
|
396
|
+
return { eligible: false, exclusionReason: 'too_short' };
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (isConversational) {
|
|
400
|
+
if (ctx.stepCount < 2) {
|
|
401
|
+
return { eligible: false, exclusionReason: 'too_few_steps' };
|
|
402
|
+
}
|
|
403
|
+
return { eligible: true, exclusionReason: null };
|
|
404
|
+
}
|
|
405
|
+
|
|
371
406
|
if (ctx.stepCount < TRAINING_MIN_STEPS) {
|
|
372
407
|
return { eligible: false, exclusionReason: 'too_few_steps' };
|
|
373
408
|
}
|
|
@@ -379,12 +414,6 @@ export class TrajectoryCapture {
|
|
|
379
414
|
if (!hasObservation) {
|
|
380
415
|
return { eligible: false, exclusionReason: 'no_observations' };
|
|
381
416
|
}
|
|
382
|
-
if (ctx.totalTokens < TRAINING_MIN_TOKENS) {
|
|
383
|
-
return { eligible: false, exclusionReason: 'insufficient_tokens' };
|
|
384
|
-
}
|
|
385
|
-
if (durationSeconds < TRAINING_MIN_DURATION) {
|
|
386
|
-
return { eligible: false, exclusionReason: 'too_short' };
|
|
387
|
-
}
|
|
388
417
|
return { eligible: true, exclusionReason: null };
|
|
389
418
|
}
|
|
390
419
|
|
|
@@ -208,7 +208,7 @@ describe('TrajectoryCapture — training eligibility', () => {
|
|
|
208
208
|
assert.equal(result.exclusionReason, null);
|
|
209
209
|
});
|
|
210
210
|
|
|
211
|
-
it('exclusion reasons follow priority order', () => {
|
|
211
|
+
it('exclusion reasons follow priority order: tokens before duration before steps', () => {
|
|
212
212
|
const tc = makeTc();
|
|
213
213
|
const ctx = makeCtx({
|
|
214
214
|
stepCount: 3,
|
|
@@ -220,8 +220,189 @@ describe('TrajectoryCapture — training eligibility', () => {
|
|
|
220
220
|
],
|
|
221
221
|
});
|
|
222
222
|
const result = tc._computeTrainingEligibility(ctx, 5);
|
|
223
|
+
assert.equal(result.exclusionReason, 'insufficient_tokens');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('duration checked before steps when tokens pass', () => {
|
|
227
|
+
const tc = makeTc();
|
|
228
|
+
const ctx = makeCtx({
|
|
229
|
+
stepCount: 3,
|
|
230
|
+
totalTokens: 5000,
|
|
231
|
+
allSteps: [
|
|
232
|
+
{ step: 1, type: 'thought', content: 'thinking' },
|
|
233
|
+
{ step: 2, type: 'thought', content: 'more' },
|
|
234
|
+
{ step: 3, type: 'thought', content: 'done' },
|
|
235
|
+
],
|
|
236
|
+
});
|
|
237
|
+
const result = tc._computeTrainingEligibility(ctx, 5);
|
|
238
|
+
assert.equal(result.exclusionReason, 'too_short');
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('steps checked after tokens and duration pass', () => {
|
|
242
|
+
const tc = makeTc();
|
|
243
|
+
const ctx = makeCtx({
|
|
244
|
+
stepCount: 3,
|
|
245
|
+
totalTokens: 5000,
|
|
246
|
+
allSteps: [
|
|
247
|
+
{ step: 1, type: 'thought', content: 'thinking' },
|
|
248
|
+
{ step: 2, type: 'thought', content: 'more' },
|
|
249
|
+
{ step: 3, type: 'thought', content: 'done' },
|
|
250
|
+
],
|
|
251
|
+
});
|
|
252
|
+
const result = tc._computeTrainingEligibility(ctx, 60);
|
|
253
|
+
assert.equal(result.exclusionReason, 'too_few_steps');
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('TrajectoryCapture — planner/conversational eligibility', () => {
|
|
258
|
+
function makeConversationalCtx(role, overrides = {}) {
|
|
259
|
+
const ctx = makeCtx(overrides);
|
|
260
|
+
ctx.metadata.agent_role = role;
|
|
261
|
+
return ctx;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
it('planner eligible with only thoughts (no actions/observations)', () => {
|
|
265
|
+
const tc = makeTc();
|
|
266
|
+
const ctx = makeConversationalCtx('planner', {
|
|
267
|
+
stepCount: 10,
|
|
268
|
+
totalTokens: 2000,
|
|
269
|
+
allSteps: Array.from({ length: 10 }, (_, i) => ({ step: i + 1, type: 'thought', content: 'planning' })),
|
|
270
|
+
});
|
|
271
|
+
const result = tc._computeTrainingEligibility(ctx, 60);
|
|
272
|
+
assert.equal(result.eligible, true);
|
|
273
|
+
assert.equal(result.exclusionReason, null);
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it('chat role eligible with only thoughts', () => {
|
|
277
|
+
const tc = makeTc();
|
|
278
|
+
const ctx = makeConversationalCtx('chat', {
|
|
279
|
+
stepCount: 5,
|
|
280
|
+
totalTokens: 1000,
|
|
281
|
+
allSteps: [
|
|
282
|
+
{ step: 1, type: 'instruction', content: 'explain React hooks' },
|
|
283
|
+
{ step: 2, type: 'thought', content: 'explaining' },
|
|
284
|
+
{ step: 3, type: 'thought', content: 'more detail' },
|
|
285
|
+
{ step: 4, type: 'thought', content: 'examples' },
|
|
286
|
+
{ step: 5, type: 'resolution', content: 'done' },
|
|
287
|
+
],
|
|
288
|
+
});
|
|
289
|
+
const result = tc._computeTrainingEligibility(ctx, 30);
|
|
290
|
+
assert.equal(result.eligible, true);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('advisor role eligible with only thoughts', () => {
|
|
294
|
+
const tc = makeTc();
|
|
295
|
+
const ctx = makeConversationalCtx('advisor', {
|
|
296
|
+
stepCount: 3,
|
|
297
|
+
totalTokens: 800,
|
|
298
|
+
allSteps: [
|
|
299
|
+
{ step: 1, type: 'instruction', content: 'review approach' },
|
|
300
|
+
{ step: 2, type: 'thought', content: 'analysis' },
|
|
301
|
+
{ step: 3, type: 'resolution', content: 'recommendation' },
|
|
302
|
+
],
|
|
303
|
+
});
|
|
304
|
+
const result = tc._computeTrainingEligibility(ctx, 20);
|
|
305
|
+
assert.equal(result.eligible, true);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('planner still requires minimum tokens', () => {
|
|
309
|
+
const tc = makeTc();
|
|
310
|
+
const ctx = makeConversationalCtx('planner', {
|
|
311
|
+
stepCount: 10,
|
|
312
|
+
totalTokens: 100,
|
|
313
|
+
allSteps: Array.from({ length: 10 }, (_, i) => ({ step: i + 1, type: 'thought', content: 'plan' })),
|
|
314
|
+
});
|
|
315
|
+
const result = tc._computeTrainingEligibility(ctx, 60);
|
|
316
|
+
assert.equal(result.eligible, false);
|
|
317
|
+
assert.equal(result.exclusionReason, 'insufficient_tokens');
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it('planner still requires minimum duration', () => {
|
|
321
|
+
const tc = makeTc();
|
|
322
|
+
const ctx = makeConversationalCtx('planner', {
|
|
323
|
+
stepCount: 10,
|
|
324
|
+
totalTokens: 2000,
|
|
325
|
+
allSteps: Array.from({ length: 10 }, (_, i) => ({ step: i + 1, type: 'thought', content: 'plan' })),
|
|
326
|
+
});
|
|
327
|
+
const result = tc._computeTrainingEligibility(ctx, 5);
|
|
328
|
+
assert.equal(result.eligible, false);
|
|
329
|
+
assert.equal(result.exclusionReason, 'too_short');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('planner requires at least 2 steps', () => {
|
|
333
|
+
const tc = makeTc();
|
|
334
|
+
const ctx = makeConversationalCtx('planner', {
|
|
335
|
+
stepCount: 1,
|
|
336
|
+
totalTokens: 2000,
|
|
337
|
+
allSteps: [{ step: 1, type: 'thought', content: 'plan' }],
|
|
338
|
+
});
|
|
339
|
+
const result = tc._computeTrainingEligibility(ctx, 60);
|
|
340
|
+
assert.equal(result.eligible, false);
|
|
223
341
|
assert.equal(result.exclusionReason, 'too_few_steps');
|
|
224
342
|
});
|
|
343
|
+
|
|
344
|
+
it('coding role (fullstack) still requires actions and observations', () => {
|
|
345
|
+
const tc = makeTc();
|
|
346
|
+
const ctx = makeConversationalCtx('fullstack', {
|
|
347
|
+
stepCount: 10,
|
|
348
|
+
totalTokens: 2000,
|
|
349
|
+
allSteps: Array.from({ length: 10 }, (_, i) => ({ step: i + 1, type: 'thought', content: 'thinking' })),
|
|
350
|
+
});
|
|
351
|
+
const result = tc._computeTrainingEligibility(ctx, 60);
|
|
352
|
+
assert.equal(result.eligible, false);
|
|
353
|
+
assert.equal(result.exclusionReason, 'no_actions');
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
describe('TrajectoryCapture — initial prompt capture', () => {
|
|
358
|
+
function makeSpawnTc() {
|
|
359
|
+
const tc = makeTc();
|
|
360
|
+
tc._enabled = true;
|
|
361
|
+
tc._scrubber = { scrub: (s) => s };
|
|
362
|
+
tc._attestation = { openSession: async () => {}, signEnvelope: (sid, e) => e };
|
|
363
|
+
tc._transmissionQueue = { enqueue: () => {} };
|
|
364
|
+
tc._domainTagger = null;
|
|
365
|
+
return tc;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
it('onAgentSpawn records prompt as instruction step', async () => {
|
|
369
|
+
const tc = makeSpawnTc();
|
|
370
|
+
await tc.onAgentSpawn('agent-p1', 'claude-code', 'opus', 'planner', 1, 'Build a React app');
|
|
371
|
+
|
|
372
|
+
const ctx = tc._contexts.get('agent-p1');
|
|
373
|
+
assert.ok(ctx);
|
|
374
|
+
assert.equal(ctx.stepCount, 1);
|
|
375
|
+
assert.equal(ctx.allSteps[0].type, 'instruction');
|
|
376
|
+
assert.ok(ctx.allSteps[0].content.includes('Build a React app'));
|
|
377
|
+
assert.equal(ctx.allSteps[0].source, 'user');
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('onAgentSpawn with no prompt creates no instruction step', async () => {
|
|
381
|
+
const tc = makeSpawnTc();
|
|
382
|
+
await tc.onAgentSpawn('agent-p2', 'claude-code', 'opus', 'fullstack', 1);
|
|
383
|
+
|
|
384
|
+
const ctx = tc._contexts.get('agent-p2');
|
|
385
|
+
assert.ok(ctx);
|
|
386
|
+
assert.equal(ctx.stepCount, 0);
|
|
387
|
+
assert.equal(ctx.allSteps.length, 0);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it('onAgentSpawn truncates long prompts', async () => {
|
|
391
|
+
const tc = makeSpawnTc();
|
|
392
|
+
const longPrompt = 'x'.repeat(50000);
|
|
393
|
+
await tc.onAgentSpawn('agent-p3', 'claude-code', 'opus', 'planner', 1, longPrompt);
|
|
394
|
+
|
|
395
|
+
const ctx = tc._contexts.get('agent-p3');
|
|
396
|
+
assert.ok(ctx.allSteps[0].content.length <= 10001);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('onAgentSpawn ignores empty/whitespace prompts', async () => {
|
|
400
|
+
const tc = makeSpawnTc();
|
|
401
|
+
await tc.onAgentSpawn('agent-p4', 'claude-code', 'opus', 'planner', 1, ' ');
|
|
402
|
+
|
|
403
|
+
const ctx = tc._contexts.get('agent-p4');
|
|
404
|
+
assert.equal(ctx.stepCount, 0);
|
|
405
|
+
});
|
|
225
406
|
});
|
|
226
407
|
|
|
227
408
|
describe('TrajectoryCapture — user feedback emission', () => {
|
|
@@ -5,10 +5,10 @@ import { createInterface } from 'readline';
|
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import { apiCall } from '../client.js';
|
|
7
7
|
|
|
8
|
-
function
|
|
8
|
+
function prompt(question) {
|
|
9
9
|
return new Promise((resolve) => {
|
|
10
10
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
11
|
-
rl.question(
|
|
11
|
+
rl.question(question, (answer) => { rl.close(); resolve(answer.trim()); });
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
14
|
|
|
@@ -45,17 +45,32 @@ export async function teamList() {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export async function teamDelete(id) {
|
|
48
|
-
const
|
|
49
|
-
|
|
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 {
|
|
50
73
|
console.log(chalk.dim(' Cancelled.'));
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
try {
|
|
54
|
-
await apiCall('DELETE', `/api/teams/${encodeURIComponent(id)}`);
|
|
55
|
-
console.log(chalk.green(` Archived team "${id}"`) + chalk.dim(' — restore with `groove team restore <id>`'));
|
|
56
|
-
} catch (err) {
|
|
57
|
-
console.error(chalk.red(' Failed:'), err.message);
|
|
58
|
-
process.exit(1);
|
|
59
74
|
}
|
|
60
75
|
}
|
|
61
76
|
|
|
@@ -1138,8 +1138,9 @@ export function createApi(app, daemon) {
|
|
|
1138
1138
|
|
|
1139
1139
|
app.delete('/api/teams/:id', (req, res) => {
|
|
1140
1140
|
try {
|
|
1141
|
-
|
|
1142
|
-
daemon.
|
|
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 });
|
|
1143
1144
|
res.json({ ok: true });
|
|
1144
1145
|
} catch (err) {
|
|
1145
1146
|
res.status(400).json({ error: err.message });
|