@fragments-sdk/classifier 0.2.0

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.
Files changed (51) hide show
  1. package/LICENSE +84 -0
  2. package/dist/index.d.ts +184 -0
  3. package/dist/index.js +1856 -0
  4. package/dist/index.js.map +1 -0
  5. package/package.json +45 -0
  6. package/src/__tests__/combiner.test.ts +222 -0
  7. package/src/__tests__/fixtures.ts +96 -0
  8. package/src/ai/__tests__/cache-key.test.ts +50 -0
  9. package/src/ai/__tests__/prompt.test.ts +95 -0
  10. package/src/ai/__tests__/schema.test.ts +145 -0
  11. package/src/ai/__tests__/secret-scrub.test.ts +70 -0
  12. package/src/ai/__tests__/signal.test.ts +94 -0
  13. package/src/ai/cache-key.ts +46 -0
  14. package/src/ai/index.ts +42 -0
  15. package/src/ai/prompt.ts +154 -0
  16. package/src/ai/schema.ts +148 -0
  17. package/src/ai/secret-scrub.ts +116 -0
  18. package/src/ai/signal.ts +81 -0
  19. package/src/ai/version.ts +15 -0
  20. package/src/canonical-vocab/resolve-by-html-element.ts +72 -0
  21. package/src/combiner/__tests__/band.test.ts +155 -0
  22. package/src/combiner/__tests__/group.test.ts +85 -0
  23. package/src/combiner/__tests__/rank.test.ts +54 -0
  24. package/src/combiner/band.ts +85 -0
  25. package/src/combiner/group.ts +62 -0
  26. package/src/combiner/rank.ts +57 -0
  27. package/src/combiner.ts +124 -0
  28. package/src/index.ts +76 -0
  29. package/src/signals/__tests__/aria-role.test.ts +53 -0
  30. package/src/signals/__tests__/barrel-export.test.ts +29 -0
  31. package/src/signals/__tests__/html-root.test.ts +55 -0
  32. package/src/signals/__tests__/input-type.test.ts +58 -0
  33. package/src/signals/__tests__/library-reexport.test.ts +68 -0
  34. package/src/signals/__tests__/name-match.test.ts +43 -0
  35. package/src/signals/__tests__/path-hint.test.ts +55 -0
  36. package/src/signals/__tests__/prop-fingerprint.test.ts +105 -0
  37. package/src/signals/__tests__/registry.test.ts +27 -0
  38. package/src/signals/aria-role.ts +94 -0
  39. package/src/signals/barrel-export.ts +28 -0
  40. package/src/signals/html-root.ts +85 -0
  41. package/src/signals/index.ts +39 -0
  42. package/src/signals/input-type.ts +63 -0
  43. package/src/signals/library-reexport.ts +70 -0
  44. package/src/signals/name-match.ts +92 -0
  45. package/src/signals/path-hint.ts +94 -0
  46. package/src/signals/prop-fingerprint.ts +121 -0
  47. package/src/types.ts +58 -0
  48. package/src/vocabulary/canonicals.ts +106 -0
  49. package/src/vocabulary/library-map.ts +301 -0
  50. package/src/vocabulary/prop-fingerprints.ts +433 -0
  51. package/src/vocabulary/synonyms.ts +130 -0
package/LICENSE ADDED
@@ -0,0 +1,84 @@
1
+ Functional Source License, Version 1.1, MIT Future License
2
+
3
+ Licensor: Conan McNicholl
4
+ Software: Fragments SDK (@fragments-sdk/cli, @fragments-sdk/mcp, @fragments-sdk/context)
5
+
6
+ IMPORTANT: The @fragments-sdk/ui package is licensed separately under the MIT License.
7
+ See libs/ui/LICENSE for details.
8
+
9
+ ---
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The individual or entity listed above.
16
+
17
+ ### The Software
18
+
19
+ The software identified above, including all source code, object code,
20
+ documentation, and other files provided by the Licensor.
21
+
22
+ ### Grant of Rights
23
+
24
+ Subject to the conditions below, the Licensor grants you a non-exclusive,
25
+ worldwide, royalty-free license to use, copy, modify, create derivative works,
26
+ and redistribute the Software, in each case subject to the limitations below.
27
+
28
+ ### Limitation — Competing Use
29
+
30
+ You may not use the Software in, or to provide, a Commercial Product or Service
31
+ that competes with the Software or with any product or service that the Licensor
32
+ provides using the Software. A "Commercial Product or Service" is any product or
33
+ service offered to third parties for a fee or other consideration.
34
+
35
+ For clarity, the following uses are always permitted regardless of this limitation:
36
+
37
+ - Using the Software for your own internal business purposes
38
+ - Using the Software to build and deploy your own applications
39
+ - Using the Software for personal, educational, or evaluation purposes
40
+ - Providing professional services (consulting, integration) to your clients
41
+ that involve configuring or extending the Software
42
+
43
+ The following are examples of Competing Use that are NOT permitted:
44
+
45
+ - Offering a hosted developer tools service that repackages or exposes
46
+ the functionality of the Software
47
+ - Selling or distributing a product that is a substitute for any product
48
+ or service offered by the Licensor
49
+ - Building and offering an MCP server, CLI tool, or code intelligence
50
+ platform that is substantially derived from the Software
51
+
52
+ ### Change Date and License
53
+
54
+ On the second anniversary of each version's release date, the Licensor grants
55
+ you the rights under the terms of the MIT License for that version.
56
+ The "MIT License" means the license identified by SPDX as "MIT" and published
57
+ at https://opensource.org/licenses/MIT.
58
+
59
+ ### No Warranties
60
+
61
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
64
+
65
+ ### Limitation of Liability
66
+
67
+ IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
68
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
69
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
70
+ THE SOFTWARE.
71
+
72
+ ### General
73
+
74
+ If any provision of this License is held to be unenforceable, that provision
75
+ shall be reformed only to the extent necessary to make it enforceable, and the
76
+ remaining provisions shall continue in full force and effect.
77
+
78
+ This License does not grant permission to use the trade names, trademarks,
79
+ service marks, or product names of the Licensor, except as required for
80
+ reasonable and customary use in describing the origin of the Software.
81
+
82
+ ---
83
+
84
+ For more information about the Functional Source License, see https://fsl.software/
@@ -0,0 +1,184 @@
1
+ import { UniversalComponentFact } from '@fragments-sdk/extract';
2
+
3
+ type CanonicalId = string & {
4
+ readonly __brand: 'CanonicalId';
5
+ };
6
+ declare function canonicalId(value: string): CanonicalId;
7
+ type SignalType = 'LIBRARY_REEXPORT' | 'HTML_ROOT' | 'ARIA_ROLE' | 'INPUT_TYPE' | 'PROP_FINGERPRINT' | 'NAME_MATCH' | 'PATH_HINT' | 'BARREL_EXPORT' | 'AI_SEMANTIC';
8
+ type HeuristicSignalType = Exclude<SignalType, 'AI_SEMANTIC'>;
9
+ interface SignalRecord {
10
+ type: SignalType;
11
+ canonical: CanonicalId;
12
+ weight: number;
13
+ evidence: Record<string, unknown>;
14
+ }
15
+ type SignalExtractor = (ucf: UniversalComponentFact) => SignalRecord[];
16
+ type SignalRegistry = Record<HeuristicSignalType, SignalExtractor>;
17
+ type Band = 'auto' | 'suggested' | 'possible' | 'unknown';
18
+ interface ClassificationAlternate {
19
+ canonical: CanonicalId;
20
+ confidence: number;
21
+ signals: SignalRecord[];
22
+ }
23
+ interface Classification {
24
+ canonical: CanonicalId | 'unknown';
25
+ confidence: number;
26
+ rawConfidence: number;
27
+ band: Band;
28
+ signals: SignalRecord[];
29
+ alternates: ClassificationAlternate[];
30
+ classifierVersion: string;
31
+ vocabVersion: string;
32
+ }
33
+
34
+ interface CombineMeta {
35
+ classifierVersion: string;
36
+ vocabVersion: string;
37
+ }
38
+ declare function combine(signals: SignalRecord[], meta: CombineMeta): Classification;
39
+
40
+ declare const HEURISTIC_SIGNALS: SignalRegistry;
41
+
42
+ type CanonicalCategory = 'inputs' | 'overlays' | 'navigation' | 'feedback' | 'data' | 'layout';
43
+ interface CanonicalEntry {
44
+ id: CanonicalId;
45
+ category: CanonicalCategory;
46
+ primaryHtmlElement?: string;
47
+ primaryAriaRole?: string;
48
+ }
49
+ declare const VOCAB_V0_VERSION = "vocab_v0";
50
+ declare const VOCAB_V0: ReadonlyArray<CanonicalEntry>;
51
+ declare const VOCAB_V0_INDEX: ReadonlyMap<string, CanonicalEntry>;
52
+ declare function isCanonicalId(value: string): value is CanonicalId;
53
+
54
+ interface LibraryMapEntry {
55
+ canonical: CanonicalId;
56
+ }
57
+ type LibraryMap = ReadonlyMap<string, ReadonlyMap<string, LibraryMapEntry>>;
58
+ declare const LIBRARY_MAP: LibraryMap;
59
+ declare function lookupLibraryImport(pkg: string, importedName: string): CanonicalId | undefined;
60
+
61
+ declare const NAME_STRIP_PREFIXES: ReadonlyArray<string>;
62
+ declare const NAME_STRIP_SUFFIXES: ReadonlyArray<string>;
63
+ declare const NAME_VARIANT_SUFFIXES: ReadonlyArray<string>;
64
+ declare const SYNONYMS: ReadonlyMap<CanonicalId, ReadonlyArray<string>>;
65
+ declare function lookupSynonym(name: string): ReadonlyArray<CanonicalId>;
66
+
67
+ type TypeMatcher = (typeText: string) => boolean;
68
+ interface RequiredPropTest {
69
+ oneOf: ReadonlyArray<{
70
+ name: string;
71
+ typeMatcher?: TypeMatcher;
72
+ }>;
73
+ }
74
+ interface OptionalPropTest {
75
+ name: string;
76
+ typeMatcher?: TypeMatcher;
77
+ }
78
+ interface AntiPropTest {
79
+ name: string;
80
+ typeMatcher?: TypeMatcher;
81
+ }
82
+ interface PropFingerprint {
83
+ required: ReadonlyArray<RequiredPropTest>;
84
+ optional: ReadonlyArray<OptionalPropTest>;
85
+ anti: ReadonlyArray<AntiPropTest>;
86
+ }
87
+ declare const PROP_FINGERPRINTS: ReadonlyMap<CanonicalId, PropFingerprint>;
88
+ declare const POLYMORPHIC_PROP_NAMES: ReadonlySet<string>;
89
+
90
+ /**
91
+ * Tag → canonical resolver shared by:
92
+ * - `swap_to_canonical` MCP tool (`packages/mcp/src/tools/swap-to-canonical.ts`)
93
+ * - PR-review advisor (`apps/cloud/src/lib/pr-advisor/cluster-by-file.ts`)
94
+ *
95
+ * Both surfaces must produce identical canonical resolutions for the same
96
+ * input — kept in one module so a tag added in one place is automatically
97
+ * available to the other.
98
+ *
99
+ * Generic containers (`div`, `span`, `form`, `label`) are intentionally
100
+ * absent: a swap suggestion for layout markup would drown the user in
101
+ * noise, since every codebase uses layout primitives liberally.
102
+ */
103
+ interface RawAttrLike {
104
+ value: string;
105
+ dynamic: boolean;
106
+ }
107
+ type RawAttrMap = Map<string, RawAttrLike>;
108
+ declare function resolveCanonicalForHtmlElement(tagName: string, attrs: RawAttrMap): string | null;
109
+ /** Render a raw element to a short label (`<button>` / `<input type="checkbox">`). */
110
+ declare function formatRawHtmlElement(tagName: string, attrs: RawAttrMap): string;
111
+
112
+ declare const AI_PROMPT_VERSION = "aiprompt_v1";
113
+ declare const AI_REASONING_CHAR_CAP = 200;
114
+ declare const AI_SIGNAL_WEIGHTS: {
115
+ readonly high: 0.4;
116
+ readonly medium: 0.25;
117
+ readonly low: 0.1;
118
+ };
119
+
120
+ interface SecretScrubResult {
121
+ text: string;
122
+ redactionCount: number;
123
+ redactionsByType: Record<string, number>;
124
+ }
125
+ declare function scrubSecrets(input: string): SecretScrubResult;
126
+ declare function sanitizeForInjection(input: string): string;
127
+
128
+ interface PromptInputs {
129
+ ucf: UniversalComponentFact;
130
+ source: string;
131
+ callSites: ReadonlyArray<string>;
132
+ vocabulary: ReadonlyArray<VocabularyPromptEntry>;
133
+ }
134
+ interface VocabularyPromptEntry {
135
+ id: string;
136
+ category: CanonicalEntry['category'];
137
+ definition: string;
138
+ }
139
+ interface BuiltPrompt {
140
+ system: string;
141
+ user: string;
142
+ }
143
+ declare function buildAiPrompt(inputs: PromptInputs): BuiltPrompt;
144
+ declare function truncateSource(input: string, maxLines?: number): string;
145
+
146
+ type AiConfidence = 'high' | 'medium' | 'low' | 'unknown';
147
+ interface AiResponseAlternate {
148
+ canonical: string;
149
+ reason: string;
150
+ }
151
+ interface AiResponse {
152
+ canonical: string;
153
+ confidence: AiConfidence;
154
+ reasoning: string;
155
+ alternates: AiResponseAlternate[];
156
+ }
157
+ type AiParseResult = {
158
+ ok: true;
159
+ value: AiResponse;
160
+ } | {
161
+ ok: false;
162
+ reason: string;
163
+ };
164
+ declare function parseAiResponse(raw: string): AiParseResult;
165
+ declare function applyVocabWhitelist(response: AiResponse, allowedCanonicals: ReadonlySet<string>): AiResponse;
166
+
167
+ interface AiSignalInputs {
168
+ response: AiResponse;
169
+ allowedCanonicals: ReadonlySet<string>;
170
+ modelId: string;
171
+ promptVersion: string;
172
+ }
173
+ declare function aiResponseToSignals(inputs: AiSignalInputs): SignalRecord[];
174
+
175
+ interface CacheKeyInputs {
176
+ ucfId: string;
177
+ sourceTextHash: string;
178
+ promptVersion: string;
179
+ modelId: string;
180
+ }
181
+ declare function deriveAiCacheKey(inputs: CacheKeyInputs): string;
182
+ declare function hashSourceText(input: string): string;
183
+
184
+ export { AI_PROMPT_VERSION, AI_REASONING_CHAR_CAP, AI_SIGNAL_WEIGHTS, type AiConfidence, type AiParseResult, type AiResponse, type AiResponseAlternate, type AiSignalInputs, type Band, type BuiltPrompt, type CacheKeyInputs, type CanonicalCategory, type CanonicalEntry, type CanonicalId, type Classification, type ClassificationAlternate, type CombineMeta, HEURISTIC_SIGNALS, type HeuristicSignalType, LIBRARY_MAP, NAME_STRIP_PREFIXES, NAME_STRIP_SUFFIXES, NAME_VARIANT_SUFFIXES, POLYMORPHIC_PROP_NAMES, PROP_FINGERPRINTS, type PromptInputs, type PropFingerprint, type RawAttrLike, type RawAttrMap, SYNONYMS, type SecretScrubResult, type SignalExtractor, type SignalRecord, type SignalRegistry, type SignalType, VOCAB_V0, VOCAB_V0_INDEX, VOCAB_V0_VERSION, type VocabularyPromptEntry, aiResponseToSignals, applyVocabWhitelist, buildAiPrompt, canonicalId, combine, deriveAiCacheKey, formatRawHtmlElement, hashSourceText, isCanonicalId, lookupLibraryImport, lookupSynonym, parseAiResponse, resolveCanonicalForHtmlElement, sanitizeForInjection, scrubSecrets, truncateSource };