@thecorporation/cli 26.3.10 → 26.3.11

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
@@ -15,12 +15,25 @@ npm install -g @thecorporation/cli
15
15
  ## Quick Start
16
16
 
17
17
  ```bash
18
- corp setup # interactive first-run wizard
18
+ corp setup # authenticate via magic link
19
19
  corp status # workspace summary
20
20
  corp chat # AI assistant with full tool access
21
21
  corp form --type llc --name "Acme" # form a new entity
22
22
  ```
23
23
 
24
+ ## Authentication
25
+
26
+ `corp setup` authenticates via magic link:
27
+
28
+ 1. Enter your name and email
29
+ 2. Check your email for a sign-in link from TheCorporation
30
+ 3. Copy the code from the link URL and paste it into the terminal
31
+ 4. Credentials are saved to `~/.corp/config.json`
32
+
33
+ Your workspace is shared across the CLI, [MCP server](https://www.npmjs.com/package/@thecorporation/mcp-server), and [chat](https://humans.thecorporation.ai/chat) — all keyed on your email.
34
+
35
+ For self-hosted setups (`CORP_API_URL` pointing to your own server), `corp setup` provisions a workspace directly without requiring a magic link.
36
+
24
37
  ## Commands
25
38
 
26
39
  ### Core
@@ -204,7 +217,7 @@ Inside `corp chat`, these slash commands are available:
204
217
 
205
218
  ## Configuration
206
219
 
207
- Config is stored at `~/.corp/config.json`. The `corp setup` wizard will populate it, or set values manually:
220
+ Config is stored at `~/.corp/config.json`. `corp setup` populates it via magic link auth. You can also set values manually:
208
221
 
209
222
  ```bash
210
223
  corp config set api_url https://api.thecorporation.ai
package/dist/index.js CHANGED
@@ -479,25 +479,112 @@ __export(setup_exports, {
479
479
  setupCommand: () => setupCommand
480
480
  });
481
481
  import { input, confirm } from "@inquirer/prompts";
482
+ async function requestMagicLink(apiUrl, email, tosAccepted) {
483
+ const resp = await fetch(`${apiUrl}/v1/auth/magic-link`, {
484
+ method: "POST",
485
+ headers: { "Content-Type": "application/json" },
486
+ body: JSON.stringify({ email, tos_accepted: tosAccepted })
487
+ });
488
+ if (!resp.ok) {
489
+ const data = await resp.json().catch(() => ({}));
490
+ const detail = data?.error ?? data?.message ?? resp.statusText;
491
+ throw new Error(
492
+ typeof detail === "string" ? detail : JSON.stringify(detail)
493
+ );
494
+ }
495
+ }
496
+ async function verifyMagicLinkCode(apiUrl, code) {
497
+ const resp = await fetch(`${apiUrl}/v1/auth/magic-link/verify`, {
498
+ method: "POST",
499
+ headers: { "Content-Type": "application/json" },
500
+ body: JSON.stringify({ code, client: "cli" })
501
+ });
502
+ const data = await resp.json().catch(() => ({}));
503
+ if (!resp.ok) {
504
+ const detail = data?.error ?? data?.message ?? resp.statusText;
505
+ throw new Error(
506
+ typeof detail === "string" ? detail : JSON.stringify(detail)
507
+ );
508
+ }
509
+ if (!data.api_key || !data.workspace_id) {
510
+ throw new Error("Unexpected response \u2014 missing api_key or workspace_id");
511
+ }
512
+ return {
513
+ api_key: data.api_key,
514
+ workspace_id: data.workspace_id
515
+ };
516
+ }
517
+ function isCloudApi(url) {
518
+ return url.replace(/\/+$/, "").includes("thecorporation.ai");
519
+ }
520
+ async function magicLinkAuth(apiUrl, email) {
521
+ console.log("\nSending magic link to " + email + "...");
522
+ await requestMagicLink(apiUrl, email, true);
523
+ console.log("Check your email for a sign-in link from TheCorporation.");
524
+ console.log(
525
+ "Copy the code from the URL (the ?code=... part) and paste it below.\n"
526
+ );
527
+ const code = await input({ message: "Paste your magic link code" });
528
+ const trimmed = code.trim().replace(/^.*[?&]code=/, "");
529
+ if (!trimmed) {
530
+ throw new Error("No code provided");
531
+ }
532
+ console.log("Verifying...");
533
+ return verifyMagicLinkCode(apiUrl, trimmed);
534
+ }
482
535
  async function setupCommand() {
483
536
  const cfg = loadConfig();
484
537
  console.log("Welcome to corp \u2014 corporate governance from the terminal.\n");
485
- cfg.api_url = API_URL;
538
+ const customUrl = process.env.CORP_API_URL;
539
+ if (customUrl) {
540
+ cfg.api_url = customUrl.replace(/\/+$/, "");
541
+ console.log(`Using API: ${cfg.api_url}
542
+ `);
543
+ } else {
544
+ cfg.api_url = CLOUD_API_URL;
545
+ }
486
546
  console.log("--- User Info ---");
487
547
  const user = cfg.user ?? { name: "", email: "" };
488
- user.name = await input({ message: "Your name", default: user.name || void 0 });
489
- user.email = await input({ message: "Your email", default: user.email || void 0 });
548
+ user.name = await input({
549
+ message: "Your name",
550
+ default: user.name || void 0
551
+ });
552
+ user.email = await input({
553
+ message: "Your email",
554
+ default: user.email || void 0
555
+ });
490
556
  cfg.user = user;
491
- if (!cfg.api_key || !cfg.workspace_id) {
492
- console.log("\nProvisioning workspace...");
493
- try {
494
- const result = await provisionWorkspace(cfg.api_url, `${user.name}'s workspace`);
495
- cfg.api_key = result.api_key;
496
- cfg.workspace_id = result.workspace_id;
497
- console.log(`Workspace provisioned: ${result.workspace_id}`);
498
- } catch (err) {
499
- printError(`Auto-provision failed: ${err}`);
500
- console.log("You can manually set credentials with: corp config set api_key <key>");
557
+ const needsAuth = !cfg.api_key || !cfg.workspace_id;
558
+ const cloud = isCloudApi(cfg.api_url);
559
+ if (needsAuth) {
560
+ if (cloud) {
561
+ try {
562
+ const result = await magicLinkAuth(cfg.api_url, user.email);
563
+ cfg.api_key = result.api_key;
564
+ cfg.workspace_id = result.workspace_id;
565
+ printSuccess(`Authenticated. Workspace: ${result.workspace_id}`);
566
+ } catch (err) {
567
+ printError(`Authentication failed: ${err}`);
568
+ console.log(
569
+ "You can manually set credentials with: corp config set api_key <key>"
570
+ );
571
+ }
572
+ } else {
573
+ console.log("\nProvisioning workspace...");
574
+ try {
575
+ const result = await provisionWorkspace(
576
+ cfg.api_url,
577
+ `${user.name}'s workspace`
578
+ );
579
+ cfg.api_key = result.api_key;
580
+ cfg.workspace_id = result.workspace_id;
581
+ console.log(`Workspace provisioned: ${result.workspace_id}`);
582
+ } catch (err) {
583
+ printError(`Auto-provision failed: ${err}`);
584
+ console.log(
585
+ "You can manually set credentials with: corp config set api_key <key>"
586
+ );
587
+ }
501
588
  }
502
589
  } else {
503
590
  console.log("\nVerifying existing credentials...");
@@ -514,21 +601,33 @@ async function setupCommand() {
514
601
  console.log("Credentials OK.");
515
602
  } else {
516
603
  console.log("API key is no longer valid.");
517
- const reprovision = await confirm({
518
- message: "Provision a new workspace? (This will replace your current credentials)",
519
- default: false
604
+ const reauth = await confirm({
605
+ message: cloud ? "Re-authenticate via magic link?" : "Provision a new workspace? (This will replace your current credentials)",
606
+ default: true
520
607
  });
521
- if (reprovision) {
608
+ if (reauth) {
522
609
  try {
523
- const result = await provisionWorkspace(cfg.api_url, `${user.name}'s workspace`);
524
- cfg.api_key = result.api_key;
525
- cfg.workspace_id = result.workspace_id;
526
- console.log(`Workspace provisioned: ${result.workspace_id}`);
610
+ if (cloud) {
611
+ const result = await magicLinkAuth(cfg.api_url, user.email);
612
+ cfg.api_key = result.api_key;
613
+ cfg.workspace_id = result.workspace_id;
614
+ printSuccess(`Authenticated. Workspace: ${result.workspace_id}`);
615
+ } else {
616
+ const result = await provisionWorkspace(
617
+ cfg.api_url,
618
+ `${user.name}'s workspace`
619
+ );
620
+ cfg.api_key = result.api_key;
621
+ cfg.workspace_id = result.workspace_id;
622
+ console.log(`Workspace provisioned: ${result.workspace_id}`);
623
+ }
527
624
  } catch (err) {
528
- printError(`Provisioning failed: ${err}`);
625
+ printError(`Authentication failed: ${err}`);
529
626
  }
530
627
  } else {
531
- console.log("Keeping existing credentials. You can manually update with: corp config set api_key <key>");
628
+ console.log(
629
+ "Keeping existing credentials. You can manually update with: corp config set api_key <key>"
630
+ );
532
631
  }
533
632
  }
534
633
  }
@@ -536,14 +635,14 @@ async function setupCommand() {
536
635
  console.log("\nConfig saved to ~/.corp/config.json");
537
636
  console.log("Run 'corp status' to verify your connection.");
538
637
  }
539
- var API_URL;
638
+ var CLOUD_API_URL;
540
639
  var init_setup = __esm({
541
640
  "src/commands/setup.ts"() {
542
641
  "use strict";
543
642
  init_config();
544
643
  init_api_client();
545
644
  init_output();
546
- API_URL = "https://api.thecorporation.ai";
645
+ CLOUD_API_URL = "https://api.thecorporation.ai";
547
646
  }
548
647
  });
549
648