Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,33 @@ jobs:
)
print("both client trees ship:", ", ".join(artifacts))
PY
# The sdist manifest is an allowlist, so `/skills` shipping is a single
# line someone can delete without noticing -- and the wheel boundary is
# the only thing keeping the skills OUT of an installed package. Assert
# both directions here, next to the assertions that already guard the
# test suite and the generated sync tree.
- run: |
python - <<'PY'
import pathlib, tarfile, zipfile
wheel = next(pathlib.Path("dist").glob("*.whl"))
sdist = next(pathlib.Path("dist").glob("*.tar.gz"))
sdist_names = tarfile.open(sdist).getnames()
wheel_names = zipfile.ZipFile(wheel).namelist()
assert any(n.endswith("skills/README.md") for n in sdist_names), (
"skills/ is missing from the sdist -- is '/skills' still in the "
"[tool.hatch.build.targets.sdist] include allowlist?"
)
# The index alone shipping would satisfy the assertion above while
# every skill it indexes was missing, so count them: one SKILL.md
# per skill directory on disk, no more and no fewer.
skills_dir = pathlib.Path("skills")
on_disk = sorted(p.name for p in skills_dir.iterdir() if p.is_dir())
shipped = sorted(n for n in sdist_names if n.endswith("/SKILL.md"))
assert len(shipped) == len(on_disk), (
f"the sdist carries {len(shipped)} SKILL.md files but skills/ has "
f"{len(on_disk)} directories on disk ({on_disk}); shipped: {shipped}"
)
leaked = [n for n in wheel_names if "skills/" in n]
assert not leaked, f"skills/ leaked into the wheel: {leaked}"
print(f"skills/ ships in the sdist only ({len(shipped)} SKILL.md)")
PY
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ a deprecation policy will follow the 1.0 release.

### Added

- `skills/`: eight Agent Skills covering client setup, search syntax, tickets,
ticket actions, documents, assets, the directory and reporting/context, with
an index in `skills/README.md`. Shipped in the source distribution, not in
the wheel.
- `scripts/tests/test_skills_contract.py`: checks every skill's frontmatter and
code snippets against the real public API, so a rename fails CI.
- Public `filters.py`: `ev_equals_filter`, `ev_in_filter`, `escape_ev_value`, and
`is_safe_ev_value` for building EasyVista `search` expressions safely.
- `Request` now declares fields that were previously reachable only as untyped
Expand Down
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,14 @@ Never commit an instance host, account id, or token — see the note below.
example a model asserted only via the resource and client tests that build
it) does not need its own near-empty test file. Check coverage before adding
one.

## Agent skills

A change to the public API must update the affected `skills/*/SKILL.md`, and a
release that bumps `__version__` must bump every skill's `metadata.version`.
`scripts/tests/test_skills_contract.py` is the gate: it parses every `SKILL.md`
and asserts each symbol, client method, keyword argument and model field the
skill names still exists on the public surface. Run it with
`pytest scripts/tests/test_skills_contract.py --no-cov` (see the coverage note
above — a single-file run without `--no-cov` fails the 95% gate even when
every test passes).
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ Set `EASYVISTA_URL` (or `EASYVISTA_SERVER`), `EASYVISTA_ACCOUNT`, and either
`EASYVISTA_TOKEN` / `EASYVISTA_TOKEN_FILE` or `EASYVISTA_LOGIN` + `EASYVISTA_PASSWORD`,
then call `EasyvistaConfig.from_env()`.

## Agent skills

`skills/` holds Agent Skills for driving this client from an AI agent — one per
domain (client setup, search syntax, tickets, actions, documents, assets,
directory, reporting and context). Each is a directory with a `SKILL.md`
following the Agent Skills specification; see [skills/README.md](skills/README.md)
for the index.

They are source-tree material: present in the git repository and the source
distribution, absent from the installed wheel.

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup and quality checks.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ packages = ["easyvista_python_client"]
include = [
"/easyvista_python_client",
"/docs",
"/skills",
"/CHANGELOG.md",
"/CONTRIBUTING.md",
"/LICENSE",
Expand Down
Loading
Loading