@rikaidev/yomi 0.3.1 → 0.4.1
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/PRIVACY.md +14 -0
- package/README.md +3 -0
- package/dist/auth/credential-store.js +11 -1
- package/dist/mcp/client-capabilities.js +55 -0
- package/dist/mcp/handlers/login-copy.js +200 -0
- package/dist/mcp/handlers/login-mrtr.js +150 -0
- package/dist/mcp/handlers/login-session.js +132 -0
- package/dist/mcp/handlers/login.js +67 -239
- package/dist/mcp/server.js +191 -229
- package/dist/mcp/tools.js +3 -14
- package/dist/mcp/ui/resource.js +3 -3
- package/dist/mcp/ui/tools-with-ui.js +3 -4
- package/dist/util/update-check.js +121 -0
- package/dist/version.js +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Is this copy of Yomi out of date?" — asked once at startup, answered to
|
|
3
|
+
* the model through the MCP `instructions` so it can tell the human.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: the drag-and-drop `.mcpb` bundle has NO auto-update. The
|
|
6
|
+
* MCPB manifest spec defines no update URL or endpoint (its `version` is
|
|
7
|
+
* plain metadata), and Claude Desktop only auto-updates extensions installed
|
|
8
|
+
* from the official directory — "for privately distributed extensions, users
|
|
9
|
+
* will need to install updated .mcpb files manually". Yomi's bundles are
|
|
10
|
+
* attached to GitHub Releases, so without this a user can sit on an old
|
|
11
|
+
* build indefinitely without ever knowing.
|
|
12
|
+
*
|
|
13
|
+
* It cannot self-update: a bundle carries native binaries (onnxruntime-node,
|
|
14
|
+
* sharp) and overwriting itself while running is neither safe nor portable.
|
|
15
|
+
* Telling the human, with the right link for how they installed, is the whole
|
|
16
|
+
* scope.
|
|
17
|
+
*
|
|
18
|
+
* PRIVACY. This is the ONE outbound request Yomi makes that is not to LINE,
|
|
19
|
+
* and it is disclosed in PRIVACY.md. It sends no message content and no
|
|
20
|
+
* account identifier — it is a plain GET of a public npm registry document.
|
|
21
|
+
* What it does reveal to the registry is that some IP is running Yomi, and
|
|
22
|
+
* (by what it does with the answer) roughly which version. `YOMI_NO_UPDATE_CHECK=1`
|
|
23
|
+
* turns it off completely.
|
|
24
|
+
*/
|
|
25
|
+
import { YOMI_VERSION } from '../version.js';
|
|
26
|
+
/**
|
|
27
|
+
* The registry document for the published package. Queried directly rather
|
|
28
|
+
* than through `npm view`, which reads a CDN-cached view that lags behind a
|
|
29
|
+
* publish by minutes.
|
|
30
|
+
*/
|
|
31
|
+
const LATEST_URL = 'https://registry.npmjs.org/@rikaidev/yomi/latest';
|
|
32
|
+
/** How long the check may take before startup gives up on it. */
|
|
33
|
+
const TIMEOUT_MS = 1500;
|
|
34
|
+
/**
|
|
35
|
+
* Compare two semver core versions (`major.minor.patch`).
|
|
36
|
+
*
|
|
37
|
+
* Pre-release suffixes are ignored on BOTH sides, which is deliberate: the
|
|
38
|
+
* only question here is "is a newer release available", and a local
|
|
39
|
+
* pre-release of the same core version should not nag.
|
|
40
|
+
*
|
|
41
|
+
* @param a - Left version.
|
|
42
|
+
* @param b - Right version.
|
|
43
|
+
* @returns Positive when `a` is newer, negative when older, 0 when equal.
|
|
44
|
+
*/
|
|
45
|
+
export function compareVersions(a, b) {
|
|
46
|
+
const parse = (value) => value
|
|
47
|
+
.trim()
|
|
48
|
+
.replace(/^v/, '')
|
|
49
|
+
.split('-')[0]
|
|
50
|
+
.split('.')
|
|
51
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
52
|
+
const left = parse(a);
|
|
53
|
+
const right = parse(b);
|
|
54
|
+
for (let i = 0; i < 3; i++) {
|
|
55
|
+
const diff = (left[i] ?? 0) - (right[i] ?? 0);
|
|
56
|
+
if (diff !== 0) {
|
|
57
|
+
return diff;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* How this copy of Yomi was installed, which decides what "update" means.
|
|
64
|
+
* The `.mcpb` build stamps `YOMI_DISTRIBUTION=mcpb` into the manifest's
|
|
65
|
+
* server env (scripts/build-mcpb.mjs); anything else is an npm/npx install.
|
|
66
|
+
*
|
|
67
|
+
* @returns The distribution channel.
|
|
68
|
+
*/
|
|
69
|
+
function distribution() {
|
|
70
|
+
return process.env.YOMI_DISTRIBUTION === 'mcpb' ? 'mcpb' : 'npm';
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Build the notice handed to the model when a newer version exists.
|
|
74
|
+
*
|
|
75
|
+
* @param latest - The newest published version.
|
|
76
|
+
* @returns Notice text, phrased for how this copy was installed.
|
|
77
|
+
*/
|
|
78
|
+
export function updateNotice(latest) {
|
|
79
|
+
const how = distribution() === 'mcpb'
|
|
80
|
+
? 'Desktop Extension bundles do NOT auto-update when installed by hand: the human has to ' +
|
|
81
|
+
'download the new .mcpb for their platform from ' +
|
|
82
|
+
'https://github.com/RikaiDev/yomi/releases/latest and drag it into Claude Desktop again ' +
|
|
83
|
+
'(same extension, it replaces this one).'
|
|
84
|
+
: 'Update with `npx @rikaidev/yomi@latest` (or reinstall the package) to pick it up.';
|
|
85
|
+
return (`UPDATE AVAILABLE — this Yomi is ${YOMI_VERSION}; ${latest} has been published. ` +
|
|
86
|
+
`${how} Mention this ONCE, early, in your own words, then carry on with what the user ` +
|
|
87
|
+
'asked — it is not urgent and never a reason to refuse work.');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Ask the registry whether a newer Yomi has been published.
|
|
91
|
+
*
|
|
92
|
+
* Best-effort by construction: offline, slow, rate-limited, or malformed
|
|
93
|
+
* answers all resolve to `null`. A version check must never delay or fail a
|
|
94
|
+
* server that is otherwise ready to work.
|
|
95
|
+
*
|
|
96
|
+
* @returns The notice text when an update exists, otherwise null.
|
|
97
|
+
*/
|
|
98
|
+
export async function checkForUpdate() {
|
|
99
|
+
if (process.env.YOMI_NO_UPDATE_CHECK === '1') {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const response = await fetch(LATEST_URL, {
|
|
104
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
105
|
+
headers: { accept: 'application/json' },
|
|
106
|
+
});
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
const body = (await response.json());
|
|
111
|
+
const latest = typeof body.version === 'string' ? body.version : null;
|
|
112
|
+
if (!latest || compareVersions(latest, YOMI_VERSION) <= 0) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
return updateNotice(latest);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
// Offline is the normal case here, not an error worth surfacing.
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
}
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=22.13.0 <23.0.0 || >=23.4.0"
|
|
5
5
|
},
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.4.1",
|
|
7
7
|
"description": "Open-source personal LINE MCP server for AI agents. Read, reply, send images, and search LINE conversations locally with Letter-Sealing E2EE.",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"license": "MIT",
|
|
@@ -50,13 +50,14 @@
|
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
52
|
"@huggingface/transformers": "^4.2.0",
|
|
53
|
-
"@modelcontextprotocol/
|
|
53
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
54
54
|
"@toon-format/toon": "^2.3.1",
|
|
55
55
|
"curve25519-js": "^0.0.4",
|
|
56
56
|
"tweetnacl": "^1.0.3"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@biomejs/biome": "^2.5.3",
|
|
60
|
+
"@modelcontextprotocol/client": "^2.0.0",
|
|
60
61
|
"@types/bun": "^1.3.14",
|
|
61
62
|
"@types/node": "^22.10.0",
|
|
62
63
|
"knip": "^6.27.0",
|