MCPcopy
hub / github.com/github/spec-kit / execute

Method execute

src/specify_cli/workflows/steps/gate/__init__.py:38–90  ·  view source on GitHub ↗
(self, config: dict[str, Any], context: StepContext)

Source from the content-addressed store, hash-verified

36 MAX_SHOW_FILE_LINES = 200
37
38 def execute(self, config: dict[str, Any], context: StepContext) -> StepResult:
39 message = config.get("message", "Review required.")
40 if isinstance(message, str) and "{{" in message:
41 message = evaluate_expression(message, context)
42
43 options = config.get("options", ["approve", "reject"])
44 on_reject = config.get("on_reject", "abort")
45
46 show_file = config.get("show_file")
47 if isinstance(show_file, str) and "{{" in show_file:
48 show_file = evaluate_expression(show_file, context)
49 # ``evaluate_expression`` can return a non-string for a single
50 # expression (e.g. a number from a prior step), and a literal
51 # non-string is also possible; coerce so it is rendered rather
52 # than silently skipped at the prompt.
53 if show_file is not None:
54 show_file = str(show_file)
55
56 output = {
57 "message": message,
58 "options": options,
59 "on_reject": on_reject,
60 "show_file": show_file,
61 "choice": None,
62 }
63
64 # Non-interactive: pause for later resume (the file is not read here)
65 if not sys.stdin.isatty():
66 return StepResult(status=StepStatus.PAUSED, output=output)
67
68 # Interactive: prompt the user. ``show_file`` contents are folded
69 # into the displayed message so the operator can review the
70 # referenced material before choosing. Composing the prompt text
71 # here keeps ``_prompt`` to its ``(message, options)`` contract, so
72 # adding review material never widens the interactive seam.
73 choice = self._prompt(self._compose_prompt(message, show_file), options)
74 output["choice"] = choice
75
76 if choice in ("reject", "abort"):
77 if on_reject == "abort":
78 output["aborted"] = True
79 return StepResult(
80 status=StepStatus.FAILED,
81 output=output,
82 error=f"Gate rejected by user at step {config.get('id', '?')!r}",
83 )
84 if on_reject == "retry":
85 # Pause so the next resume re-executes this gate
86 return StepResult(status=StepStatus.PAUSED, output=output)
87 # on_reject == "skip" → completed, downstream steps decide
88 return StepResult(status=StepStatus.COMPLETED, output=output)
89
90 return StepResult(status=StepStatus.COMPLETED, output=output)
91
92 @classmethod
93 def _compose_prompt(cls, message: object, show_file: str | None) -> str:

Calls 6

_promptMethod · 0.95
_compose_promptMethod · 0.95
evaluate_expressionFunction · 0.90
StepResultClass · 0.90
isattyMethod · 0.80
getMethod · 0.45