foliko 1.1.36 → 1.1.39

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 (168) hide show
  1. package/.agent/agents/network-requester.md +44 -0
  2. package/.agent/agents/poster-designer.md +52 -0
  3. package/.agent/agents/ui-designer.md +1 -1
  4. package/.agent/data/default.json +23 -407
  5. package/.agent/data/email/processed-emails.json +1 -0
  6. package/.agent/data/plugins-state.json +103 -200
  7. package/.agent/data/scheduler/tasks.json +1 -86
  8. package/.agent/data/web/web-config.json +5 -0
  9. package/.agent/data/weixin/images/file_1776188148383jpg +0 -0
  10. package/.agent/data/weixin/images/file_1776188458326.jpg +0 -0
  11. package/.agent/data/weixin/images/file_1776188689423.jpg +0 -0
  12. package/.agent/data/weixin/images/file_1776188813604.jpg +0 -0
  13. package/.agent/data/weixin/images/file_1776189097450.jpg +0 -0
  14. package/.agent/data/weixin/videos/file_1776188318431.mp4 +0 -0
  15. package/.agent/mcp_config.json +4 -17
  16. package/.agent/memory/user/mof6gk94-kneeuh.md +9 -0
  17. package/.agent/package.json +8 -0
  18. package/.agent/plugins/marknative/README.md +134 -0
  19. package/.agent/plugins/marknative/fonts/SegoeUI Emoji.ttf +0 -0
  20. package/.agent/plugins/marknative/fonts.zip +0 -0
  21. package/.agent/plugins/marknative/index.js +256 -0
  22. package/.agent/plugins/marknative/package.json +12 -0
  23. package/.agent/plugins/test-plugin.py +99 -0
  24. package/.agent/plugins.json +11 -5
  25. package/.agent/python-scripts/test_sample.py +24 -0
  26. package/.agent/sessions/cli_default.json +2415 -349
  27. package/.agent/sessions/default.json +82 -0
  28. package/.agent/sessions/qq_c2c_D960F12877541624D7B2C836110B3D0F.json +25 -0
  29. package/.agent/sessions/test-clean.json +26 -0
  30. package/.agent/sessions/test-compress.json +1462 -0
  31. package/.agent/sessions/test-session.json +13 -0
  32. package/.agent/sessions/weixin_test.json +22 -0
  33. package/.agent/sessions/weixin_test_user_123.json +11 -0
  34. package/.agent/skills/agent-browser/SKILL.md +311 -0
  35. package/.agent/skills/agent-browser/TEST_PLAN.md +200 -0
  36. package/.agent/skills/sysinfo/SKILL.md +38 -0
  37. package/.agent/skills/sysinfo/system-info.sh +130 -0
  38. package/.agent/skills/workflow/SKILL.md +324 -0
  39. package/.agent/test-agent.js +35 -0
  40. package/.agent/weixin.json +6 -0
  41. package/.agent/workflows/email-digest.json +50 -0
  42. package/.agent/workflows/file-backup.json +21 -0
  43. package/.agent/workflows/get-ip-notify.json +32 -0
  44. package/.agent/workflows/news-aggregator.json +93 -0
  45. package/.agent/workflows/news-dashboard-v2.json +94 -0
  46. package/.agent/workflows/notification-batch.json +32 -0
  47. package/.claude/settings.local.json +2 -1
  48. package/.env.example +56 -56
  49. package/README.md +441 -441
  50. package/cli/src/utils/debounce.js +6 -3
  51. package/docs/qq-bot.md +976 -0
  52. package/package.json +3 -1
  53. package/plugins/qq-plugin.js +939 -0
  54. package/plugins/scheduler-plugin.js +17 -17
  55. package/skills/find-skills/AGENTS.md +162 -162
  56. package/skills/find-skills/SKILL.md +133 -133
  57. package/src/core/agent-chat.js +11 -6
  58. package/temp_img.md +1 -0
  59. package/website_v2/styles/animations.css +7 -7
  60. package/.agent/.shared/ui-ux-pro-max/data/charts.csv +0 -26
  61. package/.agent/.shared/ui-ux-pro-max/data/colors.csv +0 -97
  62. package/.agent/.shared/ui-ux-pro-max/data/icons.csv +0 -101
  63. package/.agent/.shared/ui-ux-pro-max/data/landing.csv +0 -31
  64. package/.agent/.shared/ui-ux-pro-max/data/products.csv +0 -97
  65. package/.agent/.shared/ui-ux-pro-max/data/prompts.csv +0 -24
  66. package/.agent/.shared/ui-ux-pro-max/data/react-performance.csv +0 -45
  67. package/.agent/.shared/ui-ux-pro-max/data/stacks/flutter.csv +0 -53
  68. package/.agent/.shared/ui-ux-pro-max/data/stacks/html-tailwind.csv +0 -56
  69. package/.agent/.shared/ui-ux-pro-max/data/stacks/jetpack-compose.csv +0 -53
  70. package/.agent/.shared/ui-ux-pro-max/data/stacks/nextjs.csv +0 -53
  71. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxt-ui.csv +0 -51
  72. package/.agent/.shared/ui-ux-pro-max/data/stacks/nuxtjs.csv +0 -59
  73. package/.agent/.shared/ui-ux-pro-max/data/stacks/react-native.csv +0 -52
  74. package/.agent/.shared/ui-ux-pro-max/data/stacks/react.csv +0 -54
  75. package/.agent/.shared/ui-ux-pro-max/data/stacks/shadcn.csv +0 -61
  76. package/.agent/.shared/ui-ux-pro-max/data/stacks/svelte.csv +0 -54
  77. package/.agent/.shared/ui-ux-pro-max/data/stacks/swiftui.csv +0 -51
  78. package/.agent/.shared/ui-ux-pro-max/data/stacks/vue.csv +0 -50
  79. package/.agent/.shared/ui-ux-pro-max/data/styles.csv +0 -59
  80. package/.agent/.shared/ui-ux-pro-max/data/typography.csv +0 -58
  81. package/.agent/.shared/ui-ux-pro-max/data/ui-reasoning.csv +0 -101
  82. package/.agent/.shared/ui-ux-pro-max/data/ux-guidelines.csv +0 -100
  83. package/.agent/.shared/ui-ux-pro-max/data/web-interface.csv +0 -31
  84. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/core.cpython-313.pyc +0 -0
  85. package/.agent/.shared/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-313.pyc +0 -0
  86. package/.agent/.shared/ui-ux-pro-max/scripts/core.py +0 -258
  87. package/.agent/.shared/ui-ux-pro-max/scripts/design_system.py +0 -1067
  88. package/.agent/.shared/ui-ux-pro-max/scripts/search.py +0 -106
  89. package/.agent/ARCHITECTURE.md +0 -288
  90. package/.agent/data/ambient/goals.json +0 -1
  91. package/.agent/data/puppeteer-sessions/undefined.json +0 -6
  92. package/.agent/data/weixin-media/2026-04-08/img_1775618677512.jpg +0 -0
  93. package/.agent/data/weixin-media/2026-04-08/img_1775619073340.jpg +0 -0
  94. package/.agent/data/weixin-media/2026-04-08/img_1775619097536.jpg +0 -0
  95. package/.agent/data/weixin-media/2026-04-08/img_1775619209388.jpg +0 -0
  96. package/.agent/memory/feedback/mnygjgox-ualjip.md +0 -11
  97. package/.agent/memory/feedback/mnzugpej-esdwsr.md +0 -9
  98. package/.agent/memory/feedback/mo2quxke-saxs56.md +0 -9
  99. package/.agent/memory/feedback/mo9l6nw9-sm1ye2.md +0 -13
  100. package/.agent/memory/feedback/mo9uxkb3-bbxz3x.md +0 -9
  101. package/.agent/memory/feedback/mo9wpqy0-ftsez9.md +0 -13
  102. package/.agent/memory/feedback/mo9x2ps4-p7huqq.md +0 -11
  103. package/.agent/memory/feedback/mo9x2uay-z7ndjn.md +0 -9
  104. package/.agent/memory/feedback/mo9x2y7d-9wecyx.md +0 -9
  105. package/.agent/memory/feedback/mo9x39q3-nn7myt.md +0 -9
  106. package/.agent/memory/feedback/mo9xfir9-4g8a8j.md +0 -9
  107. package/.agent/memory/feedback/mo9xfui8-ujqrc6.md +0 -9
  108. package/.agent/memory/feedback/mocnx1wx-qtxxlh.md +0 -9
  109. package/.agent/memory/project/mnqx54u5-loqtoe.md +0 -9
  110. package/.agent/memory/project/mnqx84cv-mx6dmd.md +0 -9
  111. package/.agent/memory/project/mnsacuyr-hgtk5n.md +0 -20
  112. package/.agent/memory/project/mnu5hy2x-bjsg7u.md +0 -9
  113. package/.agent/memory/project/mny28ot4-8qe9au.md +0 -9
  114. package/.agent/memory/project/mnztftxj-af82rh.md +0 -9
  115. package/.agent/memory/project/mo0y04d0-bmaefl.md +0 -9
  116. package/.agent/memory/project/mo2iztxb-3c7v81.md +0 -9
  117. package/.agent/memory/project/mo2ssa5x-tpi1p3.md +0 -9
  118. package/.agent/memory/reference/mnre3cww-penbo1.md +0 -9
  119. package/.agent/memory/reference/mns9wn48-luerua.md +0 -14
  120. package/.agent/memory/reference/mns9yz5c-thc2s0.md +0 -16
  121. package/.agent/memory/reference/mnsfy4um-910f1o.md +0 -23
  122. package/.agent/memory/reference/mnsg37dp-lmfj18.md +0 -32
  123. package/.agent/memory/reference/mnsll60q-0j911u.md +0 -36
  124. package/.agent/memory/reference/mnsmlb5y-nej31u.md +0 -16
  125. package/.agent/memory/reference/mnssle72-yrot96.md +0 -9
  126. package/.agent/memory/reference/mnygj8nb-bjthmc.md +0 -20
  127. package/.agent/memory/reference/mnzfvs4m-ufyg9a.md +0 -12
  128. package/.agent/memory/user/mnsfuon6-l416q1.md +0 -21
  129. package/.agent/memory/user/mnsg9kut-95m7rf.md +0 -20
  130. package/.agent/memory/user/mnu2eo1v-yy6fhe.md +0 -9
  131. package/.agent/memory/user/mnu2etuo-8u8jk8.md +0 -9
  132. package/.agent/memory/user/mnx0rk6g-gsznjj.md +0 -9
  133. package/.agent/memory/user/mnyf1riz-4yo5yz.md +0 -9
  134. package/.agent/memory/user/mnzuh4cw-zvee8w.md +0 -13
  135. package/.agent/memory/user/mnzvewyj-jl67cq.md +0 -9
  136. package/.agent/memory/user/mnzwh9xo-43ys3f.md +0 -9
  137. package/.agent/memory/user/mo0ycvpn-eebsxc.md +0 -9
  138. package/.agent/memory/user/mo2k8c8n-132r2u.md +0 -9
  139. package/.agent/memory/user/mo6y2dei-5cf537.md +0 -13
  140. package/.agent/memory/user/mo9xsdo6-8vylww.md +0 -13
  141. package/.agent/plugins/puppeteer-plugin/README.md +0 -147
  142. package/.agent/plugins/puppeteer-plugin/index.js +0 -1422
  143. package/.agent/plugins/puppeteer-plugin/package.json +0 -9
  144. package/.agent/rules/GEMINI.md +0 -273
  145. package/.agent/rules/allow-rule.md +0 -77
  146. package/.agent/rules/log-rule.md +0 -83
  147. package/.agent/rules/security-rule.md +0 -93
  148. package/.agent/scripts/auto_preview.py +0 -148
  149. package/.agent/scripts/checklist.py +0 -217
  150. package/.agent/scripts/session_manager.py +0 -120
  151. package/.agent/scripts/verify_all.py +0 -327
  152. package/.agent/skills/doc.md +0 -177
  153. package/.agent/skills/fk-poster/SKILL.md +0 -1129
  154. package/.agent/skills/fkbuilder/SKILL.md +0 -730
  155. package/.agent/skills/mmx-cli/SKILL.md +0 -431
  156. package/.agent/workflows/brainstorm.md +0 -113
  157. package/.agent/workflows/create.md +0 -59
  158. package/.agent/workflows/debug.md +0 -103
  159. package/.agent/workflows/deploy.md +0 -176
  160. package/.agent/workflows/enhance.md +0 -63
  161. package/.agent/workflows/orchestrate.md +0 -237
  162. package/.agent/workflows/plan.md +0 -89
  163. package/.agent/workflows/preview.md +0 -81
  164. package/.agent/workflows/simple-test.md +0 -42
  165. package/.agent/workflows/status.md +0 -86
  166. package/.agent/workflows/structured-orchestrate.md +0 -180
  167. package/.agent/workflows/test.md +0 -144
  168. package/.agent/workflows/ui-ux-pro-max.md +0 -296
@@ -1,258 +0,0 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- UI/UX Pro Max Core - BM25 search engine for UI/UX style guides
5
- """
6
-
7
- import csv
8
- import re
9
- from pathlib import Path
10
- from math import log
11
- from collections import defaultdict
12
-
13
- # ============ CONFIGURATION ============
14
- DATA_DIR = Path(__file__).parent.parent / "data"
15
- MAX_RESULTS = 3
16
-
17
- CSV_CONFIG = {
18
- "style": {
19
- "file": "styles.csv",
20
- "search_cols": ["Style Category", "Keywords", "Best For", "Type"],
21
- "output_cols": ["Style Category", "Type", "Keywords", "Primary Colors", "Effects & Animation", "Best For", "Performance", "Accessibility", "Framework Compatibility", "Complexity"]
22
- },
23
- "prompt": {
24
- "file": "prompts.csv",
25
- "search_cols": ["Style Category", "AI Prompt Keywords (Copy-Paste Ready)", "CSS/Technical Keywords"],
26
- "output_cols": ["Style Category", "AI Prompt Keywords (Copy-Paste Ready)", "CSS/Technical Keywords", "Implementation Checklist"]
27
- },
28
- "color": {
29
- "file": "colors.csv",
30
- "search_cols": ["Product Type", "Keywords", "Notes"],
31
- "output_cols": ["Product Type", "Keywords", "Primary (Hex)", "Secondary (Hex)", "CTA (Hex)", "Background (Hex)", "Text (Hex)", "Border (Hex)", "Notes"]
32
- },
33
- "chart": {
34
- "file": "charts.csv",
35
- "search_cols": ["Data Type", "Keywords", "Best Chart Type", "Accessibility Notes"],
36
- "output_cols": ["Data Type", "Keywords", "Best Chart Type", "Secondary Options", "Color Guidance", "Accessibility Notes", "Library Recommendation", "Interactive Level"]
37
- },
38
- "landing": {
39
- "file": "landing.csv",
40
- "search_cols": ["Pattern Name", "Keywords", "Conversion Optimization", "Section Order"],
41
- "output_cols": ["Pattern Name", "Keywords", "Section Order", "Primary CTA Placement", "Color Strategy", "Conversion Optimization"]
42
- },
43
- "product": {
44
- "file": "products.csv",
45
- "search_cols": ["Product Type", "Keywords", "Primary Style Recommendation", "Key Considerations"],
46
- "output_cols": ["Product Type", "Keywords", "Primary Style Recommendation", "Secondary Styles", "Landing Page Pattern", "Dashboard Style (if applicable)", "Color Palette Focus"]
47
- },
48
- "ux": {
49
- "file": "ux-guidelines.csv",
50
- "search_cols": ["Category", "Issue", "Description", "Platform"],
51
- "output_cols": ["Category", "Issue", "Platform", "Description", "Do", "Don't", "Code Example Good", "Code Example Bad", "Severity"]
52
- },
53
- "typography": {
54
- "file": "typography.csv",
55
- "search_cols": ["Font Pairing Name", "Category", "Mood/Style Keywords", "Best For", "Heading Font", "Body Font"],
56
- "output_cols": ["Font Pairing Name", "Category", "Heading Font", "Body Font", "Mood/Style Keywords", "Best For", "Google Fonts URL", "CSS Import", "Tailwind Config", "Notes"]
57
- },
58
- "icons": {
59
- "file": "icons.csv",
60
- "search_cols": ["Category", "Icon Name", "Keywords", "Best For"],
61
- "output_cols": ["Category", "Icon Name", "Keywords", "Library", "Import Code", "Usage", "Best For", "Style"]
62
- },
63
- "react": {
64
- "file": "react-performance.csv",
65
- "search_cols": ["Category", "Issue", "Keywords", "Description"],
66
- "output_cols": ["Category", "Issue", "Platform", "Description", "Do", "Don't", "Code Example Good", "Code Example Bad", "Severity"]
67
- },
68
- "web": {
69
- "file": "web-interface.csv",
70
- "search_cols": ["Category", "Issue", "Keywords", "Description"],
71
- "output_cols": ["Category", "Issue", "Platform", "Description", "Do", "Don't", "Code Example Good", "Code Example Bad", "Severity"]
72
- }
73
- }
74
-
75
- STACK_CONFIG = {
76
- "html-tailwind": {"file": "stacks/html-tailwind.csv"},
77
- "react": {"file": "stacks/react.csv"},
78
- "nextjs": {"file": "stacks/nextjs.csv"},
79
- "vue": {"file": "stacks/vue.csv"},
80
- "nuxtjs": {"file": "stacks/nuxtjs.csv"},
81
- "nuxt-ui": {"file": "stacks/nuxt-ui.csv"},
82
- "svelte": {"file": "stacks/svelte.csv"},
83
- "swiftui": {"file": "stacks/swiftui.csv"},
84
- "react-native": {"file": "stacks/react-native.csv"},
85
- "flutter": {"file": "stacks/flutter.csv"},
86
- "shadcn": {"file": "stacks/shadcn.csv"},
87
- "jetpack-compose": {"file": "stacks/jetpack-compose.csv"}
88
- }
89
-
90
- # Common columns for all stacks
91
- _STACK_COLS = {
92
- "search_cols": ["Category", "Guideline", "Description", "Do", "Don't"],
93
- "output_cols": ["Category", "Guideline", "Description", "Do", "Don't", "Code Good", "Code Bad", "Severity", "Docs URL"]
94
- }
95
-
96
- AVAILABLE_STACKS = list(STACK_CONFIG.keys())
97
-
98
-
99
- # ============ BM25 IMPLEMENTATION ============
100
- class BM25:
101
- """BM25 ranking algorithm for text search"""
102
-
103
- def __init__(self, k1=1.5, b=0.75):
104
- self.k1 = k1
105
- self.b = b
106
- self.corpus = []
107
- self.doc_lengths = []
108
- self.avgdl = 0
109
- self.idf = {}
110
- self.doc_freqs = defaultdict(int)
111
- self.N = 0
112
-
113
- def tokenize(self, text):
114
- """Lowercase, split, remove punctuation, filter short words"""
115
- text = re.sub(r'[^\w\s]', ' ', str(text).lower())
116
- return [w for w in text.split() if len(w) > 2]
117
-
118
- def fit(self, documents):
119
- """Build BM25 index from documents"""
120
- self.corpus = [self.tokenize(doc) for doc in documents]
121
- self.N = len(self.corpus)
122
- if self.N == 0:
123
- return
124
- self.doc_lengths = [len(doc) for doc in self.corpus]
125
- self.avgdl = sum(self.doc_lengths) / self.N
126
-
127
- for doc in self.corpus:
128
- seen = set()
129
- for word in doc:
130
- if word not in seen:
131
- self.doc_freqs[word] += 1
132
- seen.add(word)
133
-
134
- for word, freq in self.doc_freqs.items():
135
- self.idf[word] = log((self.N - freq + 0.5) / (freq + 0.5) + 1)
136
-
137
- def score(self, query):
138
- """Score all documents against query"""
139
- query_tokens = self.tokenize(query)
140
- scores = []
141
-
142
- for idx, doc in enumerate(self.corpus):
143
- score = 0
144
- doc_len = self.doc_lengths[idx]
145
- term_freqs = defaultdict(int)
146
- for word in doc:
147
- term_freqs[word] += 1
148
-
149
- for token in query_tokens:
150
- if token in self.idf:
151
- tf = term_freqs[token]
152
- idf = self.idf[token]
153
- numerator = tf * (self.k1 + 1)
154
- denominator = tf + self.k1 * (1 - self.b + self.b * doc_len / self.avgdl)
155
- score += idf * numerator / denominator
156
-
157
- scores.append((idx, score))
158
-
159
- return sorted(scores, key=lambda x: x[1], reverse=True)
160
-
161
-
162
- # ============ SEARCH FUNCTIONS ============
163
- def _load_csv(filepath):
164
- """Load CSV and return list of dicts"""
165
- with open(filepath, 'r', encoding='utf-8') as f:
166
- return list(csv.DictReader(f))
167
-
168
-
169
- def _search_csv(filepath, search_cols, output_cols, query, max_results):
170
- """Core search function using BM25"""
171
- if not filepath.exists():
172
- return []
173
-
174
- data = _load_csv(filepath)
175
-
176
- # Build documents from search columns
177
- documents = [" ".join(str(row.get(col, "")) for col in search_cols) for row in data]
178
-
179
- # BM25 search
180
- bm25 = BM25()
181
- bm25.fit(documents)
182
- ranked = bm25.score(query)
183
-
184
- # Get top results with score > 0
185
- results = []
186
- for idx, score in ranked[:max_results]:
187
- if score > 0:
188
- row = data[idx]
189
- results.append({col: row.get(col, "") for col in output_cols if col in row})
190
-
191
- return results
192
-
193
-
194
- def detect_domain(query):
195
- """Auto-detect the most relevant domain from query"""
196
- query_lower = query.lower()
197
-
198
- domain_keywords = {
199
- "color": ["color", "palette", "hex", "#", "rgb"],
200
- "chart": ["chart", "graph", "visualization", "trend", "bar", "pie", "scatter", "heatmap", "funnel"],
201
- "landing": ["landing", "page", "cta", "conversion", "hero", "testimonial", "pricing", "section"],
202
- "product": ["saas", "ecommerce", "e-commerce", "fintech", "healthcare", "gaming", "portfolio", "crypto", "dashboard"],
203
- "prompt": ["prompt", "css", "implementation", "variable", "checklist", "tailwind"],
204
- "style": ["style", "design", "ui", "minimalism", "glassmorphism", "neumorphism", "brutalism", "dark mode", "flat", "aurora"],
205
- "ux": ["ux", "usability", "accessibility", "wcag", "touch", "scroll", "animation", "keyboard", "navigation", "mobile"],
206
- "typography": ["font", "typography", "heading", "serif", "sans"],
207
- "icons": ["icon", "icons", "lucide", "heroicons", "symbol", "glyph", "pictogram", "svg icon"],
208
- "react": ["react", "next.js", "nextjs", "suspense", "memo", "usecallback", "useeffect", "rerender", "bundle", "waterfall", "barrel", "dynamic import", "rsc", "server component"],
209
- "web": ["aria", "focus", "outline", "semantic", "virtualize", "autocomplete", "form", "input type", "preconnect"]
210
- }
211
-
212
- scores = {domain: sum(1 for kw in keywords if kw in query_lower) for domain, keywords in domain_keywords.items()}
213
- best = max(scores, key=scores.get)
214
- return best if scores[best] > 0 else "style"
215
-
216
-
217
- def search(query, domain=None, max_results=MAX_RESULTS):
218
- """Main search function with auto-domain detection"""
219
- if domain is None:
220
- domain = detect_domain(query)
221
-
222
- config = CSV_CONFIG.get(domain, CSV_CONFIG["style"])
223
- filepath = DATA_DIR / config["file"]
224
-
225
- if not filepath.exists():
226
- return {"error": f"File not found: {filepath}", "domain": domain}
227
-
228
- results = _search_csv(filepath, config["search_cols"], config["output_cols"], query, max_results)
229
-
230
- return {
231
- "domain": domain,
232
- "query": query,
233
- "file": config["file"],
234
- "count": len(results),
235
- "results": results
236
- }
237
-
238
-
239
- def search_stack(query, stack, max_results=MAX_RESULTS):
240
- """Search stack-specific guidelines"""
241
- if stack not in STACK_CONFIG:
242
- return {"error": f"Unknown stack: {stack}. Available: {', '.join(AVAILABLE_STACKS)}"}
243
-
244
- filepath = DATA_DIR / STACK_CONFIG[stack]["file"]
245
-
246
- if not filepath.exists():
247
- return {"error": f"Stack file not found: {filepath}", "stack": stack}
248
-
249
- results = _search_csv(filepath, _STACK_COLS["search_cols"], _STACK_COLS["output_cols"], query, max_results)
250
-
251
- return {
252
- "domain": "stack",
253
- "stack": stack,
254
- "query": query,
255
- "file": STACK_CONFIG[stack]["file"],
256
- "count": len(results),
257
- "results": results
258
- }