@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.
- package/CHANGELOG.md +36 -0
- package/LICENSE +29 -0
- package/README.md +920 -0
- package/dist/__test-helpers__.d.ts +95 -0
- package/dist/__test-helpers__.d.ts.map +1 -0
- package/dist/__test-helpers__.js +174 -0
- package/dist/__test-helpers__.js.map +1 -0
- package/dist/bin/pi-steering.d.ts +9 -0
- package/dist/bin/pi-steering.d.ts.map +1 -0
- package/dist/bin/pi-steering.js +506 -0
- package/dist/bin/pi-steering.js.map +1 -0
- package/dist/compat.d.ts +50 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +180 -0
- package/dist/compat.js.map +1 -0
- package/dist/defaults.d.ts +61 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +106 -0
- package/dist/defaults.js.map +1 -0
- package/dist/define-config.d.ts +235 -0
- package/dist/define-config.d.ts.map +1 -0
- package/dist/define-config.js +118 -0
- package/dist/define-config.js.map +1 -0
- package/dist/define-predicate.d.ts +49 -0
- package/dist/define-predicate.d.ts.map +1 -0
- package/dist/define-predicate.js +35 -0
- package/dist/define-predicate.js.map +1 -0
- package/dist/evaluator-internals/context.d.ts +186 -0
- package/dist/evaluator-internals/context.d.ts.map +1 -0
- package/dist/evaluator-internals/context.js +219 -0
- package/dist/evaluator-internals/context.js.map +1 -0
- package/dist/evaluator-internals/override.d.ts +19 -0
- package/dist/evaluator-internals/override.d.ts.map +1 -0
- package/dist/evaluator-internals/override.js +79 -0
- package/dist/evaluator-internals/override.js.map +1 -0
- package/dist/evaluator-internals/predicates.d.ts +152 -0
- package/dist/evaluator-internals/predicates.d.ts.map +1 -0
- package/dist/evaluator-internals/predicates.js +849 -0
- package/dist/evaluator-internals/predicates.js.map +1 -0
- package/dist/evaluator-internals/speculative-synthesis.d.ts +102 -0
- package/dist/evaluator-internals/speculative-synthesis.d.ts.map +1 -0
- package/dist/evaluator-internals/speculative-synthesis.js +101 -0
- package/dist/evaluator-internals/speculative-synthesis.js.map +1 -0
- package/dist/evaluator.d.ts +101 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +714 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/helpers/walker-unknown-cwd-reason.d.ts +68 -0
- package/dist/helpers/walker-unknown-cwd-reason.d.ts.map +1 -0
- package/dist/helpers/walker-unknown-cwd-reason.js +73 -0
- package/dist/helpers/walker-unknown-cwd-reason.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/drop-unused-observers.d.ts +43 -0
- package/dist/internal/drop-unused-observers.d.ts.map +1 -0
- package/dist/internal/drop-unused-observers.js +50 -0
- package/dist/internal/drop-unused-observers.js.map +1 -0
- package/dist/internal/finalize-plugin-state.d.ts +22 -0
- package/dist/internal/finalize-plugin-state.d.ts.map +1 -0
- package/dist/internal/finalize-plugin-state.js +14 -0
- package/dist/internal/finalize-plugin-state.js.map +1 -0
- package/dist/internal/merge-observers.d.ts +30 -0
- package/dist/internal/merge-observers.d.ts.map +1 -0
- package/dist/internal/merge-observers.js +27 -0
- package/dist/internal/merge-observers.js.map +1 -0
- package/dist/internal/pattern-utils.d.ts +33 -0
- package/dist/internal/pattern-utils.d.ts.map +1 -0
- package/dist/internal/pattern-utils.js +20 -0
- package/dist/internal/pattern-utils.js.map +1 -0
- package/dist/internal/ref-text.d.ts +11 -0
- package/dist/internal/ref-text.d.ts.map +1 -0
- package/dist/internal/ref-text.js +15 -0
- package/dist/internal/ref-text.js.map +1 -0
- package/dist/internal/session-runtime.d.ts +44 -0
- package/dist/internal/session-runtime.d.ts.map +1 -0
- package/dist/internal/session-runtime.js +143 -0
- package/dist/internal/session-runtime.js.map +1 -0
- package/dist/internal/watch-matcher.d.ts +56 -0
- package/dist/internal/watch-matcher.d.ts.map +1 -0
- package/dist/internal/watch-matcher.js +179 -0
- package/dist/internal/watch-matcher.js.map +1 -0
- package/dist/loader.d.ts +97 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +527 -0
- package/dist/loader.js.map +1 -0
- package/dist/observer-dispatcher.d.ts +69 -0
- package/dist/observer-dispatcher.d.ts.map +1 -0
- package/dist/observer-dispatcher.js +184 -0
- package/dist/observer-dispatcher.js.map +1 -0
- package/dist/plugin-merger.d.ts +175 -0
- package/dist/plugin-merger.d.ts.map +1 -0
- package/dist/plugin-merger.js +450 -0
- package/dist/plugin-merger.js.map +1 -0
- package/dist/plugins/git/branch-tracker.d.ts +85 -0
- package/dist/plugins/git/branch-tracker.d.ts.map +1 -0
- package/dist/plugins/git/branch-tracker.js +181 -0
- package/dist/plugins/git/branch-tracker.js.map +1 -0
- package/dist/plugins/git/cwd-extensions.d.ts +10 -0
- package/dist/plugins/git/cwd-extensions.d.ts.map +1 -0
- package/dist/plugins/git/cwd-extensions.js +155 -0
- package/dist/plugins/git/cwd-extensions.js.map +1 -0
- package/dist/plugins/git/git-ops.d.ts +89 -0
- package/dist/plugins/git/git-ops.d.ts.map +1 -0
- package/dist/plugins/git/git-ops.js +107 -0
- package/dist/plugins/git/git-ops.js.map +1 -0
- package/dist/plugins/git/index.d.ts +225 -0
- package/dist/plugins/git/index.d.ts.map +1 -0
- package/dist/plugins/git/index.js +52 -0
- package/dist/plugins/git/index.js.map +1 -0
- package/dist/plugins/git/predicates.d.ts +312 -0
- package/dist/plugins/git/predicates.d.ts.map +1 -0
- package/dist/plugins/git/predicates.js +580 -0
- package/dist/plugins/git/predicates.js.map +1 -0
- package/dist/plugins/git/rules.d.ts +209 -0
- package/dist/plugins/git/rules.d.ts.map +1 -0
- package/dist/plugins/git/rules.js +267 -0
- package/dist/plugins/git/rules.js.map +1 -0
- package/dist/schema.d.ts +1799 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +4 -0
- package/dist/schema.js.map +1 -0
- package/dist/testing/index.d.ts +621 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +747 -0
- package/dist/testing/index.js.map +1 -0
- package/examples/README.md +83 -0
- package/examples/combined-git-discipline/README.md +52 -0
- package/examples/combined-git-discipline/node_modules/.bin/pi-steering +43 -0
- package/examples/combined-git-discipline/package.json +18 -0
- package/examples/combined-git-discipline/steering.json +27 -0
- package/examples/combined-git-discipline/steering.test.ts +42 -0
- package/examples/combined-git-discipline/steering.ts +64 -0
- package/examples/combined-git-discipline/tsconfig.json +7 -0
- package/examples/draft-prs-only/README.md +42 -0
- package/examples/draft-prs-only/node_modules/.bin/pi-steering +43 -0
- package/examples/draft-prs-only/package.json +18 -0
- package/examples/draft-prs-only/steering.json +12 -0
- package/examples/draft-prs-only/steering.test.ts +48 -0
- package/examples/draft-prs-only/steering.ts +36 -0
- package/examples/draft-prs-only/tsconfig.json +7 -0
- package/examples/dynamic-reason-runtime-cwd/README.md +148 -0
- package/examples/dynamic-reason-runtime-cwd/node_modules/.bin/pi-steering +43 -0
- package/examples/dynamic-reason-runtime-cwd/package.json +18 -0
- package/examples/dynamic-reason-runtime-cwd/steering.test.ts +130 -0
- package/examples/dynamic-reason-runtime-cwd/steering.ts +82 -0
- package/examples/dynamic-reason-runtime-cwd/tsconfig.json +7 -0
- package/examples/force-push-strict/README.md +75 -0
- package/examples/force-push-strict/node_modules/.bin/pi-steering +43 -0
- package/examples/force-push-strict/package.json +18 -0
- package/examples/force-push-strict/steering.json +12 -0
- package/examples/force-push-strict/steering.test.ts +51 -0
- package/examples/force-push-strict/steering.ts +54 -0
- package/examples/force-push-strict/tsconfig.json +7 -0
- package/examples/no-amend/README.md +52 -0
- package/examples/no-amend/node_modules/.bin/pi-steering +43 -0
- package/examples/no-amend/package.json +18 -0
- package/examples/no-amend/steering.cwd-scoped.json +12 -0
- package/examples/no-amend/steering.json +11 -0
- package/examples/no-amend/steering.test.ts +49 -0
- package/examples/no-amend/steering.ts +38 -0
- package/examples/no-amend/tsconfig.json +7 -0
- package/examples/work-item-plugin/README.md +103 -0
- package/examples/work-item-plugin/node_modules/.bin/pi-steering +43 -0
- package/examples/work-item-plugin/package.json +19 -0
- package/examples/work-item-plugin/src/index.test.ts +168 -0
- package/examples/work-item-plugin/src/index.ts +122 -0
- package/examples/work-item-plugin/src/observers/npm-test-tracker.test.ts +95 -0
- package/examples/work-item-plugin/src/observers/npm-test-tracker.ts +88 -0
- package/examples/work-item-plugin/src/observers/retest-required-tracker.test.ts +81 -0
- package/examples/work-item-plugin/src/observers/retest-required-tracker.ts +81 -0
- package/examples/work-item-plugin/src/predicates/work-item-format.test.ts +157 -0
- package/examples/work-item-plugin/src/predicates/work-item-format.ts +99 -0
- package/examples/work-item-plugin/src/rules/commit-description-check.test.ts +107 -0
- package/examples/work-item-plugin/src/rules/commit-description-check.ts +83 -0
- package/examples/work-item-plugin/src/rules/commit-requires-work-item.test.ts +79 -0
- package/examples/work-item-plugin/src/rules/commit-requires-work-item.ts +56 -0
- package/examples/work-item-plugin/src/rules/push-requires-tests.test.ts +245 -0
- package/examples/work-item-plugin/src/rules/push-requires-tests.ts +62 -0
- package/examples/work-item-plugin/tsconfig.json +8 -0
- package/package.json +88 -0
- package/skills/steering-authoring/SKILL.md +102 -0
- package/src/INVARIANTS.md +116 -0
- package/src/__test-helpers__.ts +243 -0
- package/src/bin/pi-steering.test.ts +920 -0
- package/src/bin/pi-steering.ts +584 -0
- package/src/compat.test.ts +431 -0
- package/src/compat.ts +282 -0
- package/src/defaults.test.ts +585 -0
- package/src/defaults.ts +148 -0
- package/src/define-config.test.ts +888 -0
- package/src/define-config.ts +375 -0
- package/src/define-predicate.test.ts +70 -0
- package/src/define-predicate.ts +57 -0
- package/src/evaluator-internals/context.ts +290 -0
- package/src/evaluator-internals/override.test.ts +99 -0
- package/src/evaluator-internals/override.ts +83 -0
- package/src/evaluator-internals/predicates.ts +1037 -0
- package/src/evaluator-internals/speculative-synthesis.test.ts +411 -0
- package/src/evaluator-internals/speculative-synthesis.ts +199 -0
- package/src/evaluator.test.ts +6296 -0
- package/src/evaluator.ts +1106 -0
- package/src/factory-time-load.test.ts +630 -0
- package/src/helpers/walker-unknown-cwd-reason.test.ts +73 -0
- package/src/helpers/walker-unknown-cwd-reason.ts +83 -0
- package/src/index.test.ts +836 -0
- package/src/index.ts +229 -0
- package/src/internal/drop-unused-observers.test.ts +141 -0
- package/src/internal/drop-unused-observers.ts +81 -0
- package/src/internal/finalize-plugin-state.ts +43 -0
- package/src/internal/merge-observers.ts +51 -0
- package/src/internal/pattern-utils.test.ts +52 -0
- package/src/internal/pattern-utils.ts +38 -0
- package/src/internal/ref-text.test.ts +54 -0
- package/src/internal/ref-text.ts +17 -0
- package/src/internal/session-runtime.test.ts +629 -0
- package/src/internal/session-runtime.ts +201 -0
- package/src/internal/watch-matcher.test.ts +326 -0
- package/src/internal/watch-matcher.ts +200 -0
- package/src/jsdoc-propagation.test.ts +277 -0
- package/src/loader.test.ts +1098 -0
- package/src/loader.ts +581 -0
- package/src/not-block-onunknown.test.ts +554 -0
- package/src/observer-dispatcher.test.ts +939 -0
- package/src/observer-dispatcher.ts +290 -0
- package/src/per-predicate-typing.test.ts +361 -0
- package/src/plugin-merger.test.ts +790 -0
- package/src/plugin-merger.ts +598 -0
- package/src/plugins/git/README.md +485 -0
- package/src/plugins/git/branch-tracker.test.ts +281 -0
- package/src/plugins/git/branch-tracker.ts +187 -0
- package/src/plugins/git/cwd-extensions.test.ts +230 -0
- package/src/plugins/git/cwd-extensions.ts +160 -0
- package/src/plugins/git/git-ops.test.ts +397 -0
- package/src/plugins/git/git-ops.ts +173 -0
- package/src/plugins/git/index.ts +253 -0
- package/src/plugins/git/integration.test.ts +705 -0
- package/src/plugins/git/predicates.test.ts +1401 -0
- package/src/plugins/git/predicates.ts +693 -0
- package/src/plugins/git/rules.test.ts +1001 -0
- package/src/plugins/git/rules.ts +307 -0
- package/src/schema.test.ts +259 -0
- package/src/schema.ts +1963 -0
- package/src/testing/index.test.ts +1696 -0
- package/src/testing/index.ts +1472 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// Part of pi-steering.
|
|
3
|
+
/**
|
|
4
|
+
* Predicate handlers for the git plugin.
|
|
5
|
+
*
|
|
6
|
+
* Each handler is a `PredicateHandler<A>` where `A` is the
|
|
7
|
+
* plugin-author-facing argument shape the rule passes under the
|
|
8
|
+
* matching `when.<key>` slot. See each handler's JSDoc for the
|
|
9
|
+
* accepted shape and worked examples.
|
|
10
|
+
*
|
|
11
|
+
* Evaluation strategy:
|
|
12
|
+
*
|
|
13
|
+
* - `branch` - read `ctx.walkerState.branch` first (set by
|
|
14
|
+
* the branch tracker on in-chain checkouts).
|
|
15
|
+
* If the tracker resolved statically, use
|
|
16
|
+
* that value. If the tracker reports
|
|
17
|
+
* `"unknown"` (dynamic checkout like
|
|
18
|
+
* `git checkout $VAR` that the walker
|
|
19
|
+
* couldn't resolve), apply `onUnknown`
|
|
20
|
+
* policy without falling back to `exec` -
|
|
21
|
+
* a `git branch --show-current` call would
|
|
22
|
+
* return the PRE-checkout branch and
|
|
23
|
+
* silently defeat the walker. If no
|
|
24
|
+
* tracker state exists (no checkout in
|
|
25
|
+
* chain), shell out via `git branch
|
|
26
|
+
* --show-current`.
|
|
27
|
+
* - `upstream` - no tracker today; always shell out via
|
|
28
|
+
* `git rev-parse --abbrev-ref @{upstream}`.
|
|
29
|
+
* Inlines a {@link cwdIsWalkerUnknown} guard
|
|
30
|
+
* so walker-unknown cwd surfaces trinary
|
|
31
|
+
* `"unknown"` instead of shelling against
|
|
32
|
+
* the pi session cwd — the engine's
|
|
33
|
+
* `onUnknown:` policy then projects to a
|
|
34
|
+
* definite verdict (default `"block"` =
|
|
35
|
+
* fail-CLOSED).
|
|
36
|
+
* - `commitsAhead` - shell out via `git rev-list --count`.
|
|
37
|
+
* Inlines the same walker-unknown guard as
|
|
38
|
+
* `upstream`.
|
|
39
|
+
* - `hasStagedChanges` - shell out via `git diff --cached --quiet`.
|
|
40
|
+
* - `isClean` - shell out via `git status --porcelain`.
|
|
41
|
+
* - `remote` - shell out via `git config --get
|
|
42
|
+
* remote.origin.url`.
|
|
43
|
+
*
|
|
44
|
+
* `ctx.exec` is memoized per `(cmd, args, cwd)` within one tool_call
|
|
45
|
+
* (see the evaluator's `createExecCache`) so multiple rules reading
|
|
46
|
+
* the same git state don't re-fork git.
|
|
47
|
+
*
|
|
48
|
+
* `onUnknown` policy for string-valued predicates (`branch`,
|
|
49
|
+
* `upstream`, `remote`): fail-closed by default. When the underlying
|
|
50
|
+
* query fails (not a repo, no upstream configured, ...), the predicate
|
|
51
|
+
* reports "match" so the rule fires. Rule authors opt into the
|
|
52
|
+
* "allow-through" behavior explicitly by passing
|
|
53
|
+
* `{ pattern, onUnknown: "allow" }`.
|
|
54
|
+
*/
|
|
55
|
+
import { isPattern } from "../../internal/pattern-utils.js";
|
|
56
|
+
import { NO_CHECKOUT_IN_CHAIN } from "./branch-tracker.js";
|
|
57
|
+
import { getCommitsAhead, getRemoteUrl, getStagedChanges, getUpstream, getWorkingTreeClean, } from "./git-ops.js";
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Walker-unknown cwd guard (inline trinary)
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
/**
|
|
62
|
+
* Inline trinary guard for runtime-cwd predicates: returns `true` when
|
|
63
|
+
* the walker couldn't statically resolve the command's effective cwd
|
|
64
|
+
* (the cwd-tracker `"unknown"` sentinel is on `ctx.walkerState.cwd`),
|
|
65
|
+
* which signals to the caller that the handler should bail with
|
|
66
|
+
* `"unknown"` instead of querying the wrong repo.
|
|
67
|
+
*
|
|
68
|
+
* Each runtime-cwd handler in this module starts with:
|
|
69
|
+
*
|
|
70
|
+
* ```ts
|
|
71
|
+
* if (cwdIsWalkerUnknown(ctx)) return "unknown";
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* Surfacing walker-unknown as trinary `"unknown"` lets the engine
|
|
75
|
+
* apply the leaf-level (or block-level, inside `not:`) `onUnknown:`
|
|
76
|
+
* policy. Default `"block"` is fail-CLOSED (the rule fires); a user
|
|
77
|
+
* with `onUnknown: "allow"` opts into fail-OPEN handling.
|
|
78
|
+
* Self-documenting + composable.
|
|
79
|
+
*/
|
|
80
|
+
function cwdIsWalkerUnknown(ctx) {
|
|
81
|
+
return ctx.walkerState?.cwd === "unknown";
|
|
82
|
+
}
|
|
83
|
+
// ---------------------------------------------------------------------------
|
|
84
|
+
// Shared helpers
|
|
85
|
+
// ---------------------------------------------------------------------------
|
|
86
|
+
/**
|
|
87
|
+
* Normalize the shorthand forms accepted by the pattern-valued
|
|
88
|
+
* predicates (`branch`, `upstream`, `remote`) into a canonical
|
|
89
|
+
* `{ patterns, onUnknown }` shape:
|
|
90
|
+
*
|
|
91
|
+
* - `Pattern` -> `{ patterns: [pattern], onUnknown: "block" }`
|
|
92
|
+
* - `Pattern[]` (non-empty, all-Pattern) -> `{ patterns, onUnknown: "block" }`
|
|
93
|
+
* - `{ pattern: Pattern, onUnknown? }` -> object used as-is,
|
|
94
|
+
* `pattern` re-wrapped
|
|
95
|
+
* into a single-element
|
|
96
|
+
* array; `onUnknown`
|
|
97
|
+
* defaults to `"block"`.
|
|
98
|
+
* - `{ pattern: Pattern[], onUnknown? }` -> array preserved,
|
|
99
|
+
* same `onUnknown`
|
|
100
|
+
* handling.
|
|
101
|
+
*
|
|
102
|
+
* Array semantics are OR-of-matches: the rule fires when the input
|
|
103
|
+
* matches ANY of the listed patterns. Array form requires at least
|
|
104
|
+
* one pattern (empty arrays are invalid).
|
|
105
|
+
*
|
|
106
|
+
* Returning `null` means the author supplied something that isn't a
|
|
107
|
+
* valid value for this predicate (e.g. a bare number, an empty array,
|
|
108
|
+
* or an array containing a non-Pattern value); handlers treat that as
|
|
109
|
+
* a non-match and don't throw - invalid config shouldn't crash the
|
|
110
|
+
* evaluator, but it also shouldn't silently fire.
|
|
111
|
+
*/
|
|
112
|
+
function unwrapPatternArg(value) {
|
|
113
|
+
// Shorthand: single Pattern.
|
|
114
|
+
if (isPattern(value)) {
|
|
115
|
+
return { patterns: [value], onUnknown: "block" };
|
|
116
|
+
}
|
|
117
|
+
// Shorthand: Pattern[] (must be non-empty + all-Pattern).
|
|
118
|
+
if (Array.isArray(value) && value.every(isPattern)) {
|
|
119
|
+
if (value.length === 0)
|
|
120
|
+
return null;
|
|
121
|
+
return { patterns: value, onUnknown: "block" };
|
|
122
|
+
}
|
|
123
|
+
// Object form: { pattern: Pattern | Pattern[]; onUnknown? }.
|
|
124
|
+
if (value !== null &&
|
|
125
|
+
typeof value === "object" &&
|
|
126
|
+
"pattern" in value) {
|
|
127
|
+
const obj = value;
|
|
128
|
+
const onUnknown = obj.onUnknown === "allow" ? "allow" : "block";
|
|
129
|
+
if (isPattern(obj.pattern)) {
|
|
130
|
+
return { patterns: [obj.pattern], onUnknown };
|
|
131
|
+
}
|
|
132
|
+
if (Array.isArray(obj.pattern) && obj.pattern.every(isPattern)) {
|
|
133
|
+
if (obj.pattern.length === 0)
|
|
134
|
+
return null;
|
|
135
|
+
return { patterns: obj.pattern, onUnknown };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
/** Test a Pattern against a concrete string. */
|
|
141
|
+
function matchPattern(pattern, target) {
|
|
142
|
+
if (pattern instanceof RegExp)
|
|
143
|
+
return pattern.test(target);
|
|
144
|
+
return new RegExp(pattern).test(target);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Apply the predicate's `onUnknown` policy to a shell failure or
|
|
148
|
+
* tracker-unknown case. "block" means the predicate reports "match"
|
|
149
|
+
* (rule fires); "allow" means the predicate reports "no match" (rule
|
|
150
|
+
* skips). Fail-closed default.
|
|
151
|
+
*/
|
|
152
|
+
function unknownVerdict(onUnknown) {
|
|
153
|
+
return onUnknown === "block";
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Unwrap the boolean payload from a {@link PredicateShape}<boolean>
|
|
157
|
+
* argument. Accepts the bare form (`true` / `false`) and the
|
|
158
|
+
* spread form (`{ value: true, onUnknown? }` /
|
|
159
|
+
* `{ value: false, onUnknown? }`); the engine's `readLeafOnUnknown`
|
|
160
|
+
* reads any `onUnknown:` sibling and `projectVerdict` applies the
|
|
161
|
+
* policy to the handler's `"unknown"` returns. The handler itself
|
|
162
|
+
* treats `onUnknown:` as an opaque sibling field and only consumes
|
|
163
|
+
* `value:`.
|
|
164
|
+
*
|
|
165
|
+
* Returns `undefined` on malformed input — the caller decides what
|
|
166
|
+
* to do with that (typically `return false`, mirroring the existing
|
|
167
|
+
* pattern-unwrap fail-closed contract).
|
|
168
|
+
*
|
|
169
|
+
* Used by {@link isClean} and {@link hasStagedChanges}; both ship
|
|
170
|
+
* with `PredicateShape<boolean>` in the registry so the bare/spread
|
|
171
|
+
* shape is identical at the type level too.
|
|
172
|
+
*
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
function unwrapBooleanLeafArg(args) {
|
|
176
|
+
if (typeof args === "boolean")
|
|
177
|
+
return args;
|
|
178
|
+
if (args !== null &&
|
|
179
|
+
typeof args === "object" &&
|
|
180
|
+
typeof args.value === "boolean") {
|
|
181
|
+
return args.value;
|
|
182
|
+
}
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Test-internal export of {@link unwrapBooleanLeafArg}. Module-private
|
|
187
|
+
* by intent; the `@internal` JSDoc tag (TypeScript ecosystem-standard)
|
|
188
|
+
* flags "not part of the public surface" and the underscore prefix
|
|
189
|
+
* mirrors the convention so external consumers can grep-discover it
|
|
190
|
+
* too. Direct unit tests pin malformed-input branches that are hard
|
|
191
|
+
* to drive via the engine end-to-end.
|
|
192
|
+
*
|
|
193
|
+
* @internal
|
|
194
|
+
*/
|
|
195
|
+
export const _unwrapBooleanLeafArg = unwrapBooleanLeafArg;
|
|
196
|
+
/**
|
|
197
|
+
* Direct one-shot git exec used only by the `branch` predicate's
|
|
198
|
+
* tracker-missing fallback (the predicate's three-way tracker
|
|
199
|
+
* discrimination stays in predicate-land; see the `branch` JSDoc
|
|
200
|
+
* below AND `./git-ops.ts` file header "Branch caveat" for why
|
|
201
|
+
* `getBranch` is NOT called here).
|
|
202
|
+
* Other predicates delegate to helpers in `./git-ops.ts` and don't
|
|
203
|
+
* need this.
|
|
204
|
+
*
|
|
205
|
+
* Mirrors the failure-collapse contract of `tryGit` in git-ops:
|
|
206
|
+
* non-zero exit, spawn error, or thrown exception → `null`.
|
|
207
|
+
*/
|
|
208
|
+
async function tryExec(ctx, cmd, args, cwd) {
|
|
209
|
+
try {
|
|
210
|
+
const res = await ctx.exec(cmd, [...args], cwd !== undefined ? { cwd } : undefined);
|
|
211
|
+
if (res.exitCode !== 0)
|
|
212
|
+
return null;
|
|
213
|
+
return res.stdout.trim();
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Resolve a string tracker value from `ctx.walkerState[key]` into a
|
|
221
|
+
* three-state discriminated result. See {@link WalkerStringResult}
|
|
222
|
+
* for why callers must not conflate `unknown` with `missing`.
|
|
223
|
+
*
|
|
224
|
+
* `initialSentinel` is the tracker's initial value (distinct from
|
|
225
|
+
* its `unknown` sentinel). When `walkerState[key]` equals this
|
|
226
|
+
* sentinel, the result is `missing` - no modifier fired for this
|
|
227
|
+
* dimension in this ref's scope.
|
|
228
|
+
*/
|
|
229
|
+
export function walkerString(ctx, key, initialSentinel) {
|
|
230
|
+
// Guard against a tracker that reuses `"unknown"` as its initial
|
|
231
|
+
// sentinel. Accepting such a value here would silently collapse the
|
|
232
|
+
// three-way discrimination back into the pre-U1 two-step: the
|
|
233
|
+
// `missing` branch would swallow genuine dynamic-checkout signals
|
|
234
|
+
// and the predicate would exec-fallback onto the PRE-checkout
|
|
235
|
+
// branch — exactly the bug U1 exists to prevent. The JSDoc on
|
|
236
|
+
// WalkerStringResult documents this; the assertion makes the
|
|
237
|
+
// contract un-foot-shootable for new tracker authors.
|
|
238
|
+
if (initialSentinel === "unknown") {
|
|
239
|
+
throw new Error(`[pi-steering/git] walkerString: tracker initialSentinel cannot be ` +
|
|
240
|
+
`"unknown" — it's reserved for the unresolvable-dynamic-value ` +
|
|
241
|
+
`signal. Use a distinct initial value (e.g. "" or a sentinel ` +
|
|
242
|
+
`like NO_CHECKOUT_IN_CHAIN). See WalkerStringResult JSDoc.`);
|
|
243
|
+
}
|
|
244
|
+
const v = ctx.walkerState?.[key];
|
|
245
|
+
if (typeof v !== "string")
|
|
246
|
+
return { kind: "missing" };
|
|
247
|
+
if (v === initialSentinel)
|
|
248
|
+
return { kind: "missing" };
|
|
249
|
+
if (v === "unknown")
|
|
250
|
+
return { kind: "unknown" };
|
|
251
|
+
return { kind: "value", value: v };
|
|
252
|
+
}
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
// branch
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
/**
|
|
257
|
+
* `when.branch` - match the current git branch.
|
|
258
|
+
*
|
|
259
|
+
* Accepted arg shapes:
|
|
260
|
+
*
|
|
261
|
+
* ```ts
|
|
262
|
+
* when: { branch: /^main$/ } // single Pattern
|
|
263
|
+
* when: { branch: "^feat-" } // single Pattern (string)
|
|
264
|
+
* when: { branch: [/^main$/, /^master$/, /^trunk$/] } // Pattern[] (any-of)
|
|
265
|
+
* when: { branch: { pattern: /^main$/, onUnknown: "allow" } } // object form
|
|
266
|
+
* when: { branch: { pattern: [/^main$/, /^master$/], onUnknown: "allow" } }
|
|
267
|
+
* ```
|
|
268
|
+
*
|
|
269
|
+
* Array semantics: OR-of-matches (rule fires when the resolved
|
|
270
|
+
* branch matches ANY of the listed patterns). Empty arrays are
|
|
271
|
+
* invalid (rule skips); arrays containing non-Pattern values are
|
|
272
|
+
* invalid (rule skips).
|
|
273
|
+
*
|
|
274
|
+
* Resolution order:
|
|
275
|
+
* 1. `ctx.walkerState.branch` - set by the branch tracker when the
|
|
276
|
+
* current bash chain contains `git checkout` / `git switch`.
|
|
277
|
+
* Three outcomes:
|
|
278
|
+
* - value resolved statically (e.g. `git checkout main`) ->
|
|
279
|
+
* match the pattern against it.
|
|
280
|
+
* - `"unknown"` sentinel (dynamic checkout like `git checkout
|
|
281
|
+
* $VAR`) -> apply `onUnknown` policy. Do NOT fall through
|
|
282
|
+
* to exec: a `git branch --show-current` call here would
|
|
283
|
+
* return the PRE-checkout branch (the walker exists to
|
|
284
|
+
* track exactly this kind of in-chain change statically).
|
|
285
|
+
* - missing (no checkout in chain) -> fall through to exec.
|
|
286
|
+
* 2. `git branch --show-current` in `ctx.cwd`. Empty stdout is
|
|
287
|
+
* treated as "no branch" (detached HEAD) - the predicate falls
|
|
288
|
+
* back to `onUnknown`.
|
|
289
|
+
*
|
|
290
|
+
* `onUnknown` default is `"block"` (fail-closed): if we can't
|
|
291
|
+
* determine the branch, the predicate reports "match" so
|
|
292
|
+
* branch-gated rules still fire.
|
|
293
|
+
*/
|
|
294
|
+
export const branch = async (value, ctx) => {
|
|
295
|
+
const arg = unwrapPatternArg(value);
|
|
296
|
+
if (arg === null)
|
|
297
|
+
return false;
|
|
298
|
+
// 1. Walker state (tracker-resolved mid-command).
|
|
299
|
+
const fromWalker = walkerString(ctx, "branch", NO_CHECKOUT_IN_CHAIN);
|
|
300
|
+
if (fromWalker.kind === "value") {
|
|
301
|
+
return arg.patterns.some((p) => matchPattern(p, fromWalker.value));
|
|
302
|
+
}
|
|
303
|
+
if (fromWalker.kind === "unknown") {
|
|
304
|
+
// Dynamic in-chain checkout. Exec would return the PRE-checkout
|
|
305
|
+
// branch, which is the case the walker exists to catch. Apply
|
|
306
|
+
// the predicate's `onUnknown` policy instead of falling through.
|
|
307
|
+
return unknownVerdict(arg.onUnknown);
|
|
308
|
+
}
|
|
309
|
+
// 2. Shell out (tracker saw no in-chain checkout).
|
|
310
|
+
const out = await tryExec(ctx, "git", ["branch", "--show-current"], ctx.cwd);
|
|
311
|
+
if (out === null || out.length === 0)
|
|
312
|
+
return unknownVerdict(arg.onUnknown);
|
|
313
|
+
return arg.patterns.some((p) => matchPattern(p, out));
|
|
314
|
+
};
|
|
315
|
+
// ---------------------------------------------------------------------------
|
|
316
|
+
// upstream
|
|
317
|
+
// ---------------------------------------------------------------------------
|
|
318
|
+
/**
|
|
319
|
+
* `when.upstream` - match the current branch's configured upstream.
|
|
320
|
+
*
|
|
321
|
+
* Accepted arg shapes: same as {@link branch}.
|
|
322
|
+
*
|
|
323
|
+
* Resolves via `git rev-parse --abbrev-ref @{upstream}`. A branch
|
|
324
|
+
* without an upstream set returns a non-zero exit; the predicate then
|
|
325
|
+
* applies `onUnknown`.
|
|
326
|
+
*
|
|
327
|
+
* No tracker today - upstream configuration isn't changed by in-chain
|
|
328
|
+
* git commands at a rate that justifies modelling it (and `git push
|
|
329
|
+
* -u origin main` changes it but only AFTER the push succeeds, which
|
|
330
|
+
* is past the point where a pre-execution guard would act). The
|
|
331
|
+
* per-tool_call exec cache ensures multiple upstream-gated rules share
|
|
332
|
+
* one git call.
|
|
333
|
+
*
|
|
334
|
+
* Runtime-cwd guard: `getUpstream` shells out at `ctx.cwd`. When the
|
|
335
|
+
* walker surfaces `ctx.walkerState.cwd === "unknown"` (dynamic
|
|
336
|
+
* `cd "$VAR/pkg"` the walker couldn't resolve), the exec would run
|
|
337
|
+
* against the pi session cwd — the wrong repo — and a user who opted
|
|
338
|
+
* into `onUnknown: "allow"` would get a silent fail-OPEN. The handler
|
|
339
|
+
* inlines a {@link cwdIsWalkerUnknown} check at the top and surfaces
|
|
340
|
+
* trinary `"unknown"`; the engine's leaf-level (outer) or block-level
|
|
341
|
+
* (inside `not:`) `onUnknown:` policy then projects to the right
|
|
342
|
+
* boolean (default `"block"` = fail-CLOSED).
|
|
343
|
+
*
|
|
344
|
+
* @see walkerUnknownCwdReason — compose the agent-facing reason text
|
|
345
|
+
* for the walker-unknown-cwd fail-closed branch in your rule's
|
|
346
|
+
* ReasonFn.
|
|
347
|
+
*/
|
|
348
|
+
export const upstream = async (value, ctx) => {
|
|
349
|
+
if (cwdIsWalkerUnknown(ctx))
|
|
350
|
+
return "unknown";
|
|
351
|
+
const arg = unwrapPatternArg(value);
|
|
352
|
+
if (arg === null)
|
|
353
|
+
return false;
|
|
354
|
+
const out = await getUpstream(ctx);
|
|
355
|
+
if (out === null)
|
|
356
|
+
return unknownVerdict(arg.onUnknown);
|
|
357
|
+
return arg.patterns.some((p) => matchPattern(p, out));
|
|
358
|
+
};
|
|
359
|
+
/**
|
|
360
|
+
* `when.commitsAhead` - match when commits-ahead-of-WRT satisfy every
|
|
361
|
+
* supplied comparator.
|
|
362
|
+
*
|
|
363
|
+
* Returns `false` (rule doesn't fire) when:
|
|
364
|
+
* - the arg shape isn't an object with at least one of `eq` / `gt`
|
|
365
|
+
* / `lt`,
|
|
366
|
+
* - the `git rev-list` call fails,
|
|
367
|
+
* - the comparator chain doesn't match.
|
|
368
|
+
*
|
|
369
|
+
* No `onUnknown` here: commits-ahead is a numeric comparator, not a
|
|
370
|
+
* pattern match, and "I couldn't learn the answer" arguably shouldn't
|
|
371
|
+
* fire a rule that's gated on a specific count. Authors who want the
|
|
372
|
+
* fail-closed behavior can layer `{ upstream: "..." }` first in the
|
|
373
|
+
* same `when` (AND semantics via the ADR's plugin predicates) - that
|
|
374
|
+
* handles the "no upstream" case with explicit `onUnknown`.
|
|
375
|
+
*
|
|
376
|
+
* Runtime-cwd guard: `getCommitsAhead` shells out at `ctx.cwd`. When
|
|
377
|
+
* the walker surfaces `ctx.walkerState.cwd === "unknown"`, the exec
|
|
378
|
+
* would run against the pi session cwd — wrong repo — and the
|
|
379
|
+
* `count === null` failure path returns `false`, silently skipping
|
|
380
|
+
* the rule (fail-OPEN). The handler inlines a
|
|
381
|
+
* {@link cwdIsWalkerUnknown} check at the top and surfaces trinary
|
|
382
|
+
* `"unknown"`; the engine's `onUnknown:` policy then projects to the
|
|
383
|
+
* right boolean (default `"block"` = fail-CLOSED, matching the policy
|
|
384
|
+
* used by the other runtime-cwd predicates in this plugin).
|
|
385
|
+
*
|
|
386
|
+
* @see walkerUnknownCwdReason — compose the agent-facing reason text
|
|
387
|
+
* for the walker-unknown-cwd fail-closed branch in your rule's
|
|
388
|
+
* ReasonFn.
|
|
389
|
+
* @see PiSteeringPredicates.commitsAhead — the registry entry that
|
|
390
|
+
* declares the bare / spreadBase shape this handler dispatches
|
|
391
|
+
* on.
|
|
392
|
+
*/
|
|
393
|
+
export const commitsAhead = async (args, ctx) => {
|
|
394
|
+
if (cwdIsWalkerUnknown(ctx))
|
|
395
|
+
return "unknown";
|
|
396
|
+
// Schema advertises `PredicateShape<number, { eq?, gt?, lt?, wrt? }>`
|
|
397
|
+
// — bare-number `commitsAhead: N` is sugar for `{ eq: N }`.
|
|
398
|
+
let eq;
|
|
399
|
+
let gt;
|
|
400
|
+
let lt;
|
|
401
|
+
let wrt = "@{upstream}";
|
|
402
|
+
if (typeof args === "number") {
|
|
403
|
+
eq = args;
|
|
404
|
+
}
|
|
405
|
+
else if (args !== null && typeof args === "object") {
|
|
406
|
+
const shape = args;
|
|
407
|
+
eq = shape.eq;
|
|
408
|
+
gt = shape.gt;
|
|
409
|
+
lt = shape.lt;
|
|
410
|
+
wrt = shape.wrt ?? "@{upstream}";
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
return false;
|
|
414
|
+
}
|
|
415
|
+
if (eq === undefined && gt === undefined && lt === undefined) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const count = await getCommitsAhead(ctx, wrt);
|
|
419
|
+
if (count === null)
|
|
420
|
+
return false;
|
|
421
|
+
if (eq !== undefined && count !== eq)
|
|
422
|
+
return false;
|
|
423
|
+
if (gt !== undefined && !(count > gt))
|
|
424
|
+
return false;
|
|
425
|
+
if (lt !== undefined && !(count < lt))
|
|
426
|
+
return false;
|
|
427
|
+
return true;
|
|
428
|
+
};
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
// hasStagedChanges
|
|
431
|
+
// ---------------------------------------------------------------------------
|
|
432
|
+
/**
|
|
433
|
+
* `when.hasStagedChanges` - match on the presence / absence of staged
|
|
434
|
+
* changes in the repo at `ctx.cwd`.
|
|
435
|
+
*
|
|
436
|
+
* - `when: { hasStagedChanges: true }` - fires when there ARE staged
|
|
437
|
+
* changes.
|
|
438
|
+
* - `when: { hasStagedChanges: false }` - fires when there are NOT.
|
|
439
|
+
*
|
|
440
|
+
* Uses `git diff --cached --quiet`: exit 0 = no staged changes, exit
|
|
441
|
+
* 1 = staged changes exist. On any other exit / spawn failure, we
|
|
442
|
+
* conservatively report `false` - the caller can AND this with an
|
|
443
|
+
* `upstream` check if fail-closed behavior is needed.
|
|
444
|
+
*
|
|
445
|
+
* Runtime-cwd guard: the underlying `git diff --cached` call runs
|
|
446
|
+
* at `ctx.cwd`. When the walker surfaces `ctx.walkerState.cwd ===
|
|
447
|
+
* "unknown"` (dynamic `cd "$VAR/pkg"` the walker couldn't resolve),
|
|
448
|
+
* `ctx.cwd` falls back to the pre-cd ambient cwd — the PI session
|
|
449
|
+
* cwd, not the intended subpackage. The handler inlines a
|
|
450
|
+
* {@link cwdIsWalkerUnknown} check at the top and surfaces trinary
|
|
451
|
+
* `"unknown"`; the engine's `onUnknown:` policy then projects to the
|
|
452
|
+
* right boolean (default `"block"` = fail-CLOSED).
|
|
453
|
+
*
|
|
454
|
+
* @see walkerUnknownCwdReason — compose the agent-facing reason text
|
|
455
|
+
* for the walker-unknown-cwd fail-closed branch in your rule's
|
|
456
|
+
* ReasonFn.
|
|
457
|
+
* @see PiSteeringPredicates.hasStagedChanges — the registry entry
|
|
458
|
+
* that declares the bare / spreadBase shape this handler
|
|
459
|
+
* dispatches on.
|
|
460
|
+
*/
|
|
461
|
+
export const hasStagedChanges = async (args, ctx) => {
|
|
462
|
+
if (cwdIsWalkerUnknown(ctx))
|
|
463
|
+
return "unknown";
|
|
464
|
+
// Schema's `PredicateShape<boolean>` auto-detects spreadBase to
|
|
465
|
+
// `{ value: boolean; onUnknown? }`; unwrap consumes `value:` only.
|
|
466
|
+
// Authors attach modifiers via `{ value: true, onUnknown: "allow" }`;
|
|
467
|
+
// the engine reads any `onUnknown:` sibling via readLeafOnUnknown
|
|
468
|
+
// and projects the handler's `"unknown"` returns under that policy
|
|
469
|
+
// (the handler itself treats `onUnknown:` as an opaque sibling field).
|
|
470
|
+
const expected = unwrapBooleanLeafArg(args);
|
|
471
|
+
if (expected === undefined)
|
|
472
|
+
return false;
|
|
473
|
+
const state = await getStagedChanges(ctx);
|
|
474
|
+
if (state === null)
|
|
475
|
+
return false; // unknown — don't fire
|
|
476
|
+
return expected === state;
|
|
477
|
+
};
|
|
478
|
+
// ---------------------------------------------------------------------------
|
|
479
|
+
// isClean
|
|
480
|
+
// ---------------------------------------------------------------------------
|
|
481
|
+
/**
|
|
482
|
+
* `when.isClean` - match on the working tree's cleanliness at
|
|
483
|
+
* `ctx.cwd`.
|
|
484
|
+
*
|
|
485
|
+
* - `when: { isClean: true }` - fires when the working tree is
|
|
486
|
+
* clean (no unstaged, no untracked, no staged changes).
|
|
487
|
+
* - `when: { isClean: false }` - fires when the working tree is
|
|
488
|
+
* dirty.
|
|
489
|
+
*
|
|
490
|
+
* Uses `git status --porcelain`: empty stdout = clean. Non-zero exit
|
|
491
|
+
* returns `false` (unknown); pair with an `upstream` check for
|
|
492
|
+
* fail-closed behavior.
|
|
493
|
+
*
|
|
494
|
+
* Runtime-cwd guard: same rationale as {@link hasStagedChanges} — the
|
|
495
|
+
* handler inlines a {@link cwdIsWalkerUnknown} check at the top and
|
|
496
|
+
* surfaces trinary `"unknown"` when the walker couldn't statically
|
|
497
|
+
* resolve the command's effective cwd, rather than silently running
|
|
498
|
+
* `git status` at the pi session cwd.
|
|
499
|
+
*
|
|
500
|
+
* @see walkerUnknownCwdReason — compose the agent-facing reason text
|
|
501
|
+
* for the walker-unknown-cwd fail-closed branch in your rule's
|
|
502
|
+
* ReasonFn.
|
|
503
|
+
* @see PiSteeringPredicates.isClean — the registry entry that
|
|
504
|
+
* declares the bare / spreadBase shape this handler dispatches
|
|
505
|
+
* on.
|
|
506
|
+
*/
|
|
507
|
+
export const isClean = async (args, ctx) => {
|
|
508
|
+
if (cwdIsWalkerUnknown(ctx))
|
|
509
|
+
return "unknown";
|
|
510
|
+
// Schema's `PredicateShape<boolean>` auto-detects spreadBase to
|
|
511
|
+
// `{ value: boolean; onUnknown? }`; unwrap consumes `value:` only.
|
|
512
|
+
// Authors attach modifiers via `{ value: true, onUnknown: "allow" }`;
|
|
513
|
+
// the engine reads any `onUnknown:` sibling via readLeafOnUnknown
|
|
514
|
+
// and projects the handler's `"unknown"` returns under that policy
|
|
515
|
+
// (the handler itself treats `onUnknown:` as an opaque sibling field).
|
|
516
|
+
const expected = unwrapBooleanLeafArg(args);
|
|
517
|
+
if (expected === undefined)
|
|
518
|
+
return false;
|
|
519
|
+
const clean = await getWorkingTreeClean(ctx);
|
|
520
|
+
if (clean === null)
|
|
521
|
+
return false;
|
|
522
|
+
return expected === clean;
|
|
523
|
+
};
|
|
524
|
+
// ---------------------------------------------------------------------------
|
|
525
|
+
// remote
|
|
526
|
+
// ---------------------------------------------------------------------------
|
|
527
|
+
/**
|
|
528
|
+
* `when.remote` - match the repo's `origin` remote URL.
|
|
529
|
+
*
|
|
530
|
+
* Accepted arg shapes: same as {@link branch}. Useful for rules that
|
|
531
|
+
* should only fire in specific repos ("never force-push to
|
|
532
|
+
* github.com/org/prod").
|
|
533
|
+
*
|
|
534
|
+
* Resolves via `git config --get remote.origin.url`. Non-zero exit
|
|
535
|
+
* (no origin configured) falls back to `onUnknown`.
|
|
536
|
+
*
|
|
537
|
+
* Runtime-cwd guard: the handler inlines a {@link cwdIsWalkerUnknown}
|
|
538
|
+
* check at the top and surfaces trinary `"unknown"` when the walker
|
|
539
|
+
* couldn't statically resolve the command's effective cwd — querying
|
|
540
|
+
* the wrong repo's remote would silently mis-route a repo-gated rule.
|
|
541
|
+
* Same rationale as {@link hasStagedChanges}.
|
|
542
|
+
*
|
|
543
|
+
* @see walkerUnknownCwdReason — compose the agent-facing reason text
|
|
544
|
+
* for the walker-unknown-cwd fail-closed branch in your rule's
|
|
545
|
+
* ReasonFn.
|
|
546
|
+
*/
|
|
547
|
+
export const remote = async (value, ctx) => {
|
|
548
|
+
if (cwdIsWalkerUnknown(ctx))
|
|
549
|
+
return "unknown";
|
|
550
|
+
const arg = unwrapPatternArg(value);
|
|
551
|
+
if (arg === null)
|
|
552
|
+
return false;
|
|
553
|
+
const out = await getRemoteUrl(ctx);
|
|
554
|
+
if (out === null)
|
|
555
|
+
return unknownVerdict(arg.onUnknown);
|
|
556
|
+
return arg.patterns.some((p) => matchPattern(p, out));
|
|
557
|
+
};
|
|
558
|
+
// ---------------------------------------------------------------------------
|
|
559
|
+
// Plugin-level export
|
|
560
|
+
// ---------------------------------------------------------------------------
|
|
561
|
+
/**
|
|
562
|
+
* Bundle of predicate handlers the git plugin registers under
|
|
563
|
+
* `Plugin.predicates`. Keys become the `when.<key>` slots rule authors
|
|
564
|
+
* see.
|
|
565
|
+
*
|
|
566
|
+
* Typed as `Record<string, AnyPredicateHandler>` to match
|
|
567
|
+
* {@link Plugin.predicates} at the registry boundary — each handler's
|
|
568
|
+
* concrete argument shape is preserved in its individual declaration
|
|
569
|
+
* above, and consumers can import `commitsAhead`, `isClean`, etc.
|
|
570
|
+
* directly when they want the narrow type.
|
|
571
|
+
*/
|
|
572
|
+
export const predicates = {
|
|
573
|
+
branch,
|
|
574
|
+
upstream,
|
|
575
|
+
commitsAhead,
|
|
576
|
+
hasStagedChanges,
|
|
577
|
+
isClean,
|
|
578
|
+
remote,
|
|
579
|
+
};
|
|
580
|
+
//# sourceMappingURL=predicates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"predicates.js","sourceRoot":"","sources":["../../../src/plugins/git/predicates.ts"],"names":[],"mappings":"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"}
|