@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.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +64 -0
- package/bundle/cli.js +22702 -7775
- package/codex/bundle/capture.js +228 -0
- package/codex/bundle/commands/auth-login.js +228 -0
- package/codex/bundle/graph-pull-worker.js +1370 -0
- package/codex/bundle/pre-tool-use.js +228 -0
- package/codex/bundle/session-start-setup.js +228 -0
- package/codex/bundle/session-start.js +255 -4
- package/codex/bundle/shell/deeplake-shell.js +1028 -28
- package/codex/bundle/skillify-worker.js +94 -3
- package/codex/bundle/stop.js +282 -50
- package/codex/skills/hivemind-goals/SKILL.md +157 -0
- package/cursor/bundle/capture.js +282 -50
- package/cursor/bundle/commands/auth-login.js +228 -0
- package/cursor/bundle/graph-pull-worker.js +1370 -0
- package/cursor/bundle/pre-tool-use.js +228 -0
- package/cursor/bundle/session-end.js +65 -44
- package/cursor/bundle/session-start.js +662 -6
- package/cursor/bundle/shell/deeplake-shell.js +1028 -28
- package/cursor/bundle/skillify-worker.js +94 -3
- package/hermes/bundle/capture.js +282 -50
- package/hermes/bundle/commands/auth-login.js +228 -0
- package/hermes/bundle/graph-pull-worker.js +1370 -0
- package/hermes/bundle/pre-tool-use.js +228 -0
- package/hermes/bundle/session-end.js +65 -44
- package/hermes/bundle/session-start.js +662 -6
- package/hermes/bundle/shell/deeplake-shell.js +1028 -28
- package/hermes/bundle/skillify-worker.js +94 -3
- package/mcp/bundle/server.js +228 -0
- package/openclaw/dist/chunks/config-FH6JYSJW.js +53 -0
- package/openclaw/dist/index.js +307 -2
- package/openclaw/dist/skillify-worker.js +94 -3
- package/openclaw/openclaw.plugin.json +4 -2
- package/openclaw/package.json +1 -1
- package/openclaw/skills/hivemind-goals/SKILL.md +30 -0
- package/package.json +4 -1
- package/openclaw/dist/chunks/config-XEK4MJJS.js +0 -36
|
@@ -104,6 +104,23 @@ 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",
|
|
123
|
+
codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
|
|
107
124
|
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
|
|
108
125
|
};
|
|
109
126
|
}
|
|
@@ -204,6 +221,65 @@ var SKILLS_COLUMNS = Object.freeze([
|
|
|
204
221
|
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
205
222
|
{ name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
206
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
|
+
]);
|
|
207
283
|
function validateSchema(label, cols) {
|
|
208
284
|
const seen = /* @__PURE__ */ new Set();
|
|
209
285
|
for (const col of cols) {
|
|
@@ -221,9 +297,38 @@ function validateSchema(label, cols) {
|
|
|
221
297
|
}
|
|
222
298
|
}
|
|
223
299
|
}
|
|
300
|
+
var CODEBASE_COLUMNS = Object.freeze([
|
|
301
|
+
// Identity key (matches the PK below)
|
|
302
|
+
{ name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
303
|
+
{ name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
304
|
+
{ name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
305
|
+
{ name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
306
|
+
{ name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
307
|
+
{ name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
308
|
+
// Observation metadata
|
|
309
|
+
{ name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
310
|
+
{ name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
311
|
+
{ name: "ts", sql: "TIMESTAMP" },
|
|
312
|
+
{ name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
313
|
+
// Snapshot payload
|
|
314
|
+
{ name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
315
|
+
{ name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
316
|
+
{ name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
317
|
+
{ name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
318
|
+
// Generator metadata (for drift diagnostics — what hivemind version produced this?)
|
|
319
|
+
{ name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
|
|
320
|
+
{ name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
321
|
+
{ name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
|
|
322
|
+
]);
|
|
224
323
|
validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
225
324
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
226
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);
|
|
331
|
+
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
227
332
|
function buildCreateTableSql(tableName, cols) {
|
|
228
333
|
const safe = sqlIdent(tableName);
|
|
229
334
|
const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
|
|
@@ -788,6 +893,24 @@ var DeeplakeApi = class {
|
|
|
788
893
|
* This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
|
|
789
894
|
* worker.
|
|
790
895
|
*/
|
|
896
|
+
/**
|
|
897
|
+
* Create the codebase table. One row per (org, workspace, repo, user,
|
|
898
|
+
* worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
|
|
899
|
+
* + index follow the same pattern as ensureSessionsTable.
|
|
900
|
+
*/
|
|
901
|
+
async ensureCodebaseTable(name) {
|
|
902
|
+
const safe = sqlIdent(name);
|
|
903
|
+
const tables = await this.listTables();
|
|
904
|
+
if (!tables.includes(safe)) {
|
|
905
|
+
log3(`table "${safe}" not found, creating`);
|
|
906
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
|
|
907
|
+
log3(`table "${safe}" created`);
|
|
908
|
+
if (!tables.includes(safe))
|
|
909
|
+
this._tablesCache = [...tables, safe];
|
|
910
|
+
}
|
|
911
|
+
await this.healSchema(safe, CODEBASE_COLUMNS);
|
|
912
|
+
await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
|
|
913
|
+
}
|
|
791
914
|
async ensureSkillsTable(name) {
|
|
792
915
|
const safe = sqlIdent(name);
|
|
793
916
|
const tables = await this.listTables();
|
|
@@ -801,6 +924,111 @@ var DeeplakeApi = class {
|
|
|
801
924
|
await this.healSchema(safe, SKILLS_COLUMNS);
|
|
802
925
|
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
803
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
|
+
}
|
|
804
1032
|
};
|
|
805
1033
|
|
|
806
1034
|
// dist/src/shell/grep-core.js
|
|
@@ -126,6 +126,23 @@ 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",
|
|
145
|
+
codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
|
|
129
146
|
memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join3(home, ".deeplake", "memory")
|
|
130
147
|
};
|
|
131
148
|
}
|
|
@@ -217,6 +234,65 @@ var SKILLS_COLUMNS = Object.freeze([
|
|
|
217
234
|
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
218
235
|
{ name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
219
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
|
+
]);
|
|
220
296
|
function validateSchema(label, cols) {
|
|
221
297
|
const seen = /* @__PURE__ */ new Set();
|
|
222
298
|
for (const col of cols) {
|
|
@@ -234,9 +310,38 @@ function validateSchema(label, cols) {
|
|
|
234
310
|
}
|
|
235
311
|
}
|
|
236
312
|
}
|
|
313
|
+
var CODEBASE_COLUMNS = Object.freeze([
|
|
314
|
+
// Identity key (matches the PK below)
|
|
315
|
+
{ name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
316
|
+
{ name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
317
|
+
{ name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
318
|
+
{ name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
319
|
+
{ name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
320
|
+
{ name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
321
|
+
// Observation metadata
|
|
322
|
+
{ name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
323
|
+
{ name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
324
|
+
{ name: "ts", sql: "TIMESTAMP" },
|
|
325
|
+
{ name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
326
|
+
// Snapshot payload
|
|
327
|
+
{ name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
328
|
+
{ name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
329
|
+
{ name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
330
|
+
{ name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
331
|
+
// Generator metadata (for drift diagnostics — what hivemind version produced this?)
|
|
332
|
+
{ name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
|
|
333
|
+
{ name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
334
|
+
{ name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
|
|
335
|
+
]);
|
|
237
336
|
validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
238
337
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
239
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);
|
|
344
|
+
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
240
345
|
function buildCreateTableSql(tableName, cols) {
|
|
241
346
|
const safe = sqlIdent(tableName);
|
|
242
347
|
const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
|
|
@@ -783,6 +888,24 @@ var DeeplakeApi = class {
|
|
|
783
888
|
* This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
|
|
784
889
|
* worker.
|
|
785
890
|
*/
|
|
891
|
+
/**
|
|
892
|
+
* Create the codebase table. One row per (org, workspace, repo, user,
|
|
893
|
+
* worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
|
|
894
|
+
* + index follow the same pattern as ensureSessionsTable.
|
|
895
|
+
*/
|
|
896
|
+
async ensureCodebaseTable(name) {
|
|
897
|
+
const safe = sqlIdent(name);
|
|
898
|
+
const tables = await this.listTables();
|
|
899
|
+
if (!tables.includes(safe)) {
|
|
900
|
+
log3(`table "${safe}" not found, creating`);
|
|
901
|
+
await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
|
|
902
|
+
log3(`table "${safe}" created`);
|
|
903
|
+
if (!tables.includes(safe))
|
|
904
|
+
this._tablesCache = [...tables, safe];
|
|
905
|
+
}
|
|
906
|
+
await this.healSchema(safe, CODEBASE_COLUMNS);
|
|
907
|
+
await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
|
|
908
|
+
}
|
|
786
909
|
async ensureSkillsTable(name) {
|
|
787
910
|
const safe = sqlIdent(name);
|
|
788
911
|
const tables = await this.listTables();
|
|
@@ -796,6 +919,111 @@ var DeeplakeApi = class {
|
|
|
796
919
|
await this.healSchema(safe, SKILLS_COLUMNS);
|
|
797
920
|
await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
|
|
798
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
|
+
}
|
|
799
1027
|
};
|
|
800
1028
|
|
|
801
1029
|
// dist/src/utils/stdin.js
|