@deeplake/hivemind 0.7.50 → 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 +17 -35
- 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
|
@@ -98,13 +98,10 @@ function loadConfig() {
|
|
|
98
98
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
99
99
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
100
100
|
// Defaults match the table name written into the SQL — keep aligned
|
|
101
|
-
// with RULES_COLUMNS
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
// CLAUDE.md.
|
|
101
|
+
// with RULES_COLUMNS in deeplake-schema.ts and with the e2e test-org
|
|
102
|
+
// override convention (memory_test / sessions_test → goals_test, etc.)
|
|
103
|
+
// documented in CLAUDE.md.
|
|
105
104
|
rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
|
|
106
|
-
tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
|
|
107
|
-
taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
|
|
108
105
|
// Goals + KPIs (refined design — VFS path classifier maps
|
|
109
106
|
// memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
|
|
110
107
|
// memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
|
|
@@ -226,32 +223,6 @@ var RULES_COLUMNS = Object.freeze([
|
|
|
226
223
|
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
227
224
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
228
225
|
]);
|
|
229
|
-
var TASKS_COLUMNS = Object.freeze([
|
|
230
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
231
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
232
|
-
{ name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
233
|
-
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
234
|
-
{ name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
|
|
235
|
-
{ name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
236
|
-
{ name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
237
|
-
{ name: "kpis", sql: "JSONB" },
|
|
238
|
-
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
239
|
-
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
240
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
241
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
242
|
-
]);
|
|
243
|
-
var TASK_EVENTS_COLUMNS = Object.freeze([
|
|
244
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
245
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
246
|
-
{ name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
247
|
-
{ name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
248
|
-
{ name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
249
|
-
{ name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
250
|
-
{ name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
|
|
251
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
252
|
-
{ name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
253
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
254
|
-
]);
|
|
255
226
|
var GOALS_COLUMNS = Object.freeze([
|
|
256
227
|
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
257
228
|
{ name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
@@ -317,8 +288,6 @@ validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
|
317
288
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
318
289
|
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
319
290
|
validateSchema("RULES_COLUMNS", RULES_COLUMNS);
|
|
320
|
-
validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
|
|
321
|
-
validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
|
|
322
291
|
validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
|
|
323
292
|
validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
|
|
324
293
|
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
@@ -938,46 +907,6 @@ var DeeplakeApi = class {
|
|
|
938
907
|
await this.healSchema(safe, RULES_COLUMNS);
|
|
939
908
|
await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
|
|
940
909
|
}
|
|
941
|
-
/**
|
|
942
|
-
* Create the tasks table.
|
|
943
|
-
*
|
|
944
|
-
* Same write pattern as rules + skills. `kpis` is a nullable JSONB
|
|
945
|
-
* column with the agent's KPI metadata; KPI current values come from
|
|
946
|
-
* `task_events` (SUM(value)), not this snapshot.
|
|
947
|
-
*/
|
|
948
|
-
async ensureTasksTable(name) {
|
|
949
|
-
const safe = sqlIdent(name);
|
|
950
|
-
const tables = await this.listTables();
|
|
951
|
-
if (!tables.includes(safe)) {
|
|
952
|
-
log3(`table "${safe}" not found, creating`);
|
|
953
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
|
|
954
|
-
log3(`table "${safe}" created`);
|
|
955
|
-
if (!tables.includes(safe))
|
|
956
|
-
this._tablesCache = [...tables, safe];
|
|
957
|
-
}
|
|
958
|
-
await this.healSchema(safe, TASKS_COLUMNS);
|
|
959
|
-
await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
|
|
960
|
-
}
|
|
961
|
-
/**
|
|
962
|
-
* Create the task-events table.
|
|
963
|
-
*
|
|
964
|
-
* Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
|
|
965
|
-
* value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
|
|
966
|
-
* (task_id, kpi_id) is the canonical aggregation key.
|
|
967
|
-
*/
|
|
968
|
-
async ensureTaskEventsTable(name) {
|
|
969
|
-
const safe = sqlIdent(name);
|
|
970
|
-
const tables = await this.listTables();
|
|
971
|
-
if (!tables.includes(safe)) {
|
|
972
|
-
log3(`table "${safe}" not found, creating`);
|
|
973
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
|
|
974
|
-
log3(`table "${safe}" created`);
|
|
975
|
-
if (!tables.includes(safe))
|
|
976
|
-
this._tablesCache = [...tables, safe];
|
|
977
|
-
}
|
|
978
|
-
await this.healSchema(safe, TASK_EVENTS_COLUMNS);
|
|
979
|
-
await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
|
|
980
|
-
}
|
|
981
910
|
/**
|
|
982
911
|
* Create the goals table.
|
|
983
912
|
*
|
|
@@ -65,13 +65,10 @@ function loadConfig() {
|
|
|
65
65
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
66
66
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
67
67
|
// Defaults match the table name written into the SQL — keep aligned
|
|
68
|
-
// with RULES_COLUMNS
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
// CLAUDE.md.
|
|
68
|
+
// with RULES_COLUMNS in deeplake-schema.ts and with the e2e test-org
|
|
69
|
+
// override convention (memory_test / sessions_test → goals_test, etc.)
|
|
70
|
+
// documented in CLAUDE.md.
|
|
72
71
|
rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
|
|
73
|
-
tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
|
|
74
|
-
taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
|
|
75
72
|
// Goals + KPIs (refined design — VFS path classifier maps
|
|
76
73
|
// memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
|
|
77
74
|
// memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
|
|
@@ -122,13 +122,10 @@ function loadConfig() {
|
|
|
122
122
|
sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
|
|
123
123
|
skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
|
|
124
124
|
// Defaults match the table name written into the SQL — keep aligned
|
|
125
|
-
// with RULES_COLUMNS
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// CLAUDE.md.
|
|
125
|
+
// with RULES_COLUMNS in deeplake-schema.ts and with the e2e test-org
|
|
126
|
+
// override convention (memory_test / sessions_test → goals_test, etc.)
|
|
127
|
+
// documented in CLAUDE.md.
|
|
129
128
|
rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
|
|
130
|
-
tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
|
|
131
|
-
taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
|
|
132
129
|
// Goals + KPIs (refined design — VFS path classifier maps
|
|
133
130
|
// memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
|
|
134
131
|
// memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
|
|
@@ -164,6 +161,9 @@ function log(tag, msg) {
|
|
|
164
161
|
function sqlStr(value) {
|
|
165
162
|
return value.replace(/\\/g, "\\\\").replace(/'/g, "''").replace(/\0/g, "").replace(/[\x01-\x08\x0b\x0c\x0e-\x1f\x7f]/g, "");
|
|
166
163
|
}
|
|
164
|
+
function sqlLike(value) {
|
|
165
|
+
return sqlStr(value).replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
166
|
+
}
|
|
167
167
|
function sqlIdent(name) {
|
|
168
168
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
|
|
169
169
|
throw new Error(`Invalid SQL identifier: ${JSON.stringify(name)}`);
|
|
@@ -238,32 +238,6 @@ var RULES_COLUMNS = Object.freeze([
|
|
|
238
238
|
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
239
239
|
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
240
240
|
]);
|
|
241
|
-
var TASKS_COLUMNS = Object.freeze([
|
|
242
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
243
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
244
|
-
{ name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
245
|
-
{ name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
|
|
246
|
-
{ name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
|
|
247
|
-
{ name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
248
|
-
{ name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
249
|
-
{ name: "kpis", sql: "JSONB" },
|
|
250
|
-
{ name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
251
|
-
{ name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
252
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
|
|
253
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
254
|
-
]);
|
|
255
|
-
var TASK_EVENTS_COLUMNS = Object.freeze([
|
|
256
|
-
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
257
|
-
{ name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
258
|
-
{ name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
|
|
259
|
-
{ name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
260
|
-
{ name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
|
|
261
|
-
{ name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
262
|
-
{ name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
|
|
263
|
-
{ name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
264
|
-
{ name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
265
|
-
{ name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
|
|
266
|
-
]);
|
|
267
241
|
var GOALS_COLUMNS = Object.freeze([
|
|
268
242
|
{ name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
269
243
|
{ name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
|
|
@@ -329,8 +303,6 @@ validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
|
|
|
329
303
|
validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
|
|
330
304
|
validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
|
|
331
305
|
validateSchema("RULES_COLUMNS", RULES_COLUMNS);
|
|
332
|
-
validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
|
|
333
|
-
validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
|
|
334
306
|
validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
|
|
335
307
|
validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
|
|
336
308
|
validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
|
|
@@ -932,46 +904,6 @@ var DeeplakeApi = class {
|
|
|
932
904
|
await this.healSchema(safe, RULES_COLUMNS);
|
|
933
905
|
await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
|
|
934
906
|
}
|
|
935
|
-
/**
|
|
936
|
-
* Create the tasks table.
|
|
937
|
-
*
|
|
938
|
-
* Same write pattern as rules + skills. `kpis` is a nullable JSONB
|
|
939
|
-
* column with the agent's KPI metadata; KPI current values come from
|
|
940
|
-
* `task_events` (SUM(value)), not this snapshot.
|
|
941
|
-
*/
|
|
942
|
-
async ensureTasksTable(name) {
|
|
943
|
-
const safe = sqlIdent(name);
|
|
944
|
-
const tables = await this.listTables();
|
|
945
|
-
if (!tables.includes(safe)) {
|
|
946
|
-
log3(`table "${safe}" not found, creating`);
|
|
947
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
|
|
948
|
-
log3(`table "${safe}" created`);
|
|
949
|
-
if (!tables.includes(safe))
|
|
950
|
-
this._tablesCache = [...tables, safe];
|
|
951
|
-
}
|
|
952
|
-
await this.healSchema(safe, TASKS_COLUMNS);
|
|
953
|
-
await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
|
|
954
|
-
}
|
|
955
|
-
/**
|
|
956
|
-
* Create the task-events table.
|
|
957
|
-
*
|
|
958
|
-
* Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
|
|
959
|
-
* value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
|
|
960
|
-
* (task_id, kpi_id) is the canonical aggregation key.
|
|
961
|
-
*/
|
|
962
|
-
async ensureTaskEventsTable(name) {
|
|
963
|
-
const safe = sqlIdent(name);
|
|
964
|
-
const tables = await this.listTables();
|
|
965
|
-
if (!tables.includes(safe)) {
|
|
966
|
-
log3(`table "${safe}" not found, creating`);
|
|
967
|
-
await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
|
|
968
|
-
log3(`table "${safe}" created`);
|
|
969
|
-
if (!tables.includes(safe))
|
|
970
|
-
this._tablesCache = [...tables, safe];
|
|
971
|
-
}
|
|
972
|
-
await this.healSchema(safe, TASK_EVENTS_COLUMNS);
|
|
973
|
-
await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
|
|
974
|
-
}
|
|
975
907
|
/**
|
|
976
908
|
* Create the goals table.
|
|
977
909
|
*
|
|
@@ -1058,187 +990,10 @@ function normalize(row) {
|
|
|
1058
990
|
};
|
|
1059
991
|
}
|
|
1060
992
|
|
|
1061
|
-
// dist/src/tasks/write.js
|
|
1062
|
-
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
1063
|
-
|
|
1064
|
-
// dist/src/tasks/kpi-validator.js
|
|
1065
|
-
function parseKpis(raw) {
|
|
1066
|
-
if (raw == null || raw === "")
|
|
1067
|
-
return [];
|
|
1068
|
-
let arr;
|
|
1069
|
-
if (typeof raw === "string") {
|
|
1070
|
-
try {
|
|
1071
|
-
arr = JSON.parse(raw);
|
|
1072
|
-
} catch {
|
|
1073
|
-
return [];
|
|
1074
|
-
}
|
|
1075
|
-
} else {
|
|
1076
|
-
arr = raw;
|
|
1077
|
-
}
|
|
1078
|
-
if (!Array.isArray(arr))
|
|
1079
|
-
return [];
|
|
1080
|
-
const out = [];
|
|
1081
|
-
for (const item of arr) {
|
|
1082
|
-
const kpi = validateOne(item);
|
|
1083
|
-
if (kpi)
|
|
1084
|
-
out.push(kpi);
|
|
1085
|
-
}
|
|
1086
|
-
return out;
|
|
1087
|
-
}
|
|
1088
|
-
function validateOne(item) {
|
|
1089
|
-
if (!isObject(item))
|
|
1090
|
-
return null;
|
|
1091
|
-
const kpi_id = safeStr(item.kpi_id);
|
|
1092
|
-
const name = safeStr(item.name);
|
|
1093
|
-
const target = num(item.target);
|
|
1094
|
-
const unit = safeStr(item.unit);
|
|
1095
|
-
const generated_by = safeStr(item.generated_by);
|
|
1096
|
-
const generated_at = isoStr(item.generated_at);
|
|
1097
|
-
if (kpi_id === null || name === null || target === null || unit === null || generated_by === null || generated_at === null) {
|
|
1098
|
-
return null;
|
|
1099
|
-
}
|
|
1100
|
-
if (!Number.isInteger(target) || target <= 0) {
|
|
1101
|
-
return null;
|
|
1102
|
-
}
|
|
1103
|
-
const out = {
|
|
1104
|
-
kpi_id,
|
|
1105
|
-
name,
|
|
1106
|
-
target,
|
|
1107
|
-
unit,
|
|
1108
|
-
generated_by,
|
|
1109
|
-
generated_at
|
|
1110
|
-
};
|
|
1111
|
-
const current = num(item.current);
|
|
1112
|
-
if (current !== null)
|
|
1113
|
-
out.current = current;
|
|
1114
|
-
return out;
|
|
1115
|
-
}
|
|
1116
|
-
function isObject(v) {
|
|
1117
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1118
|
-
}
|
|
1119
|
-
function str(v) {
|
|
1120
|
-
if (typeof v !== "string" || v.length === 0)
|
|
1121
|
-
return null;
|
|
1122
|
-
return v;
|
|
1123
|
-
}
|
|
1124
|
-
function safeStr(v) {
|
|
1125
|
-
const s = str(v);
|
|
1126
|
-
if (s === null)
|
|
1127
|
-
return null;
|
|
1128
|
-
if (/[\r\n\u2028\u2029\u0085]/.test(s))
|
|
1129
|
-
return null;
|
|
1130
|
-
return s;
|
|
1131
|
-
}
|
|
1132
|
-
function num(v) {
|
|
1133
|
-
if (typeof v !== "number" || !Number.isFinite(v))
|
|
1134
|
-
return null;
|
|
1135
|
-
return v;
|
|
1136
|
-
}
|
|
1137
|
-
function isoStr(v) {
|
|
1138
|
-
const s = safeStr(v);
|
|
1139
|
-
if (s === null)
|
|
1140
|
-
return null;
|
|
1141
|
-
if (!/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:?\d{2})?$/.test(s)) {
|
|
1142
|
-
return null;
|
|
1143
|
-
}
|
|
1144
|
-
return s;
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
// dist/src/tasks/read.js
|
|
1148
|
-
var SELECT_COLS2 = "id, task_id, text, scope, status, assigned_to, assigned_by, kpis, version, created_at, agent, plugin_version";
|
|
1149
|
-
async function listTasks(query, tableName, opts = {}) {
|
|
1150
|
-
const safe = sqlIdent(tableName);
|
|
1151
|
-
const rows = await query(`SELECT ${SELECT_COLS2} FROM "${safe}" ORDER BY version DESC, created_at DESC, id DESC`);
|
|
1152
|
-
const latest = /* @__PURE__ */ new Map();
|
|
1153
|
-
for (const r of rows) {
|
|
1154
|
-
const row = normalize2(r);
|
|
1155
|
-
if (!row)
|
|
1156
|
-
continue;
|
|
1157
|
-
if (!latest.has(row.task_id))
|
|
1158
|
-
latest.set(row.task_id, row);
|
|
1159
|
-
}
|
|
1160
|
-
const scope = opts.scope ?? "all";
|
|
1161
|
-
const status = opts.status ?? "active";
|
|
1162
|
-
const current = opts.current_user;
|
|
1163
|
-
const filtered = [...latest.values()].filter((row) => {
|
|
1164
|
-
if (status !== "all" && row.status !== status)
|
|
1165
|
-
return false;
|
|
1166
|
-
if (scope === "mine") {
|
|
1167
|
-
if (!current)
|
|
1168
|
-
return false;
|
|
1169
|
-
return row.assigned_to === current;
|
|
1170
|
-
}
|
|
1171
|
-
if (scope === "me") {
|
|
1172
|
-
if (!current)
|
|
1173
|
-
return false;
|
|
1174
|
-
return row.scope === "me" && row.assigned_to === current;
|
|
1175
|
-
}
|
|
1176
|
-
if (scope === "team")
|
|
1177
|
-
return row.scope === "team";
|
|
1178
|
-
return true;
|
|
1179
|
-
});
|
|
1180
|
-
filtered.sort((a, b) => b.created_at.localeCompare(a.created_at) || b.id.localeCompare(a.id));
|
|
1181
|
-
return filtered.slice(0, opts.limit ?? 10);
|
|
1182
|
-
}
|
|
1183
|
-
function normalize2(row) {
|
|
1184
|
-
const vRaw = row.version;
|
|
1185
|
-
const version = typeof vRaw === "number" ? vRaw : typeof vRaw === "string" ? Number(vRaw) : NaN;
|
|
1186
|
-
if (!Number.isFinite(version))
|
|
1187
|
-
return null;
|
|
1188
|
-
return {
|
|
1189
|
-
id: String(row.id ?? ""),
|
|
1190
|
-
task_id: String(row.task_id ?? ""),
|
|
1191
|
-
text: String(row.text ?? ""),
|
|
1192
|
-
scope: String(row.scope ?? ""),
|
|
1193
|
-
status: String(row.status ?? ""),
|
|
1194
|
-
assigned_to: String(row.assigned_to ?? ""),
|
|
1195
|
-
assigned_by: String(row.assigned_by ?? ""),
|
|
1196
|
-
kpis: parseKpis(row.kpis),
|
|
1197
|
-
version,
|
|
1198
|
-
created_at: String(row.created_at ?? ""),
|
|
1199
|
-
agent: String(row.agent ?? ""),
|
|
1200
|
-
plugin_version: String(row.plugin_version ?? "")
|
|
1201
|
-
};
|
|
1202
|
-
}
|
|
1203
|
-
|
|
1204
|
-
// dist/src/events/append.js
|
|
1205
|
-
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
1206
|
-
|
|
1207
|
-
// dist/src/events/aggregate.js
|
|
1208
|
-
async function computeAllForTasks(query, tableName, taskIds) {
|
|
1209
|
-
if (taskIds.length === 0)
|
|
1210
|
-
return {};
|
|
1211
|
-
const safe = sqlIdent(tableName);
|
|
1212
|
-
const inList = taskIds.map((id) => `'${sqlStr(id)}'`).join(", ");
|
|
1213
|
-
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`);
|
|
1214
|
-
const out = {};
|
|
1215
|
-
for (const row of rows) {
|
|
1216
|
-
const tid = typeof row.task_id === "string" ? row.task_id : "";
|
|
1217
|
-
const kid = typeof row.kpi_id === "string" ? row.kpi_id : "";
|
|
1218
|
-
if (!tid || !kid)
|
|
1219
|
-
continue;
|
|
1220
|
-
if (!out[tid])
|
|
1221
|
-
out[tid] = {};
|
|
1222
|
-
out[tid][kid] = normalizeTotal(row.total);
|
|
1223
|
-
}
|
|
1224
|
-
return out;
|
|
1225
|
-
}
|
|
1226
|
-
function normalizeTotal(raw) {
|
|
1227
|
-
if (raw == null)
|
|
1228
|
-
return 0;
|
|
1229
|
-
if (typeof raw === "number")
|
|
1230
|
-
return Number.isFinite(raw) ? raw : 0;
|
|
1231
|
-
if (typeof raw === "string") {
|
|
1232
|
-
const n = Number(raw);
|
|
1233
|
-
return Number.isFinite(n) ? n : 0;
|
|
1234
|
-
}
|
|
1235
|
-
return 0;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
993
|
// dist/src/hooks/shared/context-renderer.js
|
|
1239
994
|
async function renderContextBlock(query, input, opts = {}) {
|
|
1240
995
|
const maxRules = opts.maxRules ?? 10;
|
|
1241
|
-
const
|
|
996
|
+
const maxGoals = opts.maxGoals ?? 10;
|
|
1242
997
|
const log7 = opts.log ?? (() => {
|
|
1243
998
|
});
|
|
1244
999
|
try {
|
|
@@ -1252,79 +1007,54 @@ async function renderContextBlock(query, input, opts = {}) {
|
|
|
1252
1007
|
const rmsg = rulesErr instanceof Error ? rulesErr.message : String(rulesErr);
|
|
1253
1008
|
log7(`render-context-block: rules unavailable (continuing): ${rmsg}`);
|
|
1254
1009
|
}
|
|
1255
|
-
let
|
|
1256
|
-
let myTasks = [];
|
|
1010
|
+
let goals = [];
|
|
1257
1011
|
try {
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
status: "active",
|
|
1261
|
-
limit: Math.max(maxTasks * 4, maxTasks + 1)
|
|
1262
|
-
});
|
|
1263
|
-
myTasks = await listTasks(query, input.tasksTable, {
|
|
1264
|
-
scope: "me",
|
|
1265
|
-
status: "active",
|
|
1266
|
-
current_user: input.currentUser,
|
|
1267
|
-
limit: Math.max(maxTasks * 4, maxTasks + 1)
|
|
1012
|
+
goals = await listOpenGoals(query, input.goalsTable, input.currentUser, {
|
|
1013
|
+
limit: Math.max(maxGoals * 4, maxGoals + 1)
|
|
1268
1014
|
});
|
|
1269
|
-
} catch (
|
|
1270
|
-
const
|
|
1271
|
-
log7(`render-context-block:
|
|
1015
|
+
} catch (goalsErr) {
|
|
1016
|
+
const gmsg = goalsErr instanceof Error ? goalsErr.message : String(goalsErr);
|
|
1017
|
+
log7(`render-context-block: goals unavailable (continuing): ${gmsg}`);
|
|
1272
1018
|
}
|
|
1273
|
-
const visibleTasks = mergeAndDedupTasks(teamTasks, myTasks);
|
|
1274
1019
|
const rulesShown = rules.slice(0, maxRules);
|
|
1275
1020
|
const rulesHidden = Math.max(0, rules.length - maxRules);
|
|
1276
|
-
const
|
|
1277
|
-
const
|
|
1278
|
-
|
|
1279
|
-
let totals = {};
|
|
1280
|
-
try {
|
|
1281
|
-
totals = await computeAllForTasks(query, input.taskEventsTable, taskIds);
|
|
1282
|
-
} catch (aggErr) {
|
|
1283
|
-
const aggMsg = aggErr instanceof Error ? aggErr.message : String(aggErr);
|
|
1284
|
-
log7(`render-context-block: aggregate failed (continuing with 0/target): ${aggMsg}`);
|
|
1285
|
-
}
|
|
1286
|
-
return formatBlock({
|
|
1287
|
-
rules: rulesShown,
|
|
1288
|
-
rulesHidden,
|
|
1289
|
-
tasks: tasksShown,
|
|
1290
|
-
tasksHidden,
|
|
1291
|
-
totals,
|
|
1292
|
-
currentUser: input.currentUser
|
|
1293
|
-
});
|
|
1021
|
+
const goalsShown = goals.slice(0, maxGoals);
|
|
1022
|
+
const goalsHidden = Math.max(0, goals.length - maxGoals);
|
|
1023
|
+
return formatBlock({ rules: rulesShown, rulesHidden, goals: goalsShown, goalsHidden });
|
|
1294
1024
|
} catch (e) {
|
|
1295
1025
|
const msg = e instanceof Error ? e.message : String(e);
|
|
1296
1026
|
log7(`render-context-block: ${msg}`);
|
|
1297
1027
|
return "";
|
|
1298
1028
|
}
|
|
1299
1029
|
}
|
|
1300
|
-
function
|
|
1301
|
-
const
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1030
|
+
async function listOpenGoals(query, goalsTable, currentUser, opts = {}) {
|
|
1031
|
+
const limit = opts.limit ?? 40;
|
|
1032
|
+
const safe = sqlIdent(goalsTable);
|
|
1033
|
+
const fullUser = currentUser.trim();
|
|
1034
|
+
const shortUser = fullUser.split("@")[0] ?? fullUser;
|
|
1035
|
+
const fullEq = sqlStr(fullUser);
|
|
1036
|
+
const shortEq = sqlStr(shortUser);
|
|
1037
|
+
const shortLike = sqlLike(shortUser);
|
|
1038
|
+
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}`;
|
|
1039
|
+
const rows = await query(sql);
|
|
1040
|
+
const out = [];
|
|
1041
|
+
for (const r of rows) {
|
|
1042
|
+
const ownerNorm = String(r["owner"] ?? "").trim();
|
|
1043
|
+
const ownerShort = ownerNorm.split("@")[0] ?? ownerNorm;
|
|
1044
|
+
if (ownerNorm !== fullUser && ownerNorm !== shortUser && ownerShort !== shortUser) {
|
|
1306
1045
|
continue;
|
|
1307
1046
|
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
}
|
|
1047
|
+
out.push({
|
|
1048
|
+
goal_id: String(r["goal_id"] ?? ""),
|
|
1049
|
+
status: String(r["status"] ?? ""),
|
|
1050
|
+
content: String(r["content"] ?? "")
|
|
1051
|
+
});
|
|
1313
1052
|
}
|
|
1314
|
-
|
|
1315
|
-
merged.sort((a, b) => {
|
|
1316
|
-
const aMe = a.scope === "me" ? 0 : 1;
|
|
1317
|
-
const bMe = b.scope === "me" ? 0 : 1;
|
|
1318
|
-
if (aMe !== bMe)
|
|
1319
|
-
return aMe - bMe;
|
|
1320
|
-
return b.created_at.localeCompare(a.created_at);
|
|
1321
|
-
});
|
|
1322
|
-
return merged;
|
|
1053
|
+
return out;
|
|
1323
1054
|
}
|
|
1324
1055
|
function formatBlock(input) {
|
|
1325
|
-
if (input.rules.length === 0 && input.
|
|
1056
|
+
if (input.rules.length === 0 && input.goals.length === 0)
|
|
1326
1057
|
return "";
|
|
1327
|
-
}
|
|
1328
1058
|
const lines = [];
|
|
1329
1059
|
if (input.rules.length > 0) {
|
|
1330
1060
|
lines.push(`=== HIVEMIND RULES (${input.rules.length} active) ===`);
|
|
@@ -1336,41 +1066,42 @@ function formatBlock(input) {
|
|
|
1336
1066
|
}
|
|
1337
1067
|
lines.push("");
|
|
1338
1068
|
}
|
|
1339
|
-
if (input.
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1069
|
+
if (input.goals.length > 0) {
|
|
1070
|
+
const inProgress = input.goals.filter((g) => g.status === "in_progress").length;
|
|
1071
|
+
const opened = input.goals.filter((g) => g.status === "opened").length;
|
|
1072
|
+
lines.push(`=== HIVEMIND GOALS (${inProgress} in_progress, ${opened} opened) ===`);
|
|
1073
|
+
for (const g of input.goals) {
|
|
1074
|
+
const firstLine = sanitizeForInject(firstNonEmptyLine(g.content));
|
|
1075
|
+
const tag = g.status === "in_progress" ? "[in_progress]" : "[opened] ";
|
|
1076
|
+
lines.push(`${tag} ${g.goal_id}: ${firstLine}`);
|
|
1343
1077
|
}
|
|
1344
|
-
if (input.
|
|
1345
|
-
lines.push(`(${input.
|
|
1078
|
+
if (input.goalsHidden > 0) {
|
|
1079
|
+
lines.push(`(${input.goalsHidden} more \u2014 run 'hivemind goal list --mine' to see all)`);
|
|
1346
1080
|
}
|
|
1347
1081
|
lines.push("");
|
|
1348
1082
|
}
|
|
1349
1083
|
lines.push("=== HIVEMIND HOW-TO ===");
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1084
|
+
if (input.rules.length > 0) {
|
|
1085
|
+
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.");
|
|
1086
|
+
}
|
|
1087
|
+
if (input.goals.length > 0) {
|
|
1088
|
+
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).");
|
|
1089
|
+
}
|
|
1090
|
+
lines.push("- Run 'hivemind rules list' / 'hivemind goal list --mine' for the full inventories beyond what's shown here.");
|
|
1353
1091
|
return lines.join("\n");
|
|
1354
1092
|
}
|
|
1355
|
-
function
|
|
1356
|
-
const
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1093
|
+
function firstNonEmptyLine(content) {
|
|
1094
|
+
for (const raw of content.split(/\r?\n/)) {
|
|
1095
|
+
const trimmed = raw.trim();
|
|
1096
|
+
if (trimmed.length > 0)
|
|
1097
|
+
return trimmed;
|
|
1098
|
+
}
|
|
1099
|
+
return "(empty)";
|
|
1360
1100
|
}
|
|
1361
1101
|
function sanitizeForInject(text) {
|
|
1362
1102
|
return text.replace(LINE_TERMINATOR_RE, "\\n");
|
|
1363
1103
|
}
|
|
1364
1104
|
var LINE_TERMINATOR_RE = /\r\n?|[\n\u2028\u2029\u0085]/g;
|
|
1365
|
-
function formatKpiSummary(kpis, totals) {
|
|
1366
|
-
if (kpis.length === 0)
|
|
1367
|
-
return "";
|
|
1368
|
-
const parts = kpis.map((k) => {
|
|
1369
|
-
const current = totals[k.kpi_id] ?? 0;
|
|
1370
|
-
return `${sanitizeForInject(k.name)}: ${current}/${k.target} ${sanitizeForInject(k.unit)}`;
|
|
1371
|
-
});
|
|
1372
|
-
return ` | ${parts.join(", ")}`;
|
|
1373
|
-
}
|
|
1374
1105
|
|
|
1375
1106
|
// dist/src/cli/skillify-spec.js
|
|
1376
1107
|
var SKILLIFY_COMMANDS = [
|
|
@@ -2332,7 +2063,7 @@ Commands (invoke via your Shell / terminal / Bash tool):
|
|
|
2332
2063
|
hivemind kpi bump <goal_id> <kpi_id> <delta>
|
|
2333
2064
|
Increment (positive int) or decrement (negative) the current value of one KPI.
|
|
2334
2065
|
|
|
2335
|
-
Workflow when the user expresses a goal:
|
|
2066
|
+
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):
|
|
2336
2067
|
1. \`hivemind goal add "<short description>"\` \u2014 capture stdout as goal_id.
|
|
2337
2068
|
2. ONLY if the user explicitly asks for KPIs: \`hivemind kpi add <goal_id> <slug> <target> <unit>\` per KPI.
|
|
2338
2069
|
3. Tell the user the goal_id and that it is now visible to the team.
|
|
@@ -2437,7 +2168,7 @@ async function main() {
|
|
|
2437
2168
|
const current = getInstalledVersion(__bundleDir, ".claude-plugin");
|
|
2438
2169
|
const pluginVersion = current ?? "";
|
|
2439
2170
|
const captureEnabled = process.env.HIVEMIND_CAPTURE !== "false";
|
|
2440
|
-
let
|
|
2171
|
+
let rulesBlock = "";
|
|
2441
2172
|
if (creds?.token) {
|
|
2442
2173
|
try {
|
|
2443
2174
|
const config = loadConfig();
|
|
@@ -2453,10 +2184,9 @@ async function main() {
|
|
|
2453
2184
|
} else {
|
|
2454
2185
|
log6("placeholder + schema ensure skipped (HIVEMIND_CAPTURE=false)");
|
|
2455
2186
|
}
|
|
2456
|
-
|
|
2187
|
+
rulesBlock = await renderContextBlock((sql) => api.query(sql), {
|
|
2457
2188
|
rulesTable: config.rulesTableName,
|
|
2458
|
-
|
|
2459
|
-
taskEventsTable: config.taskEventsTableName,
|
|
2189
|
+
goalsTable: config.goalsTableName,
|
|
2460
2190
|
currentUser: config.userName
|
|
2461
2191
|
}, { log: log6 });
|
|
2462
2192
|
}
|
|
@@ -2481,9 +2211,9 @@ Not logged in to Deeplake. Run: hivemind login${localMinedNote}${versionNotice}`
|
|
|
2481
2211
|
const baseWithGoals = creds?.token ? `${baseContext}
|
|
2482
2212
|
|
|
2483
2213
|
${GOALS_INSTRUCTIONS_CLI}` : baseContext;
|
|
2484
|
-
const additionalContext =
|
|
2214
|
+
const additionalContext = rulesBlock ? `${baseWithGoals}
|
|
2485
2215
|
|
|
2486
|
-
${
|
|
2216
|
+
${rulesBlock}` : baseWithGoals;
|
|
2487
2217
|
console.log(JSON.stringify({ additional_context: additionalContext }));
|
|
2488
2218
|
}
|
|
2489
2219
|
main().catch((e) => {
|