cassis-cli 1.5.0__tar.gz → 1.5.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.
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/PKG-INFO +10 -9
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/README.md +7 -6
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/__init__.py +4 -1
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/common.py +47 -5
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/main.py +4 -1
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/ontology.py +58 -11
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/schema.py +1 -1
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/pyproject.toml +10 -3
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/LICENSE +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/NOTICE +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/api.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/eval.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/guide.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/issues.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/ontology_design_guide.md +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/projects.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/status.py +0 -0
- {cassis_cli-1.5.0 → cassis_cli-1.5.1}/cassis_cli/verify.py +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cassis-cli
|
|
3
|
-
Version: 1.5.
|
|
4
|
-
Summary:
|
|
3
|
+
Version: 1.5.1
|
|
4
|
+
Summary: Validate, test and evaluate your Cassis ontology from your terminal, then publish it
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
License-File: NOTICE
|
|
8
|
-
Keywords: cassis,ontology,ci,text-to-sql
|
|
8
|
+
Keywords: cassis,ontology,cli,ci,text-to-sql
|
|
9
9
|
Author: Cassis
|
|
10
10
|
Author-email: tech.admin@getcassis.com
|
|
11
11
|
Requires-Python: >=3.10,<4.0
|
|
@@ -22,13 +22,13 @@ Description-Content-Type: text/markdown
|
|
|
22
22
|
|
|
23
23
|
# Cassis CLI
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Validate, test and evaluate your ontology from your terminal, then publish it. The same commands gate your pull requests in CI:
|
|
26
26
|
|
|
27
27
|
- `cassis ontology check` validates the ontology files in your repository with the exact same checks as the Cassis GitHub PR check (YAML parsing, round-trip, import validation) — so you can gate merges in any CI system, not just GitHub. It then prints advisory **ontology quality warnings** for a tree that parsed — tables not assigned to any domain, joins/metrics pointing at unknown tables or columns, missing table/column descriptions (the same findings `ontology test` reports, without the agent run). In a checkout bound to a project (`project.yml`, `--project`, or `CASSIS_PROJECT_ID`), it also cross-checks the tree against the project's source schema: references to tables or columns the warehouse doesn't have print as **warnings** too — advisory only (the object may simply not be built or synced yet). Warnings never fail the check.
|
|
28
28
|
- `cassis schema pull` downloads the data source's full source schema (as Cassis last introspected it) into `<base-path>/.schema.json` — a **gitignored** local snapshot (the command maintains the ignore entry) with a `pulled_at` stamp. The warehouse stays authoritative; the snapshot is a cache for offline/bulk work — e.g. a coding agent grepping table and column names during a modeling pass instead of paging through the MCP `get_source_schema` tool. Re-run to refresh.
|
|
29
29
|
- `cassis ontology fmt` rewrites the ontology files in canonical form (think `black`/`gofmt` for the ontology), so hand or agent edits pass the round-trip check.
|
|
30
30
|
- `cassis ontology upload` uploads the ontology files to a Cassis project (full replace) and, by default, publishes them immediately as a new version — so a merge to your main branch can go live in one CI step.
|
|
31
|
-
- `cassis ontology pull` downloads the project's unpublished ontology into your repository checkout (full sync — stale local ontology files are pruned), so you can start editing from the current state, or bootstrap a repo that isn't git-synced (e.g. Bitbucket).
|
|
31
|
+
- `cassis ontology pull` downloads the project's unpublished ontology into your repository checkout (full sync — stale local ontology files are pruned), so you can start editing from the current state, or bootstrap a repo that isn't git-synced (e.g. Bitbucket). Pruning only deletes files that are tracked and unmodified in git (i.e. restorable with `git checkout`); untracked or locally modified files are kept and listed, and every deleted path is printed.
|
|
32
32
|
- `cassis ontology pull` and `cassis ontology fmt` also write `<base-path>/AGENTS.md`, the Cassis ontology modeling guide, into the checkout (default `cassis/AGENTS.md`) — a managed file (generated banner; the CLI overwrites local edits) so a repo-aware coding agent loads current Cassis modeling doctrine by convention. It sits inside the ontology directory but is not part of the ontology tree (which is the YAML files plus the domain Markdown files `domains/**/README.md`), so it is never uploaded, validated, or pruned. Commit it alongside your ontology changes. The guide text ships inside the CLI package, so its version tracks the **installed cassis-cli version** — upgrade the CLI (`pip install -U cassis-cli`) and re-run `fmt` to pick up doctrine updates; an unpinned `pip install cassis-cli` in CI gets them automatically. The banner stamps a doctrine version, and the CLI never *downgrades* the file: if the checkout's `AGENTS.md` was written by a newer doctrine (a newer CLI, or Cassis itself on a publish), `fmt`/`pull` leave it in place, print an upgrade notice, and `fmt --check` still passes.
|
|
33
33
|
- The CLI identifies itself to the API (`User-Agent: cassis-cli/<version>`), and successful API responses advertise the newest published version — when you are behind, commands print a one-line upgrade notice on stderr (purely informational; output and exit codes are unchanged).
|
|
34
34
|
- `cassis eval run` runs the project's eval suite against your local ontology files (scored in-memory — nothing is pushed to Cassis) and prints per-question results, so you can test the changes on your git branch before merging.
|
|
@@ -73,7 +73,8 @@ cassis ontology check
|
|
|
73
73
|
cassis ontology check /path/to/checkout
|
|
74
74
|
|
|
75
75
|
# Download the project's unpublished ontology into the checkout (full sync;
|
|
76
|
-
# review with git diff —
|
|
76
|
+
# review with git diff — untracked/modified files are never deleted, and
|
|
77
|
+
# --no-prune keeps even the tracked stale files it would otherwise delete):
|
|
77
78
|
cassis ontology pull --project 019f0000-0000-7000-8000-000000000000
|
|
78
79
|
|
|
79
80
|
# Upload the ontology to a project and publish it immediately:
|
|
@@ -193,9 +194,9 @@ cassis ontology fmt --check
|
|
|
193
194
|
| 3 | Transport/API error (unreachable API, invalid key, inaccessible project, unexpected response), another run already active, out of credits, or `--timeout` reached |
|
|
194
195
|
|
|
195
196
|
Commands that send the local tree (`check`, `fmt`, `upload`, `eval run`, `test`) accept up to
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
double-check `--base-path` if you hit it.
|
|
197
|
+
20,000 ontology files / 100 MB total (path + content bytes) — sized for ontologies of
|
|
198
|
+
roughly 10,000 modeled tables. Beyond that the CLI fails fast with exit 2 before
|
|
199
|
+
uploading anything; double-check `--base-path` if you hit it.
|
|
199
200
|
|
|
200
201
|
`upload` replaces the project's entire ontology with the uploaded tree. A
|
|
201
202
|
never-published project always goes live immediately on first upload (even
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Cassis CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Validate, test and evaluate your ontology from your terminal, then publish it. The same commands gate your pull requests in CI:
|
|
4
4
|
|
|
5
5
|
- `cassis ontology check` validates the ontology files in your repository with the exact same checks as the Cassis GitHub PR check (YAML parsing, round-trip, import validation) — so you can gate merges in any CI system, not just GitHub. It then prints advisory **ontology quality warnings** for a tree that parsed — tables not assigned to any domain, joins/metrics pointing at unknown tables or columns, missing table/column descriptions (the same findings `ontology test` reports, without the agent run). In a checkout bound to a project (`project.yml`, `--project`, or `CASSIS_PROJECT_ID`), it also cross-checks the tree against the project's source schema: references to tables or columns the warehouse doesn't have print as **warnings** too — advisory only (the object may simply not be built or synced yet). Warnings never fail the check.
|
|
6
6
|
- `cassis schema pull` downloads the data source's full source schema (as Cassis last introspected it) into `<base-path>/.schema.json` — a **gitignored** local snapshot (the command maintains the ignore entry) with a `pulled_at` stamp. The warehouse stays authoritative; the snapshot is a cache for offline/bulk work — e.g. a coding agent grepping table and column names during a modeling pass instead of paging through the MCP `get_source_schema` tool. Re-run to refresh.
|
|
7
7
|
- `cassis ontology fmt` rewrites the ontology files in canonical form (think `black`/`gofmt` for the ontology), so hand or agent edits pass the round-trip check.
|
|
8
8
|
- `cassis ontology upload` uploads the ontology files to a Cassis project (full replace) and, by default, publishes them immediately as a new version — so a merge to your main branch can go live in one CI step.
|
|
9
|
-
- `cassis ontology pull` downloads the project's unpublished ontology into your repository checkout (full sync — stale local ontology files are pruned), so you can start editing from the current state, or bootstrap a repo that isn't git-synced (e.g. Bitbucket).
|
|
9
|
+
- `cassis ontology pull` downloads the project's unpublished ontology into your repository checkout (full sync — stale local ontology files are pruned), so you can start editing from the current state, or bootstrap a repo that isn't git-synced (e.g. Bitbucket). Pruning only deletes files that are tracked and unmodified in git (i.e. restorable with `git checkout`); untracked or locally modified files are kept and listed, and every deleted path is printed.
|
|
10
10
|
- `cassis ontology pull` and `cassis ontology fmt` also write `<base-path>/AGENTS.md`, the Cassis ontology modeling guide, into the checkout (default `cassis/AGENTS.md`) — a managed file (generated banner; the CLI overwrites local edits) so a repo-aware coding agent loads current Cassis modeling doctrine by convention. It sits inside the ontology directory but is not part of the ontology tree (which is the YAML files plus the domain Markdown files `domains/**/README.md`), so it is never uploaded, validated, or pruned. Commit it alongside your ontology changes. The guide text ships inside the CLI package, so its version tracks the **installed cassis-cli version** — upgrade the CLI (`pip install -U cassis-cli`) and re-run `fmt` to pick up doctrine updates; an unpinned `pip install cassis-cli` in CI gets them automatically. The banner stamps a doctrine version, and the CLI never *downgrades* the file: if the checkout's `AGENTS.md` was written by a newer doctrine (a newer CLI, or Cassis itself on a publish), `fmt`/`pull` leave it in place, print an upgrade notice, and `fmt --check` still passes.
|
|
11
11
|
- The CLI identifies itself to the API (`User-Agent: cassis-cli/<version>`), and successful API responses advertise the newest published version — when you are behind, commands print a one-line upgrade notice on stderr (purely informational; output and exit codes are unchanged).
|
|
12
12
|
- `cassis eval run` runs the project's eval suite against your local ontology files (scored in-memory — nothing is pushed to Cassis) and prints per-question results, so you can test the changes on your git branch before merging.
|
|
@@ -51,7 +51,8 @@ cassis ontology check
|
|
|
51
51
|
cassis ontology check /path/to/checkout
|
|
52
52
|
|
|
53
53
|
# Download the project's unpublished ontology into the checkout (full sync;
|
|
54
|
-
# review with git diff —
|
|
54
|
+
# review with git diff — untracked/modified files are never deleted, and
|
|
55
|
+
# --no-prune keeps even the tracked stale files it would otherwise delete):
|
|
55
56
|
cassis ontology pull --project 019f0000-0000-7000-8000-000000000000
|
|
56
57
|
|
|
57
58
|
# Upload the ontology to a project and publish it immediately:
|
|
@@ -171,9 +172,9 @@ cassis ontology fmt --check
|
|
|
171
172
|
| 3 | Transport/API error (unreachable API, invalid key, inaccessible project, unexpected response), another run already active, out of credits, or `--timeout` reached |
|
|
172
173
|
|
|
173
174
|
Commands that send the local tree (`check`, `fmt`, `upload`, `eval run`, `test`) accept up to
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
double-check `--base-path` if you hit it.
|
|
175
|
+
20,000 ontology files / 100 MB total (path + content bytes) — sized for ontologies of
|
|
176
|
+
roughly 10,000 modeled tables. Beyond that the CLI fails fast with exit 2 before
|
|
177
|
+
uploading anything; double-check `--base-path` if you hit it.
|
|
177
178
|
|
|
178
179
|
`upload` replaces the project's entire ontology with the uploaded tree. A
|
|
179
180
|
never-published project always goes live immediately on first upload (even
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Validate, test and evaluate your ontology from your terminal, then publish it.
|
|
2
|
+
|
|
3
|
+
The same commands gate your pull requests in CI.
|
|
4
|
+
"""
|
|
2
5
|
|
|
3
6
|
from importlib.metadata import PackageNotFoundError, version
|
|
4
7
|
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import re
|
|
7
|
+
import subprocess
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
from typing import Optional
|
|
8
10
|
from uuid import UUID
|
|
@@ -20,10 +22,12 @@ EXIT_USAGE = 2
|
|
|
20
22
|
EXIT_TRANSPORT = 3
|
|
21
23
|
|
|
22
24
|
# Request ceilings of the /api/ci file-tree endpoints, mirrored so oversized
|
|
23
|
-
# trees fail fast with a clear message before any upload.
|
|
25
|
+
# trees fail fast with a clear message before any upload. Sized for ~10,000
|
|
26
|
+
# modeled tables (a 6,000-table tree is ~8,600 files / ~60 MB). Source of
|
|
27
|
+
# truth: backend/app/services/ontology_check.py, enforced by
|
|
24
28
|
# backend/app/schemas/ci.py (the server's 422 remains the backstop).
|
|
25
|
-
MAX_FILES =
|
|
26
|
-
MAX_TOTAL_BYTES =
|
|
29
|
+
MAX_FILES = 20_000
|
|
30
|
+
MAX_TOTAL_BYTES = 100 * 1024 * 1024
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
def is_ontology_file(rel_path: str) -> bool:
|
|
@@ -41,6 +45,42 @@ def is_ontology_file(rel_path: str) -> bool:
|
|
|
41
45
|
return rel_path.startswith("domains/") and rel_path.endswith("/README.md")
|
|
42
46
|
|
|
43
47
|
|
|
48
|
+
def git_file_states(directory: Path) -> Optional[tuple[set[str], set[str]]]:
|
|
49
|
+
"""(tracked, dirty) path sets for files under ``directory``, relative to it.
|
|
50
|
+
|
|
51
|
+
``tracked`` is every git-tracked file below the directory; ``dirty`` the
|
|
52
|
+
subset whose working-tree content differs from the index (modified or
|
|
53
|
+
missing). Returns ``None`` when the directory is not inside a git work tree
|
|
54
|
+
or git is unavailable — callers must then treat every file as
|
|
55
|
+
unrecoverable and refuse to delete it.
|
|
56
|
+
"""
|
|
57
|
+
# GIT_OPTIONAL_LOCKS=0: read-only queries must not take the index lock
|
|
58
|
+
# (and fail) when another git process is running.
|
|
59
|
+
env = {**os.environ, "GIT_OPTIONAL_LOCKS": "0"}
|
|
60
|
+
try:
|
|
61
|
+
tracked_proc = subprocess.run(
|
|
62
|
+
["git", "ls-files", "-z"],
|
|
63
|
+
cwd=directory,
|
|
64
|
+
env=env,
|
|
65
|
+
capture_output=True,
|
|
66
|
+
check=True,
|
|
67
|
+
text=True,
|
|
68
|
+
)
|
|
69
|
+
dirty_proc = subprocess.run(
|
|
70
|
+
["git", "ls-files", "-z", "--modified"],
|
|
71
|
+
cwd=directory,
|
|
72
|
+
env=env,
|
|
73
|
+
capture_output=True,
|
|
74
|
+
check=True,
|
|
75
|
+
text=True,
|
|
76
|
+
)
|
|
77
|
+
except (OSError, subprocess.CalledProcessError, UnicodeDecodeError):
|
|
78
|
+
return None
|
|
79
|
+
tracked = {p for p in tracked_proc.stdout.split("\0") if p}
|
|
80
|
+
dirty = {p for p in dirty_proc.stdout.split("\0") if p}
|
|
81
|
+
return tracked, dirty
|
|
82
|
+
|
|
83
|
+
|
|
44
84
|
def is_legacy_domain_file(rel_path: str) -> bool:
|
|
45
85
|
"""Whether a base-relative path is a legacy (pre-Markdown) domain file.
|
|
46
86
|
|
|
@@ -84,7 +124,7 @@ def read_project_id_from_dir(ontology_dir: Path) -> Optional[str]:
|
|
|
84
124
|
"""Return the ``project_id`` recorded in ``<ontology_dir>/project.yml``, or None."""
|
|
85
125
|
try:
|
|
86
126
|
text = (ontology_dir / "project.yml").read_text(encoding="utf-8")
|
|
87
|
-
except (OSError, UnicodeDecodeError)
|
|
127
|
+
except (OSError, UnicodeDecodeError):
|
|
88
128
|
return None
|
|
89
129
|
for line in text.splitlines():
|
|
90
130
|
match = _PROJECT_ID_LINE.match(line.strip())
|
|
@@ -171,7 +211,9 @@ def collect_tree(path: Path, base_path: str) -> "tuple[dict[str, str], str]":
|
|
|
171
211
|
typer.secho(f"No ontology files found under {ontology_dir}.", fg=typer.colors.RED, err=True)
|
|
172
212
|
raise typer.Exit(EXIT_USAGE)
|
|
173
213
|
|
|
174
|
-
|
|
214
|
+
# Count path bytes too, exactly like the server's _validate_tree_files —
|
|
215
|
+
# a tree accepted here must never come back as a server-side 422.
|
|
216
|
+
total_bytes = sum(len(rel.encode()) + len(content.encode()) for rel, content in files.items())
|
|
175
217
|
if len(files) > MAX_FILES or total_bytes > MAX_TOTAL_BYTES:
|
|
176
218
|
typer.secho(
|
|
177
219
|
f"Ontology tree too large: {len(files)} files / {total_bytes / (1024 * 1024):.1f} MB "
|
|
@@ -14,7 +14,10 @@ from cassis_cli.verify import verify
|
|
|
14
14
|
|
|
15
15
|
app = typer.Typer(
|
|
16
16
|
no_args_is_help=True,
|
|
17
|
-
help=
|
|
17
|
+
help=(
|
|
18
|
+
"Cassis CLI: validate, test and evaluate your ontology from your terminal, "
|
|
19
|
+
"then publish it. The same commands gate your pull requests in CI."
|
|
20
|
+
),
|
|
18
21
|
)
|
|
19
22
|
app.add_typer(ontology_app, name="ontology")
|
|
20
23
|
app.add_typer(eval_app, name="eval")
|
|
@@ -28,6 +28,7 @@ from cassis_cli.common import (
|
|
|
28
28
|
)
|
|
29
29
|
from cassis_cli.common import collect_files as _collect_files
|
|
30
30
|
from cassis_cli.common import collect_tree as _collect_tree
|
|
31
|
+
from cassis_cli.common import git_file_states as _git_file_states
|
|
31
32
|
from cassis_cli.common import is_legacy_domain_file as _is_legacy_domain_file
|
|
32
33
|
from cassis_cli.common import require_api_key as _require_api_key
|
|
33
34
|
from cassis_cli.common import resolve_project_id as _resolve_project_id
|
|
@@ -197,7 +198,11 @@ def pull(
|
|
|
197
198
|
prune: bool = typer.Option(
|
|
198
199
|
True,
|
|
199
200
|
"--prune/--no-prune",
|
|
200
|
-
help=
|
|
201
|
+
help=(
|
|
202
|
+
"Delete local ontology files that no longer exist in the project's ontology "
|
|
203
|
+
"(default: prune). Only files that are tracked and unmodified in git are "
|
|
204
|
+
"deleted; untracked or locally modified files are always kept and reported."
|
|
205
|
+
),
|
|
201
206
|
),
|
|
202
207
|
json_output: bool = typer.Option(False, "--json", help="Print a JSON summary of written/deleted files."),
|
|
203
208
|
) -> None:
|
|
@@ -205,7 +210,9 @@ def pull(
|
|
|
205
210
|
|
|
206
211
|
Writes the ontology tree under the export path (full sync: files are
|
|
207
212
|
overwritten and, unless --no-prune, stale local ontology files are deleted,
|
|
208
|
-
so the checkout ends up matching the project exactly).
|
|
213
|
+
so the checkout ends up matching the project exactly). Pruning never touches
|
|
214
|
+
files git could not restore: untracked or locally modified files are kept
|
|
215
|
+
and listed, and every deleted path is named. Review the changes with
|
|
209
216
|
git diff before committing. Exits 0 on success, 2 on usage errors, 3 on
|
|
210
217
|
transport/API errors.
|
|
211
218
|
"""
|
|
@@ -243,15 +250,38 @@ def pull(
|
|
|
243
250
|
written.append(rel)
|
|
244
251
|
|
|
245
252
|
deleted: list[str] = []
|
|
253
|
+
kept: list[dict[str, str]] = []
|
|
246
254
|
if prune and ontology_dir.is_dir():
|
|
247
255
|
local = _collect_files(ontology_dir)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
256
|
+
stale = sorted(set(local) - set(files))
|
|
257
|
+
if stale:
|
|
258
|
+
# Only delete what git can restore. An untracked or locally
|
|
259
|
+
# modified file is user work Cassis has never seen — pruning it
|
|
260
|
+
# would be unrecoverable data loss (#27).
|
|
261
|
+
states = _git_file_states(ontology_dir)
|
|
262
|
+
to_delete: list[str] = []
|
|
263
|
+
if states is None:
|
|
264
|
+
kept = [{"path": rel, "reason": "not in a git repository"} for rel in stale]
|
|
265
|
+
else:
|
|
266
|
+
tracked, dirty = states
|
|
267
|
+
for rel in stale:
|
|
268
|
+
if rel not in tracked:
|
|
269
|
+
kept.append({"path": rel, "reason": "untracked in git"})
|
|
270
|
+
elif rel in dirty:
|
|
271
|
+
kept.append({"path": rel, "reason": "locally modified"})
|
|
272
|
+
else:
|
|
273
|
+
to_delete.append(rel)
|
|
274
|
+
if to_delete and not json_output:
|
|
275
|
+
typer.echo(f"Deleting {len(to_delete)} stale ontology file(s):")
|
|
276
|
+
for rel in to_delete:
|
|
277
|
+
typer.echo(f" {base_path}/{rel}")
|
|
278
|
+
for rel in to_delete:
|
|
279
|
+
try:
|
|
280
|
+
(ontology_dir / rel).unlink()
|
|
281
|
+
except OSError as exc:
|
|
282
|
+
typer.secho(f"Cannot delete {ontology_dir / rel}: {exc}", fg=typer.colors.RED, err=True)
|
|
283
|
+
raise typer.Exit(EXIT_USAGE) from exc
|
|
284
|
+
deleted.append(rel)
|
|
255
285
|
|
|
256
286
|
# Managed modeling guide: refresh AGENTS.md so a repo-aware agent loads
|
|
257
287
|
# current Cassis doctrine. Not part of the ontology tree (YAML-only), so it
|
|
@@ -266,14 +296,31 @@ def pull(
|
|
|
266
296
|
_warn_newer_guide(base_path)
|
|
267
297
|
|
|
268
298
|
if json_output:
|
|
269
|
-
typer.echo(
|
|
299
|
+
typer.echo(
|
|
300
|
+
json.dumps(
|
|
301
|
+
{"written": written, "deleted": deleted, "kept": kept, "guide_written": guide_written},
|
|
302
|
+
indent=2,
|
|
303
|
+
)
|
|
304
|
+
)
|
|
270
305
|
else:
|
|
271
306
|
summary = f"✓ Pulled {len(written)} files into {ontology_dir}"
|
|
272
307
|
if deleted:
|
|
273
|
-
summary += f" ({len(deleted)} stale files deleted)"
|
|
308
|
+
summary += f" ({len(deleted)} stale files deleted, listed above)"
|
|
274
309
|
if guide_written:
|
|
275
310
|
summary += f"; wrote {base_path}/{GUIDE_FILENAME}"
|
|
276
311
|
typer.secho(f"{summary}.", fg=typer.colors.GREEN)
|
|
312
|
+
if kept:
|
|
313
|
+
typer.secho(
|
|
314
|
+
f"Kept {len(kept)} local file(s) not in the project ontology "
|
|
315
|
+
"(only files tracked and unmodified in git are pruned):",
|
|
316
|
+
fg=typer.colors.YELLOW,
|
|
317
|
+
)
|
|
318
|
+
for entry in kept:
|
|
319
|
+
typer.secho(f" {base_path}/{entry['path']} ({entry['reason']})", fg=typer.colors.YELLOW)
|
|
320
|
+
typer.secho(
|
|
321
|
+
" Commit them if they are intentional, or delete them manually.",
|
|
322
|
+
fg=typer.colors.YELLOW,
|
|
323
|
+
)
|
|
277
324
|
migrated = sum(1 for rel in deleted if _is_legacy_domain_file(rel))
|
|
278
325
|
if migrated:
|
|
279
326
|
typer.secho(
|
|
@@ -134,7 +134,7 @@ def ensure_gitignored(ontology_dir: Path) -> None:
|
|
|
134
134
|
gitignore = ontology_dir / ".gitignore"
|
|
135
135
|
try:
|
|
136
136
|
existing = gitignore.read_text(encoding="utf-8")
|
|
137
|
-
except (OSError, UnicodeDecodeError)
|
|
137
|
+
except (OSError, UnicodeDecodeError):
|
|
138
138
|
existing = ""
|
|
139
139
|
if SNAPSHOT_FILENAME in existing.splitlines():
|
|
140
140
|
return
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cassis-cli"
|
|
3
|
-
version = "1.5.
|
|
4
|
-
description = "
|
|
3
|
+
version = "1.5.1"
|
|
4
|
+
description = "Validate, test and evaluate your Cassis ontology from your terminal, then publish it"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "Apache-2.0" }
|
|
7
7
|
authors = [{ name = "Cassis", email = "tech.admin@getcassis.com" }]
|
|
8
|
-
keywords = ["cassis", "ontology", "ci", "text-to-sql"]
|
|
8
|
+
keywords = ["cassis", "ontology", "cli", "ci", "text-to-sql"]
|
|
9
9
|
classifiers = [
|
|
10
10
|
"License :: OSI Approved :: Apache Software License",
|
|
11
11
|
"Environment :: Console",
|
|
@@ -43,3 +43,10 @@ build-backend = "poetry.core.masonry.api"
|
|
|
43
43
|
|
|
44
44
|
[tool.pytest.ini_options]
|
|
45
45
|
testpaths = ["tests"]
|
|
46
|
+
|
|
47
|
+
[tool.black]
|
|
48
|
+
# The package ships for Python >=3.10 (see requires-python above): formatting
|
|
49
|
+
# must target the floor, or black under the monorepo's 3.14 rewrites syntax
|
|
50
|
+
# into 3.14-only forms (e.g. stripping parens from multi-exception `except`).
|
|
51
|
+
line-length = 120
|
|
52
|
+
target-version = ["py310"]
|
|
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
|