@deeplake/hivemind 0.7.45 → 0.7.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +64 -0
  4. package/bundle/cli.js +22702 -7775
  5. package/codex/bundle/capture.js +228 -0
  6. package/codex/bundle/commands/auth-login.js +228 -0
  7. package/codex/bundle/graph-pull-worker.js +1370 -0
  8. package/codex/bundle/pre-tool-use.js +228 -0
  9. package/codex/bundle/session-start-setup.js +228 -0
  10. package/codex/bundle/session-start.js +255 -4
  11. package/codex/bundle/shell/deeplake-shell.js +1028 -28
  12. package/codex/bundle/skillify-worker.js +94 -3
  13. package/codex/bundle/stop.js +282 -50
  14. package/codex/skills/hivemind-goals/SKILL.md +157 -0
  15. package/cursor/bundle/capture.js +282 -50
  16. package/cursor/bundle/commands/auth-login.js +228 -0
  17. package/cursor/bundle/graph-pull-worker.js +1370 -0
  18. package/cursor/bundle/pre-tool-use.js +228 -0
  19. package/cursor/bundle/session-end.js +65 -44
  20. package/cursor/bundle/session-start.js +662 -6
  21. package/cursor/bundle/shell/deeplake-shell.js +1028 -28
  22. package/cursor/bundle/skillify-worker.js +94 -3
  23. package/hermes/bundle/capture.js +282 -50
  24. package/hermes/bundle/commands/auth-login.js +228 -0
  25. package/hermes/bundle/graph-pull-worker.js +1370 -0
  26. package/hermes/bundle/pre-tool-use.js +228 -0
  27. package/hermes/bundle/session-end.js +65 -44
  28. package/hermes/bundle/session-start.js +662 -6
  29. package/hermes/bundle/shell/deeplake-shell.js +1028 -28
  30. package/hermes/bundle/skillify-worker.js +94 -3
  31. package/mcp/bundle/server.js +228 -0
  32. package/openclaw/dist/chunks/config-FH6JYSJW.js +53 -0
  33. package/openclaw/dist/index.js +307 -2
  34. package/openclaw/dist/skillify-worker.js +94 -3
  35. package/openclaw/openclaw.plugin.json +4 -2
  36. package/openclaw/package.json +1 -1
  37. package/openclaw/skills/hivemind-goals/SKILL.md +30 -0
  38. package/package.json +4 -1
  39. package/openclaw/dist/chunks/config-XEK4MJJS.js +0 -36
@@ -98,6 +98,23 @@ function loadConfig() {
98
98
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
99
99
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
100
100
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
101
+ // Defaults match the table name written into the SQL — keep aligned
102
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
103
+ // deeplake-schema.ts and with the e2e test-org override convention
104
+ // (memory_test / sessions_test → goals_test, etc.) documented in
105
+ // CLAUDE.md.
106
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
107
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
108
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
109
+ // Goals + KPIs (refined design — VFS path classifier maps
110
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
111
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
112
+ // See src/shell/deeplake-fs.ts for the translation logic and
113
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
114
+ // table shape.
115
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
116
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
117
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
101
118
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
102
119
  };
103
120
  }
@@ -198,6 +215,65 @@ var SKILLS_COLUMNS = Object.freeze([
198
215
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
199
216
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
200
217
  ]);
218
+ var RULES_COLUMNS = Object.freeze([
219
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
220
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
221
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
222
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
223
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
224
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
225
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
226
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
227
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
228
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
229
+ ]);
230
+ var TASKS_COLUMNS = Object.freeze([
231
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
232
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
233
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
234
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
235
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
236
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
237
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
238
+ { name: "kpis", sql: "JSONB" },
239
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
240
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
241
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
242
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
243
+ ]);
244
+ var TASK_EVENTS_COLUMNS = Object.freeze([
245
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
247
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
248
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
249
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
250
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
251
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
252
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
253
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
254
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
255
+ ]);
256
+ var GOALS_COLUMNS = Object.freeze([
257
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
258
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
259
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
260
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
261
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
262
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
263
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
264
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
265
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
266
+ ]);
267
+ var KPIS_COLUMNS = Object.freeze([
268
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
269
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
270
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
271
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
272
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
273
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
274
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
275
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
276
+ ]);
201
277
  function validateSchema(label, cols) {
202
278
  const seen = /* @__PURE__ */ new Set();
203
279
  for (const col of cols) {
@@ -215,9 +291,38 @@ function validateSchema(label, cols) {
215
291
  }
216
292
  }
217
293
  }
294
+ var CODEBASE_COLUMNS = Object.freeze([
295
+ // Identity key (matches the PK below)
296
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
297
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
298
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
299
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
300
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
301
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
302
+ // Observation metadata
303
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
304
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
305
+ { name: "ts", sql: "TIMESTAMP" },
306
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
307
+ // Snapshot payload
308
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
309
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
310
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
311
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
312
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
313
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
314
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
315
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
316
+ ]);
218
317
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
219
318
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
220
319
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
320
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
321
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
322
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
323
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
324
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
325
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
221
326
  function buildCreateTableSql(tableName, cols) {
222
327
  const safe = sqlIdent(tableName);
223
328
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -782,6 +887,24 @@ var DeeplakeApi = class {
782
887
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
783
888
  * worker.
784
889
  */
890
+ /**
891
+ * Create the codebase table. One row per (org, workspace, repo, user,
892
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
893
+ * + index follow the same pattern as ensureSessionsTable.
894
+ */
895
+ async ensureCodebaseTable(name) {
896
+ const safe = sqlIdent(name);
897
+ const tables = await this.listTables();
898
+ if (!tables.includes(safe)) {
899
+ log3(`table "${safe}" not found, creating`);
900
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
901
+ log3(`table "${safe}" created`);
902
+ if (!tables.includes(safe))
903
+ this._tablesCache = [...tables, safe];
904
+ }
905
+ await this.healSchema(safe, CODEBASE_COLUMNS);
906
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
907
+ }
785
908
  async ensureSkillsTable(name) {
786
909
  const safe = sqlIdent(name);
787
910
  const tables = await this.listTables();
@@ -795,6 +918,111 @@ var DeeplakeApi = class {
795
918
  await this.healSchema(safe, SKILLS_COLUMNS);
796
919
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
797
920
  }
921
+ /**
922
+ * Create the rules table.
923
+ *
924
+ * One row per rule version (same write pattern as skills): edits INSERT
925
+ * a fresh row with version+1, reads pick latest per rule_id via
926
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
927
+ * UPDATE-coalescing quirk by never UPDATEing.
928
+ */
929
+ async ensureRulesTable(name) {
930
+ const safe = sqlIdent(name);
931
+ const tables = await this.listTables();
932
+ if (!tables.includes(safe)) {
933
+ log3(`table "${safe}" not found, creating`);
934
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
935
+ log3(`table "${safe}" created`);
936
+ if (!tables.includes(safe))
937
+ this._tablesCache = [...tables, safe];
938
+ }
939
+ await this.healSchema(safe, RULES_COLUMNS);
940
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
941
+ }
942
+ /**
943
+ * Create the tasks table.
944
+ *
945
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
946
+ * column with the agent's KPI metadata; KPI current values come from
947
+ * `task_events` (SUM(value)), not this snapshot.
948
+ */
949
+ async ensureTasksTable(name) {
950
+ const safe = sqlIdent(name);
951
+ const tables = await this.listTables();
952
+ if (!tables.includes(safe)) {
953
+ log3(`table "${safe}" not found, creating`);
954
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
955
+ log3(`table "${safe}" created`);
956
+ if (!tables.includes(safe))
957
+ this._tablesCache = [...tables, safe];
958
+ }
959
+ await this.healSchema(safe, TASKS_COLUMNS);
960
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
961
+ }
962
+ /**
963
+ * Create the task-events table.
964
+ *
965
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
966
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
967
+ * (task_id, kpi_id) is the canonical aggregation key.
968
+ */
969
+ async ensureTaskEventsTable(name) {
970
+ const safe = sqlIdent(name);
971
+ const tables = await this.listTables();
972
+ if (!tables.includes(safe)) {
973
+ log3(`table "${safe}" not found, creating`);
974
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
975
+ log3(`table "${safe}" created`);
976
+ if (!tables.includes(safe))
977
+ this._tablesCache = [...tables, safe];
978
+ }
979
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
980
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
981
+ }
982
+ /**
983
+ * Create the goals table.
984
+ *
985
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
986
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
987
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
988
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
989
+ * read on cat / Read of a single goal.
990
+ */
991
+ async ensureGoalsTable(name) {
992
+ const safe = sqlIdent(name);
993
+ const tables = await this.listTables();
994
+ if (!tables.includes(safe)) {
995
+ log3(`table "${safe}" not found, creating`);
996
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
997
+ log3(`table "${safe}" created`);
998
+ if (!tables.includes(safe))
999
+ this._tablesCache = [...tables, safe];
1000
+ }
1001
+ await this.healSchema(safe, GOALS_COLUMNS);
1002
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1003
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1004
+ }
1005
+ /**
1006
+ * Create the kpis table.
1007
+ *
1008
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1009
+ * owner — ownership derives from the parent goal via logical join on
1010
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1011
+ * canonical lookup the VFS uses on Read and Write.
1012
+ */
1013
+ async ensureKpisTable(name) {
1014
+ const safe = sqlIdent(name);
1015
+ const tables = await this.listTables();
1016
+ if (!tables.includes(safe)) {
1017
+ log3(`table "${safe}" not found, creating`);
1018
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1019
+ log3(`table "${safe}" created`);
1020
+ if (!tables.includes(safe))
1021
+ this._tablesCache = [...tables, safe];
1022
+ }
1023
+ await this.healSchema(safe, KPIS_COLUMNS);
1024
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1025
+ }
798
1026
  };
799
1027
 
800
1028
  // dist/src/utils/session-path.js
@@ -384,6 +384,23 @@ function loadConfig() {
384
384
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
385
385
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
386
386
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
387
+ // Defaults match the table name written into the SQL — keep aligned
388
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
389
+ // deeplake-schema.ts and with the e2e test-org override convention
390
+ // (memory_test / sessions_test → goals_test, etc.) documented in
391
+ // CLAUDE.md.
392
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
393
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
394
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
395
+ // Goals + KPIs (refined design — VFS path classifier maps
396
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
397
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
398
+ // See src/shell/deeplake-fs.ts for the translation logic and
399
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
400
+ // table shape.
401
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
402
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
403
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
387
404
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join3(home, ".deeplake", "memory")
388
405
  };
389
406
  }
@@ -472,6 +489,65 @@ var SKILLS_COLUMNS = Object.freeze([
472
489
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
473
490
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
474
491
  ]);
492
+ var RULES_COLUMNS = Object.freeze([
493
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
494
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
495
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
496
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
497
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
498
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
499
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
500
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
501
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
502
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
503
+ ]);
504
+ var TASKS_COLUMNS = Object.freeze([
505
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
506
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
507
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
508
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
509
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
510
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
511
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
512
+ { name: "kpis", sql: "JSONB" },
513
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
514
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
515
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
516
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
517
+ ]);
518
+ var TASK_EVENTS_COLUMNS = Object.freeze([
519
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
520
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
521
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
522
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
523
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
524
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
525
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
526
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
527
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
528
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
529
+ ]);
530
+ var GOALS_COLUMNS = Object.freeze([
531
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
532
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
533
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
534
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
535
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
536
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
537
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
538
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
539
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
540
+ ]);
541
+ var KPIS_COLUMNS = Object.freeze([
542
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
543
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
544
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
545
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
546
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
547
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
548
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
549
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
550
+ ]);
475
551
  function validateSchema(label, cols) {
476
552
  const seen = /* @__PURE__ */ new Set();
477
553
  for (const col of cols) {
@@ -489,9 +565,38 @@ function validateSchema(label, cols) {
489
565
  }
490
566
  }
491
567
  }
568
+ var CODEBASE_COLUMNS = Object.freeze([
569
+ // Identity key (matches the PK below)
570
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
571
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
572
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
573
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
574
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
575
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
576
+ // Observation metadata
577
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
578
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
579
+ { name: "ts", sql: "TIMESTAMP" },
580
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
581
+ // Snapshot payload
582
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
583
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
584
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
585
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
586
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
587
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
588
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
589
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
590
+ ]);
492
591
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
493
592
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
494
593
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
594
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
595
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
596
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
597
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
598
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
599
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
495
600
  function buildCreateTableSql(tableName, cols) {
496
601
  const safe = sqlIdent(tableName);
497
602
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -1038,6 +1143,24 @@ var DeeplakeApi = class {
1038
1143
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
1039
1144
  * worker.
1040
1145
  */
1146
+ /**
1147
+ * Create the codebase table. One row per (org, workspace, repo, user,
1148
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
1149
+ * + index follow the same pattern as ensureSessionsTable.
1150
+ */
1151
+ async ensureCodebaseTable(name) {
1152
+ const safe = sqlIdent(name);
1153
+ const tables = await this.listTables();
1154
+ if (!tables.includes(safe)) {
1155
+ log3(`table "${safe}" not found, creating`);
1156
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
1157
+ log3(`table "${safe}" created`);
1158
+ if (!tables.includes(safe))
1159
+ this._tablesCache = [...tables, safe];
1160
+ }
1161
+ await this.healSchema(safe, CODEBASE_COLUMNS);
1162
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
1163
+ }
1041
1164
  async ensureSkillsTable(name) {
1042
1165
  const safe = sqlIdent(name);
1043
1166
  const tables = await this.listTables();
@@ -1051,6 +1174,111 @@ var DeeplakeApi = class {
1051
1174
  await this.healSchema(safe, SKILLS_COLUMNS);
1052
1175
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
1053
1176
  }
1177
+ /**
1178
+ * Create the rules table.
1179
+ *
1180
+ * One row per rule version (same write pattern as skills): edits INSERT
1181
+ * a fresh row with version+1, reads pick latest per rule_id via
1182
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
1183
+ * UPDATE-coalescing quirk by never UPDATEing.
1184
+ */
1185
+ async ensureRulesTable(name) {
1186
+ const safe = sqlIdent(name);
1187
+ const tables = await this.listTables();
1188
+ if (!tables.includes(safe)) {
1189
+ log3(`table "${safe}" not found, creating`);
1190
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
1191
+ log3(`table "${safe}" created`);
1192
+ if (!tables.includes(safe))
1193
+ this._tablesCache = [...tables, safe];
1194
+ }
1195
+ await this.healSchema(safe, RULES_COLUMNS);
1196
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
1197
+ }
1198
+ /**
1199
+ * Create the tasks table.
1200
+ *
1201
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
1202
+ * column with the agent's KPI metadata; KPI current values come from
1203
+ * `task_events` (SUM(value)), not this snapshot.
1204
+ */
1205
+ async ensureTasksTable(name) {
1206
+ const safe = sqlIdent(name);
1207
+ const tables = await this.listTables();
1208
+ if (!tables.includes(safe)) {
1209
+ log3(`table "${safe}" not found, creating`);
1210
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
1211
+ log3(`table "${safe}" created`);
1212
+ if (!tables.includes(safe))
1213
+ this._tablesCache = [...tables, safe];
1214
+ }
1215
+ await this.healSchema(safe, TASKS_COLUMNS);
1216
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
1217
+ }
1218
+ /**
1219
+ * Create the task-events table.
1220
+ *
1221
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
1222
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
1223
+ * (task_id, kpi_id) is the canonical aggregation key.
1224
+ */
1225
+ async ensureTaskEventsTable(name) {
1226
+ const safe = sqlIdent(name);
1227
+ const tables = await this.listTables();
1228
+ if (!tables.includes(safe)) {
1229
+ log3(`table "${safe}" not found, creating`);
1230
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
1231
+ log3(`table "${safe}" created`);
1232
+ if (!tables.includes(safe))
1233
+ this._tablesCache = [...tables, safe];
1234
+ }
1235
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
1236
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
1237
+ }
1238
+ /**
1239
+ * Create the goals table.
1240
+ *
1241
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
1242
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
1243
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
1244
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
1245
+ * read on cat / Read of a single goal.
1246
+ */
1247
+ async ensureGoalsTable(name) {
1248
+ const safe = sqlIdent(name);
1249
+ const tables = await this.listTables();
1250
+ if (!tables.includes(safe)) {
1251
+ log3(`table "${safe}" not found, creating`);
1252
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
1253
+ log3(`table "${safe}" created`);
1254
+ if (!tables.includes(safe))
1255
+ this._tablesCache = [...tables, safe];
1256
+ }
1257
+ await this.healSchema(safe, GOALS_COLUMNS);
1258
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1259
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1260
+ }
1261
+ /**
1262
+ * Create the kpis table.
1263
+ *
1264
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1265
+ * owner — ownership derives from the parent goal via logical join on
1266
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1267
+ * canonical lookup the VFS uses on Read and Write.
1268
+ */
1269
+ async ensureKpisTable(name) {
1270
+ const safe = sqlIdent(name);
1271
+ const tables = await this.listTables();
1272
+ if (!tables.includes(safe)) {
1273
+ log3(`table "${safe}" not found, creating`);
1274
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1275
+ log3(`table "${safe}" created`);
1276
+ if (!tables.includes(safe))
1277
+ this._tablesCache = [...tables, safe];
1278
+ }
1279
+ await this.healSchema(safe, KPIS_COLUMNS);
1280
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1281
+ }
1054
1282
  };
1055
1283
 
1056
1284
  // dist/src/cli/util.js