cortexdb-cli 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl
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.
- cortexdb_cli/__init__.py +1 -1
- cortexdb_cli/commands/admin_access.py +14 -1
- cortexdb_cli/commands/changes.py +121 -35
- cortexdb_cli/commands/tokens.py +4 -2
- cortexdb_cli/errors.py +19 -2
- {cortexdb_cli-0.7.0.dist-info → cortexdb_cli-0.7.1.dist-info}/METADATA +23 -6
- {cortexdb_cli-0.7.0.dist-info → cortexdb_cli-0.7.1.dist-info}/RECORD +9 -9
- {cortexdb_cli-0.7.0.dist-info → cortexdb_cli-0.7.1.dist-info}/WHEEL +0 -0
- {cortexdb_cli-0.7.0.dist-info → cortexdb_cli-0.7.1.dist-info}/entry_points.txt +0 -0
cortexdb_cli/__init__.py
CHANGED
|
@@ -151,7 +151,11 @@ def tenant_settings(ctx, root, mode, readiness_ticket, clear_readiness):
|
|
|
151
151
|
def tenant_binding(ctx, root, from_tenant, apply_):
|
|
152
152
|
"""Bind a root's records and tombstones to the tenant it names (POST /v1/admin/access/tenant-binding).
|
|
153
153
|
|
|
154
|
-
A DRY RUN unless --apply; running it again is safe.
|
|
154
|
+
A DRY RUN unless --apply; running it again is safe. The dry run says how
|
|
155
|
+
the operator plane decides the real run (operator_plane: whether it
|
|
156
|
+
registers the root, is in-band, the tenant's mode): when it says
|
|
157
|
+
break_glass_required, pass --break-glass REASON --break-glass-ticket
|
|
158
|
+
TICKET with --apply.
|
|
155
159
|
"""
|
|
156
160
|
cfg = ctx.obj
|
|
157
161
|
scope = root_or_die(cfg, root)
|
|
@@ -169,6 +173,15 @@ def tenant_binding(ctx, root, from_tenant, apply_):
|
|
|
169
173
|
+ (", root registered" if d.get("root_registered") else ""))
|
|
170
174
|
if d.get("consistency_token"):
|
|
171
175
|
console.print(f"[dim] consistency token: {escape(str(d['consistency_token']))}[/dim]")
|
|
176
|
+
plane = d.get("operator_plane")
|
|
177
|
+
if isinstance(plane, dict):
|
|
178
|
+
# 0.14.1 (p6a C): how the operator plane decides the run.
|
|
179
|
+
console.print(f" operator plane: mode {escape(str(plane.get('mode')))}"
|
|
180
|
+
+ (", the run registers the root" if plane.get("registers_root") else "")
|
|
181
|
+
+ (", an in-band path for the operator key" if plane.get("in_band") else ""))
|
|
182
|
+
if plane.get("break_glass_required"):
|
|
183
|
+
console.print("[warning] The real run needs break-glass: add --break-glass REASON "
|
|
184
|
+
"--break-glass-ticket TICKET to --apply (else 403 BREAK_GLASS_REQUIRED).[/warning]")
|
|
172
185
|
if d.get("dry_run"):
|
|
173
186
|
console.print("[dim]Nothing was changed. Run again with --apply.[/dim]")
|
|
174
187
|
|
cortexdb_cli/commands/changes.py
CHANGED
|
@@ -33,7 +33,15 @@ import click
|
|
|
33
33
|
from cortexdb_cli.client import get_client, path_segment
|
|
34
34
|
from cortexdb_cli.common import api_options, body_of, emit, read_json_file, root_or_die, send
|
|
35
35
|
from cortexdb_cli.errors import handle_errors
|
|
36
|
-
from cortexdb_cli.output import console, escape, is_json_mode
|
|
36
|
+
from cortexdb_cli.output import console, err_console, escape, is_json_mode, print_json
|
|
37
|
+
|
|
38
|
+
#: The exit status of a change-set command whose --wait ran out while the
|
|
39
|
+
#: server still answered 202 (EX_TEMPFAIL): nothing failed, the evaluation
|
|
40
|
+
#: goes on, and the same command sent again collects its answer.
|
|
41
|
+
EXIT_STILL_EVALUATING = 75
|
|
42
|
+
|
|
43
|
+
#: How long a change-set command keeps sending while the server answers 202.
|
|
44
|
+
DEFAULT_WAIT_S = 120.0
|
|
37
45
|
|
|
38
46
|
|
|
39
47
|
@click.group("changes")
|
|
@@ -41,6 +49,63 @@ def changes_group() -> None:
|
|
|
41
49
|
"""Access change sets - stage, preview, activate, discard."""
|
|
42
50
|
|
|
43
51
|
|
|
52
|
+
def _wait_option(fn):
|
|
53
|
+
return click.option(
|
|
54
|
+
"--wait", "wait_s", type=click.FloatRange(min=0), default=DEFAULT_WAIT_S, show_default=True,
|
|
55
|
+
help="Seconds to keep sending the request while the server answers 202 (its evaluation runs "
|
|
56
|
+
"on); past it the command exits 75 and the same command collects the answer later.",
|
|
57
|
+
)(fn)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _evaluating(resp: Any) -> bool:
|
|
61
|
+
"""A 202 that means the evaluation still runs (0.14.1): a preview's
|
|
62
|
+
`{state: "previewing"}`, a staging's or an activation's empty body. A
|
|
63
|
+
dated activation's 202 carries its status, and is its answer."""
|
|
64
|
+
if resp.status_code != 202:
|
|
65
|
+
return False
|
|
66
|
+
data = body_of(resp)
|
|
67
|
+
return not data or (isinstance(data, dict) and data.get("state") == "previewing")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _pause(resp: Any) -> float:
|
|
71
|
+
try:
|
|
72
|
+
seconds = float(resp.headers.get("retry-after") or 2)
|
|
73
|
+
except ValueError:
|
|
74
|
+
seconds = 2.0
|
|
75
|
+
return min(max(seconds, 0.5), 10.0)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def send_until_evaluated(cfg: dict[str, Any], label: str, call, wait_s: float) -> tuple[Any, float | None]:
|
|
79
|
+
"""Send `call` until the server answers anything but an evaluation's
|
|
80
|
+
202. The same request sent again joins the evaluation, or once it ended
|
|
81
|
+
is answered by it. Returns the response and, when --wait ran out first,
|
|
82
|
+
the seconds waited (else None)."""
|
|
83
|
+
start = time.monotonic()
|
|
84
|
+
while True:
|
|
85
|
+
resp = send(cfg, label, call)
|
|
86
|
+
if not _evaluating(resp):
|
|
87
|
+
return resp, None
|
|
88
|
+
waited = time.monotonic() - start
|
|
89
|
+
pause = _pause(resp)
|
|
90
|
+
if waited + pause > wait_s:
|
|
91
|
+
return resp, waited
|
|
92
|
+
if not is_json_mode(cfg):
|
|
93
|
+
err_console.print(f"[dim] still evaluating after {waited:.0f} s (202); asking again in "
|
|
94
|
+
f"{pause:.0f} s[/dim]")
|
|
95
|
+
time.sleep(pause)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def still_evaluating(cfg: dict[str, Any], change_id: str, what: str, waited: float, again: str):
|
|
99
|
+
"""--wait ran out on a 202: say so (never as an error) and exit 75."""
|
|
100
|
+
if is_json_mode(cfg):
|
|
101
|
+
print_json({"id": change_id, "state": "evaluating", "request": what, "waited_s": round(waited),
|
|
102
|
+
"again": again})
|
|
103
|
+
else:
|
|
104
|
+
console.print(f"[warning]The server is still evaluating the {what} of {escape(change_id)} after "
|
|
105
|
+
f"{waited:.0f} s; it goes on. {escape(again)}[/warning]")
|
|
106
|
+
raise SystemExit(EXIT_STILL_EVALUATING)
|
|
107
|
+
|
|
108
|
+
|
|
44
109
|
def _scope_option(fn):
|
|
45
110
|
return click.option(
|
|
46
111
|
"--scope", "-S", default=None,
|
|
@@ -239,11 +304,12 @@ def _params(proposer: str | None, scope: str | None = None) -> dict[str, str] |
|
|
|
239
304
|
@click.option("--convert", is_flag=True, help="A version-1 tree conversion: its preview must change no access.")
|
|
240
305
|
@click.option("--resync", is_flag=True, help="A source's resync change set (served during a restore).")
|
|
241
306
|
@click.option("--resync-last", is_flag=True, help="The last resync change set of the restore.")
|
|
307
|
+
@_wait_option
|
|
242
308
|
@api_options
|
|
243
309
|
@click.pass_context
|
|
244
310
|
@handle_errors
|
|
245
311
|
def changes_stage(ctx, change_id, file, part, deletes, scope, parts_total, activate_at, reason,
|
|
246
|
-
narrowing, convert, resync, resync_last):
|
|
312
|
+
narrowing, convert, resync, resync_last, wait_s):
|
|
247
313
|
"""Stage a change set's first parts under your own id (POST /v1/access/changes).
|
|
248
314
|
|
|
249
315
|
\b
|
|
@@ -251,7 +317,9 @@ def changes_stage(ctx, change_id, file, part, deletes, scope, parts_total, activ
|
|
|
251
317
|
cortexdb changes stage drop-tmp --delete org:acme/team:tmp --narrowing
|
|
252
318
|
|
|
253
319
|
Staging is idempotent by id: the same parts sent again answer the
|
|
254
|
-
change set's status.
|
|
320
|
+
change set's status. A narrowing or a conversion staging whose check
|
|
321
|
+
runs long answers 202 and goes on; the CLI sends it again until it
|
|
322
|
+
answers (--wait).
|
|
255
323
|
"""
|
|
256
324
|
cfg = ctx.obj
|
|
257
325
|
doc = read_json_file(file, "--file") if file else None
|
|
@@ -277,8 +345,12 @@ def changes_stage(ctx, change_id, file, part, deletes, scope, parts_total, activ
|
|
|
277
345
|
if resync or resync_last:
|
|
278
346
|
body["resync"] = {"last": bool(resync_last)}
|
|
279
347
|
with get_client(cfg) as client:
|
|
280
|
-
|
|
281
|
-
|
|
348
|
+
resp, waited = send_until_evaluated(cfg, "Staging...",
|
|
349
|
+
lambda: client.post("/v1/access/changes", json=body), wait_s)
|
|
350
|
+
if waited is not None:
|
|
351
|
+
still_evaluating(cfg, change_id, "staging", waited,
|
|
352
|
+
"Send the same `cortexdb changes stage` again for its status, or `cortexdb changes get` it.")
|
|
353
|
+
emit(cfg, body_of(resp), _render_state)
|
|
282
354
|
|
|
283
355
|
|
|
284
356
|
@changes_group.command("parts")
|
|
@@ -286,24 +358,33 @@ def changes_stage(ctx, change_id, file, part, deletes, scope, parts_total, activ
|
|
|
286
358
|
@_records_options
|
|
287
359
|
@_scope_option
|
|
288
360
|
@_proposer_option
|
|
361
|
+
@_wait_option
|
|
289
362
|
@api_options
|
|
290
363
|
@click.pass_context
|
|
291
364
|
@handle_errors
|
|
292
|
-
def changes_parts(ctx, change_id, file, part, deletes, scope, proposer):
|
|
293
|
-
"""Stage more parts of a change set (POST /v1/access/changes/{id}/parts).
|
|
365
|
+
def changes_parts(ctx, change_id, file, part, deletes, scope, proposer, wait_s):
|
|
366
|
+
"""Stage more parts of a change set (POST /v1/access/changes/{id}/parts).
|
|
367
|
+
|
|
368
|
+
A part whose check runs long answers 202 and goes on; the CLI sends it
|
|
369
|
+
again until it answers (--wait).
|
|
370
|
+
"""
|
|
294
371
|
cfg = ctx.obj
|
|
295
372
|
doc = read_json_file(file, "--file") if file else None
|
|
296
373
|
body = {"scope": root_or_die(cfg, scope), "parts": build_parts(doc, part, deletes, default_part=None)}
|
|
297
374
|
with get_client(cfg) as client:
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
375
|
+
resp, waited = send_until_evaluated(
|
|
376
|
+
cfg, "Staging parts...",
|
|
377
|
+
lambda: client.post(_id_path(change_id, "/parts"), json=body, params=_params(proposer)), wait_s)
|
|
378
|
+
if waited is not None:
|
|
379
|
+
still_evaluating(cfg, change_id, "staging of its parts", waited,
|
|
380
|
+
"Send the same `cortexdb changes parts` again for its status, or `cortexdb changes get` it.")
|
|
381
|
+
emit(cfg, body_of(resp), _render_state)
|
|
302
382
|
|
|
303
383
|
|
|
304
384
|
def preview_change_set(cfg, client, change_id, root, proposer=None, people=False, limit=None,
|
|
305
|
-
cursor=None, wait_s=
|
|
306
|
-
"""POST .../preview,
|
|
385
|
+
cursor=None, wait_s=DEFAULT_WAIT_S):
|
|
386
|
+
"""POST .../preview, sent again while the server answers 202
|
|
387
|
+
`{state: "previewing"}`; exits 75 when --wait runs out first."""
|
|
307
388
|
body: dict[str, Any] = {"scope": root}
|
|
308
389
|
if people:
|
|
309
390
|
body["people"] = True
|
|
@@ -311,17 +392,13 @@ def preview_change_set(cfg, client, change_id, root, proposer=None, people=False
|
|
|
311
392
|
body["limit"] = limit
|
|
312
393
|
if cursor:
|
|
313
394
|
body["cursor"] = cursor
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
pause = float(resp.headers.get("retry-after") or 1)
|
|
322
|
-
except ValueError:
|
|
323
|
-
pause = 1.0
|
|
324
|
-
time.sleep(min(max(pause, 0.2), 5.0))
|
|
395
|
+
resp, waited = send_until_evaluated(
|
|
396
|
+
cfg, "Previewing...",
|
|
397
|
+
lambda: client.post(_id_path(change_id, "/preview"), json=body, params=_params(proposer)), wait_s)
|
|
398
|
+
if waited is not None:
|
|
399
|
+
still_evaluating(cfg, change_id, "preview", waited,
|
|
400
|
+
"Run the same `cortexdb changes preview` again to collect it.")
|
|
401
|
+
return body_of(resp)
|
|
325
402
|
|
|
326
403
|
|
|
327
404
|
@changes_group.command("preview")
|
|
@@ -331,8 +408,7 @@ def preview_change_set(cfg, client, change_id, root, proposer=None, people=False
|
|
|
331
408
|
@click.option("--people", is_flag=True, help="List each person who gains or loses access, per unit.")
|
|
332
409
|
@click.option("--limit", type=click.IntRange(min=1), default=None, help="Units per page.")
|
|
333
410
|
@click.option("--cursor", default=None, help="The next_cursor of a previous page.")
|
|
334
|
-
@
|
|
335
|
-
help="Seconds to keep asking while the preview is being computed (202).")
|
|
411
|
+
@_wait_option
|
|
336
412
|
@api_options
|
|
337
413
|
@click.pass_context
|
|
338
414
|
@handle_errors
|
|
@@ -340,7 +416,9 @@ def changes_preview(ctx, change_id, scope, proposer, people, limit, cursor, wait
|
|
|
340
416
|
"""A change set's access diff and its sha256 structural hash (POST .../{id}/preview).
|
|
341
417
|
|
|
342
418
|
A page holds at most 1 MiB: a unit that does not fit continues on the
|
|
343
|
-
next page (--cursor), and its counts on this page are marked +.
|
|
419
|
+
next page (--cursor), and its counts on this page are marked +. While
|
|
420
|
+
the evaluation runs past the server's wait it answers 202
|
|
421
|
+
{state: previewing}; the CLI asks again until it answers (--wait).
|
|
344
422
|
"""
|
|
345
423
|
cfg = ctx.obj
|
|
346
424
|
with get_client(cfg) as client:
|
|
@@ -356,16 +434,20 @@ def changes_preview(ctx, change_id, scope, proposer, people, limit, cursor, wait
|
|
|
356
434
|
@click.option("--preview-hash", metavar="HASH",
|
|
357
435
|
help="The approved preview's hash (sha256:...). Without it the CLI previews first.")
|
|
358
436
|
@click.option("--yes", "-y", is_flag=True, help="Skip the confirmation after the preview.")
|
|
437
|
+
@_wait_option
|
|
359
438
|
@api_options
|
|
360
439
|
@click.pass_context
|
|
361
440
|
@handle_errors
|
|
362
|
-
def changes_activate(ctx, change_id, scope, proposer, preview_hash, yes):
|
|
441
|
+
def changes_activate(ctx, change_id, scope, proposer, preview_hash, yes, wait_s):
|
|
363
442
|
"""Approve and activate a change set (POST /v1/access/changes/{id}/activate).
|
|
364
443
|
|
|
365
444
|
Without --preview-hash the CLI previews it, shows the diff, asks (on a
|
|
366
445
|
terminal, unless --yes), and activates with that preview's hash. A dated
|
|
367
|
-
change set (--activate-at) answers 202: the approval is
|
|
368
|
-
date.
|
|
446
|
+
change set (--activate-at) answers 202 with its status: the approval is
|
|
447
|
+
recorded for its date. An activation whose checks run long answers 202
|
|
448
|
+
with no body and goes on in the background; the CLI sends it again until
|
|
449
|
+
it answers its status (--wait), and each wait (the preview's, then the
|
|
450
|
+
activation's) has the whole of --wait.
|
|
369
451
|
|
|
370
452
|
With the operator key, a change set whose preview says in_band (it
|
|
371
453
|
registers a scope, adds a service: principal, or adds or widens a
|
|
@@ -378,7 +460,7 @@ def changes_activate(ctx, change_id, scope, proposer, preview_hash, yes):
|
|
|
378
460
|
root = root_or_die(cfg, scope)
|
|
379
461
|
with get_client(cfg) as client:
|
|
380
462
|
if not preview_hash:
|
|
381
|
-
preview = preview_change_set(cfg, client, change_id, root, proposer)
|
|
463
|
+
preview = preview_change_set(cfg, client, change_id, root, proposer, wait_s=wait_s)
|
|
382
464
|
preview_hash = preview.get("preview_hash")
|
|
383
465
|
if not preview_hash:
|
|
384
466
|
raise click.UsageError("the preview returned no preview_hash; pass --preview-hash")
|
|
@@ -390,10 +472,14 @@ def changes_activate(ctx, change_id, scope, proposer, preview_hash, yes):
|
|
|
390
472
|
if not yes:
|
|
391
473
|
click.confirm(f"Activate change set {change_id}?", abort=True)
|
|
392
474
|
body = {"scope": root, "preview_hash": preview_hash}
|
|
393
|
-
resp =
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
475
|
+
resp, waited = send_until_evaluated(
|
|
476
|
+
cfg, "Activating...",
|
|
477
|
+
lambda: client.post(_id_path(change_id, "/activate"), json=body, params=_params(proposer)), wait_s)
|
|
478
|
+
if waited is not None:
|
|
479
|
+
still_evaluating(cfg, change_id, "activation", waited,
|
|
480
|
+
"Its activation goes on in the background: `cortexdb changes get` shows its state, and "
|
|
481
|
+
"the same `cortexdb changes activate --preview-hash` again answers its status.")
|
|
482
|
+
emit(cfg, body_of(resp), _render_state)
|
|
397
483
|
|
|
398
484
|
|
|
399
485
|
@changes_group.command("get")
|
cortexdb_cli/commands/tokens.py
CHANGED
|
@@ -21,8 +21,10 @@ no `--scope`) or its `--confine` / `--exact` entries, all in that one root
|
|
|
21
21
|
the trusted operator's alone, for a `service:` or `system:` subject (else
|
|
22
22
|
403 `deployment_mint_requires_operator`). A minted token holds no more than
|
|
23
23
|
its minter: its caps and entries lie within the minting token's own.
|
|
24
|
-
Lifetimes are capped by the subject's ceiling
|
|
25
|
-
|
|
24
|
+
Lifetimes are capped by the subject's ceiling, the server's settings since
|
|
25
|
+
0.14.1 (`CORTEX_MINT_MAX_LIFETIME_*`; by default 90 days for a person, 7 for
|
|
26
|
+
an agent, 30 for a service, 24 hours with a chain claim): above it the mint
|
|
27
|
+
is 422 `ttl_too_long`, naming the ceiling (`details.ceiling_s`).
|
|
26
28
|
"""
|
|
27
29
|
|
|
28
30
|
from __future__ import annotations
|
cortexdb_cli/errors.py
CHANGED
|
@@ -171,9 +171,13 @@ def _reason_hints(err: ApiError) -> str | None:
|
|
|
171
171
|
if reason == "invalid":
|
|
172
172
|
return f"--cap {entry} is no capability name; see `cortexdb policy effective` for the names."
|
|
173
173
|
table = {
|
|
174
|
+
# The ceilings are the server's settings since 0.14.1
|
|
175
|
+
# (CORTEX_MINT_MAX_LIFETIME_*); details.ceiling_s is the one applied.
|
|
174
176
|
"ttl_too_long": lambda: (
|
|
175
|
-
f"Mint a shorter token: --ttl at most {_d(err, 'ceiling_s')} s "
|
|
176
|
-
|
|
177
|
+
(f"Mint a shorter token: --ttl at most {_d(err, 'ceiling_s')} s, this subject's ceiling"
|
|
178
|
+
if _d(err, "ceiling_s") else "Mint a shorter token: --ttl within this subject's ceiling")
|
|
179
|
+
+ " (by default 90 days for a person, 7 for an agent, 30 for a service, 24 h with chain claims; "
|
|
180
|
+
"the server's CORTEX_MINT_MAX_LIFETIME_* settings)."
|
|
177
181
|
),
|
|
178
182
|
"ttl_out_of_range": lambda: "--ttl is past what a timestamp holds; pick a sane lifetime.",
|
|
179
183
|
"lifetime_over_ceiling": lambda: (
|
|
@@ -475,6 +479,19 @@ def hint_for(err: ApiError) -> str | None: # noqa: C901 - one table
|
|
|
475
479
|
"app_unknown": "The token's application has no record (`cortexdb apps put`).",
|
|
476
480
|
"not_combinable": "--mounts does not combine with subtree, cohort or recency order.",
|
|
477
481
|
}.get(reason, None)
|
|
482
|
+
if code in ("INVALID_ACCESS_RECORD", "INVALID_SCOPE_TREE") and reason == "version_downgrade":
|
|
483
|
+
# 0.14.1 (p6a E): a put that leaves out every version-2 field of a
|
|
484
|
+
# stored version-2 record would make it version 1; only `convert`
|
|
485
|
+
# says that is meant, and a legacy route has none.
|
|
486
|
+
path = _d(err, "path") or "the record"
|
|
487
|
+
dropped = _list(_d(err, "dropped") or [], limit=8) or "its version-2 fields"
|
|
488
|
+
how = (
|
|
489
|
+
"or, if the conversion is meant, stage the change set with --convert (it may change no access)"
|
|
490
|
+
if code == "INVALID_ACCESS_RECORD"
|
|
491
|
+
else "or make the change with a change set staged with --convert (a legacy route has no convert)"
|
|
492
|
+
)
|
|
493
|
+
return (f"{path} is a version-2 record and this write leaves out {dropped}, which would make it "
|
|
494
|
+
f"version 1: state them in the record, {how}.")
|
|
478
495
|
if code == "INVALID_ACCESS_RECORD":
|
|
479
496
|
path = _d(err, "path")
|
|
480
497
|
return f"A record is out of shape{f' at {path}' if path else ''} ({reason or 'see the message'})."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cortexdb-cli
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: Command-line interface for CortexDB — the long-term memory layer for AI.
|
|
5
5
|
Project-URL: Homepage, https://cortexdb.ai
|
|
6
6
|
Project-URL: Documentation, https://cortexdb.ai/docs
|
|
@@ -36,8 +36,8 @@ Command-line interface for [CortexDB](https://cortexdb.ai) — the long-term mem
|
|
|
36
36
|
|
|
37
37
|
Wraps the v1 HTTP API in a small, fast Click + Rich CLI. Anonymous signup
|
|
38
38
|
in one command, no email or card; works against the public SaaS or any
|
|
39
|
-
self-hosted CortexDB deployment. Version 0.7.
|
|
40
|
-
shared memory included: the access API, change sets, the directory,
|
|
39
|
+
self-hosted CortexDB deployment. Version 0.7.1 covers CortexDB 0.14.1 and
|
|
40
|
+
0.14.0, shared memory included: the access API, change sets, the directory,
|
|
41
41
|
applications, rollups, publishing and the new erasures.
|
|
42
42
|
|
|
43
43
|
## Install
|
|
@@ -81,6 +81,20 @@ When a token expires you have two safe options:
|
|
|
81
81
|
For a second brain alongside the first, isolate instead of replacing:
|
|
82
82
|
`cortexdb --config-dir <dir> init`, or set `CORTEXDB_HOME`.
|
|
83
83
|
|
|
84
|
+
## What's new for CortexDB 0.14.1 (cortexdb-cli 0.7.1)
|
|
85
|
+
|
|
86
|
+
- **Change sets that take long.** A staging, a preview or an activation whose
|
|
87
|
+
evaluation runs past the server's wait answers 202 and goes on. `changes
|
|
88
|
+
stage`, `parts`, `preview` and `activate` send the request again until it
|
|
89
|
+
answers, with a progress line, for `--wait` seconds (120 by default); past
|
|
90
|
+
it they exit 75 and say how to collect the answer. A 202 is never an error.
|
|
91
|
+
- **The tenant-binding dry run** shows how the operator plane will decide the
|
|
92
|
+
real run, and says when `--apply` needs `--break-glass`.
|
|
93
|
+
- **A write that would make a version-2 record version 1** is refused; the
|
|
94
|
+
hint names the fields it drops and `--convert`.
|
|
95
|
+
- **Token lifetimes** are the server's settings: by default 90 days for a
|
|
96
|
+
person, 7 for an agent, 30 for a service, 24 hours with a chain claim.
|
|
97
|
+
|
|
84
98
|
## What's new for CortexDB 0.14.0 (cortexdb-cli 0.7.0)
|
|
85
99
|
|
|
86
100
|
CortexDB 0.14.0 is the breaking release of shared memory. What changes for a
|
|
@@ -112,9 +126,9 @@ CLI user:
|
|
|
112
126
|
compartment gets the server's default (granular there) instead of 422
|
|
113
127
|
`VIEW_NOT_ALLOWED_AT_SCOPE`.
|
|
114
128
|
- **Tokens.** A token that carries `scopes` holds only the families its
|
|
115
|
-
entries name, lifetimes are capped (
|
|
116
|
-
a
|
|
117
|
-
agent. Every mint names its tenant root (`--scope`, `--tenant` or its
|
|
129
|
+
entries name, lifetimes are capped (the server's settings since 0.14.1: by
|
|
130
|
+
default 90 days for a person, 7 for an agent, 30 for a service, 24 hours
|
|
131
|
+
with chain claims), and `act` must name a delegable agent. Every mint names its tenant root (`--scope`, `--tenant` or its
|
|
118
132
|
`--confine` entries); only the operator mints deployment-wide, for a
|
|
119
133
|
service. A minted token holds no more than its minter. `cortexdb tokens
|
|
120
134
|
mint` mints with every field: `--confine`, `--exact` (the `CAP:PATH!`
|
|
@@ -241,6 +255,9 @@ cortexdb changes discard org-compile
|
|
|
241
255
|
`--file` holds a list of records (each a put), operations
|
|
242
256
|
(`{"path", "op": "put" | "delete", "record"}`), `{"records": [...]}` or
|
|
243
257
|
`{"parts": [...]}`; `--delete PATH` adds deletes; `changes parts` stages more.
|
|
258
|
+
A staging, a preview or an activation whose evaluation runs long answers 202
|
|
259
|
+
(0.14.1): the command sends it again until it answers, for `--wait` seconds
|
|
260
|
+
(120 by default), then exits 75 saying how to collect the answer.
|
|
244
261
|
|
|
245
262
|
### watch and notices
|
|
246
263
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
cortexdb_cli/__init__.py,sha256=
|
|
1
|
+
cortexdb_cli/__init__.py,sha256=VkuIG9ak4LficJ5PaL_-FwK1yH9wnAlmdwaYYIAbhw4,90
|
|
2
2
|
cortexdb_cli/client.py,sha256=qxETsZzcSxx1NS7sG3M1a48i46ykZRZdjcbBf2wjGWA,6894
|
|
3
3
|
cortexdb_cli/common.py,sha256=1iCsiLYPDXi4ZbIGo_Nbg5xteL4_KbHC0Z--211uxac,11377
|
|
4
4
|
cortexdb_cli/config.py,sha256=ee1qmOfqMwilL81ujaqjf6TjjlrFG7WZAHRIgeyif9U,5690
|
|
5
|
-
cortexdb_cli/errors.py,sha256=
|
|
5
|
+
cortexdb_cli/errors.py,sha256=63i9dB3FvkWtb6z75nOB80ApcjeGfIQwMKA51bDIQgM,34250
|
|
6
6
|
cortexdb_cli/harness_packs_data.py,sha256=38oyPX47a_S3BRgiNxml37auhIUyWafeJ_MtApX9tWE,10693
|
|
7
7
|
cortexdb_cli/main.py,sha256=-ohG6a90vlVfTX8G9VdfitjWoHbK1WgETHKiLCEa_qw,12567
|
|
8
8
|
cortexdb_cli/onboarding.py,sha256=kjCxhMOY2nReNyEfGGGsmHO6_j4CXS5o2LIwzpFzIok,17527
|
|
@@ -11,13 +11,13 @@ cortexdb_cli/state.py,sha256=pfslyJ9xuZno4n13-maJ0qKmD7nxWkFznjrVvItYK4I,1527
|
|
|
11
11
|
cortexdb_cli/commands/__init__.py,sha256=Uqz-6IAeIxrSS94FHI6Q0iqDf_2MQeHKY0LaHgEC4HU,36
|
|
12
12
|
cortexdb_cli/commands/access.py,sha256=-Ex3JM5cpz3k5GLxnTstRlKWGsUZB9HRHqMZviiUjMY,36296
|
|
13
13
|
cortexdb_cli/commands/admin.py,sha256=Cf_Ay-duZehY2tFxHlJ4qRlAeIpQkhf0lNTZx7WcJjc,24104
|
|
14
|
-
cortexdb_cli/commands/admin_access.py,sha256=
|
|
14
|
+
cortexdb_cli/commands/admin_access.py,sha256=1cEZszPy9QFOsJLZq0f-BROMi4maPJGNDzbHKz7PiTw,12702
|
|
15
15
|
cortexdb_cli/commands/answer.py,sha256=0qWWCTEdnDG4Od4nzAGKi9DBE7rmxuVHQLv9uzW2p5I,3674
|
|
16
16
|
cortexdb_cli/commands/apps.py,sha256=_aqeDlb-cTF3exVewm-x2QJOzTDke_Mw-idvqBCXJTc,6299
|
|
17
17
|
cortexdb_cli/commands/audit.py,sha256=_zfAQZQm7hjFr-Ot3CtzCryE6VqO7pChHbGFREQ5BC4,2690
|
|
18
18
|
cortexdb_cli/commands/auth.py,sha256=5iPfUNOMnVGe-ST9FRFi65Z4Qoys35xQeGlvoYBxPCo,4193
|
|
19
19
|
cortexdb_cli/commands/beliefs.py,sha256=CRioAHyQl68xnx5TjiyKGTrrMiax_BhNYcJGq7Gye1A,8519
|
|
20
|
-
cortexdb_cli/commands/changes.py,sha256=
|
|
20
|
+
cortexdb_cli/commands/changes.py,sha256=eBZAq6BzD9lTB8avgVLDGdutppRkWdTcFBErt7mu1Rc,23742
|
|
21
21
|
cortexdb_cli/commands/claims.py,sha256=4RWhWLe1uGLTRy7Ffe3rTwGTzudLwGmInu-OCGcEYO4,3777
|
|
22
22
|
cortexdb_cli/commands/code.py,sha256=gR3hdB1eg5qA1apbwXkXAAyaPJo2Uy0E6AlrufTpClI,10906
|
|
23
23
|
cortexdb_cli/commands/compose.py,sha256=TJwDuxmVuwn0y3X4YN1wXq6xKnGzVWSRKBmMGdL_nCU,4192
|
|
@@ -41,11 +41,11 @@ cortexdb_cli/commands/recall.py,sha256=B-8s4Y9OybU0R445mh-mcBYYdkYofiBJakdp3kDU6
|
|
|
41
41
|
cortexdb_cli/commands/rollups.py,sha256=wveVXfZHTFzvCyOYvM0REL2sjUsTQDVUinwgAJR-uPc,6419
|
|
42
42
|
cortexdb_cli/commands/scopes.py,sha256=EssL4g0hNQfS6GpU8ZZeHDWtYeoC6wUW2naSknisdIE,5286
|
|
43
43
|
cortexdb_cli/commands/search.py,sha256=ntKzgEuAEJtDsw_4tS3cP6y_ycRP_RzMoyuMXRvXOao,2709
|
|
44
|
-
cortexdb_cli/commands/tokens.py,sha256=
|
|
44
|
+
cortexdb_cli/commands/tokens.py,sha256=wvbKRnsS3ACUnpdgm16G2BJ31uPI5Fxbu23Zuc_4LJY,8305
|
|
45
45
|
cortexdb_cli/commands/understanding.py,sha256=5sDus9F5xcZhtuqUAeTQIc6z6hfBTbIYyQG-c4nx5rA,6003
|
|
46
46
|
cortexdb_cli/commands/watch.py,sha256=o4o1NmYKgoDu2b-KXToziQ9tXzbShs4PU2kwUFYFwBs,10749
|
|
47
47
|
cortexdb_cli/commands/wire.py,sha256=M3UUHScmvr_MDrX_RaMBg-YLTcHKUq9woNkT4KHJKfs,8131
|
|
48
|
-
cortexdb_cli-0.7.
|
|
49
|
-
cortexdb_cli-0.7.
|
|
50
|
-
cortexdb_cli-0.7.
|
|
51
|
-
cortexdb_cli-0.7.
|
|
48
|
+
cortexdb_cli-0.7.1.dist-info/METADATA,sha256=3FE4vYfjXAD49ub_lK3rg8tLwnqTdT4tuN3eKvbZR7U,18269
|
|
49
|
+
cortexdb_cli-0.7.1.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
|
|
50
|
+
cortexdb_cli-0.7.1.dist-info/entry_points.txt,sha256=h3sEbdqqvtv8LBbRLUgybYPo9N2lpU85fQUSh5ToEvs,51
|
|
51
|
+
cortexdb_cli-0.7.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|