@rikaidev/yomi 0.2.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.
- package/LICENSE +21 -0
- package/NOTICE +81 -0
- package/PRIVACY.md +39 -0
- package/README.md +659 -0
- package/dist/auth/credential-store.js +395 -0
- package/dist/auth/keychain.js +256 -0
- package/dist/cli/login.js +142 -0
- package/dist/line/auth/protocol/e2ee-bootstrap.js +87 -0
- package/dist/line/auth/protocol/index.js +3 -0
- package/dist/line/auth/protocol/login-metadata.js +159 -0
- package/dist/line/auth/protocol/pwless-login-flow.js +83 -0
- package/dist/line/auth/pwless/index.js +163 -0
- package/dist/line/auth/pwless/steps.js +213 -0
- package/dist/line/client/auth-service/client.js +240 -0
- package/dist/line/client/e2ee-service/client.js +69 -0
- package/dist/line/client/e2ee-service/requests.js +92 -0
- package/dist/line/client/e2ee-service/shared-key-log.js +24 -0
- package/dist/line/client/e2ee-service/shared-key-payload.js +35 -0
- package/dist/line/client/index.js +213 -0
- package/dist/line/client/obs-media-client.js +140 -0
- package/dist/line/client/parsers.js +69 -0
- package/dist/line/client/shop-service/client.js +63 -0
- package/dist/line/client/sticker-meta.js +46 -0
- package/dist/line/client/sync-service/client.js +317 -0
- package/dist/line/client/talk-service/chat-query.js +122 -0
- package/dist/line/client/talk-service/command-client.js +242 -0
- package/dist/line/client/talk-service/contact-query.js +77 -0
- package/dist/line/client/talk-service/message-box-query.js +137 -0
- package/dist/line/client/talk-service/message-id-query.js +241 -0
- package/dist/line/client/talk-service/query-client.js +219 -0
- package/dist/line/client/talk-service/requests.js +383 -0
- package/dist/line/client/transport.js +138 -0
- package/dist/line/core/auth-session-logout.js +55 -0
- package/dist/line/core/auth-session-runtime.js +231 -0
- package/dist/line/core/auth-session-service.js +85 -0
- package/dist/line/core/chat-runtime-service.js +343 -0
- package/dist/line/core/client-runtime.js +17 -0
- package/dist/line/core/config.js +67 -0
- package/dist/line/core/constants.js +56 -0
- package/dist/line/core/contact-query-service.js +20 -0
- package/dist/line/core/directory-runtime-service.js +83 -0
- package/dist/line/core/e2ee/bootstrap/keychain.js +41 -0
- package/dist/line/core/e2ee/crypto/crypto-primitives.js +98 -0
- package/dist/line/core/e2ee/index.js +6 -0
- package/dist/line/core/e2ee/keys/decrypt.js +110 -0
- package/dist/line/core/e2ee/keys/encrypt.js +117 -0
- package/dist/line/core/e2ee/keys/group-key.js +260 -0
- package/dist/line/core/e2ee/keys/key-manager.js +231 -0
- package/dist/line/core/e2ee/keys/key-payload.js +130 -0
- package/dist/line/core/e2ee/keys/key-types.js +1 -0
- package/dist/line/core/e2ee/keys/message-crypto.js +146 -0
- package/dist/line/core/e2ee/keys/message-decrypt.js +390 -0
- package/dist/line/core/e2ee/keys/peer-key.js +191 -0
- package/dist/line/core/e2ee/recovery/bootstrap-keys.js +161 -0
- package/dist/line/core/e2ee/types.js +4 -0
- package/dist/line/core/group-query-service.js +20 -0
- package/dist/line/core/media-decrypt.js +78 -0
- package/dist/line/core/media-encrypt.js +97 -0
- package/dist/line/core/mention.js +89 -0
- package/dist/line/core/message-command-service.js +454 -0
- package/dist/line/core/message-query-service.js +161 -0
- package/dist/line/core/service.js +134 -0
- package/dist/line/core/session-state/index.js +243 -0
- package/dist/line/core/session-state/persist.js +192 -0
- package/dist/line/core/store.js +8 -0
- package/dist/line/core/thrift/binary/binary-reader.js +151 -0
- package/dist/line/core/thrift/binary/binary-writer.js +157 -0
- package/dist/line/core/thrift/binary/type-codec-dsl.js +42 -0
- package/dist/line/core/thrift/compact/compact-reader.js +180 -0
- package/dist/line/core/thrift/compact/compact-writer.js +161 -0
- package/dist/line/core/thrift/compact/type-codec-dsl.js +66 -0
- package/dist/line/core/thrift/fields/builders.js +124 -0
- package/dist/line/core/thrift/index.js +12 -0
- package/dist/line/core/thrift/message/decoder.js +55 -0
- package/dist/line/core/thrift/message/encoder.js +25 -0
- package/dist/line/core/thrift/primitives/varint.js +64 -0
- package/dist/line/core/thrift/struct/reader.js +172 -0
- package/dist/line/core/thrift/struct/writer.js +189 -0
- package/dist/line/core/thrift/types.js +23 -0
- package/dist/line/core/video-thumbnail.js +104 -0
- package/dist/mcp/handlers/contacts.js +166 -0
- package/dist/mcp/handlers/conversations.js +193 -0
- package/dist/mcp/handlers/groups.js +123 -0
- package/dist/mcp/handlers/index.js +15 -0
- package/dist/mcp/handlers/login.js +473 -0
- package/dist/mcp/handlers/media.js +69 -0
- package/dist/mcp/handlers/message-actions.js +62 -0
- package/dist/mcp/handlers/scope.js +120 -0
- package/dist/mcp/handlers/search.js +196 -0
- package/dist/mcp/handlers/send.js +523 -0
- package/dist/mcp/handlers/shared.js +84 -0
- package/dist/mcp/handlers/stickers.js +87 -0
- package/dist/mcp/media.js +228 -0
- package/dist/mcp/names.js +133 -0
- package/dist/mcp/phi-guard.js +105 -0
- package/dist/mcp/policy.js +34 -0
- package/dist/mcp/server.js +301 -0
- package/dist/mcp/tools.js +761 -0
- package/dist/mcp/ui/capability.js +26 -0
- package/dist/mcp/ui/login-app-protocol.js +118 -0
- package/dist/mcp/ui/login-app-styles.js +142 -0
- package/dist/mcp/ui/login-app-view.js +361 -0
- package/dist/mcp/ui/login-app.js +72 -0
- package/dist/mcp/ui/login-structured-content.js +1 -0
- package/dist/mcp/ui/resource.js +35 -0
- package/dist/mcp/ui/tools-with-ui.js +40 -0
- package/dist/search/bigram.js +86 -0
- package/dist/search/capture.js +140 -0
- package/dist/search/collector.js +176 -0
- package/dist/search/default-embedder.js +101 -0
- package/dist/search/embedder.js +13 -0
- package/dist/search/scope.js +142 -0
- package/dist/search/sqlite.js +141 -0
- package/dist/search/store.js +469 -0
- package/dist/util/data-dir.js +55 -0
- package/dist/util/log.js +86 -0
- package/dist/version.js +7 -0
- package/package.json +63 -0
- package/run.mjs +71 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Yomi conversation scoping — a DENYLIST of chats excluded from capture.
|
|
3
|
+
*
|
|
4
|
+
* Default behavior is capture-everything: every conversation is indexed by
|
|
5
|
+
* ../search/collector.ts unless its chatId appears in the `excluded_chats`
|
|
6
|
+
* table this module owns. Excluding a chat does two things, not one:
|
|
7
|
+
* 1. Blocks future capture — collectMessages drops excluded chatIds
|
|
8
|
+
* before fetching (see ../search/collector.ts).
|
|
9
|
+
* 2. Purges past capture — deleteMessagesForChats removes that chat's
|
|
10
|
+
* already-indexed messages AND their embeddings, so excluding a
|
|
11
|
+
* conversation actually removes what was already learned about it
|
|
12
|
+
* rather than just freezing the index in place. A denylist that only
|
|
13
|
+
* blocked future capture while leaving old data behind would be fake
|
|
14
|
+
* privacy.
|
|
15
|
+
*
|
|
16
|
+
* Shares the same node:sqlite connection as ../search/store.ts via the
|
|
17
|
+
* exported getDb(), so this table lives in the same search-index.db file
|
|
18
|
+
* rather than a second database.
|
|
19
|
+
*/
|
|
20
|
+
import { getDb } from './store.js';
|
|
21
|
+
let tableEnsured = false;
|
|
22
|
+
/**
|
|
23
|
+
* Create the `excluded_chats` table if it does not already exist. Memoized
|
|
24
|
+
* per process (mirrors getDb()'s own memoization) so every public function
|
|
25
|
+
* in this module can safely call it without repeating the DDL on every
|
|
26
|
+
* invocation.
|
|
27
|
+
*/
|
|
28
|
+
function ensureExcludedTable() {
|
|
29
|
+
if (tableEnsured) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const handle = getDb();
|
|
33
|
+
handle.exec(`
|
|
34
|
+
CREATE TABLE IF NOT EXISTS excluded_chats (
|
|
35
|
+
chatId TEXT PRIMARY KEY NOT NULL
|
|
36
|
+
);
|
|
37
|
+
`);
|
|
38
|
+
tableEnsured = true;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build a `(?, ?, ...)` placeholder group sized to `values.length`, for use
|
|
42
|
+
* in an `IN (...)` clause. Callers must pass `values` itself (in the same
|
|
43
|
+
* order) as the bound parameters — this never string-interpolates the
|
|
44
|
+
* values themselves, only the `?` count.
|
|
45
|
+
*
|
|
46
|
+
* @param values - Values the IN-clause will be matched against.
|
|
47
|
+
* @returns Placeholder group, e.g. `(?, ?, ?)`.
|
|
48
|
+
*/
|
|
49
|
+
function buildPlaceholders(values) {
|
|
50
|
+
return `(${values.map(() => '?').join(', ')})`;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* List every chatId currently on the exclusion denylist.
|
|
54
|
+
*
|
|
55
|
+
* @returns Set of excluded chatIds (empty when the denylist is empty).
|
|
56
|
+
*/
|
|
57
|
+
export function getExcludedChatIds() {
|
|
58
|
+
ensureExcludedTable();
|
|
59
|
+
const handle = getDb();
|
|
60
|
+
const rows = handle
|
|
61
|
+
.prepare('SELECT chatId FROM excluded_chats;')
|
|
62
|
+
.all();
|
|
63
|
+
return new Set(rows.map((row) => row.chatId));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Add chatIds to the exclusion denylist. Idempotent: chatIds already
|
|
67
|
+
* present are silently skipped (INSERT OR IGNORE), never duplicated or
|
|
68
|
+
* erroring.
|
|
69
|
+
*
|
|
70
|
+
* @param chatIds - Chat MIDs to exclude from future capture.
|
|
71
|
+
* @returns Number of chatIds now covered by this call (rows inserted or
|
|
72
|
+
* already present among the input).
|
|
73
|
+
*/
|
|
74
|
+
export function addExcludedChatIds(chatIds) {
|
|
75
|
+
if (chatIds.length === 0) {
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
ensureExcludedTable();
|
|
79
|
+
const handle = getDb();
|
|
80
|
+
const stmt = handle.prepare('INSERT OR IGNORE INTO excluded_chats (chatId) VALUES (?);');
|
|
81
|
+
const insertAll = handle.transaction((ids) => {
|
|
82
|
+
for (const id of ids) {
|
|
83
|
+
stmt.run(id);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
insertAll(chatIds);
|
|
87
|
+
return chatIds.length;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Remove chatIds from the exclusion denylist, re-allowing future capture.
|
|
91
|
+
* Does NOT re-fetch or re-index anything that was previously purged — the
|
|
92
|
+
* next `collect_messages`/`search_messages` auto-collect will pick the
|
|
93
|
+
* chat back up.
|
|
94
|
+
*
|
|
95
|
+
* @param chatIds - Chat MIDs to remove from the denylist.
|
|
96
|
+
* @returns Number of rows actually removed.
|
|
97
|
+
*/
|
|
98
|
+
export function removeExcludedChatIds(chatIds) {
|
|
99
|
+
if (chatIds.length === 0) {
|
|
100
|
+
return 0;
|
|
101
|
+
}
|
|
102
|
+
ensureExcludedTable();
|
|
103
|
+
const handle = getDb();
|
|
104
|
+
const placeholders = buildPlaceholders(chatIds);
|
|
105
|
+
const result = handle
|
|
106
|
+
.prepare(`DELETE FROM excluded_chats WHERE chatId IN ${placeholders};`)
|
|
107
|
+
.run(...chatIds);
|
|
108
|
+
return result.changes;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Purge already-indexed data for the given chats: their embeddings, then
|
|
112
|
+
* their messages, in one transaction. This is what makes exclusion an
|
|
113
|
+
* actual privacy action rather than just a future-capture filter — a chat
|
|
114
|
+
* that gets excluded loses what was already learned about it, not just
|
|
115
|
+
* what would have been learned next. The `messages_fts` external-content
|
|
116
|
+
* index stays in sync automatically via the AFTER DELETE trigger on
|
|
117
|
+
* `messages` (see ../search/store.ts), so it is never touched directly
|
|
118
|
+
* here.
|
|
119
|
+
*
|
|
120
|
+
* @param chatIds - Chat MIDs whose indexed messages + embeddings should be deleted.
|
|
121
|
+
* @returns Number of `messages` rows deleted.
|
|
122
|
+
*/
|
|
123
|
+
export function deleteMessagesForChats(chatIds) {
|
|
124
|
+
if (chatIds.length === 0) {
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
const handle = getDb();
|
|
128
|
+
const placeholders = buildPlaceholders(chatIds);
|
|
129
|
+
const purge = handle.transaction((ids) => {
|
|
130
|
+
// Count the target rows FIRST: the DELETE's own `.changes` on `messages`
|
|
131
|
+
// is inflated by the AFTER DELETE trigger that maintains messages_fts
|
|
132
|
+
// (one fts write per deleted row), so it cannot serve as the purged
|
|
133
|
+
// count. An explicit COUNT is trigger-independent and honest.
|
|
134
|
+
const counted = handle
|
|
135
|
+
.prepare(`SELECT COUNT(*) as c FROM messages WHERE chatId IN ${placeholders};`)
|
|
136
|
+
.get(...ids);
|
|
137
|
+
handle.exec(`DELETE FROM embeddings WHERE messageId IN (SELECT messageId FROM messages WHERE chatId IN ${placeholders});`, ids);
|
|
138
|
+
handle.exec(`DELETE FROM messages WHERE chatId IN ${placeholders};`, ids);
|
|
139
|
+
return counted?.c ?? 0;
|
|
140
|
+
});
|
|
141
|
+
return purge(chatIds);
|
|
142
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime-agnostic SQLite wrapper — uses bun:sqlite in bun, node:sqlite in node.
|
|
3
|
+
*
|
|
4
|
+
* The APIs differ:
|
|
5
|
+
* - bun: Database → .run(sql, params?) .query(sql).get(params?) .query(sql).all(params?) .transaction(fn)
|
|
6
|
+
* - node: DatabaseSync → .exec(sql) .prepare(sql).get(params?) .prepare(sql).all(params?) (no .transaction)
|
|
7
|
+
*
|
|
8
|
+
* This module exports a unified `Database` class that normalizes both to the
|
|
9
|
+
* same surface, so the rest of the codebase never cares which runtime it's on.
|
|
10
|
+
*/
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
const isBun = typeof process.versions.bun !== 'undefined';
|
|
13
|
+
// The sqlite binding has to be picked at runtime, not import time: `bun:sqlite`
|
|
14
|
+
// does not exist under node and vice versa, so a static import would fail on
|
|
15
|
+
// whichever runtime is not running. That means a require — but this package is
|
|
16
|
+
// `"type": "module"`, and a bare `require` in ESM only works because bun allows
|
|
17
|
+
// it as an extension. Under node it is a ReferenceError, which is why every
|
|
18
|
+
// index-backed tool (search, scope, capture, policy) died with
|
|
19
|
+
// "require is not defined" once the server ran on node rather than bun.
|
|
20
|
+
// createRequire gives ESM a real require that both runtimes honor.
|
|
21
|
+
const runtimeRequire = createRequire(import.meta.url);
|
|
22
|
+
function wrapBunDb(raw) {
|
|
23
|
+
return {
|
|
24
|
+
exec(sql) {
|
|
25
|
+
raw.run(sql);
|
|
26
|
+
},
|
|
27
|
+
prepare(sql) {
|
|
28
|
+
const q = raw.query(sql);
|
|
29
|
+
return {
|
|
30
|
+
run(...params) {
|
|
31
|
+
return q.get(...params);
|
|
32
|
+
},
|
|
33
|
+
get(...params) {
|
|
34
|
+
return q.get(...params);
|
|
35
|
+
},
|
|
36
|
+
all(...params) {
|
|
37
|
+
return q.all(...params);
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
transaction: raw.transaction.bind(raw),
|
|
42
|
+
close() {
|
|
43
|
+
raw.close();
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function wrapNodeDb(raw) {
|
|
48
|
+
return {
|
|
49
|
+
exec(sql, params) {
|
|
50
|
+
if (params && params.length > 0) {
|
|
51
|
+
const stmt = raw.prepare(sql);
|
|
52
|
+
stmt.run(...params);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
raw.exec(sql);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
prepare(sql) {
|
|
59
|
+
const stmt = raw.prepare(sql);
|
|
60
|
+
return {
|
|
61
|
+
run(...params) {
|
|
62
|
+
return stmt.run(...params);
|
|
63
|
+
},
|
|
64
|
+
get(...params) {
|
|
65
|
+
return stmt.get(...params);
|
|
66
|
+
},
|
|
67
|
+
all(...params) {
|
|
68
|
+
return stmt.all(...params);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
},
|
|
72
|
+
transaction(fn) {
|
|
73
|
+
const wrapped = (...args) => {
|
|
74
|
+
raw.exec('BEGIN');
|
|
75
|
+
try {
|
|
76
|
+
const result = fn(...args);
|
|
77
|
+
raw.exec('COMMIT');
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
catch (e) {
|
|
81
|
+
raw.exec('ROLLBACK');
|
|
82
|
+
throw e;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
return wrapped;
|
|
86
|
+
},
|
|
87
|
+
close() {
|
|
88
|
+
raw.close();
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Node versions carrying an unflagged `node:sqlite`.
|
|
94
|
+
*
|
|
95
|
+
* It was unflagged in 22.13.0 and 23.4.0 (nodejs/node#55890), so the 23 line
|
|
96
|
+
* splits: 23.0–23.3 are NEWER than 22.13 yet still lack it, which a plain
|
|
97
|
+
* `>=22.13.0` floor would wrongly admit. Keep this in step with
|
|
98
|
+
* package.json's `engines.node`.
|
|
99
|
+
*/
|
|
100
|
+
const NODE_SQLITE_REQUIREMENT = '22.13+ (or 23.4+ on the 23.x line)';
|
|
101
|
+
/** Thrown when the running runtime has no SQLite module at all. */
|
|
102
|
+
export class SqliteUnavailableError extends Error {
|
|
103
|
+
constructor(message) {
|
|
104
|
+
super(message);
|
|
105
|
+
this.name = 'SqliteUnavailableError';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Open a SQLite database at the given path. Creates the file if it doesn't exist.
|
|
110
|
+
*
|
|
111
|
+
* @param path - Database file path.
|
|
112
|
+
* @returns Runtime-agnostic database handle.
|
|
113
|
+
* @throws SqliteUnavailableError when the runtime predates `node:sqlite`.
|
|
114
|
+
*/
|
|
115
|
+
export function openDatabase(path) {
|
|
116
|
+
if (isBun) {
|
|
117
|
+
const mod = runtimeRequire('bun:sqlite');
|
|
118
|
+
return wrapBunDb(new mod.Database(path));
|
|
119
|
+
}
|
|
120
|
+
let mod;
|
|
121
|
+
try {
|
|
122
|
+
mod = runtimeRequire('node:sqlite');
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
// Runtimes without it throw "No such built-in module: node:sqlite", which
|
|
126
|
+
// tells a user nothing about what to change. `engines` does not help: npm
|
|
127
|
+
// only warns at install time, and npx ignores it entirely.
|
|
128
|
+
//
|
|
129
|
+
// The trap worth naming is that the node running this is often not the one
|
|
130
|
+
// the user configured. An MCP client launches the server through `npx`,
|
|
131
|
+
// whose `#!/usr/bin/env node` resolves against the CLIENT's PATH — so the
|
|
132
|
+
// runtime can be any node on that PATH regardless of which npx was named.
|
|
133
|
+
// Report the actual execPath rather than assume the user can guess it.
|
|
134
|
+
throw new SqliteUnavailableError(`This Node cannot open Yomi's message index: ${process.version} has no built-in \`node:sqlite\` (needs ${NODE_SQLITE_REQUIREMENT}). ` +
|
|
135
|
+
`Live tools still work; search, scope and capture do not. ` +
|
|
136
|
+
`The runtime is ${process.execPath} — an MCP client resolves \`node\` from its own PATH, so this may not be the node you expect. ` +
|
|
137
|
+
`Point the client at a supported node and restart it. ` +
|
|
138
|
+
`Original error: ${error?.message ?? String(error)}`);
|
|
139
|
+
}
|
|
140
|
+
return wrapNodeDb(new mod.DatabaseSync(path));
|
|
141
|
+
}
|