@gravitylabsllc/porthole 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/dist/device.js CHANGED
@@ -65,6 +65,34 @@ export class DeviceClient extends EventEmitter {
65
65
  * connect at all.
66
66
  */
67
67
  protocolMismatch = null;
68
+ /**
69
+ * GRA-197: null unless `hello.packageName` disagrees with
70
+ * [applicationId] — set synchronously in `connect()`'s hello handler,
71
+ * right beside [protocolMismatch] and for the same reasons: computed the
72
+ * instant `hello` lands rather than deferred to whichever tool asks
73
+ * later, so a reader is never looking at a stale answer for a previous
74
+ * connection, and cleared wherever `protocolMismatch` is (the "close"
75
+ * handler below), since both are facts about the `hello` that produced
76
+ * them and neither survives it.
77
+ *
78
+ * Unlike `protocolMismatch`, this is a refusal to trust *identity*, not
79
+ * *wire format* — the app answering the port is a real, working Porthole
80
+ * app, just not the one this server was configured for (another Porthole
81
+ * app on the device holding the same port is the concrete incident this
82
+ * guards, GRA-197's own report). The founder's ruling is "warn loudly, do
83
+ * not refuse": this never blocks a request or a connection, it only
84
+ * surfaces the fact everywhere a caller might otherwise be misled by an
85
+ * unqualified "connected".
86
+ */
87
+ packageMismatch = null;
88
+ /**
89
+ * GRA-197: what this server was started for, from `PORTHOLE_APPLICATION_ID`
90
+ * — undefined when unset, which means "no expectation configured" and
91
+ * disables the check entirely (see the hello handler): a server pointed at
92
+ * an app on purpose, with no plugin-generated `.mcp.json` in the loop at
93
+ * all, must see no behaviour change from this ticket.
94
+ */
95
+ applicationId;
68
96
  /**
69
97
  * GRA-53 `#session-writer`: null (persistence off) unless a sessions root
70
98
  * is given. `undefined`/omitted is the default on purpose — every existing
@@ -75,11 +103,12 @@ export class DeviceClient extends EventEmitter {
75
103
  * one explicitly.
76
104
  */
77
105
  sessions;
78
- constructor(host, port, sessionsRoot) {
106
+ constructor(host, port, sessionsRoot, applicationId) {
79
107
  super();
80
108
  this.host = host;
81
109
  this.port = port;
82
110
  this.sessions = sessionsRoot ? new SessionWriter(sessionsRoot) : null;
111
+ this.applicationId = applicationId;
83
112
  }
84
113
  start() {
85
114
  this.closed = false;
@@ -155,6 +184,20 @@ export class DeviceClient extends EventEmitter {
155
184
  `${PROTOCOL_VERSION}. Update the app's Porthole runtime dependency to a version that ` +
156
185
  `speaks protocol ${PROTOCOL_VERSION}, or pin the npm package this MCP server runs from ` +
157
186
  `(in .mcp.json) to the version that matches the app.`;
187
+ // GRA-197: same placement and the same reasoning as protocolMismatch
188
+ // just above — computed the instant hello lands, synchronously, so
189
+ // it sits between `this.hello = hello` and the emit below without
190
+ // reopening GRA-191's race. `this.applicationId` unset means no
191
+ // expectation was configured at all (an ordinary `porthole { }`
192
+ // with no applicationId, or a server started with no
193
+ // PORTHOLE_APPLICATION_ID), which must be indistinguishable from
194
+ // today's behaviour rather than read as "expected no package".
195
+ this.packageMismatch =
196
+ this.applicationId === undefined || hello.packageName === this.applicationId
197
+ ? null
198
+ : `Connected to \`${hello.packageName}\`, but this MCP server was configured for ` +
199
+ `\`${this.applicationId}\` (PORTHOLE_APPLICATION_ID). Another Porthole app on the ` +
200
+ `device is holding the port — stop it, or give this app its own port.`;
158
201
  // GRA-191: `this.hello = hello` above and this emit must stay
159
202
  // exactly this close together, with nothing between them that can
160
203
  // yield to the event loop. GRA-53 used to put
@@ -233,6 +276,8 @@ export class DeviceClient extends EventEmitter {
233
276
  // gone (a new connection will get its own, possibly no longer
234
277
  // mismatched) there is nothing left for this to still be true about.
235
278
  this.protocolMismatch = null;
279
+ // GRA-197: same reasoning, same place.
280
+ this.packageMismatch = null;
236
281
  this.failPending("device disconnected");
237
282
  this.setState("disconnected");
238
283
  this.scheduleReconnect();
@@ -430,6 +475,16 @@ export class DeviceClient extends EventEmitter {
430
475
  " 2. the adb bridge is up: 'adb forward tcp:PORT tcp:PORT', which",
431
476
  " 'porthole ui' and './gradlew portholeConnect' both do for you",
432
477
  ` 3. nothing else on this machine is holding ${this.port}`,
478
+ // GRA-197: the two cases that incident's own report named — a wrong
479
+ // app answering is only reachable from here for a device that is not
480
+ // even accepting connections on the port; a device that is, but
481
+ // answers as the wrong app, is packageMismatch's territory above,
482
+ // reached while "connected", not from this message at all.
483
+ " 4. another Porthole app on the device isn't already holding this port — stop it, or " +
484
+ "give this app its own port with 'porthole { port.set(...) }'",
485
+ " 5. there's only one adb transport for this device — wireless plus wired both attached " +
486
+ "makes 'adb forward' ambiguous and it fails silently for this port; pin one with " +
487
+ "'porthole { deviceSerial.set(...) }'",
433
488
  ]
434
489
  .filter(Boolean)
435
490
  .join("\n");
@@ -1 +1 @@
1
- {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,sCAAsC;AACtC,OAAO,GAAG,MAAM,UAAU,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAqB,MAAM,eAAe,CAAC;AA4CjE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AA8DlC,uGAAuG;AACvG,MAAM,CAAC,MAAM,yBAAyB,GACpC,wEAAwE,CAAC;AAE3E,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAC7B,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,kBAAkB,GAAG,KAAK,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,OAAO,YAAa,SAAQ,YAAY;IAqDzB;IACR;IArDH,MAAM,GAAsB,IAAI,CAAC;IACjC,MAAM,GAAG,EAAE,CAAC;IACZ,MAAM,GAAG,CAAC,CAAC;IACX,OAAO,GAAG,IAAI,GAAG,EAGtB,CAAC;IACI,cAAc,GAAG,gBAAgB,CAAC;IAClC,cAAc,GAA0B,IAAI,CAAC;IAC7C,MAAM,GAAG,KAAK,CAAC;IAEvB,KAAK,GAAoB,cAAc,CAAC;IACxC,KAAK,GAAiB,IAAI,CAAC;IAC3B,SAAS,GAAkB,IAAI,CAAC;IAChC;;;;;;;;;;OAUG;IACH,UAAU,GAAyB,IAAI,CAAC;IACxC;;;;;;;;;;;OAWG;IACH,gBAAgB,GAAkB,IAAI,CAAC;IAEvC;;;;;;;;OAQG;IACM,QAAQ,CAAuB;IAExC,YACmB,IAAY,EACpB,IAAY,EACrB,YAAqB;QAErB,KAAK,EAAE,CAAC;QAJS,SAAI,GAAJ,IAAI,CAAQ;QACpB,SAAI,GAAJ,IAAI,CAAQ;QAIrB,IAAI,CAAC,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,8EAA8E;QAC9E,8EAA8E;QAC9E,2EAA2E;QAC3E,qEAAqE;QACrE,IAAI,IAAI,CAAC,cAAc;YAAE,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC3B,oEAAoE;QACpE,sEAAsE;QACtE,qEAAqE;QACrE,oEAAoE;QACpE,uEAAuE;QACvE,gEAAgE;QAChE,sEAAsE;QACtE,oEAAoE;QACpE,oEAAoE;QACpE,uDAAuD;QACvD,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IAChC,CAAC;IAEO,OAAO;QACb,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACvC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;QAE5B,MAAM,MAAM,GAAG,GAAG,CAAC,gBAAgB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC1E,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACxB,IAAI,CAAC,cAAc,GAAG,gBAAgB,CAAC;YACvC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,kEAAkE;YAClE,qEAAqE;YACrE,mEAAmE;YACnE,sEAAsE;YACtE,qEAAqE;YACrE,iBAAiB;YACjB,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YAC7B,kEAAkE;YAClE,IAAI,CAAC,OAAO,CAAQ,OAAO,CAAC;iBACzB,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACpB,2DAA2D;gBAC3D,8DAA8D;gBAC9D,iEAAiE;gBACjE,iEAAiE;gBACjE,kEAAkE;gBAClE,iEAAiE;gBACjE,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;gBACnB,+DAA+D;gBAC/D,kEAAkE;gBAClE,iEAAiE;gBACjE,kEAAkE;gBAClE,kEAAkE;gBAClE,mEAAmE;gBACnE,gEAAgE;gBAChE,iEAAiE;gBACjE,gEAAgE;gBAChE,8DAA8D;gBAC9D,0DAA0D;gBAC1D,IAAI,CAAC,gBAAgB;oBACnB,KAAK,CAAC,QAAQ,KAAK,gBAAgB;wBACjC,CAAC,CAAC,IAAI;wBACN,CAAC,CAAC,gCAAgC,KAAK,CAAC,QAAQ,qCAAqC;4BACnF,GAAG,gBAAgB,mEAAmE;4BACtF,mBAAmB,gBAAgB,qDAAqD;4BACxF,qDAAqD,CAAC;gBAC5D,8DAA8D;gBAC9D,kEAAkE;gBAClE,8CAA8C;gBAC9C,+DAA+D;gBAC/D,gEAAgE;gBAChE,gEAAgE;gBAChE,+DAA+D;gBAC/D,gEAAgE;gBAChE,iEAAiE;gBACjE,4DAA4D;gBAC5D,8DAA8D;gBAC9D,iEAAiE;gBACjE,mEAAmE;gBACnE,8DAA8D;gBAC9D,kEAAkE;gBAClE,4DAA4D;gBAC5D,8DAA8D;gBAC9D,gEAAgE;gBAChE,4DAA4D;gBAC5D,iEAAiE;gBACjE,iEAAiE;gBACjE,kEAAkE;gBAClE,kEAAkE;gBAClE,mEAAmE;gBACnE,gEAAgE;gBAChE,YAAY;gBACZ,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;gBAC1B,mEAAmE;gBACnE,kEAAkE;gBAClE,8DAA8D;gBAC9D,8DAA8D;gBAC9D,4DAA4D;gBAC5D,6DAA6D;gBAC7D,IAAI,IAAI,CAAC,QAAQ;oBAAE,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBACnD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC7B,CAAC,CAAC;iBACD,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;gBACtB,6DAA6D;gBAC7D,gEAAgE;gBAChE,kEAAkE;gBAClE,mEAAmE;gBACnE,8DAA8D;gBAC9D,+DAA+D;gBAC/D,mEAAmE;gBACnE,mBAAmB;gBACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC;YACjC,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAEzD,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAY,EAAE,EAAE;YAClC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;YACnB,mEAAmE;YACnE,mEAAmE;YACnE,qEAAqE;YACrE,iEAAiE;YACjE,sEAAsE;YACtE,iEAAiE;YACjE,uEAAuE;YACvE,gEAAgE;YAChE,uDAAuD;YACvD,KAAK,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC;YAC5B,mEAAmE;YACnE,iEAAiE;YACjE,qEAAqE;YACrE,sEAAsE;YACtE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YACtE,CAAC;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,sEAAsE;YACtE,oEAAoE;YACpE,8DAA8D;YAC9D,qEAAqE;YACrE,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAC7B,IAAI,CAAC,WAAW,CAAC,qBAAqB,CAAC,CAAC;YACxC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YAC9B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,cAAc;YAAE,OAAO;QAC/C,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAC3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACxB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;IAC5E,CAAC;IAEO,MAAM,CAAC,KAAa;QAC1B,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;QACrB,IAAI,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxC,OAAO,OAAO,IAAI,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YAClD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;YAC7C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACvC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,IAAY;QACzB,IAAI,KAA6B,CAAC;QAClC,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;YACrB,iEAAiE;YACjE,oEAAoE;YACpE,sEAAsE;YACtE,qEAAqE;YACrE,oEAAoE;YACpE,qEAAqE;YACrE,mEAAmE;YACnE,iEAAiE;YACjE,gEAAgE;YAChE,oBAAoB;YACpB,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAqB,CAAC,CAAC;YAC7C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9B,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,KAAK,CAAC,EAAE;YAAE,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;;YACtC,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,sBAAsB,CAAC,CAAC,CAAC;IACvE,CAAC;IAEO,WAAW,CAAC,MAAc;QAChC,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACtC,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC3B,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;QACnC,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAEO,QAAQ,CAAC,KAAsB;QACrC,wEAAwE;QACxE,oEAAoE;QACpE,oEAAoE;QACpE,sEAAsE;QACtE,8CAA8C;QAC9C,IAAI,KAAK,KAAK,WAAW,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,uFAAuF,CACxF,CAAC;QACJ,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO;QACjC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,CAAI,MAAc,EAAE,SAAkC,EAAE;QAC7D,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,wEAAwE;QACxE,uEAAuE;QACvE,oEAAoE;QACpE,sEAAsE;QACtE,wEAAwE;QACxE,qEAAqE;QACrE,8BAA8B;QAC9B,EAAE;QACF,oEAAoE;QACpE,yEAAyE;QACzE,oEAAoE;QACpE,wEAAwE;QACxE,yEAAyE;QACzE,iEAAiE;QACjE,mEAAmE;QACnE,oEAAoE;QACpE,mEAAmE;QACnE,qEAAqE;QACrE,mCAAmC;QACnC,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACvC,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,EAAE,CAAC,CAAC,CAAC;QAC/D,CAAC;QAED,MAAM,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACzB,2EAA2E;QAC3E,8CAA8C;QAC9C,MAAM,OAAO,GAA4B,EAAE,CAAC;QAC5C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAClD,IAAI,KAAK,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAChD,CAAC;QAED,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACxC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACxB,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,MAAM,YAAY,kBAAkB,IAAI,CAAC,CAAC,CAAC;YACxF,CAAC,EAAE,kBAAkB,CAAC,CAAC;YAEvB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBACnB,OAAO,EAAE,OAAmC;gBAC5C,MAAM;gBACN,KAAK;aACN,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,cAAc;QACZ,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,cAAc,CAAC;YACpB,KAAK,YAAY;gBACf,OAAO,IAAI,CAAC,mBAAmB,EAAE,CAAC;YACpC,KAAK,aAAa;gBAChB,OAAO,yBAAyB,CAAC;YACnC,KAAK,WAAW;gBACd,OAAO,IAAI,CAAC;YACd,OAAO,CAAC,CAAC,CAAC;gBACR,MAAM,UAAU,GAAU,IAAI,CAAC,KAAK,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,4CAA4C,UAAoB,GAAG,CAAC,CAAC;YACvF,CAAC;QACH,CAAC;IACH,CAAC;IAED,mBAAmB;QACjB,OAAO;YACL,+BAA+B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,GAAG;YACxD,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI;YAC/D,kBAAkB;YAClB,sFAAsF;YACtF,mEAAmE;YACnE,oEAAoE;YACpE,gDAAgD,IAAI,CAAC,IAAI,EAAE;SAC5D;aACE,MAAM,CAAC,OAAO,CAAC;aACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;CACF;AAED,+EAA+E;AAC/E,EAAE;AACF,qEAAqE;AACrE,6EAA6E;AAC7E,oEAAoE;AACpE,sEAAsE;AACtE,yEAAyE;AACzE,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,wEAAwE;AAExE;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa,CAAC;QACnB,KAAK,WAAW;YACd,OAAO,IAAI,CAAC;QACd,KAAK,YAAY,CAAC;QAClB,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC;QACf,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,KAAK,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4CAA4C,UAAoB,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,KAAsB;IAChD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,WAAW;YACd,OAAO,IAAI,CAAC;QACd,KAAK,YAAY,CAAC;QAClB,KAAK,aAAa,CAAC;QACnB,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC;QACf,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,KAAK,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4CAA4C,UAAoB,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAsB;IAClD,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,aAAa;YAChB,OAAO,IAAI,CAAC;QACd,KAAK,YAAY,CAAC;QAClB,KAAK,WAAW,CAAC;QACjB,KAAK,cAAc;YACjB,OAAO,KAAK,CAAC;QACf,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,UAAU,GAAU,KAAK,CAAC;YAChC,MAAM,IAAI,KAAK,CAAC,4CAA4C,UAAoB,GAAG,CAAC,CAAC;QACvF,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../src/device.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ // Copyright 2026 Gravity Labs
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ /**
4
+ * Every value `EventFrame.event` can carry — the runtime's own
5
+ * `EventKinds` object (`runtime/src/main/kotlin/live/gravitylabs/porthole/
6
+ * protocol/Protocol.kt`), mirrored on this side of the wire.
7
+ *
8
+ * This is the one list `timeline`'s `kinds` filter can be asked about (see
9
+ * `index.ts`'s `kinds` zod param, generated from this array so the
10
+ * description text cannot list a kind the filter does not actually accept,
11
+ * or omit one it does) and the one `eventKinds.test.ts` compares against
12
+ * Protocol.kt's own source, so a kind added on only one side of the wire
13
+ * fails a test instead of one side silently not recognising it. Order here
14
+ * is the order the description groups them in: the nine kinds a UI lane
15
+ * already showed before GRA-200, then the rest.
16
+ *
17
+ * Deliberately does NOT include `DeviceCollector`'s own sub-kinds
18
+ * (`profile`, `trimMemory`, `foreground`, …) — those travel inside a
19
+ * `device` event's `data.kind` field, never as `EventFrame.event` itself,
20
+ * so `kinds: ["trimMemory"]` would silently match nothing. `trace.ts`'s
21
+ * `resolveProfile`/`findingsOf` read them by their own literal strings,
22
+ * matching Protocol.kt's separate `DeviceEventKinds` object.
23
+ */
24
+ export const EVENT_KINDS = [
25
+ "recompose",
26
+ "state_write",
27
+ "frame",
28
+ "nav",
29
+ "http_start",
30
+ "http_end",
31
+ "db_start",
32
+ "db_end",
33
+ "log",
34
+ "log_append",
35
+ "mark",
36
+ "device",
37
+ "exit",
38
+ "work_start",
39
+ "work_end",
40
+ "blocked",
41
+ "gc",
42
+ "memory",
43
+ ];
44
+ const KIND_GROUPS = [
45
+ {
46
+ kinds: ["exit"],
47
+ narrated: "narrated in `porthole_status` (its `exits` list and `exitTrace` RPC); `findings`' own " +
48
+ "`alsoInWindow` block also inventories every exit in the window it examined, including the " +
49
+ "ones that did not cross a severity worth a finding on their own",
50
+ },
51
+ {
52
+ kinds: ["memory", "gc"],
53
+ narrated: "raw here; `gc` becomes a `findings` entry only when a collection blocks the app, and a " +
54
+ "device's `trimMemory` sub-kind (below) becomes one whenever the system actually asks for " +
55
+ "memory back — `memory`'s own periodic samples never do, and stay raw everywhere but " +
56
+ "`findings`' `alsoInWindow` count",
57
+ },
58
+ {
59
+ kinds: ["device"],
60
+ narrated: "raw here; its one-time startup profile sub-kind is what `findings` and `frames` read their " +
61
+ "frame budget from, and its other sub-kinds cover lifecycle changes (`foreground`/" +
62
+ "`background`), rotation, theme, font scale, power and network — see `DeviceEventKinds` in " +
63
+ "Protocol.kt for the full set",
64
+ },
65
+ {
66
+ kinds: [
67
+ "recompose",
68
+ "state_write",
69
+ "frame",
70
+ "nav",
71
+ "http_start",
72
+ "http_end",
73
+ "db_start",
74
+ "db_end",
75
+ "log",
76
+ ],
77
+ narrated: "raw here, as before",
78
+ },
79
+ {
80
+ kinds: ["log_append", "mark", "work_start", "work_end", "blocked"],
81
+ narrated: "raw here",
82
+ },
83
+ ];
84
+ /**
85
+ * Refuses to describe a set of groups that silently drops or invents a
86
+ * kind — a clause removed from `groups` without removing its kind from
87
+ * `kinds` (or the reverse) throws here rather than shipping a description
88
+ * that quietly stopped matching the filter it documents. Exported (rather
89
+ * than inlined into [timelineKindsDescription]) so a test can hand it a
90
+ * synthetic, deliberately-broken group list without having to break the
91
+ * real [KIND_GROUPS]/[EVENT_KINDS] to prove the check works at all.
92
+ */
93
+ export function validateKindCoverage(groups, kinds) {
94
+ const covered = groups.flatMap((g) => g.kinds);
95
+ const coveredSet = new Set(covered);
96
+ const missing = kinds.filter((k) => !coveredSet.has(k));
97
+ if (missing.length > 0) {
98
+ throw new Error(`timelineKindsDescription() does not narrate: ${missing.join(", ")}`);
99
+ }
100
+ if (covered.length !== coveredSet.size) {
101
+ throw new Error("timelineKindsDescription() lists the same kind in more than one group.");
102
+ }
103
+ const known = new Set(kinds);
104
+ const unknown = covered.filter((k) => !known.has(k));
105
+ if (unknown.length > 0) {
106
+ throw new Error(`timelineKindsDescription() narrates a kind EVENT_KINDS does not have: ${unknown.join(", ")}`);
107
+ }
108
+ }
109
+ /** Builds `timeline`'s `kinds` param description from [KIND_GROUPS] — see [validateKindCoverage]. */
110
+ export function timelineKindsDescription() {
111
+ validateKindCoverage(KIND_GROUPS, EVENT_KINDS);
112
+ const clauses = KIND_GROUPS.map((g) => `${g.kinds.map((k) => `\`${k}\``).join("/")} — ${g.narrated}`);
113
+ return "Filter by event kind. " + clauses.join("; ") + ".";
114
+ }
115
+ //# sourceMappingURL=eventKinds.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eventKinds.js","sourceRoot":"","sources":["../src/eventKinds.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -15,7 +15,8 @@ import { captureArgs, countPortholeLabels, describeCapture, planCapture } from "
15
15
  import { mkdirSync, statSync } from "node:fs";
16
16
  import { join, resolve } from "node:path";
17
17
  import { pathToFileURL } from "node:url";
18
- import { buildTrace, describeBudget, num, resolveProfile, str } from "./trace.js";
18
+ import { alsoInWindowOf, alsoInWindowSentence, buildTrace, describeBudget, num, resolveProfile, str, } from "./trace.js";
19
+ import { timelineKindsDescription } from "./eventKinds.js";
19
20
  import { UNKNOWN_DEVICE_ID, clippedMsOf, fillWindowFromDisk, sessionsRoot as sessionsRootPath, } from "./sessions.js";
20
21
  import { InvalidScenarioError, buildSavedTrace, coverageNote, defaultOutPath, defaultScenarioName, validateScenario, writeSavedTrace } from "./save.js";
21
22
  import { Watermark, buildBanner, classificationSummary, classify } from "./watermark.js";
@@ -24,6 +25,12 @@ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url),
24
25
  const HOST = process.env.PORTHOLE_HOST ?? "127.0.0.1";
25
26
  const PORT = Number(process.env.PORTHOLE_PORT ?? 8677);
26
27
  const UI_PORT = Number(process.env.PORTHOLE_UI_PORT ?? 8678);
28
+ /**
29
+ * GRA-197: the plugin's own knowledge of which app this server is for, when
30
+ * it wrote one — absent (not empty) when it did not, which is what tells
31
+ * `DeviceClient` to skip the check entirely rather than compare against "".
32
+ */
33
+ const APPLICATION_ID = process.env.PORTHOLE_APPLICATION_ID || undefined;
27
34
  /**
28
35
  * GRA-89: how much longer than the plan's own recording duration
29
36
  * `capture_system_trace` gives the on-device `perfetto` invocation before
@@ -136,7 +143,8 @@ export function createPortholeServer(options = {}) {
136
143
  // persistence; a test that injects its own `options.device` (the harness
137
144
  // in `testing/harness.ts`, or a hand-built fake) is unaffected — this
138
145
  // branch only runs when nothing was injected.
139
- const device = options.device ?? new DeviceClient(HOST, PORT, sessionsRootPath(resolveProjectRoot().directory));
146
+ const device = options.device ??
147
+ new DeviceClient(HOST, PORT, sessionsRootPath(resolveProjectRoot().directory), APPLICATION_ID);
140
148
  const timeline = options.timeline ?? new TimelineServer(device, UI_PORT);
141
149
  const adbEnv = options.adbEnv;
142
150
  const adbBinary = options.adbBinary;
@@ -679,7 +687,16 @@ export function createPortholeServer(options = {}) {
679
687
  const firstEver = pendingFirstEverNote;
680
688
  pendingFirstEverNote = null;
681
689
  const narrated = firstEver ? `${firstEver}${summary}` : summary;
682
- const withBanner = banner ? `${banner}\n${narrated}` : narrated;
690
+ // GRA-197: "warn loudly, do not refuse" means every successful result,
691
+ // from every tool, leads with the package mismatch while one stands —
692
+ // here, in the one place all of them pass through, so no tool can
693
+ // forget it (the same reason the GRA-55 banner lives here and not in
694
+ // each handler). A summary that already *is* the mismatch text —
695
+ // porthole_status's, and findings' empty-ring branch — is left alone
696
+ // rather than said twice.
697
+ const mismatch = device.packageMismatch;
698
+ const led = mismatch && !summary.startsWith(mismatch) ? `⚠ ${mismatch}\n${narrated}` : narrated;
699
+ const withBanner = banner ? `${banner}\n${led}` : led;
683
700
  const withSinceLast = payload !== null && typeof payload === "object" && !Array.isArray(payload)
684
701
  ? { ...payload, sinceLast }
685
702
  : payload;
@@ -825,6 +842,9 @@ export function createPortholeServer(options = {}) {
825
842
  // reading structured data (not just the text) can branch on it
826
843
  // without string-matching `summary`.
827
844
  protocolMismatch: device.protocolMismatch,
845
+ // GRA-197: same shape, beside it — null unless PORTHOLE_APPLICATION_ID
846
+ // was configured and disagrees with the connected hello.
847
+ packageMismatch: device.packageMismatch,
828
848
  sdkDir: sdkDir.directory,
829
849
  sdkDirSource: sdkDir.source,
830
850
  projectRoot: projectRoot.directory,
@@ -833,16 +853,20 @@ export function createPortholeServer(options = {}) {
833
853
  exits,
834
854
  exitTrace: exitTraceResult,
835
855
  };
836
- // GRA-96: a protocol mismatch takes priority over the normal "here is
856
+ // GRA-96/GRA-197: a mismatch takes priority over the normal "here is
837
857
  // what's connected" sentence — hello did land and the socket is fine,
838
- // but the one thing worth saying is that the two sides disagree on the
839
- // wire format, not the collector list a mismatched build may not even
840
- // be able to report honestly. This is what turns AC1's "specific,
841
- // actionable message... not a generic failure" into the actual summary
842
- // text an agent reads, rather than a field it has to know to check.
858
+ // but the one thing worth saying is that something disagrees, not the
859
+ // collector list a mismatched build may not even be able to report
860
+ // honestly. packageMismatch leads: talking to the wrong app entirely
861
+ // is the more fundamental problem, and its protocol is not this
862
+ // server's concern until it is talking to the right one. This is what
863
+ // turns AC1's "specific, actionable message... not a generic failure"
864
+ // into the actual summary text an agent reads, rather than a field it
865
+ // has to know to check.
843
866
  const summary = notice +
844
867
  deathNotice +
845
868
  (pending ??
869
+ device.packageMismatch ??
846
870
  device.protocolMismatch ??
847
871
  `Connected to ${device.hello.packageName} on ${device.hello.device} ` +
848
872
  `(API ${device.hello.sdkInt}). Collectors: ${device.hello.collectors.join(", ")}.`);
@@ -866,7 +890,13 @@ export function createPortholeServer(options = {}) {
866
890
  "there being nothing there.\n\n" +
867
891
  "An empty list means nothing crossed a threshold in this window. It does not mean the app " +
868
892
  "is fast, and it does not mean the window contained the problem — check `window` against " +
869
- "the moment you care about before concluding anything from silence.",
893
+ "the moment you care about before concluding anything from silence.\n\n" +
894
+ "`alsoInWindow` (present only when there is something to say) is an inventory, not a second " +
895
+ "opinion: process exits, device events, memory samples, GC and memory-trim signals that " +
896
+ "were in the window whether or not they crossed a threshold worth a finding — an exit " +
897
+ "already covered by a finding above still appears here too, because a finding is a " +
898
+ "judgement and this is a count. Absent means genuinely nothing to add, not that this tool " +
899
+ "declined to look.",
870
900
  inputSchema: windowShape,
871
901
  annotations: { readOnlyHint: true },
872
902
  }, async ({ sinceMs, from, to, since }) => {
@@ -908,6 +938,13 @@ export function createPortholeServer(options = {}) {
908
938
  if (pending !== null) {
909
939
  return ok(notice + pending, { window: null, findings: [], connected, exitedProcess });
910
940
  }
941
+ // GRA-197: the same "leads with it" rule porthole_status's summary
942
+ // follows, on an otherwise unrelated tool — a mismatched app is worth
943
+ // saying here too, not only from porthole_status, since this is
944
+ // often the first tool an agent calls.
945
+ if (device.packageMismatch) {
946
+ return ok(notice + device.packageMismatch, { window: null, findings: [], connected, exitedProcess });
947
+ }
911
948
  const summary = `Connected to ${device.hello.packageName}, nothing buffered yet. Ask again in a moment.`;
912
949
  return ok(notice + summary, { window: null, findings: [], connected, exitedProcess });
913
950
  }
@@ -1014,6 +1051,12 @@ export function createPortholeServer(options = {}) {
1014
1051
  profile,
1015
1052
  });
1016
1053
  const findings = trace.findings.map(withFollowUp);
1054
+ // GRA-200: built from the same windowed `events` `trace` itself came
1055
+ // from, so this can never name a different window than the findings
1056
+ // beside it. See alsoInWindowOf's own comment in trace.ts for why an
1057
+ // exit that already produced a finding still appears here too.
1058
+ const also = alsoInWindowOf(events);
1059
+ const alsoSentence = alsoInWindowSentence(also);
1017
1060
  // GRA-55: classified against whatever the *previous* findings call
1018
1061
  // left in the watermark, before this call's own digest overwrites it
1019
1062
  // — order matters here, `recordDigest` below must come after reading
@@ -1050,6 +1093,13 @@ export function createPortholeServer(options = {}) {
1050
1093
  findings: classified.findings,
1051
1094
  connected,
1052
1095
  exitedProcess,
1096
+ // GRA-200: absent, not `{}` or all-undefined, when there is nothing
1097
+ // to list — see alsoInWindowOf's own comment for why this is what
1098
+ // keeps the common case's payload byte-identical to before this
1099
+ // ticket. The spread (not `alsoInWindow: also`) is what actually
1100
+ // omits the key when `also` is `undefined`, rather than shipping a
1101
+ // key whose value happens to be `undefined`.
1102
+ ...(also ? { alsoInWindow: also } : {}),
1053
1103
  };
1054
1104
  const shortfall = clipped.start + clipped.end;
1055
1105
  const missing = shortfall > 0
@@ -1063,7 +1113,8 @@ export function createPortholeServer(options = {}) {
1063
1113
  "it is a question the buffer cannot answer."
1064
1114
  : `Nothing crossed a threshold in the ${Math.round(span.ms / 1000)}s examined ` +
1065
1115
  `(${events.length} events). That is not the same as the app being fast.${missing}`) +
1066
- classificationNote, payload);
1116
+ classificationNote +
1117
+ (alsoSentence ? ` ${alsoSentence}` : ""), payload);
1067
1118
  }
1068
1119
  const worst = trace.findings[0];
1069
1120
  const bySeverity = trace.findings.reduce((acc, f) => {
@@ -1075,7 +1126,8 @@ export function createPortholeServer(options = {}) {
1075
1126
  .join(", ");
1076
1127
  return ok(notice +
1077
1128
  `${findings.length} finding(s) over ${Math.round(span.ms / 1000)}s (${tally}). ` +
1078
- `Worst: ${worst.title} [${worst.confidence}].${missing}${classificationNote}`, payload);
1129
+ `Worst: ${worst.title} [${worst.confidence}].${missing}${classificationNote}` +
1130
+ (alsoSentence ? ` ${alsoSentence}` : ""), payload);
1079
1131
  });
1080
1132
  server.registerTool("system_context", {
1081
1133
  title: "What the rest of the device was doing",
@@ -1922,11 +1974,7 @@ export function createPortholeServer(options = {}) {
1922
1974
  "what the app was doing while a call was open.",
1923
1975
  inputSchema: {
1924
1976
  ...windowShape,
1925
- kinds: z
1926
- .array(z.string())
1927
- .optional()
1928
- .describe("Filter by event name: recompose, state_write, frame, nav, http_start, http_end, " +
1929
- "db_start, db_end, log."),
1977
+ kinds: z.array(z.string()).optional().describe(timelineKindsDescription()),
1930
1978
  limit: z
1931
1979
  .number()
1932
1980
  .int()