veris-cli 2.22.2__tar.gz → 2.23.0__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 (30) hide show
  1. {veris_cli-2.22.2 → veris_cli-2.23.0}/PKG-INFO +143 -7
  2. {veris_cli-2.22.2 → veris_cli-2.23.0}/README.md +141 -6
  3. {veris_cli-2.22.2 → veris_cli-2.23.0}/pyproject.toml +2 -1
  4. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/build_context.py +18 -9
  5. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/_helpers.py +119 -14
  6. veris_cli-2.23.0/src/veris_cli/commands/env.py +972 -0
  7. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/run.py +6 -3
  8. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/simulations.py +0 -1
  9. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/config.py +115 -10
  10. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/output.py +8 -8
  11. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/prompts.py +3 -2
  12. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/searchable_checkbox.py +0 -8
  13. veris_cli-2.23.0/src/veris_cli/templates.py +227 -0
  14. veris_cli-2.23.0/src/veris_cli/veris_yaml.py +325 -0
  15. veris_cli-2.22.2/src/veris_cli/commands/env.py +0 -558
  16. veris_cli-2.22.2/src/veris_cli/templates.py +0 -230
  17. {veris_cli-2.22.2 → veris_cli-2.23.0}/.gitignore +0 -0
  18. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/__init__.py +0 -0
  19. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/api.py +0 -0
  20. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/cli.py +0 -0
  21. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/__init__.py +0 -0
  22. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/auth.py +0 -0
  23. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/evaluations.py +0 -0
  24. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/profile.py +0 -0
  25. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/reports.py +0 -0
  26. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/commands/scenarios.py +0 -0
  27. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/run_output.py +0 -0
  28. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/scripts/__init__.py +0 -0
  29. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/scripts/docker_build.sh +0 -0
  30. {veris_cli-2.22.2 → veris_cli-2.23.0}/src/veris_cli/scripts/docker_push.sh +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: veris-cli
3
- Version: 2.22.2
3
+ Version: 2.23.0
4
4
  Summary: CLI to connect local agents to the Veris backend
5
5
  Project-URL: Homepage, https://github.com/veris-ai/veris-cli
6
6
  Project-URL: Bug Tracker, https://github.com/veris-ai/veris-cli/issues
@@ -9,6 +9,7 @@ Requires-Python: >=3.11
9
9
  Requires-Dist: click>=8.1.7
10
10
  Requires-Dist: httpx>=0.27.0
11
11
  Requires-Dist: pathspec>=0.12.0
12
+ Requires-Dist: pydantic>=2.6
12
13
  Requires-Dist: pyyaml>=6.0.1
13
14
  Requires-Dist: questionary>=2.0.0
14
15
  Requires-Dist: rich>=13.7.0
@@ -58,7 +59,7 @@ This saves your credentials to `~/.veris/config.yaml`.
58
59
  ### 2. Create an Environment
59
60
 
60
61
  ```bash
61
- veris env create --name "my-agent"
62
+ veris env create --name my-agent-env --agent-name "My Agent"
62
63
  ```
63
64
 
64
65
  This scaffolds a `.veris/` directory and registers your environment on Veris:
@@ -66,6 +67,8 @@ This scaffolds a `.veris/` directory and registers your environment on Veris:
66
67
  - **`veris.yaml`** — Simulation configuration (services, persona, agent settings)
67
68
  - **`.dockerignore`** — Files excluded from image build
68
69
 
70
+ The `--name` you pass is the agent's display name. The CLI slugifies it to create a target/env name: `"My Agent"` becomes `my-agent-env`. This name is used as the top-level key in `veris.yaml` and as the backend environment name.
71
+
69
72
  ### 3. Configure Your Agent
70
73
 
71
74
  Edit `.veris/Dockerfile.sandbox` and `.veris/veris.yaml` to match your agent. Set secrets:
@@ -80,6 +83,8 @@ veris env vars set OPENAI_API_KEY=sk-your-key --secret
80
83
  veris env push
81
84
  ```
82
85
 
86
+ When only one target is defined, the CLI uses it automatically — no flags needed.
87
+
83
88
  ### 5. Generate Scenarios
84
89
 
85
90
  ```bash
@@ -134,6 +139,7 @@ veris run # Full pipeline: simulations → evaluations
134
139
  --scenario-set-id ID # Scenario set (prompts if omitted)
135
140
  --grader-id ID # Grader (prompts if omitted)
136
141
  --env-id ID # Environment (uses config if omitted)
142
+ --target NAME # Target (auto-detected if only one)
137
143
  --image-tag TAG # Image tag (default: latest)
138
144
  --simulation-timeout N # Timeout per sim in seconds
139
145
  --report # Generate HTML report after evaluation
@@ -142,18 +148,30 @@ veris run # Full pipeline: simulations → evaluations
142
148
  ### Environment (`veris env`)
143
149
 
144
150
  ```bash
145
- veris env create --name NAME # Scaffold .veris/ + register environment
151
+ veris env create --name NAME # Scaffold .veris/ + register environment (NAME = env/target name)
152
+ --agent-name NAME # Agent display name (stored in veris.yaml agent.name)
146
153
  veris env push [--tag TAG] # Build and push image to Veris
154
+ --target NAME # Target to push (auto-detected if only one)
147
155
  veris env list # List environments
148
156
  veris env delete ENV_ID # Delete environment
149
157
  ```
150
158
 
159
+ ### Active Target (`veris env targets`)
160
+
161
+ ```bash
162
+ veris env targets get # Show the active target
163
+ veris env targets set NAME # Set the active target for this project
164
+ veris env targets list # List configured targets (from veris.yaml)
165
+ veris env targets clear # Clear the active target
166
+ ```
167
+
151
168
  ### Environment Config (`veris env config`)
152
169
 
153
170
  ```bash
154
171
  veris env config push # Upload veris.yaml to backend (no image build)
155
172
  --file PATH # Custom veris.yaml path (default: .veris/veris.yaml)
156
173
  --env-id ID # Override environment
174
+ --target NAME # Target to upload
157
175
  ```
158
176
 
159
177
  ### Environment Variables (`veris env vars`)
@@ -162,8 +180,11 @@ veris env config push # Upload veris.yaml to backend (no image buil
162
180
  veris env vars set K=V [K=V ...] # Set variables
163
181
  --secret # Mark as secret
164
182
  --env-id ID # Override environment
183
+ --target NAME # Target to set variables for
165
184
  veris env vars list # List variables
185
+ --target NAME
166
186
  veris env vars rm KEY # Remove a variable
187
+ --target NAME
167
188
  ```
168
189
 
169
190
  ### Scenarios (`veris scenarios`)
@@ -299,17 +320,132 @@ profiles:
299
320
 
300
321
  ### `.veris/config.yaml`
301
322
 
302
- Project config (created by `veris env create`):
323
+ Project config (created by `veris env create`). Each target's `environment_id` is stored under the profile:
303
324
  ```yaml
325
+ active_target: my-cool-agent-env
304
326
  profiles:
305
327
  default:
306
- environment_id: env_abc123
307
- environment_name: my-agent
328
+ targets:
329
+ my-cool-agent-env:
330
+ environment_id: env_abc123
331
+ environment_name: my-cool-agent-env
332
+ ```
333
+
334
+ ### `.veris/veris.yaml`
335
+
336
+ Simulation configuration. Every target is a top-level key — the target name is the backend environment name:
337
+ ```yaml
338
+ version: "1.0"
339
+
340
+ my-cool-agent-env:
341
+ services:
342
+ - name: postgres
343
+ config:
344
+ SCHEMA_PATH: /agent/schemas/schema.sql
345
+ - name: slack
346
+ dns_aliases:
347
+ - slack.com
348
+ persona:
349
+ modality:
350
+ type: http
351
+ url: http://localhost:8008/chat
352
+ agent:
353
+ name: My Cool Agent
354
+ code_path: /agent
355
+ entry_point: uv run app
356
+ port: 8008
357
+ environment:
358
+ DATABASE_URL: postgresql://postgres:postgres@localhost:5432/SIMULATION_ID
359
+ ```
360
+
361
+ When only one target is defined, all commands auto-select it.
362
+
363
+ ## Multiple Targets (Monorepo)
364
+
365
+ A single repo can manage multiple agents/environments. Each `veris env create` adds a target whose name **is** the backend environment name.
366
+
367
+ ### Creating targets
368
+
369
+ ```bash
370
+ # First agent
371
+ veris env create --name my-cool-agent-env --agent-name "My Cool Agent"
372
+
373
+ # Second agent — appended to the same veris.yaml
374
+ veris env create --name customer-support-env --agent-name "Customer Support"
375
+ ```
376
+
377
+ After two creates, `.veris/veris.yaml` looks like:
378
+ ```yaml
379
+ version: "1.0"
380
+
381
+ my-cool-agent-env:
382
+ services: [...]
383
+ persona: ...
384
+ agent:
385
+ name: My Cool Agent
386
+ ...
387
+
388
+ customer-support-env:
389
+ services: [...]
390
+ persona: ...
391
+ agent:
392
+ name: Customer Support
393
+ ...
394
+ ```
395
+
396
+ ### Pushing and running
397
+
398
+ ```bash
399
+ # With one target — auto-detected, no flag needed
400
+ veris env push
401
+
402
+ # With multiple targets — specify which one
403
+ veris env push --target customer-support-env
404
+ veris run --target customer-support-env
405
+ veris env vars set API_KEY=sk-... --target customer-support-env --secret
406
+ ```
407
+
408
+ ### Setting an active target
409
+
410
+ Avoid typing `--target` on every command:
411
+ ```bash
412
+ veris env targets set customer-support-env
413
+ veris env push # pushes customer-support-env
414
+ veris run # runs customer-support-env
415
+ veris env targets get # shows: customer-support-env
416
+ veris env targets list # lists all targets from veris.yaml
417
+ veris env targets clear # clears the active target
418
+ ```
419
+
420
+ ### Target resolution
421
+
422
+ | Priority | Source |
423
+ |----------|--------|
424
+ | 1 | `--target` flag |
425
+ | 2 | `active_target` in `.veris/config.yaml` |
426
+ | 3 | Auto-detect: sole target in `veris.yaml` |
427
+ | 4 | Error if ambiguous |
428
+
429
+ ### Per-target Dockerfile
430
+
431
+ Targets can override the default Dockerfile:
432
+ ```yaml
433
+ customer-support-env:
434
+ dockerfile: .veris/Dockerfile.support
435
+ agent:
436
+ name: Customer Support
437
+ ...
308
438
  ```
309
439
 
440
+ Falls back to `.veris/Dockerfile.sandbox` when not specified.
441
+
442
+ ### Cross-profile behavior
443
+
444
+ When you switch profiles (e.g. from `dev` to `staging`) and push, the CLI detects that the target exists on another profile and offers to create it on the current one.
445
+
310
446
  ## Profiles
311
447
 
312
- The CLI supports named profiles for managing multiple environments. Each profile stores its own API key, backend URL, console URL, organization, and environment ID.
448
+ The CLI supports named profiles for managing multiple backend accounts. Each profile stores its own API key, backend URL, console URL, organization, and environment IDs.
313
449
 
314
450
  ```bash
315
451
  # Login to a named profile (creates it if new, sets it active)
@@ -36,7 +36,7 @@ This saves your credentials to `~/.veris/config.yaml`.
36
36
  ### 2. Create an Environment
37
37
 
38
38
  ```bash
39
- veris env create --name "my-agent"
39
+ veris env create --name my-agent-env --agent-name "My Agent"
40
40
  ```
41
41
 
42
42
  This scaffolds a `.veris/` directory and registers your environment on Veris:
@@ -44,6 +44,8 @@ This scaffolds a `.veris/` directory and registers your environment on Veris:
44
44
  - **`veris.yaml`** — Simulation configuration (services, persona, agent settings)
45
45
  - **`.dockerignore`** — Files excluded from image build
46
46
 
47
+ The `--name` you pass is the agent's display name. The CLI slugifies it to create a target/env name: `"My Agent"` becomes `my-agent-env`. This name is used as the top-level key in `veris.yaml` and as the backend environment name.
48
+
47
49
  ### 3. Configure Your Agent
48
50
 
49
51
  Edit `.veris/Dockerfile.sandbox` and `.veris/veris.yaml` to match your agent. Set secrets:
@@ -58,6 +60,8 @@ veris env vars set OPENAI_API_KEY=sk-your-key --secret
58
60
  veris env push
59
61
  ```
60
62
 
63
+ When only one target is defined, the CLI uses it automatically — no flags needed.
64
+
61
65
  ### 5. Generate Scenarios
62
66
 
63
67
  ```bash
@@ -112,6 +116,7 @@ veris run # Full pipeline: simulations → evaluations
112
116
  --scenario-set-id ID # Scenario set (prompts if omitted)
113
117
  --grader-id ID # Grader (prompts if omitted)
114
118
  --env-id ID # Environment (uses config if omitted)
119
+ --target NAME # Target (auto-detected if only one)
115
120
  --image-tag TAG # Image tag (default: latest)
116
121
  --simulation-timeout N # Timeout per sim in seconds
117
122
  --report # Generate HTML report after evaluation
@@ -120,18 +125,30 @@ veris run # Full pipeline: simulations → evaluations
120
125
  ### Environment (`veris env`)
121
126
 
122
127
  ```bash
123
- veris env create --name NAME # Scaffold .veris/ + register environment
128
+ veris env create --name NAME # Scaffold .veris/ + register environment (NAME = env/target name)
129
+ --agent-name NAME # Agent display name (stored in veris.yaml agent.name)
124
130
  veris env push [--tag TAG] # Build and push image to Veris
131
+ --target NAME # Target to push (auto-detected if only one)
125
132
  veris env list # List environments
126
133
  veris env delete ENV_ID # Delete environment
127
134
  ```
128
135
 
136
+ ### Active Target (`veris env targets`)
137
+
138
+ ```bash
139
+ veris env targets get # Show the active target
140
+ veris env targets set NAME # Set the active target for this project
141
+ veris env targets list # List configured targets (from veris.yaml)
142
+ veris env targets clear # Clear the active target
143
+ ```
144
+
129
145
  ### Environment Config (`veris env config`)
130
146
 
131
147
  ```bash
132
148
  veris env config push # Upload veris.yaml to backend (no image build)
133
149
  --file PATH # Custom veris.yaml path (default: .veris/veris.yaml)
134
150
  --env-id ID # Override environment
151
+ --target NAME # Target to upload
135
152
  ```
136
153
 
137
154
  ### Environment Variables (`veris env vars`)
@@ -140,8 +157,11 @@ veris env config push # Upload veris.yaml to backend (no image buil
140
157
  veris env vars set K=V [K=V ...] # Set variables
141
158
  --secret # Mark as secret
142
159
  --env-id ID # Override environment
160
+ --target NAME # Target to set variables for
143
161
  veris env vars list # List variables
162
+ --target NAME
144
163
  veris env vars rm KEY # Remove a variable
164
+ --target NAME
145
165
  ```
146
166
 
147
167
  ### Scenarios (`veris scenarios`)
@@ -277,17 +297,132 @@ profiles:
277
297
 
278
298
  ### `.veris/config.yaml`
279
299
 
280
- Project config (created by `veris env create`):
300
+ Project config (created by `veris env create`). Each target's `environment_id` is stored under the profile:
281
301
  ```yaml
302
+ active_target: my-cool-agent-env
282
303
  profiles:
283
304
  default:
284
- environment_id: env_abc123
285
- environment_name: my-agent
305
+ targets:
306
+ my-cool-agent-env:
307
+ environment_id: env_abc123
308
+ environment_name: my-cool-agent-env
309
+ ```
310
+
311
+ ### `.veris/veris.yaml`
312
+
313
+ Simulation configuration. Every target is a top-level key — the target name is the backend environment name:
314
+ ```yaml
315
+ version: "1.0"
316
+
317
+ my-cool-agent-env:
318
+ services:
319
+ - name: postgres
320
+ config:
321
+ SCHEMA_PATH: /agent/schemas/schema.sql
322
+ - name: slack
323
+ dns_aliases:
324
+ - slack.com
325
+ persona:
326
+ modality:
327
+ type: http
328
+ url: http://localhost:8008/chat
329
+ agent:
330
+ name: My Cool Agent
331
+ code_path: /agent
332
+ entry_point: uv run app
333
+ port: 8008
334
+ environment:
335
+ DATABASE_URL: postgresql://postgres:postgres@localhost:5432/SIMULATION_ID
336
+ ```
337
+
338
+ When only one target is defined, all commands auto-select it.
339
+
340
+ ## Multiple Targets (Monorepo)
341
+
342
+ A single repo can manage multiple agents/environments. Each `veris env create` adds a target whose name **is** the backend environment name.
343
+
344
+ ### Creating targets
345
+
346
+ ```bash
347
+ # First agent
348
+ veris env create --name my-cool-agent-env --agent-name "My Cool Agent"
349
+
350
+ # Second agent — appended to the same veris.yaml
351
+ veris env create --name customer-support-env --agent-name "Customer Support"
352
+ ```
353
+
354
+ After two creates, `.veris/veris.yaml` looks like:
355
+ ```yaml
356
+ version: "1.0"
357
+
358
+ my-cool-agent-env:
359
+ services: [...]
360
+ persona: ...
361
+ agent:
362
+ name: My Cool Agent
363
+ ...
364
+
365
+ customer-support-env:
366
+ services: [...]
367
+ persona: ...
368
+ agent:
369
+ name: Customer Support
370
+ ...
371
+ ```
372
+
373
+ ### Pushing and running
374
+
375
+ ```bash
376
+ # With one target — auto-detected, no flag needed
377
+ veris env push
378
+
379
+ # With multiple targets — specify which one
380
+ veris env push --target customer-support-env
381
+ veris run --target customer-support-env
382
+ veris env vars set API_KEY=sk-... --target customer-support-env --secret
383
+ ```
384
+
385
+ ### Setting an active target
386
+
387
+ Avoid typing `--target` on every command:
388
+ ```bash
389
+ veris env targets set customer-support-env
390
+ veris env push # pushes customer-support-env
391
+ veris run # runs customer-support-env
392
+ veris env targets get # shows: customer-support-env
393
+ veris env targets list # lists all targets from veris.yaml
394
+ veris env targets clear # clears the active target
395
+ ```
396
+
397
+ ### Target resolution
398
+
399
+ | Priority | Source |
400
+ |----------|--------|
401
+ | 1 | `--target` flag |
402
+ | 2 | `active_target` in `.veris/config.yaml` |
403
+ | 3 | Auto-detect: sole target in `veris.yaml` |
404
+ | 4 | Error if ambiguous |
405
+
406
+ ### Per-target Dockerfile
407
+
408
+ Targets can override the default Dockerfile:
409
+ ```yaml
410
+ customer-support-env:
411
+ dockerfile: .veris/Dockerfile.support
412
+ agent:
413
+ name: Customer Support
414
+ ...
286
415
  ```
287
416
 
417
+ Falls back to `.veris/Dockerfile.sandbox` when not specified.
418
+
419
+ ### Cross-profile behavior
420
+
421
+ When you switch profiles (e.g. from `dev` to `staging`) and push, the CLI detects that the target exists on another profile and offers to create it on the current one.
422
+
288
423
  ## Profiles
289
424
 
290
- The CLI supports named profiles for managing multiple environments. Each profile stores its own API key, backend URL, console URL, organization, and environment ID.
425
+ The CLI supports named profiles for managing multiple backend accounts. Each profile stores its own API key, backend URL, console URL, organization, and environment IDs.
291
426
 
292
427
  ```bash
293
428
  # Login to a named profile (creates it if new, sets it active)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "veris-cli"
3
- version = "2.22.2"
3
+ version = "2.23.0"
4
4
  description = "CLI to connect local agents to the Veris backend"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -14,6 +14,7 @@ dependencies = [
14
14
  "rich>=13.7.0",
15
15
  "questionary>=2.0.0",
16
16
  "pyyaml>=6.0.1",
17
+ "pydantic>=2.6",
17
18
  ]
18
19
 
19
20
  [project.scripts]
@@ -30,22 +30,25 @@ def _load_dockerignore(project_root: Path) -> pathspec.PathSpec:
30
30
  def create_build_context(
31
31
  project_root: Path,
32
32
  output_path: Path | None = None,
33
+ dockerfile: Path | str | None = None,
33
34
  ) -> tuple[Path, int]:
34
35
  """Create a tar.gz build context from the project root.
35
36
 
36
37
  Respects .veris/.dockerignore (preferred) or .dockerignore at the project root.
37
- Always includes .veris/Dockerfile.sandbox even if matched by ignore.
38
+ Always includes the selected Dockerfile even if matched by ignore.
38
39
  Always excludes .git/ regardless of .dockerignore.
39
40
 
40
41
  Args:
41
42
  project_root: Root directory to package.
42
43
  output_path: Where to write the tarball. If None, uses a tempfile.
44
+ dockerfile: Dockerfile path (absolute or relative to project_root). Defaults
45
+ to `.veris/Dockerfile.sandbox` when None.
43
46
 
44
47
  Returns:
45
48
  Tuple of (tarball_path, size_bytes).
46
49
 
47
50
  Raises:
48
- ValueError: If tarball exceeds the size cap or Dockerfile.sandbox is missing.
51
+ ValueError: If tarball exceeds the size cap or the Dockerfile is missing.
49
52
  """
50
53
  spec = _load_dockerignore(project_root)
51
54
 
@@ -54,12 +57,18 @@ def create_build_context(
54
57
  os.close(fd)
55
58
  output_path = Path(tmp)
56
59
 
57
- dockerfile = project_root / ".veris" / "Dockerfile.sandbox"
58
- if not dockerfile.exists():
59
- raise ValueError(".veris/Dockerfile.sandbox not found")
60
+ if dockerfile is None:
61
+ dockerfile_path = project_root / ".veris" / "Dockerfile.sandbox"
62
+ dockerfile_label = ".veris/Dockerfile.sandbox"
63
+ else:
64
+ df = Path(dockerfile)
65
+ dockerfile_path = df if df.is_absolute() else project_root / df
66
+ dockerfile_label = str(dockerfile)
67
+ if not dockerfile_path.exists():
68
+ raise ValueError(f"{dockerfile_label} not found")
60
69
 
61
70
  file_count = 0
62
- dockerfile_rel = os.path.join(".veris", "Dockerfile.sandbox")
71
+ dockerfile_rel = str(dockerfile_path.relative_to(project_root))
63
72
  dockerfile_added = False
64
73
 
65
74
  with tarfile.open(output_path, "w:gz") as tar:
@@ -83,7 +92,7 @@ def create_build_context(
83
92
  if rel_path == ".":
84
93
  rel_path = f
85
94
 
86
- # Skip ignored files (but always include .veris/Dockerfile.sandbox)
95
+ # Skip ignored files (but always include the selected Dockerfile)
87
96
  if spec.match_file(rel_path) and rel_path != dockerfile_rel:
88
97
  continue
89
98
 
@@ -93,9 +102,9 @@ def create_build_context(
93
102
  if rel_path == dockerfile_rel:
94
103
  dockerfile_added = True
95
104
 
96
- # If the Dockerfile wasn't added (e.g. .veris/ dir was ignored), add it explicitly
105
+ # If the Dockerfile wasn't added (e.g. its dir was ignored), add it explicitly
97
106
  if not dockerfile_added:
98
- tar.add(str(dockerfile), arcname=dockerfile_rel)
107
+ tar.add(str(dockerfile_path), arcname=dockerfile_rel)
99
108
  file_count += 1
100
109
 
101
110
  size = output_path.stat().st_size
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from typing import Any, Callable
7
7
 
8
8
  import click
9
+ import yaml
9
10
 
10
11
  from veris_cli.config import ProjectConfig
11
12
 
@@ -22,27 +23,131 @@ def get_profile(ctx: click.Context) -> str | None:
22
23
  return ctx.obj.get("profile") if ctx.obj else None
23
24
 
24
25
 
25
- def resolve_env_id(profile: str | None, env_id: str | None) -> str:
26
- """Resolve environment ID from flag or project config. Exits on failure."""
26
+ def veris_yaml_path() -> Path:
27
+ """Default location of the project's veris.yaml."""
28
+ return Path.cwd() / ".veris" / "veris.yaml"
29
+
30
+
31
+ def repo_dir_fallback() -> str:
32
+ """Used as the legacy_target_fallback for VerisYaml.load."""
33
+ return Path.cwd().name
34
+
35
+
36
+ def resolve_target(
37
+ target: str | None,
38
+ profile: str | None = None,
39
+ parsed_veris_yaml=None,
40
+ ) -> str | None:
41
+ """Resolve target name.
42
+
43
+ Priority:
44
+ 1. Explicit `--target` flag
45
+ 2. Persisted `active_target` in .veris/config.yaml
46
+ 3. Auto-detect from veris.yaml: if exactly one target is defined, use its
47
+ name (so single-target repos never need a flag). Pass `parsed_veris_yaml`
48
+ to avoid re-parsing when the caller already loaded it.
49
+ 4. None — caller will fall back to legacy profile-level config
50
+ """
51
+ if target:
52
+ return target
53
+ try:
54
+ active = ProjectConfig(profile=profile).get_active_target()
55
+ if active:
56
+ return active
57
+ except (OSError, yaml.YAMLError):
58
+ pass
59
+
60
+ if parsed_veris_yaml is None:
61
+ path = veris_yaml_path()
62
+ if path.exists():
63
+ try:
64
+ from veris_cli.veris_yaml import VerisYaml
65
+
66
+ parsed_veris_yaml = VerisYaml.load(path, legacy_target_fallback=repo_dir_fallback())
67
+ except (OSError, yaml.YAMLError, ValueError):
68
+ parsed_veris_yaml = None
69
+
70
+ if parsed_veris_yaml is not None:
71
+ sole = parsed_veris_yaml.sole_target_name()
72
+ if sole:
73
+ return sole
74
+
75
+ return None
76
+
77
+
78
+ def _lookup_env_id(profile: str | None, target: str | None) -> tuple[str | None, str | None]:
79
+ """Look up env_id without raising. Returns (env_id, resolved_target).
80
+
81
+ Resolution: target's scoped env_id (when one was explicit/active/auto-detected),
82
+ or — only when no target could be resolved at all — the legacy profile-level
83
+ env_id. We do NOT silently fall through from a missing target to legacy:
84
+ that would mask "wrong env" bugs when a user passes --target X but X has no
85
+ env_id under the profile.
86
+ """
87
+ resolved_target = resolve_target(target, profile)
88
+ if resolved_target:
89
+ scoped = ProjectConfig(profile=profile, target=resolved_target).get_environment_id()
90
+ return scoped, resolved_target
91
+ legacy = ProjectConfig(profile=profile).get_environment_id()
92
+ return legacy, None
93
+
94
+
95
+ def find_target_on_other_profiles(
96
+ target_name: str,
97
+ current_profile: str | None,
98
+ ) -> str | None:
99
+ """Check if target_name has an env_id under a different profile. Returns that profile name."""
100
+ from veris_cli.config import Config
101
+
102
+ resolved_profile = ProjectConfig(profile=current_profile).profile
103
+ for other in Config(profile=current_profile).list_profiles():
104
+ if other == resolved_profile:
105
+ continue
106
+ other_pc = ProjectConfig(profile=other, target=target_name)
107
+ if other_pc.get_environment_id():
108
+ return other
109
+ return None
110
+
111
+
112
+ def resolve_env_id(
113
+ profile: str | None,
114
+ env_id: str | None,
115
+ target: str | None = None,
116
+ ) -> str:
117
+ """Resolve environment ID from flag, target, or project config. Exits on failure."""
27
118
  if env_id:
28
119
  return env_id
29
- project_config = ProjectConfig(profile=profile)
30
- env_id = project_config.get_environment_id()
31
- if not env_id:
32
- from veris_cli import output
33
120
 
34
- output.print_error(
35
- "No environment configured. Use --env-id or run 'veris env create' first."
36
- )
37
- sys.exit(1)
38
- return env_id
121
+ found, resolved_target = _lookup_env_id(profile, target)
122
+ if found:
123
+ return found
124
+
125
+ from veris_cli import output
126
+
127
+ hint = f" for target '{resolved_target}'" if resolved_target else ""
128
+ msg = f"No environment configured{hint}. Use --env-id or run 'veris env create' first."
129
+
130
+ if resolved_target:
131
+ other = find_target_on_other_profiles(resolved_target, profile)
132
+ if other:
133
+ current = ProjectConfig(profile=profile).profile
134
+ msg += (
135
+ f"\n (Target '{resolved_target}' exists on profile '{other}' "
136
+ f"but not on '{current}'. "
137
+ f"Run 'veris env create --name ...' on this profile, "
138
+ f"or switch with 'veris profile use {other}'.)"
139
+ )
140
+
141
+ output.print_error(msg)
142
+ sys.exit(1)
39
143
 
40
144
 
41
- def try_get_project_env_id(profile: str | None) -> str | None:
145
+ def try_get_project_env_id(profile: str | None, target: str | None = None) -> str | None:
42
146
  """Safely get env_id from project config, returning None if not found."""
43
147
  try:
44
- return ProjectConfig(profile=profile).get_environment_id()
45
- except Exception:
148
+ found, _ = _lookup_env_id(profile, target)
149
+ return found
150
+ except (OSError, yaml.YAMLError):
46
151
  return None
47
152
 
48
153