claude-dev-env 1.82.0 → 1.84.0

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 (217) hide show
  1. package/CLAUDE.md +16 -13
  2. package/_shared/pr-loop/audit-contract.md +24 -12
  3. package/_shared/pr-loop/scripts/CLAUDE.md +1 -0
  4. package/_shared/pr-loop/scripts/README.md +1 -0
  5. package/_shared/pr-loop/scripts/_claude_permissions_common.py +16 -5
  6. package/_shared/pr-loop/scripts/code_rules_gate.py +2 -3
  7. package/_shared/pr-loop/scripts/pr_loop_shared_constants/CLAUDE.md +1 -0
  8. package/_shared/pr-loop/scripts/pr_loop_shared_constants/reviewer_availability_constants.py +12 -0
  9. package/_shared/pr-loop/scripts/pr_loop_shared_constants/terminology_sweep_constants.py +0 -2
  10. package/_shared/pr-loop/scripts/reviewer_availability.py +182 -0
  11. package/_shared/pr-loop/scripts/reviews_disabled.py +2 -0
  12. package/_shared/pr-loop/scripts/terminology_sweep.py +9 -33
  13. package/_shared/pr-loop/scripts/tests/CLAUDE.md +2 -0
  14. package/_shared/pr-loop/scripts/tests/test__claude_permissions_common.py +212 -0
  15. package/_shared/pr-loop/scripts/tests/test_agent_config_carveout.py +18 -0
  16. package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +18 -0
  17. package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +37 -0
  18. package/_shared/pr-loop/scripts/tests/test_reviewer_availability.py +159 -0
  19. package/_shared/pr-loop/scripts/tests/test_reviewer_availability_constants.py +36 -0
  20. package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +14 -0
  21. package/_shared/pr-loop/scripts/tests/test_terminology_sweep.py +14 -4
  22. package/agents/clean-coder.md +3 -0
  23. package/audit-rubrics/category_rubrics/category-o-docstring-vs-impl-drift.md +1 -1
  24. package/bin/install.mjs +16 -8
  25. package/bin/install.test.mjs +17 -6
  26. package/commands/CLAUDE.md +0 -1
  27. package/docs/CODE_RULES.md +1 -1
  28. package/hooks/blocking/CLAUDE.md +2 -4
  29. package/hooks/blocking/code_rules_constants_config.py +164 -1
  30. package/hooks/blocking/code_rules_docstrings.py +428 -15
  31. package/hooks/blocking/code_rules_enforcer.py +33 -0
  32. package/hooks/blocking/code_rules_imports_logging.py +867 -1
  33. package/hooks/blocking/code_rules_magic_values.py +5 -0
  34. package/hooks/blocking/code_rules_naming_collection.py +152 -6
  35. package/hooks/blocking/code_rules_shared.py +34 -0
  36. package/hooks/blocking/code_rules_string_magic.py +68 -0
  37. package/hooks/blocking/duplicate_rmtree_helper_blocker.py +4 -4
  38. package/hooks/blocking/pre_tool_use_dispatcher.py +3 -3
  39. package/hooks/blocking/reviewer_spawn_gate.py +182 -0
  40. package/hooks/blocking/stale_comment_reference_blocker.py +267 -0
  41. package/hooks/blocking/state_description_blocker.py +96 -5
  42. package/hooks/blocking/test_code_rules_config_duplicate_path_anchor.py +132 -0
  43. package/hooks/blocking/test_code_rules_enforcer_cap_meta.py +2 -0
  44. package/hooks/blocking/test_code_rules_enforcer_docstring_delegation_summary.py +385 -0
  45. package/hooks/blocking/test_code_rules_enforcer_docstring_prose_wall_illustration.py +197 -0
  46. package/hooks/blocking/test_code_rules_enforcer_docstring_runon_sentence.py +27 -0
  47. package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +67 -0
  48. package/hooks/blocking/test_code_rules_enforcer_module_docstring_roster.py +40 -0
  49. package/hooks/blocking/test_code_rules_enforcer_naive_datetime.py +213 -0
  50. package/hooks/blocking/test_code_rules_enforcer_referenced_underscore_loop.py +169 -0
  51. package/hooks/blocking/test_code_rules_enforcer_split_constants_config.py +33 -0
  52. package/hooks/blocking/test_code_rules_enforcer_split_shared.py +23 -0
  53. package/hooks/blocking/test_code_rules_js_bare_flag_return_directive.py +266 -0
  54. package/hooks/blocking/test_code_rules_js_sibling_return_object_key_drift.py +490 -0
  55. package/hooks/blocking/test_code_rules_logging_adjacent_literals.py +171 -0
  56. package/hooks/blocking/test_code_rules_magic_values.py +54 -0
  57. package/hooks/blocking/test_duplicate_rmtree_helper_blocker.py +0 -6
  58. package/hooks/blocking/test_pr_converge_bugteam_enforcer_state_tolerance.py +184 -0
  59. package/hooks/blocking/test_pre_tool_use_dispatcher.py +9 -3
  60. package/hooks/blocking/test_reviewer_spawn_gate.py +230 -0
  61. package/hooks/blocking/test_shared_stdin_adoption.py +5 -30
  62. package/hooks/blocking/test_stale_comment_reference_blocker.py +236 -0
  63. package/hooks/blocking/test_state_description_blocker.py +135 -0
  64. package/hooks/hooks.json +5 -0
  65. package/hooks/hooks_constants/CLAUDE.md +3 -4
  66. package/hooks/hooks_constants/blocking_check_limits.py +46 -0
  67. package/hooks/hooks_constants/code_rules_enforcer_constants.py +41 -0
  68. package/hooks/hooks_constants/code_rules_path_utils_constants.py +1 -1
  69. package/hooks/hooks_constants/duplicate_rmtree_helper_blocker_constants.py +0 -1
  70. package/hooks/hooks_constants/post_tool_use_dispatcher_constants.py +0 -5
  71. package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +4 -0
  72. package/hooks/hooks_constants/reviewer_spawn_gate_constants.py +41 -0
  73. package/hooks/hooks_constants/stale_comment_reference_blocker_constants.py +76 -0
  74. package/hooks/hooks_constants/state_description_blocker_constants.py +8 -0
  75. package/hooks/validation/post_tool_use_dispatcher.py +1 -1
  76. package/hooks/validation/test_post_tool_use_dispatcher.py +51 -35
  77. package/hooks/workflow/CLAUDE.md +2 -8
  78. package/package.json +1 -1
  79. package/rules/CLAUDE.md +5 -2
  80. package/rules/claude-md-orphan-file.md +5 -0
  81. package/rules/docstring-prose-matches-implementation.md +10 -1
  82. package/rules/env-var-table-code-drift.md +5 -0
  83. package/rules/es-exe-file-search.md +17 -0
  84. package/rules/no-historical-clutter.md +12 -1
  85. package/rules/orphan-css-class.md +5 -0
  86. package/rules/package-inventory-stale-entry.md +10 -0
  87. package/rules/paired-test-coverage.md +5 -0
  88. package/rules/plain-illustrative-docstrings.md +40 -1
  89. package/rules/verify-before-asking.md +7 -0
  90. package/rules/verify-runtime-state.md +40 -0
  91. package/rules/windows-filesystem-safe.md +8 -0
  92. package/rules/workers-done-before-complete.md +33 -0
  93. package/rules/workflow-substitution-slots.md +5 -0
  94. package/skills/CLAUDE.md +7 -2
  95. package/skills/autoconverge/SKILL.md +48 -61
  96. package/skills/autoconverge/reference/closing-report.md +6 -6
  97. package/skills/autoconverge/reference/convergence.md +17 -15
  98. package/skills/autoconverge/reference/gotchas.md +6 -3
  99. package/skills/autoconverge/workflow/autoconverge_report_constants/render_report_constants.py +2 -9
  100. package/skills/autoconverge/workflow/converge.contract.test.mjs +153 -10
  101. package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +55 -19
  102. package/skills/autoconverge/workflow/converge.merge-conflict.test.mjs +16 -9
  103. package/skills/autoconverge/workflow/converge.mjs +167 -106
  104. package/skills/autoconverge/workflow/render_report.py +7 -11
  105. package/skills/bugteam/CLAUDE.md +1 -1
  106. package/skills/bugteam/PROMPTS.md +7 -6
  107. package/skills/bugteam/SKILL.md +25 -72
  108. package/skills/bugteam/reference/CLAUDE.md +1 -3
  109. package/skills/bugteam/reference/README.md +1 -1
  110. package/skills/bugteam/reference/audit-and-teammates.md +1 -1
  111. package/skills/bugteam/reference/obstacles/fix-publish-summary.md +1 -1
  112. package/skills/bugteam/reference/team-setup.md +8 -7
  113. package/skills/bugteam/scripts/CLAUDE.md +0 -6
  114. package/skills/bugteam/scripts/README.md +0 -4
  115. package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +0 -1
  116. package/skills/code/SKILL.md +2 -0
  117. package/skills/copilot-review/CLAUDE.md +1 -1
  118. package/skills/copilot-review/SKILL.md +25 -23
  119. package/skills/everything-search/SKILL.md +5 -0
  120. package/skills/findbugs/CLAUDE.md +2 -2
  121. package/skills/findbugs/SKILL.md +22 -83
  122. package/skills/fixbugs/SKILL.md +2 -4
  123. package/skills/log-audit/CLAUDE.md +20 -0
  124. package/skills/log-audit/SKILL.md +68 -0
  125. package/skills/log-audit/reference/CLAUDE.md +9 -0
  126. package/skills/log-audit/reference/charter.md +52 -0
  127. package/skills/log-audit/scripts/CLAUDE.md +27 -0
  128. package/skills/log-audit/scripts/cluster_recurrences.py +261 -0
  129. package/skills/log-audit/scripts/collect_log_window.py +199 -0
  130. package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +12 -0
  131. package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +23 -0
  132. package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +24 -0
  133. package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +49 -0
  134. package/skills/log-audit/scripts/mine_copilot_findings.py +302 -0
  135. package/skills/log-audit/scripts/test_cluster_recurrences.py +160 -0
  136. package/skills/log-audit/scripts/test_collect_log_window.py +111 -0
  137. package/skills/log-audit/scripts/test_mine_copilot_findings.py +126 -0
  138. package/skills/monitor-open-prs/SKILL.md +2 -2
  139. package/skills/post-audit-findings/SKILL.md +84 -0
  140. package/skills/pr-converge/CLAUDE.md +2 -0
  141. package/skills/pr-converge/SKILL.md +72 -59
  142. package/skills/pr-converge/reference/CLAUDE.md +1 -1
  143. package/skills/pr-converge/reference/convergence-gates.md +16 -19
  144. package/skills/pr-converge/reference/examples.md +5 -5
  145. package/skills/pr-converge/reference/fix-protocol.md +16 -43
  146. package/skills/pr-converge/reference/obstacles/fix-publish-summary.md +1 -1
  147. package/skills/pr-converge/reference/per-tick.md +24 -45
  148. package/skills/pr-converge/reference/state-schema.md +15 -0
  149. package/skills/pr-converge/scripts/README.md +3 -5
  150. package/skills/pr-fix-protocol/SKILL.md +70 -0
  151. package/skills/pr-loop-lifecycle/SKILL.md +73 -0
  152. package/skills/{bugteam → pr-loop-lifecycle}/reference/teardown-publish-permissions.md +22 -24
  153. package/skills/pr-scope-resolve/SKILL.md +48 -0
  154. package/skills/qbug/CLAUDE.md +4 -4
  155. package/skills/qbug/SKILL.md +46 -144
  156. package/skills/qbug/test_qbug_skill_audit_schema.py +2 -2
  157. package/skills/qbug/test_qbug_skill_post_fix_audit.py +1 -1
  158. package/skills/reviewer-gates/SKILL.md +96 -0
  159. package/skills/session-log/CLAUDE.md +7 -7
  160. package/skills/session-log/SKILL.md +27 -44
  161. package/skills/test_markdown_link_integrity.py +103 -0
  162. package/commands/doc-gist.md +0 -16
  163. package/hooks/blocking/_md_to_html_blocker_test_support.py +0 -65
  164. package/hooks/blocking/conftest.py +0 -30
  165. package/hooks/blocking/md_path_exemptions.py +0 -224
  166. package/hooks/blocking/md_to_html_blocker.py +0 -155
  167. package/hooks/blocking/test_md_to_html_blocker_exemptions.py +0 -434
  168. package/hooks/blocking/test_md_to_html_blocker_extensions.py +0 -157
  169. package/hooks/blocking/test_md_to_html_blocker_path_resolution.py +0 -336
  170. package/hooks/hooks_constants/doc_gist_auto_publish_constants.py +0 -18
  171. package/hooks/hooks_constants/html_companion_constants.py +0 -20
  172. package/hooks/hooks_constants/md_to_html_blocker_constants.py +0 -76
  173. package/hooks/hooks_constants/test_md_to_html_blocker_constants.py +0 -125
  174. package/hooks/workflow/doc_gist_auto_publish.py +0 -144
  175. package/hooks/workflow/md_to_html_companion.py +0 -358
  176. package/hooks/workflow/test_doc_gist_auto_publish.py +0 -117
  177. package/hooks/workflow/test_md_to_html_companion.py +0 -613
  178. package/skills/bugteam/reference/audit-contract.md +0 -163
  179. package/skills/bugteam/scripts/_bugteam_permissions_common.py +0 -455
  180. package/skills/bugteam/scripts/bugteam_scripts_constants/claude_permissions_common_constants.py +0 -69
  181. package/skills/bugteam/scripts/grant_project_claude_permissions.py +0 -280
  182. package/skills/bugteam/scripts/revoke_project_claude_permissions.py +0 -266
  183. package/skills/bugteam/scripts/test__bugteam_permissions_common.py +0 -160
  184. package/skills/bugteam/scripts/test_agent_config_carveout.py +0 -356
  185. package/skills/bugteam/scripts/test_bugteam_permissions_common.py +0 -140
  186. package/skills/doc-gist/CLAUDE.md +0 -25
  187. package/skills/doc-gist/SKILL.md +0 -97
  188. package/skills/doc-gist/references/CLAUDE.md +0 -9
  189. package/skills/doc-gist/references/examples/01-exploration-code-approaches.html +0 -453
  190. package/skills/doc-gist/references/examples/02-exploration-visual-designs.html +0 -515
  191. package/skills/doc-gist/references/examples/03-code-review-pr.html +0 -638
  192. package/skills/doc-gist/references/examples/04-code-understanding.html +0 -491
  193. package/skills/doc-gist/references/examples/05-design-system.html +0 -629
  194. package/skills/doc-gist/references/examples/06-component-variants.html +0 -605
  195. package/skills/doc-gist/references/examples/07-prototype-animation.html +0 -455
  196. package/skills/doc-gist/references/examples/08-prototype-interaction.html +0 -396
  197. package/skills/doc-gist/references/examples/09-slide-deck.html +0 -592
  198. package/skills/doc-gist/references/examples/10-svg-illustrations.html +0 -492
  199. package/skills/doc-gist/references/examples/11-status-report.html +0 -528
  200. package/skills/doc-gist/references/examples/12-incident-report.html +0 -596
  201. package/skills/doc-gist/references/examples/13-flowchart-diagram.html +0 -395
  202. package/skills/doc-gist/references/examples/14-research-feature-explainer.html +0 -381
  203. package/skills/doc-gist/references/examples/15-research-concept-explainer.html +0 -368
  204. package/skills/doc-gist/references/examples/16-implementation-plan.html +0 -702
  205. package/skills/doc-gist/references/examples/17-pr-writeup.html +0 -595
  206. package/skills/doc-gist/references/examples/18-editor-triage-board.html +0 -573
  207. package/skills/doc-gist/references/examples/19-editor-feature-flags.html +0 -663
  208. package/skills/doc-gist/references/examples/20-editor-prompt-tuner.html +0 -722
  209. package/skills/doc-gist/references/examples/21-decision-signoff.html +0 -546
  210. package/skills/doc-gist/references/examples/CLAUDE.md +0 -25
  211. package/skills/doc-gist/references/examples/README.md +0 -5
  212. package/skills/doc-gist/scripts/CLAUDE.md +0 -27
  213. package/skills/doc-gist/scripts/doc_gist_scripts_constants/CLAUDE.md +0 -10
  214. package/skills/doc-gist/scripts/doc_gist_scripts_constants/gist_upload_constants.py +0 -16
  215. package/skills/doc-gist/scripts/gist_upload.py +0 -177
  216. package/skills/doc-gist/scripts/test_gist_upload.py +0 -51
  217. /package/skills/{doc-gist/scripts/doc_gist_scripts_constants → log-audit/scripts/log_audit_constants}/__init__.py +0 -0
@@ -1,177 +0,0 @@
1
- """Upload an HTML file as a secret GitHub gist and emit the htmlpreview URL.
2
-
3
- Single-purpose transport. Takes HTML on stdin or via `--input <path>`, runs
4
- `gh gist create` (secret by default), parses the gist URL from gh's output,
5
- composes the htmlpreview.github.io preview URL, optionally opens it in the
6
- default browser, and prints both URLs.
7
-
8
- Designed to compose with anything that produces HTML — pipe in the output of
9
- a script, the contents of a hand-authored file, or have the auto-publish
10
- hook invoke it on a file Claude just wrote. The script does not opine on
11
- HTML shape, structure, or styling.
12
-
13
- Usage:
14
- gist_upload.py --input <path>
15
- gist_upload.py --input - --filename writeup.html < some.html
16
- """
17
-
18
- from __future__ import annotations
19
-
20
- import argparse
21
- import os
22
- import subprocess
23
- import sys
24
- import tempfile
25
- import webbrowser
26
- from pathlib import Path
27
- from urllib.parse import quote
28
-
29
- _script_directory = str(Path(__file__).resolve().parent)
30
- if _script_directory not in sys.path:
31
- sys.path.insert(0, _script_directory)
32
-
33
- from doc_gist_scripts_constants.gist_upload_constants import ( # noqa: E402
34
- GIST_DEFAULT_FILENAME,
35
- GIST_HOST_PREFIX,
36
- MINIMUM_GIST_URL_PARTS,
37
- PREVIEW_URL_TEMPLATE,
38
- UPLOAD_TIMEOUT_SECONDS,
39
- )
40
-
41
-
42
- def _read_html(input_argument: str) -> str:
43
- """Read HTML content from stdin (when input is '-') or a file path.
44
-
45
- Reads the full stdin stream when input_argument is '-'. Callers piping
46
- content through an external process should ensure bounded input.
47
- """
48
- if input_argument == "-":
49
- return sys.stdin.read()
50
- try:
51
- return Path(input_argument).expanduser().resolve().read_text(encoding="utf-8")
52
- except (OSError, UnicodeError) as error:
53
- raise SystemExit(f"Cannot read {input_argument}: {error}")
54
-
55
-
56
- def _resolve_filename(input_argument: str, override: str | None) -> str:
57
- """Pick the filename gh will use for the gist file."""
58
- default_filename = GIST_DEFAULT_FILENAME
59
- if override:
60
- return Path(override).name
61
- if input_argument != "-":
62
- return Path(input_argument).name
63
- return default_filename
64
-
65
-
66
- def _write_to_temp(html_text: str, filename: str, parent_directory: Path) -> Path:
67
- """Write HTML to a temp file inside parent_directory with the given filename."""
68
- target_path = parent_directory / filename
69
- target_path.write_text(html_text, encoding="utf-8")
70
- return target_path
71
-
72
-
73
- def _create_secret_gist(html_path: Path, description: str) -> str:
74
- """Run `gh gist create` against html_path and return the gist URL."""
75
- try:
76
- completed = subprocess.run(
77
- ["gh", "gist", "create", str(html_path), "--desc", description],
78
- check=False,
79
- capture_output=True,
80
- text=True,
81
- encoding="utf-8",
82
- errors="replace",
83
- timeout=UPLOAD_TIMEOUT_SECONDS,
84
- )
85
- except FileNotFoundError:
86
- raise SystemExit(
87
- "gh CLI not found. Install GitHub CLI (https://cli.github.com) and run `gh auth login`."
88
- )
89
- except subprocess.TimeoutExpired:
90
- raise SystemExit(
91
- f"gh gist create timed out after {UPLOAD_TIMEOUT_SECONDS}s. Check network and retry."
92
- )
93
- if completed.returncode != 0:
94
- message_text = completed.stderr.strip() or completed.stdout.strip()
95
- raise SystemExit(
96
- f"gh gist create failed:\n{message_text}\nRun `gh auth login` and retry."
97
- )
98
- output_lines = completed.stdout.strip().splitlines()
99
- if not output_lines:
100
- raise SystemExit("gh gist create produced no output.")
101
- last_line = output_lines[-1].strip()
102
- if not last_line.startswith(GIST_HOST_PREFIX):
103
- raise SystemExit(f"Unexpected gh gist create output: {last_line!r}")
104
- return last_line
105
-
106
-
107
- def _compose_preview_url(gist_url: str, filename: str) -> str:
108
- """Build the htmlpreview.github.io URL from the gist URL and the gist filename."""
109
- minimum_parts = MINIMUM_GIST_URL_PARTS
110
- preview_template = PREVIEW_URL_TEMPLATE
111
- path_after_host = gist_url[len(GIST_HOST_PREFIX) :]
112
- parts = path_after_host.split("/")
113
- if len(parts) < minimum_parts:
114
- raise SystemExit(f"Cannot parse gist URL: {gist_url!r}")
115
- return preview_template.format(user=parts[0], gist_id=parts[1], filename=quote(filename, safe=""))
116
-
117
-
118
- def _open_in_browser(url: str) -> None:
119
- """Open the URL in the default browser, deferring to OS-native behavior on Windows."""
120
- if sys.platform.startswith("win"):
121
- os.startfile(url)
122
- return
123
- webbrowser.open(url)
124
-
125
-
126
- def main() -> int:
127
- """Entry point — read HTML, upload as secret gist, print URLs, open preview.
128
-
129
- Returns:
130
- Process exit code (0 on success).
131
- """
132
- parser = argparse.ArgumentParser(
133
- description="Upload HTML as a secret gist; print gist + htmlpreview URLs."
134
- )
135
- parser.add_argument(
136
- "--input",
137
- required=True,
138
- help="Path to an .html file, or '-' for stdin.",
139
- )
140
- parser.add_argument(
141
- "--filename",
142
- default=None,
143
- help="Filename inside the gist. Defaults to the input filename, or 'doc.html' for stdin.",
144
- )
145
- parser.add_argument(
146
- "--description",
147
- default="HTML artifact",
148
- help="Gist description.",
149
- )
150
- parser.add_argument(
151
- "--no-open",
152
- action="store_true",
153
- help="Skip opening the preview URL in the default browser.",
154
- )
155
- arguments = parser.parse_args()
156
-
157
- html_text = _read_html(arguments.input)
158
- filename = _resolve_filename(arguments.input, arguments.filename)
159
-
160
- with tempfile.TemporaryDirectory(prefix="gist-upload-") as temp_directory:
161
- upload_path = _write_to_temp(html_text, filename, Path(temp_directory))
162
- gist_url = _create_secret_gist(upload_path, arguments.description)
163
- preview_url = _compose_preview_url(gist_url, filename)
164
-
165
- print(f"Gist: {gist_url}", file=sys.stderr)
166
- print(f"Preview: {preview_url}", file=sys.stderr)
167
-
168
- if not arguments.no_open:
169
- _open_in_browser(preview_url)
170
- print("Opened preview in default browser.", file=sys.stderr)
171
-
172
- print(preview_url)
173
- return 0
174
-
175
-
176
- if __name__ == "__main__":
177
- sys.exit(main())
@@ -1,51 +0,0 @@
1
- """Tests for gist_upload.py pure functions — URL composition and filename resolution."""
2
-
3
- from pathlib import Path
4
- import sys
5
-
6
- _script_directory = str(Path(__file__).resolve().parent)
7
- if _script_directory not in sys.path:
8
- sys.path.insert(0, _script_directory)
9
-
10
- from gist_upload import _compose_preview_url, _resolve_filename
11
-
12
-
13
- class TestResolveFilename:
14
- def test_uses_override_when_provided(self):
15
- assert (
16
- _resolve_filename("report.html", "custom-name.html") == "custom-name.html"
17
- )
18
-
19
- def test_strips_directory_from_override(self):
20
- assert (
21
- _resolve_filename("report.html", "/some/path/override.html")
22
- == "override.html"
23
- )
24
-
25
- def test_uses_input_filename_when_no_override(self):
26
- assert _resolve_filename("report.html", None) == "report.html"
27
-
28
- def test_uses_default_for_stdin_without_override(self):
29
- assert _resolve_filename("-", None) == "doc.html"
30
-
31
- def test_override_takes_precedence_over_stdin(self):
32
- assert _resolve_filename("-", "writeup.html") == "writeup.html"
33
-
34
-
35
- class TestComposePreviewUrl:
36
- def test_standard_gist_url(self):
37
- result = _compose_preview_url(
38
- "https://gist.github.com/user123/abc123def456",
39
- "report.html",
40
- )
41
- assert result == (
42
- "https://htmlpreview.github.io/"
43
- "?https://gist.githubusercontent.com/user123/abc123def456/raw/report.html"
44
- )
45
-
46
- def test_filename_with_spaces_is_encoded(self):
47
- result = _compose_preview_url(
48
- "https://gist.github.com/user123/abc123def456",
49
- "my report.html",
50
- )
51
- assert "my%20report.html" in result