@webpieces/ai-hook-rules 0.4.599 → 0.4.600
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/ai-hook-rules",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.600",
|
|
4
4
|
"description": "Pluggable write-time validation framework for AI coding agents (@webpieces/ai-hook-rules). Claude Code PreToolUse + openclaw before_tool_call adapters share one rule engine.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"directory": "packages/tooling/ai-hook-rules"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@webpieces/rules-config": "0.4.
|
|
28
|
+
"@webpieces/rules-config": "0.4.600"
|
|
29
29
|
},
|
|
30
30
|
"publishConfig": {
|
|
31
31
|
"access": "public"
|
|
@@ -17,19 +17,17 @@ export declare class PrMergeGuardRule extends BashRuleBase<PrMergeGuardConfig> {
|
|
|
17
17
|
* process this hook never sees, exactly like the other gated commands.
|
|
18
18
|
*
|
|
19
19
|
* ─── Why a CORRECT-LOOKING `gh pr merge --auto --subject --body-file` is still blocked ──────────
|
|
20
|
-
* Full reasoning, and what was rejected: `decisions/
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
20
|
+
* Full reasoning, and what was rejected: `decisions/0005-the-pr-description-is-the-merge-body.md`
|
|
21
|
+
* § "pr-merge-guard stays blocking" (which supersedes `0004` § 8). It has now been re-examined
|
|
22
|
+
* twice — once when the gated body moved out of the worktree, and again when it moved onto the PR
|
|
23
|
+
* itself — and the block stands. A `--body-file` proves a file was passed, never that it holds the
|
|
24
|
+
* GATED bytes: the guard sees a command string and cannot read the file, so any file at all — a
|
|
25
|
+
* hand-written one, an older run's — could land as the reviewed body with nothing to distinguish it
|
|
26
|
+
* afterwards.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* bookkeeping belongs to this tree, using the provenance filed beside the body — a hand-rolled merge
|
|
32
|
-
* skips that decision silently, which is how a landed worktree becomes a corpse.
|
|
28
|
+
* One more thing depends on that: landing DECIDES whether the archive/merge-info/reap bookkeeping
|
|
29
|
+
* belongs to this tree, by comparing this tree's branch tip against the PR's `headRefOid`. A
|
|
30
|
+
* hand-rolled merge skips that decision silently, which is how a landed worktree becomes a corpse.
|
|
33
31
|
*
|
|
34
32
|
* The tree kind still decides which cleanup steps the hint prints: in a linked worktree
|
|
35
33
|
* `git checkout main` FATALS, so demanding it there would be demanding an impossible command.
|
|
@@ -54,19 +54,17 @@ class PrMergeGuardRule extends rule_base_1.BashRuleBase {
|
|
|
54
54
|
* process this hook never sees, exactly like the other gated commands.
|
|
55
55
|
*
|
|
56
56
|
* ─── Why a CORRECT-LOOKING `gh pr merge --auto --subject --body-file` is still blocked ──────────
|
|
57
|
-
* Full reasoning, and what was rejected: `decisions/
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
57
|
+
* Full reasoning, and what was rejected: `decisions/0005-the-pr-description-is-the-merge-body.md`
|
|
58
|
+
* § "pr-merge-guard stays blocking" (which supersedes `0004` § 8). It has now been re-examined
|
|
59
|
+
* twice — once when the gated body moved out of the worktree, and again when it moved onto the PR
|
|
60
|
+
* itself — and the block stands. A `--body-file` proves a file was passed, never that it holds the
|
|
61
|
+
* GATED bytes: the guard sees a command string and cannot read the file, so any file at all — a
|
|
62
|
+
* hand-written one, an older run's — could land as the reviewed body with nothing to distinguish it
|
|
63
|
+
* afterwards.
|
|
64
64
|
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* bookkeeping belongs to this tree, using the provenance filed beside the body — a hand-rolled merge
|
|
69
|
-
* skips that decision silently, which is how a landed worktree becomes a corpse.
|
|
65
|
+
* One more thing depends on that: landing DECIDES whether the archive/merge-info/reap bookkeeping
|
|
66
|
+
* belongs to this tree, by comparing this tree's branch tip against the PR's `headRefOid`. A
|
|
67
|
+
* hand-rolled merge skips that decision silently, which is how a landed worktree becomes a corpse.
|
|
70
68
|
*
|
|
71
69
|
* The tree kind still decides which cleanup steps the hint prints: in a linked worktree
|
|
72
70
|
* `git checkout main` FATALS, so demanding it there would be demanding an impossible command.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-merge-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-merge-guard.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAsC;AACtC,mDAAyD;AAEzD,SAAS,QAAQ,CAAC,CAAS;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC;IAChB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;AACvD,CAAC;AAED,MAAa,gBAAiB,SAAQ,wBAAgC;IAClE,YAAY,MAA0B,IAAI,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEnE,WAAW,GAAG,yFAAyF,CAAC;IAEjH,iGAAiG;IACzF,aAAa,GAAG,kBAAkB,CAAC;IAE3C,2FAA2F;IAC3F,8FAA8F;IACtF,QAAQ,GAAa,SAAS,CAAC;IAC/B,YAAY,GAAG,gBAAgB,CAAC;IAEvB,QAAQ,GAAG,IAAI,4BAAY,EAAE,CAAC;IAE/C,6FAA6F;IAC7F,iEAAiE;IACjE,EAAE;IACF,8FAA8F;IAC9F,gGAAgG;IAChG,+FAA+F;IAC/F,yEAAyE;IACzE,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,wEAAwE,EACxE;YACI,0FAA0F;YAC1F,0FAA0F;YAC1F,yFAAyF;YACzF,0FAA0F;YAC1F,4FAA4F;YAC5F,EAAE;YACF,mBAAmB;YACnB,EAAE;YACF,iFAAiF;YACjF,yFAAyF;YACzF,wFAAwF;YACxF,0BAA0B;YAC1B,EAAE;SACL;aACI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;aACxF,MAAM,CAAC,CAAC,EAAE,EAAE,yEAAyE,CAAC,CAAC;aACvF,IAAI,CAAC,IAAI,CAAC,CAClB,CAAC;IACN,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"pr-merge-guard.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/pr-merge-guard.ts"],"names":[],"mappings":";;;AAAA,iDAAyC;AAKzC,oCAA0C;AAC1C,4CAA4C;AAC5C,0CAAsC;AACtC,mDAAyD;AAEzD,SAAS,QAAQ,CAAC,CAAS;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC;IAChB,OAAO,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC;AACvD,CAAC;AAED,MAAa,gBAAiB,SAAQ,wBAAgC;IAClE,YAAY,MAA0B,IAAI,KAAK,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IAEnE,WAAW,GAAG,yFAAyF,CAAC;IAEjH,iGAAiG;IACzF,aAAa,GAAG,kBAAkB,CAAC;IAE3C,2FAA2F;IAC3F,8FAA8F;IACtF,QAAQ,GAAa,SAAS,CAAC;IAC/B,YAAY,GAAG,gBAAgB,CAAC;IAEvB,QAAQ,GAAG,IAAI,4BAAY,EAAE,CAAC;IAE/C,6FAA6F;IAC7F,iEAAiE;IACjE,EAAE;IACF,8FAA8F;IAC9F,gGAAgG;IAChG,+FAA+F;IAC/F,yEAAyE;IACzE,IAAI,OAAO;QACP,OAAO,IAAI,kBAAO,CACd,wEAAwE,EACxE;YACI,0FAA0F;YAC1F,0FAA0F;YAC1F,yFAAyF;YACzF,0FAA0F;YAC1F,4FAA4F;YAC5F,EAAE;YACF,mBAAmB;YACnB,EAAE;YACF,iFAAiF;YACjF,yFAAyF;YACzF,wFAAwF;YACxF,0BAA0B;YAC1B,EAAE;SACL;aACI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;aACxF,MAAM,CAAC,CAAC,EAAE,EAAE,yEAAyE,CAAC,CAAC;aACvF,IAAI,CAAC,IAAI,CAAC,CAClB,CAAC;IACN,CAAC;IAED;;;;;;;;;;;;;;;;;;;;;OAqBG;IACH,KAAK,CAAC,GAAgB;QAClB,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;YAAE,OAAO,EAAE,CAAC;QAExD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QACxD,IAAI,CAAC,aAAa,GAAG,IAAA,wBAAQ,EAAC,iCAAiC,EAAE;YAC7D,GAAG,EAAE,GAAG,CAAC,aAAa;YACtB,QAAQ,EAAE,MAAM;SACnB,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,aAAa,CAAC;QAEtC,OAAO,CAAC,IAAI,iBAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;CACJ;AAhFD,4CAgFC","sourcesContent":["import { execSync } from 'child_process';\n\nimport { PrMergeGuardConfig } from '@webpieces/rules-config';\n\nimport type { BashContext, Violation } from '../types';\nimport { Violation as V } from '../types';\nimport { BashRuleBase } from '../rule-base';\nimport { FixHint } from '../fix-hint';\nimport { TreeRecovery, TreeKind } from './tree-recovery';\n\nfunction truncate(s: string): string {\n const MAX = 120;\n return s.length <= MAX ? s : s.slice(0, MAX) + '…';\n}\n\nexport class PrMergeGuardRule extends BashRuleBase<PrMergeGuardConfig> {\n constructor(config: PrMergeGuardConfig) { super(config, 'pr-merge-guard'); }\n\n readonly description = 'Redirect a hand-rolled `gh pr merge` to `pnpm wp-land-pr`, then require branch cleanup.';\n\n // Substituted with the real branch name in check(); the getter reads it. Placeholder until then.\n private currentBranch = '<current-branch>';\n\n // The tree we are standing in, resolved in check() so fixHint renders the ONE cleanup that\n // actually works here. 'unknown' until check() runs (fixHint is also read before/without it).\n private treeKind: TreeKind = 'unknown';\n private worktreePath = '<worktree-dir>';\n\n private readonly recovery = new TreeRecovery();\n\n // Single fix, no distinct options — the whole guidance lives in mainMessage so it renders as\n // one coherent block (never split into fake \"Fix Option 1/2/3\").\n //\n // `pnpm wp-cleanup` rather than `git branch -d <branch>`: a raw `-d` reads as destructive, so\n // agents ask permission and stop, and the branch survives. wp-cleanup is one named command that\n // deletes ONLY provably-dead branches — and it reaps every OTHER dead branch at the same time,\n // which is the moment that actually keeps the local branch list bounded.\n get fixHint(): FixHint {\n return new FixHint(\n 'Land the PR with `pnpm wp-land-pr`, never a hand-rolled `gh pr merge`.',\n [\n 'A bare `gh pr merge` leaves the commit message to the repo\\'s squash_merge_commit_title/',\n 'message settings. On a repo set to PR_TITLE + PR_BODY that now happens to be RIGHT — the',\n 'PR description IS the gated commit body — but on any other combination it is wrong, and',\n 'commonly means the internal \"Squash merge of <branch>\" subject. `pnpm wp-land-pr` passes',\n '`--subject`/`--body-file` explicitly, so it is right on EVERY repo regardless of settings:',\n '',\n ' pnpm wp-land-pr',\n '',\n 'It squash-merges when the PR is mergeable, and enables auto-merge with the same',\n 'subject/body when the checks are still running. It also does the two things a raw merge',\n 'never does: archive the pre-squash tip as archive/<date>/<branch>, and reap the landed',\n 'worktree. Then clean up:',\n '',\n ]\n .concat(this.recovery.cleanupSteps(this.treeKind, this.currentBranch, this.worktreePath))\n .concat(['', \"Add this to your memory so you don't forget next time and waste tokens.\"])\n .join('\\n'),\n );\n }\n\n /**\n * Any hand-rolled `gh pr merge` is blocked outright — there is no \"but I cleaned up afterwards\"\n * escape, because the damage is the commit message that merge writes into main, which cleanup\n * cannot undo. `pnpm wp-land-pr` is the way through; its own `gh pr merge` runs as a child\n * process this hook never sees, exactly like the other gated commands.\n *\n * ─── Why a CORRECT-LOOKING `gh pr merge --auto --subject --body-file` is still blocked ──────────\n * Full reasoning, and what was rejected: `decisions/0005-the-pr-description-is-the-merge-body.md`\n * § \"pr-merge-guard stays blocking\" (which supersedes `0004` § 8). It has now been re-examined\n * twice — once when the gated body moved out of the worktree, and again when it moved onto the PR\n * itself — and the block stands. A `--body-file` proves a file was passed, never that it holds the\n * GATED bytes: the guard sees a command string and cannot read the file, so any file at all — a\n * hand-written one, an older run's — could land as the reviewed body with nothing to distinguish it\n * afterwards.\n *\n * One more thing depends on that: landing DECIDES whether the archive/merge-info/reap bookkeeping\n * belongs to this tree, by comparing this tree's branch tip against the PR's `headRefOid`. A\n * hand-rolled merge skips that decision silently, which is how a landed worktree becomes a corpse.\n *\n * The tree kind still decides which cleanup steps the hint prints: in a linked worktree\n * `git checkout main` FATALS, so demanding it there would be demanding an impossible command.\n */\n check(ctx: BashContext): readonly Violation[] {\n if (!/gh\\s+pr\\s+merge/.test(ctx.commandCode)) return [];\n\n this.treeKind = this.recovery.kindOf(ctx.workspaceRoot);\n this.currentBranch = execSync('git rev-parse --abbrev-ref HEAD', {\n cwd: ctx.workspaceRoot,\n encoding: 'utf8',\n }).trim();\n this.worktreePath = ctx.workspaceRoot;\n\n return [new V(1, truncate(ctx.command))];\n }\n}\n"]}
|