deepcell-cli 0.6.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.
Files changed (67) hide show
  1. deepcell_cli/__init__.py +12 -0
  2. deepcell_cli/__main__.py +5 -0
  3. deepcell_cli/_findings.py +84 -0
  4. deepcell_cli/capabilities.py +560 -0
  5. deepcell_cli/capability-contract.json +15622 -0
  6. deepcell_cli/client.py +503 -0
  7. deepcell_cli/commands/__init__.py +1 -0
  8. deepcell_cli/commands/_batch_input.py +29 -0
  9. deepcell_cli/commands/_datatypes.py +56 -0
  10. deepcell_cli/commands/_negative_args.py +133 -0
  11. deepcell_cli/commands/_swapped_args.py +153 -0
  12. deepcell_cli/commands/_version_display.py +40 -0
  13. deepcell_cli/commands/_write_opts.py +139 -0
  14. deepcell_cli/commands/account.py +123 -0
  15. deepcell_cli/commands/auth.py +610 -0
  16. deepcell_cli/commands/changes.py +307 -0
  17. deepcell_cli/commands/deck.py +594 -0
  18. deepcell_cli/commands/defs.py +3890 -0
  19. deepcell_cli/commands/describe.py +902 -0
  20. deepcell_cli/commands/doc.py +529 -0
  21. deepcell_cli/commands/doctor.py +257 -0
  22. deepcell_cli/commands/download.py +36 -0
  23. deepcell_cli/commands/edit.py +384 -0
  24. deepcell_cli/commands/example.py +161 -0
  25. deepcell_cli/commands/export.py +81 -0
  26. deepcell_cli/commands/export_docx.py +57 -0
  27. deepcell_cli/commands/export_pdf.py +66 -0
  28. deepcell_cli/commands/export_pptx.py +45 -0
  29. deepcell_cli/commands/files.py +386 -0
  30. deepcell_cli/commands/grep.py +90 -0
  31. deepcell_cli/commands/guide.py +431 -0
  32. deepcell_cli/commands/help_cmd.py +348 -0
  33. deepcell_cli/commands/impact.py +382 -0
  34. deepcell_cli/commands/import_cmd.py +208 -0
  35. deepcell_cli/commands/ingest.py +110 -0
  36. deepcell_cli/commands/merge.py +399 -0
  37. deepcell_cli/commands/query.py +718 -0
  38. deepcell_cli/commands/reasoning.py +2981 -0
  39. deepcell_cli/commands/ref.py +279 -0
  40. deepcell_cli/commands/replace.py +326 -0
  41. deepcell_cli/commands/rules.py +206 -0
  42. deepcell_cli/commands/share.py +186 -0
  43. deepcell_cli/commands/sync.py +804 -0
  44. deepcell_cli/commands/upgrade.py +185 -0
  45. deepcell_cli/commands/variant.py +353 -0
  46. deepcell_cli/commands/version.py +445 -0
  47. deepcell_cli/commands/viewer.py +54 -0
  48. deepcell_cli/commands/workspace.py +101 -0
  49. deepcell_cli/config.py +352 -0
  50. deepcell_cli/context.py +187 -0
  51. deepcell_cli/errors.py +141 -0
  52. deepcell_cli/logging_setup.py +161 -0
  53. deepcell_cli/main.py +518 -0
  54. deepcell_cli/mcp_server.py +906 -0
  55. deepcell_cli/oauth_provider.py +580 -0
  56. deepcell_cli/output.py +503 -0
  57. deepcell_cli/revision.py +164 -0
  58. deepcell_cli/stages.py +223 -0
  59. deepcell_cli/surface.py +628 -0
  60. deepcell_cli/sync_state.py +120 -0
  61. deepcell_cli/upgrade_check.py +399 -0
  62. deepcell_cli/xml_replace.py +89 -0
  63. deepcell_cli-0.6.1.dist-info/METADATA +264 -0
  64. deepcell_cli-0.6.1.dist-info/RECORD +67 -0
  65. deepcell_cli-0.6.1.dist-info/WHEEL +5 -0
  66. deepcell_cli-0.6.1.dist-info/entry_points.txt +3 -0
  67. deepcell_cli-0.6.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,161 @@
1
+ """``deepcell example`` — complete, valid documents, indexed by mechanic.
2
+
3
+ The anti-guessing surface. Models are complicated to build, and an agent that
4
+ guesses at the format gets rejected by the parser; give it a shape that is
5
+ already valid and it copies that instead. See ``docs/cli-agent-surface.md`` §7.
6
+
7
+ Three layers per example, read in order — skeleton, full, transcript — and the
8
+ transcript is the point. Agents rarely get the XML wrong once they have seen
9
+ one; they routinely get the *verb order* wrong.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from pathlib import Path
15
+
16
+ import click
17
+
18
+ from deepcell_cli.context import Ctx, pass_ctx
19
+ from deepcell_cli.output import output, print_plain
20
+
21
+
22
+ @click.group(invoke_without_command=True)
23
+ @click.option("--pack", default=None, help="Core examples plus this pack's.")
24
+ @pass_ctx
25
+ def example(ctx: Ctx, pack: str | None) -> None:
26
+ """Complete, valid documents to copy the shape from.
27
+
28
+ \b
29
+ List them: deepcell example
30
+ Read the build: deepcell example show ops/headcount-plan transcript
31
+ Seed a file: deepcell example get ops/headcount-plan --into plan.deepcell
32
+
33
+ Indexed by the hard feature each demonstrates, not by industry — one
34
+ example per mechanic, each in a different domain.
35
+ """
36
+ if click.get_current_context().invoked_subcommand is not None:
37
+ return
38
+ _print_example_list(ctx, pack)
39
+
40
+
41
+ def _print_example_list(ctx: Ctx, pack: str | None = None) -> None:
42
+ """Print every example name and the mechanic it demonstrates."""
43
+ data = ctx.client.get("/examples", params={"pack": pack} if pack else None)
44
+ examples = data.get("examples", []) if isinstance(data, dict) else data
45
+
46
+ if ctx.fmt == "json":
47
+ output(data, ctx.fmt)
48
+ return
49
+ if not isinstance(examples, list) or not examples:
50
+ print_plain("No examples available.")
51
+ return
52
+
53
+ width = max(len(str(e.get("name", ""))) for e in examples)
54
+ lines = [
55
+ f"{str(e.get('name', '')):<{width}} {e.get('mechanic', '')}"
56
+ f" [{' + '.join(str(s).title() for s in e.get('surfaces', []))}]"
57
+ f" [{','.join(e.get('journeys', []))}]"
58
+ f"{' [' + e['pack'] + ' pack]' if e.get('pack') else ''}"
59
+ for e in examples
60
+ ]
61
+ lines += [
62
+ "",
63
+ "Read the build order: deepcell example show <name> transcript",
64
+ "Seed a file: deepcell example get <name> --into <file>",
65
+ ]
66
+ print_plain("\n".join(lines))
67
+
68
+
69
+ @example.command("list")
70
+ @click.option("--pack", default=None, help="Core examples plus this pack's.")
71
+ @pass_ctx
72
+ def example_list(ctx: Ctx, pack: str | None) -> None:
73
+ """List every example name — the same output as bare `deepcell example`.
74
+
75
+ An alias, and a deliberate one: every other surface with a listing has a
76
+ verb (`ref search`, `defs list`, `workspace list`), so `example list` is
77
+ the natural guess, and it used to fail with a bare `No such command`.
78
+ """
79
+ _print_example_list(ctx, pack)
80
+
81
+
82
+ @example.command("show")
83
+ @click.argument("name", required=False)
84
+ @click.argument("layer", required=False, default="full")
85
+ @pass_ctx
86
+ def example_show(ctx: Ctx, name: str | None, layer: str) -> None:
87
+ """Print one layer of an example: skeleton, full, or transcript.
88
+
89
+ Defaults to `full`. `transcript` is the one worth reading first — it is
90
+ the ordered command sequence that produced the document, which is the part
91
+ agents most need and never get.
92
+
93
+ With no NAME it lists the examples. Omitting the argument was the one case
94
+ that got *less* help than getting it wrong — a wrong name has always come
95
+ back with every legal name and a did-you-mean, while no name at all raised
96
+ a bare `Missing argument 'NAME'`. Two of eleven tasks in the 2026-08-02 CLI
97
+ eval hit that, and an empty argument is the clearer request for a list.
98
+ """
99
+ if not name:
100
+ _print_example_list(ctx)
101
+ return
102
+ data = ctx.client.get(f"/examples/{name}/layer/{layer}")
103
+ if ctx.fmt == "json":
104
+ output(data, ctx.fmt)
105
+ return
106
+ content = data.get("content", "") if isinstance(data, dict) else str(data)
107
+ print_plain(content.rstrip())
108
+
109
+
110
+ @example.command("get")
111
+ @click.argument("name")
112
+ @click.option(
113
+ "--into",
114
+ "into",
115
+ required=True,
116
+ type=click.Path(dir_okay=False, writable=True),
117
+ help="Local path to write the document to.",
118
+ )
119
+ @click.option(
120
+ "--layer",
121
+ default="full",
122
+ type=click.Choice(["skeleton", "full"]),
123
+ show_default=True,
124
+ help="Which document to seed from.",
125
+ )
126
+ @click.option("--force", is_flag=True, help="Overwrite an existing file.")
127
+ @pass_ctx
128
+ def example_get(ctx: Ctx, name: str, into: str, layer: str, force: bool) -> None:
129
+ """Write an example document to a local file.
130
+
131
+ The file is guaranteed to parse — that is the whole point of seeding from
132
+ one rather than writing XML from memory. Upload it with
133
+ `deepcell write <workspace-file> --file <local-file>`, then edit it in
134
+ place.
135
+ """
136
+ target = Path(into)
137
+ if target.exists() and not force:
138
+ # Refuse rather than clobber: `--into` is a local path and the caller
139
+ # may have pointed it at real work.
140
+ raise click.ClickException(
141
+ f"{target} already exists. Pass --force to overwrite it."
142
+ )
143
+
144
+ data = ctx.client.get(f"/examples/{name}/layer/{layer}")
145
+ content = data.get("content", "") if isinstance(data, dict) else str(data)
146
+ if not content.strip():
147
+ raise click.ClickException(f"Example {name}/{layer} is empty.")
148
+
149
+ target.parent.mkdir(parents=True, exist_ok=True)
150
+ target.write_text(content, encoding="utf-8")
151
+
152
+ if ctx.fmt == "json":
153
+ output({"name": name, "layer": layer, "path": str(target),
154
+ "bytes": len(content.encode("utf-8"))}, ctx.fmt)
155
+ return
156
+ print_plain(
157
+ f"Wrote {target} ({len(content.encode('utf-8'))} bytes) from "
158
+ f"example {name}/{layer}.\n"
159
+ f"Upload it: deepcell write {target.name} --file {target}\n"
160
+ f"See how it was built: deepcell example show {name} transcript"
161
+ )
@@ -0,0 +1,81 @@
1
+ """``deepcell to-excel`` — export .deepcell files to Excel."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from deepcell_cli.context import Ctx, pass_ctx
8
+ from deepcell_cli.output import echo_conversion_warnings, echo_success
9
+
10
+
11
+ @click.command()
12
+ @click.argument("filename")
13
+ @click.option("-o", "--output", "out_path", default=None, help="Output file path (default: <filename>.xlsx).")
14
+ @click.option("--formulas", is_flag=True, help="Export with live Excel formulas.")
15
+ @click.option("--recalculate", is_flag=True, help="Recompute formula values via the LibreOffice service (requires --formulas).")
16
+ @click.option("--scenario", "scenario_id", default=None, help="Document scenario ID to export (applies its VariableOverrides; omit for the default scenario).")
17
+ @click.option(
18
+ "--variant",
19
+ "variant_id",
20
+ default=None,
21
+ hidden=True,
22
+ help="(removed) Never worked — see --scenario for document scenarios.",
23
+ )
24
+ @pass_ctx
25
+ def to_excel(ctx: Ctx, filename: str, out_path: str | None, formulas: bool, recalculate: bool, scenario_id: str | None, variant_id: str | None) -> None:
26
+ """Export a .deepcell file to Excel format.
27
+
28
+ The exported workbook is shaped by two optional definition sections:
29
+ PresentationDefinitions (tab/block layout) and FormatDefinitions (cell
30
+ styling). Run `deepcell guide present/layout` or `deepcell ref format` for
31
+ details.
32
+
33
+ A workbook carries the MODEL: cells, formats and text blocks. It does not
34
+ carry charts or the SourceDefinitions provenance footnotes — the export
35
+ reports both as conversion warnings rather than dropping them silently.
36
+ Read sources with `deepcell ref source`, and take charts to a deck with
37
+ to-pptx or to the web viewer; see `deepcell guide present/deliver`.
38
+ """
39
+ if variant_id is not None:
40
+ raise click.UsageError(
41
+ "--variant was removed: the backend's /to-excel has no variant field, "
42
+ "so the flag silently exported the base model. To export a document "
43
+ "scenario (Bull/Bear/... defined via `deepcell defs add-scenario`) use "
44
+ "--scenario SCENARIO_ID. Workspace variants are git branches "
45
+ "(`deepcell variant list`); to-excel always exports the file content "
46
+ "of the current variant."
47
+ )
48
+
49
+ if recalculate and not formulas:
50
+ raise click.UsageError(
51
+ "--recalculate requires --formulas: the LibreOffice pass recomputes "
52
+ "the workbook's live formulas, so without --formulas the server "
53
+ "silently skips it."
54
+ )
55
+
56
+ slug = ctx.require_workspace()
57
+
58
+ # Determine output filename
59
+ if not out_path:
60
+ base = filename.rsplit(".", 1)[0] if "." in filename else filename
61
+ out_path = f"{base}.xlsx"
62
+
63
+ body: dict = {
64
+ "workspace_slug": slug,
65
+ "source_filename": filename,
66
+ "filename": out_path,
67
+ "export_formulas": formulas,
68
+ "should_recalculate": True,
69
+ "recalculate": recalculate,
70
+ }
71
+ if scenario_id:
72
+ body["scenario_id"] = scenario_id
73
+
74
+ # Server-side recalculation can exceed the default 30s client timeout.
75
+ resp = ctx.client.post_raw("/to-excel", json=body, timeout=300.0)
76
+
77
+ with open(out_path, "wb") as fh:
78
+ fh.write(resp.content)
79
+
80
+ echo_conversion_warnings(resp)
81
+ echo_success(f"Exported to {out_path} ({len(resp.content)} bytes)")
@@ -0,0 +1,57 @@
1
+ """``deepcell to-docx`` — export a `<Document>` prose section to Word."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from deepcell_cli.context import Ctx, pass_ctx
8
+ from deepcell_cli.output import echo_conversion_warnings, echo_success
9
+
10
+
11
+ @click.command()
12
+ @click.argument("filename")
13
+ @click.option("--doc", "doc_id", default=None, help="Document ID (required when the file has multiple documents).")
14
+ @click.option("--scenario", "scenario_id", default=None, help="Document scenario ID to export.")
15
+ @click.option("-o", "--output", "out_path", default=None, help="Output path (default: <filename>.docx).")
16
+ @click.option("--bundle", "bundle", is_flag=True, default=False, help="Link to sibling .xlsx / .pptx exports written alongside this one.")
17
+ @pass_ctx
18
+ def to_docx(
19
+ ctx: Ctx,
20
+ filename: str,
21
+ doc_id: str | None,
22
+ scenario_id: str | None,
23
+ out_path: str | None,
24
+ bundle: bool,
25
+ ) -> None:
26
+ """Export one document's prose as a Word file.
27
+
28
+ Links resolve against what is actually in the export: a bookmark inside
29
+ this file, a relative link to a sibling artifact written alongside it, and
30
+ otherwise an absolute viewer URL. Pass ``--bundle`` when the .xlsx and
31
+ .pptx are being written next to this file, so a cell reference lands on the
32
+ workbook cell rather than the hosted viewer.
33
+ """
34
+ slug = ctx.require_workspace()
35
+ base = filename.rsplit(".", 1)[0] if "." in filename else filename
36
+ if not out_path:
37
+ out_path = f"{base}.docx"
38
+ body: dict = {
39
+ "workspace_slug": slug,
40
+ "source_filename": filename,
41
+ "filename": out_path,
42
+ }
43
+ if doc_id:
44
+ body["doc_id"] = doc_id
45
+ if scenario_id:
46
+ body["scenario_id"] = scenario_id
47
+ if bundle:
48
+ xlsx_name = f"{base}.xlsx"
49
+ pptx_name = f"{base}.pptx"
50
+ body["bundle_files"] = [xlsx_name, pptx_name]
51
+ body["xlsx_name"] = xlsx_name
52
+ body["pptx_name"] = pptx_name
53
+ resp = ctx.client.post_raw("/to-docx", json=body, timeout=120.0)
54
+ with open(out_path, "wb") as fh:
55
+ fh.write(resp.content)
56
+ echo_conversion_warnings(resp)
57
+ echo_success(f"Exported to {out_path} ({len(resp.content)} bytes)")
@@ -0,0 +1,66 @@
1
+ """``deepcell to-pdf`` — export a document or a deck as PDF."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from deepcell_cli.context import Ctx, pass_ctx
8
+ from deepcell_cli.output import echo_conversion_warnings, echo_success
9
+
10
+
11
+ @click.command()
12
+ @click.argument("filename")
13
+ @click.option(
14
+ "--from", "source", type=click.Choice(["deck", "doc"]), default="deck",
15
+ show_default=True,
16
+ help="Which surface to render: the presentation deck, or the prose document.",
17
+ )
18
+ @click.option("--deck", "deck_id", default=None, help="Deck ID (required when the file has multiple decks).")
19
+ @click.option("--doc", "doc_id", default=None, help="Document ID (required when the file has multiple documents).")
20
+ @click.option("--scenario", "scenario_id", default=None, help="Document scenario ID to export.")
21
+ @click.option("-o", "--output", "out_path", default=None, help="Output path (default: <filename>_<deck|doc>.pdf).")
22
+ @pass_ctx
23
+ def to_pdf(
24
+ ctx: Ctx,
25
+ filename: str,
26
+ source: str,
27
+ deck_id: str | None,
28
+ doc_id: str | None,
29
+ scenario_id: str | None,
30
+ out_path: str | None,
31
+ ) -> None:
32
+ """Export a deck or a document as a PDF.
33
+
34
+ The PDF is the PowerPoint or Word export rendered one step further, so it
35
+ shows exactly what those files show — including anything wrong with them,
36
+ which is what makes it useful for checking an export you cannot open.
37
+
38
+ Needs a server with the LibreOffice service configured; without one the
39
+ command reports that PDF export is unavailable rather than writing a file.
40
+ """
41
+ slug = ctx.require_workspace()
42
+ base = filename.rsplit(".", 1)[0] if "." in filename else filename
43
+ if not out_path:
44
+ # The surface is part of the default name: one file can yield both a deck
45
+ # PDF and a document PDF, and a shared default would make the second
46
+ # export silently overwrite the first.
47
+ out_path = f"{base}_{source}.pdf"
48
+ body: dict = {
49
+ "source": source,
50
+ "workspace_slug": slug,
51
+ "source_filename": filename,
52
+ "filename": out_path,
53
+ }
54
+ if deck_id:
55
+ body["deck_id"] = deck_id
56
+ if doc_id:
57
+ body["doc_id"] = doc_id
58
+ if scenario_id:
59
+ body["scenario_id"] = scenario_id
60
+ # Two services in series (deck export, then conversion), so the deadline is
61
+ # the sum rather than either one's.
62
+ resp = ctx.client.post_raw("/to-pdf", json=body, timeout=240.0)
63
+ with open(out_path, "wb") as fh:
64
+ fh.write(resp.content)
65
+ echo_conversion_warnings(resp)
66
+ echo_success(f"Exported to {out_path} ({len(resp.content)} bytes)")
@@ -0,0 +1,45 @@
1
+ """``deepcell to-pptx`` — export an HTML deck to editable PowerPoint."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import click
6
+
7
+ from deepcell_cli.context import Ctx, pass_ctx
8
+ from deepcell_cli.output import echo_conversion_warnings, echo_success
9
+
10
+
11
+ @click.command()
12
+ @click.argument("filename")
13
+ @click.option("--deck", "deck_id", default=None, help="Deck ID (required when the document has multiple decks).")
14
+ @click.option("--scenario", "scenario_id", default=None, help="Document scenario ID to export.")
15
+ @click.option("-o", "--output", "out_path", default=None, help="Output path (default: <filename>.pptx).")
16
+ @pass_ctx
17
+ def to_pptx(
18
+ ctx: Ctx,
19
+ filename: str,
20
+ deck_id: str | None,
21
+ scenario_id: str | None,
22
+ out_path: str | None,
23
+ ) -> None:
24
+ """Export one document-defined HTML deck as editable PowerPoint objects."""
25
+ slug = ctx.require_workspace()
26
+ if not out_path:
27
+ base = filename.rsplit(".", 1)[0] if "." in filename else filename
28
+ out_path = f"{base}.pptx"
29
+ body: dict = {
30
+ "workspace_slug": slug,
31
+ "source_filename": filename,
32
+ "filename": out_path,
33
+ "should_recalculate": True,
34
+ }
35
+ if deck_id:
36
+ body["deck_id"] = deck_id
37
+ if scenario_id:
38
+ body["scenario_id"] = scenario_id
39
+ # Export recalculates and renders every slide in headless Chromium
40
+ # server-side — far slower than the default 30s client timeout allows.
41
+ resp = ctx.client.post_raw("/to-pptx", json=body, timeout=300.0)
42
+ with open(out_path, "wb") as fh:
43
+ fh.write(resp.content)
44
+ echo_conversion_warnings(resp)
45
+ echo_success(f"Exported to {out_path} ({len(resp.content)} bytes)")