Initial Arka plugin registry: Official plugins mirror + Arka-signed index

11 plugins from github.com/librefang/librefang-registry plugins/.
index.json / index.json.sig are signed with Arka's Ed25519 key
(not upstream stats.librefang.ai). Private key is not in this repo.
This commit is contained in:
ixoblakp committed 2026-09-01 10:22:07 +03:00
commit 8dec8f6038
62 files changed
+5189

No files matched your search

+148
View File
@@ -0,0 +1,148 @@
#!/usr/bin/env python3
"""Keyword memory ingest hook.
Extracts keywords and named entities from user messages and returns
them as contextual memories so agents have topic awareness.
Receives via stdin:
{"type": "ingest", "agent_id": "...", "message": "user message text"}
Prints to stdout:
{"type": "ingest_result", "memories": [{"content": "..."}]}
"""
import json
import re
import sys
# Compact English stopword set (~50 common words)
STOPWORDS = frozenset({
"a", "an", "the", "and", "or", "but", "in", "on", "at", "to", "for",
"of", "with", "by", "from", "is", "are", "was", "were", "be", "been",
"being", "have", "has", "had", "do", "does", "did", "will", "would",
"could", "should", "may", "might", "shall", "can", "need", "must",
"it", "its", "i", "me", "my", "you", "your", "he", "she", "we",
"they", "them", "their", "this", "that", "these", "those", "what",
"which", "who", "how", "when", "where", "why", "if", "then", "so",
"not", "no", "just", "also", "very", "too", "about", "up", "out",
"all", "some", "any", "each", "every", "into", "over", "after",
})
# Minimum word length for plain keyword extraction
MIN_WORD_LEN = 3
# Maximum keywords to return
MAX_KEYWORDS = 10
# Pattern: email addresses
RE_EMAIL = re.compile(r"[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}")
# Pattern: URLs (http/https/ftp) — excludes trailing punctuation
RE_URL = re.compile(r"https?://[^\s,)>]+(?<=[a-zA-Z0-9/])|ftp://[^\s,)>]+(?<=[a-zA-Z0-9/])")
# Pattern: numbers with units (e.g. 500ms, 10GB, 3.5GHz, 200k)
RE_NUMBER_UNIT = re.compile(r"\b\d+(?:\.\d+)?(?:ms|s|min|hr|h|kb|mb|gb|tb|ghz|mhz|hz|k|m|px|em|rem|%)\b", re.IGNORECASE)
# Pattern: dates (YYYY-MM-DD, MM/DD/YYYY, DD.MM.YYYY)
RE_DATE = re.compile(
r"\b\d{4}-\d{2}-\d{2}\b"
r"|\b\d{1,2}/\d{1,2}/\d{2,4}\b"
r"|\b\d{1,2}\.\d{1,2}\.\d{2,4}\b"
)
# Pattern: camelCase or PascalCase identifiers
RE_CAMEL = re.compile(r"\b[a-z]+(?:[A-Z][a-z0-9]+)+\b|\b(?:[A-Z][a-z0-9]+){2,}\b")
# Pattern: snake_case identifiers (at least one underscore)
RE_SNAKE = re.compile(r"\b[a-zA-Z][a-zA-Z0-9]*(?:_[a-zA-Z0-9]+)+\b")
# Pattern: dotted technical terms (e.g. api.endpoint, os.path)
RE_DOTTED = re.compile(r"\b[a-zA-Z][a-zA-Z0-9]*(?:\.[a-zA-Z][a-zA-Z0-9]*)+\b")
def extract_patterns(text):
"""Extract structured patterns: emails, URLs, numbers+units, dates, tech terms."""
found = []
for pattern in (RE_EMAIL, RE_URL, RE_NUMBER_UNIT, RE_DATE, RE_CAMEL, RE_SNAKE, RE_DOTTED):
found.extend(pattern.findall(text))
return found
def extract_capitalized_phrases(text):
"""Detect consecutive capitalized words (likely proper nouns / named entities).
Skips single capitalized words at sentence boundaries by requiring
either multi-word phrases or mid-sentence capitalized words.
"""
phrases = []
# Find sequences of 2+ capitalized words
for match in re.finditer(r"\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\b", text):
phrases.append(match.group(0))
# Find single capitalized words that are NOT at sentence start
# (preceded by a lowercase letter, comma, or mid-sentence punctuation)
for match in re.finditer(r"(?<=[a-z,;]\s)([A-Z][a-zA-Z0-9]+)\b", text):
word = match.group(1)
if word.lower() not in STOPWORDS and len(word) >= MIN_WORD_LEN:
phrases.append(word)
return phrases
def extract_plain_keywords(text):
"""Split text into words and filter out stopwords and short tokens."""
# Remove URLs and emails first so they don't pollute word splitting
cleaned = RE_URL.sub(" ", text)
cleaned = RE_EMAIL.sub(" ", cleaned)
# Split on non-alphanumeric (keep hyphens inside words)
words = re.findall(r"[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9]|[a-zA-Z]", cleaned)
keywords = []
for w in words:
lower = w.lower()
if lower not in STOPWORDS and len(lower) >= MIN_WORD_LEN:
keywords.append(lower)
return keywords
def deduplicate_keywords(items):
"""Deduplicate while preserving insertion order. Case-insensitive for plain words."""
seen = set()
result = []
for item in items:
key = item.lower()
if key not in seen:
seen.add(key)
result.append(item)
return result
def main():
request = json.loads(sys.stdin.read())
message = request.get("message", "")
if not message.strip():
print(json.dumps({"type": "ingest_result", "memories": []}))
return
# Collect keywords from all extraction methods (patterns first for priority)
all_keywords = []
all_keywords.extend(extract_patterns(message))
all_keywords.extend(extract_capitalized_phrases(message))
all_keywords.extend(extract_plain_keywords(message))
# Deduplicate and cap at MAX_KEYWORDS
keywords = deduplicate_keywords(all_keywords)[:MAX_KEYWORDS]
if not keywords:
print(json.dumps({"type": "ingest_result", "memories": []}))
return
topic_str = ", ".join(keywords)
memories = [
{"content": f"[keyword-memory] Key topics: {topic_str}"}
]
print(json.dumps({"type": "ingest_result", "memories": memories}))
if __name__ == "__main__":
main()