@@ -4231,7 +4231,7 @@ def test_from_yaml_sets_workflow_dir(self, project_dir):
42314231 state = engine .execute (definition )
42324232
42334233 stdout = state .step_results ["check-dir" ]["output" ]["stdout" ]
4234- assert stdout .strip () == f"DIR={ wf_dir } "
4234+ assert stdout .strip () == f"DIR={ wf_dir . resolve () } "
42354235
42364236 def test_from_string_has_empty_workflow_dir (self , project_dir ):
42374237 """String-loaded workflows have empty workflow_dir."""
@@ -4279,7 +4279,7 @@ def test_shell_step_receives_speckit_workflow_dir_env_var(self, project_dir):
42794279 state = engine .execute (definition )
42804280
42814281 stdout = state .step_results ["print-env" ]["output" ]["stdout" ]
4282- assert stdout .strip () == str (wf_dir )
4282+ assert stdout .strip () == str (wf_dir . resolve () )
42834283
42844284 def test_shell_step_no_env_var_when_workflow_dir_unset (self , project_dir , monkeypatch ):
42854285 """Shell steps do not set SPECKIT_WORKFLOW_DIR for string-loaded workflows."""
@@ -4336,7 +4336,7 @@ def test_resume_preserves_original_workflow_dir(self, project_dir):
43364336 # Execute -- gate pauses the workflow
43374337 state = engine .execute (definition )
43384338 assert state .status == RunStatus .PAUSED
4339- assert state .workflow_dir == str (wf_dir )
4339+ assert state .workflow_dir == str (wf_dir . resolve () )
43404340
43414341 # Simulate gate approval by patching the gate step
43424342 from unittest .mock import patch
@@ -4350,7 +4350,7 @@ def test_resume_preserves_original_workflow_dir(self, project_dir):
43504350
43514351 assert state .status == RunStatus .COMPLETED
43524352 stdout = state .step_results ["after-gate" ]["output" ]["stdout" ]
4353- assert stdout .strip () == f"DIR={ wf_dir } "
4353+ assert stdout .strip () == f"DIR={ wf_dir . resolve () } "
43544354
43554355 def test_workflow_dir_persisted_in_state (self , project_dir ):
43564356 """workflow_dir is persisted in state.json and survives load/save."""
@@ -4376,7 +4376,71 @@ def test_workflow_dir_persisted_in_state(self, project_dir):
43764376
43774377 # Reload state from disk and verify workflow_dir survived
43784378 loaded = RunState .load (state .run_id , project_dir )
4379- assert loaded .workflow_dir == str (wf_dir )
4379+ assert loaded .workflow_dir == str (wf_dir .resolve ())
4380+
4381+ def test_installed_workflow_has_workflow_dir (self , project_dir ):
4382+ """Installed-by-ID workflows get workflow_dir pointing to the
4383+ installation directory (.specify/workflows/<id>/).
4384+ """
4385+ from specify_cli .workflows .engine import WorkflowEngine
4386+ from specify_cli .workflows .base import RunStatus
4387+
4388+ wf_id = "installed-wfdir"
4389+ install_dir = project_dir / ".specify" / "workflows" / wf_id
4390+ install_dir .mkdir (parents = True )
4391+ (install_dir / "workflow.yml" ).write_text ("""
4392+ schema_version: "1.0"
4393+ workflow:
4394+ id: "installed-wfdir"
4395+ name: "Installed WfDir"
4396+ version: "1.0.0"
4397+ steps:
4398+ - id: check-dir
4399+ type: shell
4400+ run: "echo DIR={{ context.workflow_dir }}"
4401+ """ )
4402+ engine = WorkflowEngine (project_dir )
4403+ definition = engine .load_workflow (wf_id )
4404+ state = engine .execute (definition )
4405+
4406+ assert state .status == RunStatus .COMPLETED
4407+ stdout = state .step_results ["check-dir" ]["output" ]["stdout" ]
4408+ assert stdout .strip () == f"DIR={ install_dir .resolve ()} "
4409+
4410+ def test_workflow_dir_is_resolved_to_absolute (self , project_dir ):
4411+ """workflow_dir is resolved to an absolute path even when the
4412+ source path is relative.
4413+ """
4414+ from specify_cli .workflows .engine import WorkflowDefinition , WorkflowEngine
4415+ import os
4416+
4417+ wf_dir = project_dir / "rel-test"
4418+ wf_dir .mkdir ()
4419+ wf_file = wf_dir / "workflow.yml"
4420+ wf_file .write_text ("""
4421+ schema_version: "1.0"
4422+ workflow:
4423+ id: "rel-path"
4424+ name: "Relative Path"
4425+ version: "1.0.0"
4426+ steps:
4427+ - id: check
4428+ type: shell
4429+ run: "echo ok"
4430+ """ )
4431+ # Load via a relative path
4432+ saved_cwd = os .getcwd ()
4433+ try :
4434+ os .chdir (project_dir )
4435+ rel_path = Path ("rel-test/workflow.yml" )
4436+ definition = WorkflowDefinition .from_yaml (rel_path )
4437+ engine = WorkflowEngine (project_dir )
4438+ state = engine .execute (definition )
4439+ finally :
4440+ os .chdir (saved_cwd )
4441+
4442+ assert Path (state .workflow_dir ).is_absolute ()
4443+ assert state .workflow_dir == str (wf_dir .resolve ())
43804444
43814445
43824446# ===== continue_on_error Tests =====
0 commit comments