offhands 0.1.13 → 0.1.15

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 (2) hide show
  1. package/dist/daemon.mjs +49 -37
  2. package/package.json +4 -1
package/dist/daemon.mjs CHANGED
@@ -4959,6 +4959,52 @@ var AsyncEventQueue = class {
4959
4959
 
4960
4960
  // ../daemon/src/runners/claude-code.ts
4961
4961
  var APPROVAL_MCP_PATH = join(dirname(fileURLToPath(import.meta.url)), "..", "approval-mcp.mjs");
4962
+ var CLAUDE_PREALLOWED_OFFHAND_TOOLS = [
4963
+ "mcp__offhand__offhand_status_update",
4964
+ "mcp__offhand__offhand_context",
4965
+ "mcp__offhand__offhand_send_file"
4966
+ ];
4967
+ function buildClaudeArgs(run, approvalUrl2) {
4968
+ const args2 = ["-p", run.prompt, "--output-format", "stream-json", "--verbose", "--include-partial-messages"];
4969
+ if (run.model) args2.push("--model", run.model);
4970
+ if (run.resumeConversationId) args2.push("--resume", run.resumeConversationId);
4971
+ const mode = run.permissionMode ?? "guarded";
4972
+ if (mode === "bypass") {
4973
+ args2.push("--permission-mode", "bypassPermissions");
4974
+ } else if (approvalUrl2) {
4975
+ if (mode === "plan") args2.push("--permission-mode", "plan");
4976
+ else if (mode === "acceptEdits") args2.push("--permission-mode", "acceptEdits");
4977
+ const mcpConfig = {
4978
+ mcpServers: {
4979
+ offhand: {
4980
+ command: process.execPath,
4981
+ args: [APPROVAL_MCP_PATH],
4982
+ // OFFHAND_STATUS_URL is derived from approvalUrl rather than a
4983
+ // second constructor param — same daemon, same port, one fewer
4984
+ // thing to keep in sync as approvalUrl already carries the
4985
+ // host:port everything else here needs.
4986
+ env: {
4987
+ OFFHAND_APPROVAL_URL: approvalUrl2,
4988
+ OFFHAND_STATUS_URL: approvalUrl2.replace(/\/approval$/, "/status"),
4989
+ OFFHAND_SESSION_ID: run.sessionId
4990
+ }
4991
+ }
4992
+ }
4993
+ };
4994
+ args2.push(
4995
+ "--mcp-config",
4996
+ JSON.stringify(mcpConfig),
4997
+ "--strict-mcp-config",
4998
+ "--permission-prompt-tool",
4999
+ "mcp__offhand__approval_prompt",
5000
+ "--allowedTools",
5001
+ CLAUDE_PREALLOWED_OFFHAND_TOOLS.join(",")
5002
+ );
5003
+ } else {
5004
+ args2.push("--permission-mode", "acceptEdits");
5005
+ }
5006
+ return args2;
5007
+ }
4962
5008
  var ClaudeCodeRunner = class {
4963
5009
  constructor(broker2, approvalUrl2) {
4964
5010
  this.broker = broker2;
@@ -5012,42 +5058,7 @@ var ClaudeCodeRunner = class {
5012
5058
  }
5013
5059
  };
5014
5060
  const detachBroker = this.broker?.attach((ev) => queue.push(ev));
5015
- const args2 = ["-p", run.prompt, "--output-format", "stream-json", "--verbose", "--include-partial-messages"];
5016
- if (run.model) args2.push("--model", run.model);
5017
- if (run.resumeConversationId) args2.push("--resume", run.resumeConversationId);
5018
- const mode = run.permissionMode ?? "guarded";
5019
- if (mode === "bypass") {
5020
- args2.push("--permission-mode", "bypassPermissions");
5021
- } else if (this.broker && this.approvalUrl) {
5022
- if (mode === "plan") args2.push("--permission-mode", "plan");
5023
- else if (mode === "acceptEdits") args2.push("--permission-mode", "acceptEdits");
5024
- const mcpConfig = {
5025
- mcpServers: {
5026
- offhand: {
5027
- command: process.execPath,
5028
- args: [APPROVAL_MCP_PATH],
5029
- // OFFHAND_STATUS_URL is derived from approvalUrl rather than a
5030
- // second constructor param — same daemon, same port, one fewer
5031
- // thing to keep in sync as this.approvalUrl already carries the
5032
- // host:port everything else here needs.
5033
- env: {
5034
- OFFHAND_APPROVAL_URL: this.approvalUrl,
5035
- OFFHAND_STATUS_URL: this.approvalUrl.replace(/\/approval$/, "/status"),
5036
- OFFHAND_SESSION_ID: run.sessionId
5037
- }
5038
- }
5039
- }
5040
- };
5041
- args2.push(
5042
- "--mcp-config",
5043
- JSON.stringify(mcpConfig),
5044
- "--strict-mcp-config",
5045
- "--permission-prompt-tool",
5046
- "mcp__offhand__approval_prompt"
5047
- );
5048
- } else {
5049
- args2.push("--permission-mode", "acceptEdits");
5050
- }
5061
+ const args2 = buildClaudeArgs(run, this.broker && this.approvalUrl ? this.approvalUrl : void 0);
5051
5062
  const thinking = { low: 0, medium: 8e3, high: 16e3, max: 31999 };
5052
5063
  const env = run.effort !== void 0 ? { ...process.env, MAX_THINKING_TOKENS: String(thinking[run.effort]) } : process.env;
5053
5064
  try {
@@ -43782,7 +43793,8 @@ var ApprovalBroker = class {
43782
43793
  }
43783
43794
  };
43784
43795
  function classifyRisk(toolName, input) {
43785
- if (toolName === "offhand_send_file") return "high";
43796
+ const bareName = toolName.replace(/^mcp__.+?__/, "");
43797
+ if (bareName === "offhand_send_file") return "high";
43786
43798
  const i2 = input ?? {};
43787
43799
  const text = [toolName, i2.command, i2.file_path, i2.path, i2.filepath].filter((x2) => typeof x2 === "string").join(" ");
43788
43800
  return /\b(rm|del|rmdir|rd|format|mkfs|shutdown|reboot|kill|drop\s+table|truncate|git\s+push\s+--force|--hard)\b/i.test(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "offhands",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Phone → coding-agent relay. Daemon runs on your laptop, PWA on your phone. E2E encrypted.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -22,5 +22,8 @@
22
22
  },
23
23
  "devDependencies": {
24
24
  "esbuild": "^0.24.0"
25
+ },
26
+ "dependencies": {
27
+ "offhands": "^0.1.14"
25
28
  }
26
29
  }