agentcad-cli 0.1.2__tar.gz → 0.1.3__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.
Files changed (63) hide show
  1. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/PKG-INFO +2 -9
  2. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/README.md +1 -8
  3. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/pyproject.toml +1 -1
  4. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/CLAUDE.md +0 -1
  5. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/cli.py +7 -23
  6. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/PKG-INFO +2 -9
  7. agentcad_cli-0.1.3/tests/test_cli.py +164 -0
  8. agentcad_cli-0.1.2/tests/test_cli.py +0 -138
  9. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/setup.cfg +0 -0
  10. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/__init__.py +0 -0
  11. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/__main__.py +0 -0
  12. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/__init__.py +0 -0
  13. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/model/README.md +0 -0
  14. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/model/design.json +0 -0
  15. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/model/params.json +0 -0
  16. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/model/part.py +0 -0
  17. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/cadproject.json +0 -0
  18. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/models/.gitkeep +0 -0
  19. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/references/build123d-guide.md +0 -0
  20. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/references/images/.gitkeep +0 -0
  21. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/references/notes.md +0 -0
  22. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/_templates/workspace/references/validation-strategy.md +0 -0
  23. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/checks/__init__.py +0 -0
  24. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/checks/mesh.py +0 -0
  25. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/checks/relations.py +0 -0
  26. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/checks/section.py +0 -0
  27. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/contract.py +0 -0
  28. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/geometry.py +0 -0
  29. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/inspect.py +0 -0
  30. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/jsonio.py +0 -0
  31. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/measure.py +0 -0
  32. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/payloads.py +0 -0
  33. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/precheck.py +0 -0
  34. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/probe.py +0 -0
  35. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/render.py +0 -0
  36. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/report.py +0 -0
  37. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/review.py +0 -0
  38. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/runner.py +0 -0
  39. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/section.py +0 -0
  40. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/stl.py +0 -0
  41. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/templates.py +0 -0
  42. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/validate.py +0 -0
  43. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad/workspace.py +0 -0
  44. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/SOURCES.txt +0 -0
  45. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/dependency_links.txt +0 -0
  46. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/entry_points.txt +0 -0
  47. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/requires.txt +0 -0
  48. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/src/agentcad_cli.egg-info/top_level.txt +0 -0
  49. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_checks_relations.py +0 -0
  50. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_checks_section.py +0 -0
  51. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_deliver.py +0 -0
  52. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_geometry.py +0 -0
  53. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_jsonio.py +0 -0
  54. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_precheck_review.py +0 -0
  55. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_probe.py +0 -0
  56. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_render.py +0 -0
  57. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_runner.py +0 -0
  58. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_section.py +0 -0
  59. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_stale.py +0 -0
  60. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_stl.py +0 -0
  61. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_validate.py +0 -0
  62. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_weak_check.py +0 -0
  63. {agentcad_cli-0.1.2 → agentcad_cli-0.1.3}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentcad-cli
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Agent-first CAD workflow runtime
5
5
  Author: AgentCAD contributors
6
6
  License-Expression: MIT
@@ -89,13 +89,6 @@ agentcad init --model demo
89
89
  Then open this directory in Claude Code / Cursor and continue from
90
90
  `models/demo/part.py`.
91
91
 
92
- `--project` is optional. Use it only when you run commands outside the
93
- workspace root, for example:
94
-
95
- ```bash
96
- agentcad init --model demo --project /tmp/agentcad-demo
97
- ```
98
-
99
92
  For local development:
100
93
 
101
94
  ```bash
@@ -106,7 +99,7 @@ uv run agentcad --help
106
99
  ## Quick example
107
100
 
108
101
  ```bash
109
- agentcad init --model bracket --project /tmp/my-cad-project
102
+ agentcad init --model bracket
110
103
  cd /tmp/my-cad-project
111
104
 
112
105
  # 1. Design-time: solve the contract before writing geometry
@@ -77,13 +77,6 @@ agentcad init --model demo
77
77
  Then open this directory in Claude Code / Cursor and continue from
78
78
  `models/demo/part.py`.
79
79
 
80
- `--project` is optional. Use it only when you run commands outside the
81
- workspace root, for example:
82
-
83
- ```bash
84
- agentcad init --model demo --project /tmp/agentcad-demo
85
- ```
86
-
87
80
  For local development:
88
81
 
89
82
  ```bash
@@ -94,7 +87,7 @@ uv run agentcad --help
94
87
  ## Quick example
95
88
 
96
89
  ```bash
97
- agentcad init --model bracket --project /tmp/my-cad-project
90
+ agentcad init --model bracket
98
91
  cd /tmp/my-cad-project
99
92
 
100
93
  # 1. Design-time: solve the contract before writing geometry
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentcad-cli"
7
- version = "0.1.2"
7
+ version = "0.1.3"
8
8
  description = "Agent-first CAD workflow runtime"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.13"
@@ -363,7 +363,6 @@ agentcad inspect <model> # Three-axis scan + section SVG
363
363
  agentcad report <model> # Generate Markdown validation report
364
364
  ```
365
365
 
366
- All commands accept `--project <dir>` (defaults to current directory).
367
366
  All commands output machine-readable JSON by default.
368
367
 
369
368
  ### agentcad probe — Discover expected values before writing design.json
@@ -39,27 +39,23 @@ def build_parser() -> argparse.ArgumentParser:
39
39
  parser.add_argument("--version", action="version", version=f"agentcad {__version__}")
40
40
  sub = parser.add_subparsers(dest="command", required=True)
41
41
 
42
- init = sub.add_parser("init", help="initialize a workspace (optionally create first model)")
43
- add_project_arg(init)
42
+ init = sub.add_parser("init", help="initialize a workspace and create first model")
43
+ init.add_argument("name", help="workspace name")
44
44
  init.add_argument("--model", default=None, help="create an initial model after workspace initialization")
45
45
  init.add_argument("--force", action="store_true")
46
46
 
47
47
  new = sub.add_parser("new", help="create a new model (auto-initializes workspace)")
48
- add_project_arg(new)
49
48
  new.add_argument("model")
50
49
  new.add_argument("--force", action="store_true")
51
50
 
52
51
  build = sub.add_parser("build", help="build a model and export STEP/STL")
53
- add_project_arg(build)
54
52
  build.add_argument("model")
55
53
  build.add_argument("--force", action="store_true", help="force rebuild even if source is unchanged")
56
54
 
57
55
  measure = sub.add_parser("measure", help="measure generated STL geometry")
58
- add_project_arg(measure)
59
56
  measure.add_argument("model")
60
57
 
61
58
  render = sub.add_parser("render", help="render an SVG preview from STL")
62
- add_project_arg(render)
63
59
  render.add_argument("model")
64
60
  render.add_argument("--view", choices=["iso", "front", "top", "side", "back"], default="iso")
65
61
  render.add_argument(
@@ -75,7 +71,6 @@ def build_parser() -> argparse.ArgumentParser:
75
71
  help="render a Y cross-section SVG (XZ plane) at this position (mm)")
76
72
 
77
73
  validate = sub.add_parser("validate", help="build, measure, render, and validate a model")
78
- add_project_arg(validate)
79
74
  validate.add_argument("model")
80
75
  validate.add_argument("--view", choices=["iso", "front", "top", "side", "back"], default="iso")
81
76
  validate.add_argument(
@@ -85,12 +80,10 @@ def build_parser() -> argparse.ArgumentParser:
85
80
  )
86
81
 
87
82
  deliver = sub.add_parser("deliver", help="write a delivery manifest")
88
- add_project_arg(deliver)
89
83
  deliver.add_argument("model")
90
84
  deliver.add_argument("--no-validate", action="store_true")
91
85
 
92
86
  probe = sub.add_parser("probe", help="probe STL cross-section to get geometry values for design.json")
93
- add_project_arg(probe)
94
87
  probe.add_argument("model")
95
88
  probe.add_argument("--z", default=None, help="Z height(s) to probe, comma-separated")
96
89
  probe.add_argument("--x", default=None, help="X position(s) to probe (YZ plane), comma-separated")
@@ -104,24 +97,19 @@ def build_parser() -> argparse.ArgumentParser:
104
97
  probe.add_argument("--samples", type=int, default=20, help="number of scan samples (default: 20)")
105
98
 
106
99
  report = sub.add_parser("report", help="generate a human-readable Markdown validation report")
107
- add_project_arg(report)
108
100
  report.add_argument("model")
109
101
 
110
102
  inspect = sub.add_parser("inspect", help="three-axis scan + section SVGs + suggested probe commands")
111
- add_project_arg(inspect)
112
103
  inspect.add_argument("model")
113
104
  inspect.add_argument("--samples", type=int, default=20, help="scan samples per axis (default: 20)")
114
105
 
115
106
  precheck = sub.add_parser("precheck", help="solve design.json statically (before writing part.py)")
116
- add_project_arg(precheck)
117
107
  precheck.add_argument("model")
118
108
 
119
109
  review = sub.add_parser("review", help="pre-delivery checklist + pairwise relations matrix")
120
- add_project_arg(review)
121
110
  review.add_argument("model")
122
111
 
123
112
  sync = sub.add_parser("sync", help="update workspace scaffold files from templates")
124
- add_project_arg(sync)
125
113
  sync.add_argument("--dry-run", action="store_true", help="preview template updates without writing files")
126
114
  sync.add_argument("--only", default=None, help="sync only one template path prefix (e.g. references/)")
127
115
  sync.add_argument("--prune-deprecated", action="store_true", help="remove deprecated scaffold paths like skills/")
@@ -129,13 +117,9 @@ def build_parser() -> argparse.ArgumentParser:
129
117
  return parser
130
118
 
131
119
 
132
- def add_project_arg(parser: argparse.ArgumentParser) -> None:
133
- parser.add_argument("--project", default=".", help="project directory, defaults to current directory")
134
-
135
-
136
120
  def _resolve_project(args: argparse.Namespace) -> Path:
137
121
  """Find existing project, or auto-init when creating a new model."""
138
- project = Path(getattr(args, "project", "."))
122
+ project = Path(".")
139
123
  try:
140
124
  return find_project(project)
141
125
  except FileNotFoundError:
@@ -153,11 +137,11 @@ def _resolve_project(args: argparse.Namespace) -> Path:
153
137
 
154
138
  def dispatch(args: argparse.Namespace) -> dict:
155
139
  if args.command == "init":
156
- target = Path(getattr(args, "project", ".")).expanduser().resolve()
140
+ workspace_name = str(getattr(args, "name"))
141
+ model_name = str(getattr(args, "model", "") or workspace_name)
142
+ target = (Path.cwd() / workspace_name).resolve()
143
+
157
144
  init_payload = init_workspace(target, force=getattr(args, "force", False))
158
- model_name = getattr(args, "model", None)
159
- if not model_name:
160
- return init_payload
161
145
  model_payload = new_model(target, model_name, force=getattr(args, "force", False))
162
146
  return {
163
147
  "ok": bool(init_payload.get("ok")) and bool(model_payload.get("ok")),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentcad-cli
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: Agent-first CAD workflow runtime
5
5
  Author: AgentCAD contributors
6
6
  License-Expression: MIT
@@ -89,13 +89,6 @@ agentcad init --model demo
89
89
  Then open this directory in Claude Code / Cursor and continue from
90
90
  `models/demo/part.py`.
91
91
 
92
- `--project` is optional. Use it only when you run commands outside the
93
- workspace root, for example:
94
-
95
- ```bash
96
- agentcad init --model demo --project /tmp/agentcad-demo
97
- ```
98
-
99
92
  For local development:
100
93
 
101
94
  ```bash
@@ -106,7 +99,7 @@ uv run agentcad --help
106
99
  ## Quick example
107
100
 
108
101
  ```bash
109
- agentcad init --model bracket --project /tmp/my-cad-project
102
+ agentcad init --model bracket
110
103
  cd /tmp/my-cad-project
111
104
 
112
105
  # 1. Design-time: solve the contract before writing geometry
@@ -0,0 +1,164 @@
1
+ """Tests for CLI dispatch and auto-init behavior."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ from pathlib import Path
6
+
7
+ import agentcad.cli as cli_mod
8
+ from agentcad.cli import main
9
+
10
+
11
+ def test_new_auto_init(tmp_path, monkeypatch):
12
+ monkeypatch.chdir(tmp_path)
13
+ result = main(["new", "bracket"])
14
+ assert result == 0
15
+ assert (tmp_path / "bracket" / "cadproject.json").exists()
16
+ assert (tmp_path / "bracket" / "CLAUDE.md").exists()
17
+ assert (tmp_path / "bracket" / "models" / "bracket" / "part.py").exists()
18
+
19
+
20
+ def test_init_creates_workspace_and_optional_model(tmp_path, monkeypatch):
21
+ monkeypatch.chdir(tmp_path)
22
+ result = main(["init", "initproj", "--model", "demo"])
23
+ assert result == 0
24
+ project = tmp_path / "initproj"
25
+ assert (project / "cadproject.json").exists()
26
+ assert (project / "models" / "demo" / "part.py").exists()
27
+
28
+
29
+ def test_init_default_creates_project_dir_named_after_model(tmp_path, monkeypatch):
30
+ monkeypatch.chdir(tmp_path)
31
+ result = main(["init", "fan8025"])
32
+ assert result == 0
33
+ assert (tmp_path / "fan8025" / "cadproject.json").exists()
34
+ assert (tmp_path / "fan8025" / "models" / "fan8025" / "part.py").exists()
35
+
36
+
37
+ def test_init_model_overrides_workspace_name_for_model(tmp_path, monkeypatch):
38
+ monkeypatch.chdir(tmp_path)
39
+ result = main(["init", "fan8025", "--model", "demo"])
40
+ assert result == 0
41
+ assert (tmp_path / "fan8025" / "cadproject.json").exists()
42
+ assert (tmp_path / "fan8025" / "models" / "demo" / "part.py").exists()
43
+
44
+
45
+ def test_new_default_creates_project_dir_named_after_model(tmp_path, monkeypatch):
46
+ monkeypatch.chdir(tmp_path)
47
+ result = main(["new", "fan8025"])
48
+ assert result == 0
49
+ assert (tmp_path / "fan8025" / "cadproject.json").exists()
50
+ assert (tmp_path / "fan8025" / "models" / "fan8025" / "part.py").exists()
51
+
52
+
53
+ def test_new_duplicate_fails(tmp_path, monkeypatch):
54
+ monkeypatch.chdir(tmp_path)
55
+ main(["new", "bracket"])
56
+ result = main(["new", "bracket"])
57
+ assert result == 1
58
+
59
+
60
+ def test_new_duplicate_force(tmp_path, monkeypatch):
61
+ monkeypatch.chdir(tmp_path)
62
+ main(["new", "bracket"])
63
+ result = main(["new", "bracket", "--force"])
64
+ assert result == 0
65
+
66
+
67
+ def test_build_missing_model(tmp_path, monkeypatch):
68
+ monkeypatch.chdir(tmp_path)
69
+ main(["new", "bracket"])
70
+ result = main(["build", "nonexistent"])
71
+ assert result == 1
72
+
73
+
74
+ def test_validate_default_model(tmp_path, monkeypatch):
75
+ """Validate the default scaffold model (should build and validate ok)."""
76
+ monkeypatch.chdir(tmp_path)
77
+ main(["new", "test_block"])
78
+ monkeypatch.chdir(tmp_path / "test_block")
79
+ result = main(["validate", "test_block"])
80
+ assert result == 0
81
+
82
+
83
+ def test_version():
84
+ import pytest
85
+ with pytest.raises(SystemExit) as exc_info:
86
+ main(["--version"])
87
+ assert exc_info.value.code == 0
88
+
89
+
90
+ def test_sync_updates_workspace(tmp_path, monkeypatch):
91
+ monkeypatch.chdir(tmp_path)
92
+ main(["new", "bracket"])
93
+ project = tmp_path / "bracket"
94
+ monkeypatch.chdir(project)
95
+
96
+ # Modify a scaffold file
97
+ claude = project / "CLAUDE.md"
98
+ original = claude.read_text()
99
+ claude.write_text("OLD CONTENT")
100
+
101
+ # Sync should overwrite it
102
+ result = main(["sync"])
103
+ assert result == 0
104
+ assert claude.read_text() == original
105
+
106
+ # Model files should be untouched
107
+ assert (project / "models" / "bracket" / "part.py").exists()
108
+
109
+
110
+ def test_sync_not_a_workspace(tmp_path, monkeypatch):
111
+ monkeypatch.chdir(tmp_path)
112
+ result = main(["sync"])
113
+ assert result == 1
114
+
115
+
116
+ def test_sync_dry_run_does_not_overwrite(tmp_path, monkeypatch):
117
+ monkeypatch.chdir(tmp_path)
118
+ main(["new", "bracket"])
119
+ project = tmp_path / "bracket"
120
+ monkeypatch.chdir(project)
121
+ claude = project / "CLAUDE.md"
122
+ claude.write_text("LOCAL", encoding="utf-8")
123
+
124
+ result = main(["sync", "--dry-run"])
125
+ assert result == 0
126
+ assert claude.read_text(encoding="utf-8") == "LOCAL"
127
+
128
+
129
+ def test_probe_cx_cy_alias(monkeypatch, tmp_path):
130
+ monkeypatch.chdir(tmp_path)
131
+ main(["new", "bracket"])
132
+ monkeypatch.chdir(tmp_path / "bracket")
133
+ captured = {}
134
+
135
+ def fake_probe(project_path, model_name, z_values=None, x_values=None, y_values=None, center=None, region=None):
136
+ captured["center"] = center
137
+ return {"ok": True, "stage": "probe", "model": model_name}
138
+
139
+ monkeypatch.setattr(cli_mod, "probe_model", fake_probe)
140
+ result = main([
141
+ "probe", "bracket",
142
+ "--z", "1.0", "--cx", "-10.5", "--cy", "4.25",
143
+ ])
144
+ assert result == 0
145
+ assert captured["center"] == (-10.5, 4.25)
146
+
147
+
148
+ def test_probe_center_and_cx_merge(monkeypatch, tmp_path):
149
+ monkeypatch.chdir(tmp_path)
150
+ main(["new", "bracket"])
151
+ monkeypatch.chdir(tmp_path / "bracket")
152
+ captured = {}
153
+
154
+ def fake_probe(project_path, model_name, z_values=None, x_values=None, y_values=None, center=None, region=None):
155
+ captured["center"] = center
156
+ return {"ok": True, "stage": "probe", "model": model_name}
157
+
158
+ monkeypatch.setattr(cli_mod, "probe_model", fake_probe)
159
+ result = main([
160
+ "probe", "bracket",
161
+ "--z", "1.0", "--center=1,2", "--cx", "3",
162
+ ])
163
+ assert result == 0
164
+ assert captured["center"] == (3.0, 2.0)
@@ -1,138 +0,0 @@
1
- """Tests for CLI dispatch and auto-init behavior."""
2
- from __future__ import annotations
3
-
4
- import json
5
- from pathlib import Path
6
-
7
- import agentcad.cli as cli_mod
8
- from agentcad.cli import main
9
-
10
-
11
- def test_new_auto_init(tmp_path):
12
- result = main(["new", "--project", str(tmp_path / "newproject"), "bracket"])
13
- assert result == 0
14
- assert (tmp_path / "newproject" / "cadproject.json").exists()
15
- assert (tmp_path / "newproject" / "CLAUDE.md").exists()
16
- assert (tmp_path / "newproject" / "models" / "bracket" / "part.py").exists()
17
-
18
-
19
- def test_init_creates_workspace_and_optional_model(tmp_path):
20
- project = tmp_path / "initproj"
21
- result = main(["init", "--project", str(project), "--model", "demo"])
22
- assert result == 0
23
- assert (project / "cadproject.json").exists()
24
- assert (project / "models" / "demo" / "part.py").exists()
25
-
26
-
27
- def test_new_default_creates_project_dir_named_after_model(tmp_path, monkeypatch):
28
- monkeypatch.chdir(tmp_path)
29
- result = main(["new", "fan8025"])
30
- assert result == 0
31
- assert (tmp_path / "fan8025" / "cadproject.json").exists()
32
- assert (tmp_path / "fan8025" / "models" / "fan8025" / "part.py").exists()
33
-
34
-
35
- def test_new_duplicate_fails(tmp_path):
36
- project = tmp_path / "proj"
37
- main(["new", "--project", str(project), "bracket"])
38
- result = main(["new", "--project", str(project), "bracket"])
39
- assert result == 1
40
-
41
-
42
- def test_new_duplicate_force(tmp_path):
43
- project = tmp_path / "proj"
44
- main(["new", "--project", str(project), "bracket"])
45
- result = main(["new", "--project", str(project), "bracket", "--force"])
46
- assert result == 0
47
-
48
-
49
- def test_build_missing_model(tmp_path):
50
- project = tmp_path / "proj"
51
- main(["new", "--project", str(project), "bracket"])
52
- result = main(["build", "--project", str(project), "nonexistent"])
53
- assert result == 1
54
-
55
-
56
- def test_validate_default_model(tmp_path):
57
- """Validate the default scaffold model (should build and validate ok)."""
58
- project = tmp_path / "proj"
59
- main(["new", "--project", str(project), "test_block"])
60
- result = main(["validate", "--project", str(project), "test_block"])
61
- assert result == 0
62
-
63
-
64
- def test_version():
65
- import pytest
66
- with pytest.raises(SystemExit) as exc_info:
67
- main(["--version"])
68
- assert exc_info.value.code == 0
69
-
70
-
71
- def test_sync_updates_workspace(tmp_path):
72
- project = tmp_path / "proj"
73
- main(["new", "--project", str(project), "bracket"])
74
-
75
- # Modify a scaffold file
76
- claude = project / "CLAUDE.md"
77
- original = claude.read_text()
78
- claude.write_text("OLD CONTENT")
79
-
80
- # Sync should overwrite it
81
- result = main(["sync", "--project", str(project)])
82
- assert result == 0
83
- assert claude.read_text() == original
84
-
85
- # Model files should be untouched
86
- assert (project / "models" / "bracket" / "part.py").exists()
87
-
88
-
89
- def test_sync_not_a_workspace(tmp_path):
90
- result = main(["sync", "--project", str(tmp_path)])
91
- assert result == 1
92
-
93
-
94
- def test_sync_dry_run_does_not_overwrite(tmp_path):
95
- project = tmp_path / "proj"
96
- main(["new", "--project", str(project), "bracket"])
97
- claude = project / "CLAUDE.md"
98
- claude.write_text("LOCAL", encoding="utf-8")
99
-
100
- result = main(["sync", "--project", str(project), "--dry-run"])
101
- assert result == 0
102
- assert claude.read_text(encoding="utf-8") == "LOCAL"
103
-
104
-
105
- def test_probe_cx_cy_alias(monkeypatch, tmp_path):
106
- project = tmp_path / "proj"
107
- main(["new", "--project", str(project), "bracket"])
108
- captured = {}
109
-
110
- def fake_probe(project_path, model_name, z_values=None, x_values=None, y_values=None, center=None, region=None):
111
- captured["center"] = center
112
- return {"ok": True, "stage": "probe", "model": model_name}
113
-
114
- monkeypatch.setattr(cli_mod, "probe_model", fake_probe)
115
- result = main([
116
- "probe", "--project", str(project), "bracket",
117
- "--z", "1.0", "--cx", "-10.5", "--cy", "4.25",
118
- ])
119
- assert result == 0
120
- assert captured["center"] == (-10.5, 4.25)
121
-
122
-
123
- def test_probe_center_and_cx_merge(monkeypatch, tmp_path):
124
- project = tmp_path / "proj"
125
- main(["new", "--project", str(project), "bracket"])
126
- captured = {}
127
-
128
- def fake_probe(project_path, model_name, z_values=None, x_values=None, y_values=None, center=None, region=None):
129
- captured["center"] = center
130
- return {"ok": True, "stage": "probe", "model": model_name}
131
-
132
- monkeypatch.setattr(cli_mod, "probe_model", fake_probe)
133
- result = main([
134
- "probe", "--project", str(project), "bracket",
135
- "--z", "1.0", "--center=1,2", "--cx", "3",
136
- ])
137
- assert result == 0
138
- assert captured["center"] == (3.0, 2.0)
File without changes