@fenglimg/fabric-shared 1.8.0-rc.3 → 2.0.0-rc.1

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.js CHANGED
@@ -1,4 +1,3 @@
1
- import "./chunk-LXNCAKJZ.js";
2
1
  import {
3
2
  PROTECTED_TOKENS,
4
3
  createTranslator,
@@ -7,9 +6,16 @@ import {
7
6
  enMessages,
8
7
  normalizeLocale,
9
8
  zhCNMessages
10
- } from "./chunk-FEEWLYO3.js";
9
+ } from "./chunk-KHIM6MWS.js";
11
10
  import {
11
+ KNOWLEDGE_TYPE_CODES,
12
+ KnowledgeEntryFrontmatterSchema,
13
+ KnowledgeTypeSchema,
14
+ LayerSchema,
15
+ MaturitySchema,
16
+ StableIdSchema,
12
17
  annotateIntentRequestSchema,
18
+ formatKnowledgeId,
13
19
  getRulesAnnotations,
14
20
  getRulesInputSchema,
15
21
  getRulesOutputSchema,
@@ -18,6 +24,7 @@ import {
18
24
  humanLockFileParamsSchema,
19
25
  ledgerQuerySchema,
20
26
  ledgerSourceSchema,
27
+ parseKnowledgeId,
21
28
  planContextAnnotations,
22
29
  planContextInputSchema,
23
30
  planContextOutputSchema,
@@ -25,7 +32,8 @@ import {
25
32
  ruleSectionsInputSchema,
26
33
  ruleSectionsOutputSchema,
27
34
  structuredWarningSchema
28
- } from "./chunk-KV27CZH3.js";
35
+ } from "./chunk-HACPXMLL.js";
36
+ import "./chunk-LXNCAKJZ.js";
29
37
 
30
38
  // src/schemas/agents-meta.ts
31
39
  import { z } from "zod";
@@ -42,7 +50,16 @@ var ruleDescriptionSchema = z.object({
42
50
  tech_stack: z.array(z.string()),
43
51
  impact: z.array(z.string()),
44
52
  must_read_if: z.string(),
45
- entities: z.array(z.string()).optional()
53
+ entities: z.array(z.string()).optional(),
54
+ // v2.0 knowledge entry fields (TASK-002 schemas). All optional for backward compat.
55
+ id: z.string().optional(),
56
+ knowledge_type: z.enum(["model", "decision", "guideline", "pitfall", "process"]).optional(),
57
+ maturity: z.enum(["draft", "verified", "proven"]).optional(),
58
+ knowledge_layer: z.enum(["personal", "team"]).optional(),
59
+ layer_reason: z.string().optional(),
60
+ created_at: z.string().optional(),
61
+ // v2/rc.2: flat flow-style YAML array; populated by init-scan from forensic tech stack and editable by user. Used by rc.3 review skill for tag-filter search.
62
+ tags: z.array(z.string()).default([]).optional()
46
63
  }).strict();
47
64
  var ruleDescriptionIndexItemSchema = z.object({
48
65
  stable_id: z.string(),
@@ -76,13 +93,33 @@ var agentsMetaNodeSchema = z.preprocess((value) => {
76
93
  }
77
94
  return withDerivedAgentsMetaNodeDefaults(value);
78
95
  }, agentsMetaNodeBaseSchema);
96
+ var knowledgeTypeCountersSchema = z.object({
97
+ MOD: z.number().int().nonnegative().default(0),
98
+ DEC: z.number().int().nonnegative().default(0),
99
+ GLD: z.number().int().nonnegative().default(0),
100
+ PIT: z.number().int().nonnegative().default(0),
101
+ PRO: z.number().int().nonnegative().default(0)
102
+ }).default({ MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 });
103
+ var AgentsMetaCountersSchema = z.object({
104
+ KP: knowledgeTypeCountersSchema,
105
+ KT: knowledgeTypeCountersSchema
106
+ }).default({
107
+ KP: { MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 },
108
+ KT: { MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 }
109
+ });
79
110
  var agentsMetaSchema = z.object({
80
111
  revision: z.string(),
81
- nodes: z.record(agentsMetaNodeSchema)
112
+ nodes: z.record(agentsMetaNodeSchema),
113
+ counters: AgentsMetaCountersSchema.optional()
82
114
  });
115
+ var KNOWLEDGE_STABLE_ID_PATTERN = /^K[PT]-(MOD|DEC|GLD|PIT|PRO)-\d{4,}$/u;
116
+ function isKnowledgeStableId(stableId) {
117
+ return stableId !== void 0 && KNOWLEDGE_STABLE_ID_PATTERN.test(stableId);
118
+ }
83
119
  function withDerivedAgentsMetaNodeDefaults(node) {
120
+ const isKnowledgeEntry = isKnowledgeStableId(node.stable_id);
84
121
  const stableId = node.stable_id ?? deriveAgentsMetaStableId(node.file);
85
- const identitySource = deriveAgentsMetaIdentitySource(node);
122
+ const identitySource = isKnowledgeEntry ? "declared" : deriveAgentsMetaIdentitySource(node);
86
123
  return {
87
124
  ...node,
88
125
  layer: node.layer ?? node.level ?? deriveAgentsMetaLayer(node.file),
@@ -92,6 +129,27 @@ function withDerivedAgentsMetaNodeDefaults(node) {
92
129
  identity_source: identitySource
93
130
  };
94
131
  }
132
+ function allocateKnowledgeId(layer, type, current) {
133
+ const layerKey = layer === "personal" ? "KP" : "KT";
134
+ const typeCode = KNOWLEDGE_TYPE_CODES[type];
135
+ const previousCount = current[layerKey][typeCode] ?? 0;
136
+ const nextCount = previousCount + 1;
137
+ const id = formatKnowledgeId(layer, type, nextCount);
138
+ const nextCounters = {
139
+ ...current,
140
+ [layerKey]: {
141
+ ...current[layerKey],
142
+ [typeCode]: nextCount
143
+ }
144
+ };
145
+ return { id, nextCounters };
146
+ }
147
+ function defaultAgentsMetaCounters() {
148
+ return {
149
+ KP: { MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 },
150
+ KT: { MOD: 0, DEC: 0, GLD: 0, PIT: 0, PRO: 0 }
151
+ };
152
+ }
95
153
  function deriveAgentsMetaStableId(file) {
96
154
  const normalized = normalizePath(file);
97
155
  if (normalized === "AGENTS.md" || normalized === ".fabric/bootstrap/README.md") {
@@ -103,6 +161,9 @@ function deriveAgentsMetaIdentitySource(node) {
103
161
  if (node.identity_source !== void 0) {
104
162
  return node.identity_source;
105
163
  }
164
+ if (isKnowledgeStableId(node.stable_id)) {
165
+ return "declared";
166
+ }
106
167
  const derivedStableId = deriveAgentsMetaStableId(node.file);
107
168
  return node.stable_id !== void 0 && node.stable_id !== derivedStableId ? "declared" : "derived";
108
169
  }
@@ -226,7 +287,7 @@ var clientPathsSchema = z5.object({
226
287
  claudeCodeDesktop: z5.string().optional(),
227
288
  cursor: z5.string().optional(),
228
289
  codexCLI: z5.string().optional()
229
- }).passthrough();
290
+ }).strict();
230
291
  var mcpPayloadLimitsSchema = z5.object({
231
292
  warnBytes: z5.number().int().positive().optional(),
232
293
  hardBytes: z5.number().int().positive().optional()
@@ -408,9 +469,9 @@ var eventLedgerEnvelopeSchema = {
408
469
  session_id: z9.string().optional()
409
470
  };
410
471
  var stringRecordSchema = z9.record(z9.string());
411
- var ruleContextPlannedEventSchema = z9.object({
472
+ var knowledgeContextPlannedEventSchema = z9.object({
412
473
  ...eventLedgerEnvelopeSchema,
413
- event_type: z9.literal("rule_context_planned"),
474
+ event_type: z9.literal("knowledge_context_planned"),
414
475
  target_paths: z9.array(z9.string()),
415
476
  required_stable_ids: z9.array(z9.string()),
416
477
  ai_selectable_stable_ids: z9.array(z9.string()),
@@ -421,9 +482,9 @@ var ruleContextPlannedEventSchema = z9.object({
421
482
  known_tech: z9.array(z9.string()).optional(),
422
483
  diagnostics: z9.array(z9.unknown()).optional()
423
484
  });
424
- var ruleSelectionEventSchema = z9.object({
485
+ var knowledgeSelectionEventSchema = z9.object({
425
486
  ...eventLedgerEnvelopeSchema,
426
- event_type: z9.literal("rule_selection"),
487
+ event_type: z9.literal("knowledge_selection"),
427
488
  selection_token: z9.string(),
428
489
  target_paths: z9.array(z9.string()),
429
490
  required_stable_ids: z9.array(z9.string()),
@@ -434,9 +495,9 @@ var ruleSelectionEventSchema = z9.object({
434
495
  rejected_stable_ids: z9.array(z9.string()),
435
496
  ignored_stable_ids: z9.array(z9.string())
436
497
  });
437
- var ruleSectionsFetchedEventSchema = z9.object({
498
+ var knowledgeSectionsFetchedEventSchema = z9.object({
438
499
  ...eventLedgerEnvelopeSchema,
439
- event_type: z9.literal("rule_sections_fetched"),
500
+ event_type: z9.literal("knowledge_sections_fetched"),
440
501
  selection_token: z9.string(),
441
502
  target_paths: z9.array(z9.string()).optional(),
442
503
  requested_sections: z9.array(z9.string()),
@@ -460,9 +521,9 @@ var editIntentCheckedEventSchema = z9.object({
460
521
  matched_rule_context_ts: z9.number().int().nonnegative().nullable(),
461
522
  window_ms: z9.number().int().nonnegative()
462
523
  });
463
- var ruleDriftDetectedEventSchema = z9.object({
524
+ var knowledgeDriftDetectedEventSchema = z9.object({
464
525
  ...eventLedgerEnvelopeSchema,
465
- event_type: z9.literal("rule_drift_detected"),
526
+ event_type: z9.literal("knowledge_drift_detected"),
466
527
  revision: z9.string().optional(),
467
528
  drifted_stable_ids: z9.array(z9.string()),
468
529
  missing_files: z9.array(z9.string()),
@@ -476,23 +537,6 @@ var ruleDriftDetectedEventSchema = z9.object({
476
537
  })
477
538
  ).optional()
478
539
  });
479
- var ruleBaselineAcceptedEventSchema = z9.object({
480
- ...eventLedgerEnvelopeSchema,
481
- event_type: z9.literal("rule_baseline_accepted"),
482
- revision: z9.string(),
483
- previous_revision: z9.string().optional(),
484
- accepted_stable_ids: z9.array(z9.string()),
485
- source: z9.enum(["doctor_fix", "sync_meta"]).optional()
486
- });
487
- var baselineSyncedEventSchema = z9.object({
488
- ...eventLedgerEnvelopeSchema,
489
- event_type: z9.literal("baseline_synced"),
490
- revision: z9.string(),
491
- previous_revision: z9.string().optional(),
492
- synced_files: z9.array(z9.string()),
493
- accepted_stable_ids: z9.array(z9.string()),
494
- source: z9.enum(["doctor_fix", "sync_meta"])
495
- });
496
540
  var mcpEventLedgerEventSchema = z9.object({
497
541
  ...eventLedgerEnvelopeSchema,
498
542
  event_type: z9.literal("mcp_event"),
@@ -553,19 +597,19 @@ var codexSkillPathMigratedEventSchema = z9.object({
553
597
  from: z9.string(),
554
598
  to: z9.string()
555
599
  });
556
- var legacyClientPathPresentEventSchema = z9.object({
600
+ var initScanCompletedEventSchema = z9.object({
557
601
  ...eventLedgerEnvelopeSchema,
558
- event_type: z9.literal("legacy_client_path_present"),
559
- removed: z9.array(z9.string())
602
+ event_type: z9.literal("init_scan_completed"),
603
+ written_stable_ids: z9.array(z9.string()),
604
+ duration_ms: z9.number().int().nonnegative(),
605
+ source: z9.enum(["init", "scan", "doctor_fix"]).optional()
560
606
  });
561
607
  var eventLedgerEventSchema = z9.discriminatedUnion("event_type", [
562
- ruleContextPlannedEventSchema,
563
- ruleSelectionEventSchema,
564
- ruleSectionsFetchedEventSchema,
608
+ knowledgeContextPlannedEventSchema,
609
+ knowledgeSelectionEventSchema,
610
+ knowledgeSectionsFetchedEventSchema,
565
611
  editIntentCheckedEventSchema,
566
- ruleDriftDetectedEventSchema,
567
- ruleBaselineAcceptedEventSchema,
568
- baselineSyncedEventSchema,
612
+ knowledgeDriftDetectedEventSchema,
569
613
  mcpEventLedgerEventSchema,
570
614
  reapplyCompletedEventSchema,
571
615
  eventLedgerTruncatedEventSchema,
@@ -575,29 +619,37 @@ var eventLedgerEventSchema = z9.discriminatedUnion("event_type", [
575
619
  claudeSkillPathMigratedEventSchema,
576
620
  claudeHookPathMigratedEventSchema,
577
621
  codexSkillPathMigratedEventSchema,
578
- legacyClientPathPresentEventSchema
622
+ initScanCompletedEventSchema
579
623
  ]);
580
624
  export {
581
625
  AGENTS_META_IDENTITY_SOURCES,
582
626
  AGENTS_META_LAYERS,
583
627
  AGENTS_META_TOPOLOGY_TYPES,
628
+ AgentsMetaCountersSchema,
629
+ KNOWLEDGE_TYPE_CODES,
630
+ KnowledgeEntryFrontmatterSchema,
631
+ KnowledgeTypeSchema,
632
+ LayerSchema,
633
+ MaturitySchema,
584
634
  PROTECTED_TOKENS,
585
635
  RULE_TEST_INDEX_SCHEMA_VERSION,
636
+ StableIdSchema,
586
637
  agentsIdentitySourceSchema,
587
638
  agentsLayerSchema,
588
639
  agentsMetaNodeSchema,
589
640
  agentsMetaSchema,
590
641
  agentsTopologyTypeSchema,
591
642
  aiLedgerEntrySchema,
643
+ allocateKnowledgeId,
592
644
  annotateIntentRequestSchema,
593
645
  auditModeSchema,
594
- baselineSyncedEventSchema,
595
646
  candidateFileEntrySchema,
596
647
  claudeHookPathMigratedEventSchema,
597
648
  claudeSkillPathMigratedEventSchema,
598
649
  clientPathsSchema,
599
650
  codexSkillPathMigratedEventSchema,
600
651
  createTranslator,
652
+ defaultAgentsMetaCounters,
601
653
  defaultMessages,
602
654
  deriveAgentsMetaIdentitySource,
603
655
  deriveAgentsMetaLayer,
@@ -621,6 +673,7 @@ export {
621
673
  forensicReportSchema,
622
674
  forensicSamplingBudgetSchema,
623
675
  forensicTopologySchema,
676
+ formatKnowledgeId,
624
677
  getRulesAnnotations,
625
678
  getRulesInputSchema,
626
679
  getRulesOutputSchema,
@@ -637,11 +690,16 @@ export {
637
690
  initContextInvariantSchema,
638
691
  initContextSchema,
639
692
  initContextSourceEvidenceSchema,
693
+ initScanCompletedEventSchema,
694
+ isKnowledgeStableId,
695
+ knowledgeContextPlannedEventSchema,
696
+ knowledgeDriftDetectedEventSchema,
697
+ knowledgeSectionsFetchedEventSchema,
698
+ knowledgeSelectionEventSchema,
640
699
  ledgerAppendedEventSchema,
641
700
  ledgerEntrySchema,
642
701
  ledgerQuerySchema,
643
702
  ledgerSourceSchema,
644
- legacyClientPathPresentEventSchema,
645
703
  lockApprovedEventSchema,
646
704
  lockDriftEventSchema,
647
705
  mcpConfigMigratedEventSchema,
@@ -651,20 +709,16 @@ export {
651
709
  metaReconciledOnStartupEventSchema,
652
710
  metaUpdatedEventSchema,
653
711
  normalizeLocale,
712
+ parseKnowledgeId,
654
713
  planContextAnnotations,
655
714
  planContextInputSchema,
656
715
  planContextOutputSchema,
657
716
  reapplyCompletedEventSchema,
658
- ruleBaselineAcceptedEventSchema,
659
- ruleContextPlannedEventSchema,
660
717
  ruleDescriptionIndexItemSchema,
661
718
  ruleDescriptionSchema,
662
- ruleDriftDetectedEventSchema,
663
719
  ruleSectionsAnnotations,
664
- ruleSectionsFetchedEventSchema,
665
720
  ruleSectionsInputSchema,
666
721
  ruleSectionsOutputSchema,
667
- ruleSelectionEventSchema,
668
722
  ruleTestIndexSchema,
669
723
  ruleTestLinkSchema,
670
724
  ruleTestOrphanAnnotationSchema,
package/dist/node.js CHANGED
@@ -1,6 +1,175 @@
1
- import {
2
- detectFramework
3
- } from "./chunk-GI6L6VTT.js";
1
+ // src/detector.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ function detectFramework(root) {
5
+ const evidence = [];
6
+ const creatorConfigPath = join(root, "project.config.json");
7
+ if (existsSync(creatorConfigPath)) {
8
+ const version = readCreatorVersion(creatorConfigPath);
9
+ return {
10
+ kind: "cocos-creator",
11
+ version,
12
+ subkind: inferCocosSubkind(root, version),
13
+ evidence: version === "unknown" ? ["project.config.json"] : [`project.config.json: creator.version=${version}`],
14
+ framework: "cocos-creator",
15
+ confidence: "HIGH",
16
+ ast_evidence: [],
17
+ co_packages: collectProjectFileEvidence(root, ["package.json", "tsconfig.json"])
18
+ };
19
+ }
20
+ const packageJsonPath = join(root, "package.json");
21
+ if (existsSync(packageJsonPath)) {
22
+ const packageJson = readPackageJson(packageJsonPath);
23
+ const creatorVersion = packageJson.creator?.version;
24
+ if (typeof creatorVersion === "string" && creatorVersion.trim().length > 0) {
25
+ const deps2 = collectDependencyVersions(packageJson);
26
+ return {
27
+ kind: "cocos-creator",
28
+ version: creatorVersion,
29
+ subkind: inferCocosSubkind(root, creatorVersion),
30
+ evidence: [`package.json: creator.version=${creatorVersion}`],
31
+ framework: "cocos-creator",
32
+ confidence: "HIGH",
33
+ ast_evidence: [],
34
+ co_packages: collectCoPackages(deps2, "cocos-creator", root)
35
+ };
36
+ }
37
+ const deps = collectDependencyVersions(packageJson);
38
+ for (const [dependencyName, kind] of [
39
+ ["next", "next"],
40
+ ["vite", "vite"],
41
+ ["react", "react"],
42
+ ["vue", "vue"]
43
+ ]) {
44
+ if (deps.has(dependencyName)) {
45
+ const version = deps.get(dependencyName) ?? "unknown";
46
+ evidence.push(`package.json dependency: ${dependencyName}@${version}`);
47
+ return {
48
+ kind,
49
+ version,
50
+ subkind: inferPackageSubkind(kind),
51
+ evidence,
52
+ framework: kind,
53
+ confidence: determinePackageConfidence(kind, deps, root),
54
+ ast_evidence: [],
55
+ co_packages: collectCoPackages(deps, kind, root)
56
+ };
57
+ }
58
+ }
59
+ evidence.push("package.json");
60
+ }
61
+ if (existsSync(join(root, "Cargo.toml"))) {
62
+ return {
63
+ kind: "rust",
64
+ version: "unknown",
65
+ subkind: "cargo-project",
66
+ evidence: ["Cargo.toml"],
67
+ framework: "rust",
68
+ confidence: "HIGH",
69
+ ast_evidence: [],
70
+ co_packages: collectProjectFileEvidence(root, ["Cargo.lock"])
71
+ };
72
+ }
73
+ if (existsSync(join(root, "pyproject.toml"))) {
74
+ return {
75
+ kind: "python",
76
+ version: "unknown",
77
+ subkind: "pyproject",
78
+ evidence: ["pyproject.toml"],
79
+ framework: "python",
80
+ confidence: "HIGH",
81
+ ast_evidence: [],
82
+ co_packages: collectProjectFileEvidence(root, ["uv.lock", "poetry.lock", "requirements.txt"])
83
+ };
84
+ }
85
+ return {
86
+ kind: "unknown",
87
+ version: "unknown",
88
+ subkind: "unknown",
89
+ evidence,
90
+ framework: "unknown",
91
+ confidence: "LOW",
92
+ ast_evidence: [],
93
+ co_packages: []
94
+ };
95
+ }
96
+ function readPackageJson(packageJsonPath) {
97
+ try {
98
+ return JSON.parse(readFileSync(packageJsonPath, "utf8"));
99
+ } catch {
100
+ return {};
101
+ }
102
+ }
103
+ function readCreatorVersion(creatorConfigPath) {
104
+ try {
105
+ const creatorConfig = JSON.parse(readFileSync(creatorConfigPath, "utf8"));
106
+ return creatorConfig.creator?.version ?? "unknown";
107
+ } catch {
108
+ return "unknown";
109
+ }
110
+ }
111
+ function collectDependencyVersions(packageJson) {
112
+ return new Map([
113
+ ...Object.entries(packageJson.dependencies ?? {}),
114
+ ...Object.entries(packageJson.devDependencies ?? {}),
115
+ ...Object.entries(packageJson.peerDependencies ?? {}),
116
+ ...Object.entries(packageJson.optionalDependencies ?? {})
117
+ ]);
118
+ }
119
+ function inferCocosSubkind(root, version) {
120
+ const majorVersion = Number.parseInt(version.split(".")[0] ?? "", 10);
121
+ if (majorVersion === 2) {
122
+ return "javascript-traditional";
123
+ }
124
+ if (majorVersion >= 3) {
125
+ return "typescript-component";
126
+ }
127
+ return existsSync(join(root, "tsconfig.json")) ? "typescript-component" : "javascript-traditional";
128
+ }
129
+ function inferPackageSubkind(kind) {
130
+ switch (kind) {
131
+ case "next":
132
+ return "next-application";
133
+ case "vite":
134
+ return "vite-application";
135
+ case "react":
136
+ return "react-application";
137
+ case "vue":
138
+ return "vue-application";
139
+ default:
140
+ return "unknown";
141
+ }
142
+ }
143
+ function determinePackageConfidence(kind, deps, root) {
144
+ const coPackages = collectCoPackages(deps, kind, root);
145
+ return coPackages.length > 0 ? "HIGH" : "MEDIUM";
146
+ }
147
+ function collectCoPackages(deps, kind, root) {
148
+ const expectedPackagesByFramework = {
149
+ next: ["react", "react-dom", "typescript"],
150
+ vite: ["@vitejs/plugin-react", "@vitejs/plugin-vue", "typescript", "react", "vue"],
151
+ react: ["react-dom", "@types/react", "@types/react-dom"],
152
+ vue: ["@vitejs/plugin-vue", "typescript"],
153
+ "cocos-creator": ["typescript"]
154
+ };
155
+ const expectedProjectFilesByFramework = {
156
+ next: ["next.config.js", "next.config.mjs", "next.config.ts", "tsconfig.json"],
157
+ vite: ["vite.config.js", "vite.config.mjs", "vite.config.ts", "tsconfig.json"],
158
+ react: ["tsconfig.json"],
159
+ vue: ["vue.config.js", "vite.config.ts", "tsconfig.json"],
160
+ "cocos-creator": ["project.config.json", "tsconfig.json"]
161
+ };
162
+ return [
163
+ ...compactStrings((expectedPackagesByFramework[kind] ?? []).map((packageName) => deps.has(packageName) ? packageName : null)),
164
+ ...collectProjectFileEvidence(root, expectedProjectFilesByFramework[kind] ?? [])
165
+ ];
166
+ }
167
+ function collectProjectFileEvidence(root, relativePaths) {
168
+ return relativePaths.filter((relativePath) => existsSync(join(root, relativePath)));
169
+ }
170
+ function compactStrings(values) {
171
+ return [...new Set(values.filter((value) => value !== null && value !== void 0 && value.length > 0))];
172
+ }
4
173
  export {
5
174
  detectFramework
6
175
  };