indico-cli 0.2.1__tar.gz → 0.4.1__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.
- {indico_cli-0.2.1 → indico_cli-0.4.1}/PKG-INFO +1 -1
- {indico_cli-0.2.1 → indico_cli-0.4.1}/indico_cli/_version.py +2 -2
- {indico_cli-0.2.1 → indico_cli-0.4.1}/indico_cli/cli.py +19 -4
- {indico_cli-0.2.1 → indico_cli-0.4.1}/indico_cli/indico_api.py +16 -4
- {indico_cli-0.2.1 → indico_cli-0.4.1}/skills/indico-skill/SKILL.md +12 -2
- {indico_cli-0.2.1 → indico_cli-0.4.1}/.gitignore +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/.gitlab-ci.yml +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/CLAUDE.md +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/LICENSE +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/README.md +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/docs/superpowers/plans/2026-03-24-search-results-and-error-messages.md +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/docs/superpowers/specs/2026-03-24-search-results-and-error-messages-design.md +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/indico_cli/__init__.py +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/indico_cli/utils.py +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/pyproject.toml +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/tests/__init__.py +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/tests/test_error_messages.py +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/tests/test_format_search_result.py +0 -0
- {indico_cli-0.2.1 → indico_cli-0.4.1}/uv.lock +0 -0
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.
|
|
32
|
-
__version_tuple__ = version_tuple = (0,
|
|
31
|
+
__version__ = version = '0.4.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 4, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -71,10 +71,21 @@ def cli(ctx, base_url, token):
|
|
|
71
71
|
|
|
72
72
|
@cli.command()
|
|
73
73
|
@click.option("--base-url", required=True, help="Indico instance URL")
|
|
74
|
-
@click.option("--token", default="", help="API bearer token")
|
|
74
|
+
@click.option("--token", envvar="INDICO_API_TOKEN", default="", help="API bearer token (or set INDICO_API_TOKEN)")
|
|
75
75
|
def configure(base_url, token):
|
|
76
76
|
"""Configure connection to an Indico instance and test it."""
|
|
77
|
-
|
|
77
|
+
if not token:
|
|
78
|
+
try:
|
|
79
|
+
token = click.prompt("API token", hide_input=True)
|
|
80
|
+
except (EOFError, click.Abort):
|
|
81
|
+
pass
|
|
82
|
+
if not token:
|
|
83
|
+
click.echo("Error: no token provided.", err=True)
|
|
84
|
+
click.echo("Either:", err=True)
|
|
85
|
+
click.echo(" 1. Run in a real terminal: indico-cli configure --base-url URL", err=True)
|
|
86
|
+
click.echo(" 2. Set env var first: export INDICO_API_TOKEN=indp_... && indico-cli configure --base-url URL", err=True)
|
|
87
|
+
sys.exit(1)
|
|
88
|
+
api = IndicoAPI(base_url, bearer_token=token)
|
|
78
89
|
client = IndicoClient(api)
|
|
79
90
|
try:
|
|
80
91
|
result = run_async(client.get_user_info())
|
|
@@ -84,6 +95,7 @@ def configure(base_url, token):
|
|
|
84
95
|
click.echo(f"Configuration saved to {CONFIG_FILE}")
|
|
85
96
|
except Exception as error:
|
|
86
97
|
click.echo(f"Connection test failed: {error}", err=True)
|
|
98
|
+
click.echo("Check that your token starts with 'indp_' and has the correct scopes.", err=True)
|
|
87
99
|
sys.exit(1)
|
|
88
100
|
|
|
89
101
|
|
|
@@ -113,11 +125,14 @@ def search_events(ctx, category_id, from_date, to_date, limit, only_public):
|
|
|
113
125
|
@cli.command("search-by-term")
|
|
114
126
|
@click.option("--term", required=True, help="Search term")
|
|
115
127
|
@click.option("--limit", type=int, default=50, help="Maximum number of results")
|
|
128
|
+
@click.option("--type", "type_filter", default=None,
|
|
129
|
+
type=click.Choice(["category", "event", "contribution", "subcontribution", "attachment", "event_note"]),
|
|
130
|
+
help="Filter to a specific content type")
|
|
116
131
|
@click.pass_context
|
|
117
|
-
def search_by_term(ctx, term, limit):
|
|
132
|
+
def search_by_term(ctx, term, limit, type_filter):
|
|
118
133
|
"""Search for events by keyword/term."""
|
|
119
134
|
client = get_client(ctx.obj["base_url"], ctx.obj["token"])
|
|
120
|
-
result = run_async(client.search_events_by_term(term, limit))
|
|
135
|
+
result = run_async(client.search_events_by_term(term, limit, type_filter))
|
|
121
136
|
click.echo(result)
|
|
122
137
|
|
|
123
138
|
|
|
@@ -365,13 +365,12 @@ class IndicoClient:
|
|
|
365
365
|
return response
|
|
366
366
|
|
|
367
367
|
async def search_events_by_term(
|
|
368
|
-
self, search_term: str, limit: int = 50
|
|
368
|
+
self, search_term: str, limit: int = 50, type_filter: Optional[str] = None
|
|
369
369
|
) -> str:
|
|
370
370
|
"""Search for content by keyword/term using comprehensive Indico search API"""
|
|
371
371
|
try:
|
|
372
|
-
# URL-encode the search term to handle special characters
|
|
373
372
|
# Define all search types to query
|
|
374
|
-
|
|
373
|
+
all_search_types = [
|
|
375
374
|
("category", "Categories"),
|
|
376
375
|
("event", "Events"),
|
|
377
376
|
("contribution", "Contributions"),
|
|
@@ -380,6 +379,14 @@ class IndicoClient:
|
|
|
380
379
|
("event_note", "Event Notes")
|
|
381
380
|
]
|
|
382
381
|
|
|
382
|
+
# Filter to specific type if requested
|
|
383
|
+
if type_filter:
|
|
384
|
+
search_types = [(t, d) for t, d in all_search_types if t == type_filter]
|
|
385
|
+
if not search_types:
|
|
386
|
+
return f"Unknown search type '{type_filter}'. Valid types: category, event, contribution, subcontribution, attachment, event_note"
|
|
387
|
+
else:
|
|
388
|
+
search_types = all_search_types
|
|
389
|
+
|
|
383
390
|
all_results = {}
|
|
384
391
|
total_found = 0
|
|
385
392
|
|
|
@@ -1243,12 +1250,17 @@ class IndicoClient:
|
|
|
1243
1250
|
else:
|
|
1244
1251
|
path = download_url
|
|
1245
1252
|
|
|
1253
|
+
# Build legacy export path if the URL uses /event/... format
|
|
1254
|
+
legacy_path = path
|
|
1255
|
+
if path.startswith("/event/") and not path.startswith("/export/"):
|
|
1256
|
+
legacy_path = f"/export{path}"
|
|
1257
|
+
|
|
1246
1258
|
# Use our download method
|
|
1247
1259
|
fake_file_info = {
|
|
1248
1260
|
"filename": filename or "downloaded_file",
|
|
1249
1261
|
"download_url": download_url,
|
|
1250
1262
|
"api_path": path,
|
|
1251
|
-
"legacy_path":
|
|
1263
|
+
"legacy_path": legacy_path,
|
|
1252
1264
|
}
|
|
1253
1265
|
|
|
1254
1266
|
file_response = await self.download_file_with_auth(fake_file_info, "unknown")
|
|
@@ -23,11 +23,13 @@ Set up or update Indico CLI credentials.
|
|
|
23
23
|
|
|
24
24
|
1. **Check if already configured**: run `uvx indico-cli user-info 2>&1`. If it returns user info, stop — already configured.
|
|
25
25
|
2. **Ask the user** which Indico instance to connect to (e.g., `https://indico.cern.ch`, `https://indico.fnal.gov`, or a custom URL).
|
|
26
|
-
3. **Guide token creation**: tell the user to open `<base_url>/user/
|
|
26
|
+
3. **Guide token creation**: tell the user to open `<base_url>/user/tokens/`, click "Create new token", name it (e.g., "indico-cli"), select all scopes (you can avoid write in case want to play on the safe side), click "Create", and copy the `indp_...` token immediately (shown only once).
|
|
27
27
|
4. **Save credentials**:
|
|
28
|
+
|
|
28
29
|
```bash
|
|
29
30
|
uvx indico-cli configure --base-url <BASE_URL> --token <TOKEN>
|
|
30
31
|
```
|
|
32
|
+
|
|
31
33
|
Saves to `~/.config/indico-cli/config.json` (never inside a repo).
|
|
32
34
|
5. **Verify**: the configure command tests the connection automatically. On failure: 403/401 = wrong scopes or expired token; connection error = wrong URL; SSL error = network issue.
|
|
33
35
|
|
|
@@ -44,6 +46,7 @@ If an event returns "not found" or "deleted", don't stop — use `search-by-term
|
|
|
44
46
|
### Chaining commands for deeper answers
|
|
45
47
|
|
|
46
48
|
Many tasks require chaining multiple commands. For example, to find out what someone concluded in a talk:
|
|
49
|
+
|
|
47
50
|
1. `search-by-term` or `contributions` to find the relevant contribution
|
|
48
51
|
2. `files` or `download` to get the slides/PDF
|
|
49
52
|
3. **Read the downloaded file** and extract the answer
|
|
@@ -53,6 +56,7 @@ The goal is to answer the user's question, not just list metadata. If slides wer
|
|
|
53
56
|
### Using event IDs from search results
|
|
54
57
|
|
|
55
58
|
`search-by-term` returns `Event ID` for every contribution, attachment, and note result. Use this ID to drill into the event:
|
|
59
|
+
|
|
56
60
|
1. `search-by-term --term "my topic"` — find the contribution and note its Event ID
|
|
57
61
|
2. `event-details --event-id <ID>` — get full event info
|
|
58
62
|
3. `contributions --event-id <ID>` — list all contributions
|
|
@@ -71,13 +75,14 @@ The goal is to answer the user's question, not just list metadata. If slides wer
|
|
|
71
75
|
### search-by-term — Full-text search across all Indico content
|
|
72
76
|
|
|
73
77
|
```bash
|
|
74
|
-
uvx indico-cli search-by-term --term "<query>" [--limit N]
|
|
78
|
+
uvx indico-cli search-by-term --term "<query>" [--limit N] [--type TYPE]
|
|
75
79
|
```
|
|
76
80
|
|
|
77
81
|
| Parameter | Required | Description |
|
|
78
82
|
|-----------|----------|-------------|
|
|
79
83
|
| `--term` | Yes | Search keyword or phrase |
|
|
80
84
|
| `--limit` | No | Max results per content type (default: 50) |
|
|
85
|
+
| `--type` | No | Filter to one content type: `event`, `contribution`, `subcontribution`, `attachment`, `event_note`, `category` |
|
|
81
86
|
|
|
82
87
|
Searches categories, events, contributions, subcontributions, attachments, and notes.
|
|
83
88
|
|
|
@@ -155,6 +160,7 @@ uvx indico-cli files --event-id <ID> [--download | --no-download] [--download-di
|
|
|
155
160
|
| `--download-dir` | No | Directory for downloads |
|
|
156
161
|
|
|
157
162
|
If the built-in download fails (403), list with `--no-download` to get URLs, then use curl:
|
|
163
|
+
|
|
158
164
|
```bash
|
|
159
165
|
curl -L -H "Authorization: Bearer $INDICO_API_TOKEN" -o filename.pdf "DOWNLOAD_URL"
|
|
160
166
|
```
|
|
@@ -309,11 +315,13 @@ Used by `create-event-with-agenda`. A JSON array where items with a `contributio
|
|
|
309
315
|
## Examples
|
|
310
316
|
|
|
311
317
|
Search for beam dynamics content:
|
|
318
|
+
|
|
312
319
|
```bash
|
|
313
320
|
uvx indico-cli search-by-term --term "beam dynamics" --limit 5
|
|
314
321
|
```
|
|
315
322
|
|
|
316
323
|
Create a meeting with agenda:
|
|
324
|
+
|
|
317
325
|
```bash
|
|
318
326
|
uvx indico-cli create-event-with-agenda \
|
|
319
327
|
--title "Workshop on ML" \
|
|
@@ -327,11 +335,13 @@ uvx indico-cli create-event-with-agenda \
|
|
|
327
335
|
```
|
|
328
336
|
|
|
329
337
|
Download all files from an event:
|
|
338
|
+
|
|
330
339
|
```bash
|
|
331
340
|
uvx indico-cli files --event-id 137346
|
|
332
341
|
```
|
|
333
342
|
|
|
334
343
|
Schedule a contribution:
|
|
344
|
+
|
|
335
345
|
```bash
|
|
336
346
|
uvx indico-cli add-timetable-entry --event-id 137346 --type contribution --object-id 12 --start 2025-06-15T14:00:00 --duration 30
|
|
337
347
|
```
|
|
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
|