licos-dev-cli 0.3.3__tar.gz → 0.3.5__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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: licos-dev-cli
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: LICOS Dev CLI - generate files and call model capabilities
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: click>=8.1
7
- Requires-Dist: licos-dev-sdk>=0.3.3
7
+ Requires-Dist: licos-dev-sdk>=0.3.5
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-dev-cli"
7
- version = "0.3.3"
7
+ version = "0.3.5"
8
8
  description = "LICOS Dev CLI - generate files and call model capabilities"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
11
- "licos-dev-sdk>=0.3.3",
11
+ "licos-dev-sdk>=0.3.5",
12
12
  "click>=8.1",
13
13
  ]
14
14
 
@@ -180,6 +180,20 @@ def pdf_inspect(
180
180
  raise click.exceptions.Exit(2)
181
181
 
182
182
 
183
+ @cli.command("pdf-read")
184
+ @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
185
+ @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
186
+ @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
187
+ @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
188
+ def pdf_read(file_path, offset, limit, max_chars):
189
+ """Read PDF page text as paginated JSON."""
190
+ from licos_dev_sdk import read_pdf
191
+
192
+ report = read_pdf(file_path, offset=offset, limit=limit, max_chars=max_chars)
193
+ report["path"] = _path_to_cli_output(report["path"])
194
+ _echo_json(report)
195
+
196
+
183
197
  # ── DOCX ─────────────────────────────────────────────────────────────────────
184
198
 
185
199
  @cli.command()
@@ -232,6 +246,20 @@ def docx_template(template_path, input_path, data_content, filename, output_dir)
232
246
  _echo_path(path)
233
247
 
234
248
 
249
+ @cli.command("docx-read")
250
+ @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
251
+ @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
252
+ @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
253
+ @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
254
+ def docx_read(file_path, offset, limit, max_chars):
255
+ """Read DOCX paragraphs and table rows as paginated JSON."""
256
+ from licos_dev_sdk import read_docx
257
+
258
+ report = read_docx(file_path, offset=offset, limit=limit, max_chars=max_chars)
259
+ report["path"] = _path_to_cli_output(report["path"])
260
+ _echo_json(report)
261
+
262
+
235
263
  # ── XLSX ─────────────────────────────────────────────────────────────────────
236
264
 
237
265
  @cli.command()
@@ -284,6 +312,29 @@ def xlsx_inspect(file_path):
284
312
  click.echo(json.dumps(inspect_xlsx(file_path), ensure_ascii=False, indent=2))
285
313
 
286
314
 
315
+ @cli.command("xlsx-read")
316
+ @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
317
+ @click.option("--sheet", default=None, help="Worksheet name. Omit it to list workbook structure first.")
318
+ @click.option("--range", "cell_range", default=None, help="Cell range in the selected worksheet, for example A1:F100")
319
+ @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
320
+ @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
321
+ @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
322
+ def xlsx_read(file_path, sheet, cell_range, offset, limit, max_chars):
323
+ """List XLSX worksheets or read rows from a selected worksheet."""
324
+ from licos_dev_sdk import read_xlsx
325
+
326
+ report = read_xlsx(
327
+ file_path,
328
+ sheet=sheet,
329
+ cell_range=cell_range,
330
+ offset=offset,
331
+ limit=limit,
332
+ max_chars=max_chars,
333
+ )
334
+ report["path"] = _path_to_cli_output(report["path"])
335
+ _echo_json(report)
336
+
337
+
287
338
  # ── CSV ──────────────────────────────────────────────────────────────────────
288
339
 
289
340
  @cli.command()
@@ -315,6 +366,62 @@ def pptx(input_path, content, filename, output_dir, content_type):
315
366
  _echo_path(path)
316
367
 
317
368
 
369
+ @cli.command("pptx-deck")
370
+ @click.option("-i", "--input", "input_path", help="JSON presentation specification file")
371
+ @click.option("-c", "--content", help="JSON presentation specification")
372
+ @click.option("-f", "--filename", required=True, help="Output filename without extension")
373
+ @click.option("-o", "--output-dir", default=None, help="Output directory")
374
+ @click.option(
375
+ "--asset-base-path",
376
+ default=None,
377
+ type=click.Path(file_okay=False),
378
+ help="Base directory for relative image paths; defaults to the JSON file directory",
379
+ )
380
+ def pptx_deck(input_path, content, filename, output_dir, asset_base_path):
381
+ """Generate a professional PPTX from a structured JSON specification."""
382
+ from licos_dev_sdk import create_pptx_deck
383
+
384
+ spec = _read_json(input_path, content)
385
+ if not isinstance(spec, dict):
386
+ raise click.BadParameter("presentation specification must be a JSON object")
387
+ base_path = asset_base_path or (str(Path(input_path).resolve().parent) if input_path else None)
388
+ path = create_pptx_deck(
389
+ spec,
390
+ filename,
391
+ output_dir=output_dir,
392
+ asset_base_path=base_path,
393
+ )
394
+ _echo_path(path)
395
+
396
+
397
+ @cli.command("pptx-inspect")
398
+ @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
399
+ @click.option("--min-slides", type=click.IntRange(min=1), default=None)
400
+ @click.option("--max-slides", type=click.IntRange(min=1), default=None)
401
+ def pptx_inspect(file_path, min_slides, max_slides):
402
+ """Inspect PPTX structure, content density, and requested slide-count limits."""
403
+ from licos_dev_sdk import inspect_pptx
404
+
405
+ report = inspect_pptx(file_path, min_slides=min_slides, max_slides=max_slides)
406
+ _echo_json(report)
407
+ if not report["quality_passed"]:
408
+ raise click.exceptions.Exit(2)
409
+
410
+
411
+ @cli.command("pptx-read")
412
+ @click.option("-f", "--file", "file_path", required=True, type=click.Path(exists=True, dir_okay=False))
413
+ @click.option("--offset", type=click.IntRange(min=1), default=1, show_default=True)
414
+ @click.option("--limit", type=click.IntRange(min=1), default=20, show_default=True)
415
+ @click.option("--max-chars", type=click.IntRange(min=256), default=8_000, show_default=True)
416
+ def pptx_read(file_path, offset, limit, max_chars):
417
+ """Read PPTX slide text, tables, and notes as paginated JSON."""
418
+ from licos_dev_sdk import read_pptx
419
+
420
+ report = read_pptx(file_path, offset=offset, limit=limit, max_chars=max_chars)
421
+ report["path"] = _path_to_cli_output(report["path"])
422
+ _echo_json(report)
423
+
424
+
318
425
  # ── Chart ────────────────────────────────────────────────────────────────────
319
426
 
320
427
  @cli.command()
@@ -0,0 +1,48 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ from click.testing import CliRunner
5
+
6
+ from licos_dev_cli.main import cli
7
+
8
+
9
+ def test_docx_read_command_returns_paginated_json(tmp_path: Path, monkeypatch):
10
+ from docx import Document
11
+
12
+ project = tmp_path / "projects"
13
+ project.mkdir()
14
+ path = project / "brief.docx"
15
+ document = Document()
16
+ document.add_paragraph("First paragraph")
17
+ document.add_paragraph("Second paragraph")
18
+ document.save(path)
19
+ monkeypatch.setenv("LICOS_PROJECT_PATH", str(project))
20
+
21
+ result = CliRunner().invoke(
22
+ cli,
23
+ ["docx-read", "--file", str(path), "--offset", "1", "--limit", "1"],
24
+ )
25
+
26
+ assert result.exit_code == 0, result.output
27
+ payload = json.loads(result.output)
28
+ assert payload["path"] == "brief.docx"
29
+ assert payload["items"][0]["text"] == "First paragraph"
30
+ assert payload["has_more"] is True
31
+ assert payload["next_offset"] == 2
32
+
33
+
34
+ def test_xlsx_read_without_sheet_returns_workbook_structure(tmp_path: Path):
35
+ from openpyxl import Workbook
36
+
37
+ path = tmp_path / "book.xlsx"
38
+ workbook = Workbook()
39
+ workbook.active.title = "Overview"
40
+ workbook.create_sheet("Details")
41
+ workbook.save(path)
42
+
43
+ result = CliRunner().invoke(cli, ["xlsx-read", "--file", str(path)])
44
+
45
+ assert result.exit_code == 0, result.output
46
+ payload = json.loads(result.output)
47
+ assert payload["mode"] == "workbook_overview"
48
+ assert payload["sheet_names"] == ["Overview", "Details"]
File without changes