Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 8 additions & 43 deletions claude-code/bundle/pre-tool-use.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

// dist/src/hooks/pre-tool-use.js
import { existsSync as existsSync2 } from "node:fs";
import { execFileSync } from "node:child_process";
import { join as join3 } from "node:path";
import { homedir as homedir3 } from "node:os";
import { fileURLToPath } from "node:url";
Expand Down Expand Up @@ -442,17 +441,12 @@ function getShellCommand(toolName, toolInput) {
const cmd = toolInput.command;
if (!cmd || !touchesMemory(cmd))
break;
if (/\bdeeplake\s+(mount|login|unmount|status)\b/.test(cmd) || cmd.includes("deeplake.ai/install"))
break;
{
const rewritten = rewritePaths(cmd);
if (!isSafe(rewritten)) {
log3(`unsafe command blocked: ${rewritten}`);
return null;
}
return rewritten;
const rewritten = rewritePaths(cmd);
if (!isSafe(rewritten)) {
log3(`unsafe command blocked: ${rewritten}`);
return null;
}
break;
return rewritten;
}
case "Glob": {
const p = toolInput.path;
Expand All @@ -469,43 +463,14 @@ async function main() {
log3(`hook fired: tool=${input.tool_name} input=${JSON.stringify(input.tool_input)}`);
const cmd = input.tool_input.command ?? "";
const shellCmd = getShellCommand(input.tool_name, input.tool_input);
if (!shellCmd && touchesMemory(cmd) && (/\bdeeplake\s+(mount|login|unmount|status)\b/.test(cmd) || cmd.includes("deeplake.ai/install"))) {
log3(`deeplake CLI command \u2014 passing through to real bash`);
return;
}
if (!shellCmd && touchesMemory(cmd)) {
let cliInstalled = false;
try {
execFileSync("which", ["deeplake"], { stdio: "ignore", timeout: 2e3 });
cliInstalled = true;
} catch {
const paths = ["/usr/local/bin/deeplake", join3(homedir3(), ".local", "bin", "deeplake"), join3(homedir3(), ".deeplake", "bin", "deeplake")];
cliInstalled = paths.some((p) => existsSync2(p));
}
if (cliInstalled) {
const mountActive = existsSync2(join3(MEMORY_PATH, ".deeplake"));
if (mountActive) {
log3(`unsafe, CLI installed + mounted \u2014 passing through to real bash`);
return;
}
log3(`unsafe, CLI installed but not mounted \u2192 suggesting mount`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "The Deeplake CLI is installed but the memory filesystem is not mounted.",
additionalContext: "Ask the user: 'The Deeplake memory filesystem needs to be mounted. Shall I mount it?' If they agree, run: deeplake mount ~/.deeplake/memory \u2014 then retry the original command. If mount fails, report the error and stop."
}
}));
return;
}
log3(`unsafe, CLI not installed \u2192 suggesting install`);
log3(`unsafe command denied: ${cmd.slice(0, 100)}`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "This command requires the Deeplake CLI with FUSE mount support.",
additionalContext: "Ask the user: 'This command needs the Deeplake CLI. Shall I install it?' If they agree, run: curl -fsSL https://deeplake.ai/install.sh | bash && deeplake mount ~/.deeplake/memory \u2014 then retry the original command. If they decline, rewrite using safe builtins (cat, grep, jq, head, tail). If install fails (FUSE not supported, Windows, permission error), report the error and stop."
permissionDecisionReason: "This command uses tools not supported by the virtual filesystem.",
additionalContext: "Rewrite using safe builtins: cat, ls, grep, jq, head, tail, sort, wc, find, sed, awk. These work natively with Hivemind memory."
}
}));
return;
Expand Down
59 changes: 9 additions & 50 deletions src/hooks/pre-tool-use.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env node

import { appendFileSync, existsSync } from "node:fs";
import { execFileSync } from "node:child_process";
import { join } from "node:path";
import { homedir } from "node:os";
import { fileURLToPath } from "node:url";
Expand Down Expand Up @@ -106,17 +105,12 @@ function getShellCommand(toolName: string, toolInput: Record<string, unknown>):
case "Bash": {
const cmd = toolInput.command as string | undefined;
if (!cmd || !touchesMemory(cmd)) break;
// Let deeplake CLI commands pass through to real bash (install, mount, login, etc.)
if (/\bdeeplake\s+(mount|login|unmount|status)\b/.test(cmd) || cmd.includes("deeplake.ai/install")) break;
{
const rewritten = rewritePaths(cmd);
if (!isSafe(rewritten)) {
log(`unsafe command blocked: ${rewritten}`);
return null;
}
return rewritten;
const rewritten = rewritePaths(cmd);
if (!isSafe(rewritten)) {
log(`unsafe command blocked: ${rewritten}`);
return null;
}
break;
return rewritten;
}
case "Glob": {
const p = toolInput.path as string | undefined;
Expand All @@ -136,50 +130,15 @@ async function main(): Promise<void> {
const cmd = (input.tool_input.command as string) ?? "";
const shellCmd = getShellCommand(input.tool_name, input.tool_input);

// Let deeplake CLI commands (install, mount, login) pass through to real bash
if (!shellCmd && touchesMemory(cmd) && (/\bdeeplake\s+(mount|login|unmount|status)\b/.test(cmd) || cmd.includes("deeplake.ai/install"))) {
log(`deeplake CLI command — passing through to real bash`);
return;
}

if (!shellCmd && touchesMemory(cmd)) {
// Check if deeplake CLI is installed — if yes, let it run on real FUSE mount
let cliInstalled = false;
try {
execFileSync("which", ["deeplake"], { stdio: "ignore", timeout: 2000 });
cliInstalled = true;
} catch {
// Also check common install paths
const paths = ["/usr/local/bin/deeplake", join(homedir(), ".local", "bin", "deeplake"), join(homedir(), ".deeplake", "bin", "deeplake")];
cliInstalled = paths.some(p => existsSync(p));
}

if (cliInstalled) {
// Check if FUSE mount is active
const mountActive = existsSync(join(MEMORY_PATH, ".deeplake"));
if (mountActive) {
log(`unsafe, CLI installed + mounted — passing through to real bash`);
return;
}
log(`unsafe, CLI installed but not mounted → suggesting mount`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "The Deeplake CLI is installed but the memory filesystem is not mounted.",
additionalContext: "Ask the user: 'The Deeplake memory filesystem needs to be mounted. Shall I mount it?' If they agree, run: deeplake mount ~/.deeplake/memory — then retry the original command. If mount fails, report the error and stop.",
},
}));
return;
}

log(`unsafe, CLI not installed → suggesting install`);
// Unsafe command targeting memory — deny and suggest safe alternatives
log(`unsafe command denied: ${cmd.slice(0, 100)}`);
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "This command requires the Deeplake CLI with FUSE mount support.",
additionalContext: "Ask the user: 'This command needs the Deeplake CLI. Shall I install it?' If they agree, run: curl -fsSL https://deeplake.ai/install.sh | bash && deeplake mount ~/.deeplake/memory — then retry the original command. If they decline, rewrite using safe builtins (cat, grep, jq, head, tail). If install fails (FUSE not supported, Windows, permission error), report the error and stop.",
permissionDecisionReason: "This command uses tools not supported by the virtual filesystem.",
additionalContext: "Rewrite using safe builtins: cat, ls, grep, jq, head, tail, sort, wc, find, sed, awk. These work natively with Hivemind memory.",
},
}));
return;
Expand Down
Loading