swarm-mail 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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/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 +474 -379
- package/dist/streams/migrations.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/{beads → hive}/migrations.d.ts +0 -0
package/dist/index.js
CHANGED
|
@@ -16964,6 +16964,90 @@ var init_migrations = __esm(() => {
|
|
|
16964
16964
|
CREATE INDEX IF NOT EXISTS idx_swarm_contexts_epic ON swarm_contexts(epic_id);
|
|
16965
16965
|
CREATE INDEX IF NOT EXISTS idx_swarm_contexts_bead ON swarm_contexts(bead_id);
|
|
16966
16966
|
`
|
|
16967
|
+
},
|
|
16968
|
+
{
|
|
16969
|
+
version: 6,
|
|
16970
|
+
description: "Add core event store tables (events, agents, messages, reservations)",
|
|
16971
|
+
up: `
|
|
16972
|
+
-- Events table: append-only event log
|
|
16973
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
16974
|
+
id SERIAL PRIMARY KEY,
|
|
16975
|
+
sequence SERIAL,
|
|
16976
|
+
type TEXT NOT NULL,
|
|
16977
|
+
project_key TEXT NOT NULL,
|
|
16978
|
+
timestamp BIGINT NOT NULL,
|
|
16979
|
+
data JSONB NOT NULL DEFAULT '{}'
|
|
16980
|
+
);
|
|
16981
|
+
CREATE INDEX IF NOT EXISTS idx_events_project ON events(project_key);
|
|
16982
|
+
CREATE INDEX IF NOT EXISTS idx_events_type ON events(type);
|
|
16983
|
+
CREATE INDEX IF NOT EXISTS idx_events_sequence ON events(sequence);
|
|
16984
|
+
CREATE INDEX IF NOT EXISTS idx_events_timestamp ON events(timestamp);
|
|
16985
|
+
|
|
16986
|
+
-- Agents table: materialized view of registered agents
|
|
16987
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
16988
|
+
id SERIAL PRIMARY KEY,
|
|
16989
|
+
project_key TEXT NOT NULL,
|
|
16990
|
+
name TEXT NOT NULL,
|
|
16991
|
+
program TEXT,
|
|
16992
|
+
model TEXT,
|
|
16993
|
+
task_description TEXT,
|
|
16994
|
+
registered_at BIGINT NOT NULL,
|
|
16995
|
+
last_active_at BIGINT NOT NULL,
|
|
16996
|
+
UNIQUE(project_key, name)
|
|
16997
|
+
);
|
|
16998
|
+
CREATE INDEX IF NOT EXISTS idx_agents_project ON agents(project_key);
|
|
16999
|
+
|
|
17000
|
+
-- Messages table: materialized view of sent messages
|
|
17001
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
17002
|
+
id SERIAL PRIMARY KEY,
|
|
17003
|
+
project_key TEXT NOT NULL,
|
|
17004
|
+
from_agent TEXT NOT NULL,
|
|
17005
|
+
subject TEXT NOT NULL,
|
|
17006
|
+
body TEXT,
|
|
17007
|
+
thread_id TEXT,
|
|
17008
|
+
importance TEXT NOT NULL DEFAULT 'normal',
|
|
17009
|
+
ack_required BOOLEAN NOT NULL DEFAULT FALSE,
|
|
17010
|
+
created_at BIGINT NOT NULL
|
|
17011
|
+
);
|
|
17012
|
+
CREATE INDEX IF NOT EXISTS idx_messages_project ON messages(project_key);
|
|
17013
|
+
CREATE INDEX IF NOT EXISTS idx_messages_thread ON messages(thread_id);
|
|
17014
|
+
CREATE INDEX IF NOT EXISTS idx_messages_from ON messages(from_agent);
|
|
17015
|
+
|
|
17016
|
+
-- Message recipients: join table for message routing
|
|
17017
|
+
CREATE TABLE IF NOT EXISTS message_recipients (
|
|
17018
|
+
id SERIAL PRIMARY KEY,
|
|
17019
|
+
message_id INTEGER NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
|
|
17020
|
+
agent_name TEXT NOT NULL,
|
|
17021
|
+
read_at BIGINT,
|
|
17022
|
+
acked_at BIGINT,
|
|
17023
|
+
UNIQUE(message_id, agent_name)
|
|
17024
|
+
);
|
|
17025
|
+
CREATE INDEX IF NOT EXISTS idx_message_recipients_agent ON message_recipients(agent_name);
|
|
17026
|
+
CREATE INDEX IF NOT EXISTS idx_message_recipients_message ON message_recipients(message_id);
|
|
17027
|
+
|
|
17028
|
+
-- Reservations table: materialized view of file locks
|
|
17029
|
+
CREATE TABLE IF NOT EXISTS reservations (
|
|
17030
|
+
id SERIAL PRIMARY KEY,
|
|
17031
|
+
project_key TEXT NOT NULL,
|
|
17032
|
+
agent_name TEXT NOT NULL,
|
|
17033
|
+
path_pattern TEXT NOT NULL,
|
|
17034
|
+
exclusive BOOLEAN NOT NULL DEFAULT TRUE,
|
|
17035
|
+
reason TEXT,
|
|
17036
|
+
created_at BIGINT NOT NULL,
|
|
17037
|
+
expires_at BIGINT NOT NULL,
|
|
17038
|
+
released_at BIGINT
|
|
17039
|
+
);
|
|
17040
|
+
CREATE INDEX IF NOT EXISTS idx_reservations_project ON reservations(project_key);
|
|
17041
|
+
CREATE INDEX IF NOT EXISTS idx_reservations_agent ON reservations(agent_name);
|
|
17042
|
+
CREATE INDEX IF NOT EXISTS idx_reservations_expires ON reservations(expires_at);
|
|
17043
|
+
`,
|
|
17044
|
+
down: `
|
|
17045
|
+
DROP TABLE IF EXISTS message_recipients;
|
|
17046
|
+
DROP TABLE IF EXISTS messages;
|
|
17047
|
+
DROP TABLE IF EXISTS reservations;
|
|
17048
|
+
DROP TABLE IF EXISTS agents;
|
|
17049
|
+
DROP TABLE IF EXISTS events;
|
|
17050
|
+
`
|
|
16967
17051
|
}
|
|
16968
17052
|
];
|
|
16969
17053
|
});
|
|
@@ -18145,7 +18229,7 @@ var init_store = __esm(() => {
|
|
|
18145
18229
|
TIMESTAMP_SAFE_UNTIL = new Date("2286-01-01").getTime();
|
|
18146
18230
|
});
|
|
18147
18231
|
|
|
18148
|
-
// src/
|
|
18232
|
+
// src/hive/dependencies.ts
|
|
18149
18233
|
var exports_dependencies = {};
|
|
18150
18234
|
__export(exports_dependencies, {
|
|
18151
18235
|
wouldCreateCycle: () => wouldCreateCycle,
|
|
@@ -18154,82 +18238,82 @@ __export(exports_dependencies, {
|
|
|
18154
18238
|
invalidateBlockedCache: () => invalidateBlockedCache,
|
|
18155
18239
|
getOpenBlockers: () => getOpenBlockers
|
|
18156
18240
|
});
|
|
18157
|
-
async function wouldCreateCycle(db,
|
|
18241
|
+
async function wouldCreateCycle(db, cellId, dependsOnId) {
|
|
18158
18242
|
const result = await db.query(`WITH RECURSIVE paths AS (
|
|
18159
18243
|
-- Start from the target (what we want to depend on)
|
|
18160
18244
|
SELECT
|
|
18161
|
-
|
|
18245
|
+
cell_id,
|
|
18162
18246
|
depends_on_id,
|
|
18163
18247
|
1 as depth
|
|
18164
18248
|
FROM bead_dependencies
|
|
18165
|
-
WHERE
|
|
18249
|
+
WHERE cell_id = $2
|
|
18166
18250
|
|
|
18167
18251
|
UNION
|
|
18168
18252
|
|
|
18169
18253
|
-- Follow dependencies transitively
|
|
18170
18254
|
SELECT
|
|
18171
|
-
bd.
|
|
18255
|
+
bd.cell_id,
|
|
18172
18256
|
bd.depends_on_id,
|
|
18173
18257
|
p.depth + 1
|
|
18174
18258
|
FROM bead_dependencies bd
|
|
18175
|
-
JOIN paths p ON bd.
|
|
18259
|
+
JOIN paths p ON bd.cell_id = p.depends_on_id
|
|
18176
18260
|
WHERE p.depth < $3
|
|
18177
18261
|
)
|
|
18178
18262
|
SELECT EXISTS(
|
|
18179
18263
|
SELECT 1 FROM paths WHERE depends_on_id = $1
|
|
18180
|
-
) as exists`, [
|
|
18264
|
+
) as exists`, [cellId, dependsOnId, MAX_DEPENDENCY_DEPTH]);
|
|
18181
18265
|
return result.rows[0]?.exists ?? false;
|
|
18182
18266
|
}
|
|
18183
|
-
async function getOpenBlockers(db, projectKey,
|
|
18267
|
+
async function getOpenBlockers(db, projectKey, cellId) {
|
|
18184
18268
|
const result = await db.query(`WITH RECURSIVE blockers AS (
|
|
18185
18269
|
-- Direct blockers
|
|
18186
18270
|
SELECT depends_on_id as blocker_id, 1 as depth
|
|
18187
18271
|
FROM bead_dependencies
|
|
18188
|
-
WHERE
|
|
18272
|
+
WHERE cell_id = $1 AND relationship = 'blocks'
|
|
18189
18273
|
|
|
18190
18274
|
UNION
|
|
18191
18275
|
|
|
18192
18276
|
-- Transitive blockers
|
|
18193
18277
|
SELECT bd.depends_on_id, b.depth + 1
|
|
18194
18278
|
FROM bead_dependencies bd
|
|
18195
|
-
JOIN blockers b ON bd.
|
|
18279
|
+
JOIN blockers b ON bd.cell_id = b.blocker_id
|
|
18196
18280
|
WHERE bd.relationship = 'blocks' AND b.depth < $3
|
|
18197
18281
|
)
|
|
18198
18282
|
SELECT DISTINCT b.blocker_id
|
|
18199
18283
|
FROM blockers b
|
|
18200
18284
|
JOIN beads bead ON b.blocker_id = bead.id
|
|
18201
|
-
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]);
|
|
18202
18286
|
return result.rows.map((r) => r.blocker_id);
|
|
18203
18287
|
}
|
|
18204
|
-
async function rebuildBeadBlockedCache(db, projectKey,
|
|
18205
|
-
const blockerIds = await getOpenBlockers(db, projectKey,
|
|
18288
|
+
async function rebuildBeadBlockedCache(db, projectKey, cellId) {
|
|
18289
|
+
const blockerIds = await getOpenBlockers(db, projectKey, cellId);
|
|
18206
18290
|
if (blockerIds.length > 0) {
|
|
18207
|
-
await db.query(`INSERT INTO blocked_beads_cache (
|
|
18291
|
+
await db.query(`INSERT INTO blocked_beads_cache (cell_id, blocker_ids, updated_at)
|
|
18208
18292
|
VALUES ($1, $2, $3)
|
|
18209
|
-
ON CONFLICT (
|
|
18210
|
-
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()]);
|
|
18211
18295
|
} else {
|
|
18212
|
-
await db.query(`DELETE FROM blocked_beads_cache WHERE
|
|
18296
|
+
await db.query(`DELETE FROM blocked_beads_cache WHERE cell_id = $1`, [cellId]);
|
|
18213
18297
|
}
|
|
18214
18298
|
}
|
|
18215
18299
|
async function rebuildAllBlockedCaches(db, projectKey) {
|
|
18216
18300
|
const result = await db.query(`SELECT DISTINCT b.id FROM beads b
|
|
18217
|
-
JOIN bead_dependencies bd ON b.id = bd.
|
|
18301
|
+
JOIN bead_dependencies bd ON b.id = bd.cell_id
|
|
18218
18302
|
WHERE b.project_key = $1 AND bd.relationship = 'blocks' AND b.deleted_at IS NULL`, [projectKey]);
|
|
18219
18303
|
for (const row of result.rows) {
|
|
18220
18304
|
await rebuildBeadBlockedCache(db, projectKey, row.id);
|
|
18221
18305
|
}
|
|
18222
18306
|
}
|
|
18223
|
-
async function invalidateBlockedCache(db, projectKey,
|
|
18224
|
-
await rebuildBeadBlockedCache(db, projectKey,
|
|
18225
|
-
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]);
|
|
18226
18310
|
for (const row of dependents.rows) {
|
|
18227
|
-
await rebuildBeadBlockedCache(db, projectKey, row.
|
|
18311
|
+
await rebuildBeadBlockedCache(db, projectKey, row.cell_id);
|
|
18228
18312
|
}
|
|
18229
18313
|
}
|
|
18230
18314
|
var MAX_DEPENDENCY_DEPTH = 100;
|
|
18231
18315
|
|
|
18232
|
-
// src/
|
|
18316
|
+
// src/hive/migrations.ts
|
|
18233
18317
|
var exports_migrations2 = {};
|
|
18234
18318
|
__export(exports_migrations2, {
|
|
18235
18319
|
beadsMigrations: () => beadsMigrations,
|
|
@@ -18279,15 +18363,15 @@ var init_migrations2 = __esm(() => {
|
|
|
18279
18363
|
-- Dependencies Table
|
|
18280
18364
|
-- ========================================================================
|
|
18281
18365
|
CREATE TABLE IF NOT EXISTS bead_dependencies (
|
|
18282
|
-
|
|
18366
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18283
18367
|
depends_on_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18284
18368
|
relationship TEXT NOT NULL CHECK (relationship IN ('blocks', 'related', 'parent-child', 'discovered-from', 'replies-to', 'relates-to', 'duplicates', 'supersedes')),
|
|
18285
18369
|
created_at BIGINT NOT NULL,
|
|
18286
18370
|
created_by TEXT,
|
|
18287
|
-
PRIMARY KEY (
|
|
18371
|
+
PRIMARY KEY (cell_id, depends_on_id, relationship)
|
|
18288
18372
|
);
|
|
18289
18373
|
|
|
18290
|
-
CREATE INDEX IF NOT EXISTS idx_bead_deps_bead ON bead_dependencies(
|
|
18374
|
+
CREATE INDEX IF NOT EXISTS idx_bead_deps_bead ON bead_dependencies(cell_id);
|
|
18291
18375
|
CREATE INDEX IF NOT EXISTS idx_bead_deps_depends_on ON bead_dependencies(depends_on_id);
|
|
18292
18376
|
CREATE INDEX IF NOT EXISTS idx_bead_deps_relationship ON bead_dependencies(relationship);
|
|
18293
18377
|
|
|
@@ -18295,10 +18379,10 @@ var init_migrations2 = __esm(() => {
|
|
|
18295
18379
|
-- Labels Table
|
|
18296
18380
|
-- ========================================================================
|
|
18297
18381
|
CREATE TABLE IF NOT EXISTS bead_labels (
|
|
18298
|
-
|
|
18382
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18299
18383
|
label TEXT NOT NULL,
|
|
18300
18384
|
created_at BIGINT NOT NULL,
|
|
18301
|
-
PRIMARY KEY (
|
|
18385
|
+
PRIMARY KEY (cell_id, label)
|
|
18302
18386
|
);
|
|
18303
18387
|
|
|
18304
18388
|
CREATE INDEX IF NOT EXISTS idx_bead_labels_label ON bead_labels(label);
|
|
@@ -18308,7 +18392,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18308
18392
|
-- ========================================================================
|
|
18309
18393
|
CREATE TABLE IF NOT EXISTS bead_comments (
|
|
18310
18394
|
id SERIAL PRIMARY KEY,
|
|
18311
|
-
|
|
18395
|
+
cell_id TEXT NOT NULL REFERENCES beads(id) ON DELETE CASCADE,
|
|
18312
18396
|
author TEXT NOT NULL,
|
|
18313
18397
|
body TEXT NOT NULL,
|
|
18314
18398
|
parent_id INTEGER REFERENCES bead_comments(id) ON DELETE CASCADE,
|
|
@@ -18316,7 +18400,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18316
18400
|
updated_at BIGINT
|
|
18317
18401
|
);
|
|
18318
18402
|
|
|
18319
|
-
CREATE INDEX IF NOT EXISTS idx_bead_comments_bead ON bead_comments(
|
|
18403
|
+
CREATE INDEX IF NOT EXISTS idx_bead_comments_bead ON bead_comments(cell_id);
|
|
18320
18404
|
CREATE INDEX IF NOT EXISTS idx_bead_comments_author ON bead_comments(author);
|
|
18321
18405
|
CREATE INDEX IF NOT EXISTS idx_bead_comments_created ON bead_comments(created_at);
|
|
18322
18406
|
|
|
@@ -18326,7 +18410,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18326
18410
|
-- Materialized view for fast blocked queries
|
|
18327
18411
|
-- Updated by projections when dependencies change
|
|
18328
18412
|
CREATE TABLE IF NOT EXISTS blocked_beads_cache (
|
|
18329
|
-
|
|
18413
|
+
cell_id TEXT PRIMARY KEY REFERENCES beads(id) ON DELETE CASCADE,
|
|
18330
18414
|
blocker_ids TEXT[] NOT NULL,
|
|
18331
18415
|
updated_at BIGINT NOT NULL
|
|
18332
18416
|
);
|
|
@@ -18338,7 +18422,7 @@ var init_migrations2 = __esm(() => {
|
|
|
18338
18422
|
-- ========================================================================
|
|
18339
18423
|
-- Tracks beads that need JSONL export (incremental sync)
|
|
18340
18424
|
CREATE TABLE IF NOT EXISTS dirty_beads (
|
|
18341
|
-
|
|
18425
|
+
cell_id TEXT PRIMARY KEY REFERENCES beads(id) ON DELETE CASCADE,
|
|
18342
18426
|
marked_at BIGINT NOT NULL
|
|
18343
18427
|
);
|
|
18344
18428
|
|
|
@@ -18828,74 +18912,74 @@ async function closeAllSwarmMail() {
|
|
|
18828
18912
|
// src/index.ts
|
|
18829
18913
|
init_streams();
|
|
18830
18914
|
|
|
18831
|
-
// src/
|
|
18915
|
+
// src/hive/store.ts
|
|
18832
18916
|
init_streams();
|
|
18833
18917
|
|
|
18834
|
-
// src/
|
|
18918
|
+
// src/hive/projections.ts
|
|
18835
18919
|
async function updateProjections(db, event) {
|
|
18836
18920
|
switch (event.type) {
|
|
18837
|
-
case "
|
|
18921
|
+
case "cell_created":
|
|
18838
18922
|
await handleBeadCreated(db, event);
|
|
18839
18923
|
break;
|
|
18840
|
-
case "
|
|
18924
|
+
case "cell_updated":
|
|
18841
18925
|
await handleBeadUpdated(db, event);
|
|
18842
18926
|
break;
|
|
18843
|
-
case "
|
|
18844
|
-
await
|
|
18927
|
+
case "cell_status_changed":
|
|
18928
|
+
await handleCellStatusChanged(db, event);
|
|
18845
18929
|
break;
|
|
18846
|
-
case "
|
|
18930
|
+
case "cell_closed":
|
|
18847
18931
|
await handleBeadClosed(db, event);
|
|
18848
18932
|
break;
|
|
18849
|
-
case "
|
|
18933
|
+
case "cell_reopened":
|
|
18850
18934
|
await handleBeadReopened(db, event);
|
|
18851
18935
|
break;
|
|
18852
|
-
case "
|
|
18936
|
+
case "cell_deleted":
|
|
18853
18937
|
await handleBeadDeleted(db, event);
|
|
18854
18938
|
break;
|
|
18855
|
-
case "
|
|
18939
|
+
case "cell_dependency_added":
|
|
18856
18940
|
await handleDependencyAdded(db, event);
|
|
18857
18941
|
break;
|
|
18858
|
-
case "
|
|
18942
|
+
case "cell_dependency_removed":
|
|
18859
18943
|
await handleDependencyRemoved(db, event);
|
|
18860
18944
|
break;
|
|
18861
|
-
case "
|
|
18945
|
+
case "cell_label_added":
|
|
18862
18946
|
await handleLabelAdded(db, event);
|
|
18863
18947
|
break;
|
|
18864
|
-
case "
|
|
18948
|
+
case "cell_label_removed":
|
|
18865
18949
|
await handleLabelRemoved(db, event);
|
|
18866
18950
|
break;
|
|
18867
|
-
case "
|
|
18951
|
+
case "cell_comment_added":
|
|
18868
18952
|
await handleCommentAdded(db, event);
|
|
18869
18953
|
break;
|
|
18870
|
-
case "
|
|
18954
|
+
case "cell_comment_updated":
|
|
18871
18955
|
await handleCommentUpdated(db, event);
|
|
18872
18956
|
break;
|
|
18873
|
-
case "
|
|
18957
|
+
case "cell_comment_deleted":
|
|
18874
18958
|
await handleCommentDeleted(db, event);
|
|
18875
18959
|
break;
|
|
18876
|
-
case "
|
|
18960
|
+
case "cell_epic_child_added":
|
|
18877
18961
|
await handleEpicChildAdded(db, event);
|
|
18878
18962
|
break;
|
|
18879
|
-
case "
|
|
18963
|
+
case "cell_epic_child_removed":
|
|
18880
18964
|
await handleEpicChildRemoved(db, event);
|
|
18881
18965
|
break;
|
|
18882
|
-
case "
|
|
18966
|
+
case "cell_assigned":
|
|
18883
18967
|
await handleBeadAssigned(db, event);
|
|
18884
18968
|
break;
|
|
18885
|
-
case "
|
|
18969
|
+
case "cell_work_started":
|
|
18886
18970
|
await handleWorkStarted(db, event);
|
|
18887
18971
|
break;
|
|
18888
18972
|
default:
|
|
18889
18973
|
console.warn(`[beads/projections] Unknown event type: ${event.type}`);
|
|
18890
18974
|
}
|
|
18891
|
-
await markBeadDirty(db, event.project_key, event.
|
|
18975
|
+
await markBeadDirty(db, event.project_key, event.cell_id);
|
|
18892
18976
|
}
|
|
18893
18977
|
async function handleBeadCreated(db, event) {
|
|
18894
18978
|
await db.query(`INSERT INTO beads (
|
|
18895
18979
|
id, project_key, type, status, title, description, priority,
|
|
18896
18980
|
parent_id, assignee, created_at, updated_at, created_by
|
|
18897
18981
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [
|
|
18898
|
-
event.
|
|
18982
|
+
event.cell_id,
|
|
18899
18983
|
event.project_key,
|
|
18900
18984
|
event.issue_type,
|
|
18901
18985
|
"open",
|
|
@@ -18933,12 +19017,12 @@ async function handleBeadUpdated(db, event) {
|
|
|
18933
19017
|
if (updates.length > 0) {
|
|
18934
19018
|
updates.push(`updated_at = $${paramIndex++}`);
|
|
18935
19019
|
params.push(event.timestamp);
|
|
18936
|
-
params.push(event.
|
|
19020
|
+
params.push(event.cell_id);
|
|
18937
19021
|
await db.query(`UPDATE beads SET ${updates.join(", ")} WHERE id = $${paramIndex}`, params);
|
|
18938
19022
|
}
|
|
18939
19023
|
}
|
|
18940
|
-
async function
|
|
18941
|
-
await db.query(`UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3`, [event.to_status, event.timestamp, event.
|
|
19024
|
+
async function handleCellStatusChanged(db, event) {
|
|
19025
|
+
await db.query(`UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3`, [event.to_status, event.timestamp, event.cell_id]);
|
|
18942
19026
|
}
|
|
18943
19027
|
async function handleBeadClosed(db, event) {
|
|
18944
19028
|
await db.query(`UPDATE beads SET
|
|
@@ -18946,9 +19030,9 @@ async function handleBeadClosed(db, event) {
|
|
|
18946
19030
|
closed_at = $1,
|
|
18947
19031
|
closed_reason = $2,
|
|
18948
19032
|
updated_at = $3
|
|
18949
|
-
WHERE id = $4`, [event.timestamp, event.reason, event.timestamp, event.
|
|
19033
|
+
WHERE id = $4`, [event.timestamp, event.reason, event.timestamp, event.cell_id]);
|
|
18950
19034
|
const { invalidateBlockedCache: invalidateBlockedCache2 } = await Promise.resolve().then(() => exports_dependencies);
|
|
18951
|
-
await invalidateBlockedCache2(db, event.project_key, event.
|
|
19035
|
+
await invalidateBlockedCache2(db, event.project_key, event.cell_id);
|
|
18952
19036
|
}
|
|
18953
19037
|
async function handleBeadReopened(db, event) {
|
|
18954
19038
|
await db.query(`UPDATE beads SET
|
|
@@ -18956,7 +19040,7 @@ async function handleBeadReopened(db, event) {
|
|
|
18956
19040
|
closed_at = NULL,
|
|
18957
19041
|
closed_reason = NULL,
|
|
18958
19042
|
updated_at = $1
|
|
18959
|
-
WHERE id = $2`, [event.timestamp, event.
|
|
19043
|
+
WHERE id = $2`, [event.timestamp, event.cell_id]);
|
|
18960
19044
|
}
|
|
18961
19045
|
async function handleBeadDeleted(db, event) {
|
|
18962
19046
|
await db.query(`UPDATE beads SET
|
|
@@ -18964,34 +19048,34 @@ async function handleBeadDeleted(db, event) {
|
|
|
18964
19048
|
deleted_by = $2,
|
|
18965
19049
|
delete_reason = $3,
|
|
18966
19050
|
updated_at = $4
|
|
18967
|
-
WHERE id = $5`, [event.timestamp, event.deleted_by || null, event.reason || null, event.timestamp, event.
|
|
19051
|
+
WHERE id = $5`, [event.timestamp, event.deleted_by || null, event.reason || null, event.timestamp, event.cell_id]);
|
|
18968
19052
|
}
|
|
18969
19053
|
async function handleDependencyAdded(db, event) {
|
|
18970
19054
|
const dep = event.dependency;
|
|
18971
|
-
await db.query(`INSERT INTO bead_dependencies (
|
|
19055
|
+
await db.query(`INSERT INTO bead_dependencies (cell_id, depends_on_id, relationship, created_at, created_by)
|
|
18972
19056
|
VALUES ($1, $2, $3, $4, $5)
|
|
18973
|
-
ON CONFLICT (
|
|
19057
|
+
ON CONFLICT (cell_id, depends_on_id, relationship) DO NOTHING`, [event.cell_id, dep.target, dep.type, event.timestamp, event.added_by || null]);
|
|
18974
19058
|
const { invalidateBlockedCache: invalidate } = await Promise.resolve().then(() => exports_dependencies);
|
|
18975
|
-
await invalidate(db, event.project_key, event.
|
|
19059
|
+
await invalidate(db, event.project_key, event.cell_id);
|
|
18976
19060
|
}
|
|
18977
19061
|
async function handleDependencyRemoved(db, event) {
|
|
18978
19062
|
const dep = event.dependency;
|
|
18979
19063
|
await db.query(`DELETE FROM bead_dependencies
|
|
18980
|
-
WHERE
|
|
19064
|
+
WHERE cell_id = $1 AND depends_on_id = $2 AND relationship = $3`, [event.cell_id, dep.target, dep.type]);
|
|
18981
19065
|
const { invalidateBlockedCache: invalidate } = await Promise.resolve().then(() => exports_dependencies);
|
|
18982
|
-
await invalidate(db, event.project_key, event.
|
|
19066
|
+
await invalidate(db, event.project_key, event.cell_id);
|
|
18983
19067
|
}
|
|
18984
19068
|
async function handleLabelAdded(db, event) {
|
|
18985
|
-
await db.query(`INSERT INTO bead_labels (
|
|
19069
|
+
await db.query(`INSERT INTO bead_labels (cell_id, label, created_at)
|
|
18986
19070
|
VALUES ($1, $2, $3)
|
|
18987
|
-
ON CONFLICT (
|
|
19071
|
+
ON CONFLICT (cell_id, label) DO NOTHING`, [event.cell_id, event.label, event.timestamp]);
|
|
18988
19072
|
}
|
|
18989
19073
|
async function handleLabelRemoved(db, event) {
|
|
18990
|
-
await db.query(`DELETE FROM bead_labels WHERE
|
|
19074
|
+
await db.query(`DELETE FROM bead_labels WHERE cell_id = $1 AND label = $2`, [event.cell_id, event.label]);
|
|
18991
19075
|
}
|
|
18992
19076
|
async function handleCommentAdded(db, event) {
|
|
18993
|
-
await db.query(`INSERT INTO bead_comments (
|
|
18994
|
-
VALUES ($1, $2, $3, $4, $5)`, [event.
|
|
19077
|
+
await db.query(`INSERT INTO bead_comments (cell_id, author, body, parent_id, created_at)
|
|
19078
|
+
VALUES ($1, $2, $3, $4, $5)`, [event.cell_id, event.author, event.body, event.parent_comment_id || null, event.timestamp]);
|
|
18995
19079
|
}
|
|
18996
19080
|
async function handleCommentUpdated(db, event) {
|
|
18997
19081
|
await db.query(`UPDATE bead_comments SET body = $1, updated_at = $2 WHERE id = $3`, [event.new_body, event.timestamp, event.comment_id]);
|
|
@@ -19000,22 +19084,22 @@ async function handleCommentDeleted(db, event) {
|
|
|
19000
19084
|
await db.query(`DELETE FROM bead_comments WHERE id = $1`, [event.comment_id]);
|
|
19001
19085
|
}
|
|
19002
19086
|
async function handleEpicChildAdded(db, event) {
|
|
19003
|
-
await db.query(`UPDATE beads SET parent_id = $1, updated_at = $2 WHERE id = $3`, [event.
|
|
19087
|
+
await db.query(`UPDATE beads SET parent_id = $1, updated_at = $2 WHERE id = $3`, [event.cell_id, event.timestamp, event.child_id]);
|
|
19004
19088
|
}
|
|
19005
19089
|
async function handleEpicChildRemoved(db, event) {
|
|
19006
19090
|
await db.query(`UPDATE beads SET parent_id = NULL, updated_at = $1 WHERE id = $2`, [event.timestamp, event.child_id]);
|
|
19007
19091
|
}
|
|
19008
19092
|
async function handleBeadAssigned(db, event) {
|
|
19009
|
-
await db.query(`UPDATE beads SET assignee = $1, updated_at = $2 WHERE id = $3`, [event.assignee, event.timestamp, event.
|
|
19093
|
+
await db.query(`UPDATE beads SET assignee = $1, updated_at = $2 WHERE id = $3`, [event.assignee, event.timestamp, event.cell_id]);
|
|
19010
19094
|
}
|
|
19011
19095
|
async function handleWorkStarted(db, event) {
|
|
19012
|
-
await db.query(`UPDATE beads SET status = 'in_progress', updated_at = $1 WHERE id = $2`, [event.timestamp, event.
|
|
19096
|
+
await db.query(`UPDATE beads SET status = 'in_progress', updated_at = $1 WHERE id = $2`, [event.timestamp, event.cell_id]);
|
|
19013
19097
|
}
|
|
19014
|
-
async function
|
|
19015
|
-
const result = await db.query(`SELECT * FROM beads WHERE project_key = $1 AND id = $2 AND deleted_at IS NULL`, [projectKey,
|
|
19098
|
+
async function getCell(db, projectKey, cellId) {
|
|
19099
|
+
const result = await db.query(`SELECT * FROM beads WHERE project_key = $1 AND id = $2 AND deleted_at IS NULL`, [projectKey, cellId]);
|
|
19016
19100
|
return result.rows[0] ?? null;
|
|
19017
19101
|
}
|
|
19018
|
-
async function
|
|
19102
|
+
async function queryCells(db, projectKey, options = {}) {
|
|
19019
19103
|
const conditions = ["project_key = $1"];
|
|
19020
19104
|
const params = [projectKey];
|
|
19021
19105
|
let paramIndex = 2;
|
|
@@ -19052,81 +19136,81 @@ async function queryBeads(db, projectKey, options = {}) {
|
|
|
19052
19136
|
const result = await db.query(query, params);
|
|
19053
19137
|
return result.rows;
|
|
19054
19138
|
}
|
|
19055
|
-
async function getDependencies(db, projectKey,
|
|
19056
|
-
const result = await db.query(`SELECT * FROM bead_dependencies WHERE
|
|
19139
|
+
async function getDependencies(db, projectKey, cellId) {
|
|
19140
|
+
const result = await db.query(`SELECT * FROM bead_dependencies WHERE cell_id = $1`, [cellId]);
|
|
19057
19141
|
return result.rows;
|
|
19058
19142
|
}
|
|
19059
|
-
async function getDependents(db, projectKey,
|
|
19060
|
-
const result = await db.query(`SELECT * FROM bead_dependencies WHERE depends_on_id = $1`, [
|
|
19143
|
+
async function getDependents(db, projectKey, cellId) {
|
|
19144
|
+
const result = await db.query(`SELECT * FROM bead_dependencies WHERE depends_on_id = $1`, [cellId]);
|
|
19061
19145
|
return result.rows;
|
|
19062
19146
|
}
|
|
19063
|
-
async function isBlocked(db, projectKey,
|
|
19064
|
-
const result = await db.query(`SELECT EXISTS(SELECT 1 FROM blocked_beads_cache WHERE
|
|
19147
|
+
async function isBlocked(db, projectKey, cellId) {
|
|
19148
|
+
const result = await db.query(`SELECT EXISTS(SELECT 1 FROM blocked_beads_cache WHERE cell_id = $1) as exists`, [cellId]);
|
|
19065
19149
|
return result.rows[0]?.exists ?? false;
|
|
19066
19150
|
}
|
|
19067
|
-
async function getBlockers(db, projectKey,
|
|
19068
|
-
const result = await db.query(`SELECT blocker_ids FROM blocked_beads_cache WHERE
|
|
19151
|
+
async function getBlockers(db, projectKey, cellId) {
|
|
19152
|
+
const result = await db.query(`SELECT blocker_ids FROM blocked_beads_cache WHERE cell_id = $1`, [cellId]);
|
|
19069
19153
|
return result.rows[0]?.blocker_ids ?? [];
|
|
19070
19154
|
}
|
|
19071
|
-
async function getLabels(db, projectKey,
|
|
19072
|
-
const result = await db.query(`SELECT label FROM bead_labels WHERE
|
|
19155
|
+
async function getLabels(db, projectKey, cellId) {
|
|
19156
|
+
const result = await db.query(`SELECT label FROM bead_labels WHERE cell_id = $1 ORDER BY label`, [cellId]);
|
|
19073
19157
|
return result.rows.map((r) => r.label);
|
|
19074
19158
|
}
|
|
19075
|
-
async function getComments(db, projectKey,
|
|
19076
|
-
const result = await db.query(`SELECT * FROM bead_comments WHERE
|
|
19159
|
+
async function getComments(db, projectKey, cellId) {
|
|
19160
|
+
const result = await db.query(`SELECT * FROM bead_comments WHERE cell_id = $1 ORDER BY created_at ASC`, [cellId]);
|
|
19077
19161
|
return result.rows;
|
|
19078
19162
|
}
|
|
19079
|
-
async function
|
|
19163
|
+
async function getNextReadyCell(db, projectKey) {
|
|
19080
19164
|
const result = await db.query(`SELECT b.* FROM beads b
|
|
19081
19165
|
WHERE b.project_key = $1
|
|
19082
19166
|
AND b.status = 'open'
|
|
19083
19167
|
AND b.deleted_at IS NULL
|
|
19084
19168
|
AND NOT EXISTS (
|
|
19085
|
-
SELECT 1 FROM blocked_beads_cache bbc WHERE bbc.
|
|
19169
|
+
SELECT 1 FROM blocked_beads_cache bbc WHERE bbc.cell_id = b.id
|
|
19086
19170
|
)
|
|
19087
19171
|
ORDER BY b.priority DESC, b.created_at ASC
|
|
19088
19172
|
LIMIT 1`, [projectKey]);
|
|
19089
19173
|
return result.rows[0] ?? null;
|
|
19090
19174
|
}
|
|
19091
|
-
async function
|
|
19175
|
+
async function getInProgressCells(db, projectKey) {
|
|
19092
19176
|
const result = await db.query(`SELECT * FROM beads
|
|
19093
19177
|
WHERE project_key = $1 AND status = 'in_progress' AND deleted_at IS NULL
|
|
19094
19178
|
ORDER BY priority DESC, created_at ASC`, [projectKey]);
|
|
19095
19179
|
return result.rows;
|
|
19096
19180
|
}
|
|
19097
|
-
async function
|
|
19181
|
+
async function getBlockedCells(db, projectKey) {
|
|
19098
19182
|
const result = await db.query(`SELECT b.*, bbc.blocker_ids
|
|
19099
19183
|
FROM beads b
|
|
19100
|
-
JOIN blocked_beads_cache bbc ON b.id =
|
|
19184
|
+
JOIN blocked_beads_cache bbc ON b.id = bcc.cell_id
|
|
19101
19185
|
WHERE b.project_key = $1 AND b.deleted_at IS NULL
|
|
19102
19186
|
ORDER BY b.priority DESC, b.created_at ASC`, [projectKey]);
|
|
19103
19187
|
return result.rows.map((r) => {
|
|
19104
|
-
const { blocker_ids, ...
|
|
19105
|
-
return {
|
|
19188
|
+
const { blocker_ids, ...cellData } = r;
|
|
19189
|
+
return { cell: cellData, blockers: blocker_ids };
|
|
19106
19190
|
});
|
|
19107
19191
|
}
|
|
19108
|
-
async function markBeadDirty(db, projectKey,
|
|
19109
|
-
await db.query(`INSERT INTO dirty_beads (
|
|
19192
|
+
async function markBeadDirty(db, projectKey, cellId) {
|
|
19193
|
+
await db.query(`INSERT INTO dirty_beads (cell_id, marked_at)
|
|
19110
19194
|
VALUES ($1, $2)
|
|
19111
|
-
ON CONFLICT (
|
|
19195
|
+
ON CONFLICT (cell_id) DO UPDATE SET marked_at = $2`, [cellId, Date.now()]);
|
|
19112
19196
|
}
|
|
19113
|
-
async function
|
|
19114
|
-
const result = await db.query(`SELECT db.
|
|
19115
|
-
JOIN beads b ON db.
|
|
19197
|
+
async function getDirtyCells(db, projectKey) {
|
|
19198
|
+
const result = await db.query(`SELECT db.cell_id FROM dirty_beads db
|
|
19199
|
+
JOIN beads b ON db.cell_id = b.id
|
|
19116
19200
|
WHERE b.project_key = $1
|
|
19117
19201
|
ORDER BY db.marked_at ASC`, [projectKey]);
|
|
19118
|
-
return result.rows.map((r) => r.
|
|
19202
|
+
return result.rows.map((r) => r.cell_id);
|
|
19119
19203
|
}
|
|
19120
|
-
async function clearDirtyBead(db, projectKey,
|
|
19121
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19204
|
+
async function clearDirtyBead(db, projectKey, cellId) {
|
|
19205
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id = $1`, [cellId]);
|
|
19122
19206
|
}
|
|
19123
19207
|
async function clearAllDirtyBeads(db, projectKey) {
|
|
19124
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19208
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id IN (
|
|
19125
19209
|
SELECT id FROM beads WHERE project_key = $1
|
|
19126
19210
|
)`, [projectKey]);
|
|
19127
19211
|
}
|
|
19128
19212
|
|
|
19129
|
-
// src/
|
|
19213
|
+
// src/hive/store.ts
|
|
19130
19214
|
function parseTimestamp2(timestamp) {
|
|
19131
19215
|
const ts = parseInt(timestamp, 10);
|
|
19132
19216
|
if (Number.isNaN(ts)) {
|
|
@@ -19137,7 +19221,7 @@ function parseTimestamp2(timestamp) {
|
|
|
19137
19221
|
}
|
|
19138
19222
|
return ts;
|
|
19139
19223
|
}
|
|
19140
|
-
async function
|
|
19224
|
+
async function appendCellEvent(event, projectPath, dbOverride) {
|
|
19141
19225
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19142
19226
|
const { type, project_key, timestamp, ...rest } = event;
|
|
19143
19227
|
const result = await db.query(`INSERT INTO events (type, project_key, timestamp, data)
|
|
@@ -19151,20 +19235,20 @@ async function appendBeadEvent(event, projectPath, dbOverride) {
|
|
|
19151
19235
|
await updateProjections(db, { ...event, id, sequence });
|
|
19152
19236
|
return { ...event, id, sequence };
|
|
19153
19237
|
}
|
|
19154
|
-
async function
|
|
19155
|
-
return withTiming("
|
|
19238
|
+
async function readCellEvents(options = {}, projectPath, dbOverride) {
|
|
19239
|
+
return withTiming("readCellEvents", async () => {
|
|
19156
19240
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19157
19241
|
const conditions = [];
|
|
19158
19242
|
const params = [];
|
|
19159
19243
|
let paramIndex = 1;
|
|
19160
|
-
conditions.push(`type LIKE '
|
|
19244
|
+
conditions.push(`type LIKE 'cell_%'`);
|
|
19161
19245
|
if (options.projectKey) {
|
|
19162
19246
|
conditions.push(`project_key = $${paramIndex++}`);
|
|
19163
19247
|
params.push(options.projectKey);
|
|
19164
19248
|
}
|
|
19165
|
-
if (options.
|
|
19166
|
-
conditions.push(`data->>'
|
|
19167
|
-
params.push(options.
|
|
19249
|
+
if (options.cellId) {
|
|
19250
|
+
conditions.push(`data->>'cell_id' = $${paramIndex++}`);
|
|
19251
|
+
params.push(options.cellId);
|
|
19168
19252
|
}
|
|
19169
19253
|
if (options.types && options.types.length > 0) {
|
|
19170
19254
|
conditions.push(`type = ANY($${paramIndex++})`);
|
|
@@ -19211,25 +19295,25 @@ async function readBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19211
19295
|
});
|
|
19212
19296
|
});
|
|
19213
19297
|
}
|
|
19214
|
-
async function
|
|
19215
|
-
return withTiming("
|
|
19298
|
+
async function replayCellEvents(options = {}, projectPath, dbOverride) {
|
|
19299
|
+
return withTiming("replayCellEvents", async () => {
|
|
19216
19300
|
const startTime = Date.now();
|
|
19217
19301
|
const db = dbOverride ?? await getDatabase(projectPath);
|
|
19218
19302
|
if (options.clearViews) {
|
|
19219
19303
|
if (options.projectKey) {
|
|
19220
|
-
await db.query(`DELETE FROM bead_comments WHERE
|
|
19304
|
+
await db.query(`DELETE FROM bead_comments WHERE cell_id IN (
|
|
19221
19305
|
SELECT id FROM beads WHERE project_key = $1
|
|
19222
19306
|
)`, [options.projectKey]);
|
|
19223
|
-
await db.query(`DELETE FROM bead_labels WHERE
|
|
19307
|
+
await db.query(`DELETE FROM bead_labels WHERE cell_id IN (
|
|
19224
19308
|
SELECT id FROM beads WHERE project_key = $1
|
|
19225
19309
|
)`, [options.projectKey]);
|
|
19226
|
-
await db.query(`DELETE FROM bead_dependencies WHERE
|
|
19310
|
+
await db.query(`DELETE FROM bead_dependencies WHERE cell_id IN (
|
|
19227
19311
|
SELECT id FROM beads WHERE project_key = $1
|
|
19228
19312
|
)`, [options.projectKey]);
|
|
19229
|
-
await db.query(`DELETE FROM blocked_beads_cache WHERE
|
|
19313
|
+
await db.query(`DELETE FROM blocked_beads_cache WHERE cell_id IN (
|
|
19230
19314
|
SELECT id FROM beads WHERE project_key = $1
|
|
19231
19315
|
)`, [options.projectKey]);
|
|
19232
|
-
await db.query(`DELETE FROM dirty_beads WHERE
|
|
19316
|
+
await db.query(`DELETE FROM dirty_beads WHERE cell_id IN (
|
|
19233
19317
|
SELECT id FROM beads WHERE project_key = $1
|
|
19234
19318
|
)`, [options.projectKey]);
|
|
19235
19319
|
await db.query(`DELETE FROM beads WHERE project_key = $1`, [
|
|
@@ -19246,7 +19330,7 @@ async function replayBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19246
19330
|
`);
|
|
19247
19331
|
}
|
|
19248
19332
|
}
|
|
19249
|
-
const events2 = await
|
|
19333
|
+
const events2 = await readCellEvents({
|
|
19250
19334
|
projectKey: options.projectKey,
|
|
19251
19335
|
afterSequence: options.fromSequence
|
|
19252
19336
|
}, projectPath, dbOverride);
|
|
@@ -19260,14 +19344,14 @@ async function replayBeadEvents(options = {}, projectPath, dbOverride) {
|
|
|
19260
19344
|
});
|
|
19261
19345
|
}
|
|
19262
19346
|
|
|
19263
|
-
// src/
|
|
19264
|
-
function
|
|
19347
|
+
// src/hive/adapter.ts
|
|
19348
|
+
function createHiveAdapter(db, projectKey) {
|
|
19265
19349
|
return {
|
|
19266
|
-
async
|
|
19350
|
+
async createCell(projectKeyParam, options, projectPath) {
|
|
19267
19351
|
const event = {
|
|
19268
|
-
type: "
|
|
19352
|
+
type: "cell_created",
|
|
19269
19353
|
project_key: projectKeyParam,
|
|
19270
|
-
|
|
19354
|
+
cell_id: generateBeadId(projectKeyParam),
|
|
19271
19355
|
timestamp: Date.now(),
|
|
19272
19356
|
title: options.title,
|
|
19273
19357
|
description: options.description || null,
|
|
@@ -19277,34 +19361,34 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19277
19361
|
created_by: options.created_by || null,
|
|
19278
19362
|
metadata: options.metadata || null
|
|
19279
19363
|
};
|
|
19280
|
-
await
|
|
19364
|
+
await appendCellEvent(event, projectPath, db);
|
|
19281
19365
|
if (options.assignee) {
|
|
19282
19366
|
const assignEvent = {
|
|
19283
|
-
type: "
|
|
19367
|
+
type: "cell_assigned",
|
|
19284
19368
|
project_key: projectKeyParam,
|
|
19285
|
-
|
|
19369
|
+
cell_id: event.cell_id,
|
|
19286
19370
|
timestamp: Date.now(),
|
|
19287
19371
|
assignee: options.assignee,
|
|
19288
19372
|
assigned_by: options.created_by || null
|
|
19289
19373
|
};
|
|
19290
|
-
await
|
|
19374
|
+
await appendCellEvent(assignEvent, projectPath, db);
|
|
19291
19375
|
}
|
|
19292
|
-
const bead = await
|
|
19376
|
+
const bead = await getCell(db, projectKeyParam, event.cell_id);
|
|
19293
19377
|
if (!bead) {
|
|
19294
|
-
throw new Error(`[
|
|
19378
|
+
throw new Error(`[HiveAdapter] Failed to create bead - not found after insert`);
|
|
19295
19379
|
}
|
|
19296
19380
|
return bead;
|
|
19297
19381
|
},
|
|
19298
|
-
async
|
|
19299
|
-
return
|
|
19382
|
+
async getCell(projectKeyParam, cellId, projectPath) {
|
|
19383
|
+
return getCell(db, projectKeyParam, cellId);
|
|
19300
19384
|
},
|
|
19301
|
-
async
|
|
19302
|
-
return
|
|
19385
|
+
async queryCells(projectKeyParam, options, projectPath) {
|
|
19386
|
+
return queryCells(db, projectKeyParam, options);
|
|
19303
19387
|
},
|
|
19304
|
-
async
|
|
19305
|
-
const existingBead = await
|
|
19388
|
+
async updateCell(projectKeyParam, cellId, options, projectPath) {
|
|
19389
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19306
19390
|
if (!existingBead) {
|
|
19307
|
-
throw new Error(`[
|
|
19391
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19308
19392
|
}
|
|
19309
19393
|
const changes = {};
|
|
19310
19394
|
if (options.title && options.title !== existingBead.title) {
|
|
@@ -19323,120 +19407,120 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19323
19407
|
return existingBead;
|
|
19324
19408
|
}
|
|
19325
19409
|
const event = {
|
|
19326
|
-
type: "
|
|
19410
|
+
type: "cell_updated",
|
|
19327
19411
|
project_key: projectKeyParam,
|
|
19328
|
-
|
|
19412
|
+
cell_id: cellId,
|
|
19329
19413
|
timestamp: Date.now(),
|
|
19330
19414
|
changes,
|
|
19331
19415
|
updated_by: options.updated_by || null
|
|
19332
19416
|
};
|
|
19333
|
-
await
|
|
19334
|
-
const updated = await
|
|
19417
|
+
await appendCellEvent(event, projectPath, db);
|
|
19418
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19335
19419
|
if (!updated) {
|
|
19336
|
-
throw new Error(`[
|
|
19420
|
+
throw new Error(`[HiveAdapter] Bead disappeared after update: ${cellId}`);
|
|
19337
19421
|
}
|
|
19338
19422
|
return updated;
|
|
19339
19423
|
},
|
|
19340
|
-
async
|
|
19341
|
-
const existingBead = await
|
|
19424
|
+
async changeCellStatus(projectKeyParam, cellId, toStatus, options, projectPath) {
|
|
19425
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19342
19426
|
if (!existingBead) {
|
|
19343
|
-
throw new Error(`[
|
|
19427
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19344
19428
|
}
|
|
19345
19429
|
const event = {
|
|
19346
|
-
type: "
|
|
19430
|
+
type: "cell_status_changed",
|
|
19347
19431
|
project_key: projectKeyParam,
|
|
19348
|
-
|
|
19432
|
+
cell_id: cellId,
|
|
19349
19433
|
timestamp: Date.now(),
|
|
19350
19434
|
from_status: existingBead.status,
|
|
19351
19435
|
to_status: toStatus,
|
|
19352
19436
|
reason: options?.reason || null,
|
|
19353
19437
|
changed_by: options?.changed_by || null
|
|
19354
19438
|
};
|
|
19355
|
-
await
|
|
19356
|
-
const updated = await
|
|
19439
|
+
await appendCellEvent(event, projectPath, db);
|
|
19440
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19357
19441
|
if (!updated) {
|
|
19358
|
-
throw new Error(`[
|
|
19442
|
+
throw new Error(`[HiveAdapter] Bead disappeared after status change: ${cellId}`);
|
|
19359
19443
|
}
|
|
19360
19444
|
return updated;
|
|
19361
19445
|
},
|
|
19362
|
-
async
|
|
19363
|
-
const existingBead = await
|
|
19446
|
+
async closeCell(projectKeyParam, cellId, reason, options, projectPath) {
|
|
19447
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19364
19448
|
if (!existingBead) {
|
|
19365
|
-
throw new Error(`[
|
|
19449
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19366
19450
|
}
|
|
19367
19451
|
const event = {
|
|
19368
|
-
type: "
|
|
19452
|
+
type: "cell_closed",
|
|
19369
19453
|
project_key: projectKeyParam,
|
|
19370
|
-
|
|
19454
|
+
cell_id: cellId,
|
|
19371
19455
|
timestamp: Date.now(),
|
|
19372
19456
|
reason,
|
|
19373
19457
|
closed_by: options?.closed_by || null,
|
|
19374
19458
|
files_touched: options?.files_touched || null,
|
|
19375
19459
|
duration_ms: options?.duration_ms || null
|
|
19376
19460
|
};
|
|
19377
|
-
await
|
|
19378
|
-
const updated = await
|
|
19461
|
+
await appendCellEvent(event, projectPath, db);
|
|
19462
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19379
19463
|
if (!updated) {
|
|
19380
|
-
throw new Error(`[
|
|
19464
|
+
throw new Error(`[HiveAdapter] Bead disappeared after close: ${cellId}`);
|
|
19381
19465
|
}
|
|
19382
19466
|
return updated;
|
|
19383
19467
|
},
|
|
19384
|
-
async
|
|
19385
|
-
const existingBead = await
|
|
19468
|
+
async reopenCell(projectKeyParam, cellId, options, projectPath) {
|
|
19469
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19386
19470
|
if (!existingBead) {
|
|
19387
|
-
throw new Error(`[
|
|
19471
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19388
19472
|
}
|
|
19389
19473
|
const event = {
|
|
19390
|
-
type: "
|
|
19474
|
+
type: "cell_reopened",
|
|
19391
19475
|
project_key: projectKeyParam,
|
|
19392
|
-
|
|
19476
|
+
cell_id: cellId,
|
|
19393
19477
|
timestamp: Date.now(),
|
|
19394
19478
|
reason: options?.reason || null,
|
|
19395
19479
|
reopened_by: options?.reopened_by || null
|
|
19396
19480
|
};
|
|
19397
|
-
await
|
|
19398
|
-
const updated = await
|
|
19481
|
+
await appendCellEvent(event, projectPath, db);
|
|
19482
|
+
const updated = await getCell(db, projectKeyParam, cellId);
|
|
19399
19483
|
if (!updated) {
|
|
19400
|
-
throw new Error(`[
|
|
19484
|
+
throw new Error(`[HiveAdapter] Bead disappeared after reopen: ${cellId}`);
|
|
19401
19485
|
}
|
|
19402
19486
|
return updated;
|
|
19403
19487
|
},
|
|
19404
|
-
async
|
|
19405
|
-
const existingBead = await
|
|
19488
|
+
async deleteCell(projectKeyParam, cellId, options, projectPath) {
|
|
19489
|
+
const existingBead = await getCell(db, projectKeyParam, cellId);
|
|
19406
19490
|
if (!existingBead) {
|
|
19407
|
-
throw new Error(`[
|
|
19491
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19408
19492
|
}
|
|
19409
19493
|
const event = {
|
|
19410
|
-
type: "
|
|
19494
|
+
type: "cell_deleted",
|
|
19411
19495
|
project_key: projectKeyParam,
|
|
19412
|
-
|
|
19496
|
+
cell_id: cellId,
|
|
19413
19497
|
timestamp: Date.now(),
|
|
19414
19498
|
reason: options?.reason || null,
|
|
19415
19499
|
deleted_by: options?.deleted_by || null
|
|
19416
19500
|
};
|
|
19417
|
-
await
|
|
19501
|
+
await appendCellEvent(event, projectPath, db);
|
|
19418
19502
|
},
|
|
19419
|
-
async addDependency(projectKeyParam,
|
|
19420
|
-
const sourceBead = await
|
|
19503
|
+
async addDependency(projectKeyParam, cellId, dependsOnId, relationship, options, projectPath) {
|
|
19504
|
+
const sourceBead = await getCell(db, projectKeyParam, cellId);
|
|
19421
19505
|
if (!sourceBead) {
|
|
19422
|
-
throw new Error(`[
|
|
19506
|
+
throw new Error(`[HiveAdapter] Bead not found: ${cellId}`);
|
|
19423
19507
|
}
|
|
19424
|
-
const
|
|
19425
|
-
if (!
|
|
19426
|
-
throw new Error(`[
|
|
19508
|
+
const targetCell = await getCell(db, projectKeyParam, dependsOnId);
|
|
19509
|
+
if (!targetCell) {
|
|
19510
|
+
throw new Error(`[HiveAdapter] Target bead not found: ${dependsOnId}`);
|
|
19427
19511
|
}
|
|
19428
|
-
if (
|
|
19429
|
-
throw new Error(`[
|
|
19512
|
+
if (cellId === dependsOnId) {
|
|
19513
|
+
throw new Error(`[HiveAdapter] Bead cannot depend on itself`);
|
|
19430
19514
|
}
|
|
19431
19515
|
const { wouldCreateCycle: wouldCreateCycle2 } = await Promise.resolve().then(() => exports_dependencies);
|
|
19432
|
-
const hasCycle = await wouldCreateCycle2(db,
|
|
19516
|
+
const hasCycle = await wouldCreateCycle2(db, cellId, dependsOnId);
|
|
19433
19517
|
if (hasCycle) {
|
|
19434
|
-
throw new Error(`[
|
|
19518
|
+
throw new Error(`[HiveAdapter] Adding dependency would create a cycle`);
|
|
19435
19519
|
}
|
|
19436
19520
|
const event = {
|
|
19437
|
-
type: "
|
|
19521
|
+
type: "cell_dependency_added",
|
|
19438
19522
|
project_key: projectKeyParam,
|
|
19439
|
-
|
|
19523
|
+
cell_id: cellId,
|
|
19440
19524
|
timestamp: Date.now(),
|
|
19441
19525
|
dependency: {
|
|
19442
19526
|
target: dependsOnId,
|
|
@@ -19445,19 +19529,19 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19445
19529
|
reason: options?.reason || null,
|
|
19446
19530
|
added_by: options?.added_by || null
|
|
19447
19531
|
};
|
|
19448
|
-
await
|
|
19449
|
-
const deps = await getDependencies(db, projectKeyParam,
|
|
19532
|
+
await appendCellEvent(event, projectPath, db);
|
|
19533
|
+
const deps = await getDependencies(db, projectKeyParam, cellId);
|
|
19450
19534
|
const dep = deps.find((d) => d.depends_on_id === dependsOnId && d.relationship === relationship);
|
|
19451
19535
|
if (!dep) {
|
|
19452
|
-
throw new Error(`[
|
|
19536
|
+
throw new Error(`[HiveAdapter] Dependency not found after insert`);
|
|
19453
19537
|
}
|
|
19454
19538
|
return dep;
|
|
19455
19539
|
},
|
|
19456
|
-
async removeDependency(projectKeyParam,
|
|
19540
|
+
async removeDependency(projectKeyParam, cellId, dependsOnId, relationship, options, projectPath) {
|
|
19457
19541
|
const event = {
|
|
19458
|
-
type: "
|
|
19542
|
+
type: "cell_dependency_removed",
|
|
19459
19543
|
project_key: projectKeyParam,
|
|
19460
|
-
|
|
19544
|
+
cell_id: cellId,
|
|
19461
19545
|
timestamp: Date.now(),
|
|
19462
19546
|
dependency: {
|
|
19463
19547
|
target: dependsOnId,
|
|
@@ -19466,86 +19550,86 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19466
19550
|
reason: options?.reason || null,
|
|
19467
19551
|
removed_by: options?.removed_by || null
|
|
19468
19552
|
};
|
|
19469
|
-
await
|
|
19553
|
+
await appendCellEvent(event, projectPath, db);
|
|
19470
19554
|
},
|
|
19471
|
-
async getDependencies(projectKeyParam,
|
|
19472
|
-
return getDependencies(db, projectKeyParam,
|
|
19555
|
+
async getDependencies(projectKeyParam, cellId, projectPath) {
|
|
19556
|
+
return getDependencies(db, projectKeyParam, cellId);
|
|
19473
19557
|
},
|
|
19474
|
-
async getDependents(projectKeyParam,
|
|
19475
|
-
return getDependents(db, projectKeyParam,
|
|
19558
|
+
async getDependents(projectKeyParam, cellId, projectPath) {
|
|
19559
|
+
return getDependents(db, projectKeyParam, cellId);
|
|
19476
19560
|
},
|
|
19477
|
-
async isBlocked(projectKeyParam,
|
|
19478
|
-
return isBlocked(db, projectKeyParam,
|
|
19561
|
+
async isBlocked(projectKeyParam, cellId, projectPath) {
|
|
19562
|
+
return isBlocked(db, projectKeyParam, cellId);
|
|
19479
19563
|
},
|
|
19480
|
-
async getBlockers(projectKeyParam,
|
|
19481
|
-
return getBlockers(db, projectKeyParam,
|
|
19564
|
+
async getBlockers(projectKeyParam, cellId, projectPath) {
|
|
19565
|
+
return getBlockers(db, projectKeyParam, cellId);
|
|
19482
19566
|
},
|
|
19483
|
-
async addLabel(projectKeyParam,
|
|
19567
|
+
async addLabel(projectKeyParam, cellId, label, options, projectPath) {
|
|
19484
19568
|
const event = {
|
|
19485
|
-
type: "
|
|
19569
|
+
type: "cell_label_added",
|
|
19486
19570
|
project_key: projectKeyParam,
|
|
19487
|
-
|
|
19571
|
+
cell_id: cellId,
|
|
19488
19572
|
timestamp: Date.now(),
|
|
19489
19573
|
label,
|
|
19490
19574
|
added_by: options?.added_by || null
|
|
19491
19575
|
};
|
|
19492
|
-
await
|
|
19576
|
+
await appendCellEvent(event, projectPath, db);
|
|
19493
19577
|
return {
|
|
19494
|
-
|
|
19578
|
+
cell_id: cellId,
|
|
19495
19579
|
label,
|
|
19496
19580
|
created_at: event.timestamp
|
|
19497
19581
|
};
|
|
19498
19582
|
},
|
|
19499
|
-
async removeLabel(projectKeyParam,
|
|
19583
|
+
async removeLabel(projectKeyParam, cellId, label, options, projectPath) {
|
|
19500
19584
|
const event = {
|
|
19501
|
-
type: "
|
|
19585
|
+
type: "cell_label_removed",
|
|
19502
19586
|
project_key: projectKeyParam,
|
|
19503
|
-
|
|
19587
|
+
cell_id: cellId,
|
|
19504
19588
|
timestamp: Date.now(),
|
|
19505
19589
|
label,
|
|
19506
19590
|
removed_by: options?.removed_by || null
|
|
19507
19591
|
};
|
|
19508
|
-
await
|
|
19592
|
+
await appendCellEvent(event, projectPath, db);
|
|
19509
19593
|
},
|
|
19510
|
-
async getLabels(projectKeyParam,
|
|
19511
|
-
return getLabels(db, projectKeyParam,
|
|
19594
|
+
async getLabels(projectKeyParam, cellId, projectPath) {
|
|
19595
|
+
return getLabels(db, projectKeyParam, cellId);
|
|
19512
19596
|
},
|
|
19513
|
-
async
|
|
19514
|
-
return
|
|
19597
|
+
async getCellsWithLabel(projectKeyParam, label, projectPath) {
|
|
19598
|
+
return queryCells(db, projectKeyParam, { labels: [label] });
|
|
19515
19599
|
},
|
|
19516
|
-
async addComment(projectKeyParam,
|
|
19600
|
+
async addComment(projectKeyParam, cellId, author, body, options, projectPath) {
|
|
19517
19601
|
const event = {
|
|
19518
|
-
type: "
|
|
19602
|
+
type: "cell_comment_added",
|
|
19519
19603
|
project_key: projectKeyParam,
|
|
19520
|
-
|
|
19604
|
+
cell_id: cellId,
|
|
19521
19605
|
timestamp: Date.now(),
|
|
19522
19606
|
author,
|
|
19523
19607
|
body,
|
|
19524
19608
|
parent_comment_id: options?.parent_id || null,
|
|
19525
19609
|
metadata: options?.metadata || null
|
|
19526
19610
|
};
|
|
19527
|
-
await
|
|
19528
|
-
const comments = await getComments(db, projectKeyParam,
|
|
19611
|
+
await appendCellEvent(event, projectPath, db);
|
|
19612
|
+
const comments = await getComments(db, projectKeyParam, cellId);
|
|
19529
19613
|
const comment = comments[comments.length - 1];
|
|
19530
19614
|
if (!comment) {
|
|
19531
|
-
throw new Error(`[
|
|
19615
|
+
throw new Error(`[HiveAdapter] Comment not found after insert`);
|
|
19532
19616
|
}
|
|
19533
19617
|
return comment;
|
|
19534
19618
|
},
|
|
19535
19619
|
async updateComment(projectKeyParam, commentId, newBody, updated_by, projectPath) {
|
|
19536
19620
|
const event = {
|
|
19537
|
-
type: "
|
|
19621
|
+
type: "cell_comment_updated",
|
|
19538
19622
|
project_key: projectKeyParam,
|
|
19539
|
-
|
|
19623
|
+
cell_id: "",
|
|
19540
19624
|
timestamp: Date.now(),
|
|
19541
19625
|
comment_id: commentId,
|
|
19542
19626
|
new_body: newBody,
|
|
19543
19627
|
updated_by
|
|
19544
19628
|
};
|
|
19545
|
-
await
|
|
19629
|
+
await appendCellEvent(event, projectPath, db);
|
|
19546
19630
|
return {
|
|
19547
19631
|
id: commentId,
|
|
19548
|
-
|
|
19632
|
+
cell_id: "",
|
|
19549
19633
|
author: updated_by,
|
|
19550
19634
|
body: newBody,
|
|
19551
19635
|
parent_id: null,
|
|
@@ -19555,67 +19639,67 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19555
19639
|
},
|
|
19556
19640
|
async deleteComment(projectKeyParam, commentId, deleted_by, options, projectPath) {
|
|
19557
19641
|
const event = {
|
|
19558
|
-
type: "
|
|
19642
|
+
type: "cell_comment_deleted",
|
|
19559
19643
|
project_key: projectKeyParam,
|
|
19560
|
-
|
|
19644
|
+
cell_id: "",
|
|
19561
19645
|
timestamp: Date.now(),
|
|
19562
19646
|
comment_id: commentId,
|
|
19563
19647
|
deleted_by,
|
|
19564
19648
|
reason: options?.reason || null
|
|
19565
19649
|
};
|
|
19566
|
-
await
|
|
19650
|
+
await appendCellEvent(event, projectPath, db);
|
|
19567
19651
|
},
|
|
19568
|
-
async getComments(projectKeyParam,
|
|
19569
|
-
return getComments(db, projectKeyParam,
|
|
19652
|
+
async getComments(projectKeyParam, cellId, projectPath) {
|
|
19653
|
+
return getComments(db, projectKeyParam, cellId);
|
|
19570
19654
|
},
|
|
19571
19655
|
async addChildToEpic(projectKeyParam, epicId, childId, options, projectPath) {
|
|
19572
19656
|
const event = {
|
|
19573
|
-
type: "
|
|
19657
|
+
type: "cell_epic_child_added",
|
|
19574
19658
|
project_key: projectKeyParam,
|
|
19575
|
-
|
|
19659
|
+
cell_id: epicId,
|
|
19576
19660
|
timestamp: Date.now(),
|
|
19577
19661
|
child_id: childId,
|
|
19578
19662
|
child_index: options?.child_index || null,
|
|
19579
19663
|
added_by: options?.added_by || null
|
|
19580
19664
|
};
|
|
19581
|
-
await
|
|
19665
|
+
await appendCellEvent(event, projectPath, db);
|
|
19582
19666
|
},
|
|
19583
19667
|
async removeChildFromEpic(projectKeyParam, epicId, childId, options, projectPath) {
|
|
19584
19668
|
const event = {
|
|
19585
|
-
type: "
|
|
19669
|
+
type: "cell_epic_child_removed",
|
|
19586
19670
|
project_key: projectKeyParam,
|
|
19587
|
-
|
|
19671
|
+
cell_id: epicId,
|
|
19588
19672
|
timestamp: Date.now(),
|
|
19589
19673
|
child_id: childId,
|
|
19590
19674
|
reason: options?.reason || null,
|
|
19591
19675
|
removed_by: options?.removed_by || null
|
|
19592
19676
|
};
|
|
19593
|
-
await
|
|
19677
|
+
await appendCellEvent(event, projectPath, db);
|
|
19594
19678
|
},
|
|
19595
19679
|
async getEpicChildren(projectKeyParam, epicId, projectPath) {
|
|
19596
|
-
return
|
|
19680
|
+
return queryCells(db, projectKeyParam, { parent_id: epicId });
|
|
19597
19681
|
},
|
|
19598
19682
|
async isEpicClosureEligible(projectKeyParam, epicId, projectPath) {
|
|
19599
|
-
const children = await
|
|
19683
|
+
const children = await queryCells(db, projectKeyParam, { parent_id: epicId });
|
|
19600
19684
|
return children.every((child) => child.status === "closed");
|
|
19601
19685
|
},
|
|
19602
|
-
async
|
|
19603
|
-
return
|
|
19686
|
+
async getNextReadyCell(projectKeyParam, projectPath) {
|
|
19687
|
+
return getNextReadyCell(db, projectKeyParam);
|
|
19604
19688
|
},
|
|
19605
|
-
async
|
|
19606
|
-
return
|
|
19689
|
+
async getInProgressCells(projectKeyParam, projectPath) {
|
|
19690
|
+
return getInProgressCells(db, projectKeyParam);
|
|
19607
19691
|
},
|
|
19608
|
-
async
|
|
19609
|
-
return
|
|
19692
|
+
async getBlockedCells(projectKeyParam, projectPath) {
|
|
19693
|
+
return getBlockedCells(db, projectKeyParam);
|
|
19610
19694
|
},
|
|
19611
|
-
async markDirty(projectKeyParam,
|
|
19612
|
-
await markBeadDirty(db, projectKeyParam,
|
|
19695
|
+
async markDirty(projectKeyParam, cellId, projectPath) {
|
|
19696
|
+
await markBeadDirty(db, projectKeyParam, cellId);
|
|
19613
19697
|
},
|
|
19614
|
-
async
|
|
19615
|
-
return
|
|
19698
|
+
async getDirtyCells(projectKeyParam, projectPath) {
|
|
19699
|
+
return getDirtyCells(db, projectKeyParam);
|
|
19616
19700
|
},
|
|
19617
|
-
async clearDirty(projectKeyParam,
|
|
19618
|
-
await clearDirtyBead(db, projectKeyParam,
|
|
19701
|
+
async clearDirty(projectKeyParam, cellId, projectPath) {
|
|
19702
|
+
await clearDirtyBead(db, projectKeyParam, cellId);
|
|
19619
19703
|
},
|
|
19620
19704
|
async runMigrations(projectPath) {
|
|
19621
19705
|
const { beadsMigration: beadsMigration2 } = await Promise.resolve().then(() => (init_migrations2(), exports_migrations2));
|
|
@@ -19637,7 +19721,7 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19637
19721
|
throw error45;
|
|
19638
19722
|
}
|
|
19639
19723
|
},
|
|
19640
|
-
async
|
|
19724
|
+
async getCellsStats(projectPath) {
|
|
19641
19725
|
const [totalResult, openResult, inProgressResult, blockedResult, closedResult] = await Promise.all([
|
|
19642
19726
|
db.query("SELECT COUNT(*) as count FROM beads WHERE project_key = $1", [projectKey]),
|
|
19643
19727
|
db.query("SELECT COUNT(*) as count FROM beads WHERE project_key = $1 AND status = 'open'", [projectKey]),
|
|
@@ -19651,7 +19735,7 @@ function createBeadsAdapter(db, projectKey) {
|
|
|
19651
19735
|
by_type[row.type] = parseInt(row.count);
|
|
19652
19736
|
}
|
|
19653
19737
|
return {
|
|
19654
|
-
|
|
19738
|
+
total_cells: parseInt(totalResult.rows[0]?.count || "0"),
|
|
19655
19739
|
open: parseInt(openResult.rows[0]?.count || "0"),
|
|
19656
19740
|
in_progress: parseInt(inProgressResult.rows[0]?.count || "0"),
|
|
19657
19741
|
blocked: parseInt(blockedResult.rows[0]?.count || "0"),
|
|
@@ -19685,25 +19769,25 @@ function generateBeadId(projectKey) {
|
|
|
19685
19769
|
return `bd-${hash2}-${timestamp}${random}`;
|
|
19686
19770
|
}
|
|
19687
19771
|
|
|
19688
|
-
// src/
|
|
19772
|
+
// src/hive/index.ts
|
|
19689
19773
|
init_migrations2();
|
|
19690
19774
|
|
|
19691
|
-
// src/
|
|
19692
|
-
async function
|
|
19775
|
+
// src/hive/labels.ts
|
|
19776
|
+
async function getCellsByLabel(db, projectKey, label) {
|
|
19693
19777
|
const result = await db.query(`SELECT b.* FROM beads b
|
|
19694
|
-
JOIN bead_labels bl ON b.id = bl.
|
|
19778
|
+
JOIN bead_labels bl ON b.id = bl.cell_id
|
|
19695
19779
|
WHERE b.project_key = $1 AND bl.label = $2 AND b.deleted_at IS NULL
|
|
19696
19780
|
ORDER BY b.priority DESC, b.created_at ASC`, [projectKey, label]);
|
|
19697
19781
|
return result.rows;
|
|
19698
19782
|
}
|
|
19699
19783
|
async function getAllLabels(db, projectKey) {
|
|
19700
19784
|
const result = await db.query(`SELECT DISTINCT bl.label FROM bead_labels bl
|
|
19701
|
-
JOIN beads b ON bl.
|
|
19785
|
+
JOIN beads b ON bl.cell_id = b.id
|
|
19702
19786
|
WHERE b.project_key = $1 AND b.deleted_at IS NULL
|
|
19703
19787
|
ORDER BY bl.label`, [projectKey]);
|
|
19704
19788
|
return result.rows.map((r) => r.label);
|
|
19705
19789
|
}
|
|
19706
|
-
// src/
|
|
19790
|
+
// src/hive/comments.ts
|
|
19707
19791
|
async function getCommentById(db, commentId) {
|
|
19708
19792
|
const result = await db.query(`SELECT * FROM bead_comments WHERE id = $1`, [commentId]);
|
|
19709
19793
|
return result.rows[0] ?? null;
|
|
@@ -19722,10 +19806,10 @@ async function getCommentThread(db, rootCommentId) {
|
|
|
19722
19806
|
SELECT * FROM thread ORDER BY created_at ASC`, [rootCommentId]);
|
|
19723
19807
|
return result.rows;
|
|
19724
19808
|
}
|
|
19725
|
-
// src/
|
|
19809
|
+
// src/hive/jsonl.ts
|
|
19726
19810
|
import { createHash as createHash2 } from "node:crypto";
|
|
19727
|
-
function serializeToJSONL(
|
|
19728
|
-
return JSON.stringify(
|
|
19811
|
+
function serializeToJSONL(cell) {
|
|
19812
|
+
return JSON.stringify(cell);
|
|
19729
19813
|
}
|
|
19730
19814
|
function parseJSONL(jsonl) {
|
|
19731
19815
|
if (!jsonl || jsonl.trim() === "") {
|
|
@@ -19733,23 +19817,23 @@ function parseJSONL(jsonl) {
|
|
|
19733
19817
|
}
|
|
19734
19818
|
const lines = jsonl.split(`
|
|
19735
19819
|
`);
|
|
19736
|
-
const
|
|
19820
|
+
const cells = [];
|
|
19737
19821
|
for (const line of lines) {
|
|
19738
19822
|
const trimmed = line.trim();
|
|
19739
19823
|
if (trimmed === "") {
|
|
19740
19824
|
continue;
|
|
19741
19825
|
}
|
|
19742
19826
|
try {
|
|
19743
|
-
const
|
|
19744
|
-
|
|
19827
|
+
const cell = JSON.parse(trimmed);
|
|
19828
|
+
cells.push(cell);
|
|
19745
19829
|
} catch (err) {
|
|
19746
19830
|
throw new Error(`Invalid JSON in JSONL: ${err instanceof Error ? err.message : String(err)}`);
|
|
19747
19831
|
}
|
|
19748
19832
|
}
|
|
19749
|
-
return
|
|
19833
|
+
return cells;
|
|
19750
19834
|
}
|
|
19751
|
-
function computeContentHash(
|
|
19752
|
-
const canonical = JSON.stringify(
|
|
19835
|
+
function computeContentHash(cell) {
|
|
19836
|
+
const canonical = JSON.stringify(cell, Object.keys(cell).sort());
|
|
19753
19837
|
return createHash2("sha256").update(canonical).digest("hex");
|
|
19754
19838
|
}
|
|
19755
19839
|
async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
@@ -19760,12 +19844,12 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19760
19844
|
if (!options.includeDeleted) {
|
|
19761
19845
|
conditions.push("deleted_at IS NULL");
|
|
19762
19846
|
}
|
|
19763
|
-
if (options.
|
|
19847
|
+
if (options.cellIds && options.cellIds.length > 0) {
|
|
19764
19848
|
conditions.push(`id = ANY($${paramIndex++})`);
|
|
19765
|
-
params.push(options.
|
|
19849
|
+
params.push(options.cellIds);
|
|
19766
19850
|
}
|
|
19767
19851
|
const query = `
|
|
19768
|
-
SELECT * FROM
|
|
19852
|
+
SELECT * FROM cells
|
|
19769
19853
|
WHERE ${conditions.join(" AND ")}
|
|
19770
19854
|
ORDER BY id ASC
|
|
19771
19855
|
`;
|
|
@@ -19787,7 +19871,7 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19787
19871
|
author: c.author,
|
|
19788
19872
|
text: c.body
|
|
19789
19873
|
}));
|
|
19790
|
-
const
|
|
19874
|
+
const cellExport = {
|
|
19791
19875
|
id: bead.id,
|
|
19792
19876
|
title: bead.title,
|
|
19793
19877
|
description: bead.description || undefined,
|
|
@@ -19803,51 +19887,51 @@ async function exportToJSONL(adapter, projectKey, options = {}) {
|
|
|
19803
19887
|
labels,
|
|
19804
19888
|
comments: commentExports
|
|
19805
19889
|
};
|
|
19806
|
-
lines.push(serializeToJSONL(
|
|
19890
|
+
lines.push(serializeToJSONL(cellExport));
|
|
19807
19891
|
}
|
|
19808
19892
|
return lines.join(`
|
|
19809
19893
|
`);
|
|
19810
19894
|
}
|
|
19811
19895
|
async function exportDirtyBeads(adapter, projectKey) {
|
|
19812
19896
|
const db = await adapter.getDatabase();
|
|
19813
|
-
const dirtyIds = await
|
|
19897
|
+
const dirtyIds = await getDirtyCells(db, projectKey);
|
|
19814
19898
|
if (dirtyIds.length === 0) {
|
|
19815
|
-
return { jsonl: "",
|
|
19899
|
+
return { jsonl: "", cellIds: [] };
|
|
19816
19900
|
}
|
|
19817
19901
|
const jsonl = await exportToJSONL(adapter, projectKey, {
|
|
19818
|
-
|
|
19902
|
+
cellIds: dirtyIds
|
|
19819
19903
|
});
|
|
19820
|
-
return { jsonl,
|
|
19904
|
+
return { jsonl, cellIds: dirtyIds };
|
|
19821
19905
|
}
|
|
19822
19906
|
async function importFromJSONL(adapter, projectKey, jsonl, options = {}) {
|
|
19823
|
-
const
|
|
19907
|
+
const cells = parseJSONL(jsonl);
|
|
19824
19908
|
const result = {
|
|
19825
19909
|
created: 0,
|
|
19826
19910
|
updated: 0,
|
|
19827
19911
|
skipped: 0,
|
|
19828
19912
|
errors: []
|
|
19829
19913
|
};
|
|
19830
|
-
for (const
|
|
19914
|
+
for (const cellExport of cells) {
|
|
19831
19915
|
try {
|
|
19832
|
-
await
|
|
19916
|
+
await importSingleCell(adapter, projectKey, cellExport, options, result);
|
|
19833
19917
|
} catch (err) {
|
|
19834
19918
|
result.errors.push({
|
|
19835
|
-
|
|
19919
|
+
cellId: cellExport.id,
|
|
19836
19920
|
error: err instanceof Error ? err.message : String(err)
|
|
19837
19921
|
});
|
|
19838
19922
|
}
|
|
19839
19923
|
}
|
|
19840
19924
|
return result;
|
|
19841
19925
|
}
|
|
19842
|
-
async function
|
|
19843
|
-
const existing = await adapter.
|
|
19926
|
+
async function importSingleCell(adapter, projectKey, cellExport, options, result) {
|
|
19927
|
+
const existing = await adapter.getCell(projectKey, cellExport.id);
|
|
19844
19928
|
if (existing && options.skipExisting) {
|
|
19845
19929
|
result.skipped++;
|
|
19846
19930
|
return;
|
|
19847
19931
|
}
|
|
19848
19932
|
if (existing) {
|
|
19849
19933
|
const existingHash = await computeBeadHash(adapter, projectKey, existing.id);
|
|
19850
|
-
const importHash = computeContentHash(
|
|
19934
|
+
const importHash = computeContentHash(cellExport);
|
|
19851
19935
|
if (existingHash === importHash) {
|
|
19852
19936
|
result.skipped++;
|
|
19853
19937
|
return;
|
|
@@ -19863,114 +19947,124 @@ async function importSingleBead(adapter, projectKey, beadExport, options, result
|
|
|
19863
19947
|
}
|
|
19864
19948
|
if (!existing) {
|
|
19865
19949
|
const db = await adapter.getDatabase();
|
|
19866
|
-
|
|
19950
|
+
const status = cellExport.status === "tombstone" ? "closed" : cellExport.status;
|
|
19951
|
+
const isClosed = status === "closed";
|
|
19952
|
+
const closedAt = isClosed ? cellExport.closed_at ? new Date(cellExport.closed_at).getTime() : new Date(cellExport.updated_at).getTime() : null;
|
|
19953
|
+
await db.query(`INSERT INTO cells (
|
|
19867
19954
|
id, project_key, type, status, title, description, priority,
|
|
19868
|
-
parent_id, assignee, created_at, updated_at
|
|
19869
|
-
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`, [
|
|
19870
|
-
|
|
19955
|
+
parent_id, assignee, created_at, updated_at, closed_at
|
|
19956
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`, [
|
|
19957
|
+
cellExport.id,
|
|
19871
19958
|
projectKey,
|
|
19872
|
-
|
|
19873
|
-
|
|
19874
|
-
|
|
19875
|
-
|
|
19876
|
-
|
|
19877
|
-
|
|
19878
|
-
|
|
19879
|
-
new Date(
|
|
19880
|
-
new Date(
|
|
19959
|
+
cellExport.issue_type,
|
|
19960
|
+
status,
|
|
19961
|
+
cellExport.title,
|
|
19962
|
+
cellExport.description || null,
|
|
19963
|
+
cellExport.priority,
|
|
19964
|
+
cellExport.parent_id || null,
|
|
19965
|
+
cellExport.assignee || null,
|
|
19966
|
+
new Date(cellExport.created_at).getTime(),
|
|
19967
|
+
new Date(cellExport.updated_at).getTime(),
|
|
19968
|
+
closedAt
|
|
19881
19969
|
]);
|
|
19882
|
-
if (
|
|
19883
|
-
await db.query("UPDATE beads SET
|
|
19884
|
-
}
|
|
19885
|
-
if (beadExport.status === "tombstone") {
|
|
19886
|
-
await db.query("UPDATE beads SET deleted_at = $1 WHERE id = $2", [Date.now(), beadExport.id]);
|
|
19970
|
+
if (cellExport.status === "tombstone") {
|
|
19971
|
+
await db.query("UPDATE beads SET deleted_at = $1 WHERE id = $2", [Date.now(), cellExport.id]);
|
|
19887
19972
|
}
|
|
19888
19973
|
result.created++;
|
|
19889
19974
|
} else {
|
|
19890
|
-
await adapter.
|
|
19891
|
-
title:
|
|
19892
|
-
description:
|
|
19893
|
-
priority:
|
|
19894
|
-
assignee:
|
|
19975
|
+
await adapter.updateCell(projectKey, cellExport.id, {
|
|
19976
|
+
title: cellExport.title,
|
|
19977
|
+
description: cellExport.description,
|
|
19978
|
+
priority: cellExport.priority,
|
|
19979
|
+
assignee: cellExport.assignee
|
|
19895
19980
|
});
|
|
19896
|
-
if (existing.status !==
|
|
19897
|
-
if (
|
|
19898
|
-
await adapter.
|
|
19899
|
-
} else if (
|
|
19981
|
+
if (existing.status !== cellExport.status) {
|
|
19982
|
+
if (cellExport.status === "closed") {
|
|
19983
|
+
await adapter.closeCell(projectKey, cellExport.id, "imported");
|
|
19984
|
+
} else if (cellExport.status === "in_progress") {
|
|
19900
19985
|
const db = await adapter.getDatabase();
|
|
19901
|
-
await db.query("UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3", ["in_progress", Date.now(),
|
|
19986
|
+
await db.query("UPDATE beads SET status = $1, updated_at = $2 WHERE id = $3", ["in_progress", Date.now(), cellExport.id]);
|
|
19902
19987
|
}
|
|
19903
19988
|
}
|
|
19904
19989
|
result.updated++;
|
|
19905
19990
|
}
|
|
19906
|
-
await importDependencies(adapter, projectKey,
|
|
19907
|
-
await importLabels(adapter, projectKey,
|
|
19908
|
-
await importComments(adapter, projectKey,
|
|
19991
|
+
await importDependencies(adapter, projectKey, cellExport);
|
|
19992
|
+
await importLabels(adapter, projectKey, cellExport);
|
|
19993
|
+
await importComments(adapter, projectKey, cellExport);
|
|
19909
19994
|
}
|
|
19910
|
-
async function computeBeadHash(adapter, projectKey,
|
|
19995
|
+
async function computeBeadHash(adapter, projectKey, cellId) {
|
|
19911
19996
|
const db = await adapter.getDatabase();
|
|
19912
|
-
const beadResult = await db.query("SELECT * FROM beads WHERE project_key = $1 AND id = $2", [projectKey,
|
|
19913
|
-
const
|
|
19914
|
-
if (!
|
|
19915
|
-
throw new Error(`
|
|
19997
|
+
const beadResult = await db.query("SELECT * FROM beads WHERE project_key = $1 AND id = $2", [projectKey, cellId]);
|
|
19998
|
+
const cell = beadResult.rows[0];
|
|
19999
|
+
if (!cell) {
|
|
20000
|
+
throw new Error(`Cell not found: ${cellId}`);
|
|
19916
20001
|
}
|
|
19917
|
-
const deps = await getDependencies(db, projectKey,
|
|
20002
|
+
const deps = await getDependencies(db, projectKey, cellId);
|
|
19918
20003
|
const dependencies = deps.map((d) => ({
|
|
19919
20004
|
depends_on_id: d.depends_on_id,
|
|
19920
20005
|
type: d.relationship
|
|
19921
20006
|
}));
|
|
19922
|
-
const labels = await getLabels(db, projectKey,
|
|
19923
|
-
const comments = await getComments(db, projectKey,
|
|
20007
|
+
const labels = await getLabels(db, projectKey, cellId);
|
|
20008
|
+
const comments = await getComments(db, projectKey, cellId);
|
|
19924
20009
|
const commentExports = comments.map((c) => ({
|
|
19925
20010
|
author: c.author,
|
|
19926
20011
|
text: c.body
|
|
19927
20012
|
}));
|
|
19928
|
-
const
|
|
19929
|
-
id:
|
|
19930
|
-
title:
|
|
19931
|
-
description:
|
|
19932
|
-
status:
|
|
19933
|
-
priority:
|
|
19934
|
-
issue_type:
|
|
19935
|
-
created_at: new Date(
|
|
19936
|
-
updated_at: new Date(
|
|
19937
|
-
closed_at:
|
|
19938
|
-
assignee:
|
|
19939
|
-
parent_id:
|
|
20013
|
+
const cellExport = {
|
|
20014
|
+
id: cell.id,
|
|
20015
|
+
title: cell.title,
|
|
20016
|
+
description: cell.description || undefined,
|
|
20017
|
+
status: cell.deleted_at ? "tombstone" : cell.status,
|
|
20018
|
+
priority: cell.priority,
|
|
20019
|
+
issue_type: cell.type,
|
|
20020
|
+
created_at: new Date(cell.created_at).toISOString(),
|
|
20021
|
+
updated_at: new Date(cell.updated_at).toISOString(),
|
|
20022
|
+
closed_at: cell.closed_at ? new Date(cell.closed_at).toISOString() : undefined,
|
|
20023
|
+
assignee: cell.assignee || undefined,
|
|
20024
|
+
parent_id: cell.parent_id || undefined,
|
|
19940
20025
|
dependencies,
|
|
19941
20026
|
labels,
|
|
19942
20027
|
comments: commentExports
|
|
19943
20028
|
};
|
|
19944
|
-
return computeContentHash(
|
|
20029
|
+
return computeContentHash(cellExport);
|
|
19945
20030
|
}
|
|
19946
|
-
async function importDependencies(adapter, projectKey,
|
|
20031
|
+
async function importDependencies(adapter, projectKey, cellExport) {
|
|
20032
|
+
if (!cellExport.dependencies || cellExport.dependencies.length === 0) {
|
|
20033
|
+
return;
|
|
20034
|
+
}
|
|
19947
20035
|
const db = await adapter.getDatabase();
|
|
19948
|
-
await db.query("DELETE FROM
|
|
19949
|
-
|
|
20036
|
+
await db.query("DELETE FROM cell_dependencies WHERE cell_id = $1", [
|
|
20037
|
+
cellExport.id
|
|
19950
20038
|
]);
|
|
19951
|
-
for (const dep of
|
|
19952
|
-
await adapter.addDependency(projectKey,
|
|
20039
|
+
for (const dep of cellExport.dependencies) {
|
|
20040
|
+
await adapter.addDependency(projectKey, cellExport.id, dep.depends_on_id, dep.type);
|
|
19953
20041
|
}
|
|
19954
20042
|
}
|
|
19955
|
-
async function importLabels(adapter, projectKey,
|
|
20043
|
+
async function importLabels(adapter, projectKey, cellExport) {
|
|
20044
|
+
if (!cellExport.labels || cellExport.labels.length === 0) {
|
|
20045
|
+
return;
|
|
20046
|
+
}
|
|
19956
20047
|
const db = await adapter.getDatabase();
|
|
19957
|
-
await db.query("DELETE FROM
|
|
19958
|
-
|
|
20048
|
+
await db.query("DELETE FROM cell_labels WHERE cell_id = $1", [
|
|
20049
|
+
cellExport.id
|
|
19959
20050
|
]);
|
|
19960
|
-
for (const label of
|
|
19961
|
-
await adapter.addLabel(projectKey,
|
|
20051
|
+
for (const label of cellExport.labels) {
|
|
20052
|
+
await adapter.addLabel(projectKey, cellExport.id, label);
|
|
19962
20053
|
}
|
|
19963
20054
|
}
|
|
19964
|
-
async function importComments(adapter, projectKey,
|
|
20055
|
+
async function importComments(adapter, projectKey, cellExport) {
|
|
20056
|
+
if (!cellExport.comments || cellExport.comments.length === 0) {
|
|
20057
|
+
return;
|
|
20058
|
+
}
|
|
19965
20059
|
const db = await adapter.getDatabase();
|
|
19966
|
-
await db.query("DELETE FROM
|
|
19967
|
-
|
|
20060
|
+
await db.query("DELETE FROM cell_comments WHERE cell_id = $1", [
|
|
20061
|
+
cellExport.id
|
|
19968
20062
|
]);
|
|
19969
|
-
for (const comment of
|
|
19970
|
-
await adapter.addComment(projectKey,
|
|
20063
|
+
for (const comment of cellExport.comments) {
|
|
20064
|
+
await adapter.addComment(projectKey, cellExport.id, comment.author, comment.text);
|
|
19971
20065
|
}
|
|
19972
20066
|
}
|
|
19973
|
-
// src/
|
|
20067
|
+
// src/hive/flush-manager.ts
|
|
19974
20068
|
import { writeFile as writeFile2 } from "node:fs/promises";
|
|
19975
20069
|
class FlushManager {
|
|
19976
20070
|
adapter;
|
|
@@ -20001,7 +20095,7 @@ class FlushManager {
|
|
|
20001
20095
|
const startTime = Date.now();
|
|
20002
20096
|
if (this.flushing) {
|
|
20003
20097
|
return {
|
|
20004
|
-
|
|
20098
|
+
cellsExported: 0,
|
|
20005
20099
|
bytesWritten: 0,
|
|
20006
20100
|
duration: 0
|
|
20007
20101
|
};
|
|
@@ -20012,10 +20106,10 @@ class FlushManager {
|
|
|
20012
20106
|
clearTimeout(this.timer);
|
|
20013
20107
|
this.timer = null;
|
|
20014
20108
|
}
|
|
20015
|
-
const { jsonl,
|
|
20016
|
-
if (
|
|
20109
|
+
const { jsonl, cellIds } = await exportDirtyBeads(this.adapter, this.projectKey);
|
|
20110
|
+
if (cellIds.length === 0) {
|
|
20017
20111
|
return {
|
|
20018
|
-
|
|
20112
|
+
cellsExported: 0,
|
|
20019
20113
|
bytesWritten: 0,
|
|
20020
20114
|
duration: Date.now() - startTime
|
|
20021
20115
|
};
|
|
@@ -20023,11 +20117,11 @@ class FlushManager {
|
|
|
20023
20117
|
await writeFile2(this.outputPath, jsonl, "utf-8");
|
|
20024
20118
|
const bytesWritten = Buffer.byteLength(jsonl, "utf-8");
|
|
20025
20119
|
const db = await this.adapter.getDatabase();
|
|
20026
|
-
for (const
|
|
20027
|
-
await clearDirtyBead(db, this.projectKey,
|
|
20120
|
+
for (const cellId of cellIds) {
|
|
20121
|
+
await clearDirtyBead(db, this.projectKey, cellId);
|
|
20028
20122
|
}
|
|
20029
20123
|
const result = {
|
|
20030
|
-
|
|
20124
|
+
cellsExported: cellIds.length,
|
|
20031
20125
|
bytesWritten,
|
|
20032
20126
|
duration: Date.now() - startTime
|
|
20033
20127
|
};
|
|
@@ -20046,30 +20140,30 @@ class FlushManager {
|
|
|
20046
20140
|
}
|
|
20047
20141
|
}
|
|
20048
20142
|
}
|
|
20049
|
-
// src/
|
|
20143
|
+
// src/hive/merge.ts
|
|
20050
20144
|
var DEFAULT_TOMBSTONE_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
20051
20145
|
var MIN_TOMBSTONE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
20052
20146
|
var CLOCK_SKEW_GRACE_MS = 60 * 60 * 1000;
|
|
20053
20147
|
var STATUS_TOMBSTONE = "tombstone";
|
|
20054
|
-
function makeKey(
|
|
20148
|
+
function makeKey(cell) {
|
|
20055
20149
|
const key = {
|
|
20056
|
-
id:
|
|
20057
|
-
createdAt:
|
|
20150
|
+
id: cell.id,
|
|
20151
|
+
createdAt: cell.created_at,
|
|
20058
20152
|
createdBy: undefined
|
|
20059
20153
|
};
|
|
20060
20154
|
return JSON.stringify(key);
|
|
20061
20155
|
}
|
|
20062
|
-
function isTombstone(
|
|
20063
|
-
return
|
|
20156
|
+
function isTombstone(cell) {
|
|
20157
|
+
return cell.status === STATUS_TOMBSTONE;
|
|
20064
20158
|
}
|
|
20065
|
-
function isExpiredTombstone(
|
|
20066
|
-
if (!isTombstone(
|
|
20159
|
+
function isExpiredTombstone(cell, ttlMs = DEFAULT_TOMBSTONE_TTL_MS) {
|
|
20160
|
+
if (!isTombstone(cell)) {
|
|
20067
20161
|
return false;
|
|
20068
20162
|
}
|
|
20069
|
-
if (!
|
|
20163
|
+
if (!cell.closed_at) {
|
|
20070
20164
|
return false;
|
|
20071
20165
|
}
|
|
20072
|
-
const deletedAt = new Date(
|
|
20166
|
+
const deletedAt = new Date(cell.closed_at).getTime();
|
|
20073
20167
|
if (Number.isNaN(deletedAt)) {
|
|
20074
20168
|
return false;
|
|
20075
20169
|
}
|
|
@@ -20388,7 +20482,7 @@ export {
|
|
|
20388
20482
|
reserveAgentFiles,
|
|
20389
20483
|
replayEventsBatched2 as replayEventsBatched,
|
|
20390
20484
|
replayEvents,
|
|
20391
|
-
|
|
20485
|
+
replayCellEvents,
|
|
20392
20486
|
releaseSwarmFiles,
|
|
20393
20487
|
releaseAgentFiles,
|
|
20394
20488
|
registerAgent,
|
|
@@ -20396,9 +20490,9 @@ export {
|
|
|
20396
20490
|
rebuildAllBlockedCaches,
|
|
20397
20491
|
readSwarmMessage,
|
|
20398
20492
|
readEvents,
|
|
20399
|
-
|
|
20493
|
+
readCellEvents,
|
|
20400
20494
|
readAgentMessage,
|
|
20401
|
-
|
|
20495
|
+
queryCells,
|
|
20402
20496
|
parseJSONL,
|
|
20403
20497
|
migrations,
|
|
20404
20498
|
mergeJsonl,
|
|
@@ -20426,16 +20520,16 @@ export {
|
|
|
20426
20520
|
getPidFilePath,
|
|
20427
20521
|
getPendingMigrations,
|
|
20428
20522
|
getOpenBlockers,
|
|
20429
|
-
|
|
20523
|
+
getNextReadyCell,
|
|
20430
20524
|
getMessage,
|
|
20431
20525
|
getLatestSequence,
|
|
20432
20526
|
getLabels,
|
|
20433
20527
|
getInbox,
|
|
20434
|
-
|
|
20528
|
+
getInProgressCells,
|
|
20435
20529
|
getEventTimeline,
|
|
20436
20530
|
getEvalStats,
|
|
20437
20531
|
getEvalRecords,
|
|
20438
|
-
|
|
20532
|
+
getDirtyCells,
|
|
20439
20533
|
getDependents,
|
|
20440
20534
|
getDependencies,
|
|
20441
20535
|
getDatabaseStats,
|
|
@@ -20445,10 +20539,10 @@ export {
|
|
|
20445
20539
|
getComments,
|
|
20446
20540
|
getCommentThread,
|
|
20447
20541
|
getCommentById,
|
|
20542
|
+
getCellsByLabel,
|
|
20543
|
+
getCell,
|
|
20448
20544
|
getBlockers,
|
|
20449
|
-
|
|
20450
|
-
getBeadsByLabel,
|
|
20451
|
-
getBead,
|
|
20545
|
+
getBlockedCells,
|
|
20452
20546
|
getAppliedMigrations,
|
|
20453
20547
|
getAllLabels,
|
|
20454
20548
|
getAgents,
|
|
@@ -20464,8 +20558,9 @@ export {
|
|
|
20464
20558
|
createSwarmMailAdapter,
|
|
20465
20559
|
createSocketAdapter,
|
|
20466
20560
|
createInMemorySwarmMail,
|
|
20561
|
+
createHiveAdapter,
|
|
20467
20562
|
createEvent,
|
|
20468
|
-
createBeadsAdapter,
|
|
20563
|
+
createHiveAdapter as createBeadsAdapter,
|
|
20469
20564
|
computeContentHash,
|
|
20470
20565
|
closeSwarmMail,
|
|
20471
20566
|
closeDatabase,
|
|
@@ -20480,7 +20575,7 @@ export {
|
|
|
20480
20575
|
beadsMigration,
|
|
20481
20576
|
appendEvents,
|
|
20482
20577
|
appendEvent,
|
|
20483
|
-
|
|
20578
|
+
appendCellEvent,
|
|
20484
20579
|
acknowledgeSwarmMessage,
|
|
20485
20580
|
acknowledgeMessage,
|
|
20486
20581
|
TaskStartedEventSchema,
|