groove-dev 0.27.26 → 0.27.28
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/.groove-staging/state.json +3 -0
- package/.groove-staging/timeline.json +13 -0
- package/CLAUDE.md +0 -10
- package/DECENTRALIZED_NET_WP_V1.md +871 -0
- package/README.md +28 -0
- package/SECURITY_SWEEP.md +228 -0
- package/decentralized-net/ACTION_PLAN.md +422 -0
- package/node_modules/@groove-dev/cli/package.json +1 -1
- package/node_modules/@groove-dev/daemon/package.json +1 -1
- package/node_modules/@groove-dev/daemon/src/api.js +99 -0
- package/node_modules/@groove-dev/daemon/src/introducer.js +7 -7
- package/node_modules/@groove-dev/daemon/src/journalist.js +36 -6
- package/node_modules/@groove-dev/daemon/src/memory.js +29 -10
- package/node_modules/@groove-dev/daemon/src/process.js +29 -12
- package/node_modules/@groove-dev/daemon/src/providers/claude-code.js +26 -1
- package/node_modules/@groove-dev/daemon/src/providers/codex.js +34 -11
- package/node_modules/@groove-dev/daemon/src/rotator.js +24 -1
- package/node_modules/@groove-dev/daemon/test/introducer.test.js +63 -0
- package/node_modules/@groove-dev/daemon/test/journalist.test.js +106 -0
- package/node_modules/@groove-dev/daemon/test/memory.test.js +49 -0
- package/node_modules/@groove-dev/daemon/test/rotator.test.js +99 -0
- package/node_modules/@groove-dev/gui/dist/assets/{index-DieCV-v1.js → index-Ch1N9G4Z.js} +1728 -1728
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/package.json +1 -1
- package/node_modules/@groove-dev/gui/src/components/agents/agent-config.jsx +147 -21
- package/node_modules/@groove-dev/gui/src/components/agents/spawn-wizard.jsx +206 -44
- package/node_modules/@groove-dev/gui/src/components/marketplace/integration-wizard.jsx +11 -24
- package/node_modules/@groove-dev/gui/src/components/marketplace/marketplace-card.jsx +1 -36
- package/node_modules/@groove-dev/gui/src/lib/integration-logos.js +39 -0
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/daemon/package.json +1 -1
- package/packages/daemon/src/api.js +99 -0
- package/packages/daemon/src/introducer.js +7 -7
- package/packages/daemon/src/journalist.js +36 -6
- package/packages/daemon/src/memory.js +29 -10
- package/packages/daemon/src/process.js +29 -12
- package/packages/daemon/src/providers/claude-code.js +26 -1
- package/packages/daemon/src/providers/codex.js +34 -11
- package/packages/daemon/src/rotator.js +24 -1
- package/packages/gui/dist/assets/{index-DieCV-v1.js → index-Ch1N9G4Z.js} +1728 -1728
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/package.json +1 -1
- package/packages/gui/src/components/agents/agent-config.jsx +147 -21
- package/packages/gui/src/components/agents/spawn-wizard.jsx +206 -44
- package/packages/gui/src/components/marketplace/integration-wizard.jsx +11 -24
- package/packages/gui/src/components/marketplace/marketplace-card.jsx +1 -36
- package/packages/gui/src/lib/integration-logos.js +39 -0
- package/MUST_FIX_ISSUES.md +0 -305
|
@@ -95,6 +95,7 @@ export class CodexProvider extends Provider {
|
|
|
95
95
|
if (agent.prompt) args.push(agent.prompt);
|
|
96
96
|
|
|
97
97
|
this._currentModel = agent.model;
|
|
98
|
+
this._sessionInputTokens = 0;
|
|
98
99
|
|
|
99
100
|
return {
|
|
100
101
|
command: 'codex',
|
|
@@ -109,6 +110,11 @@ export class CodexProvider extends Provider {
|
|
|
109
110
|
return { command: 'codex', args, env: {} };
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
_getMaxContext() {
|
|
114
|
+
const model = CodexProvider.models.find((m) => m.id === this._currentModel);
|
|
115
|
+
return model?.maxContext || 200000;
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
switchModel(agent, newModel) {
|
|
113
119
|
return false; // Codex doesn't support mid-session model switch
|
|
114
120
|
}
|
|
@@ -175,36 +181,48 @@ export class CodexProvider extends Provider {
|
|
|
175
181
|
|
|
176
182
|
case 'item.completed': {
|
|
177
183
|
const item = event.item || {};
|
|
184
|
+
|
|
185
|
+
// Accumulate usage for intermediate context estimation.
|
|
186
|
+
// Codex only reports full contextUsage at turn.completed — without this,
|
|
187
|
+
// the rotator sees stale contextUsage between turns and never triggers.
|
|
188
|
+
if (event.usage) {
|
|
189
|
+
this._sessionInputTokens += event.usage.input_tokens || 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let result = null;
|
|
178
193
|
if (item.type === 'agent_message') {
|
|
179
|
-
|
|
194
|
+
result = {
|
|
180
195
|
type: 'activity', subtype: 'assistant',
|
|
181
196
|
data: [{ type: 'text', text: item.text || '' }],
|
|
182
197
|
};
|
|
183
|
-
}
|
|
184
|
-
if (item.type === 'command_execution') {
|
|
198
|
+
} else if (item.type === 'command_execution') {
|
|
185
199
|
const output = (item.aggregated_output || '').slice(0, 2000);
|
|
186
|
-
|
|
200
|
+
result = {
|
|
187
201
|
type: 'activity', subtype: 'assistant',
|
|
188
202
|
data: [
|
|
189
203
|
{ type: 'tool_use', id: item.id || 'exec', name: 'Bash', input: { command: item.command } },
|
|
190
204
|
...(output ? [{ type: 'text', text: output }] : []),
|
|
191
205
|
],
|
|
192
206
|
};
|
|
193
|
-
}
|
|
194
|
-
if (item.type === 'todo_list') {
|
|
207
|
+
} else if (item.type === 'todo_list') {
|
|
195
208
|
const steps = (item.items || []).map((s) => `${s.completed ? '✓' : '○'} ${s.text}`).join('\n');
|
|
196
|
-
|
|
209
|
+
result = {
|
|
197
210
|
type: 'activity', subtype: 'assistant',
|
|
198
211
|
data: [{ type: 'text', text: steps }],
|
|
199
212
|
};
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return {
|
|
213
|
+
} else if (item.type === 'file_edit' || item.type === 'file_write' || item.type === 'file_read') {
|
|
214
|
+
result = {
|
|
203
215
|
type: 'activity', subtype: 'assistant',
|
|
204
216
|
data: [{ type: 'tool_use', id: item.id || 'file', name: item.type === 'file_read' ? 'Read' : item.type === 'file_write' ? 'Write' : 'Edit', input: { path: item.path || item.file || '' } }],
|
|
205
217
|
};
|
|
206
218
|
}
|
|
207
|
-
|
|
219
|
+
|
|
220
|
+
// Attach intermediate context estimate so all 7 layers see Codex progress
|
|
221
|
+
if (result && this._sessionInputTokens > 0) {
|
|
222
|
+
result.contextUsage = this._sessionInputTokens / this._getMaxContext();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return result;
|
|
208
226
|
}
|
|
209
227
|
|
|
210
228
|
case 'turn.completed': {
|
|
@@ -215,11 +233,15 @@ export class CodexProvider extends Provider {
|
|
|
215
233
|
const outputTokens = usage.output_tokens || 0;
|
|
216
234
|
const cachedTokens = usage.cached_input_tokens || 0;
|
|
217
235
|
const totalTokens = inputTokens + outputTokens;
|
|
236
|
+
const cacheCreationTokens = cachedTokens > 0 ? Math.max(0, inputTokens - cachedTokens) : 0;
|
|
218
237
|
|
|
219
238
|
const model = CodexProvider.models.find((m) => m.id === this._currentModel);
|
|
220
239
|
const pricing = model?.pricing;
|
|
221
240
|
const maxContext = model?.maxContext || 200000;
|
|
222
241
|
|
|
242
|
+
// Sync accumulator to actual cumulative value from turn completion
|
|
243
|
+
this._sessionInputTokens = inputTokens;
|
|
244
|
+
|
|
223
245
|
let estimatedCostUsd = 0;
|
|
224
246
|
if (pricing) {
|
|
225
247
|
const newInput = inputTokens - cachedTokens;
|
|
@@ -235,6 +257,7 @@ export class CodexProvider extends Provider {
|
|
|
235
257
|
inputTokens,
|
|
236
258
|
outputTokens,
|
|
237
259
|
cacheReadTokens: cachedTokens,
|
|
260
|
+
cacheCreationTokens,
|
|
238
261
|
contextUsage: inputTokens / maxContext,
|
|
239
262
|
estimatedCostUsd,
|
|
240
263
|
costSource: pricing ? 'calculated' : 'estimated',
|
|
@@ -31,6 +31,7 @@ export class Rotator extends EventEmitter {
|
|
|
31
31
|
this.rotationHistory = [];
|
|
32
32
|
this.rotating = new Set();
|
|
33
33
|
this.lastRotationTime = new Map(); // agentId -> timestamp of last rotation
|
|
34
|
+
this._lastContextState = new Map(); // agentId -> { contextUsage, timestamp }
|
|
34
35
|
this.enabled = false;
|
|
35
36
|
this.liveScores = {};
|
|
36
37
|
this.scoreHistory = {};
|
|
@@ -180,6 +181,25 @@ export class Rotator extends EventEmitter {
|
|
|
180
181
|
continue;
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
// Stale context fallback — safety net for providers (like Codex) that don't
|
|
185
|
+
// report intermediate contextUsage. If contextUsage hasn't changed in 120+
|
|
186
|
+
// seconds but tokens are being consumed, estimate from total tokens.
|
|
187
|
+
const knownCtx = this._lastContextState.get(agent.id);
|
|
188
|
+
if (!knownCtx || knownCtx.contextUsage !== agent.contextUsage) {
|
|
189
|
+
this._lastContextState.set(agent.id, { contextUsage: agent.contextUsage, timestamp: Date.now() });
|
|
190
|
+
} else if (agent.tokensUsed > 0 && (Date.now() - knownCtx.timestamp) >= 120_000) {
|
|
191
|
+
const providerClass = getProvider(agent.provider)?.constructor;
|
|
192
|
+
const models = providerClass?.models || [];
|
|
193
|
+
const model = models.find((m) => m.id === agent.model) || models[0];
|
|
194
|
+
const maxContext = model?.maxContext || 200000;
|
|
195
|
+
const estimatedContext = agent.tokensUsed / maxContext;
|
|
196
|
+
if (estimatedContext >= HARD_CEILING) {
|
|
197
|
+
console.log(` Rotator: ${agent.name} estimated context ${Math.round(estimatedContext * 100)}% (stale contextUsage fallback)`);
|
|
198
|
+
await this.rotate(agent.id, { reason: 'estimated_context_ceiling' });
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
183
203
|
// Cooldown — skip threshold/quality rotation if recently rotated
|
|
184
204
|
if (this._isOnCooldown(agent.id)) continue;
|
|
185
205
|
|
|
@@ -274,7 +294,7 @@ export class Rotator extends EventEmitter {
|
|
|
274
294
|
oldTokens: agent.tokensUsed,
|
|
275
295
|
contextUsage: agent.contextUsage,
|
|
276
296
|
brief: brief.slice(0, 4000),
|
|
277
|
-
}, agent.workingDir);
|
|
297
|
+
}, agent.workingDir, agent.teamId);
|
|
278
298
|
}
|
|
279
299
|
|
|
280
300
|
const record = {
|
|
@@ -312,6 +332,7 @@ export class Rotator extends EventEmitter {
|
|
|
312
332
|
workingDir: agent.workingDir,
|
|
313
333
|
name: agent.name,
|
|
314
334
|
teamId: agent.teamId,
|
|
335
|
+
isRotation: true,
|
|
315
336
|
});
|
|
316
337
|
} catch (spawnErr) {
|
|
317
338
|
// Spawn failed — re-add old agent so the user can see and retry.
|
|
@@ -499,6 +520,7 @@ export class Rotator extends EventEmitter {
|
|
|
499
520
|
const naturalCompactions = this.rotationHistory.filter((r) => r.reason === 'natural_compaction').length;
|
|
500
521
|
const hardCeilingRotations = this.rotationHistory.filter((r) => r.reason === 'hard_ceiling').length;
|
|
501
522
|
const tokenCeilingRotations = this.rotationHistory.filter((r) => r.reason === 'token_ceiling').length;
|
|
523
|
+
const estimatedCeilingRotations = this.rotationHistory.filter((r) => r.reason === 'estimated_context_ceiling').length;
|
|
502
524
|
return {
|
|
503
525
|
enabled: this.enabled,
|
|
504
526
|
totalRotations,
|
|
@@ -508,6 +530,7 @@ export class Rotator extends EventEmitter {
|
|
|
508
530
|
naturalCompactions,
|
|
509
531
|
hardCeilingRotations,
|
|
510
532
|
tokenCeilingRotations,
|
|
533
|
+
estimatedCeilingRotations,
|
|
511
534
|
rotating: Array.from(this.rotating),
|
|
512
535
|
liveScores: this.liveScores,
|
|
513
536
|
scoreHistory: this.scoreHistory,
|