granttap-mcp 0.8.48 → 0.8.49

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.
@@ -3,7 +3,8 @@ import { join } from "node:path";
3
3
  import { RelayClient } from "../../../../../packages/core/relay-client";
4
4
  import { configDir, loadConfig, machineConfigPath } from "../../config";
5
5
  import { EngineSupervisor } from "../../engine/runtime/engine-supervisor";
6
- import { meshSnapshots } from "../../mesh/runtime";
6
+ import { meshSnapshotsAsync } from "../../mesh/runtime";
7
+ import { publishedCatalog } from "../../session-catalog";
7
8
  import { recoverLocalGraphBindings } from "../../mesh/runtime/graph/binding-sync";
8
9
  import { startSessionMonitor } from "../../monitor";
9
10
  import { controllerPeerGate } from "../../pairing/controllers";
@@ -50,7 +51,9 @@ void engine.ensureAvailable().then((health) => {
50
51
  if (health.state === "healthy") {
51
52
  // A new Engine binary starts with its own registry. Re-admit existing,
52
53
  // locally verified Git bindings so linked repositories have a graph again.
53
- void recoverLocalGraphBindings(meshSnapshots())
54
+ const known = publishedCatalog(client);
55
+ void meshSnapshotsAsync(known ? [...known.sessions, ...(known.history ?? [])] : [])
56
+ .then(recoverLocalGraphBindings)
54
57
  .then(() => monitor.publish())
55
58
  .catch(() => undefined);
56
59
  }
@@ -270,7 +270,7 @@ function handleInboundSubscription(
270
270
  // The transcript goes first, before a potentially slow catalog rescan.
271
271
  void publishSessionEvents(client, payload.sessionId).catch(() => false);
272
272
  if (handleSubscription(subscriptions, payload)) {
273
- void publish(true).catch(() => {});
273
+ void publish().catch(() => {});
274
274
  }
275
275
  return true;
276
276
  }
@@ -26,7 +26,8 @@ import { boundedCatalogHistory, INTERVAL_MS, publishSessionEvents } from "../han
26
26
  import { sweepAttachments } from "../handlers/receipts";
27
27
  import { handleMonitorMessage } from "../handlers/inbound";
28
28
 
29
- const HISTORY_INTERVAL_MS = 10_000;
29
+ const HISTORY_INTERVAL_MS = 60_000;
30
+ const resumedHeads = new WeakSet<RelayClient>();
30
31
  import { publishMonitorMeshes, stopMonitorMeshes } from "../mesh-publication";
31
32
 
32
33
  export type SessionMonitor = {
@@ -118,18 +119,20 @@ async function publishMonitorTick(input: {
118
119
  if (!client.isConnected) return { lastHistoryPublishedAt, lastCapabilityPublishedAt };
119
120
  await publishHeartbeat(client).catch(() => {});
120
121
  if (!leadership.acquire()) return { lastHistoryPublishedAt, lastCapabilityPublishedAt };
121
- if (lastHistoryPublishedAt === 0) {
122
- await resumePublishedChats(client,
123
- (session, status) => publishSessionEvents(client, session.sessionId, status));
124
- }
125
- const includeHistory = forceHistory || Date.now() - lastHistoryPublishedAt >= HISTORY_INTERVAL_MS;
122
+ const initial = lastHistoryPublishedAt === 0;
123
+ const includeHistory = forceHistory || (!initial && Date.now() - lastHistoryPublishedAt >= HISTORY_INTERVAL_MS);
126
124
  const status = monitorSnapshot({ includeHistory, forceHistory, subscriptions, history });
127
125
  rememberPublishedCatalog(client, status);
128
126
  await client.send(status, "phone", { ttlMs: INTERVAL_MS * 24, reliable: false });
127
+ if (initial && !resumedHeads.has(client)) {
128
+ resumedHeads.add(client);
129
+ void resumePublishedChats(client,
130
+ (session, saved) => publishSessionEvents(client, session.sessionId, saved)).catch(() => {});
131
+ }
129
132
  // Provider review is independent of task visibility; a hung hook RPC must
130
133
  // never hold the current catalog behind its discovery timeout.
131
134
  void refreshCodexHooks().catch(() => {});
132
- if (includeHistory) lastHistoryPublishedAt = Date.now();
135
+ if (includeHistory || initial) lastHistoryPublishedAt = Date.now();
133
136
  loadLoop.updateStatus(status);
134
137
  void refreshMcpLoad(status.sessions).catch(() => {});
135
138
  for (const sessionId of subscriptions) {
@@ -9,8 +9,9 @@ unreadable merely because hundreds of newer logs appeared.
9
9
  The private `session-catalog-cache.json` contains metadata and validated native
10
10
  source locations. It excludes messages, capability descriptions, and credentials.
11
11
  The room and provider roots bind its scope. On restart the primary monitor sends
12
- the saved Now chats' current native heads under their independent task keys before
13
- performing an expensive fresh discovery scan. It does not republish an old catalog
12
+ a fresh live catalog first, then resumes the saved Now chats' native heads under
13
+ their independent task keys in the background. Closed-history discovery runs
14
+ separately from that first live publication. It does not republish an old catalog
14
15
  as fresh. The phone continues its durable historical backfill independently.
15
16
 
16
17
  Tests live in `tests/`. This runtime module uses the repository MIT License.
@@ -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.48
13
+ npm install -g granttap-mcp@0.8.49
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.48\";\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 20+ 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.49\";\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 20+ 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.48";
10
+ const PACKAGE = "granttap-mcp@0.8.49";
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "granttap-mcp",
3
- "version": "0.8.48",
3
+ "version": "0.8.49",
4
4
  "description": "Personal live control center runtime for local coding agents on iPhone and Apple Watch.",
5
5
  "type": "module",
6
6
  "bin": {