specify-cli 1.2.1__py3-none-any.whl → 1.2.2__py3-none-any.whl

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.
@@ -48,4 +48,9 @@ def bundle_init(
48
48
  f"{_escape_markup(str(project_root))}."
49
49
  )
50
50
  if bundle:
51
- bundle_install(bundle, integration=integration, offline=offline)
51
+ bundle_install(
52
+ bundle,
53
+ integration=integration,
54
+ offline=offline,
55
+ refresh=False,
56
+ )
@@ -211,6 +211,17 @@ class BundleManifest:
211
211
  errors.append(
212
212
  f"{ref.kind[:-1]} '{ref.id}' has invalid version '{ref.version}'."
213
213
  )
214
+ # Preset and extension installs refuse a priority below 1, which
215
+ # would otherwise surface only mid-install, after earlier components.
216
+ if (
217
+ ref.kind in ("extensions", "presets")
218
+ and ref.priority is not None
219
+ and ref.priority < 1
220
+ ):
221
+ errors.append(
222
+ f"{ref.kind[:-1]} '{ref.id}' priority must be 1 or higher, "
223
+ f"got {ref.priority}."
224
+ )
214
225
 
215
226
  for ref in self.presets:
216
227
  if ref.priority is None:
@@ -32,6 +32,8 @@ import typer
32
32
  from ..integrations._file_changes import unlink as _unlink_file, write_text as _write_text
33
33
 
34
34
  if TYPE_CHECKING:
35
+ from collections.abc import Iterable
36
+
35
37
  from ..integrations.base import IntegrationBase
36
38
  from ..integrations.manifest import IntegrationManifest
37
39
 
@@ -2153,13 +2155,15 @@ def _remove_opencode_entries(config_path: Path) -> bool:
2153
2155
  if existing is None:
2154
2156
  return False
2155
2157
  plugins = existing.get("plugin", [])
2156
- if isinstance(plugins, list):
2157
- ref = "./.opencode/plugin/speckit-events.ts"
2158
- plugins = [p for p in plugins if p != ref]
2159
- if plugins:
2160
- existing["plugin"] = plugins
2161
- else:
2162
- existing.pop("plugin", None)
2158
+ ref = "./.opencode/plugin/speckit-events.ts"
2159
+ # No Spec Kit plugin ref to strip: leave the user's file untouched.
2160
+ if not isinstance(plugins, list) or ref not in plugins:
2161
+ return False
2162
+ plugins = [p for p in plugins if p != ref]
2163
+ if plugins:
2164
+ existing["plugin"] = plugins
2165
+ else:
2166
+ existing.pop("plugin", None)
2163
2167
  if not existing:
2164
2168
  _unlink_file(config_path, missing_ok=True)
2165
2169
  return True
@@ -2376,8 +2380,9 @@ def _remove_copilot_entries(dst: Path) -> bool:
2376
2380
  if not isinstance(existing, dict):
2377
2381
  return False
2378
2382
  hooks = existing.get("hooks", {})
2379
- if not isinstance(hooks, dict):
2380
- hooks = {}
2383
+ # Nothing Specify-owned to strip: leave the user's file untouched.
2384
+ if not isinstance(hooks, dict) or not _has_marked_entry(hooks.values()):
2385
+ return False
2381
2386
  cleaned: dict[str, list] = {}
2382
2387
  for event, entries in hooks.items():
2383
2388
  if not isinstance(entries, list):
@@ -2505,7 +2510,8 @@ def _remove_json_root_entries(dst: Path) -> bool:
2505
2510
  existing = _load_user_json(dst)
2506
2511
  if existing is None:
2507
2512
  return False
2508
- if not isinstance(existing, dict):
2513
+ # Nothing Specify-owned to strip: leave the user's file untouched.
2514
+ if not isinstance(existing, dict) or not _has_marked_entry(existing.values()):
2509
2515
  return False
2510
2516
  cleaned: dict[str, Any] = {}
2511
2517
  for event, entries in existing.items():
@@ -2627,7 +2633,10 @@ def _remove_json_entries(dst: Path) -> bool:
2627
2633
  if existing is None:
2628
2634
  return False
2629
2635
  hooks = existing.get("hooks", {})
2630
- if not isinstance(hooks, dict):
2636
+ # Nothing Specify-owned to strip: leave the user's file untouched, so a
2637
+ # no-op event refresh neither reformats nor deletes it (the JSON
2638
+ # counterpart of the TOML guard added for #4563).
2639
+ if not isinstance(hooks, dict) or not _has_marked_entry(hooks.values()):
2631
2640
  return False
2632
2641
  cleaned: dict[str, list] = {}
2633
2642
  for event, entries in hooks.items():
@@ -2671,6 +2680,16 @@ def _has_marker(entry: Any) -> bool:
2671
2680
  return False
2672
2681
 
2673
2682
 
2683
+ def _has_marked_entry(groups: Iterable[Any]) -> bool:
2684
+ """Return True if any list among *groups* holds a Specify-marked entry."""
2685
+ return any(
2686
+ _has_marker(entry)
2687
+ for entries in groups
2688
+ if isinstance(entries, list)
2689
+ for entry in entries
2690
+ )
2691
+
2692
+
2674
2693
  def register(app: typer.Typer) -> None:
2675
2694
  """Attach the event command group to the root application."""
2676
2695
  from . import command_run # noqa: F401 -- registers handler
@@ -564,6 +564,10 @@ def run_update_command(extension: str | None) -> None:
564
564
  if cfg_file.is_file():
565
565
  shutil.copy2(cfg_file, new_extension_dir / cfg_file.name)
566
566
 
567
+ # Scaffold config templates the new version declares, as
568
+ # `extension add` does; the configs restored above are kept.
569
+ scaffolded, _, unscaffolded = manager.scaffold_config(extension_id)
570
+
567
571
  # 9. Restore metadata from backup (installed_at, enabled state)
568
572
  if backup_registry_entry and isinstance(backup_registry_entry, dict):
569
573
  init_options = _commands.load_init_options(project_root)
@@ -630,6 +634,17 @@ def run_update_command(extension: str | None) -> None:
630
634
  console.print(
631
635
  f" [green]✓[/green] Updated to v{update.available}"
632
636
  )
637
+ config_home = f".specify/extensions/{_escape_markup(extension_id)}"
638
+ for cfg in scaffolded:
639
+ console.print(
640
+ f" Config scaffolded: {config_home}/{_escape_markup(cfg)}"
641
+ )
642
+ if unscaffolded:
643
+ console.print(
644
+ " [yellow]Warning:[/yellow] Config templates not scaffolded: "
645
+ f"{_escape_markup(', '.join(unscaffolded))}. "
646
+ "Verify the extension manifest and template files."
647
+ )
633
648
  if cleanup_error is not None:
634
649
  console.print(
635
650
  " [yellow]Warning:[/yellow] Could not fully remove "
@@ -19,6 +19,17 @@ from ._lifecycle import external_lifecycle, lifecycle_owns_rollback, lifecycle_s
19
19
  from ._helpers import _MANIFEST_READ_ERRORS, _SharedTemplateRefreshError, _clear_init_options_for_integration, _cli_error_detail, _cli_phase_label, _get_speckit_version, _read_integration_json, _register_extensions_for_agent, _register_presets_for_agent, _remove_integration_json, _resolve_integration_options, _resolve_script_type, _set_default_integration, _set_default_integration_or_exit, _unregister_extensions_for_agent, _unregister_presets_for_agent, _write_integration_json
20
20
 
21
21
 
22
+ def _missing_required_options(integration, parsed_options) -> list[str]:
23
+ """Return the integration's required options that are absent or blank."""
24
+ parsed = parsed_options or {}
25
+ missing = []
26
+ for option in integration.options():
27
+ value = parsed.get(option.name.lstrip("-").replace("-", "_"))
28
+ if option.required and (value is None or (isinstance(value, str) and not value.strip())):
29
+ missing.append(option.name)
30
+ return missing
31
+
32
+
22
33
  @integration_app.command("switch")
23
34
  @external_lifecycle("switch")
24
35
  def integration_switch(
@@ -131,6 +142,16 @@ def integration_switch(
131
142
  target_integration, current, target, integration_options
132
143
  )
133
144
  target_integration.is_skills_mode(target_parsed_options, project_root)
145
+ # Required options are otherwise only enforced by setup(), which runs
146
+ # after Phase 1 has already removed the current integration.
147
+ missing_options = _missing_required_options(target_integration, target_parsed_options)
148
+ if missing_options:
149
+ console.print(
150
+ f"[red]Error:[/red] Integration '{escape(target)}' requires "
151
+ f"{', '.join(missing_options)} in --integration-options."
152
+ )
153
+ console.print("No files were changed.")
154
+ raise typer.Exit(1)
134
155
 
135
156
  # Phase 1: Uninstall current integration (if any)
136
157
  if installed_key:
@@ -8,6 +8,10 @@ for template- and script-driven workflows such as spec-kit.
8
8
 
9
9
  from __future__ import annotations
10
10
 
11
+ from collections.abc import Mapping, Sequence
12
+ from pathlib import Path
13
+ from typing import Any
14
+
11
15
  from ..base import IntegrationOption, SkillsIntegration
12
16
 
13
17
 
@@ -40,3 +44,29 @@ class ZcodeIntegration(SkillsIntegration):
40
44
  help="Install as agent skills (default for ZCode)",
41
45
  ),
42
46
  ]
47
+
48
+ def build_exec_args(
49
+ self,
50
+ prompt: str,
51
+ *,
52
+ model: str | None = None,
53
+ output_json: bool = True,
54
+ integration_args: Sequence[str] | None = None,
55
+ integration_options: Mapping[str, Any] | None = None,
56
+ project_root: Path | None = None,
57
+ ) -> list[str] | None:
58
+ """Build CLI arguments for non-interactive ``zcode`` execution.
59
+
60
+ ``SkillsIntegration``'s default appends ``--model``, which the ZCode
61
+ CLI does not define. Its argument parser is strict, so a dispatched
62
+ step exits 1 with ``Unknown option '--model'`` whenever a ``model``
63
+ is configured. ``model`` is deliberately dropped: ZCode has no
64
+ per-invocation model flag and switches models in-session with
65
+ ``/model``. ``-p`` and ``--output-format json`` are both valid.
66
+ """
67
+ self.validate_runtime_config(integration_args, integration_options)
68
+ args = [self._resolve_executable(), "-p", prompt]
69
+ self._apply_extra_args_env_var(args)
70
+ if output_json:
71
+ args.extend(["--output-format", "json"])
72
+ return args
@@ -44,11 +44,18 @@ def preset_catalog_remove(
44
44
  "[red]Error:[/red] Invalid catalog config: 'catalogs' must be a list."
45
45
  )
46
46
  raise typer.Exit(1)
47
+ for index, entry in enumerate(catalogs):
48
+ if not isinstance(entry, dict):
49
+ console.print(
50
+ f"[red]Error:[/red] Invalid catalog entry at index {index}: "
51
+ f"expected a mapping, got {type(entry).__name__}"
52
+ )
53
+ raise typer.Exit(1)
47
54
  # Rendering only — the raw name drives the comparison below.
48
55
  safe_name = _escape_markup(str(name))
49
56
 
50
57
  original_count = len(catalogs)
51
- catalogs = [c for c in catalogs if isinstance(c, dict) and c.get("name") != name]
58
+ catalogs = [c for c in catalogs if c.get("name") != name]
52
59
 
53
60
  if len(catalogs) == original_count:
54
61
  console.print(f"[red]Error:[/red] Catalog '{safe_name}' not found.")
@@ -79,6 +79,24 @@ def _fail_workflow_execution(
79
79
  raise typer.Exit(1) from exc
80
80
 
81
81
 
82
+ def _fail_recorded_run(
83
+ exc: Exception, *, json_output: bool, state: Any, resume: bool = False,
84
+ ) -> None:
85
+ """Report *exc* as the run's outcome when the engine recorded it as one.
86
+
87
+ ``WorkflowEngine.execute``/``resume`` persist an exception raised while
88
+ steps run (an expression error, say) as the run's ``failed`` status and
89
+ error, and mark that exception on the in-memory state, before re-raising
90
+ it. Errors raised before that point, such as input validation or a refused
91
+ resume, are not marked even when a loaded failed run carries the same
92
+ message, so this returns and the caller reports them as before.
93
+ """
94
+ if state is not None and getattr(state, "_recorded_exception", None) is exc:
95
+ _fail_workflow_execution(
96
+ exc, json_output=json_output, state=state, resume=resume
97
+ )
98
+
99
+
82
100
  def _open_workflow_registry(project_root: Path, out=None):
83
101
  """Construct a WorkflowRegistry, exiting cleanly on an unreadable file.
84
102
 
@@ -110,9 +110,15 @@ def workflow_resume(
110
110
  exc, json_output=json_output, state=engine._execution_state.get(), resume=True,
111
111
  )
112
112
  except ValueError as exc:
113
+ cli._fail_recorded_run(
114
+ exc, json_output=json_output, state=engine._execution_state.get(), resume=True,
115
+ )
113
116
  err.print(f"[red]Error:[/red] {cli._escape_markup(str(exc))}")
114
117
  raise cli.typer.Exit(1)
115
118
  except Exception as exc:
119
+ cli._fail_recorded_run(
120
+ exc, json_output=json_output, state=engine._execution_state.get(), resume=True,
121
+ )
116
122
  err.print(f"[red]Resume failed:[/red] {cli._escape_markup(str(exc))}")
117
123
  raise cli.typer.Exit(1)
118
124
 
@@ -159,9 +159,11 @@ def workflow_run(
159
159
  except OSError as exc:
160
160
  cli._fail_workflow_execution(exc, json_output=json_output, state=engine._execution_state.get())
161
161
  except ValueError as exc:
162
+ cli._fail_recorded_run(exc, json_output=json_output, state=engine._execution_state.get())
162
163
  err.print(f"[red]Error:[/red] {cli._escape_markup(str(exc))}")
163
164
  raise cli.typer.Exit(1)
164
165
  except Exception as exc:
166
+ cli._fail_recorded_run(exc, json_output=json_output, state=engine._execution_state.get())
165
167
  err.print(f"[red]Workflow failed:[/red] {cli._escape_markup(str(exc))}")
166
168
  raise cli.typer.Exit(1)
167
169
 
@@ -714,6 +714,9 @@ class RunState:
714
714
  self.step_results: dict[str, dict[str, Any]] = {}
715
715
  self.execution: dict[str, Any] | None = None
716
716
  self._checkpoint_failed = False
717
+ # The exception this process just recorded as the run's failure (never
718
+ # persisted), so the CLI can tell it apart from an older failure.
719
+ self._recorded_exception: BaseException | None = None
717
720
  # Guards step_results mutation and save() so a concurrent fan-out cannot
718
721
  # mutate the dict while save() is serializing it (which would raise
719
722
  # "dictionary changed size during iteration").
@@ -1148,6 +1151,7 @@ class WorkflowEngine:
1148
1151
  raise
1149
1152
  state.status = RunStatus.FAILED
1150
1153
  state.error = str(exc)
1154
+ state._recorded_exception = exc
1151
1155
  state.append_log({"event": "workflow_failed", "error": str(exc)})
1152
1156
  state.save()
1153
1157
  raise
@@ -1262,6 +1266,7 @@ class WorkflowEngine:
1262
1266
  raise
1263
1267
  state.status = RunStatus.FAILED
1264
1268
  state.error = str(exc)
1269
+ state._recorded_exception = exc
1265
1270
  state.append_log({"event": "resume_failed", "error": str(exc)})
1266
1271
  state.save()
1267
1272
  raise
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: specify-cli
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: Specify CLI, part of GitHub Spec Kit. A tool to bootstrap your projects for Spec-Driven Development (SDD).
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.11
@@ -58,7 +58,7 @@ specify_cli/bundles/catalogs.py,sha256=cg-7YiYRwYgKrk488Nkg8I3j-O6KfcbESsEdrX_Zm
58
58
  specify_cli/bundles/command_add.py,sha256=AeO_JEMWqV8XDQUgTPSy28u0Luw-0efnH8_aX9P4uo8,1118
59
59
  specify_cli/bundles/command_build.py,sha256=DVqW3TpLZkHWverkqBE7MurWyx81wL69r7mAwtAvrkU,1116
60
60
  specify_cli/bundles/command_info.py,sha256=UZqgnUIxJ0bA000UCt5x4N5IfyLB9D91SiTRhrfxoJU,7515
61
- specify_cli/bundles/command_init.py,sha256=xctL2zSJvLL4-JDu9DEsXFan8UJH7HYTafODLyYsdLw,1687
61
+ specify_cli/bundles/command_init.py,sha256=r7sWADfl9xV9kBf6E84db3VQARn7mKKhGo6q9GGtVjI,1761
62
62
  specify_cli/bundles/command_install.py,sha256=BNXVLxnzqIUUSSX8temWOBRMDcXJzfoUrxr2AnTcXAk,6045
63
63
  specify_cli/bundles/command_list.py,sha256=JqtewKGBXsab-3V9U8oKSRupL6nBOYTde76gkHkA9pc,1524
64
64
  specify_cli/bundles/command_remove.py,sha256=MeXUWiNbi_z_6kyA7bfUA_Wb0z-jWNMqc4qDJ1s0GFg,1042
@@ -68,7 +68,7 @@ specify_cli/bundles/command_validate.py,sha256=gxxHK5TxuWztfWz7B5_bscJhZ5d_qrW1P
68
68
  specify_cli/bundles/component_catalog.py,sha256=GfDXhGooqM54BJE3mbnBa73x7HO4bPFBoNAjVGxVIs0,6002
69
69
  specify_cli/bundles/conflict.py,sha256=pM2GdgNsSUrnaQ3N0RFL0BCZ9yry4pChfE7VI3QN1IU,2371
70
70
  specify_cli/bundles/installer.py,sha256=kyUcQAAnmYGl9m9hem4Dtcjxj6mAYVhele3RJy0XnLA,18011
71
- specify_cli/bundles/manifest.py,sha256=NLuaqgOCUfea0BEkArYayMYiudB2JTqT0Sfe5XWPzwA,11440
71
+ specify_cli/bundles/manifest.py,sha256=c2MzDCcV-56cNOofFfYcEKq_pNb8u_TkQ_1E-o7-1AM,11940
72
72
  specify_cli/bundles/packager.py,sha256=uS8e9hUIa38Oo78AsmxTgR5vobT6ncGdbYUerozUu7c,6487
73
73
  specify_cli/bundles/primitives.py,sha256=bmrsaANt-RSmOEG-sYIWC0qP7jwfWW7DHDRIkeCM-mI,27596
74
74
  specify_cli/bundles/project.py,sha256=HTXiPsibosAvU3I9xUjg3MCpeB9acxf3nKLq_1XVkIc,6526
@@ -83,13 +83,13 @@ specify_cli/bundles/catalog/__init__.py,sha256=0lmWgrtdajbD2w0HnBVfiTTLUFo4SN25M
83
83
  specify_cli/bundles/catalog/command_add.py,sha256=EMV0zUbs8RPAayzwqfslIZQLJLsZlPb_aowOl3vcIX8,1543
84
84
  specify_cli/bundles/catalog/command_list.py,sha256=zUoT6u0qxa6Ywaa-cfWKnpPxYNkfEa4VQGs9OW4Ch8o,1319
85
85
  specify_cli/bundles/catalog/command_remove.py,sha256=KZ7zVP7MZespNWbRVvgr1bhpD0-uf-lgwOFlojOJrXU,894
86
- specify_cli/events/__init__.py,sha256=nzO1tF5ou1FfvvjYi9eP2t7OG4PD8pCiWsTumIWpV2s,118524
86
+ specify_cli/events/__init__.py,sha256=3EQQ-nltcZNVCNaj5H6cE6yhAiOzFXKRak7Qo08JAvQ,119410
87
87
  specify_cli/events/command_run.py,sha256=oFh_whU3m9kiPU4FgdRD1bxKiQLCoAvKKb8cPNdHQD0,2296
88
88
  specify_cli/extensions/__init__.py,sha256=6FRCn7PEKWbsxWjBJWe87u9tIFDIrKzGx29xi3AwEMg,278139
89
89
  specify_cli/extensions/_catalog_versions.py,sha256=ElzFMhU2asQGWYoK9nmsKSNdbzzJpMZll2RfkVRIp9E,5554
90
90
  specify_cli/extensions/_command_update_artifacts.py,sha256=GJ4GYR9wuVoeWtNNy806ULEzFRp_jt3ZHmcVbY2afHY,5943
91
91
  specify_cli/extensions/_command_update_discovery.py,sha256=R7LeqdCqE488PXV2XN5uQbQ3HhzKcxUwofVCajwMyKo,4987
92
- specify_cli/extensions/_command_update_transaction.py,sha256=0abhs3IYWpH1eQcRCbd_UfjTXAb5kUa92WuEZEhC3eM,46719
92
+ specify_cli/extensions/_command_update_transaction.py,sha256=Z6QNMuwzLfShOyrDpyprflI3mUPXCH-4z0uich2a6iw,47557
93
93
  specify_cli/extensions/_commands.py,sha256=9PtGA3mwPjL1Ju22LWScW1PwQat5QrzV3xMk3GPPkgE,27744
94
94
  specify_cli/extensions/command_add.py,sha256=-rhAknnboLRoOLWC9kbywJjglQMY0VmwFCclGIQhQI4,17919
95
95
  specify_cli/extensions/command_disable.py,sha256=8owd9vu93g0lHjt5vJJa9xlaftd9s1sm5oHXcnTos9A,2740
@@ -122,7 +122,7 @@ specify_cli/integrations/command_list.py,sha256=EwU88UfsVecNJFXRs1daZrqz8Yl_EBK6
122
122
  specify_cli/integrations/command_scaffold.py,sha256=wAECcT8a2eD_HLO1KWQcUNsiGGAQJAkQmuo81Z6IWyE,2132
123
123
  specify_cli/integrations/command_search.py,sha256=VmdCj397uoaDW1OWS6y5WZZVFQLzfEiTuC_cvrb7qGw,4374
124
124
  specify_cli/integrations/command_status.py,sha256=SJf-2MhQ_lYvhqQ3IrRjb4_Fz0YYAo6MWXpGL9a1Rn0,3339
125
- specify_cli/integrations/command_switch.py,sha256=tEMFq0efmSqtTxQ6P1TBJs2oEokMEOStr_FOjr8xL_U,17795
125
+ specify_cli/integrations/command_switch.py,sha256=iI7ot6KR57V8MOk4eQBYxEFCiBnvgD-ApeZ3LCwgN0Y,18774
126
126
  specify_cli/integrations/command_uninstall.py,sha256=_ZtEaKIfHGNOR0j9JkeWvbc0P-abkzPUOL_IBECpsGo,7647
127
127
  specify_cli/integrations/command_upgrade.py,sha256=slHER4CZhNyscvz3AFAAlj8RdnxpUFcUiIJmQVfIBQQ,16948
128
128
  specify_cli/integrations/command_use.py,sha256=XU4w-jTJNw6ZqXO5d0wEyN8z851JzwHu7gmTecITOQU,2655
@@ -172,7 +172,7 @@ specify_cli/integrations/shai/__init__.py,sha256=43uPKmbeZ-EDnGlkM9qsYzrsIe94HVp
172
172
  specify_cli/integrations/tabnine/__init__.py,sha256=bNZoaopS368kvACXVikqZbZUlNjvyj6T8tI0M4tUJhc,1711
173
173
  specify_cli/integrations/trae/__init__.py,sha256=dTD001UlAz1vlgQtvD4U6mu_tNNiC_nQdYII80QidjQ,1097
174
174
  specify_cli/integrations/vibe/__init__.py,sha256=xVdJHyWCPa6dBewSjZWueWH6x8UfSUBsxGGQvb2y-iM,9255
175
- specify_cli/integrations/zcode/__init__.py,sha256=tbCl7PFwVPS9J5UKUut9eRR_WOeBElOo66t9LiB5r5c,1198
175
+ specify_cli/integrations/zcode/__init__.py,sha256=nD0w4U9lIUd5VXaqM_17zIGuXLRvBlHCAcUqvSJKsJ8,2422
176
176
  specify_cli/integrations/zed/__init__.py,sha256=XyEDpaBIu0mv_dbyQl24qusuhIK2RzKmitnTPCQ1GKU,838
177
177
  specify_cli/mcp_server/__init__.py,sha256=TWT51FaEX8Ysa8aZKHmxIJs6Ig416mWfqP1fPTj1qKE,176
178
178
  specify_cli/mcp_server/_worker.py,sha256=YiduD0lVSQ-Rdkb0US1ti2HbeBzlgt1Pp79jtzfiM3E,135
@@ -202,7 +202,7 @@ specify_cli/presets/command_update.py,sha256=qRp5GHyrEZBDsClxc3Xyr7BikSj21NvG5Jk
202
202
  specify_cli/presets/catalog/__init__.py,sha256=AAl1Y6faar4Tuy_KE2nh6qzQMQolcQkkF_rxNcvru2Y,725
203
203
  specify_cli/presets/catalog/command_add.py,sha256=YNpmX0nGnoAS07ViEumVa4-XEZWvWR3Pu2PVFadxgDI,4194
204
204
  specify_cli/presets/catalog/command_list.py,sha256=SwPs8HgtgQMG25fBPIkTR0TDrkcKS4TaNgfidKVf0KE,2783
205
- specify_cli/presets/catalog/command_remove.py,sha256=7nq1e5qyav3c2MnP-LpLAeASQ7HTEJz4RT20WFGF528,2294
205
+ specify_cli/presets/catalog/command_remove.py,sha256=ZwoUnrCBCFuW4Xq_Opm1bFsuxfvgVUIXemUJBHOHKFo,2572
206
206
  specify_cli/selfs/__init__.py,sha256=mvW41FasanvjzTr82hnUv3qrCbdNJpLqk_LxdiGRVqU,722
207
207
  specify_cli/selfs/command_check.py,sha256=dwBJ2cBBkOMMLjF5to-IIEQqUvqjOj8AziZBcpsx4ds,3040
208
208
  specify_cli/selfs/command_upgrade.py,sha256=i1VtdtEOTPagj-0LiTXOLpNxgWzpUk77_OSZu6HKX2A,7877
@@ -210,7 +210,7 @@ specify_cli/workflows/__init__.py,sha256=Ru8Da8hHxrJfC77eRJxDSxco_k-Vkw9NMXRMCYE
210
210
  specify_cli/workflows/_catalog_cache.py,sha256=BSkhiY6lanh5rSZ9CgkDY_wyAtuV9SFsTPJNA7ia3fY,7166
211
211
  specify_cli/workflows/_command_resume_state.py,sha256=zXcVBeT9gipLwAyHqmLUzhFh0TeypUX-bsEaj_vfikc,1798
212
212
  specify_cli/workflows/_command_run_ownership.py,sha256=5-BFmNhqVkwaQTzpZRpf9mGulNpvir2EfI-znOFFv64,7843
213
- specify_cli/workflows/_commands.py,sha256=t5tmWP__DSzoc8R_iLrD28-E4hT7vv28Dmk2mErDMAo,62594
213
+ specify_cli/workflows/_commands.py,sha256=ZoJRl8iL9gHomXP2_aYuIGW3426Ve0PE1jVSRutHpr0,63437
214
214
  specify_cli/workflows/_execution.py,sha256=zkzU8GAHZd23qzro3kp-PzeF3NzYhwHmZtPmCek9kM8,40687
215
215
  specify_cli/workflows/base.py,sha256=pdM89fOJFHN4d0lxg0PHT459buVSJ-98F4EtHKvy48k,4519
216
216
  specify_cli/workflows/command_add.py,sha256=ls4R1JTaH4AYp3AgeL7oMW7EAm2xdcfui9iY8FYJqKQ,23332
@@ -220,13 +220,13 @@ specify_cli/workflows/command_info.py,sha256=XGkBcu5x0UnoI5XOjrN05vK7u8a2IqXLQ2_
220
220
  specify_cli/workflows/command_list.py,sha256=a2L9eKlk4AeUibr2AmoS29HyIychmH4X6Ptk9ilTYYg,1429
221
221
  specify_cli/workflows/command_remove.py,sha256=m8fL9UOIO5Oh_BZBuzSgPiD2nPdCcbRPkn26ZriS0cI,4796
222
222
  specify_cli/workflows/command_resolve.py,sha256=Go2mDhvEDN_NPNpHXNiTMt_PANR2Cn36sRkKu_CiwlU,525
223
- specify_cli/workflows/command_resume.py,sha256=iW2pw8kY2Qxo58F2C7glEnHeIeLjXkKXu0Gh1CxfaPc,5997
224
- specify_cli/workflows/command_run.py,sha256=NO5J3DU30rx33qIvdAP6YUnvxeS3weU5ulA1lX8fYAU,7934
223
+ specify_cli/workflows/command_resume.py,sha256=UCU_KddQ8u1X2Lsa8AwKrgcBRh7P75X80pafBmTVvr8,6265
224
+ specify_cli/workflows/command_run.py,sha256=9hvuYYYBwyfqT_nmnb1Wi7l0MrGR6Vf0h1krHL9az1A,8130
225
225
  specify_cli/workflows/command_search.py,sha256=ytgqLqvX0jR46c8jxdtvHNWIKxZJQQLXg7te9YTslD8,1700
226
226
  specify_cli/workflows/command_status.py,sha256=dLpAJRvfBhVJS4kJEG5aNXjiAMvoSzVTluMHuHiCyiQ,5252
227
227
  specify_cli/workflows/command_update.py,sha256=U1oWvlg_nrI1j1gyzikCycLIEhRulMcFTY2HVA8Y_l0,5810
228
228
  specify_cli/workflows/composition.py,sha256=j5cJU2WgRUr3CKn9OAfZr_4fFz_fC1-oEAS6H2ImlsY,6116
229
- specify_cli/workflows/engine.py,sha256=KIvQM7PhH-L5n_TBTr2UHvilU1tygRVBR7BS0PdnCK8,66931
229
+ specify_cli/workflows/engine.py,sha256=aHCgxTx1YxD_Mj4HVIMA15zUs1h0ezYHZqDp1Pfl5KI,67234
230
230
  specify_cli/workflows/expressions.py,sha256=wu0UpabUWqUieKa1f40IGL-PgFjqCl5gDGw6xBUOktk,69727
231
231
  specify_cli/workflows/catalog/__init__.py,sha256=hi48lfC4OBFnd-l4P009GP_Y8n219ohmBp6lMLeaFX0,1690
232
232
  specify_cli/workflows/catalog/_domain.py,sha256=je47vVMdcE3XDlgoedd5YhsBEDqtdpLW8Az6Pz9y95k,36248
@@ -372,8 +372,8 @@ specify_cli/core_pack/templates/vscode-settings.json,sha256=PbOh2EF9OKVrQF9gtgDc
372
372
  specify_cli/core_pack/workflows/assess/workflow.yml,sha256=AAnpPIQ-6dlpBHXZOX8LM8bcbSAGEWKI0u5YzN_xIag,1768
373
373
  specify_cli/core_pack/workflows/bugfix/workflow.yml,sha256=0zcr3uE4Be-FJobRYL36Q-y85WQRRZzXxK0BxxKmP-s,1302
374
374
  specify_cli/core_pack/workflows/speckit/workflow.yml,sha256=F3dhxeffKBJr7qBDtctFrq95WAkMAi3BGscTmUIvz7w,2118
375
- specify_cli-1.2.1.dist-info/METADATA,sha256=4CNnmqN5q-_JZS5oefHs5ww7PKQA8FtJLgtXpt3LjGw,12736
376
- specify_cli-1.2.1.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
377
- specify_cli-1.2.1.dist-info/entry_points.txt,sha256=zO7Jooxo-O6FCM02xdzsNB8WNakvnPDv5bpZr1P4Pmo,45
378
- specify_cli-1.2.1.dist-info/licenses/LICENSE,sha256=JRC0RrwfDPlwJFMHXSDNiGMeIOVkJljttzJdnB61NPc,1060
379
- specify_cli-1.2.1.dist-info/RECORD,,
375
+ specify_cli-1.2.2.dist-info/METADATA,sha256=Yq9gc8IuZxX_2oFTdXmRWiNFfRHQZHyH7p4rKUL9nv4,12736
376
+ specify_cli-1.2.2.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
377
+ specify_cli-1.2.2.dist-info/entry_points.txt,sha256=zO7Jooxo-O6FCM02xdzsNB8WNakvnPDv5bpZr1P4Pmo,45
378
+ specify_cli-1.2.2.dist-info/licenses/LICENSE,sha256=JRC0RrwfDPlwJFMHXSDNiGMeIOVkJljttzJdnB61NPc,1060
379
+ specify_cli-1.2.2.dist-info/RECORD,,