opencode-swarm-plugin 0.43.0 → 0.44.1
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/bin/cass.characterization.test.ts +422 -0
- package/bin/swarm.serve.test.ts +6 -4
- package/bin/swarm.test.ts +68 -0
- package/bin/swarm.ts +81 -8
- package/dist/compaction-prompt-scoring.js +139 -0
- package/dist/contributor-tools.d.ts +42 -0
- package/dist/contributor-tools.d.ts.map +1 -0
- package/dist/eval-capture.js +12811 -0
- package/dist/hive.d.ts.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7728 -62590
- package/dist/plugin.js +23833 -78695
- package/dist/sessions/agent-discovery.d.ts +59 -0
- package/dist/sessions/agent-discovery.d.ts.map +1 -0
- package/dist/sessions/index.d.ts +10 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/swarm-orchestrate.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-review.d.ts.map +1 -1
- package/package.json +17 -5
- package/.changeset/swarm-insights-data-layer.md +0 -63
- package/.hive/analysis/eval-failure-analysis-2025-12-25.md +0 -331
- package/.hive/analysis/session-data-quality-audit.md +0 -320
- package/.hive/eval-results.json +0 -483
- package/.hive/issues.jsonl +0 -138
- package/.hive/memories.jsonl +0 -729
- package/.opencode/eval-history.jsonl +0 -327
- package/.turbo/turbo-build.log +0 -9
- package/CHANGELOG.md +0 -2255
- package/SCORER-ANALYSIS.md +0 -598
- package/docs/analysis/subagent-coordination-patterns.md +0 -902
- package/docs/analysis-socratic-planner-pattern.md +0 -504
- package/docs/planning/ADR-001-monorepo-structure.md +0 -171
- package/docs/planning/ADR-002-package-extraction.md +0 -393
- package/docs/planning/ADR-003-performance-improvements.md +0 -451
- package/docs/planning/ADR-004-message-queue-features.md +0 -187
- package/docs/planning/ADR-005-devtools-observability.md +0 -202
- package/docs/planning/ADR-007-swarm-enhancements-worktree-review.md +0 -168
- package/docs/planning/ADR-008-worker-handoff-protocol.md +0 -293
- package/docs/planning/ADR-009-oh-my-opencode-patterns.md +0 -353
- package/docs/planning/ROADMAP.md +0 -368
- package/docs/semantic-memory-cli-syntax.md +0 -123
- package/docs/swarm-mail-architecture.md +0 -1147
- package/docs/testing/context-recovery-test.md +0 -470
- package/evals/ARCHITECTURE.md +0 -1189
- package/evals/README.md +0 -768
- package/evals/compaction-prompt.eval.ts +0 -149
- package/evals/compaction-resumption.eval.ts +0 -289
- package/evals/coordinator-behavior.eval.ts +0 -307
- package/evals/coordinator-session.eval.ts +0 -154
- package/evals/evalite.config.ts.bak +0 -15
- package/evals/example.eval.ts +0 -31
- package/evals/fixtures/compaction-cases.ts +0 -350
- package/evals/fixtures/compaction-prompt-cases.ts +0 -311
- package/evals/fixtures/coordinator-sessions.ts +0 -328
- package/evals/fixtures/decomposition-cases.ts +0 -105
- package/evals/lib/compaction-loader.test.ts +0 -248
- package/evals/lib/compaction-loader.ts +0 -320
- package/evals/lib/data-loader.evalite-test.ts +0 -289
- package/evals/lib/data-loader.test.ts +0 -345
- package/evals/lib/data-loader.ts +0 -281
- package/evals/lib/llm.ts +0 -115
- package/evals/scorers/compaction-prompt-scorers.ts +0 -145
- package/evals/scorers/compaction-scorers.ts +0 -305
- package/evals/scorers/coordinator-discipline.evalite-test.ts +0 -539
- package/evals/scorers/coordinator-discipline.ts +0 -325
- package/evals/scorers/index.test.ts +0 -146
- package/evals/scorers/index.ts +0 -328
- package/evals/scorers/outcome-scorers.evalite-test.ts +0 -27
- package/evals/scorers/outcome-scorers.ts +0 -349
- package/evals/swarm-decomposition.eval.ts +0 -121
- package/examples/commands/swarm.md +0 -745
- package/examples/plugin-wrapper-template.ts +0 -2426
- package/examples/skills/hive-workflow/SKILL.md +0 -212
- package/examples/skills/skill-creator/SKILL.md +0 -223
- package/examples/skills/swarm-coordination/SKILL.md +0 -292
- package/global-skills/cli-builder/SKILL.md +0 -344
- package/global-skills/cli-builder/references/advanced-patterns.md +0 -244
- package/global-skills/learning-systems/SKILL.md +0 -644
- package/global-skills/skill-creator/LICENSE.txt +0 -202
- package/global-skills/skill-creator/SKILL.md +0 -352
- package/global-skills/skill-creator/references/output-patterns.md +0 -82
- package/global-skills/skill-creator/references/workflows.md +0 -28
- package/global-skills/swarm-coordination/SKILL.md +0 -995
- package/global-skills/swarm-coordination/references/coordinator-patterns.md +0 -235
- package/global-skills/swarm-coordination/references/strategies.md +0 -138
- package/global-skills/system-design/SKILL.md +0 -213
- package/global-skills/testing-patterns/SKILL.md +0 -430
- package/global-skills/testing-patterns/references/dependency-breaking-catalog.md +0 -586
- package/opencode-swarm-plugin-0.30.7.tgz +0 -0
- package/opencode-swarm-plugin-0.31.0.tgz +0 -0
- package/scripts/cleanup-test-memories.ts +0 -346
- package/scripts/init-skill.ts +0 -222
- package/scripts/migrate-unknown-sessions.ts +0 -349
- package/scripts/validate-skill.ts +0 -204
- package/src/agent-mail.ts +0 -1724
- package/src/anti-patterns.test.ts +0 -1167
- package/src/anti-patterns.ts +0 -448
- package/src/compaction-capture.integration.test.ts +0 -257
- package/src/compaction-hook.test.ts +0 -838
- package/src/compaction-hook.ts +0 -1204
- package/src/compaction-observability.integration.test.ts +0 -139
- package/src/compaction-observability.test.ts +0 -187
- package/src/compaction-observability.ts +0 -324
- package/src/compaction-prompt-scorers.test.ts +0 -475
- package/src/compaction-prompt-scoring.ts +0 -300
- package/src/dashboard.test.ts +0 -611
- package/src/dashboard.ts +0 -462
- package/src/error-enrichment.test.ts +0 -403
- package/src/error-enrichment.ts +0 -219
- package/src/eval-capture.test.ts +0 -1015
- package/src/eval-capture.ts +0 -929
- package/src/eval-gates.test.ts +0 -306
- package/src/eval-gates.ts +0 -218
- package/src/eval-history.test.ts +0 -508
- package/src/eval-history.ts +0 -214
- package/src/eval-learning.test.ts +0 -378
- package/src/eval-learning.ts +0 -360
- package/src/eval-runner.test.ts +0 -223
- package/src/eval-runner.ts +0 -402
- package/src/export-tools.test.ts +0 -476
- package/src/export-tools.ts +0 -257
- package/src/hive.integration.test.ts +0 -2241
- package/src/hive.ts +0 -1628
- package/src/index.ts +0 -935
- package/src/learning.integration.test.ts +0 -1815
- package/src/learning.ts +0 -1079
- package/src/logger.test.ts +0 -189
- package/src/logger.ts +0 -135
- package/src/mandate-promotion.test.ts +0 -473
- package/src/mandate-promotion.ts +0 -239
- package/src/mandate-storage.integration.test.ts +0 -601
- package/src/mandate-storage.test.ts +0 -578
- package/src/mandate-storage.ts +0 -794
- package/src/mandates.ts +0 -540
- package/src/memory-tools.test.ts +0 -195
- package/src/memory-tools.ts +0 -344
- package/src/memory.integration.test.ts +0 -334
- package/src/memory.test.ts +0 -158
- package/src/memory.ts +0 -527
- package/src/model-selection.test.ts +0 -188
- package/src/model-selection.ts +0 -68
- package/src/observability-tools.test.ts +0 -359
- package/src/observability-tools.ts +0 -871
- package/src/output-guardrails.test.ts +0 -438
- package/src/output-guardrails.ts +0 -381
- package/src/pattern-maturity.test.ts +0 -1160
- package/src/pattern-maturity.ts +0 -525
- package/src/planning-guardrails.test.ts +0 -491
- package/src/planning-guardrails.ts +0 -438
- package/src/plugin.ts +0 -23
- package/src/post-compaction-tracker.test.ts +0 -251
- package/src/post-compaction-tracker.ts +0 -237
- package/src/query-tools.test.ts +0 -636
- package/src/query-tools.ts +0 -324
- package/src/rate-limiter.integration.test.ts +0 -466
- package/src/rate-limiter.ts +0 -774
- package/src/replay-tools.test.ts +0 -496
- package/src/replay-tools.ts +0 -240
- package/src/repo-crawl.integration.test.ts +0 -441
- package/src/repo-crawl.ts +0 -610
- package/src/schemas/cell-events.test.ts +0 -347
- package/src/schemas/cell-events.ts +0 -807
- package/src/schemas/cell.ts +0 -257
- package/src/schemas/evaluation.ts +0 -166
- package/src/schemas/index.test.ts +0 -199
- package/src/schemas/index.ts +0 -286
- package/src/schemas/mandate.ts +0 -232
- package/src/schemas/swarm-context.ts +0 -115
- package/src/schemas/task.ts +0 -161
- package/src/schemas/worker-handoff.test.ts +0 -302
- package/src/schemas/worker-handoff.ts +0 -131
- package/src/skills.integration.test.ts +0 -1192
- package/src/skills.test.ts +0 -643
- package/src/skills.ts +0 -1549
- package/src/storage.integration.test.ts +0 -341
- package/src/storage.ts +0 -884
- package/src/structured.integration.test.ts +0 -817
- package/src/structured.test.ts +0 -1046
- package/src/structured.ts +0 -762
- package/src/swarm-decompose.test.ts +0 -188
- package/src/swarm-decompose.ts +0 -1302
- package/src/swarm-deferred.integration.test.ts +0 -157
- package/src/swarm-deferred.test.ts +0 -38
- package/src/swarm-insights.test.ts +0 -214
- package/src/swarm-insights.ts +0 -459
- package/src/swarm-mail.integration.test.ts +0 -970
- package/src/swarm-mail.ts +0 -739
- package/src/swarm-orchestrate.integration.test.ts +0 -282
- package/src/swarm-orchestrate.test.ts +0 -548
- package/src/swarm-orchestrate.ts +0 -3084
- package/src/swarm-prompts.test.ts +0 -1270
- package/src/swarm-prompts.ts +0 -2077
- package/src/swarm-research.integration.test.ts +0 -701
- package/src/swarm-research.test.ts +0 -698
- package/src/swarm-research.ts +0 -472
- package/src/swarm-review.integration.test.ts +0 -285
- package/src/swarm-review.test.ts +0 -879
- package/src/swarm-review.ts +0 -709
- package/src/swarm-strategies.ts +0 -407
- package/src/swarm-worktree.test.ts +0 -501
- package/src/swarm-worktree.ts +0 -575
- package/src/swarm.integration.test.ts +0 -2377
- package/src/swarm.ts +0 -38
- package/src/tool-adapter.integration.test.ts +0 -1221
- package/src/tool-availability.ts +0 -461
- package/tsconfig.json +0 -28
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Integration tests for compaction hook observability
|
|
3
|
-
*
|
|
4
|
-
* Tests the full integration of metrics collection with the compaction hook.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { afterEach, beforeEach, describe, expect, it, mock } from "bun:test";
|
|
8
|
-
import { createCompactionHook } from "./compaction-hook";
|
|
9
|
-
|
|
10
|
-
// Track log calls
|
|
11
|
-
let logCalls: Array<{ level: string; data: unknown; message?: string }> = [];
|
|
12
|
-
|
|
13
|
-
const createMockLogger = () => ({
|
|
14
|
-
info: (data: unknown, message?: string) => {
|
|
15
|
-
logCalls.push({ level: "info", data, message });
|
|
16
|
-
},
|
|
17
|
-
debug: (data: unknown, message?: string) => {
|
|
18
|
-
logCalls.push({ level: "debug", data, message });
|
|
19
|
-
},
|
|
20
|
-
warn: (data: unknown, message?: string) => {
|
|
21
|
-
logCalls.push({ level: "warn", data, message });
|
|
22
|
-
},
|
|
23
|
-
error: (data: unknown, message?: string) => {
|
|
24
|
-
logCalls.push({ level: "error", data, message });
|
|
25
|
-
},
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Mock dependencies
|
|
29
|
-
mock.module("./hive", () => ({
|
|
30
|
-
getHiveWorkingDirectory: () => "/test/project",
|
|
31
|
-
getHiveAdapter: async () => ({
|
|
32
|
-
queryCells: async () => [],
|
|
33
|
-
}),
|
|
34
|
-
}));
|
|
35
|
-
|
|
36
|
-
mock.module("swarm-mail", () => ({
|
|
37
|
-
checkSwarmHealth: async () => ({
|
|
38
|
-
healthy: true,
|
|
39
|
-
database: "connected",
|
|
40
|
-
stats: {
|
|
41
|
-
events: 0,
|
|
42
|
-
agents: 0,
|
|
43
|
-
messages: 0,
|
|
44
|
-
reservations: 0,
|
|
45
|
-
},
|
|
46
|
-
}),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
mock.module("./logger", () => ({
|
|
50
|
-
createChildLogger: () => createMockLogger(),
|
|
51
|
-
}));
|
|
52
|
-
|
|
53
|
-
describe("Compaction Hook with Observability", () => {
|
|
54
|
-
beforeEach(() => {
|
|
55
|
-
logCalls = [];
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
afterEach(() => {
|
|
59
|
-
logCalls = [];
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("logs structured metrics on compaction run", async () => {
|
|
63
|
-
const hook = createCompactionHook();
|
|
64
|
-
const input = { sessionID: "test-session-123" };
|
|
65
|
-
const output = { context: [] as string[] };
|
|
66
|
-
|
|
67
|
-
await hook(input, output);
|
|
68
|
-
|
|
69
|
-
// Should have START log
|
|
70
|
-
const startLog = logCalls.find(
|
|
71
|
-
(log) => log.level === "info" && log.message === "compaction started",
|
|
72
|
-
);
|
|
73
|
-
expect(startLog).toBeDefined();
|
|
74
|
-
expect((startLog?.data as { session_id?: string })?.session_id).toBe("test-session-123");
|
|
75
|
-
|
|
76
|
-
// Should have COMPLETE log
|
|
77
|
-
const completeLog = logCalls.find(
|
|
78
|
-
(log) => log.level === "info" && log.message === "compaction complete",
|
|
79
|
-
);
|
|
80
|
-
expect(completeLog).toBeDefined();
|
|
81
|
-
expect((completeLog?.data as { duration_ms?: number })?.duration_ms).toBeGreaterThanOrEqual(0);
|
|
82
|
-
expect((completeLog?.data as { success?: boolean })?.success).toBe(true);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
it("logs timing breakdown for each phase", async () => {
|
|
86
|
-
const hook = createCompactionHook();
|
|
87
|
-
await hook({ sessionID: "test" }, { context: [] });
|
|
88
|
-
|
|
89
|
-
// Should have debug logs for swarm-mail and hive checks
|
|
90
|
-
const swarmMailLog = logCalls.find(
|
|
91
|
-
(log) => log.level === "debug" && (log.data as { source?: string })?.source === "swarm-mail",
|
|
92
|
-
);
|
|
93
|
-
expect(swarmMailLog).toBeDefined();
|
|
94
|
-
expect((swarmMailLog?.data as { duration_ms?: number })?.duration_ms).toBeGreaterThanOrEqual(0);
|
|
95
|
-
|
|
96
|
-
const hiveLog = logCalls.find(
|
|
97
|
-
(log) => log.level === "debug" && (log.data as { source?: string })?.source === "hive",
|
|
98
|
-
);
|
|
99
|
-
expect(hiveLog).toBeDefined();
|
|
100
|
-
expect((hiveLog?.data as { duration_ms?: number })?.duration_ms).toBeGreaterThanOrEqual(0);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
it("logs pattern extraction/skipping decisions", async () => {
|
|
104
|
-
const hook = createCompactionHook();
|
|
105
|
-
await hook({ sessionID: "test" }, { context: [] });
|
|
106
|
-
|
|
107
|
-
// Should have detection complete log
|
|
108
|
-
const detectionLog = logCalls.find(
|
|
109
|
-
(log) => log.level === "debug" && log.message === "swarm detection complete",
|
|
110
|
-
);
|
|
111
|
-
expect(detectionLog).toBeDefined();
|
|
112
|
-
expect((detectionLog?.data as { confidence?: string })?.confidence).toBeDefined();
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it("captures metrics summary in completion log", async () => {
|
|
116
|
-
const hook = createCompactionHook();
|
|
117
|
-
await hook({ sessionID: "test-metrics" }, { context: [] });
|
|
118
|
-
|
|
119
|
-
const completeLog = logCalls.find(
|
|
120
|
-
(log) => log.level === "info" && log.message === "compaction complete",
|
|
121
|
-
);
|
|
122
|
-
expect(completeLog).toBeDefined();
|
|
123
|
-
|
|
124
|
-
const data = completeLog?.data as {
|
|
125
|
-
duration_ms?: number;
|
|
126
|
-
success?: boolean;
|
|
127
|
-
detected?: boolean;
|
|
128
|
-
confidence?: string;
|
|
129
|
-
context_injected?: boolean;
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// Should have complete metrics
|
|
133
|
-
expect(data.duration_ms).toBeGreaterThanOrEqual(0);
|
|
134
|
-
expect(data.success).toBe(true);
|
|
135
|
-
expect(data.detected).toBeDefined();
|
|
136
|
-
expect(data.confidence).toBeDefined();
|
|
137
|
-
expect(data.context_injected).toBeDefined();
|
|
138
|
-
});
|
|
139
|
-
});
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Compaction Observability
|
|
3
|
-
*
|
|
4
|
-
* TDD for adding structured metrics, timing breakdown, and queryable history
|
|
5
|
-
* to the pre-compaction hook.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { describe, expect, it } from "bun:test";
|
|
9
|
-
import {
|
|
10
|
-
CompactionPhase,
|
|
11
|
-
createMetricsCollector,
|
|
12
|
-
getMetricsSummary,
|
|
13
|
-
recordPatternExtracted,
|
|
14
|
-
recordPatternSkipped,
|
|
15
|
-
recordPhaseComplete,
|
|
16
|
-
recordPhaseStart,
|
|
17
|
-
} from "./compaction-observability";
|
|
18
|
-
|
|
19
|
-
describe("CompactionMetrics", () => {
|
|
20
|
-
describe("Phase timing", () => {
|
|
21
|
-
it("tracks timing for each phase", () => {
|
|
22
|
-
const metrics = createMetricsCollector();
|
|
23
|
-
|
|
24
|
-
recordPhaseStart(metrics, CompactionPhase.DETECT);
|
|
25
|
-
// Simulate work
|
|
26
|
-
recordPhaseComplete(metrics, CompactionPhase.DETECT);
|
|
27
|
-
|
|
28
|
-
const summary = getMetricsSummary(metrics);
|
|
29
|
-
|
|
30
|
-
expect(summary.phases.DETECT).toBeDefined();
|
|
31
|
-
expect(summary.phases.DETECT.duration_ms).toBeGreaterThanOrEqual(0);
|
|
32
|
-
expect(summary.phases.DETECT.success).toBe(true);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it("tracks multiple phases independently", () => {
|
|
36
|
-
const metrics = createMetricsCollector();
|
|
37
|
-
|
|
38
|
-
recordPhaseStart(metrics, CompactionPhase.GATHER_SWARM_MAIL);
|
|
39
|
-
recordPhaseComplete(metrics, CompactionPhase.GATHER_SWARM_MAIL);
|
|
40
|
-
|
|
41
|
-
recordPhaseStart(metrics, CompactionPhase.GATHER_HIVE);
|
|
42
|
-
recordPhaseComplete(metrics, CompactionPhase.GATHER_HIVE);
|
|
43
|
-
|
|
44
|
-
const summary = getMetricsSummary(metrics);
|
|
45
|
-
|
|
46
|
-
expect(summary.phases.GATHER_SWARM_MAIL).toBeDefined();
|
|
47
|
-
expect(summary.phases.GATHER_HIVE).toBeDefined();
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
it("tracks phase failures", () => {
|
|
51
|
-
const metrics = createMetricsCollector();
|
|
52
|
-
|
|
53
|
-
recordPhaseStart(metrics, CompactionPhase.INJECT);
|
|
54
|
-
recordPhaseComplete(metrics, CompactionPhase.INJECT, {
|
|
55
|
-
success: false,
|
|
56
|
-
error: "Context injection failed"
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
const summary = getMetricsSummary(metrics);
|
|
60
|
-
|
|
61
|
-
expect(summary.phases.INJECT.success).toBe(false);
|
|
62
|
-
expect(summary.phases.INJECT.error).toBe("Context injection failed");
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe("Pattern extraction tracking", () => {
|
|
67
|
-
it("records extracted patterns with reasons", () => {
|
|
68
|
-
const metrics = createMetricsCollector();
|
|
69
|
-
|
|
70
|
-
recordPatternExtracted(metrics, "epic_state", "Epic bd-123 in_progress");
|
|
71
|
-
recordPatternExtracted(metrics, "agent_name", "BoldWind registered");
|
|
72
|
-
|
|
73
|
-
const summary = getMetricsSummary(metrics);
|
|
74
|
-
|
|
75
|
-
expect(summary.patterns_extracted).toBe(2);
|
|
76
|
-
expect(summary.extracted_patterns).toContain("epic_state");
|
|
77
|
-
expect(summary.extracted_patterns).toContain("agent_name");
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("records skipped patterns with reasons", () => {
|
|
81
|
-
const metrics = createMetricsCollector();
|
|
82
|
-
|
|
83
|
-
recordPatternSkipped(metrics, "subtask_details", "No subtasks found");
|
|
84
|
-
|
|
85
|
-
const summary = getMetricsSummary(metrics);
|
|
86
|
-
|
|
87
|
-
expect(summary.patterns_skipped).toBe(1);
|
|
88
|
-
expect(summary.skipped_patterns).toContain("subtask_details");
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
it("tracks extraction success rate", () => {
|
|
92
|
-
const metrics = createMetricsCollector();
|
|
93
|
-
|
|
94
|
-
recordPatternExtracted(metrics, "epic_state", "Found epic");
|
|
95
|
-
recordPatternExtracted(metrics, "agent_name", "Found agent");
|
|
96
|
-
recordPatternSkipped(metrics, "reservations", "None active");
|
|
97
|
-
|
|
98
|
-
const summary = getMetricsSummary(metrics);
|
|
99
|
-
|
|
100
|
-
expect(summary.patterns_extracted).toBe(2);
|
|
101
|
-
expect(summary.patterns_skipped).toBe(1);
|
|
102
|
-
expect(summary.extraction_success_rate).toBeCloseTo(0.67, 1);
|
|
103
|
-
});
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
describe("Overall metrics", () => {
|
|
107
|
-
it("tracks total duration from start to complete", () => {
|
|
108
|
-
const metrics = createMetricsCollector();
|
|
109
|
-
const startTime = Date.now();
|
|
110
|
-
|
|
111
|
-
recordPhaseStart(metrics, CompactionPhase.START);
|
|
112
|
-
recordPhaseComplete(metrics, CompactionPhase.START);
|
|
113
|
-
|
|
114
|
-
recordPhaseStart(metrics, CompactionPhase.DETECT);
|
|
115
|
-
recordPhaseComplete(metrics, CompactionPhase.DETECT);
|
|
116
|
-
|
|
117
|
-
recordPhaseStart(metrics, CompactionPhase.COMPLETE);
|
|
118
|
-
recordPhaseComplete(metrics, CompactionPhase.COMPLETE);
|
|
119
|
-
|
|
120
|
-
const summary = getMetricsSummary(metrics);
|
|
121
|
-
|
|
122
|
-
expect(summary.total_duration_ms).toBeGreaterThanOrEqual(0);
|
|
123
|
-
expect(summary.total_duration_ms).toBeLessThan(Date.now() - startTime + 10);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("captures session metadata", () => {
|
|
127
|
-
const metrics = createMetricsCollector({
|
|
128
|
-
session_id: "test-session-123",
|
|
129
|
-
has_sdk_client: true,
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
const summary = getMetricsSummary(metrics);
|
|
133
|
-
|
|
134
|
-
expect(summary.session_id).toBe("test-session-123");
|
|
135
|
-
expect(summary.has_sdk_client).toBe(true);
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
it("captures final detection confidence", () => {
|
|
139
|
-
const metrics = createMetricsCollector();
|
|
140
|
-
|
|
141
|
-
recordPhaseComplete(metrics, CompactionPhase.DETECT, {
|
|
142
|
-
confidence: "high",
|
|
143
|
-
detected: true,
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
const summary = getMetricsSummary(metrics);
|
|
147
|
-
|
|
148
|
-
expect(summary.confidence).toBe("high");
|
|
149
|
-
expect(summary.detected).toBe(true);
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe("Debug mode", () => {
|
|
154
|
-
it("records verbose decision details when enabled", () => {
|
|
155
|
-
const metrics = createMetricsCollector({ debug: true });
|
|
156
|
-
|
|
157
|
-
recordPatternExtracted(metrics, "epic_state", "Epic bd-123 in_progress", {
|
|
158
|
-
cell_id: "bd-123",
|
|
159
|
-
cell_status: "in_progress",
|
|
160
|
-
subtask_count: 5,
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
const summary = getMetricsSummary(metrics);
|
|
164
|
-
|
|
165
|
-
// Debug details should be captured
|
|
166
|
-
expect(summary.debug_info).toBeDefined();
|
|
167
|
-
expect(summary.debug_info.length).toBeGreaterThan(0);
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe("Metrics persistence", () => {
|
|
173
|
-
it("can serialize metrics to JSON", () => {
|
|
174
|
-
const metrics = createMetricsCollector({ session_id: "test-123" });
|
|
175
|
-
|
|
176
|
-
recordPhaseStart(metrics, CompactionPhase.DETECT);
|
|
177
|
-
recordPhaseComplete(metrics, CompactionPhase.DETECT);
|
|
178
|
-
recordPatternExtracted(metrics, "epic_state", "Found epic");
|
|
179
|
-
|
|
180
|
-
const summary = getMetricsSummary(metrics);
|
|
181
|
-
const json = JSON.stringify(summary);
|
|
182
|
-
|
|
183
|
-
expect(json).toContain("test-123");
|
|
184
|
-
expect(json).toContain("DETECT");
|
|
185
|
-
expect(json).toContain("epic_state");
|
|
186
|
-
});
|
|
187
|
-
});
|
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compaction Hook Observability
|
|
3
|
-
*
|
|
4
|
-
* Structured logging, metrics, and queryable history for the pre-compaction hook.
|
|
5
|
-
*
|
|
6
|
-
* **Philosophy:** Make the invisible visible. When patterns aren't extracted,
|
|
7
|
-
* when detection fails, when timing explodes - we need to know WHY.
|
|
8
|
-
*
|
|
9
|
-
* @example
|
|
10
|
-
* ```typescript
|
|
11
|
-
* const metrics = createMetricsCollector({ session_id: "abc123" });
|
|
12
|
-
*
|
|
13
|
-
* recordPhaseStart(metrics, CompactionPhase.DETECT);
|
|
14
|
-
* // ... detection logic ...
|
|
15
|
-
* recordPhaseComplete(metrics, CompactionPhase.DETECT, { confidence: "high" });
|
|
16
|
-
*
|
|
17
|
-
* recordPatternExtracted(metrics, "epic_state", "Found epic bd-123");
|
|
18
|
-
*
|
|
19
|
-
* const summary = getMetricsSummary(metrics);
|
|
20
|
-
* console.log(`Detected: ${summary.detected}, Confidence: ${summary.confidence}`);
|
|
21
|
-
* ```
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Compaction phases - aligned with existing log structure
|
|
26
|
-
*
|
|
27
|
-
* From compaction-hook.ts:
|
|
28
|
-
* - START: session_id, trigger
|
|
29
|
-
* - GATHER: source (swarm-mail|hive), duration_ms, stats/counts
|
|
30
|
-
* - DETECT: confidence, detected, reason_count, reasons
|
|
31
|
-
* - INJECT: confidence, context_length, context_type (full|fallback|none)
|
|
32
|
-
* - COMPLETE: duration_ms, success, detected, confidence, context_injected
|
|
33
|
-
*/
|
|
34
|
-
export enum CompactionPhase {
|
|
35
|
-
START = "START",
|
|
36
|
-
GATHER_SWARM_MAIL = "GATHER_SWARM_MAIL",
|
|
37
|
-
GATHER_HIVE = "GATHER_HIVE",
|
|
38
|
-
DETECT = "DETECT",
|
|
39
|
-
INJECT = "INJECT",
|
|
40
|
-
COMPLETE = "COMPLETE",
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Phase timing and outcome
|
|
45
|
-
*/
|
|
46
|
-
interface PhaseMetrics {
|
|
47
|
-
duration_ms: number;
|
|
48
|
-
success: boolean;
|
|
49
|
-
error?: string;
|
|
50
|
-
/** Additional phase-specific data */
|
|
51
|
-
metadata?: Record<string, unknown>;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Pattern extraction record
|
|
56
|
-
*/
|
|
57
|
-
interface PatternRecord {
|
|
58
|
-
pattern_type: string;
|
|
59
|
-
reason: string;
|
|
60
|
-
/** Debug details (only captured if debug mode enabled) */
|
|
61
|
-
details?: Record<string, unknown>;
|
|
62
|
-
timestamp: number;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Compaction metrics collector
|
|
67
|
-
*
|
|
68
|
-
* Mutable state object that accumulates metrics during a compaction run.
|
|
69
|
-
*/
|
|
70
|
-
export interface CompactionMetrics {
|
|
71
|
-
/** Session metadata */
|
|
72
|
-
session_id?: string;
|
|
73
|
-
has_sdk_client?: boolean;
|
|
74
|
-
debug?: boolean;
|
|
75
|
-
|
|
76
|
-
/** Phase timings */
|
|
77
|
-
phases: Map<CompactionPhase, {
|
|
78
|
-
start_time: number;
|
|
79
|
-
end_time?: number;
|
|
80
|
-
metadata?: Record<string, unknown>;
|
|
81
|
-
error?: string;
|
|
82
|
-
}>;
|
|
83
|
-
|
|
84
|
-
/** Pattern extraction tracking */
|
|
85
|
-
extracted: PatternRecord[];
|
|
86
|
-
skipped: PatternRecord[];
|
|
87
|
-
|
|
88
|
-
/** Final detection result */
|
|
89
|
-
confidence?: "high" | "medium" | "low" | "none";
|
|
90
|
-
detected?: boolean;
|
|
91
|
-
|
|
92
|
-
/** Overall timing */
|
|
93
|
-
start_time: number;
|
|
94
|
-
end_time?: number;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Metrics summary (read-only snapshot)
|
|
99
|
-
*/
|
|
100
|
-
export interface CompactionMetricsSummary {
|
|
101
|
-
session_id?: string;
|
|
102
|
-
has_sdk_client?: boolean;
|
|
103
|
-
|
|
104
|
-
/** Phase breakdown */
|
|
105
|
-
phases: Record<string, PhaseMetrics>;
|
|
106
|
-
|
|
107
|
-
/** Pattern extraction stats */
|
|
108
|
-
patterns_extracted: number;
|
|
109
|
-
patterns_skipped: number;
|
|
110
|
-
extraction_success_rate: number;
|
|
111
|
-
extracted_patterns: string[];
|
|
112
|
-
skipped_patterns: string[];
|
|
113
|
-
|
|
114
|
-
/** Detection outcome */
|
|
115
|
-
confidence?: "high" | "medium" | "low" | "none";
|
|
116
|
-
detected?: boolean;
|
|
117
|
-
|
|
118
|
-
/** Timing */
|
|
119
|
-
total_duration_ms: number;
|
|
120
|
-
|
|
121
|
-
/** Debug info (only if debug mode enabled) */
|
|
122
|
-
debug_info?: Array<{
|
|
123
|
-
phase: string;
|
|
124
|
-
pattern: string;
|
|
125
|
-
details: Record<string, unknown>;
|
|
126
|
-
}>;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Create a metrics collector
|
|
131
|
-
*
|
|
132
|
-
* @param metadata - Session metadata to capture
|
|
133
|
-
* @returns Mutable metrics collector
|
|
134
|
-
*/
|
|
135
|
-
export function createMetricsCollector(metadata?: {
|
|
136
|
-
session_id?: string;
|
|
137
|
-
has_sdk_client?: boolean;
|
|
138
|
-
debug?: boolean;
|
|
139
|
-
}): CompactionMetrics {
|
|
140
|
-
return {
|
|
141
|
-
session_id: metadata?.session_id,
|
|
142
|
-
has_sdk_client: metadata?.has_sdk_client,
|
|
143
|
-
debug: metadata?.debug,
|
|
144
|
-
phases: new Map(),
|
|
145
|
-
extracted: [],
|
|
146
|
-
skipped: [],
|
|
147
|
-
start_time: Date.now(),
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Record phase start
|
|
153
|
-
*
|
|
154
|
-
* @param metrics - Metrics collector
|
|
155
|
-
* @param phase - Phase being started
|
|
156
|
-
*/
|
|
157
|
-
export function recordPhaseStart(
|
|
158
|
-
metrics: CompactionMetrics,
|
|
159
|
-
phase: CompactionPhase,
|
|
160
|
-
): void {
|
|
161
|
-
metrics.phases.set(phase, {
|
|
162
|
-
start_time: Date.now(),
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Record phase completion
|
|
168
|
-
*
|
|
169
|
-
* @param metrics - Metrics collector
|
|
170
|
-
* @param phase - Phase being completed
|
|
171
|
-
* @param result - Phase outcome
|
|
172
|
-
*/
|
|
173
|
-
export function recordPhaseComplete(
|
|
174
|
-
metrics: CompactionMetrics,
|
|
175
|
-
phase: CompactionPhase,
|
|
176
|
-
result?: {
|
|
177
|
-
success?: boolean;
|
|
178
|
-
error?: string;
|
|
179
|
-
confidence?: "high" | "medium" | "low" | "none";
|
|
180
|
-
detected?: boolean;
|
|
181
|
-
[key: string]: unknown;
|
|
182
|
-
},
|
|
183
|
-
): void {
|
|
184
|
-
let phaseData = metrics.phases.get(phase);
|
|
185
|
-
if (!phaseData) {
|
|
186
|
-
// Phase wasn't started, record it now
|
|
187
|
-
phaseData = {
|
|
188
|
-
start_time: Date.now(),
|
|
189
|
-
end_time: Date.now(),
|
|
190
|
-
error: "Phase completed without start",
|
|
191
|
-
};
|
|
192
|
-
metrics.phases.set(phase, phaseData);
|
|
193
|
-
} else {
|
|
194
|
-
phaseData.end_time = Date.now();
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (result) {
|
|
198
|
-
if (result.error) {
|
|
199
|
-
phaseData.error = result.error;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
// Extract known fields
|
|
203
|
-
// biome-ignore lint/correctness/noUnusedVariables: extracting for spread
|
|
204
|
-
const { success, error, confidence, detected, ...rest } = result;
|
|
205
|
-
|
|
206
|
-
if (Object.keys(rest).length > 0) {
|
|
207
|
-
phaseData.metadata = rest;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
// Update top-level detection result if provided in result
|
|
211
|
-
if (confidence) {
|
|
212
|
-
metrics.confidence = confidence;
|
|
213
|
-
}
|
|
214
|
-
if (detected !== undefined) {
|
|
215
|
-
metrics.detected = detected;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* Record an extracted pattern
|
|
222
|
-
*
|
|
223
|
-
* @param metrics - Metrics collector
|
|
224
|
-
* @param pattern_type - Type of pattern extracted (e.g., "epic_state", "agent_name")
|
|
225
|
-
* @param reason - Human-readable reason for extraction
|
|
226
|
-
* @param details - Debug details (only captured if debug mode enabled)
|
|
227
|
-
*/
|
|
228
|
-
export function recordPatternExtracted(
|
|
229
|
-
metrics: CompactionMetrics,
|
|
230
|
-
pattern_type: string,
|
|
231
|
-
reason: string,
|
|
232
|
-
details?: Record<string, unknown>,
|
|
233
|
-
): void {
|
|
234
|
-
const record: PatternRecord = {
|
|
235
|
-
pattern_type,
|
|
236
|
-
reason,
|
|
237
|
-
timestamp: Date.now(),
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
if (metrics.debug && details) {
|
|
241
|
-
record.details = details;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
metrics.extracted.push(record);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Record a skipped pattern
|
|
249
|
-
*
|
|
250
|
-
* @param metrics - Metrics collector
|
|
251
|
-
* @param pattern_type - Type of pattern that was skipped
|
|
252
|
-
* @param reason - Human-readable reason for skipping
|
|
253
|
-
*/
|
|
254
|
-
export function recordPatternSkipped(
|
|
255
|
-
metrics: CompactionMetrics,
|
|
256
|
-
pattern_type: string,
|
|
257
|
-
reason: string,
|
|
258
|
-
): void {
|
|
259
|
-
metrics.skipped.push({
|
|
260
|
-
pattern_type,
|
|
261
|
-
reason,
|
|
262
|
-
timestamp: Date.now(),
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Get metrics summary (read-only snapshot)
|
|
268
|
-
*
|
|
269
|
-
* Computes derived metrics like success rates and total duration.
|
|
270
|
-
*
|
|
271
|
-
* @param metrics - Metrics collector
|
|
272
|
-
* @returns Immutable summary
|
|
273
|
-
*/
|
|
274
|
-
export function getMetricsSummary(metrics: CompactionMetrics): CompactionMetricsSummary {
|
|
275
|
-
// Compute phase breakdown
|
|
276
|
-
const phases: Record<string, PhaseMetrics> = {};
|
|
277
|
-
for (const [phase, data] of metrics.phases) {
|
|
278
|
-
const duration = data.end_time ? data.end_time - data.start_time : 0;
|
|
279
|
-
phases[phase] = {
|
|
280
|
-
duration_ms: duration,
|
|
281
|
-
success: !data.error,
|
|
282
|
-
error: data.error,
|
|
283
|
-
metadata: data.metadata,
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Compute extraction stats
|
|
288
|
-
const totalPatterns = metrics.extracted.length + metrics.skipped.length;
|
|
289
|
-
const extractionSuccessRate = totalPatterns > 0
|
|
290
|
-
? metrics.extracted.length / totalPatterns
|
|
291
|
-
: 0;
|
|
292
|
-
|
|
293
|
-
// Compute total duration
|
|
294
|
-
const totalDuration = metrics.end_time
|
|
295
|
-
? metrics.end_time - metrics.start_time
|
|
296
|
-
: Date.now() - metrics.start_time;
|
|
297
|
-
|
|
298
|
-
const summary: CompactionMetricsSummary = {
|
|
299
|
-
session_id: metrics.session_id,
|
|
300
|
-
has_sdk_client: metrics.has_sdk_client,
|
|
301
|
-
phases,
|
|
302
|
-
patterns_extracted: metrics.extracted.length,
|
|
303
|
-
patterns_skipped: metrics.skipped.length,
|
|
304
|
-
extraction_success_rate: extractionSuccessRate,
|
|
305
|
-
extracted_patterns: metrics.extracted.map(p => p.pattern_type),
|
|
306
|
-
skipped_patterns: metrics.skipped.map(p => p.pattern_type),
|
|
307
|
-
confidence: metrics.confidence,
|
|
308
|
-
detected: metrics.detected,
|
|
309
|
-
total_duration_ms: totalDuration,
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
// Add debug info if enabled
|
|
313
|
-
if (metrics.debug) {
|
|
314
|
-
summary.debug_info = metrics.extracted
|
|
315
|
-
.filter(p => p.details !== undefined)
|
|
316
|
-
.map(p => ({
|
|
317
|
-
phase: "EXTRACT",
|
|
318
|
-
pattern: p.pattern_type,
|
|
319
|
-
details: p.details as Record<string, unknown>,
|
|
320
|
-
}));
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
return summary;
|
|
324
|
-
}
|