lql-cli 0.3.0__tar.gz → 0.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.
Files changed (35) hide show
  1. lql_cli-0.3.0/README.md → lql_cli-0.5.0/PKG-INFO +50 -7
  2. lql_cli-0.3.0/PKG-INFO → lql_cli-0.5.0/README.md +34 -22
  3. {lql_cli-0.3.0 → lql_cli-0.5.0}/pyproject.toml +3 -2
  4. lql_cli-0.5.0/src/lql/__init__.py +1 -0
  5. lql_cli-0.5.0/src/lql/_group.py +50 -0
  6. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/cli.py +3 -0
  7. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/annotations.py +3 -1
  8. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/auth.py +3 -1
  9. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/buckets.py +3 -1
  10. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/datasets.py +16 -1
  11. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/edits.py +3 -1
  12. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/evals.py +3 -1
  13. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/highlights.py +3 -1
  14. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/instructions.py +24 -3
  15. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/issues.py +3 -1
  16. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/preview.py +254 -37
  17. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/reports.py +3 -1
  18. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/skills.py +3 -1
  19. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/spec.py +3 -1
  20. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/tui.py +207 -13
  21. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/workspaces.py +23 -4
  22. {lql_cli-0.3.0 → lql_cli-0.5.0}/uv.lock +109 -280
  23. lql_cli-0.3.0/src/lql/__init__.py +0 -1
  24. {lql_cli-0.3.0 → lql_cli-0.5.0}/.claude/settings.local.json +0 -0
  25. {lql_cli-0.3.0 → lql_cli-0.5.0}/.gitignore +0 -0
  26. {lql_cli-0.3.0 → lql_cli-0.5.0}/examples/agent-traces.jsonl +0 -0
  27. {lql_cli-0.3.0 → lql_cli-0.5.0}/package-lock.json +0 -0
  28. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/_opts.py +0 -0
  29. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/api.py +0 -0
  30. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/__init__.py +0 -0
  31. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/commands/update.py +0 -0
  32. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/config.py +0 -0
  33. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/output.py +0 -0
  34. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/sessions.py +0 -0
  35. {lql_cli-0.3.0 → lql_cli-0.5.0}/src/lql/util.py +0 -0
@@ -1,8 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: lql-cli
3
+ Version: 0.5.0
4
+ Summary: lql — CLI for the Liquid DataViewer platform
5
+ Project-URL: Homepage, https://github.com/Liquid4All/lql
6
+ Author: Liquid AI
7
+ License: MIT
8
+ Requires-Python: >=3.12
9
+ Requires-Dist: httpx>=0.27
10
+ Requires-Dist: huggingface-hub>=0.24
11
+ Requires-Dist: rich>=13.0
12
+ Requires-Dist: textual-image>=0.7
13
+ Requires-Dist: textual>=0.50
14
+ Requires-Dist: typer>=0.12
15
+ Description-Content-Type: text/markdown
16
+
1
17
  # lql — Liquid Query Language CLI
2
18
 
3
19
  Scriptable CLI for the [Liquid DataViewer](https://dataviewer.liquid.ai) platform. Designed for both humans and AI agents (Claude Code, Codex, etc.) to automate datasets, eval analysis, spec docs, annotations, and more.
4
20
 
5
- A Python package (Python ≥ 3.9), published on PyPI as **[`lql-cli`](https://pypi.org/project/lql-cli/)** — the installed command is `lql`.
21
+ A Python package (Python ≥ 3.12), published on PyPI as **[`lql-cli`](https://pypi.org/project/lql-cli/)** — the installed command is `lql`.
6
22
 
7
23
  ## Quick start
8
24
 
@@ -14,7 +30,7 @@ lql skills install # teach Claude Code + Codex how to use lql
14
30
 
15
31
  ## Install
16
32
 
17
- `lql` is a Python package (requires Python ≥ 3.9), distributed on PyPI as **`lql-cli`** (the
33
+ `lql` is a Python package (requires Python ≥ 3.12), distributed on PyPI as **`lql-cli`** (the
18
34
  command it installs is `lql`). Install it as a standalone CLI tool with
19
35
  [uv](https://docs.astral.sh/uv/):
20
36
 
@@ -84,6 +100,13 @@ lql logout
84
100
 
85
101
  ## Command reference
86
102
 
103
+ Running a group with no subcommand (e.g. `lql datasets`) lists its subcommands.
104
+ For faster typing, **aliases** and **unique prefixes** resolve everywhere:
105
+ group aliases (`ds`, `ws`, `ev`, `ann`, `hl`, `rep`, `bkt`, `iss`), verb aliases
106
+ (`ls`=list, `rm`/`del`=delete, `new`/`mk`=create, `info`=show), and prefixes
107
+ (`lql datasets l` → `list`). So `lql ds ls --workspace <id>` ≡ `lql datasets list
108
+ --workspace <id>`. The canonical names below always work (use those in scripts).
109
+
87
110
  ### Auth
88
111
 
89
112
  ```
@@ -95,7 +118,7 @@ lql whoami Show current user
95
118
  ### Workspaces
96
119
 
97
120
  ```
98
- lql workspaces list List all workspaces
121
+ lql workspaces list [--search <text>] List workspaces (--search filters by name/slug)
99
122
  lql workspaces create <name> Create a workspace
100
123
  lql workspaces show <id> Show workspace details
101
124
  lql workspaces update <id> --name <n> Rename a workspace
@@ -108,7 +131,7 @@ lql workspaces members remove <id> <uid> Remove member by user ID
108
131
  ### Datasets
109
132
 
110
133
  ```
111
- lql datasets list [--workspace <id>] List datasets
134
+ lql datasets list [--workspace <id>] [--search <text>] List datasets (--search filters by name/HF repo)
112
135
  lql datasets show <id> Show dataset details
113
136
  lql datasets create --workspace <id> --hf-repo <repo> [--name <n>] [--split <s>]
114
137
  lql datasets create --workspace <id> --hf-bucket <org/bucket> --key <path-or-glob> [--name <n>]
@@ -134,23 +157,43 @@ multimodal content (text/image/audio), ShareGPT `{from, value}`, native OpenAI
134
157
  `tool_calls`, plus `<think>` reasoning blocks, `<|tool_call_start|>…<|tool_call_end|>`
135
158
  / Python / XML / JSON tool calls, tool results, tool-definition tables, and code.
136
159
 
137
- Works on a local `.jsonl`/`.json` file or a platform dataset ID. No browser, and
138
- nothing to forward over SSH — it's just the terminal.
160
+ Works on a local `.jsonl`/`.json` file, a platform dataset ID, or with `--hf`
161
+ — a HuggingFace repo. No browser, and nothing to forward over SSH — it's just
162
+ the terminal.
139
163
 
140
164
  ```
141
165
  lql preview <file.jsonl|file.json> Local file: each line/object is a row
142
166
  lql preview <dataset-id> Platform dataset (fetched & paged lazily)
167
+ lql preview <org/name> --hf HuggingFace repo: sync to DataViewer, then view
143
168
  lql preview <src> -c <field> Force field(s) as conversations (repeatable)
144
169
  lql preview <src> -n <N> Page size when paging a platform dataset
145
170
  lql preview <src> --offset N Start at row index N
146
171
  lql preview <src> --title "<title>" Title shown in the viewer header
147
172
  ```
148
173
 
174
+ **HuggingFace datasets (`--hf`).** `lql preview org/name --hf` syncs the repo
175
+ into a DataViewer workspace, then opens it. You pick the target workspace from
176
+ an interactive list (or pass `--workspace <id>`; `--split` defaults to `train`).
177
+ Already-synced repos are reused — no duplicate, instant re-open.
178
+
179
+ ```
180
+ lql preview tatsu-lab/alpaca --hf
181
+ lql preview org/name --hf --split validation --workspace <id>
182
+ ```
183
+
184
+ **Media.** Images render **inline** in terminals that support an image protocol
185
+ (Kitty/Ghostty, iTerm2, Sixel; falls back to a compact `🖼 …` placeholder
186
+ elsewhere) — both multimodal `image_url`/data-URI segments and image-mode
187
+ columns. Audio can't play inline in a terminal, so each clip shows a `♪` line
188
+ and **`p` plays** the current sample's audio via the system player (`afplay`/
189
+ `open`). Images render inline in pager mode (one sample at a time); scroll mode
190
+ shows placeholders to avoid decoding the whole buffer.
191
+
149
192
  **Navigation** — two modes, toggle with `m` / `Tab`:
150
193
 
151
194
  - **pager** (default): one sample at a time · `←/→` or `n`/`b` switch samples · `↑/↓`/`j`/`k`/PgUp-Dn scroll
152
195
  - **scroll**: all samples in one buffer · `n`/`b` jump between samples · arrows scroll
153
- - `q` quits
196
+ - `p` play audio · `q` quits
154
197
 
155
198
  ```
156
199
  lql preview examples/agent-traces.jsonl # 20-sample file of agent-trace/tool-use formats
@@ -1,23 +1,8 @@
1
- Metadata-Version: 2.4
2
- Name: lql-cli
3
- Version: 0.3.0
4
- Summary: lql — CLI for the Liquid DataViewer platform
5
- Project-URL: Homepage, https://github.com/Liquid4All/lql
6
- Author: Liquid AI
7
- License: MIT
8
- Requires-Python: >=3.9
9
- Requires-Dist: httpx>=0.27
10
- Requires-Dist: huggingface-hub>=0.24
11
- Requires-Dist: rich>=13.0
12
- Requires-Dist: textual>=0.50
13
- Requires-Dist: typer>=0.12
14
- Description-Content-Type: text/markdown
15
-
16
1
  # lql — Liquid Query Language CLI
17
2
 
18
3
  Scriptable CLI for the [Liquid DataViewer](https://dataviewer.liquid.ai) platform. Designed for both humans and AI agents (Claude Code, Codex, etc.) to automate datasets, eval analysis, spec docs, annotations, and more.
19
4
 
20
- A Python package (Python ≥ 3.9), published on PyPI as **[`lql-cli`](https://pypi.org/project/lql-cli/)** — the installed command is `lql`.
5
+ A Python package (Python ≥ 3.12), published on PyPI as **[`lql-cli`](https://pypi.org/project/lql-cli/)** — the installed command is `lql`.
21
6
 
22
7
  ## Quick start
23
8
 
@@ -29,7 +14,7 @@ lql skills install # teach Claude Code + Codex how to use lql
29
14
 
30
15
  ## Install
31
16
 
32
- `lql` is a Python package (requires Python ≥ 3.9), distributed on PyPI as **`lql-cli`** (the
17
+ `lql` is a Python package (requires Python ≥ 3.12), distributed on PyPI as **`lql-cli`** (the
33
18
  command it installs is `lql`). Install it as a standalone CLI tool with
34
19
  [uv](https://docs.astral.sh/uv/):
35
20
 
@@ -99,6 +84,13 @@ lql logout
99
84
 
100
85
  ## Command reference
101
86
 
87
+ Running a group with no subcommand (e.g. `lql datasets`) lists its subcommands.
88
+ For faster typing, **aliases** and **unique prefixes** resolve everywhere:
89
+ group aliases (`ds`, `ws`, `ev`, `ann`, `hl`, `rep`, `bkt`, `iss`), verb aliases
90
+ (`ls`=list, `rm`/`del`=delete, `new`/`mk`=create, `info`=show), and prefixes
91
+ (`lql datasets l` → `list`). So `lql ds ls --workspace <id>` ≡ `lql datasets list
92
+ --workspace <id>`. The canonical names below always work (use those in scripts).
93
+
102
94
  ### Auth
103
95
 
104
96
  ```
@@ -110,7 +102,7 @@ lql whoami Show current user
110
102
  ### Workspaces
111
103
 
112
104
  ```
113
- lql workspaces list List all workspaces
105
+ lql workspaces list [--search <text>] List workspaces (--search filters by name/slug)
114
106
  lql workspaces create <name> Create a workspace
115
107
  lql workspaces show <id> Show workspace details
116
108
  lql workspaces update <id> --name <n> Rename a workspace
@@ -123,7 +115,7 @@ lql workspaces members remove <id> <uid> Remove member by user ID
123
115
  ### Datasets
124
116
 
125
117
  ```
126
- lql datasets list [--workspace <id>] List datasets
118
+ lql datasets list [--workspace <id>] [--search <text>] List datasets (--search filters by name/HF repo)
127
119
  lql datasets show <id> Show dataset details
128
120
  lql datasets create --workspace <id> --hf-repo <repo> [--name <n>] [--split <s>]
129
121
  lql datasets create --workspace <id> --hf-bucket <org/bucket> --key <path-or-glob> [--name <n>]
@@ -149,23 +141,43 @@ multimodal content (text/image/audio), ShareGPT `{from, value}`, native OpenAI
149
141
  `tool_calls`, plus `<think>` reasoning blocks, `<|tool_call_start|>…<|tool_call_end|>`
150
142
  / Python / XML / JSON tool calls, tool results, tool-definition tables, and code.
151
143
 
152
- Works on a local `.jsonl`/`.json` file or a platform dataset ID. No browser, and
153
- nothing to forward over SSH — it's just the terminal.
144
+ Works on a local `.jsonl`/`.json` file, a platform dataset ID, or with `--hf`
145
+ — a HuggingFace repo. No browser, and nothing to forward over SSH — it's just
146
+ the terminal.
154
147
 
155
148
  ```
156
149
  lql preview <file.jsonl|file.json> Local file: each line/object is a row
157
150
  lql preview <dataset-id> Platform dataset (fetched & paged lazily)
151
+ lql preview <org/name> --hf HuggingFace repo: sync to DataViewer, then view
158
152
  lql preview <src> -c <field> Force field(s) as conversations (repeatable)
159
153
  lql preview <src> -n <N> Page size when paging a platform dataset
160
154
  lql preview <src> --offset N Start at row index N
161
155
  lql preview <src> --title "<title>" Title shown in the viewer header
162
156
  ```
163
157
 
158
+ **HuggingFace datasets (`--hf`).** `lql preview org/name --hf` syncs the repo
159
+ into a DataViewer workspace, then opens it. You pick the target workspace from
160
+ an interactive list (or pass `--workspace <id>`; `--split` defaults to `train`).
161
+ Already-synced repos are reused — no duplicate, instant re-open.
162
+
163
+ ```
164
+ lql preview tatsu-lab/alpaca --hf
165
+ lql preview org/name --hf --split validation --workspace <id>
166
+ ```
167
+
168
+ **Media.** Images render **inline** in terminals that support an image protocol
169
+ (Kitty/Ghostty, iTerm2, Sixel; falls back to a compact `🖼 …` placeholder
170
+ elsewhere) — both multimodal `image_url`/data-URI segments and image-mode
171
+ columns. Audio can't play inline in a terminal, so each clip shows a `♪` line
172
+ and **`p` plays** the current sample's audio via the system player (`afplay`/
173
+ `open`). Images render inline in pager mode (one sample at a time); scroll mode
174
+ shows placeholders to avoid decoding the whole buffer.
175
+
164
176
  **Navigation** — two modes, toggle with `m` / `Tab`:
165
177
 
166
178
  - **pager** (default): one sample at a time · `←/→` or `n`/`b` switch samples · `↑/↓`/`j`/`k`/PgUp-Dn scroll
167
179
  - **scroll**: all samples in one buffer · `n`/`b` jump between samples · arrows scroll
168
- - `q` quits
180
+ - `p` play audio · `q` quits
169
181
 
170
182
  ```
171
183
  lql preview examples/agent-traces.jsonl # 20-sample file of agent-trace/tool-use formats
@@ -4,10 +4,10 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "lql-cli"
7
- version = "0.3.0"
7
+ version = "0.5.0"
8
8
  description = "lql — CLI for the Liquid DataViewer platform"
9
9
  readme = "README.md"
10
- requires-python = ">=3.9"
10
+ requires-python = ">=3.12"
11
11
  license = { text = "MIT" }
12
12
  authors = [{ name = "Liquid AI" }]
13
13
  dependencies = [
@@ -16,6 +16,7 @@ dependencies = [
16
16
  "rich>=13.0",
17
17
  "huggingface-hub>=0.24",
18
18
  "textual>=0.50",
19
+ "textual-image>=0.7",
19
20
  ]
20
21
 
21
22
  [project.scripts]
@@ -0,0 +1 @@
1
+ __version__ = "0.5.0"
@@ -0,0 +1,50 @@
1
+ """A Typer/Click group that adds two conveniences to every command group:
2
+
3
+ * short aliases — `ds`→`datasets`, `ws`→`workspaces`, `ls`→`list`, …
4
+ * unique-prefix matching — `lql datasets l` resolves to `list`
5
+
6
+ Both are purely additive: the canonical command names always work, and
7
+ `lql instructions` documents the canonical forms, so agents are unaffected —
8
+ these are conveniences for humans typing at a prompt.
9
+ """
10
+
11
+ from typer.core import TyperGroup
12
+
13
+ # alias -> canonical. Kept intentionally small and unambiguous.
14
+ ALIASES = {
15
+ # command groups
16
+ "ds": "datasets",
17
+ "ws": "workspaces",
18
+ "ev": "eval",
19
+ "evals": "eval",
20
+ "ann": "annotations",
21
+ "hl": "highlights",
22
+ "rep": "reports",
23
+ "bkt": "buckets",
24
+ "iss": "issues",
25
+ # verbs
26
+ "ls": "list",
27
+ "rm": "delete",
28
+ "del": "delete",
29
+ "new": "create",
30
+ "mk": "create",
31
+ "info": "show",
32
+ }
33
+
34
+
35
+ class AliasGroup(TyperGroup):
36
+ def get_command(self, ctx, name):
37
+ # Exact name first so a real command is never shadowed by an alias;
38
+ # then explicit alias; then an unambiguous prefix.
39
+ cmd = super().get_command(ctx, name)
40
+ if cmd is not None:
41
+ return cmd
42
+ alias = ALIASES.get(name)
43
+ if alias is not None:
44
+ cmd = super().get_command(ctx, alias)
45
+ if cmd is not None:
46
+ return cmd
47
+ matches = [c for c in self.list_commands(ctx) if c.startswith(name)]
48
+ if len(matches) == 1:
49
+ return super().get_command(ctx, matches[0])
50
+ return None
@@ -3,6 +3,8 @@ from typing import Annotated, Optional
3
3
 
4
4
  import typer
5
5
 
6
+ from ._group import AliasGroup
7
+
6
8
  from . import __version__
7
9
  from .output import print_error
8
10
  from .commands import (
@@ -32,6 +34,7 @@ app = typer.Typer(
32
34
  ),
33
35
  no_args_is_help=True,
34
36
  add_completion=False,
37
+ cls=AliasGroup,
35
38
  )
36
39
 
37
40
 
@@ -3,13 +3,15 @@ from typing import Annotated, Optional
3
3
 
4
4
  import typer
5
5
 
6
+ from .._group import AliasGroup
7
+
6
8
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
7
9
  from ..api import ApiClient
8
10
  from ..output import print_json, print_table
9
11
  from ..sessions import resolve_session_id
10
12
  from ..util import q
11
13
 
12
- app = typer.Typer(help="Manage annotations")
14
+ app = typer.Typer(help="Manage annotations", cls=AliasGroup, no_args_is_help=True)
13
15
 
14
16
  SessionOpt = Annotated[Optional[str], typer.Option("--session", help="Target a specific review session (advanced)")]
15
17
 
@@ -7,6 +7,8 @@ from typing import Annotated, Optional
7
7
  import httpx
8
8
  import typer
9
9
 
10
+ from .._group import AliasGroup
11
+
10
12
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
11
13
  from ..api import ApiClient
12
14
  from ..config import get_api_url, read_config, validate_api_url, write_config
@@ -148,7 +150,7 @@ def whoami(
148
150
  )
149
151
 
150
152
 
151
- auth_app = typer.Typer(help="Authentication commands")
153
+ auth_app = typer.Typer(help="Authentication commands", cls=AliasGroup, no_args_is_help=True)
152
154
  auth_app.command("login")(login)
153
155
  auth_app.command("logout")(logout)
154
156
  auth_app.command("whoami")(whoami)
@@ -4,12 +4,14 @@ from typing import Annotated, Optional
4
4
 
5
5
  import typer
6
6
 
7
+ from .._group import AliasGroup
8
+
7
9
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
8
10
  from ..api import ApiClient
9
11
  from ..output import print_json, print_table
10
12
  from ..util import q
11
13
 
12
- app = typer.Typer(help="Manage S3 and Hugging Face buckets")
14
+ app = typer.Typer(help="Manage S3 and Hugging Face buckets", cls=AliasGroup, no_args_is_help=True)
13
15
 
14
16
 
15
17
  @app.command("list")
@@ -6,12 +6,14 @@ from typing import Annotated, Optional
6
6
 
7
7
  import typer
8
8
 
9
+ from .._group import AliasGroup
10
+
9
11
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
10
12
  from ..api import ApiClient
11
13
  from ..output import print_error, print_json, print_table
12
14
  from ..util import q
13
15
 
14
- app = typer.Typer(help="Manage datasets")
16
+ app = typer.Typer(help="Manage datasets", cls=AliasGroup, no_args_is_help=True)
15
17
 
16
18
 
17
19
  def _truncate(v: object, n: int = 80) -> str:
@@ -22,6 +24,10 @@ def _truncate(v: object, n: int = 80) -> str:
22
24
  @app.command("list")
23
25
  def list_datasets(
24
26
  workspace: Annotated[Optional[str], typer.Option("--workspace", help="Filter by workspace ID")] = None,
27
+ search: Annotated[
28
+ Optional[str],
29
+ typer.Option("--search", "-s", help="Filter by case-insensitive substring of name / HF repo"),
30
+ ] = None,
25
31
  json_out: JsonOpt = False,
26
32
  profile: ProfileOpt = None,
27
33
  api_url: ApiUrlOpt = None,
@@ -32,6 +38,15 @@ def list_datasets(
32
38
  if workspace:
33
39
  params["workspace_id"] = workspace
34
40
  items = client.get("/v1/datasets", params=params).json()
41
+ if search:
42
+ s = search.lower()
43
+ items = [
44
+ d
45
+ for d in items
46
+ if s in (d.get("display_name") or "").lower()
47
+ or s in (d.get("name") or "").lower()
48
+ or s in (d.get("hf_repo_id") or "").lower()
49
+ ]
35
50
  print_table(
36
51
  ["ID", "Name", "Workspace", "Rows"],
37
52
  [
@@ -4,12 +4,14 @@ from typing import Annotated, Optional
4
4
 
5
5
  import typer
6
6
 
7
+ from .._group import AliasGroup
8
+
7
9
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
8
10
  from ..api import ApiClient
9
11
  from ..output import print_error, print_json, print_table
10
12
  from ..util import q
11
13
 
12
- app = typer.Typer(help="Manage row edits")
14
+ app = typer.Typer(help="Manage row edits", cls=AliasGroup, no_args_is_help=True)
13
15
 
14
16
 
15
17
  @app.command("list")
@@ -6,12 +6,14 @@ from typing import Annotated, List, Optional
6
6
 
7
7
  import typer
8
8
 
9
+ from .._group import AliasGroup
10
+
9
11
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
10
12
  from ..api import ApiClient
11
13
  from ..output import print_error, print_json, print_table
12
14
  from ..util import q
13
15
 
14
- app = typer.Typer(help="Inspect and analyze eval datasets (accuracy, failure modes, samples)")
16
+ app = typer.Typer(help="Inspect and analyze eval datasets (accuracy, failure modes, samples)", cls=AliasGroup, no_args_is_help=True)
15
17
 
16
18
  # Mirrors front/src/lib/eval-dataset.ts so `eval samples --search` searches the
17
19
  # same prompt/response columns the eval views do.
@@ -3,13 +3,15 @@ from typing import Annotated, Optional
3
3
 
4
4
  import typer
5
5
 
6
+ from .._group import AliasGroup
7
+
6
8
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
7
9
  from ..api import ApiClient
8
10
  from ..output import print_error, print_json, print_table
9
11
  from ..sessions import resolve_session_id
10
12
  from ..util import q
11
13
 
12
- app = typer.Typer(help="Manage highlights")
14
+ app = typer.Typer(help="Manage highlights", cls=AliasGroup, no_args_is_help=True)
13
15
 
14
16
  SessionOpt = Annotated[Optional[str], typer.Option("--session", help="Target a specific review session (advanced)")]
15
17
 
@@ -8,6 +8,15 @@ INSTRUCTIONS = r"""
8
8
  CLI for the DataViewer platform. Gives agents and humans complete scriptable
9
9
  control over workspaces, datasets, spec docs, annotations, and S3.
10
10
 
11
+ Running a group with no subcommand (e.g. `lql datasets`) lists its subcommands.
12
+
13
+ Shortcuts (for humans typing): group aliases (`ds`=datasets, `ws`=workspaces,
14
+ `ev`=eval, `ann`=annotations, `hl`=highlights, `rep`=reports, `bkt`=buckets,
15
+ `iss`=issues), verb aliases (`ls`=list, `rm`/`del`=delete, `new`/`mk`=create,
16
+ `info`=show), and unique prefixes (`lql datasets l` → list) all resolve.
17
+ AGENTS: use the full canonical names shown throughout this reference — they are
18
+ the stable contract; the aliases are conveniences layered on top.
19
+
11
20
  ## Authentication
12
21
 
13
22
  lql login # Open browser → click Authorize → token stored automatically
@@ -43,7 +52,7 @@ Pagination: --limit N --offset N on list commands.
43
52
 
44
53
  A workspace is the top-level container for datasets, spec docs, and members.
45
54
 
46
- lql workspaces list
55
+ lql workspaces list [--search <text>] # --search filters by name / slug substring
47
56
  lql workspaces create <name>
48
57
  lql workspaces show <id>
49
58
  lql workspaces update <id> --name <new-name>
@@ -54,7 +63,7 @@ A workspace is the top-level container for datasets, spec docs, and members.
54
63
 
55
64
  ## Datasets
56
65
 
57
- lql datasets list [--workspace <id>]
66
+ lql datasets list [--workspace <id>] [--search <text>] # --search filters by name / HF repo substring
58
67
  lql datasets show <id>
59
68
  lql datasets create --workspace <id> --hf-repo <org/repo> [--name <display>] [--split <split>]
60
69
  lql datasets create --workspace <id> --hf-bucket <org/bucket> --key <path-or-glob> [--name <display>]
@@ -83,16 +92,26 @@ Non-conversation fields render as labeled metadata.
83
92
 
84
93
  lql preview <file.jsonl|file.json> # local file: each line/object is a row
85
94
  lql preview <dataset-id> # platform dataset, fetched & paged lazily
95
+ lql preview <org/name> --hf # HuggingFace repo: sync to DataViewer, then view
86
96
  lql preview data.jsonl -c messages # force field(s) as conversations
87
97
 
98
+ With --hf, SOURCE is a HuggingFace repo (org/name): it's synced into a
99
+ DataViewer workspace (you pick one interactively, or pass --workspace <id>;
100
+ --split defaults to train) and reused on later previews (dedup by repo+split).
101
+
88
102
  Options: -c/--column (field(s) to treat as conversations; default auto-detect,
89
103
  repeatable), -n/--limit (page size when paging a platform dataset), --offset
90
- (start row index), --title, --profile, --api-url.
104
+ (start row index), --title, --hf, --split, --workspace, --profile, --api-url.
91
105
 
92
106
  Navigation: two modes toggled with m/Tab — pager (one sample at a time; ←/→ or
93
107
  n/b switch samples, ↑/↓/j/k scroll) and scroll (all samples; n/b jump between
94
108
  them). q quits. Works over plain SSH with no browser or port-forward.
95
109
 
110
+ Media: images render inline in image-capable terminals (Kitty/Ghostty, iTerm2,
111
+ Sixel; placeholder otherwise) for both multimodal image segments and image-mode
112
+ columns; audio shows a ♪ line and `p` plays the current sample's clip via the
113
+ system player (afplay/open).
114
+
96
115
  ## Evals
97
116
 
98
117
  Eval datasets (evaluation-run output: each row a sample with a model 'response'
@@ -215,7 +234,9 @@ never goes stale.
215
234
 
216
235
  ### Discover workspaces and datasets
217
236
  lql workspaces list --json
237
+ lql workspaces list --search <name> --json # find a workspace by name
218
238
  lql datasets list --workspace <id> --json
239
+ lql datasets list --search <name> --json # find a dataset by name / HF repo
219
240
 
220
241
  ### Read dataset contents
221
242
  lql datasets schema <id> --json
@@ -3,12 +3,14 @@ from typing import Annotated, Optional
3
3
 
4
4
  import typer
5
5
 
6
+ from .._group import AliasGroup
7
+
6
8
  from .._opts import ApiUrlOpt, JsonOpt, ProfileOpt
7
9
  from ..api import ApiClient
8
10
  from ..output import print_json, print_table
9
11
  from ..util import q
10
12
 
11
- app = typer.Typer(help="Manage issues")
13
+ app = typer.Typer(help="Manage issues", cls=AliasGroup, no_args_is_help=True)
12
14
 
13
15
 
14
16
  @app.command("list")