@seanyao/roll 3.609.2 → 3.610.1
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.
- package/CHANGELOG.md +23 -1
- package/README.md +1 -2
- package/dist/roll.mjs +20572 -18445
- package/package.json +1 -2
- package/bin/roll +0 -15361
- package/lib/backfill-pi-usage.py +0 -243
- package/lib/changelog_audit.py +0 -149
- package/lib/changelog_generate.py +0 -470
- package/lib/consistency_check.py +0 -409
- package/lib/context_feed_budget.sh +0 -194
- package/lib/github_sync.py +0 -876
- package/lib/i18n.sh +0 -211
- package/lib/loop-exit-summary.py +0 -393
- package/lib/loop-fmt.py +0 -589
- package/lib/loop_pick_agent.py +0 -316
- package/lib/loop_result_eval.py +0 -469
- package/lib/loop_unstick.py +0 -180
- package/lib/model_prices.py +0 -194
- package/lib/prices_fetcher.py +0 -534
- package/lib/roll-backlog.py +0 -225
- package/lib/roll-brief.py +0 -286
- package/lib/roll-help.py +0 -158
- package/lib/roll-home.py +0 -556
- package/lib/roll-init.py +0 -156
- package/lib/roll-loop-status.py +0 -1691
- package/lib/roll-loop-story.py +0 -191
- package/lib/roll-peer.py +0 -252
- package/lib/roll-setup.py +0 -102
- package/lib/roll-status.py +0 -367
- package/lib/roll_git.py +0 -41
- package/lib/roll_render.py +0 -414
- package/lib/slides-render.py +0 -778
- package/lib/slides-validate.py +0 -357
- package/lib/test_quality_gate.py +0 -143
package/lib/roll-init.py
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""roll-init — v2 terminal view for `roll init`.
|
|
3
|
-
|
|
4
|
-
Reads a single JSON document from stdin describing real step outcomes
|
|
5
|
-
captured by the bash flow in `bin/roll cmd_init`. Renders the v2 UI
|
|
6
|
-
(banner + horizontal rule + numbered steps + NEXT block) preserving the
|
|
7
|
-
visual style of US-VIEW-008 but reflecting what actually happened.
|
|
8
|
-
|
|
9
|
-
Input schema (single JSON object on stdin):
|
|
10
|
-
{
|
|
11
|
-
"kind": "init", # informational; UI label uses header_label
|
|
12
|
-
"header_label": "INIT", # banner label (e.g. "INIT" / "REINIT")
|
|
13
|
-
"subtitle": "项目初始化", # banner subtitle
|
|
14
|
-
"project_path": "/path/to/project", # right-aligned banner text
|
|
15
|
-
"steps": [
|
|
16
|
-
{"num": 1, "label": "Detect project type", "status": "ok"},
|
|
17
|
-
{"num": 2, "label": "Create AGENTS.md", "status": "ok",
|
|
18
|
-
"files": [["+", "AGENTS.md"]]},
|
|
19
|
-
{"num": 3, "label": "...", "status": "skip", "note": "already exists"},
|
|
20
|
-
{"num": 4, "label": "...", "status": "fail", "error": "permission denied"}
|
|
21
|
-
],
|
|
22
|
-
"footer": {"status": "ok", "label": "Project ready"},
|
|
23
|
-
"next": [["Edit .roll/backlog.md", "open the backlog and add your first US"]]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
`status` values: ok | skip | fail.
|
|
27
|
-
`files` ops: "+" created "~" merged "·" unchanged "✗" failed.
|
|
28
|
-
|
|
29
|
-
If stdin is empty or invalid JSON, exit 1 with a short message — the
|
|
30
|
-
renderer is no longer runnable standalone, it always renders real data.
|
|
31
|
-
"""
|
|
32
|
-
from __future__ import annotations
|
|
33
|
-
|
|
34
|
-
import argparse
|
|
35
|
-
import json
|
|
36
|
-
import os
|
|
37
|
-
import sys
|
|
38
|
-
|
|
39
|
-
_LIB_DIR = os.path.dirname(os.path.realpath(__file__))
|
|
40
|
-
if _LIB_DIR not in sys.path:
|
|
41
|
-
sys.path.insert(0, _LIB_DIR)
|
|
42
|
-
import roll_render
|
|
43
|
-
from roll_render import c, row, COLS
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
def _divider(char: str = "─") -> None:
|
|
47
|
-
print(c("dim", char * min(COLS, 80)))
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def _op_marker(op: str) -> str:
|
|
51
|
-
if op == "+":
|
|
52
|
-
return c("green", "+", bold=True)
|
|
53
|
-
if op == "~":
|
|
54
|
-
return c("amber", "~", bold=True)
|
|
55
|
-
if op == "·":
|
|
56
|
-
return c("dim", "·")
|
|
57
|
-
if op == "✗":
|
|
58
|
-
return c("red", "✗", bold=True)
|
|
59
|
-
return c("dim", op)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def _step_icon(status: str) -> str:
|
|
63
|
-
if status == "ok":
|
|
64
|
-
return c("green", "✓")
|
|
65
|
-
if status == "skip":
|
|
66
|
-
return c("amber", "↷")
|
|
67
|
-
if status == "fail":
|
|
68
|
-
return c("red", "✗", bold=True)
|
|
69
|
-
return c("dim", "·")
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def _file_color(op: str) -> str:
|
|
73
|
-
if op == "+":
|
|
74
|
-
return "green"
|
|
75
|
-
if op == "~":
|
|
76
|
-
return "amber"
|
|
77
|
-
if op == "✗":
|
|
78
|
-
return "red"
|
|
79
|
-
return "dim"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def render(payload: dict) -> None:
|
|
83
|
-
header_label = payload.get("header_label", "INIT")
|
|
84
|
-
subtitle = payload.get("subtitle", "项目初始化")
|
|
85
|
-
project_path = payload.get("project_path", "")
|
|
86
|
-
|
|
87
|
-
left = " " + c("blue", header_label, bold=True) + c("dim", " · ") + c("dim", subtitle)
|
|
88
|
-
right = c("dim", project_path) + " "
|
|
89
|
-
print(row(left, right))
|
|
90
|
-
_divider()
|
|
91
|
-
print()
|
|
92
|
-
|
|
93
|
-
for step in payload.get("steps", []):
|
|
94
|
-
num = c("dim", f" {step.get('num', 0)}.")
|
|
95
|
-
icon = _step_icon(step.get("status", "ok"))
|
|
96
|
-
label = step.get("label", "")
|
|
97
|
-
print(f"{num} {icon} {label}")
|
|
98
|
-
for entry in step.get("files", []) or []:
|
|
99
|
-
op, fname = entry[0], entry[1]
|
|
100
|
-
mark = _op_marker(op)
|
|
101
|
-
color = _file_color(op)
|
|
102
|
-
print(" " + mark + " " + c(color, fname))
|
|
103
|
-
note = step.get("note") or step.get("error")
|
|
104
|
-
if note:
|
|
105
|
-
tone = "red" if step.get("status") == "fail" else "dim"
|
|
106
|
-
print(" " + c(tone, str(note)))
|
|
107
|
-
|
|
108
|
-
print()
|
|
109
|
-
_divider()
|
|
110
|
-
|
|
111
|
-
footer = payload.get("footer") or {}
|
|
112
|
-
f_status = footer.get("status", "ok")
|
|
113
|
-
f_label = footer.get("label", "Done")
|
|
114
|
-
icon_color = "green" if f_status == "ok" else "red"
|
|
115
|
-
icon = "✓" if f_status == "ok" else "✗"
|
|
116
|
-
print(" " + c(icon_color, icon) + " " + c(icon_color, f_label, bold=True))
|
|
117
|
-
|
|
118
|
-
next_items = payload.get("next") or []
|
|
119
|
-
if next_items:
|
|
120
|
-
print()
|
|
121
|
-
print(" " + c("pink", "NEXT", bold=True) + c("dim", " · 下一步"))
|
|
122
|
-
for i, entry in enumerate(next_items, start=1):
|
|
123
|
-
label = entry[0]
|
|
124
|
-
hint = entry[1] if len(entry) > 1 else ""
|
|
125
|
-
num = c("dim", f" {i}.")
|
|
126
|
-
print(f"{num} {c('fg', label, bold=True)}")
|
|
127
|
-
if hint:
|
|
128
|
-
print(" " + c("dim", hint))
|
|
129
|
-
_divider("═")
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
def _read_payload() -> dict:
|
|
133
|
-
raw = sys.stdin.read()
|
|
134
|
-
if not raw.strip():
|
|
135
|
-
sys.stderr.write("roll-init.py: expected JSON on stdin\n")
|
|
136
|
-
sys.exit(1)
|
|
137
|
-
try:
|
|
138
|
-
return json.loads(raw)
|
|
139
|
-
except json.JSONDecodeError as exc:
|
|
140
|
-
sys.stderr.write(f"roll-init.py: invalid JSON on stdin: {exc}\n")
|
|
141
|
-
sys.exit(1)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def main() -> None:
|
|
145
|
-
ap = argparse.ArgumentParser(add_help=False)
|
|
146
|
-
ap.add_argument("--no-color", dest="no_color", action="store_true")
|
|
147
|
-
args, _ = ap.parse_known_args()
|
|
148
|
-
|
|
149
|
-
if args.no_color or os.environ.get("NO_COLOR") or not sys.stdout.isatty():
|
|
150
|
-
roll_render.USE_COLOR = False
|
|
151
|
-
|
|
152
|
-
render(_read_payload())
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if __name__ == "__main__":
|
|
156
|
-
main()
|