stepgate 0.1.0__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stepgate
3
- Version: 0.1.0
3
+ Version: 0.2.0
4
4
  Summary: A step-gated micro-change protocol CLI for coding agents: propose, approve, execute, verify — one small step at a time.
5
5
  Project-URL: Homepage, https://github.com/LeoCostta/stepgate
6
6
  Project-URL: Repository, https://github.com/LeoCostta/stepgate
@@ -135,7 +135,11 @@ all sessions and agents, append-only.
135
135
  | `stepgate verify --evidence "..."` | Record verification evidence |
136
136
  | `stepgate close` | Close a verified micro-change |
137
137
  | `stepgate abandon --reason "..."` | Cleanly abandon from any non-terminal state |
138
- | `stepgate next --suggest "..."` | Record a next-step suggestion (opens nothing) |
138
+ | `stepgate next [--suggest "..."]` | With `--suggest`, record a next-step suggestion; without it, show the current one |
139
+
140
+ The four flow verbs also accept Portuguese aliases — English stays the default:
141
+ `aprovar` = `approve`, `rejeitar` = `reject`, `fechar` = `close`,
142
+ `proximo` = `next`.
139
143
  | `stepgate status` | Current session + aggregated project view |
140
144
  | `stepgate history [--session X] [--since DATE]` | Append-only, cross-session log |
141
145
  | `stepgate doctor` | Report corrupted/invalid state files (fixes nothing) |
@@ -106,7 +106,11 @@ all sessions and agents, append-only.
106
106
  | `stepgate verify --evidence "..."` | Record verification evidence |
107
107
  | `stepgate close` | Close a verified micro-change |
108
108
  | `stepgate abandon --reason "..."` | Cleanly abandon from any non-terminal state |
109
- | `stepgate next --suggest "..."` | Record a next-step suggestion (opens nothing) |
109
+ | `stepgate next [--suggest "..."]` | With `--suggest`, record a next-step suggestion; without it, show the current one |
110
+
111
+ The four flow verbs also accept Portuguese aliases — English stays the default:
112
+ `aprovar` = `approve`, `rejeitar` = `reject`, `fechar` = `close`,
113
+ `proximo` = `next`.
110
114
  | `stepgate status` | Current session + aggregated project view |
111
115
  | `stepgate history [--session X] [--since DATE]` | Append-only, cross-session log |
112
116
  | `stepgate doctor` | Report corrupted/invalid state files (fixes nothing) |
@@ -1,3 +1,3 @@
1
1
  """stepgate: a step-gated micro-change protocol CLI for coding agents."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.2.0"
@@ -44,13 +44,13 @@ def build_parser() -> argparse.ArgumentParser:
44
44
  p = sub.add_parser("show", help="show the active proposal rendered as prose")
45
45
  _add_session_flags(p)
46
46
 
47
- p = sub.add_parser("approve", help="PENDING -> APPROVED")
47
+ p = sub.add_parser("approve", aliases=["aprovar"], help="PENDING -> APPROVED")
48
48
  p.add_argument("--adjust", action="store_true", help="approve with an adjusted/reduced scope")
49
49
  p.add_argument("--scope", help="comma-separated adjusted scope (files/areas)")
50
50
  p.add_argument("--note", help="note describing the adjustment")
51
51
  _add_session_flags(p)
52
52
 
53
- p = sub.add_parser("reject", help="PENDING -> REJECTED")
53
+ p = sub.add_parser("reject", aliases=["rejeitar"], help="PENDING -> REJECTED")
54
54
  p.add_argument("--note", required=True, help="reason for rejection")
55
55
  _add_session_flags(p)
56
56
 
@@ -63,15 +63,15 @@ def build_parser() -> argparse.ArgumentParser:
63
63
  p.add_argument("--evidence", required=True, help="tests/runs/evidence demonstrating the result")
64
64
  _add_session_flags(p)
65
65
 
66
- p = sub.add_parser("close", help="VERIFIED -> CLOSED")
66
+ p = sub.add_parser("close", aliases=["fechar"], help="VERIFIED -> CLOSED")
67
67
  _add_session_flags(p)
68
68
 
69
69
  p = sub.add_parser("abandon", help="any non-terminal state -> ABANDONED")
70
70
  p.add_argument("--reason", required=True, help="why the proposal is being abandoned")
71
71
  _add_session_flags(p)
72
72
 
73
- p = sub.add_parser("next", help="record a next-step suggestion (does not open a proposal)")
74
- p.add_argument("--suggest", required=True, help="the suggested next step")
73
+ p = sub.add_parser("next", aliases=["proximo"], help="show or record a next-step suggestion (does not open a proposal)")
74
+ p.add_argument("--suggest", help="the suggested next step; omit to show the current one")
75
75
  _add_session_flags(p)
76
76
 
77
77
  p = sub.add_parser("status", help="current session state + aggregated project view")
@@ -115,8 +115,12 @@ def main(argv: list[str] | None = None) -> int:
115
115
  "history": views.cmd_history,
116
116
  "doctor": doctor.cmd_doctor,
117
117
  }
118
+ # argparse fills args.command with the alias actually typed, so map the
119
+ # convenience aliases back to their canonical command name.
120
+ aliases = {"aprovar": "approve", "rejeitar": "reject", "fechar": "close", "proximo": "next"}
121
+ command = aliases.get(args.command, args.command)
118
122
  try:
119
- return handlers[args.command](args)
123
+ return handlers[command](args)
120
124
  except StepgateError as exc:
121
125
  print(f"stepgate: error: {exc}", file=sys.stderr)
122
126
  return 1
@@ -54,7 +54,8 @@ the scope of *execution*, never the depth of *investigation*. Then:
54
54
  `stepgate exec-log --summary "..." --files "a,b"`.
55
55
  4. Verify with real evidence: `stepgate verify --evidence "npm test: 12 passed"`.
56
56
  5. After the user runs `stepgate close`, suggest (don't start) the next step:
57
- `stepgate next --suggest "..."`.
57
+ `stepgate next --suggest "..."`. Running `stepgate next` with no `--suggest`
58
+ just shows the currently recorded suggestion, without changing anything.
58
59
 
59
60
  **Rules:**
60
61
  - Approval is per micro-change, never cumulative. One approval is not a blanket
@@ -68,6 +69,8 @@ the scope of *execution*, never the depth of *investigation*. Then:
68
69
  proposing, or when closing a cycle) — not as a habitual check.
69
70
  - stepgate never blocks edits, commits, or the user. It records and makes the
70
71
  flow visible; deviating from it is visible, never silent.
72
+ - The four flow verbs accept Portuguese aliases (English stays the default):
73
+ `aprovar` = approve, `rejeitar` = reject, `fechar` = close, `proximo` = next.
71
74
  {END_MARKER}"""
72
75
 
73
76
 
@@ -8,6 +8,8 @@ import json
8
8
  import subprocess
9
9
  from pathlib import Path
10
10
 
11
+ from rich.text import Text
12
+
11
13
  from stepgate import render
12
14
  from stepgate.model import (
13
15
  APPROVED,
@@ -228,6 +230,22 @@ def cmd_abandon(args) -> int:
228
230
  def cmd_next(args) -> int:
229
231
  store = Store.find()
230
232
  session = resolve_session(store, args, active_only=False)
233
+ if args.suggest is None:
234
+ if session.pending_suggestion:
235
+ render.console.print(
236
+ Text.assemble(
237
+ ("Suggested next step", "bold green"),
238
+ (f" ({session.name}): ", "dim"),
239
+ session.pending_suggestion,
240
+ )
241
+ )
242
+ else:
243
+ render.info(
244
+ f"No next-step suggestion recorded in session "
245
+ f"[bold magenta]{session.name}[/]. Record one with "
246
+ "'stepgate next --suggest \"...\"'."
247
+ )
248
+ return 0
231
249
  session.pending_suggestion = args.suggest
232
250
  store.save_session(session)
233
251
  store.append_history(session.name, session.agent, "next-suggest", {"suggestion": args.suggest})
@@ -54,6 +54,49 @@ def test_full_cycle(project, plan_file, capsys):
54
54
  assert read_state(project).pending_suggestion is None
55
55
 
56
56
 
57
+ def test_next_without_suggest_shows_current(project, plan_file, capsys):
58
+ run("propose", "--agent", "claude", "--file", str(plan_file))
59
+ run("next", "--agent", "claude", "--suggest", "wire SalaJogo.tsx via supabase.rpc")
60
+ store = Store.find(project)
61
+ before = len(store.read_history())
62
+ capsys.readouterr()
63
+
64
+ # read-only: prints the recorded suggestion, writes nothing
65
+ assert run("next", "--agent", "claude") == 0
66
+ assert "supabase.rpc" in capsys.readouterr().out
67
+ assert len(Store.find(project).read_history()) == before
68
+
69
+
70
+ def test_next_without_suggest_and_none_recorded(project, plan_file, capsys):
71
+ run("propose", "--agent", "claude", "--file", str(plan_file))
72
+ capsys.readouterr()
73
+ assert run("next", "--agent", "claude") == 0
74
+ assert "No next-step suggestion" in capsys.readouterr().out
75
+
76
+
77
+ def test_portuguese_aliases(project, plan_file, capsys):
78
+ run("propose", "--agent", "claude", "--file", str(plan_file))
79
+ # 'aprovar' == approve
80
+ assert run("aprovar", "--agent", "claude") == 0
81
+ assert read_state(project).proposal.state == "APPROVED"
82
+ run("exec-log", "--agent", "claude", "--summary", "done")
83
+ run("verify", "--agent", "claude", "--evidence", "ok")
84
+ # 'fechar' == close
85
+ assert run("fechar", "--agent", "claude") == 0
86
+ assert read_state(project).proposal.state == "CLOSED"
87
+ # 'proximo' == next: records with --suggest, reads without it
88
+ assert run("proximo", "--agent", "claude", "--suggest", "wire it up") == 0
89
+ capsys.readouterr()
90
+ assert run("proximo", "--agent", "claude") == 0
91
+ assert "wire it up" in capsys.readouterr().out
92
+
93
+
94
+ def test_rejeitar_alias(project, plan_file):
95
+ run("propose", "--agent", "claude", "--file", str(plan_file))
96
+ assert run("rejeitar", "--agent", "claude", "--note", "abordagem errada") == 0
97
+ assert read_state(project).proposal.state == "REJECTED"
98
+
99
+
57
100
  def test_cannot_skip_states_via_cli(project, plan_file, capsys):
58
101
  run("propose", "--agent", "claude", "--file", str(plan_file))
59
102
  assert run("exec-log", "--agent", "claude", "--summary", "sneaky") == 1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes