bevor-cli 0.1.0__tar.gz → 0.1.1__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 (109) hide show
  1. bevor_cli-0.1.1/PKG-INFO +130 -0
  2. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/main.py +31 -1
  3. bevor_cli-0.1.1/bevor_cli/callbacks/notify.py +26 -0
  4. bevor_cli-0.1.1/bevor_cli/callbacks/upgrade.py +23 -0
  5. bevor_cli-0.1.1/bevor_cli/callbacks/version.py +25 -0
  6. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/retry.py +2 -2
  7. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/run.py +2 -2
  8. bevor_cli-0.1.1/bevor_cli/commands/workspaces/__init__.py +0 -0
  9. bevor_cli-0.1.1/bevor_cli/configuration/__init__.py +0 -0
  10. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/creds.py +4 -2
  11. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/state.py +2 -1
  12. bevor_cli-0.1.1/bevor_cli/configuration/update.py +50 -0
  13. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/main.py +19 -3
  14. bevor_cli-0.1.1/bevor_cli/settings.py +4 -0
  15. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/pyproject.toml +4 -2
  16. bevor_cli-0.1.0/PKG-INFO +0 -14
  17. bevor_cli-0.1.0/bevor_cli/settings.py +0 -4
  18. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/.gitignore +0 -0
  19. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/README.md +0 -0
  20. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/__init__.py +0 -0
  21. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/__init__.py +0 -0
  22. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/confirmations.py +0 -0
  23. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/annotations/query.py +0 -0
  24. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/agent.py +0 -0
  25. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/analyses.py +0 -0
  26. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/chat.py +0 -0
  27. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/codes.py +0 -0
  28. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/findings.py +0 -0
  29. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/nodes.py +0 -0
  30. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/projects.py +0 -0
  31. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/sessions.py +0 -0
  32. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/apps/workspaces.py +0 -0
  33. {bevor_cli-0.1.0/bevor_cli/commands → bevor_cli-0.1.1/bevor_cli/callbacks}/__init__.py +0 -0
  34. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/client.py +0 -0
  35. {bevor_cli-0.1.0/bevor_cli/commands/agent → bevor_cli-0.1.1/bevor_cli/commands}/__init__.py +0 -0
  36. {bevor_cli-0.1.0/bevor_cli/commands/analyses → bevor_cli-0.1.1/bevor_cli/commands/agent}/__init__.py +0 -0
  37. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/agent/materialze_cmd.py +0 -0
  38. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/agent/setup_cmd.py +0 -0
  39. {bevor_cli-0.1.0/bevor_cli/commands/analyses/chats → bevor_cli-0.1.1/bevor_cli/commands/analyses}/__init__.py +0 -0
  40. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/active.py +0 -0
  41. {bevor_cli-0.1.0/bevor_cli/commands/codes → bevor_cli-0.1.1/bevor_cli/commands/analyses/chats}/__init__.py +0 -0
  42. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/get.py +0 -0
  43. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/list.py +0 -0
  44. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/messages.py +0 -0
  45. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/new.py +0 -0
  46. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/resume.py +0 -0
  47. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/chats/session.py +0 -0
  48. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/child.py +0 -0
  49. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/commit.py +0 -0
  50. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/create.py +0 -0
  51. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/delete.py +0 -0
  52. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/diff.py +0 -0
  53. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/entrypoints.py +0 -0
  54. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/findings.py +0 -0
  55. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/fork.py +0 -0
  56. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/list.py +0 -0
  57. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/merge.py +0 -0
  58. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/select.py +0 -0
  59. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/set_head.py +0 -0
  60. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/transitions.py +0 -0
  61. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/analyses/view.py +0 -0
  62. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/__init__.py +0 -0
  63. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/login.py +0 -0
  64. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/logout.py +0 -0
  65. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/auth/whoami.py +0 -0
  66. {bevor_cli-0.1.0/bevor_cli/commands/findings → bevor_cli-0.1.1/bevor_cli/commands/codes}/__init__.py +0 -0
  67. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/list.py +0 -0
  68. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/push.py +0 -0
  69. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/select.py +0 -0
  70. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/codes/view.py +0 -0
  71. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/context/__init__.py +0 -0
  72. {bevor_cli-0.1.0/bevor_cli/commands/graph → bevor_cli-0.1.1/bevor_cli/commands/findings}/__init__.py +0 -0
  73. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/acknowledge.py +0 -0
  74. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/add.py +0 -0
  75. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/bulk.py +0 -0
  76. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/delete.py +0 -0
  77. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/edit.py +0 -0
  78. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/get.py +0 -0
  79. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/interactive.py +0 -0
  80. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/list.py +0 -0
  81. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/findings/revert.py +0 -0
  82. {bevor_cli-0.1.0/bevor_cli/commands/nodes → bevor_cli-0.1.1/bevor_cli/commands/graph}/__init__.py +0 -0
  83. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/call_chain.py +0 -0
  84. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/edges.py +0 -0
  85. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/interactive.py +0 -0
  86. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/graph/renderer.py +0 -0
  87. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/link/__init__.py +0 -0
  88. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/link/helpers.py +0 -0
  89. {bevor_cli-0.1.0/bevor_cli/commands/projects → bevor_cli-0.1.1/bevor_cli/commands/nodes}/__init__.py +0 -0
  90. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/get.py +0 -0
  91. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/list.py +0 -0
  92. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/nodes/source.py +0 -0
  93. {bevor_cli-0.1.0/bevor_cli/commands/sessions → bevor_cli-0.1.1/bevor_cli/commands/projects}/__init__.py +0 -0
  94. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/create.py +0 -0
  95. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/list.py +0 -0
  96. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/select.py +0 -0
  97. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/projects/view.py +0 -0
  98. {bevor_cli-0.1.0/bevor_cli/commands/workspaces → bevor_cli-0.1.1/bevor_cli/commands/sessions}/__init__.py +0 -0
  99. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/sessions/list.py +0 -0
  100. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/sessions/revoke.py +0 -0
  101. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/list.py +0 -0
  102. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/pick.py +0 -0
  103. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/select.py +0 -0
  104. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/commands/workspaces/view.py +0 -0
  105. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/configuration/settings.py +0 -0
  106. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/findings_yaml.py +0 -0
  107. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/output.py +0 -0
  108. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/bevor_cli/select.py +0 -0
  109. {bevor_cli-0.1.0 → bevor_cli-0.1.1}/cli-hierarchy.py +0 -0
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.5
2
+ Name: bevor-cli
3
+ Version: 0.1.1
4
+ Summary: Bevor CLI tool for security analysis and graph inspection
5
+ Classifier: Development Status :: 3 - Alpha
6
+ Requires-Python: >=3.13
7
+ Requires-Dist: bevor-sdk==0.1.1
8
+ Requires-Dist: click~=8.1
9
+ Requires-Dist: httpx~=0.28
10
+ Requires-Dist: packaging~=26.2
11
+ Requires-Dist: pydantic~=2.12
12
+ Requires-Dist: pyyaml~=6.0
13
+ Requires-Dist: questionary~=2.0
14
+ Requires-Dist: rich~=15.0
15
+ Requires-Dist: typer~=0.26
16
+ Description-Content-Type: text/markdown
17
+
18
+ # Bevor CLI
19
+
20
+ The official command-line interface for [Bevor](https://bevor.io) — smart contract security analysis and code graph exploration.
21
+
22
+ Use `bevor` to upload Solidity codebases, run security analyses, explore the code graph interactively, and manage findings — all from your terminal.
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ curl -LsSf https://bevor.io/install.sh | bash
30
+ ```
31
+
32
+ ---
33
+
34
+ ## Setup
35
+
36
+ ```bash
37
+ bevor login
38
+ bevor link
39
+ #
40
+ bevor codes push
41
+ bevor analyses create
42
+ ```
43
+
44
+ ---
45
+
46
+ ## Contents
47
+
48
+ `[]` -> optional args.
49
+ `<>` -> required args.
50
+
51
+ Simplification: EVERYTHING operates on the currently configured analysis. Findings as well.
52
+ Simplifies the DX, and we can take the stance that it's a rare state to want to operate on OTHER things via the CLI.
53
+ "version" is a flag that can be passed, but it's intentionally hard to act on arbitrary versions, unless the head is moved or the flag is passed.
54
+
55
+ ### Local Configuration
56
+ - workspace [id]
57
+ - project [id]
58
+ - code [id, fingerprint]
59
+ - analysis [id]
60
+
61
+ ```bash
62
+ help
63
+ login
64
+ logout
65
+ whoami [--json]
66
+ link
67
+ context [--json]
68
+ sessions
69
+ sessions list
70
+ sessions revoke <token_id>
71
+ workspaces
72
+ workspaces list [--json]
73
+ workspaces view [workspace_id] [--json]
74
+ workspaces select [workspace_id]
75
+ projects
76
+ projects list [--json]
77
+ projects view [project_id] [--json]
78
+ projects select [project_id]
79
+ projects create [--name] [--description] [--kind] [--yes]
80
+ codes
81
+ codes list [--page] [--page-size] [--order] [--order-by] [--project] [--network] [--identifier] [--status] [--json]
82
+ codes view [code_id] [--json]
83
+ codes select [code_id]
84
+ codes push [--path] [--no-wait] [--yes]
85
+ codes nodes
86
+ codes nodes list [--code] [--entrypoints] [--file] [--no-deps] [--name] [--node-type] [--json]
87
+ codes nodes view <node_id> [--code] [--json]
88
+ codes nodes content <node_id> [--code]
89
+ codes nodes edges <node_id> [--code] [--direction] [--type] [--json]
90
+ codes nodes call-chain <node_id> [--code] [--json]
91
+ codes nodes interactive <node_id> [--code]
92
+ analyses
93
+ analyses list [--page] [--page-size] [--order] [--order-by] [--project] [--user] [--is-owner] [--json]
94
+ analyses view [analysis_id] [--version] [--json]
95
+ analyses select [analysis_id] [--page] [--page-size]
96
+ analyses recent [--json]
97
+ analyses create [--name] [--collision] [--yes] [--json] [--force]
98
+ analyses set-head <version_id>
99
+ analyses run [--version] [--no-wait] [--silent]
100
+ analyses retry [--version] [--no-wait] [--silent]
101
+ analyses diff [--version] [--staged] [--json]
102
+ analyses commit [--version]
103
+ analyses child [--version] [--collision]
104
+ analyses fork [--version]
105
+ analyses merge <from_analysis> [--to]
106
+ analyses findings [--version] [--interactive] [--json] [--sarif]
107
+ analyses entrypoints [--version] [--json]
108
+ analyses transitions [--page] [--page-size] [--order] [--order-by] [--reason] [--version] [--project-wide] [--json]
109
+ analyses delete
110
+ analyses delete full
111
+ analyses delete version [version]
112
+ findings
113
+ findings list [--page] [--page-size] [--order] [--order-by] [--project] [--self] [--user] [--code] [--analyses] [--type] [--level] [--acknowledged] [--operation] [--created-by-self] [--created-by] [--json]
114
+ findings view <finding_id> [--json]
115
+ findings add [--version] [--file] [--interactive] [--type] [--level] [--name] [--explanation] [--recommendation] [--poc] [--tool] [--node] [--location] [--uri] [--start-line] [--start-column] [--end-line] [--end-column] [--char-offset] [--char-length] [--byte-offset] [--byte-length] [--fqn]
116
+ findings bulk <source> [--version]
117
+ findings edit <finding_id> [--file]
118
+ findings delete <finding_id>
119
+ findings revert <finding_id>
120
+ findings acknowledge <finding_id>
121
+ agent
122
+ agent setup
123
+ agent materialize
124
+ chats
125
+ chats list --page --page-size --order --order-by --project [--json]
126
+ chats view <chat_id> [--json]
127
+ chats messages <chat_id> [--json]
128
+ chats new <mode>
129
+ chats resume <chat_id>
130
+ ```
@@ -1,3 +1,5 @@
1
+ import subprocess
2
+
1
3
  import typer
2
4
  from bevor_cli import output
3
5
  from bevor_cli.apps import (
@@ -10,6 +12,9 @@ from bevor_cli.apps import (
10
12
  sessions,
11
13
  workspaces,
12
14
  )
15
+ from bevor_cli.callbacks.notify import _notify_if_outdated, _update_check_enabled
16
+ from bevor_cli.callbacks.upgrade import _upgrade_command
17
+ from bevor_cli.callbacks.version import _current_version, _latest_version, _version_callback
13
18
  from bevor_cli.commands.auth import login, logout, whoami
14
19
  from bevor_cli.commands.context import run_context
15
20
  from bevor_cli.commands.link import run_link
@@ -26,13 +31,24 @@ app = typer.Typer(
26
31
 
27
32
  @app.callback(invoke_without_command=True)
28
33
  def _root(
34
+ ctx: typer.Context,
29
35
  quiet: bool = typer.Option(
30
36
  False,
31
37
  "--quiet",
32
38
  help="Suppress informational output; useful for scripting.",
33
- is_eager=False,
39
+ ),
40
+ version: bool = typer.Option(
41
+ False,
42
+ "--version",
43
+ "-v",
44
+ help="Show the CLI version and exit.",
45
+ callback=_version_callback,
46
+ is_eager=True,
34
47
  ),
35
48
  ) -> None:
49
+ if ctx.invoked_subcommand != "upgrade" and _update_check_enabled(quiet):
50
+ ctx.call_on_close(_notify_if_outdated)
51
+
36
52
  output.set_quiet(quiet)
37
53
 
38
54
 
@@ -43,6 +59,20 @@ def help_command(ctx: typer.Context) -> None:
43
59
  console.print(root_ctx.get_help())
44
60
 
45
61
 
62
+ @app.command("upgrade")
63
+ def upgrade() -> None:
64
+ """Upgrade bevor-cli to the latest release."""
65
+ current = _current_version()
66
+ latest = _latest_version()
67
+ if current >= latest:
68
+ typer.echo(f"Already on the latest version ({current}).")
69
+ return
70
+
71
+ typer.echo(f"Upgrading {current} → {latest}")
72
+ result = subprocess.run(_upgrade_command())
73
+ raise typer.Exit(result.returncode)
74
+
75
+
46
76
  app.command("login")(login)
47
77
  app.command("logout")(logout)
48
78
  app.command("whoami")(whoami)
@@ -0,0 +1,26 @@
1
+ import os
2
+ import sys
3
+
4
+ import typer
5
+
6
+ from bevor_cli.callbacks.version import _current_version
7
+ from bevor_cli.configuration.update import UpdateCheck
8
+
9
+
10
+ def _notify_if_outdated() -> None:
11
+ check = UpdateCheck.refresh()
12
+ if check and check.is_outdated:
13
+ typer.echo(
14
+ f"\nA new version of bevor-cli is available: {_current_version()} → {check.latest}\n"
15
+ "Run `bevor upgrade` to update.",
16
+ err=True,
17
+ )
18
+
19
+
20
+ def _update_check_enabled(quiet: bool) -> bool:
21
+ return (
22
+ not quiet
23
+ and sys.stderr.isatty()
24
+ and not os.environ.get("CI")
25
+ and not os.environ.get("BEVOR_NO_UPDATE_CHECK")
26
+ )
@@ -0,0 +1,23 @@
1
+ import shutil
2
+ import subprocess
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ PACKAGE = "bevor-cli"
7
+
8
+
9
+ def _uv_tool_dir(uv: str) -> Path | None:
10
+ result = subprocess.run([uv, "tool", "dir"], capture_output=True, text=True)
11
+ if result.returncode != 0:
12
+ return None
13
+ return Path(result.stdout.strip()).resolve()
14
+
15
+
16
+ def _upgrade_command() -> list[str]:
17
+ prefix = Path(sys.prefix).resolve()
18
+ uv = shutil.which("uv")
19
+ if uv:
20
+ tool_dir = _uv_tool_dir(uv)
21
+ if tool_dir and prefix.is_relative_to(tool_dir):
22
+ return [uv, "tool", "upgrade", PACKAGE]
23
+ return [sys.executable, "-m", "pip", "install", "--upgrade", PACKAGE]
@@ -0,0 +1,25 @@
1
+ import importlib.metadata
2
+ import json
3
+ import urllib.request
4
+
5
+ import typer
6
+ from packaging.version import Version
7
+
8
+ PACKAGE = "bevor-cli"
9
+
10
+
11
+ def _current_version() -> Version:
12
+ return Version(importlib.metadata.version(PACKAGE))
13
+
14
+
15
+ def _latest_version(timeout: float = 5) -> Version:
16
+ url = f"https://pypi.org/pypi/{PACKAGE}/json"
17
+ with urllib.request.urlopen(url, timeout=timeout) as res:
18
+ return Version(json.load(res)["info"]["version"])
19
+
20
+
21
+ def _version_callback(value: bool) -> None:
22
+ if not value:
23
+ return
24
+ typer.echo(f"bevor-cli {_current_version()}")
25
+ raise typer.Exit()
@@ -59,13 +59,13 @@ def retry_analysis(
59
59
  for event in run_result.stream_completion():
60
60
  if event.id in ep_map:
61
61
  short_id, name, _ = ep_map[event.id]
62
- ep_map[event.id] = (short_id, name, event.status)
62
+ ep_map[event.id] = (short_id, name, event.payload.status)
63
63
  render_status(ep_map)
64
64
  else:
65
65
  for event in run_result.stream_completion():
66
66
  if event.id in ep_map:
67
67
  short_id, name, _ = ep_map[event.id]
68
- ep_map[event.id] = (short_id, name, event.status)
68
+ ep_map[event.id] = (short_id, name, event.payload.status)
69
69
 
70
70
  n_failures = sum(1 if status == "failed" else 0 for _, _, status in ep_map.values())
71
71
  if n_failures > 0:
@@ -69,13 +69,13 @@ def run_analysis(
69
69
  for event in run_result.stream_completion():
70
70
  if event.id in ep_map:
71
71
  short_id, name, _ = ep_map[event.id]
72
- ep_map[event.id] = (short_id, name, event.status)
72
+ ep_map[event.id] = (short_id, name, event.payload.status)
73
73
  live.update(render_status(ep_map))
74
74
  else:
75
75
  for event in run_result.stream_completion():
76
76
  if event.id in ep_map:
77
77
  short_id, name, _ = ep_map[event.id]
78
- ep_map[event.id] = (short_id, name, event.status)
78
+ ep_map[event.id] = (short_id, name, event.payload.status)
79
79
 
80
80
  n_failures = sum(1 if status == "failed" else 0 for _, _, status in ep_map.values())
81
81
  if n_failures > 0:
File without changes
@@ -5,10 +5,12 @@ import json
5
5
  from pathlib import Path
6
6
 
7
7
  import typer
8
- from bevor_cli import output
9
8
  from pydantic import BaseModel
10
9
 
11
- _CREDENTIALS_PATH = Path.home() / ".bevor" / "credentials"
10
+ from bevor_cli import output
11
+
12
+ BEVOR_DIR = Path.home() / ".bevor"
13
+ _CREDENTIALS_PATH = BEVOR_DIR / "credentials"
12
14
 
13
15
 
14
16
  class Credentials(BaseModel):
@@ -5,12 +5,13 @@ from pathlib import Path
5
5
  from typing import Optional
6
6
 
7
7
  import typer
8
- from bevor_cli import output
9
8
  from bevor_sdk.types import ID
10
9
  from bevor_sdk.types.responses.graph import CodeMappingSchema
11
10
  from bevor_sdk.types.responses.security import AnalysisSchema
12
11
  from pydantic import BaseModel
13
12
 
13
+ from bevor_cli import output
14
+
14
15
  _CONFIG_DIR = ".bevor"
15
16
  _CONFIG_FILE = "config.json"
16
17
 
@@ -0,0 +1,50 @@
1
+ import datetime
2
+
3
+ from packaging.version import Version
4
+ from pydantic import BaseModel
5
+
6
+ from bevor_cli.callbacks.version import _current_version, _latest_version
7
+
8
+ from .creds import BEVOR_DIR
9
+
10
+ _UPDATE_CHECK_PATH = BEVOR_DIR / "update-check.json"
11
+ _UPDATE_CHECK_INTERVAL = datetime.timedelta(days=1)
12
+
13
+
14
+ class UpdateCheck(BaseModel):
15
+ latest: str
16
+ checked_at: datetime.datetime
17
+
18
+ @property
19
+ def is_stale(self) -> bool:
20
+ return datetime.datetime.now(datetime.UTC) - self.checked_at >= _UPDATE_CHECK_INTERVAL
21
+
22
+ @property
23
+ def is_outdated(self) -> bool:
24
+ return Version(self.latest) > _current_version()
25
+
26
+ @classmethod
27
+ def load(cls) -> "UpdateCheck | None":
28
+ if not _UPDATE_CHECK_PATH.exists():
29
+ return None
30
+ try:
31
+ return cls.model_validate_json(_UPDATE_CHECK_PATH.read_text())
32
+ except Exception:
33
+ return None
34
+
35
+ @classmethod
36
+ def save(cls, latest: Version) -> "UpdateCheck":
37
+ check = cls(latest=str(latest), checked_at=datetime.datetime.now(datetime.UTC))
38
+ _UPDATE_CHECK_PATH.parent.mkdir(parents=True, exist_ok=True)
39
+ _UPDATE_CHECK_PATH.write_text(check.model_dump_json(indent=2))
40
+ return check
41
+
42
+ @classmethod
43
+ def refresh(cls) -> "UpdateCheck | None":
44
+ check = cls.load()
45
+ if check and not check.is_stale:
46
+ return check
47
+ try:
48
+ return cls.save(_latest_version(timeout=1))
49
+ except (OSError, ValueError):
50
+ return check
@@ -1,17 +1,32 @@
1
1
  import sys
2
2
 
3
3
  import typer
4
- from bevor_sdk.exceptions import BaseError, InvalidScopeError, UnauthorizedError
4
+ from bevor_sdk.exceptions import (
5
+ BaseError,
6
+ InvalidScopeError,
7
+ SessionExpiredError,
8
+ UnauthenticatedError,
9
+ UnauthorizedError,
10
+ )
5
11
 
6
12
  from bevor_cli import output
7
13
  from bevor_cli.apps.main import app
14
+ from bevor_cli.configuration.creds import Credentials
8
15
 
9
16
 
10
17
  def main() -> None:
11
18
  try:
12
- app(standalone_mode=False)
19
+ app()
20
+ except UnauthenticatedError:
21
+ Credentials.delete()
22
+ output.error("Unauthenticated.", hint="Run `bevor login`.")
23
+ sys.exit(1)
13
24
  except UnauthorizedError:
14
- output.error("Unauthorized.", hint="Run `bevor login`.")
25
+ output.error("Unauthorized.", hint="Run `bevor link`.")
26
+ sys.exit(1)
27
+ except SessionExpiredError:
28
+ Credentials.delete()
29
+ output.error("Session Expired. Please re-authenticate", hint="Run `bevor login`.")
15
30
  sys.exit(1)
16
31
  except InvalidScopeError:
17
32
  output.error("Unauthorized: configure a workspace and project.", hint="Run `bevor link`.")
@@ -25,6 +40,7 @@ def main() -> None:
25
40
  except typer.Exit as e:
26
41
  sys.exit(e.exit_code)
27
42
  except Exception as e:
43
+ print(e, type(e))
28
44
  output.error(f"Unexpected error: {e}")
29
45
  sys.exit(1)
30
46
 
@@ -0,0 +1,4 @@
1
+ import os
2
+
3
+ API_URL = os.environ.get("BEVOR_API_URL", "https://api.bevor.io")
4
+ APP_URL = os.environ.get("BEVOR_APP_URL", "https://app.bevor.io")
@@ -1,10 +1,10 @@
1
1
  [project]
2
2
  name = "bevor-cli"
3
- version = "0.1.0"
3
+ version = "0.1.1"
4
4
  description = "Bevor CLI tool for security analysis and graph inspection"
5
5
  requires-python = ">=3.13"
6
6
  dependencies = [
7
- "bevor-sdk==0.1.0",
7
+ "bevor-sdk==0.1.1",
8
8
  "typer~=0.26",
9
9
  "httpx~=0.28",
10
10
  "pydantic~=2.12",
@@ -12,8 +12,10 @@ dependencies = [
12
12
  "rich~=15.0",
13
13
  "pyyaml~=6.0",
14
14
  "click~=8.1",
15
+ "packaging~=26.2",
15
16
  ]
16
17
  classifiers = ["Development Status :: 3 - Alpha"]
18
+ readme = "README.md"
17
19
 
18
20
  [project.scripts]
19
21
  bevor = "bevor_cli.main:main"
bevor_cli-0.1.0/PKG-INFO DELETED
@@ -1,14 +0,0 @@
1
- Metadata-Version: 2.5
2
- Name: bevor-cli
3
- Version: 0.1.0
4
- Summary: Bevor CLI tool for security analysis and graph inspection
5
- Classifier: Development Status :: 3 - Alpha
6
- Requires-Python: >=3.13
7
- Requires-Dist: bevor-sdk==0.1.0
8
- Requires-Dist: click~=8.1
9
- Requires-Dist: httpx~=0.28
10
- Requires-Dist: pydantic~=2.12
11
- Requires-Dist: pyyaml~=6.0
12
- Requires-Dist: questionary~=2.0
13
- Requires-Dist: rich~=15.0
14
- Requires-Dist: typer~=0.26
@@ -1,4 +0,0 @@
1
- import os
2
-
3
- API_URL = os.environ.get("BEVOR_API_URL", "https://api.bevor.ai")
4
- APP_URL = os.environ.get("BEVOR_APP_URL", "https://app.bevor.ai")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes