brain-wiki 0.1.0.dev0__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.
Files changed (141) hide show
  1. brain_wiki-0.1.0.dev0.dist-info/METADATA +231 -0
  2. brain_wiki-0.1.0.dev0.dist-info/RECORD +141 -0
  3. brain_wiki-0.1.0.dev0.dist-info/WHEEL +4 -0
  4. brain_wiki-0.1.0.dev0.dist-info/entry_points.txt +4 -0
  5. brain_wiki-0.1.0.dev0.dist-info/licenses/LICENSE +202 -0
  6. brainwiki/__init__.py +17 -0
  7. brainwiki/__main__.py +5 -0
  8. brainwiki/assets/plugin/.claude-plugin/marketplace.json +16 -0
  9. brainwiki/assets/plugin/.claude-plugin/plugin.json +19 -0
  10. brainwiki/assets/plugin/.mcp.json +16 -0
  11. brainwiki/assets/plugin/mcp.json +17 -0
  12. brainwiki/assets/plugin/mcp_config.json +15 -0
  13. brainwiki/assets/plugin/plugin.json +37 -0
  14. brainwiki/assets/plugin/rules/brain-wiki.md +30 -0
  15. brainwiki/assets/plugin/server.json +30 -0
  16. brainwiki/assets/plugin/skills/brain/SKILL.md +145 -0
  17. brainwiki/assets/plugin/skills/brain/references/format.md +149 -0
  18. brainwiki/assets/plugin/skills/brain-maintain/SKILL.md +111 -0
  19. brainwiki/assets/plugin/skills/brain-maintain/references/consolidate.md +91 -0
  20. brainwiki/assets/plugin/skills/brain-maintain/references/harvest.md +144 -0
  21. brainwiki/assets/plugin/skills/brain-setup/SKILL.md +184 -0
  22. brainwiki/assets/plugin/skills/brain-setup/references/hosts.md +88 -0
  23. brainwiki/assets/plugin/skills/brain-setup/references/privacy.md +67 -0
  24. brainwiki/assets/prompts/consolidate.md +89 -0
  25. brainwiki/assets/prompts/distill.md +96 -0
  26. brainwiki/assets/prompts/harvest.md +142 -0
  27. brainwiki/bench/__init__.py +8 -0
  28. brainwiki/bench/_generate.py +440 -0
  29. brainwiki/bench/_report.py +166 -0
  30. brainwiki/bench/_suites.py +959 -0
  31. brainwiki/cli/__init__.py +7 -0
  32. brainwiki/cli/_cmd_bench.py +101 -0
  33. brainwiki/cli/_cmd_browse.py +281 -0
  34. brainwiki/cli/_cmd_consolidate.py +108 -0
  35. brainwiki/cli/_cmd_core.py +155 -0
  36. brainwiki/cli/_cmd_harvest.py +137 -0
  37. brainwiki/cli/_cmd_hosts.py +52 -0
  38. brainwiki/cli/_cmd_import.py +149 -0
  39. brainwiki/cli/_cmd_lint.py +117 -0
  40. brainwiki/cli/_cmd_read.py +131 -0
  41. brainwiki/cli/_cmd_runs.py +66 -0
  42. brainwiki/cli/_cmd_viz.py +57 -0
  43. brainwiki/cli/_cmd_write.py +122 -0
  44. brainwiki/cli/_main.py +511 -0
  45. brainwiki/cli/_output.py +19 -0
  46. brainwiki/config/__init__.py +56 -0
  47. brainwiki/config/_dirs.py +69 -0
  48. brainwiki/config/_manifest.py +307 -0
  49. brainwiki/config/_resolve.py +169 -0
  50. brainwiki/config/_user.py +183 -0
  51. brainwiki/consolidate/__init__.py +19 -0
  52. brainwiki/consolidate/_apply.py +408 -0
  53. brainwiki/consolidate/_packet.py +489 -0
  54. brainwiki/consolidate/_pipeline.py +215 -0
  55. brainwiki/consolidate/_presets.py +230 -0
  56. brainwiki/consolidate/_review.py +104 -0
  57. brainwiki/consolidate/_schema.py +153 -0
  58. brainwiki/consolidate/_validate.py +252 -0
  59. brainwiki/doctor.py +216 -0
  60. brainwiki/engine.py +80 -0
  61. brainwiki/errors.py +81 -0
  62. brainwiki/format/__init__.py +112 -0
  63. brainwiki/format/_agents_md.py +26 -0
  64. brainwiki/format/_claims.py +95 -0
  65. brainwiki/format/_document.py +203 -0
  66. brainwiki/format/_edit.py +94 -0
  67. brainwiki/format/_episode.py +67 -0
  68. brainwiki/format/_fields.py +350 -0
  69. brainwiki/format/_frontmatter.py +175 -0
  70. brainwiki/format/_links.py +72 -0
  71. brainwiki/format/_meta.py +67 -0
  72. brainwiki/format/_normalize.py +70 -0
  73. brainwiki/format/_relations.py +211 -0
  74. brainwiki/format/_rules.py +41 -0
  75. brainwiki/harvest.py +414 -0
  76. brainwiki/hosts/__init__.py +22 -0
  77. brainwiki/hosts/_antigravity.py +163 -0
  78. brainwiki/hosts/_claude_code.py +174 -0
  79. brainwiki/hosts/_codex.py +149 -0
  80. brainwiki/hosts/_connect.py +443 -0
  81. brainwiki/hosts/_detect.py +39 -0
  82. brainwiki/hosts/_instructions.py +220 -0
  83. brainwiki/hosts/_sessions.py +176 -0
  84. brainwiki/ids.py +69 -0
  85. brainwiki/importer/__init__.py +17 -0
  86. brainwiki/importer/_episodes.py +112 -0
  87. brainwiki/importer/_into.py +102 -0
  88. brainwiki/importer/_normalize.py +64 -0
  89. brainwiki/importer/_overlay.py +199 -0
  90. brainwiki/importer/_survey.py +167 -0
  91. brainwiki/index/__init__.py +44 -0
  92. brainwiki/index/_brains.py +119 -0
  93. brainwiki/index/_db.py +131 -0
  94. brainwiki/index/_guards.py +154 -0
  95. brainwiki/index/_neighbors.py +174 -0
  96. brainwiki/index/_orient.py +400 -0
  97. brainwiki/index/_read.py +285 -0
  98. brainwiki/index/_resolver.py +147 -0
  99. brainwiki/index/_scanner.py +665 -0
  100. brainwiki/index/_schema.py +164 -0
  101. brainwiki/index/_search.py +659 -0
  102. brainwiki/index/_topics.py +253 -0
  103. brainwiki/index/_written.py +29 -0
  104. brainwiki/lifecycle.py +158 -0
  105. brainwiki/lint/__init__.py +20 -0
  106. brainwiki/lint/_catalog.py +85 -0
  107. brainwiki/lint/_cross.py +649 -0
  108. brainwiki/lint/_files.py +483 -0
  109. brainwiki/lint/_fixes.py +87 -0
  110. brainwiki/lint/_hook.py +54 -0
  111. brainwiki/lint/_model.py +103 -0
  112. brainwiki/lint/_reports.py +242 -0
  113. brainwiki/lint/_runner.py +156 -0
  114. brainwiki/logs.py +34 -0
  115. brainwiki/mcp/__init__.py +7 -0
  116. brainwiki/mcp/_server.py +917 -0
  117. brainwiki/origin.py +97 -0
  118. brainwiki/runs/__init__.py +21 -0
  119. brainwiki/runs/_git.py +89 -0
  120. brainwiki/runs/_lock.py +42 -0
  121. brainwiki/runs/_record.py +145 -0
  122. brainwiki/runs/_transaction.py +441 -0
  123. brainwiki/runs/_undo.py +159 -0
  124. brainwiki/setup_wizard.py +143 -0
  125. brainwiki/store/__init__.py +7 -0
  126. brainwiki/store/_local.py +153 -0
  127. brainwiki/viz/__init__.py +9 -0
  128. brainwiki/viz/_export.py +414 -0
  129. brainwiki/viz/_lod.py +455 -0
  130. brainwiki/viz/_server.py +327 -0
  131. brainwiki/viz/app/BUILD_INFO.json +5 -0
  132. brainwiki/viz/app/THIRD_PARTY_NOTICES.txt +1519 -0
  133. brainwiki/viz/app/assets/index-gK1pnQdO.js +4496 -0
  134. brainwiki/viz/app/assets/style-Cg8NUCst.css +1 -0
  135. brainwiki/viz/app/index.html +14 -0
  136. brainwiki/write/__init__.py +23 -0
  137. brainwiki/write/_edits.py +730 -0
  138. brainwiki/write/_episode.py +195 -0
  139. brainwiki/write/_move.py +181 -0
  140. brainwiki/write/_rules.py +204 -0
  141. brainwiki/write/_secrets.py +108 -0
@@ -0,0 +1,166 @@
1
+ """Bench output: results.json, report.md, a terminal table, and comparisons (design doc 11 §5)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from collections import defaultdict
7
+ from datetime import UTC, datetime
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from brainwiki.bench._suites import SuiteResult
12
+
13
+ _SCHEMA = 1
14
+
15
+
16
+ def build(results: list[SuiteResult], **meta: Any) -> dict[str, Any]:
17
+ import brainwiki
18
+
19
+ return {
20
+ "schema": _SCHEMA,
21
+ "version": brainwiki.__version__,
22
+ "created": datetime.now(UTC).replace(microsecond=0).isoformat(),
23
+ **meta,
24
+ "suites": {
25
+ r.name: {"status": r.status, "skipped": r.skipped, "details": r.details}
26
+ for r in results
27
+ },
28
+ "metrics": [m.to_json() for r in results for m in r.metrics],
29
+ }
30
+
31
+
32
+ def hard_failures(data: dict[str, Any]) -> list[dict[str, Any]]:
33
+ return [m for m in data["metrics"] if m["hard"] and m["pass"] is False]
34
+
35
+
36
+ def _value(value: Any) -> str:
37
+ if isinstance(value, float):
38
+ return f"{value:.4g}"
39
+ text = "-" if value is None else str(value)
40
+ return text if len(text) <= 60 else text[:59] + "…" # results.json keeps the full text
41
+
42
+
43
+ def _ok(row: dict[str, Any]) -> str:
44
+ return {True: "ok", False: "FAIL" if row["hard"] else "miss", None: ""}[row["pass"]]
45
+
46
+
47
+ def _render(rows: list[list[str]], header: list[str], markdown: bool) -> list[str]:
48
+ if markdown:
49
+ lines = ["| " + " | ".join(header) + " |", "|" + "---|" * len(header)]
50
+ return lines + ["| " + " | ".join(r) + " |" for r in rows]
51
+ widths = [max(len(x) for x in col) for col in zip(header, *rows, strict=False)]
52
+ return [
53
+ " ".join(cell.ljust(w) for cell, w in zip(row, widths, strict=False)).rstrip()
54
+ for row in [header, *rows]
55
+ ]
56
+
57
+
58
+ def table(data: dict[str, Any], *, markdown: bool = False, collapse: int = 6) -> str:
59
+ """One line per metric; groups larger than `collapse` (lint rules) fold into their worst value."""
60
+ header = ["suite", "case", "backend", "metric", "value", "target", "ok"]
61
+ groups: dict[tuple[str, str, str], list[dict[str, Any]]] = defaultdict(list)
62
+ for row in data["metrics"]:
63
+ groups[(row["suite"], row["metric"], row["backend"])].append(row)
64
+ rows: list[list[str]] = []
65
+ for (suite, metric, backend), members in groups.items():
66
+ numeric = [m for m in members if isinstance(m["value"], int | float)]
67
+ if len(members) <= collapse or len(numeric) != len(members):
68
+ for m in members:
69
+ rows.append(
70
+ [
71
+ suite,
72
+ m["case"],
73
+ backend,
74
+ metric,
75
+ _value(m["value"]),
76
+ m["target"] or "",
77
+ _ok(m),
78
+ ]
79
+ )
80
+ continue
81
+ failed = [m["case"] for m in members if m["pass"] is False]
82
+ worst = min(numeric, key=lambda m: m["value"] if metric != "violations" else -m["value"])
83
+ case = f"{len(members)} cases" + (f"; failing: {', '.join(failed)}" if failed else "")
84
+ rows.append(
85
+ [
86
+ suite,
87
+ case,
88
+ backend,
89
+ metric,
90
+ _value(worst["value"]),
91
+ worst["target"] or "",
92
+ _ok(worst),
93
+ ]
94
+ )
95
+ for name, suite in data["suites"].items():
96
+ if suite["skipped"]:
97
+ rows.append([name, "-", "-", "status", "skipped", "", ""])
98
+ return "\n".join(_render(rows, header, markdown))
99
+
100
+
101
+ def _markdown(data: dict[str, Any]) -> str:
102
+ lines = [
103
+ "# brain-wiki bench",
104
+ "",
105
+ f"`{data.get('command', 'brain bench')}` · brain-wiki {data['version']} · {data['created']}",
106
+ "",
107
+ "| suite | status |",
108
+ "|---|---|",
109
+ *[f"| {n} | {s['status']} |" for n, s in data["suites"].items()],
110
+ "",
111
+ ]
112
+ for name, suite in data["suites"].items():
113
+ lines += [f"## {name}", ""]
114
+ if suite["skipped"]:
115
+ lines += [f"Skipped: {suite['skipped']}", ""]
116
+ continue
117
+ rows = [m for m in data["metrics"] if m["suite"] == name]
118
+ worst = [m for m in rows if m["metric"].startswith("worst_model")]
119
+ sub = {"metrics": worst + [m for m in rows if m not in worst], "suites": {}}
120
+ lines += [table(sub, markdown=True, collapse=10_000), ""]
121
+ for key, value in suite["details"].items():
122
+ if value in ({}, [], None):
123
+ continue
124
+ text = json.dumps(value, indent=1, ensure_ascii=False)
125
+ lines += [f"**{key}**", "", "```json", text, "```", ""]
126
+ return "\n".join(lines)
127
+
128
+
129
+ def write(out: Path, data: dict[str, Any]) -> tuple[Path, Path]:
130
+ out.mkdir(parents=True, exist_ok=True)
131
+ results, report = out / "results.json", out / "report.md"
132
+ results.write_text(json.dumps(data, indent=1, ensure_ascii=False) + "\n", encoding="utf-8")
133
+ report.write_text(_markdown(data), encoding="utf-8")
134
+ return results, report
135
+
136
+
137
+ def compare(a: Path, b: Path) -> tuple[str, int]:
138
+ """Metric deltas from results file A to B, and the number of regressions (pass -> fail)."""
139
+ old, new = (json.loads(Path(p).read_text(encoding="utf-8")) for p in (a, b))
140
+
141
+ def key(m: dict[str, Any]) -> tuple[str, str, str, str]:
142
+ return (m["suite"], m["case"], m["backend"], m["metric"])
143
+
144
+ before = {key(m): m for m in old["metrics"]}
145
+ after = {key(m): m for m in new["metrics"]}
146
+ lines, regressions = [], 0
147
+ for k in sorted(before.keys() | after.keys()):
148
+ x, y = before.get(k), after.get(k)
149
+ name = " ".join(p for p in k if p != "-")
150
+ if x is None or y is None:
151
+ lines.append(f"{'+' if x is None else '-'} {name}: {_value((y or x)['value'])}")
152
+ continue
153
+ if x["value"] == y["value"] and x["pass"] == y["pass"]:
154
+ continue
155
+ mark = " "
156
+ if x["pass"] is not False and y["pass"] is False:
157
+ mark, regressions = "!", regressions + 1
158
+ elif x["pass"] is False and y["pass"] is not False:
159
+ mark = "*"
160
+ delta = ""
161
+ if isinstance(x["value"], int | float) and isinstance(y["value"], int | float):
162
+ delta = f" ({y['value'] - x['value']:+.4g})"
163
+ lines.append(f"{mark} {name}: {_value(x['value'])} -> {_value(y['value'])}{delta}")
164
+ head = f"{a} ({old['version']}) -> {b} ({new['version']}): {regressions} regression(s)"
165
+ legend = "! regression (pass -> fail) * fixed (fail -> pass) +/- metric added/removed"
166
+ return "\n".join([head, legend, *(lines or ["no metric changed"])]), regressions