@cad0p/pi-steering 0.1.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 (246) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/LICENSE +29 -0
  3. package/README.md +920 -0
  4. package/dist/__test-helpers__.d.ts +95 -0
  5. package/dist/__test-helpers__.d.ts.map +1 -0
  6. package/dist/__test-helpers__.js +174 -0
  7. package/dist/__test-helpers__.js.map +1 -0
  8. package/dist/bin/pi-steering.d.ts +9 -0
  9. package/dist/bin/pi-steering.d.ts.map +1 -0
  10. package/dist/bin/pi-steering.js +506 -0
  11. package/dist/bin/pi-steering.js.map +1 -0
  12. package/dist/compat.d.ts +50 -0
  13. package/dist/compat.d.ts.map +1 -0
  14. package/dist/compat.js +180 -0
  15. package/dist/compat.js.map +1 -0
  16. package/dist/defaults.d.ts +61 -0
  17. package/dist/defaults.d.ts.map +1 -0
  18. package/dist/defaults.js +106 -0
  19. package/dist/defaults.js.map +1 -0
  20. package/dist/define-config.d.ts +235 -0
  21. package/dist/define-config.d.ts.map +1 -0
  22. package/dist/define-config.js +118 -0
  23. package/dist/define-config.js.map +1 -0
  24. package/dist/define-predicate.d.ts +49 -0
  25. package/dist/define-predicate.d.ts.map +1 -0
  26. package/dist/define-predicate.js +35 -0
  27. package/dist/define-predicate.js.map +1 -0
  28. package/dist/evaluator-internals/context.d.ts +186 -0
  29. package/dist/evaluator-internals/context.d.ts.map +1 -0
  30. package/dist/evaluator-internals/context.js +219 -0
  31. package/dist/evaluator-internals/context.js.map +1 -0
  32. package/dist/evaluator-internals/override.d.ts +19 -0
  33. package/dist/evaluator-internals/override.d.ts.map +1 -0
  34. package/dist/evaluator-internals/override.js +79 -0
  35. package/dist/evaluator-internals/override.js.map +1 -0
  36. package/dist/evaluator-internals/predicates.d.ts +152 -0
  37. package/dist/evaluator-internals/predicates.d.ts.map +1 -0
  38. package/dist/evaluator-internals/predicates.js +849 -0
  39. package/dist/evaluator-internals/predicates.js.map +1 -0
  40. package/dist/evaluator-internals/speculative-synthesis.d.ts +102 -0
  41. package/dist/evaluator-internals/speculative-synthesis.d.ts.map +1 -0
  42. package/dist/evaluator-internals/speculative-synthesis.js +101 -0
  43. package/dist/evaluator-internals/speculative-synthesis.js.map +1 -0
  44. package/dist/evaluator.d.ts +101 -0
  45. package/dist/evaluator.d.ts.map +1 -0
  46. package/dist/evaluator.js +714 -0
  47. package/dist/evaluator.js.map +1 -0
  48. package/dist/helpers/walker-unknown-cwd-reason.d.ts +68 -0
  49. package/dist/helpers/walker-unknown-cwd-reason.d.ts.map +1 -0
  50. package/dist/helpers/walker-unknown-cwd-reason.js +73 -0
  51. package/dist/helpers/walker-unknown-cwd-reason.js.map +1 -0
  52. package/dist/index.d.ts +42 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +93 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/internal/drop-unused-observers.d.ts +43 -0
  57. package/dist/internal/drop-unused-observers.d.ts.map +1 -0
  58. package/dist/internal/drop-unused-observers.js +50 -0
  59. package/dist/internal/drop-unused-observers.js.map +1 -0
  60. package/dist/internal/finalize-plugin-state.d.ts +22 -0
  61. package/dist/internal/finalize-plugin-state.d.ts.map +1 -0
  62. package/dist/internal/finalize-plugin-state.js +14 -0
  63. package/dist/internal/finalize-plugin-state.js.map +1 -0
  64. package/dist/internal/merge-observers.d.ts +30 -0
  65. package/dist/internal/merge-observers.d.ts.map +1 -0
  66. package/dist/internal/merge-observers.js +27 -0
  67. package/dist/internal/merge-observers.js.map +1 -0
  68. package/dist/internal/pattern-utils.d.ts +33 -0
  69. package/dist/internal/pattern-utils.d.ts.map +1 -0
  70. package/dist/internal/pattern-utils.js +20 -0
  71. package/dist/internal/pattern-utils.js.map +1 -0
  72. package/dist/internal/ref-text.d.ts +11 -0
  73. package/dist/internal/ref-text.d.ts.map +1 -0
  74. package/dist/internal/ref-text.js +15 -0
  75. package/dist/internal/ref-text.js.map +1 -0
  76. package/dist/internal/session-runtime.d.ts +44 -0
  77. package/dist/internal/session-runtime.d.ts.map +1 -0
  78. package/dist/internal/session-runtime.js +143 -0
  79. package/dist/internal/session-runtime.js.map +1 -0
  80. package/dist/internal/watch-matcher.d.ts +56 -0
  81. package/dist/internal/watch-matcher.d.ts.map +1 -0
  82. package/dist/internal/watch-matcher.js +179 -0
  83. package/dist/internal/watch-matcher.js.map +1 -0
  84. package/dist/loader.d.ts +97 -0
  85. package/dist/loader.d.ts.map +1 -0
  86. package/dist/loader.js +527 -0
  87. package/dist/loader.js.map +1 -0
  88. package/dist/observer-dispatcher.d.ts +69 -0
  89. package/dist/observer-dispatcher.d.ts.map +1 -0
  90. package/dist/observer-dispatcher.js +184 -0
  91. package/dist/observer-dispatcher.js.map +1 -0
  92. package/dist/plugin-merger.d.ts +175 -0
  93. package/dist/plugin-merger.d.ts.map +1 -0
  94. package/dist/plugin-merger.js +450 -0
  95. package/dist/plugin-merger.js.map +1 -0
  96. package/dist/plugins/git/branch-tracker.d.ts +85 -0
  97. package/dist/plugins/git/branch-tracker.d.ts.map +1 -0
  98. package/dist/plugins/git/branch-tracker.js +181 -0
  99. package/dist/plugins/git/branch-tracker.js.map +1 -0
  100. package/dist/plugins/git/cwd-extensions.d.ts +10 -0
  101. package/dist/plugins/git/cwd-extensions.d.ts.map +1 -0
  102. package/dist/plugins/git/cwd-extensions.js +155 -0
  103. package/dist/plugins/git/cwd-extensions.js.map +1 -0
  104. package/dist/plugins/git/git-ops.d.ts +89 -0
  105. package/dist/plugins/git/git-ops.d.ts.map +1 -0
  106. package/dist/plugins/git/git-ops.js +107 -0
  107. package/dist/plugins/git/git-ops.js.map +1 -0
  108. package/dist/plugins/git/index.d.ts +225 -0
  109. package/dist/plugins/git/index.d.ts.map +1 -0
  110. package/dist/plugins/git/index.js +52 -0
  111. package/dist/plugins/git/index.js.map +1 -0
  112. package/dist/plugins/git/predicates.d.ts +312 -0
  113. package/dist/plugins/git/predicates.d.ts.map +1 -0
  114. package/dist/plugins/git/predicates.js +580 -0
  115. package/dist/plugins/git/predicates.js.map +1 -0
  116. package/dist/plugins/git/rules.d.ts +209 -0
  117. package/dist/plugins/git/rules.d.ts.map +1 -0
  118. package/dist/plugins/git/rules.js +267 -0
  119. package/dist/plugins/git/rules.js.map +1 -0
  120. package/dist/schema.d.ts +1799 -0
  121. package/dist/schema.d.ts.map +1 -0
  122. package/dist/schema.js +4 -0
  123. package/dist/schema.js.map +1 -0
  124. package/dist/testing/index.d.ts +621 -0
  125. package/dist/testing/index.d.ts.map +1 -0
  126. package/dist/testing/index.js +747 -0
  127. package/dist/testing/index.js.map +1 -0
  128. package/examples/README.md +83 -0
  129. package/examples/combined-git-discipline/README.md +52 -0
  130. package/examples/combined-git-discipline/node_modules/.bin/pi-steering +43 -0
  131. package/examples/combined-git-discipline/package.json +18 -0
  132. package/examples/combined-git-discipline/steering.json +27 -0
  133. package/examples/combined-git-discipline/steering.test.ts +42 -0
  134. package/examples/combined-git-discipline/steering.ts +64 -0
  135. package/examples/combined-git-discipline/tsconfig.json +7 -0
  136. package/examples/draft-prs-only/README.md +42 -0
  137. package/examples/draft-prs-only/node_modules/.bin/pi-steering +43 -0
  138. package/examples/draft-prs-only/package.json +18 -0
  139. package/examples/draft-prs-only/steering.json +12 -0
  140. package/examples/draft-prs-only/steering.test.ts +48 -0
  141. package/examples/draft-prs-only/steering.ts +36 -0
  142. package/examples/draft-prs-only/tsconfig.json +7 -0
  143. package/examples/dynamic-reason-runtime-cwd/README.md +148 -0
  144. package/examples/dynamic-reason-runtime-cwd/node_modules/.bin/pi-steering +43 -0
  145. package/examples/dynamic-reason-runtime-cwd/package.json +18 -0
  146. package/examples/dynamic-reason-runtime-cwd/steering.test.ts +130 -0
  147. package/examples/dynamic-reason-runtime-cwd/steering.ts +82 -0
  148. package/examples/dynamic-reason-runtime-cwd/tsconfig.json +7 -0
  149. package/examples/force-push-strict/README.md +75 -0
  150. package/examples/force-push-strict/node_modules/.bin/pi-steering +43 -0
  151. package/examples/force-push-strict/package.json +18 -0
  152. package/examples/force-push-strict/steering.json +12 -0
  153. package/examples/force-push-strict/steering.test.ts +51 -0
  154. package/examples/force-push-strict/steering.ts +54 -0
  155. package/examples/force-push-strict/tsconfig.json +7 -0
  156. package/examples/no-amend/README.md +52 -0
  157. package/examples/no-amend/node_modules/.bin/pi-steering +43 -0
  158. package/examples/no-amend/package.json +18 -0
  159. package/examples/no-amend/steering.cwd-scoped.json +12 -0
  160. package/examples/no-amend/steering.json +11 -0
  161. package/examples/no-amend/steering.test.ts +49 -0
  162. package/examples/no-amend/steering.ts +38 -0
  163. package/examples/no-amend/tsconfig.json +7 -0
  164. package/examples/work-item-plugin/README.md +103 -0
  165. package/examples/work-item-plugin/node_modules/.bin/pi-steering +43 -0
  166. package/examples/work-item-plugin/package.json +19 -0
  167. package/examples/work-item-plugin/src/index.test.ts +168 -0
  168. package/examples/work-item-plugin/src/index.ts +122 -0
  169. package/examples/work-item-plugin/src/observers/npm-test-tracker.test.ts +95 -0
  170. package/examples/work-item-plugin/src/observers/npm-test-tracker.ts +88 -0
  171. package/examples/work-item-plugin/src/observers/retest-required-tracker.test.ts +81 -0
  172. package/examples/work-item-plugin/src/observers/retest-required-tracker.ts +81 -0
  173. package/examples/work-item-plugin/src/predicates/work-item-format.test.ts +157 -0
  174. package/examples/work-item-plugin/src/predicates/work-item-format.ts +99 -0
  175. package/examples/work-item-plugin/src/rules/commit-description-check.test.ts +107 -0
  176. package/examples/work-item-plugin/src/rules/commit-description-check.ts +83 -0
  177. package/examples/work-item-plugin/src/rules/commit-requires-work-item.test.ts +79 -0
  178. package/examples/work-item-plugin/src/rules/commit-requires-work-item.ts +56 -0
  179. package/examples/work-item-plugin/src/rules/push-requires-tests.test.ts +245 -0
  180. package/examples/work-item-plugin/src/rules/push-requires-tests.ts +62 -0
  181. package/examples/work-item-plugin/tsconfig.json +8 -0
  182. package/package.json +88 -0
  183. package/skills/steering-authoring/SKILL.md +102 -0
  184. package/src/INVARIANTS.md +116 -0
  185. package/src/__test-helpers__.ts +243 -0
  186. package/src/bin/pi-steering.test.ts +920 -0
  187. package/src/bin/pi-steering.ts +584 -0
  188. package/src/compat.test.ts +431 -0
  189. package/src/compat.ts +282 -0
  190. package/src/defaults.test.ts +585 -0
  191. package/src/defaults.ts +148 -0
  192. package/src/define-config.test.ts +888 -0
  193. package/src/define-config.ts +375 -0
  194. package/src/define-predicate.test.ts +70 -0
  195. package/src/define-predicate.ts +57 -0
  196. package/src/evaluator-internals/context.ts +290 -0
  197. package/src/evaluator-internals/override.test.ts +99 -0
  198. package/src/evaluator-internals/override.ts +83 -0
  199. package/src/evaluator-internals/predicates.ts +1037 -0
  200. package/src/evaluator-internals/speculative-synthesis.test.ts +411 -0
  201. package/src/evaluator-internals/speculative-synthesis.ts +199 -0
  202. package/src/evaluator.test.ts +6296 -0
  203. package/src/evaluator.ts +1106 -0
  204. package/src/factory-time-load.test.ts +630 -0
  205. package/src/helpers/walker-unknown-cwd-reason.test.ts +73 -0
  206. package/src/helpers/walker-unknown-cwd-reason.ts +83 -0
  207. package/src/index.test.ts +836 -0
  208. package/src/index.ts +229 -0
  209. package/src/internal/drop-unused-observers.test.ts +141 -0
  210. package/src/internal/drop-unused-observers.ts +81 -0
  211. package/src/internal/finalize-plugin-state.ts +43 -0
  212. package/src/internal/merge-observers.ts +51 -0
  213. package/src/internal/pattern-utils.test.ts +52 -0
  214. package/src/internal/pattern-utils.ts +38 -0
  215. package/src/internal/ref-text.test.ts +54 -0
  216. package/src/internal/ref-text.ts +17 -0
  217. package/src/internal/session-runtime.test.ts +629 -0
  218. package/src/internal/session-runtime.ts +201 -0
  219. package/src/internal/watch-matcher.test.ts +326 -0
  220. package/src/internal/watch-matcher.ts +200 -0
  221. package/src/jsdoc-propagation.test.ts +277 -0
  222. package/src/loader.test.ts +1098 -0
  223. package/src/loader.ts +581 -0
  224. package/src/not-block-onunknown.test.ts +554 -0
  225. package/src/observer-dispatcher.test.ts +939 -0
  226. package/src/observer-dispatcher.ts +290 -0
  227. package/src/per-predicate-typing.test.ts +361 -0
  228. package/src/plugin-merger.test.ts +790 -0
  229. package/src/plugin-merger.ts +598 -0
  230. package/src/plugins/git/README.md +485 -0
  231. package/src/plugins/git/branch-tracker.test.ts +281 -0
  232. package/src/plugins/git/branch-tracker.ts +187 -0
  233. package/src/plugins/git/cwd-extensions.test.ts +230 -0
  234. package/src/plugins/git/cwd-extensions.ts +160 -0
  235. package/src/plugins/git/git-ops.test.ts +397 -0
  236. package/src/plugins/git/git-ops.ts +173 -0
  237. package/src/plugins/git/index.ts +253 -0
  238. package/src/plugins/git/integration.test.ts +705 -0
  239. package/src/plugins/git/predicates.test.ts +1401 -0
  240. package/src/plugins/git/predicates.ts +693 -0
  241. package/src/plugins/git/rules.test.ts +1001 -0
  242. package/src/plugins/git/rules.ts +307 -0
  243. package/src/schema.test.ts +259 -0
  244. package/src/schema.ts +1963 -0
  245. package/src/testing/index.test.ts +1696 -0
  246. package/src/testing/index.ts +1472 -0
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Bash command pattern matching `git commit` (with optional pre-subcommand
3
+ * flag slots like `git -C /path commit ...`). Shared by `no-main-commit`
4
+ * and `no-main-commit-github` so the family stays byte-equal as the
5
+ * regex evolves; reorderings that touch one rule's pattern can't
6
+ * silently drift from the other.
7
+ *
8
+ * Exported so tests can pin each rule's `pattern` field against this
9
+ * constant by value (`noMainCommit.pattern === GIT_COMMIT_PATTERN`).
10
+ * That catches accidental divergence between the two rules' patterns
11
+ * (e.g. one drops a `\b`, the other doesn't) and removal/rename of
12
+ * the constant itself. It does NOT catch a future inlining of the
13
+ * literal at a rule's definition site with the SAME bytes — string
14
+ * primitives compare by value, so byte-equal copy-pasted literals
15
+ * pass `===`. Plugin authors who need true shared-reference pinning
16
+ * should use a `RegExp` (object) constant instead of a string source.
17
+ */
18
+ export declare const GIT_COMMIT_PATTERN = "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
19
+ /**
20
+ * Protected branch names that the gitPlugin's commit-on-main rules
21
+ * block by default (`main`, `master`, `mainline`, `trunk`). Shared by
22
+ * `no-main-commit` and `no-main-commit-github` so the protected-
23
+ * branch list stays uniform across the rule family — adding an alias
24
+ * here (e.g. a vendor-specific default-branch name) automatically
25
+ * propagates to both rules.
26
+ *
27
+ * `RegExp` (object) constant rather than a string source: that gives
28
+ * true shared-reference pinning at the test layer
29
+ * (`noMainCommit.when.branch === PROTECTED_BRANCH_PATTERN`), which
30
+ * also catches a future inline of the SAME bytes at a rule's
31
+ * definition site — something the string-source `GIT_COMMIT_PATTERN`
32
+ * pin can't do (see its JSDoc for the value-vs-reference tradeoff).
33
+ */
34
+ export declare const PROTECTED_BRANCH_PATTERN: RegExp;
35
+ /**
36
+ * `no-main-commit` - block direct commits to a protected branch
37
+ * (main / master / mainline / trunk).
38
+ *
39
+ * Fires on:
40
+ * - `git commit -m "..."` when the current branch is one of the
41
+ * protected names,
42
+ * - `git checkout main && git commit ...` (the branch tracker folds
43
+ * the checkout into the branch state for the commit),
44
+ * - `sh -c 'git commit ...'` (wrapper expansion),
45
+ * - `git -C /other commit ...` where the repo at `/other` is on
46
+ * main (the `branch` predicate queries git at the effective cwd).
47
+ *
48
+ * Does NOT fire on:
49
+ * - `git commit` while on a feature branch,
50
+ * - `git log --grep="commit"` (anchored to `git commit`, not
51
+ * arbitrary git subcommands),
52
+ * - `echo 'git commit -m "x"'` (extraction anchors to the
53
+ * basename).
54
+ *
55
+ * Fail-closed on unresolvable branch: if the branch predicate can't
56
+ * determine the current branch (detached HEAD, not a repo, or the
57
+ * tracker collapsed to `unknown` via `git checkout $VAR`), the rule
58
+ * fires by default. Authors who want the allow-through behavior
59
+ * supply the object form explicitly:
60
+ *
61
+ * `when: { branch: { pattern: /.../, onUnknown: "allow" } }`
62
+ *
63
+ * Reason text is dynamic via {@link ReasonFn}: when the branch
64
+ * tracker has resolved a concrete branch name for the guarded
65
+ * command (statically from a `git checkout <name>` earlier in the
66
+ * chain), the name is injected into the block message so the agent
67
+ * sees "You are on 'main'" instead of a generic reminder. The
68
+ * ReasonFn filters out the tracker's internal sentinels
69
+ * (`NO_CHECKOUT_IN_CHAIN` — no in-chain checkout, exec-fallback
70
+ * path; `"unknown"` — dynamic checkout the walker couldn't
71
+ * resolve) so those strings never leak into the agent-facing
72
+ * message; the static actionable tail still guides the agent to a
73
+ * feature branch in those cases.
74
+ *
75
+ * Pairs with {@link noMainCommitGithub} (specialization for
76
+ * github.com clones, placed BEFORE this rule in the rule array so
77
+ * first-match-wins routes the github-flavored guidance to github
78
+ * users; non-github contexts fall through to this generic rule).
79
+ *
80
+ * Override: allowed (the rule is overridable via a
81
+ * `# steering-override: no-main-commit` comment). This is a workflow
82
+ * rule, not an inherent-destructiveness rule - authors override when
83
+ * the commit is intentional (e.g. release process on `main`).
84
+ */
85
+ export declare const noMainCommit: {
86
+ readonly name: "no-main-commit";
87
+ readonly tool: "bash";
88
+ readonly field: "command";
89
+ readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
90
+ readonly when: {
91
+ readonly branch: RegExp;
92
+ };
93
+ readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string;
94
+ readonly noOverride: false;
95
+ };
96
+ /**
97
+ * `no-main-commit-github` — block direct commits to a protected
98
+ * branch (main / master / mainline / trunk) on github.com clones.
99
+ * Specialization of {@link noMainCommit} that emits PR-flow guidance
100
+ * instead of the generic feature-branch reminder.
101
+ *
102
+ * Pairs with {@link noMainCommit}: this rule is more specific (adds
103
+ * `remote:` check), placed BEFORE `noMainCommit` in the plugin's
104
+ * rule array so first-match-wins routing surfaces the github-
105
+ * flavored reason on github clones. Non-github contexts (Brazil
106
+ * packages, vault paths, /tmp scratch repos with non-github remotes)
107
+ * fall through to the generic `noMainCommit`.
108
+ *
109
+ * Override: allowed (intentionally overridable for legitimate cases
110
+ * like release-process commits to main). User can:
111
+ * - Disable: `disabledRules: ["no-main-commit-github"]`
112
+ * - Per-invocation: `# steering-override: no-main-commit-github` comment
113
+ * - Customize: see gitPlugin's README "Customization" section
114
+ *
115
+ * @remarks Both `https://github.com/...` and `git@github.com:...`
116
+ * clone URLs are matched (the `remote:` regex's `[/:]`
117
+ * character class accepts both the HTTPS path separator
118
+ * and the SSH user-host separator).
119
+ *
120
+ * @remarks `remote:` is configured as `{ pattern, onUnknown: "allow" }`.
121
+ * The `onUnknown: "allow"` argument governs the case where
122
+ * the walker resolved cwd but the inner exec couldn't
123
+ * determine the remote URL — i.e. a known-cwd repo with no
124
+ * `origin` remote configured (fresh-init, repo with
125
+ * `upstream` but no `origin`, or other exec failure). In that
126
+ * case the predicate skips and the engine falls through to
127
+ * the generic `noMainCommit` (correct generic message).
128
+ * The branch predicate stays at default `onUnknown: "block"`
129
+ * (fail-closed) so protected-branch detection isn't weakened.
130
+ *
131
+ * Walker-unknown cwd: the `remote:` leaf surfaces trinary
132
+ * `"unknown"` (via the inline walker-unknown-cwd guard at the top of
133
+ * the handler) before the inner exec runs whenever
134
+ * `walkerState.cwd === "unknown"`. The engine's leaf-level
135
+ * `onUnknown:` policy reads the `"allow"` set on the leaf, projects
136
+ * `"unknown" → false`, and the github rule SKIPS. The engine then
137
+ * falls through to the generic {@link noMainCommit} (only `branch:`
138
+ * leaf), which fires fail-CLOSED and emits the generic
139
+ * protected-branch reason. The github-specific rule deliberately
140
+ * does NOT fire under walker-unknown cwd — a github-flavored reason
141
+ * would overstate what the engine has confirmed.
142
+ *
143
+ * Walker-unknown branch state: when `walkerState.cwd` is known but
144
+ * the branch tracker collapses to its `"unknown"` sentinel (dynamic
145
+ * checkout the walker couldn't resolve), the reason fn routes to a
146
+ * "could not verify the current branch" message rather than
147
+ * asserting a specific protected branch the engine hasn't
148
+ * confirmed.
149
+ *
150
+ * Pattern is shared with `noMainCommit` via the exported
151
+ * {@link GIT_COMMIT_PATTERN} constant so the two rules' bash-
152
+ * command applicability stays byte-equal as the family evolves.
153
+ *
154
+ * @see {@link noMainCommit}
155
+ */
156
+ export declare const noMainCommitGithub: {
157
+ readonly name: "no-main-commit-github";
158
+ readonly tool: "bash";
159
+ readonly field: "command";
160
+ readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
161
+ readonly when: {
162
+ readonly branch: RegExp;
163
+ readonly remote: {
164
+ readonly pattern: RegExp;
165
+ readonly onUnknown: "allow";
166
+ };
167
+ };
168
+ readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string;
169
+ readonly noOverride: false;
170
+ };
171
+ /**
172
+ * Suggested rules for the git plugin.
173
+ *
174
+ * **Order matters — first-match-wins.** The github-specific rule
175
+ * (`no-main-commit-github`) is placed BEFORE the generic
176
+ * (`no-main-commit`) so on github clones + on main, the github
177
+ * rule's `remote:` predicate matches → fires first → user gets
178
+ * PR-flow guidance. On non-github contexts (Brazil packages, vault
179
+ * paths, scratch repos with non-github remotes) the github rule's
180
+ * `remote:` predicate doesn't match → the engine falls through to
181
+ * the generic `no-main-commit`. Reordering for stylistic reasons
182
+ * breaks this routing; pinned via a unit test in `./rules.test.ts`.
183
+ */
184
+ export declare const rules: readonly [{
185
+ readonly name: "no-main-commit-github";
186
+ readonly tool: "bash";
187
+ readonly field: "command";
188
+ readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
189
+ readonly when: {
190
+ readonly branch: RegExp;
191
+ readonly remote: {
192
+ readonly pattern: RegExp;
193
+ readonly onUnknown: "allow";
194
+ };
195
+ };
196
+ readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string;
197
+ readonly noOverride: false;
198
+ }, {
199
+ readonly name: "no-main-commit";
200
+ readonly tool: "bash";
201
+ readonly field: "command";
202
+ readonly pattern: "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
203
+ readonly when: {
204
+ readonly branch: RegExp;
205
+ };
206
+ readonly reason: (ctx: import("../../schema.ts").PredicateContext) => string;
207
+ readonly noOverride: false;
208
+ }];
209
+ //# sourceMappingURL=rules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../../../src/plugins/git/rules.ts"],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,kBAAkB,iEACiC,CAAC;AAEjE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,wBAAwB,QAAmC,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;CA4BA,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;CA+EN,CAAC;AAE1B;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;EAGkB,CAAC"}
@@ -0,0 +1,267 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Part of pi-steering.
3
+ import { NO_CHECKOUT_IN_CHAIN } from "./branch-tracker.js";
4
+ import { walkerString } from "./predicates.js";
5
+ /**
6
+ * Bash command pattern matching `git commit` (with optional pre-subcommand
7
+ * flag slots like `git -C /path commit ...`). Shared by `no-main-commit`
8
+ * and `no-main-commit-github` so the family stays byte-equal as the
9
+ * regex evolves; reorderings that touch one rule's pattern can't
10
+ * silently drift from the other.
11
+ *
12
+ * Exported so tests can pin each rule's `pattern` field against this
13
+ * constant by value (`noMainCommit.pattern === GIT_COMMIT_PATTERN`).
14
+ * That catches accidental divergence between the two rules' patterns
15
+ * (e.g. one drops a `\b`, the other doesn't) and removal/rename of
16
+ * the constant itself. It does NOT catch a future inlining of the
17
+ * literal at a rule's definition site with the SAME bytes — string
18
+ * primitives compare by value, so byte-equal copy-pasted literals
19
+ * pass `===`. Plugin authors who need true shared-reference pinning
20
+ * should use a `RegExp` (object) constant instead of a string source.
21
+ */
22
+ export const GIT_COMMIT_PATTERN = "^git\\b(?:\\s+-{1,2}[A-Za-z]\\S*(?:\\s+\\S+)?)*\\s+commit\\b";
23
+ /**
24
+ * Protected branch names that the gitPlugin's commit-on-main rules
25
+ * block by default (`main`, `master`, `mainline`, `trunk`). Shared by
26
+ * `no-main-commit` and `no-main-commit-github` so the protected-
27
+ * branch list stays uniform across the rule family — adding an alias
28
+ * here (e.g. a vendor-specific default-branch name) automatically
29
+ * propagates to both rules.
30
+ *
31
+ * `RegExp` (object) constant rather than a string source: that gives
32
+ * true shared-reference pinning at the test layer
33
+ * (`noMainCommit.when.branch === PROTECTED_BRANCH_PATTERN`), which
34
+ * also catches a future inline of the SAME bytes at a rule's
35
+ * definition site — something the string-source `GIT_COMMIT_PATTERN`
36
+ * pin can't do (see its JSDoc for the value-vs-reference tradeoff).
37
+ */
38
+ export const PROTECTED_BRANCH_PATTERN = /^(main|master|mainline|trunk)$/;
39
+ /**
40
+ * `no-main-commit` - block direct commits to a protected branch
41
+ * (main / master / mainline / trunk).
42
+ *
43
+ * Fires on:
44
+ * - `git commit -m "..."` when the current branch is one of the
45
+ * protected names,
46
+ * - `git checkout main && git commit ...` (the branch tracker folds
47
+ * the checkout into the branch state for the commit),
48
+ * - `sh -c 'git commit ...'` (wrapper expansion),
49
+ * - `git -C /other commit ...` where the repo at `/other` is on
50
+ * main (the `branch` predicate queries git at the effective cwd).
51
+ *
52
+ * Does NOT fire on:
53
+ * - `git commit` while on a feature branch,
54
+ * - `git log --grep="commit"` (anchored to `git commit`, not
55
+ * arbitrary git subcommands),
56
+ * - `echo 'git commit -m "x"'` (extraction anchors to the
57
+ * basename).
58
+ *
59
+ * Fail-closed on unresolvable branch: if the branch predicate can't
60
+ * determine the current branch (detached HEAD, not a repo, or the
61
+ * tracker collapsed to `unknown` via `git checkout $VAR`), the rule
62
+ * fires by default. Authors who want the allow-through behavior
63
+ * supply the object form explicitly:
64
+ *
65
+ * `when: { branch: { pattern: /.../, onUnknown: "allow" } }`
66
+ *
67
+ * Reason text is dynamic via {@link ReasonFn}: when the branch
68
+ * tracker has resolved a concrete branch name for the guarded
69
+ * command (statically from a `git checkout <name>` earlier in the
70
+ * chain), the name is injected into the block message so the agent
71
+ * sees "You are on 'main'" instead of a generic reminder. The
72
+ * ReasonFn filters out the tracker's internal sentinels
73
+ * (`NO_CHECKOUT_IN_CHAIN` — no in-chain checkout, exec-fallback
74
+ * path; `"unknown"` — dynamic checkout the walker couldn't
75
+ * resolve) so those strings never leak into the agent-facing
76
+ * message; the static actionable tail still guides the agent to a
77
+ * feature branch in those cases.
78
+ *
79
+ * Pairs with {@link noMainCommitGithub} (specialization for
80
+ * github.com clones, placed BEFORE this rule in the rule array so
81
+ * first-match-wins routes the github-flavored guidance to github
82
+ * users; non-github contexts fall through to this generic rule).
83
+ *
84
+ * Override: allowed (the rule is overridable via a
85
+ * `# steering-override: no-main-commit` comment). This is a workflow
86
+ * rule, not an inherent-destructiveness rule - authors override when
87
+ * the commit is intentional (e.g. release process on `main`).
88
+ */
89
+ export const noMainCommit = {
90
+ name: "no-main-commit",
91
+ tool: "bash",
92
+ field: "command",
93
+ pattern: GIT_COMMIT_PATTERN,
94
+ when: { branch: PROTECTED_BRANCH_PATTERN },
95
+ reason: (ctx) => {
96
+ // Delegate the sentinel classification to `walkerString` — the
97
+ // same three-way discrimination (value / unknown / missing)
98
+ // every other branch-consumer in this plugin uses. Single source
99
+ // of truth for tracker-sentinel semantics; future sentinel
100
+ // additions update one site (the classifier in predicates.ts),
101
+ // not this filter too. Empty-string remains filtered inline as
102
+ // a defensive check against future tracker contracts (detached
103
+ // HEAD or similar); the branch tracker doesn't emit it today.
104
+ const res = walkerString(ctx, "branch", NO_CHECKOUT_IN_CHAIN);
105
+ const branch = res.kind === "value" && res.value !== "" ? res.value : undefined;
106
+ const onClause = branch !== undefined ? ` You are on '${branch}'.` : "";
107
+ return (`Don't commit directly to a protected branch ` +
108
+ `(main / master / mainline / trunk).${onClause} ` +
109
+ `Create a feature branch first: \`git checkout -b feat/...\`.`);
110
+ },
111
+ // Explicit override-OK: workflow rules are intentionally
112
+ // overridable.
113
+ noOverride: false,
114
+ };
115
+ /**
116
+ * `no-main-commit-github` — block direct commits to a protected
117
+ * branch (main / master / mainline / trunk) on github.com clones.
118
+ * Specialization of {@link noMainCommit} that emits PR-flow guidance
119
+ * instead of the generic feature-branch reminder.
120
+ *
121
+ * Pairs with {@link noMainCommit}: this rule is more specific (adds
122
+ * `remote:` check), placed BEFORE `noMainCommit` in the plugin's
123
+ * rule array so first-match-wins routing surfaces the github-
124
+ * flavored reason on github clones. Non-github contexts (Brazil
125
+ * packages, vault paths, /tmp scratch repos with non-github remotes)
126
+ * fall through to the generic `noMainCommit`.
127
+ *
128
+ * Override: allowed (intentionally overridable for legitimate cases
129
+ * like release-process commits to main). User can:
130
+ * - Disable: `disabledRules: ["no-main-commit-github"]`
131
+ * - Per-invocation: `# steering-override: no-main-commit-github` comment
132
+ * - Customize: see gitPlugin's README "Customization" section
133
+ *
134
+ * @remarks Both `https://github.com/...` and `git@github.com:...`
135
+ * clone URLs are matched (the `remote:` regex's `[/:]`
136
+ * character class accepts both the HTTPS path separator
137
+ * and the SSH user-host separator).
138
+ *
139
+ * @remarks `remote:` is configured as `{ pattern, onUnknown: "allow" }`.
140
+ * The `onUnknown: "allow"` argument governs the case where
141
+ * the walker resolved cwd but the inner exec couldn't
142
+ * determine the remote URL — i.e. a known-cwd repo with no
143
+ * `origin` remote configured (fresh-init, repo with
144
+ * `upstream` but no `origin`, or other exec failure). In that
145
+ * case the predicate skips and the engine falls through to
146
+ * the generic `noMainCommit` (correct generic message).
147
+ * The branch predicate stays at default `onUnknown: "block"`
148
+ * (fail-closed) so protected-branch detection isn't weakened.
149
+ *
150
+ * Walker-unknown cwd: the `remote:` leaf surfaces trinary
151
+ * `"unknown"` (via the inline walker-unknown-cwd guard at the top of
152
+ * the handler) before the inner exec runs whenever
153
+ * `walkerState.cwd === "unknown"`. The engine's leaf-level
154
+ * `onUnknown:` policy reads the `"allow"` set on the leaf, projects
155
+ * `"unknown" → false`, and the github rule SKIPS. The engine then
156
+ * falls through to the generic {@link noMainCommit} (only `branch:`
157
+ * leaf), which fires fail-CLOSED and emits the generic
158
+ * protected-branch reason. The github-specific rule deliberately
159
+ * does NOT fire under walker-unknown cwd — a github-flavored reason
160
+ * would overstate what the engine has confirmed.
161
+ *
162
+ * Walker-unknown branch state: when `walkerState.cwd` is known but
163
+ * the branch tracker collapses to its `"unknown"` sentinel (dynamic
164
+ * checkout the walker couldn't resolve), the reason fn routes to a
165
+ * "could not verify the current branch" message rather than
166
+ * asserting a specific protected branch the engine hasn't
167
+ * confirmed.
168
+ *
169
+ * Pattern is shared with `noMainCommit` via the exported
170
+ * {@link GIT_COMMIT_PATTERN} constant so the two rules' bash-
171
+ * command applicability stays byte-equal as the family evolves.
172
+ *
173
+ * @see {@link noMainCommit}
174
+ */
175
+ export const noMainCommitGithub = {
176
+ name: "no-main-commit-github",
177
+ tool: "bash",
178
+ field: "command",
179
+ pattern: GIT_COMMIT_PATTERN,
180
+ when: {
181
+ branch: PROTECTED_BRANCH_PATTERN,
182
+ // Intentional fail-OPEN — falls through to the generic
183
+ // `noMainCommit` rule when origin can't be resolved.
184
+ //
185
+ // `onUnknown: "allow"` posture: a github-specialized rule
186
+ // should only fire when github context is confirmed. The
187
+ // `"allow"` covers two opt-out paths:
188
+ // 1. Known-cwd no-`origin` case (fresh-init repo, repo with
189
+ // `upstream` but no `origin`, or other exec failure):
190
+ // handler returns `false`, leaf projects to false, github
191
+ // rule skips. Generic `noMainCommit` fires next — user
192
+ // gets the correct generic message rather than PR-flow
193
+ // guidance for a repo where there's no PR to open.
194
+ // 2. Walker-unknown cwd (`cd "$VAR" && git commit`): the
195
+ // handler's inline guard surfaces trinary `"unknown"`,
196
+ // the leaf-level `"allow"` projects to false, github rule
197
+ // skips. Generic `noMainCommit` fires fail-CLOSED via the
198
+ // branch predicate's default `onUnknown: "block"`.
199
+ // Both paths land on the same generic protected-branch reason,
200
+ // avoiding overstated github-specific claims when context is
201
+ // unverified.
202
+ remote: { pattern: /github\.com[/:]/, onUnknown: "allow" },
203
+ },
204
+ reason: (ctx) => {
205
+ // Walker-unknown branch: protected-branch unverified. Don't
206
+ // make a positive claim about which protected branch is
207
+ // involved.
208
+ //
209
+ // (CWD is always known in this rule's reason fn — `remote:`'s
210
+ // `onUnknown: "allow"` projects walker-unknown CWD to false at
211
+ // the leaf level, so the rule skips to the generic
212
+ // `noMainCommit` before this reason fn runs.)
213
+ const branchRes = walkerString(ctx, "branch", NO_CHECKOUT_IN_CHAIN);
214
+ if (branchRes.kind === "unknown") {
215
+ return (`Could not verify the current branch — your command used a ` +
216
+ `dynamic checkout target (\`git checkout $VAR\`) that ` +
217
+ `couldn't be statically resolved. If you're on a protected ` +
218
+ `branch (main / master / mainline / trunk) on a github ` +
219
+ `clone, open a PR for review instead of committing directly.` +
220
+ `\n\n` +
221
+ `Safety: NEVER merge a PR or mark it ready-for-review unless ` +
222
+ `the user explicitly asks. Wait for explicit user instruction.`);
223
+ }
224
+ // Reuse the same walkerString-based branch interpolation idiom
225
+ // noMainCommit's reason fn uses (single source of truth for
226
+ // tracker-sentinel semantics).
227
+ const branch = branchRes.kind === "value" && branchRes.value !== ""
228
+ ? branchRes.value
229
+ : undefined;
230
+ const onClause = branch !== undefined ? ` You are on '${branch}'.` : "";
231
+ // Prose says "protected branch" rather than "main branch":
232
+ // the `when:` clause matches all four protected branch names
233
+ // (main / master / mainline / trunk). Mirrors
234
+ // `noMainCommit`'s wording, which lists them.
235
+ return (`You're on a github clone's protected branch.${onClause} Open ` +
236
+ `a PR for review; \`gh pr merge\` lands the change after ` +
237
+ `approval. Direct commits to a protected branch bypass review ` +
238
+ `and break PR discipline.` +
239
+ `\n\n` +
240
+ `Safety: NEVER merge a PR or mark it ready-for-review unless ` +
241
+ `the user explicitly asks. Wait for explicit user instruction.`);
242
+ },
243
+ // Explicit override-OK: workflow rules are intentionally
244
+ // overridable. Mirrors `noMainCommit`'s posture. Without this
245
+ // field the schema defaults to `defaultNoOverride: true`
246
+ // (fail-closed), making the rule non-overridable and contradicting
247
+ // the JSDoc above.
248
+ noOverride: false,
249
+ };
250
+ /**
251
+ * Suggested rules for the git plugin.
252
+ *
253
+ * **Order matters — first-match-wins.** The github-specific rule
254
+ * (`no-main-commit-github`) is placed BEFORE the generic
255
+ * (`no-main-commit`) so on github clones + on main, the github
256
+ * rule's `remote:` predicate matches → fires first → user gets
257
+ * PR-flow guidance. On non-github contexts (Brazil packages, vault
258
+ * paths, scratch repos with non-github remotes) the github rule's
259
+ * `remote:` predicate doesn't match → the engine falls through to
260
+ * the generic `no-main-commit`. Reordering for stylistic reasons
261
+ * breaks this routing; pinned via a unit test in `./rules.test.ts`.
262
+ */
263
+ export const rules = [
264
+ noMainCommitGithub,
265
+ noMainCommit,
266
+ ];
267
+ //# sourceMappingURL=rules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules.js","sourceRoot":"","sources":["../../../src/plugins/git/rules.ts"],"names":[],"mappings":"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"}