granttap-mcp 0.8.109 → 0.8.110

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.
@@ -23,7 +23,7 @@ export async function handleDeviceManagement(client: RelayClient, request: Devic
23
23
  const computerId = observedComputerId();
24
24
  if (request.computerId != null && request.computerId !== computerId) return false;
25
25
  // Sign-in material is deliberately non-durable and addressed only to the requesting paired controller.
26
- const send: Send = value => client.sendToPeer(value, peer, { reliable: false, ttlMs: 60_000 });
26
+ const send: Send = value => client.sendToPeer(value, peer, { reliable: false, urgent: true, ttlMs: 60_000 });
27
27
  const key = client.room + ':' + peer + ':' + request.requestId;
28
28
  const fingerprint = createHash('sha256').update(JSON.stringify(request)).digest('hex');
29
29
  for (const [k, value] of requests) if (Date.now() - value.at > value.ttl && !value.pending) requests.delete(k);
@@ -66,6 +66,7 @@ async function execute(request: DeviceManagementRequest, scope: string, computer
66
66
  await send({ ...result('waiting', login.message), login }); return;
67
67
  }
68
68
  await send(result('running', request.action === 'status' ? 'Reading this computer…' : 'Working on this computer…'));
69
+ if (request.action === 'status') providerLogins.replay(scope);
69
70
  let message = 'Computer status refreshed.';
70
71
  if (request.action === 'clear-cache') {
71
72
  if (!maintenanceIdle()) throw Error('Finish active requests and sign-in before clearing computer caches.');
@@ -16,6 +16,13 @@ export class ProviderLogins {
16
16
 
17
17
  active(): boolean { return [...this.flows.values()].some(f => !terminal.has(f.progress.phase)); }
18
18
 
19
+ /** A phone can leave for Safari while its final event is dropped. Status refresh replays only its latest flows. */
20
+ replay(scope: string): void {
21
+ const latest = new Map<CodingAgent, Flow>();
22
+ for (const flow of this.flows.values()) if (flow.scope === scope) latest.set(flow.progress.agent, flow);
23
+ for (const flow of latest.values()) flow.emit(flow.progress);
24
+ }
25
+
19
26
  start(scope: string, agent: CodingAgent, emit: Flow['emit']): ProviderLoginProgress {
20
27
  const existing = [...this.flows.values()].find(f => f.scope === scope && f.progress.agent === agent
21
28
  && !terminal.has(f.progress.phase));
@@ -104,7 +111,9 @@ export class ProviderLogins {
104
111
  }
105
112
 
106
113
  private prune(): void {
107
- for (const [id, f] of this.flows) if (terminal.has(f.progress.phase)) this.flows.delete(id);
114
+ for (const [id, f] of this.flows) {
115
+ if (terminal.has(f.progress.phase) && this.now() >= f.progress.expiresAt) this.flows.delete(id);
116
+ }
108
117
  }
109
118
  }
110
119
  export const providerLogins = new ProviderLogins();
@@ -10,7 +10,7 @@ keeps each phone response tied to the exact originating chat and prompt.
10
10
  Install the supported CLI on this computer, then run:
11
11
 
12
12
  ```bash
13
- npm install -g granttap-mcp@0.8.109
13
+ npm install -g granttap-mcp@0.8.110
14
14
  granttap setup
15
15
  granttap status
16
16
  ```
@@ -4,7 +4,7 @@
4
4
  "command": "node",
5
5
  "args": [
6
6
  "-e",
7
- "\"use strict\";\n\n// Cursor may start this MCP from any cwd. Execute JavaScript entry points with\n// Node itself: Windows batch shims require shell quoting that differs by host.\nconst { spawn } = require(\"node:child_process\");\nconst { existsSync } = require(\"node:fs\");\nconst { delimiter, dirname, join } = require(\"node:path\");\n\nconst PACKAGE = \"granttap-mcp@0.8.109\";\nconst dryRun = process.env.GRANTTAP_BOOTSTRAP_DRY_RUN === \"1\";\nconst platform = dryRun && process.env.GRANTTAP_BOOTSTRAP_PLATFORM\n ? process.env.GRANTTAP_BOOTSTRAP_PLATFORM : process.platform;\nconst nodeRoot = dryRun && process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT\n ? process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT : dirname(process.execPath);\nconst pathRoots = (process.env.PATH || \"\").split(delimiter).filter(Boolean);\nconst appData = process.env.APPDATA;\nconst roots = [nodeRoot, ...pathRoots, ...(appData ? [join(appData, \"npm\")] : [])];\nconst first = (paths) => paths.find((path) => existsSync(path));\n\nfunction launch() {\n if (platform !== \"win32\") {\n const installed = first(roots.map((root) => join(root, \"granttap-mcp\")));\n if (installed) return { command: installed, args: [] };\n const npx = first(roots.map((root) => join(root, \"npx\"))) || \"npx\";\n return { command: npx, args: [\"-y\", PACKAGE] };\n }\n const installed = first(roots.map((root) =>\n join(root, \"node_modules\", \"granttap-mcp\", \"bin\", \"granttap-mcp.mjs\")));\n if (installed) return { command: process.execPath, args: [installed] };\n const npx = first(roots.map((root) =>\n join(root, \"node_modules\", \"npm\", \"bin\", \"npx-cli.js\")));\n if (npx) return { command: process.execPath, args: [npx, \"-y\", PACKAGE] };\n throw new Error(\"Node.js/npm 22.13.0+ is required on this Windows device. Install npm and retry GrantTap.\");\n}\n\nlet target;\ntry { target = launch(); }\ncatch (error) {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n}\n\nif (dryRun) {\n process.stdout.write(JSON.stringify(target));\n process.exit(0);\n}\n\nconst child = spawn(target.command, target.args, { stdio: \"inherit\", windowsHide: true });\nchild.on(\"error\", (error) => {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n});\nchild.on(\"exit\", (code, signal) => {\n if (signal && platform !== \"win32\") {\n try { process.kill(process.pid, signal); } catch { process.exit(code ?? 1); }\n return;\n }\n process.exit(code ?? 1);\n});\n"
7
+ "\"use strict\";\n\n// Cursor may start this MCP from any cwd. Execute JavaScript entry points with\n// Node itself: Windows batch shims require shell quoting that differs by host.\nconst { spawn } = require(\"node:child_process\");\nconst { existsSync } = require(\"node:fs\");\nconst { delimiter, dirname, join } = require(\"node:path\");\n\nconst PACKAGE = \"granttap-mcp@0.8.110\";\nconst dryRun = process.env.GRANTTAP_BOOTSTRAP_DRY_RUN === \"1\";\nconst platform = dryRun && process.env.GRANTTAP_BOOTSTRAP_PLATFORM\n ? process.env.GRANTTAP_BOOTSTRAP_PLATFORM : process.platform;\nconst nodeRoot = dryRun && process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT\n ? process.env.GRANTTAP_BOOTSTRAP_NODE_ROOT : dirname(process.execPath);\nconst pathRoots = (process.env.PATH || \"\").split(delimiter).filter(Boolean);\nconst appData = process.env.APPDATA;\nconst roots = [nodeRoot, ...pathRoots, ...(appData ? [join(appData, \"npm\")] : [])];\nconst first = (paths) => paths.find((path) => existsSync(path));\n\nfunction launch() {\n if (platform !== \"win32\") {\n const installed = first(roots.map((root) => join(root, \"granttap-mcp\")));\n if (installed) return { command: installed, args: [] };\n const npx = first(roots.map((root) => join(root, \"npx\"))) || \"npx\";\n return { command: npx, args: [\"-y\", PACKAGE] };\n }\n const installed = first(roots.map((root) =>\n join(root, \"node_modules\", \"granttap-mcp\", \"bin\", \"granttap-mcp.mjs\")));\n if (installed) return { command: process.execPath, args: [installed] };\n const npx = first(roots.map((root) =>\n join(root, \"node_modules\", \"npm\", \"bin\", \"npx-cli.js\")));\n if (npx) return { command: process.execPath, args: [npx, \"-y\", PACKAGE] };\n throw new Error(\"Node.js/npm 22.13.0+ is required on this Windows device. Install npm and retry GrantTap.\");\n}\n\nlet target;\ntry { target = launch(); }\ncatch (error) {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n}\n\nif (dryRun) {\n process.stdout.write(JSON.stringify(target));\n process.exit(0);\n}\n\nconst child = spawn(target.command, target.args, { stdio: \"inherit\", windowsHide: true });\nchild.on(\"error\", (error) => {\n process.stderr.write(`[granttap] ${error.message}\\n`);\n process.exit(1);\n});\nchild.on(\"exit\", (code, signal) => {\n if (signal && platform !== \"win32\") {\n try { process.kill(process.pid, signal); } catch { process.exit(code ?? 1); }\n return;\n }\n process.exit(code ?? 1);\n});\n"
8
8
  ]
9
9
  }
10
10
  }
@@ -7,7 +7,7 @@ const { spawn } = require("node:child_process");
7
7
  const { existsSync } = require("node:fs");
8
8
  const { delimiter, dirname, join } = require("node:path");
9
9
 
10
- const PACKAGE = "granttap-mcp@0.8.109";
10
+ const PACKAGE = "granttap-mcp@0.8.110";
11
11
  const dryRun = process.env.GRANTTAP_BOOTSTRAP_DRY_RUN === "1";
12
12
  const platform = dryRun && process.env.GRANTTAP_BOOTSTRAP_PLATFORM
13
13
  ? process.env.GRANTTAP_BOOTSTRAP_PLATFORM : process.platform;
@@ -1,6 +1,6 @@
1
1
  # Computer controls from GrantTap
2
2
 
3
- MCP 0.8.109 adds the paired-controller `device.manage` protocol. The iOS client
3
+ MCP 0.8.110 adds the paired-controller `device.manage` protocol. The iOS client
4
4
  must also support these controls. A computer without an installed, connected
5
5
  MCP cannot execute remote commands; install and pair MCP on that computer first.
6
6
 
@@ -43,3 +43,7 @@ without durable mailbox storage.
43
43
  Regression tests cover controller/room/computer isolation, request idempotency,
44
44
  native login challenge formats, code ownership/cancellation/expiry, UTF-8
45
45
  streams, launchd Node PATH recovery and preservation during cache cleanup.
46
+
47
+ The latest sign-in state is replayed privately when its controller refreshes status.
48
+ This restores completion after a phone returns from the browser without starting
49
+ another login, resending a prompt, or retaining terminal authorization codes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "granttap-mcp",
3
- "version": "0.8.109",
3
+ "version": "0.8.110",
4
4
  "description": "Commercial computer runtime connecting local coding agents to GrantTap on Mac, iPhone, iPad and Apple Watch.",
5
5
  "type": "module",
6
6
  "bin": {