pinrule 0.16.0__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 (169) hide show
  1. pinrule-0.16.0/.github/ISSUE_TEMPLATE/bug_report.md +35 -0
  2. pinrule-0.16.0/.github/ISSUE_TEMPLATE/bug_report.zh.md +35 -0
  3. pinrule-0.16.0/.github/ISSUE_TEMPLATE/feature_request.md +26 -0
  4. pinrule-0.16.0/.github/ISSUE_TEMPLATE/feature_request.zh.md +26 -0
  5. pinrule-0.16.0/.github/PULL_REQUEST_TEMPLATE.md +26 -0
  6. pinrule-0.16.0/.github/PULL_REQUEST_TEMPLATE.zh.md +26 -0
  7. pinrule-0.16.0/.github/workflows/ci.yml +101 -0
  8. pinrule-0.16.0/.gitignore +28 -0
  9. pinrule-0.16.0/CHANGELOG.md +3127 -0
  10. pinrule-0.16.0/CHANGELOG.zh.md +5366 -0
  11. pinrule-0.16.0/CLAUDE.md +103 -0
  12. pinrule-0.16.0/CLAUDE.zh.md +103 -0
  13. pinrule-0.16.0/CODE_OF_CONDUCT.md +29 -0
  14. pinrule-0.16.0/CODE_OF_CONDUCT.zh.md +29 -0
  15. pinrule-0.16.0/LICENSE +21 -0
  16. pinrule-0.16.0/PKG-INFO +487 -0
  17. pinrule-0.16.0/README.md +456 -0
  18. pinrule-0.16.0/README.zh.md +475 -0
  19. pinrule-0.16.0/SECURITY.md +47 -0
  20. pinrule-0.16.0/SECURITY.zh.md +47 -0
  21. pinrule-0.16.0/assets/demo-en.svg +80 -0
  22. pinrule-0.16.0/assets/demo-zh.svg +80 -0
  23. pinrule-0.16.0/data/config.example.yaml +34 -0
  24. pinrule-0.16.0/data/locales/en.yaml +167 -0
  25. pinrule-0.16.0/data/locales/zh.yaml +164 -0
  26. pinrule-0.16.0/data/rules.dev.example.yaml +175 -0
  27. pinrule-0.16.0/data/rules.dev.example.zh.yaml +143 -0
  28. pinrule-0.16.0/data/rules.dev.minimal.example.yaml +109 -0
  29. pinrule-0.16.0/data/rules.dev.minimal.example.zh.yaml +92 -0
  30. pinrule-0.16.0/data/signals/agent_saturation/en.txt +57 -0
  31. pinrule-0.16.0/data/signals/agent_saturation/zh.txt +52 -0
  32. pinrule-0.16.0/data/signals/completion_words/en.txt +27 -0
  33. pinrule-0.16.0/data/signals/completion_words/zh.txt +21 -0
  34. pinrule-0.16.0/data/signals/explicit_handoff/en.txt +25 -0
  35. pinrule-0.16.0/data/signals/explicit_handoff/zh.txt +24 -0
  36. pinrule-0.16.0/data/signals/push_signals/en.yaml +114 -0
  37. pinrule-0.16.0/data/signals/push_signals/zh.yaml +156 -0
  38. pinrule-0.16.0/data/signals/stop_hints/en.txt +45 -0
  39. pinrule-0.16.0/data/signals/stop_hints/zh.txt +41 -0
  40. pinrule-0.16.0/data/signals/user_stop_hints/en.txt +77 -0
  41. pinrule-0.16.0/data/signals/user_stop_hints/zh.txt +66 -0
  42. pinrule-0.16.0/data/signals/weak_claims/en.txt +28 -0
  43. pinrule-0.16.0/data/signals/weak_claims/zh.txt +41 -0
  44. pinrule-0.16.0/docs/ARCHITECTURE.md +448 -0
  45. pinrule-0.16.0/docs/ARCHITECTURE.zh.md +470 -0
  46. pinrule-0.16.0/docs/CODEX_BACKEND.md +146 -0
  47. pinrule-0.16.0/docs/CODEX_BACKEND.zh.md +146 -0
  48. pinrule-0.16.0/docs/HANDOFF.md +94 -0
  49. pinrule-0.16.0/docs/HANDOFF.zh.md +861 -0
  50. pinrule-0.16.0/docs/HOOK_CONFIGURATION_GUIDE.md +139 -0
  51. pinrule-0.16.0/docs/HOOK_PROTOCOL_RESEARCH.md +115 -0
  52. pinrule-0.16.0/docs/PRD.md +249 -0
  53. pinrule-0.16.0/docs/PRD.zh.md +254 -0
  54. pinrule-0.16.0/docs/REFACTOR_PLAN_RULE_AND_I18N.md +114 -0
  55. pinrule-0.16.0/docs/REFACTOR_PLAN_RULE_AND_I18N.zh.md +263 -0
  56. pinrule-0.16.0/docs/RULES_REDESIGN_PROPOSAL.md +118 -0
  57. pinrule-0.16.0/docs/RULES_REDESIGN_PROPOSAL.zh.md +334 -0
  58. pinrule-0.16.0/docs/V0_6_0_PLAN.md +99 -0
  59. pinrule-0.16.0/docs/V0_6_0_PLAN.zh.md +99 -0
  60. pinrule-0.16.0/pinrule/__init__.py +10 -0
  61. pinrule-0.16.0/pinrule/__main__.py +6 -0
  62. pinrule-0.16.0/pinrule/backends/HOWTO.md +181 -0
  63. pinrule-0.16.0/pinrule/backends/HOWTO.zh.md +196 -0
  64. pinrule-0.16.0/pinrule/backends/__init__.py +42 -0
  65. pinrule-0.16.0/pinrule/backends/_base.py +147 -0
  66. pinrule-0.16.0/pinrule/backends/_json_hooks.py +210 -0
  67. pinrule-0.16.0/pinrule/backends/claude_code.py +65 -0
  68. pinrule-0.16.0/pinrule/backends/codex.py +1016 -0
  69. pinrule-0.16.0/pinrule/backends/cursor.py +218 -0
  70. pinrule-0.16.0/pinrule/backends/native_capabilities.py +59 -0
  71. pinrule-0.16.0/pinrule/backends/protocol_adapter.py +155 -0
  72. pinrule-0.16.0/pinrule/checks/__init__.py +88 -0
  73. pinrule-0.16.0/pinrule/checks/_types.py +28 -0
  74. pinrule-0.16.0/pinrule/checks/bypass_pinrule.py +202 -0
  75. pinrule-0.16.0/pinrule/checks/chinese_plain.py +200 -0
  76. pinrule-0.16.0/pinrule/checks/common.py +237 -0
  77. pinrule-0.16.0/pinrule/checks/description_context.py +121 -0
  78. pinrule-0.16.0/pinrule/checks/evidence.py +133 -0
  79. pinrule-0.16.0/pinrule/checks/keep_pushing.py +174 -0
  80. pinrule-0.16.0/pinrule/checks/long_term.py +224 -0
  81. pinrule-0.16.0/pinrule/checks/non_blocking.py +186 -0
  82. pinrule-0.16.0/pinrule/checks/read_first.py +77 -0
  83. pinrule-0.16.0/pinrule/checks/testset.py +110 -0
  84. pinrule-0.16.0/pinrule/cli.py +1628 -0
  85. pinrule-0.16.0/pinrule/config.py +85 -0
  86. pinrule-0.16.0/pinrule/cursor_rules_sync.py +95 -0
  87. pinrule-0.16.0/pinrule/cursor_visibility.py +119 -0
  88. pinrule-0.16.0/pinrule/hooks/__init__.py +1 -0
  89. pinrule-0.16.0/pinrule/hooks/_payload.py +40 -0
  90. pinrule-0.16.0/pinrule/hooks/_tool_gate.py +152 -0
  91. pinrule-0.16.0/pinrule/hooks/_transcript.py +63 -0
  92. pinrule-0.16.0/pinrule/hooks/after_agent_response.py +45 -0
  93. pinrule-0.16.0/pinrule/hooks/before_mcp_execution.py +72 -0
  94. pinrule-0.16.0/pinrule/hooks/before_read_file.py +32 -0
  95. pinrule-0.16.0/pinrule/hooks/before_shell_execution.py +36 -0
  96. pinrule-0.16.0/pinrule/hooks/post_tool_use.py +323 -0
  97. pinrule-0.16.0/pinrule/hooks/pre_compact.py +131 -0
  98. pinrule-0.16.0/pinrule/hooks/pre_tool_use.py +30 -0
  99. pinrule-0.16.0/pinrule/hooks/session_start.py +140 -0
  100. pinrule-0.16.0/pinrule/hooks/stop.py +361 -0
  101. pinrule-0.16.0/pinrule/hooks/subagent_start.py +116 -0
  102. pinrule-0.16.0/pinrule/hooks/subagent_stop.py +67 -0
  103. pinrule-0.16.0/pinrule/hooks/user_prompt_submit.py +233 -0
  104. pinrule-0.16.0/pinrule/i18n.py +98 -0
  105. pinrule-0.16.0/pinrule/locale_detect.py +85 -0
  106. pinrule-0.16.0/pinrule/model_threshold.py +151 -0
  107. pinrule-0.16.0/pinrule/notify.py +112 -0
  108. pinrule-0.16.0/pinrule/paths.py +34 -0
  109. pinrule-0.16.0/pinrule/rule.py +224 -0
  110. pinrule-0.16.0/pinrule/session_state.py +589 -0
  111. pinrule-0.16.0/pinrule/signals.py +210 -0
  112. pinrule-0.16.0/pinrule/violations.py +426 -0
  113. pinrule-0.16.0/pyproject.toml +80 -0
  114. pinrule-0.16.0/scripts/cursor-install-local.sh +65 -0
  115. pinrule-0.16.0/scripts/demo-fixtures/rules-en.yaml +44 -0
  116. pinrule-0.16.0/scripts/demo-fixtures/rules-zh.yaml +40 -0
  117. pinrule-0.16.0/scripts/demo-fixtures/short-term-talk-en.jsonl +1 -0
  118. pinrule-0.16.0/scripts/demo-fixtures/short-term-talk.jsonl +1 -0
  119. pinrule-0.16.0/scripts/demo-fixtures/silent-stop-en.jsonl +1 -0
  120. pinrule-0.16.0/scripts/demo-fixtures/silent-stop.jsonl +1 -0
  121. pinrule-0.16.0/scripts/demo-script.sh +124 -0
  122. pinrule-0.16.0/scripts/measure_perf.py +131 -0
  123. pinrule-0.16.0/scripts/record-demo.sh +108 -0
  124. pinrule-0.16.0/scripts/regenerate-demo-svg.sh +30 -0
  125. pinrule-0.16.0/scripts/release-finalize.sh +48 -0
  126. pinrule-0.16.0/scripts/release.sh +63 -0
  127. pinrule-0.16.0/scripts/verify-installed.sh +44 -0
  128. pinrule-0.16.0/skills/pinrule/SKILL.md +353 -0
  129. pinrule-0.16.0/tests/__init__.py +0 -0
  130. pinrule-0.16.0/tests/conftest.py +18 -0
  131. pinrule-0.16.0/tests/contract/__init__.py +0 -0
  132. pinrule-0.16.0/tests/contract/test_backend_contract.py +196 -0
  133. pinrule-0.16.0/tests/test_backends.py +492 -0
  134. pinrule-0.16.0/tests/test_bypass_pinrule.py +387 -0
  135. pinrule-0.16.0/tests/test_checks.py +1184 -0
  136. pinrule-0.16.0/tests/test_cli.py +1044 -0
  137. pinrule-0.16.0/tests/test_codex_backend.py +499 -0
  138. pinrule-0.16.0/tests/test_compact_hooks.py +258 -0
  139. pinrule-0.16.0/tests/test_config.py +79 -0
  140. pinrule-0.16.0/tests/test_config_defaults.py +209 -0
  141. pinrule-0.16.0/tests/test_cursor_native_hooks.py +45 -0
  142. pinrule-0.16.0/tests/test_cursor_rules_sync.py +34 -0
  143. pinrule-0.16.0/tests/test_cursor_user_prompt_inject.py +27 -0
  144. pinrule-0.16.0/tests/test_cursor_visibility.py +35 -0
  145. pinrule-0.16.0/tests/test_description_context.py +89 -0
  146. pinrule-0.16.0/tests/test_false_negative_regression.py +603 -0
  147. pinrule-0.16.0/tests/test_hooks.py +817 -0
  148. pinrule-0.16.0/tests/test_i18n.py +175 -0
  149. pinrule-0.16.0/tests/test_keep_pushing.py +507 -0
  150. pinrule-0.16.0/tests/test_locale_detect.py +172 -0
  151. pinrule-0.16.0/tests/test_model_threshold.py +257 -0
  152. pinrule-0.16.0/tests/test_no_sticky_in_user_facing.py +72 -0
  153. pinrule-0.16.0/tests/test_notify.py +96 -0
  154. pinrule-0.16.0/tests/test_paths.py +80 -0
  155. pinrule-0.16.0/tests/test_payload.py +91 -0
  156. pinrule-0.16.0/tests/test_post_tool_use_reinject.py +151 -0
  157. pinrule-0.16.0/tests/test_pre_tool_use.py +217 -0
  158. pinrule-0.16.0/tests/test_protocol_adapter.py +442 -0
  159. pinrule-0.16.0/tests/test_rule_format.py +263 -0
  160. pinrule-0.16.0/tests/test_rule_schema.py +299 -0
  161. pinrule-0.16.0/tests/test_run_checks.py +196 -0
  162. pinrule-0.16.0/tests/test_session_state.py +703 -0
  163. pinrule-0.16.0/tests/test_session_state_atomic.py +294 -0
  164. pinrule-0.16.0/tests/test_signals.py +280 -0
  165. pinrule-0.16.0/tests/test_sticky.py +266 -0
  166. pinrule-0.16.0/tests/test_subagent_isolation.py +151 -0
  167. pinrule-0.16.0/tests/test_transcript.py +47 -0
  168. pinrule-0.16.0/tests/test_violations.py +407 -0
  169. pinrule-0.16.0/whitelist.py +28 -0
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: Bug Report (English)
3
+ about: Report a pinrule bug / false positive / install issue / hook malfunction
4
+ title: '[Bug] '
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## What did you encounter
10
+
11
+ Brief description of the problem. For **false positives** (pinrule blocks legitimate operations), paste `pinrule audit` output with the `⚠️ possible false positive` markers.
12
+
13
+ ## Reproduction steps
14
+
15
+ 1. Install via `pinrule install-hooks ...`
16
+ 2. ...
17
+ 3. Observed error / unexpected behavior
18
+
19
+ ## Real state (output of `pinrule doctor`)
20
+
21
+ ```
22
+ (paste complete `pinrule doctor` output)
23
+ ```
24
+
25
+ ## Environment
26
+
27
+ - pinrule version: (`pinrule --version`)
28
+ - AI client: Claude Code / Codex CLI / Gemini CLI (with version)
29
+ - OS: macOS / Linux / WSL
30
+ - Python: (`python --version`)
31
+ - Shell: zsh / bash / fish
32
+
33
+ ## Key logs (if any)
34
+
35
+ If hook output schema errors or installation failures occur, paste the stderr / Claude Code UI error section.
@@ -0,0 +1,35 @@
1
+ ---
2
+ name: Bug 报告
3
+ about: 报告 pinrule 的 bug / 假阳 / 装机问题 / hook 失效
4
+ title: '[Bug] '
5
+ labels: bug
6
+ assignees: ''
7
+ ---
8
+
9
+ ## 你遇到什么
10
+
11
+ 简短描述问题。如果是**假阳**(pinrule 误拦合法操作)请贴 `pinrule audit` 输出含 `⚠️ 可能假阳` 标记的 trigger。
12
+
13
+ ## 复现步骤
14
+
15
+ 1. 装机 `pinrule install-hooks ...`
16
+ 2. ...
17
+ 3. 看到的错误 / 不预期行为
18
+
19
+ ## 状态(用 `pinrule doctor` 输出)
20
+
21
+ ```
22
+ (贴 `pinrule doctor` 完整输出)
23
+ ```
24
+
25
+ ## 环境
26
+
27
+ - pinrule 版本: (`pinrule --version`)
28
+ - AI 客户端: Claude Code / Codex CLI / Gemini CLI(含版本)
29
+ - OS: macOS / Linux / WSL
30
+ - Python: (`python --version`)
31
+ - Shell: zsh / bash / fish
32
+
33
+ ## 关键日志(如有)
34
+
35
+ 如果 hook 输出 schema 错或装机失败,贴 stderr / Claude Code UI 报错段。
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: Feature / Improvement Suggestion (English)
3
+ about: Suggest new features / new rule scenarios / new AI client backend
4
+ title: '[Feature] '
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## Your real pain point
10
+
11
+ Describe the scenario concretely. pinrule's design principle is "user-real-pain-driven" — we don't accept "I think this might be useful" type preventive suggestions.
12
+
13
+ ## Proposed solution
14
+
15
+ If you have a specific idea, write it out. Include:
16
+ - Is it at the rule layer (can users solve this by writing their own `rules.yaml`)?
17
+ - Or at the check layer (needs new engine-layer violation_check function)?
18
+ - Or at the hook layer (needs new hook event or changes to existing hook behavior)?
19
+
20
+ ## Have you considered alternatives
21
+
22
+ pinrule explicitly **doesn't do** these things — see README's "What pinrule doesn't do" section. If your need falls outside those boundaries, explain why an exception is necessary.
23
+
24
+ ## Real user scenario (not speculation)
25
+
26
+ One of pinrule v1's failure lessons was "preventive design." New features must be driven by real user scenarios; we don't accept "might be useful" type needs.
@@ -0,0 +1,26 @@
1
+ ---
2
+ name: 功能 / 改进建议
3
+ about: 建议新功能 / 新规则场景 / 新 AI 客户端 backend
4
+ title: '[Feature] '
5
+ labels: enhancement
6
+ assignees: ''
7
+ ---
8
+
9
+ ## 你的痛点
10
+
11
+ 具体描述场景。pinrule 设计原则是「用户痛点驱动」— 不接受「我觉得可能有用」类预防性建议。
12
+
13
+ ## 提议方案
14
+
15
+ 如有具体思路写出来。包括:
16
+ - 是规则层(用户自己写 `rules.yaml` 能解决吗)
17
+ - 还是 check 层(需要新工程层 `violation_check` 函数)
18
+ - 还是 hook 层(需要新 hook event 或改现有 hook 行为)
19
+
20
+ ## 替代方案考虑过吗
21
+
22
+ pinrule 明确**不做**这些 — 看 README「试过但放弃的」段。如果你的需求落在这些边界外,说明为什么必须破例。
23
+
24
+ ## 真实用户场景(不是猜测)
25
+
26
+ pinrule v1 的教训之一是「预防性设计」— 新功能必须有真实用户场景驱动,不接受「可能有用」类需求。
@@ -0,0 +1,26 @@
1
+ ## What this PR does
2
+
3
+ Brief description of the change. If it's a new feature, explain whether it's at the rule layer / check layer / hook layer.
4
+
5
+ ## Real driving scenario
6
+
7
+ pinrule's validation criterion is "the author / user can describe 3 concrete cases" — what real scenarios does this PR solve?
8
+
9
+ ## Verification evidence
10
+
11
+ - [ ] All tests pass: `pytest tests/ -q`
12
+ - [ ] Static checks clean: `ruff check pinrule/ tests/ && mypy pinrule/ tests/ && vulture pinrule/ --min-confidence 80`
13
+ - [ ] Manual run verifies hook behavior (if hooks changed)
14
+ - [ ] If adding new rule templates / check functions, add corresponding tests
15
+
16
+ ## Boundary check
17
+
18
+ - [ ] No LLM dependency introduced
19
+ - [ ] No retrieval / cosine / scoring system introduced
20
+ - [ ] No backward-incompatible breakage of existing rule configs
21
+ - [ ] Small and reviewable by default; larger batches OK when the maintainer has explicitly asked for "one PR, don't fragment it"
22
+
23
+ ## Related
24
+
25
+ - Related issue: #
26
+ - Related version: (see `pinrule --version`)
@@ -0,0 +1,26 @@
1
+ ## 这个 PR 做什么
2
+
3
+ 简短描述改动。如果是新功能,说明对应规则层 / check 层 / hook 层哪一层。
4
+
5
+ ## 驱动场景
6
+
7
+ pinrule 验证标准是「作者 / 用户能讲出 3 个具体案例」— 这个 PR 解决的场景是什么?
8
+
9
+ ## 验证证据
10
+
11
+ - [ ] 测试全过:`pytest tests/ -q`
12
+ - [ ] 静态检查清干净:`ruff check pinrule/ tests/ && mypy pinrule/ tests/ && vulture pinrule/ --min-confidence 80`
13
+ - [ ] manual run 验证 hook 行为(如果改了 hook)
14
+ - [ ] 如果加规则模板 / check 函数,加对应测试
15
+
16
+ ## 边界检查
17
+
18
+ - [ ] 不引入 LLM 依赖
19
+ - [ ] 不引入 retrieval / cosine / 评分系统
20
+ - [ ] 不破现有 `rules.yaml` 配置兼容
21
+ - [ ] 默认保持小、可 review;维护者明确要求「一个 PR 别拆碎」时一波到位也合理
22
+
23
+ ## 相关
24
+
25
+ - 关联 issue: #
26
+ - 相关版本: (从 `pinrule --version` 看)
@@ -0,0 +1,101 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest]
16
+ python-version: ["3.11", "3.12"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Setup Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install
26
+ run: |
27
+ python -m pip install --upgrade pip
28
+ pip install -e ".[dev]"
29
+
30
+ - name: Lint (ruff)
31
+ run: ruff check pinrule/ tests/
32
+
33
+ - name: Dead code scan (vulture, min-confidence 60)
34
+ run: vulture pinrule/ whitelist.py --min-confidence 60
35
+
36
+ - name: Type check (mypy)
37
+ run: |
38
+ mypy pinrule/
39
+ mypy tests/
40
+
41
+ - name: Test
42
+ run: pytest tests/ -q
43
+
44
+ - name: Build wheel
45
+ run: |
46
+ pip install build
47
+ python -m build --wheel
48
+
49
+ - name: Verify wheel contains yaml templates AND signal data
50
+ run: |
51
+ python -c "
52
+ import glob, zipfile, sys
53
+ wheels = glob.glob('dist/pinrule-*-py3-none-any.whl')
54
+ if not wheels: sys.exit('wheel build 失败 — dist/ 无 wheel')
55
+ z = zipfile.ZipFile(wheels[0])
56
+ names = z.namelist()
57
+ # v0.6.0 BREAKING: sticky.* → rules.* 重命名 (v0.9.6 修)
58
+ # v0.9.15 critical: data/signals/ 整个目录之前漏 force-include
59
+ # → wheel 缺 signals 导致 compile_alternation() never-match →
60
+ # evidence / keep_pushing / non_blocking 等 keyword 层失效.
61
+ # codex GPT-5.5 cross-model audit 抓到. 影响所有 pip install 用户.
62
+ expected = [
63
+ 'data/rules.dev.example.yaml',
64
+ 'data/rules.dev.example.zh.yaml',
65
+ 'data/locales/en.yaml',
66
+ 'data/locales/zh.yaml',
67
+ 'data/config.example.yaml',
68
+ 'skills/pinrule/SKILL.md',
69
+ # v0.9.15: 7 个 signal type * 2 lang = 14 文件
70
+ # 用 sampling 而非全列:每个 signal type 至少 1 个 lang 在
71
+ 'data/signals/weak_claims/en.txt',
72
+ 'data/signals/completion_words/en.txt',
73
+ 'data/signals/push_signals/en.yaml',
74
+ 'data/signals/stop_hints/en.txt',
75
+ 'data/signals/agent_saturation/zh.txt',
76
+ 'data/signals/explicit_handoff/zh.txt',
77
+ 'data/signals/user_stop_hints/zh.txt',
78
+ ]
79
+ missing = [n for n in expected if n not in names]
80
+ if missing: sys.exit(f'wheel 缺文件: {missing}')
81
+ print(f'{wheels[0]} 含全部 {len(expected)} 个关键模板 + signals ✓')
82
+ "
83
+
84
+ - name: Wheel smoke test - signals compile_alternation truly works
85
+ # v0.9.15 critical: 即便 wheel 含 signal 文件,也要 functional 验证
86
+ # 真能编译出 non-empty regex(防 packaging path 错 / load 失败).
87
+ # codex GPT-5.5 推荐 smoke test pattern.
88
+ run: |
89
+ python -m venv /tmp/pinrule-wheel-test
90
+ /tmp/pinrule-wheel-test/bin/pip install dist/pinrule-*-py3-none-any.whl
91
+ /tmp/pinrule-wheel-test/bin/python -c "
92
+ from pinrule.signals import compile_alternation
93
+ # 验证 4 个关键 signal 真编译成 working regex
94
+ for sig in ('weak_claims', 'completion_words', 'push_signals', 'stop_hints'):
95
+ pat = compile_alternation(sig)
96
+ # never-match pattern '(?!)' 长度 4,真 pattern 应 >> 50
97
+ assert pat.pattern != '(?!)', f'{sig}: signals 没 load → never-match'
98
+ assert len(pat.pattern) > 50, f'{sig}: pattern 太短可能漏字眼 ({len(pat.pattern)} chars)'
99
+ print(f' ✓ {sig}: pattern {len(pat.pattern)} chars')
100
+ print('signals compile_alternation smoke test ✓')
101
+ "
@@ -0,0 +1,28 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ .venv/
8
+ venv/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ *.egg-info/
12
+ dist/
13
+ build/
14
+
15
+ # IDE
16
+ .vscode/
17
+ .idea/
18
+
19
+ # karma 本地状态(不进仓库)
20
+ violations.jsonl
21
+ stats.json
22
+
23
+ # Cursor IDE dogfood 资产 (含真 stdin captures 可能有 user_email 等敏感字段)
24
+ .cursor/
25
+ .dogfood/
26
+
27
+ # OS
28
+ .DS_Store