applied-cli 0.1.0__tar.gz → 0.2.0__tar.gz

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 (40) hide show
  1. {applied_cli-0.1.0 → applied_cli-0.2.0}/PKG-INFO +7 -3
  2. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/auth.py +323 -0
  3. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/mcp_server.py +63 -1
  4. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/PKG-INFO +7 -3
  5. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/requires.txt +5 -0
  6. {applied_cli-0.1.0 → applied_cli-0.2.0}/pyproject.toml +8 -3
  7. {applied_cli-0.1.0 → applied_cli-0.2.0}/README.md +0 -0
  8. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/__init__.py +0 -0
  9. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/auth_store.py +0 -0
  10. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/__init__.py +0 -0
  11. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/_hints.py +0 -0
  12. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/_normalize.py +0 -0
  13. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/_parsers.py +0 -0
  14. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/_ui.py +0 -0
  15. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/agent.py +0 -0
  16. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/chat.py +0 -0
  17. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/coverage.py +0 -0
  18. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/discover.py +0 -0
  19. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/fix.py +0 -0
  20. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/insights.py +0 -0
  21. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/intents.py +0 -0
  22. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/rate.py +0 -0
  23. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/responses.py +0 -0
  24. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/shop.py +0 -0
  25. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/simulate.py +0 -0
  26. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/commands/spec.py +0 -0
  27. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/config.py +0 -0
  28. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/error_reporting.py +0 -0
  29. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/http.py +0 -0
  30. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/main.py +0 -0
  31. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/presets/demo.yaml +0 -0
  32. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/runtime.py +0 -0
  33. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/shop_spec.py +0 -0
  34. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli/spec_workflow.py +0 -0
  35. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/SOURCES.txt +0 -0
  36. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/dependency_links.txt +0 -0
  37. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/entry_points.txt +0 -0
  38. {applied_cli-0.1.0 → applied_cli-0.2.0}/applied_cli.egg-info/top_level.txt +0 -0
  39. {applied_cli-0.1.0 → applied_cli-0.2.0}/setup.cfg +0 -0
  40. {applied_cli-0.1.0 → applied_cli-0.2.0}/tests/test_parsers_and_insights.py +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: CLI and MCP server for Applied Labs AI support agents
5
5
  Author: Applied Labs
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/appliedlabs/applied-cli
8
- Project-URL: Repository, https://github.com/appliedlabs/applied-cli
7
+ Project-URL: Homepage, https://github.com/AppliedLabsAI/applied-cli
8
+ Project-URL: Repository, https://github.com/AppliedLabsAI/applied-cli
9
9
  Keywords: applied-labs,ai-agents,support,mcp,claude
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
@@ -19,6 +19,10 @@ Requires-Dist: pyyaml>=6.0
19
19
  Requires-Dist: typer>=0.16.0
20
20
  Provides-Extra: mcp
21
21
  Requires-Dist: mcp>=1.2.0; extra == "mcp"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=8.0; extra == "dev"
24
+ Requires-Dist: build>=1.0; extra == "dev"
25
+ Requires-Dist: twine>=5.0; extra == "dev"
22
26
 
23
27
  # Applied Labs CLI
24
28
 
@@ -720,6 +720,329 @@ def use_shop(
720
720
  typer.echo("To switch again: applied-cli auth use-shop \"<shop name or uuid>\"")
721
721
 
722
722
 
723
+ @app.command("login-start")
724
+ def login_start(
725
+ endpoint: Optional[str] = typer.Option(
726
+ None,
727
+ "--endpoint",
728
+ help="Endpoint alias or URL: prod, dev, local, or full host.",
729
+ envvar="APPLIED_ENDPOINT",
730
+ ),
731
+ output_json: bool = typer.Option(False, "--json", help="Emit JSON output."),
732
+ # Hidden options
733
+ base_url: Optional[str] = typer.Option(None, envvar="APPLIED_BASE_URL", hidden=True),
734
+ timeout: float = typer.Option(10.0, hidden=True),
735
+ ) -> None:
736
+ """Start device login flow and return approval URL (non-blocking).
737
+
738
+ This command starts the OAuth device flow and immediately returns the
739
+ approval URL and device code. Use `login-complete` to finish authentication
740
+ after the user approves in their browser.
741
+
742
+ Example:
743
+ applied-cli auth login-start --json
744
+ # User visits URL and approves
745
+ applied-cli auth login-complete --device-code <code> --json
746
+ """
747
+ resolved_base_url = _resolve_base_url_for_auth(
748
+ endpoint=endpoint,
749
+ base_url=base_url,
750
+ existing=None,
751
+ )
752
+
753
+ try:
754
+ device_start = start_cli_device_login(
755
+ base_url=resolved_base_url,
756
+ timeout_seconds=timeout,
757
+ )
758
+ except APIError as exc:
759
+ if exc.status_code == 404:
760
+ if output_json:
761
+ typer.echo(
762
+ json.dumps(
763
+ {
764
+ "success": False,
765
+ "error": "endpoint_not_found",
766
+ "message": f"Device login endpoint not found at {resolved_base_url}.",
767
+ "hint": "Specify an endpoint: --endpoint prod or --endpoint local",
768
+ },
769
+ indent=2,
770
+ ),
771
+ err=True,
772
+ )
773
+ else:
774
+ typer.echo(
775
+ f"Device login endpoint not found at {resolved_base_url}.\n"
776
+ "Try: applied-cli auth login-start --endpoint prod",
777
+ err=True,
778
+ )
779
+ raise typer.Exit(code=1) from exc
780
+ typer.echo(render_api_error(exc, action="start device login"), err=True)
781
+ raise typer.Exit(code=1) from exc
782
+
783
+ approval_url = str(
784
+ device_start.get("verification_uri_complete")
785
+ or device_start.get("verification_uri")
786
+ or device_start.get("verification_url")
787
+ or ""
788
+ ).strip()
789
+ device_code = str(device_start.get("device_code") or "").strip()
790
+ user_code = str(device_start.get("user_code") or "").strip()
791
+ expires_in = int(device_start.get("expires_in") or 180)
792
+
793
+ if not device_code:
794
+ err_msg = "Device login start response missing device code."
795
+ if output_json:
796
+ typer.echo(
797
+ json.dumps({"success": False, "error": "invalid_response", "message": err_msg}),
798
+ err=True,
799
+ )
800
+ else:
801
+ typer.echo(err_msg, err=True)
802
+ raise typer.Exit(code=1)
803
+
804
+ result = {
805
+ "success": True,
806
+ "status": "pending_approval",
807
+ "approval_url": approval_url,
808
+ "device_code": device_code,
809
+ "user_code": user_code or None,
810
+ "expires_in": expires_in,
811
+ "endpoint": resolved_base_url,
812
+ "next_step": "Visit the approval URL, then run: applied-cli auth login-complete --device-code <device_code>",
813
+ }
814
+
815
+ if output_json:
816
+ typer.echo(json.dumps(result, indent=2))
817
+ else:
818
+ typer.echo(f"Approval URL: {approval_url}")
819
+ if user_code:
820
+ typer.echo(f"User code: {user_code}")
821
+ typer.echo(f"Device code: {device_code}")
822
+ typer.echo(f"Expires in: {expires_in} seconds")
823
+ typer.echo("")
824
+ typer.echo("After approving in browser, run:")
825
+ typer.echo(f" applied-cli auth login-complete --device-code {device_code}")
826
+
827
+
828
+ @app.command("login-complete")
829
+ def login_complete(
830
+ device_code: str = typer.Option(..., "--device-code", help="Device code from login-start."),
831
+ endpoint: Optional[str] = typer.Option(
832
+ None,
833
+ "--endpoint",
834
+ help="Endpoint alias or URL (must match login-start).",
835
+ envvar="APPLIED_ENDPOINT",
836
+ ),
837
+ shop_id: Optional[str] = typer.Option(
838
+ None, "--shop-id", help="Pre-select a shop UUID.", envvar="APPLIED_SHOP_ID"
839
+ ),
840
+ output_json: bool = typer.Option(False, "--json", help="Emit JSON output."),
841
+ # Hidden options
842
+ profile: Optional[str] = typer.Option(None, "--profile", envvar="APPLIED_PROFILE", hidden=True),
843
+ base_url: Optional[str] = typer.Option(None, envvar="APPLIED_BASE_URL", hidden=True),
844
+ timeout: float = typer.Option(10.0, hidden=True),
845
+ max_attempts: int = typer.Option(3, hidden=True),
846
+ poll_interval: float = typer.Option(2.0, hidden=True),
847
+ ) -> None:
848
+ """Complete device login after user approves in browser.
849
+
850
+ Polls the API to check if the user has approved the login request.
851
+ If approved, saves credentials and selects a shop.
852
+
853
+ Example:
854
+ applied-cli auth login-complete --device-code abc123 --json
855
+ """
856
+ profile_name = _resolve_profile_name(profile)
857
+ resolved_base_url = _resolve_base_url_for_auth(
858
+ endpoint=endpoint,
859
+ base_url=base_url,
860
+ existing=None,
861
+ )
862
+ explicit_shop_id = shop_id or os.getenv("APPLIED_SHOP_ID")
863
+
864
+ # Poll for approval (with limited attempts for non-blocking behavior)
865
+ resolved_token = None
866
+ resolved_shop_id = explicit_shop_id or ""
867
+ resolved_shop_name = ""
868
+
869
+ for attempt in range(max_attempts):
870
+ try:
871
+ poll = poll_cli_device_login(
872
+ base_url=resolved_base_url,
873
+ device_code=device_code,
874
+ timeout_seconds=timeout,
875
+ )
876
+ except APIError as exc:
877
+ if output_json:
878
+ typer.echo(
879
+ json.dumps(
880
+ {"success": False, "error": "poll_failed", "message": str(exc)},
881
+ indent=2,
882
+ ),
883
+ err=True,
884
+ )
885
+ else:
886
+ typer.echo(render_api_error(exc, action="poll device login"), err=True)
887
+ raise typer.Exit(code=1) from exc
888
+
889
+ status_value = str(poll.get("status") or "pending").strip().lower()
890
+
891
+ if status_value == "approved":
892
+ resolved_token = str(poll.get("api_token") or "").strip()
893
+ discovered_shop_id = str(poll.get("shop_id") or "").strip()
894
+ if discovered_shop_id and not resolved_shop_id:
895
+ resolved_shop_id = discovered_shop_id
896
+ break
897
+ elif status_value in {"expired", "denied"}:
898
+ err_result = {
899
+ "success": False,
900
+ "error": f"login_{status_value}",
901
+ "message": f"Device login {status_value}.",
902
+ "hint": "Run `applied-cli auth login-start` again to get a new approval URL.",
903
+ }
904
+ if output_json:
905
+ typer.echo(json.dumps(err_result, indent=2), err=True)
906
+ else:
907
+ typer.echo(f"Device login {status_value}. Start a new login flow.", err=True)
908
+ raise typer.Exit(code=1)
909
+ else:
910
+ # Still pending
911
+ if attempt < max_attempts - 1:
912
+ time.sleep(poll_interval)
913
+
914
+ if not resolved_token:
915
+ pending_result = {
916
+ "success": False,
917
+ "status": "pending",
918
+ "message": "Login not yet approved. User must visit the approval URL first.",
919
+ "hint": "Wait for user to approve in browser, then retry this command.",
920
+ }
921
+ if output_json:
922
+ typer.echo(json.dumps(pending_result, indent=2))
923
+ else:
924
+ typer.echo("Login not yet approved. Please approve in browser first.")
925
+ raise typer.Exit(code=1)
926
+
927
+ # Resolve shop name if we have an ID
928
+ if resolved_shop_id and not resolved_shop_name:
929
+ try:
930
+ shops_for_name = list_accessible_shops(
931
+ base_url=resolved_base_url,
932
+ api_token=resolved_token,
933
+ timeout_seconds=timeout,
934
+ )
935
+ name_match = next(
936
+ (r for r in shops_for_name if str(r.get("id")) == resolved_shop_id), None
937
+ )
938
+ if name_match:
939
+ resolved_shop_name = str(name_match.get("name") or "")
940
+ except APIError:
941
+ pass
942
+
943
+ # If no shop_id yet, try to auto-select (single shop) or require explicit selection
944
+ if not resolved_shop_id:
945
+ try:
946
+ shops = list_accessible_shops(
947
+ base_url=resolved_base_url,
948
+ api_token=resolved_token,
949
+ timeout_seconds=timeout,
950
+ )
951
+ except APIError:
952
+ shops = []
953
+
954
+ if shops:
955
+ if len(shops) == 1 and shops[0].get("id"):
956
+ resolved_shop_id = str(shops[0]["id"])
957
+ resolved_shop_name = str(shops[0].get("name") or "")
958
+ elif output_json:
959
+ # Multiple shops - return them for selection
960
+ typer.echo(
961
+ json.dumps(
962
+ {
963
+ "success": False,
964
+ "error": "shop_selection_required",
965
+ "message": "Multiple shops available. Specify --shop-id.",
966
+ "available_shops": shops,
967
+ },
968
+ indent=2,
969
+ )
970
+ )
971
+ raise typer.Exit(code=1)
972
+ else:
973
+ resolved_shop_id, resolved_shop_name = _select_shop_interactively(shops)
974
+
975
+ if not resolved_shop_id:
976
+ err_result = {
977
+ "success": False,
978
+ "error": "missing_shop_id",
979
+ "message": "Could not determine shop. Pass --shop-id explicitly.",
980
+ }
981
+ if output_json:
982
+ typer.echo(json.dumps(err_result, indent=2), err=True)
983
+ else:
984
+ typer.echo("Could not determine shop. Pass --shop-id.", err=True)
985
+ raise typer.Exit(code=1)
986
+
987
+ # Validate token against shop
988
+ try:
989
+ validate_api_token(
990
+ base_url=resolved_base_url,
991
+ shop_id=resolved_shop_id,
992
+ api_token=resolved_token,
993
+ timeout_seconds=timeout,
994
+ )
995
+ except APIError as exc:
996
+ if output_json:
997
+ typer.echo(
998
+ json.dumps(
999
+ {
1000
+ "success": False,
1001
+ "error": "validation_failed",
1002
+ "message": str(exc),
1003
+ },
1004
+ indent=2,
1005
+ ),
1006
+ err=True,
1007
+ )
1008
+ else:
1009
+ typer.echo(render_api_error(exc, action="validate token"), err=True)
1010
+ raise typer.Exit(code=1) from exc
1011
+
1012
+ # Save credentials
1013
+ save_credentials(
1014
+ Credentials(
1015
+ base_url=resolved_base_url,
1016
+ shop_id=resolved_shop_id,
1017
+ api_token=resolved_token,
1018
+ ),
1019
+ profile=profile_name,
1020
+ set_active=True,
1021
+ )
1022
+
1023
+ shop_label = (
1024
+ f"{resolved_shop_name} ({resolved_shop_id})" if resolved_shop_name else resolved_shop_id
1025
+ )
1026
+
1027
+ if output_json:
1028
+ result: dict = {
1029
+ "success": True,
1030
+ "logged_in": True,
1031
+ "endpoint": resolved_base_url,
1032
+ "shop_id": resolved_shop_id,
1033
+ "token_masked": mask_token(resolved_token),
1034
+ }
1035
+ if resolved_shop_name:
1036
+ result["shop_name"] = resolved_shop_name
1037
+ typer.echo(json.dumps(result, indent=2))
1038
+ return
1039
+
1040
+ typer.echo("Login successful!")
1041
+ typer.echo(f"- shop: {shop_label}")
1042
+ typer.echo(f"- endpoint: {resolved_base_url}")
1043
+ typer.echo(f"- token: {mask_token(resolved_token)}")
1044
+
1045
+
723
1046
  @app.command("logout")
724
1047
  def logout(
725
1048
  yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt."),
@@ -22,11 +22,33 @@ from mcp.server.fastmcp import FastMCP
22
22
  mcp = FastMCP(
23
23
  "applied-cli",
24
24
  instructions="""
25
- You have access to the Applied Labs CLI for managing AI support agents.
25
+ You have access to the Applied Labs plugin for managing AI support agents.
26
+
27
+ IMPORTANT: Never tell users to run CLI commands. Always use these MCP tools directly.
28
+
29
+ ## Authentication Flow
30
+
31
+ When a user is not logged in, YOU must handle authentication using these tools:
32
+
33
+ 1. Call `auth_login()` → Returns JSON with `approval_url` and `device_code`
34
+ 2. Tell user: "Please visit this URL to authorize: [approval_url]"
35
+ 3. Ask user to confirm when they've approved
36
+ 4. Call `auth_login_complete(device_code="...")` with the device_code from step 1
37
+ 5. Verify with `auth_status()`
38
+
39
+ Example response when not logged in:
40
+ "You need to authenticate. Please visit this URL to authorize:
41
+ https://appliedlabs.ai/cli/authorize?code=XXXX
42
+
43
+ Let me know when you've approved, and I'll complete the login."
44
+
45
+ DO NOT tell users to run `applied-cli auth login` or any other CLI command.
26
46
 
27
47
  ## Quick Reference
28
48
 
29
49
  ### Setup & Auth
50
+ - `auth_login` - Start login flow (returns approval URL for user)
51
+ - `auth_login_complete` - Complete login after user approves
30
52
  - `auth_status` - Check authentication and current shop
31
53
  - `auth_shops` / `auth_switch_shop` - List and switch shops
32
54
  - `shop_setup` - Full shop bootstrap from YAML spec
@@ -106,6 +128,46 @@ def _run_cli(args: list[str], timeout: int = 120) -> dict[str, Any]:
106
128
  # =============================================================================
107
129
 
108
130
 
131
+ @mcp.tool()
132
+ async def auth_login(endpoint: str = "prod") -> str:
133
+ """
134
+ Start the login flow by initiating device authentication.
135
+
136
+ Returns an approval URL that the user must visit in their browser to authorize.
137
+ After the user approves, call `auth_login_complete` with the device_code to finish.
138
+
139
+ Args:
140
+ endpoint: API endpoint - 'prod', 'dev', 'local', or full URL (default: prod)
141
+
142
+ Returns:
143
+ JSON with approval_url, device_code, and user_code for the user to complete login.
144
+ """
145
+ result = _run_cli(["auth", "login-start", "--endpoint", endpoint, "--json"])
146
+ return json.dumps(result, indent=2)
147
+
148
+
149
+ @mcp.tool()
150
+ async def auth_login_complete(device_code: str, endpoint: str = "prod", shop_id: str = None) -> str:
151
+ """
152
+ Complete the login flow after user has approved in browser.
153
+
154
+ Call this after the user has visited the approval URL from `auth_login`.
155
+
156
+ Args:
157
+ device_code: The device_code returned by auth_login
158
+ endpoint: API endpoint - must match the one used in auth_login
159
+ shop_id: Optional shop UUID to select (required if user has multiple shops)
160
+
161
+ Returns:
162
+ JSON with login result - success with credentials or pending/error status.
163
+ """
164
+ args = ["auth", "login-complete", "--device-code", device_code, "--endpoint", endpoint, "--json"]
165
+ if shop_id:
166
+ args.extend(["--shop-id", shop_id])
167
+ result = _run_cli(args, timeout=30)
168
+ return json.dumps(result, indent=2)
169
+
170
+
109
171
  @mcp.tool()
110
172
  async def auth_status() -> str:
111
173
  """Check authentication status and current shop."""
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: applied-cli
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: CLI and MCP server for Applied Labs AI support agents
5
5
  Author: Applied Labs
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/appliedlabs/applied-cli
8
- Project-URL: Repository, https://github.com/appliedlabs/applied-cli
7
+ Project-URL: Homepage, https://github.com/AppliedLabsAI/applied-cli
8
+ Project-URL: Repository, https://github.com/AppliedLabsAI/applied-cli
9
9
  Keywords: applied-labs,ai-agents,support,mcp,claude
10
10
  Classifier: Development Status :: 4 - Beta
11
11
  Classifier: Intended Audience :: Developers
@@ -19,6 +19,10 @@ Requires-Dist: pyyaml>=6.0
19
19
  Requires-Dist: typer>=0.16.0
20
20
  Provides-Extra: mcp
21
21
  Requires-Dist: mcp>=1.2.0; extra == "mcp"
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest>=8.0; extra == "dev"
24
+ Requires-Dist: build>=1.0; extra == "dev"
25
+ Requires-Dist: twine>=5.0; extra == "dev"
22
26
 
23
27
  # Applied Labs CLI
24
28
 
@@ -3,5 +3,10 @@ keyring>=25.6.0
3
3
  pyyaml>=6.0
4
4
  typer>=0.16.0
5
5
 
6
+ [dev]
7
+ pytest>=8.0
8
+ build>=1.0
9
+ twine>=5.0
10
+
6
11
  [mcp]
7
12
  mcp>=1.2.0
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "applied-cli"
3
- version = "0.1.0"
3
+ version = "0.2.0"
4
4
  description = "CLI and MCP server for Applied Labs AI support agents"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -26,14 +26,19 @@ dependencies = [
26
26
  mcp = [
27
27
  "mcp>=1.2.0",
28
28
  ]
29
+ dev = [
30
+ "pytest>=8.0",
31
+ "build>=1.0",
32
+ "twine>=5.0",
33
+ ]
29
34
 
30
35
  [project.scripts]
31
36
  applied-cli = "applied_cli.main:app"
32
37
  applied-cli-mcp = "applied_cli.mcp_server:main"
33
38
 
34
39
  [project.urls]
35
- Homepage = "https://github.com/appliedlabs/applied-cli"
36
- Repository = "https://github.com/appliedlabs/applied-cli"
40
+ Homepage = "https://github.com/AppliedLabsAI/applied-cli"
41
+ Repository = "https://github.com/AppliedLabsAI/applied-cli"
37
42
 
38
43
  [tool.setuptools.packages.find]
39
44
  include = ["applied_cli", "applied_cli.*"]
File without changes
File without changes