swarm-mail 0.2.1 → 0.3.2
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/dist/{beads → hive}/adapter.d.ts +10 -10
- package/dist/hive/adapter.d.ts.map +1 -0
- package/dist/{beads → hive}/blocked-cache.d.ts +1 -1
- package/dist/hive/blocked-cache.d.ts.map +1 -0
- package/dist/{beads → hive}/comments.d.ts +3 -3
- package/dist/hive/comments.d.ts.map +1 -0
- package/dist/{beads → hive}/dependencies.d.ts +6 -6
- package/dist/hive/dependencies.d.ts.map +1 -0
- package/dist/hive/events.d.ts +163 -0
- package/dist/hive/events.d.ts.map +1 -0
- package/dist/{beads → hive}/flush-manager.d.ts +3 -3
- package/dist/hive/flush-manager.d.ts.map +1 -0
- package/dist/hive/index.d.ts +26 -0
- package/dist/hive/index.d.ts.map +1 -0
- package/dist/{beads → hive}/jsonl.d.ts +14 -14
- package/dist/hive/jsonl.d.ts.map +1 -0
- package/dist/{beads → hive}/labels.d.ts +2 -2
- package/dist/hive/labels.d.ts.map +1 -0
- package/dist/{beads → hive}/merge.d.ts +5 -5
- package/dist/hive/merge.d.ts.map +1 -0
- package/dist/{beads → hive}/migrations.d.ts +14 -1
- package/dist/hive/migrations.d.ts.map +1 -0
- package/dist/hive/operations.d.ts +56 -0
- package/dist/hive/operations.d.ts.map +1 -0
- package/dist/{beads → hive}/projections.d.ts +19 -19
- package/dist/hive/projections.d.ts.map +1 -0
- package/dist/{beads → hive}/queries.d.ts +10 -10
- package/dist/hive/queries.d.ts.map +1 -0
- package/dist/{beads → hive}/store.d.ts +9 -9
- package/dist/hive/store.d.ts.map +1 -0
- package/dist/{beads → hive}/validation.d.ts +7 -7
- package/dist/hive/validation.d.ts.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +517 -393
- package/dist/pglite.d.ts.map +1 -1
- package/dist/types/{beads-adapter.d.ts → hive-adapter.d.ts} +155 -103
- package/dist/types/hive-adapter.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/beads/adapter.d.ts.map +0 -1
- package/dist/beads/blocked-cache.d.ts.map +0 -1
- package/dist/beads/comments.d.ts.map +0 -1
- package/dist/beads/dependencies.d.ts.map +0 -1
- package/dist/beads/events.d.ts +0 -163
- package/dist/beads/events.d.ts.map +0 -1
- package/dist/beads/flush-manager.d.ts.map +0 -1
- package/dist/beads/index.d.ts +0 -25
- package/dist/beads/index.d.ts.map +0 -1
- package/dist/beads/jsonl.d.ts.map +0 -1
- package/dist/beads/labels.d.ts.map +0 -1
- package/dist/beads/merge.d.ts.map +0 -1
- package/dist/beads/migrations.d.ts.map +0 -1
- package/dist/beads/operations.d.ts +0 -56
- package/dist/beads/operations.d.ts.map +0 -1
- package/dist/beads/projections.d.ts.map +0 -1
- package/dist/beads/queries.d.ts.map +0 -1
- package/dist/beads/store.d.ts.map +0 -1
- package/dist/beads/validation.d.ts.map +0 -1
- package/dist/types/beads-adapter.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -18229,7 +18229,7 @@ var init_store = __esm(() => {
|
|
|
18229
18229
|
TIMESTAMP_SAFE_UNTIL = new Date("2286-01-01").getTime();
|
|
18230
18230
|
});
|
|
18231
18231
|
|
|
18232
|
-
// src/
|
|
18232
|
+
// src/hive/dependencies.ts
|
|
18233
18233
|
var exports_dependencies = {};
|
|
18234
18234
|
__export(exports_dependencies, {
|
|
18235
18235
|
wouldCreateCycle: () => wouldCreateCycle,
|
|
@@ -18238,88 +18238,90 @@ __export(exports_dependencies, {
|
|
|
18238
18238
|
invalidateBlockedCache: () => invalidateBlockedCache,
|
|
18239
18239
|
getOpenBlockers: () => getOpenBlockers
|
|
18240
18240
|
});
|
|
18241
|
-
async function wouldCreateCycle(db,
|
|
18241
|
+
async function wouldCreateCycle(db, cellId, dependsOnId) {
|
|
18242
18242
|
const result = await db.query(`WITH RECURSIVE paths AS (
|
|
18243
18243
|
-- Start from the target (what we want to depend on)
|
|
18244
18244
|
SELECT
|
|
18245
|
-
|
|
18245
|
+
cell_id,
|
|
18246
18246
|
depends_on_id,
|
|
18247
18247
|
1 as depth
|
|
18248
18248
|
FROM bead_dependencies
|
|
18249
|
-
WHERE
|
|
18249
|
+
WHERE cell_id = $2
|
|
18250
18250
|
|
|
18251
18251
|
UNION
|
|
18252
18252
|
|
|
18253
18253
|
-- Follow dependencies transitively
|
|
18254
18254
|
SELECT
|
|
18255
|
-
bd.
|
|
18255
|
+
bd.cell_id,
|
|
18256
18256
|
bd.depends_on_id,
|
|
18257
18257
|
p.depth + 1
|
|
18258
18258
|
FROM bead_dependencies bd
|
|
18259
|
-
JOIN paths p ON bd.
|
|
18259
|
+
JOIN paths p ON bd.cell_id = p.depends_on_id
|
|
18260
18260
|
WHERE p.depth < $3
|
|
18261
18261
|
)
|
|
18262
18262
|
SELECT EXISTS(
|
|
18263
18263
|
SELECT 1 FROM paths WHERE depends_on_id = $1
|
|
18264
|
-
) as exists`, [
|
|
18264
|
+
) as exists`, [cellId, dependsOnId, MAX_DEPENDENCY_DEPTH]);
|
|
18265
18265
|
return result.rows[0]?.exists ?? false;
|
|
18266
18266
|
}
|
|
18267
|
-
async function getOpenBlockers(db, projectKey,
|
|
18267
|
+
async function getOpenBlockers(db, projectKey, cellId) {
|
|
18268
18268
|
const result = await db.query(`WITH RECURSIVE blockers AS (
|
|
18269
18269
|
-- Direct blockers
|
|
18270
18270
|
SELECT depends_on_id as blocker_id, 1 as depth
|
|
18271
18271
|
FROM bead_dependencies
|
|
18272
|
-
WHERE
|
|
18272
|
+
WHERE cell_id = $1 AND relationship = 'blocks'
|
|
18273
18273
|
|
|
18274
18274
|
UNION
|
|
18275
18275
|
|
|
18276
18276
|
-- Transitive blockers
|
|
18277
18277
|
SELECT bd.depends_on_id, b.depth + 1
|
|
18278
18278
|
FROM bead_dependencies bd
|
|
18279
|
-
JOIN blockers b ON bd.
|
|
18279
|
+
JOIN blockers b ON bd.cell_id = b.blocker_id
|
|
18280
18280
|
WHERE bd.relationship = 'blocks' AND b.depth < $3
|
|
18281
18281
|
)
|
|
18282
18282
|
SELECT DISTINCT b.blocker_id
|
|
18283
18283
|
FROM blockers b
|
|
18284
18284
|
JOIN beads bead ON b.blocker_id = bead.id
|
|
18285
|
-
WHERE bead.project_key = $2 AND bead.status != 'closed' AND bead.deleted_at IS NULL`, [
|
|
18285
|
+
WHERE bead.project_key = $2 AND bead.status != 'closed' AND bead.deleted_at IS NULL`, [cellId, projectKey, MAX_DEPENDENCY_DEPTH]);
|
|
18286
18286
|
return result.rows.map((r) => r.blocker_id);
|
|
18287
18287
|
}
|
|
18288
|
-
async function rebuildBeadBlockedCache(db, projectKey,
|
|
18289
|
-
const blockerIds = await getOpenBlockers(db, projectKey,
|
|
18288
|
+
async function rebuildBeadBlockedCache(db, projectKey, cellId) {
|
|
18289
|
+
const blockerIds = await getOpenBlockers(db, projectKey, cellId);
|
|
18290
18290
|
if (blockerIds.length > 0) {
|
|
18291
|
-
await db.query(`INSERT INTO blocked_beads_cache (
|
|
18291
|
+
await db.query(`INSERT INTO blocked_beads_cache (cell_id, blocker_ids, updated_at)
|
|
18292
18292
|
VALUES ($1, $2, $3)
|
|
18293
|
-
ON CONFLICT (
|
|
18294
|
-
DO UPDATE SET blocker_ids = $2, updated_at = $3`, [
|
|
18293
|
+
ON CONFLICT (cell_id)
|
|
18294
|
+
DO UPDATE SET blocker_ids = $2, updated_at = $3`, [cellId, blockerIds, Date.now()]);
|
|
18295
18295
|
} else {
|
|
18296
|
-
await db.query(`DELETE FROM blocked_beads_cache WHERE
|
|
18296
|
+
await db.query(`DELETE FROM blocked_beads_cache WHERE cell_id = $1`, [cellId]);
|
|
18297
18297
|
}
|
|
18298
18298
|
}
|
|
18299
18299
|
async function rebuildAllBlockedCaches(db, projectKey) {
|
|
18300
18300
|
const result = await db.query(`SELECT DISTINCT b.id FROM beads b
|
|
18301
|
-
JOIN bead_dependencies bd ON b.id = bd.
|
|
18301
|
+
JOIN bead_dependencies bd ON b.id = bd.cell_id
|
|
18302
18302
|
WHERE b.project_key = $1 AND bd.relationship = 'blocks' AND b.deleted_at IS NULL`, [projectKey]);
|
|
18303
18303
|
for (const row of result.rows) {
|
|
18304
18304
|
await rebuildBeadBlockedCache(db, projectKey, row.id);
|
|
18305
18305
|
}
|
|
18306
18306
|
}
|
|
18307
|
-
async function invalidateBlockedCache(db, projectKey,
|
|
18308
|
-
await rebuildBeadBlockedCache(db, projectKey,
|
|
18309
|
-
const dependents = await db.query(`SELECT
|
|
18307
|
+
async function invalidateBlockedCache(db, projectKey, cellId) {
|
|
18308
|
+
await rebuildBeadBlockedCache(db, projectKey, cellId);
|
|
18309
|
+
const dependents = await db.query(`SELECT cell_id FROM bead_dependencies WHERE depends_on_id = $1`, [cellId]);
|
|
18310
18310
|
for (const row of dependents.rows) {
|
|
18311
|
-
await rebuildBeadBlockedCache(db, projectKey, row.
|
|
18311
|
+
await rebuildBeadBlockedCache(db, projectKey, row.cell_id);
|
|
18312
18312
|
}
|
|
18313
18313
|
}
|
|
18314
18314
|
var MAX_DEPENDENCY_DEPTH = 100;
|
|
18315
18315
|
|
|
18316
|
-
// src/
|
|
18316
|
+
// src/hive/migrations.ts
|
|
18317
18317
|
var exports_migrations2 = {};
|
|
18318
18318
|
__export(exports_migrations2, {
|
|
18319
|
+
hiveMigrations: () => hiveMigrations,
|
|
18320
|
+
cellsViewMigration: () => cellsViewMigration,
|
|
18319
18321
|
beadsMigrations: () => beadsMigrations,
|
|
18320
18322
|
beadsMigration: () => beadsMigration
|
|
18321
18323
|
});
|
|
18322
|
-
var beadsMigration, beadsMigrations;
|
|
18324
|
+
var beadsMigration, cellsViewMigration, beadsMigrations, hiveMigrations;
|
|
18323
18325
|
var init_migrations2 = __esm(() => {
|
|
18324
18326
|
beadsMigration = {
|
|
18325
18327
|
version: 6,
|
|
@@ -18363,15 +18365,15 @@ var init_migrations2 = __esm(() => {
|
|
|
18363
18365
|
-- Dependencies Table
|
|
18364
18366
|
-- ========================================================================
|
|
18365
18367
|
CREATE TABLE IF NOT EXISTS bead_dependencies (
|
|
18366
|
-
|
|
18368
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18367
18369
|
depends_on_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18368
18370
|
relationship TEXT NOT NULL CHECK (relationship IN ('blocks', 'related', 'parent-child', 'discovered-from', 'replies-to', 'relates-to', 'duplicates', 'supersedes')),
|
|
18369
18371
|
created_at BIGINT NOT NULL,
|
|
18370
18372
|
created_by TEXT,
|
|
18371
|
-
PRIMARY KEY (
|
|
18373
|
+
PRIMARY KEY (cell_id, depends_on_id, relationship)
|
|
18372
18374
|
);
|
|
18373
18375
|
|
|
18374
|
-
CREATE INDEX IF NOT EXISTS idx_bead_deps_bead ON bead_dependencies(
|
|
18376
|
+
CREATE INDEX IF NOT EXISTS idx_bead_deps_bead ON bead_dependencies(cell_id);
|
|
18375
18377
|
CREATE INDEX IF NOT EXISTS idx_bead_deps_depends_on ON bead_dependencies(depends_on_id);
|
|
18376
18378
|
CREATE INDEX IF NOT EXISTS idx_bead_deps_relationship ON bead_dependencies(relationship);
|
|
18377
18379
|
|
|
@@ -18379,10 +18381,10 @@ var init_migrations2 = __esm(() => {
|
|
|
18379
18381
|
-- Labels Table
|
|
18380
18382
|
-- ========================================================================
|
|
18381
18383
|
CREATE TABLE IF NOT EXISTS bead_labels (
|
|
18382
|
-
|
|
18384
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18383
18385
|
label TEXT NOT NULL,
|
|
18384
18386
|
created_at BIGINT NOT NULL,
|
|
18385
|
-
PRIMARY KEY (
|
|
18387
|
+
PRIMARY KEY (cell_id, label)
|
|
18386
18388
|
);
|
|
18387
18389
|
|
|
18388
18390
|
CREATE INDEX IF NOT EXISTS idx_bead_labels_label ON bead_labels(label);
|
|
@@ -18392,7 +18394,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18392
18394
|
-- ========================================================================
|
|
18393
18395
|
CREATE TABLE IF NOT EXISTS bead_comments (
|
|
18394
18396
|
id SERIAL PRIMARY KEY,
|
|
18395
|
-
|
|
18397
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18396
18398
|
author TEXT NOT NULL,
|
|
18397
18399
|
body TEXT NOT NULL,
|
|
18398
18400
|
parent_id INTEGER REFERENCES bead_comments(id) ON DELETE CASCADE,
|
|
@@ -18400,7 +18402,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18400
18402
|
updated_at BIGINT
|
|
18401
18403
|
);
|
|
18402
18404
|
|
|
18403
|
-
CREATE INDEX IF NOT EXISTS idx_bead_comments_bead ON bead_comments(
|
|
18405
|
+
CREATE INDEX IF NOT EXISTS idx_bead_comments_bead ON bead_comments(cell_id);
|
|
18404
18406
|
CREATE INDEX IF NOT EXISTS idx_bead_comments_author ON bead_comments(author);
|
|
18405
18407
|
CREATE INDEX IF NOT EXISTS idx_bead_comments_created ON bead_comments(created_at);
|
|
18406
18408
|
|
|
@@ -18410,7 +18412,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18410
18412
|
-- Materialized view for fast blocked queries
|
|
18411
18413
|
-- Updated by projections when dependencies change
|
|
18412
18414
|
CREATE TABLE IF NOT EXISTS blocked_beads_cache (
|
|
18413
|
-
|
|
18415
|
+
cell_id TEXT PRIMARY KEY REFERENCES beads(id) ON DELETE CASCADE,
|
|
18414
18416
|
blocker_ids TEXT[] NOT NULL,
|
|
18415
18417
|
updated_at BIGINT NOT NULL
|
|
18416
18418
|
);
|
|
@@ -18422,7 +18424,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18422
18424
|
-- ========================================================================
|
|
18423
18425
|
-- Tracks beads that need JSONL export (incremental sync)
|
|
18424
18426
|
CREATE TABLE IF NOT EXISTS dirty_beads (
|
|
18425
|
-
|
|
18427
|
+
cell_id TEXT PRIMARY KEY REFERENCES beads(id) ON DELETE CASCADE,
|
|
18426
18428
|
marked_at BIGINT NOT NULL
|
|
18427
18429
|
);
|
|
18428
18430
|
|
|
@@ -18438,7 +18440,90 @@ var init_migrations2 = __esm(() => {
|
|
|
18438
18440
|
DROP TABLE IF EXISTS beads;
|
|
18439
18441
|
`
|
|
18440
18442
|
};
|
|
18443
|
+
cellsViewMigration = {
|
|
18444
|
+
version: 7,
|
|
18445
|
+
description: "Add cells view for beads→hive rename compatibility",
|
|
18446
|
+
up: `
|
|
18447
|
+
-- ========================================================================
|
|
18448
|
+
-- Cells View (alias for beads table)
|
|
18449
|
+
-- ========================================================================
|
|
18450
|
+
-- This view allows code to reference "cells" while data lives in "beads"
|
|
18451
|
+
CREATE OR REPLACE VIEW cells AS SELECT * FROM beads;
|
|
18452
|
+
|
|
18453
|
+
-- INSTEAD OF INSERT trigger
|
|
18454
|
+
CREATE OR REPLACE FUNCTION cells_insert_trigger()
|
|
18455
|
+
RETURNS TRIGGER AS $$
|
|
18456
|
+
BEGIN
|
|
18457
|
+
INSERT INTO beads VALUES (NEW.*);
|
|
18458
|
+
RETURN NEW;
|
|
18459
|
+
END;
|
|
18460
|
+
$$ LANGUAGE plpgsql;
|
|
18461
|
+
|
|
18462
|
+
DROP TRIGGER IF EXISTS cells_insert ON cells;
|
|
18463
|
+
CREATE TRIGGER cells_insert
|
|
18464
|
+
INSTEAD OF INSERT ON cells
|
|
18465
|
+
FOR EACH ROW
|
|
18466
|
+
EXECUTE FUNCTION cells_insert_trigger();
|
|
18467
|
+
|
|
18468
|
+
-- INSTEAD OF UPDATE trigger
|
|
18469
|
+
CREATE OR REPLACE FUNCTION cells_update_trigger()
|
|
18470
|
+
RETURNS TRIGGER AS $$
|
|
18471
|
+
BEGIN
|
|
18472
|
+
UPDATE beads SET
|
|
18473
|
+
project_key = NEW.project_key,
|
|
18474
|
+
type = NEW.type,
|
|
18475
|
+
status = NEW.status,
|
|
18476
|
+
title = NEW.title,
|
|
18477
|
+
description = NEW.description,
|
|
18478
|
+
priority = NEW.priority,
|
|
18479
|
+
parent_id = NEW.parent_id,
|
|
18480
|
+
assignee = NEW.assignee,
|
|
18481
|
+
created_at = NEW.created_at,
|
|
18482
|
+
updated_at = NEW.updated_at,
|
|
18483
|
+
closed_at = NEW.closed_at,
|
|
18484
|
+
closed_reason = NEW.closed_reason,
|
|
18485
|
+
deleted_at = NEW.deleted_at,
|
|
18486
|
+
deleted_by = NEW.deleted_by,
|
|
18487
|
+
delete_reason = NEW.delete_reason,
|
|
18488
|
+
created_by = NEW.created_by
|
|
18489
|
+
WHERE id = OLD.id;
|
|
18490
|
+
RETURN NEW;
|
|
18491
|
+
END;
|
|
18492
|
+
$$ LANGUAGE plpgsql;
|
|
18493
|
+
|
|
18494
|
+
DROP TRIGGER IF EXISTS cells_update ON cells;
|
|
18495
|
+
CREATE TRIGGER cells_update
|
|
18496
|
+
INSTEAD OF UPDATE ON cells
|
|
18497
|
+
FOR EACH ROW
|
|
18498
|
+
EXECUTE FUNCTION cells_update_trigger();
|
|
18499
|
+
|
|
18500
|
+
-- INSTEAD OF DELETE trigger
|
|
18501
|
+
CREATE OR REPLACE FUNCTION cells_delete_trigger()
|
|
18502
|
+
RETURNS TRIGGER AS $$
|
|
18503
|
+
BEGIN
|
|
18504
|
+
DELETE FROM beads WHERE id = OLD.id;
|
|
18505
|
+
RETURN OLD;
|
|
18506
|
+
END;
|
|
18507
|
+
$$ LANGUAGE plpgsql;
|
|
18508
|
+
|
|
18509
|
+
DROP TRIGGER IF EXISTS cells_delete ON cells;
|
|
18510
|
+
CREATE TRIGGER cells_delete
|
|
18511
|
+
INSTEAD OF DELETE ON cells
|
|
18512
|
+
FOR EACH ROW
|
|
18513
|
+
EXECUTE FUNCTION cells_delete_trigger();
|
|
18514
|
+
`,
|
|
18515
|
+
down: `
|
|
18516
|
+
DROP TRIGGER IF EXISTS cells_delete ON cells;
|
|
18517
|
+
DROP TRIGGER IF EXISTS cells_update ON cells;
|
|
18518
|
+
DROP TRIGGER IF EXISTS cells_insert ON cells;
|
|
18519
|
+
DROP FUNCTION IF EXISTS cells_delete_trigger();
|
|
18520
|
+
DROP FUNCTION IF EXISTS cells_update_trigger();
|
|
18521
|
+
DROP FUNCTION IF EXISTS cells_insert_trigger();
|
|
18522
|
+
DROP VIEW IF EXISTS cells;
|
|
18523
|
+
`
|
|
18524
|
+
};
|
|
18441
18525
|
beadsMigrations = [beadsMigration];
|
|
18526
|
+
hiveMigrations = [beadsMigration, cellsViewMigration];
|
|
18442
18527
|
});
|
|
18443
18528
|
|
|
18444
18529
|
// src/adapter.ts
|
|
@@ -18572,10 +18657,10 @@ function createSwarmMailAdapter(db, projectKey) {
|
|
|
18572
18657
|
}
|
|
18573
18658
|
// src/pglite.ts
|
|
18574
18659
|
import { PGlite as PGlite2 } from "@electric-sql/pglite";
|
|
18575
|
-
import { existsSync as existsSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
18576
|
-
import { join as join4, basename } from "node:path";
|
|
18577
|
-
import { tmpdir as tmpdir2 } from "node:os";
|
|
18578
18660
|
import { createHash } from "node:crypto";
|
|
18661
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync4, rmSync } from "node:fs";
|
|
18662
|
+
import { basename, join as join4 } from "node:path";
|
|
18663
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
18579
18664
|
|
|
18580
18665
|
// src/socket-adapter.ts
|
|
18581
18666
|
import postgres from "postgres";
|
|
@@ -18827,6 +18912,36 @@ function getDatabasePath2(projectPath) {
|
|
|
18827
18912
|
return join4(globalTmpDir, "streams");
|
|
18828
18913
|
}
|
|
18829
18914
|
var instances2 = new Map;
|
|
18915
|
+
function isWasmAbortError(error45) {
|
|
18916
|
+
if (error45 instanceof Error) {
|
|
18917
|
+
const message = error45.message.toLowerCase();
|
|
18918
|
+
return message.includes("aborted") || message.includes("unreachable code") || message.includes("runtimeerror");
|
|
18919
|
+
}
|
|
18920
|
+
return false;
|
|
18921
|
+
}
|
|
18922
|
+
async function createPGliteWithRecovery(dbPath) {
|
|
18923
|
+
try {
|
|
18924
|
+
const pglite = new PGlite2(dbPath);
|
|
18925
|
+
await pglite.query("SELECT 1");
|
|
18926
|
+
return pglite;
|
|
18927
|
+
} catch (error45) {
|
|
18928
|
+
if (isWasmAbortError(error45)) {
|
|
18929
|
+
console.warn(`[swarm-mail] PGLite WASM abort detected, recovering by deleting corrupted database: ${dbPath}`);
|
|
18930
|
+
if (existsSync4(dbPath)) {
|
|
18931
|
+
rmSync(dbPath, { recursive: true, force: true });
|
|
18932
|
+
}
|
|
18933
|
+
try {
|
|
18934
|
+
const pglite = new PGlite2(dbPath);
|
|
18935
|
+
await pglite.query("SELECT 1");
|
|
18936
|
+
console.log("[swarm-mail] Successfully recovered from corrupted database");
|
|
18937
|
+
return pglite;
|
|
18938
|
+
} catch (retryError) {
|
|
18939
|
+
throw new Error(`Failed to recover PGLite database after deleting corrupted data: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
|
|
18940
|
+
}
|
|
18941
|
+
}
|
|
18942
|
+
throw error45;
|
|
18943
|
+
}
|
|
18944
|
+
}
|
|
18830
18945
|
async function getSwarmMail(projectPath) {
|
|
18831
18946
|
const dbPath = getDatabasePath2(projectPath);
|
|
18832
18947
|
const projectKey = projectPath || dbPath;
|
|
@@ -18841,7 +18956,7 @@ async function getSwarmMail(projectPath) {
|
|
|
18841
18956
|
console.warn(`[swarm-mail] Socket mode failed, falling back to embedded PGLite: ${error45 instanceof Error ? error45.message : String(error45)}`);
|
|
18842
18957
|
}
|
|
18843
18958
|
}
|
|
18844
|
-
const pglite =
|
|
18959
|
+
const pglite = await createPGliteWithRecovery(dbPath);
|
|
18845
18960
|
const db = wrapPGlite(pglite);
|
|
18846
18961
|
const adapter = createSwarmMailAdapter(db, projectKey);
|
|
18847
18962
|
await adapter.runMigrations();
|
|
@@ -18912,74 +19027,74 @@ async function closeAllSwarmMail() {
|
|
|
18912
19027
|
// src/index.ts
|
|
18913
19028
|
init_streams();
|
|
18914
19029
|
|
|
18915
|
-
// src/
|
|
19030
|
+
// src/hive/store.ts
|
|
18916
19031
|
init_streams();
|
|
18917
19032
|
|
|
18918
|
-
// src/
|
|
19033
|
+
// src/hive/projections.ts
|
|
18919
19034
|
async function updateProjections(db, event) {
|
|
18920
19035
|
switch (event.type) {
|
|
18921
|
-
case "
|
|
19036
|
+
case "cell_created":
|
|
18922
19037
|
await handleBeadCreated(db, event);
|
|
18923
19038
|
break;
|
|
18924
|
-
case "
|
|
19039
|
+
case "cell_updated":
|
|
18925
19040
|
await handleBeadUpdated(db, event);
|
|
18926
19041
|
break;
|
|
18927
|
-
case "
|
|
18928
|
-
await
|
|
19042
|
+
case "cell_status_changed":
|
|
19043
|
+
await handleCellStatusChanged(db, event);
|
|
18929
19044
|
break;
|
|
18930
|
-
case "
|
|
19045
|
+
case "cell_closed":
|
|
18931
19046
|
await handleBeadClosed(db, event);
|
|
18932
19047
|
break;
|
|
18933
|
-
case "
|
|
19048
|
+
case "cell_reopened":
|
|
18934
19049
|
await handleBeadReopened(db, event);
|
|
18935
19050
|
break;
|
|
18936
|
-
case "
|
|
19051
|
+
case "cell_deleted":
|
|
18937
19052
|
await handleBeadDeleted(db, event);
|
|
18938
19053
|
break;
|
|
18939
|
-
case "
|
|
19054
|
+
case "cell_dependency_added":
|
|
18940
19055
|
await handleDependencyAdded(db, event);
|
|
18941
19056
|
break;
|
|
18942
|
-
case "
|
|
19057
|
+
case "cell_dependency_removed":
|
|
18943
19058
|
await handleDependencyRemoved(db, event);
|
|
18944
19059
|
break;
|
|
18945
|
-
case "
|
|
19060
|
+
case "cell_label_added":
|
|
18946
19061
|
await handleLabelAdded(db, event);
|
|
18947
19062
|
break;
|
|
18948
|
-
case "
|
|
19063
|
+
case "cell_label_removed":
|
|
18949
19064
|
await handleLabelRemoved(db, event);
|
|
18950
19065
|
break;
|
|
18951
|
-
case "
|
|
19066
|
+
case "cell_comment_added":
|
|
18952
19067
|
await handleCommentAdded(db, event);
|
|
18953
19068
|
break;
|
|
18954
|
-
case "
|
|
19069
|
+
case "cell_comment_updated":
|
|
18955
19070
|
await handleCommentUpdated(db, event);
|
|
18956
19071
|
break;
|
|
18957
|
-
case "
|
|
19072
|
+
case "cell_comment_deleted":
|
|
18958
19073
|
await handleCommentDeleted(db, event);
|
|
18959
19074
|
break;
|
|
18960
|
-
case "
|
|
19075
|
+
case "cell_epic_child_added":
|
|
18961
19076
|
await handleEpicChildAdded(db, event);
|
|
18962
19077
|
break;
|
|
18963
|
-
case "
|
|
19078
|
+
case "cell_epic_child_removed":
|
|
18964
19079
|
await handleEpicChildRemoved(db, event);
|
|
18965
19080
|
break;
|
|
18966
|
-
case "
|
|
19081
|
+
case "cell_assigned":
|
|
18967
19082
|
await handleBeadAssigned(db, event);
|
|
18968
19083
|
break;
|
|
18969
|
-
case "
|
|
19084
|
+
case "cell_work_started":
|
|
18970
19085
|
await handleWorkStarted(db, event);
|
|
18971
19086
|
break;
|
|
18972
19087
|
default:
|
|
18973
19088
|
console.warn(`[beads/projections] Unknown event type: ${event.type}`);
|
|
18974
19089
|
}
|
|
18975
|
-
await markBeadDirty(db, event.project_key, event.
|
|
19090
|
+
await markBeadDirty(db, event.project_key, event.cell_id);
|
|
18976
19091
|
}
|
|
18977
19092
|
async function handleBeadCreated(db, event) {
|
|
18978
19093
|
await db.query(`INSERT INTO beads (
|
|
18979
19094
|
id, project_key, type, status, title, description, priority,
|
|
18980
19095
|
parent_id, assignee, created_at, updated_at, created_by
|
|
18981
19096
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [
|
|
18982
|
-
event.
|
|
19097
|
+
event.cell_id,
|
|
18983
19098
|
event.project_key,
|
|
18984
19099
|
event.issue_type,
|
|
18985
19100
|
"open",
|
|
@@ -19017,12 +19132,12 @@ async function handleBeadUpdated(db, event) {
|
|
|
19017
19132
|
if (updates.length > 0) {
|
|
19018
19133
|
updates.push(`updated_at = $${paramIndex++}`);
|
|
19019
19134
|
params.push(event.timestamp);
|
|
19020
|
-
params.push(event.
|
|
19135
|
+
params.push(event.cell_id);
|
|
19021
19136
|
await db.query(`UPDATE beads SET ${updates.join(", ")} WHERE id = $${paramIndex}`, params);
|
|
19022
19137
|
}
|
|
19023
19138
|
}
|
|
19024
|
-
async function
|
|
19025
|
-
await db.query(`UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3`, [event.to_status, event.timestamp, event.
|
|
19139
|
+
async function handleCellStatusChanged(db, event) {
|
|
19140
|
+
await db.query(`UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3`, [event.to_status, event.timestamp, event.cell_id]);
|
|
19026
19141
|
}
|
|
19027
19142
|
async function handleBeadClosed(db, event) {
|
|
19028
19143
|
await db.query(`UPDATE beads SET
|
|
@@ -19030,9 +19145,9 @@ async function handleBeadClosed(db, event) {
|
|
|
19030
19145
|
closed_at = $1,
|
|
19031
19146
|
closed_reason = $2,
|
|
19032
19147
|
updated_at = $3
|
|
19033
|
-
WHERE id = $4`, [event.timestamp, event.reason, event.timestamp, event.
|
|
19148
|
+
WHERE id = $4`, [event.timestamp, event.reason, event.timestamp, event.cell_id]);
|
|
19034
19149
|
const { invalidateBlockedCache: invalidateBlockedCache2 } = await Promise.resolve().then(() => exports_dependencies);
|
|
19035
|
-
await invalidateBlockedCache2(db, event.project_key, event.
|
|
19150
|
+
await invalidateBlockedCache2(db, event.project_key, event.cell_id);
|
|
19036
19151
|
}
|
|
19037
19152
|
async function handleBeadReopened(db, event) {
|
|
19038
19153
|
await db.query(`UPDATE beads SET
|
|
@@ -19040,7 +19155,7 @@ async function handleBeadReopened(db, event) {
|
|
|
19040
19155
|
closed_at = NULL,
|
|
19041
19156
|
closed_reason = NULL,
|
|
19042
19157
|
updated_at = $1
|
|
19043
|
-
WHERE id = $2`, [event.timestamp, event.
|
|
19158
|
+
WHERE id = $2`, [event.timestamp, event.cell_id]);
|
|
19044
19159
|
}
|
|
19045
19160
|
async function handleBeadDeleted(db, event) {
|
|
19046
19161
|
await db.query(`UPDATE beads SET
|
|
@@ -19048,34 +19163,34 @@ async function handleBeadDeleted(db, event) {
|
|
|
19048
19163
|
deleted_by = $2,
|
|
19049
19164
|
delete_reason = $3,
|
|
19050
19165
|
updated_at = $4
|
|
19051
|
-
WHERE id = $5`, [event.timestamp, event.deleted_by || null, event.reason || null, event.timestamp, event.
|
|
19166
|
+
WHERE id = $5`, [event.timestamp, event.deleted_by || null, event.reason || null, event.timestamp, event.cell_id]);
|
|
19052
19167
|
}
|
|
19053
19168
|
async function handleDependencyAdded(db, event) {
|
|
19054
19169
|
const dep = event.dependency;
|
|
19055
|
-
await db.query(`INSERT INTO bead_dependencies (
|
|
19170
|
+
await db.query(`INSERT INTO bead_dependencies (cell_id, depends_on_id, relationship, created_at, created_by)
|
|
19056
19171
|
VALUES ($1, $2, $3, $4, $5)
|
|
19057
|
-
ON CONFLICT (
|
|
19172
|
+
ON CONFLICT (cell_id, depends_on_id, relationship) DO NOTHING`, [event.cell_id, dep.target, dep.type, event.timestamp, event.added_by || null]);
|
|
19058
19173
|
const { invalidateBlockedCache: invalidate } = await Promise.resolve().then(() => exports_dependencies);
|
|
19059
|
-
await invalidate(db, event.project_key, event.
|
|
19174
|
+
await invalidate(db, event.project_key, event.cell_id);
|
|
19060
19175
|
}
|
|
19061
19176
|
async function handleDependencyRemoved(db, event) {
|
|
19062
19177
|
const dep = event.dependency;
|
|
19063
19178
|
await db.query(`DELETE FROM bead_dependencies
|
|
19064
|
-
WHERE
|
|
19179
|
+
WHERE cell_id = $1 AND depends_on_id = $2 AND relationship = $3`, [event.cell_id, dep.target, dep.type]);
|
|
19065
19180
|
const { invalidateBlockedCache: invalidate } = await Promise.resolve().then(() => exports_dependencies);
|
|
19066
|
-
await invalidate(db, event.project_key, event.
|
|
19181
|
+
await invalidate(db, event.project_key, event.cell_id);
|
|
19067
19182
|
}
|
|
19068
19183
|
async function handleLabelAdded(db, event) {
|
|
19069
|
-
await db.query(`INSERT INTO bead_labels (
|
|
19184
|
+
await db.query(`INSERT INTO bead_labels (cell_id, label, created_at)
|
|
19070
19185
|
VALUES ($1, $2, $3)
|
|
19071
|
-
ON CONFLICT (
|
|
19186
|
+
ON CONFLICT (cell_id, label) DO NOTHING`, [event.cell_id, event.label, event.timestamp]);
|
|
19072
19187
|
}
|
|
19073
19188
|
async function handleLabelRemoved(db, event) {
|
|
19074
|
-
await db.query(`DELETE FROM bead_labels WHERE
|
|
19189
|
+
await db.query(`DELETE FROM bead_labels WHERE cell_id = $1 AND label = $2`, [event.cell_id, event.label]);
|
|
19075
19190
|
}
|
|
19076
19191
|
async function handleCommentAdded(db, event) {
|
|
19077
|
-
await db.query(`INSERT INTO bead_comments (
|
|
19078
|
-
VALUES ($1, $2, $3, $4, $5)`, [event.
|
|
19192
|
+
await db.query(`INSERT INTO bead_comments (cell_id, author, body, parent_id, created_at)
|
|
19193
|
+
VALUES ($1, $2, $3, $4, $5)`, [event.cell_id, event.author, event.body, event.parent_comment_id || null, event.timestamp]);
|
|
19079
19194
|
}
|
|
19080
19195
|
async function handleCommentUpdated(db, event) {
|
|
19081
19196
|
await db.query(`UPDATE bead_comments SET body = $1, updated_at = $2 WHERE id = $3`, [event.new_body, event.timestamp, event.comment_id]);
|
|
@@ -19084,22 +19199,22 @@ async function handleCommentDeleted(db, event) {
|
|
|
19084
19199
|
await db.query(`DELETE FROM bead_comments WHERE id = $1`, [event.comment_id]);
|
|
19085
19200
|
}
|
|
19086
19201
|
async function handleEpicChildAdded(db, event) {
|
|
19087
|
-
await db.query(`UPDATE beads SET parent_id = $1, updated_at = $2 WHERE id = $3`, [event.
|
|
19202
|
+
await db.query(`UPDATE beads SET parent_id = $1, updated_at = $2 WHERE id = $3`, [event.cell_id, event.timestamp, event.child_id]);
|
|
19088
19203
|
}
|
|
19089
19204
|
async function handleEpicChildRemoved(db, event) {
|
|
19090
19205
|
await db.query(`UPDATE beads SET parent_id = NULL, updated_at = $1 WHERE id = $2`, [event.timestamp, event.child_id]);
|
|
19091
19206
|
}
|
|
19092
19207
|
async function handleBeadAssigned(db, event) {
|
|
19093
|
-
await db.query(`UPDATE beads SET assignee = $1, updated_at = $2 WHERE id = $3`, [event.assignee, event.timestamp, event.
|
|
19208
|
+
await db.query(`UPDATE beads SET assignee = $1, updated_at = $2 WHERE id = $3`, [event.assignee, event.timestamp, event.cell_id]);
|
|
19094
19209
|
}
|
|
19095
19210
|
async function handleWorkStarted(db, event) {
|
|
19096
|
-
await db.query(`UPDATE beads SET status = 'in_progress', updated_at = $1 WHERE id = $2`, [event.timestamp, event.
|
|
19211
|
+
await db.query(`UPDATE beads SET status = 'in_progress', updated_at = $1 WHERE id = $2`, [event.timestamp, event.cell_id]);
|
|
19097
19212
|
}
|
|
19098
|
-
async function
|
|
19099
|
-
const result = await db.query(`SELECT * FROM beads WHERE project_key = $1 AND id = $2 AND deleted_at IS NULL`, [projectKey,
|
|
19213
|
+
async function getCell(db, projectKey, cellId) {
|
|
19214
|
+
const result = await db.query(`SELECT * FROM beads WHERE project_key = $1 AND id = $2 AND deleted_at IS NULL`, [projectKey, cellId]);
|
|
19100
19215
|
return result.rows[0] ?? null;
|
|
19101
19216
|
}
|
|
19102
|
-
async function
|
|
19217
|
+
async function queryCells(db, projectKey, options = {}) {
|
|
19103
19218
|
const conditions = ["project_key = $1"];
|
|
19104
19219
|
const params = [projectKey];
|
|
19105
19220
|
let paramIndex = 2;
|
|
@@ -19136,81 +19251,81 @@ async function queryBeads(db, projectKey, options = {}) {
|
|
|
19136
19251
|
const result = await db.query(query, params);
|
|
19137
19252
|
return result.rows;
|
|
19138
19253
|
}
|
|
19139
|
-
async function getDependencies(db, projectKey,
|
|
19140
|
-
const result = await db.query(`SELECT * FROM bead_dependencies WHERE
|
|
19254
|
+
async function getDependencies(db, projectKey, cellId) {
|
|
19255
|
+
const result = await db.query(`SELECT * FROM bead_dependencies WHERE cell_id = $1`, [cellId]);
|
|
19141
19256
|
return result.rows;
|
|
19142
19257
|
}
|
|
19143
|
-
async function getDependents(db, projectKey,
|
|
19144
|
-
const result = await db.query(`SELECT * FROM bead_dependencies WHERE depends_on_id = $1`, [
|
|
19258
|
+
async function getDependents(db, projectKey, cellId) {
|
|
19259
|
+
const result = await db.query(`SELECT * FROM bead_dependencies WHERE depends_on_id = $1`, [cellId]);
|
|
19145
19260
|
return result.rows;
|
|
19146
19261
|
}
|
|
19147
|
-
async function isBlocked(db, projectKey,
|
|
19148
|
-
const result = await db.query(`SELECT EXISTS(SELECT 1 FROM blocked_beads_cache WHERE
|
|
19262
|
+
async function isBlocked(db, projectKey, cellId) {
|
|
19263
|
+
const result = await db.query(`SELECT EXISTS(SELECT 1 FROM blocked_beads_cache WHERE cell_id = $1) as exists`, [cellId]);
|
|
19149
19264
|
return result.rows[0]?.exists ?? false;
|
|
19150
19265
|
}
|
|
19151
|
-
async function getBlockers(db, projectKey,
|
|
19152
|
-
const result = await db.query(`SELECT blocker_ids FROM blocked_beads_cache WHERE
|
|
19266
|
+
async function getBlockers(db, projectKey, cellId) {
|
|
19267
|
+
const result = await db.query(`SELECT blocker_ids FROM blocked_beads_cache WHERE cell_id = $1`, [cellId]);
|
|
19153
19268
|
return result.rows[0]?.blocker_ids ?? [];
|
|
19154
19269
|
}
|
|
19155
|
-
async function getLabels(db, projectKey,
|
|
19156
|
-
const result = await db.query(`SELECT label FROM bead_labels WHERE
|
|
19270
|
+
async function getLabels(db, projectKey, cellId) {
|
|
19271
|
+
const result = await db.query(`SELECT label FROM bead_labels WHERE cell_id = $1 ORDER BY label`, [cellId]);
|
|
19157
19272
|
return result.rows.map((r) => r.label);
|
|
19158
19273
|
}
|
|
19159
|
-
async function getComments(db, projectKey,
|
|
19160
|
-
const result = await db.query(`SELECT * FROM bead_comments WHERE
|
|
19274
|
+
async function getComments(db, projectKey, cellId) {
|
|
19275
|
+
const result = await db.query(`SELECT * FROM bead_comments WHERE cell_id = $1 ORDER BY created_at ASC`, [cellId]);
|
|
19161
19276
|
return result.rows;
|
|
19162
19277
|
}
|
|
19163
|
-
async function
|
|
19278
|
+
async function getNextReadyCell(db, projectKey) {
|
|
19164
19279
|
const result = await db.query(`SELECT b.* FROM beads b
|
|
19165
19280
|
WHERE b.project_key = $1
|
|
19166
19281
|
AND b.status = 'open'
|
|
19167
19282
|
AND b.deleted_at IS NULL
|
|
19168
19283
|
AND NOT EXISTS (
|
|
19169
|
-
SELECT 1 FROM blocked_beads_cache bbc WHERE bbc.
|
|
19284
|
+
SELECT 1 FROM blocked_beads_cache bbc WHERE bbc.cell_id = b.id
|
|
19170
19285
|
)
|
|
19171
19286
|
ORDER BY b.priority DESC, b.created_at ASC
|
|
19172
19287
|
LIMIT 1`, [projectKey]);
|
|
19173
19288
|
return result.rows[0] ?? null;
|
|
19174
19289
|
}
|
|
19175
|
-
async function
|
|
19290
|
+
async function getInProgressCells(db, projectKey) {
|
|
19176
19291
|
const result = await db.query(`SELECT * FROM beads
|
|
19177
19292
|
WHERE project_key = $1 AND status = 'in_progress' AND deleted_at IS NULL
|
|
19178
19293
|
ORDER BY priority DESC, created_at ASC`, [projectKey]);
|
|
19179
19294
|
return result.rows;
|
|
19180
19295
|
}
|
|
19181
|
-
async function
|
|
19296
|
+
async function getBlockedCells(db, projectKey) {
|
|
19182
19297
|
const result = await db.query(`SELECT b.*, bbc.blocker_ids
|
|
19183
19298
|
FROM beads b
|
|
19184
|
-
JOIN blocked_beads_cache bbc ON b.id =
|
|
19299
|
+
JOIN blocked_beads_cache bbc ON b.id = bcc.cell_id
|
|
19185
19300
|
WHERE b.project_key = $1 AND b.deleted_at IS NULL
|
|
19186
19301
|
ORDER BY b.priority DESC, b.created_at ASC`, [projectKey]);
|
|
19187
19302
|
return result.rows.map((r) => {
|
|
19188
|
-
const { blocker_ids, ...
|
|
19189
|
-
return {
|
|
19303
|
+
const { blocker_ids, ...cellData } = r;
|
|
19304
|
+
return { cell: cellData, blockers: blocker_ids };
|
|
19190
19305
|
});
|
|
19191
19306
|
}
|
|
19192
|
-
async function markBeadDirty(db, projectKey,
|
|
19193
|
-
await db.query(`INSERT INTO dirty_beads (
|
|
19307
|
+
async function markBeadDirty(db, projectKey, cellId) {
|
|
19308
|
+
await db.query(`INSERT INTO dirty_beads (cell_id, marked_at)
|
|
19194
19309
|
VALUES ($1, $2)
|
|
19195
|
-
ON CONFLICT (
|
|
19310
|
+
ON CONFLICT (cell_id) DO UPDATE SET marked_at = $2`, [cellId, Date.now()]);
|
|
19196
19311
|
}
|
|
19197
|
-
async function
|
|
19198
|
-
const result = await db.query(`SELECT db.
|
|
19199
|
-
JOIN beads b ON db.
|
|
19312
|
+
async function getDirtyCells(db, projectKey) {
|
|
19313
|
+
const result = await db.query(`SELECT db.cell_id FROM dirty_beads db
|
|
19314
|
+
JOIN beads b ON db.cell_id = b.id
|
|
19200
19315
|
WHERE b.project_key = $1
|
|
19201
19316
|
ORDER BY db.marked_at ASC`, [projectKey]);
|
|
19202
|
-
return result.rows.map((r) => r.
|
|
19317
|
+
return result.rows.map((r) => r.cell_id);
|
|
19203
19318
|
}
|
|
19204
|
-
async function clearDirtyBead(db, projectKey,
|
|
19205
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19319
|
+
async function clearDirtyBead(db, projectKey, cellId) {
|
|
19320
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id = $1`, [cellId]);
|
|
19206
19321
|
}
|
|
19207
19322
|
async function clearAllDirtyBeads(db, projectKey) {
|
|
19208
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19323
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id IN (
|
|
19209
19324
|
SELECT id FROM beads WHERE project_key = $1
|
|
19210
19325
|
)`, [projectKey]);
|
|
19211
19326
|
}
|
|
19212
19327
|
|
|
19213
|
-
// src/
|
|
19328
|
+
// src/hive/store.ts
|
|
19214
19329
|
function parseTimestamp2(timestamp) {
|
|
19215
19330
|
const ts = parseInt(timestamp, 10);
|
|
19216
19331
|
if (Number.isNaN(ts)) {
|
|
@@ -19221,7 +19336,7 @@ function parseTimestamp2(timestamp) {
|
|
|
19221
19336
|
}
|
|
19222
19337
|
return ts;
|
|
19223
19338
|
}
|
|
19224
|
-
async function
|
|
19339
|
+
async function appendCellEvent(event, projectPath, dbOverride) {
|
|
19225
19340
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19226
19341
|
const { type, project_key, timestamp, ...rest } = event;
|
|
19227
19342
|
const result = await db.query(`INSERT INTO events (type, project_key, timestamp, data)
|
|
@@ -19235,20 +19350,20 @@ async function appendBeadEvent(event, projectPath, dbOverride) {
|
|
|
19235
19350
|
await updateProjections(db, { ...event, id, sequence });
|
|
19236
19351
|
return { ...event, id, sequence };
|
|
19237
19352
|
}
|
|
19238
|
-
async function
|
|
19239
|
-
return withTiming("
|
|
19353
|
+
async function readCellEvents(options = {}, projectPath, dbOverride) {
|
|
19354
|
+
return withTiming("readCellEvents", async () => {
|
|
19240
19355
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19241
19356
|
const conditions = [];
|
|
19242
19357
|
const params = [];
|
|
19243
19358
|
let paramIndex = 1;
|
|
19244
|
-
conditions.push(`type LIKE '
|
|
19359
|
+
conditions.push(`type LIKE 'cell_%'`);
|
|
19245
19360
|
if (options.projectKey) {
|
|
19246
19361
|
conditions.push(`project_key = $${paramIndex++}`);
|
|
19247
19362
|
params.push(options.projectKey);
|
|
19248
19363
|
}
|
|
19249
|
-
if (options.
|
|
19250
|
-
conditions.push(`data->>'
|
|
19251
|
-
params.push(options.
|
|
19364
|
+
if (options.cellId) {
|
|
19365
|
+
conditions.push(`data->>'cell_id' = $${paramIndex++}`);
|
|
19366
|
+
params.push(options.cellId);
|
|
19252
19367
|
}
|
|
19253
19368
|
if (options.types && options.types.length > 0) {
|
|
19254
19369
|
conditions.push(`type = ANY($${paramIndex++})`);
|
|
@@ -19295,25 +19410,25 @@ async function readBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19295
19410
|
});
|
|
19296
19411
|
});
|
|
19297
19412
|
}
|
|
19298
|
-
async function
|
|
19299
|
-
return withTiming("
|
|
19413
|
+
async function replayCellEvents(options = {}, projectPath, dbOverride) {
|
|
19414
|
+
return withTiming("replayCellEvents", async () => {
|
|
19300
19415
|
const startTime = Date.now();
|
|
19301
19416
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19302
19417
|
if (options.clearViews) {
|
|
19303
19418
|
if (options.projectKey) {
|
|
19304
|
-
await db.query(`DELETE FROM bead_comments WHERE
|
|
19419
|
+
await db.query(`DELETE FROM bead_comments WHERE cell_id IN (
|
|
19305
19420
|
SELECT id FROM beads WHERE project_key = $1
|
|
19306
19421
|
)`, [options.projectKey]);
|
|
19307
|
-
await db.query(`DELETE FROM bead_labels WHERE
|
|
19422
|
+
await db.query(`DELETE FROM bead_labels WHERE cell_id IN (
|
|
19308
19423
|
SELECT id FROM beads WHERE project_key = $1
|
|
19309
19424
|
)`, [options.projectKey]);
|
|
19310
|
-
await db.query(`DELETE FROM bead_dependencies WHERE
|
|
19425
|
+
await db.query(`DELETE FROM bead_dependencies WHERE cell_id IN (
|
|
19311
19426
|
SELECT id FROM beads WHERE project_key = $1
|
|
19312
19427
|
)`, [options.projectKey]);
|
|
19313
|
-
await db.query(`DELETE FROM blocked_beads_cache WHERE
|
|
19428
|
+
await db.query(`DELETE FROM blocked_beads_cache WHERE cell_id IN (
|
|
19314
19429
|
SELECT id FROM beads WHERE project_key = $1
|
|
19315
19430
|
)`, [options.projectKey]);
|
|
19316
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19431
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id IN (
|
|
19317
19432
|
SELECT id FROM beads WHERE project_key = $1
|
|
19318
19433
|
)`, [options.projectKey]);
|
|
19319
19434
|
await db.query(`DELETE FROM beads WHERE project_key = $1`, [
|
|
@@ -19330,7 +19445,7 @@ async function replayBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19330
19445
|
`);
|
|
19331
19446
|
}
|
|
19332
19447
|
}
|
|
19333
|
-
const events2 = await
|
|
19448
|
+
const events2 = await readCellEvents({
|
|
19334
19449
|
projectKey: options.projectKey,
|
|
19335
19450
|
afterSequence: options.fromSequence
|
|
19336
19451
|
}, projectPath, dbOverride);
|
|
@@ -19344,14 +19459,14 @@ async function replayBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19344
19459
|
});
|
|
19345
19460
|
}
|
|
19346
19461
|
|
|
19347
|
-
// src/
|
|
19348
|
-
function
|
|
19462
|
+
// src/hive/adapter.ts
|
|
19463
|
+
function createHiveAdapter(db, projectKey) {
|
|
19349
19464
|
return {
|
|
19350
|
-
async
|
|
19465
|
+
async createCell(projectKeyParam, options, projectPath) {
|
|
19351
19466
|
const event = {
|
|
19352
|
-
type: "
|
|
19467
|
+
type: "cell_created",
|
|
19353
19468
|
project_key: projectKeyParam,
|
|
19354
|
-
|
|
19469
|
+
cell_id: generateBeadId(projectKeyParam),
|
|
19355
19470
|
timestamp: Date.now(),
|
|
19356
19471
|
title: options.title,
|
|
19357
19472
|
description: options.description || null,
|
|
@@ -19361,34 +19476,34 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19361
19476
|
created_by: options.created_by || null,
|
|
19362
19477
|
metadata: options.metadata || null
|
|
19363
19478
|
};
|
|
19364
|
-
await
|
|
19479
|
+
await appendCellEvent(event, projectPath, db);
|
|
19365
19480
|
if (options.assignee) {
|
|
19366
19481
|
const assignEvent = {
|
|
19367
|
-
type: "
|
|
19482
|
+
type: "cell_assigned",
|
|
19368
19483
|
project_key: projectKeyParam,
|
|
19369
|
-
|
|
19484
|
+
cell_id: event.cell_id,
|
|
19370
19485
|
timestamp: Date.now(),
|
|
19371
19486
|
assignee: options.assignee,
|
|
19372
19487
|
assigned_by: options.created_by || null
|
|
19373
19488
|
};
|
|
19374
|
-
await
|
|
19489
|
+
await appendCellEvent(assignEvent, projectPath, db);
|
|
19375
19490
|
}
|
|
19376
|
-
const bead = await
|
|
19491
|
+
const bead = await getCell(db, projectKeyParam, event.cell_id);
|
|
19377
19492
|
if (!bead) {
|
|
19378
|
-
throw new Error(`[
|
|
19493
|
+
throw new Error(`[HiveAdapter] Failed to create bead - not found after insert`);
|
|
19379
19494
|
}
|
|
19380
19495
|
return bead;
|
|
19381
19496
|
},
|
|
19382
|
-
async
|
|
19383
|
-
return
|
|
19497
|
+
async getCell(projectKeyParam, cellId, projectPath) {
|
|
19498
|
+
return getCell(db, projectKeyParam, cellId);
|
|
19384
19499
|
},
|
|
19385
|
-
async
|
|
19386
|
-
return
|
|
19500
|
+
async queryCells(projectKeyParam, options, projectPath) {
|
|
19501
|
+
return queryCells(db, projectKeyParam, options);
|
|
19387
19502
|
},
|
|
19388
|
-
async
|
|
19389
|
-
const existingBead = await
|
|
19503
|
+
async updateCell(projectKeyParam, cellId, options, projectPath) {
|
|
19504
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19390
19505
|
if (!existingBead) {
|
|
19391
|
-
throw new Error(`[
|
|
19506
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19392
19507
|
}
|
|
19393
19508
|
const changes = {};
|
|
19394
19509
|
if (options.title && options.title !== existingBead.title) {
|
|
@@ -19407,120 +19522,120 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19407
19522
|
return existingBead;
|
|
19408
19523
|
}
|
|
19409
19524
|
const event = {
|
|
19410
|
-
type: "
|
|
19525
|
+
type: "cell_updated",
|
|
19411
19526
|
project_key: projectKeyParam,
|
|
19412
|
-
|
|
19527
|
+
cell_id: cellId,
|
|
19413
19528
|
timestamp: Date.now(),
|
|
19414
19529
|
changes,
|
|
19415
19530
|
updated_by: options.updated_by || null
|
|
19416
19531
|
};
|
|
19417
|
-
await
|
|
19418
|
-
const updated = await
|
|
19532
|
+
await appendCellEvent(event, projectPath, db);
|
|
19533
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19419
19534
|
if (!updated) {
|
|
19420
|
-
throw new Error(`[
|
|
19535
|
+
throw new Error(`[HiveAdapter] Bead disappeared after update: ${cellId}`);
|
|
19421
19536
|
}
|
|
19422
19537
|
return updated;
|
|
19423
19538
|
},
|
|
19424
|
-
async
|
|
19425
|
-
const existingBead = await
|
|
19539
|
+
async changeCellStatus(projectKeyParam, cellId, toStatus, options, projectPath) {
|
|
19540
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19426
19541
|
if (!existingBead) {
|
|
19427
|
-
throw new Error(`[
|
|
19542
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19428
19543
|
}
|
|
19429
19544
|
const event = {
|
|
19430
|
-
type: "
|
|
19545
|
+
type: "cell_status_changed",
|
|
19431
19546
|
project_key: projectKeyParam,
|
|
19432
|
-
|
|
19547
|
+
cell_id: cellId,
|
|
19433
19548
|
timestamp: Date.now(),
|
|
19434
19549
|
from_status: existingBead.status,
|
|
19435
19550
|
to_status: toStatus,
|
|
19436
19551
|
reason: options?.reason || null,
|
|
19437
19552
|
changed_by: options?.changed_by || null
|
|
19438
19553
|
};
|
|
19439
|
-
await
|
|
19440
|
-
const updated = await
|
|
19554
|
+
await appendCellEvent(event, projectPath, db);
|
|
19555
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19441
19556
|
if (!updated) {
|
|
19442
|
-
throw new Error(`[
|
|
19557
|
+
throw new Error(`[HiveAdapter] Bead disappeared after status change: ${cellId}`);
|
|
19443
19558
|
}
|
|
19444
19559
|
return updated;
|
|
19445
19560
|
},
|
|
19446
|
-
async
|
|
19447
|
-
const existingBead = await
|
|
19561
|
+
async closeCell(projectKeyParam, cellId, reason, options, projectPath) {
|
|
19562
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19448
19563
|
if (!existingBead) {
|
|
19449
|
-
throw new Error(`[
|
|
19564
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19450
19565
|
}
|
|
19451
19566
|
const event = {
|
|
19452
|
-
type: "
|
|
19567
|
+
type: "cell_closed",
|
|
19453
19568
|
project_key: projectKeyParam,
|
|
19454
|
-
|
|
19569
|
+
cell_id: cellId,
|
|
19455
19570
|
timestamp: Date.now(),
|
|
19456
19571
|
reason,
|
|
19457
19572
|
closed_by: options?.closed_by || null,
|
|
19458
19573
|
files_touched: options?.files_touched || null,
|
|
19459
19574
|
duration_ms: options?.duration_ms || null
|
|
19460
19575
|
};
|
|
19461
|
-
await
|
|
19462
|
-
const updated = await
|
|
19576
|
+
await appendCellEvent(event, projectPath, db);
|
|
19577
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19463
19578
|
if (!updated) {
|
|
19464
|
-
throw new Error(`[
|
|
19579
|
+
throw new Error(`[HiveAdapter] Bead disappeared after close: ${cellId}`);
|
|
19465
19580
|
}
|
|
19466
19581
|
return updated;
|
|
19467
19582
|
},
|
|
19468
|
-
async
|
|
19469
|
-
const existingBead = await
|
|
19583
|
+
async reopenCell(projectKeyParam, cellId, options, projectPath) {
|
|
19584
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19470
19585
|
if (!existingBead) {
|
|
19471
|
-
throw new Error(`[
|
|
19586
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19472
19587
|
}
|
|
19473
19588
|
const event = {
|
|
19474
|
-
type: "
|
|
19589
|
+
type: "cell_reopened",
|
|
19475
19590
|
project_key: projectKeyParam,
|
|
19476
|
-
|
|
19591
|
+
cell_id: cellId,
|
|
19477
19592
|
timestamp: Date.now(),
|
|
19478
19593
|
reason: options?.reason || null,
|
|
19479
19594
|
reopened_by: options?.reopened_by || null
|
|
19480
19595
|
};
|
|
19481
|
-
await
|
|
19482
|
-
const updated = await
|
|
19596
|
+
await appendCellEvent(event, projectPath, db);
|
|
19597
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19483
19598
|
if (!updated) {
|
|
19484
|
-
throw new Error(`[
|
|
19599
|
+
throw new Error(`[HiveAdapter] Bead disappeared after reopen: ${cellId}`);
|
|
19485
19600
|
}
|
|
19486
19601
|
return updated;
|
|
19487
19602
|
},
|
|
19488
|
-
async
|
|
19489
|
-
const existingBead = await
|
|
19603
|
+
async deleteCell(projectKeyParam, cellId, options, projectPath) {
|
|
19604
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19490
19605
|
if (!existingBead) {
|
|
19491
|
-
throw new Error(`[
|
|
19606
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19492
19607
|
}
|
|
19493
19608
|
const event = {
|
|
19494
|
-
type: "
|
|
19609
|
+
type: "cell_deleted",
|
|
19495
19610
|
project_key: projectKeyParam,
|
|
19496
|
-
|
|
19611
|
+
cell_id: cellId,
|
|
19497
19612
|
timestamp: Date.now(),
|
|
19498
19613
|
reason: options?.reason || null,
|
|
19499
19614
|
deleted_by: options?.deleted_by || null
|
|
19500
19615
|
};
|
|
19501
|
-
await
|
|
19616
|
+
await appendCellEvent(event, projectPath, db);
|
|
19502
19617
|
},
|
|
19503
|
-
async addDependency(projectKeyParam,
|
|
19504
|
-
const sourceBead = await
|
|
19618
|
+
async addDependency(projectKeyParam, cellId, dependsOnId, relationship, options, projectPath) {
|
|
19619
|
+
const sourceBead = await getCell(db, projectKeyParam, cellId);
|
|
19505
19620
|
if (!sourceBead) {
|
|
19506
|
-
throw new Error(`[
|
|
19621
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19507
19622
|
}
|
|
19508
|
-
const
|
|
19509
|
-
if (!
|
|
19510
|
-
throw new Error(`[
|
|
19623
|
+
const targetCell = await getCell(db, projectKeyParam, dependsOnId);
|
|
19624
|
+
if (!targetCell) {
|
|
19625
|
+
throw new Error(`[HiveAdapter] Target bead not found: ${dependsOnId}`);
|
|
19511
19626
|
}
|
|
19512
|
-
if (
|
|
19513
|
-
throw new Error(`[
|
|
19627
|
+
if (cellId === dependsOnId) {
|
|
19628
|
+
throw new Error(`[HiveAdapter] Bead cannot depend on itself`);
|
|
19514
19629
|
}
|
|
19515
19630
|
const { wouldCreateCycle: wouldCreateCycle2 } = await Promise.resolve().then(() => exports_dependencies);
|
|
19516
|
-
const hasCycle = await wouldCreateCycle2(db,
|
|
19631
|
+
const hasCycle = await wouldCreateCycle2(db, cellId, dependsOnId);
|
|
19517
19632
|
if (hasCycle) {
|
|
19518
|
-
throw new Error(`[
|
|
19633
|
+
throw new Error(`[HiveAdapter] Adding dependency would create a cycle`);
|
|
19519
19634
|
}
|
|
19520
19635
|
const event = {
|
|
19521
|
-
type: "
|
|
19636
|
+
type: "cell_dependency_added",
|
|
19522
19637
|
project_key: projectKeyParam,
|
|
19523
|
-
|
|
19638
|
+
cell_id: cellId,
|
|
19524
19639
|
timestamp: Date.now(),
|
|
19525
19640
|
dependency: {
|
|
19526
19641
|
target: dependsOnId,
|
|
@@ -19529,19 +19644,19 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19529
19644
|
reason: options?.reason || null,
|
|
19530
19645
|
added_by: options?.added_by || null
|
|
19531
19646
|
};
|
|
19532
|
-
await
|
|
19533
|
-
const deps = await getDependencies(db, projectKeyParam,
|
|
19647
|
+
await appendCellEvent(event, projectPath, db);
|
|
19648
|
+
const deps = await getDependencies(db, projectKeyParam, cellId);
|
|
19534
19649
|
const dep = deps.find((d) => d.depends_on_id === dependsOnId && d.relationship === relationship);
|
|
19535
19650
|
if (!dep) {
|
|
19536
|
-
throw new Error(`[
|
|
19651
|
+
throw new Error(`[HiveAdapter] Dependency not found after insert`);
|
|
19537
19652
|
}
|
|
19538
19653
|
return dep;
|
|
19539
19654
|
},
|
|
19540
|
-
async removeDependency(projectKeyParam,
|
|
19655
|
+
async removeDependency(projectKeyParam, cellId, dependsOnId, relationship, options, projectPath) {
|
|
19541
19656
|
const event = {
|
|
19542
|
-
type: "
|
|
19657
|
+
type: "cell_dependency_removed",
|
|
19543
19658
|
project_key: projectKeyParam,
|
|
19544
|
-
|
|
19659
|
+
cell_id: cellId,
|
|
19545
19660
|
timestamp: Date.now(),
|
|
19546
19661
|
dependency: {
|
|
19547
19662
|
target: dependsOnId,
|
|
@@ -19550,86 +19665,86 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19550
19665
|
reason: options?.reason || null,
|
|
19551
19666
|
removed_by: options?.removed_by || null
|
|
19552
19667
|
};
|
|
19553
|
-
await
|
|
19668
|
+
await appendCellEvent(event, projectPath, db);
|
|
19554
19669
|
},
|
|
19555
|
-
async getDependencies(projectKeyParam,
|
|
19556
|
-
return getDependencies(db, projectKeyParam,
|
|
19670
|
+
async getDependencies(projectKeyParam, cellId, projectPath) {
|
|
19671
|
+
return getDependencies(db, projectKeyParam, cellId);
|
|
19557
19672
|
},
|
|
19558
|
-
async getDependents(projectKeyParam,
|
|
19559
|
-
return getDependents(db, projectKeyParam,
|
|
19673
|
+
async getDependents(projectKeyParam, cellId, projectPath) {
|
|
19674
|
+
return getDependents(db, projectKeyParam, cellId);
|
|
19560
19675
|
},
|
|
19561
|
-
async isBlocked(projectKeyParam,
|
|
19562
|
-
return isBlocked(db, projectKeyParam,
|
|
19676
|
+
async isBlocked(projectKeyParam, cellId, projectPath) {
|
|
19677
|
+
return isBlocked(db, projectKeyParam, cellId);
|
|
19563
19678
|
},
|
|
19564
|
-
async getBlockers(projectKeyParam,
|
|
19565
|
-
return getBlockers(db, projectKeyParam,
|
|
19679
|
+
async getBlockers(projectKeyParam, cellId, projectPath) {
|
|
19680
|
+
return getBlockers(db, projectKeyParam, cellId);
|
|
19566
19681
|
},
|
|
19567
|
-
async addLabel(projectKeyParam,
|
|
19682
|
+
async addLabel(projectKeyParam, cellId, label, options, projectPath) {
|
|
19568
19683
|
const event = {
|
|
19569
|
-
type: "
|
|
19684
|
+
type: "cell_label_added",
|
|
19570
19685
|
project_key: projectKeyParam,
|
|
19571
|
-
|
|
19686
|
+
cell_id: cellId,
|
|
19572
19687
|
timestamp: Date.now(),
|
|
19573
19688
|
label,
|
|
19574
19689
|
added_by: options?.added_by || null
|
|
19575
19690
|
};
|
|
19576
|
-
await
|
|
19691
|
+
await appendCellEvent(event, projectPath, db);
|
|
19577
19692
|
return {
|
|
19578
|
-
|
|
19693
|
+
cell_id: cellId,
|
|
19579
19694
|
label,
|
|
19580
19695
|
created_at: event.timestamp
|
|
19581
19696
|
};
|
|
19582
19697
|
},
|
|
19583
|
-
async removeLabel(projectKeyParam,
|
|
19698
|
+
async removeLabel(projectKeyParam, cellId, label, options, projectPath) {
|
|
19584
19699
|
const event = {
|
|
19585
|
-
type: "
|
|
19700
|
+
type: "cell_label_removed",
|
|
19586
19701
|
project_key: projectKeyParam,
|
|
19587
|
-
|
|
19702
|
+
cell_id: cellId,
|
|
19588
19703
|
timestamp: Date.now(),
|
|
19589
19704
|
label,
|
|
19590
19705
|
removed_by: options?.removed_by || null
|
|
19591
19706
|
};
|
|
19592
|
-
await
|
|
19707
|
+
await appendCellEvent(event, projectPath, db);
|
|
19593
19708
|
},
|
|
19594
|
-
async getLabels(projectKeyParam,
|
|
19595
|
-
return getLabels(db, projectKeyParam,
|
|
19709
|
+
async getLabels(projectKeyParam, cellId, projectPath) {
|
|
19710
|
+
return getLabels(db, projectKeyParam, cellId);
|
|
19596
19711
|
},
|
|
19597
|
-
async
|
|
19598
|
-
return
|
|
19712
|
+
async getCellsWithLabel(projectKeyParam, label, projectPath) {
|
|
19713
|
+
return queryCells(db, projectKeyParam, { labels: [label] });
|
|
19599
19714
|
},
|
|
19600
|
-
async addComment(projectKeyParam,
|
|
19715
|
+
async addComment(projectKeyParam, cellId, author, body, options, projectPath) {
|
|
19601
19716
|
const event = {
|
|
19602
|
-
type: "
|
|
19717
|
+
type: "cell_comment_added",
|
|
19603
19718
|
project_key: projectKeyParam,
|
|
19604
|
-
|
|
19719
|
+
cell_id: cellId,
|
|
19605
19720
|
timestamp: Date.now(),
|
|
19606
19721
|
author,
|
|
19607
19722
|
body,
|
|
19608
19723
|
parent_comment_id: options?.parent_id || null,
|
|
19609
19724
|
metadata: options?.metadata || null
|
|
19610
19725
|
};
|
|
19611
|
-
await
|
|
19612
|
-
const comments = await getComments(db, projectKeyParam,
|
|
19726
|
+
await appendCellEvent(event, projectPath, db);
|
|
19727
|
+
const comments = await getComments(db, projectKeyParam, cellId);
|
|
19613
19728
|
const comment = comments[comments.length - 1];
|
|
19614
19729
|
if (!comment) {
|
|
19615
|
-
throw new Error(`[
|
|
19730
|
+
throw new Error(`[HiveAdapter] Comment not found after insert`);
|
|
19616
19731
|
}
|
|
19617
19732
|
return comment;
|
|
19618
19733
|
},
|
|
19619
19734
|
async updateComment(projectKeyParam, commentId, newBody, updated_by, projectPath) {
|
|
19620
19735
|
const event = {
|
|
19621
|
-
type: "
|
|
19736
|
+
type: "cell_comment_updated",
|
|
19622
19737
|
project_key: projectKeyParam,
|
|
19623
|
-
|
|
19738
|
+
cell_id: "",
|
|
19624
19739
|
timestamp: Date.now(),
|
|
19625
19740
|
comment_id: commentId,
|
|
19626
19741
|
new_body: newBody,
|
|
19627
19742
|
updated_by
|
|
19628
19743
|
};
|
|
19629
|
-
await
|
|
19744
|
+
await appendCellEvent(event, projectPath, db);
|
|
19630
19745
|
return {
|
|
19631
19746
|
id: commentId,
|
|
19632
|
-
|
|
19747
|
+
cell_id: "",
|
|
19633
19748
|
author: updated_by,
|
|
19634
19749
|
body: newBody,
|
|
19635
19750
|
parent_id: null,
|
|
@@ -19639,70 +19754,70 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19639
19754
|
},
|
|
19640
19755
|
async deleteComment(projectKeyParam, commentId, deleted_by, options, projectPath) {
|
|
19641
19756
|
const event = {
|
|
19642
|
-
type: "
|
|
19757
|
+
type: "cell_comment_deleted",
|
|
19643
19758
|
project_key: projectKeyParam,
|
|
19644
|
-
|
|
19759
|
+
cell_id: "",
|
|
19645
19760
|
timestamp: Date.now(),
|
|
19646
19761
|
comment_id: commentId,
|
|
19647
19762
|
deleted_by,
|
|
19648
19763
|
reason: options?.reason || null
|
|
19649
19764
|
};
|
|
19650
|
-
await
|
|
19765
|
+
await appendCellEvent(event, projectPath, db);
|
|
19651
19766
|
},
|
|
19652
|
-
async getComments(projectKeyParam,
|
|
19653
|
-
return getComments(db, projectKeyParam,
|
|
19767
|
+
async getComments(projectKeyParam, cellId, projectPath) {
|
|
19768
|
+
return getComments(db, projectKeyParam, cellId);
|
|
19654
19769
|
},
|
|
19655
19770
|
async addChildToEpic(projectKeyParam, epicId, childId, options, projectPath) {
|
|
19656
19771
|
const event = {
|
|
19657
|
-
type: "
|
|
19772
|
+
type: "cell_epic_child_added",
|
|
19658
19773
|
project_key: projectKeyParam,
|
|
19659
|
-
|
|
19774
|
+
cell_id: epicId,
|
|
19660
19775
|
timestamp: Date.now(),
|
|
19661
19776
|
child_id: childId,
|
|
19662
19777
|
child_index: options?.child_index || null,
|
|
19663
19778
|
added_by: options?.added_by || null
|
|
19664
19779
|
};
|
|
19665
|
-
await
|
|
19780
|
+
await appendCellEvent(event, projectPath, db);
|
|
19666
19781
|
},
|
|
19667
19782
|
async removeChildFromEpic(projectKeyParam, epicId, childId, options, projectPath) {
|
|
19668
19783
|
const event = {
|
|
19669
|
-
type: "
|
|
19784
|
+
type: "cell_epic_child_removed",
|
|
19670
19785
|
project_key: projectKeyParam,
|
|
19671
|
-
|
|
19786
|
+
cell_id: epicId,
|
|
19672
19787
|
timestamp: Date.now(),
|
|
19673
19788
|
child_id: childId,
|
|
19674
19789
|
reason: options?.reason || null,
|
|
19675
19790
|
removed_by: options?.removed_by || null
|
|
19676
19791
|
};
|
|
19677
|
-
await
|
|
19792
|
+
await appendCellEvent(event, projectPath, db);
|
|
19678
19793
|
},
|
|
19679
19794
|
async getEpicChildren(projectKeyParam, epicId, projectPath) {
|
|
19680
|
-
return
|
|
19795
|
+
return queryCells(db, projectKeyParam, { parent_id: epicId });
|
|
19681
19796
|
},
|
|
19682
19797
|
async isEpicClosureEligible(projectKeyParam, epicId, projectPath) {
|
|
19683
|
-
const children = await
|
|
19798
|
+
const children = await queryCells(db, projectKeyParam, { parent_id: epicId });
|
|
19684
19799
|
return children.every((child) => child.status === "closed");
|
|
19685
19800
|
},
|
|
19686
|
-
async
|
|
19687
|
-
return
|
|
19801
|
+
async getNextReadyCell(projectKeyParam, projectPath) {
|
|
19802
|
+
return getNextReadyCell(db, projectKeyParam);
|
|
19688
19803
|
},
|
|
19689
|
-
async
|
|
19690
|
-
return
|
|
19804
|
+
async getInProgressCells(projectKeyParam, projectPath) {
|
|
19805
|
+
return getInProgressCells(db, projectKeyParam);
|
|
19691
19806
|
},
|
|
19692
|
-
async
|
|
19693
|
-
return
|
|
19807
|
+
async getBlockedCells(projectKeyParam, projectPath) {
|
|
19808
|
+
return getBlockedCells(db, projectKeyParam);
|
|
19694
19809
|
},
|
|
19695
|
-
async markDirty(projectKeyParam,
|
|
19696
|
-
await markBeadDirty(db, projectKeyParam,
|
|
19810
|
+
async markDirty(projectKeyParam, cellId, projectPath) {
|
|
19811
|
+
await markBeadDirty(db, projectKeyParam, cellId);
|
|
19697
19812
|
},
|
|
19698
|
-
async
|
|
19699
|
-
return
|
|
19813
|
+
async getDirtyCells(projectKeyParam, projectPath) {
|
|
19814
|
+
return getDirtyCells(db, projectKeyParam);
|
|
19700
19815
|
},
|
|
19701
|
-
async clearDirty(projectKeyParam,
|
|
19702
|
-
await clearDirtyBead(db, projectKeyParam,
|
|
19816
|
+
async clearDirty(projectKeyParam, cellId, projectPath) {
|
|
19817
|
+
await clearDirtyBead(db, projectKeyParam, cellId);
|
|
19703
19818
|
},
|
|
19704
19819
|
async runMigrations(projectPath) {
|
|
19705
|
-
const {
|
|
19820
|
+
const { hiveMigrations: hiveMigrations2 } = await Promise.resolve().then(() => (init_migrations2(), exports_migrations2));
|
|
19706
19821
|
await db.exec(`
|
|
19707
19822
|
CREATE TABLE IF NOT EXISTS schema_version (
|
|
19708
19823
|
version INTEGER PRIMARY KEY,
|
|
@@ -19710,18 +19825,24 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19710
19825
|
description TEXT
|
|
19711
19826
|
);
|
|
19712
19827
|
`);
|
|
19713
|
-
await db.
|
|
19714
|
-
|
|
19715
|
-
|
|
19716
|
-
|
|
19717
|
-
|
|
19718
|
-
|
|
19719
|
-
|
|
19720
|
-
|
|
19721
|
-
|
|
19828
|
+
const versionResult = await db.query("SELECT MAX(version) as version FROM schema_version");
|
|
19829
|
+
const currentVersion = versionResult.rows[0]?.version ?? 0;
|
|
19830
|
+
for (const migration of hiveMigrations2) {
|
|
19831
|
+
if (migration.version > currentVersion) {
|
|
19832
|
+
await db.exec("BEGIN");
|
|
19833
|
+
try {
|
|
19834
|
+
await db.exec(migration.up);
|
|
19835
|
+
await db.query(`INSERT INTO schema_version (version, applied_at, description) VALUES ($1, $2, $3)
|
|
19836
|
+
ON CONFLICT (version) DO NOTHING`, [migration.version, Date.now(), migration.description]);
|
|
19837
|
+
await db.exec("COMMIT");
|
|
19838
|
+
} catch (error45) {
|
|
19839
|
+
await db.exec("ROLLBACK");
|
|
19840
|
+
throw error45;
|
|
19841
|
+
}
|
|
19842
|
+
}
|
|
19722
19843
|
}
|
|
19723
19844
|
},
|
|
19724
|
-
async
|
|
19845
|
+
async getCellsStats(projectPath) {
|
|
19725
19846
|
const [totalResult, openResult, inProgressResult, blockedResult, closedResult] = await Promise.all([
|
|
19726
19847
|
db.query("SELECT COUNT(*) as count FROM beads WHERE project_key = $1", [projectKey]),
|
|
19727
19848
|
db.query("SELECT COUNT(*) as count FROM beads WHERE project_key = $1 AND status = 'open'", [projectKey]),
|
|
@@ -19735,7 +19856,7 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19735
19856
|
by_type[row.type] = parseInt(row.count);
|
|
19736
19857
|
}
|
|
19737
19858
|
return {
|
|
19738
|
-
|
|
19859
|
+
total_cells: parseInt(totalResult.rows[0]?.count || "0"),
|
|
19739
19860
|
open: parseInt(openResult.rows[0]?.count || "0"),
|
|
19740
19861
|
in_progress: parseInt(inProgressResult.rows[0]?.count || "0"),
|
|
19741
19862
|
blocked: parseInt(blockedResult.rows[0]?.count || "0"),
|
|
@@ -19769,25 +19890,25 @@ function generateBeadId(projectKey) {
|
|
|
19769
19890
|
return `bd-${hash2}-${timestamp}${random}`;
|
|
19770
19891
|
}
|
|
19771
19892
|
|
|
19772
|
-
// src/
|
|
19893
|
+
// src/hive/index.ts
|
|
19773
19894
|
init_migrations2();
|
|
19774
19895
|
|
|
19775
|
-
// src/
|
|
19776
|
-
async function
|
|
19896
|
+
// src/hive/labels.ts
|
|
19897
|
+
async function getCellsByLabel(db, projectKey, label) {
|
|
19777
19898
|
const result = await db.query(`SELECT b.* FROM beads b
|
|
19778
|
-
JOIN bead_labels bl ON b.id = bl.
|
|
19899
|
+
JOIN bead_labels bl ON b.id = bl.cell_id
|
|
19779
19900
|
WHERE b.project_key = $1 AND bl.label = $2 AND b.deleted_at IS NULL
|
|
19780
19901
|
ORDER BY b.priority DESC, b.created_at ASC`, [projectKey, label]);
|
|
19781
19902
|
return result.rows;
|
|
19782
19903
|
}
|
|
19783
19904
|
async function getAllLabels(db, projectKey) {
|
|
19784
19905
|
const result = await db.query(`SELECT DISTINCT bl.label FROM bead_labels bl
|
|
19785
|
-
JOIN beads b ON bl.
|
|
19906
|
+
JOIN beads b ON bl.cell_id = b.id
|
|
19786
19907
|
WHERE b.project_key = $1 AND b.deleted_at IS NULL
|
|
19787
19908
|
ORDER BY bl.label`, [projectKey]);
|
|
19788
19909
|
return result.rows.map((r) => r.label);
|
|
19789
19910
|
}
|
|
19790
|
-
// src/
|
|
19911
|
+
// src/hive/comments.ts
|
|
19791
19912
|
async function getCommentById(db, commentId) {
|
|
19792
19913
|
const result = await db.query(`SELECT * FROM bead_comments WHERE id = $1`, [commentId]);
|
|
19793
19914
|
return result.rows[0] ?? null;
|
|
@@ -19806,10 +19927,10 @@ async function getCommentThread(db, rootCommentId) {
|
|
|
19806
19927
|
SELECT * FROM thread ORDER BY created_at ASC`, [rootCommentId]);
|
|
19807
19928
|
return result.rows;
|
|
19808
19929
|
}
|
|
19809
|
-
// src/
|
|
19930
|
+
// src/hive/jsonl.ts
|
|
19810
19931
|
import { createHash as createHash2 } from "node:crypto";
|
|
19811
|
-
function serializeToJSONL(
|
|
19812
|
-
return JSON.stringify(
|
|
19932
|
+
function serializeToJSONL(cell) {
|
|
19933
|
+
return JSON.stringify(cell);
|
|
19813
19934
|
}
|
|
19814
19935
|
function parseJSONL(jsonl) {
|
|
19815
19936
|
if (!jsonl || jsonl.trim() === "") {
|
|
@@ -19817,23 +19938,23 @@ function parseJSONL(jsonl) {
|
|
|
19817
19938
|
}
|
|
19818
19939
|
const lines = jsonl.split(`
|
|
19819
19940
|
`);
|
|
19820
|
-
const
|
|
19941
|
+
const cells = [];
|
|
19821
19942
|
for (const line of lines) {
|
|
19822
19943
|
const trimmed = line.trim();
|
|
19823
19944
|
if (trimmed === "") {
|
|
19824
19945
|
continue;
|
|
19825
19946
|
}
|
|
19826
19947
|
try {
|
|
19827
|
-
const
|
|
19828
|
-
|
|
19948
|
+
const cell = JSON.parse(trimmed);
|
|
19949
|
+
cells.push(cell);
|
|
19829
19950
|
} catch (err) {
|
|
19830
19951
|
throw new Error(`Invalid JSON in JSONL: ${err instanceof Error ? err.message : String(err)}`);
|
|
19831
19952
|
}
|
|
19832
19953
|
}
|
|
19833
|
-
return
|
|
19954
|
+
return cells;
|
|
19834
19955
|
}
|
|
19835
|
-
function computeContentHash(
|
|
19836
|
-
const canonical = JSON.stringify(
|
|
19956
|
+
function computeContentHash(cell) {
|
|
19957
|
+
const canonical = JSON.stringify(cell, Object.keys(cell).sort());
|
|
19837
19958
|
return createHash2("sha256").update(canonical).digest("hex");
|
|
19838
19959
|
}
|
|
19839
19960
|
async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
@@ -19844,12 +19965,12 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19844
19965
|
if (!options.includeDeleted) {
|
|
19845
19966
|
conditions.push("deleted_at IS NULL");
|
|
19846
19967
|
}
|
|
19847
|
-
if (options.
|
|
19968
|
+
if (options.cellIds && options.cellIds.length > 0) {
|
|
19848
19969
|
conditions.push(`id = ANY($${paramIndex++})`);
|
|
19849
|
-
params.push(options.
|
|
19970
|
+
params.push(options.cellIds);
|
|
19850
19971
|
}
|
|
19851
19972
|
const query = `
|
|
19852
|
-
SELECT * FROM
|
|
19973
|
+
SELECT * FROM cells
|
|
19853
19974
|
WHERE ${conditions.join(" AND ")}
|
|
19854
19975
|
ORDER BY id ASC
|
|
19855
19976
|
`;
|
|
@@ -19871,7 +19992,7 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19871
19992
|
author: c.author,
|
|
19872
19993
|
text: c.body
|
|
19873
19994
|
}));
|
|
19874
|
-
const
|
|
19995
|
+
const cellExport = {
|
|
19875
19996
|
id: bead.id,
|
|
19876
19997
|
title: bead.title,
|
|
19877
19998
|
description: bead.description || undefined,
|
|
@@ -19887,51 +20008,51 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19887
20008
|
labels,
|
|
19888
20009
|
comments: commentExports
|
|
19889
20010
|
};
|
|
19890
|
-
lines.push(serializeToJSONL(
|
|
20011
|
+
lines.push(serializeToJSONL(cellExport));
|
|
19891
20012
|
}
|
|
19892
20013
|
return lines.join(`
|
|
19893
20014
|
`);
|
|
19894
20015
|
}
|
|
19895
20016
|
async function exportDirtyBeads(adapter, projectKey) {
|
|
19896
20017
|
const db = await adapter.getDatabase();
|
|
19897
|
-
const dirtyIds = await
|
|
20018
|
+
const dirtyIds = await getDirtyCells(db, projectKey);
|
|
19898
20019
|
if (dirtyIds.length === 0) {
|
|
19899
|
-
return { jsonl: "",
|
|
20020
|
+
return { jsonl: "", cellIds: [] };
|
|
19900
20021
|
}
|
|
19901
20022
|
const jsonl = await exportToJSONL(adapter, projectKey, {
|
|
19902
|
-
|
|
20023
|
+
cellIds: dirtyIds
|
|
19903
20024
|
});
|
|
19904
|
-
return { jsonl,
|
|
20025
|
+
return { jsonl, cellIds: dirtyIds };
|
|
19905
20026
|
}
|
|
19906
20027
|
async function importFromJSONL(adapter, projectKey, jsonl, options = {}) {
|
|
19907
|
-
const
|
|
20028
|
+
const cells = parseJSONL(jsonl);
|
|
19908
20029
|
const result = {
|
|
19909
20030
|
created: 0,
|
|
19910
20031
|
updated: 0,
|
|
19911
20032
|
skipped: 0,
|
|
19912
20033
|
errors: []
|
|
19913
20034
|
};
|
|
19914
|
-
for (const
|
|
20035
|
+
for (const cellExport of cells) {
|
|
19915
20036
|
try {
|
|
19916
|
-
await
|
|
20037
|
+
await importSingleCell(adapter, projectKey, cellExport, options, result);
|
|
19917
20038
|
} catch (err) {
|
|
19918
20039
|
result.errors.push({
|
|
19919
|
-
|
|
20040
|
+
cellId: cellExport.id,
|
|
19920
20041
|
error: err instanceof Error ? err.message : String(err)
|
|
19921
20042
|
});
|
|
19922
20043
|
}
|
|
19923
20044
|
}
|
|
19924
20045
|
return result;
|
|
19925
20046
|
}
|
|
19926
|
-
async function
|
|
19927
|
-
const existing = await adapter.
|
|
20047
|
+
async function importSingleCell(adapter, projectKey, cellExport, options, result) {
|
|
20048
|
+
const existing = await adapter.getCell(projectKey, cellExport.id);
|
|
19928
20049
|
if (existing && options.skipExisting) {
|
|
19929
20050
|
result.skipped++;
|
|
19930
20051
|
return;
|
|
19931
20052
|
}
|
|
19932
20053
|
if (existing) {
|
|
19933
20054
|
const existingHash = await computeBeadHash(adapter, projectKey, existing.id);
|
|
19934
|
-
const importHash = computeContentHash(
|
|
20055
|
+
const importHash = computeContentHash(cellExport);
|
|
19935
20056
|
if (existingHash === importHash) {
|
|
19936
20057
|
result.skipped++;
|
|
19937
20058
|
return;
|
|
@@ -19947,124 +20068,124 @@ async function importSingleBead(adapter, projectKey, beadExport, options, result
|
|
|
19947
20068
|
}
|
|
19948
20069
|
if (!existing) {
|
|
19949
20070
|
const db = await adapter.getDatabase();
|
|
19950
|
-
const status =
|
|
20071
|
+
const status = cellExport.status === "tombstone" ? "closed" : cellExport.status;
|
|
19951
20072
|
const isClosed = status === "closed";
|
|
19952
|
-
const closedAt = isClosed ?
|
|
19953
|
-
await db.query(`INSERT INTO
|
|
20073
|
+
const closedAt = isClosed ? cellExport.closed_at ? new Date(cellExport.closed_at).getTime() : new Date(cellExport.updated_at).getTime() : null;
|
|
20074
|
+
await db.query(`INSERT INTO cells (
|
|
19954
20075
|
id, project_key, type, status, title, description, priority,
|
|
19955
20076
|
parent_id, assignee, created_at, updated_at, closed_at
|
|
19956
20077
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [
|
|
19957
|
-
|
|
20078
|
+
cellExport.id,
|
|
19958
20079
|
projectKey,
|
|
19959
|
-
|
|
20080
|
+
cellExport.issue_type,
|
|
19960
20081
|
status,
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
19965
|
-
|
|
19966
|
-
new Date(
|
|
19967
|
-
new Date(
|
|
20082
|
+
cellExport.title,
|
|
20083
|
+
cellExport.description || null,
|
|
20084
|
+
cellExport.priority,
|
|
20085
|
+
cellExport.parent_id || null,
|
|
20086
|
+
cellExport.assignee || null,
|
|
20087
|
+
new Date(cellExport.created_at).getTime(),
|
|
20088
|
+
new Date(cellExport.updated_at).getTime(),
|
|
19968
20089
|
closedAt
|
|
19969
20090
|
]);
|
|
19970
|
-
if (
|
|
19971
|
-
await db.query("UPDATE beads SET deleted_at = $1 WHERE id = $2", [Date.now(),
|
|
20091
|
+
if (cellExport.status === "tombstone") {
|
|
20092
|
+
await db.query("UPDATE beads SET deleted_at = $1 WHERE id = $2", [Date.now(), cellExport.id]);
|
|
19972
20093
|
}
|
|
19973
20094
|
result.created++;
|
|
19974
20095
|
} else {
|
|
19975
|
-
await adapter.
|
|
19976
|
-
title:
|
|
19977
|
-
description:
|
|
19978
|
-
priority:
|
|
19979
|
-
assignee:
|
|
20096
|
+
await adapter.updateCell(projectKey, cellExport.id, {
|
|
20097
|
+
title: cellExport.title,
|
|
20098
|
+
description: cellExport.description,
|
|
20099
|
+
priority: cellExport.priority,
|
|
20100
|
+
assignee: cellExport.assignee
|
|
19980
20101
|
});
|
|
19981
|
-
if (existing.status !==
|
|
19982
|
-
if (
|
|
19983
|
-
await adapter.
|
|
19984
|
-
} else if (
|
|
20102
|
+
if (existing.status !== cellExport.status) {
|
|
20103
|
+
if (cellExport.status === "closed") {
|
|
20104
|
+
await adapter.closeCell(projectKey, cellExport.id, "imported");
|
|
20105
|
+
} else if (cellExport.status === "in_progress") {
|
|
19985
20106
|
const db = await adapter.getDatabase();
|
|
19986
|
-
await db.query("UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3", ["in_progress", Date.now(),
|
|
20107
|
+
await db.query("UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3", ["in_progress", Date.now(), cellExport.id]);
|
|
19987
20108
|
}
|
|
19988
20109
|
}
|
|
19989
20110
|
result.updated++;
|
|
19990
20111
|
}
|
|
19991
|
-
await importDependencies(adapter, projectKey,
|
|
19992
|
-
await importLabels(adapter, projectKey,
|
|
19993
|
-
await importComments(adapter, projectKey,
|
|
20112
|
+
await importDependencies(adapter, projectKey, cellExport);
|
|
20113
|
+
await importLabels(adapter, projectKey, cellExport);
|
|
20114
|
+
await importComments(adapter, projectKey, cellExport);
|
|
19994
20115
|
}
|
|
19995
|
-
async function computeBeadHash(adapter, projectKey,
|
|
20116
|
+
async function computeBeadHash(adapter, projectKey, cellId) {
|
|
19996
20117
|
const db = await adapter.getDatabase();
|
|
19997
|
-
const beadResult = await db.query("SELECT * FROM beads WHERE project_key = $1 AND id = $2", [projectKey,
|
|
19998
|
-
const
|
|
19999
|
-
if (!
|
|
20000
|
-
throw new Error(`
|
|
20118
|
+
const beadResult = await db.query("SELECT * FROM beads WHERE project_key = $1 AND id = $2", [projectKey, cellId]);
|
|
20119
|
+
const cell = beadResult.rows[0];
|
|
20120
|
+
if (!cell) {
|
|
20121
|
+
throw new Error(`Cell not found: ${cellId}`);
|
|
20001
20122
|
}
|
|
20002
|
-
const deps = await getDependencies(db, projectKey,
|
|
20123
|
+
const deps = await getDependencies(db, projectKey, cellId);
|
|
20003
20124
|
const dependencies = deps.map((d) => ({
|
|
20004
20125
|
depends_on_id: d.depends_on_id,
|
|
20005
20126
|
type: d.relationship
|
|
20006
20127
|
}));
|
|
20007
|
-
const labels = await getLabels(db, projectKey,
|
|
20008
|
-
const comments = await getComments(db, projectKey,
|
|
20128
|
+
const labels = await getLabels(db, projectKey, cellId);
|
|
20129
|
+
const comments = await getComments(db, projectKey, cellId);
|
|
20009
20130
|
const commentExports = comments.map((c) => ({
|
|
20010
20131
|
author: c.author,
|
|
20011
20132
|
text: c.body
|
|
20012
20133
|
}));
|
|
20013
|
-
const
|
|
20014
|
-
id:
|
|
20015
|
-
title:
|
|
20016
|
-
description:
|
|
20017
|
-
status:
|
|
20018
|
-
priority:
|
|
20019
|
-
issue_type:
|
|
20020
|
-
created_at: new Date(
|
|
20021
|
-
updated_at: new Date(
|
|
20022
|
-
closed_at:
|
|
20023
|
-
assignee:
|
|
20024
|
-
parent_id:
|
|
20134
|
+
const cellExport = {
|
|
20135
|
+
id: cell.id,
|
|
20136
|
+
title: cell.title,
|
|
20137
|
+
description: cell.description || undefined,
|
|
20138
|
+
status: cell.deleted_at ? "tombstone" : cell.status,
|
|
20139
|
+
priority: cell.priority,
|
|
20140
|
+
issue_type: cell.type,
|
|
20141
|
+
created_at: new Date(cell.created_at).toISOString(),
|
|
20142
|
+
updated_at: new Date(cell.updated_at).toISOString(),
|
|
20143
|
+
closed_at: cell.closed_at ? new Date(cell.closed_at).toISOString() : undefined,
|
|
20144
|
+
assignee: cell.assignee || undefined,
|
|
20145
|
+
parent_id: cell.parent_id || undefined,
|
|
20025
20146
|
dependencies,
|
|
20026
20147
|
labels,
|
|
20027
20148
|
comments: commentExports
|
|
20028
20149
|
};
|
|
20029
|
-
return computeContentHash(
|
|
20150
|
+
return computeContentHash(cellExport);
|
|
20030
20151
|
}
|
|
20031
|
-
async function importDependencies(adapter, projectKey,
|
|
20032
|
-
if (!
|
|
20152
|
+
async function importDependencies(adapter, projectKey, cellExport) {
|
|
20153
|
+
if (!cellExport.dependencies || cellExport.dependencies.length === 0) {
|
|
20033
20154
|
return;
|
|
20034
20155
|
}
|
|
20035
20156
|
const db = await adapter.getDatabase();
|
|
20036
|
-
await db.query("DELETE FROM
|
|
20037
|
-
|
|
20157
|
+
await db.query("DELETE FROM cell_dependencies WHERE cell_id = $1", [
|
|
20158
|
+
cellExport.id
|
|
20038
20159
|
]);
|
|
20039
|
-
for (const dep of
|
|
20040
|
-
await adapter.addDependency(projectKey,
|
|
20160
|
+
for (const dep of cellExport.dependencies) {
|
|
20161
|
+
await adapter.addDependency(projectKey, cellExport.id, dep.depends_on_id, dep.type);
|
|
20041
20162
|
}
|
|
20042
20163
|
}
|
|
20043
|
-
async function importLabels(adapter, projectKey,
|
|
20044
|
-
if (!
|
|
20164
|
+
async function importLabels(adapter, projectKey, cellExport) {
|
|
20165
|
+
if (!cellExport.labels || cellExport.labels.length === 0) {
|
|
20045
20166
|
return;
|
|
20046
20167
|
}
|
|
20047
20168
|
const db = await adapter.getDatabase();
|
|
20048
|
-
await db.query("DELETE FROM
|
|
20049
|
-
|
|
20169
|
+
await db.query("DELETE FROM cell_labels WHERE cell_id = $1", [
|
|
20170
|
+
cellExport.id
|
|
20050
20171
|
]);
|
|
20051
|
-
for (const label of
|
|
20052
|
-
await adapter.addLabel(projectKey,
|
|
20172
|
+
for (const label of cellExport.labels) {
|
|
20173
|
+
await adapter.addLabel(projectKey, cellExport.id, label);
|
|
20053
20174
|
}
|
|
20054
20175
|
}
|
|
20055
|
-
async function importComments(adapter, projectKey,
|
|
20056
|
-
if (!
|
|
20176
|
+
async function importComments(adapter, projectKey, cellExport) {
|
|
20177
|
+
if (!cellExport.comments || cellExport.comments.length === 0) {
|
|
20057
20178
|
return;
|
|
20058
20179
|
}
|
|
20059
20180
|
const db = await adapter.getDatabase();
|
|
20060
|
-
await db.query("DELETE FROM
|
|
20061
|
-
|
|
20181
|
+
await db.query("DELETE FROM cell_comments WHERE cell_id = $1", [
|
|
20182
|
+
cellExport.id
|
|
20062
20183
|
]);
|
|
20063
|
-
for (const comment of
|
|
20064
|
-
await adapter.addComment(projectKey,
|
|
20184
|
+
for (const comment of cellExport.comments) {
|
|
20185
|
+
await adapter.addComment(projectKey, cellExport.id, comment.author, comment.text);
|
|
20065
20186
|
}
|
|
20066
20187
|
}
|
|
20067
|
-
// src/
|
|
20188
|
+
// src/hive/flush-manager.ts
|
|
20068
20189
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
20069
20190
|
class FlushManager {
|
|
20070
20191
|
adapter;
|
|
@@ -20095,7 +20216,7 @@ class FlushManager {
|
|
|
20095
20216
|
const startTime = Date.now();
|
|
20096
20217
|
if (this.flushing) {
|
|
20097
20218
|
return {
|
|
20098
|
-
|
|
20219
|
+
cellsExported: 0,
|
|
20099
20220
|
bytesWritten: 0,
|
|
20100
20221
|
duration: 0
|
|
20101
20222
|
};
|
|
@@ -20106,10 +20227,10 @@ class FlushManager {
|
|
|
20106
20227
|
clearTimeout(this.timer);
|
|
20107
20228
|
this.timer = null;
|
|
20108
20229
|
}
|
|
20109
|
-
const { jsonl,
|
|
20110
|
-
if (
|
|
20230
|
+
const { jsonl, cellIds } = await exportDirtyBeads(this.adapter, this.projectKey);
|
|
20231
|
+
if (cellIds.length === 0) {
|
|
20111
20232
|
return {
|
|
20112
|
-
|
|
20233
|
+
cellsExported: 0,
|
|
20113
20234
|
bytesWritten: 0,
|
|
20114
20235
|
duration: Date.now() - startTime
|
|
20115
20236
|
};
|
|
@@ -20117,11 +20238,11 @@ class FlushManager {
|
|
|
20117
20238
|
await writeFile2(this.outputPath, jsonl, "utf-8");
|
|
20118
20239
|
const bytesWritten = Buffer.byteLength(jsonl, "utf-8");
|
|
20119
20240
|
const db = await this.adapter.getDatabase();
|
|
20120
|
-
for (const
|
|
20121
|
-
await clearDirtyBead(db, this.projectKey,
|
|
20241
|
+
for (const cellId of cellIds) {
|
|
20242
|
+
await clearDirtyBead(db, this.projectKey, cellId);
|
|
20122
20243
|
}
|
|
20123
20244
|
const result = {
|
|
20124
|
-
|
|
20245
|
+
cellsExported: cellIds.length,
|
|
20125
20246
|
bytesWritten,
|
|
20126
20247
|
duration: Date.now() - startTime
|
|
20127
20248
|
};
|
|
@@ -20140,30 +20261,30 @@ class FlushManager {
|
|
|
20140
20261
|
}
|
|
20141
20262
|
}
|
|
20142
20263
|
}
|
|
20143
|
-
// src/
|
|
20264
|
+
// src/hive/merge.ts
|
|
20144
20265
|
var DEFAULT_TOMBSTONE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
20145
20266
|
var MIN_TOMBSTONE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
20146
20267
|
var CLOCK_SKEW_GRACE_MS = 60 * 60 * 1000;
|
|
20147
20268
|
var STATUS_TOMBSTONE = "tombstone";
|
|
20148
|
-
function makeKey(
|
|
20269
|
+
function makeKey(cell) {
|
|
20149
20270
|
const key = {
|
|
20150
|
-
id:
|
|
20151
|
-
createdAt:
|
|
20271
|
+
id: cell.id,
|
|
20272
|
+
createdAt: cell.created_at,
|
|
20152
20273
|
createdBy: undefined
|
|
20153
20274
|
};
|
|
20154
20275
|
return JSON.stringify(key);
|
|
20155
20276
|
}
|
|
20156
|
-
function isTombstone(
|
|
20157
|
-
return
|
|
20277
|
+
function isTombstone(cell) {
|
|
20278
|
+
return cell.status === STATUS_TOMBSTONE;
|
|
20158
20279
|
}
|
|
20159
|
-
function isExpiredTombstone(
|
|
20160
|
-
if (!isTombstone(
|
|
20280
|
+
function isExpiredTombstone(cell, ttlMs = DEFAULT_TOMBSTONE_TTL_MS) {
|
|
20281
|
+
if (!isTombstone(cell)) {
|
|
20161
20282
|
return false;
|
|
20162
20283
|
}
|
|
20163
|
-
if (!
|
|
20284
|
+
if (!cell.closed_at) {
|
|
20164
20285
|
return false;
|
|
20165
20286
|
}
|
|
20166
|
-
const deletedAt = new Date(
|
|
20287
|
+
const deletedAt = new Date(cell.closed_at).getTime();
|
|
20167
20288
|
if (Number.isNaN(deletedAt)) {
|
|
20168
20289
|
return false;
|
|
20169
20290
|
}
|
|
@@ -20482,7 +20603,7 @@ export {
|
|
|
20482
20603
|
reserveAgentFiles,
|
|
20483
20604
|
replayEventsBatched2 as replayEventsBatched,
|
|
20484
20605
|
replayEvents,
|
|
20485
|
-
|
|
20606
|
+
replayCellEvents,
|
|
20486
20607
|
releaseSwarmFiles,
|
|
20487
20608
|
releaseAgentFiles,
|
|
20488
20609
|
registerAgent,
|
|
@@ -20490,9 +20611,9 @@ export {
|
|
|
20490
20611
|
rebuildAllBlockedCaches,
|
|
20491
20612
|
readSwarmMessage,
|
|
20492
20613
|
readEvents,
|
|
20493
|
-
|
|
20614
|
+
readCellEvents,
|
|
20494
20615
|
readAgentMessage,
|
|
20495
|
-
|
|
20616
|
+
queryCells,
|
|
20496
20617
|
parseJSONL,
|
|
20497
20618
|
migrations,
|
|
20498
20619
|
mergeJsonl,
|
|
@@ -20510,6 +20631,7 @@ export {
|
|
|
20510
20631
|
initSwarmAgent,
|
|
20511
20632
|
initAgent,
|
|
20512
20633
|
importFromJSONL,
|
|
20634
|
+
hiveMigrations,
|
|
20513
20635
|
healthCheck,
|
|
20514
20636
|
hashProjectPath,
|
|
20515
20637
|
getThreadMessages,
|
|
@@ -20520,16 +20642,16 @@ export {
|
|
|
20520
20642
|
getPidFilePath,
|
|
20521
20643
|
getPendingMigrations,
|
|
20522
20644
|
getOpenBlockers,
|
|
20523
|
-
|
|
20645
|
+
getNextReadyCell,
|
|
20524
20646
|
getMessage,
|
|
20525
20647
|
getLatestSequence,
|
|
20526
20648
|
getLabels,
|
|
20527
20649
|
getInbox,
|
|
20528
|
-
|
|
20650
|
+
getInProgressCells,
|
|
20529
20651
|
getEventTimeline,
|
|
20530
20652
|
getEvalStats,
|
|
20531
20653
|
getEvalRecords,
|
|
20532
|
-
|
|
20654
|
+
getDirtyCells,
|
|
20533
20655
|
getDependents,
|
|
20534
20656
|
getDependencies,
|
|
20535
20657
|
getDatabaseStats,
|
|
@@ -20539,10 +20661,10 @@ export {
|
|
|
20539
20661
|
getComments,
|
|
20540
20662
|
getCommentThread,
|
|
20541
20663
|
getCommentById,
|
|
20664
|
+
getCellsByLabel,
|
|
20665
|
+
getCell,
|
|
20542
20666
|
getBlockers,
|
|
20543
|
-
|
|
20544
|
-
getBeadsByLabel,
|
|
20545
|
-
getBead,
|
|
20667
|
+
getBlockedCells,
|
|
20546
20668
|
getAppliedMigrations,
|
|
20547
20669
|
getAllLabels,
|
|
20548
20670
|
getAgents,
|
|
@@ -20558,8 +20680,9 @@ export {
|
|
|
20558
20680
|
createSwarmMailAdapter,
|
|
20559
20681
|
createSocketAdapter,
|
|
20560
20682
|
createInMemorySwarmMail,
|
|
20683
|
+
createHiveAdapter,
|
|
20561
20684
|
createEvent,
|
|
20562
|
-
createBeadsAdapter,
|
|
20685
|
+
createHiveAdapter as createBeadsAdapter,
|
|
20563
20686
|
computeContentHash,
|
|
20564
20687
|
closeSwarmMail,
|
|
20565
20688
|
closeDatabase,
|
|
@@ -20570,11 +20693,12 @@ export {
|
|
|
20570
20693
|
checkSwarmHealth,
|
|
20571
20694
|
checkHealth,
|
|
20572
20695
|
checkConflicts,
|
|
20696
|
+
cellsViewMigration,
|
|
20573
20697
|
beadsMigrations,
|
|
20574
20698
|
beadsMigration,
|
|
20575
20699
|
appendEvents,
|
|
20576
20700
|
appendEvent,
|
|
20577
|
-
|
|
20701
|
+
appendCellEvent,
|
|
20578
20702
|
acknowledgeSwarmMessage,
|
|
20579
20703
|
acknowledgeMessage,
|
|
20580
20704
|
TaskStartedEventSchema,
|