@webpieces/ai-hook-rules 0.3.144 → 0.3.146

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.3.144",
3
+ "version": "0.3.146",
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",
@@ -32,7 +32,7 @@
32
32
  "directory": "packages/tooling/ai-hook-rules"
33
33
  },
34
34
  "dependencies": {
35
- "@webpieces/rules-config": "0.3.144"
35
+ "@webpieces/rules-config": "0.3.146"
36
36
  },
37
37
  "publishConfig": {
38
38
  "access": "public"
@@ -2,29 +2,59 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const types_1 = require("../types");
4
4
  const SYMBOL_DI_REGEX = /=\s*Symbol(?:\.for)?\(/;
5
- const ALLOWED_PATHS = [
6
- /^libraries\/apis\//,
7
- /^libraries\/apis-external\//,
8
- /^packages\/http\/http-api\//,
9
- ];
10
5
  const TEST_PATHS = [/\.test\.ts$/, /\.spec\.ts$/, /__tests__\//];
11
- function isAllowedPath(relativePath) {
12
- return ALLOWED_PATHS.some((re) => re.test(relativePath)) ||
13
- TEST_PATHS.some((re) => re.test(relativePath));
6
+ function globToRegex(pattern) {
7
+ let re = '';
8
+ let i = 0;
9
+ while (i < pattern.length) {
10
+ const ch = pattern[i];
11
+ if (ch === '*') {
12
+ if (pattern[i + 1] === '*') {
13
+ re += '.*';
14
+ i += 2;
15
+ if (pattern[i] === '/')
16
+ i += 1;
17
+ continue;
18
+ }
19
+ re += '[^/]*';
20
+ i += 1;
21
+ continue;
22
+ }
23
+ if (ch === '?') {
24
+ re += '[^/]';
25
+ i += 1;
26
+ continue;
27
+ }
28
+ if ('.+^$(){}|[]\\'.includes(ch)) {
29
+ re += '\\' + ch;
30
+ i += 1;
31
+ continue;
32
+ }
33
+ re += ch;
34
+ i += 1;
35
+ }
36
+ return new RegExp('^' + re + '$');
37
+ }
38
+ function isAllowedPath(relativePath, allowedPaths) {
39
+ if (TEST_PATHS.some((re) => re.test(relativePath)))
40
+ return true;
41
+ return allowedPaths.some((pattern) => globToRegex(pattern).test(relativePath));
14
42
  }
15
43
  const noSymbolDiTokensRule = {
16
44
  name: 'no-symbol-di-tokens',
17
- description: 'Disallow Symbol() DI tokens outside api(-external) packages. Use @provideSingleton() + inject-by-type instead.',
45
+ description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',
18
46
  scope: 'edit',
19
47
  files: ['**/*.ts', '**/*.tsx'],
20
- defaultOptions: {},
48
+ defaultOptions: { allowedPaths: [] },
21
49
  fixHint: [
22
- '(PREFERRED) Use @provideSingleton() on the class and inject that class directly — no Symbol needed.',
23
- 'Interface+impl pair (e.g. FirestoreApi/FirestoreImpl): co-locate the Symbol with the Api file and add // webpieces-disable no-symbol-di-tokens -- <reason>',
24
- 'External lib creating a class needing binding: put Symbol in a symbols file and add // webpieces-disable no-symbol-di-tokens -- <reason> on each one.',
50
+ '(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',
51
+ '(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',
52
+ '(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule no Symbol needed.',
53
+ 'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',
25
54
  ],
26
55
  check(ctx) {
27
- if (isAllowedPath(ctx.relativePath))
56
+ const allowedPaths = ctx.options['allowedPaths'] ?? [];
57
+ if (isAllowedPath(ctx.relativePath, allowedPaths))
28
58
  return [];
29
59
  const violations = [];
30
60
  for (let i = 0; i < ctx.strippedLines.length; i += 1) {
@@ -1 +1 @@
1
- {"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":";;AACA,oCAA0C;AAE1C,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,MAAM,aAAa,GAAa;IAC5B,oBAAoB;IACpB,6BAA6B;IAC7B,6BAA6B;CAChC,CAAC;AAEF,MAAM,UAAU,GAAa,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAE3E,SAAS,aAAa,CAAC,YAAoB;IACvC,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC5D,UAAU,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,oBAAoB,GAAa;IACnC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,gHAAgH;IAC7H,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAC9B,cAAc,EAAE,EAAE;IAClB,OAAO,EAAE;QACL,qGAAqG;QACrG,4JAA4J;QAC5J,uJAAuJ;KAC1J;IAED,KAAK,CAAC,GAAgB;QAClB,IAAI,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,OAAO,EAAE,CAAC;QAE/C,MAAM,UAAU,GAAQ,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;gBAAE,SAAS;YACpD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,CAAC;gBAAE,SAAS;YACjE,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAC1B,wFAAwF,CAC3F,CAAC,CAAC;QACP,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ,CAAC;AAEF,kBAAe,oBAAoB,CAAC","sourcesContent":["import type { EditRule, EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\n\nconst SYMBOL_DI_REGEX = /=\\s*Symbol(?:\\.for)?\\(/;\n\nconst ALLOWED_PATHS: RegExp[] = [\n /^libraries\\/apis\\//,\n /^libraries\\/apis-external\\//,\n /^packages\\/http\\/http-api\\//,\n];\n\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\nfunction isAllowedPath(relativePath: string): boolean {\n return ALLOWED_PATHS.some((re: RegExp) => re.test(relativePath)) ||\n TEST_PATHS.some((re: RegExp) => re.test(relativePath));\n}\n\nconst noSymbolDiTokensRule: EditRule = {\n name: 'no-symbol-di-tokens',\n description: 'Disallow Symbol() DI tokens outside api(-external) packages. Use @provideSingleton() + inject-by-type instead.',\n scope: 'edit',\n files: ['**/*.ts', '**/*.tsx'],\n defaultOptions: {},\n fixHint: [\n '(PREFERRED) Use @provideSingleton() on the class and inject that class directly — no Symbol needed.',\n 'Interface+impl pair (e.g. FirestoreApi/FirestoreImpl): co-locate the Symbol with the Api file and add // webpieces-disable no-symbol-di-tokens -- <reason>',\n 'External lib creating a class needing binding: put Symbol in a symbols file and add // webpieces-disable no-symbol-di-tokens -- <reason> on each one.',\n ],\n\n check(ctx: EditContext): readonly Violation[] {\n if (isAllowedPath(ctx.relativePath)) return [];\n\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!SYMBOL_DI_REGEX.test(stripped ?? '')) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, 'no-symbol-di-tokens')) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i]?.trim() ?? '',\n 'Symbol() used as a DI token. Mostly we avoid Symbol if we can — see fix options below.',\n ));\n }\n return violations;\n },\n};\n\nexport default noSymbolDiTokensRule;\n"]}
1
+ {"version":3,"file":"no-symbol-di-tokens.js","sourceRoot":"","sources":["../../../../../../../packages/tooling/ai-hook-rules/src/core/rules/no-symbol-di-tokens.ts"],"names":[],"mappings":";;AACA,oCAA0C;AAE1C,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,MAAM,UAAU,GAAa,CAAC,aAAa,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;AAE3E,SAAS,WAAW,CAAC,OAAe;IAChC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACb,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACzB,EAAE,IAAI,IAAI,CAAC;gBACX,CAAC,IAAI,CAAC,CAAC;gBACP,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG;oBAAE,CAAC,IAAI,CAAC,CAAC;gBAC/B,SAAS;YACb,CAAC;YACD,EAAE,IAAI,OAAO,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACb,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACb,EAAE,IAAI,MAAM,CAAC;YACb,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACb,CAAC;QACD,IAAI,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC;YAC/B,EAAE,IAAI,IAAI,GAAG,EAAE,CAAC;YAChB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACb,CAAC;QACD,EAAE,IAAI,EAAE,CAAC;QACT,CAAC,IAAI,CAAC,CAAC;IACX,CAAC;IACD,OAAO,IAAI,MAAM,CAAC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,aAAa,CAAC,YAAoB,EAAE,YAA+B;IACxE,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACxE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,OAAe,EAAE,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,oBAAoB,GAAa;IACnC,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EAAE,oHAAoH;IACjI,KAAK,EAAE,MAAM;IACb,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAC9B,cAAc,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE;IACpC,OAAO,EAAE;QACL,yFAAyF;QACzF,6GAA6G;QAC7G,+HAA+H;QAC/H,mGAAmG;KACtG;IAED,KAAK,CAAC,GAAgB;QAClB,MAAM,YAAY,GAAI,GAAG,CAAC,OAAO,CAAC,cAAc,CAA0B,IAAI,EAAE,CAAC;QACjF,IAAI,aAAa,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC;YAAE,OAAO,EAAE,CAAC;QAE7D,MAAM,UAAU,GAAQ,EAAE,CAAC;QAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YACnD,MAAM,QAAQ,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;YACtC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC;gBAAE,SAAS;YACpD,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;YACtB,IAAI,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE,qBAAqB,CAAC;gBAAE,SAAS;YACjE,UAAU,CAAC,IAAI,CAAC,IAAI,iBAAC,CACjB,OAAO,EACP,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAC1B,wFAAwF,CAC3F,CAAC,CAAC;QACP,CAAC;QACD,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ,CAAC;AAEF,kBAAe,oBAAoB,CAAC","sourcesContent":["import type { EditRule, EditContext, Violation } from '../types';\nimport { Violation as V } from '../types';\n\nconst SYMBOL_DI_REGEX = /=\\s*Symbol(?:\\.for)?\\(/;\n\nconst TEST_PATHS: RegExp[] = [/\\.test\\.ts$/, /\\.spec\\.ts$/, /__tests__\\//];\n\nfunction globToRegex(pattern: string): RegExp {\n let re = '';\n let i = 0;\n while (i < pattern.length) {\n const ch = pattern[i];\n if (ch === '*') {\n if (pattern[i + 1] === '*') {\n re += '.*';\n i += 2;\n if (pattern[i] === '/') i += 1;\n continue;\n }\n re += '[^/]*';\n i += 1;\n continue;\n }\n if (ch === '?') {\n re += '[^/]';\n i += 1;\n continue;\n }\n if ('.+^$(){}|[]\\\\'.includes(ch)) {\n re += '\\\\' + ch;\n i += 1;\n continue;\n }\n re += ch;\n i += 1;\n }\n return new RegExp('^' + re + '$');\n}\n\nfunction isAllowedPath(relativePath: string, allowedPaths: readonly string[]): boolean {\n if (TEST_PATHS.some((re: RegExp) => re.test(relativePath))) return true;\n return allowedPaths.some((pattern: string) => globToRegex(pattern).test(relativePath));\n}\n\nconst noSymbolDiTokensRule: EditRule = {\n name: 'no-symbol-di-tokens',\n description: 'Disallow Symbol() DI tokens outside explicitly configured paths. Use @provideSingleton() + inject-by-type instead.',\n scope: 'edit',\n files: ['**/*.ts', '**/*.tsx'],\n defaultOptions: { allowedPaths: [] },\n fixHint: [\n '(OWN class) Use @provideSingleton() on the class and inject by type — no Symbol needed.',\n '(apis-external impl) Import the Symbol from libraries/apis/** and annotate with @provideSingletonAs(TOKEN).',\n '(External lib class: DataSource, Anthropic, etc.) bind<Cls>(Cls).toDynamicValue(...) in a ContainerModule no Symbol needed.',\n 'Last resort: add // webpieces-disable no-symbol-di-tokens -- <reason> with a clear justification.',\n ],\n\n check(ctx: EditContext): readonly Violation[] {\n const allowedPaths = (ctx.options['allowedPaths'] as string[] | undefined) ?? [];\n if (isAllowedPath(ctx.relativePath, allowedPaths)) return [];\n\n const violations: V[] = [];\n for (let i = 0; i < ctx.strippedLines.length; i += 1) {\n const stripped = ctx.strippedLines[i];\n if (!SYMBOL_DI_REGEX.test(stripped ?? '')) continue;\n const lineNum = i + 1;\n if (ctx.isLineDisabled(lineNum, 'no-symbol-di-tokens')) continue;\n violations.push(new V(\n lineNum,\n ctx.lines[i]?.trim() ?? '',\n 'Symbol() used as a DI token. Mostly we avoid Symbol if we can — see fix options below.',\n ));\n }\n return violations;\n },\n};\n\nexport default noSymbolDiTokensRule;\n"]}