lightnow-cli 1.3.0__tar.gz → 1.4.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.3.0 → lightnow_cli-1.4.0}/.github/workflows/release.yml +24 -0
- lightnow_cli-1.4.0/.release-please-manifest.json +3 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/CHANGELOG.md +20 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/PKG-INFO +23 -1
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/README.md +21 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/docs/release.md +17 -6
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/__init__.py +1 -1
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/integrations.py +31 -0
- lightnow_cli-1.4.0/lightnow_cli/commands/updates.py +93 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/main.py +23 -3
- lightnow_cli-1.4.0/lightnow_cli/updates.py +382 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/pyproject.toml +2 -1
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_cli.py +2 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_integrations.py +71 -1
- lightnow_cli-1.4.0/tests/test_updates.py +424 -0
- lightnow_cli-1.3.0/.release-please-manifest.json +0 -3
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/.github/workflows/ci.yml +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/.github/workflows/release-please.yml +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/.gitignore +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/CONTRIBUTING.md +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/LICENSE +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/Makefile +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/SECURITY.md +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/docs/development.md +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/examples/README.md +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/examples/docs.md +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/examples/openapi.json +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/examples/server.json +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/authenticated_http.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/client.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/__init__.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/auth.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/context.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/publish.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/query.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/runner.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/commands/validate.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/config.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/tls.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/lightnow_cli/validation.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/release-please-config.json +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/__init__.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_auth_flow.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_authenticated_http.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_client.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_config.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_context.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_tls.py +0 -0
- {lightnow_cli-1.3.0 → lightnow_cli-1.4.0}/tests/test_validation.py +0 -0
|
@@ -96,3 +96,27 @@ jobs:
|
|
|
96
96
|
|
|
97
97
|
- name: Publish distributions to PyPI
|
|
98
98
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
99
|
+
|
|
100
|
+
update-homebrew:
|
|
101
|
+
name: Update Homebrew formula
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
needs: publish-pypi
|
|
104
|
+
|
|
105
|
+
steps:
|
|
106
|
+
- name: Dispatch published version to Homebrew tap
|
|
107
|
+
env:
|
|
108
|
+
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
109
|
+
TAG_NAME: ${{ github.ref_name }}
|
|
110
|
+
run: |
|
|
111
|
+
version="${TAG_NAME#v}"
|
|
112
|
+
payload="$(jq -n \
|
|
113
|
+
--arg formula "lightnow-cli" \
|
|
114
|
+
--arg version "$version" \
|
|
115
|
+
'{event_type: "python-release-published", client_payload: {formula: $formula, version: $version}}')"
|
|
116
|
+
curl --fail-with-body --silent --show-error \
|
|
117
|
+
--request POST \
|
|
118
|
+
--header "Accept: application/vnd.github+json" \
|
|
119
|
+
--header "Authorization: Bearer ${GH_TOKEN}" \
|
|
120
|
+
--header "X-GitHub-Api-Version: 2022-11-28" \
|
|
121
|
+
https://api.github.com/repos/lightnow-ai/homebrew-tap/dispatches \
|
|
122
|
+
--data "$payload"
|
|
@@ -4,6 +4,26 @@ All notable changes to the LightNow CLI are documented here.
|
|
|
4
4
|
|
|
5
5
|
This project follows semantic versioning.
|
|
6
6
|
|
|
7
|
+
## [1.4.0](https://github.com/lightnow-ai/lightnow-cli/compare/v1.3.1...v1.4.0) (2026-07-17)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* **#13:** add managed updates ([844e9c5](https://github.com/lightnow-ai/lightnow-cli/commit/844e9c5cb0fb2134f9e6014f02a0a4ca49db019c))
|
|
13
|
+
* add managed updates ([275387e](https://github.com/lightnow-ai/lightnow-cli/commit/275387e05fd40f5b0564d9001acf9d3ed19ced5a))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* harden managed update checks ([0c3a285](https://github.com/lightnow-ai/lightnow-cli/commit/0c3a285ccdfab4b39e60f905c9274e242245b2d8))
|
|
19
|
+
|
|
20
|
+
## [1.3.1](https://github.com/lightnow-ai/lightnow-cli/compare/v1.3.0...v1.3.1) (2026-07-17)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* **sync:** replace existing codex proxy connection ([c09b7f7](https://github.com/lightnow-ai/lightnow-cli/commit/c09b7f75f9d78c943ed7556b10b10ff99dbb2008))
|
|
26
|
+
|
|
7
27
|
## [1.3.0](https://github.com/lightnow-ai/lightnow-cli/compare/v1.2.0...v1.3.0) (2026-07-15)
|
|
8
28
|
|
|
9
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: lightnow-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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).
|
|
@@ -19,6 +19,9 @@ Required GitHub setup:
|
|
|
19
19
|
- Repository secret: `RELEASE_PLEASE_TOKEN`
|
|
20
20
|
- Token permissions: contents, pull requests, and issues read/write for this
|
|
21
21
|
repository
|
|
22
|
+
- Repository secret: `HOMEBREW_TAP_TOKEN`
|
|
23
|
+
- Token permissions: contents read/write for `lightnow-ai/homebrew-tap`; the
|
|
24
|
+
token is used only to send the post-PyPI repository dispatch
|
|
22
25
|
- Repository Actions setting: allow GitHub Actions to create pull requests
|
|
23
26
|
|
|
24
27
|
Use a real PAT or GitHub App token for `RELEASE_PLEASE_TOKEN`, not the default
|
|
@@ -33,7 +36,11 @@ Normal release flow:
|
|
|
33
36
|
4. Release Please creates the `vX.Y.Z` tag and GitHub Release.
|
|
34
37
|
5. The existing tag-based `Release` workflow builds and publishes PyPI
|
|
35
38
|
distributions through Trusted Publishing.
|
|
36
|
-
6.
|
|
39
|
+
6. After PyPI succeeds, the release workflow dispatches the exact published
|
|
40
|
+
version to `lightnow-ai/homebrew-tap`. The tap regenerates, audits, installs,
|
|
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.
|
|
37
44
|
|
|
38
45
|
Manual release checklist for fallback or first-time setup:
|
|
39
46
|
|
|
@@ -64,11 +71,15 @@ Manual release checklist for fallback or first-time setup:
|
|
|
64
71
|
- `twine check` passes,
|
|
65
72
|
- a GitHub Release is created with generated release notes and distribution artifacts,
|
|
66
73
|
- PyPI publish succeeds through Trusted Publishing.
|
|
67
|
-
8.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
8. Verify the `Update formula` workflow in `lightnow-ai/homebrew-tap`. For a
|
|
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
|
+
```
|
|
72
83
|
|
|
73
84
|
Do not publish with long-lived local PyPI tokens.
|
|
74
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,
|
|
@@ -602,6 +603,8 @@ def sync(
|
|
|
602
603
|
)
|
|
603
604
|
if local_proxy and remove_unmanaged_client_servers:
|
|
604
605
|
removed_direct_servers = direct_server_aliases(existing, export_format)
|
|
606
|
+
if local_proxy and client == "codex" and export_format == "toml":
|
|
607
|
+
existing = remove_codex_mcp_server_alias(existing, connection)
|
|
605
608
|
if (
|
|
606
609
|
local_proxy
|
|
607
610
|
and remove_unmanaged_client_servers
|
|
@@ -1205,6 +1208,11 @@ def build_local_proxy_config(
|
|
|
1205
1208
|
"client_instance_id": client_instance_id,
|
|
1206
1209
|
"device_hostname": socket.gethostname(),
|
|
1207
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),
|
|
1208
1216
|
"telemetry_enabled": True,
|
|
1209
1217
|
}
|
|
1210
1218
|
if isinstance(local_proxy_settings, dict):
|
|
@@ -1296,6 +1304,13 @@ def register_runtime_device_client(
|
|
|
1296
1304
|
"device": {
|
|
1297
1305
|
"reported_hostname": socket.gethostname(),
|
|
1298
1306
|
"platform": runtime_device_platform(),
|
|
1307
|
+
"cli_version": __version__,
|
|
1308
|
+
"cli_install_method": updates.detect_install_method(
|
|
1309
|
+
"lightnow-cli", shutil.which("lightnow") or sys.argv[0]
|
|
1310
|
+
),
|
|
1311
|
+
"cli_latest_version": None,
|
|
1312
|
+
"cli_update_status": "unknown",
|
|
1313
|
+
"cli_update_checked_at": None,
|
|
1299
1314
|
},
|
|
1300
1315
|
"client": {
|
|
1301
1316
|
"name": client,
|
|
@@ -1303,6 +1318,12 @@ def register_runtime_device_client(
|
|
|
1303
1318
|
"profile": profile,
|
|
1304
1319
|
"runner_name": "lightnow-local-proxy",
|
|
1305
1320
|
"runner_version": None,
|
|
1321
|
+
"runner_install_method": updates.detect_install_method(
|
|
1322
|
+
"lightnow-proxy", local_proxy_command()
|
|
1323
|
+
),
|
|
1324
|
+
"runner_latest_version": None,
|
|
1325
|
+
"runner_update_status": "unknown",
|
|
1326
|
+
"runner_update_checked_at": None,
|
|
1306
1327
|
"transport": transport,
|
|
1307
1328
|
},
|
|
1308
1329
|
},
|
|
@@ -2281,6 +2302,16 @@ def prepare_codex_local_proxy_config(existing: str) -> str:
|
|
|
2281
2302
|
return strip_codex_mcp_server_tables(existing, preserved)
|
|
2282
2303
|
|
|
2283
2304
|
|
|
2305
|
+
def remove_codex_mcp_server_alias(existing: str, alias: str) -> str:
|
|
2306
|
+
"""Remove one Codex MCP table before writing its managed replacement."""
|
|
2307
|
+
if not existing.strip():
|
|
2308
|
+
return existing
|
|
2309
|
+
entries = extract_mcp_entries(existing, "toml")
|
|
2310
|
+
if alias not in entries:
|
|
2311
|
+
return existing
|
|
2312
|
+
return strip_codex_mcp_server_tables(existing, set(entries) - {alias})
|
|
2313
|
+
|
|
2314
|
+
|
|
2284
2315
|
def prepare_json_local_proxy_config(existing: str) -> str:
|
|
2285
2316
|
"""Remove direct JSON servers while preserving existing proxy connections."""
|
|
2286
2317
|
if not existing.strip():
|
|
@@ -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:
|