housebroken-cli 0.6.7__tar.gz → 0.6.8__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.
Files changed (27) hide show
  1. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/PKG-INFO +1 -1
  2. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/pyproject.toml +1 -1
  3. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/branch-check.sh +1 -1
  4. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/file-pr.sh +30 -4
  5. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/prior-art.sh +31 -3
  6. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/verify-filed-pr.sh +1 -0
  7. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/skills/housebroken/SKILL.md +5 -2
  8. housebroken_cli-0.6.8/src/housebroken/__init__.py +1 -0
  9. housebroken_cli-0.6.7/src/housebroken/__init__.py +0 -1
  10. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/.gitignore +0 -0
  11. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/LICENSE +0 -0
  12. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/README.md +0 -0
  13. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/bin/housebroken +0 -0
  14. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/hatch_build.py +0 -0
  15. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/check-ai-policy.sh +0 -0
  16. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/claim-check.sh +0 -0
  17. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/comment-census.sh +0 -0
  18. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/comment-check.sh +0 -0
  19. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/diff-defaults.sh +0 -0
  20. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/distinct-outside.sh +0 -0
  21. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/file-issue.sh +0 -0
  22. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/fork-hygiene.sh +0 -0
  23. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/inbox.sh +0 -0
  24. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/notes.sh +0 -0
  25. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/pr-sweep.sh +0 -0
  26. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/scripts/review.sh +0 -0
  27. {housebroken_cli-0.6.7 → housebroken_cli-0.6.8}/src/housebroken/cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: housebroken-cli
3
- Version: 0.6.7
3
+ Version: 0.6.8
4
4
  Summary: Agent-written pull requests that do not make a mess in someone else's house.
5
5
  Project-URL: Repository, https://github.com/lenamonj/housebroken
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "housebroken-cli"
7
- version = "0.6.7"
7
+ version = "0.6.8"
8
8
  description = "Agent-written pull requests that do not make a mess in someone else's house."
9
9
  dynamic = ["readme"]
10
10
  license = "MIT"
@@ -184,6 +184,6 @@ fi
184
184
  # The stamp file-pr.sh reads: this head passed, against this base, at this time.
185
185
  head=$(git rev-parse HEAD)
186
186
  mkdir -p "$home/branch-checks"
187
- printf 'head: %s\nbase: %s\nchecked: %s\n' "$head" "$(git rev-parse "$base")" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$home/branch-checks/$head"
187
+ printf 'head: %s\nbase: %s\nbase-ref: %s\nchecked: %s\n' "$head" "$(git rev-parse "$base")" "$base" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$home/branch-checks/$head"
188
188
  echo
189
189
  echo "branch-check: nothing mechanical blocks this branch."
@@ -47,9 +47,11 @@ gates:
47
47
  be under 24 hours old and not read RESULT: BAN; when it reads
48
48
  RESULT: DISCLOSE the body must name the AI use
49
49
  prose no tool footer, session trailer, co-author trailer, em dash or
50
- en dash, in any case, in the --body-file or the --title
50
+ en dash, in any case, in the --body-file or the --title; a
51
+ body of at most 120 words
51
52
  branch $HOUSEBROKEN_HOME/branch-checks/<head> must exist, written by
52
- branch-check.sh when this head passed
53
+ branch-check.sh when this head passed, against the branch this
54
+ files into (--base, or the repository's default branch)
53
55
  review run from the clone being filed; the report at
54
56
  $HOUSEBROKEN_HOME/reviews/review-<owner>-<repo>-<head12>.md must
55
57
  pass review.sh check for this head and the --body-file, and an
@@ -128,6 +130,7 @@ check_text() {
128
130
  # as its own argument or after an equals sign.
129
131
  bodyfile=""
130
132
  title=""
133
+ filebase=""
131
134
  pass=()
132
135
  while [ "$#" -gt 0 ]; do
133
136
  case "$1" in
@@ -135,8 +138,10 @@ while [ "$#" -gt 0 ]; do
135
138
  --body-file=*) bodyfile="${1#--body-file=}"; pass+=("$1") ;;
136
139
  -t|--title) title="${2:-}"; pass+=("$1" "${2:-}"); shift ;;
137
140
  --title=*) title="${1#--title=}"; pass+=("$1") ;;
138
- -B|--base|-l|--label|-a|--assignee|-r|--reviewer|-m|--milestone|-p|--project) pass+=("$1" "${2:-}"); shift ;;
139
- --base=*|--label=*|--assignee=*|--reviewer=*|--milestone=*|--project=*) pass+=("$1") ;;
141
+ -B|--base) filebase="${2:-}"; pass+=("$1" "${2:-}"); shift ;;
142
+ --base=*) filebase="${1#--base=}"; pass+=("$1") ;;
143
+ -l|--label|-a|--assignee|-r|--reviewer|-m|--milestone|-p|--project) pass+=("$1" "${2:-}"); shift ;;
144
+ --label=*|--assignee=*|--reviewer=*|--milestone=*|--project=*) pass+=("$1") ;;
140
145
  -d|--draft|--no-maintainer-edit) pass+=("$1") ;;
141
146
  *)
142
147
  echo "REFUSED: file-pr.sh does not pass $1 to gh pr create: the body comes from one --body-file, the head is the branch you are on, the repository is the first argument" >&2
@@ -152,6 +157,11 @@ if [ "$bodyfile" = "-" ] || [ ! -f "$bodyfile" ]; then
152
157
  fi
153
158
  check_text "body file $bodyfile" "$(cat "$bodyfile")"
154
159
  check_text "--title" "$title"
160
+ words=$(wc -w < "$bodyfile" | tr -d ' ')
161
+ if [ "$words" -gt 120 ]; then
162
+ echo "REFUSED: the body is $words words - say what was wrong, what the change does and how it was verified in 120 or fewer" >&2
163
+ exit 2
164
+ fi
155
165
  if [ "$policy_result" = "DISCLOSE" ] && ! grep -qiE '\bAI\b|LLM|Claude|Copilot|ChatGPT|language model|assist' "$bodyfile"; then
156
166
  echo "REFUSED: $repo requires AI use to be disclosed ($policy) and the body does not name it" >&2
157
167
  exit 2
@@ -162,6 +172,22 @@ if [ ! -f "$home/branch-checks/$head" ]; then
162
172
  echo "REFUSED: branch-check.sh has not passed head ${head:0:12} - run it from this clone first" >&2
163
173
  exit 2
164
174
  fi
175
+ # Every diff gate read the diff against the stamp's base; it must be the branch this files into.
176
+ checked=$(sed -n 's/^base-ref: //p' "$home/branch-checks/$head" | tr -d '\r')
177
+ if [ -z "$checked" ]; then
178
+ echo "REFUSED: the branch-check stamp for head ${head:0:12} names no base - rerun branch-check.sh" >&2
179
+ exit 2
180
+ fi
181
+ target="$filebase"
182
+ if [ -z "$target" ]; then
183
+ target=$(gh repo view "$repo" --json defaultBranchRef --jq .defaultBranchRef.name 2>/dev/null | tr -d '\r')
184
+ [ -n "$target" ] || { echo "REFUSED: cannot read the default branch of $repo - pass --base" >&2; exit 2; }
185
+ fi
186
+ case "$checked" in
187
+ "$target"|*/"$target") ;;
188
+ *) echo "REFUSED: branch-check.sh measured this head against $checked, but it is filed into $target - rerun branch-check.sh --base <remote>/$target" >&2
189
+ exit 2 ;;
190
+ esac
165
191
  review="$home/reviews/review-${repo%%/*}-${repo##*/}-${head:0:12}.md"
166
192
  if [ ! -f "$review" ]; then
167
193
  echo "REFUSED: no adversarial review at $review - run review.sh brief and have a different model attack this head" >&2
@@ -9,7 +9,9 @@
9
9
  # 2026-09-04) argued against a ruling already made in CLOSED issue #98, which
10
10
  # nobody read, so this script prints the last non-author comment on every closed
11
11
  # item. A term containing a slash or a dot is treated as a file path and the
12
- # commit history of that path is scanned for the PRs that touched it.
12
+ # commit history of that path is scanned for the PRs that touched it, and
13
+ # every open PR that changes it is listed, which no text search finds
14
+ # (Shopify/ruby-lsp #4103 deleted the file a fix was written against).
13
15
  # Written 2026-09-07.
14
16
  #
15
17
  # Usage:
@@ -34,7 +36,8 @@ usage: prior-art.sh owner/repo <term>... [--out]
34
36
 
35
37
  owner/repo the upstream repository to search
36
38
  <term> a symbol, phrase or file path; a term with a slash or a dot is
37
- also treated as a path and its commit history is scanned
39
+ also treated as a path: its commit history is scanned and
40
+ every open PR that changes it is listed
38
41
  --out save the printout under $HOUSEBROKEN_HOME/prior-art/
39
42
 
40
43
  environment:
@@ -70,7 +73,8 @@ calls=0
70
73
  items=0
71
74
  tmp=$(mktemp) || { echo "prior-art.sh: cannot create temp file" >&2; exit 1; }
72
75
  row=$(mktemp) || { echo "prior-art.sh: cannot create temp file" >&2; exit 1; }
73
- trap 'rm -f "$tmp" "$row"' EXIT
76
+ openfiles=$(mktemp) || { echo "prior-art.sh: cannot create temp file" >&2; exit 1; }
77
+ trap 'rm -f "$tmp" "$row" "$openfiles"' EXIT
74
78
 
75
79
  # last comment on a closed item written by somebody other than its author
76
80
  last_word() {
@@ -132,6 +136,30 @@ for term in "${terms[@]}"; do
132
136
  printf '| PR | #%s | merged | %s | %s | %s | |\n' "$num" "$date" "$author" "$subject" >>"$tmp"
133
137
  items=$((items+1))
134
138
  done <"$row"
139
+
140
+ # an open PR that changes the path is prior art even when no title or body names it
141
+ if [ ! -s "$openfiles" ]; then
142
+ # shellcheck disable=SC2016 # $p is a jq variable
143
+ gh pr list -R "$repo" --state open --limit 200 --json number,createdAt,author,title,changedFiles,files \
144
+ --jq '.[] | . as $p | (if .changedFiles > (.files | length) then ["MORE"] else [.files[].path] end)[] |
145
+ [($p.number|tostring), $p.createdAt[0:10], $p.author.login,
146
+ ($p.title|gsub("[|]";"/")|gsub("[\n\r\t]";" ")), .] | @tsv' >"$openfiles" ||
147
+ { echo "prior-art.sh: open PR listing failed for $repo" >&2; exit 1; }
148
+ calls=$((calls+1))
149
+ # GitHub returns at most 100 files per PR here; a larger PR is read in full
150
+ awk -F'\t' '$5 == "MORE"' "$openfiles" | while IFS=$'\t' read -r num date author title _; do
151
+ gh api --paginate "repos/$repo/pulls/$num/files?per_page=100" --jq '.[].filename' |
152
+ while IFS= read -r f; do printf '%s\t%s\t%s\t%s\t%s\n' "$num" "$date" "$author" "$title" "$f"; done
153
+ done >"$row"
154
+ cat "$row" >>"$openfiles"
155
+ [ -s "$openfiles" ] || printf 'none\n' >"$openfiles"
156
+ fi
157
+ while IFS=$'\t' read -r num date author title path; do
158
+ case "$path" in "$term"|*/"$term") ;; *) continue ;; esac
159
+ grep -q "^| PR | #$num | open, changes this file |" "$tmp" && continue
160
+ printf '| PR | #%s | open, changes this file | %s | %s | %s | |\n' "$num" "$date" "$author" "$title" >>"$tmp"
161
+ items=$((items+1))
162
+ done <"$openfiles"
135
163
  ;;
136
164
  esac
137
165
  done
@@ -97,6 +97,7 @@ view comments '.comments[] | " " + .author.login + ": " + (.body | gsub("\n";
97
97
 
98
98
  echo ""
99
99
  if [ "$fail" -ne 0 ]; then echo "PR-VERIFY: PROBLEMS ABOVE"
100
+ elif [ "${waiting:-0}" -gt 0 ]; then echo "PR-VERIFY: NOT SETTLED ($waiting workflow run(s) wait for a maintainer to approve them; nothing settles until one does, so move on)"
100
101
  elif [ "$unsettled" -ne 0 ]; then echo "PR-VERIFY: NOT SETTLED (CI has not run on this head)"
101
102
  else echo "PR-VERIFY: OK"; fi
102
103
  [ "$fail" -eq 0 ] && [ "$unsettled" -ne 0 ] && exit 3
@@ -179,8 +179,11 @@ report it in one line and do not proceed to the next step.
179
179
  is missing or older than a day, when the policy printout is missing, older
180
180
  than a day or reads BAN, when the policy reads DISCLOSE and the body does
181
181
  not disclose, when the body carries a footer, a trailer or a dash
182
- character, when `housebroken branch` has not stamped the exact head, or
183
- when there is no POST AS IS review of the exact head and body being filed.
182
+ character or runs past 120 words, when `housebroken branch` has not
183
+ stamped the exact head against the branch it is filed into (`--base`
184
+ to both when the project takes pull requests on a branch other than its
185
+ default), or when there is no POST AS IS review of the exact head and
186
+ body being filed.
184
187
  A refusal is a result; fix the cause.
185
188
 
186
189
  10. **Watch it land.**
@@ -0,0 +1 @@
1
+ __version__ = "0.6.8"
@@ -1 +0,0 @@
1
- __version__ = "0.6.7"
File without changes