@shrkcrft/rules 0.1.0-alpha.21 → 0.1.0-alpha.22

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/dist/index.d.ts CHANGED
@@ -2,4 +2,5 @@ export * from './rule.js';
2
2
  export * from './rule-query.js';
3
3
  export * from './rule-formatter.js';
4
4
  export * from './rule-service.js';
5
+ export * from './rule-applicability.js';
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,yBAAyB,CAAC"}
package/dist/index.js CHANGED
@@ -2,3 +2,4 @@ export * from "./rule.js";
2
2
  export * from "./rule-query.js";
3
3
  export * from "./rule-formatter.js";
4
4
  export * from "./rule-service.js";
5
+ export * from "./rule-applicability.js";
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Heuristic file matchers for knowledge-model rules.
3
+ *
4
+ * Rules in the knowledge model don't carry path patterns directly the way
5
+ * boundary rules do. Consumers that need "which files does this rule apply
6
+ * to?" derive it from two sources, in order:
7
+ *
8
+ * 1. **Explicit**: `rule.metadata.appliesTo` — an array of glob patterns.
9
+ * Authoritative when present.
10
+ * 2. **Tag-based heuristics**: well-known tags map to file patterns. For
11
+ * example a rule tagged `mcp` likely applies to files under
12
+ * `packages/mcp-server/**`. The map is intentionally conservative — when
13
+ * no tag matches, the rule is *not* matched (better silent than noisy).
14
+ *
15
+ * Authors who want predictable matching set `metadata.appliesTo`.
16
+ *
17
+ * This lives in `@shrkcrft/rules` (a low layer) so BOTH the rule-graph bridge
18
+ * (`shrk rule-graph for <file>`) and the inspector's `shrk why <file>` share a
19
+ * single source of truth — otherwise the two surfaces drift on which rules
20
+ * apply to a file.
21
+ */
22
+ export interface IRuleApplicability {
23
+ /** Glob patterns to match against file paths. */
24
+ patterns: readonly string[];
25
+ /**
26
+ * When non-empty, the rule applies to every file whose `tags` array
27
+ * intersects this set. Currently used by `testing`-tagged rules.
28
+ */
29
+ fileTags: readonly string[];
30
+ /** How we derived the applicability — useful for diagnostics. */
31
+ source: 'metadata' | 'tags' | 'none';
32
+ }
33
+ export declare function deriveApplicability(rule: {
34
+ tags?: readonly string[];
35
+ metadata?: Readonly<Record<string, unknown>>;
36
+ }): IRuleApplicability;
37
+ //# sourceMappingURL=rule-applicability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-applicability.d.ts","sourceRoot":"","sources":["../src/rule-applicability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAyBH,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B;;;OAGG;IACH,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,iEAAiE;IACjE,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;CACtC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACxC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC9C,GAAG,kBAAkB,CAwBrB"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Heuristic file matchers for knowledge-model rules.
3
+ *
4
+ * Rules in the knowledge model don't carry path patterns directly the way
5
+ * boundary rules do. Consumers that need "which files does this rule apply
6
+ * to?" derive it from two sources, in order:
7
+ *
8
+ * 1. **Explicit**: `rule.metadata.appliesTo` — an array of glob patterns.
9
+ * Authoritative when present.
10
+ * 2. **Tag-based heuristics**: well-known tags map to file patterns. For
11
+ * example a rule tagged `mcp` likely applies to files under
12
+ * `packages/mcp-server/**`. The map is intentionally conservative — when
13
+ * no tag matches, the rule is *not* matched (better silent than noisy).
14
+ *
15
+ * Authors who want predictable matching set `metadata.appliesTo`.
16
+ *
17
+ * This lives in `@shrkcrft/rules` (a low layer) so BOTH the rule-graph bridge
18
+ * (`shrk rule-graph for <file>`) and the inspector's `shrk why <file>` share a
19
+ * single source of truth — otherwise the two surfaces drift on which rules
20
+ * apply to a file.
21
+ */
22
+ const TAG_PATTERNS = new Map([
23
+ // Engine packages.
24
+ ['mcp', ['packages/mcp-server/**']],
25
+ ['cli', ['packages/cli/**']],
26
+ ['dashboard', ['packages/dashboard/**', 'packages/dashboard-api/**']],
27
+ ['generator', ['packages/generator/**']],
28
+ ['importer', ['packages/importer/**']],
29
+ ['inspector', ['packages/inspector/**']],
30
+ ['packs', ['packages/packs/**']],
31
+ ['core', ['packages/core/**']],
32
+ // Asset categories.
33
+ ['boundaries', ['sharkcraft/boundaries.ts', 'packages/boundaries/**']],
34
+ ['rules', ['sharkcraft/rules.ts', 'packages/rules/**']],
35
+ ['paths', ['sharkcraft/paths.ts', 'packages/paths/**']],
36
+ ['templates', ['sharkcraft/templates.ts', 'packages/templates/**']],
37
+ ['pipelines', ['sharkcraft/pipelines.ts', 'packages/pipelines/**']],
38
+ ['presets', ['sharkcraft/presets.ts', 'packages/presets/**']],
39
+ // Cross-cutting concerns.
40
+ ['imports', ['packages/**/*.ts']],
41
+ ['testing', []], // signal-only; consumers attach via the file's `tags: test` separately
42
+ ['tests', []],
43
+ ]);
44
+ export function deriveApplicability(rule) {
45
+ const explicit = rule.metadata?.['appliesTo'];
46
+ if (Array.isArray(explicit) && explicit.every((p) => typeof p === 'string')) {
47
+ return { patterns: explicit, fileTags: [], source: 'metadata' };
48
+ }
49
+ const tags = rule.tags ?? [];
50
+ const patterns = [];
51
+ const fileTags = [];
52
+ for (const tag of tags) {
53
+ if (tag === 'testing' || tag === 'tests') {
54
+ fileTags.push('test');
55
+ continue;
56
+ }
57
+ const mapped = TAG_PATTERNS.get(tag);
58
+ if (mapped) {
59
+ for (const p of mapped) {
60
+ if (!patterns.includes(p))
61
+ patterns.push(p);
62
+ }
63
+ }
64
+ }
65
+ if (patterns.length === 0 && fileTags.length === 0) {
66
+ return { patterns: [], fileTags: [], source: 'none' };
67
+ }
68
+ return { patterns, fileTags, source: 'tags' };
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shrkcrft/rules",
3
- "version": "0.1.0-alpha.21",
3
+ "version": "0.1.0-alpha.22",
4
4
  "description": "SharkCraft rules service: typed rule entries, relevance lookup, AI formatting.",
5
5
  "license": "MIT",
6
6
  "author": "SharkCraft contributors",
@@ -43,8 +43,8 @@
43
43
  "typecheck": "tsc --noEmit -p tsconfig.json"
44
44
  },
45
45
  "dependencies": {
46
- "@shrkcrft/core": "^0.1.0-alpha.21",
47
- "@shrkcrft/knowledge": "^0.1.0-alpha.21"
46
+ "@shrkcrft/core": "^0.1.0-alpha.22",
47
+ "@shrkcrft/knowledge": "^0.1.0-alpha.22"
48
48
  },
49
49
  "publishConfig": {
50
50
  "access": "public"