| 72 | type_key = "init" |
| 73 | |
| 74 | def execute(self, config: dict[str, Any], context: StepContext) -> StepResult: |
| 75 | project = self._resolve(config.get("project"), context) |
| 76 | here = self._resolve_bool(config.get("here"), context) |
| 77 | |
| 78 | integration = self._resolve(config.get("integration"), context) |
| 79 | if not integration: |
| 80 | integration = self._resolve(context.default_integration, context) |
| 81 | # Apply the same default that specify init uses in non-interactive mode |
| 82 | # so that output.integration reflects the actual integration used. |
| 83 | if not integration: |
| 84 | integration = DEFAULT_INIT_INTEGRATION |
| 85 | |
| 86 | integration_options = self._resolve( |
| 87 | config.get("integration_options"), context |
| 88 | ) |
| 89 | script = self._resolve(config.get("script"), context) |
| 90 | preset = self._resolve(config.get("preset"), context) |
| 91 | |
| 92 | force = self._resolve_bool(config.get("force"), context) |
| 93 | # Workflows run unattended; skip the agent CLI presence check by default. |
| 94 | ignore_agent_tools = self._resolve_bool( |
| 95 | config.get("ignore_agent_tools", True), context |
| 96 | ) |
| 97 | |
| 98 | argv: list[str] = ["init"] |
| 99 | if here: |
| 100 | argv.append("--here") |
| 101 | elif project: |
| 102 | argv.append(str(project)) |
| 103 | else: |
| 104 | # No explicit target → initialize the current directory. |
| 105 | argv.append(".") |
| 106 | |
| 107 | # Build the full argv (except --force, which may be set implicitly |
| 108 | # below) so early-return outputs always reflect the complete command. |
| 109 | if integration: |
| 110 | argv.extend(["--integration", str(integration)]) |
| 111 | if integration_options: |
| 112 | argv.extend(["--integration-options", str(integration_options)]) |
| 113 | if script: |
| 114 | argv.extend(["--script", str(script)]) |
| 115 | if preset: |
| 116 | argv.extend(["--preset", str(preset)]) |
| 117 | if ignore_agent_tools: |
| 118 | argv.append("--ignore-agent-tools") |
| 119 | |
| 120 | # When the target is the current directory and ``force`` is not set, |
| 121 | # ``specify init`` prompts for confirmation if the directory is not |
| 122 | # empty. Workflows run unattended (no stdin), so the prompt would |
| 123 | # abort with a confusing error. Fail fast with an actionable message. |
| 124 | # Exception: if the only pre-existing content is engine-owned (e.g. |
| 125 | # .specify/workflows/runs/), treat it as implicitly empty and auto-add |
| 126 | # --force so init can proceed unattended. |
| 127 | targets_current_dir = here or not project or str(project) == "." |
| 128 | if targets_current_dir and not force: |
| 129 | base = context.project_root or os.getcwd() |
| 130 | has_engine_dirs = False |
| 131 | try: |