swarm-mail 0.4.0 → 1.0.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.
Files changed (59) hide show
  1. package/README.md +121 -0
  2. package/bin/daemon-cli.ts +4 -4
  3. package/dist/beads/adapter.d.ts +38 -0
  4. package/dist/beads/adapter.d.ts.map +1 -0
  5. package/dist/beads/blocked-cache.d.ts +21 -0
  6. package/dist/beads/blocked-cache.d.ts.map +1 -0
  7. package/dist/beads/comments.d.ts +21 -0
  8. package/dist/beads/comments.d.ts.map +1 -0
  9. package/dist/beads/dependencies.d.ts +58 -0
  10. package/dist/beads/dependencies.d.ts.map +1 -0
  11. package/dist/beads/events.d.ts +163 -0
  12. package/dist/beads/events.d.ts.map +1 -0
  13. package/dist/beads/flush-manager.d.ts +71 -0
  14. package/dist/beads/flush-manager.d.ts.map +1 -0
  15. package/dist/beads/index.d.ts +25 -0
  16. package/dist/beads/index.d.ts.map +1 -0
  17. package/dist/beads/jsonl.d.ts +103 -0
  18. package/dist/beads/jsonl.d.ts.map +1 -0
  19. package/dist/beads/labels.d.ts +21 -0
  20. package/dist/beads/labels.d.ts.map +1 -0
  21. package/dist/beads/merge.d.ts +99 -0
  22. package/dist/beads/merge.d.ts.map +1 -0
  23. package/dist/beads/migrations.d.ts +41 -0
  24. package/dist/beads/migrations.d.ts.map +1 -0
  25. package/dist/beads/operations.d.ts +56 -0
  26. package/dist/beads/operations.d.ts.map +1 -0
  27. package/dist/beads/projections.d.ts +103 -0
  28. package/dist/beads/projections.d.ts.map +1 -0
  29. package/dist/beads/queries.d.ts +77 -0
  30. package/dist/beads/queries.d.ts.map +1 -0
  31. package/dist/beads/store.d.ts +98 -0
  32. package/dist/beads/store.d.ts.map +1 -0
  33. package/dist/beads/validation.d.ts +75 -0
  34. package/dist/beads/validation.d.ts.map +1 -0
  35. package/dist/index.d.ts +9 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +34994 -227
  38. package/dist/memory/adapter.d.ts +157 -0
  39. package/dist/memory/adapter.d.ts.map +1 -0
  40. package/dist/memory/index.d.ts +12 -0
  41. package/dist/memory/index.d.ts.map +1 -0
  42. package/dist/memory/migrate-legacy.d.ts +88 -0
  43. package/dist/memory/migrate-legacy.d.ts.map +1 -0
  44. package/dist/memory/migrations.d.ts +42 -0
  45. package/dist/memory/migrations.d.ts.map +1 -0
  46. package/dist/memory/ollama.d.ts +80 -0
  47. package/dist/memory/ollama.d.ts.map +1 -0
  48. package/dist/memory/store.d.ts +138 -0
  49. package/dist/memory/store.d.ts.map +1 -0
  50. package/dist/memory/sync.d.ts +93 -0
  51. package/dist/memory/sync.d.ts.map +1 -0
  52. package/dist/pglite.d.ts.map +1 -1
  53. package/dist/streams/events.d.ts +4 -0
  54. package/dist/streams/events.d.ts.map +1 -1
  55. package/dist/streams/index.d.ts.map +1 -1
  56. package/dist/streams/migrations.d.ts.map +1 -1
  57. package/dist/types/beads-adapter.d.ts +397 -0
  58. package/dist/types/beads-adapter.d.ts.map +1 -0
  59. package/package.json +7 -4
package/README.md CHANGED
@@ -47,6 +47,9 @@ Event sourcing primitives for multi-agent coordination. Local-first, no external
47
47
  │ ├── DurableCursor - Checkpointed stream reader │
48
48
  │ └── DurableDeferred - Distributed promise │
49
49
  │ │
50
+ │ MEMORY │
51
+ │ └── Semantic Memory - Vector embeddings (pgvector/Ollama) │
52
+ │ │
50
53
  │ STORAGE │
51
54
  │ └── PGLite (Embedded Postgres) + Migrations │
52
55
  └─────────────────────────────────────────────────────────────┘
@@ -136,6 +139,90 @@ const swarmMail = await getSwarmMail('/my/project') // persistent
136
139
  const swarmMail = await createInMemorySwarmMail() // in-memory
137
140
  ```
138
141
 
142
+ ## Deployment
143
+
144
+ ### Connection Modes
145
+
146
+ #### Daemon Mode (Default)
147
+
148
+ By default, swarm-mail starts an in-process `PGLiteSocketServer` when you call `getSwarmMail()`. All database operations go through this server, preventing multi-process corruption.
149
+
150
+ ```typescript
151
+ import { getSwarmMail } from 'swarm-mail'
152
+
153
+ // Default: starts daemon automatically
154
+ const swarmMail = await getSwarmMail('/my/project')
155
+
156
+ // Keep alive - handles cleanup on shutdown
157
+ process.on('SIGTERM', async () => {
158
+ await swarmMail.close() // Flushes WAL, closes cleanly
159
+ process.exit(0)
160
+ })
161
+ ```
162
+
163
+ **Why daemon mode is the default:**
164
+
165
+ - **No external dependencies** - Uses `@electric-sql/pglite-socket` in-process
166
+ - **Multi-process safe** - One PGLite instance, multiple clients can connect safely
167
+ - **WAL safety** - Single process prevents WAL accumulation from multiple instances
168
+ - **Proper cleanup** - Graceful shutdown triggers checkpoint, preventing unclean state
169
+ - **Resource efficiency** - One PGLite instance shared across operations
170
+
171
+ #### Embedded Mode (Opt-out)
172
+
173
+ For single-process use cases where you're certain only one process will access the database, you can opt out of daemon mode:
174
+
175
+ ```bash
176
+ SWARM_MAIL_SOCKET=false
177
+ ```
178
+
179
+ ⚠️ **Warning:** Embedded mode is NOT safe for multi-process access. PGLite uses a single connection, so concurrent processes will cause database corruption. Use only when you're absolutely certain only one process will access the database
180
+
181
+ ### WAL Safety Features
182
+
183
+ PGLite uses PostgreSQL's Write-Ahead Log (WAL) for durability. Swarm Mail includes safeguards against WAL bloat:
184
+
185
+ **Automatic checkpointing:**
186
+ ```typescript
187
+ // After batch operations, force WAL flush
188
+ await db.checkpoint()
189
+ ```
190
+
191
+ **Health monitoring:**
192
+ ```typescript
193
+ // Check WAL size (default threshold: 100MB)
194
+ const health = await swarmMail.healthCheck({ walThresholdMb: 100 })
195
+
196
+ if (!health.walHealth?.healthy) {
197
+ console.warn(health.walHealth?.message)
198
+ // "WAL size 120MB exceeds 100MB threshold (15 files)"
199
+ }
200
+
201
+ // Get detailed stats
202
+ const stats = await swarmMail.getDatabaseStats()
203
+ // { connected: true, wal: { size: 120_000_000, fileCount: 15 } }
204
+ ```
205
+
206
+ **When to checkpoint manually:**
207
+
208
+ - After migrations: `await swarmMail.runMigrations(); await db.checkpoint()`
209
+ - After bulk event appends (100+ events)
210
+ - Before long-running operations
211
+
212
+ ### Ephemeral Instances (Testing)
213
+
214
+ For tests, create isolated in-memory instances:
215
+
216
+ ```typescript
217
+ import { createInMemorySwarmMail } from 'swarm-mail'
218
+
219
+ const swarmMail = await createInMemorySwarmMail('test-id')
220
+ // ... run tests ...
221
+ await swarmMail.close()
222
+ ```
223
+
224
+ **Don't use ephemeral instances in production** - multiple short-lived processes compound WAL accumulation since each instance creates new PGLite connections without coordinated cleanup.
225
+
139
226
  ## Event Types
140
227
 
141
228
  ```typescript
@@ -183,12 +270,46 @@ Materialized views derived from events:
183
270
  | `swarm_contexts` | Checkpoint state for recovery |
184
271
  | `eval_records` | Outcome data for learning |
185
272
 
273
+ ### Semantic Memory
274
+
275
+ Persistent, searchable storage for agent learnings:
276
+
277
+ ```typescript
278
+ import { createMemoryAdapter } from 'swarm-mail/memory'
279
+
280
+ const swarmMail = await getSwarmMail('/my/project')
281
+ const db = await swarmMail.getDatabase()
282
+ const memory = await createMemoryAdapter(db)
283
+
284
+ // Store a learning
285
+ const { id } = await memory.store(
286
+ "OAuth refresh tokens need 5min buffer before expiry...",
287
+ { tags: "auth,tokens,debugging" }
288
+ )
289
+
290
+ // Search by meaning (vector similarity)
291
+ const results = await memory.find("token refresh issues")
292
+
293
+ // Check Ollama health
294
+ const health = await memory.checkHealth()
295
+ // { ollama: true, model: "mxbai-embed-large" }
296
+ ```
297
+
298
+ > **Note:** Requires [Ollama](https://ollama.ai/) for vector embeddings. Falls back to full-text search if unavailable.
299
+ >
300
+ > ```bash
301
+ > ollama pull mxbai-embed-large
302
+ > ```
303
+
304
+ > **Deprecation Notice:** The standalone [semantic-memory MCP server](https://github.com/joelhooks/semantic-memory) is deprecated. Use the embedded memory in swarm-mail instead - same API, single PGLite instance, no separate process.
305
+
186
306
  ## Architecture
187
307
 
188
308
  - **Append-only log** - Events are immutable, projections are derived
189
309
  - **Local-first** - PGLite embedded Postgres, no external servers
190
310
  - **Effect-TS** - Type-safe, composable, testable
191
311
  - **Exactly-once** - DurableCursor checkpoints position
312
+ - **Semantic memory** - Vector embeddings with pgvector + Ollama
192
313
 
193
314
  ## API Reference
194
315
 
package/bin/daemon-cli.ts CHANGED
@@ -2,10 +2,10 @@
2
2
  /**
3
3
  * swarm-mail-daemon CLI
4
4
  *
5
- * Command-line interface for managing the swarm-mail pglite-server daemon.
5
+ * Command-line interface for managing the in-process PGLiteSocketServer daemon.
6
6
  *
7
7
  * Commands:
8
- * start [options] - Start the daemon
8
+ * start [options] - Start the in-process daemon
9
9
  * stop - Stop the daemon
10
10
  * status - Show daemon status
11
11
  *
@@ -65,13 +65,13 @@ function info(msg: string) {
65
65
 
66
66
  function showHelp() {
67
67
  console.log(`
68
- ${colors.bold}swarm-mail-daemon${colors.reset} - Manage pglite-server daemon for swarm-mail
68
+ ${colors.bold}swarm-mail-daemon${colors.reset} - Manage in-process PGLiteSocketServer daemon
69
69
 
70
70
  ${colors.bold}USAGE${colors.reset}
71
71
  swarm-mail-daemon <command> [options]
72
72
 
73
73
  ${colors.bold}COMMANDS${colors.reset}
74
- start [options] Start the daemon
74
+ start [options] Start the in-process daemon
75
75
  stop Stop the daemon
76
76
  status Show daemon status
77
77
 
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Beads Adapter - Factory for creating BeadsAdapter instances
3
+ *
4
+ * This file implements the adapter pattern for beads event sourcing,
5
+ * enabling dependency injection of the database.
6
+ *
7
+ * ## Design Pattern
8
+ * - Accept DatabaseAdapter via factory parameter
9
+ * - Return BeadsAdapter interface
10
+ * - Delegate to store.ts for event operations
11
+ * - Delegate to projections.ts for queries
12
+ * - No direct database access (all via adapter)
13
+ *
14
+ * ## Usage
15
+ * ```typescript
16
+ * import { wrapPGlite } from '@opencode/swarm-mail/pglite';
17
+ * import { createBeadsAdapter } from '@opencode/swarm-mail/beads';
18
+ *
19
+ * const pglite = new PGlite('./streams.db');
20
+ * const db = wrapPGlite(pglite);
21
+ * const beads = createBeadsAdapter(db, '/path/to/project');
22
+ *
23
+ * // Use the adapter
24
+ * await beads.createBead(projectKey, { title: "Task", type: "task", priority: 2 });
25
+ * const bead = await beads.getBead(projectKey, "bd-123");
26
+ * ```
27
+ */
28
+ import type { DatabaseAdapter } from "../types/database.js";
29
+ import type { BeadsAdapter } from "../types/beads-adapter.js";
30
+ /**
31
+ * Create a BeadsAdapter instance
32
+ *
33
+ * @param db - DatabaseAdapter instance (PGLite, SQLite, PostgreSQL, etc.)
34
+ * @param projectKey - Project identifier (typically the project path)
35
+ * @returns BeadsAdapter interface
36
+ */
37
+ export declare function createBeadsAdapter(db: DatabaseAdapter, projectKey: string): BeadsAdapter;
38
+ //# sourceMappingURL=adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/beads/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AA6B9D;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,GACjB,YAAY,CAkiBd"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Blocked Beads Cache Management
3
+ *
4
+ * Convenience re-exports for blocked cache operations.
5
+ * The actual implementation is in dependencies.ts to avoid circular dependencies.
6
+ *
7
+ * ## Cache Strategy
8
+ * - blocked_beads_cache table stores bead_id → blocker_ids[]
9
+ * - Rebuilt when dependencies change or bead status changes
10
+ * - Enables fast "ready work" queries without recursive CTEs
11
+ *
12
+ * ## Performance
13
+ * - Cache rebuild: <50ms for typical projects
14
+ * - Ready work query: 25x faster with cache (752ms → 29ms on 10K beads)
15
+ *
16
+ * Reference: steveyegge/beads/internal/storage/sqlite/blocked_cache.go
17
+ *
18
+ * @module beads/blocked-cache
19
+ */
20
+ export { rebuildBeadBlockedCache, rebuildAllBlockedCaches, invalidateBlockedCache, } from "./dependencies.js";
21
+ //# sourceMappingURL=blocked-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blocked-cache.d.ts","sourceRoot":"","sources":["../../src/beads/blocked-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EACL,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Comment Operations
3
+ *
4
+ * Comment management with threading support.
5
+ * Comments can have parent_id for nested discussions.
6
+ *
7
+ * Reference: steveyegge/beads/internal/storage/sqlite/comments.go
8
+ *
9
+ * @module beads/comments
10
+ */
11
+ import type { DatabaseAdapter } from "../types/database.js";
12
+ import type { BeadComment } from "../types/beads-adapter.js";
13
+ /**
14
+ * Get a specific comment by ID
15
+ */
16
+ export declare function getCommentById(db: DatabaseAdapter, commentId: number): Promise<BeadComment | null>;
17
+ /**
18
+ * Get comment thread (comment + all replies)
19
+ */
20
+ export declare function getCommentThread(db: DatabaseAdapter, rootCommentId: number): Promise<BeadComment[]>;
21
+ //# sourceMappingURL=comments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../src/beads/comments.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAE7D;;GAEG;AACH,wBAAsB,cAAc,CAClC,EAAE,EAAE,eAAe,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAM7B;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,eAAe,EACnB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,WAAW,EAAE,CAAC,CAgBxB"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Dependency Graph Operations
3
+ *
4
+ * Provides dependency management with cycle detection and blocked bead tracking.
5
+ *
6
+ * ## Dependency Types
7
+ * - **blocks**: Hard dependency - target must be closed before source can start
8
+ * - **blocked-by**: Inverse of blocks (computed, not stored)
9
+ * - **related**: Soft relationship - doesn't affect ready state
10
+ * - **discovered-from**: Tracking relationship - found while working on another bead
11
+ *
12
+ * ## Cycle Prevention
13
+ * All dependency types are checked for cycles to maintain a DAG (Directed Acyclic Graph).
14
+ * This ensures:
15
+ * - Ready work calculation works correctly
16
+ * - Dependency traversal doesn't loop
17
+ * - Semantic clarity (no circular dependencies)
18
+ *
19
+ * Reference: steveyegge/beads/internal/storage/sqlite/dependencies.go
20
+ *
21
+ * @module beads/dependencies
22
+ */
23
+ import type { DatabaseAdapter } from "../types/database.js";
24
+ /**
25
+ * Check if adding a dependency would create a cycle
26
+ *
27
+ * Uses recursive CTE to traverse from dependsOnId to see if we can reach beadId.
28
+ * If yes, adding "beadId depends on dependsOnId" would complete a cycle.
29
+ */
30
+ export declare function wouldCreateCycle(db: DatabaseAdapter, beadId: string, dependsOnId: string): Promise<boolean>;
31
+ /**
32
+ * Get all open blockers for a bead (including transitive)
33
+ *
34
+ * Returns bead IDs of all beads blocking this one that aren't closed.
35
+ * Only considers "blocks" relationship type.
36
+ */
37
+ export declare function getOpenBlockers(db: DatabaseAdapter, projectKey: string, beadId: string): Promise<string[]>;
38
+ /**
39
+ * Rebuild blocked cache for a specific bead
40
+ *
41
+ * Finds all open blockers and updates the cache.
42
+ * If no open blockers, removes from cache (bead is unblocked).
43
+ */
44
+ export declare function rebuildBeadBlockedCache(db: DatabaseAdapter, projectKey: string, beadId: string): Promise<void>;
45
+ /**
46
+ * Rebuild blocked cache for all beads in a project
47
+ *
48
+ * Used after bulk operations or status changes that affect blocking.
49
+ */
50
+ export declare function rebuildAllBlockedCaches(db: DatabaseAdapter, projectKey: string): Promise<void>;
51
+ /**
52
+ * Invalidate blocked cache when dependencies change
53
+ *
54
+ * Marks beads as needing cache rebuild.
55
+ * In this simple implementation, we just rebuild immediately.
56
+ */
57
+ export declare function invalidateBlockedCache(db: DatabaseAdapter, projectKey: string, beadId: string): Promise<void>;
58
+ //# sourceMappingURL=dependencies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencies.d.ts","sourceRoot":"","sources":["../../src/beads/dependencies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,EAAE,EAAE,eAAe,EACnB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,EAAE,CAAC,CAwBnB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAaf;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,EAAE,EAAE,eAAe,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAYf"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Bead Event Types - Minimal type definitions for swarm-mail
3
+ *
4
+ * These are simplified type definitions that match the bead-events from
5
+ * opencode-swarm-plugin but avoid cross-package TypeScript imports.
6
+ *
7
+ * The actual event schemas with Zod validation live in:
8
+ * packages/opencode-swarm-plugin/src/schemas/bead-events.ts
9
+ *
10
+ * This file provides just enough type information for the store to work.
11
+ */
12
+ /**
13
+ * Base bead event (all events extend this)
14
+ */
15
+ export interface BaseBeadEvent {
16
+ id?: number;
17
+ type: string;
18
+ project_key: string;
19
+ bead_id: string;
20
+ timestamp: number;
21
+ sequence?: number;
22
+ }
23
+ /**
24
+ * Union of all bead event types
25
+ *
26
+ * This matches the discriminated union in bead-events.ts but as pure TypeScript
27
+ */
28
+ export type BeadEvent = BeadCreatedEvent | BeadUpdatedEvent | BeadStatusChangedEvent | BeadClosedEvent | BeadReopenedEvent | BeadDeletedEvent | BeadDependencyAddedEvent | BeadDependencyRemovedEvent | BeadLabelAddedEvent | BeadLabelRemovedEvent | BeadCommentAddedEvent | BeadCommentUpdatedEvent | BeadCommentDeletedEvent | BeadEpicChildAddedEvent | BeadEpicChildRemovedEvent | BeadEpicClosureEligibleEvent | BeadAssignedEvent | BeadWorkStartedEvent | BeadCompactedEvent;
29
+ export interface BeadCreatedEvent extends BaseBeadEvent {
30
+ type: "bead_created";
31
+ title: string;
32
+ description?: string;
33
+ issue_type: "bug" | "feature" | "task" | "epic" | "chore";
34
+ priority: number;
35
+ parent_id?: string;
36
+ created_by?: string;
37
+ metadata?: Record<string, unknown>;
38
+ }
39
+ export interface BeadUpdatedEvent extends BaseBeadEvent {
40
+ type: "bead_updated";
41
+ updated_by?: string;
42
+ changes: {
43
+ title?: {
44
+ old: string;
45
+ new: string;
46
+ };
47
+ description?: {
48
+ old: string;
49
+ new: string;
50
+ };
51
+ priority?: {
52
+ old: number;
53
+ new: number;
54
+ };
55
+ };
56
+ }
57
+ export interface BeadStatusChangedEvent extends BaseBeadEvent {
58
+ type: "bead_status_changed";
59
+ from_status: "open" | "in_progress" | "blocked" | "closed" | "tombstone";
60
+ to_status: "open" | "in_progress" | "blocked" | "closed" | "tombstone";
61
+ changed_by?: string;
62
+ reason?: string;
63
+ }
64
+ export interface BeadClosedEvent extends BaseBeadEvent {
65
+ type: "bead_closed";
66
+ reason: string;
67
+ closed_by?: string;
68
+ files_touched?: string[];
69
+ duration_ms?: number;
70
+ }
71
+ export interface BeadReopenedEvent extends BaseBeadEvent {
72
+ type: "bead_reopened";
73
+ reason?: string;
74
+ reopened_by?: string;
75
+ }
76
+ export interface BeadDeletedEvent extends BaseBeadEvent {
77
+ type: "bead_deleted";
78
+ reason?: string;
79
+ deleted_by?: string;
80
+ }
81
+ export interface BeadDependencyAddedEvent extends BaseBeadEvent {
82
+ type: "bead_dependency_added";
83
+ dependency: {
84
+ target: string;
85
+ type: "blocks" | "blocked-by" | "related" | "discovered-from";
86
+ };
87
+ added_by?: string;
88
+ reason?: string;
89
+ }
90
+ export interface BeadDependencyRemovedEvent extends BaseBeadEvent {
91
+ type: "bead_dependency_removed";
92
+ dependency: {
93
+ target: string;
94
+ type: "blocks" | "blocked-by" | "related" | "discovered-from";
95
+ };
96
+ removed_by?: string;
97
+ reason?: string;
98
+ }
99
+ export interface BeadLabelAddedEvent extends BaseBeadEvent {
100
+ type: "bead_label_added";
101
+ label: string;
102
+ added_by?: string;
103
+ }
104
+ export interface BeadLabelRemovedEvent extends BaseBeadEvent {
105
+ type: "bead_label_removed";
106
+ label: string;
107
+ removed_by?: string;
108
+ }
109
+ export interface BeadCommentAddedEvent extends BaseBeadEvent {
110
+ type: "bead_comment_added";
111
+ comment_id?: number;
112
+ author: string;
113
+ body: string;
114
+ parent_comment_id?: number;
115
+ metadata?: Record<string, unknown>;
116
+ }
117
+ export interface BeadCommentUpdatedEvent extends BaseBeadEvent {
118
+ type: "bead_comment_updated";
119
+ comment_id: number;
120
+ old_body: string;
121
+ new_body: string;
122
+ updated_by: string;
123
+ }
124
+ export interface BeadCommentDeletedEvent extends BaseBeadEvent {
125
+ type: "bead_comment_deleted";
126
+ comment_id: number;
127
+ deleted_by: string;
128
+ reason?: string;
129
+ }
130
+ export interface BeadEpicChildAddedEvent extends BaseBeadEvent {
131
+ type: "bead_epic_child_added";
132
+ child_id: string;
133
+ child_index?: number;
134
+ added_by?: string;
135
+ }
136
+ export interface BeadEpicChildRemovedEvent extends BaseBeadEvent {
137
+ type: "bead_epic_child_removed";
138
+ child_id: string;
139
+ removed_by?: string;
140
+ reason?: string;
141
+ }
142
+ export interface BeadEpicClosureEligibleEvent extends BaseBeadEvent {
143
+ type: "bead_epic_closure_eligible";
144
+ child_ids: string[];
145
+ total_duration_ms?: number;
146
+ all_files_touched?: string[];
147
+ }
148
+ export interface BeadAssignedEvent extends BaseBeadEvent {
149
+ type: "bead_assigned";
150
+ agent_name: string;
151
+ task_description?: string;
152
+ }
153
+ export interface BeadWorkStartedEvent extends BaseBeadEvent {
154
+ type: "bead_work_started";
155
+ agent_name: string;
156
+ reserved_files?: string[];
157
+ }
158
+ export interface BeadCompactedEvent extends BaseBeadEvent {
159
+ type: "bead_compacted";
160
+ events_archived: number;
161
+ new_start_sequence: number;
162
+ }
163
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/beads/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * FlushManager - Debounced JSONL export to file
3
+ *
4
+ * Automatically exports dirty beads to a JSONL file on a debounced timer.
5
+ * Prevents excessive writes while ensuring changes are persisted.
6
+ *
7
+ * Based on steveyegge/beads flush_manager.go
8
+ *
9
+ * @module beads/flush-manager
10
+ */
11
+ import type { BeadsAdapter } from "../types/beads-adapter.js";
12
+ export interface FlushManagerOptions {
13
+ adapter: BeadsAdapter;
14
+ projectKey: string;
15
+ outputPath: string;
16
+ debounceMs?: number;
17
+ onFlush?: (result: FlushResult) => void;
18
+ }
19
+ export interface FlushResult {
20
+ beadsExported: number;
21
+ bytesWritten: number;
22
+ duration: number;
23
+ }
24
+ /**
25
+ * FlushManager handles debounced export of dirty beads to JSONL
26
+ *
27
+ * Usage:
28
+ * ```ts
29
+ * const manager = new FlushManager({
30
+ * adapter,
31
+ * projectKey: "/path/to/project",
32
+ * outputPath: ".beads/issues.jsonl",
33
+ * debounceMs: 30000,
34
+ * });
35
+ *
36
+ * // Schedule flushes as beads change
37
+ * manager.scheduleFlush();
38
+ *
39
+ * // Clean up
40
+ * manager.stop();
41
+ * ```
42
+ */
43
+ export declare class FlushManager {
44
+ private adapter;
45
+ private projectKey;
46
+ private outputPath;
47
+ private debounceMs;
48
+ private onFlush?;
49
+ private timer;
50
+ private flushing;
51
+ constructor(options: FlushManagerOptions);
52
+ /**
53
+ * Schedule a flush (debounced)
54
+ *
55
+ * If a flush is already scheduled, resets the timer.
56
+ */
57
+ scheduleFlush(): void;
58
+ /**
59
+ * Force immediate flush
60
+ *
61
+ * Exports all dirty beads to the output file.
62
+ */
63
+ flush(): Promise<FlushResult>;
64
+ /**
65
+ * Stop the flush manager
66
+ *
67
+ * Clears any pending timers. Does NOT flush pending changes.
68
+ */
69
+ stop(): void;
70
+ }
71
+ //# sourceMappingURL=flush-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flush-manager.d.ts","sourceRoot":"","sources":["../../src/beads/flush-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAI9D,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,CAAC;CACzC;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,OAAO,CAAC,CAAgC;IAChD,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,mBAAmB;IAQxC;;;;OAIG;IACH,aAAa,IAAI,IAAI;IAcrB;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IA8DnC;;;;OAIG;IACH,IAAI,IAAI,IAAI;CAMb"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Beads Module - Event-sourced issue tracking
3
+ *
4
+ * Exports:
5
+ * - BeadsAdapter interface and types
6
+ * - Migration definitions
7
+ * - Projection functions
8
+ * - Store operations (append, read, replay)
9
+ * - Event type definitions
10
+ *
11
+ * @module beads
12
+ */
13
+ export type { Bead, BeadAdapter, BeadComment, BeadDependency, BeadLabel, BeadsAdapter, BeadsAdapterFactory, BeadsSchemaAdapter, BeadStatus, BeadType, CommentAdapter, CreateBeadOptions, DependencyAdapter, DependencyRelationship, EpicAdapter, LabelAdapter, QueryAdapter, QueryBeadsOptions, UpdateBeadOptions, } from "../types/beads-adapter.js";
14
+ export type { BeadEvent, BaseBeadEvent, BeadCreatedEvent, BeadUpdatedEvent, BeadStatusChangedEvent, BeadClosedEvent, BeadReopenedEvent, BeadDeletedEvent, BeadDependencyAddedEvent, BeadDependencyRemovedEvent, BeadLabelAddedEvent, BeadLabelRemovedEvent, BeadCommentAddedEvent, BeadCommentUpdatedEvent, BeadCommentDeletedEvent, BeadEpicChildAddedEvent, BeadEpicChildRemovedEvent, BeadEpicClosureEligibleEvent, BeadAssignedEvent, BeadWorkStartedEvent, BeadCompactedEvent, } from "./events.js";
15
+ export { createBeadsAdapter } from "./adapter.js";
16
+ export { beadsMigration, beadsMigrations } from "./migrations.js";
17
+ export { appendBeadEvent, readBeadEvents, replayBeadEvents, type ReadBeadEventsOptions, } from "./store.js";
18
+ export { clearAllDirtyBeads, clearDirtyBead, getBead, getBlockedBeads, getBlockers, getComments, getDependencies, getDependents, getDirtyBeads, getInProgressBeads, getLabels, getNextReadyBead, isBlocked, markBeadDirty, queryBeads, updateProjections, } from "./projections.js";
19
+ export { wouldCreateCycle, getOpenBlockers, rebuildBeadBlockedCache, rebuildAllBlockedCaches, invalidateBlockedCache, } from "./dependencies.js";
20
+ export { getBeadsByLabel, getAllLabels, } from "./labels.js";
21
+ export { getCommentById, getCommentThread, } from "./comments.js";
22
+ export { exportToJSONL, exportDirtyBeads, importFromJSONL, parseJSONL, serializeToJSONL, computeContentHash, type BeadExport, type ExportOptions, type ImportOptions, type ImportResult, } from "./jsonl.js";
23
+ export { FlushManager, type FlushManagerOptions, type FlushResult, } from "./flush-manager.js";
24
+ export { merge3Way, mergeJsonl, isTombstone, isExpiredTombstone, DEFAULT_TOMBSTONE_TTL_MS, MIN_TOMBSTONE_TTL_MS, CLOCK_SKEW_GRACE_MS, STATUS_TOMBSTONE, type IssueKey, type MergeResult, type MergeOptions, } from "./merge.js";
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/beads/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,YAAY,EACV,IAAI,EACJ,WAAW,EACX,WAAW,EACX,cAAc,EACd,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,EACV,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,sBAAsB,EACtB,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EACV,SAAS,EACT,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,mBAAmB,EACnB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,4BAA4B,EAC5B,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGlD,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGlE,OAAO,EACL,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,KAAK,qBAAqB,GAC3B,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,kBAAkB,EAClB,cAAc,EACd,OAAO,EACP,eAAe,EACf,WAAW,EACX,WAAW,EACX,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,SAAS,EACT,aAAa,EACb,UAAU,EACV,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,eAAe,EACf,YAAY,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,cAAc,EACd,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,UAAU,EACV,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,KAAK,WAAW,GACjB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,SAAS,EACT,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,YAAY,GAClB,MAAM,YAAY,CAAC"}