lightnow-cli 1.3.1__tar.gz → 1.5.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.
- lightnow_cli-1.5.0/.release-please-manifest.json +3 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/CHANGELOG.md +21 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/PKG-INFO +23 -1
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/README.md +21 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/docs/release.md +11 -4
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/__init__.py +1 -1
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/integrations.py +23 -0
- lightnow_cli-1.5.0/lightnow_cli/commands/updates.py +93 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/main.py +23 -3
- lightnow_cli-1.5.0/lightnow_cli/updates.py +382 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/pyproject.toml +2 -1
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_cli.py +2 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_integrations.py +28 -1
- lightnow_cli-1.5.0/tests/test_updates.py +424 -0
- lightnow_cli-1.3.1/.release-please-manifest.json +0 -3
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/.github/workflows/ci.yml +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/.github/workflows/release-please.yml +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/.github/workflows/release.yml +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/.gitignore +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/CONTRIBUTING.md +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/LICENSE +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/Makefile +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/SECURITY.md +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/docs/development.md +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/examples/README.md +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/examples/docs.md +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/examples/openapi.json +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/examples/server.json +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/authenticated_http.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/client.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/__init__.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/auth.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/context.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/publish.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/query.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/runner.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/commands/validate.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/config.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/tls.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/lightnow_cli/validation.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/release-please-config.json +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/__init__.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_auth_flow.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_authenticated_http.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_client.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_config.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_context.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_tls.py +0 -0
- {lightnow_cli-1.3.1 → lightnow_cli-1.5.0}/tests/test_validation.py +0 -0
|
@@ -4,6 +4,27 @@ All notable changes to the LightNow CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
This project follows semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [1.5.0](https://github.com/lightnow-ai/lightnow-cli/compare/v1.4.0...v1.5.0) (2026-07-18)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **#15:** configure runtime tool argument capture ([c83ff54](https://github.com/lightnow-ai/lightnow-cli/commit/c83ff54d4373bde152cca68a40f1c4e802e79e86))
|
|
13
|
+
* **sync:** configure tool argument capture ([09f591a](https://github.com/lightnow-ai/lightnow-cli/commit/09f591a94cb014998681223147a79ffcaff062e8))
|
|
14
|
+
|
|
15
|
+
## [1.4.0](https://github.com/lightnow-ai/lightnow-cli/compare/v1.3.1...v1.4.0) (2026-07-17)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Features
|
|
19
|
+
|
|
20
|
+
* **#13:** add managed updates ([844e9c5](https://github.com/lightnow-ai/lightnow-cli/commit/844e9c5cb0fb2134f9e6014f02a0a4ca49db019c))
|
|
21
|
+
* add managed updates ([275387e](https://github.com/lightnow-ai/lightnow-cli/commit/275387e05fd40f5b0564d9001acf9d3ed19ced5a))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
* harden managed update checks ([0c3a285](https://github.com/lightnow-ai/lightnow-cli/commit/0c3a285ccdfab4b39e60f905c9274e242245b2d8))
|
|
27
|
+
|
|
7
28
|
## [1.3.1](https://github.com/lightnow-ai/lightnow-cli/compare/v1.3.0...v1.3.1) (2026-07-17)
|
|
8
29
|
|
|
9
30
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lightnow-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: Official LightNow CLI for MCP registry discovery, client config sync, and local MCP runner workflows
|
|
5
5
|
Project-URL: Homepage, https://github.com/lightnow-ai/lightnow-cli
|
|
6
6
|
Project-URL: Repository, https://github.com/lightnow-ai/lightnow-cli
|
|
@@ -21,6 +21,7 @@ Requires-Python: >=3.11
|
|
|
21
21
|
Requires-Dist: filelock>=3.16.1
|
|
22
22
|
Requires-Dist: httpx>=0.24.0
|
|
23
23
|
Requires-Dist: jsonschema>=4.17.0
|
|
24
|
+
Requires-Dist: packaging>=24.0
|
|
24
25
|
Requires-Dist: pydantic>=2.0.0
|
|
25
26
|
Requires-Dist: pyjwt>=2.8.0
|
|
26
27
|
Requires-Dist: pyyaml>=6.0.0
|
|
@@ -88,6 +89,25 @@ If you prefer installing directly from the public repository:
|
|
|
88
89
|
pipx install git+https://github.com/lightnow-ai/lightnow-cli.git
|
|
89
90
|
```
|
|
90
91
|
|
|
92
|
+
## Update
|
|
93
|
+
|
|
94
|
+
The CLI manages supported installations of both the CLI and Local Proxy:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
lightnow update --check
|
|
98
|
+
lightnow update
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Use `lightnow update --yes` for an approved non-interactive update or
|
|
102
|
+
`lightnow update --check --json` for automation. Managed updates support
|
|
103
|
+
Homebrew, pipx and uv. Editable, plain pip and unknown virtual-environment
|
|
104
|
+
installs are reported but never changed automatically.
|
|
105
|
+
|
|
106
|
+
Interactive CLI sessions check the release catalog at most once per day and
|
|
107
|
+
show a short notice when an update is ready across all supported channels. Set
|
|
108
|
+
`LIGHTNOW_NO_UPDATE_CHECK=1` to disable this background check. The Local Proxy
|
|
109
|
+
never installs updates itself.
|
|
110
|
+
|
|
91
111
|
## Sign In
|
|
92
112
|
|
|
93
113
|
```bash
|
|
@@ -227,6 +247,8 @@ machine and its client-specific Runtime Profile in the LightNow Control Plane.
|
|
|
227
247
|
The CLI stores a stable installation UUID in its protected configuration and a
|
|
228
248
|
separate stable client-instance UUID in each generated proxy configuration. It
|
|
229
249
|
does not report IP or MAC addresses, serial numbers, local paths, or secrets.
|
|
250
|
+
The Control Plane can additionally show the observed CLI and Proxy versions,
|
|
251
|
+
their supported installation channel and whether an update is available.
|
|
230
252
|
|
|
231
253
|
For details, examples, diagrams and troubleshooting, see
|
|
232
254
|
[Connect MCP clients](https://docs.lightnow.ai/getting-started/sync-mcp-clients).
|
|
@@ -41,6 +41,25 @@ If you prefer installing directly from the public repository:
|
|
|
41
41
|
pipx install git+https://github.com/lightnow-ai/lightnow-cli.git
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
## Update
|
|
45
|
+
|
|
46
|
+
The CLI manages supported installations of both the CLI and Local Proxy:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
lightnow update --check
|
|
50
|
+
lightnow update
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Use `lightnow update --yes` for an approved non-interactive update or
|
|
54
|
+
`lightnow update --check --json` for automation. Managed updates support
|
|
55
|
+
Homebrew, pipx and uv. Editable, plain pip and unknown virtual-environment
|
|
56
|
+
installs are reported but never changed automatically.
|
|
57
|
+
|
|
58
|
+
Interactive CLI sessions check the release catalog at most once per day and
|
|
59
|
+
show a short notice when an update is ready across all supported channels. Set
|
|
60
|
+
`LIGHTNOW_NO_UPDATE_CHECK=1` to disable this background check. The Local Proxy
|
|
61
|
+
never installs updates itself.
|
|
62
|
+
|
|
44
63
|
## Sign In
|
|
45
64
|
|
|
46
65
|
```bash
|
|
@@ -180,6 +199,8 @@ machine and its client-specific Runtime Profile in the LightNow Control Plane.
|
|
|
180
199
|
The CLI stores a stable installation UUID in its protected configuration and a
|
|
181
200
|
separate stable client-instance UUID in each generated proxy configuration. It
|
|
182
201
|
does not report IP or MAC addresses, serial numbers, local paths, or secrets.
|
|
202
|
+
The Control Plane can additionally show the observed CLI and Proxy versions,
|
|
203
|
+
their supported installation channel and whether an update is available.
|
|
183
204
|
|
|
184
205
|
For details, examples, diagrams and troubleshooting, see
|
|
185
206
|
[Connect MCP clients](https://docs.lightnow.ai/getting-started/sync-mcp-clients).
|
|
@@ -38,7 +38,9 @@ Normal release flow:
|
|
|
38
38
|
distributions through Trusted Publishing.
|
|
39
39
|
6. After PyPI succeeds, the release workflow dispatches the exact published
|
|
40
40
|
version to `lightnow-ai/homebrew-tap`. The tap regenerates, audits, installs,
|
|
41
|
-
and tests the formula before committing it.
|
|
41
|
+
and tests the formula before committing it together with `releases.json`.
|
|
42
|
+
The public catalog advances only after the Homebrew artifact is verified,
|
|
43
|
+
so `lightnow update` never advertises a release that the tap cannot install.
|
|
42
44
|
|
|
43
45
|
Manual release checklist for fallback or first-time setup:
|
|
44
46
|
|
|
@@ -70,9 +72,14 @@ Manual release checklist for fallback or first-time setup:
|
|
|
70
72
|
- a GitHub Release is created with generated release notes and distribution artifacts,
|
|
71
73
|
- PyPI publish succeeds through Trusted Publishing.
|
|
72
74
|
8. Verify the `Update formula` workflow in `lightnow-ai/homebrew-tap`. For a
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
recovery run, dispatch it manually with formula `lightnow-cli` and the exact
|
|
76
|
+
already-published version; it uses the same generation and verification path
|
|
77
|
+
as the automatic release dispatch.
|
|
78
|
+
9. Verify the catalog and managed update path:
|
|
79
|
+
```bash
|
|
80
|
+
curl -fsSL https://raw.githubusercontent.com/lightnow-ai/homebrew-tap/main/releases.json
|
|
81
|
+
lightnow update --check
|
|
82
|
+
```
|
|
76
83
|
|
|
77
84
|
Do not publish with long-lived local PyPI tokens.
|
|
78
85
|
|
|
@@ -23,6 +23,7 @@ import yaml
|
|
|
23
23
|
from rich.console import Console
|
|
24
24
|
from typing_extensions import Annotated
|
|
25
25
|
|
|
26
|
+
from .. import __version__, updates
|
|
26
27
|
from ..authenticated_http import (
|
|
27
28
|
authentication_error_from_response,
|
|
28
29
|
request_with_refresh,
|
|
@@ -1207,12 +1208,21 @@ def build_local_proxy_config(
|
|
|
1207
1208
|
"client_instance_id": client_instance_id,
|
|
1208
1209
|
"device_hostname": socket.gethostname(),
|
|
1209
1210
|
"device_platform": runtime_device_platform(),
|
|
1211
|
+
"cli_version": __version__,
|
|
1212
|
+
"cli_install_method": updates.detect_install_method(
|
|
1213
|
+
"lightnow-cli", shutil.which("lightnow") or sys.argv[0]
|
|
1214
|
+
),
|
|
1215
|
+
"update_state_path": str(updates.UPDATE_STATE_PATH),
|
|
1210
1216
|
"telemetry_enabled": True,
|
|
1217
|
+
"capture_tool_arguments": True,
|
|
1211
1218
|
}
|
|
1212
1219
|
if isinstance(local_proxy_settings, dict):
|
|
1213
1220
|
local_proxy_config["telemetry_enabled"] = (
|
|
1214
1221
|
local_proxy_settings.get("telemetryEnabled") is not False
|
|
1215
1222
|
)
|
|
1223
|
+
local_proxy_config["capture_tool_arguments"] = (
|
|
1224
|
+
local_proxy_settings.get("captureToolArguments") is not False
|
|
1225
|
+
)
|
|
1216
1226
|
local_proxy_config["allow_unmanaged_client_servers"] = (
|
|
1217
1227
|
local_proxy_settings.get("allowUnmanagedClientServers") is not False
|
|
1218
1228
|
)
|
|
@@ -1298,6 +1308,13 @@ def register_runtime_device_client(
|
|
|
1298
1308
|
"device": {
|
|
1299
1309
|
"reported_hostname": socket.gethostname(),
|
|
1300
1310
|
"platform": runtime_device_platform(),
|
|
1311
|
+
"cli_version": __version__,
|
|
1312
|
+
"cli_install_method": updates.detect_install_method(
|
|
1313
|
+
"lightnow-cli", shutil.which("lightnow") or sys.argv[0]
|
|
1314
|
+
),
|
|
1315
|
+
"cli_latest_version": None,
|
|
1316
|
+
"cli_update_status": "unknown",
|
|
1317
|
+
"cli_update_checked_at": None,
|
|
1301
1318
|
},
|
|
1302
1319
|
"client": {
|
|
1303
1320
|
"name": client,
|
|
@@ -1305,6 +1322,12 @@ def register_runtime_device_client(
|
|
|
1305
1322
|
"profile": profile,
|
|
1306
1323
|
"runner_name": "lightnow-local-proxy",
|
|
1307
1324
|
"runner_version": None,
|
|
1325
|
+
"runner_install_method": updates.detect_install_method(
|
|
1326
|
+
"lightnow-proxy", local_proxy_command()
|
|
1327
|
+
),
|
|
1328
|
+
"runner_latest_version": None,
|
|
1329
|
+
"runner_update_status": "unknown",
|
|
1330
|
+
"runner_update_checked_at": None,
|
|
1308
1331
|
"transport": transport,
|
|
1309
1332
|
},
|
|
1310
1333
|
},
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""User-facing managed update commands."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json as json_module
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Annotated
|
|
8
|
+
|
|
9
|
+
import typer
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.table import Table
|
|
12
|
+
|
|
13
|
+
from lightnow_cli import updates
|
|
14
|
+
|
|
15
|
+
console = Console()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _render(state: dict, json_output: bool) -> None:
|
|
19
|
+
if json_output:
|
|
20
|
+
typer.echo(json_module.dumps(state, indent=2))
|
|
21
|
+
return
|
|
22
|
+
table = Table(title="LightNow updates")
|
|
23
|
+
table.add_column("Component")
|
|
24
|
+
table.add_column("Installed")
|
|
25
|
+
table.add_column("Latest")
|
|
26
|
+
table.add_column("Installer")
|
|
27
|
+
table.add_column("Status")
|
|
28
|
+
table.add_column("Result")
|
|
29
|
+
for package, entry in state.get("packages", {}).items():
|
|
30
|
+
table.add_row(
|
|
31
|
+
package,
|
|
32
|
+
entry.get("installed_version") or "not installed",
|
|
33
|
+
entry.get("latest_version") or "unknown",
|
|
34
|
+
entry.get("install_method") or "unknown",
|
|
35
|
+
entry.get("status") or "unknown",
|
|
36
|
+
entry.get("result") or "checked",
|
|
37
|
+
)
|
|
38
|
+
if entry.get("error"):
|
|
39
|
+
table.add_row("", "", "", "", "", f"[red]{entry['error']}[/red]")
|
|
40
|
+
console.print(table)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def update(
|
|
44
|
+
yes: Annotated[
|
|
45
|
+
bool, typer.Option("--yes", "-y", help="Apply updates without prompting.")
|
|
46
|
+
] = False,
|
|
47
|
+
check: Annotated[
|
|
48
|
+
bool, typer.Option("--check", help="Check only; do not install updates.")
|
|
49
|
+
] = False,
|
|
50
|
+
json_output: Annotated[
|
|
51
|
+
bool, typer.Option("--json", help="Print machine-readable JSON.")
|
|
52
|
+
] = False,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""Check for and apply LightNow CLI and Local Proxy updates."""
|
|
55
|
+
if check and yes:
|
|
56
|
+
raise typer.BadParameter("--yes cannot be combined with --check")
|
|
57
|
+
if json_output and not check and not yes:
|
|
58
|
+
raise typer.BadParameter(
|
|
59
|
+
"--json requires --check or --yes to avoid an interactive prompt"
|
|
60
|
+
)
|
|
61
|
+
try:
|
|
62
|
+
state = updates.refresh_update_state()
|
|
63
|
+
except Exception as error:
|
|
64
|
+
if json_output:
|
|
65
|
+
typer.echo(
|
|
66
|
+
json_module.dumps({"error": str(error), "packages": {}}, indent=2)
|
|
67
|
+
)
|
|
68
|
+
else:
|
|
69
|
+
console.print(f"[red]Could not check for LightNow updates:[/red] {error}")
|
|
70
|
+
raise typer.Exit(1) from error
|
|
71
|
+
|
|
72
|
+
outdated = updates.cached_outdated_packages(state)
|
|
73
|
+
if check or not outdated:
|
|
74
|
+
_render(state, json_output)
|
|
75
|
+
return
|
|
76
|
+
if not yes and not typer.confirm(
|
|
77
|
+
f"Update {len(outdated)} LightNow component(s) now?"
|
|
78
|
+
):
|
|
79
|
+
_render(state, json_output)
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
state, success = updates.apply_updates(state)
|
|
83
|
+
_render(state, json_output)
|
|
84
|
+
if not success:
|
|
85
|
+
raise typer.Exit(1)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def refresh_update_state() -> None:
|
|
89
|
+
"""Refresh update state in a detached helper process."""
|
|
90
|
+
try:
|
|
91
|
+
updates.refresh_update_state()
|
|
92
|
+
finally:
|
|
93
|
+
Path(updates.UPDATE_PENDING_PATH).unlink(missing_ok=True)
|
|
@@ -3,8 +3,19 @@
|
|
|
3
3
|
import typer
|
|
4
4
|
from typing_extensions import Annotated
|
|
5
5
|
|
|
6
|
-
from . import __version__
|
|
7
|
-
from .commands import
|
|
6
|
+
from . import __version__, updates
|
|
7
|
+
from .commands import (
|
|
8
|
+
auth,
|
|
9
|
+
context,
|
|
10
|
+
integrations,
|
|
11
|
+
publish,
|
|
12
|
+
query,
|
|
13
|
+
runner,
|
|
14
|
+
)
|
|
15
|
+
from .commands import updates as update_commands
|
|
16
|
+
from .commands import (
|
|
17
|
+
validate,
|
|
18
|
+
)
|
|
8
19
|
from .tls import configure_tls_trust_store
|
|
9
20
|
|
|
10
21
|
configure_tls_trust_store()
|
|
@@ -29,6 +40,8 @@ app.command("import-config")(integrations.import_config)
|
|
|
29
40
|
app.command("sync")(integrations.sync)
|
|
30
41
|
app.command("config-status")(integrations.config_status)
|
|
31
42
|
app.command("run")(runner.run)
|
|
43
|
+
app.command("update")(update_commands.update)
|
|
44
|
+
app.command("_refresh-update-state", hidden=True)(update_commands.refresh_update_state)
|
|
32
45
|
|
|
33
46
|
|
|
34
47
|
def version_callback(value: bool) -> None:
|
|
@@ -45,7 +58,14 @@ def main(
|
|
|
45
58
|
] = False,
|
|
46
59
|
) -> None:
|
|
47
60
|
"""LightNow CLI."""
|
|
48
|
-
|
|
61
|
+
if updates.should_check_automatically():
|
|
62
|
+
outdated = updates.cached_outdated_packages(updates.read_update_state())
|
|
63
|
+
if outdated:
|
|
64
|
+
typer.echo(
|
|
65
|
+
f"LightNow update available for {', '.join(outdated)}. Run `lightnow update`.",
|
|
66
|
+
err=True,
|
|
67
|
+
)
|
|
68
|
+
updates.start_background_refresh()
|
|
49
69
|
|
|
50
70
|
|
|
51
71
|
def cli() -> None:
|