@deeplake/hivemind 0.7.49 → 0.7.51
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 +68 -40
- package/bundle/cli.js +9743 -21944
- package/codex/bundle/capture.js +3 -74
- package/codex/bundle/commands/auth-login.js +3 -74
- package/codex/bundle/graph-pull-worker.js +3 -74
- package/codex/bundle/pre-tool-use.js +3 -74
- package/codex/bundle/session-start-setup.js +3 -74
- package/codex/bundle/session-start.js +3 -74
- package/codex/bundle/shell/deeplake-shell.js +3 -74
- package/codex/bundle/skillify-worker.js +0 -28
- package/codex/bundle/stop.js +3 -74
- package/codex/skills/hivemind-goals/SKILL.md +2 -2
- package/cursor/bundle/capture.js +3 -74
- package/cursor/bundle/commands/auth-login.js +3 -74
- package/cursor/bundle/graph-pull-worker.js +3 -74
- package/cursor/bundle/pre-tool-use.js +3 -74
- package/cursor/bundle/session-end.js +3 -6
- package/cursor/bundle/session-start.js +68 -338
- package/cursor/bundle/shell/deeplake-shell.js +3 -74
- package/cursor/bundle/skillify-worker.js +0 -28
- package/hermes/bundle/capture.js +3 -74
- package/hermes/bundle/commands/auth-login.js +3 -74
- package/hermes/bundle/graph-pull-worker.js +3 -74
- package/hermes/bundle/pre-tool-use.js +3 -74
- package/hermes/bundle/session-end.js +3 -6
- package/hermes/bundle/session-start.js +68 -338
- package/hermes/bundle/shell/deeplake-shell.js +3 -74
- package/hermes/bundle/skillify-worker.js +0 -28
- package/mcp/bundle/server.js +3 -74
- package/openclaw/dist/chunks/{config-FH6JYSJW.js → config-3D3X7JQH.js} +3 -6
- package/openclaw/dist/index.js +2 -68
- package/openclaw/dist/skillify-worker.js +0 -28
- package/openclaw/openclaw.plugin.json +1 -1
- package/openclaw/package.json +1 -1
- package/openclaw/skills/hivemind-goals/SKILL.md +1 -1
- package/package.json +1 -1
|
@@ -121,13 +121,10 @@ function loadConfig() {
|
|
|
121
121
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
122
122
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
123
123
|
// Defaults match the table name written into the SQL — keep aligned
|
|
124
|
-
// with RULES_COLUMNS
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
// CLAUDE.md.
|
|
124
|
+
// with RULES_COLUMNS in deeplake-schema.ts and with the e2e test-org
|
|
125
|
+
// override convention (memory_test / sessions_test → goals_test, etc.)
|
|
126
|
+
// documented in CLAUDE.md.
|
|
128
127
|
rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
|
|
129
|
-
tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
|
|
130
|
-
taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
|
|
131
128
|
// Goals + KPIs (refined design — VFS path classifier maps
|
|
132
129
|
// memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
|
|
133
130
|
// memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
|
|
@@ -163,6 +160,9 @@ function log(tag, msg) {
|
|
|
163
160
|
function sqlStr(value) {
|
|
164
161
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
165
162
|
}
|
|
163
|
+
function sqlLike(value) {
|
|
164
|
+
return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
165
|
+
}
|
|
166
166
|
function sqlIdent(name) {
|
|
167
167
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
168
168
|
throw new Error(`Invalid SQL identifier: ${JSON.stringify(name)}`);
|
|
@@ -237,32 +237,6 @@ var RULES_COLUMNS = Object.freeze([
|
|
|
237
237
|
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
238
238
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
239
239
|
]);
|
|
240
|
-
var TASKS_COLUMNS = Object.freeze([
|
|
241
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
242
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
243
|
-
{ name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
244
|
-
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
245
|
-
{ name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
|
|
246
|
-
{ name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
247
|
-
{ name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
248
|
-
{ name: "kpis", sql: "JSONB" },
|
|
249
|
-
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
250
|
-
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
251
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
252
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
253
|
-
]);
|
|
254
|
-
var TASK_EVENTS_COLUMNS = Object.freeze([
|
|
255
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
256
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
257
|
-
{ name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
258
|
-
{ name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
259
|
-
{ name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
260
|
-
{ name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
261
|
-
{ name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
|
|
262
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
263
|
-
{ name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
264
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
265
|
-
]);
|
|
266
240
|
var GOALS_COLUMNS = Object.freeze([
|
|
267
241
|
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
268
242
|
{ name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
@@ -328,8 +302,6 @@ validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
|
328
302
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
329
303
|
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
330
304
|
validateSchema("RULES_COLUMNS", RULES_COLUMNS);
|
|
331
|
-
validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
|
|
332
|
-
validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
|
|
333
305
|
validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
|
|
334
306
|
validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
|
|
335
307
|
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
@@ -931,46 +903,6 @@ var DeeplakeApi = class {
|
|
|
931
903
|
await this.healSchema(safe, RULES_COLUMNS);
|
|
932
904
|
await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
|
|
933
905
|
}
|
|
934
|
-
/**
|
|
935
|
-
* Create the tasks table.
|
|
936
|
-
*
|
|
937
|
-
* Same write pattern as rules + skills. `kpis` is a nullable JSONB
|
|
938
|
-
* column with the agent's KPI metadata; KPI current values come from
|
|
939
|
-
* `task_events` (SUM(value)), not this snapshot.
|
|
940
|
-
*/
|
|
941
|
-
async ensureTasksTable(name) {
|
|
942
|
-
const safe = sqlIdent(name);
|
|
943
|
-
const tables = await this.listTables();
|
|
944
|
-
if (!tables.includes(safe)) {
|
|
945
|
-
log3(`table "${safe}" not found, creating`);
|
|
946
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
|
|
947
|
-
log3(`table "${safe}" created`);
|
|
948
|
-
if (!tables.includes(safe))
|
|
949
|
-
this._tablesCache = [...tables, safe];
|
|
950
|
-
}
|
|
951
|
-
await this.healSchema(safe, TASKS_COLUMNS);
|
|
952
|
-
await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
|
|
953
|
-
}
|
|
954
|
-
/**
|
|
955
|
-
* Create the task-events table.
|
|
956
|
-
*
|
|
957
|
-
* Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
|
|
958
|
-
* value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
|
|
959
|
-
* (task_id, kpi_id) is the canonical aggregation key.
|
|
960
|
-
*/
|
|
961
|
-
async ensureTaskEventsTable(name) {
|
|
962
|
-
const safe = sqlIdent(name);
|
|
963
|
-
const tables = await this.listTables();
|
|
964
|
-
if (!tables.includes(safe)) {
|
|
965
|
-
log3(`table "${safe}" not found, creating`);
|
|
966
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
|
|
967
|
-
log3(`table "${safe}" created`);
|
|
968
|
-
if (!tables.includes(safe))
|
|
969
|
-
this._tablesCache = [...tables, safe];
|
|
970
|
-
}
|
|
971
|
-
await this.healSchema(safe, TASK_EVENTS_COLUMNS);
|
|
972
|
-
await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
|
|
973
|
-
}
|
|
974
906
|
/**
|
|
975
907
|
* Create the goals table.
|
|
976
908
|
*
|
|
@@ -1057,187 +989,10 @@ function normalize(row) {
|
|
|
1057
989
|
};
|
|
1058
990
|
}
|
|
1059
991
|
|
|
1060
|
-
// dist/src/tasks/write.js
|
|
1061
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
1062
|
-
|
|
1063
|
-
// dist/src/tasks/kpi-validator.js
|
|
1064
|
-
function parseKpis(raw) {
|
|
1065
|
-
if (raw == null || raw === "")
|
|
1066
|
-
return [];
|
|
1067
|
-
let arr;
|
|
1068
|
-
if (typeof raw === "string") {
|
|
1069
|
-
try {
|
|
1070
|
-
arr = JSON.parse(raw);
|
|
1071
|
-
} catch {
|
|
1072
|
-
return [];
|
|
1073
|
-
}
|
|
1074
|
-
} else {
|
|
1075
|
-
arr = raw;
|
|
1076
|
-
}
|
|
1077
|
-
if (!Array.isArray(arr))
|
|
1078
|
-
return [];
|
|
1079
|
-
const out = [];
|
|
1080
|
-
for (const item of arr) {
|
|
1081
|
-
const kpi = validateOne(item);
|
|
1082
|
-
if (kpi)
|
|
1083
|
-
out.push(kpi);
|
|
1084
|
-
}
|
|
1085
|
-
return out;
|
|
1086
|
-
}
|
|
1087
|
-
function validateOne(item) {
|
|
1088
|
-
if (!isObject(item))
|
|
1089
|
-
return null;
|
|
1090
|
-
const kpi_id = safeStr(item.kpi_id);
|
|
1091
|
-
const name = safeStr(item.name);
|
|
1092
|
-
const target = num(item.target);
|
|
1093
|
-
const unit = safeStr(item.unit);
|
|
1094
|
-
const generated_by = safeStr(item.generated_by);
|
|
1095
|
-
const generated_at = isoStr(item.generated_at);
|
|
1096
|
-
if (kpi_id === null || name === null || target === null || unit === null || generated_by === null || generated_at === null) {
|
|
1097
|
-
return null;
|
|
1098
|
-
}
|
|
1099
|
-
if (!Number.isInteger(target) || target <= 0) {
|
|
1100
|
-
return null;
|
|
1101
|
-
}
|
|
1102
|
-
const out = {
|
|
1103
|
-
kpi_id,
|
|
1104
|
-
name,
|
|
1105
|
-
target,
|
|
1106
|
-
unit,
|
|
1107
|
-
generated_by,
|
|
1108
|
-
generated_at
|
|
1109
|
-
};
|
|
1110
|
-
const current = num(item.current);
|
|
1111
|
-
if (current !== null)
|
|
1112
|
-
out.current = current;
|
|
1113
|
-
return out;
|
|
1114
|
-
}
|
|
1115
|
-
function isObject(v) {
|
|
1116
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1117
|
-
}
|
|
1118
|
-
function str(v) {
|
|
1119
|
-
if (typeof v !== "string" || v.length === 0)
|
|
1120
|
-
return null;
|
|
1121
|
-
return v;
|
|
1122
|
-
}
|
|
1123
|
-
function safeStr(v) {
|
|
1124
|
-
const s = str(v);
|
|
1125
|
-
if (s === null)
|
|
1126
|
-
return null;
|
|
1127
|
-
if (/[\r\n\u2028\u2029\u0085]/.test(s))
|
|
1128
|
-
return null;
|
|
1129
|
-
return s;
|
|
1130
|
-
}
|
|
1131
|
-
function num(v) {
|
|
1132
|
-
if (typeof v !== "number" || !Number.isFinite(v))
|
|
1133
|
-
return null;
|
|
1134
|
-
return v;
|
|
1135
|
-
}
|
|
1136
|
-
function isoStr(v) {
|
|
1137
|
-
const s = safeStr(v);
|
|
1138
|
-
if (s === null)
|
|
1139
|
-
return null;
|
|
1140
|
-
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?$/.test(s)) {
|
|
1141
|
-
return null;
|
|
1142
|
-
}
|
|
1143
|
-
return s;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
// dist/src/tasks/read.js
|
|
1147
|
-
var SELECT_COLS2 = "id, task_id, text, scope, status, assigned_to, assigned_by, kpis, version, created_at, agent, plugin_version";
|
|
1148
|
-
async function listTasks(query, tableName, opts = {}) {
|
|
1149
|
-
const safe = sqlIdent(tableName);
|
|
1150
|
-
const rows = await query(`SELECT ${SELECT_COLS2} FROM "${safe}" ORDER BY version DESC, created_at DESC, id DESC`);
|
|
1151
|
-
const latest = /* @__PURE__ */ new Map();
|
|
1152
|
-
for (const r of rows) {
|
|
1153
|
-
const row = normalize2(r);
|
|
1154
|
-
if (!row)
|
|
1155
|
-
continue;
|
|
1156
|
-
if (!latest.has(row.task_id))
|
|
1157
|
-
latest.set(row.task_id, row);
|
|
1158
|
-
}
|
|
1159
|
-
const scope = opts.scope ?? "all";
|
|
1160
|
-
const status = opts.status ?? "active";
|
|
1161
|
-
const current = opts.current_user;
|
|
1162
|
-
const filtered = [...latest.values()].filter((row) => {
|
|
1163
|
-
if (status !== "all" && row.status !== status)
|
|
1164
|
-
return false;
|
|
1165
|
-
if (scope === "mine") {
|
|
1166
|
-
if (!current)
|
|
1167
|
-
return false;
|
|
1168
|
-
return row.assigned_to === current;
|
|
1169
|
-
}
|
|
1170
|
-
if (scope === "me") {
|
|
1171
|
-
if (!current)
|
|
1172
|
-
return false;
|
|
1173
|
-
return row.scope === "me" && row.assigned_to === current;
|
|
1174
|
-
}
|
|
1175
|
-
if (scope === "team")
|
|
1176
|
-
return row.scope === "team";
|
|
1177
|
-
return true;
|
|
1178
|
-
});
|
|
1179
|
-
filtered.sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id.localeCompare(a.id));
|
|
1180
|
-
return filtered.slice(0, opts.limit ?? 10);
|
|
1181
|
-
}
|
|
1182
|
-
function normalize2(row) {
|
|
1183
|
-
const vRaw = row.version;
|
|
1184
|
-
const version = typeof vRaw === "number" ? vRaw : typeof vRaw === "string" ? Number(vRaw) : NaN;
|
|
1185
|
-
if (!Number.isFinite(version))
|
|
1186
|
-
return null;
|
|
1187
|
-
return {
|
|
1188
|
-
id: String(row.id ?? ""),
|
|
1189
|
-
task_id: String(row.task_id ?? ""),
|
|
1190
|
-
text: String(row.text ?? ""),
|
|
1191
|
-
scope: String(row.scope ?? ""),
|
|
1192
|
-
status: String(row.status ?? ""),
|
|
1193
|
-
assigned_to: String(row.assigned_to ?? ""),
|
|
1194
|
-
assigned_by: String(row.assigned_by ?? ""),
|
|
1195
|
-
kpis: parseKpis(row.kpis),
|
|
1196
|
-
version,
|
|
1197
|
-
created_at: String(row.created_at ?? ""),
|
|
1198
|
-
agent: String(row.agent ?? ""),
|
|
1199
|
-
plugin_version: String(row.plugin_version ?? "")
|
|
1200
|
-
};
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
// dist/src/events/append.js
|
|
1204
|
-
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
1205
|
-
|
|
1206
|
-
// dist/src/events/aggregate.js
|
|
1207
|
-
async function computeAllForTasks(query, tableName, taskIds) {
|
|
1208
|
-
if (taskIds.length === 0)
|
|
1209
|
-
return {};
|
|
1210
|
-
const safe = sqlIdent(tableName);
|
|
1211
|
-
const inList = taskIds.map((id) => `'${sqlStr(id)}'`).join(", ");
|
|
1212
|
-
const rows = await query(`SELECT task_id, kpi_id, SUM(value) AS total FROM "${safe}" WHERE task_id IN (${inList}) GROUP BY task_id, kpi_id`);
|
|
1213
|
-
const out = {};
|
|
1214
|
-
for (const row of rows) {
|
|
1215
|
-
const tid = typeof row.task_id === "string" ? row.task_id : "";
|
|
1216
|
-
const kid = typeof row.kpi_id === "string" ? row.kpi_id : "";
|
|
1217
|
-
if (!tid || !kid)
|
|
1218
|
-
continue;
|
|
1219
|
-
if (!out[tid])
|
|
1220
|
-
out[tid] = {};
|
|
1221
|
-
out[tid][kid] = normalizeTotal(row.total);
|
|
1222
|
-
}
|
|
1223
|
-
return out;
|
|
1224
|
-
}
|
|
1225
|
-
function normalizeTotal(raw) {
|
|
1226
|
-
if (raw == null)
|
|
1227
|
-
return 0;
|
|
1228
|
-
if (typeof raw === "number")
|
|
1229
|
-
return Number.isFinite(raw) ? raw : 0;
|
|
1230
|
-
if (typeof raw === "string") {
|
|
1231
|
-
const n = Number(raw);
|
|
1232
|
-
return Number.isFinite(n) ? n : 0;
|
|
1233
|
-
}
|
|
1234
|
-
return 0;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
992
|
// dist/src/hooks/shared/context-renderer.js
|
|
1238
993
|
async function renderContextBlock(query, input, opts = {}) {
|
|
1239
994
|
const maxRules = opts.maxRules ?? 10;
|
|
1240
|
-
const
|
|
995
|
+
const maxGoals = opts.maxGoals ?? 10;
|
|
1241
996
|
const log7 = opts.log ?? (() => {
|
|
1242
997
|
});
|
|
1243
998
|
try {
|
|
@@ -1251,79 +1006,54 @@ async function renderContextBlock(query, input, opts = {}) {
|
|
|
1251
1006
|
const rmsg = rulesErr instanceof Error ? rulesErr.message : String(rulesErr);
|
|
1252
1007
|
log7(`render-context-block: rules unavailable (continuing): ${rmsg}`);
|
|
1253
1008
|
}
|
|
1254
|
-
let
|
|
1255
|
-
let myTasks = [];
|
|
1009
|
+
let goals = [];
|
|
1256
1010
|
try {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
status: "active",
|
|
1260
|
-
limit: Math.max(maxTasks * 4, maxTasks + 1)
|
|
1261
|
-
});
|
|
1262
|
-
myTasks = await listTasks(query, input.tasksTable, {
|
|
1263
|
-
scope: "me",
|
|
1264
|
-
status: "active",
|
|
1265
|
-
current_user: input.currentUser,
|
|
1266
|
-
limit: Math.max(maxTasks * 4, maxTasks + 1)
|
|
1011
|
+
goals = await listOpenGoals(query, input.goalsTable, input.currentUser, {
|
|
1012
|
+
limit: Math.max(maxGoals * 4, maxGoals + 1)
|
|
1267
1013
|
});
|
|
1268
|
-
} catch (
|
|
1269
|
-
const
|
|
1270
|
-
log7(`render-context-block:
|
|
1014
|
+
} catch (goalsErr) {
|
|
1015
|
+
const gmsg = goalsErr instanceof Error ? goalsErr.message : String(goalsErr);
|
|
1016
|
+
log7(`render-context-block: goals unavailable (continuing): ${gmsg}`);
|
|
1271
1017
|
}
|
|
1272
|
-
const visibleTasks = mergeAndDedupTasks(teamTasks, myTasks);
|
|
1273
1018
|
const rulesShown = rules.slice(0, maxRules);
|
|
1274
1019
|
const rulesHidden = Math.max(0, rules.length - maxRules);
|
|
1275
|
-
const
|
|
1276
|
-
const
|
|
1277
|
-
|
|
1278
|
-
let totals = {};
|
|
1279
|
-
try {
|
|
1280
|
-
totals = await computeAllForTasks(query, input.taskEventsTable, taskIds);
|
|
1281
|
-
} catch (aggErr) {
|
|
1282
|
-
const aggMsg = aggErr instanceof Error ? aggErr.message : String(aggErr);
|
|
1283
|
-
log7(`render-context-block: aggregate failed (continuing with 0/target): ${aggMsg}`);
|
|
1284
|
-
}
|
|
1285
|
-
return formatBlock({
|
|
1286
|
-
rules: rulesShown,
|
|
1287
|
-
rulesHidden,
|
|
1288
|
-
tasks: tasksShown,
|
|
1289
|
-
tasksHidden,
|
|
1290
|
-
totals,
|
|
1291
|
-
currentUser: input.currentUser
|
|
1292
|
-
});
|
|
1020
|
+
const goalsShown = goals.slice(0, maxGoals);
|
|
1021
|
+
const goalsHidden = Math.max(0, goals.length - maxGoals);
|
|
1022
|
+
return formatBlock({ rules: rulesShown, rulesHidden, goals: goalsShown, goalsHidden });
|
|
1293
1023
|
} catch (e) {
|
|
1294
1024
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1295
1025
|
log7(`render-context-block: ${msg}`);
|
|
1296
1026
|
return "";
|
|
1297
1027
|
}
|
|
1298
1028
|
}
|
|
1299
|
-
function
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1029
|
+
async function listOpenGoals(query, goalsTable, currentUser, opts = {}) {
|
|
1030
|
+
const limit = opts.limit ?? 40;
|
|
1031
|
+
const safe = sqlIdent(goalsTable);
|
|
1032
|
+
const fullUser = currentUser.trim();
|
|
1033
|
+
const shortUser = fullUser.split("@")[0] ?? fullUser;
|
|
1034
|
+
const fullEq = sqlStr(fullUser);
|
|
1035
|
+
const shortEq = sqlStr(shortUser);
|
|
1036
|
+
const shortLike = sqlLike(shortUser);
|
|
1037
|
+
const sql = `SELECT goal_id, owner, status, content FROM "${safe}" g1 WHERE (owner = '${fullEq}' OR owner = '${shortEq}' OR owner LIKE '${shortLike}@%') AND status IN ('opened', 'in_progress') AND version = (SELECT MAX(version) FROM "${safe}" g2 WHERE g2.goal_id = g1.goal_id) ORDER BY status ASC, created_at DESC LIMIT ${limit}`;
|
|
1038
|
+
const rows = await query(sql);
|
|
1039
|
+
const out = [];
|
|
1040
|
+
for (const r of rows) {
|
|
1041
|
+
const ownerNorm = String(r["owner"] ?? "").trim();
|
|
1042
|
+
const ownerShort = ownerNorm.split("@")[0] ?? ownerNorm;
|
|
1043
|
+
if (ownerNorm !== fullUser && ownerNorm !== shortUser && ownerShort !== shortUser) {
|
|
1305
1044
|
continue;
|
|
1306
1045
|
}
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
}
|
|
1046
|
+
out.push({
|
|
1047
|
+
goal_id: String(r["goal_id"] ?? ""),
|
|
1048
|
+
status: String(r["status"] ?? ""),
|
|
1049
|
+
content: String(r["content"] ?? "")
|
|
1050
|
+
});
|
|
1312
1051
|
}
|
|
1313
|
-
|
|
1314
|
-
merged.sort((a, b) => {
|
|
1315
|
-
const aMe = a.scope === "me" ? 0 : 1;
|
|
1316
|
-
const bMe = b.scope === "me" ? 0 : 1;
|
|
1317
|
-
if (aMe !== bMe)
|
|
1318
|
-
return aMe - bMe;
|
|
1319
|
-
return b.created_at.localeCompare(a.created_at);
|
|
1320
|
-
});
|
|
1321
|
-
return merged;
|
|
1052
|
+
return out;
|
|
1322
1053
|
}
|
|
1323
1054
|
function formatBlock(input) {
|
|
1324
|
-
if (input.rules.length === 0 && input.
|
|
1055
|
+
if (input.rules.length === 0 && input.goals.length === 0)
|
|
1325
1056
|
return "";
|
|
1326
|
-
}
|
|
1327
1057
|
const lines = [];
|
|
1328
1058
|
if (input.rules.length > 0) {
|
|
1329
1059
|
lines.push(`=== HIVEMIND RULES (${input.rules.length} active) ===`);
|
|
@@ -1335,41 +1065,42 @@ function formatBlock(input) {
|
|
|
1335
1065
|
}
|
|
1336
1066
|
lines.push("");
|
|
1337
1067
|
}
|
|
1338
|
-
if (input.
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1068
|
+
if (input.goals.length > 0) {
|
|
1069
|
+
const inProgress = input.goals.filter((g) => g.status === "in_progress").length;
|
|
1070
|
+
const opened = input.goals.filter((g) => g.status === "opened").length;
|
|
1071
|
+
lines.push(`=== HIVEMIND GOALS (${inProgress} in_progress, ${opened} opened) ===`);
|
|
1072
|
+
for (const g of input.goals) {
|
|
1073
|
+
const firstLine = sanitizeForInject(firstNonEmptyLine(g.content));
|
|
1074
|
+
const tag = g.status === "in_progress" ? "[in_progress]" : "[opened] ";
|
|
1075
|
+
lines.push(`${tag} ${g.goal_id}: ${firstLine}`);
|
|
1342
1076
|
}
|
|
1343
|
-
if (input.
|
|
1344
|
-
lines.push(`(${input.
|
|
1077
|
+
if (input.goalsHidden > 0) {
|
|
1078
|
+
lines.push(`(${input.goalsHidden} more \u2014 run 'hivemind goal list --mine' to see all)`);
|
|
1345
1079
|
}
|
|
1346
1080
|
lines.push("");
|
|
1347
1081
|
}
|
|
1348
1082
|
lines.push("=== HIVEMIND HOW-TO ===");
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1083
|
+
if (input.rules.length > 0) {
|
|
1084
|
+
lines.push("- Rules above are team principles. Treat any action that would violate one as a critical error and surface it to the user before proceeding.");
|
|
1085
|
+
}
|
|
1086
|
+
if (input.goals.length > 0) {
|
|
1087
|
+
lines.push("- Goals above are your current open work items. Move a goal forward by `mv`-ing its file between memory/goal/<user>/{opened,in_progress,closed}/ (claude-code/codex) or `hivemind goal progress <goal_id> <status>` (cursor/hermes/pi).");
|
|
1088
|
+
}
|
|
1089
|
+
lines.push("- Run 'hivemind rules list' / 'hivemind goal list --mine' for the full inventories beyond what's shown here.");
|
|
1352
1090
|
return lines.join("\n");
|
|
1353
1091
|
}
|
|
1354
|
-
function
|
|
1355
|
-
const
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1092
|
+
function firstNonEmptyLine(content) {
|
|
1093
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
1094
|
+
const trimmed = raw.trim();
|
|
1095
|
+
if (trimmed.length > 0)
|
|
1096
|
+
return trimmed;
|
|
1097
|
+
}
|
|
1098
|
+
return "(empty)";
|
|
1359
1099
|
}
|
|
1360
1100
|
function sanitizeForInject(text) {
|
|
1361
1101
|
return text.replace(LINE_TERMINATOR_RE, "\\n");
|
|
1362
1102
|
}
|
|
1363
1103
|
var LINE_TERMINATOR_RE = /\r\n?|[\n\u2028\u2029\u0085]/g;
|
|
1364
|
-
function formatKpiSummary(kpis, totals) {
|
|
1365
|
-
if (kpis.length === 0)
|
|
1366
|
-
return "";
|
|
1367
|
-
const parts = kpis.map((k) => {
|
|
1368
|
-
const current = totals[k.kpi_id] ?? 0;
|
|
1369
|
-
return `${sanitizeForInject(k.name)}: ${current}/${k.target} ${sanitizeForInject(k.unit)}`;
|
|
1370
|
-
});
|
|
1371
|
-
return ` | ${parts.join(", ")}`;
|
|
1372
|
-
}
|
|
1373
1104
|
|
|
1374
1105
|
// dist/src/cli/skillify-spec.js
|
|
1375
1106
|
var SKILLIFY_COMMANDS = [
|
|
@@ -2331,7 +2062,7 @@ Commands (invoke via your Shell / terminal / Bash tool):
|
|
|
2331
2062
|
hivemind kpi bump <goal_id> <kpi_id> <delta>
|
|
2332
2063
|
Increment (positive int) or decrement (negative) the current value of one KPI.
|
|
2333
2064
|
|
|
2334
|
-
Workflow when the user expresses a goal:
|
|
2065
|
+
Workflow when the user expresses a goal OR a task / todo / work item (they are the same thing \u2014 the goals system absorbed the legacy hivemind tasks CLI):
|
|
2335
2066
|
1. \`hivemind goal add "<short description>"\` \u2014 capture stdout as goal_id.
|
|
2336
2067
|
2. ONLY if the user explicitly asks for KPIs: \`hivemind kpi add <goal_id> <slug> <target> <unit>\` per KPI.
|
|
2337
2068
|
3. Tell the user the goal_id and that it is now visible to the team.
|
|
@@ -2423,7 +2154,7 @@ async function main() {
|
|
|
2423
2154
|
await autoUpdate(creds, { agent: "hermes" });
|
|
2424
2155
|
const current = getInstalledVersion(__bundleDir, ".claude-plugin");
|
|
2425
2156
|
const pluginVersion = current ?? "";
|
|
2426
|
-
let
|
|
2157
|
+
let rulesBlock = "";
|
|
2427
2158
|
if (creds?.token) {
|
|
2428
2159
|
try {
|
|
2429
2160
|
const config = loadConfig();
|
|
@@ -2437,10 +2168,9 @@ async function main() {
|
|
|
2437
2168
|
} else {
|
|
2438
2169
|
log6("placeholder + schema ensure skipped (HIVEMIND_CAPTURE=false)");
|
|
2439
2170
|
}
|
|
2440
|
-
|
|
2171
|
+
rulesBlock = await renderContextBlock((sql) => api.query(sql), {
|
|
2441
2172
|
rulesTable: config.rulesTableName,
|
|
2442
|
-
|
|
2443
|
-
taskEventsTable: config.taskEventsTableName,
|
|
2173
|
+
goalsTable: config.goalsTableName,
|
|
2444
2174
|
currentUser: config.userName
|
|
2445
2175
|
}, { log: log6 });
|
|
2446
2176
|
}
|
|
@@ -2465,9 +2195,9 @@ Not logged in to Deeplake. Run: hivemind login${localMinedNote}${versionNotice}`
|
|
|
2465
2195
|
const baseWithGoals = creds?.token ? `${baseContext}
|
|
2466
2196
|
|
|
2467
2197
|
${GOALS_INSTRUCTIONS_CLI}` : baseContext;
|
|
2468
|
-
const additional =
|
|
2198
|
+
const additional = rulesBlock ? `${baseWithGoals}
|
|
2469
2199
|
|
|
2470
|
-
${
|
|
2200
|
+
${rulesBlock}` : baseWithGoals;
|
|
2471
2201
|
console.log(JSON.stringify({ context: additional }));
|
|
2472
2202
|
}
|
|
2473
2203
|
main().catch((e) => {
|
|
@@ -66793,13 +66793,10 @@ function loadConfig() {
|
|
|
66793
66793
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
66794
66794
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
66795
66795
|
// Defaults match the table name written into the SQL — keep aligned
|
|
66796
|
-
// with RULES_COLUMNS
|
|
66797
|
-
//
|
|
66798
|
-
//
|
|
66799
|
-
// CLAUDE.md.
|
|
66796
|
+
// with RULES_COLUMNS in deeplake-schema.ts and with the e2e test-org
|
|
66797
|
+
// override convention (memory_test / sessions_test → goals_test, etc.)
|
|
66798
|
+
// documented in CLAUDE.md.
|
|
66800
66799
|
rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
|
|
66801
|
-
tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
|
|
66802
|
-
taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
|
|
66803
66800
|
// Goals + KPIs (refined design — VFS path classifier maps
|
|
66804
66801
|
// memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
|
|
66805
66802
|
// memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
|
|
@@ -66921,32 +66918,6 @@ var RULES_COLUMNS = Object.freeze([
|
|
|
66921
66918
|
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
66922
66919
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66923
66920
|
]);
|
|
66924
|
-
var TASKS_COLUMNS = Object.freeze([
|
|
66925
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66926
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66927
|
-
{ name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66928
|
-
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
66929
|
-
{ name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
|
|
66930
|
-
{ name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66931
|
-
{ name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66932
|
-
{ name: "kpis", sql: "JSONB" },
|
|
66933
|
-
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
66934
|
-
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66935
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
66936
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66937
|
-
]);
|
|
66938
|
-
var TASK_EVENTS_COLUMNS = Object.freeze([
|
|
66939
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66940
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66941
|
-
{ name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
66942
|
-
{ name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66943
|
-
{ name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
66944
|
-
{ name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66945
|
-
{ name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
|
|
66946
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66947
|
-
{ name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66948
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
66949
|
-
]);
|
|
66950
66921
|
var GOALS_COLUMNS = Object.freeze([
|
|
66951
66922
|
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
66952
66923
|
{ name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
@@ -67012,8 +66983,6 @@ validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
|
67012
66983
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
67013
66984
|
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
67014
66985
|
validateSchema("RULES_COLUMNS", RULES_COLUMNS);
|
|
67015
|
-
validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
|
|
67016
|
-
validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
|
|
67017
66986
|
validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
|
|
67018
66987
|
validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
|
|
67019
66988
|
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
@@ -67633,46 +67602,6 @@ var DeeplakeApi = class {
|
|
|
67633
67602
|
await this.healSchema(safe, RULES_COLUMNS);
|
|
67634
67603
|
await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
|
|
67635
67604
|
}
|
|
67636
|
-
/**
|
|
67637
|
-
* Create the tasks table.
|
|
67638
|
-
*
|
|
67639
|
-
* Same write pattern as rules + skills. `kpis` is a nullable JSONB
|
|
67640
|
-
* column with the agent's KPI metadata; KPI current values come from
|
|
67641
|
-
* `task_events` (SUM(value)), not this snapshot.
|
|
67642
|
-
*/
|
|
67643
|
-
async ensureTasksTable(name) {
|
|
67644
|
-
const safe = sqlIdent(name);
|
|
67645
|
-
const tables = await this.listTables();
|
|
67646
|
-
if (!tables.includes(safe)) {
|
|
67647
|
-
log3(`table "${safe}" not found, creating`);
|
|
67648
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
|
|
67649
|
-
log3(`table "${safe}" created`);
|
|
67650
|
-
if (!tables.includes(safe))
|
|
67651
|
-
this._tablesCache = [...tables, safe];
|
|
67652
|
-
}
|
|
67653
|
-
await this.healSchema(safe, TASKS_COLUMNS);
|
|
67654
|
-
await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
|
|
67655
|
-
}
|
|
67656
|
-
/**
|
|
67657
|
-
* Create the task-events table.
|
|
67658
|
-
*
|
|
67659
|
-
* Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
|
|
67660
|
-
* value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
|
|
67661
|
-
* (task_id, kpi_id) is the canonical aggregation key.
|
|
67662
|
-
*/
|
|
67663
|
-
async ensureTaskEventsTable(name) {
|
|
67664
|
-
const safe = sqlIdent(name);
|
|
67665
|
-
const tables = await this.listTables();
|
|
67666
|
-
if (!tables.includes(safe)) {
|
|
67667
|
-
log3(`table "${safe}" not found, creating`);
|
|
67668
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
|
|
67669
|
-
log3(`table "${safe}" created`);
|
|
67670
|
-
if (!tables.includes(safe))
|
|
67671
|
-
this._tablesCache = [...tables, safe];
|
|
67672
|
-
}
|
|
67673
|
-
await this.healSchema(safe, TASK_EVENTS_COLUMNS);
|
|
67674
|
-
await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
|
|
67675
|
-
}
|
|
67676
67605
|
/**
|
|
67677
67606
|
* Create the goals table.
|
|
67678
67607
|
*
|
|
@@ -390,32 +390,6 @@ var RULES_COLUMNS = Object.freeze([
|
|
|
390
390
|
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
391
391
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
392
392
|
]);
|
|
393
|
-
var TASKS_COLUMNS = Object.freeze([
|
|
394
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
395
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
396
|
-
{ name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
397
|
-
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
398
|
-
{ name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
|
|
399
|
-
{ name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
400
|
-
{ name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
401
|
-
{ name: "kpis", sql: "JSONB" },
|
|
402
|
-
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
403
|
-
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
404
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
405
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
406
|
-
]);
|
|
407
|
-
var TASK_EVENTS_COLUMNS = Object.freeze([
|
|
408
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
409
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
410
|
-
{ name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
411
|
-
{ name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
412
|
-
{ name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
413
|
-
{ name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
414
|
-
{ name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
|
|
415
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
416
|
-
{ name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
417
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
418
|
-
]);
|
|
419
393
|
var GOALS_COLUMNS = Object.freeze([
|
|
420
394
|
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
421
395
|
{ name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
@@ -481,8 +455,6 @@ validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
|
481
455
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
482
456
|
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
483
457
|
validateSchema("RULES_COLUMNS", RULES_COLUMNS);
|
|
484
|
-
validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
|
|
485
|
-
validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
|
|
486
458
|
validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
|
|
487
459
|
validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
|
|
488
460
|
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|