@displaydev/cli 0.2.1 → 0.3.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 (3) hide show
  1. package/README.md +31 -0
  2. package/dist/main.js +130 -55
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -18,6 +18,37 @@ dsp login
18
18
  export DISPLAYDEV_API_KEY=sk_live_...
19
19
  ```
20
20
 
21
+ ### Agent-native login
22
+
23
+ `dsp login` is designed to be driven entirely by an AI agent that has inbox
24
+ access (Gmail/IMAP via MCP, etc.) — no human-in-the-loop required.
25
+
26
+ The command adapts to its environment:
27
+
28
+ | Invocation | Behavior |
29
+ |---|---|
30
+ | `dsp login --email you@acme.com` **(TTY)** | Sends OTP, prompts for the code in the terminal. |
31
+ | `dsp login --email you@acme.com` **(non-TTY)** | Sends OTP and exits 0. Caller reads the code (e.g. from inbox) and re-invokes. |
32
+ | `dsp login --email you@acme.com --code 123456` | Verifies the code, persists the token, exits. |
33
+
34
+ For structured output that doesn't rely on prose parsing:
35
+
36
+ ```bash
37
+ dsp login --email you@acme.com --json
38
+ # → {"status":"otp_sent","email":"you@acme.com",
39
+ # "next":{"command":"dsp login","args":["--email","you@acme.com","--code","<code>"]}}
40
+
41
+ dsp login --email you@acme.com --code 123456 --json
42
+ # → {"status":"authenticated","method":"otp","email":"you@acme.com"}
43
+ ```
44
+
45
+ **OTP email format** is stable and regex-parseable:
46
+
47
+ - Subject: `123456 is your display.dev sign-in code`
48
+ - Body: `Your verification code is: 123456`
49
+
50
+ Extraction pattern: `/Your verification code is: (\d{6})/`.
51
+
21
52
  ## Usage
22
53
 
23
54
  ```bash
package/dist/main.js CHANGED
@@ -513,12 +513,28 @@ function sleep(ms) {
513
513
  });
514
514
  }
515
515
  // --- login ---
516
- program.command('login').description('Authenticate with display.dev').option('--email <email>', 'Email address').option('--api-key [key]', 'Authenticate with an API key').action(function(opts) {
516
+ program.command('login').description('Authenticate with display.dev').option('--email <email>', 'Email address').option('--code <code>', 'OTP code (verify step; pair with --email)').option('--api-key [key]', 'Authenticate with an API key').option('--json', 'Machine-readable output (structured status, no prose)').action(function(opts) {
517
517
  return _async_to_generator(function() {
518
- var _process_env_DISPLAYDEV_API_URL, apiUrl, client, key, rl, validation, email, rl1, method, check, unused, err, msg, rl2, code, result, unused1, deviceResult, unused2, device_code, verification_uri_complete, initialInterval, interval, tokenResult, unused3, _$err;
518
+ var _process_env_DISPLAYDEV_API_URL, emit, emitErr, apiUrl, client, key, rl, validation, email, rl1, method, check, unused, err, msg, code, rl2, result, unused1, deviceResult, unused2, device_code, verification_uri_complete, initialInterval, interval, tokenResult, unused3, _$err;
519
519
  return _ts_generator(this, function(_state) {
520
520
  switch(_state.label){
521
521
  case 0:
522
+ // Small helper: emit either prose (default) or a JSON line. Agents use
523
+ // --json to avoid string-matching against the prose hints.
524
+ emit = function emit(prose, json) {
525
+ if (opts.json) {
526
+ console.log(JSON.stringify(json));
527
+ } else {
528
+ console.log(prose);
529
+ }
530
+ };
531
+ emitErr = function emitErr(prose, json) {
532
+ if (opts.json) {
533
+ console.log(JSON.stringify(json));
534
+ } else {
535
+ console.error(prose);
536
+ }
537
+ };
522
538
  apiUrl = (_process_env_DISPLAYDEV_API_URL = process.env.DISPLAYDEV_API_URL) !== null && _process_env_DISPLAYDEV_API_URL !== void 0 ? _process_env_DISPLAYDEV_API_URL : DEFAULT_API_URL;
523
539
  client = new ApiClient({
524
540
  baseUrl: apiUrl,
@@ -610,7 +626,10 @@ program.command('login').description('Authenticate with display.dev').option('--
610
626
  case 6:
611
627
  validation = _state.sent();
612
628
  if (validation === 'invalid') {
613
- console.error('Invalid API key. Check the key and try again.');
629
+ emitErr('Invalid API key. Check the key and try again.', {
630
+ status: 'error',
631
+ error: 'invalid_api_key'
632
+ });
614
633
  process.exit(1);
615
634
  }
616
635
  if (validation === 'network_error') {
@@ -625,7 +644,10 @@ program.command('login').description('Authenticate with display.dev').option('--
625
644
  ];
626
645
  case 7:
627
646
  _state.sent();
628
- console.log('Authenticated.');
647
+ emit('Authenticated.', {
648
+ status: 'authenticated',
649
+ method: 'api_key'
650
+ });
629
651
  return [
630
652
  2
631
653
  ];
@@ -684,7 +706,11 @@ program.command('login').description('Authenticate with display.dev').option('--
684
706
  case 14:
685
707
  if (!(method === 'otp')) return [
686
708
  3,
687
- 25
709
+ 27
710
+ ];
711
+ if (!!opts.code) return [
712
+ 3,
713
+ 19
688
714
  ];
689
715
  _state.label = 15;
690
716
  case 15:
@@ -708,9 +734,15 @@ program.command('login').description('Authenticate with display.dev').option('--
708
734
  err = _state.sent();
709
735
  msg = _instanceof(err, Error) ? err.message : 'Something went wrong';
710
736
  if (msg.includes('requires SSO')) {
711
- console.error('Your organization requires SSO. Run dsp login again.');
737
+ emitErr('Your organization requires SSO. Run dsp login again.', {
738
+ status: 'error',
739
+ error: 'sso_required'
740
+ });
712
741
  } else {
713
- console.error('Something went wrong. Check your connection and try again.');
742
+ emitErr('Something went wrong. Check your connection and try again.', {
743
+ status: 'error',
744
+ error: 'send_failed'
745
+ });
714
746
  }
715
747
  process.exit(1);
716
748
  return [
@@ -718,11 +750,47 @@ program.command('login').description('Authenticate with display.dev').option('--
718
750
  18
719
751
  ];
720
752
  case 18:
721
- console.log("Code sent to ".concat(email));
722
753
  if (!process.stdin.isTTY) {
723
- console.error('OTP code required. Use dsp login --api-key for non-interactive auth.');
724
- process.exit(1);
754
+ // Non-interactive: exit after sending. The caller (typically an
755
+ // agent) will collect the OTP from the user and re-invoke with --code.
756
+ if (opts.json) {
757
+ console.log(JSON.stringify({
758
+ status: 'otp_sent',
759
+ email: email,
760
+ next: {
761
+ command: 'dsp login',
762
+ args: [
763
+ '--email',
764
+ email,
765
+ '--code',
766
+ '<code>'
767
+ ]
768
+ }
769
+ }));
770
+ } else {
771
+ console.log("Code sent to ".concat(email));
772
+ console.log("Re-run with --code <6-digit code> to complete login.");
773
+ }
774
+ return [
775
+ 2
776
+ ];
725
777
  }
778
+ // TTY path prints the same prose hint then prompts.
779
+ if (!opts.json) {
780
+ console.log("Code sent to ".concat(email));
781
+ }
782
+ _state.label = 19;
783
+ case 19:
784
+ if (!opts.code) return [
785
+ 3,
786
+ 20
787
+ ];
788
+ code = opts.code;
789
+ return [
790
+ 3,
791
+ 22
792
+ ];
793
+ case 20:
726
794
  rl2 = createInterface({
727
795
  input: process.stdin,
728
796
  output: process.stdout
@@ -731,22 +799,22 @@ program.command('login').description('Authenticate with display.dev').option('--
731
799
  4,
732
800
  rl2.question('Enter the 6-digit code: ')
733
801
  ];
734
- case 19:
802
+ case 21:
735
803
  code = _state.sent();
736
804
  rl2.close();
737
- _state.label = 20;
738
- case 20:
805
+ _state.label = 22;
806
+ case 22:
739
807
  _state.trys.push([
740
- 20,
741
- 23,
808
+ 22,
809
+ 25,
742
810
  ,
743
- 24
811
+ 26
744
812
  ]);
745
813
  return [
746
814
  4,
747
815
  client.verifyOtp(email, code.trim())
748
816
  ];
749
- case 21:
817
+ case 23:
750
818
  result = _state.sent();
751
819
  return [
752
820
  4,
@@ -755,56 +823,63 @@ program.command('login').description('Authenticate with display.dev').option('--
755
823
  apiUrl: apiUrl
756
824
  })
757
825
  ];
758
- case 22:
826
+ case 24:
759
827
  _state.sent();
760
- console.log("Logged in as ".concat(email));
828
+ emit("Logged in as ".concat(email), {
829
+ status: 'authenticated',
830
+ method: 'otp',
831
+ email: email
832
+ });
761
833
  return [
762
834
  3,
763
- 24
835
+ 26
764
836
  ];
765
- case 23:
837
+ case 25:
766
838
  unused1 = _state.sent();
767
- console.error('Invalid or expired code. Try again.');
839
+ emitErr('Invalid or expired code. Try again.', {
840
+ status: 'error',
841
+ error: 'invalid_or_expired_code'
842
+ });
768
843
  process.exit(1);
769
844
  return [
770
845
  3,
771
- 24
846
+ 26
772
847
  ];
773
- case 24:
848
+ case 26:
774
849
  return [
775
850
  3,
776
- 38
851
+ 40
777
852
  ];
778
- case 25:
853
+ case 27:
779
854
  // --- Mode 2: SSO device flow ---
780
855
  console.log('Your organization requires SSO. Opening browser...');
781
- _state.label = 26;
782
- case 26:
856
+ _state.label = 28;
857
+ case 28:
783
858
  _state.trys.push([
784
- 26,
785
859
  28,
860
+ 30,
786
861
  ,
787
- 29
862
+ 31
788
863
  ]);
789
864
  return [
790
865
  4,
791
866
  client.requestDeviceCode('dsp-cli')
792
867
  ];
793
- case 27:
868
+ case 29:
794
869
  deviceResult = _state.sent();
795
870
  return [
796
871
  3,
797
- 29
872
+ 31
798
873
  ];
799
- case 28:
874
+ case 30:
800
875
  unused2 = _state.sent();
801
876
  console.error('Something went wrong. Check your connection and try again.');
802
877
  process.exit(1);
803
878
  return [
804
879
  3,
805
- 29
880
+ 31
806
881
  ];
807
- case 29:
882
+ case 31:
808
883
  device_code = deviceResult.device_code, verification_uri_complete = deviceResult.verification_uri_complete, initialInterval = deviceResult.interval;
809
884
  console.log();
810
885
  console.log(" ".concat(verification_uri_complete));
@@ -813,48 +888,48 @@ program.command('login').description('Authenticate with display.dev').option('--
813
888
  // Poll for token
814
889
  interval = (initialInterval || 5) * 1000;
815
890
  process.stdout.write('Waiting for authentication...');
816
- _state.label = 30;
817
- case 30:
891
+ _state.label = 32;
892
+ case 32:
818
893
  if (!true) return [
819
894
  3,
820
- 38
895
+ 40
821
896
  ];
822
897
  return [
823
898
  4,
824
899
  sleep(interval)
825
900
  ];
826
- case 31:
901
+ case 33:
827
902
  _state.sent();
828
903
  tokenResult = void 0;
829
- _state.label = 32;
830
- case 32:
904
+ _state.label = 34;
905
+ case 34:
831
906
  _state.trys.push([
832
- 32,
833
907
  34,
908
+ 36,
834
909
  ,
835
- 35
910
+ 37
836
911
  ]);
837
912
  return [
838
913
  4,
839
914
  client.pollDeviceToken(device_code, 'dsp-cli')
840
915
  ];
841
- case 33:
916
+ case 35:
842
917
  tokenResult = _state.sent();
843
918
  return [
844
919
  3,
845
- 35
920
+ 37
846
921
  ];
847
- case 34:
922
+ case 36:
848
923
  unused3 = _state.sent();
849
924
  // Transient network error — retry on next interval
850
925
  return [
851
926
  3,
852
- 30
927
+ 32
853
928
  ];
854
- case 35:
929
+ case 37:
855
930
  if (!('access_token' in tokenResult)) return [
856
931
  3,
857
- 37
932
+ 39
858
933
  ];
859
934
  console.log(' done');
860
935
  return [
@@ -864,25 +939,25 @@ program.command('login').description('Authenticate with display.dev').option('--
864
939
  apiUrl: apiUrl
865
940
  })
866
941
  ];
867
- case 36:
942
+ case 38:
868
943
  _state.sent();
869
944
  console.log("Logged in as ".concat(email));
870
945
  return [
871
946
  2
872
947
  ];
873
- case 37:
948
+ case 39:
874
949
  _$err = tokenResult;
875
950
  if (_$err.error === 'authorization_pending') {
876
951
  return [
877
952
  3,
878
- 30
953
+ 32
879
954
  ];
880
955
  }
881
956
  if (_$err.error === 'slow_down') {
882
957
  interval += 5000;
883
958
  return [
884
959
  3,
885
- 30
960
+ 32
886
961
  ];
887
962
  }
888
963
  if (_$err.error === 'access_denied') {
@@ -901,9 +976,9 @@ program.command('login').description('Authenticate with display.dev').option('--
901
976
  process.exit(1);
902
977
  return [
903
978
  3,
904
- 30
979
+ 32
905
980
  ];
906
- case 38:
981
+ case 40:
907
982
  return [
908
983
  2
909
984
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@displaydev/cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "dsp": "dist/main.js"
@@ -12,6 +12,7 @@
12
12
  "scripts": {
13
13
  "build": "swc src -d dist --strip-leading-paths",
14
14
  "typecheck": "tsgo --project tsconfig.json --noEmit",
15
+ "lint": "oxlint --deny-warnings .",
15
16
  "test": "vitest run"
16
17
  },
17
18
  "dependencies": {