context-mode 1.0.99 → 1.0.101
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +22 -8
- package/build/adapters/claude-code/hooks.d.ts +4 -2
- package/build/adapters/claude-code/hooks.js +11 -4
- package/build/adapters/codex/index.d.ts +1 -1
- package/build/adapters/codex/index.js +6 -5
- package/build/adapters/gemini-cli/hooks.js +2 -1
- package/build/adapters/jetbrains-copilot/hooks.js +2 -1
- package/build/adapters/kiro/hooks.js +2 -1
- package/build/adapters/qwen-code/index.d.ts +1 -1
- package/build/adapters/qwen-code/index.js +13 -10
- package/build/adapters/types.d.ts +13 -0
- package/build/adapters/types.js +23 -1
- package/build/adapters/vscode-copilot/hooks.js +2 -1
- package/build/openclaw-plugin.js +3 -2
- package/build/pi-extension.js +1 -1
- package/build/search/auto-memory.d.ts +29 -0
- package/build/search/auto-memory.js +121 -0
- package/build/search/unified.d.ts +41 -0
- package/build/search/unified.js +89 -0
- package/build/server.js +73 -24
- package/build/session/analytics.js +1 -1
- package/build/session/db.d.ts +17 -0
- package/build/session/db.js +28 -0
- package/build/session/extract.d.ts +4 -0
- package/build/session/extract.js +232 -1
- package/build/session/snapshot.js +31 -0
- package/build/store.js +67 -4
- package/build/types.d.ts +1 -0
- package/cli.bundle.mjs +254 -119
- package/configs/claude-code/CLAUDE.md +21 -1
- package/configs/codex/AGENTS.md +22 -1
- package/configs/cursor/context-mode.mdc +18 -1
- package/configs/gemini-cli/GEMINI.md +22 -1
- package/configs/jetbrains-copilot/copilot-instructions.md +22 -1
- package/configs/kilo/AGENTS.md +19 -2
- package/configs/kiro/KIRO.md +18 -1
- package/configs/openclaw/AGENTS.md +22 -2
- package/configs/opencode/AGENTS.md +18 -1
- package/configs/pi/AGENTS.md +18 -1
- package/configs/qwen-code/QWEN.md +38 -18
- package/configs/vscode-copilot/copilot-instructions.md +22 -1
- package/hooks/auto-injection.mjs +76 -0
- package/hooks/codex/userpromptsubmit.mjs +1 -1
- package/hooks/core/mcp-ready.mjs +7 -1
- package/hooks/ensure-deps.mjs +35 -7
- package/hooks/posttooluse.mjs +50 -1
- package/hooks/precompact.mjs +9 -0
- package/hooks/pretooluse.mjs +27 -0
- package/hooks/routing-block.mjs +7 -1
- package/hooks/session-db.bundle.mjs +19 -13
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-snapshot.bundle.mjs +18 -17
- package/hooks/sessionstart.mjs +17 -0
- package/hooks/userpromptsubmit.mjs +1 -1
- package/insight/server.mjs +379 -1
- package/insight/src/lib/api.ts +88 -16
- package/insight/src/routes/index.tsx +566 -5
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +222 -87
- package/start.mjs +3 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { useEffect, useState } from "react";
|
|
3
|
-
import { api, type AnalyticsData } from "@/lib/api";
|
|
3
|
+
import { api, type AnalyticsData, type CategoryAnalyticsData } from "@/lib/api";
|
|
4
4
|
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
|
5
5
|
import { Badge } from "@/components/ui/badge";
|
|
6
6
|
import { Separator } from "@/components/ui/separator";
|
|
@@ -137,7 +137,7 @@ function generateInsights(d: AnalyticsData): Insight[] {
|
|
|
137
137
|
metric: `You read ${ratio}x more than you write`,
|
|
138
138
|
evidence: `${t.reads} files read vs ${t.writes} files written. You're spending most of your AI time understanding code, not producing it.`,
|
|
139
139
|
action: "Write a short plan before starting. Clarify what you want to change before reading everything.",
|
|
140
|
-
roi: "Planning
|
|
140
|
+
roi: "Planning upfront typically reduces the number of file re-reads.",
|
|
141
141
|
});
|
|
142
142
|
} else if (ratio < 2 && ratio > 0) {
|
|
143
143
|
ins.push({
|
|
@@ -274,7 +274,290 @@ function generateInsights(d: AnalyticsData): Insight[] {
|
|
|
274
274
|
metric: `${(t.totalTasks / t.totalSessions).toFixed(1)} tasks per session — you plan ahead`,
|
|
275
275
|
evidence: `${t.totalTasks} structured tasks across ${t.totalSessions} sessions. You break work into steps.`,
|
|
276
276
|
action: "Keep using tasks — they make sessions resumable after breaks.",
|
|
277
|
-
roi: "Structured sessions
|
|
277
|
+
roi: "Structured sessions are easier to resume and track progress.",
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return ins;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function generateCategoryInsights(c: CategoryAnalyticsData): Insight[] {
|
|
285
|
+
const ins: Insight[] = [];
|
|
286
|
+
const cs = c.compositeScores;
|
|
287
|
+
const ei = c.errorIntelligence;
|
|
288
|
+
const del = c.delegation;
|
|
289
|
+
const gov = c.governance;
|
|
290
|
+
const ctx = c.contextHealth;
|
|
291
|
+
const fi = c.fileIntelligence;
|
|
292
|
+
const git = c.gitProductivity;
|
|
293
|
+
const totalEvents = c.categories.reduce((a, b) => a + b.count, 0);
|
|
294
|
+
|
|
295
|
+
// P1 removed — duplicate of generateInsights read:write ratio pattern
|
|
296
|
+
|
|
297
|
+
// ── P2: High file churn ──
|
|
298
|
+
if (fi.hotFiles.length > 3) {
|
|
299
|
+
const top = fi.hotFiles[0];
|
|
300
|
+
ins.push({
|
|
301
|
+
icon: <AlertTriangle className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
302
|
+
metric: `${fi.hotFiles.length} hot files with repeated edits`,
|
|
303
|
+
evidence: `${top.file.split('/').pop()} was touched ${top.touches} times. Possible rework loop.`,
|
|
304
|
+
action: "Read the full file before editing. Add constraints to CLAUDE.md.",
|
|
305
|
+
roi: `Fewer re-edits save ~${fi.hotFiles.length * 3} minutes per session.`,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// ── P3: Session failed — errors + 0 commits (★★ STRONG from agentisd #5) ──
|
|
310
|
+
if (ei.totalErrors > 3 && git.totalCommits === 0 && totalEvents > 50) {
|
|
311
|
+
ins.push({
|
|
312
|
+
icon: <AlertTriangle className="h-5 w-5 text-red-500" />, severity: "critical",
|
|
313
|
+
metric: `${ei.totalErrors} errors, zero commits — session effort lost`,
|
|
314
|
+
evidence: `${totalEvents} events with ${ei.totalErrors} errors and no commits. All effort was lost.`,
|
|
315
|
+
action: "Review the error pattern, fix root cause, break tasks into smaller deliverable chunks.",
|
|
316
|
+
roi: `Recovering from failed sessions costs an additional ${Math.round(totalEvents * 0.5)} minutes.`,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// ── P4: Zero commits ──
|
|
321
|
+
if (git.totalCommits === 0 && totalEvents > 100) {
|
|
322
|
+
ins.push({
|
|
323
|
+
icon: <GitBranch className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
324
|
+
metric: "No commits across all sessions",
|
|
325
|
+
evidence: `${totalEvents} events recorded, zero commits. Work may not be reaching the codebase.`,
|
|
326
|
+
action: "Commit incrementally — small commits are easier to review.",
|
|
327
|
+
roi: "Regular commits create a safety net for rollbacks.",
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ── Q1: High error resolution ──
|
|
332
|
+
if (ei.totalErrors >= 5 && ei.resolutionRate > 80) {
|
|
333
|
+
ins.push({
|
|
334
|
+
icon: <CheckCircle className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
335
|
+
metric: `${ei.resolutionRate}% of errors resolved within session`,
|
|
336
|
+
evidence: `${ei.resolvedErrors} of ${ei.totalErrors} errors fixed. Self-healing sessions.`,
|
|
337
|
+
action: "Keep this up — self-healing sessions are the gold standard.",
|
|
338
|
+
roi: "Each resolved error saves 5-10 min of next-session debugging.",
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// ── Q2: Retry storm (>=2 to avoid single-fluke false positive) ──
|
|
343
|
+
if (ei.retryStorms >= 2) {
|
|
344
|
+
ins.push({
|
|
345
|
+
icon: <AlertTriangle className="h-5 w-5 text-red-500" />, severity: "critical",
|
|
346
|
+
metric: `${ei.retryStorms} retry storm${ei.retryStorms > 1 ? 's' : ''} detected`,
|
|
347
|
+
evidence: `Sessions where the same tool was called 3+ times with similar input. The agent gets stuck in loops.`,
|
|
348
|
+
action: "Stop and re-think the approach. Add error context to CLAUDE.md.",
|
|
349
|
+
roi: `Breaking retry loops saves ~${ei.retryStorms * 5} minutes of wasted compute.`,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ── Q3: Persistent errors ──
|
|
354
|
+
if (ei.totalErrors >= 5 && ei.resolutionRate < 30) {
|
|
355
|
+
ins.push({
|
|
356
|
+
icon: <AlertTriangle className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
357
|
+
metric: `Only ${ei.resolutionRate}% of errors get resolved`,
|
|
358
|
+
evidence: `${ei.totalErrors - ei.resolvedErrors} errors left unresolved. Technical debt accumulating.`,
|
|
359
|
+
action: "Address root causes — add patterns to prevent recurring errors.",
|
|
360
|
+
roi: `Resolving persistent errors prevents hours of future debugging.`,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ── Q4: Slow tool bottleneck ──
|
|
365
|
+
if (ei.p95LatencyMs > 15000 && ei.slowestTool) {
|
|
366
|
+
ins.push({
|
|
367
|
+
icon: <Clock className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
368
|
+
metric: `${ei.slowestTool} averaging ${Math.round(ei.avgLatencyMs / 1000)}s — bottleneck`,
|
|
369
|
+
evidence: `P95 latency: ${Math.round(ei.p95LatencyMs / 1000)}s. ${ei.latencyByTool.length} tools tracked for latency.`,
|
|
370
|
+
action: "Check if tool can be replaced or if input can be simplified.",
|
|
371
|
+
roi: `Fixing bottleneck saves ~${Math.round(ei.latencyByTool.reduce((a, t) => a + t.count, 0) * ei.avgLatencyMs / 60000)} minutes total.`,
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// ── S1: Power delegator ──
|
|
376
|
+
if (del.launched > 10 && del.completionRate > 70) {
|
|
377
|
+
ins.push({
|
|
378
|
+
icon: <Users className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
379
|
+
metric: `${del.launched} agents delegated — ${del.completionRate}% completion`,
|
|
380
|
+
evidence: `${del.parallelBursts} parallel bursts, up to ${del.maxConcurrent} concurrent. ~${del.timeSavedMin} min saved.`,
|
|
381
|
+
action: "Excellent use of parallelism. Share this pattern with the team.",
|
|
382
|
+
roi: `Parallel delegation saved ~${del.timeSavedMin} minutes.`,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// ── S2: No delegation ──
|
|
387
|
+
if (del.launched === 0 && totalEvents > 50) {
|
|
388
|
+
ins.push({
|
|
389
|
+
icon: <Users className="h-5 w-5 text-muted-foreground" />, severity: "neutral",
|
|
390
|
+
metric: "Everything ran sequentially — zero delegation",
|
|
391
|
+
evidence: `${totalEvents} events, zero parallel agents. Single-threaded workflow.`,
|
|
392
|
+
action: "Try subagents for research — fire 3-5 at once instead of one by one.",
|
|
393
|
+
roi: "One parallel burst turns 10 minutes of research into 2 minutes.",
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// ── S3: Low agent completion ──
|
|
398
|
+
if (del.launched >= 5 && del.completionRate < 60) {
|
|
399
|
+
ins.push({
|
|
400
|
+
icon: <AlertTriangle className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
401
|
+
metric: `Only ${del.completionRate}% of agents complete successfully`,
|
|
402
|
+
evidence: `${del.launched} launched, ${del.completed} completed. ${del.launched - del.completed} failed or timed out.`,
|
|
403
|
+
action: "Simplify agent prompts. Break complex tasks into smaller units.",
|
|
404
|
+
roi: "Higher completion = less wasted compute.",
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ── S4: Parallel burst champion ──
|
|
409
|
+
if (del.maxConcurrent >= 4) {
|
|
410
|
+
ins.push({
|
|
411
|
+
icon: <Cpu className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
412
|
+
metric: `Peak parallelism: ${del.maxConcurrent} agents simultaneously`,
|
|
413
|
+
evidence: `${del.parallelBursts} bursts of parallel work. Maximum throughput achieved.`,
|
|
414
|
+
action: "You're using the platform at full capacity. Well done.",
|
|
415
|
+
roi: `Peak parallelism multiplies throughput by ${del.maxConcurrent}x.`,
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// ── G1: High rejection rate ──
|
|
420
|
+
if (gov.totalRejections > 10) {
|
|
421
|
+
const topRej = gov.topRejected[0];
|
|
422
|
+
ins.push({
|
|
423
|
+
icon: <Shield className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
424
|
+
metric: `${gov.totalRejections} approaches rejected by user`,
|
|
425
|
+
evidence: `Top rejected: ${topRej?.tool || 'unknown'} (${topRej?.count || 0} times). The agent keeps trying things you don't want.`,
|
|
426
|
+
action: "Update CLAUDE.md with clearer constraints to prevent unwanted actions.",
|
|
427
|
+
roi: `Better rules prevent ${gov.totalRejections} unnecessary tool calls.`,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// ── G2: Productive session — commits + clean exit (★★ STRONG from agentisd #25) ──
|
|
432
|
+
if (git.totalCommits > 0 && ei.totalErrors < 3) {
|
|
433
|
+
ins.push({
|
|
434
|
+
icon: <CheckCircle className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
435
|
+
metric: `Productive sessions — ${git.totalCommits} commits, clean exit`,
|
|
436
|
+
evidence: `${git.totalCommits} commits with only ${ei.totalErrors} errors. Work shipped successfully.`,
|
|
437
|
+
action: "Document what made this session productive — replicate the pattern.",
|
|
438
|
+
roi: "Productive sessions compound. Each clean commit is future-proof.",
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
// ── G3: Plan discipline ──
|
|
443
|
+
if (gov.planApproved + gov.planRejected > 0 && gov.planApprovalRate > 80) {
|
|
444
|
+
ins.push({
|
|
445
|
+
icon: <CheckCircle className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
446
|
+
metric: `${gov.planApprovalRate}% of plans approved on first try`,
|
|
447
|
+
evidence: `${gov.planApproved} plans approved, ${gov.planRejected} rejected. Strong alignment.`,
|
|
448
|
+
action: "Strong planning discipline. Keep using plan mode for complex tasks.",
|
|
449
|
+
roi: "Approved plans mean fewer mid-session course corrections.",
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// ── G4: Error rate high for event volume (★★ STRONG from agentisd #2) ──
|
|
454
|
+
if (ei.totalErrors > 0 && totalEvents > 30) {
|
|
455
|
+
const errorPct = Math.round(1000 * ei.totalErrors / totalEvents) / 10;
|
|
456
|
+
if (errorPct > 15) {
|
|
457
|
+
ins.push({
|
|
458
|
+
icon: <AlertTriangle className="h-5 w-5 text-red-500" />, severity: "warning",
|
|
459
|
+
metric: `${errorPct}% error rate — ${ei.totalErrors} errors in ${totalEvents} events`,
|
|
460
|
+
evidence: `Error rate is above 15%. Most tools should succeed on first try. High error rate wastes compute.`,
|
|
461
|
+
action: "Check repeating errors. Add error patterns to CLAUDE.md to prevent them.",
|
|
462
|
+
roi: `Fixing the top error source saves ~${Math.round(ei.totalErrors * 1.5)} minutes of retry loops.`,
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// ── H1: Rules loaded consistently ──
|
|
468
|
+
if (ctx.uniqueRuleFiles > 0 && ctx.ruleLoadsPerSession > 1) {
|
|
469
|
+
ins.push({
|
|
470
|
+
icon: <FileCode className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
471
|
+
metric: `${ctx.uniqueRuleFiles} rule files loaded consistently`,
|
|
472
|
+
evidence: `${ctx.ruleLoadsPerSession.toFixed(1)} loads per session. Rules are guiding behavior.`,
|
|
473
|
+
action: "Consistent rule loading means consistent behavior.",
|
|
474
|
+
roi: "Rules prevent the top error patterns.",
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// ── H2: No rules ──
|
|
479
|
+
if (ctx.uniqueRuleFiles === 0) {
|
|
480
|
+
ins.push({
|
|
481
|
+
icon: <FileCode className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
482
|
+
metric: "No CLAUDE.md or rule files detected",
|
|
483
|
+
evidence: "The agent runs without project-specific instructions.",
|
|
484
|
+
action: "Create a CLAUDE.md with project conventions, constraints, and patterns.",
|
|
485
|
+
roi: "Projects with CLAUDE.md consistently show lower error rates.",
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// H3 (low skill usage) removed — filler, not actionable
|
|
490
|
+
// H4 (implement-heavy) removed — observational, no clear action
|
|
491
|
+
|
|
492
|
+
// ── W1: Unresolved blockers ──
|
|
493
|
+
if (ctx.totalBlockers > 0 && ctx.blockerResolutionRate < 50) {
|
|
494
|
+
ins.push({
|
|
495
|
+
icon: <AlertTriangle className="h-5 w-5 text-red-500" />, severity: "critical",
|
|
496
|
+
metric: `${ctx.totalBlockers - ctx.resolvedBlockers} unresolved blockers`,
|
|
497
|
+
evidence: `Only ${ctx.blockerResolutionRate}% of blockers resolved. Open items: ${ctx.totalBlockers - ctx.resolvedBlockers}.`,
|
|
498
|
+
action: "Document blockers for the next session or escalate.",
|
|
499
|
+
roi: "Unresolved blockers multiply in cost over time.",
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ── W2: CLAUDE.md update correlated with error drop (★★★ KILLER from agentisd #22) ──
|
|
504
|
+
if (ctx.uniqueRuleFiles > 0 && ei.totalErrors > 0 && ei.resolutionRate > 50) {
|
|
505
|
+
ins.push({
|
|
506
|
+
icon: <FileCode className="h-5 w-5 text-emerald-500" />, severity: "positive",
|
|
507
|
+
metric: "CLAUDE.md loaded + errors resolving — rules are working",
|
|
508
|
+
evidence: `${ctx.uniqueRuleFiles} rule files loaded, ${ei.resolutionRate}% error resolution rate. Rules correlate with self-healing sessions.`,
|
|
509
|
+
action: "Update CLAUDE.md when you discover new error patterns — each rule prevents future errors.",
|
|
510
|
+
roi: "Sessions with rules loaded show measurably higher error resolution rates.",
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
if (ctx.uniqueRuleFiles === 0 && ei.totalErrors > 5) {
|
|
514
|
+
ins.push({
|
|
515
|
+
icon: <FileCode className="h-5 w-5 text-red-500" />, severity: "critical",
|
|
516
|
+
metric: `No CLAUDE.md + ${ei.totalErrors} errors — rules would prevent this`,
|
|
517
|
+
evidence: `${ei.totalErrors} errors without any project rules loaded. CLAUDE.md is the #1 way to reduce errors.`,
|
|
518
|
+
action: "Create CLAUDE.md with error patterns, constraints, and project conventions.",
|
|
519
|
+
roi: "Adding CLAUDE.md is the single most impactful action for reducing errors.",
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// ── W3: Persistent struggle — same file across sessions (★★ STRONG from agentisd #13) ──
|
|
524
|
+
if (fi.hotFiles.length > 0 && fi.hotFiles[0].touches > 8) {
|
|
525
|
+
const worst = fi.hotFiles[0];
|
|
526
|
+
ins.push({
|
|
527
|
+
icon: <AlertTriangle className="h-5 w-5 text-red-500" />, severity: "warning",
|
|
528
|
+
metric: `${worst.file.split('/').pop()} touched ${worst.touches} times — persistent struggle`,
|
|
529
|
+
evidence: `File edited ${worst.touches} times across sessions. This suggests unclear requirements or wrong approach.`,
|
|
530
|
+
action: "Write a spec or test first. Consider if the approach needs rethinking entirely.",
|
|
531
|
+
roi: `Spec-first approach reduces rework from ${worst.touches} to ~3 edits.`,
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// X1-X4 composite scores shown as hero cards — only generate insight for critical scores
|
|
536
|
+
if (cs.productivity < 40) {
|
|
537
|
+
ins.push({
|
|
538
|
+
icon: <TrendingUp className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
539
|
+
metric: `Productivity Score: ${cs.productivity}/100 — room to improve`,
|
|
540
|
+
evidence: `Low commit rate or high rework. Consider structured planning before execution.`,
|
|
541
|
+
action: "Start sessions with a plan. Commit incrementally. Delegate research to agents.",
|
|
542
|
+
roi: "Planning + committing incrementally improves output consistency.",
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
if (cs.quality < 40) {
|
|
546
|
+
ins.push({
|
|
547
|
+
icon: <Shield className="h-5 w-5 text-red-500" />, severity: "critical",
|
|
548
|
+
metric: `Quality Score: ${cs.quality}/100 — needs attention`,
|
|
549
|
+
evidence: `High error rate or unresolved errors. Retry loops detected.`,
|
|
550
|
+
action: "Add error patterns to CLAUDE.md. Write tests first. Break retry loops early.",
|
|
551
|
+
roi: "Addressing error patterns in-session prevents them from recurring.",
|
|
552
|
+
});
|
|
553
|
+
}
|
|
554
|
+
if (cs.contextHealth < 40) {
|
|
555
|
+
ins.push({
|
|
556
|
+
icon: <Brain className="h-5 w-5 text-amber-500" />, severity: "warning",
|
|
557
|
+
metric: `Context Health: ${cs.contextHealth}/100 — agent lacks guidance`,
|
|
558
|
+
evidence: `Missing rules, few skills, no plans. The agent works without context.`,
|
|
559
|
+
action: "Create CLAUDE.md, use plan mode, try skills like /commit.",
|
|
560
|
+
roi: "Better context hygiene directly correlates with fewer errors.",
|
|
278
561
|
});
|
|
279
562
|
}
|
|
280
563
|
|
|
@@ -284,11 +567,21 @@ function generateInsights(d: AnalyticsData): Insight[] {
|
|
|
284
567
|
// ── Dashboard ──
|
|
285
568
|
function Dashboard() {
|
|
286
569
|
const [data, setData] = useState<AnalyticsData | null>(null);
|
|
287
|
-
|
|
570
|
+
const [catData, setCatData] = useState<CategoryAnalyticsData | null>(null);
|
|
571
|
+
useEffect(() => {
|
|
572
|
+
api.analytics().then(setData);
|
|
573
|
+
api.categoryAnalytics().then(setCatData).catch(() => {}); // graceful — catData stays null, sections hidden
|
|
574
|
+
}, []);
|
|
288
575
|
if (!data) return <p className="text-muted-foreground animate-pulse">Loading analytics...</p>;
|
|
289
576
|
|
|
290
577
|
const t = data.totals;
|
|
291
|
-
const
|
|
578
|
+
const categoryInsights = catData ? generateCategoryInsights(catData) : [];
|
|
579
|
+
const allInsights = [...generateInsights(data), ...categoryInsights];
|
|
580
|
+
// Sort: critical first, then warning, positive, neutral
|
|
581
|
+
const SEV_ORDER = { critical: 0, warning: 1, positive: 2, neutral: 3 };
|
|
582
|
+
allInsights.sort((a, b) => (SEV_ORDER[a.severity] ?? 4) - (SEV_ORDER[b.severity] ?? 4));
|
|
583
|
+
const [showAllInsights, setShowAllInsights] = useState(false);
|
|
584
|
+
const insights = showAllInsights ? allInsights : allInsights.slice(0, 8);
|
|
292
585
|
|
|
293
586
|
// Compute derived values
|
|
294
587
|
const topTool = data.toolUsage[0];
|
|
@@ -326,6 +619,14 @@ function Dashboard() {
|
|
|
326
619
|
<div className="grid gap-3 md:grid-cols-2">
|
|
327
620
|
{insights.map((ins, i) => <InsightCard key={i} {...ins} />)}
|
|
328
621
|
</div>
|
|
622
|
+
{allInsights.length > 8 && (
|
|
623
|
+
<button
|
|
624
|
+
onClick={() => setShowAllInsights(!showAllInsights)}
|
|
625
|
+
className="mt-2 text-[11px] text-muted-foreground hover:text-foreground transition-colors"
|
|
626
|
+
>
|
|
627
|
+
{showAllInsights ? "Show less" : `Show all ${allInsights.length} insights`}
|
|
628
|
+
</button>
|
|
629
|
+
)}
|
|
329
630
|
</div>
|
|
330
631
|
)}
|
|
331
632
|
|
|
@@ -915,6 +1216,266 @@ function Dashboard() {
|
|
|
915
1216
|
)}
|
|
916
1217
|
</div>
|
|
917
1218
|
|
|
1219
|
+
{catData && !catData.insufficientData && (
|
|
1220
|
+
<>
|
|
1221
|
+
<Separator />
|
|
1222
|
+
|
|
1223
|
+
{/* ── Category Intelligence ── */}
|
|
1224
|
+
<div>
|
|
1225
|
+
<div className="flex items-center gap-2 mb-3">
|
|
1226
|
+
<Cpu className="h-4 w-4 text-purple-500" />
|
|
1227
|
+
<h3 className="text-sm font-semibold uppercase tracking-wide text-muted-foreground">Session Intelligence</h3>
|
|
1228
|
+
</div>
|
|
1229
|
+
|
|
1230
|
+
{/* Composite Scores */}
|
|
1231
|
+
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
|
|
1232
|
+
<Card className={catData.compositeScores.productivity >= 70 ? "border-emerald-500/30" : catData.compositeScores.productivity < 40 ? "border-red-500/30" : "border-amber-500/30"}>
|
|
1233
|
+
<CardContent className="pt-4">
|
|
1234
|
+
<div className="text-center">
|
|
1235
|
+
<div className="text-3xl font-bold tabular-nums">{catData.compositeScores.productivity}</div>
|
|
1236
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mt-1">Productivity</p>
|
|
1237
|
+
</div>
|
|
1238
|
+
</CardContent>
|
|
1239
|
+
</Card>
|
|
1240
|
+
<Card className={catData.compositeScores.quality >= 70 ? "border-emerald-500/30" : catData.compositeScores.quality < 40 ? "border-red-500/30" : "border-amber-500/30"}>
|
|
1241
|
+
<CardContent className="pt-4">
|
|
1242
|
+
<div className="text-center">
|
|
1243
|
+
<div className="text-3xl font-bold tabular-nums">{catData.compositeScores.quality}</div>
|
|
1244
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mt-1">Quality</p>
|
|
1245
|
+
</div>
|
|
1246
|
+
</CardContent>
|
|
1247
|
+
</Card>
|
|
1248
|
+
<Card className={catData.compositeScores.delegation >= 70 ? "border-emerald-500/30" : catData.compositeScores.delegation < 40 ? "border-red-500/30" : "border-amber-500/30"}>
|
|
1249
|
+
<CardContent className="pt-4">
|
|
1250
|
+
<div className="text-center">
|
|
1251
|
+
<div className="text-3xl font-bold tabular-nums">{catData.compositeScores.delegation}</div>
|
|
1252
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mt-1">Delegation</p>
|
|
1253
|
+
</div>
|
|
1254
|
+
</CardContent>
|
|
1255
|
+
</Card>
|
|
1256
|
+
<Card className={catData.compositeScores.contextHealth >= 70 ? "border-emerald-500/30" : catData.compositeScores.contextHealth < 40 ? "border-red-500/30" : "border-amber-500/30"}>
|
|
1257
|
+
<CardContent className="pt-4">
|
|
1258
|
+
<div className="text-center">
|
|
1259
|
+
<div className="text-3xl font-bold tabular-nums">{catData.compositeScores.contextHealth}</div>
|
|
1260
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mt-1">Context Health</p>
|
|
1261
|
+
</div>
|
|
1262
|
+
</CardContent>
|
|
1263
|
+
</Card>
|
|
1264
|
+
</div>
|
|
1265
|
+
|
|
1266
|
+
{/* Category Distribution */}
|
|
1267
|
+
<div className="grid gap-4 lg:grid-cols-2">
|
|
1268
|
+
<Card>
|
|
1269
|
+
<CardHeader>
|
|
1270
|
+
<div className="flex items-center gap-2">
|
|
1271
|
+
<Activity className="h-4 w-4 text-blue-500" />
|
|
1272
|
+
<CardTitle className="text-sm">Event Categories</CardTitle>
|
|
1273
|
+
</div>
|
|
1274
|
+
<CardDescription>{catData.categories.reduce((a, b) => a + b.count, 0)} events across {catData.categories.filter(c => c.count > 0).length} categories</CardDescription>
|
|
1275
|
+
</CardHeader>
|
|
1276
|
+
<CardContent>
|
|
1277
|
+
<div className="space-y-2">
|
|
1278
|
+
{catData.categories.filter(c => c.count > 0).sort((a, b) => b.count - a.count).slice(0, 12).map((cat, i) => {
|
|
1279
|
+
const max = catData.categories.reduce((a, b) => Math.max(a, b.count), 0);
|
|
1280
|
+
return (
|
|
1281
|
+
<div key={cat.category} className="flex items-center gap-2">
|
|
1282
|
+
<span className="text-[11px] text-muted-foreground w-28 truncate">{cat.category}</span>
|
|
1283
|
+
<div className="flex-1 h-5 bg-muted/50 rounded-sm overflow-hidden">
|
|
1284
|
+
<div className="h-full rounded-sm" style={{ width: `${(cat.count / max) * 100}%`, backgroundColor: COLORS[i % COLORS.length] }} />
|
|
1285
|
+
</div>
|
|
1286
|
+
<span className="text-[11px] tabular-nums text-muted-foreground w-8 text-right">{cat.count}</span>
|
|
1287
|
+
</div>
|
|
1288
|
+
);
|
|
1289
|
+
})}
|
|
1290
|
+
</div>
|
|
1291
|
+
</CardContent>
|
|
1292
|
+
</Card>
|
|
1293
|
+
|
|
1294
|
+
{/* Error Intelligence */}
|
|
1295
|
+
<Card>
|
|
1296
|
+
<CardHeader>
|
|
1297
|
+
<div className="flex items-center gap-2">
|
|
1298
|
+
<Shield className="h-4 w-4 text-red-500" />
|
|
1299
|
+
<CardTitle className="text-sm">Error Intelligence</CardTitle>
|
|
1300
|
+
</div>
|
|
1301
|
+
<CardDescription>Resolution rate, retry storms, latency</CardDescription>
|
|
1302
|
+
</CardHeader>
|
|
1303
|
+
<CardContent>
|
|
1304
|
+
<div className="grid grid-cols-3 gap-4 mb-4">
|
|
1305
|
+
<Mini label="Errors" value={catData.errorIntelligence.totalErrors} />
|
|
1306
|
+
<Mini label="Resolved" value={`${catData.errorIntelligence.resolutionRate}%`} color={catData.errorIntelligence.resolutionRate > 70 ? "text-emerald-500" : "text-amber-500"} />
|
|
1307
|
+
<Mini label="Retry Storms" value={catData.errorIntelligence.retryStorms} color={catData.errorIntelligence.retryStorms > 0 ? "text-red-500" : ""} />
|
|
1308
|
+
</div>
|
|
1309
|
+
{catData.errorIntelligence.latencyByTool.length > 0 && (
|
|
1310
|
+
<div className="space-y-1.5">
|
|
1311
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider">Slowest Tools</p>
|
|
1312
|
+
{catData.errorIntelligence.latencyByTool.slice(0, 5).map((t) => (
|
|
1313
|
+
<div key={t.tool} className="flex items-center gap-2">
|
|
1314
|
+
<span className="text-[11px] text-muted-foreground w-20 truncate">{t.tool}</span>
|
|
1315
|
+
<div className="flex-1 h-4 bg-muted/50 rounded-sm overflow-hidden">
|
|
1316
|
+
<div className="h-full bg-amber-500/60 rounded-sm" style={{ width: `${Math.min((t.avg_ms / 30000) * 100, 100)}%` }} />
|
|
1317
|
+
</div>
|
|
1318
|
+
<span className="text-[11px] tabular-nums text-muted-foreground w-12 text-right">{(t.avg_ms / 1000).toFixed(1)}s</span>
|
|
1319
|
+
</div>
|
|
1320
|
+
))}
|
|
1321
|
+
</div>
|
|
1322
|
+
)}
|
|
1323
|
+
{catData.errorIntelligence.topErrorTools.length > 0 && (
|
|
1324
|
+
<div className="space-y-1.5 mt-3">
|
|
1325
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider">Top Error Sources</p>
|
|
1326
|
+
{catData.errorIntelligence.topErrorTools.slice(0, 5).map((t) => (
|
|
1327
|
+
<div key={t.tool} className="flex items-center justify-between">
|
|
1328
|
+
<span className="text-[11px] text-muted-foreground">{t.tool}</span>
|
|
1329
|
+
<Badge variant="secondary" className="text-[10px]">{t.count}</Badge>
|
|
1330
|
+
</div>
|
|
1331
|
+
))}
|
|
1332
|
+
</div>
|
|
1333
|
+
)}
|
|
1334
|
+
</CardContent>
|
|
1335
|
+
</Card>
|
|
1336
|
+
</div>
|
|
1337
|
+
</div>
|
|
1338
|
+
|
|
1339
|
+
<Separator />
|
|
1340
|
+
|
|
1341
|
+
{/* ── Governance + Delegation ── */}
|
|
1342
|
+
<div className="grid gap-4 lg:grid-cols-2">
|
|
1343
|
+
<Card>
|
|
1344
|
+
<CardHeader>
|
|
1345
|
+
<div className="flex items-center gap-2">
|
|
1346
|
+
<Shield className="h-4 w-4 text-purple-500" />
|
|
1347
|
+
<CardTitle className="text-sm">Governance</CardTitle>
|
|
1348
|
+
</div>
|
|
1349
|
+
<CardDescription>Decisions, rejections, plans, constraints</CardDescription>
|
|
1350
|
+
</CardHeader>
|
|
1351
|
+
<CardContent>
|
|
1352
|
+
<div className="grid grid-cols-2 gap-4 mb-4">
|
|
1353
|
+
<Mini label="Rejections" value={catData.governance.totalRejections} color={catData.governance.totalRejections > 20 ? "text-amber-500" : ""} />
|
|
1354
|
+
<Mini label="Decisions" value={catData.governance.totalDecisions} />
|
|
1355
|
+
<Mini label="Plans Approved" value={catData.governance.planApproved} />
|
|
1356
|
+
<Mini label="Constraints" value={catData.governance.totalConstraints} />
|
|
1357
|
+
</div>
|
|
1358
|
+
{catData.governance.topRejected.length > 0 && (
|
|
1359
|
+
<div className="space-y-1.5">
|
|
1360
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider">Top Rejected Tools</p>
|
|
1361
|
+
{catData.governance.topRejected.slice(0, 5).map((t) => (
|
|
1362
|
+
<div key={t.tool} className="flex items-center justify-between">
|
|
1363
|
+
<span className="text-[11px] text-muted-foreground">{t.tool}</span>
|
|
1364
|
+
<Badge variant="secondary" className="text-[10px]">{t.count}</Badge>
|
|
1365
|
+
</div>
|
|
1366
|
+
))}
|
|
1367
|
+
</div>
|
|
1368
|
+
)}
|
|
1369
|
+
</CardContent>
|
|
1370
|
+
</Card>
|
|
1371
|
+
|
|
1372
|
+
<Card>
|
|
1373
|
+
<CardHeader>
|
|
1374
|
+
<div className="flex items-center gap-2">
|
|
1375
|
+
<Cpu className="h-4 w-4 text-emerald-500" />
|
|
1376
|
+
<CardTitle className="text-sm">Delegation</CardTitle>
|
|
1377
|
+
</div>
|
|
1378
|
+
<CardDescription>Agent parallelism and completion</CardDescription>
|
|
1379
|
+
</CardHeader>
|
|
1380
|
+
<CardContent>
|
|
1381
|
+
<div className="grid grid-cols-3 gap-4 mb-4">
|
|
1382
|
+
<Mini label="Launched" value={catData.delegation.launched} />
|
|
1383
|
+
<Mini label="Completed" value={catData.delegation.completed} />
|
|
1384
|
+
<Mini label="Rate" value={`${catData.delegation.completionRate}%`} color={catData.delegation.completionRate > 70 ? "text-emerald-500" : "text-amber-500"} />
|
|
1385
|
+
</div>
|
|
1386
|
+
<div className="grid grid-cols-3 gap-4">
|
|
1387
|
+
<Mini label="Bursts" value={catData.delegation.parallelBursts} />
|
|
1388
|
+
<Mini label="Max ∥" value={catData.delegation.maxConcurrent} />
|
|
1389
|
+
<Mini label="Saved" value={`${catData.delegation.timeSavedMin}m`} color="text-emerald-500" />
|
|
1390
|
+
</div>
|
|
1391
|
+
</CardContent>
|
|
1392
|
+
</Card>
|
|
1393
|
+
</div>
|
|
1394
|
+
|
|
1395
|
+
<Separator />
|
|
1396
|
+
|
|
1397
|
+
{/* ── Git Productivity + Context Health ── */}
|
|
1398
|
+
<div className="grid gap-4 lg:grid-cols-2">
|
|
1399
|
+
<Card>
|
|
1400
|
+
<CardHeader>
|
|
1401
|
+
<div className="flex items-center gap-2">
|
|
1402
|
+
<GitBranch className="h-4 w-4 text-blue-500" />
|
|
1403
|
+
<CardTitle className="text-sm">Git Productivity</CardTitle>
|
|
1404
|
+
</div>
|
|
1405
|
+
<CardDescription>Commit patterns and operation mix</CardDescription>
|
|
1406
|
+
</CardHeader>
|
|
1407
|
+
<CardContent>
|
|
1408
|
+
<div className="grid grid-cols-3 gap-4 mb-4">
|
|
1409
|
+
<Mini label="Commits" value={catData.gitProductivity.totalCommits} />
|
|
1410
|
+
<Mini label="Pushes" value={catData.gitProductivity.totalPushes} />
|
|
1411
|
+
<Mini label="C:P Ratio" value={catData.gitProductivity.commitPushRatio > 0 ? `${catData.gitProductivity.commitPushRatio}:1` : "—"} />
|
|
1412
|
+
</div>
|
|
1413
|
+
{catData.gitProductivity.operationMix.length > 0 && (
|
|
1414
|
+
<div className="space-y-1.5">
|
|
1415
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider">Git Operations</p>
|
|
1416
|
+
{catData.gitProductivity.operationMix.slice(0, 8).map((op) => {
|
|
1417
|
+
const max = catData.gitProductivity.operationMix[0]?.count || 1;
|
|
1418
|
+
return (
|
|
1419
|
+
<div key={op.operation} className="flex items-center gap-2">
|
|
1420
|
+
<span className="text-[11px] text-muted-foreground w-16 truncate">{op.operation}</span>
|
|
1421
|
+
<div className="flex-1 h-4 bg-muted/50 rounded-sm overflow-hidden">
|
|
1422
|
+
<div className="h-full bg-blue-500/60 rounded-sm" style={{ width: `${(op.count / max) * 100}%` }} />
|
|
1423
|
+
</div>
|
|
1424
|
+
<span className="text-[11px] tabular-nums text-muted-foreground w-6 text-right">{op.count}</span>
|
|
1425
|
+
</div>
|
|
1426
|
+
);
|
|
1427
|
+
})}
|
|
1428
|
+
</div>
|
|
1429
|
+
)}
|
|
1430
|
+
</CardContent>
|
|
1431
|
+
</Card>
|
|
1432
|
+
|
|
1433
|
+
<Card>
|
|
1434
|
+
<CardHeader>
|
|
1435
|
+
<div className="flex items-center gap-2">
|
|
1436
|
+
<Brain className="h-4 w-4 text-cyan-500" />
|
|
1437
|
+
<CardTitle className="text-sm">Context Health</CardTitle>
|
|
1438
|
+
</div>
|
|
1439
|
+
<CardDescription>Rules, skills, work modes, blockers</CardDescription>
|
|
1440
|
+
</CardHeader>
|
|
1441
|
+
<CardContent>
|
|
1442
|
+
<div className="grid grid-cols-3 gap-4 mb-4">
|
|
1443
|
+
<Mini label="Rule Files" value={catData.contextHealth.uniqueRuleFiles} />
|
|
1444
|
+
<Mini label="Skills" value={catData.contextHealth.uniqueSkills} />
|
|
1445
|
+
<Mini label="Compact Rate" value={`${catData.contextHealth.compactRate}%`} color={catData.contextHealth.compactRate > 60 ? "text-amber-500" : "text-emerald-500"} />
|
|
1446
|
+
</div>
|
|
1447
|
+
{catData.contextHealth.modeDistribution.length > 0 && (
|
|
1448
|
+
<div className="mb-3">
|
|
1449
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mb-1.5">Work Modes</p>
|
|
1450
|
+
<RatioBar items={catData.contextHealth.modeDistribution.map((m, i) => ({
|
|
1451
|
+
label: `${m.mode} (${m.pct}%)`,
|
|
1452
|
+
value: m.count,
|
|
1453
|
+
color: COLORS[i % COLORS.length],
|
|
1454
|
+
}))} />
|
|
1455
|
+
</div>
|
|
1456
|
+
)}
|
|
1457
|
+
{catData.contextHealth.skillList.length > 0 && (
|
|
1458
|
+
<div>
|
|
1459
|
+
<p className="text-[10px] text-muted-foreground uppercase tracking-wider mb-1.5">Active Skills</p>
|
|
1460
|
+
<div className="flex flex-wrap gap-1">
|
|
1461
|
+
{catData.contextHealth.skillList.map(s => (
|
|
1462
|
+
<Badge key={s} variant="secondary" className="text-[10px]">{s}</Badge>
|
|
1463
|
+
))}
|
|
1464
|
+
</div>
|
|
1465
|
+
</div>
|
|
1466
|
+
)}
|
|
1467
|
+
{catData.contextHealth.totalBlockers > 0 && (
|
|
1468
|
+
<div className="mt-3 grid grid-cols-2 gap-4">
|
|
1469
|
+
<Mini label="Blockers" value={catData.contextHealth.totalBlockers} color="text-amber-500" />
|
|
1470
|
+
<Mini label="Resolved" value={`${catData.contextHealth.blockerResolutionRate}%`} color={catData.contextHealth.blockerResolutionRate > 70 ? "text-emerald-500" : "text-red-500"} />
|
|
1471
|
+
</div>
|
|
1472
|
+
)}
|
|
1473
|
+
</CardContent>
|
|
1474
|
+
</Card>
|
|
1475
|
+
</div>
|
|
1476
|
+
</>
|
|
1477
|
+
)}
|
|
1478
|
+
|
|
918
1479
|
</div>
|
|
919
1480
|
</div>
|
|
920
1481
|
);
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "Context Mode",
|
|
4
4
|
"kind": "tool",
|
|
5
5
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.101",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.101",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
|
|
6
6
|
"author": "Mert Koseoğlu",
|