@webpieces/ai-hooks 0.2.105 → 0.2.107
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 +4 -1
- package/src/core/load-config.d.ts +1 -3
- package/src/core/load-config.js +7 -78
- package/src/core/load-config.js.map +1 -1
- package/src/core/types.d.ts +2 -13
- package/src/core/types.js +4 -16
- package/src/core/types.js.map +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webpieces/ai-hooks",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.107",
|
|
4
4
|
"description": "Pluggable write-time validation framework for AI coding agents. Claude Code PreToolUse + openclaw before_tool_call adapters share one rule engine.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
"url": "https://github.com/deanhiller/webpieces-ts.git",
|
|
29
29
|
"directory": "packages/tooling/ai-hooks"
|
|
30
30
|
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@webpieces/config": "0.2.107"
|
|
33
|
+
},
|
|
31
34
|
"publishConfig": {
|
|
32
35
|
"access": "public"
|
|
33
36
|
},
|
package/src/core/load-config.js
CHANGED
|
@@ -1,81 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findConfigFile =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
function
|
|
10
|
-
let dir = startDir;
|
|
11
|
-
while (true) {
|
|
12
|
-
const candidate = path.join(dir, 'webpieces.ai-hooks.json');
|
|
13
|
-
if (fs.existsSync(candidate))
|
|
14
|
-
return candidate;
|
|
15
|
-
const parent = path.dirname(dir);
|
|
16
|
-
if (parent === dir)
|
|
17
|
-
return null;
|
|
18
|
-
dir = parent;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
// webpieces-disable no-any-unknown -- default config returns opaque rule option bags
|
|
22
|
-
function loadDefaultConfig() {
|
|
23
|
-
const defaultModule = require('./configs/default');
|
|
24
|
-
// webpieces-disable no-any-unknown -- opaque rule option bags
|
|
25
|
-
return defaultModule.defaultRules;
|
|
26
|
-
}
|
|
27
|
-
// webpieces-disable no-any-unknown -- merging opaque option bags from config JSON
|
|
28
|
-
function mergeRule(
|
|
29
|
-
// webpieces-disable no-any-unknown -- opaque option bag
|
|
30
|
-
baseRule,
|
|
31
|
-
// webpieces-disable no-any-unknown -- opaque option bag
|
|
32
|
-
overrideRule) {
|
|
33
|
-
if (!baseRule && !overrideRule)
|
|
34
|
-
return new types_1.ResolvedRuleConfig(false, {});
|
|
35
|
-
if (!baseRule)
|
|
36
|
-
return new types_1.ResolvedRuleConfig(true, overrideRule);
|
|
37
|
-
if (!overrideRule) {
|
|
38
|
-
const enabled = baseRule['enabled'] !== false;
|
|
39
|
-
return new types_1.ResolvedRuleConfig(enabled, baseRule);
|
|
40
|
-
}
|
|
41
|
-
// webpieces-disable no-any-unknown -- building merged option bag
|
|
42
|
-
const merged = {};
|
|
43
|
-
for (const key of Object.keys(baseRule))
|
|
44
|
-
merged[key] = baseRule[key];
|
|
45
|
-
for (const key of Object.keys(overrideRule))
|
|
46
|
-
merged[key] = overrideRule[key];
|
|
47
|
-
const enabled = merged['enabled'] !== false;
|
|
48
|
-
return new types_1.ResolvedRuleConfig(enabled, merged);
|
|
49
|
-
}
|
|
50
|
-
function loadConfig(cwd) {
|
|
51
|
-
const configPath = findConfigFile(cwd);
|
|
52
|
-
const defaultRules = loadDefaultConfig();
|
|
53
|
-
if (!configPath) {
|
|
54
|
-
return new types_1.ResolvedConfig(new Map(), [], null);
|
|
55
|
-
}
|
|
56
|
-
let consumerConfig;
|
|
57
|
-
// eslint-disable-next-line @webpieces/no-unmanaged-exceptions
|
|
58
|
-
try {
|
|
59
|
-
const raw = fs.readFileSync(configPath, 'utf8');
|
|
60
|
-
consumerConfig = JSON.parse(raw);
|
|
61
|
-
}
|
|
62
|
-
catch (err) {
|
|
63
|
-
// eslint-disable-next-line @webpieces/catch-error-pattern -- malformed config fails open
|
|
64
|
-
void err;
|
|
65
|
-
return new types_1.ResolvedConfig(new Map(), [], configPath);
|
|
66
|
-
}
|
|
67
|
-
const overrideRules = consumerConfig.rules || {};
|
|
68
|
-
const mergedRules = new Map();
|
|
69
|
-
const allRuleNames = new Set([
|
|
70
|
-
...Object.keys(defaultRules),
|
|
71
|
-
...Object.keys(overrideRules),
|
|
72
|
-
]);
|
|
73
|
-
for (const name of allRuleNames) {
|
|
74
|
-
mergedRules.set(name, mergeRule(defaultRules[name], overrideRules[name]));
|
|
75
|
-
}
|
|
76
|
-
const baseDirs = [];
|
|
77
|
-
const overrideDirs = consumerConfig.rulesDir || [];
|
|
78
|
-
const rulesDir = [...baseDirs, ...overrideDirs];
|
|
79
|
-
return new types_1.ResolvedConfig(mergedRules, rulesDir, configPath);
|
|
80
|
-
}
|
|
3
|
+
exports.CONFIG_FILENAME = exports.findConfigFile = exports.loadConfig = void 0;
|
|
4
|
+
// Re-export the shared workspace config loader so ai-hooks and the Nx
|
|
5
|
+
// validate-code executor use the same webpieces.config.json.
|
|
6
|
+
var config_1 = require("@webpieces/config");
|
|
7
|
+
Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return config_1.loadConfig; } });
|
|
8
|
+
Object.defineProperty(exports, "findConfigFile", { enumerable: true, get: function () { return config_1.findConfigFile; } });
|
|
9
|
+
Object.defineProperty(exports, "CONFIG_FILENAME", { enumerable: true, get: function () { return config_1.CONFIG_FILENAME; } });
|
|
81
10
|
//# sourceMappingURL=load-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hooks/src/core/load-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"load-config.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hooks/src/core/load-config.ts"],"names":[],"mappings":";;;AAAA,sEAAsE;AACtE,6DAA6D;AAC7D,4CAAgF;AAAvE,oGAAA,UAAU,OAAA;AAAE,wGAAA,cAAc,OAAA;AAAE,yGAAA,eAAe,OAAA","sourcesContent":["// Re-export the shared workspace config loader so ai-hooks and the Nx\n// validate-code executor use the same webpieces.config.json.\nexport { loadConfig, findConfigFile, CONFIG_FILENAME } from '@webpieces/config';\n"]}
|
package/src/core/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { RuleOptions } from '@webpieces/config';
|
|
2
|
+
export { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from '@webpieces/config';
|
|
1
3
|
export type ToolKind = 'Write' | 'Edit' | 'MultiEdit';
|
|
2
4
|
export type RuleScope = 'edit' | 'file';
|
|
3
|
-
export type RuleOptions = Record<string, unknown>;
|
|
4
5
|
export type IsLineDisabled = (lineNum: number, ruleName: string) => boolean;
|
|
5
6
|
export declare class Violation {
|
|
6
7
|
readonly line: number;
|
|
@@ -75,15 +76,3 @@ export declare class BlockedResult {
|
|
|
75
76
|
readonly report: string;
|
|
76
77
|
constructor(report: string);
|
|
77
78
|
}
|
|
78
|
-
export declare class ResolvedConfig {
|
|
79
|
-
readonly rules: Map<string, ResolvedRuleConfig>;
|
|
80
|
-
readonly rulesDir: readonly string[];
|
|
81
|
-
readonly configPath: string | null;
|
|
82
|
-
constructor(rules: Map<string, ResolvedRuleConfig>, rulesDir: readonly string[], configPath: string | null);
|
|
83
|
-
}
|
|
84
|
-
export declare class ResolvedRuleConfig {
|
|
85
|
-
readonly enabled: boolean;
|
|
86
|
-
readonly options: RuleOptions;
|
|
87
|
-
constructor(enabled: boolean, options: RuleOptions);
|
|
88
|
-
}
|
|
89
|
-
export {};
|
package/src/core/types.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.BlockedResult = exports.RuleGroup = exports.FileContext = exports.EditContext = exports.NormalizedToolInput = exports.NormalizedEdit = exports.Violation = exports.ResolvedRuleConfig = exports.ResolvedConfig = void 0;
|
|
4
|
+
var config_1 = require("@webpieces/config");
|
|
5
|
+
Object.defineProperty(exports, "ResolvedConfig", { enumerable: true, get: function () { return config_1.ResolvedConfig; } });
|
|
6
|
+
Object.defineProperty(exports, "ResolvedRuleConfig", { enumerable: true, get: function () { return config_1.ResolvedRuleConfig; } });
|
|
4
7
|
class Violation {
|
|
5
8
|
constructor(line, snippet, message) {
|
|
6
9
|
this.line = line;
|
|
@@ -72,19 +75,4 @@ class BlockedResult {
|
|
|
72
75
|
}
|
|
73
76
|
}
|
|
74
77
|
exports.BlockedResult = BlockedResult;
|
|
75
|
-
class ResolvedConfig {
|
|
76
|
-
constructor(rules, rulesDir, configPath) {
|
|
77
|
-
this.rules = rules;
|
|
78
|
-
this.rulesDir = rulesDir;
|
|
79
|
-
this.configPath = configPath;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
exports.ResolvedConfig = ResolvedConfig;
|
|
83
|
-
class ResolvedRuleConfig {
|
|
84
|
-
constructor(enabled, options) {
|
|
85
|
-
this.enabled = enabled;
|
|
86
|
-
this.options = options;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
exports.ResolvedRuleConfig = ResolvedRuleConfig;
|
|
90
78
|
//# sourceMappingURL=types.js.map
|
package/src/core/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hooks/src/core/types.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../packages/tooling/ai-hooks/src/core/types.ts"],"names":[],"mappings":"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","sourcesContent":["// ResolvedConfig / ResolvedRuleConfig / RuleOptions now live in @webpieces/config\n// so ai-hooks and the Nx validate-code executor share one loader and one config file.\nimport { RuleOptions } from '@webpieces/config';\nexport { ResolvedConfig, ResolvedRuleConfig, RuleOptions } from '@webpieces/config';\n\nexport type ToolKind = 'Write' | 'Edit' | 'MultiEdit';\nexport type RuleScope = 'edit' | 'file';\nexport type IsLineDisabled = (lineNum: number, ruleName: string) => boolean;\n\nexport class Violation {\n readonly line: number;\n readonly snippet: string;\n readonly message: string;\n editIndex: number | undefined;\n editCount: number | undefined;\n\n constructor(line: number, snippet: string, message: string) {\n this.line = line;\n this.snippet = snippet;\n this.message = message;\n this.editIndex = undefined;\n this.editCount = undefined;\n }\n}\n\nexport class NormalizedEdit {\n readonly oldString: string;\n readonly newString: string;\n\n constructor(oldString: string, newString: string) {\n this.oldString = oldString;\n this.newString = newString;\n }\n}\n\nexport class NormalizedToolInput {\n readonly filePath: string;\n readonly edits: readonly NormalizedEdit[];\n\n constructor(filePath: string, edits: readonly NormalizedEdit[]) {\n this.filePath = filePath;\n this.edits = edits;\n }\n}\n\nexport class EditContext {\n readonly tool: ToolKind;\n readonly editIndex: number;\n readonly editCount: number;\n readonly filePath: string;\n readonly relativePath: string;\n readonly workspaceRoot: string;\n readonly addedContent: string;\n readonly strippedContent: string;\n readonly lines: readonly string[];\n readonly strippedLines: readonly string[];\n readonly removedContent: string;\n readonly isLineDisabled: IsLineDisabled;\n options: RuleOptions;\n\n constructor(\n tool: ToolKind,\n editIndex: number,\n editCount: number,\n filePath: string,\n relativePath: string,\n workspaceRoot: string,\n addedContent: string,\n strippedContent: string,\n lines: readonly string[],\n strippedLines: readonly string[],\n removedContent: string,\n isLineDisabled: IsLineDisabled,\n ) {\n this.tool = tool;\n this.editIndex = editIndex;\n this.editCount = editCount;\n this.filePath = filePath;\n this.relativePath = relativePath;\n this.workspaceRoot = workspaceRoot;\n this.addedContent = addedContent;\n this.strippedContent = strippedContent;\n this.lines = lines;\n this.strippedLines = strippedLines;\n this.removedContent = removedContent;\n this.isLineDisabled = isLineDisabled;\n this.options = {};\n }\n}\n\nexport class FileContext {\n readonly tool: ToolKind;\n readonly filePath: string;\n readonly relativePath: string;\n readonly workspaceRoot: string;\n readonly currentFileLines: number;\n readonly linesAdded: number;\n readonly linesRemoved: number;\n readonly projectedFileLines: number;\n options: RuleOptions;\n\n constructor(\n tool: ToolKind,\n filePath: string,\n relativePath: string,\n workspaceRoot: string,\n currentFileLines: number,\n linesAdded: number,\n linesRemoved: number,\n projectedFileLines: number,\n ) {\n this.tool = tool;\n this.filePath = filePath;\n this.relativePath = relativePath;\n this.workspaceRoot = workspaceRoot;\n this.currentFileLines = currentFileLines;\n this.linesAdded = linesAdded;\n this.linesRemoved = linesRemoved;\n this.projectedFileLines = projectedFileLines;\n this.options = {};\n }\n}\n\ninterface RuleBase {\n readonly name: string;\n readonly description: string;\n readonly files: readonly string[];\n readonly defaultOptions: RuleOptions;\n readonly fixHint: readonly string[];\n}\n\nexport interface EditRule extends RuleBase {\n readonly scope: 'edit';\n check(ctx: EditContext): readonly Violation[];\n}\n\nexport interface FileRule extends RuleBase {\n readonly scope: 'file';\n check(ctx: FileContext): readonly Violation[];\n}\n\nexport type Rule = EditRule | FileRule;\n\nexport class RuleGroup {\n readonly ruleName: string;\n readonly ruleDescription: string;\n readonly fixHint: readonly string[];\n readonly violations: readonly Violation[];\n\n constructor(\n ruleName: string,\n ruleDescription: string,\n fixHint: readonly string[],\n violations: readonly Violation[],\n ) {\n this.ruleName = ruleName;\n this.ruleDescription = ruleDescription;\n this.fixHint = fixHint;\n this.violations = violations;\n }\n}\n\nexport class BlockedResult {\n readonly report: string;\n\n constructor(report: string) {\n this.report = report;\n }\n}\n\n"]}
|