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.
Files changed (46) hide show
  1. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/PKG-INFO +1 -1
  2. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/pyproject.toml +1 -1
  3. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/oauth.py +5 -1
  4. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/auth.py +11 -0
  5. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/get.py +5 -1
  6. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/helpers.py +17 -0
  7. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/hierarchy.py +3 -1
  8. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/list_cmd.py +4 -1
  9. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/search.py +3 -1
  10. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/todo.py +3 -1
  11. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/PKG-INFO +1 -1
  12. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/README.md +0 -0
  13. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/setup.cfg +0 -0
  14. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/__init__.py +0 -0
  15. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/__init__.py +0 -0
  16. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/encryption.py +0 -0
  17. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/auth/token_store.py +0 -0
  18. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/__init__.py +0 -0
  19. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/asset.py +0 -0
  20. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/automation.py +0 -0
  21. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/completions.py +0 -0
  22. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/config_cmd.py +0 -0
  23. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/context.py +0 -0
  24. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/entry.py +0 -0
  25. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/files.py +0 -0
  26. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/framework.py +0 -0
  27. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/main.py +0 -0
  28. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/cli/profile_cmd.py +0 -0
  29. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/client.py +0 -0
  30. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/config.py +0 -0
  31. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/errors.py +0 -0
  32. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/__init__.py +0 -0
  33. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/json_fmt.py +0 -0
  34. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/table.py +0 -0
  35. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/formatters/tree.py +0 -0
  36. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/profile.py +0 -0
  37. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/src/uploads.py +0 -0
  38. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_client.py +0 -0
  39. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_config.py +0 -0
  40. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_profile.py +0 -0
  41. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/tests/test_uploads.py +0 -0
  42. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/SOURCES.txt +0 -0
  43. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/dependency_links.txt +0 -0
  44. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/entry_points.txt +0 -0
  45. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/requires.txt +0 -0
  46. {upscaler_cli-0.2.3.dev6697 → upscaler_cli-0.2.3.dev6699}/upscaler_cli.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: upscaler-cli
3
- Version: 0.2.3.dev6697
3
+ Version: 0.2.3.dev6699
4
4
  Summary: Upscaler CLI - search, retrieve, and manage documents, records, and workflows
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: click>=8.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.dev6697"
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
- organization_id=token_data.organization_id,
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: upscaler-cli
3
- Version: 0.2.3.dev6697
3
+ Version: 0.2.3.dev6699
4
4
  Summary: Upscaler CLI - search, retrieve, and manage documents, records, and workflows
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: click>=8.0