yakmesh 2.8.2 → 2.9.0
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/CONTRIBUTING.md +42 -0
- package/adapters/adapter-mlv-bible/README.md +124 -0
- package/adapters/adapter-mlv-bible/index.js +400 -0
- package/adapters/chat-mod-adapter.js +532 -0
- package/adapters/content-adapter.js +273 -0
- package/content/index.js +1 -0
- package/content/store.js +40 -4
- package/embedded-docs/bundle.js +174 -74
- package/mesh/beacon-broadcast.js +109 -0
- package/mesh/darshan.js +1706 -0
- package/mesh/gumba.js +1533 -0
- package/mesh/katha.js +1009 -0
- package/mesh/rate-limiter.js +127 -15
- package/mesh/vani.js +1364 -0
- package/mesh/yurt.js +1285 -0
- package/oracle/network-identity.js +16 -0
- package/oracle/sst.js +579 -0
- package/package.json +1 -1
- package/protocol/yak-protocol.js +22 -8
- package/scripts/update-docs-nav.cjs +194 -0
- package/scripts/update-docs-nav.js +194 -0
- package/security/dharma-moderation.js +516 -0
- package/security/mesh-revocation.js +355 -0
- package/security/sakshi.js +358 -0
- package/update-docs-nav.cjs +18 -0
- package/update-nav.ps1 +16 -0
package/CONTRIBUTING.md
CHANGED
|
@@ -47,6 +47,48 @@ Changes to the timing/oracle layer must:
|
|
|
47
47
|
|
|
48
48
|
---
|
|
49
49
|
|
|
50
|
+
## 📚 Documentation Guidelines
|
|
51
|
+
|
|
52
|
+
### Adding New Documentation Pages
|
|
53
|
+
|
|
54
|
+
When adding new pages to the `docs/` directory:
|
|
55
|
+
|
|
56
|
+
1. **Update the navigation manifest** in `docs/nav-order.json`:
|
|
57
|
+
- Add your new page at the appropriate position in the `pages` array
|
|
58
|
+
- Include: `file`, `icon`, `title`, and `description`
|
|
59
|
+
|
|
60
|
+
2. **Run the navigation update script**:
|
|
61
|
+
```bash
|
|
62
|
+
node scripts/update-docs-nav.cjs
|
|
63
|
+
```
|
|
64
|
+
This automatically updates prev/next links in all affected pages.
|
|
65
|
+
|
|
66
|
+
3. **Update the sidebar** in all doc pages:
|
|
67
|
+
- Add the new page to the sidebar nav list in every `.html` file
|
|
68
|
+
- Use consistent icon and title
|
|
69
|
+
|
|
70
|
+
### Navigation Order
|
|
71
|
+
|
|
72
|
+
The canonical page order is defined in `docs/nav-order.json`. This ensures:
|
|
73
|
+
- Consistent prev/next links across all pages
|
|
74
|
+
- Single source of truth for navigation
|
|
75
|
+
- Easy insertion of new pages without manual link updates
|
|
76
|
+
|
|
77
|
+
**Example: Adding a new page "DHARMA" between KATHA and VANI**
|
|
78
|
+
|
|
79
|
+
1. Edit `docs/nav-order.json`:
|
|
80
|
+
```json
|
|
81
|
+
{ "file": "katha.html", "icon": "💬", "title": "KATHA", "description": "Rich chat" },
|
|
82
|
+
{ "file": "dharma.html", "icon": "☸️", "title": "DHARMA", "description": "New protocol" },
|
|
83
|
+
{ "file": "vani.html", "icon": "🎙️", "title": "VANI", "description": "Voice calls" },
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
2. Run: `node scripts/update-docs-nav.cjs`
|
|
87
|
+
|
|
88
|
+
3. This updates KATHA (next→DHARMA), creates correct links in DHARMA, and updates VANI (prev→DHARMA).
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
50
92
|
## 🏷️ Branding & Trademark
|
|
51
93
|
|
|
52
94
|
**YAKMESH** is a trademark of the YAKMESH Project (PeerQuanta).
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# MLV Bible Adapter for Yakmesh
|
|
2
|
+
|
|
3
|
+
Serve the Modern Literal Version Bible via DARSHAN streaming and enable scripture lookup in KATHA chat.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This adapter demonstrates Yakmesh's **anti-censorship ethos** by enabling peer-to-peer scripture distribution without central servers or gatekeepers.
|
|
8
|
+
|
|
9
|
+
**\\For where two or three are gathered in my name, there am I among them.\\ - Matthew 18:20**
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **📖 PDF Streaming** - Serve MLV Bible PDFs via DARSHAN (view-not-copy paradigm)
|
|
14
|
+
- **🔍 Scripture Lookup** - Reference parser for all 66 books (e.g., \\John 3:16\\)
|
|
15
|
+
- **💬 Chat Commands** - \\/bible\\, \\/mlv\\, \\/verse\\, \\/scripture\\
|
|
16
|
+
- **🔐 Signed Quotes** - Verifiable scripture cards in chat
|
|
17
|
+
- **🌐 Decentralized** - Each user hosts their own copy
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
\\\javascript
|
|
22
|
+
import { MLVBibleAdapter } from '@yakmesh/adapters/adapter-mlv-bible';
|
|
23
|
+
|
|
24
|
+
// Create adapter
|
|
25
|
+
const mlv = new MLVBibleAdapter({
|
|
26
|
+
contentPath: './mlv-content', // Path to your MLV PDFs
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Initialize
|
|
30
|
+
await mlv.init();
|
|
31
|
+
|
|
32
|
+
// Register with DARSHAN for streaming
|
|
33
|
+
await mlv.registerWithDarshan(darshan);
|
|
34
|
+
|
|
35
|
+
// Register with KATHA for chat commands
|
|
36
|
+
mlv.registerWithKatha(katha, chatModRegistry);
|
|
37
|
+
\\\
|
|
38
|
+
|
|
39
|
+
## Content Setup
|
|
40
|
+
|
|
41
|
+
1. Download MLV Bible from [modernliteralversion.org](https://www.modernliteralversion.org)
|
|
42
|
+
2. Place PDF files in your content directory
|
|
43
|
+
3. Optionally create a \\erses.json\\ for instant lookup:
|
|
44
|
+
|
|
45
|
+
\\\json
|
|
46
|
+
{
|
|
47
|
+
\"John 3:16\": \"For God so loved the world...\",
|
|
48
|
+
\"Genesis 1:1\": \"In the beginning God created...\"
|
|
49
|
+
}
|
|
50
|
+
\\\
|
|
51
|
+
|
|
52
|
+
## Chat Commands
|
|
53
|
+
|
|
54
|
+
| Command | Example | Description |
|
|
55
|
+
|---------|---------|-------------|
|
|
56
|
+
| \\/bible\\ | \\/bible John 3:16\\ | Look up a verse |
|
|
57
|
+
| \\/mlv\\ | \\/mlv Gen 1:1-5\\ | Look up a passage |
|
|
58
|
+
| \\/verse\\ | \\/verse Ps 23:1\\ | Look up a verse |
|
|
59
|
+
| \\/scripture\\ | \\/scripture Rom 8:28\\ | Look up a verse |
|
|
60
|
+
|
|
61
|
+
## Creating Your Own Scripture Adapter
|
|
62
|
+
|
|
63
|
+
This adapter serves as a template for other religious texts:
|
|
64
|
+
|
|
65
|
+
\\\javascript
|
|
66
|
+
import { ContentAdapter, CONTENT_CAPABILITIES } from '../content-adapter.js';
|
|
67
|
+
import { ChatModAdapter, ChatModManifest, CHAT_MOD_CAPABILITIES } from '../chat-mod-adapter.js';
|
|
68
|
+
|
|
69
|
+
class MyScriptureAdapter extends ContentAdapter {
|
|
70
|
+
constructor(config) {
|
|
71
|
+
super({
|
|
72
|
+
name: 'My Scripture Name',
|
|
73
|
+
id: 'my-scripture-id',
|
|
74
|
+
capabilities: [
|
|
75
|
+
CONTENT_CAPABILITIES.SERVE_PDF,
|
|
76
|
+
CONTENT_CAPABILITIES.SEARCH_REFERENCE,
|
|
77
|
+
CONTENT_CAPABILITIES.CHAT_QUOTE,
|
|
78
|
+
],
|
|
79
|
+
...config,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async lookupReference(reference) {
|
|
84
|
+
// Parse your reference format
|
|
85
|
+
// Return { reference, text, ... }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
\\\
|
|
89
|
+
|
|
90
|
+
## Security Model
|
|
91
|
+
|
|
92
|
+
### Capability Declaration
|
|
93
|
+
Adapters MUST declare what they can do upfront:
|
|
94
|
+
- \\SERVE_PDF\\ - Can serve PDF content
|
|
95
|
+
- \\CHAT_QUOTE\\ - Can generate chat quotes
|
|
96
|
+
- \\CMD_SLASH\\ - Can handle slash commands
|
|
97
|
+
|
|
98
|
+
### Rate Limiting
|
|
99
|
+
Default: 30 messages per minute to prevent spam.
|
|
100
|
+
|
|
101
|
+
### Signed Responses
|
|
102
|
+
All adapter-generated content includes:
|
|
103
|
+
- Adapter ID and version
|
|
104
|
+
- Manifest hash for verification
|
|
105
|
+
- Timestamp
|
|
106
|
+
|
|
107
|
+
### No Raw Message Access
|
|
108
|
+
Chat adapters only receive sanitized context based on declared capabilities.
|
|
109
|
+
|
|
110
|
+
## Philosophy
|
|
111
|
+
|
|
112
|
+
Yakmesh rejects centralised gatekeeping of religious texts. This adapter embodies:
|
|
113
|
+
|
|
114
|
+
1. **Host Sovereignty** - You control your content
|
|
115
|
+
2. **No Central Server** - Peer-to-peer distribution
|
|
116
|
+
3. **Anti-Censorship** - No authority can block scripture
|
|
117
|
+
4. **Verification** - Mathematical proof replaces human trust
|
|
118
|
+
|
|
119
|
+
*\"Let the one who is thirsty come; and let the one who wishes take the free gift of the water of life.\"* - Revelation 22:17
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
This adapter code is MIT licensed.
|
|
124
|
+
The Modern Literal Version Bible is in the public domain per [modernliteralversion.org](https://www.modernliteralversion.org).
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yakmesh - Modern Literal Version Bible Adapter
|
|
3
|
+
*
|
|
4
|
+
* Serves the Modern Literal Version Bible (https://www.modernliteralversion.org)
|
|
5
|
+
* via DARSHAN streaming and provides scripture lookup for KATHA chat.
|
|
6
|
+
*
|
|
7
|
+
* This adapter demonstrates:
|
|
8
|
+
* 1. ContentAdapter for PDF/document serving
|
|
9
|
+
* 2. ChatModAdapter for scripture commands (/bible, /mlv)
|
|
10
|
+
* 3. Secure, verifiable scripture quoting in chat
|
|
11
|
+
*
|
|
12
|
+
* SCRIPTURE SOVEREIGNTY: Users host their own scripture copies.
|
|
13
|
+
* No central server, no censorship, no manipulation.
|
|
14
|
+
*
|
|
15
|
+
* "For where two or three are gathered in my name,
|
|
16
|
+
* there am I among them." - Matthew 18:20
|
|
17
|
+
*
|
|
18
|
+
* @module adapters/adapter-mlv-bible
|
|
19
|
+
* @version 1.0.0
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { ContentAdapter, ContentMetadata, CONTENT_CAPABILITIES } from '../content-adapter.js';
|
|
23
|
+
import { ChatModAdapter, ChatModManifest, CHAT_MOD_CAPABILITIES } from '../chat-mod-adapter.js';
|
|
24
|
+
import { createReadStream, promises as fs } from 'fs';
|
|
25
|
+
import { join, dirname } from 'path';
|
|
26
|
+
import { fileURLToPath } from 'url';
|
|
27
|
+
|
|
28
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Bible book metadata
|
|
32
|
+
*/
|
|
33
|
+
const BIBLE_BOOKS = {
|
|
34
|
+
// Old Testament
|
|
35
|
+
'Genesis': { abbrev: ['Gen', 'Ge'], chapters: 50, testament: 'OT' },
|
|
36
|
+
'Exodus': { abbrev: ['Ex', 'Exod'], chapters: 40, testament: 'OT' },
|
|
37
|
+
'Leviticus': { abbrev: ['Lev', 'Le'], chapters: 27, testament: 'OT' },
|
|
38
|
+
'Numbers': { abbrev: ['Num', 'Nu'], chapters: 36, testament: 'OT' },
|
|
39
|
+
'Deuteronomy': { abbrev: ['Deut', 'De'], chapters: 34, testament: 'OT' },
|
|
40
|
+
'Joshua': { abbrev: ['Josh', 'Jos'], chapters: 24, testament: 'OT' },
|
|
41
|
+
'Judges': { abbrev: ['Judg', 'Jdg'], chapters: 21, testament: 'OT' },
|
|
42
|
+
'Ruth': { abbrev: ['Ruth', 'Ru'], chapters: 4, testament: 'OT' },
|
|
43
|
+
'1 Samuel': { abbrev: ['1Sam', '1Sa'], chapters: 31, testament: 'OT' },
|
|
44
|
+
'2 Samuel': { abbrev: ['2Sam', '2Sa'], chapters: 24, testament: 'OT' },
|
|
45
|
+
'1 Kings': { abbrev: ['1Ki', '1Kgs'], chapters: 22, testament: 'OT' },
|
|
46
|
+
'2 Kings': { abbrev: ['2Ki', '2Kgs'], chapters: 25, testament: 'OT' },
|
|
47
|
+
'1 Chronicles': { abbrev: ['1Chr', '1Ch'], chapters: 29, testament: 'OT' },
|
|
48
|
+
'2 Chronicles': { abbrev: ['2Chr', '2Ch'], chapters: 36, testament: 'OT' },
|
|
49
|
+
'Ezra': { abbrev: ['Ezra', 'Ezr'], chapters: 10, testament: 'OT' },
|
|
50
|
+
'Nehemiah': { abbrev: ['Neh', 'Ne'], chapters: 13, testament: 'OT' },
|
|
51
|
+
'Esther': { abbrev: ['Est', 'Esth'], chapters: 10, testament: 'OT' },
|
|
52
|
+
'Job': { abbrev: ['Job'], chapters: 42, testament: 'OT' },
|
|
53
|
+
'Psalms': { abbrev: ['Ps', 'Psa', 'Psalm'], chapters: 150, testament: 'OT' },
|
|
54
|
+
'Proverbs': { abbrev: ['Prov', 'Pr'], chapters: 31, testament: 'OT' },
|
|
55
|
+
'Ecclesiastes': { abbrev: ['Ecc', 'Eccl'], chapters: 12, testament: 'OT' },
|
|
56
|
+
'Song of Solomon': { abbrev: ['Song', 'SoS', 'SS'], chapters: 8, testament: 'OT' },
|
|
57
|
+
'Isaiah': { abbrev: ['Isa', 'Is'], chapters: 66, testament: 'OT' },
|
|
58
|
+
'Jeremiah': { abbrev: ['Jer', 'Je'], chapters: 52, testament: 'OT' },
|
|
59
|
+
'Lamentations': { abbrev: ['Lam', 'La'], chapters: 5, testament: 'OT' },
|
|
60
|
+
'Ezekiel': { abbrev: ['Ezek', 'Eze'], chapters: 48, testament: 'OT' },
|
|
61
|
+
'Daniel': { abbrev: ['Dan', 'Da'], chapters: 12, testament: 'OT' },
|
|
62
|
+
'Hosea': { abbrev: ['Hos', 'Ho'], chapters: 14, testament: 'OT' },
|
|
63
|
+
'Joel': { abbrev: ['Joel', 'Joe'], chapters: 3, testament: 'OT' },
|
|
64
|
+
'Amos': { abbrev: ['Amos', 'Am'], chapters: 9, testament: 'OT' },
|
|
65
|
+
'Obadiah': { abbrev: ['Obad', 'Ob'], chapters: 1, testament: 'OT' },
|
|
66
|
+
'Jonah': { abbrev: ['Jonah', 'Jon'], chapters: 4, testament: 'OT' },
|
|
67
|
+
'Micah': { abbrev: ['Mic', 'Mi'], chapters: 7, testament: 'OT' },
|
|
68
|
+
'Nahum': { abbrev: ['Nah', 'Na'], chapters: 3, testament: 'OT' },
|
|
69
|
+
'Habakkuk': { abbrev: ['Hab'], chapters: 3, testament: 'OT' },
|
|
70
|
+
'Zephaniah': { abbrev: ['Zeph', 'Zep'], chapters: 3, testament: 'OT' },
|
|
71
|
+
'Haggai': { abbrev: ['Hag'], chapters: 2, testament: 'OT' },
|
|
72
|
+
'Zechariah': { abbrev: ['Zech', 'Zec'], chapters: 14, testament: 'OT' },
|
|
73
|
+
'Malachi': { abbrev: ['Mal'], chapters: 4, testament: 'OT' },
|
|
74
|
+
|
|
75
|
+
// New Testament
|
|
76
|
+
'Matthew': { abbrev: ['Matt', 'Mt'], chapters: 28, testament: 'NT' },
|
|
77
|
+
'Mark': { abbrev: ['Mark', 'Mk'], chapters: 16, testament: 'NT' },
|
|
78
|
+
'Luke': { abbrev: ['Luke', 'Lk'], chapters: 24, testament: 'NT' },
|
|
79
|
+
'John': { abbrev: ['John', 'Jn'], chapters: 21, testament: 'NT' },
|
|
80
|
+
'Acts': { abbrev: ['Acts', 'Ac'], chapters: 28, testament: 'NT' },
|
|
81
|
+
'Romans': { abbrev: ['Rom', 'Ro'], chapters: 16, testament: 'NT' },
|
|
82
|
+
'1 Corinthians': { abbrev: ['1Cor', '1Co'], chapters: 16, testament: 'NT' },
|
|
83
|
+
'2 Corinthians': { abbrev: ['2Cor', '2Co'], chapters: 13, testament: 'NT' },
|
|
84
|
+
'Galatians': { abbrev: ['Gal', 'Ga'], chapters: 6, testament: 'NT' },
|
|
85
|
+
'Ephesians': { abbrev: ['Eph'], chapters: 6, testament: 'NT' },
|
|
86
|
+
'Philippians': { abbrev: ['Phil', 'Php'], chapters: 4, testament: 'NT' },
|
|
87
|
+
'Colossians': { abbrev: ['Col'], chapters: 4, testament: 'NT' },
|
|
88
|
+
'1 Thessalonians': { abbrev: ['1Thess', '1Th'], chapters: 5, testament: 'NT' },
|
|
89
|
+
'2 Thessalonians': { abbrev: ['2Thess', '2Th'], chapters: 3, testament: 'NT' },
|
|
90
|
+
'1 Timothy': { abbrev: ['1Tim', '1Ti'], chapters: 6, testament: 'NT' },
|
|
91
|
+
'2 Timothy': { abbrev: ['2Tim', '2Ti'], chapters: 4, testament: 'NT' },
|
|
92
|
+
'Titus': { abbrev: ['Titus', 'Tit'], chapters: 3, testament: 'NT' },
|
|
93
|
+
'Philemon': { abbrev: ['Phlm', 'Phm'], chapters: 1, testament: 'NT' },
|
|
94
|
+
'Hebrews': { abbrev: ['Heb'], chapters: 13, testament: 'NT' },
|
|
95
|
+
'James': { abbrev: ['Jas', 'Jam'], chapters: 5, testament: 'NT' },
|
|
96
|
+
'1 Peter': { abbrev: ['1Pet', '1Pe'], chapters: 5, testament: 'NT' },
|
|
97
|
+
'2 Peter': { abbrev: ['2Pet', '2Pe'], chapters: 3, testament: 'NT' },
|
|
98
|
+
'1 John': { abbrev: ['1Jn', '1Jo'], chapters: 5, testament: 'NT' },
|
|
99
|
+
'2 John': { abbrev: ['2Jn', '2Jo'], chapters: 1, testament: 'NT' },
|
|
100
|
+
'3 John': { abbrev: ['3Jn', '3Jo'], chapters: 1, testament: 'NT' },
|
|
101
|
+
'Jude': { abbrev: ['Jude'], chapters: 1, testament: 'NT' },
|
|
102
|
+
'Revelation': { abbrev: ['Rev', 'Re'], chapters: 22, testament: 'NT' },
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse a scripture reference (e.g., \"John 3:16\" or \"Gen 1:1-5\")
|
|
107
|
+
*/
|
|
108
|
+
function parseReference(ref) {
|
|
109
|
+
// Pattern: Book Chapter:Verse(-EndVerse)?
|
|
110
|
+
const pattern = /^(\d?\s*[A-Za-z]+)\s*(\d+):(\d+)(?:-(\d+))?$/;
|
|
111
|
+
const match = ref.trim().match(pattern);
|
|
112
|
+
|
|
113
|
+
if (!match) return null;
|
|
114
|
+
|
|
115
|
+
const [, bookPart, chapter, startVerse, endVerse] = match;
|
|
116
|
+
const bookName = bookPart.trim();
|
|
117
|
+
|
|
118
|
+
// Find the book
|
|
119
|
+
let foundBook = null;
|
|
120
|
+
for (const [name, data] of Object.entries(BIBLE_BOOKS)) {
|
|
121
|
+
if (name.toLowerCase() === bookName.toLowerCase() ||
|
|
122
|
+
data.abbrev.some(a => a.toLowerCase() === bookName.toLowerCase())) {
|
|
123
|
+
foundBook = { name, ...data };
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!foundBook) return null;
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
book: foundBook.name,
|
|
132
|
+
chapter: parseInt(chapter, 10),
|
|
133
|
+
startVerse: parseInt(startVerse, 10),
|
|
134
|
+
endVerse: endVerse ? parseInt(endVerse, 10) : parseInt(startVerse, 10),
|
|
135
|
+
testament: foundBook.testament,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* MLV Bible Content Adapter
|
|
141
|
+
* Serves PDF files and handles scripture lookup
|
|
142
|
+
*/
|
|
143
|
+
export class MLVContentAdapter extends ContentAdapter {
|
|
144
|
+
constructor(config = {}) {
|
|
145
|
+
super({
|
|
146
|
+
name: 'Modern Literal Version Bible',
|
|
147
|
+
id: 'mlv-bible-content',
|
|
148
|
+
capabilities: [
|
|
149
|
+
CONTENT_CAPABILITIES.SERVE_PDF,
|
|
150
|
+
CONTENT_CAPABILITIES.SERVE_TEXT,
|
|
151
|
+
CONTENT_CAPABILITIES.SEARCH_REFERENCE,
|
|
152
|
+
CONTENT_CAPABILITIES.CHAT_QUOTE,
|
|
153
|
+
CONTENT_CAPABILITIES.CHAT_LOOKUP,
|
|
154
|
+
CONTENT_CAPABILITIES.NET_STREAM,
|
|
155
|
+
],
|
|
156
|
+
...config,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Path to MLV content files
|
|
160
|
+
this.contentPath = config.contentPath || join(__dirname, 'content');
|
|
161
|
+
|
|
162
|
+
// In-memory verse index (populated on init)
|
|
163
|
+
this.verseIndex = new Map(); // \"John 3:16\" -> verse text
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async init() {
|
|
167
|
+
// Register PDF files
|
|
168
|
+
try {
|
|
169
|
+
const files = await fs.readdir(this.contentPath);
|
|
170
|
+
|
|
171
|
+
for (const file of files) {
|
|
172
|
+
if (file.endsWith('.pdf')) {
|
|
173
|
+
const filePath = join(this.contentPath, file);
|
|
174
|
+
const stat = await fs.stat(filePath);
|
|
175
|
+
|
|
176
|
+
const id = file.replace('.pdf', '');
|
|
177
|
+
this.catalog.set(id, new ContentMetadata({
|
|
178
|
+
id,
|
|
179
|
+
title: this._formatTitle(id),
|
|
180
|
+
author: 'Modern Literal Version Translation Committee',
|
|
181
|
+
copyright: 'Public Domain / MLV License',
|
|
182
|
+
license: 'Free to distribute - https://www.modernliteralversion.org',
|
|
183
|
+
contentType: 'application/pdf',
|
|
184
|
+
size: stat.size,
|
|
185
|
+
created: stat.birthtime,
|
|
186
|
+
modified: stat.mtime,
|
|
187
|
+
tags: ['bible', 'scripture', 'mlv', 'christianity'],
|
|
188
|
+
}));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Load verse JSON index if present
|
|
192
|
+
if (file === 'verses.json') {
|
|
193
|
+
const data = await fs.readFile(join(this.contentPath, file), 'utf8');
|
|
194
|
+
const verses = JSON.parse(data);
|
|
195
|
+
for (const [ref, text] of Object.entries(verses)) {
|
|
196
|
+
this.verseIndex.set(ref.toLowerCase(), { ref, text });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
} catch (err) {
|
|
201
|
+
// Content directory might not exist yet - that's okay
|
|
202
|
+
console.log('[MLV] No content directory found. Create:', this.contentPath);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
this.emit('initialized', { catalogSize: this.catalog.size });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
_formatTitle(id) {
|
|
209
|
+
// Convert \"mlv-nt\" to \"MLV New Testament\", etc.
|
|
210
|
+
return id
|
|
211
|
+
.replace('mlv-', 'MLV ')
|
|
212
|
+
.replace('nt', 'New Testament')
|
|
213
|
+
.replace('ot', 'Old Testament')
|
|
214
|
+
.replace('complete', 'Complete Bible');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async search(query, options = {}) {
|
|
218
|
+
this.stats.searchQueries++;
|
|
219
|
+
|
|
220
|
+
const results = [];
|
|
221
|
+
const q = query.toLowerCase();
|
|
222
|
+
|
|
223
|
+
for (const [ref, data] of this.verseIndex) {
|
|
224
|
+
if (ref.includes(q) || data.text.toLowerCase().includes(q)) {
|
|
225
|
+
results.push({
|
|
226
|
+
reference: data.ref,
|
|
227
|
+
text: data.text,
|
|
228
|
+
score: ref.includes(q) ? 1.0 : 0.5,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (results.length >= (options.limit || 20)) break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return results.sort((a, b) => b.score - a.score);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async lookupReference(reference) {
|
|
239
|
+
const parsed = parseReference(reference);
|
|
240
|
+
if (!parsed) return null;
|
|
241
|
+
|
|
242
|
+
// Build the lookup key
|
|
243
|
+
const key = \\ \:\\;
|
|
244
|
+
|
|
245
|
+
// Check verse index
|
|
246
|
+
const verse = this.verseIndex.get(key);
|
|
247
|
+
if (verse) {
|
|
248
|
+
return {
|
|
249
|
+
reference: \\ \:\\,
|
|
250
|
+
text: verse.text,
|
|
251
|
+
book: parsed.book,
|
|
252
|
+
chapter: parsed.chapter,
|
|
253
|
+
verse: parsed.startVerse,
|
|
254
|
+
testament: parsed.testament,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// If not in index, return a placeholder indicating lookup needed
|
|
259
|
+
return {
|
|
260
|
+
reference: \\ \:\\,
|
|
261
|
+
text: '[Verse text available in PDF - download MLV from modernliteralversion.org]',
|
|
262
|
+
book: parsed.book,
|
|
263
|
+
chapter: parsed.chapter,
|
|
264
|
+
verse: parsed.startVerse,
|
|
265
|
+
testament: parsed.testament,
|
|
266
|
+
needsFullContent: true,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async getContentStream(id, options = {}) {
|
|
271
|
+
const meta = this.catalog.get(id);
|
|
272
|
+
if (!meta) {
|
|
273
|
+
throw new Error('Content not found: ' + id);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const filePath = join(this.contentPath, id + '.pdf');
|
|
277
|
+
this.stats.contentServed++;
|
|
278
|
+
|
|
279
|
+
return createReadStream(filePath, {
|
|
280
|
+
start: options.start || 0,
|
|
281
|
+
end: options.end,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* MLV Bible Chat Mod Adapter
|
|
288
|
+
* Handles /bible and /mlv commands in KATHA chat
|
|
289
|
+
*/
|
|
290
|
+
export class MLVChatAdapter extends ChatModAdapter {
|
|
291
|
+
constructor(contentAdapter, config = {}) {
|
|
292
|
+
super(
|
|
293
|
+
new ChatModManifest({
|
|
294
|
+
id: 'mlv-bible-chat',
|
|
295
|
+
name: 'MLV Bible Chat',
|
|
296
|
+
version: '1.0.0',
|
|
297
|
+
author: 'Yakmesh Community',
|
|
298
|
+
description: 'Scripture lookup and sharing in chat. Commands: /bible, /mlv',
|
|
299
|
+
capabilities: [
|
|
300
|
+
CHAT_MOD_CAPABILITIES.CMD_SLASH,
|
|
301
|
+
CHAT_MOD_CAPABILITIES.MSG_RESPOND,
|
|
302
|
+
CHAT_MOD_CAPABILITIES.GEN_QUOTE,
|
|
303
|
+
CHAT_MOD_CAPABILITIES.GEN_CARD,
|
|
304
|
+
],
|
|
305
|
+
commands: ['bible', 'mlv', 'scripture', 'verse'],
|
|
306
|
+
triggers: [], // Only respond to explicit commands
|
|
307
|
+
rateLimit: { messages: 30, window: 60000 }, // 30/min for scripture
|
|
308
|
+
}),
|
|
309
|
+
config
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
this.contentAdapter = contentAdapter;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async init() {
|
|
316
|
+
await this.contentAdapter.init();
|
|
317
|
+
this.emit('initialized');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async onCommand(command, args, context) {
|
|
321
|
+
const reference = args.join(' ');
|
|
322
|
+
|
|
323
|
+
if (!reference) {
|
|
324
|
+
return {
|
|
325
|
+
type: 'text',
|
|
326
|
+
content: \Usage: /\ <reference>\nExample: /\ John 3:16\,
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const result = await this.contentAdapter.lookupReference(reference);
|
|
331
|
+
|
|
332
|
+
if (!result) {
|
|
333
|
+
return {
|
|
334
|
+
type: 'text',
|
|
335
|
+
content: \Could not find: \\nCheck the format: Book Chapter:Verse (e.g., John 3:16)\,
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Return a rich scripture card
|
|
340
|
+
return {
|
|
341
|
+
type: 'scripture-card',
|
|
342
|
+
reference: result.reference,
|
|
343
|
+
text: result.text,
|
|
344
|
+
translation: 'Modern Literal Version',
|
|
345
|
+
source: 'https://www.modernliteralversion.org',
|
|
346
|
+
testament: result.testament,
|
|
347
|
+
metadata: {
|
|
348
|
+
adapterId: this.manifest.id,
|
|
349
|
+
timestamp: Date.now(),
|
|
350
|
+
},
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Combined MLV Bible Adapter
|
|
357
|
+
* Convenience class that bundles content + chat functionality
|
|
358
|
+
*/
|
|
359
|
+
export class MLVBibleAdapter {
|
|
360
|
+
constructor(config = {}) {
|
|
361
|
+
this.contentAdapter = new MLVContentAdapter(config);
|
|
362
|
+
this.chatAdapter = new MLVChatAdapter(this.contentAdapter, config);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
async init() {
|
|
366
|
+
await this.contentAdapter.init();
|
|
367
|
+
// Chat adapter shares the content adapter's data
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Register with a DARSHAN instance for content streaming
|
|
372
|
+
*/
|
|
373
|
+
async registerWithDarshan(darshan) {
|
|
374
|
+
this.contentAdapter.darshan = darshan;
|
|
375
|
+
|
|
376
|
+
// Register all PDF content
|
|
377
|
+
for (const [id] of this.contentAdapter.catalog) {
|
|
378
|
+
await this.contentAdapter.registerWithDarshan(id, {
|
|
379
|
+
allowDownload: true, // MLV is freely distributable
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Register with KATHA chat for commands
|
|
386
|
+
*/
|
|
387
|
+
registerWithKatha(katha, registry) {
|
|
388
|
+
registry.register(this.chatAdapter);
|
|
389
|
+
this.chatAdapter.katha = katha;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
getStats() {
|
|
393
|
+
return {
|
|
394
|
+
content: this.contentAdapter.getStats(),
|
|
395
|
+
chat: this.chatAdapter.getStats(),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
export default MLVBibleAdapter;
|