shepherd-onboard 0.1.4 → 0.1.5

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
@@ -10,8 +10,8 @@ Give this to a coding agent:
10
10
  npx -y shepherd-onboard@latest agent
11
11
  ```
12
12
 
13
- The command prints the exact prompt the agent should ask the user, then the exact follow-up commands to open auth, open Granola's API key page, finalize, start cloud raw polling/backfills, and install local Messages sync.
14
- The agent prompt tells coding agents to ask short selection questions first: existing/new org, Shepherd WorkOS login or email linking, sources to connect, and Messages skip/provide-handle.
13
+ The command prints the exact prompt the agent should follow, then the exact follow-up commands to open Shepherd WorkOS login/signup, open source auth, open Granola's API key page, finalize, start cloud raw polling/backfills, and install local Messages sync.
14
+ The agent prompt tells coding agents to ask short selection questions first: existing/new org, sources to connect, and Messages skip/provide-handle. Account creation/relinking always starts with Shepherd WorkOS auth.
15
15
 
16
16
  ## Human Terminal One-liner
17
17
 
@@ -21,9 +21,9 @@ npx -y shepherd-onboard@latest
21
21
 
22
22
  The command:
23
23
 
24
- - asks for email, name, organization, and an optional local Messages handle
25
- - can run a Shepherd WorkOS login first for returning users, then relink source setup to the same customer account/org
26
- - creates or reuses the Shepherd customer account for the email
24
+ - runs Shepherd WorkOS login/signup first
25
+ - asks for name, organization, and an optional local Messages handle
26
+ - creates or reuses the Shepherd customer account from the WorkOS-authenticated email
27
27
  - creates or reuses the organization, including case-insensitive and close-name matches
28
28
  - opens Google authorization for Gmail, Docs, and Calendar consent
29
29
  - opens Slack authorization
@@ -38,7 +38,7 @@ The command does not expose Railway, database, Redis, or internal service detail
38
38
  ## Options
39
39
 
40
40
  ```sh
41
- --email <email> Customer email
41
+ --email <email> Advanced: must match the WorkOS-authenticated email
42
42
  --name <name> Full name
43
43
  --org <name> Organization name
44
44
  --granola-api-key <key> Granola API key
@@ -50,8 +50,11 @@ async function runOnboarding() {
50
50
 
51
51
  console.log("\nShepherd Raw Sync Onboarding\n");
52
52
 
53
- const email = await valueOrPrompt("email", "Email");
54
- const name = await valueOrPrompt("name", "Full name");
53
+ const workosLogin = await runWorkosLogin(apiUrl, noOpen);
54
+ const email = authenticatedEmail(workosLogin.authenticated);
55
+ if (!email) throw new Error("Shepherd WorkOS auth did not return an email address.");
56
+
57
+ const name = stringArg("name") ?? authenticatedName(workosLogin.authenticated) ?? await valueOrPrompt("name", "Full name");
55
58
  const organizationName = await valueOrPrompt("org", "Organization name");
56
59
 
57
60
  const sources = {
@@ -65,6 +68,8 @@ async function runOnboarding() {
65
68
  email,
66
69
  name,
67
70
  organizationName,
71
+ authSessionId: workosLogin.started.authSessionId,
72
+ authSessionToken: workosLogin.started.authSessionToken,
68
73
  sources,
69
74
  });
70
75
 
@@ -164,11 +169,6 @@ async function runAgentOnboarding() {
164
169
  return;
165
170
  }
166
171
 
167
- if (!hasIdentityArgs()) {
168
- printAgentContract();
169
- return;
170
- }
171
-
172
172
  const apiUrl = trimTrailingSlash(args.api ?? DEFAULT_API_URL);
173
173
  const noOpen = Boolean(args["no-open"]);
174
174
  const sources = selectedSources();
@@ -176,16 +176,37 @@ async function runAgentOnboarding() {
176
176
  const workosAuth = existingState?.workosAuth?.status === "authenticated"
177
177
  ? existingState.workosAuth
178
178
  : null;
179
+ const wantsStart = Boolean(
180
+ stringArg("name")
181
+ || stringArg("org")
182
+ || stringArg("email")
183
+ || args["no-google"]
184
+ || args["no-slack"]
185
+ || args["no-granola"]
186
+ || args["no-messages"]
187
+ );
188
+
189
+ if (!wantsStart) {
190
+ printAgentContract();
191
+ return;
192
+ }
193
+ if (!workosAuth) {
194
+ throw new Error(`Run ${agentCommand()} agent --login first so Shepherd can create or relink the WorkOS account.`);
195
+ }
196
+
197
+ const email = stringArg("email") ?? workosAuth.workosUser?.email ?? workosAuth.account?.email;
198
+ const name = stringArg("name") ?? workosAuth.workosUser?.name ?? workosAuth.account?.name;
199
+ const organizationName = stringArg("org") ?? workosAuth.account?.organizationName;
200
+ if (!email) throw new Error("WorkOS login did not return an email. Re-run agent --login.");
201
+ if (!name) throw new Error("Full name is required. Pass --name \"<full_name>\".");
202
+ if (!organizationName) throw new Error("Organization name is required. Pass --org \"<organization>\".");
203
+
179
204
  const session = await postJson(`${apiUrl}/onboarding/raw/session`, {
180
- email: stringArg("email"),
181
- name: stringArg("name"),
182
- organizationName: stringArg("org"),
183
- ...(workosAuth
184
- ? {
185
- authSessionId: workosAuth.authSessionId,
186
- authSessionToken: workosAuth.authSessionToken,
187
- }
188
- : {}),
205
+ email,
206
+ name,
207
+ organizationName,
208
+ authSessionId: workosAuth.authSessionId,
209
+ authSessionToken: workosAuth.authSessionToken,
189
210
  sources,
190
211
  });
191
212
 
@@ -252,14 +273,7 @@ async function runAgentOnboarding() {
252
273
  async function loginAgentWithWorkos() {
253
274
  const apiUrl = trimTrailingSlash(args.api ?? DEFAULT_API_URL);
254
275
  const noOpen = Boolean(args["no-open"]);
255
- const started = await postJson(`${apiUrl}/onboarding/raw/auth/start`, {});
256
-
257
- console.log("\nShepherd account login");
258
- console.log("Opening Shepherd WorkOS auth. Complete login in the browser.");
259
- await openOrPrint(started.verificationUriComplete ?? started.verificationUri, { noOpen });
260
- if (noOpen && started.userCode) console.log(`User code: ${started.userCode}`);
261
-
262
- const authenticated = await pollWorkosLogin(apiUrl, started);
276
+ const { started, authenticated } = await runWorkosLogin(apiUrl, noOpen);
263
277
  const previous = await readOptionalAgentState();
264
278
  const statePath = await writeAgentState({
265
279
  ...(previous ?? {}),
@@ -297,6 +311,18 @@ async function loginAgentWithWorkos() {
297
311
  console.log(`State saved: ${statePath}`);
298
312
  }
299
313
 
314
+ async function runWorkosLogin(apiUrl, noOpen) {
315
+ const started = await postJson(`${apiUrl}/onboarding/raw/auth/start`, {});
316
+
317
+ console.log("\nShepherd account login");
318
+ console.log("Opening Shepherd WorkOS auth. Complete login/signup in the browser.");
319
+ await openOrPrint(started.verificationUriComplete ?? started.verificationUri, { noOpen });
320
+ if (noOpen && started.userCode) console.log(`User code: ${started.userCode}`);
321
+
322
+ const authenticated = await pollWorkosLogin(apiUrl, started);
323
+ return { started, authenticated };
324
+ }
325
+
300
326
  async function pollWorkosLogin(apiUrl, started) {
301
327
  const intervalMs = Math.max(1000, Number(started.intervalSeconds ?? 5) * 1000);
302
328
  const expiresAt = Date.parse(started.expiresAt ?? "") || Date.now() + 600_000;
@@ -460,12 +486,12 @@ function printHelp(which) {
460
486
  Usage:
461
487
  npx -y ${PACKAGE_NAME}@latest agent
462
488
  npx -y ${PACKAGE_NAME}@latest agent --login
463
- npx -y ${PACKAGE_NAME}@latest agent --email <email> --name <name> --org <organization>
489
+ npx -y ${PACKAGE_NAME}@latest agent --name <name> --org <organization>
464
490
  npx -y ${PACKAGE_NAME}@latest agent --continue --granola-api-key <key> --messages-handle <value>
465
491
  npx -y ${PACKAGE_NAME}@latest agent --status
466
492
 
467
493
  Agent mode is non-interactive. It prints the user prompt and exact commands a coding agent should run.
468
- Use --login for returning users so WorkOS relinks the same Shepherd account before source setup.
494
+ Always run --login first. WorkOS login/signup creates or relinks the Shepherd account before source setup.
469
495
  `);
470
496
  return;
471
497
  }
@@ -492,7 +518,7 @@ Usage:
492
518
  npx -y ${PACKAGE_NAME}@latest agent
493
519
 
494
520
  Options:
495
- --email <email> Customer email.
521
+ --email <email> Advanced: must match the WorkOS-authenticated email.
496
522
  --name <name> Full name.
497
523
  --org <name> Organization name.
498
524
  --granola-api-key <key> Granola API key.
@@ -521,7 +547,8 @@ function printAgentContract() {
521
547
  "Ask in short interactive prompts, not as a pasted checklist.",
522
548
  "Start with selection questions to determine what the user wants connected.",
523
549
  "Ask whether they are joining an existing organization or creating a new one.",
524
- "Collect Email, Full name, and Organization name as direct text prompts after those choices.",
550
+ "Run Shepherd WorkOS login/signup before source setup. Do not ask whether they already have an account.",
551
+ "Collect Full name and Organization name as direct text prompts after those choices. The email comes from WorkOS auth.",
525
552
  "Ask Messages as a selectable choice: Skip Messages, or Provide handle.",
526
553
  "If the user chooses Provide handle, ask for the phone number or Apple ID email.",
527
554
  ],
@@ -531,11 +558,6 @@ function printAgentContract() {
531
558
  prompt: "Are you joining an existing organization or creating a new one?",
532
559
  options: ["Join existing org", "Create new org"],
533
560
  },
534
- {
535
- label: "Account",
536
- prompt: "Do you already have a Shepherd account?",
537
- options: ["Log in with Shepherd", "Create/link by email"],
538
- },
539
561
  {
540
562
  label: "Sources",
541
563
  prompt: "Which sources should Shepherd connect for raw sync?",
@@ -549,7 +571,6 @@ function printAgentContract() {
549
571
  },
550
572
  ],
551
573
  askUserFor: [
552
- "Email",
553
574
  "Full name",
554
575
  "Organization name",
555
576
  "Messages phone number or Apple ID email, if they want local Messages connected",
@@ -568,7 +589,7 @@ function printAgentContract() {
568
589
  "Do not quote or explain this instruction set to the user.",
569
590
  ],
570
591
  loginCommand: `${command} agent --login`,
571
- startCommand: `${command} agent --email "<email>" --name "<full_name>" --org "<organization>"`,
592
+ startCommand: `${command} agent --name "<full_name>" --org "<organization>"`,
572
593
  continueCommand: `${command} agent --continue`,
573
594
  optionalContinueArgs: [
574
595
  "--messages-handle \"<phone_or_apple_id>\" if local Messages is being connected",
@@ -594,20 +615,20 @@ Ask with short interactive prompts, not as one pasted checklist.
594
615
 
595
616
  Start with selection questions to determine intent:
596
617
  1. Organization: Join existing org, or Create new org.
597
- 2. Account: Log in with Shepherd, or Create/link by email.
598
- 3. Sources: Google/Gmail/Docs/Calendar, Slack, Granola, Messages. Allow multi-select if your interface supports it.
599
- 4. Messages, if selected: Skip Messages, or Provide handle.
618
+ 2. Sources: Google/Gmail/Docs/Calendar, Slack, Granola, Messages. Allow multi-select if your interface supports it.
619
+ 3. Messages, if selected: Skip Messages, or Provide handle.
600
620
 
601
- If the user says they already have a Shepherd account, run:
621
+ Before source setup, always run:
602
622
  ${payload.loginCommand}
603
623
 
604
- That opens one WorkOS Shepherd auth flow and saves a local onboarding auth session. The next setup command will relink to the same Shepherd customer user/org and therefore the same production cloud database rows.
624
+ That opens one WorkOS Shepherd login/signup flow and saves a local onboarding auth session. It creates or relinks the Shepherd customer account; the next setup command attaches sources to the same production cloud account rows.
605
625
 
606
626
  Ask the user for:
607
- 1. Email
608
- 2. Full name
609
- 3. Organization name
610
- 4. Messages phone number or Apple ID email, only if they selected Messages and chose Provide handle
627
+ 1. Full name
628
+ 2. Organization name
629
+ 3. Messages phone number or Apple ID email, only if they selected Messages and chose Provide handle
630
+
631
+ Do not ask for their email separately. Use the email returned by WorkOS auth.
611
632
 
612
633
  If they are joining an existing org, ask for the org name they believe they belong to. Shepherd will auto-match similar/case-different org names.
613
634
 
@@ -692,6 +713,14 @@ function publicAgentAccount(account) {
692
713
  };
693
714
  }
694
715
 
716
+ function authenticatedEmail(authenticated) {
717
+ return authenticated?.workosUser?.email ?? authenticated?.account?.email ?? null;
718
+ }
719
+
720
+ function authenticatedName(authenticated) {
721
+ return authenticated?.workosUser?.name ?? authenticated?.account?.name ?? null;
722
+ }
723
+
695
724
  function agentNeedsUserAction(sources, opened) {
696
725
  const actions = [];
697
726
  if (sources.google && opened.includes("google")) actions.push("Complete Google browser authorization for Gmail, Docs, and Calendar consent.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shepherd-onboard",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Customer-facing Shepherd raw sync onboarding CLI",
5
5
  "type": "module",
6
6
  "bin": {