bmad-method 6.11.1-next.25 → 6.11.1-next.26
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/package.json +1 -1
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc +0 -0
- package/src/bmm-skills/plan/bmad-sprint-planning/scripts/tests/__pycache__/test_sprint_plan.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_git_evidence.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/bmm-skills/ship/bmad-retrospective/scripts/tests/__pycache__/test_sprint_status.cpython-311-pytest-9.1.1.pyc +0 -0
- package/src/core-skills/bmad-brainstorming/scripts/brain.py +19 -0
- package/src/core-skills/bmad-brainstorming/scripts/tests/test_brain.py +50 -0
- package/src/scripts/__pycache__/config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_config_utils.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_config.cpython-311.pyc +0 -0
- package/src/scripts/tests/__pycache__/test_resolve_customization.cpython-311.pyc +0 -0
package/package.json
CHANGED
package/src/bmm-skills/plan/bmad-sprint-planning/scripts/__pycache__/sprint_plan.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
package/src/bmm-skills/ship/bmad-retrospective/scripts/__pycache__/sprint_status.cpython-311.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -692,7 +692,26 @@ def html_doc(rows: list[dict]) -> str:
|
|
|
692
692
|
)
|
|
693
693
|
|
|
694
694
|
|
|
695
|
+
def pin_utf8(stream):
|
|
696
|
+
"""Pin a console stream to UTF-8, keeping its own error handler.
|
|
697
|
+
|
|
698
|
+
`--extra` technique text and the technique names echoed to stderr are
|
|
699
|
+
arbitrary user input, so either stream can carry a character the platform
|
|
700
|
+
default cannot encode (cp1252 on Windows) and print() then raises.
|
|
701
|
+
|
|
702
|
+
errors= is passed through deliberately: reconfigure(encoding=...) alone
|
|
703
|
+
resets the handler to "strict", which would silently downgrade stderr's
|
|
704
|
+
POSIX default of "backslashreplace" and turn a diagnostic about an
|
|
705
|
+
undecodable path into a traceback.
|
|
706
|
+
"""
|
|
707
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
708
|
+
if reconfigure is not None:
|
|
709
|
+
reconfigure(encoding="utf-8", errors=getattr(stream, "errors", None) or "strict")
|
|
710
|
+
|
|
711
|
+
|
|
695
712
|
def main(argv: list[str] | None = None) -> int:
|
|
713
|
+
pin_utf8(sys.stdout)
|
|
714
|
+
pin_utf8(sys.stderr)
|
|
696
715
|
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
697
716
|
p.add_argument("--file", type=Path, default=DEFAULT_FILE, help="technique CSV (default: sibling assets/brain-methods.csv)")
|
|
698
717
|
p.add_argument("--extra", type=Path, help="JSON overlay of additional techniques (customize.toml additional_techniques), merged into every command")
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# dependencies = ["pytest>=8.0"]
|
|
4
4
|
# ///
|
|
5
5
|
"""Tests for brain.py. Run: uv run -m pytest scripts/tests/test_brain.py"""
|
|
6
|
+
import io
|
|
6
7
|
import json
|
|
7
8
|
import sys
|
|
8
9
|
from pathlib import Path
|
|
@@ -227,6 +228,55 @@ def test_unknown_category_style_uses_fallback_glyph():
|
|
|
227
228
|
assert glyph == brain._FALLBACK_GLYPH
|
|
228
229
|
|
|
229
230
|
|
|
231
|
+
# --- console encoding (Windows cp1252) ----------------------------------
|
|
232
|
+
|
|
233
|
+
def _cp1252_stream():
|
|
234
|
+
"""A text stream that behaves like a Windows console: cp1252, strict."""
|
|
235
|
+
return io.TextIOWrapper(io.BytesIO(), encoding="cp1252", errors="strict", write_through=True)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_extra_technique_prints_when_stdout_encoding_is_cp1252(lib, tmp_path, monkeypatch):
|
|
239
|
+
# --extra text is arbitrary user input; the shipped catalog happens to be
|
|
240
|
+
# cp1252-safe, an overlay is not. Unpinned stdout raises UnicodeEncodeError
|
|
241
|
+
# and the command exits having printed nothing.
|
|
242
|
+
overlay = tmp_path / "extra.json"
|
|
243
|
+
overlay.write_text(
|
|
244
|
+
json.dumps([{"category": "wild", "technique_name": "Fikir Fırtınası 🌪", "description": "Beyin fırtınası — 日本語"}]),
|
|
245
|
+
encoding="utf-8",
|
|
246
|
+
)
|
|
247
|
+
fake = _cp1252_stream()
|
|
248
|
+
monkeypatch.setattr(sys, "stdout", fake)
|
|
249
|
+
assert brain.main(["--file", str(lib), "--extra", str(overlay), "list", "--all"]) == 0
|
|
250
|
+
out = fake.buffer.getvalue().decode("utf-8")
|
|
251
|
+
assert "Fikir Fırtınası 🌪" in out
|
|
252
|
+
assert "日本語" in out
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def test_missing_technique_name_reports_when_stderr_encoding_is_cp1252(lib, monkeypatch):
|
|
256
|
+
# `show` echoes the name it could not find; that name came from argv.
|
|
257
|
+
fake = _cp1252_stream()
|
|
258
|
+
monkeypatch.setattr(sys, "stderr", fake)
|
|
259
|
+
assert brain.main(["--file", str(lib), "show", "日本語"]) == 1
|
|
260
|
+
assert "日本語" in fake.buffer.getvalue().decode("utf-8")
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def test_pin_utf8_preserves_the_streams_error_handler():
|
|
264
|
+
# reconfigure(encoding=...) on its own resets errors to "strict"; stderr on
|
|
265
|
+
# POSIX defaults to "backslashreplace" and must keep it, or a diagnostic
|
|
266
|
+
# carrying a surrogate-escaped path becomes a traceback.
|
|
267
|
+
stream = io.TextIOWrapper(io.BytesIO(), encoding="ascii", errors="backslashreplace")
|
|
268
|
+
brain.pin_utf8(stream)
|
|
269
|
+
assert stream.encoding == "utf-8"
|
|
270
|
+
assert stream.errors == "backslashreplace"
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def test_pin_utf8_ignores_a_stream_without_reconfigure():
|
|
274
|
+
class Captured: # e.g. pytest's capture object, or a StringIO stand-in
|
|
275
|
+
errors = None
|
|
276
|
+
|
|
277
|
+
brain.pin_utf8(Captured()) # must not raise
|
|
278
|
+
|
|
279
|
+
|
|
230
280
|
def test_shipped_selector_is_in_sync_with_catalog():
|
|
231
281
|
# foolproofing: if someone edits brain-methods.csv they must regenerate the page.
|
|
232
282
|
# Regenerate with: uv run brain.py html --out assets/brain-selector.html
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|