@instaclaw/dispatch 0.1.1 → 0.2.0

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/dist/index.js CHANGED
@@ -9,7 +9,7 @@
9
9
  import { loadConfig, saveConfig, getConfigPath } from "./config.js";
10
10
  import { checkPermissions, printPermissionGuide, runPermissionTest } from "./permissions.js";
11
11
  import { connect, disconnect } from "./connection.js";
12
- import { closeSupervisor } from "./supervisor.js";
12
+ import { closeSupervisor, setMode } from "./supervisor.js";
13
13
  import readline from "readline";
14
14
  import os from "os";
15
15
  async function main() {
@@ -55,7 +55,7 @@ async function main() {
55
55
  gatewayToken: args.token,
56
56
  vmAddress: args.vm,
57
57
  port: args.port || 8765,
58
- mode: "supervised",
58
+ mode: args.autonomous ? "autonomous" : "supervised",
59
59
  };
60
60
  saveConfig(config);
61
61
  }
@@ -65,6 +65,10 @@ async function main() {
65
65
  saveConfig(config);
66
66
  console.log(` Config saved to ${getConfigPath()}\n`);
67
67
  }
68
+ // Set supervisor mode
69
+ if (config.mode === "autonomous") {
70
+ setMode("autonomous");
71
+ }
68
72
  console.log(` VM: ${config.vmAddress}:${config.port}`);
69
73
  console.log(` Mode: ${config.mode}`);
70
74
  console.log(` Token: ${config.gatewayToken.substring(0, 8)}...\n`);
@@ -77,8 +81,14 @@ async function main() {
77
81
  rejectUnauthorized: false, // Accept self-signed (TOFU)
78
82
  certFingerprint: config.certFingerprint,
79
83
  onConnect: () => {
80
- console.log(`\n Dispatch mode: SUPERVISED`);
81
- console.log(` Screenshots auto-approved. Actions require [Enter] to confirm.`);
84
+ if (config.mode === "autonomous") {
85
+ console.log(`\n Dispatch mode: AUTONOMOUS`);
86
+ console.log(` All actions auto-approved (dangerous actions still require confirmation).`);
87
+ }
88
+ else {
89
+ console.log(`\n Dispatch mode: SUPERVISED`);
90
+ console.log(` Screenshots auto-approved. Actions require [Enter] to confirm.`);
91
+ }
82
92
  console.log(` Press Ctrl+C to disconnect.\n`);
83
93
  },
84
94
  onDisconnect: () => {
@@ -133,6 +143,9 @@ function parseArgs() {
133
143
  else if ((args[i] === "--port" || args[i] === "-p") && args[i + 1]) {
134
144
  result.port = parseInt(args[++i], 10);
135
145
  }
146
+ else if (args[i] === "--autonomous" || args[i] === "--auto") {
147
+ result.autonomous = true;
148
+ }
136
149
  }
137
150
  return result;
138
151
  }
@@ -1,3 +1,4 @@
1
1
  import type { DispatchCommand } from "./types.js";
2
+ export declare function setMode(m: "supervised" | "autonomous"): void;
2
3
  export declare function requestApproval(command: DispatchCommand): Promise<boolean>;
3
4
  export declare function closeSupervisor(): void;
@@ -1,9 +1,25 @@
1
1
  /**
2
- * Supervisor — prompts user for approval before executing commands.
3
- * Screenshots are auto-approved. All other actions require Enter to proceed.
2
+ * Supervisor — controls whether commands need user approval.
3
+ *
4
+ * Modes:
5
+ * supervised (default) — all non-passive commands require Enter to approve
6
+ * autonomous — auto-approves most commands, but ALWAYS prompts for dangerous ones
4
7
  */
5
8
  import readline from "readline";
6
9
  const AUTO_APPROVE_TYPES = new Set(["screenshot", "windows", "status"]);
10
+ // Patterns that indicate dangerous actions — always require confirmation even in autonomous mode
11
+ const DANGEROUS_TEXT_PATTERNS = [
12
+ /password/i, /passwd/i, /secret/i, /credential/i,
13
+ /delete/i, /remove/i, /destroy/i, /format/i, /erase/i,
14
+ /purchase/i, /submit.*order/i, /confirm.*payment/i, /buy\s/i,
15
+ /transfer.*fund/i, /send.*money/i, /withdraw/i,
16
+ /sudo\s/i, /rm\s+-rf/i, /shutdown/i, /reboot/i,
17
+ ];
18
+ const DANGEROUS_KEY_COMBOS = new Set([
19
+ "cmd+delete", "cmd+shift+delete", "ctrl+delete",
20
+ "cmd+q", "alt+f4",
21
+ ]);
22
+ let mode = "supervised";
7
23
  const isTTY = process.stdin.isTTY ?? false;
8
24
  let rl = null;
9
25
  if (isTTY) {
@@ -12,18 +28,36 @@ if (isTTY) {
12
28
  output: process.stdout,
13
29
  });
14
30
  }
31
+ export function setMode(m) {
32
+ mode = m;
33
+ }
15
34
  export async function requestApproval(command) {
16
- // Auto-approve passive commands
35
+ // Always auto-approve passive commands
17
36
  if (AUTO_APPROVE_TYPES.has(command.type)) {
18
37
  return true;
19
38
  }
20
39
  const desc = formatCommand(command);
21
- console.log(`\n Agent wants to: ${desc}`);
22
- // Non-interactive mode (no TTY) — auto-approve with log
40
+ const dangerous = isDangerous(command);
41
+ // Non-interactive (no TTY) — auto-approve everything (can't prompt)
23
42
  if (!rl) {
43
+ if (dangerous) {
44
+ console.log(`\n BLOCKED (dangerous, no TTY): ${desc}`);
45
+ return false;
46
+ }
47
+ console.log(`\n Agent wants to: ${desc}`);
24
48
  console.log(" Auto-approved (non-interactive mode)");
25
49
  return true;
26
50
  }
51
+ // Autonomous mode — auto-approve non-dangerous actions
52
+ if (mode === "autonomous" && !dangerous) {
53
+ console.log(`\n Agent: ${desc}`);
54
+ return true;
55
+ }
56
+ // Supervised mode OR dangerous action in autonomous mode — prompt user
57
+ console.log(`\n Agent wants to: ${desc}`);
58
+ if (dangerous) {
59
+ console.log(" ⚠️ DANGEROUS ACTION — requires confirmation");
60
+ }
27
61
  return new Promise((resolve) => {
28
62
  rl.question(" [Enter] to approve, [n] to deny: ", (answer) => {
29
63
  const denied = answer.trim().toLowerCase() === "n";
@@ -34,6 +68,18 @@ export async function requestApproval(command) {
34
68
  });
35
69
  });
36
70
  }
71
+ function isDangerous(cmd) {
72
+ const p = cmd.params;
73
+ if (cmd.type === "type") {
74
+ const text = String(p.text || "");
75
+ return DANGEROUS_TEXT_PATTERNS.some((pat) => pat.test(text));
76
+ }
77
+ if (cmd.type === "press") {
78
+ const key = String(p.key || "").toLowerCase();
79
+ return DANGEROUS_KEY_COMBOS.has(key);
80
+ }
81
+ return false;
82
+ }
37
83
  function formatCommand(cmd) {
38
84
  const p = cmd.params;
39
85
  switch (cmd.type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instaclaw/dispatch",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "Let your InstaClaw AI agent control your computer — screenshots, clicks, typing, and more via a secure WebSocket relay",
5
5
  "bin": {
6
6
  "instaclaw-dispatch": "./dist/index.js"