catalyst-core-internal 0.1.4 → 0.1.6

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 (43) hide show
  1. package/bin/catalyst.js +1 -8
  2. package/changelog.md +21 -0
  3. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/BridgeMessageValidator.kt +1 -1
  4. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/CustomWebview.kt +1 -12
  5. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/MainActivity.kt +3 -18
  6. package/dist/native/buildAppAndroid.js +2 -2
  7. package/dist/native/buildAppIos.js +17 -10
  8. package/dist/native/iosnativeWebView/Sources/Core/WebView/NativeBridge.swift +2 -13
  9. package/dist/native/iosnativeWebView/Sources/Core/WebView/WebView.swift +0 -6
  10. package/dist/native/iosnativeWebView/iosnativeWebView.xcodeproj/project.pbxproj +0 -4
  11. package/mcp_v2/conversion-tasks.json +326 -0
  12. package/mcp_v2/knowledge-base.json +1068 -0
  13. package/mcp_v2/lib/helpers.js +170 -0
  14. package/mcp_v2/mcp.js +563 -0
  15. package/mcp_v2/package.json +13 -0
  16. package/mcp_v2/schema.sql +88 -0
  17. package/mcp_v2/setup.js +282 -0
  18. package/mcp_v2/tools/build.js +686 -0
  19. package/mcp_v2/tools/config.js +453 -0
  20. package/mcp_v2/tools/conversion.js +799 -0
  21. package/mcp_v2/tools/debug.js +113 -0
  22. package/mcp_v2/tools/knowledge.js +219 -0
  23. package/mcp_v2/tools/sync.js +23 -0
  24. package/mcp_v2/tools/tasks.js +945 -0
  25. package/package.json +7 -15
  26. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/CatalystPlugin.kt +0 -7
  27. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/GeneratedPluginIndex.kt +0 -6
  28. package/dist/native/androidProject/app/src/main/java/io/yourname/androidproject/plugins/PluginBridge.kt +0 -253
  29. package/dist/native/androidProject/app/src/test/java/io/yourname/androidproject/plugins/PluginBridgeTest.kt +0 -139
  30. package/dist/native/internal-plugins/device-info-plugin/android/DeviceInfoPlugin.kt +0 -43
  31. package/dist/native/internal-plugins/device-info-plugin/ios/DeviceInfoPlugin.swift +0 -28
  32. package/dist/native/internal-plugins/device-info-plugin/manifest.json +0 -19
  33. package/dist/native/internalPluginUtils.js +0 -1
  34. package/dist/native/iosnativeWebView/Sources/Core/Plugins/CatalystPlugin.swift +0 -5
  35. package/dist/native/iosnativeWebView/Sources/Core/Plugins/GeneratedPluginIndex.swift +0 -6
  36. package/dist/native/iosnativeWebView/Sources/Core/Plugins/PluginBridge.swift +0 -364
  37. package/dist/native/iosnativeWebView/Sources/Core/WebView/WeakScriptMessageHandler.swift +0 -14
  38. package/dist/native/iosnativeWebView/iosnativeWebViewTests/PluginBridgeTests.swift +0 -160
  39. package/dist/native/plugin-bridge/PluginBridge.js +0 -1
  40. package/dist/native/pluginComposerAndroid.js +0 -9
  41. package/dist/native/pluginComposerIos.js +0 -7
  42. package/dist/scripts/plugins.js +0 -1
  43. package/license +0 -10
@@ -0,0 +1,113 @@
1
+ "use strict"
2
+
3
+ let _db
4
+
5
+ function init(db) {
6
+ _db = db
7
+ }
8
+
9
+ function handle_debug_issue({ symptom, layer } = {}) {
10
+ const NOISE = new Set([
11
+ "the",
12
+ "a",
13
+ "an",
14
+ "is",
15
+ "are",
16
+ "was",
17
+ "not",
18
+ "does",
19
+ "do",
20
+ "on",
21
+ "in",
22
+ "at",
23
+ "to",
24
+ "for",
25
+ "of",
26
+ "and",
27
+ "or",
28
+ "with",
29
+ "my",
30
+ "i",
31
+ "its",
32
+ "it",
33
+ "this",
34
+ "that",
35
+ "when",
36
+ "why",
37
+ "how",
38
+ "what",
39
+ "where",
40
+ "after",
41
+ "before",
42
+ "but",
43
+ "can",
44
+ "cant",
45
+ "cannot",
46
+ "will",
47
+ "wont",
48
+ "still",
49
+ "always",
50
+ "never",
51
+ "app",
52
+ "apps",
53
+ ])
54
+ const tokens = symptom
55
+ .toLowerCase()
56
+ .replace(/[^a-z0-9\s]/g, " ")
57
+ .split(/\s+/)
58
+ .filter((t) => t.length > 2 && !NOISE.has(t))
59
+
60
+ function scoreRow(text) {
61
+ const lower = text.toLowerCase()
62
+ let score = 0
63
+ for (const token of tokens) {
64
+ if (lower.includes(token)) score++
65
+ }
66
+ return score
67
+ }
68
+
69
+ const allErrors = layer
70
+ ? _db.prepare(`SELECT * FROM known_errors WHERE layer = ?`).all(layer)
71
+ : _db.prepare(`SELECT * FROM known_errors`).all()
72
+
73
+ const scored = allErrors
74
+ .map((r) => ({ ...r, _score: scoreRow(r.symptom + " " + r.cause + " " + r.tags) }))
75
+ .sort((a, b) => b._score - a._score)
76
+
77
+ const matched = scored.filter((r) => r._score > 0).slice(0, 5)
78
+ const fallback = matched.length === 0 ? scored.slice(0, 3) : []
79
+
80
+ const matchedLayers = [...new Set(matched.map((r) => r.layer))]
81
+ const knowledgeLayers = layer ? [layer] : matchedLayers.length ? matchedLayers : null
82
+
83
+ let knowledge = []
84
+ if (knowledgeLayers && knowledgeLayers.length) {
85
+ const placeholders = knowledgeLayers.map(() => "?").join(",")
86
+ knowledge = _db
87
+ .prepare(
88
+ `
89
+ SELECT title, content, layer FROM framework_knowledge
90
+ WHERE source = 'static' AND layer IN (${placeholders})
91
+ ORDER BY layer, id
92
+ LIMIT 8
93
+ `
94
+ )
95
+ .all(...knowledgeLayers)
96
+ }
97
+
98
+ const result = { symptom, tokens_used: tokens, layer: layer || "auto" }
99
+
100
+ if (matched.length > 0) {
101
+ result.matched_errors = matched.map(({ _score, ...r }) => ({ ...r, match_score: _score }))
102
+ result.relevant_knowledge = knowledge
103
+ } else {
104
+ result.matched_errors = []
105
+ result.fallback_errors = fallback.map(({ ...r }) => r)
106
+ result.relevant_knowledge = knowledge
107
+ result.note = `No strong keyword matches for "${symptom}". Showing top known_errors entries as fallback. Try rephrasing with more specific terms (e.g. "android build sdkPath", "localhost blocked", "clearWebData cache").`
108
+ }
109
+
110
+ return result
111
+ }
112
+
113
+ module.exports = { init, handle_debug_issue }
@@ -0,0 +1,219 @@
1
+ "use strict"
2
+
3
+ const https = require("https")
4
+ const { findCatalystRoot } = require("../lib/helpers")
5
+
6
+ let _db
7
+
8
+ // Keywords that signal the LLM wants a complete/live list rather than a concept explanation.
9
+ // When a matched KB entry has github_files + query matches these, we auto-fetch from GitHub.
10
+ const LIST_INTENT_PATTERNS =
11
+ /\b(all|list|available|new|latest|complete|full|enumerate|what hooks|any hooks|what.*available|show.*all)\b/i
12
+
13
+ function init(db) {
14
+ _db = db
15
+
16
+ // Migrate: add github_files column if missing (existing DBs)
17
+ const cols = _db
18
+ .prepare(`PRAGMA table_info(framework_knowledge)`)
19
+ .all()
20
+ .map((c) => c.name)
21
+ if (!cols.includes("github_files")) {
22
+ _db.exec(`ALTER TABLE framework_knowledge ADD COLUMN github_files TEXT`)
23
+ }
24
+ // Drop always_fetch_github if it exists (replaced by intent detection)
25
+ // SQLite can't DROP COLUMN before 3.35 — just leave it, it's ignored
26
+
27
+ // Create FTS5 virtual table if not exists (standalone, not external-content)
28
+ _db.exec(`
29
+ CREATE VIRTUAL TABLE IF NOT EXISTS fk_fts USING fts5(
30
+ title, content, tags, section,
31
+ tokenize='unicode61 remove_diacritics 1'
32
+ );
33
+ `)
34
+
35
+ // Populate FTS index if empty
36
+ const count = _db.prepare(`SELECT count(*) as c FROM fk_fts`).get().c
37
+ if (count === 0) {
38
+ _db.exec(
39
+ `INSERT INTO fk_fts(rowid, title, content, tags, section) SELECT id, title, content, COALESCE(tags,''), section FROM framework_knowledge`
40
+ )
41
+ }
42
+ }
43
+
44
+ function fetchRaw(url) {
45
+ return new Promise((resolve, reject) => {
46
+ https
47
+ .get(url, { headers: { "User-Agent": "catalyst-mcp/1.0" } }, (res) => {
48
+ if (res.statusCode === 404) return resolve(null)
49
+ if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`))
50
+ const chunks = []
51
+ res.on("data", (c) => chunks.push(c))
52
+ res.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")))
53
+ })
54
+ .on("error", reject)
55
+ })
56
+ }
57
+
58
+ // Fetch first available file — used for KB-miss GitHub fallback
59
+ async function fetchFromGithub(files, installedVersion) {
60
+ if (!files || files.length === 0) return null
61
+
62
+ const tag = installedVersion || "main"
63
+ const base = `https://raw.githubusercontent.com/tata1mg/catalyst-core/${tag}`
64
+
65
+ for (const file of files) {
66
+ try {
67
+ const content = await fetchRaw(`${base}/${file}`)
68
+ if (content) return { file, tag, content: content.slice(0, 8000) }
69
+ } catch (_err) {
70
+ // Ignore missing/unreachable files and continue to the next candidate.
71
+ }
72
+ }
73
+
74
+ // Retry with main if versioned tag failed
75
+ if (tag !== "main") {
76
+ for (const file of files) {
77
+ try {
78
+ const content = await fetchRaw(
79
+ `https://raw.githubusercontent.com/tata1mg/catalyst-core/main/${file}`
80
+ )
81
+ if (content) return { file, tag: "main", content: content.slice(0, 8000) }
82
+ } catch (_err) {
83
+ // Ignore missing/unreachable files and continue to the next candidate.
84
+ }
85
+ }
86
+ }
87
+
88
+ return null
89
+ }
90
+
91
+ // Build FTS5 query string from keywords array — each term ORed, quoted for safety
92
+ function buildFtsQuery(keywords) {
93
+ return keywords.map((k) => `"${k.replace(/"/g, "")}"`).join(" OR ")
94
+ }
95
+
96
+ function stripGithubFiles(rows) {
97
+ return rows.map((row) => {
98
+ const sanitizedRow = { ...row }
99
+ delete sanitizedRow.github_files
100
+ return sanitizedRow
101
+ })
102
+ }
103
+
104
+ // Narrow down which github_file to fetch based on query keywords.
105
+ // Avoids fetching all files when query is clearly about one specific hook/file.
106
+ function narrowGithubFile(files, query) {
107
+ if (!files || files.length <= 1) return files
108
+ const q = query.toLowerCase()
109
+ // If query mentions a specific file hint, prefer that file
110
+ for (const file of files) {
111
+ const basename = file.split("/").pop().replace(/\.js$/, "").toLowerCase()
112
+ if (q.includes(basename)) return [file]
113
+ }
114
+ // Default: return all (caller fetches first available)
115
+ return files
116
+ }
117
+
118
+ async function handle_query_knowledge({ query, keywords, section, github_files } = {}) {
119
+ if (!query) return { error: "query is required." }
120
+
121
+ // ── FTS5 search ────────────────────────────────────────────────────────────
122
+ const searchTerms = keywords && keywords.length > 0 ? keywords : [query]
123
+ const ftsQuery = buildFtsQuery(searchTerms)
124
+
125
+ let rows = []
126
+ try {
127
+ // Join back to framework_knowledge to get github_files
128
+ const sql = section
129
+ ? `SELECT fk.title, fk.content, fk.tags, fk.section, fk.github_files
130
+ FROM fk_fts
131
+ JOIN framework_knowledge fk ON fk_fts.rowid = fk.id
132
+ WHERE fk_fts MATCH ? AND fk_fts.section = ? ORDER BY rank LIMIT 6`
133
+ : `SELECT fk.title, fk.content, fk.tags, fk.section, fk.github_files
134
+ FROM fk_fts
135
+ JOIN framework_knowledge fk ON fk_fts.rowid = fk.id
136
+ WHERE fk_fts MATCH ? ORDER BY rank LIMIT 6`
137
+ rows = section ? _db.prepare(sql).all(ftsQuery, section) : _db.prepare(sql).all(ftsQuery)
138
+ } catch (_err) {
139
+ // FTS syntax error — fall through to github
140
+ }
141
+
142
+ if (rows.length > 0) {
143
+ // Find first matched entry that has github_files attached
144
+ const entryWithFiles = rows.find((r) => r.github_files)
145
+ const parsedFiles = entryWithFiles ? JSON.parse(entryWithFiles.github_files) : null
146
+
147
+ // ── Intent detection: does the query want a live/complete list? ──────────
148
+ const isListIntent = LIST_INTENT_PATTERNS.test(query)
149
+
150
+ if (isListIntent && parsedFiles) {
151
+ let installedVersion = null
152
+ try {
153
+ const root = findCatalystRoot()
154
+ installedVersion = root ? root.installedVersion : null
155
+ } catch (_err) {
156
+ // Installed version lookup is best effort.
157
+ }
158
+
159
+ // Narrow to the most relevant file based on query keywords
160
+ const targetFiles = narrowGithubFile(parsedFiles, query)
161
+ const github = await fetchFromGithub(targetFiles, installedVersion)
162
+
163
+ return {
164
+ query,
165
+ source: "knowledge_base+github",
166
+ results: stripGithubFiles(rows),
167
+ github_file: github ? github.file : null,
168
+ github_tag: github ? github.tag : null,
169
+ github_content: github ? github.content : null,
170
+ installed_version: installedVersion,
171
+ note: `${rows.length} KB entries matched. List intent detected — fetched latest source${github ? ` (${github.file}@${github.tag})` : " (GitHub fetch failed)"}.`,
172
+ }
173
+ }
174
+
175
+ // ── Standard KB hit: return results + hint about live source files ───────
176
+ return {
177
+ query,
178
+ source: "knowledge_base",
179
+ results: stripGithubFiles(rows),
180
+ live_source_files: parsedFiles || null, // LLM can re-query with these if it needs fresher data
181
+ note: `${rows.length} entries matched from local knowledge base.${parsedFiles ? " Pass live_source_files as github_files in a follow-up query_knowledge call if you need the latest source." : ""}`,
182
+ }
183
+ }
184
+
185
+ // ── GitHub fallback (KB miss) ──────────────────────────────────────────────
186
+ let installedVersion = null
187
+ try {
188
+ const root = findCatalystRoot()
189
+ installedVersion = root ? root.installedVersion : null
190
+ } catch (_err) {
191
+ // Installed version lookup is best effort.
192
+ }
193
+
194
+ const github = await fetchFromGithub(github_files || [], installedVersion)
195
+
196
+ if (github) {
197
+ return {
198
+ query,
199
+ source: "github",
200
+ github_file: github.file,
201
+ github_tag: github.tag,
202
+ installed_version: installedVersion,
203
+ content: github.content,
204
+ note: `No KB match. Fetched source file '${github.file}' from catalyst-core@${github.tag} on GitHub.`,
205
+ }
206
+ }
207
+
208
+ // ── Hard miss ──────────────────────────────────────────────────────────────
209
+ return {
210
+ query,
211
+ source: "none",
212
+ results: [],
213
+ llm_instruction:
214
+ "No match found in the knowledge base and no source file was provided for GitHub fallback. DO NOT search node_modules, dist, or the filesystem. Tell the user this topic is not fully covered in the knowledge base yet, and suggest they check the catalyst-core source directly at node_modules/catalyst-core/src/.",
215
+ note: `No KB match for "${query}". If you know the relevant source file path, retry with github_files: ["src/path/to/file.js"].`,
216
+ }
217
+ }
218
+
219
+ module.exports = { init, handle_query_knowledge }
@@ -0,0 +1,23 @@
1
+ "use strict"
2
+
3
+ let _db
4
+
5
+ function init(db) {
6
+ _db = db
7
+ }
8
+
9
+ function handle_sync_catalyst_docs({ force = false } = {}) {
10
+ const snapshot_count = _db.prepare(`SELECT COUNT(*) as c FROM doc_snapshots`).get()
11
+ const knowledge_count = _db
12
+ .prepare(`SELECT COUNT(*) as c FROM framework_knowledge WHERE source = 'sitemap'`)
13
+ .get()
14
+ return {
15
+ _phase: 6,
16
+ force,
17
+ existing_snapshots: snapshot_count.c,
18
+ sitemap_knowledge_rows: knowledge_count.c,
19
+ message: "Live sync not yet implemented (Phase 6). Run setup.js for initial sync.",
20
+ }
21
+ }
22
+
23
+ module.exports = { init, handle_sync_catalyst_docs }