@sjhmars/happy-bridge 0.2.1 → 0.2.3

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/lib/client.js CHANGED
@@ -17,21 +17,21 @@ window.__ModuleLoader__.load({
17
17
  document.head.appendChild(tag);
18
18
  }
19
19
  var HappyBridgeCard_module_css_default = {
20
- "error": "l9rBEq_error",
21
- "row": "l9rBEq_row",
22
20
  "chevron": "l9rBEq_chevron",
21
+ "header": "l9rBEq_header",
22
+ "select": "l9rBEq_select",
23
+ "headText": "l9rBEq_headText",
23
24
  "body": "l9rBEq_body",
25
+ "name": "l9rBEq_name",
26
+ "error": "l9rBEq_error",
27
+ "status": "l9rBEq_status",
28
+ "card": "l9rBEq_card",
24
29
  "button": "l9rBEq_button",
25
30
  "qr": "l9rBEq_qr",
26
- "status": "l9rBEq_status",
27
- "checkbox": "l9rBEq_checkbox",
28
- "name": "l9rBEq_name",
29
- "header": "l9rBEq_header",
30
- "select": "l9rBEq_select",
31
- "description": "l9rBEq_description",
31
+ "row": "l9rBEq_row",
32
32
  "label": "l9rBEq_label",
33
- "headText": "l9rBEq_headText",
34
- "card": "l9rBEq_card"
33
+ "checkbox": "l9rBEq_checkbox",
34
+ "description": "l9rBEq_description"
35
35
  };
36
36
  //#endregion
37
37
  //#region src/client/HappyBridgeCard.tsx
package/lib/index.js CHANGED
@@ -2481,6 +2481,22 @@ var HappySessionSocket = class {
2481
2481
  this.ensureAliveTimer();
2482
2482
  }
2483
2483
  /**
2484
+ * Assert the session state with a reliable (non-volatile) emit: state
2485
+ * transitions must not ride the droppable heartbeat path, or the App
2486
+ * flickers between online and thinking until the next 2s tick.
2487
+ * @param thinking - `true` while the Host turn is still executing.
2488
+ */
2489
+ keepAliveNow(thinking) {
2490
+ this.thinking = thinking;
2491
+ this.socket?.emit("session-alive", {
2492
+ sid: this.happySessionId,
2493
+ time: Date.now(),
2494
+ thinking: this.thinking,
2495
+ mode: "remote"
2496
+ });
2497
+ this.ensureAliveTimer();
2498
+ }
2499
+ /**
2484
2500
  * Restart session-alive if the timer was cleared. Happy lists the row as
2485
2501
  * offline once heartbeats stop; opening the chat on the phone does not
2486
2502
  * start them again.
@@ -3947,7 +3963,9 @@ var HappyBridge = class {
3947
3963
  if (link.alwaysAllow.has(req.toolName)) return "allowed-once";
3948
3964
  if (!grantAtLeast(this.config.remoteGrant, "approve")) return next();
3949
3965
  const id = req.callId;
3950
- this.startTool(link, id, req.toolName, req.reason === void 0 ? {} : { reason: req.reason });
3966
+ const controller = new AbortController();
3967
+ req.signal = req.signal === void 0 ? controller.signal : AbortSignal.any([req.signal, controller.signal]);
3968
+ this.pushRequests(link);
3951
3969
  const phone = new Promise((resolve) => {
3952
3970
  link.pendingHuman = {
3953
3971
  kind: "approval",
@@ -3956,18 +3974,23 @@ var HappyBridge = class {
3956
3974
  resolve
3957
3975
  };
3958
3976
  });
3959
- this.pushRequests(link);
3960
- const winner = await Promise.race([phone.then((outcome) => ({
3961
- src: "phone",
3977
+ const web = next().then((outcome) => ({
3978
+ src: "web",
3962
3979
  outcome
3963
- })), next().then((outcome) => ({
3980
+ }), () => ({
3964
3981
  src: "web",
3982
+ outcome: "cancelled"
3983
+ }));
3984
+ const winner = await Promise.race([phone.then((outcome) => ({
3985
+ src: "phone",
3965
3986
  outcome
3966
- }))]);
3987
+ })), web]);
3988
+ if (winner.src === "phone") controller.abort();
3967
3989
  if (winner.src === "web" && link.pendingHuman?.kind === "approval" && link.pendingHuman.id === id) {
3968
3990
  delete link.pendingHuman;
3969
3991
  this.clearRequest(link, id, winner.outcome === "allowed-once" ? "approved" : "canceled");
3970
3992
  }
3993
+ if (this.running) link.socket.keepAliveNow(true);
3971
3994
  return winner.outcome;
3972
3995
  }
3973
3996
  onAsk(questions, original, request) {
@@ -116,6 +116,13 @@ export declare class HappySessionSocket {
116
116
  * @param thinking - `agent/status === running`.
117
117
  */
118
118
  keepAlive(thinking: boolean): void;
119
+ /**
120
+ * Assert the session state with a reliable (non-volatile) emit: state
121
+ * transitions must not ride the droppable heartbeat path, or the App
122
+ * flickers between online and thinking until the next 2s tick.
123
+ * @param thinking - `true` while the Host turn is still executing.
124
+ */
125
+ keepAliveNow(thinking: boolean): void;
119
126
  /**
120
127
  * Restart session-alive if the timer was cleared. Happy lists the row as
121
128
  * offline once heartbeats stop; opening the chat on the phone does not
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sjhmars/happy-bridge",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Pair an already-running dsh web/desktop client with Happy App so the phone remote-controls the same harness sessions",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",