upscaler-cli 0.2.3.dev6697__tar.gz → 0.2.3.dev6699__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.
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/PKG-INFO +1 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/pyproject.toml +1 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/oauth.py +5 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/auth.py +11 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/get.py +5 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/helpers.py +17 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/hierarchy.py +3 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/list_cmd.py +4 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/search.py +3 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/todo.py +3 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/PKG-INFO +1 -1
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/README.md +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/setup.cfg +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/__init__.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/__init__.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/encryption.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/token_store.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/__init__.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/asset.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/automation.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/completions.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/config_cmd.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/context.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/entry.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/files.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/framework.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/main.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/profile_cmd.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/client.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/config.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/errors.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/__init__.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/json_fmt.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/table.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/tree.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/profile.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/uploads.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_client.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_config.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_profile.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_uploads.py +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/SOURCES.txt +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/dependency_links.txt +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/entry_points.txt +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/requires.txt +0 -0
- {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/top_level.txt +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "upscaler-cli"
|
|
7
|
-
version = "0.2.3.
|
|
7
|
+
version = "0.2.3.dev6699"
|
|
8
8
|
description = "Upscaler CLI - search, retrieve, and manage documents, records, and workflows"
|
|
9
9
|
requires-python = ">=3.10"
|
|
10
10
|
dependencies = [
|
|
@@ -477,7 +477,11 @@ class OAuthFlow:
|
|
|
477
477
|
expires_at=time.time() + data.get("expires_in", 86400),
|
|
478
478
|
client_id=token_data.client_id,
|
|
479
479
|
client_secret=token_data.client_secret,
|
|
480
|
-
|
|
480
|
+
# Read org from the refresh response (matching the login path) so a
|
|
481
|
+
# refreshed session reflects the token's real scope. Fall back to the
|
|
482
|
+
# existing value when the endpoint omits it, to avoid nulling a
|
|
483
|
+
# previously-valid org.
|
|
484
|
+
organization_id=data.get("organization_id") or token_data.organization_id,
|
|
481
485
|
token_endpoint=token_data.token_endpoint,
|
|
482
486
|
)
|
|
483
487
|
|
|
@@ -388,6 +388,7 @@ def status(ctx):
|
|
|
388
388
|
return
|
|
389
389
|
|
|
390
390
|
mode = "device" if token_data.client_id == "device" else "oauth"
|
|
391
|
+
refresh_present = bool(token_data.refresh_token)
|
|
391
392
|
|
|
392
393
|
if ctx.json_mode:
|
|
393
394
|
expires_in = int(token_data.expires_at - time.time())
|
|
@@ -397,11 +398,21 @@ def status(ctx):
|
|
|
397
398
|
"expires_in": max(0, expires_in),
|
|
398
399
|
"organization_id": token_data.organization_id,
|
|
399
400
|
"mode": mode,
|
|
401
|
+
"refresh_token_present": refresh_present,
|
|
400
402
|
}))
|
|
401
403
|
else:
|
|
404
|
+
expires_in = int(token_data.expires_at - time.time())
|
|
402
405
|
click.echo(f"Status: Authenticated ({mode})")
|
|
403
406
|
if token_data.organization_id:
|
|
404
407
|
click.echo(f"Organization: {token_data.organization_id}")
|
|
408
|
+
if expires_in <= 0:
|
|
409
|
+
click.echo("Token: expired (run: upscaler refresh)")
|
|
410
|
+
else:
|
|
411
|
+
click.echo(f"Expires in: {_format_duration(expires_in)}")
|
|
412
|
+
if refresh_present:
|
|
413
|
+
click.echo("Refresh token: present")
|
|
414
|
+
else:
|
|
415
|
+
click.echo("Refresh token: missing (re-login required on expiry)")
|
|
405
416
|
|
|
406
417
|
|
|
407
418
|
@click.command()
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
import click
|
|
7
7
|
|
|
8
8
|
from src.cli.context import pass_context
|
|
9
|
-
from src.cli.helpers import handle_error
|
|
9
|
+
from src.cli.helpers import handle_error, raise_on_envelope_error
|
|
10
10
|
|
|
11
11
|
# Prefix → (type, endpoint)
|
|
12
12
|
# NOTE: longer prefixes must come before shorter ones (e.g. "to_" before "t_")
|
|
@@ -133,6 +133,8 @@ def _get_asset(ctx, client, asset_id, fmt, format_json, draft=False):
|
|
|
133
133
|
handle_error(ctx, e)
|
|
134
134
|
return
|
|
135
135
|
|
|
136
|
+
raise_on_envelope_error(ctx, result)
|
|
137
|
+
|
|
136
138
|
data = result.get("data", {})
|
|
137
139
|
|
|
138
140
|
if ctx.json_mode:
|
|
@@ -161,6 +163,8 @@ def _get_simple(ctx, client, endpoint, format_json):
|
|
|
161
163
|
handle_error(ctx, e)
|
|
162
164
|
return
|
|
163
165
|
|
|
166
|
+
raise_on_envelope_error(ctx, result)
|
|
167
|
+
|
|
164
168
|
data = result.get("data", {})
|
|
165
169
|
|
|
166
170
|
if ctx.json_mode:
|
|
@@ -142,6 +142,21 @@ def handle_error(ctx, e) -> None:
|
|
|
142
142
|
sys.exit(exit_code)
|
|
143
143
|
|
|
144
144
|
|
|
145
|
+
def raise_on_envelope_error(ctx, result) -> None:
|
|
146
|
+
"""Exit with the server's error when a read returns a failure envelope.
|
|
147
|
+
|
|
148
|
+
The REST API returns HTTP 200 with {"success": false, "error": {...},
|
|
149
|
+
"data": []} for failures the native tools catch internally (e.g. missing
|
|
150
|
+
organization context). `client.request` only raises on HTTP >= 400, so these
|
|
151
|
+
slip through to read commands that look only at `data` and render the empty
|
|
152
|
+
result as "No results". Mirror the write-path guard (emit_action_result) so
|
|
153
|
+
reads fail loudly and exit non-zero too. Only an explicit `success: false`
|
|
154
|
+
triggers this; success responses (success true or absent) pass through.
|
|
155
|
+
"""
|
|
156
|
+
if isinstance(result, dict) and result.get("success") is False:
|
|
157
|
+
handle_error(ctx, CLIError(_envelope_error_message(result.get("error"))))
|
|
158
|
+
|
|
159
|
+
|
|
145
160
|
def _resolve_id(data: dict, id_keys) -> str:
|
|
146
161
|
"""Return the first non-empty id value among id_keys, or ''."""
|
|
147
162
|
for key in id_keys:
|
|
@@ -307,6 +322,8 @@ def execute_rest_action(ctx, payload: dict, endpoint: str, render=None, dry_run:
|
|
|
307
322
|
handle_error(ctx, e)
|
|
308
323
|
return
|
|
309
324
|
|
|
325
|
+
raise_on_envelope_error(ctx, result)
|
|
326
|
+
|
|
310
327
|
if ctx.json_mode:
|
|
311
328
|
click.echo(format_json(result, compact=True))
|
|
312
329
|
return
|
|
@@ -5,7 +5,7 @@ import asyncio
|
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
7
|
from src.cli.context import pass_context
|
|
8
|
-
from src.cli.helpers import handle_error
|
|
8
|
+
from src.cli.helpers import handle_error, raise_on_envelope_error
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@click.command()
|
|
@@ -37,6 +37,8 @@ def hierarchy(ctx, asset_id, depth, include_siblings):
|
|
|
37
37
|
handle_error(ctx, e)
|
|
38
38
|
return
|
|
39
39
|
|
|
40
|
+
raise_on_envelope_error(ctx, result)
|
|
41
|
+
|
|
40
42
|
if ctx.json_mode:
|
|
41
43
|
click.echo(format_json(result, compact=True))
|
|
42
44
|
else:
|
|
@@ -7,7 +7,7 @@ import re
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from src.cli.context import pass_context
|
|
10
|
-
from src.cli.helpers import handle_error
|
|
10
|
+
from src.cli.helpers import handle_error, raise_on_envelope_error
|
|
11
11
|
|
|
12
12
|
# Top-level filter keys that are not asset value fields. Anything else passed
|
|
13
13
|
# via --filter without a `values.` prefix gets auto-prefixed for ergonomics.
|
|
@@ -265,6 +265,7 @@ def _fetch_schema_fields(ctx, definition_id):
|
|
|
265
265
|
except Exception as e:
|
|
266
266
|
handle_error(ctx, e)
|
|
267
267
|
raise click.Abort()
|
|
268
|
+
raise_on_envelope_error(ctx, result)
|
|
268
269
|
schema = result.get("data", {}).get("schema") or {}
|
|
269
270
|
return schema.get("fields") or []
|
|
270
271
|
|
|
@@ -365,6 +366,8 @@ def _do_list(
|
|
|
365
366
|
handle_error(ctx, e)
|
|
366
367
|
return
|
|
367
368
|
|
|
369
|
+
raise_on_envelope_error(ctx, result)
|
|
370
|
+
|
|
368
371
|
if schema_fields:
|
|
369
372
|
_rewrite_values_to_labels(result, schema_fields)
|
|
370
373
|
|
|
@@ -5,7 +5,7 @@ import asyncio
|
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
7
|
from src.cli.context import pass_context
|
|
8
|
-
from src.cli.helpers import handle_error
|
|
8
|
+
from src.cli.helpers import handle_error, raise_on_envelope_error
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@click.command()
|
|
@@ -116,6 +116,8 @@ def search(
|
|
|
116
116
|
handle_error(ctx, e)
|
|
117
117
|
return
|
|
118
118
|
|
|
119
|
+
raise_on_envelope_error(ctx, result)
|
|
120
|
+
|
|
119
121
|
if ctx.json_mode:
|
|
120
122
|
click.echo(format_json(result, compact=True))
|
|
121
123
|
else:
|
|
@@ -5,7 +5,7 @@ import asyncio
|
|
|
5
5
|
import click
|
|
6
6
|
|
|
7
7
|
from src.cli.context import pass_context
|
|
8
|
-
from src.cli.helpers import handle_error
|
|
8
|
+
from src.cli.helpers import handle_error, raise_on_envelope_error
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@click.group("todo")
|
|
@@ -115,6 +115,8 @@ def _execute_todo(ctx, operation, todo_id=None, data=None, dry_run=False):
|
|
|
115
115
|
handle_error(ctx, e)
|
|
116
116
|
return
|
|
117
117
|
|
|
118
|
+
raise_on_envelope_error(ctx, result)
|
|
119
|
+
|
|
118
120
|
if ctx.json_mode:
|
|
119
121
|
click.echo(format_json(result, compact=True))
|
|
120
122
|
else:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/requires.txt
RENAMED
|
File without changes
|
{upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/top_level.txt
RENAMED
|
File without changes
|