@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.
Files changed (39) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +64 -0
  4. package/bundle/cli.js +22702 -7775
  5. package/codex/bundle/capture.js +228 -0
  6. package/codex/bundle/commands/auth-login.js +228 -0
  7. package/codex/bundle/graph-pull-worker.js +1370 -0
  8. package/codex/bundle/pre-tool-use.js +228 -0
  9. package/codex/bundle/session-start-setup.js +228 -0
  10. package/codex/bundle/session-start.js +255 -4
  11. package/codex/bundle/shell/deeplake-shell.js +1028 -28
  12. package/codex/bundle/skillify-worker.js +94 -3
  13. package/codex/bundle/stop.js +282 -50
  14. package/codex/skills/hivemind-goals/SKILL.md +157 -0
  15. package/cursor/bundle/capture.js +282 -50
  16. package/cursor/bundle/commands/auth-login.js +228 -0
  17. package/cursor/bundle/graph-pull-worker.js +1370 -0
  18. package/cursor/bundle/pre-tool-use.js +228 -0
  19. package/cursor/bundle/session-end.js +65 -44
  20. package/cursor/bundle/session-start.js +662 -6
  21. package/cursor/bundle/shell/deeplake-shell.js +1028 -28
  22. package/cursor/bundle/skillify-worker.js +94 -3
  23. package/hermes/bundle/capture.js +282 -50
  24. package/hermes/bundle/commands/auth-login.js +228 -0
  25. package/hermes/bundle/graph-pull-worker.js +1370 -0
  26. package/hermes/bundle/pre-tool-use.js +228 -0
  27. package/hermes/bundle/session-end.js +65 -44
  28. package/hermes/bundle/session-start.js +662 -6
  29. package/hermes/bundle/shell/deeplake-shell.js +1028 -28
  30. package/hermes/bundle/skillify-worker.js +94 -3
  31. package/mcp/bundle/server.js +228 -0
  32. package/openclaw/dist/chunks/config-FH6JYSJW.js +53 -0
  33. package/openclaw/dist/index.js +307 -2
  34. package/openclaw/dist/skillify-worker.js +94 -3
  35. package/openclaw/openclaw.plugin.json +4 -2
  36. package/openclaw/package.json +1 -1
  37. package/openclaw/skills/hivemind-goals/SKILL.md +30 -0
  38. package/package.json +4 -1
  39. package/openclaw/dist/chunks/config-XEK4MJJS.js +0 -36
@@ -378,6 +378,65 @@ var SKILLS_COLUMNS = Object.freeze([
378
378
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
379
379
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
380
380
  ]);
381
+ var RULES_COLUMNS = Object.freeze([
382
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
383
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
384
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
385
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
386
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
387
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
388
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
389
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
390
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
391
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
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
+ var GOALS_COLUMNS = Object.freeze([
420
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
421
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
422
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
423
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
424
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
425
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
426
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
427
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
428
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
429
+ ]);
430
+ var KPIS_COLUMNS = Object.freeze([
431
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
432
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
433
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
434
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
435
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
436
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
437
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
438
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
439
+ ]);
381
440
  function validateSchema(label, cols) {
382
441
  const seen = /* @__PURE__ */ new Set();
383
442
  for (const col of cols) {
@@ -395,9 +454,38 @@ function validateSchema(label, cols) {
395
454
  }
396
455
  }
397
456
  }
457
+ var CODEBASE_COLUMNS = Object.freeze([
458
+ // Identity key (matches the PK below)
459
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
460
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
461
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
462
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
463
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
464
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
465
+ // Observation metadata
466
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
467
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
468
+ { name: "ts", sql: "TIMESTAMP" },
469
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
470
+ // Snapshot payload
471
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
472
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
473
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
474
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
475
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
476
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
477
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
478
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
479
+ ]);
398
480
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
399
481
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
400
482
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
483
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
484
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
485
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
486
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
487
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
488
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
401
489
  function buildCreateTableSql(tableName, cols) {
402
490
  const safe = sqlIdent(tableName);
403
491
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -693,9 +781,12 @@ function resolveRecordScope(args) {
693
781
 
694
782
  // dist/src/skillify/state.js
695
783
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, writeSync, mkdirSync as mkdirSync2, renameSync as renameSync2, rmdirSync, existsSync as existsSync4, lstatSync, unlinkSync, openSync, closeSync } from "node:fs";
784
+ import { join as join6 } from "node:path";
785
+
786
+ // dist/src/utils/repo-identity.js
696
787
  import { execSync } from "node:child_process";
697
788
  import { createHash } from "node:crypto";
698
- import { join as join6, basename } from "node:path";
789
+ import { basename, resolve } from "node:path";
699
790
 
700
791
  // dist/src/skillify/legacy-migration.js
701
792
  import { existsSync as existsSync3, renameSync } from "node:fs";
@@ -881,7 +972,7 @@ async function query(sql, retries = 4) {
881
972
  const base = Math.min(3e4, 2e3 * Math.pow(2, attempt));
882
973
  const delay = base + Math.floor(Math.random() * 1e3);
883
974
  wlog(`fetch failed (${e?.name ?? e?.code ?? e?.message}), retrying in ${delay}ms (attempt ${attempt + 1}/${retries})`);
884
- await new Promise((resolve) => setTimeout(resolve, delay));
975
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
885
976
  continue;
886
977
  }
887
978
  throw e;
@@ -897,7 +988,7 @@ async function query(sql, retries = 4) {
897
988
  const base = Math.min(3e4, 2e3 * Math.pow(2, attempt));
898
989
  const delay = base + Math.floor(Math.random() * 1e3);
899
990
  wlog(`API ${r.status}, retrying in ${delay}ms (attempt ${attempt + 1}/${retries})`);
900
- await new Promise((resolve) => setTimeout(resolve, delay));
991
+ await new Promise((resolve2) => setTimeout(resolve2, delay));
901
992
  continue;
902
993
  }
903
994
  throw new Error(`API ${r.status}: ${(await r.text()).slice(0, 200)}`);
@@ -53,13 +53,13 @@ var init_index_marker_store = __esm({
53
53
 
54
54
  // dist/src/utils/stdin.js
55
55
  function readStdin() {
56
- return new Promise((resolve2, reject) => {
56
+ return new Promise((resolve3, reject) => {
57
57
  let data = "";
58
58
  process.stdin.setEncoding("utf-8");
59
59
  process.stdin.on("data", (chunk) => data += chunk);
60
60
  process.stdin.on("end", () => {
61
61
  try {
62
- resolve2(JSON.parse(data));
62
+ resolve3(JSON.parse(data));
63
63
  } catch (err) {
64
64
  reject(new Error(`Failed to parse hook input: ${err}`));
65
65
  }
@@ -97,6 +97,23 @@ function loadConfig() {
97
97
  tableName: process.env.HIVEMIND_TABLE ?? "memory",
98
98
  sessionsTableName: process.env.HIVEMIND_SESSIONS_TABLE ?? "sessions",
99
99
  skillsTableName: process.env.HIVEMIND_SKILLS_TABLE ?? "skills",
100
+ // Defaults match the table name written into the SQL — keep aligned
101
+ // with RULES_COLUMNS / TASKS_COLUMNS / TASK_EVENTS_COLUMNS in
102
+ // deeplake-schema.ts and with the e2e test-org override convention
103
+ // (memory_test / sessions_test → goals_test, etc.) documented in
104
+ // CLAUDE.md.
105
+ rulesTableName: process.env.HIVEMIND_RULES_TABLE ?? "hivemind_rules",
106
+ tasksTableName: process.env.HIVEMIND_TASKS_TABLE ?? "hivemind_tasks",
107
+ taskEventsTableName: process.env.HIVEMIND_TASK_EVENTS_TABLE ?? "hivemind_task_events",
108
+ // Goals + KPIs (refined design — VFS path classifier maps
109
+ // memory/goal/<user>/<status>/<uuid>.md → hivemind_goals row
110
+ // memory/kpi/<uuid>/<kpi_id>.md → hivemind_kpis row
111
+ // See src/shell/deeplake-fs.ts for the translation logic and
112
+ // GOALS_COLUMNS / KPIS_COLUMNS in deeplake-schema.ts for the
113
+ // table shape.
114
+ goalsTableName: process.env.HIVEMIND_GOALS_TABLE ?? "hivemind_goals",
115
+ kpisTableName: process.env.HIVEMIND_KPIS_TABLE ?? "hivemind_kpis",
116
+ codebaseTableName: process.env.HIVEMIND_CODEBASE_TABLE ?? "codebase",
100
117
  memoryPath: process.env.HIVEMIND_MEMORY_PATH ?? join(home, ".deeplake", "memory")
101
118
  };
102
119
  }
@@ -197,6 +214,65 @@ var SKILLS_COLUMNS = Object.freeze([
197
214
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
198
215
  { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" }
199
216
  ]);
217
+ var RULES_COLUMNS = Object.freeze([
218
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
219
+ { name: "rule_id", sql: "TEXT NOT NULL DEFAULT ''" },
220
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
221
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'team'" },
222
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
223
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
224
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
225
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
226
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
227
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
228
+ ]);
229
+ var TASKS_COLUMNS = Object.freeze([
230
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
231
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
232
+ { name: "text", sql: "TEXT NOT NULL DEFAULT ''" },
233
+ { name: "scope", sql: "TEXT NOT NULL DEFAULT 'me'" },
234
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'active'" },
235
+ { name: "assigned_to", sql: "TEXT NOT NULL DEFAULT ''" },
236
+ { name: "assigned_by", sql: "TEXT NOT NULL DEFAULT ''" },
237
+ { name: "kpis", sql: "JSONB" },
238
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
239
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
240
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
241
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
242
+ ]);
243
+ var TASK_EVENTS_COLUMNS = Object.freeze([
244
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
245
+ { name: "task_id", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "task_version", sql: "BIGINT NOT NULL DEFAULT 1" },
247
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
248
+ { name: "value", sql: "BIGINT NOT NULL DEFAULT 0" },
249
+ { name: "note", sql: "TEXT NOT NULL DEFAULT ''" },
250
+ { name: "source", sql: "TEXT NOT NULL DEFAULT 'user'" },
251
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT ''" },
252
+ { name: "ts", sql: "TEXT NOT NULL DEFAULT ''" },
253
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
254
+ ]);
255
+ var GOALS_COLUMNS = Object.freeze([
256
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
257
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
258
+ { name: "owner", sql: "TEXT NOT NULL DEFAULT ''" },
259
+ { name: "status", sql: "TEXT NOT NULL DEFAULT 'opened'" },
260
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
261
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
262
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
263
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
264
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
265
+ ]);
266
+ var KPIS_COLUMNS = Object.freeze([
267
+ { name: "id", sql: "TEXT NOT NULL DEFAULT ''" },
268
+ { name: "goal_id", sql: "TEXT NOT NULL DEFAULT ''" },
269
+ { name: "kpi_id", sql: "TEXT NOT NULL DEFAULT ''" },
270
+ { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
271
+ { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
272
+ { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
273
+ { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
274
+ { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
275
+ ]);
200
276
  function validateSchema(label, cols) {
201
277
  const seen = /* @__PURE__ */ new Set();
202
278
  for (const col of cols) {
@@ -214,9 +290,38 @@ function validateSchema(label, cols) {
214
290
  }
215
291
  }
216
292
  }
293
+ var CODEBASE_COLUMNS = Object.freeze([
294
+ // Identity key (matches the PK below)
295
+ { name: "org_id", sql: "TEXT NOT NULL DEFAULT ''" },
296
+ { name: "workspace_id", sql: "TEXT NOT NULL DEFAULT ''" },
297
+ { name: "repo_slug", sql: "TEXT NOT NULL DEFAULT ''" },
298
+ { name: "user_id", sql: "TEXT NOT NULL DEFAULT ''" },
299
+ { name: "worktree_id", sql: "TEXT NOT NULL DEFAULT ''" },
300
+ { name: "commit_sha", sql: "TEXT NOT NULL DEFAULT ''" },
301
+ // Observation metadata
302
+ { name: "parent_sha", sql: "TEXT NOT NULL DEFAULT ''" },
303
+ { name: "branch", sql: "TEXT NOT NULL DEFAULT ''" },
304
+ { name: "ts", sql: "TIMESTAMP" },
305
+ { name: "pushed_by", sql: "TEXT NOT NULL DEFAULT ''" },
306
+ // Snapshot payload
307
+ { name: "snapshot_sha256", sql: "TEXT NOT NULL DEFAULT ''" },
308
+ { name: "snapshot_jsonb", sql: "TEXT NOT NULL DEFAULT ''" },
309
+ { name: "node_count", sql: "BIGINT NOT NULL DEFAULT 0" },
310
+ { name: "edge_count", sql: "BIGINT NOT NULL DEFAULT 0" },
311
+ // Generator metadata (for drift diagnostics — what hivemind version produced this?)
312
+ { name: "generator", sql: "TEXT NOT NULL DEFAULT 'hivemind-graph'" },
313
+ { name: "generator_version", sql: "TEXT NOT NULL DEFAULT ''" },
314
+ { name: "schema_version", sql: "BIGINT NOT NULL DEFAULT 1" }
315
+ ]);
217
316
  validateSchema("MEMORY_COLUMNS", MEMORY_COLUMNS);
218
317
  validateSchema("SESSIONS_COLUMNS", SESSIONS_COLUMNS);
219
318
  validateSchema("SKILLS_COLUMNS", SKILLS_COLUMNS);
319
+ validateSchema("RULES_COLUMNS", RULES_COLUMNS);
320
+ validateSchema("TASKS_COLUMNS", TASKS_COLUMNS);
321
+ validateSchema("TASK_EVENTS_COLUMNS", TASK_EVENTS_COLUMNS);
322
+ validateSchema("GOALS_COLUMNS", GOALS_COLUMNS);
323
+ validateSchema("KPIS_COLUMNS", KPIS_COLUMNS);
324
+ validateSchema("CODEBASE_COLUMNS", CODEBASE_COLUMNS);
220
325
  function buildCreateTableSql(tableName, cols) {
221
326
  const safe = sqlIdent(tableName);
222
327
  const colSql = cols.map((c) => `${c.name} ${c.sql}`).join(", ");
@@ -441,7 +546,7 @@ function getQueryTimeoutMs() {
441
546
  return Number(process.env.HIVEMIND_QUERY_TIMEOUT_MS ?? 1e4);
442
547
  }
443
548
  function sleep2(ms) {
444
- return new Promise((resolve2) => setTimeout(resolve2, ms));
549
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
445
550
  }
446
551
  function isTimeoutError(error) {
447
552
  const name = error instanceof Error ? error.name.toLowerCase() : "";
@@ -471,7 +576,7 @@ var Semaphore = class {
471
576
  this.active++;
472
577
  return;
473
578
  }
474
- await new Promise((resolve2) => this.waiting.push(resolve2));
579
+ await new Promise((resolve3) => this.waiting.push(resolve3));
475
580
  }
476
581
  release() {
477
582
  this.active--;
@@ -781,6 +886,24 @@ var DeeplakeApi = class {
781
886
  * This sidesteps the Deeplake UPDATE-coalescing quirk that bit the wiki
782
887
  * worker.
783
888
  */
889
+ /**
890
+ * Create the codebase table. One row per (org, workspace, repo, user,
891
+ * worktree, commit) — see CODEBASE_COLUMNS for the schema. Healing
892
+ * + index follow the same pattern as ensureSessionsTable.
893
+ */
894
+ async ensureCodebaseTable(name) {
895
+ const safe = sqlIdent(name);
896
+ const tables = await this.listTables();
897
+ if (!tables.includes(safe)) {
898
+ log3(`table "${safe}" not found, creating`);
899
+ await this.createTableWithRetry(buildCreateTableSql(safe, CODEBASE_COLUMNS), safe);
900
+ log3(`table "${safe}" created`);
901
+ if (!tables.includes(safe))
902
+ this._tablesCache = [...tables, safe];
903
+ }
904
+ await this.healSchema(safe, CODEBASE_COLUMNS);
905
+ await this.ensureLookupIndex(safe, "codebase_identity", `("org_id", "workspace_id", "repo_slug", "user_id", "worktree_id", "commit_sha")`);
906
+ }
784
907
  async ensureSkillsTable(name) {
785
908
  const safe = sqlIdent(name);
786
909
  const tables = await this.listTables();
@@ -794,6 +917,111 @@ var DeeplakeApi = class {
794
917
  await this.healSchema(safe, SKILLS_COLUMNS);
795
918
  await this.ensureLookupIndex(safe, "project_key_name", `("project_key", "name")`);
796
919
  }
920
+ /**
921
+ * Create the rules table.
922
+ *
923
+ * One row per rule version (same write pattern as skills): edits INSERT
924
+ * a fresh row with version+1, reads pick latest per rule_id via
925
+ * `ORDER BY version DESC LIMIT 1`. Sidesteps the Deeplake
926
+ * UPDATE-coalescing quirk by never UPDATEing.
927
+ */
928
+ async ensureRulesTable(name) {
929
+ const safe = sqlIdent(name);
930
+ const tables = await this.listTables();
931
+ if (!tables.includes(safe)) {
932
+ log3(`table "${safe}" not found, creating`);
933
+ await this.createTableWithRetry(buildCreateTableSql(safe, RULES_COLUMNS), safe);
934
+ log3(`table "${safe}" created`);
935
+ if (!tables.includes(safe))
936
+ this._tablesCache = [...tables, safe];
937
+ }
938
+ await this.healSchema(safe, RULES_COLUMNS);
939
+ await this.ensureLookupIndex(safe, "rule_id_version", `("rule_id", "version")`);
940
+ }
941
+ /**
942
+ * Create the tasks table.
943
+ *
944
+ * Same write pattern as rules + skills. `kpis` is a nullable JSONB
945
+ * column with the agent's KPI metadata; KPI current values come from
946
+ * `task_events` (SUM(value)), not this snapshot.
947
+ */
948
+ async ensureTasksTable(name) {
949
+ const safe = sqlIdent(name);
950
+ const tables = await this.listTables();
951
+ if (!tables.includes(safe)) {
952
+ log3(`table "${safe}" not found, creating`);
953
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASKS_COLUMNS), safe);
954
+ log3(`table "${safe}" created`);
955
+ if (!tables.includes(safe))
956
+ this._tablesCache = [...tables, safe];
957
+ }
958
+ await this.healSchema(safe, TASKS_COLUMNS);
959
+ await this.ensureLookupIndex(safe, "task_id_version", `("task_id", "version")`);
960
+ }
961
+ /**
962
+ * Create the task-events table.
963
+ *
964
+ * Append-only. Every INSERT is a fresh row; never UPDATE. KPI current
965
+ * value is `SUM(value) WHERE task_id=? AND kpi_id=?`. Index on
966
+ * (task_id, kpi_id) is the canonical aggregation key.
967
+ */
968
+ async ensureTaskEventsTable(name) {
969
+ const safe = sqlIdent(name);
970
+ const tables = await this.listTables();
971
+ if (!tables.includes(safe)) {
972
+ log3(`table "${safe}" not found, creating`);
973
+ await this.createTableWithRetry(buildCreateTableSql(safe, TASK_EVENTS_COLUMNS), safe);
974
+ log3(`table "${safe}" created`);
975
+ if (!tables.includes(safe))
976
+ this._tablesCache = [...tables, safe];
977
+ }
978
+ await this.healSchema(safe, TASK_EVENTS_COLUMNS);
979
+ await this.ensureLookupIndex(safe, "task_id_kpi_id", `("task_id", "kpi_id")`);
980
+ }
981
+ /**
982
+ * Create the goals table.
983
+ *
984
+ * Backed by the VFS path convention memory/goal/<owner>/<status>/<goal_id>.md.
985
+ * INSERT-only version-bumped: rm and mv operations translate to fresh
986
+ * v=N+1 rows (status flips for mv → closed; rm is the same soft-close).
987
+ * The (goal_id, version) index lets the VFS dispatch a cheap latest-row
988
+ * read on cat / Read of a single goal.
989
+ */
990
+ async ensureGoalsTable(name) {
991
+ const safe = sqlIdent(name);
992
+ const tables = await this.listTables();
993
+ if (!tables.includes(safe)) {
994
+ log3(`table "${safe}" not found, creating`);
995
+ await this.createTableWithRetry(buildCreateTableSql(safe, GOALS_COLUMNS), safe);
996
+ log3(`table "${safe}" created`);
997
+ if (!tables.includes(safe))
998
+ this._tablesCache = [...tables, safe];
999
+ }
1000
+ await this.healSchema(safe, GOALS_COLUMNS);
1001
+ await this.ensureLookupIndex(safe, "goal_id_version", `("goal_id", "version")`);
1002
+ await this.ensureLookupIndex(safe, "owner_status", `("owner", "status")`);
1003
+ }
1004
+ /**
1005
+ * Create the kpis table.
1006
+ *
1007
+ * Backed by memory/kpi/<goal_id>/<kpi_id>.md. KPI rows do NOT carry
1008
+ * owner — ownership derives from the parent goal via logical join on
1009
+ * goal_id. INSERT-only version-bumped. (goal_id, kpi_id) index is the
1010
+ * canonical lookup the VFS uses on Read and Write.
1011
+ */
1012
+ async ensureKpisTable(name) {
1013
+ const safe = sqlIdent(name);
1014
+ const tables = await this.listTables();
1015
+ if (!tables.includes(safe)) {
1016
+ log3(`table "${safe}" not found, creating`);
1017
+ await this.createTableWithRetry(buildCreateTableSql(safe, KPIS_COLUMNS), safe);
1018
+ log3(`table "${safe}" created`);
1019
+ if (!tables.includes(safe))
1020
+ this._tablesCache = [...tables, safe];
1021
+ }
1022
+ await this.healSchema(safe, KPIS_COLUMNS);
1023
+ await this.ensureLookupIndex(safe, "goal_id_kpi_id", `("goal_id", "kpi_id")`);
1024
+ }
797
1025
  };
798
1026
 
799
1027
  // dist/src/utils/session-path.js
@@ -1056,7 +1284,7 @@ var EmbedClient = class {
1056
1284
  }
1057
1285
  }
1058
1286
  connectOnce() {
1059
- return new Promise((resolve2, reject) => {
1287
+ return new Promise((resolve3, reject) => {
1060
1288
  const sock = connect(this.socketPath);
1061
1289
  const to = setTimeout(() => {
1062
1290
  sock.destroy();
@@ -1064,7 +1292,7 @@ var EmbedClient = class {
1064
1292
  }, this.timeoutMs);
1065
1293
  sock.once("connect", () => {
1066
1294
  clearTimeout(to);
1067
- resolve2(sock);
1295
+ resolve3(sock);
1068
1296
  });
1069
1297
  sock.once("error", (e) => {
1070
1298
  clearTimeout(to);
@@ -1146,7 +1374,7 @@ var EmbedClient = class {
1146
1374
  throw new Error("daemon did not become ready within spawnWaitMs");
1147
1375
  }
1148
1376
  sendAndWait(sock, req) {
1149
- return new Promise((resolve2, reject) => {
1377
+ return new Promise((resolve3, reject) => {
1150
1378
  let buf = "";
1151
1379
  const to = setTimeout(() => {
1152
1380
  sock.destroy();
@@ -1161,7 +1389,7 @@ var EmbedClient = class {
1161
1389
  const line = buf.slice(0, nl);
1162
1390
  clearTimeout(to);
1163
1391
  try {
1164
- resolve2(JSON.parse(line));
1392
+ resolve3(JSON.parse(line));
1165
1393
  } catch (e) {
1166
1394
  reject(e);
1167
1395
  }
@@ -1818,9 +2046,54 @@ function spawnSkillifyWorker(opts) {
1818
2046
 
1819
2047
  // dist/src/skillify/state.js
1820
2048
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync8, writeSync as writeSync3, mkdirSync as mkdirSync10, renameSync as renameSync6, rmdirSync, existsSync as existsSync9, lstatSync as lstatSync2, unlinkSync as unlinkSync5, openSync as openSync4, closeSync as closeSync4 } from "node:fs";
2049
+ import { join as join18 } from "node:path";
2050
+
2051
+ // dist/src/utils/repo-identity.js
1821
2052
  import { execSync as execSync2 } from "node:child_process";
1822
2053
  import { createHash } from "node:crypto";
1823
- import { join as join18, basename as basename2 } from "node:path";
2054
+ import { basename as basename2, resolve as resolve2 } from "node:path";
2055
+ var DEFAULT_PORTS = {
2056
+ http: "80",
2057
+ https: "443",
2058
+ ssh: "22",
2059
+ git: "9418"
2060
+ };
2061
+ function normalizeGitRemoteUrl(url) {
2062
+ let s = url.trim();
2063
+ const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
2064
+ const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
2065
+ if (schemeMatch)
2066
+ s = s.slice(schemeMatch[0].length);
2067
+ if (!scheme) {
2068
+ const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
2069
+ if (scp)
2070
+ s = `${scp[1]}/${scp[2]}`;
2071
+ }
2072
+ s = s.replace(/^[^@/]+@/, "");
2073
+ if (scheme && DEFAULT_PORTS[scheme]) {
2074
+ s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
2075
+ }
2076
+ s = s.replace(/\.git\/?$/i, "");
2077
+ s = s.replace(/\/+$/, "");
2078
+ return s.toLowerCase();
2079
+ }
2080
+ function deriveProjectKey(cwd) {
2081
+ const absCwd = resolve2(cwd);
2082
+ const project = basename2(absCwd) || "unknown";
2083
+ let signature = null;
2084
+ try {
2085
+ const raw = execSync2("git config --get remote.origin.url", {
2086
+ cwd: absCwd,
2087
+ encoding: "utf-8",
2088
+ stdio: ["ignore", "pipe", "ignore"]
2089
+ }).trim();
2090
+ signature = raw ? normalizeGitRemoteUrl(raw) : null;
2091
+ } catch {
2092
+ }
2093
+ const input = signature ?? absCwd;
2094
+ const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
2095
+ return { key, project };
2096
+ }
1824
2097
 
1825
2098
  // dist/src/skillify/legacy-migration.js
1826
2099
  import { existsSync as existsSync8, renameSync as renameSync5 } from "node:fs";
@@ -1875,47 +2148,6 @@ function statePath2(projectKey) {
1875
2148
  function lockPath3(projectKey) {
1876
2149
  return join18(getStateDir(), `${projectKey}.lock`);
1877
2150
  }
1878
- var DEFAULT_PORTS = {
1879
- http: "80",
1880
- https: "443",
1881
- ssh: "22",
1882
- git: "9418"
1883
- };
1884
- function normalizeGitRemoteUrl(url) {
1885
- let s = url.trim();
1886
- const schemeMatch = s.match(/^([a-z][a-z0-9+.-]*):\/\//i);
1887
- const scheme = schemeMatch ? schemeMatch[1].toLowerCase() : null;
1888
- if (schemeMatch)
1889
- s = s.slice(schemeMatch[0].length);
1890
- if (!scheme) {
1891
- const scp = s.match(/^(?:[^@/\s]+@)?([^:/\s]+):(.+)$/);
1892
- if (scp)
1893
- s = `${scp[1]}/${scp[2]}`;
1894
- }
1895
- s = s.replace(/^[^@/]+@/, "");
1896
- if (scheme && DEFAULT_PORTS[scheme]) {
1897
- s = s.replace(new RegExp(`^([^/]+):${DEFAULT_PORTS[scheme]}(/|$)`), "$1$2");
1898
- }
1899
- s = s.replace(/\.git\/?$/i, "");
1900
- s = s.replace(/\/+$/, "");
1901
- return s.toLowerCase();
1902
- }
1903
- function deriveProjectKey(cwd) {
1904
- const project = basename2(cwd) || "unknown";
1905
- let signature = null;
1906
- try {
1907
- const raw = execSync2("git config --get remote.origin.url", {
1908
- cwd,
1909
- encoding: "utf-8",
1910
- stdio: ["ignore", "pipe", "ignore"]
1911
- }).trim();
1912
- signature = raw ? normalizeGitRemoteUrl(raw) : null;
1913
- } catch {
1914
- }
1915
- const input = signature ?? cwd;
1916
- const key = createHash("sha1").update(input).digest("hex").slice(0, 16);
1917
- return { key, project };
1918
- }
1919
2151
  function readState2(projectKey) {
1920
2152
  migrateLegacyStateDir();
1921
2153
  const p = statePath2(projectKey);