@deeplake/hivemind 0.7.70 → 0.7.72

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 (37) hide show
  1. package/.claude-plugin/marketplace.json +3 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/bundle/cli.js +15 -11
  4. package/codex/bundle/capture.js +4 -2
  5. package/codex/bundle/commands/auth-login.js +2 -0
  6. package/codex/bundle/graph-pull-worker.js +2 -0
  7. package/codex/bundle/pre-tool-use.js +78 -68
  8. package/codex/bundle/session-start-setup.js +2 -0
  9. package/codex/bundle/session-start.js +2 -0
  10. package/codex/bundle/shell/deeplake-shell.js +12 -6
  11. package/codex/bundle/skillify-worker.js +2 -0
  12. package/codex/bundle/stop.js +4 -2
  13. package/codex/bundle/wiki-worker.js +1 -1
  14. package/cursor/bundle/capture.js +4 -2
  15. package/cursor/bundle/commands/auth-login.js +2 -0
  16. package/cursor/bundle/graph-pull-worker.js +2 -0
  17. package/cursor/bundle/pre-tool-use.js +10 -2
  18. package/cursor/bundle/session-end.js +2 -2
  19. package/cursor/bundle/session-start.js +2 -0
  20. package/cursor/bundle/shell/deeplake-shell.js +12 -6
  21. package/cursor/bundle/skillify-worker.js +2 -0
  22. package/cursor/bundle/wiki-worker.js +1 -1
  23. package/hermes/bundle/capture.js +4 -2
  24. package/hermes/bundle/commands/auth-login.js +2 -0
  25. package/hermes/bundle/graph-pull-worker.js +2 -0
  26. package/hermes/bundle/pre-tool-use.js +10 -2
  27. package/hermes/bundle/session-end.js +2 -2
  28. package/hermes/bundle/session-start.js +2 -0
  29. package/hermes/bundle/shell/deeplake-shell.js +12 -6
  30. package/hermes/bundle/skillify-worker.js +2 -0
  31. package/hermes/bundle/wiki-worker.js +1 -1
  32. package/mcp/bundle/server.js +2 -0
  33. package/openclaw/dist/index.js +5 -3
  34. package/openclaw/dist/skillify-worker.js +2 -0
  35. package/openclaw/openclaw.plugin.json +1 -1
  36. package/openclaw/package.json +1 -1
  37. package/package.json +1 -1
@@ -6,18 +6,18 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Cloud-backed persistent shared memory for AI agents powered by Deeplake",
9
- "version": "0.7.70"
9
+ "version": "0.7.72"
10
10
  },
11
11
  "plugins": [
12
12
  {
13
13
  "name": "hivemind",
14
14
  "description": "Persistent shared memory powered by Deeplake — captures all session activity and provides cross-session, cross-agent memory search",
15
- "version": "0.7.70",
15
+ "version": "0.7.72",
16
16
  "source": {
17
17
  "source": "git-subdir",
18
18
  "url": "https://github.com/activeloopai/hivemind.git",
19
19
  "path": "claude-code",
20
- "sha": "b90aadd1f9d2f959a2c9800a14a4b9131bdb75d8"
20
+ "sha": "103bb69c8ecb83325c0c3e39029d22691c4f2d4a"
21
21
  },
22
22
  "homepage": "https://github.com/activeloopai/hivemind"
23
23
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "hivemind",
3
3
  "description": "Cloud-backed persistent memory powered by Deeplake — read, write, and share memory across Claude Code sessions and agents",
4
- "version": "0.7.70",
4
+ "version": "0.7.72",
5
5
  "author": {
6
6
  "name": "Activeloop",
7
7
  "url": "https://deeplake.ai"
package/bundle/cli.js CHANGED
@@ -4598,6 +4598,7 @@ var GOALS_COLUMNS = Object.freeze([
4598
4598
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
4599
4599
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
4600
4600
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
4601
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
4601
4602
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
4602
4603
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
4603
4604
  ]);
@@ -4608,6 +4609,7 @@ var KPIS_COLUMNS = Object.freeze([
4608
4609
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
4609
4610
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
4610
4611
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
4612
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
4611
4613
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
4612
4614
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
4613
4615
  ]);
@@ -11057,7 +11059,7 @@ async function goalAdd(text, agent = "manual") {
11057
11059
  const safe = sqlIdent(table);
11058
11060
  const goalId = randomUUID4();
11059
11061
  const ts = (/* @__PURE__ */ new Date()).toISOString();
11060
- await query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(cfg.userName)}', 'opened', E'${sqlStr(text)}', 1, '${sqlStr(ts)}', '${sqlStr(agent)}', '')`);
11062
+ await query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, updated_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(cfg.userName)}', 'opened', E'${sqlStr(text)}', 1, '${sqlStr(ts)}', '${sqlStr(ts)}', '${sqlStr(agent)}', '')`);
11061
11063
  process.stdout.write(`${goalId}
11062
11064
  `);
11063
11065
  }
@@ -11130,10 +11132,11 @@ async function goalProgress(goalId, status) {
11130
11132
  process.stderr.write("not logged in\n");
11131
11133
  process.exit(1);
11132
11134
  }
11133
- const { query } = loadApiOrDie(cfg.goalsTableName);
11135
+ const { api, query } = loadApiOrDie(cfg.goalsTableName);
11136
+ await api.ensureGoalsTable(cfg.goalsTableName);
11134
11137
  const safe = sqlIdent(cfg.goalsTableName);
11135
11138
  const ts = (/* @__PURE__ */ new Date()).toISOString();
11136
- await query(`UPDATE "${safe}" SET status = '${sqlStr(status)}', created_at = '${sqlStr(ts)}' WHERE goal_id = '${sqlStr(goalId)}'`);
11139
+ await query(`UPDATE "${safe}" SET status = '${sqlStr(status)}', updated_at = '${sqlStr(ts)}' WHERE goal_id = '${sqlStr(goalId)}'`);
11137
11140
  process.stdout.write(`${goalId} -> ${status}
11138
11141
  `);
11139
11142
  }
@@ -11164,7 +11167,7 @@ async function kpiAdd(args) {
11164
11167
  - current: 0
11165
11168
  - unit: ${unit}`;
11166
11169
  const ts = (/* @__PURE__ */ new Date()).toISOString();
11167
- await query(`INSERT INTO "${safe}" (id, goal_id, kpi_id, content, version, created_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(kpiId)}', E'${sqlStr(content)}', 1, '${sqlStr(ts)}', 'manual', '')`);
11170
+ await query(`INSERT INTO "${safe}" (id, goal_id, kpi_id, content, version, created_at, updated_at, agent, plugin_version) VALUES ('${randomUUID4()}', '${sqlStr(goalId)}', '${sqlStr(kpiId)}', E'${sqlStr(content)}', 1, '${sqlStr(ts)}', '${sqlStr(ts)}', 'manual', '')`);
11168
11171
  process.stdout.write(`${goalId}/${kpiId}
11169
11172
  `);
11170
11173
  }
@@ -11213,7 +11216,8 @@ async function kpiBump(goalId, kpiId, deltaStr) {
11213
11216
  process.stderr.write("not logged in\n");
11214
11217
  process.exit(1);
11215
11218
  }
11216
- const { query } = loadApiOrDie(cfg.kpisTableName);
11219
+ const { api, query } = loadApiOrDie(cfg.kpisTableName);
11220
+ await api.ensureKpisTable(cfg.kpisTableName);
11217
11221
  const safe = sqlIdent(cfg.kpisTableName);
11218
11222
  const rows = await query(`SELECT content FROM "${safe}" WHERE goal_id = '${sqlStr(goalId)}' AND kpi_id = '${sqlStr(kpiId)}' LIMIT 1`);
11219
11223
  if (rows.length === 0) {
@@ -11229,7 +11233,7 @@ async function kpiBump(goalId, kpiId, deltaStr) {
11229
11233
  process.exit(1);
11230
11234
  }
11231
11235
  const ts = (/* @__PURE__ */ new Date()).toISOString();
11232
- await query(`UPDATE "${safe}" SET content = E'${sqlStr(newContent)}', created_at = '${sqlStr(ts)}' WHERE goal_id = '${sqlStr(goalId)}' AND kpi_id = '${sqlStr(kpiId)}'`);
11236
+ await query(`UPDATE "${safe}" SET content = E'${sqlStr(newContent)}', updated_at = '${sqlStr(ts)}' WHERE goal_id = '${sqlStr(goalId)}' AND kpi_id = '${sqlStr(kpiId)}'`);
11233
11237
  process.stdout.write(`${goalId}/${kpiId} +${delta}
11234
11238
  `);
11235
11239
  }
@@ -11643,7 +11647,7 @@ async function runUpdate(opts = {}) {
11643
11647
  switch (detected.kind) {
11644
11648
  case "npm-global": {
11645
11649
  if (opts.dryRun) {
11646
- log(`(dry-run) Would run: npm install -g ${PKG_NAME}@latest`);
11650
+ log(`(dry-run) Would run: npm install -g ${PKG_NAME}@${latest}`);
11647
11651
  log(`(dry-run) Would re-run: hivemind install --skip-auth`);
11648
11652
  return 0;
11649
11653
  }
@@ -11654,10 +11658,10 @@ async function runUpdate(opts = {}) {
11654
11658
  try {
11655
11659
  log(`Upgrading via npm\u2026`);
11656
11660
  try {
11657
- spawn5("npm", ["install", "-g", `${PKG_NAME}@latest`]);
11661
+ spawn5("npm", ["install", "-g", `${PKG_NAME}@${latest}`]);
11658
11662
  } catch (e) {
11659
11663
  warn(`npm install failed: ${e.message}`);
11660
- warn(`Try running it manually: npm install -g ${PKG_NAME}@latest`);
11664
+ warn(`Try running it manually: npm install -g ${PKG_NAME}@${latest}`);
11661
11665
  return 1;
11662
11666
  }
11663
11667
  log(``);
@@ -11688,7 +11692,7 @@ async function runUpdate(opts = {}) {
11688
11692
  log(``);
11689
11693
  log(`Or install globally so future updates are one command:`);
11690
11694
  log(``);
11691
- log(` npm install -g ${PKG_NAME}@latest`);
11695
+ log(` npm install -g ${PKG_NAME}@${latest}`);
11692
11696
  return 0;
11693
11697
  }
11694
11698
  case "local-dev": {
@@ -11708,7 +11712,7 @@ async function runUpdate(opts = {}) {
11708
11712
  return 0;
11709
11713
  }
11710
11714
  warn(`Could not determine how hivemind was installed (path: ${detected.installDir}).`);
11711
- warn(`Update manually: npm install -g ${PKG_NAME}@latest`);
11715
+ warn(`Update manually: npm install -g ${PKG_NAME}@${latest}`);
11712
11716
  return 1;
11713
11717
  }
11714
11718
  }
@@ -232,6 +232,7 @@ var GOALS_COLUMNS = Object.freeze([
232
232
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
233
233
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
234
234
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
235
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
235
236
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
236
237
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
237
238
  ]);
@@ -242,6 +243,7 @@ var KPIS_COLUMNS = Object.freeze([
242
243
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
243
244
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
244
245
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
245
247
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
246
248
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
247
249
  ]);
@@ -1573,7 +1575,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
1573
1575
  import { dirname as dirname5, join as join14 } from "node:path";
1574
1576
 
1575
1577
  // dist/src/hooks/summary-state.js
1576
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync6, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync4, openSync as openSync3, closeSync as closeSync3 } from "node:fs";
1578
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, writeSync as writeSync2, mkdirSync as mkdirSync6, renameSync as renameSync4, existsSync as existsSync6, unlinkSync as unlinkSync4, openSync as openSync3, closeSync as closeSync3, statSync as statSync3 } from "node:fs";
1577
1579
  import { homedir as homedir9 } from "node:os";
1578
1580
  import { join as join10 } from "node:path";
1579
1581
  var dlog = (msg) => log("summary-state", msg);
@@ -1844,7 +1846,7 @@ Format: **entity** (type) \u2014 what was done with it, its current state>
1844
1846
  <Anything unresolved, blocked, or explicitly deferred>
1845
1847
 
1846
1848
  ## Next Steps
1847
- <The single concrete next action to resume with, as one imperative line (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). If the session reached a clean stopping point with nothing pending, write exactly: none>
1849
+ <Default to writing exactly: none. Most sessions are DONE when they end \u2014 do not invent a next step just to fill this section. Only name one when the session left GENUINELY SUBSTANTIVE, non-obvious work that a knowledgeable engineer returning later would actually need flagged. Make a real judgment: is there unfinished work truly WORTH resuming? If not, write: none. Write none when the work reached a natural stopping point, is complete, only trivial/obvious follow-ups remain, the "next step" is just continuing an open-ended exploration, or the only thing left is administrative wrap-up (committing, pushing, opening/merging a PR, deploying, monitoring CI) \u2014 treat all such wrap-up as ALREADY DONE. When a next step IS warranted, write a single concrete imperative line for the substantive work (e.g. "Wire the resume-brief Next Steps fallback and run the tests"). Administrative actions qualify ONLY when the session's core purpose itself was that release/ops task.>
1848
1850
 
1849
1851
  IMPORTANT: Be exhaustive. Extract EVERY entity, decision, and fact.
1850
1852
  PRIVACY: Never include absolute filesystem paths in the summary.
@@ -513,6 +513,7 @@ var GOALS_COLUMNS = Object.freeze([
513
513
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
514
514
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
515
515
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
516
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
516
517
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
517
518
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
518
519
  ]);
@@ -523,6 +524,7 @@ var KPIS_COLUMNS = Object.freeze([
523
524
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
524
525
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
525
526
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
527
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
526
528
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
527
529
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
528
530
  ]);
@@ -222,6 +222,7 @@ var GOALS_COLUMNS = Object.freeze([
222
222
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
223
223
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
224
224
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
225
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
225
226
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
226
227
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
227
228
  ]);
@@ -232,6 +233,7 @@ var KPIS_COLUMNS = Object.freeze([
232
233
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
233
234
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
234
235
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
236
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
235
237
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
236
238
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
237
239
  ]);
@@ -52,12 +52,6 @@ var init_index_marker_store = __esm({
52
52
  }
53
53
  });
54
54
 
55
- // dist/src/hooks/codex/pre-tool-use.js
56
- import { execFileSync } from "node:child_process";
57
- import { existsSync as existsSync5 } from "node:fs";
58
- import { join as join12, dirname as dirname3 } from "node:path";
59
- import { fileURLToPath as fileURLToPath3 } from "node:url";
60
-
61
55
  // dist/src/utils/stdin.js
62
56
  function readStdin() {
63
57
  return new Promise((resolve3, reject) => {
@@ -238,6 +232,7 @@ var GOALS_COLUMNS = Object.freeze([
238
232
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
239
233
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
240
234
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
235
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
241
236
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
242
237
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
243
238
  ]);
@@ -248,6 +243,7 @@ var KPIS_COLUMNS = Object.freeze([
248
243
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
249
244
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
250
245
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
246
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
251
247
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
252
248
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
253
249
  ]);
@@ -3040,12 +3036,13 @@ var SAFE_BUILTINS = /* @__PURE__ */ new Set([
3040
3036
  "du",
3041
3037
  "tree",
3042
3038
  "file",
3039
+ // sed and awk removed: sed supports `-e '1e <cmd>'` (execute shell command)
3040
+ // and awk supports `system()` / `|` pipelines — both enable arbitrary code
3041
+ // execution through the just-bash fallback.
3043
3042
  "grep",
3044
3043
  "egrep",
3045
3044
  "fgrep",
3046
3045
  "rg",
3047
- "sed",
3048
- "awk",
3049
3046
  "cut",
3050
3047
  "tr",
3051
3048
  "sort",
@@ -3066,15 +3063,18 @@ var SAFE_BUILTINS = /* @__PURE__ */ new Set([
3066
3063
  "diff",
3067
3064
  "strings",
3068
3065
  "split",
3066
+ // xargs removed: it executes its input as a child command (`… | xargs curl`).
3067
+ // `find` stays because the VFS serves `find -name`, but isSafe() rejects the
3068
+ // command-dispatching `-exec/-execdir/-ok/-okdir` primaries below.
3069
3069
  "find",
3070
- "xargs",
3071
3070
  "which",
3072
3071
  "jq",
3073
3072
  "yq",
3074
3073
  "xan",
3075
3074
  "base64",
3076
3075
  "od",
3077
- "tar",
3076
+ // tar removed: --to-command=<cmd> executes an arbitrary program per entry.
3077
+ // env removed: `env <cmd>` runs an arbitrary program.
3078
3078
  "gzip",
3079
3079
  "gunzip",
3080
3080
  "zcat",
@@ -3088,16 +3088,15 @@ var SAFE_BUILTINS = /* @__PURE__ */ new Set([
3088
3088
  "cd",
3089
3089
  "basename",
3090
3090
  "dirname",
3091
- "env",
3092
3091
  "printenv",
3093
3092
  "hostname",
3094
3093
  "whoami",
3094
+ // timeout and time removed: both are wrappers that run an arbitrary child
3095
+ // command (`timeout 1 curl …`, `time curl …`).
3095
3096
  "date",
3096
3097
  "seq",
3097
3098
  "expr",
3098
3099
  "sleep",
3099
- "timeout",
3100
- "time",
3101
3100
  "true",
3102
3101
  "false",
3103
3102
  "test",
@@ -3105,22 +3104,42 @@ var SAFE_BUILTINS = /* @__PURE__ */ new Set([
3105
3104
  "unalias",
3106
3105
  "history",
3107
3106
  "help",
3108
- "clear",
3109
- "for",
3110
- "while",
3111
- "do",
3112
- "done",
3113
- "if",
3114
- "then",
3115
- "else",
3116
- "fi",
3117
- "case",
3118
- "esac"
3107
+ "clear"
3108
+ // Shell control keywords removed: as a stage's first token they let a child
3109
+ // command ride in as a later token (`if true; then curl …; fi` splits into a
3110
+ // `then curl …` stage whose leading `then` would otherwise pass). No VFS
3111
+ // handler emulates control flow, so dropping them only sends such commands to
3112
+ // the guidance/deny path — they never reach a real shell.
3119
3113
  ]);
3114
+ function stripHeredocBodies(cmd) {
3115
+ if (!cmd.includes("<<"))
3116
+ return cmd;
3117
+ const lines = cmd.split("\n");
3118
+ const kept = [];
3119
+ for (let i = 0; i < lines.length; i++) {
3120
+ const line = lines[i];
3121
+ kept.push(line);
3122
+ const heredoc = line.match(/<<-?\s*(['"])([A-Za-z_]\w*)\1/);
3123
+ if (!heredoc)
3124
+ continue;
3125
+ const delimiter = heredoc[2];
3126
+ const stripTabs = line.includes("<<-");
3127
+ while (i + 1 < lines.length) {
3128
+ const body = lines[++i];
3129
+ const probe = stripTabs ? body.replace(/^\t+/, "") : body;
3130
+ if (probe === delimiter)
3131
+ break;
3132
+ }
3133
+ }
3134
+ return kept.join("\n");
3135
+ }
3120
3136
  function isSafe(cmd) {
3121
- if (/\$\(|`|<\(/.test(cmd))
3137
+ const validated = stripHeredocBodies(cmd);
3138
+ if (/\$\(|`|<\(|\$'/.test(validated))
3139
+ return false;
3140
+ const stripped = validated.replace(/'[^']*'/g, "''").replace(/"[^"]*"/g, '""');
3141
+ if (/(?:^|\s)-(?:exec|execdir|ok|okdir)\b/.test(stripped))
3122
3142
  return false;
3123
- const stripped = cmd.replace(/'[^']*'/g, "''").replace(/"[^"]*"/g, '""');
3124
3143
  const stages = stripped.split(/\||;|&&|\|\||\n/);
3125
3144
  for (const stage of stages) {
3126
3145
  const firstToken = stage.trim().split(/\s+/)[0] ?? "";
@@ -3129,32 +3148,23 @@ function isSafe(cmd) {
3129
3148
  }
3130
3149
  return true;
3131
3150
  }
3151
+ function escapeRe(s) {
3152
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3153
+ }
3154
+ var MEMORY_BOUNDARY = "(?![A-Za-z0-9._-])";
3155
+ var MEMORY_PREFIX_RE = new RegExp("(?:" + [MEMORY_PATH, TILDE_PATH, HOME_VAR_PATH].map(escapeRe).join("|") + ")" + MEMORY_BOUNDARY);
3132
3156
  function touchesMemory(p) {
3133
- return p.includes(MEMORY_PATH) || p.includes(TILDE_PATH) || p.includes(HOME_VAR_PATH);
3157
+ return MEMORY_PREFIX_RE.test(p);
3134
3158
  }
3135
3159
  function rewritePaths(cmd) {
3136
- return cmd.replace(new RegExp(MEMORY_PATH.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "/?", "g"), "/").replace(/~\/.deeplake\/memory\/?/g, "/").replace(/\$HOME\/.deeplake\/memory\/?/g, "/").replace(/"\$HOME\/.deeplake\/memory\/?"/g, '"/"');
3160
+ const tail = "(?:\\/|" + MEMORY_BOUNDARY + ")";
3161
+ return cmd.replace(new RegExp(escapeRe(MEMORY_PATH) + tail, "g"), "/").replace(new RegExp(escapeRe(TILDE_PATH) + tail, "g"), "/").replace(new RegExp('"' + escapeRe(HOME_VAR_PATH) + tail + '"', "g"), '"/"').replace(new RegExp(escapeRe(HOME_VAR_PATH) + tail, "g"), "/");
3137
3162
  }
3138
3163
 
3139
3164
  // dist/src/hooks/codex/pre-tool-use.js
3140
3165
  var log6 = (msg) => log("codex-pre", msg);
3141
- var __bundleDir = dirname3(fileURLToPath3(import.meta.url));
3142
- var SHELL_BUNDLE = existsSync5(join12(__bundleDir, "shell", "deeplake-shell.js")) ? join12(__bundleDir, "shell", "deeplake-shell.js") : join12(__bundleDir, "..", "shell", "deeplake-shell.js");
3143
3166
  function buildUnsupportedGuidance() {
3144
- return "This command is not supported for ~/.deeplake/memory/ operations. Only bash builtins are available: cat, ls, grep, echo, jq, head, tail, sed, awk, wc, sort, find, etc. Do NOT use python, python3, node, curl, or other interpreters. Rewrite your command using only bash tools and retry.";
3145
- }
3146
- function runVirtualShell(cmd, shellBundle = SHELL_BUNDLE, logFn = log6) {
3147
- try {
3148
- return execFileSync("node", [shellBundle, "-c", cmd], {
3149
- encoding: "utf-8",
3150
- timeout: 1e4,
3151
- env: { ...process.env },
3152
- stdio: ["pipe", "pipe", "pipe"]
3153
- }).trim();
3154
- } catch (e) {
3155
- logFn(`virtual shell failed: ${e.message}`);
3156
- return "";
3157
- }
3167
+ return "This command is not supported for ~/.deeplake/memory/ operations. Only bash builtins are available: cat, ls, grep, echo, jq, head, tail, wc, sort, find, etc. Do NOT use python, python3, node, curl, or other interpreters. Rewrite your command using only bash tools and retry.";
3158
3168
  }
3159
3169
  function buildIndexContent(rows) {
3160
3170
  const lines = ["# Memory Index", "", `${rows.length} sessions:`, ""];
@@ -3168,18 +3178,17 @@ function buildIndexContent(rows) {
3168
3178
  return lines.join("\n");
3169
3179
  }
3170
3180
  async function processCodexPreToolUse(input, deps = {}) {
3171
- const { config = loadConfig(), createApi = (table, activeConfig) => new DeeplakeApi(activeConfig.token, activeConfig.apiUrl, activeConfig.orgId, activeConfig.workspaceId, table), executeCompiledBashCommandFn = executeCompiledBashCommand, readVirtualPathContentsFn = readVirtualPathContents, readVirtualPathContentFn = readVirtualPathContent, listVirtualPathRowsFn = listVirtualPathRows, findVirtualPathsFn = findVirtualPaths, handleGrepDirectFn = handleGrepDirect, readCachedIndexContentFn = readCachedIndexContent, writeCachedIndexContentFn = writeCachedIndexContent, runVirtualShellFn = runVirtualShell, shellBundle = SHELL_BUNDLE, logFn = log6 } = deps;
3181
+ const { config = loadConfig(), createApi = (table, activeConfig) => new DeeplakeApi(activeConfig.token, activeConfig.apiUrl, activeConfig.orgId, activeConfig.workspaceId, table), executeCompiledBashCommandFn = executeCompiledBashCommand, readVirtualPathContentsFn = readVirtualPathContents, readVirtualPathContentFn = readVirtualPathContent, listVirtualPathRowsFn = listVirtualPathRows, findVirtualPathsFn = findVirtualPaths, handleGrepDirectFn = handleGrepDirect, readCachedIndexContentFn = readCachedIndexContent, writeCachedIndexContentFn = writeCachedIndexContent, logFn = log6 } = deps;
3172
3182
  const cmd = input.tool_input?.command ?? "";
3173
3183
  logFn(`hook fired: cmd=${cmd}`);
3174
3184
  if (!touchesMemory(cmd))
3175
3185
  return { action: "pass" };
3176
3186
  const rewritten = rewritePaths(cmd);
3177
3187
  if (!isSafe(rewritten)) {
3178
- const guidance = buildUnsupportedGuidance();
3179
- logFn(`unsupported command, returning guidance: ${rewritten}`);
3188
+ logFn(`unsupported command, blocking with guidance: ${rewritten}`);
3180
3189
  return {
3181
- action: "guide",
3182
- output: guidance,
3190
+ action: "block",
3191
+ output: buildUnsupportedGuidance(),
3183
3192
  rewrittenCommand: rewritten
3184
3193
  };
3185
3194
  }
@@ -3189,22 +3198,22 @@ async function processCodexPreToolUse(input, deps = {}) {
3189
3198
  const api = createApi(table, config);
3190
3199
  const readVirtualPathContentsWithCache = async (cachePaths) => {
3191
3200
  const uniquePaths = [...new Set(cachePaths)];
3192
- const result2 = new Map(uniquePaths.map((path) => [path, null]));
3201
+ const result = new Map(uniquePaths.map((path) => [path, null]));
3193
3202
  const cachedIndex = uniquePaths.includes("/index.md") ? readCachedIndexContentFn(input.session_id) : null;
3194
3203
  const remainingPaths = cachedIndex === null ? uniquePaths : uniquePaths.filter((path) => path !== "/index.md");
3195
3204
  if (cachedIndex !== null) {
3196
- result2.set("/index.md", cachedIndex);
3205
+ result.set("/index.md", cachedIndex);
3197
3206
  }
3198
3207
  if (remainingPaths.length > 0) {
3199
3208
  const fetched = await readVirtualPathContentsFn(api, table, sessionsTable, remainingPaths);
3200
3209
  for (const [path, content] of fetched)
3201
- result2.set(path, content);
3210
+ result.set(path, content);
3202
3211
  }
3203
- const fetchedIndex = result2.get("/index.md");
3212
+ const fetchedIndex = result.get("/index.md");
3204
3213
  if (typeof fetchedIndex === "string") {
3205
3214
  writeCachedIndexContentFn(input.session_id, fetchedIndex);
3206
3215
  }
3207
- return result2;
3216
+ return result;
3208
3217
  };
3209
3218
  try {
3210
3219
  const compiled = await executeCompiledBashCommandFn(api, table, sessionsTable, rewritten, {
@@ -3282,6 +3291,8 @@ async function processCodexPreToolUse(input, deps = {}) {
3282
3291
  }
3283
3292
  return { action: "block", output: content, rewrittenCommand: rewritten };
3284
3293
  }
3294
+ logFn(`virtual path not found: ${virtualPath}`);
3295
+ return { action: "block", output: `${virtualPath}: No such file or directory`, rewrittenCommand: rewritten };
3285
3296
  }
3286
3297
  const lsMatch = rewritten.match(/^ls\s+(?:-[a-zA-Z]+\s+)*(\S+)?\s*$/);
3287
3298
  if (lsMatch) {
@@ -3327,38 +3338,38 @@ async function processCodexPreToolUse(input, deps = {}) {
3327
3338
  rewrittenCommand: rewritten
3328
3339
  };
3329
3340
  }
3330
- const findMatch = rewritten.match(/^find\s+(\S+)\s+(?:-type\s+\S+\s+)?-name\s+'([^']+)'/);
3341
+ const findMatch = rewritten.match(/^find\s+(\S+)\s+-name\s+(?:'([^']+)'|"([^"]+)"|([^\s|]+))\s*(?:\|\s*wc\s+-l)?\s*$/);
3331
3342
  if (findMatch) {
3332
3343
  const dir = findMatch[1].replace(/\/+$/, "") || "/";
3333
- const namePattern = sqlLike(findMatch[2]).replace(/\*/g, "%").replace(/\?/g, "_");
3334
- logFn(`direct find: ${dir} -name '${findMatch[2]}'`);
3344
+ const rawPattern = findMatch[2] ?? findMatch[3] ?? findMatch[4] ?? "";
3345
+ const namePattern = sqlLike(rawPattern).replace(/\*/g, "%").replace(/\?/g, "_");
3346
+ logFn(`direct find: ${dir} -name '${rawPattern}'`);
3335
3347
  const paths = await findVirtualPathsFn(api, table, sessionsTable, dir, namePattern);
3336
- let result2 = paths.join("\n") || "";
3348
+ let result = paths.join("\n") || "";
3337
3349
  if (/\|\s*wc\s+-l\s*$/.test(rewritten))
3338
- result2 = String(paths.length);
3350
+ result = String(paths.length);
3339
3351
  return {
3340
3352
  action: "block",
3341
- output: result2 || "(no matches)",
3353
+ output: result || "(no matches)",
3342
3354
  rewrittenCommand: rewritten
3343
3355
  };
3344
3356
  }
3345
3357
  const grepParams = parseBashGrep(rewritten);
3346
3358
  if (grepParams) {
3347
3359
  logFn(`direct grep: pattern=${grepParams.pattern} path=${grepParams.targetPath}`);
3348
- const result2 = await handleGrepDirectFn(api, table, sessionsTable, grepParams);
3349
- if (result2 !== null) {
3350
- return { action: "block", output: result2, rewrittenCommand: rewritten };
3360
+ const result = await handleGrepDirectFn(api, table, sessionsTable, grepParams);
3361
+ if (result !== null) {
3362
+ return { action: "block", output: result, rewrittenCommand: rewritten };
3351
3363
  }
3352
3364
  }
3353
3365
  } catch (e) {
3354
- logFn(`direct query failed, falling back to shell: ${e.message}`);
3366
+ logFn(`direct query failed: ${e.message}`);
3355
3367
  }
3356
3368
  }
3357
- logFn(`intercepted \u2192 running via virtual shell: ${rewritten}`);
3358
- const result = runVirtualShellFn(rewritten, shellBundle, logFn);
3369
+ logFn(`unroutable memory command, blocking with guidance: ${rewritten}`);
3359
3370
  return {
3360
3371
  action: "block",
3361
- output: result || "[Deeplake Memory] Command returned empty or the file does not exist in cloud storage.",
3372
+ output: buildUnsupportedGuidance(),
3362
3373
  rewrittenCommand: rewritten
3363
3374
  };
3364
3375
  }
@@ -3387,6 +3398,5 @@ export {
3387
3398
  isSafe,
3388
3399
  processCodexPreToolUse,
3389
3400
  rewritePaths,
3390
- runVirtualShell,
3391
3401
  touchesMemory
3392
3402
  };
@@ -251,6 +251,7 @@ var GOALS_COLUMNS = Object.freeze([
251
251
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
252
252
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
253
253
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
254
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
254
255
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
255
256
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
256
257
  ]);
@@ -261,6 +262,7 @@ var KPIS_COLUMNS = Object.freeze([
261
262
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
262
263
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
263
264
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
265
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
264
266
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
265
267
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
266
268
  ]);
@@ -490,6 +490,7 @@ var GOALS_COLUMNS = Object.freeze([
490
490
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
491
491
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
492
492
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
493
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
493
494
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
494
495
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
495
496
  ]);
@@ -500,6 +501,7 @@ var KPIS_COLUMNS = Object.freeze([
500
501
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
501
502
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
502
503
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
504
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
503
505
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
504
506
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
505
507
  ]);
@@ -66926,6 +66926,7 @@ var GOALS_COLUMNS = Object.freeze([
66926
66926
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
66927
66927
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
66928
66928
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
66929
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
66929
66930
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
66930
66931
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
66931
66932
  ]);
@@ -66936,6 +66937,7 @@ var KPIS_COLUMNS = Object.freeze([
66936
66937
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
66937
66938
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
66938
66939
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
66940
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
66939
66941
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
66940
66942
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
66941
66943
  ]);
@@ -69530,13 +69532,15 @@ var DeeplakeFs = class _DeeplakeFs {
69530
69532
  throw new Error("goalsTable not configured");
69531
69533
  const parts = decomposeGoalPath(r10.path);
69532
69534
  const safe = this.goalsTable;
69533
- const ts3 = r10.lastUpdateDate ?? r10.creationDate ?? (/* @__PURE__ */ new Date()).toISOString();
69535
+ const now = (/* @__PURE__ */ new Date()).toISOString();
69536
+ const createdAt = r10.creationDate ?? now;
69537
+ const updatedAt = r10.lastUpdateDate ?? createdAt;
69534
69538
  const existing = await this.client.query(`SELECT id FROM "${safe}" WHERE goal_id = '${sqlStr(parts.goal_id)}' LIMIT 1`);
69535
69539
  if (existing.length > 0) {
69536
- await this.client.query(`UPDATE "${safe}" SET owner = '${sqlStr(parts.owner)}', status = '${sqlStr(parts.status)}', content = E'${sqlStr(r10.contentText)}', created_at = '${sqlStr(ts3)}' WHERE goal_id = '${sqlStr(parts.goal_id)}'`);
69540
+ await this.client.query(`UPDATE "${safe}" SET owner = '${sqlStr(parts.owner)}', status = '${sqlStr(parts.status)}', content = E'${sqlStr(r10.contentText)}', updated_at = '${sqlStr(updatedAt)}' WHERE goal_id = '${sqlStr(parts.goal_id)}'`);
69537
69541
  } else {
69538
69542
  const id = randomUUID2();
69539
- await this.client.query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, agent, plugin_version) VALUES ('${id}', '${sqlStr(parts.goal_id)}', '${sqlStr(parts.owner)}', '${sqlStr(parts.status)}', E'${sqlStr(r10.contentText)}', 1, '${sqlStr(ts3)}', 'manual', '')`);
69543
+ await this.client.query(`INSERT INTO "${safe}" (id, goal_id, owner, status, content, version, created_at, updated_at, agent, plugin_version) VALUES ('${id}', '${sqlStr(parts.goal_id)}', '${sqlStr(parts.owner)}', '${sqlStr(parts.status)}', E'${sqlStr(r10.contentText)}', 1, '${sqlStr(createdAt)}', '${sqlStr(updatedAt)}', 'manual', '')`);
69540
69544
  }
69541
69545
  this.flushed.add(r10.path);
69542
69546
  }
@@ -69551,13 +69555,15 @@ var DeeplakeFs = class _DeeplakeFs {
69551
69555
  throw new Error("kpisTable not configured");
69552
69556
  const parts = decomposeKpiPath(r10.path);
69553
69557
  const safe = this.kpisTable;
69554
- const ts3 = r10.lastUpdateDate ?? r10.creationDate ?? (/* @__PURE__ */ new Date()).toISOString();
69558
+ const now = (/* @__PURE__ */ new Date()).toISOString();
69559
+ const createdAt = r10.creationDate ?? now;
69560
+ const updatedAt = r10.lastUpdateDate ?? createdAt;
69555
69561
  const existing = await this.client.query(`SELECT id FROM "${safe}" WHERE goal_id = '${sqlStr(parts.goal_id)}' AND kpi_id = '${sqlStr(parts.kpi_id)}' LIMIT 1`);
69556
69562
  if (existing.length > 0) {
69557
- await this.client.query(`UPDATE "${safe}" SET content = E'${sqlStr(r10.contentText)}', created_at = '${sqlStr(ts3)}' WHERE goal_id = '${sqlStr(parts.goal_id)}' AND kpi_id = '${sqlStr(parts.kpi_id)}'`);
69563
+ await this.client.query(`UPDATE "${safe}" SET content = E'${sqlStr(r10.contentText)}', updated_at = '${sqlStr(updatedAt)}' WHERE goal_id = '${sqlStr(parts.goal_id)}' AND kpi_id = '${sqlStr(parts.kpi_id)}'`);
69558
69564
  } else {
69559
69565
  const id = randomUUID2();
69560
- await this.client.query(`INSERT INTO "${safe}" (id, goal_id, kpi_id, content, version, created_at, agent, plugin_version) VALUES ('${id}', '${sqlStr(parts.goal_id)}', '${sqlStr(parts.kpi_id)}', E'${sqlStr(r10.contentText)}', 1, '${sqlStr(ts3)}', 'manual', '')`);
69566
+ await this.client.query(`INSERT INTO "${safe}" (id, goal_id, kpi_id, content, version, created_at, updated_at, agent, plugin_version) VALUES ('${id}', '${sqlStr(parts.goal_id)}', '${sqlStr(parts.kpi_id)}', E'${sqlStr(r10.contentText)}', 1, '${sqlStr(createdAt)}', '${sqlStr(updatedAt)}', 'manual', '')`);
69561
69567
  }
69562
69568
  this.flushed.add(r10.path);
69563
69569
  }
@@ -398,6 +398,7 @@ var GOALS_COLUMNS = Object.freeze([
398
398
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
399
399
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
400
400
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
401
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
401
402
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
402
403
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
403
404
  ]);
@@ -408,6 +409,7 @@ var KPIS_COLUMNS = Object.freeze([
408
409
  { name: "content", sql: "TEXT NOT NULL DEFAULT ''" },
409
410
  { name: "version", sql: "BIGINT NOT NULL DEFAULT 1" },
410
411
  { name: "created_at", sql: "TEXT NOT NULL DEFAULT ''" },
412
+ { name: "updated_at", sql: "TEXT NOT NULL DEFAULT ''" },
411
413
  { name: "agent", sql: "TEXT NOT NULL DEFAULT 'manual'" },
412
414
  { name: "plugin_version", sql: "TEXT NOT NULL DEFAULT ''" }
413
415
  ]);