opencode-swarm-plugin 0.56.0 → 0.57.0
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/README.md +21 -0
- package/claude-plugin/.claude-plugin/plugin.json +1 -4
- package/claude-plugin/agents/background-worker.md +1 -0
- package/claude-plugin/agents/coordinator.md +1 -0
- package/claude-plugin/agents/worker.md +1 -0
- package/claude-plugin/bin/swarm-mcp-server.ts +47 -8
- package/claude-plugin/commands/hive.md +1 -1
- package/claude-plugin/commands/swarm.md +5 -1
- package/claude-plugin/dist/agent-mail.d.ts +480 -0
- package/claude-plugin/dist/agent-mail.d.ts.map +1 -0
- package/claude-plugin/dist/anti-patterns.d.ts +257 -0
- package/claude-plugin/dist/anti-patterns.d.ts.map +1 -0
- package/claude-plugin/dist/bin/swarm.js +373128 -0
- package/claude-plugin/dist/cass-tools.d.ts +74 -0
- package/claude-plugin/dist/cass-tools.d.ts.map +1 -0
- package/claude-plugin/dist/claude-plugin/claude-plugin-assets.d.ts +10 -0
- package/claude-plugin/dist/claude-plugin/claude-plugin-assets.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-hook.d.ts +178 -0
- package/claude-plugin/dist/compaction-hook.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-observability.d.ts +173 -0
- package/claude-plugin/dist/compaction-observability.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-prompt-scoring.d.ts +125 -0
- package/claude-plugin/dist/compaction-prompt-scoring.d.ts.map +1 -0
- package/claude-plugin/dist/compaction-prompt-scoring.js +139 -0
- package/claude-plugin/dist/contributor-tools.d.ts +42 -0
- package/claude-plugin/dist/contributor-tools.d.ts.map +1 -0
- package/claude-plugin/dist/coordinator-guard.d.ts +79 -0
- package/claude-plugin/dist/coordinator-guard.d.ts.map +1 -0
- package/claude-plugin/dist/dashboard.d.ts +82 -0
- package/claude-plugin/dist/dashboard.d.ts.map +1 -0
- package/claude-plugin/dist/decision-trace-integration.d.ts +204 -0
- package/claude-plugin/dist/decision-trace-integration.d.ts.map +1 -0
- package/claude-plugin/dist/error-enrichment.d.ts +49 -0
- package/claude-plugin/dist/error-enrichment.d.ts.map +1 -0
- package/claude-plugin/dist/eval-capture.d.ts +494 -0
- package/claude-plugin/dist/eval-capture.d.ts.map +1 -0
- package/claude-plugin/dist/eval-capture.js +12844 -0
- package/claude-plugin/dist/eval-gates.d.ts +84 -0
- package/claude-plugin/dist/eval-gates.d.ts.map +1 -0
- package/claude-plugin/dist/eval-history.d.ts +117 -0
- package/claude-plugin/dist/eval-history.d.ts.map +1 -0
- package/claude-plugin/dist/eval-learning.d.ts +216 -0
- package/claude-plugin/dist/eval-learning.d.ts.map +1 -0
- package/claude-plugin/dist/eval-runner.d.ts +134 -0
- package/claude-plugin/dist/eval-runner.d.ts.map +1 -0
- package/claude-plugin/dist/examples/plugin-wrapper-template.ts +3341 -0
- package/claude-plugin/dist/export-tools.d.ts +76 -0
- package/claude-plugin/dist/export-tools.d.ts.map +1 -0
- package/claude-plugin/dist/hive.d.ts +949 -0
- package/claude-plugin/dist/hive.d.ts.map +1 -0
- package/claude-plugin/dist/hive.js +15009 -0
- package/claude-plugin/dist/hivemind-tools.d.ts +479 -0
- package/claude-plugin/dist/hivemind-tools.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/atomic-write.d.ts +21 -0
- package/claude-plugin/dist/hooks/atomic-write.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/constants.d.ts +28 -0
- package/claude-plugin/dist/hooks/constants.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/index.d.ts +16 -0
- package/claude-plugin/dist/hooks/index.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/session-start.d.ts +30 -0
- package/claude-plugin/dist/hooks/session-start.d.ts.map +1 -0
- package/claude-plugin/dist/hooks/tool-complete.d.ts +54 -0
- package/claude-plugin/dist/hooks/tool-complete.d.ts.map +1 -0
- package/claude-plugin/dist/index.d.ts +2017 -0
- package/claude-plugin/dist/index.d.ts.map +1 -0
- package/claude-plugin/dist/index.js +73453 -0
- package/claude-plugin/dist/learning.d.ts +700 -0
- package/claude-plugin/dist/learning.d.ts.map +1 -0
- package/claude-plugin/dist/logger.d.ts +38 -0
- package/claude-plugin/dist/logger.d.ts.map +1 -0
- package/claude-plugin/dist/mandate-promotion.d.ts +93 -0
- package/claude-plugin/dist/mandate-promotion.d.ts.map +1 -0
- package/claude-plugin/dist/mandate-storage.d.ts +209 -0
- package/claude-plugin/dist/mandate-storage.d.ts.map +1 -0
- package/claude-plugin/dist/mandates.d.ts +230 -0
- package/claude-plugin/dist/mandates.d.ts.map +1 -0
- package/claude-plugin/dist/memory-tools.d.ts +281 -0
- package/claude-plugin/dist/memory-tools.d.ts.map +1 -0
- package/claude-plugin/dist/memory.d.ts +164 -0
- package/claude-plugin/dist/memory.d.ts.map +1 -0
- package/claude-plugin/dist/model-selection.d.ts +37 -0
- package/claude-plugin/dist/model-selection.d.ts.map +1 -0
- package/claude-plugin/dist/observability-health.d.ts +87 -0
- package/claude-plugin/dist/observability-health.d.ts.map +1 -0
- package/claude-plugin/dist/observability-tools.d.ts +184 -0
- package/claude-plugin/dist/observability-tools.d.ts.map +1 -0
- package/claude-plugin/dist/output-guardrails.d.ts +125 -0
- package/claude-plugin/dist/output-guardrails.d.ts.map +1 -0
- package/claude-plugin/dist/pattern-maturity.d.ts +246 -0
- package/claude-plugin/dist/pattern-maturity.d.ts.map +1 -0
- package/claude-plugin/dist/planning-guardrails.d.ts +183 -0
- package/claude-plugin/dist/planning-guardrails.d.ts.map +1 -0
- package/claude-plugin/dist/plugin.d.ts +22 -0
- package/claude-plugin/dist/plugin.d.ts.map +1 -0
- package/claude-plugin/dist/plugin.js +72295 -0
- package/claude-plugin/dist/post-compaction-tracker.d.ts +133 -0
- package/claude-plugin/dist/post-compaction-tracker.d.ts.map +1 -0
- package/claude-plugin/dist/query-tools.d.ts +90 -0
- package/claude-plugin/dist/query-tools.d.ts.map +1 -0
- package/claude-plugin/dist/rate-limiter.d.ts +218 -0
- package/claude-plugin/dist/rate-limiter.d.ts.map +1 -0
- package/claude-plugin/dist/regression-detection.d.ts +58 -0
- package/claude-plugin/dist/regression-detection.d.ts.map +1 -0
- package/claude-plugin/dist/replay-tools.d.ts +28 -0
- package/claude-plugin/dist/replay-tools.d.ts.map +1 -0
- package/claude-plugin/dist/repo-crawl.d.ts +146 -0
- package/claude-plugin/dist/repo-crawl.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/cell-events.d.ts +1352 -0
- package/claude-plugin/dist/schemas/cell-events.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/cell.d.ts +413 -0
- package/claude-plugin/dist/schemas/cell.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/evaluation.d.ts +161 -0
- package/claude-plugin/dist/schemas/evaluation.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/index.d.ts +46 -0
- package/claude-plugin/dist/schemas/index.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/mandate.d.ts +336 -0
- package/claude-plugin/dist/schemas/mandate.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/swarm-context.d.ts +131 -0
- package/claude-plugin/dist/schemas/swarm-context.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/task.d.ts +189 -0
- package/claude-plugin/dist/schemas/task.d.ts.map +1 -0
- package/claude-plugin/dist/schemas/worker-handoff.d.ts +78 -0
- package/claude-plugin/dist/schemas/worker-handoff.d.ts.map +1 -0
- package/claude-plugin/dist/sessions/agent-discovery.d.ts +59 -0
- package/claude-plugin/dist/sessions/agent-discovery.d.ts.map +1 -0
- package/claude-plugin/dist/sessions/index.d.ts +10 -0
- package/claude-plugin/dist/sessions/index.d.ts.map +1 -0
- package/claude-plugin/dist/skills.d.ts +490 -0
- package/claude-plugin/dist/skills.d.ts.map +1 -0
- package/claude-plugin/dist/storage.d.ts +260 -0
- package/claude-plugin/dist/storage.d.ts.map +1 -0
- package/claude-plugin/dist/structured.d.ts +206 -0
- package/claude-plugin/dist/structured.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-adversarial-review.d.ts +104 -0
- package/claude-plugin/dist/swarm-adversarial-review.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-decompose.d.ts +297 -0
- package/claude-plugin/dist/swarm-decompose.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-insights.d.ts +390 -0
- package/claude-plugin/dist/swarm-insights.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-mail.d.ts +274 -0
- package/claude-plugin/dist/swarm-mail.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-orchestrate.d.ts +924 -0
- package/claude-plugin/dist/swarm-orchestrate.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-prompts.d.ts +467 -0
- package/claude-plugin/dist/swarm-prompts.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-prompts.js +45283 -0
- package/claude-plugin/dist/swarm-research.d.ts +125 -0
- package/claude-plugin/dist/swarm-research.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-review.d.ts +214 -0
- package/claude-plugin/dist/swarm-review.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-signature.d.ts +106 -0
- package/claude-plugin/dist/swarm-signature.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-strategies.d.ts +113 -0
- package/claude-plugin/dist/swarm-strategies.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-validation.d.ts +127 -0
- package/claude-plugin/dist/swarm-validation.d.ts.map +1 -0
- package/claude-plugin/dist/swarm-worktree.d.ts +185 -0
- package/claude-plugin/dist/swarm-worktree.d.ts.map +1 -0
- package/claude-plugin/dist/swarm.d.ts +590 -0
- package/claude-plugin/dist/swarm.d.ts.map +1 -0
- package/claude-plugin/dist/tool-availability.d.ts +91 -0
- package/claude-plugin/dist/tool-availability.d.ts.map +1 -0
- package/claude-plugin/dist/utils/tree-renderer.d.ts +61 -0
- package/claude-plugin/dist/utils/tree-renderer.d.ts.map +1 -0
- package/claude-plugin/dist/validators/index.d.ts +7 -0
- package/claude-plugin/dist/validators/index.d.ts.map +1 -0
- package/claude-plugin/dist/validators/schema-validator.d.ts +58 -0
- package/claude-plugin/dist/validators/schema-validator.d.ts.map +1 -0
- package/claude-plugin/skills/always-on-guidance/SKILL.md +44 -0
- package/dist/agent-mail.d.ts +4 -4
- package/dist/agent-mail.d.ts.map +1 -1
- package/dist/bin/swarm.js +477 -22
- package/dist/claude-plugin/claude-plugin-assets.d.ts +10 -0
- package/dist/claude-plugin/claude-plugin-assets.d.ts.map +1 -0
- package/dist/compaction-hook.d.ts +1 -1
- package/dist/compaction-hook.d.ts.map +1 -1
- package/dist/index.js +375 -265
- package/dist/plugin.js +374 -264
- package/dist/skills.d.ts +15 -0
- package/dist/skills.d.ts.map +1 -1
- package/dist/swarm-mail.d.ts.map +1 -1
- package/dist/swarm-prompts.d.ts +4 -2
- package/dist/swarm-prompts.d.ts.map +1 -1
- package/dist/swarm-prompts.js +84 -7
- package/global-skills/swarm-coordination/SKILL.md +21 -20
- package/package.json +2 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-Compaction Tool Call Tracker
|
|
3
|
+
*
|
|
4
|
+
* Tracks tool calls after compaction resumption to detect coordinator violations
|
|
5
|
+
* and provide learning signals for eval-driven development.
|
|
6
|
+
*
|
|
7
|
+
* ## Purpose
|
|
8
|
+
*
|
|
9
|
+
* When context is compacted, the continuation agent needs observation to learn
|
|
10
|
+
* if it's following coordinator discipline. This tracker:
|
|
11
|
+
*
|
|
12
|
+
* 1. Emits resumption_started on first tool call (marks compaction exit)
|
|
13
|
+
* 2. Tracks up to N tool calls (default 20) with violation detection
|
|
14
|
+
* 3. Stops tracking after limit to avoid noise in long sessions
|
|
15
|
+
*
|
|
16
|
+
* ## Coordinator Violations Detected
|
|
17
|
+
*
|
|
18
|
+
* - **Edit/Write**: Coordinators NEVER edit files - spawn worker instead
|
|
19
|
+
* - **swarmmail_reserve/agentmail_reserve**: Workers reserve, not coordinators
|
|
20
|
+
*
|
|
21
|
+
* ## Integration
|
|
22
|
+
*
|
|
23
|
+
* Used by compaction hook to wire tool.call events → eval capture.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const tracker = createPostCompactionTracker({
|
|
28
|
+
* sessionId: "session-123",
|
|
29
|
+
* epicId: "bd-epic-456",
|
|
30
|
+
* onEvent: captureCompactionEvent,
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* // Wire to OpenCode hook
|
|
34
|
+
* hooks["tool.call"] = (input) => {
|
|
35
|
+
* tracker.trackToolCall({
|
|
36
|
+
* tool: input.tool,
|
|
37
|
+
* args: input.args,
|
|
38
|
+
* timestamp: Date.now(),
|
|
39
|
+
* });
|
|
40
|
+
* };
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Tool call event structure
|
|
45
|
+
*/
|
|
46
|
+
export interface ToolCallEvent {
|
|
47
|
+
tool: string;
|
|
48
|
+
args: Record<string, unknown>;
|
|
49
|
+
timestamp: number;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Compaction event payload (matches eval-capture.ts structure)
|
|
53
|
+
*/
|
|
54
|
+
export interface CompactionEvent {
|
|
55
|
+
session_id: string;
|
|
56
|
+
epic_id: string;
|
|
57
|
+
compaction_type: "detection_complete" | "prompt_generated" | "context_injected" | "resumption_started" | "tool_call_tracked";
|
|
58
|
+
payload: {
|
|
59
|
+
session_id?: string;
|
|
60
|
+
epic_id?: string;
|
|
61
|
+
tool?: string;
|
|
62
|
+
args?: Record<string, unknown>;
|
|
63
|
+
call_number?: number;
|
|
64
|
+
is_coordinator_violation?: boolean;
|
|
65
|
+
violation_reason?: string;
|
|
66
|
+
timestamp?: number;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Tracker configuration
|
|
71
|
+
*/
|
|
72
|
+
export interface PostCompactionTrackerConfig {
|
|
73
|
+
sessionId: string;
|
|
74
|
+
epicId: string;
|
|
75
|
+
onEvent: (event: CompactionEvent) => void;
|
|
76
|
+
maxCalls?: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Post-compaction tracker instance
|
|
80
|
+
*/
|
|
81
|
+
export interface PostCompactionTracker {
|
|
82
|
+
trackToolCall(event: ToolCallEvent): void;
|
|
83
|
+
isTracking(): boolean;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Default maximum number of tool calls to track
|
|
87
|
+
*
|
|
88
|
+
* Chosen to balance:
|
|
89
|
+
* - Enough data for pattern detection (20 calls is ~2-3 minutes of coordinator work)
|
|
90
|
+
* - Avoiding noise pollution in long sessions
|
|
91
|
+
*/
|
|
92
|
+
export declare const DEFAULT_MAX_TRACKED_CALLS = 20;
|
|
93
|
+
/**
|
|
94
|
+
* Check if tool call is a coordinator violation
|
|
95
|
+
*
|
|
96
|
+
* @param tool - Tool name from OpenCode tool.call hook
|
|
97
|
+
* @returns Violation status with reason if forbidden
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* const result = isCoordinatorViolation("edit");
|
|
102
|
+
* // { isViolation: true, reason: "Coordinators NEVER edit..." }
|
|
103
|
+
*
|
|
104
|
+
* const result = isCoordinatorViolation("read");
|
|
105
|
+
* // { isViolation: false }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export declare function isCoordinatorViolation(tool: string): {
|
|
109
|
+
isViolation: boolean;
|
|
110
|
+
reason?: string;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* Create a post-compaction tool call tracker
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```typescript
|
|
117
|
+
* const tracker = createPostCompactionTracker({
|
|
118
|
+
* sessionId: "session-123",
|
|
119
|
+
* epicId: "bd-epic-456",
|
|
120
|
+
* onEvent: (event) => captureCompactionEvent(event),
|
|
121
|
+
* maxCalls: 20
|
|
122
|
+
* });
|
|
123
|
+
*
|
|
124
|
+
* // Track tool calls
|
|
125
|
+
* tracker.trackToolCall({
|
|
126
|
+
* tool: "read",
|
|
127
|
+
* args: { filePath: "/test.ts" },
|
|
128
|
+
* timestamp: Date.now()
|
|
129
|
+
* });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
export declare function createPostCompactionTracker(config: PostCompactionTrackerConfig): PostCompactionTracker;
|
|
133
|
+
//# sourceMappingURL=post-compaction-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-compaction-tracker.d.ts","sourceRoot":"","sources":["../src/post-compaction-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,EACX,oBAAoB,GACpB,kBAAkB,GAClB,kBAAkB,GAClB,oBAAoB,GACpB,mBAAmB,CAAC;IACxB,OAAO,EAAE;QACP,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC1C,UAAU,IAAI,OAAO,CAAC;CACvB;AAMD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAoB5C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG;IACpD,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAMA;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,2BAA2B,GAClC,qBAAqB,CA2DvB"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GREEN PHASE: SQL Query Tools Implementation
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - 13 preset queries for observability insights (10 base + 3 decision trace)
|
|
6
|
+
* - Custom SQL execution with timing
|
|
7
|
+
* - 3 output formats: Table (box-drawing), CSV, JSON
|
|
8
|
+
*/
|
|
9
|
+
import type { DatabaseAdapter } from "swarm-mail";
|
|
10
|
+
export type PresetQueryName = "failed_decompositions" | "duration_by_strategy" | "file_conflicts" | "worker_success_rate" | "review_rejections" | "blocked_tasks" | "agent_activity" | "event_frequency" | "error_patterns" | "compaction_stats" | "decision_quality" | "strategy_success_rates" | "decisions_by_pattern";
|
|
11
|
+
export interface QueryResult {
|
|
12
|
+
columns: string[];
|
|
13
|
+
rows: Record<string, unknown>[];
|
|
14
|
+
rowCount: number;
|
|
15
|
+
executionTimeMs: number;
|
|
16
|
+
}
|
|
17
|
+
export declare const presetQueries: Record<PresetQueryName, string>;
|
|
18
|
+
/**
|
|
19
|
+
* Get database path from project path.
|
|
20
|
+
* Uses global database (~/.config/swarm-tools/swarm.db)
|
|
21
|
+
*/
|
|
22
|
+
export declare function getDbPath(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Execute custom SQL against the events table (low-level).
|
|
25
|
+
*
|
|
26
|
+
* @param db - DatabaseAdapter instance
|
|
27
|
+
* @param sql - SQL query string
|
|
28
|
+
* @param params - Optional parameterized query values
|
|
29
|
+
* @returns QueryResult with rows, columns, timing
|
|
30
|
+
*/
|
|
31
|
+
export declare function executeQuery(db: DatabaseAdapter, sql: string, params?: unknown[]): Promise<QueryResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Execute a preset query by name (low-level, requires DatabaseAdapter).
|
|
34
|
+
*
|
|
35
|
+
* @param db - DatabaseAdapter instance
|
|
36
|
+
* @param presetName - Name of the preset query
|
|
37
|
+
* @returns QueryResult with rows, columns, timing
|
|
38
|
+
*/
|
|
39
|
+
export declare function executePresetQuery(db: DatabaseAdapter, presetName: string): Promise<QueryResult>;
|
|
40
|
+
/**
|
|
41
|
+
* Execute custom SQL query (CLI wrapper).
|
|
42
|
+
* Creates database adapter automatically.
|
|
43
|
+
*
|
|
44
|
+
* @param projectPath - Project path (unused, queries global database)
|
|
45
|
+
* @param sql - SQL query string
|
|
46
|
+
* @returns Raw rows array for CLI formatting
|
|
47
|
+
*/
|
|
48
|
+
export declare function executeQueryCLI(projectPath: string, sql: string): Promise<any[]>;
|
|
49
|
+
/**
|
|
50
|
+
* Execute a preset query by name (CLI wrapper).
|
|
51
|
+
* Creates database adapter automatically.
|
|
52
|
+
*
|
|
53
|
+
* @param projectPath - Project path (unused, queries global database)
|
|
54
|
+
* @param presetName - Name of the preset query
|
|
55
|
+
* @returns Raw rows array for CLI formatting
|
|
56
|
+
*/
|
|
57
|
+
export declare function executePreset(projectPath: string, presetName: string): Promise<any[]>;
|
|
58
|
+
/**
|
|
59
|
+
* Format query result as aligned table with box-drawing characters.
|
|
60
|
+
*
|
|
61
|
+
* Example output:
|
|
62
|
+
* ┌──────────┬───────┐
|
|
63
|
+
* │ name │ count │
|
|
64
|
+
* ├──────────┼───────┤
|
|
65
|
+
* │ AgentA │ 5 │
|
|
66
|
+
* │ AgentB │ 3 │
|
|
67
|
+
* └──────────┴───────┘
|
|
68
|
+
* 2 rows (12.5ms)
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatAsTable(result: QueryResult): string;
|
|
71
|
+
/**
|
|
72
|
+
* Format query result as CSV with proper escaping.
|
|
73
|
+
*
|
|
74
|
+
* Escapes:
|
|
75
|
+
* - Commas → wrap in quotes
|
|
76
|
+
* - Quotes → double them
|
|
77
|
+
* - Newlines → wrap in quotes
|
|
78
|
+
*/
|
|
79
|
+
export declare function formatAsCSV(result: QueryResult): string;
|
|
80
|
+
/**
|
|
81
|
+
* Format query result as pretty-printed JSON array.
|
|
82
|
+
*
|
|
83
|
+
* Example:
|
|
84
|
+
* [
|
|
85
|
+
* { "name": "AgentA", "count": 5 },
|
|
86
|
+
* { "name": "AgentB", "count": 3 }
|
|
87
|
+
* ]
|
|
88
|
+
*/
|
|
89
|
+
export declare function formatAsJSON(result: QueryResult): string;
|
|
90
|
+
//# sourceMappingURL=query-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-tools.d.ts","sourceRoot":"","sources":["../src/query-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,MAAM,MAAM,eAAe,GACxB,uBAAuB,GACvB,sBAAsB,GACtB,gBAAgB,GAChB,qBAAqB,GACrB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,GAClB,wBAAwB,GACxB,sBAAsB,CAAC;AAE1B,MAAM,WAAW,WAAW;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;CACxB;AAMD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,eAAe,EAAE,MAAM,CAgKzD,CAAC;AAMF;;;GAGG;AACH,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAeD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CACjC,EAAE,EAAE,eAAe,EACnB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC,WAAW,CAAC,CAiBtB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACvC,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,CAAC,CAStB;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACpC,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACT,OAAO,CAAC,GAAG,EAAE,CAAC,CAIhB;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAClC,WAAW,EAAE,MAAM,EACnB,UAAU,EAAE,MAAM,GAChB,OAAO,CAAC,GAAG,EAAE,CAAC,CAIhB;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAkEzD;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CA2BvD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAExD"}
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rate Limiter Module - Distributed rate limiting for Agent Mail
|
|
3
|
+
*
|
|
4
|
+
* Provides sliding window rate limiting with dual backends:
|
|
5
|
+
* - Redis (primary) - Distributed, uses sorted sets for sliding window
|
|
6
|
+
* - SQLite (fallback) - Local, file-based persistence
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Dual window enforcement: per-minute AND per-hour limits
|
|
10
|
+
* - Automatic backend fallback (Redis → SQLite)
|
|
11
|
+
* - Configurable limits per endpoint via env vars
|
|
12
|
+
* - Auto-cleanup of expired entries
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* // Create rate limiter (auto-selects backend)
|
|
17
|
+
* const limiter = await createRateLimiter();
|
|
18
|
+
*
|
|
19
|
+
* // Check if request is allowed
|
|
20
|
+
* const result = await limiter.checkLimit("BlueLake", "send");
|
|
21
|
+
* if (!result.allowed) {
|
|
22
|
+
* console.log(`Rate limited. Reset at ${result.resetAt}`);
|
|
23
|
+
* }
|
|
24
|
+
*
|
|
25
|
+
* // Record a request after it completes
|
|
26
|
+
* await limiter.recordRequest("BlueLake", "send");
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
import Redis from "ioredis";
|
|
30
|
+
/**
|
|
31
|
+
* Result of checking a rate limit
|
|
32
|
+
*/
|
|
33
|
+
export interface RateLimitResult {
|
|
34
|
+
/** Whether the request is allowed */
|
|
35
|
+
allowed: boolean;
|
|
36
|
+
/** Remaining requests in the most restrictive window */
|
|
37
|
+
remaining: number;
|
|
38
|
+
/** Unix timestamp (ms) when the limit resets */
|
|
39
|
+
resetAt: number;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Rate limiter interface
|
|
43
|
+
*/
|
|
44
|
+
export interface RateLimiter {
|
|
45
|
+
/**
|
|
46
|
+
* Check if a request is allowed under rate limits
|
|
47
|
+
* Checks BOTH minute and hour windows - both must pass
|
|
48
|
+
*
|
|
49
|
+
* @param agentName - The agent making the request
|
|
50
|
+
* @param endpoint - The endpoint being accessed
|
|
51
|
+
* @returns Rate limit check result
|
|
52
|
+
*/
|
|
53
|
+
checkLimit(agentName: string, endpoint: string): Promise<RateLimitResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Record a request against the rate limit
|
|
56
|
+
* Should be called AFTER the request succeeds
|
|
57
|
+
*
|
|
58
|
+
* @param agentName - The agent making the request
|
|
59
|
+
* @param endpoint - The endpoint being accessed
|
|
60
|
+
*/
|
|
61
|
+
recordRequest(agentName: string, endpoint: string): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Close the rate limiter and release resources
|
|
64
|
+
*/
|
|
65
|
+
close(): Promise<void>;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Rate limit configuration for an endpoint
|
|
69
|
+
*/
|
|
70
|
+
export interface EndpointLimits {
|
|
71
|
+
/** Requests allowed per minute */
|
|
72
|
+
perMinute: number;
|
|
73
|
+
/** Requests allowed per hour */
|
|
74
|
+
perHour: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Default rate limits per endpoint
|
|
78
|
+
* Can be overridden via OPENCODE_RATE_LIMIT_{ENDPOINT}_PER_MIN and _PER_HOUR
|
|
79
|
+
*/
|
|
80
|
+
export declare const DEFAULT_LIMITS: Record<string, EndpointLimits>;
|
|
81
|
+
/**
|
|
82
|
+
* Get rate limits for an endpoint, with env var overrides
|
|
83
|
+
*
|
|
84
|
+
* @param endpoint - The endpoint name
|
|
85
|
+
* @returns Rate limits for the endpoint
|
|
86
|
+
*/
|
|
87
|
+
export declare function getLimitsForEndpoint(endpoint: string): EndpointLimits;
|
|
88
|
+
/**
|
|
89
|
+
* Redis-backed rate limiter using sorted sets
|
|
90
|
+
*
|
|
91
|
+
* Uses sliding window algorithm:
|
|
92
|
+
* 1. Store each request as a member with timestamp as score
|
|
93
|
+
* 2. Remove expired entries (outside window)
|
|
94
|
+
* 3. Count remaining entries
|
|
95
|
+
*
|
|
96
|
+
* Key format: ratelimit:{agent}:{endpoint}:{window}
|
|
97
|
+
* Window values: "minute" or "hour"
|
|
98
|
+
*/
|
|
99
|
+
export declare class RedisRateLimiter implements RateLimiter {
|
|
100
|
+
private redis;
|
|
101
|
+
private connected;
|
|
102
|
+
constructor(redis: Redis);
|
|
103
|
+
/**
|
|
104
|
+
* Build Redis key for rate limiting
|
|
105
|
+
*/
|
|
106
|
+
private buildKey;
|
|
107
|
+
/**
|
|
108
|
+
* Get window duration in milliseconds
|
|
109
|
+
*/
|
|
110
|
+
private getWindowDuration;
|
|
111
|
+
checkLimit(agentName: string, endpoint: string): Promise<RateLimitResult>;
|
|
112
|
+
/**
|
|
113
|
+
* Check a single window's rate limit
|
|
114
|
+
*/
|
|
115
|
+
private checkWindow;
|
|
116
|
+
recordRequest(agentName: string, endpoint: string): Promise<void>;
|
|
117
|
+
close(): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* SQLite-backed rate limiter for local/fallback use
|
|
121
|
+
*
|
|
122
|
+
* Table schema:
|
|
123
|
+
* - agent_name: TEXT
|
|
124
|
+
* - endpoint: TEXT
|
|
125
|
+
* - window: TEXT ('minute' or 'hour')
|
|
126
|
+
* - timestamp: INTEGER (Unix ms)
|
|
127
|
+
*
|
|
128
|
+
* Uses sliding window via COUNT query with timestamp filter.
|
|
129
|
+
*/
|
|
130
|
+
export declare class SqliteRateLimiter implements RateLimiter {
|
|
131
|
+
private db;
|
|
132
|
+
constructor(dbPath: string);
|
|
133
|
+
/**
|
|
134
|
+
* Initialize the database schema and cleanup old entries
|
|
135
|
+
*/
|
|
136
|
+
private initialize;
|
|
137
|
+
checkLimit(agentName: string, endpoint: string): Promise<RateLimitResult>;
|
|
138
|
+
/**
|
|
139
|
+
* Check a single window's rate limit
|
|
140
|
+
*/
|
|
141
|
+
private checkWindow;
|
|
142
|
+
/**
|
|
143
|
+
* Clean up old rate limit entries in bounded batches
|
|
144
|
+
*
|
|
145
|
+
* Limits cleanup to prevent blocking recordRequest on large datasets:
|
|
146
|
+
* - BATCH_SIZE: 1000 rows per iteration
|
|
147
|
+
* - MAX_BATCHES: 10 (max 10k rows per cleanup invocation)
|
|
148
|
+
*
|
|
149
|
+
* Stops early if fewer than BATCH_SIZE rows deleted (no more to clean).
|
|
150
|
+
*/
|
|
151
|
+
private cleanup;
|
|
152
|
+
recordRequest(agentName: string, endpoint: string): Promise<void>;
|
|
153
|
+
close(): Promise<void>;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* In-memory rate limiter for testing
|
|
157
|
+
*
|
|
158
|
+
* Uses Map storage with timestamp arrays per key.
|
|
159
|
+
* No persistence - resets on process restart.
|
|
160
|
+
*/
|
|
161
|
+
export declare class InMemoryRateLimiter implements RateLimiter {
|
|
162
|
+
private storage;
|
|
163
|
+
private buildKey;
|
|
164
|
+
checkLimit(agentName: string, endpoint: string): Promise<RateLimitResult>;
|
|
165
|
+
private checkWindow;
|
|
166
|
+
recordRequest(agentName: string, endpoint: string): Promise<void>;
|
|
167
|
+
close(): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Reset all rate limits (for testing)
|
|
170
|
+
*/
|
|
171
|
+
reset(): void;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Create a rate limiter with automatic backend selection
|
|
175
|
+
*
|
|
176
|
+
* Tries Redis first, falls back to SQLite on connection failure.
|
|
177
|
+
* Warns once when falling back to SQLite.
|
|
178
|
+
*
|
|
179
|
+
* @returns Configured rate limiter instance
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript
|
|
183
|
+
* // Auto-select backend
|
|
184
|
+
* const limiter = await createRateLimiter();
|
|
185
|
+
*
|
|
186
|
+
* // Force SQLite
|
|
187
|
+
* const limiter = await createRateLimiter({ backend: "sqlite" });
|
|
188
|
+
*
|
|
189
|
+
* // Force in-memory (testing)
|
|
190
|
+
* const limiter = await createRateLimiter({ backend: "memory" });
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
export declare function createRateLimiter(options?: {
|
|
194
|
+
backend?: "redis" | "sqlite" | "memory";
|
|
195
|
+
redisUrl?: string;
|
|
196
|
+
sqlitePath?: string;
|
|
197
|
+
}): Promise<RateLimiter>;
|
|
198
|
+
/**
|
|
199
|
+
* Reset the fallback warning flag (for testing)
|
|
200
|
+
*/
|
|
201
|
+
export declare function resetFallbackWarning(): void;
|
|
202
|
+
/**
|
|
203
|
+
* Get or create the global rate limiter instance
|
|
204
|
+
*
|
|
205
|
+
* Uses auto-selection (Redis → SQLite) by default.
|
|
206
|
+
*/
|
|
207
|
+
export declare function getRateLimiter(): Promise<RateLimiter>;
|
|
208
|
+
/**
|
|
209
|
+
* Set the global rate limiter instance
|
|
210
|
+
*
|
|
211
|
+
* Useful for testing or custom configurations.
|
|
212
|
+
*/
|
|
213
|
+
export declare function setRateLimiter(limiter: RateLimiter): void;
|
|
214
|
+
/**
|
|
215
|
+
* Reset the global rate limiter instance
|
|
216
|
+
*/
|
|
217
|
+
export declare function resetRateLimiter(): Promise<void>;
|
|
218
|
+
//# sourceMappingURL=rate-limiter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.d.ts","sourceRoot":"","sources":["../src/rate-limiter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression detection result
|
|
3
|
+
*/
|
|
4
|
+
export interface RegressionResult {
|
|
5
|
+
/** Name of the eval that regressed */
|
|
6
|
+
evalName: string;
|
|
7
|
+
/** Previous run score */
|
|
8
|
+
oldScore: number;
|
|
9
|
+
/** Latest run score */
|
|
10
|
+
newScore: number;
|
|
11
|
+
/** Absolute delta (oldScore - newScore) */
|
|
12
|
+
delta: number;
|
|
13
|
+
/** Percentage change ((newScore - oldScore) / oldScore * 100) */
|
|
14
|
+
deltaPercent: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Detect regressions by comparing latest run to previous run
|
|
18
|
+
*
|
|
19
|
+
* Scans all evals in eval-history.jsonl and compares the last two runs
|
|
20
|
+
* for each eval. Returns evals where the score dropped more than the
|
|
21
|
+
* threshold.
|
|
22
|
+
*
|
|
23
|
+
* **Algorithm**:
|
|
24
|
+
* 1. Read all eval history records
|
|
25
|
+
* 2. Group by eval name
|
|
26
|
+
* 3. For each eval with ≥2 runs:
|
|
27
|
+
* - Get last 2 runs
|
|
28
|
+
* - Calculate delta and deltaPercent
|
|
29
|
+
* - If delta exceeds threshold AND score dropped, record regression
|
|
30
|
+
* 4. Sort results by severity (largest delta first)
|
|
31
|
+
*
|
|
32
|
+
* **Delta calculation**:
|
|
33
|
+
* - delta = oldScore - newScore (absolute drop)
|
|
34
|
+
* - deltaPercent = (newScore - oldScore) / oldScore * 100 (negative for regression)
|
|
35
|
+
*
|
|
36
|
+
* **Threshold**: Specified as absolute value (e.g., 0.10 = 10% drop required to report)
|
|
37
|
+
*
|
|
38
|
+
* @param projectPath - Absolute path to project root
|
|
39
|
+
* @param threshold - Minimum delta to report (default: 0.10 = 10%)
|
|
40
|
+
* @returns List of regressions sorted by severity (largest delta first)
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { detectRegressions } from "./regression-detection.js";
|
|
45
|
+
*
|
|
46
|
+
* const regressions = detectRegressions("/path/to/project", 0.10);
|
|
47
|
+
*
|
|
48
|
+
* if (regressions.length > 0) {
|
|
49
|
+
* console.error("⚠️ REGRESSION DETECTED");
|
|
50
|
+
* for (const reg of regressions) {
|
|
51
|
+
* console.error(`├── ${reg.evalName}: ${(reg.oldScore * 100).toFixed(1)}% → ${(reg.newScore * 100).toFixed(1)}% (${reg.deltaPercent.toFixed(1)}%)`);
|
|
52
|
+
* }
|
|
53
|
+
* console.error(`└── Threshold: ${(threshold * 100).toFixed(0)}%`);
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export declare function detectRegressions(projectPath: string, threshold?: number): RegressionResult[];
|
|
58
|
+
//# sourceMappingURL=regression-detection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"regression-detection.d.ts","sourceRoot":"","sources":["../src/regression-detection.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,yBAAyB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB;AA6CD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAAY,GACtB,gBAAgB,EAAE,CA0CpB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replay Tools - Event replay with timing simulation
|
|
3
|
+
*
|
|
4
|
+
* TDD GREEN: Minimal implementation to pass tests
|
|
5
|
+
*/
|
|
6
|
+
export type ReplaySpeed = "1x" | "2x" | "instant";
|
|
7
|
+
export interface ReplayEvent {
|
|
8
|
+
session_id: string;
|
|
9
|
+
epic_id: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
event_type: "DECISION" | "VIOLATION" | "OUTCOME" | "COMPACTION";
|
|
12
|
+
decision_type?: string;
|
|
13
|
+
violation_type?: string;
|
|
14
|
+
outcome_type?: string;
|
|
15
|
+
payload: Record<string, unknown>;
|
|
16
|
+
delta_ms: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ReplayFilter {
|
|
19
|
+
type?: Array<"DECISION" | "VIOLATION" | "OUTCOME" | "COMPACTION">;
|
|
20
|
+
agent?: string;
|
|
21
|
+
since?: Date;
|
|
22
|
+
until?: Date;
|
|
23
|
+
}
|
|
24
|
+
export declare function fetchEpicEvents(epicId: string, sessionFile: string): Promise<ReplayEvent[]>;
|
|
25
|
+
export declare function filterEvents(events: ReplayEvent[], filter: ReplayFilter): ReplayEvent[];
|
|
26
|
+
export declare function replayWithTiming(events: ReplayEvent[], speed: ReplaySpeed): AsyncGenerator<ReplayEvent>;
|
|
27
|
+
export declare function formatReplayEvent(event: ReplayEvent): string;
|
|
28
|
+
//# sourceMappingURL=replay-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-tools.d.ts","sourceRoot":"","sources":["../src/replay-tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AASH,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;AAElD,MAAM,WAAW,WAAW;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,CAAC,EAAE,KAAK,CAAC,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,KAAK,CAAC,EAAE,IAAI,CAAC;CACb;AAMD,wBAAsB,eAAe,CACpC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC,CA4CxB;AAMD,wBAAgB,YAAY,CAC3B,MAAM,EAAE,WAAW,EAAE,EACrB,MAAM,EAAE,YAAY,GAClB,WAAW,EAAE,CAiCf;AAMD,wBAAuB,gBAAgB,CACtC,MAAM,EAAE,WAAW,EAAE,EACrB,KAAK,EAAE,WAAW,GAChB,cAAc,CAAC,WAAW,CAAC,CAuC7B;AAMD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CA0D5D"}
|