@deeplake/hivemind 0.7.46 → 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 (38) 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 +17230 -4177
  5. package/codex/bundle/capture.js +185 -0
  6. package/codex/bundle/commands/auth-login.js +185 -0
  7. package/codex/bundle/graph-pull-worker.js +185 -0
  8. package/codex/bundle/pre-tool-use.js +185 -0
  9. package/codex/bundle/session-start-setup.js +185 -0
  10. package/codex/bundle/session-start.js +185 -0
  11. package/codex/bundle/shell/deeplake-shell.js +451 -3
  12. package/codex/bundle/skillify-worker.js +64 -0
  13. package/codex/bundle/stop.js +185 -0
  14. package/codex/skills/hivemind-goals/SKILL.md +157 -0
  15. package/cursor/bundle/capture.js +185 -0
  16. package/cursor/bundle/commands/auth-login.js +185 -0
  17. package/cursor/bundle/graph-pull-worker.js +185 -0
  18. package/cursor/bundle/pre-tool-use.js +185 -0
  19. package/cursor/bundle/session-end.js +16 -0
  20. package/cursor/bundle/session-start.js +596 -6
  21. package/cursor/bundle/shell/deeplake-shell.js +451 -3
  22. package/cursor/bundle/skillify-worker.js +64 -0
  23. package/hermes/bundle/capture.js +185 -0
  24. package/hermes/bundle/commands/auth-login.js +185 -0
  25. package/hermes/bundle/graph-pull-worker.js +185 -0
  26. package/hermes/bundle/pre-tool-use.js +185 -0
  27. package/hermes/bundle/session-end.js +16 -0
  28. package/hermes/bundle/session-start.js +596 -6
  29. package/hermes/bundle/shell/deeplake-shell.js +451 -3
  30. package/hermes/bundle/skillify-worker.js +64 -0
  31. package/mcp/bundle/server.js +185 -0
  32. package/openclaw/dist/chunks/{config-O5PDJQ7Y.js → config-FH6JYSJW.js} +16 -0
  33. package/openclaw/dist/index.js +262 -2
  34. package/openclaw/dist/skillify-worker.js +64 -0
  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 +2 -1
@@ -384,6 +384,22 @@ 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",
387
403
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
388
404
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join3(home, ".deeplake", "memory")
389
405
  };
@@ -473,6 +489,65 @@ var SKILLS_COLUMNS = Object.freeze([
473
489
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
474
490
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
475
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
+ ]);
476
551
  function validateSchema(label, cols) {
477
552
  const seen = /* @__PURE__ */ new Set();
478
553
  for (const col of cols) {
@@ -516,6 +591,11 @@ var CODEBASE_COLUMNS = Object.freeze([
516
591
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
517
592
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
518
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);
519
599
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
520
600
  function buildCreateTableSql(tableName, cols) {
521
601
  const safe = sqlIdent(tableName);
@@ -1094,6 +1174,111 @@ var DeeplakeApi = class {
1094
1174
  await this.healSchema(safe, SKILLS_COLUMNS);
1095
1175
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
1096
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
+ }
1097
1282
  };
1098
1283
 
1099
1284
  // dist/src/cli/util.js
@@ -91,6 +91,22 @@ function loadConfig() {
91
91
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
92
92
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
93
93
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
94
+ // Defaults match the table name written into the SQL — keep aligned
95
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
96
+ // deeplake-schema.ts and with the e2e test-org override convention
97
+ // (memory_test / sessions_test → goals_test, etc.) documented in
98
+ // CLAUDE.md.
99
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
100
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
101
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
102
+ // Goals + KPIs (refined design — VFS path classifier maps
103
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
104
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
105
+ // See src/shell/deeplake-fs.ts for the translation logic and
106
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
107
+ // table shape.
108
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
109
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
94
110
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
95
111
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
96
112
  };
@@ -189,6 +205,65 @@ var SKILLS_COLUMNS = Object.freeze([
189
205
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
190
206
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
191
207
  ]);
208
+ var RULES_COLUMNS = Object.freeze([
209
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
210
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
211
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
212
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
213
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
214
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
215
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
216
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
217
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
218
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
219
+ ]);
220
+ var TASKS_COLUMNS = Object.freeze([
221
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
222
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
223
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
224
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
225
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
226
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
227
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
228
+ { name: "kpis", sql: "JSONB" },
229
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
230
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
231
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
232
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
233
+ ]);
234
+ var TASK_EVENTS_COLUMNS = Object.freeze([
235
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
236
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
237
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
238
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
239
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
240
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
241
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
242
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
243
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
244
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
245
+ ]);
246
+ var GOALS_COLUMNS = Object.freeze([
247
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
248
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
249
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
250
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
251
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
252
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
253
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
254
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
255
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
256
+ ]);
257
+ var KPIS_COLUMNS = Object.freeze([
258
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
259
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
260
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
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
+ ]);
192
267
  function validateSchema(label, cols) {
193
268
  const seen = /* @__PURE__ */ new Set();
194
269
  for (const col of cols) {
@@ -232,6 +307,11 @@ var CODEBASE_COLUMNS = Object.freeze([
232
307
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
233
308
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
234
309
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
310
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
311
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
312
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
313
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
314
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
235
315
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
236
316
  function buildCreateTableSql(tableName, cols) {
237
317
  const safe = sqlIdent(tableName);
@@ -828,6 +908,111 @@ var DeeplakeApi = class {
828
908
  await this.healSchema(safe, SKILLS_COLUMNS);
829
909
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
830
910
  }
911
+ /**
912
+ * Create the rules table.
913
+ *
914
+ * One row per rule version (same write pattern as skills): edits INSERT
915
+ * a fresh row with version+1, reads pick latest per rule_id via
916
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
917
+ * UPDATE-coalescing quirk by never UPDATEing.
918
+ */
919
+ async ensureRulesTable(name) {
920
+ const safe = sqlIdent(name);
921
+ const tables = await this.listTables();
922
+ if (!tables.includes(safe)) {
923
+ log3(`table "${safe}" not found, creating`);
924
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
925
+ log3(`table "${safe}" created`);
926
+ if (!tables.includes(safe))
927
+ this._tablesCache = [...tables, safe];
928
+ }
929
+ await this.healSchema(safe, RULES_COLUMNS);
930
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
931
+ }
932
+ /**
933
+ * Create the tasks table.
934
+ *
935
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
936
+ * column with the agent's KPI metadata; KPI current values come from
937
+ * `task_events` (SUM(value)), not this snapshot.
938
+ */
939
+ async ensureTasksTable(name) {
940
+ const safe = sqlIdent(name);
941
+ const tables = await this.listTables();
942
+ if (!tables.includes(safe)) {
943
+ log3(`table "${safe}" not found, creating`);
944
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
945
+ log3(`table "${safe}" created`);
946
+ if (!tables.includes(safe))
947
+ this._tablesCache = [...tables, safe];
948
+ }
949
+ await this.healSchema(safe, TASKS_COLUMNS);
950
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
951
+ }
952
+ /**
953
+ * Create the task-events table.
954
+ *
955
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
956
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
957
+ * (task_id, kpi_id) is the canonical aggregation key.
958
+ */
959
+ async ensureTaskEventsTable(name) {
960
+ const safe = sqlIdent(name);
961
+ const tables = await this.listTables();
962
+ if (!tables.includes(safe)) {
963
+ log3(`table "${safe}" not found, creating`);
964
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
965
+ log3(`table "${safe}" created`);
966
+ if (!tables.includes(safe))
967
+ this._tablesCache = [...tables, safe];
968
+ }
969
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
970
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
971
+ }
972
+ /**
973
+ * Create the goals table.
974
+ *
975
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
976
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
977
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
978
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
979
+ * read on cat / Read of a single goal.
980
+ */
981
+ async ensureGoalsTable(name) {
982
+ const safe = sqlIdent(name);
983
+ const tables = await this.listTables();
984
+ if (!tables.includes(safe)) {
985
+ log3(`table "${safe}" not found, creating`);
986
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
987
+ log3(`table "${safe}" created`);
988
+ if (!tables.includes(safe))
989
+ this._tablesCache = [...tables, safe];
990
+ }
991
+ await this.healSchema(safe, GOALS_COLUMNS);
992
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
993
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
994
+ }
995
+ /**
996
+ * Create the kpis table.
997
+ *
998
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
999
+ * owner — ownership derives from the parent goal via logical join on
1000
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1001
+ * canonical lookup the VFS uses on Read and Write.
1002
+ */
1003
+ async ensureKpisTable(name) {
1004
+ const safe = sqlIdent(name);
1005
+ const tables = await this.listTables();
1006
+ if (!tables.includes(safe)) {
1007
+ log3(`table "${safe}" not found, creating`);
1008
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1009
+ log3(`table "${safe}" created`);
1010
+ if (!tables.includes(safe))
1011
+ this._tablesCache = [...tables, safe];
1012
+ }
1013
+ await this.healSchema(safe, KPIS_COLUMNS);
1014
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1015
+ }
831
1016
  };
832
1017
 
833
1018
  // dist/src/utils/repo-identity.js
@@ -97,6 +97,22 @@ function loadConfig() {
97
97
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
98
98
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
99
99
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
100
+ // Defaults match the table name written into the SQL — keep aligned
101
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
102
+ // deeplake-schema.ts and with the e2e test-org override convention
103
+ // (memory_test / sessions_test → goals_test, etc.) documented in
104
+ // CLAUDE.md.
105
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
106
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
107
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
108
+ // Goals + KPIs (refined design — VFS path classifier maps
109
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
110
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
111
+ // See src/shell/deeplake-fs.ts for the translation logic and
112
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
113
+ // table shape.
114
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
115
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
100
116
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
101
117
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
102
118
  };
@@ -198,6 +214,65 @@ var SKILLS_COLUMNS = Object.freeze([
198
214
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
199
215
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
200
216
  ]);
217
+ var RULES_COLUMNS = Object.freeze([
218
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
219
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
220
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
221
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
222
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
223
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
224
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
225
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
226
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
227
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
228
+ ]);
229
+ var TASKS_COLUMNS = Object.freeze([
230
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
231
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
232
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
233
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
234
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
235
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
236
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
237
+ { name: "kpis", sql: "JSONB" },
238
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
239
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
241
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
242
+ ]);
243
+ var TASK_EVENTS_COLUMNS = Object.freeze([
244
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
245
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
247
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
248
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
249
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
250
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
251
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
252
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
253
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
254
+ ]);
255
+ var GOALS_COLUMNS = Object.freeze([
256
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
257
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
258
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
259
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
260
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
261
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
262
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
263
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
264
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
265
+ ]);
266
+ var KPIS_COLUMNS = Object.freeze([
267
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
268
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
269
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
270
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
271
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
272
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
273
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
274
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
275
+ ]);
201
276
  function validateSchema(label, cols) {
202
277
  const seen = /* @__PURE__ */ new Set();
203
278
  for (const col of cols) {
@@ -241,6 +316,11 @@ var CODEBASE_COLUMNS = Object.freeze([
241
316
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
242
317
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
243
318
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
319
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
320
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
321
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
322
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
323
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
244
324
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
245
325
  function buildCreateTableSql(tableName, cols) {
246
326
  const safe = sqlIdent(tableName);
@@ -837,6 +917,111 @@ var DeeplakeApi = class {
837
917
  await this.healSchema(safe, SKILLS_COLUMNS);
838
918
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
839
919
  }
920
+ /**
921
+ * Create the rules table.
922
+ *
923
+ * One row per rule version (same write pattern as skills): edits INSERT
924
+ * a fresh row with version+1, reads pick latest per rule_id via
925
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
926
+ * UPDATE-coalescing quirk by never UPDATEing.
927
+ */
928
+ async ensureRulesTable(name) {
929
+ const safe = sqlIdent(name);
930
+ const tables = await this.listTables();
931
+ if (!tables.includes(safe)) {
932
+ log3(`table "${safe}" not found, creating`);
933
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
934
+ log3(`table "${safe}" created`);
935
+ if (!tables.includes(safe))
936
+ this._tablesCache = [...tables, safe];
937
+ }
938
+ await this.healSchema(safe, RULES_COLUMNS);
939
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
940
+ }
941
+ /**
942
+ * Create the tasks table.
943
+ *
944
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
945
+ * column with the agent's KPI metadata; KPI current values come from
946
+ * `task_events` (SUM(value)), not this snapshot.
947
+ */
948
+ async ensureTasksTable(name) {
949
+ const safe = sqlIdent(name);
950
+ const tables = await this.listTables();
951
+ if (!tables.includes(safe)) {
952
+ log3(`table "${safe}" not found, creating`);
953
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
954
+ log3(`table "${safe}" created`);
955
+ if (!tables.includes(safe))
956
+ this._tablesCache = [...tables, safe];
957
+ }
958
+ await this.healSchema(safe, TASKS_COLUMNS);
959
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
960
+ }
961
+ /**
962
+ * Create the task-events table.
963
+ *
964
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
965
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
966
+ * (task_id, kpi_id) is the canonical aggregation key.
967
+ */
968
+ async ensureTaskEventsTable(name) {
969
+ const safe = sqlIdent(name);
970
+ const tables = await this.listTables();
971
+ if (!tables.includes(safe)) {
972
+ log3(`table "${safe}" not found, creating`);
973
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
974
+ log3(`table "${safe}" created`);
975
+ if (!tables.includes(safe))
976
+ this._tablesCache = [...tables, safe];
977
+ }
978
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
979
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
980
+ }
981
+ /**
982
+ * Create the goals table.
983
+ *
984
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
985
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
986
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
987
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
988
+ * read on cat / Read of a single goal.
989
+ */
990
+ async ensureGoalsTable(name) {
991
+ const safe = sqlIdent(name);
992
+ const tables = await this.listTables();
993
+ if (!tables.includes(safe)) {
994
+ log3(`table "${safe}" not found, creating`);
995
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
996
+ log3(`table "${safe}" created`);
997
+ if (!tables.includes(safe))
998
+ this._tablesCache = [...tables, safe];
999
+ }
1000
+ await this.healSchema(safe, GOALS_COLUMNS);
1001
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1002
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1003
+ }
1004
+ /**
1005
+ * Create the kpis table.
1006
+ *
1007
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1008
+ * owner — ownership derives from the parent goal via logical join on
1009
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1010
+ * canonical lookup the VFS uses on Read and Write.
1011
+ */
1012
+ async ensureKpisTable(name) {
1013
+ const safe = sqlIdent(name);
1014
+ const tables = await this.listTables();
1015
+ if (!tables.includes(safe)) {
1016
+ log3(`table "${safe}" not found, creating`);
1017
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1018
+ log3(`table "${safe}" created`);
1019
+ if (!tables.includes(safe))
1020
+ this._tablesCache = [...tables, safe];
1021
+ }
1022
+ await this.healSchema(safe, KPIS_COLUMNS);
1023
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1024
+ }
840
1025
  };
841
1026
 
842
1027
  // dist/src/shell/grep-core.js
@@ -64,6 +64,22 @@ function loadConfig() {
64
64
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
65
65
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
66
66
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
67
+ // Defaults match the table name written into the SQL — keep aligned
68
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
69
+ // deeplake-schema.ts and with the e2e test-org override convention
70
+ // (memory_test / sessions_test → goals_test, etc.) documented in
71
+ // CLAUDE.md.
72
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
73
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
74
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
75
+ // Goals + KPIs (refined design — VFS path classifier maps
76
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
77
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
78
+ // See src/shell/deeplake-fs.ts for the translation logic and
79
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
80
+ // table shape.
81
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
82
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
67
83
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
68
84
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join2(home, ".deeplake", "memory")
69
85
  };