fix(opencode-plugin): fix tsconfig, add publishConfig and bun lockfile (#5273)

This commit is contained in:
Kartik
2026-05-28 11:28:21 +05:30
committed by GitHub
parent 116c439b1d
commit add6aad40b
7 changed files with 979 additions and 248 deletions
@@ -149,9 +149,9 @@ See the [migration guide](https://docs.mem0.ai/migration/platform-v2-to-v3) for
For the latest docs beyond what's in the references, use the doc search tool:
```bash
python ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.py --query "topic"
python ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.py --page "/platform/features/graph-memory"
python ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.py --index
bun ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.ts --query "topic"
bun ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.ts --page "/platform/features/graph-memory"
bun ${CLAUDE_SKILL_DIR}/scripts/mem0_doc_search.ts --index
```
No API key needed — searches docs.mem0.ai directly.
@@ -1,224 +0,0 @@
#!/usr/bin/env python3
"""
Mem0 Documentation Search Agent (Mintlify-based)
On-demand search tool for querying Mem0 documentation without storing content locally.
This tool leverages Mintlify's documentation structure to perform just-in-time
retrieval of technical information from docs.mem0.ai.
Usage:
python mem0_doc_search.py --query "how to add graph memory"
python mem0_doc_search.py --query "filter syntax for categories"
python mem0_doc_search.py --page "/platform/features/graph-memory"
python mem0_doc_search.py --index
python mem0_doc_search.py --query "webhook events" --section platform
Purpose:
- Avoid bloating local context with full documentation
- Enable just-in-time retrieval of technical details
- Query specific documentation pages on demand
- Search across the full Mem0 documentation site
"""
import argparse
import json
import sys
import urllib.error
import urllib.parse
import urllib.request
DOCS_BASE = "https://docs.mem0.ai"
SEARCH_ENDPOINT = f"{DOCS_BASE}/api/search"
LLMS_INDEX = f"{DOCS_BASE}/llms.txt"
# Known documentation sections for targeted retrieval
SECTION_MAP = {
"platform": [
"/platform/overview",
"/platform/quickstart",
"/platform/features",
"/platform/features/graph-memory",
"/platform/features/selective-memory",
"/platform/features/custom-categories",
"/platform/features/v2-memory-filters",
"/platform/features/async-client",
"/platform/features/webhooks",
"/platform/features/multimodal-support",
],
"api": [
"/api-reference/memory/add-memories",
"/api-reference/memory/v2-search-memories",
"/api-reference/memory/v2-get-memories",
"/api-reference/memory/get-memory",
"/api-reference/memory/update-memory",
"/api-reference/memory/delete-memory",
],
"open-source": [
"/open-source/overview",
"/open-source/python-quickstart",
"/open-source/node-quickstart",
"/open-source/features",
"/open-source/features/graph-memory",
"/open-source/features/rest-api",
"/open-source/configure-components",
],
"openmemory": [
"/openmemory/overview",
"/openmemory/quickstart",
],
"sdks": [
"/sdks/python",
"/sdks/js",
],
"integrations": [
"/integrations",
],
}
def fetch_url(url: str) -> str:
"""Fetch content from a URL."""
req = urllib.request.Request(url, headers={"User-Agent": "Mem0DocSearchAgent/1.0"})
try:
with urllib.request.urlopen(req, timeout=15) as resp:
return resp.read().decode("utf-8")
except urllib.error.HTTPError as e:
return f"HTTP Error {e.code}: {e.reason}"
except urllib.error.URLError as e:
return f"URL Error: {e.reason}"
def search_docs(query: str, section: str | None = None) -> dict:
"""
Search Mem0 documentation using Mintlify's search API.
Falls back to the llms.txt index for keyword matching if the API is unavailable.
"""
# Try Mintlify search API first
params = urllib.parse.urlencode({"query": query})
search_url = f"{SEARCH_ENDPOINT}?{params}"
try:
result = fetch_url(search_url)
data = json.loads(result)
if isinstance(data, dict) and data.get("results"):
results = data["results"]
if section and section in SECTION_MAP:
section_paths = SECTION_MAP[section]
results = [r for r in results if any(r.get("url", "").startswith(p) for p in section_paths)]
return {"source": "mintlify_search", "results": results}
except (json.JSONDecodeError, Exception):
pass
# Fallback: search llms.txt index for matching URLs
index_content = fetch_url(LLMS_INDEX)
query_lower = query.lower()
matching_urls = []
for line in index_content.splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
if query_lower in line.lower():
matching_urls.append(line)
if section and section in SECTION_MAP:
section_paths = SECTION_MAP[section]
matching_urls = [u for u in matching_urls if any(p in u for p in section_paths)]
return {
"source": "llms_txt_index",
"query": query,
"matching_urls": matching_urls[:20],
"suggestion": "Fetch specific URLs for detailed content",
}
def fetch_page(page_path: str) -> dict:
"""Fetch a specific documentation page."""
url = f"{DOCS_BASE}{page_path}" if page_path.startswith("/") else page_path
content = fetch_url(url)
return {"url": url, "content": content[:10000], "truncated": len(content) > 10000}
def get_index() -> dict:
"""Fetch the full documentation index from llms.txt."""
content = fetch_url(LLMS_INDEX)
urls = [line.strip() for line in content.splitlines() if line.strip() and not line.startswith("#")]
return {"total_pages": len(urls), "urls": urls, "sections": list(SECTION_MAP.keys())}
def list_section(section: str) -> dict:
"""List all known pages in a documentation section."""
if section not in SECTION_MAP:
return {"error": f"Unknown section: {section}", "available": list(SECTION_MAP.keys())}
return {
"section": section,
"pages": [f"{DOCS_BASE}{p}" for p in SECTION_MAP[section]],
}
def main():
parser = argparse.ArgumentParser(description="Search Mem0 documentation on demand")
parser.add_argument("--query", help="Search query for documentation")
parser.add_argument("--page", help="Fetch a specific page path (e.g., /platform/features/graph-memory)")
parser.add_argument("--index", action="store_true", help="Show full documentation index")
parser.add_argument("--section", help="Filter by section or list section pages")
parser.add_argument("--json", action="store_true", help="Output as JSON")
args = parser.parse_args()
if args.index:
result = get_index()
elif args.section and not args.query:
result = list_section(args.section)
elif args.page:
result = fetch_page(args.page)
elif args.query:
result = search_docs(args.query, section=args.section)
else:
parser.print_help()
sys.exit(1)
if args.json:
print(json.dumps(result, indent=2))
else:
if isinstance(result, dict):
if "results" in result:
print(f"Source: {result.get('source', 'unknown')}")
for r in result["results"]:
print(f" - {r.get('title', 'N/A')}: {r.get('url', 'N/A')}")
if r.get("description"):
print(f" {r['description'][:200]}")
elif "matching_urls" in result:
print(f"Source: {result['source']}")
print(f"Query: {result['query']}")
for url in result["matching_urls"]:
print(f" - {url}")
if result.get("suggestion"):
print(f"\n{result['suggestion']}")
elif "urls" in result:
print(f"Total documentation pages: {result['total_pages']}")
print(f"Sections: {', '.join(result['sections'])}")
for url in result["urls"][:30]:
print(f" - {url}")
if result["total_pages"] > 30:
print(f" ... and {result['total_pages'] - 30} more")
elif "pages" in result:
print(f"Section: {result['section']}")
for page in result["pages"]:
print(f" - {page}")
elif "content" in result:
print(f"URL: {result['url']}")
if result.get("truncated"):
print("[Content truncated to 10000 chars]")
print(result["content"])
elif "error" in result:
print(f"Error: {result['error']}")
if result.get("available"):
print(f"Available sections: {', '.join(result['available'])}")
else:
print(json.dumps(result, indent=2))
if __name__ == "__main__":
main()
@@ -0,0 +1,181 @@
#!/usr/bin/env bun
export {};
const DOCS_BASE = "https://docs.mem0.ai";
const SEARCH_ENDPOINT = `${DOCS_BASE}/api/search`;
const LLMS_INDEX = `${DOCS_BASE}/llms.txt`;
const SECTION_MAP: Record<string, string[]> = {
platform: [
"/platform/overview",
"/platform/quickstart",
"/platform/features",
"/platform/features/graph-memory",
"/platform/features/selective-memory",
"/platform/features/custom-categories",
"/platform/features/v2-memory-filters",
"/platform/features/async-client",
"/platform/features/webhooks",
"/platform/features/multimodal-support",
],
api: [
"/api-reference/memory/add-memories",
"/api-reference/memory/v2-search-memories",
"/api-reference/memory/v2-get-memories",
"/api-reference/memory/get-memory",
"/api-reference/memory/update-memory",
"/api-reference/memory/delete-memory",
],
"open-source": [
"/open-source/overview",
"/open-source/python-quickstart",
"/open-source/node-quickstart",
"/open-source/features",
"/open-source/features/graph-memory",
"/open-source/features/rest-api",
"/open-source/configure-components",
],
openmemory: [
"/openmemory/overview",
"/openmemory/quickstart",
],
sdks: ["/sdks/python", "/sdks/js"],
integrations: ["/integrations"],
};
async function fetchUrl(url: string): Promise<string> {
try {
const res = await fetch(url, {
headers: { "User-Agent": "Mem0DocSearchAgent/1.0" },
signal: AbortSignal.timeout(15000),
});
if (!res.ok) return `HTTP Error ${res.status}: ${res.statusText}`;
return await res.text();
} catch (e: any) {
return `Error: ${e.message}`;
}
}
async function searchDocs(query: string, section?: string) {
const params = new URLSearchParams({ query });
try {
const result = await fetchUrl(`${SEARCH_ENDPOINT}?${params}`);
const data = JSON.parse(result);
if (data?.results) {
let results = data.results;
if (section && SECTION_MAP[section]) {
const paths = SECTION_MAP[section];
results = results.filter((r: any) =>
paths.some((p) => r.url?.startsWith(p)),
);
}
return { source: "mintlify_search", results };
}
} catch {}
const indexContent = await fetchUrl(LLMS_INDEX);
const queryLower = query.toLowerCase();
let matching = indexContent
.split("\n")
.map((l) => l.trim())
.filter((l) => l && !l.startsWith("#") && l.toLowerCase().includes(queryLower));
if (section && SECTION_MAP[section]) {
const paths = SECTION_MAP[section];
matching = matching.filter((u) => paths.some((p) => u.includes(p)));
}
return {
source: "llms_txt_index",
query,
matching_urls: matching.slice(0, 20),
suggestion: "Fetch specific URLs for detailed content",
};
}
async function fetchPage(pagePath: string) {
const url = pagePath.startsWith("/") ? `${DOCS_BASE}${pagePath}` : pagePath;
const content = await fetchUrl(url);
return { url, content: content.slice(0, 10000), truncated: content.length > 10000 };
}
async function getIndex() {
const content = await fetchUrl(LLMS_INDEX);
const urls = content
.split("\n")
.map((l) => l.trim())
.filter((l) => l && !l.startsWith("#"));
return { total_pages: urls.length, urls, sections: Object.keys(SECTION_MAP) };
}
function listSection(section: string) {
if (!SECTION_MAP[section]) {
return { error: `Unknown section: ${section}`, available: Object.keys(SECTION_MAP) };
}
return { section, pages: SECTION_MAP[section].map((p) => `${DOCS_BASE}${p}`) };
}
function printResult(result: any) {
if (result.results) {
console.log(`Source: ${result.source ?? "unknown"}`);
for (const r of result.results) {
console.log(` - ${r.title ?? "N/A"}: ${r.url ?? "N/A"}`);
if (r.description) console.log(` ${r.description.slice(0, 200)}`);
}
} else if (result.matching_urls) {
console.log(`Source: ${result.source}`);
console.log(`Query: ${result.query}`);
for (const url of result.matching_urls) console.log(` - ${url}`);
if (result.suggestion) console.log(`\n${result.suggestion}`);
} else if (result.urls) {
console.log(`Total documentation pages: ${result.total_pages}`);
console.log(`Sections: ${result.sections.join(", ")}`);
for (const url of result.urls.slice(0, 30)) console.log(` - ${url}`);
if (result.total_pages > 30) console.log(` ... and ${result.total_pages - 30} more`);
} else if (result.pages) {
console.log(`Section: ${result.section}`);
for (const page of result.pages) console.log(` - ${page}`);
} else if (result.content) {
console.log(`URL: ${result.url}`);
if (result.truncated) console.log("[Content truncated to 10000 chars]");
console.log(result.content);
} else if (result.error) {
console.log(`Error: ${result.error}`);
if (result.available) console.log(`Available sections: ${result.available.join(", ")}`);
} else {
console.log(JSON.stringify(result, null, 2));
}
}
const args = process.argv.slice(2);
const flags: Record<string, string | boolean> = {};
for (let i = 0; i < args.length; i++) {
if (args[i] === "--query" && args[i + 1]) flags.query = args[++i];
else if (args[i] === "--page" && args[i + 1]) flags.page = args[++i];
else if (args[i] === "--section" && args[i + 1]) flags.section = args[++i];
else if (args[i] === "--index") flags.index = true;
else if (args[i] === "--json") flags.json = true;
}
let result: any;
if (flags.index) {
result = await getIndex();
} else if (flags.section && !flags.query) {
result = listSection(flags.section as string);
} else if (flags.page) {
result = await fetchPage(flags.page as string);
} else if (flags.query) {
result = await searchDocs(flags.query as string, flags.section as string | undefined);
} else {
console.log("Usage:");
console.log(" bun scripts/mem0_doc_search.ts --query \"topic\"");
console.log(" bun scripts/mem0_doc_search.ts --page \"/platform/features/graph-memory\"");
console.log(" bun scripts/mem0_doc_search.ts --index");
console.log(" bun scripts/mem0_doc_search.ts --section platform");
process.exit(1);
}
if (flags.json) {
console.log(JSON.stringify(result, null, 2));
} else {
printResult(result);
}