@webpieces/ai-hook-rules 0.4.842 → 0.4.844

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,13 +1,14 @@
1
1
  {
2
2
  "name": "@webpieces/ai-hook-rules",
3
- "version": "0.4.842",
3
+ "version": "0.4.844",
4
4
  "description": "Independent source edit rules and source hook for AI coding agents.",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
7
7
  "exports": {
8
8
  ".": "./src/index.js",
9
9
  "./package.json": "./package.json",
10
- "./claude-code-rules": "./src/adapters/rules-hook.js"
10
+ "./claude-code-rules": "./src/adapters/rules-hook.js",
11
+ "./rule-pack": "./src/rule-pack.js"
11
12
  },
12
13
  "files": [
13
14
  "src/**/*",
@@ -21,15 +22,19 @@
21
22
  "directory": "packages/tooling/ai-hook-rules"
22
23
  },
23
24
  "dependencies": {
24
- "@webpieces/hook-runtime": "0.4.842",
25
- "@webpieces/rules-config": "0.4.842",
25
+ "@webpieces/hook-runtime": "0.4.844",
26
+ "@webpieces/rules-config": "0.4.844",
26
27
  "inversify": "7.10.4",
27
28
  "reflect-metadata": "0.2.2",
28
- "@webpieces/tooling-common": "0.4.842"
29
+ "@webpieces/tooling-common": "0.4.844",
30
+ "@webpieces/rules-sdk": "0.4.844"
29
31
  },
30
32
  "publishConfig": {
31
33
  "access": "public"
32
34
  },
35
+ "devDependencies": {
36
+ "@webpieces/tooling-testkit": "0.4.844"
37
+ },
33
38
  "types": "./src/index.d.ts",
34
39
  "bin": {
35
40
  "wp-ai-rules-hook": "./src/adapters/rules-hook.js"
@@ -2,10 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GoldenRepoBuilder = exports.GOLDEN_FIXTURES = exports.REPO_TOKEN = exports.PreparedFixture = exports.GoldenFixture = void 0;
4
4
  const tslib_1 = require("tslib");
5
+ const tooling_testkit_1 = require("@webpieces/tooling-testkit");
5
6
  const child_process_1 = require("child_process");
6
7
  const fs = tslib_1.__importStar(require("fs"));
7
8
  const path = tslib_1.__importStar(require("path"));
8
- const rules_config_1 = require("@webpieces/rules-config");
9
9
  /**
10
10
  * THE WIRE BYTES the golden tests drive, and the throwaway repo they are judged against.
11
11
  *
@@ -127,7 +127,7 @@ class GoldenRepoBuilder {
127
127
  this.configJson = fs.readFileSync(path.join(__dirname, '__goldens__', 'fixture-webpieces.config.json'), 'utf8');
128
128
  }
129
129
  build(fixture) {
130
- const root = rules_config_1.specTempDirs.makeReal('wp-hook-golden-');
130
+ const root = tooling_testkit_1.specTempDirs.makeReal('wp-hook-golden-');
131
131
  const repo = path.join(root, 'repo');
132
132
  fs.mkdirSync(repo);
133
133
  this.git(repo, 'init -q -b main');
@@ -1 +1 @@
1
- {"version":3,"file":"hook-app-fixtures.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/adapters/hook-app-fixtures.ts"],"names":[],"mappings":"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","sourcesContent":["import { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\n\nimport { HookMode } from '@webpieces/hook-runtime';\nimport { specTempDirs } from '@webpieces/rules-config';\n\n/**\n * THE WIRE BYTES the golden tests drive, and the throwaway repo they are judged against.\n *\n * Everything here exists so a reader can see EXACTLY what a harness sends: the payloads are built from\n * the measured envelope key sets (see the fixture docs on GoldenFixture below), not from anything the\n * hook itself produces, and the repo is a real `git init` with a frozen webpieces.config.json rather\n * than whatever tree the suite happens to be running in. A golden computed against the live repo would\n * change verdict with the branch you are standing on.\n *\n * This is NOT a spec file, deliberately: `tsconfig.lib.json` excludes `*.spec.ts`, so a payload builder\n * living in one would never be type-checked by the build.\n */\n\n/** How one PreToolUse call is presented to the hook. Data class per CLAUDE.md rule 1. */\nexport class GoldenFixture {\n /** Stable key into `__goldens__/hook-app-goldens.json`. */\n readonly name: string;\n /** Which hook binary's mode — `guards` or `rules`. */\n readonly mode: HookMode;\n /**\n * The raw stdin bytes. A STRING, never an object, because malformed stdin is one of the fixtures\n * and a shape that cannot express \"not JSON\" would quietly drop the case that matters most.\n */\n readonly stdin: string;\n /** True ⇒ the fixture repo also gets a `rulesDir` whose one module throws when required. */\n readonly crashingRulesDir: boolean;\n\n constructor(name: string, mode: HookMode, stdin: string, crashingRulesDir: boolean = false) {\n this.name = name;\n this.mode = mode;\n this.stdin = stdin;\n this.crashingRulesDir = crashingRulesDir;\n }\n}\n\n/** A built fixture repo: where it lives, and the stdin bytes with `<REPO>` resolved into it. */\nexport class PreparedFixture {\n readonly repo: string;\n readonly root: string;\n readonly stdin: string;\n\n constructor(repo: string, root: string, stdin: string) {\n this.repo = repo;\n this.root = root;\n this.stdin = stdin;\n }\n}\n\n/**\n * The placeholder that stands for the fixture repo's absolute path, in BOTH directions: payloads are\n * written with it and it is substituted in before the run; golden bytes are compared with the real\n * path substituted back out. Guard reports legitimately name absolute paths (the git-workflow doc\n * pointer, the blocked file), and a golden that hard-coded one machine's `/var/folders/...` would be\n * a golden nobody else could run.\n */\nexport const REPO_TOKEN = '<REPO>';\n\nconst CLAUDE_ENVELOPE = { hook_event_name: 'PreToolUse', session_id: 'sess-golden', transcript_path: '/dev/null', cwd: REPO_TOKEN };\n\n/**\n * The Codex additions, MEASURED from codex-cli 0.151.0: it uses Claude's key names and merely ADDS\n * `model`, `turn_id`, `tool_use_id` and `permission_mode`. `turn_id` is the one discriminator (see\n * detect-ai.ts). `agent_id` empty ⇒ the coordinator, populated ⇒ a subagent — identical semantics in\n * both harnesses.\n */\nconst CODEX_ENVELOPE = { ...CLAUDE_ENVELOPE, model: 'gpt-5-codex', turn_id: 'turn-golden', tool_use_id: 'call_1', permission_mode: 'default', agent_type: 'default', agent_id: '' };\n\n// Codex's edit tool. MEASURED: the tool is named `apply_patch`, it carries `tool_input.command` (not\n// file_path), hunk headers are a bare `@@`, and ONE patch may carry many files with mixed operations.\nconst PATCH_ADD_JS = '*** Begin Patch\\n*** Add File: src/foo.js\\n+var x = 1;\\n*** End Patch\\n';\nconst PATCH_ADD_TS = '*** Begin Patch\\n*** Add File: scripts/added.ts\\n+export const b = 2;\\n*** End Patch\\n';\n\n/**\n * Serializes ONE PreToolUse envelope to the bytes a harness would put on stdin. A class rather than a\n * module-scope function because that is the repo rule, and the one instance below is built at module\n * load so the fixture table can stay a plain literal list.\n */\nclass WirePayload {\n // webpieces-disable no-any-unknown -- these objects ARE the wire envelope; JSON.stringify of a plain object is the payload under test, and naming a type for it would assert a shape the fixtures exist to state literally\n write(envelope: Record<string, unknown>, toolName: string, toolInput: Record<string, unknown>): string {\n return JSON.stringify({ ...envelope, tool_name: toolName, tool_input: toolInput });\n }\n}\n\nconst WIRE = new WirePayload();\n\n/**\n * ONE fixture per row of the coverage the composed pipeline had none of before: for BOTH harnesses a\n * Bash deny (the ANSI-red systemMessage), a file-tool deny (NO systemMessage), an allow, a read-only\n * tool, malformed stdin, and a fail-closed crash.\n */\nexport const GOLDEN_FIXTURES: readonly GoldenFixture[] = [\n // ── Claude Code ────────────────────────────────────────────────────────────────────────────────\n // A Bash deny. `git merge` is blocked on every branch, so this verdict does not depend on repo\n // state — and a Bash deny is the ONE case that carries the red `systemMessage`.\n // The read-only tool: log-and-allow, and the only guard that can deny it is a stale `main`.\n // Write / Edit / MultiEdit denies — all three must emit NO systemMessage.\n new GoldenFixture('claude/write-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/src/foo.js`, content: 'var x = 1;\\n' })),\n new GoldenFixture('claude/edit-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Edit', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, old_string: 'const a = 1;', new_string: 'const { a } = b;' })),\n new GoldenFixture('claude/multiedit-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'MultiEdit', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, edits: [{ old_string: 'const a = 1;', new_string: 'const { a } = b;' }] })),\n new GoldenFixture('claude/write-allow', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, content: 'export const a = 1;\\n' })),\n new GoldenFixture('claude/crash', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, content: 'export const a = 1;\\n' }), true),\n\n // ── Codex ──────────────────────────────────────────────────────────────────────────────────────\n // Codex has no Read tool: a read arrives as `Bash` running a pager, which read parity turns into a\n // read-scoped verdict ON TOP of the bash guards.\n new GoldenFixture('codex/apply-patch-deny', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_JS })),\n new GoldenFixture('codex/apply-patch-allow', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_TS })),\n new GoldenFixture('codex/crash', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_TS }), true),\n];\n\n// A rules module that blows up the moment it is required — the shortest honest way to reach the hook's\n// fail-closed boundary from OUTSIDE the hook, i.e. without stubbing anything the pipeline owns.\nconst CRASHING_RULE_MODULE = \"throw new Error('boom from a custom rule module');\\n\";\n\n/**\n * Builds ONE throwaway git repo per fixture and returns it with the payload's `<REPO>` resolved.\n *\n * A FRESH repo per fixture, not one shared: the hook writes `.webpieces/` state (the decision log, the\n * main-sync cache) as it runs, so a shared tree would let fixture N's leftovers decide fixture N+1's\n * verdict — an order-dependent suite, which is the one kind of golden test worse than none.\n *\n * `realpathSync` matters on macOS: `os.tmpdir()` hands back `/var/folders/...` which resolves to\n * `/private/var/...`, and the L1 location guard compares the payload's cwd against the resolved repo\n * root. Without it every fixture denies with \"run git from the repo root\" instead of the verdict under\n * test.\n */\nexport class GoldenRepoBuilder {\n private readonly configJson: string;\n\n constructor() {\n this.configJson = fs.readFileSync(path.join(__dirname, '__goldens__', 'fixture-webpieces.config.json'), 'utf8');\n }\n\n build(fixture: GoldenFixture): PreparedFixture {\n const root = specTempDirs.makeReal('wp-hook-golden-');\n const repo = path.join(root, 'repo');\n fs.mkdirSync(repo);\n this.git(repo, 'init -q -b main');\n // The developer's own commit hooks would otherwise fire inside this throwaway repo.\n this.git(repo, 'config core.hooksPath /dev/null');\n this.git(repo, 'config user.email t@t.co');\n this.git(repo, 'config user.name tester');\n fs.writeFileSync(path.join(repo, 'webpieces.config.json'), this.repoConfig(fixture));\n fs.writeFileSync(path.join(repo, 'f.txt'), 'hello\\n');\n fs.mkdirSync(path.join(repo, 'scripts'));\n fs.writeFileSync(path.join(repo, 'scripts', 'ok.ts'), 'const a = 1;\\n');\n if (fixture.crashingRulesDir) {\n fs.mkdirSync(path.join(repo, 'wprules'));\n fs.writeFileSync(path.join(repo, 'wprules', 'crash.js'), CRASHING_RULE_MODULE);\n }\n this.git(repo, 'add -A');\n this.git(repo, 'commit -qm init');\n // A local origin/main, so `origin/main..<branch>` resolves exactly as it does in a real clone.\n this.git(repo, 'update-ref refs/remotes/origin/main HEAD');\n // A feature branch, because that is where an agent actually works.\n this.git(repo, 'checkout -q -b dean/fixture');\n return new PreparedFixture(repo, root, fixture.stdin.split(REPO_TOKEN).join(repo));\n }\n\n private repoConfig(fixture: GoldenFixture): string {\n if (!fixture.crashingRulesDir) return this.configJson;\n // webpieces-disable no-any-unknown -- the frozen fixture config is data on disk; re-parsing it into a named type here would be a second declaration of a file whose whole point is being literal\n const parsed = JSON.parse(this.configJson) as Record<string, unknown>;\n parsed['rulesDir'] = ['wprules'];\n return JSON.stringify(parsed, null, 4);\n }\n\n private git(repo: string, args: string): void {\n execSync(`git ${args}`, { cwd: repo, encoding: 'utf8' });\n }\n}\n"]}
1
+ {"version":3,"file":"hook-app-fixtures.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/adapters/hook-app-fixtures.ts"],"names":[],"mappings":";;;;AAAA,gEAA0D;AAC1D,iDAAyC;AACzC,+CAAyB;AAEzB,mDAA6B;AAK7B;;;;;;;;;;;GAWG;AAEH,yFAAyF;AACzF,MAAa,aAAa;IACtB,2DAA2D;IAClD,IAAI,CAAS;IACtB,sDAAsD;IAC7C,IAAI,CAAW;IACxB;;;OAGG;IACM,KAAK,CAAS;IACvB,4FAA4F;IACnF,gBAAgB,CAAU;IAEnC,YAAY,IAAY,EAAE,IAAc,EAAE,KAAa,EAAE,mBAA4B,KAAK;QACtF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC7C,CAAC;CACJ;AAnBD,sCAmBC;AAED,gGAAgG;AAChG,MAAa,eAAe;IACf,IAAI,CAAS;IACb,IAAI,CAAS;IACb,KAAK,CAAS;IAEvB,YAAY,IAAY,EAAE,IAAY,EAAE,KAAa;QACjD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AAVD,0CAUC;AAED;;;;;;GAMG;AACU,QAAA,UAAU,GAAG,QAAQ,CAAC;AAEnC,MAAM,eAAe,GAAG,EAAE,eAAe,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,WAAW,EAAE,GAAG,EAAE,kBAAU,EAAE,CAAC;AAEpI;;;;;GAKG;AACH,MAAM,cAAc,GAAG,EAAE,GAAG,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEpL,qGAAqG;AACrG,sGAAsG;AACtG,MAAM,YAAY,GAAG,yEAAyE,CAAC;AAC/F,MAAM,YAAY,GAAG,wFAAwF,CAAC;AAE9G;;;;GAIG;AACH,MAAM,WAAW;IACb,2NAA2N;IAC3N,KAAK,CAAC,QAAiC,EAAE,QAAgB,EAAE,SAAkC;QACzF,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;IACvF,CAAC;CACJ;AAED,MAAM,IAAI,GAAG,IAAI,WAAW,EAAE,CAAC;AAE/B;;;;GAIG;AACU,QAAA,eAAe,GAA6B;IACrD,kGAAkG;IAClG,+FAA+F;IAC/F,gFAAgF;IAChF,4FAA4F;IAC5F,0EAA0E;IAC1E,IAAI,aAAa,CAAC,mBAAmB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,kBAAU,aAAa,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC;IACzJ,IAAI,aAAa,CAAC,kBAAkB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,GAAG,kBAAU,gBAAgB,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC7L,IAAI,aAAa,CAAC,uBAAuB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,GAAG,kBAAU,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC,EAAE,CAAC,CAAC;IACpN,IAAI,aAAa,CAAC,oBAAoB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,kBAAU,gBAAgB,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACtK,IAAI,aAAa,CAAC,cAAc,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,GAAG,kBAAU,gBAAgB,EAAE,OAAO,EAAE,uBAAuB,EAAE,CAAC,EAAE,IAAI,CAAC;IAEtK,kGAAkG;IAClG,mGAAmG;IACnG,iDAAiD;IACjD,IAAI,aAAa,CAAC,wBAAwB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAC1H,IAAI,aAAa,CAAC,yBAAyB,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;IAC3H,IAAI,aAAa,CAAC,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,aAAa,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,IAAI,CAAC;CACxH,CAAC;AAEF,uGAAuG;AACvG,gGAAgG;AAChG,MAAM,oBAAoB,GAAG,sDAAsD,CAAC;AAEpF;;;;;;;;;;;GAWG;AACH,MAAa,iBAAiB;IACT,UAAU,CAAS;IAEpC;QACI,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,+BAA+B,CAAC,EAAE,MAAM,CAAC,CAAC;IACpH,CAAC;IAED,KAAK,CAAC,OAAsB;QACxB,MAAM,IAAI,GAAG,8BAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;QACtD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;QAClC,oFAAoF;QACpF,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,iCAAiC,CAAC,CAAC;QAClD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC;QAC3C,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,yBAAyB,CAAC,CAAC;QAC1C,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,uBAAuB,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;QACrF,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,SAAS,CAAC,CAAC;QACtD,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;QACzC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACxE,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC3B,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;YACzC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,oBAAoB,CAAC,CAAC;QACnF,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACzB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;QAClC,+FAA+F;QAC/F,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,0CAA0C,CAAC,CAAC;QAC3D,mEAAmE;QACnE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,6BAA6B,CAAC,CAAC;QAC9C,OAAO,IAAI,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACvF,CAAC;IAEO,UAAU,CAAC,OAAsB;QACrC,IAAI,CAAC,OAAO,CAAC,gBAAgB;YAAE,OAAO,IAAI,CAAC,UAAU,CAAC;QACtD,iMAAiM;QACjM,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAA4B,CAAC;QACtE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3C,CAAC;IAEO,GAAG,CAAC,IAAY,EAAE,IAAY;QAClC,IAAA,wBAAQ,EAAC,OAAO,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;CACJ;AA5CD,8CA4CC","sourcesContent":["import { specTempDirs } from '@webpieces/tooling-testkit';\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as os from 'os';\nimport * as path from 'path';\n\nimport { HookMode } from '@webpieces/hook-runtime';\n\n\n/**\n * THE WIRE BYTES the golden tests drive, and the throwaway repo they are judged against.\n *\n * Everything here exists so a reader can see EXACTLY what a harness sends: the payloads are built from\n * the measured envelope key sets (see the fixture docs on GoldenFixture below), not from anything the\n * hook itself produces, and the repo is a real `git init` with a frozen webpieces.config.json rather\n * than whatever tree the suite happens to be running in. A golden computed against the live repo would\n * change verdict with the branch you are standing on.\n *\n * This is NOT a spec file, deliberately: `tsconfig.lib.json` excludes `*.spec.ts`, so a payload builder\n * living in one would never be type-checked by the build.\n */\n\n/** How one PreToolUse call is presented to the hook. Data class per CLAUDE.md rule 1. */\nexport class GoldenFixture {\n /** Stable key into `__goldens__/hook-app-goldens.json`. */\n readonly name: string;\n /** Which hook binary's mode — `guards` or `rules`. */\n readonly mode: HookMode;\n /**\n * The raw stdin bytes. A STRING, never an object, because malformed stdin is one of the fixtures\n * and a shape that cannot express \"not JSON\" would quietly drop the case that matters most.\n */\n readonly stdin: string;\n /** True ⇒ the fixture repo also gets a `rulesDir` whose one module throws when required. */\n readonly crashingRulesDir: boolean;\n\n constructor(name: string, mode: HookMode, stdin: string, crashingRulesDir: boolean = false) {\n this.name = name;\n this.mode = mode;\n this.stdin = stdin;\n this.crashingRulesDir = crashingRulesDir;\n }\n}\n\n/** A built fixture repo: where it lives, and the stdin bytes with `<REPO>` resolved into it. */\nexport class PreparedFixture {\n readonly repo: string;\n readonly root: string;\n readonly stdin: string;\n\n constructor(repo: string, root: string, stdin: string) {\n this.repo = repo;\n this.root = root;\n this.stdin = stdin;\n }\n}\n\n/**\n * The placeholder that stands for the fixture repo's absolute path, in BOTH directions: payloads are\n * written with it and it is substituted in before the run; golden bytes are compared with the real\n * path substituted back out. Guard reports legitimately name absolute paths (the git-workflow doc\n * pointer, the blocked file), and a golden that hard-coded one machine's `/var/folders/...` would be\n * a golden nobody else could run.\n */\nexport const REPO_TOKEN = '<REPO>';\n\nconst CLAUDE_ENVELOPE = { hook_event_name: 'PreToolUse', session_id: 'sess-golden', transcript_path: '/dev/null', cwd: REPO_TOKEN };\n\n/**\n * The Codex additions, MEASURED from codex-cli 0.151.0: it uses Claude's key names and merely ADDS\n * `model`, `turn_id`, `tool_use_id` and `permission_mode`. `turn_id` is the one discriminator (see\n * detect-ai.ts). `agent_id` empty ⇒ the coordinator, populated ⇒ a subagent — identical semantics in\n * both harnesses.\n */\nconst CODEX_ENVELOPE = { ...CLAUDE_ENVELOPE, model: 'gpt-5-codex', turn_id: 'turn-golden', tool_use_id: 'call_1', permission_mode: 'default', agent_type: 'default', agent_id: '' };\n\n// Codex's edit tool. MEASURED: the tool is named `apply_patch`, it carries `tool_input.command` (not\n// file_path), hunk headers are a bare `@@`, and ONE patch may carry many files with mixed operations.\nconst PATCH_ADD_JS = '*** Begin Patch\\n*** Add File: src/foo.js\\n+var x = 1;\\n*** End Patch\\n';\nconst PATCH_ADD_TS = '*** Begin Patch\\n*** Add File: scripts/added.ts\\n+export const b = 2;\\n*** End Patch\\n';\n\n/**\n * Serializes ONE PreToolUse envelope to the bytes a harness would put on stdin. A class rather than a\n * module-scope function because that is the repo rule, and the one instance below is built at module\n * load so the fixture table can stay a plain literal list.\n */\nclass WirePayload {\n // webpieces-disable no-any-unknown -- these objects ARE the wire envelope; JSON.stringify of a plain object is the payload under test, and naming a type for it would assert a shape the fixtures exist to state literally\n write(envelope: Record<string, unknown>, toolName: string, toolInput: Record<string, unknown>): string {\n return JSON.stringify({ ...envelope, tool_name: toolName, tool_input: toolInput });\n }\n}\n\nconst WIRE = new WirePayload();\n\n/**\n * ONE fixture per row of the coverage the composed pipeline had none of before: for BOTH harnesses a\n * Bash deny (the ANSI-red systemMessage), a file-tool deny (NO systemMessage), an allow, a read-only\n * tool, malformed stdin, and a fail-closed crash.\n */\nexport const GOLDEN_FIXTURES: readonly GoldenFixture[] = [\n // ── Claude Code ────────────────────────────────────────────────────────────────────────────────\n // A Bash deny. `git merge` is blocked on every branch, so this verdict does not depend on repo\n // state — and a Bash deny is the ONE case that carries the red `systemMessage`.\n // The read-only tool: log-and-allow, and the only guard that can deny it is a stale `main`.\n // Write / Edit / MultiEdit denies — all three must emit NO systemMessage.\n new GoldenFixture('claude/write-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/src/foo.js`, content: 'var x = 1;\\n' })),\n new GoldenFixture('claude/edit-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Edit', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, old_string: 'const a = 1;', new_string: 'const { a } = b;' })),\n new GoldenFixture('claude/multiedit-deny', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'MultiEdit', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, edits: [{ old_string: 'const a = 1;', new_string: 'const { a } = b;' }] })),\n new GoldenFixture('claude/write-allow', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, content: 'export const a = 1;\\n' })),\n new GoldenFixture('claude/crash', 'rules', WIRE.write(CLAUDE_ENVELOPE, 'Write', { file_path: `${REPO_TOKEN}/scripts/ok.ts`, content: 'export const a = 1;\\n' }), true),\n\n // ── Codex ──────────────────────────────────────────────────────────────────────────────────────\n // Codex has no Read tool: a read arrives as `Bash` running a pager, which read parity turns into a\n // read-scoped verdict ON TOP of the bash guards.\n new GoldenFixture('codex/apply-patch-deny', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_JS })),\n new GoldenFixture('codex/apply-patch-allow', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_TS })),\n new GoldenFixture('codex/crash', 'rules', WIRE.write(CODEX_ENVELOPE, 'apply_patch', { command: PATCH_ADD_TS }), true),\n];\n\n// A rules module that blows up the moment it is required — the shortest honest way to reach the hook's\n// fail-closed boundary from OUTSIDE the hook, i.e. without stubbing anything the pipeline owns.\nconst CRASHING_RULE_MODULE = \"throw new Error('boom from a custom rule module');\\n\";\n\n/**\n * Builds ONE throwaway git repo per fixture and returns it with the payload's `<REPO>` resolved.\n *\n * A FRESH repo per fixture, not one shared: the hook writes `.webpieces/` state (the decision log, the\n * main-sync cache) as it runs, so a shared tree would let fixture N's leftovers decide fixture N+1's\n * verdict — an order-dependent suite, which is the one kind of golden test worse than none.\n *\n * `realpathSync` matters on macOS: `os.tmpdir()` hands back `/var/folders/...` which resolves to\n * `/private/var/...`, and the L1 location guard compares the payload's cwd against the resolved repo\n * root. Without it every fixture denies with \"run git from the repo root\" instead of the verdict under\n * test.\n */\nexport class GoldenRepoBuilder {\n private readonly configJson: string;\n\n constructor() {\n this.configJson = fs.readFileSync(path.join(__dirname, '__goldens__', 'fixture-webpieces.config.json'), 'utf8');\n }\n\n build(fixture: GoldenFixture): PreparedFixture {\n const root = specTempDirs.makeReal('wp-hook-golden-');\n const repo = path.join(root, 'repo');\n fs.mkdirSync(repo);\n this.git(repo, 'init -q -b main');\n // The developer's own commit hooks would otherwise fire inside this throwaway repo.\n this.git(repo, 'config core.hooksPath /dev/null');\n this.git(repo, 'config user.email t@t.co');\n this.git(repo, 'config user.name tester');\n fs.writeFileSync(path.join(repo, 'webpieces.config.json'), this.repoConfig(fixture));\n fs.writeFileSync(path.join(repo, 'f.txt'), 'hello\\n');\n fs.mkdirSync(path.join(repo, 'scripts'));\n fs.writeFileSync(path.join(repo, 'scripts', 'ok.ts'), 'const a = 1;\\n');\n if (fixture.crashingRulesDir) {\n fs.mkdirSync(path.join(repo, 'wprules'));\n fs.writeFileSync(path.join(repo, 'wprules', 'crash.js'), CRASHING_RULE_MODULE);\n }\n this.git(repo, 'add -A');\n this.git(repo, 'commit -qm init');\n // A local origin/main, so `origin/main..<branch>` resolves exactly as it does in a real clone.\n this.git(repo, 'update-ref refs/remotes/origin/main HEAD');\n // A feature branch, because that is where an agent actually works.\n this.git(repo, 'checkout -q -b dean/fixture');\n return new PreparedFixture(repo, root, fixture.stdin.split(REPO_TOKEN).join(repo));\n }\n\n private repoConfig(fixture: GoldenFixture): string {\n if (!fixture.crashingRulesDir) return this.configJson;\n // webpieces-disable no-any-unknown -- the frozen fixture config is data on disk; re-parsing it into a named type here would be a second declaration of a file whose whole point is being literal\n const parsed = JSON.parse(this.configJson) as Record<string, unknown>;\n parsed['rulesDir'] = ['wprules'];\n return JSON.stringify(parsed, null, 4);\n }\n\n private git(repo: string, args: string): void {\n execSync(`git ${args}`, { cwd: repo, encoding: 'utf8' });\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"load-rules.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/core/load-rules.ts"],"names":[],"mappings":"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","sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\n\nimport { BaseRuleConfig, RuleOptions, WebpiecesRulesConfig, NoAnyUnknownConfig, NoImplicitAnyConfig, MaxFileLinesConfig, ValidateTsInSrcConfig, NoDestructureConfig, RequireReturnTypeConfig, NoUnmanagedExceptionsConfig, CatchErrorPatternConfig, ThrowCauseRequiredConfig, NoSymbolDiTokensConfig, NoCustomCssConfig, NoProcessExitOutsideMainConfig, NoJsFilesConfig, MatchRuleConfig } from '@webpieces/rules-config';\n\nimport type { Rule, PlainRule } from '@webpieces/hook-runtime';\nimport { InformAiError } from '@webpieces/tooling-common';\nimport { toError } from '@webpieces/tooling-common/to-error';\nimport { EmptyRuleConfig } from '@webpieces/hook-runtime';\nimport { CustomRuleAdapter } from '@webpieces/hook-runtime';\nimport { builtInConfigKeys } from './rules/index';\nimport { NoAnyUnknownRule } from './rules/no-any-unknown';\nimport { NoImplicitAnyRule } from './rules/no-implicit-any';\nimport { MaxFileLinesRule } from './rules/max-file-lines';\nimport { ValidateTsInSrcRule } from './rules/validate-ts-in-src';\nimport { NoDestructureRule } from './rules/no-destructure';\nimport { RequireReturnTypeRule } from './rules/require-return-type';\nimport { NoUnmanagedExceptionsRule } from './rules/no-unmanaged-exceptions';\nimport { CatchErrorPatternRule } from './rules/catch-error-pattern';\nimport { ThrowCauseRequiredRule } from './rules/throw-cause-required';\nimport { NoSymbolDiTokensRule } from './rules/no-symbol-di-tokens';\nimport { NoCustomCssRule } from './rules/no-custom-css';\nimport { NoProcessExitOutsideMainRule } from './rules/no-process-exit-outside-main';\nimport { NoJsFilesRule } from './rules/no-js-files';\nimport { MatchRule } from './rules/match-rule';\n\nconst REQUIRED_FIELDS: readonly string[] = ['name', 'description', 'scope', 'files', 'check'];\nconst VALID_SCOPES = new Set(['edit', 'file', 'bash']);\n\n/**\n * ONE CONFIG KEY → N RULES.\n *\n * Each built-in rule is constructed from its typed *Config (the entry in webpieces.config.json). The\n * config arrives as a plain object structurally typed as the *Config class, so the `as` narrows the\n * shared BaseRuleConfig param back to the concrete config the rule consumes.\n *\n * This registry contains source-rule factories only. Each accepts BaseRuleConfig and returns an\n * array of source rule instances for its config key. Workflow policies and command hints are owned\n * by agent-workflow-rules and are not inputs to this loader.\n */\ntype RuleFactory = (config: BaseRuleConfig) => readonly Rule[];\n\nconst BUILT_IN_RULE_MAP: Record<string, RuleFactory> = {\n 'no-any-unknown': (c: BaseRuleConfig) => [new NoAnyUnknownRule(c as NoAnyUnknownConfig)],\n 'no-implicit-any': (c: BaseRuleConfig) => [new NoImplicitAnyRule(c as NoImplicitAnyConfig)],\n 'max-file-lines': (c: BaseRuleConfig) => [new MaxFileLinesRule(c as MaxFileLinesConfig)],\n 'validate-ts-in-src': (c: BaseRuleConfig) => [new ValidateTsInSrcRule(c as ValidateTsInSrcConfig)],\n 'no-destructure': (c: BaseRuleConfig) => [new NoDestructureRule(c as NoDestructureConfig)],\n 'require-return-type': (c: BaseRuleConfig) => [new RequireReturnTypeRule(c as RequireReturnTypeConfig)],\n 'no-unmanaged-exceptions': (c: BaseRuleConfig) => [new NoUnmanagedExceptionsRule(c as NoUnmanagedExceptionsConfig)],\n 'catch-error-pattern': (c: BaseRuleConfig) => [new CatchErrorPatternRule(c as CatchErrorPatternConfig)],\n 'throw-cause-required': (c: BaseRuleConfig) => [new ThrowCauseRequiredRule(c as ThrowCauseRequiredConfig)],\n 'no-symbol-di-tokens': (c: BaseRuleConfig) => [new NoSymbolDiTokensRule(c as NoSymbolDiTokensConfig)],\n 'no-custom-css': (c: BaseRuleConfig) => [new NoCustomCssRule(c as NoCustomCssConfig)],\n 'no-process-exit-outside-main': (c: BaseRuleConfig) => [new NoProcessExitOutsideMainRule(c as NoProcessExitOutsideMainConfig)],\n 'no-js-files': (c: BaseRuleConfig) => [new NoJsFilesRule(c as NoJsFilesConfig)],\n\n};\n\n// Index the typed config by rule name. Each value is the rule's *Config (a plain object from\n// JSON), or undefined when the rule has no entry yet (the sync check reports those).\nfunction asConfigMap(config: WebpiecesRulesConfig): Record<string, BaseRuleConfig | undefined> {\n // webpieces-disable no-any-unknown -- index the typed config by dynamic rule name\n return config as unknown as Record<string, BaseRuleConfig | undefined>;\n}\n\n// webpieces-disable no-function-outside-class -- the module's entry point, beside loadMatchRules/loadKeylessBashRules; this whole loader is module-scope functions and a lone class for one of them would break the file's shape\nexport function loadRules(\n config: WebpiecesRulesConfig,\n workspaceRoot: string,\n): readonly Rule[] {\n const builtIns = loadBuiltInRules(config);\n const custom = loadCustomRules(config, workspaceRoot);\n return [...builtIns, ...custom];\n}\n\n// One MatchRule per entry of the `match-rules` array. Kept separate from loadRules (built-ins/custom)\n// because match-rules live in their own validated section — they must NOT flow through the\n// config-sync check, which compares rule names against the `rules`/`hookGuards` map.\nexport function loadMatchRules(matchRules: readonly MatchRuleConfig[]): Rule[] {\n return matchRules.map((c: MatchRuleConfig) => new MatchRule(c));\n}\n\n// Iterates CONFIG KEYS, not rule names — one entry can yield several rules (see BUILT_IN_RULE_MAP).\n// webpieces-disable no-function-outside-class -- the body of loadRules above, in the same module of loader functions\nexport function loadBuiltInRules(config: WebpiecesRulesConfig): Rule[] {\n const map = asConfigMap(config);\n const rules: Rule[] = [];\n for (const configKey of builtInConfigKeys) {\n const factory = BUILT_IN_RULE_MAP[configKey];\n if (!factory) {\n process.stderr.write(`[ai-hooks] unknown built-in config key: ${configKey}\\n`);\n continue;\n }\n const ruleConfig = map[configKey] ?? new EmptyRuleConfig();\n rules.push(...factory(ruleConfig));\n }\n return rules;\n}\n\n// webpieces-disable no-function-outside-class -- existing source registry helper contributed to both source and umbrella runners\nexport function loadCustomRules(config: WebpiecesRulesConfig, workspaceRoot: string): Rule[] {\n const dirs = config.rulesDir ?? [];\n // webpieces-disable no-any-unknown -- index the typed config by dynamic custom-rule name\n const map = config as unknown as Record<string, RuleOptions | undefined>;\n const rules: Rule[] = [];\n for (const plain of loadCustomPlainRules(dirs, workspaceRoot)) {\n const rawConfig = map[plain.name] ?? {};\n rules.push(new CustomRuleAdapter(plain, rawConfig));\n }\n return rules;\n}\n\nfunction loadCustomPlainRules(rulesDirs: readonly string[], workspaceRoot: string): PlainRule[] {\n const modules: PlainRule[] = [];\n for (const dir of rulesDirs) {\n const absDir = path.isAbsolute(dir) ? dir : path.join(workspaceRoot, dir);\n if (!fs.existsSync(absDir)) {\n process.stderr.write(`[ai-hooks] rulesDir not found: ${absDir}\\n`);\n continue;\n }\n let entries: string[];\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n entries = fs.readdirSync(absDir).filter((e: string) => e.endsWith('.js'));\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Cannot read custom rules directory '${absDir}'`, { cause: error });\n }\n for (const entry of entries) {\n const full = path.join(absDir, entry);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const mod = require(full);\n const candidate = mod.default || mod;\n if (validateRule(candidate)) modules.push(candidate);\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Cannot load custom rule '${full}'`, { cause: error });\n }\n }\n }\n return modules;\n}\n\n// webpieces-disable no-any-unknown -- validates untrusted require() output at system boundary\nfunction validateRule(rule: unknown): rule is PlainRule {\n if (!rule || typeof rule !== 'object') {\n process.stderr.write('[ai-hooks] rule is not an object, skipping\\n');\n return false;\n }\n // webpieces-disable no-any-unknown -- narrowing from unknown at system boundary\n const obj = rule as Record<string, unknown>;\n for (const field of REQUIRED_FIELDS) {\n if (obj[field] === undefined) {\n const name = typeof obj['name'] === 'string' ? obj['name'] : '<unnamed>';\n process.stderr.write(`[ai-hooks] rule \"${name}\" missing required field: ${field}\\n`);\n return false;\n }\n }\n if (!VALID_SCOPES.has(obj['scope'] as string)) {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" has invalid scope: ${String(obj['scope'])}\\n`);\n return false;\n }\n if (!Array.isArray(obj['files'])) {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" files must be an array\\n`);\n return false;\n }\n if (typeof obj['check'] !== 'function') {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" check must be a function\\n`);\n return false;\n }\n return true;\n}\n"]}
1
+ {"version":3,"file":"load-rules.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hook-rules/src/core/load-rules.ts"],"names":[],"mappings":"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","sourcesContent":["import { BaseRuleConfig } from '@webpieces/rules-sdk';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\nimport { RuleOptions, WebpiecesRulesConfig, NoAnyUnknownConfig, NoImplicitAnyConfig, MaxFileLinesConfig, ValidateTsInSrcConfig, NoDestructureConfig, RequireReturnTypeConfig, NoUnmanagedExceptionsConfig, CatchErrorPatternConfig, ThrowCauseRequiredConfig, NoSymbolDiTokensConfig, NoCustomCssConfig, NoProcessExitOutsideMainConfig, NoJsFilesConfig, MatchRuleConfig } from '@webpieces/rules-config';\n\nimport type { Rule, PlainRule } from '@webpieces/hook-runtime';\nimport { InformAiError } from '@webpieces/tooling-common';\nimport { toError } from '@webpieces/tooling-common/to-error';\nimport { EmptyRuleConfig } from '@webpieces/hook-runtime';\nimport { CustomRuleAdapter } from '@webpieces/hook-runtime';\nimport { builtInConfigKeys } from './rules/index';\nimport { NoAnyUnknownRule } from './rules/no-any-unknown';\nimport { NoImplicitAnyRule } from './rules/no-implicit-any';\nimport { MaxFileLinesRule } from './rules/max-file-lines';\nimport { ValidateTsInSrcRule } from './rules/validate-ts-in-src';\nimport { NoDestructureRule } from './rules/no-destructure';\nimport { RequireReturnTypeRule } from './rules/require-return-type';\nimport { NoUnmanagedExceptionsRule } from './rules/no-unmanaged-exceptions';\nimport { CatchErrorPatternRule } from './rules/catch-error-pattern';\nimport { ThrowCauseRequiredRule } from './rules/throw-cause-required';\nimport { NoSymbolDiTokensRule } from './rules/no-symbol-di-tokens';\nimport { NoCustomCssRule } from './rules/no-custom-css';\nimport { NoProcessExitOutsideMainRule } from './rules/no-process-exit-outside-main';\nimport { NoJsFilesRule } from './rules/no-js-files';\nimport { MatchRule } from './rules/match-rule';\n\nconst REQUIRED_FIELDS: readonly string[] = ['name', 'description', 'scope', 'files', 'check'];\nconst VALID_SCOPES = new Set(['edit', 'file', 'bash']);\n\n/**\n * ONE CONFIG KEY → N RULES.\n *\n * Each built-in rule is constructed from its typed *Config (the entry in webpieces.config.json). The\n * config arrives as a plain object structurally typed as the *Config class, so the `as` narrows the\n * shared BaseRuleConfig param back to the concrete config the rule consumes.\n *\n * This registry contains source-rule factories only. Each accepts BaseRuleConfig and returns an\n * array of source rule instances for its config key. Workflow policies and command hints are owned\n * by agent-workflow-rules and are not inputs to this loader.\n */\ntype RuleFactory = (config: BaseRuleConfig) => readonly Rule[];\n\nconst BUILT_IN_RULE_MAP: Record<string, RuleFactory> = {\n 'no-any-unknown': (c: BaseRuleConfig) => [new NoAnyUnknownRule(c as NoAnyUnknownConfig)],\n 'no-implicit-any': (c: BaseRuleConfig) => [new NoImplicitAnyRule(c as NoImplicitAnyConfig)],\n 'max-file-lines': (c: BaseRuleConfig) => [new MaxFileLinesRule(c as MaxFileLinesConfig)],\n 'validate-ts-in-src': (c: BaseRuleConfig) => [new ValidateTsInSrcRule(c as ValidateTsInSrcConfig)],\n 'no-destructure': (c: BaseRuleConfig) => [new NoDestructureRule(c as NoDestructureConfig)],\n 'require-return-type': (c: BaseRuleConfig) => [new RequireReturnTypeRule(c as RequireReturnTypeConfig)],\n 'no-unmanaged-exceptions': (c: BaseRuleConfig) => [new NoUnmanagedExceptionsRule(c as NoUnmanagedExceptionsConfig)],\n 'catch-error-pattern': (c: BaseRuleConfig) => [new CatchErrorPatternRule(c as CatchErrorPatternConfig)],\n 'throw-cause-required': (c: BaseRuleConfig) => [new ThrowCauseRequiredRule(c as ThrowCauseRequiredConfig)],\n 'no-symbol-di-tokens': (c: BaseRuleConfig) => [new NoSymbolDiTokensRule(c as NoSymbolDiTokensConfig)],\n 'no-custom-css': (c: BaseRuleConfig) => [new NoCustomCssRule(c as NoCustomCssConfig)],\n 'no-process-exit-outside-main': (c: BaseRuleConfig) => [new NoProcessExitOutsideMainRule(c as NoProcessExitOutsideMainConfig)],\n 'no-js-files': (c: BaseRuleConfig) => [new NoJsFilesRule(c as NoJsFilesConfig)],\n\n};\n\n// Index the typed config by rule name. Each value is the rule's *Config (a plain object from\n// JSON), or undefined when the rule has no entry yet (the sync check reports those).\nfunction asConfigMap(config: WebpiecesRulesConfig): Record<string, BaseRuleConfig | undefined> {\n // webpieces-disable no-any-unknown -- index the typed config by dynamic rule name\n return config as unknown as Record<string, BaseRuleConfig | undefined>;\n}\n\n// webpieces-disable no-function-outside-class -- the module's entry point, beside loadMatchRules/loadKeylessBashRules; this whole loader is module-scope functions and a lone class for one of them would break the file's shape\nexport function loadRules(\n config: WebpiecesRulesConfig,\n workspaceRoot: string,\n): readonly Rule[] {\n const builtIns = loadBuiltInRules(config);\n const custom = loadCustomRules(config, workspaceRoot);\n return [...builtIns, ...custom];\n}\n\n// One MatchRule per entry of the `match-rules` array. Kept separate from loadRules (built-ins/custom)\n// because match-rules live in their own validated section — they must NOT flow through the\n// config-sync check, which compares rule names against the `rules`/`hookGuards` map.\nexport function loadMatchRules(matchRules: readonly MatchRuleConfig[]): Rule[] {\n return matchRules.map((c: MatchRuleConfig) => new MatchRule(c));\n}\n\n// Iterates CONFIG KEYS, not rule names — one entry can yield several rules (see BUILT_IN_RULE_MAP).\n// webpieces-disable no-function-outside-class -- the body of loadRules above, in the same module of loader functions\nexport function loadBuiltInRules(config: WebpiecesRulesConfig): Rule[] {\n const map = asConfigMap(config);\n const rules: Rule[] = [];\n for (const configKey of builtInConfigKeys) {\n const factory = BUILT_IN_RULE_MAP[configKey];\n if (!factory) {\n process.stderr.write(`[ai-hooks] unknown built-in config key: ${configKey}\\n`);\n continue;\n }\n const ruleConfig = map[configKey] ?? new EmptyRuleConfig();\n rules.push(...factory(ruleConfig));\n }\n return rules;\n}\n\n// webpieces-disable no-function-outside-class -- existing source registry helper contributed to both source and umbrella runners\nexport function loadCustomRules(config: WebpiecesRulesConfig, workspaceRoot: string): Rule[] {\n const dirs = config.rulesDir ?? [];\n // webpieces-disable no-any-unknown -- index the typed config by dynamic custom-rule name\n const map = config as unknown as Record<string, RuleOptions | undefined>;\n const rules: Rule[] = [];\n for (const plain of loadCustomPlainRules(dirs, workspaceRoot)) {\n const rawConfig = map[plain.name] ?? {};\n rules.push(new CustomRuleAdapter(plain, rawConfig));\n }\n return rules;\n}\n\nfunction loadCustomPlainRules(rulesDirs: readonly string[], workspaceRoot: string): PlainRule[] {\n const modules: PlainRule[] = [];\n for (const dir of rulesDirs) {\n const absDir = path.isAbsolute(dir) ? dir : path.join(workspaceRoot, dir);\n if (!fs.existsSync(absDir)) {\n process.stderr.write(`[ai-hooks] rulesDir not found: ${absDir}\\n`);\n continue;\n }\n let entries: string[];\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n entries = fs.readdirSync(absDir).filter((e: string) => e.endsWith('.js'));\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Cannot read custom rules directory '${absDir}'`, { cause: error });\n }\n for (const entry of entries) {\n const full = path.join(absDir, entry);\n // eslint-disable-next-line @webpieces/no-unmanaged-exceptions\n try {\n const mod = require(full);\n const candidate = mod.default || mod;\n if (validateRule(candidate)) modules.push(candidate);\n } catch (err: unknown) {\n const error = toError(err);\n throw new InformAiError(`Cannot load custom rule '${full}'`, { cause: error });\n }\n }\n }\n return modules;\n}\n\n// webpieces-disable no-any-unknown -- validates untrusted require() output at system boundary\nfunction validateRule(rule: unknown): rule is PlainRule {\n if (!rule || typeof rule !== 'object') {\n process.stderr.write('[ai-hooks] rule is not an object, skipping\\n');\n return false;\n }\n // webpieces-disable no-any-unknown -- narrowing from unknown at system boundary\n const obj = rule as Record<string, unknown>;\n for (const field of REQUIRED_FIELDS) {\n if (obj[field] === undefined) {\n const name = typeof obj['name'] === 'string' ? obj['name'] : '<unnamed>';\n process.stderr.write(`[ai-hooks] rule \"${name}\" missing required field: ${field}\\n`);\n return false;\n }\n }\n if (!VALID_SCOPES.has(obj['scope'] as string)) {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" has invalid scope: ${String(obj['scope'])}\\n`);\n return false;\n }\n if (!Array.isArray(obj['files'])) {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" files must be an array\\n`);\n return false;\n }\n if (typeof obj['check'] !== 'function') {\n process.stderr.write(`[ai-hooks] rule \"${obj['name']}\" check must be a function\\n`);\n return false;\n }\n return true;\n}\n"]}
@@ -0,0 +1,2 @@
1
+ import { RulePackManifest } from '@webpieces/rules-sdk';
2
+ export declare const rulePackManifest: RulePackManifest;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rulePackManifest = void 0;
4
+ const rules_sdk_1 = require("@webpieces/rules-sdk");
5
+ const rules_config_1 = require("@webpieces/rules-config");
6
+ const package_json_1 = require("../package.json");
7
+ /** Compatibility manifest; executable registries remain authoritative until ownership migration. */
8
+ const ownedRuleIds = [
9
+ "throw-cause-required",
10
+ "no-js-files",
11
+ "validate-ts-in-src"
12
+ ];
13
+ exports.rulePackManifest = new rules_sdk_1.RulePackManifest('@webpieces/ai-hook-rules', package_json_1.version, rules_sdk_1.RULE_PACK_API_VERSION, ownedRuleIds.map(id => new rules_sdk_1.OwnedRuleDefinition(id, rules_config_1.RULE_SCHEMAS[id], rules_sdk_1.RULE_SCHEMA_API_VERSION)), [
14
+ ...ownedRuleIds.map(id => new rules_sdk_1.RuleContribution(id, '@webpieces/ai-hook-rules', 'source-hook')),
15
+ new rules_sdk_1.RuleContribution('no-any-unknown', '@webpieces/code-rules', 'source-hook'),
16
+ new rules_sdk_1.RuleContribution('no-implicit-any', '@webpieces/code-rules', 'source-hook'),
17
+ new rules_sdk_1.RuleContribution('max-file-lines', '@webpieces/code-rules', 'source-hook'),
18
+ new rules_sdk_1.RuleContribution('no-destructure', '@webpieces/code-rules', 'source-hook'),
19
+ new rules_sdk_1.RuleContribution('require-return-type', '@webpieces/code-rules', 'source-hook'),
20
+ new rules_sdk_1.RuleContribution('no-unmanaged-exceptions', '@webpieces/code-rules', 'source-hook'),
21
+ new rules_sdk_1.RuleContribution('catch-error-pattern', '@webpieces/code-rules', 'source-hook'),
22
+ new rules_sdk_1.RuleContribution('no-symbol-di-tokens', '@webpieces/code-rules', 'source-hook'),
23
+ new rules_sdk_1.RuleContribution('no-custom-css', '@webpieces/code-rules', 'source-hook'),
24
+ new rules_sdk_1.RuleContribution('no-process-exit-outside-main', '@webpieces/code-rules', 'source-hook'),
25
+ ]);
26
+ //# sourceMappingURL=rule-pack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-pack.js","sourceRoot":"","sources":["../../../../../packages/tooling/ai-hook-rules/src/rule-pack.ts"],"names":[],"mappings":";;;AAAA,oDAA+I;AAC/I,0DAAuD;AACvD,kDAA0C;AAE1C,oGAAoG;AACpG,MAAM,YAAY,GAAG;IACjB,sBAAsB;IACtB,aAAa;IACb,oBAAoB;CACd,CAAC;AAEE,QAAA,gBAAgB,GAAG,IAAI,4BAAgB,CAChD,0BAA0B,EAC1B,sBAAO,EACP,iCAAqB,EACrB,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,+BAAmB,CAAC,EAAE,EAAE,2BAAY,CAAC,EAAE,CAAC,EAAE,mCAAuB,CAAC,CAAC,EAC9F;IACI,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,4BAAgB,CAAC,EAAE,EAAE,0BAA0B,EAAE,aAAa,CAAC,CAAC;IAC9F,IAAI,4BAAgB,CAAC,gBAAgB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IAC9E,IAAI,4BAAgB,CAAC,iBAAiB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IAC/E,IAAI,4BAAgB,CAAC,gBAAgB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IAC9E,IAAI,4BAAgB,CAAC,gBAAgB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IAC9E,IAAI,4BAAgB,CAAC,qBAAqB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IACnF,IAAI,4BAAgB,CAAC,yBAAyB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IACvF,IAAI,4BAAgB,CAAC,qBAAqB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IACnF,IAAI,4BAAgB,CAAC,qBAAqB,EAAE,uBAAuB,EAAE,aAAa,CAAC;IACnF,IAAI,4BAAgB,CAAC,eAAe,EAAE,uBAAuB,EAAE,aAAa,CAAC;IAC7E,IAAI,4BAAgB,CAAC,8BAA8B,EAAE,uBAAuB,EAAE,aAAa,CAAC;CAC/F,CACJ,CAAC","sourcesContent":["import { OwnedRuleDefinition, RuleContribution, RulePackManifest, RULE_PACK_API_VERSION, RULE_SCHEMA_API_VERSION } from '@webpieces/rules-sdk';\nimport { RULE_SCHEMAS } from '@webpieces/rules-config';\nimport { version } from '../package.json';\n\n/** Compatibility manifest; executable registries remain authoritative until ownership migration. */\nconst ownedRuleIds = [\n \"throw-cause-required\",\n \"no-js-files\",\n \"validate-ts-in-src\"\n] as const;\n\nexport const rulePackManifest = new RulePackManifest(\n '@webpieces/ai-hook-rules',\n version,\n RULE_PACK_API_VERSION,\n ownedRuleIds.map(id => new OwnedRuleDefinition(id, RULE_SCHEMAS[id], RULE_SCHEMA_API_VERSION)),\n [\n ...ownedRuleIds.map(id => new RuleContribution(id, '@webpieces/ai-hook-rules', 'source-hook')),\n new RuleContribution('no-any-unknown', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-implicit-any', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('max-file-lines', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-destructure', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('require-return-type', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-unmanaged-exceptions', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('catch-error-pattern', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-symbol-di-tokens', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-custom-css', '@webpieces/code-rules', 'source-hook'),\n new RuleContribution('no-process-exit-outside-main', '@webpieces/code-rules', 'source-hook'),\n ],\n);\n"]}