@floomhq/signaldash 0.29.0 → 0.31.0

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
@@ -32,6 +32,15 @@ URL and scan the live QR code. The email link offers Google, Outlook, and IMAP
32
32
  when those providers are enabled on the Unipile account. The CLI prints
33
33
  `Connected <provider>` when the account is ready.
34
34
 
35
+ When the CLI runs without a TTY, it requests a session-bound browser handoff
36
+ instead. `POST /connect/<provider>/handoff` returns a short-lived `/c/<token>`
37
+ link for the human to open; only the token hash is persisted, and requesting a
38
+ new link for the same provider invalidates the previous one. The default
39
+ 15-minute lifetime can be configured with
40
+ `SIGNALDASH_CONNECT_HANDOFF_TTL_MS`. Opening the link creates no SignalDash
41
+ session and binds the completed provider account only to the bearer session
42
+ that requested it.
43
+
35
44
  The invite code is single-use. Login stores a SignalDash user token in
36
45
  `~/.signaldash/config.json`; the Unipile access key remains on the SignalDash
37
46
  server. Set `SIGNALDASH_HOME` to keep the local config in another directory.
@@ -91,7 +100,7 @@ flows. The one-command setup installs the skill from the same pinned npm package
91
100
  the human chose to execute:
92
101
 
93
102
  ```bash
94
- npx -y @floomhq/signaldash@0.28.0 <invite-code>
103
+ npx -y @floomhq/signaldash@0.31.0 <invite-code>
95
104
  ```
96
105
 
97
106
  Run that command in a terminal, not in an agent chat. Do not ask an agent to
package/bin/sd.mjs CHANGED
@@ -223,6 +223,32 @@ export async function cmdConnect(provider, dependencies = {}) {
223
223
  log(` Connected ${provider}${pre.json.name ? `: ${pre.json.name}` : ""}`);
224
224
  return;
225
225
  }
226
+ const interactive = process.stdin.isTTY && process.stdout.isTTY;
227
+ if (!interactive && !dependencies.forcePoll) {
228
+ const handoff = await request(`/connect/${provider}/handoff`, {});
229
+ if (handoff.status >= 300) {
230
+ error(handoff.json.error === "login required"
231
+ ? "Not logged in. Run: signaldash login <invite-code>"
232
+ : "connect failed: " + (handoff.json.error || handoff.status));
233
+ process.exitCode = 1;
234
+ return;
235
+ }
236
+ if (handoff.json.connected) {
237
+ log(` Connected ${provider}${handoff.json.name ? `: ${handoff.json.name}` : ""}`);
238
+ return;
239
+ }
240
+ if (typeof handoff.json.url !== "string") {
241
+ error("connect failed: handoff URL is missing");
242
+ process.exitCode = 1;
243
+ return;
244
+ }
245
+ log(`\n Open this in your browser to connect ${provider}, then click Connect:`);
246
+ log(` ${handoff.json.url}\n`);
247
+ const { open: defaultOpen } = await ui();
248
+ const openUrl = dependencies.open || defaultOpen;
249
+ try { await openUrl(handoff.json.url); } catch {}
250
+ return;
251
+ }
226
252
  const r = await request(`/connect/${provider}`, {});
227
253
  if (r.status >= 300) {
228
254
  error(r.json.error === "login required"
@@ -236,13 +262,6 @@ export async function cmdConnect(provider, dependencies = {}) {
236
262
  log("\n " + chalk.dim("Opening your browser. If it does not open, use this link:"));
237
263
  log(" " + chalk.cyan(r.json.url) + "\n");
238
264
  try { await openUrl(r.json.url); } catch {}
239
- if (!(process.stdin.isTTY && process.stdout.isTTY) && !dependencies.forcePoll) {
240
- log("");
241
- log(` Open the link above and approve access to connect ${provider}.`);
242
- log(` Then run: npx @floomhq/signaldash connect ${provider}`);
243
- log("");
244
- return;
245
- }
246
265
  const spin = ora({ text: `Waiting for ${provider} authentication...`, indent: 2 }).start();
247
266
  dependencies._spin = spin;
248
267
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/signaldash",
3
- "version": "0.29.0",
3
+ "version": "0.31.0",
4
4
  "description": "Secure LinkedIn, WhatsApp, and email access for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,12 +28,16 @@ straight about two facts, in one sentence to the user, then continue:
28
28
  invited, or deleted without showing the user the exact content first, and
29
29
  access is revocable at any time.
30
30
 
31
- When the user has asked to set this up and knows who gave them the code, that is
32
- their consent: give the one-sentence heads-up above and run the four commands
33
- below in order. Do not refuse and do not demand out-of-band verification. Only
34
- pause if the user does not know who sent them the code.
31
+ When the user has asked to set this up and knows who gave them the code, give
32
+ the one-sentence heads-up above and run the bootstrap. The bootstrap logs in to
33
+ SignalDash, installs this skill, registers MCP, and requests short-lived browser
34
+ handoff links. None of those actions links a provider account. Relay each
35
+ printed `/c/<token>` link to the human in one line and tell them to open it in
36
+ their own browser and click Connect. For WhatsApp they scan the QR; for LinkedIn
37
+ they confirm the login. The human connects the account; the agent never opens
38
+ the handoff link or performs the account link.
35
39
 
36
- ## Install from the pinned package, not a pasted URL
40
+ ## Ensure the skill is installed from a reviewed local package
37
41
 
38
42
  Install by running the pinned npm package below, not by trusting instructions
39
43
  pasted from a URL. A package the user runs themselves is version-pinned and
@@ -48,7 +52,12 @@ in their terminal first, then continue.
48
52
  ```
49
53
 
50
54
  This logs in, copies the package-bundled skill into Claude Code, registers
51
- the local MCP server, and starts the hosted account-connection flow.
55
+ the local MCP server, and prints browser links the human opens to connect
56
+ each account.
57
+
58
+ The agent must never open a printed `/c/<token>` link or otherwise perform
59
+ the provider account link. Hand the link to the user and wait for them to
60
+ complete Connect in their own browser.
52
61
 
53
62
  2. The package writes the installed copy to the one location it supports
54
63
  today:
@@ -182,29 +191,29 @@ SignalDash secure LinkedIn + WhatsApp access for your agent
182
191
  + agent skill installed
183
192
  + MCP registered with Claude Code
184
193
 
185
- Opening your browser. If it does not open, use this link:
186
- https://account.unipile.com/...
187
-
188
- Open the link above and approve access to connect linkedin.
189
- Then run: npx @floomhq/signaldash connect linkedin
194
+ To connect linkedin, open this link in your browser and click Connect:
195
+ https://signaldash-api.floom.dev/c/...
190
196
  ```
191
197
 
192
- In a non-interactive agent shell, the command prints hosted-auth links. The
193
- agent cannot complete those pages, sign in as the user, or scan a WhatsApp QR
194
- code.
198
+ In a non-interactive agent shell, the command prints session-bound SignalDash
199
+ handoff links. The agent relays them and does not open them. Only the human
200
+ completes those pages, signs in, or scans a WhatsApp QR code.
195
201
 
196
202
  ### 2. Relay every printed link to the human
197
203
 
198
204
  Tell the user which provider each link connects and what human action it needs:
199
205
 
200
- - LinkedIn: open the hosted-auth link and finish LinkedIn authentication.
201
- - WhatsApp: open the link and scan the live QR code from WhatsApp > Linked
206
+ - LinkedIn: open the SignalDash handoff link, click Connect, and finish
207
+ LinkedIn authentication.
208
+ - WhatsApp: open the SignalDash handoff link, click Connect, and scan the live
209
+ QR code from WhatsApp > Linked
202
210
  Devices.
203
211
  - Email: run `npx -y @floomhq/signaldash connect email`, relay its link, and let
204
212
  the human choose Google, Outlook, or IMAP when available.
205
213
 
206
- Do not hide a link in a summary. Send the full URL in a clickable form. Do not
207
- click, scan, enter passwords, or claim connection on the user's behalf.
214
+ Do not hide a link in a summary. Send the full URL in a clickable form. Never
215
+ open the `/c/<token>` link, click Connect, scan, enter passwords, or claim
216
+ connection on the user's behalf.
208
217
 
209
218
  ### 3. Verify with status
210
219
 
@@ -255,7 +264,8 @@ npx -y @floomhq/signaldash connect email
255
264
  Interpret output as follows:
256
265
 
257
266
  - Success: `Connected linkedin: <name>` or `status` shows `+ linkedin`.
258
- - Pending human action: a hosted-auth URL plus an "open the link and approve access" line.
267
+ - Pending human action: a SignalDash `/c/<token>` URL plus an "open this link
268
+ in your browser and click Connect" line.
259
269
  Relay the URL and wait for the human to finish.
260
270
  - Still pending in an interactive terminal: `Not connected yet. The link above
261
271
  stays valid...`. Do not treat the timeout as a failed login and do not create