@floomhq/signaldash 0.7.0 → 0.8.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.
Files changed (2) hide show
  1. package/bin/sd.mjs +34 -22
  2. package/package.json +1 -1
package/bin/sd.mjs CHANGED
@@ -276,36 +276,48 @@ export async function cmdStatus(dependencies = {}) {
276
276
 
277
277
  export async function cmdConnections(outPath, dependencies = {}) {
278
278
  const log = dependencies.log || console.log;
279
- const error = dependencies.error || console.error;
280
279
  const request = dependencies.request || api;
281
280
  const { chalk, ora } = await ui();
282
- const spin = ora({ text: "Fetching your LinkedIn connections...", indent: 2 }).start();
283
- const r = await request("/li/connections", {});
284
- if (r.status >= 300) { spin.fail(r.json.error || "failed"); process.exitCode = 1; return; }
285
- const rows = r.json.connections || [];
281
+ const { writeFileSync: wf, readFileSync: rf, existsSync: ex } = await import("node:fs");
282
+ const file = outPath || "linkedin-connections.csv";
283
+
284
+ // Resume support: keep the cursor next to the CSV so a large network is
285
+ // fetched over several paced passes instead of one burst (LinkedIn detection
286
+ // is behavioural; bursts are what get accounts flagged).
287
+ const stateFile = file + ".state.json";
288
+ let cursor = null, rows = [];
289
+ if (ex(stateFile)) {
290
+ try {
291
+ const prev = JSON.parse(rf(stateFile, "utf8"));
292
+ cursor = prev.cursor || null; rows = prev.rows || [];
293
+ if (cursor) log(" " + chalk.dim(`resuming from previous run (${rows.length} already fetched)`));
294
+ } catch {}
295
+ }
296
+
297
+ const spin = ora({ text: "Fetching connections (paced, this is deliberate)...", indent: 2 }).start();
298
+ for (;;) {
299
+ const r = await request("/li/connections", { cursor, max_pages: 10 });
300
+ if (r.status >= 300) {
301
+ spin.fail(r.json.error || "failed");
302
+ if (rows.length) { wf(stateFile, JSON.stringify({ cursor, rows })); log(" " + chalk.dim("progress saved; run again to resume")); }
303
+ process.exitCode = 1; return;
304
+ }
305
+ rows = rows.concat(r.json.connections || []);
306
+ cursor = r.json.next_cursor;
307
+ spin.text = `Fetched ${rows.length} connections...`;
308
+ if (!cursor) break;
309
+ wf(stateFile, JSON.stringify({ cursor, rows }));
310
+ }
286
311
  spin.succeed(`${rows.length} connections`);
287
- const { writeFileSync: wf } = await import("node:fs");
312
+
288
313
  const esc = v => `"${String(v ?? "").replace(/"/g, '""')}"`;
289
314
  const csv = ["name,headline,public_id,profile_url,connected_at",
290
315
  ...rows.map(c => [c.name, c.headline, c.public_id, c.profile_url, c.connected_at].map(esc).join(","))].join("\n");
291
- const file = outPath || "linkedin-connections.csv";
292
316
  wf(file, csv);
317
+ try { const { unlinkSync } = await import("node:fs"); if (ex(stateFile)) unlinkSync(stateFile); } catch {}
293
318
  log(" " + chalk.green("+") + " saved " + chalk.cyan(file));
294
- }
295
-
296
-
297
- function printHelp(log = console.log) {
298
- log(`SignalDash — secure LinkedIn + WhatsApp access for your agent.
299
-
300
- signaldash <invite-code> set up everything in one go
301
- signaldash status show what is connected
302
- signaldash connect linkedin|whatsapp connect a channel
303
- signaldash connections [file.csv] export your LinkedIn connections
304
- signaldash skill install the agent skill
305
- signaldash mcp run the MCP server (used by your agent)
306
- signaldash logout revoke this device
307
-
308
- The agent reaches your channels only through SignalDash. No keys on your machine.`);
319
+ log(" " + chalk.dim("Tip: LinkedIn's own export (Settings > Get a copy of your data) is zero-risk"));
320
+ log(" " + chalk.dim("and includes emails. Both work; that one never touches the API."));
309
321
  }
310
322
 
311
323
  export async function main(argv = process.argv.slice(2), dependencies = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floomhq/signaldash",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Secure LinkedIn and WhatsApp MCP access for AI agents",
5
5
  "type": "module",
6
6
  "bin": {