poke-gate 0.2.1 → 0.2.2

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/README.md CHANGED
@@ -241,7 +241,7 @@ Poke Gate supports three access modes that control what your agent can do:
241
241
 
242
242
  | Mode | Description |
243
243
  |------|-------------|
244
- | **Full** (default) | All tools available. Risky actions (commands, file writes, screenshots) require chat approval. |
244
+ | **Full** (default) | All tools available with no approval required. The agent can run commands, write files, and take screenshots directly. |
245
245
  | **Limited** | Read-only tools plus a curated set of safe commands (`ls`, `cat`, `grep`, `curl`, etc.). `write_file` and `take_screenshot` are disabled. |
246
246
  | **Sandbox** | Broader command support than Limited, but writes are restricted to `~/Downloads` and `/tmp` via macOS `sandbox-exec`. |
247
247
 
@@ -91,6 +91,7 @@ class GateService: ObservableObject {
91
91
 
92
92
  @Published var status: Status = .stopped
93
93
  @Published var logs: [String] = []
94
+ @Published var processLogs: [String] = []
94
95
  @Published var terminalPreviews: [TerminalPreview] = []
95
96
  @Published var userName: String? = nil
96
97
  @Published var permissionMode: PermissionMode
@@ -489,11 +490,21 @@ class GateService: ObservableObject {
489
490
  outputPipe?.fileHandleForReading.readabilityHandler = nil
490
491
  process = nil
491
492
  outputPipe = nil
493
+ killOrphanedProcesses()
494
+ }
495
+
496
+ private func killOrphanedProcesses() {
497
+ let task = Process()
498
+ task.executableURL = URL(fileURLWithPath: "/usr/bin/pkill")
499
+ task.arguments = ["-f", "poke-gate"]
500
+ try? task.run()
501
+ task.waitUntilExit()
492
502
  }
493
503
 
494
504
  private func handleOutput(_ raw: String) {
495
505
  for line in raw.components(separatedBy: .newlines) where !line.isEmpty {
496
506
  appendLog(line)
507
+ appendProcessLog(line)
497
508
  parseTerminalPreviewLine(line)
498
509
 
499
510
  if line.contains("Tunnel connected") || line.contains("Ready") {
@@ -510,6 +521,15 @@ class GateService: ObservableObject {
510
521
  }
511
522
  }
512
523
 
524
+ private func appendProcessLog(_ line: String) {
525
+ let stripped = stripToolTimestamp(from: line)
526
+ guard !stripped.isEmpty else { return }
527
+ processLogs.append(stripped)
528
+ if processLogs.count > maxLogs {
529
+ processLogs.removeFirst(processLogs.count - maxLogs)
530
+ }
531
+ }
532
+
513
533
  private func handleTermination(exitCode: Int32) {
514
534
  appendLog("Process exited with code \(exitCode)")
515
535
  stopHealthCheck()
@@ -189,9 +189,9 @@ struct PopoverContent: View {
189
189
  .truncationMode(.tail)
190
190
  }
191
191
  }
192
- } else if !service.logs.isEmpty {
193
- ForEach(Array(service.logs.suffix(4).enumerated()), id: \.offset) { _, log in
194
- Text(log)
192
+ } else if !service.processLogs.isEmpty {
193
+ ForEach(Array(service.processLogs.suffix(4).enumerated()), id: \.offset) { _, entry in
194
+ Text(entry)
195
195
  .font(.system(size: 9, design: .monospaced))
196
196
  .foregroundStyle(.tertiary)
197
197
  .lineLimit(1)
@@ -286,7 +286,7 @@
286
286
  "@executable_path/../Frameworks",
287
287
  );
288
288
  MACOSX_DEPLOYMENT_TARGET = 15.0;
289
- MARKETING_VERSION = 0.2.0;
289
+ MARKETING_VERSION = 0.2.1;
290
290
  PRODUCT_BUNDLE_IDENTIFIER = "dev.fka.Poke-macOS-Gate";
291
291
  PRODUCT_NAME = "$(TARGET_NAME)";
292
292
  REGISTER_APP_GROUPS = YES;
@@ -322,7 +322,7 @@
322
322
  "@executable_path/../Frameworks",
323
323
  );
324
324
  MACOSX_DEPLOYMENT_TARGET = 15.0;
325
- MARKETING_VERSION = 0.2.0;
325
+ MARKETING_VERSION = 0.2.1;
326
326
  PRODUCT_BUNDLE_IDENTIFIER = "dev.fka.Poke-macOS-Gate";
327
327
  PRODUCT_NAME = "$(TARGET_NAME)";
328
328
  REGISTER_APP_GROUPS = YES;
package/docs/security.md CHANGED
@@ -10,7 +10,7 @@ Poke Gate supports three access modes that control what tools your agent can use
10
10
 
11
11
  ### Full (default)
12
12
 
13
- All tools are available. Risky actions (`run_command`, `write_file`, `take_screenshot`) require **chat approval** the agent must ask you in chat before executing, and you approve with a signed token.
13
+ All tools are available with no approval required. The agent can run commands, write files, and take screenshots directly.
14
14
 
15
15
  ### Limited
16
16
 
@@ -48,13 +48,15 @@ POKE_GATE_PERMISSION_MODE=sandbox npx poke-gate
48
48
 
49
49
  ## Tool approval flow
50
50
 
51
- In **full** mode, risky tools (`run_command`, `write_file`, `take_screenshot`) use an HMAC-signed approval flow:
51
+ In **limited** and **sandbox** modes, risky tools (`run_command`, `write_file`, `take_screenshot`) use an HMAC-signed approval flow:
52
52
 
53
53
  1. The agent calls the tool — Poke Gate returns `AWAITING_APPROVAL` with a signed token
54
54
  2. The agent asks you in chat to approve
55
55
  3. You approve — the agent re-calls the tool with the approval token
56
56
  4. Optionally, you can `remember_in_session` (same command) or `remember_all_risky` (all risky tools for the session)
57
57
 
58
+ In **full** mode, all tools execute directly without approval.
59
+
58
60
  ## What protects you
59
61
 
60
62
  - **Authentication** — only your Poke agent (authenticated via Poke OAuth) can reach the tunnel
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poke-gate",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Expose your machine to your Poke AI assistant via MCP tunnel",
5
5
  "type": "module",
6
6
  "bin": {
package/src/app.js CHANGED
@@ -2,10 +2,23 @@ import { startMcpServer, enableLogging, getPermissionMode } from "./mcp-server.j
2
2
  import { startTunnel } from "./tunnel.js";
3
3
  import { startAgentScheduler, stopAgentScheduler } from "./agents.js";
4
4
  import { Poke, isLoggedIn, login, getToken } from "poke";
5
+ import { execSync } from "node:child_process";
5
6
 
6
7
  const verbose = process.argv.includes("--verbose") || process.argv.includes("-v");
7
8
  enableLogging(verbose);
8
9
 
10
+ function killExistingInstances() {
11
+ const myPid = process.pid;
12
+ try {
13
+ const out = execSync("pgrep -f 'poke-gate'", { encoding: "utf-8" }).trim();
14
+ const pids = out.split("\n").map(Number).filter((p) => p && p !== myPid);
15
+ for (const pid of pids) {
16
+ try { process.kill(pid, "SIGTERM"); } catch {}
17
+ }
18
+ if (pids.length > 0) log(`Killed ${pids.length} existing poke-gate process(es).`);
19
+ } catch {}
20
+ }
21
+
9
22
  function log(msg) {
10
23
  const ts = new Date().toISOString().slice(11, 19);
11
24
  console.log(`[${ts}] ${msg}`);
@@ -102,6 +115,7 @@ function scheduleReconnect(mcpUrl, token) {
102
115
  }
103
116
 
104
117
  async function main() {
118
+ killExistingInstances();
105
119
  log("poke-gate starting...");
106
120
  log(`Access mode: ${getPermissionMode()}`);
107
121
 
@@ -133,7 +147,7 @@ function buildAccessModeMessage(mode) {
133
147
  return (
134
148
  "Access mode: Full. " +
135
149
  "You can run any shell command, read and write files, list directories, take screenshots, and check system info. " +
136
- "Risky actions (commands, file writes, screenshots) require user approval in chat before execution."
150
+ "Use the tools directly whenever needed no approval required."
137
151
  );
138
152
  }
139
153
  }
package/src/mcp-server.js CHANGED
@@ -565,7 +565,7 @@ function handleToolCall(name, args, context = {}) {
565
565
  return blocked;
566
566
  }
567
567
 
568
- if (permissionService.isRisky(name)) {
568
+ if (PERMISSION_MODE !== "full" && permissionService.isRisky(name)) {
569
569
  const commandText = typeof cleanArgs.command === "string" ? cleanArgs.command : "";
570
570
  const alreadyAllowed = sessionAutoApproveAllRisky.has(sessionId) ||
571
571
  (commandText && permissionService.isAllowedBySessionPattern(sessionId, commandText));