@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
@@ -104,6 +104,22 @@ function loadConfig() {
104
104
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
105
105
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
106
106
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
107
+ // Defaults match the table name written into the SQL — keep aligned
108
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
109
+ // deeplake-schema.ts and with the e2e test-org override convention
110
+ // (memory_test / sessions_test → goals_test, etc.) documented in
111
+ // CLAUDE.md.
112
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
113
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
114
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
115
+ // Goals + KPIs (refined design — VFS path classifier maps
116
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
117
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
118
+ // See src/shell/deeplake-fs.ts for the translation logic and
119
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
120
+ // table shape.
121
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
122
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
107
123
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
108
124
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
109
125
  };
@@ -205,6 +221,65 @@ var SKILLS_COLUMNS = Object.freeze([
205
221
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
206
222
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
207
223
  ]);
224
+ var RULES_COLUMNS = Object.freeze([
225
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
226
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
227
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
228
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
229
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
230
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
231
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
232
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
233
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
234
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
235
+ ]);
236
+ var TASKS_COLUMNS = Object.freeze([
237
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
238
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
239
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
241
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
242
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
243
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
244
+ { name: "kpis", sql: "JSONB" },
245
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
246
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
247
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
248
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
249
+ ]);
250
+ var TASK_EVENTS_COLUMNS = Object.freeze([
251
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
252
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
253
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
254
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
255
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
256
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
257
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
258
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
259
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
260
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
261
+ ]);
262
+ var GOALS_COLUMNS = Object.freeze([
263
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
264
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
265
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
266
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
267
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
268
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
269
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
270
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
271
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
272
+ ]);
273
+ var KPIS_COLUMNS = Object.freeze([
274
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
275
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
276
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
277
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
278
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
279
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
280
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
281
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
282
+ ]);
208
283
  function validateSchema(label, cols) {
209
284
  const seen = /* @__PURE__ */ new Set();
210
285
  for (const col of cols) {
@@ -248,6 +323,11 @@ var CODEBASE_COLUMNS = Object.freeze([
248
323
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
249
324
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
250
325
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
326
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
327
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
328
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
329
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
330
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
251
331
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
252
332
  function buildCreateTableSql(tableName, cols) {
253
333
  const safe = sqlIdent(tableName);
@@ -844,6 +924,111 @@ var DeeplakeApi = class {
844
924
  await this.healSchema(safe, SKILLS_COLUMNS);
845
925
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
846
926
  }
927
+ /**
928
+ * Create the rules table.
929
+ *
930
+ * One row per rule version (same write pattern as skills): edits INSERT
931
+ * a fresh row with version+1, reads pick latest per rule_id via
932
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
933
+ * UPDATE-coalescing quirk by never UPDATEing.
934
+ */
935
+ async ensureRulesTable(name) {
936
+ const safe = sqlIdent(name);
937
+ const tables = await this.listTables();
938
+ if (!tables.includes(safe)) {
939
+ log3(`table "${safe}" not found, creating`);
940
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
941
+ log3(`table "${safe}" created`);
942
+ if (!tables.includes(safe))
943
+ this._tablesCache = [...tables, safe];
944
+ }
945
+ await this.healSchema(safe, RULES_COLUMNS);
946
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
947
+ }
948
+ /**
949
+ * Create the tasks table.
950
+ *
951
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
952
+ * column with the agent's KPI metadata; KPI current values come from
953
+ * `task_events` (SUM(value)), not this snapshot.
954
+ */
955
+ async ensureTasksTable(name) {
956
+ const safe = sqlIdent(name);
957
+ const tables = await this.listTables();
958
+ if (!tables.includes(safe)) {
959
+ log3(`table "${safe}" not found, creating`);
960
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
961
+ log3(`table "${safe}" created`);
962
+ if (!tables.includes(safe))
963
+ this._tablesCache = [...tables, safe];
964
+ }
965
+ await this.healSchema(safe, TASKS_COLUMNS);
966
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
967
+ }
968
+ /**
969
+ * Create the task-events table.
970
+ *
971
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
972
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
973
+ * (task_id, kpi_id) is the canonical aggregation key.
974
+ */
975
+ async ensureTaskEventsTable(name) {
976
+ const safe = sqlIdent(name);
977
+ const tables = await this.listTables();
978
+ if (!tables.includes(safe)) {
979
+ log3(`table "${safe}" not found, creating`);
980
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
981
+ log3(`table "${safe}" created`);
982
+ if (!tables.includes(safe))
983
+ this._tablesCache = [...tables, safe];
984
+ }
985
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
986
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
987
+ }
988
+ /**
989
+ * Create the goals table.
990
+ *
991
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
992
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
993
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
994
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
995
+ * read on cat / Read of a single goal.
996
+ */
997
+ async ensureGoalsTable(name) {
998
+ const safe = sqlIdent(name);
999
+ const tables = await this.listTables();
1000
+ if (!tables.includes(safe)) {
1001
+ log3(`table "${safe}" not found, creating`);
1002
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
1003
+ log3(`table "${safe}" created`);
1004
+ if (!tables.includes(safe))
1005
+ this._tablesCache = [...tables, safe];
1006
+ }
1007
+ await this.healSchema(safe, GOALS_COLUMNS);
1008
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1009
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1010
+ }
1011
+ /**
1012
+ * Create the kpis table.
1013
+ *
1014
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1015
+ * owner — ownership derives from the parent goal via logical join on
1016
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1017
+ * canonical lookup the VFS uses on Read and Write.
1018
+ */
1019
+ async ensureKpisTable(name) {
1020
+ const safe = sqlIdent(name);
1021
+ const tables = await this.listTables();
1022
+ if (!tables.includes(safe)) {
1023
+ log3(`table "${safe}" not found, creating`);
1024
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1025
+ log3(`table "${safe}" created`);
1026
+ if (!tables.includes(safe))
1027
+ this._tablesCache = [...tables, safe];
1028
+ }
1029
+ await this.healSchema(safe, KPIS_COLUMNS);
1030
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1031
+ }
847
1032
  };
848
1033
 
849
1034
  // dist/src/shell/grep-core.js
@@ -126,6 +126,22 @@ function loadConfig() {
126
126
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
127
127
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
128
128
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
129
+ // Defaults match the table name written into the SQL — keep aligned
130
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
131
+ // deeplake-schema.ts and with the e2e test-org override convention
132
+ // (memory_test / sessions_test → goals_test, etc.) documented in
133
+ // CLAUDE.md.
134
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
135
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
136
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
137
+ // Goals + KPIs (refined design — VFS path classifier maps
138
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
139
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
140
+ // See src/shell/deeplake-fs.ts for the translation logic and
141
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
142
+ // table shape.
143
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
144
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
129
145
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
130
146
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join3(home, ".deeplake", "memory")
131
147
  };
@@ -218,6 +234,65 @@ var SKILLS_COLUMNS = Object.freeze([
218
234
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
219
235
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
220
236
  ]);
237
+ var RULES_COLUMNS = Object.freeze([
238
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
239
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
241
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
242
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
243
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
244
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
245
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
247
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
248
+ ]);
249
+ var TASKS_COLUMNS = Object.freeze([
250
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
251
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
252
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
253
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
254
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
255
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
256
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
257
+ { name: "kpis", sql: "JSONB" },
258
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
259
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
260
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
261
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
262
+ ]);
263
+ var TASK_EVENTS_COLUMNS = Object.freeze([
264
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
265
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
266
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
267
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
268
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
269
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
270
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
271
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
272
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
273
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
274
+ ]);
275
+ var GOALS_COLUMNS = Object.freeze([
276
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
277
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
278
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
279
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
280
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
281
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
282
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
283
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
284
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
285
+ ]);
286
+ var KPIS_COLUMNS = Object.freeze([
287
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
288
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
289
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
290
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
291
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
292
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
293
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
294
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
295
+ ]);
221
296
  function validateSchema(label, cols) {
222
297
  const seen = /* @__PURE__ */ new Set();
223
298
  for (const col of cols) {
@@ -261,6 +336,11 @@ var CODEBASE_COLUMNS = Object.freeze([
261
336
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
262
337
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
263
338
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
339
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
340
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
341
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
342
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
343
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
264
344
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
265
345
  function buildCreateTableSql(tableName, cols) {
266
346
  const safe = sqlIdent(tableName);
@@ -839,6 +919,111 @@ var DeeplakeApi = class {
839
919
  await this.healSchema(safe, SKILLS_COLUMNS);
840
920
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
841
921
  }
922
+ /**
923
+ * Create the rules table.
924
+ *
925
+ * One row per rule version (same write pattern as skills): edits INSERT
926
+ * a fresh row with version+1, reads pick latest per rule_id via
927
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
928
+ * UPDATE-coalescing quirk by never UPDATEing.
929
+ */
930
+ async ensureRulesTable(name) {
931
+ const safe = sqlIdent(name);
932
+ const tables = await this.listTables();
933
+ if (!tables.includes(safe)) {
934
+ log3(`table "${safe}" not found, creating`);
935
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
936
+ log3(`table "${safe}" created`);
937
+ if (!tables.includes(safe))
938
+ this._tablesCache = [...tables, safe];
939
+ }
940
+ await this.healSchema(safe, RULES_COLUMNS);
941
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
942
+ }
943
+ /**
944
+ * Create the tasks table.
945
+ *
946
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
947
+ * column with the agent's KPI metadata; KPI current values come from
948
+ * `task_events` (SUM(value)), not this snapshot.
949
+ */
950
+ async ensureTasksTable(name) {
951
+ const safe = sqlIdent(name);
952
+ const tables = await this.listTables();
953
+ if (!tables.includes(safe)) {
954
+ log3(`table "${safe}" not found, creating`);
955
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
956
+ log3(`table "${safe}" created`);
957
+ if (!tables.includes(safe))
958
+ this._tablesCache = [...tables, safe];
959
+ }
960
+ await this.healSchema(safe, TASKS_COLUMNS);
961
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
962
+ }
963
+ /**
964
+ * Create the task-events table.
965
+ *
966
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
967
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
968
+ * (task_id, kpi_id) is the canonical aggregation key.
969
+ */
970
+ async ensureTaskEventsTable(name) {
971
+ const safe = sqlIdent(name);
972
+ const tables = await this.listTables();
973
+ if (!tables.includes(safe)) {
974
+ log3(`table "${safe}" not found, creating`);
975
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
976
+ log3(`table "${safe}" created`);
977
+ if (!tables.includes(safe))
978
+ this._tablesCache = [...tables, safe];
979
+ }
980
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
981
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
982
+ }
983
+ /**
984
+ * Create the goals table.
985
+ *
986
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
987
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
988
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
989
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
990
+ * read on cat / Read of a single goal.
991
+ */
992
+ async ensureGoalsTable(name) {
993
+ const safe = sqlIdent(name);
994
+ const tables = await this.listTables();
995
+ if (!tables.includes(safe)) {
996
+ log3(`table "${safe}" not found, creating`);
997
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
998
+ log3(`table "${safe}" created`);
999
+ if (!tables.includes(safe))
1000
+ this._tablesCache = [...tables, safe];
1001
+ }
1002
+ await this.healSchema(safe, GOALS_COLUMNS);
1003
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1004
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1005
+ }
1006
+ /**
1007
+ * Create the kpis table.
1008
+ *
1009
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1010
+ * owner — ownership derives from the parent goal via logical join on
1011
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1012
+ * canonical lookup the VFS uses on Read and Write.
1013
+ */
1014
+ async ensureKpisTable(name) {
1015
+ const safe = sqlIdent(name);
1016
+ const tables = await this.listTables();
1017
+ if (!tables.includes(safe)) {
1018
+ log3(`table "${safe}" not found, creating`);
1019
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1020
+ log3(`table "${safe}" created`);
1021
+ if (!tables.includes(safe))
1022
+ this._tablesCache = [...tables, safe];
1023
+ }
1024
+ await this.healSchema(safe, KPIS_COLUMNS);
1025
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1026
+ }
842
1027
  };
843
1028
 
844
1029
  // dist/src/utils/stdin.js
@@ -324,6 +324,22 @@ function loadConfig() {
324
324
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
325
325
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
326
326
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
327
+ // Defaults match the table name written into the SQL — keep aligned
328
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
329
+ // deeplake-schema.ts and with the e2e test-org override convention
330
+ // (memory_test / sessions_test → goals_test, etc.) documented in
331
+ // CLAUDE.md.
332
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
333
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
334
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
335
+ // Goals + KPIs (refined design — VFS path classifier maps
336
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
337
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
338
+ // See src/shell/deeplake-fs.ts for the translation logic and
339
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
340
+ // table shape.
341
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
342
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
327
343
  codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
328
344
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join7(home, ".deeplake", "memory")
329
345
  };
@@ -398,6 +414,65 @@ var SKILLS_COLUMNS = Object.freeze([
398
414
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
399
415
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
400
416
  ]);
417
+ var RULES_COLUMNS = Object.freeze([
418
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
419
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
420
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
421
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
422
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
423
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
424
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
425
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
426
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
427
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
428
+ ]);
429
+ var TASKS_COLUMNS = Object.freeze([
430
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
431
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
432
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
433
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
434
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
435
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
436
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
437
+ { name: "kpis", sql: "JSONB" },
438
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
439
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
440
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
441
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
442
+ ]);
443
+ var TASK_EVENTS_COLUMNS = Object.freeze([
444
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
445
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
446
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
447
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
448
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
449
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
450
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
451
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
452
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
453
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
454
+ ]);
455
+ var GOALS_COLUMNS = Object.freeze([
456
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
457
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
458
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
459
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
460
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
461
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
462
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
463
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
464
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
465
+ ]);
466
+ var KPIS_COLUMNS = Object.freeze([
467
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
468
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
469
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
470
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
471
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
472
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
473
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
474
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
475
+ ]);
401
476
  function validateSchema(label, cols) {
402
477
  const seen = /* @__PURE__ */ new Set();
403
478
  for (const col of cols) {
@@ -441,6 +516,11 @@ var CODEBASE_COLUMNS = Object.freeze([
441
516
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
442
517
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
443
518
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
519
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
520
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
521
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
522
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
523
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
444
524
  validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
445
525
  function buildCreateTableSql(tableName, cols) {
446
526
  const safe = sqlIdent(tableName);
@@ -1019,6 +1099,111 @@ var DeeplakeApi = class {
1019
1099
  await this.healSchema(safe, SKILLS_COLUMNS);
1020
1100
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
1021
1101
  }
1102
+ /**
1103
+ * Create the rules table.
1104
+ *
1105
+ * One row per rule version (same write pattern as skills): edits INSERT
1106
+ * a fresh row with version+1, reads pick latest per rule_id via
1107
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
1108
+ * UPDATE-coalescing quirk by never UPDATEing.
1109
+ */
1110
+ async ensureRulesTable(name) {
1111
+ const safe = sqlIdent(name);
1112
+ const tables = await this.listTables();
1113
+ if (!tables.includes(safe)) {
1114
+ log3(`table "${safe}" not found, creating`);
1115
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
1116
+ log3(`table "${safe}" created`);
1117
+ if (!tables.includes(safe))
1118
+ this._tablesCache = [...tables, safe];
1119
+ }
1120
+ await this.healSchema(safe, RULES_COLUMNS);
1121
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
1122
+ }
1123
+ /**
1124
+ * Create the tasks table.
1125
+ *
1126
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
1127
+ * column with the agent's KPI metadata; KPI current values come from
1128
+ * `task_events` (SUM(value)), not this snapshot.
1129
+ */
1130
+ async ensureTasksTable(name) {
1131
+ const safe = sqlIdent(name);
1132
+ const tables = await this.listTables();
1133
+ if (!tables.includes(safe)) {
1134
+ log3(`table "${safe}" not found, creating`);
1135
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
1136
+ log3(`table "${safe}" created`);
1137
+ if (!tables.includes(safe))
1138
+ this._tablesCache = [...tables, safe];
1139
+ }
1140
+ await this.healSchema(safe, TASKS_COLUMNS);
1141
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
1142
+ }
1143
+ /**
1144
+ * Create the task-events table.
1145
+ *
1146
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
1147
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
1148
+ * (task_id, kpi_id) is the canonical aggregation key.
1149
+ */
1150
+ async ensureTaskEventsTable(name) {
1151
+ const safe = sqlIdent(name);
1152
+ const tables = await this.listTables();
1153
+ if (!tables.includes(safe)) {
1154
+ log3(`table "${safe}" not found, creating`);
1155
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
1156
+ log3(`table "${safe}" created`);
1157
+ if (!tables.includes(safe))
1158
+ this._tablesCache = [...tables, safe];
1159
+ }
1160
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
1161
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
1162
+ }
1163
+ /**
1164
+ * Create the goals table.
1165
+ *
1166
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
1167
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
1168
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
1169
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
1170
+ * read on cat / Read of a single goal.
1171
+ */
1172
+ async ensureGoalsTable(name) {
1173
+ const safe = sqlIdent(name);
1174
+ const tables = await this.listTables();
1175
+ if (!tables.includes(safe)) {
1176
+ log3(`table "${safe}" not found, creating`);
1177
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
1178
+ log3(`table "${safe}" created`);
1179
+ if (!tables.includes(safe))
1180
+ this._tablesCache = [...tables, safe];
1181
+ }
1182
+ await this.healSchema(safe, GOALS_COLUMNS);
1183
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1184
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1185
+ }
1186
+ /**
1187
+ * Create the kpis table.
1188
+ *
1189
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1190
+ * owner — ownership derives from the parent goal via logical join on
1191
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1192
+ * canonical lookup the VFS uses on Read and Write.
1193
+ */
1194
+ async ensureKpisTable(name) {
1195
+ const safe = sqlIdent(name);
1196
+ const tables = await this.listTables();
1197
+ if (!tables.includes(safe)) {
1198
+ log3(`table "${safe}" not found, creating`);
1199
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1200
+ log3(`table "${safe}" created`);
1201
+ if (!tables.includes(safe))
1202
+ this._tablesCache = [...tables, safe];
1203
+ }
1204
+ await this.healSchema(safe, KPIS_COLUMNS);
1205
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1206
+ }
1022
1207
  };
1023
1208
 
1024
1209
  // dist/src/skillify/pull.js