@geminilight/mindos 0.6.71 → 0.6.73
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/_standalone/.mindos-build-version +1 -1
- package/_standalone/.next/BUILD_ID +1 -1
- package/_standalone/.next/app-path-routes-manifest.json +27 -27
- package/_standalone/.next/build-manifest.json +3 -3
- package/_standalone/.next/cache/.previewinfo +1 -1
- package/_standalone/.next/cache/.rscinfo +1 -1
- package/_standalone/.next/cache/config.json +3 -3
- package/_standalone/.next/prerender-manifest.json +3 -3
- package/_standalone/.next/react-loadable-manifest.json +4 -4
- package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error.html +2 -2
- package/_standalone/.next/server/app/_global-error.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/_standalone/.next/server/app/_not-found/page.js +1 -1
- package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/page.js +1 -1
- package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/channels/verify/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/connect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/embedding/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/test/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/webhook/feishu/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/im/webhook-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/clip/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/lint/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/direct-tools/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/space-overview/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/changelog/page.js +1 -1
- package/_standalone/.next/server/app/changelog/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/changes/page.js +1 -1
- package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/page.js +1 -1
- package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/explore/page.js +1 -1
- package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/help/page.js +1 -1
- package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/login/page.js +1 -1
- package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/page.js +1 -1
- package/_standalone/.next/server/app/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/setup/page.js +1 -1
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +2 -2
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app-paths-manifest.json +27 -27
- package/_standalone/.next/server/chunks/{3311.js → 2449.js} +2 -2
- package/_standalone/.next/server/chunks/5299.js +1 -1
- package/_standalone/.next/server/chunks/6022.js +34 -34
- package/_standalone/.next/server/middleware-build-manifest.js +1 -1
- package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/_standalone/.next/server/pages/500.html +2 -2
- package/_standalone/.next/server/server-reference-manifest.js +1 -1
- package/_standalone/.next/server/server-reference-manifest.json +1 -1
- package/_standalone/.next/static/chunks/{7143.879daa87569c5b02.js → 4094.09364c01df411380.js} +1 -1
- package/_standalone/.next/static/chunks/{5795.d9099a1afecd6047.js → 5331.c89084fd7f67887d.js} +2 -2
- package/_standalone/.next/static/chunks/app/{layout-a344709b8447be75.js → layout-fcbde5bee626d21a.js} +63 -63
- package/_standalone/.next/static/chunks/app/trash/page-e623ff0ab35de002.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/page-49c4eff6ffdb5168.js +12 -0
- package/_standalone/.next/static/chunks/{webpack-2f2787d3469d3df1.js → webpack-dc486b68118d1328.js} +1 -1
- package/_standalone/.next/trace +72 -72
- package/_standalone/package-lock.json +2 -2
- package/_standalone/package.json +1 -1
- package/app/package.json +1 -1
- package/package.json +1 -1
- package/_standalone/.next/static/chunks/app/trash/page-0907fdd06a4467de.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-f53ce199b4a4bbb5.js +0 -12
- package/browser-extension/README.md +0 -160
- package/browser-extension/build.mjs +0 -63
- package/browser-extension/extension/background/service-worker.js +0 -1
- package/browser-extension/extension/content/extractor.js +0 -2
- package/browser-extension/extension/icons/icon-128.png +0 -0
- package/browser-extension/extension/icons/icon-128.svg +0 -4
- package/browser-extension/extension/icons/icon-16.png +0 -0
- package/browser-extension/extension/icons/icon-16.svg +0 -4
- package/browser-extension/extension/icons/icon-32.png +0 -0
- package/browser-extension/extension/icons/icon-32.svg +0 -4
- package/browser-extension/extension/icons/icon-48.png +0 -0
- package/browser-extension/extension/icons/icon-48.svg +0 -4
- package/browser-extension/extension/manifest.json +0 -47
- package/browser-extension/extension/popup/popup.css +0 -510
- package/browser-extension/extension/popup/popup.html +0 -128
- package/browser-extension/extension/popup/popup.js +0 -73
- package/browser-extension/package-lock.json +0 -617
- package/browser-extension/package.json +0 -21
- package/browser-extension/scripts/gen-icons.sh +0 -38
- package/browser-extension/src/background/service-worker.ts +0 -27
- package/browser-extension/src/content/extractor.ts +0 -44
- package/browser-extension/src/icons/icon-128.png +0 -0
- package/browser-extension/src/icons/icon-128.svg +0 -4
- package/browser-extension/src/icons/icon-16.png +0 -0
- package/browser-extension/src/icons/icon-16.svg +0 -4
- package/browser-extension/src/icons/icon-32.png +0 -0
- package/browser-extension/src/icons/icon-32.svg +0 -4
- package/browser-extension/src/icons/icon-48.png +0 -0
- package/browser-extension/src/icons/icon-48.svg +0 -4
- package/browser-extension/src/lib/api.ts +0 -146
- package/browser-extension/src/lib/markdown.ts +0 -68
- package/browser-extension/src/lib/storage.ts +0 -37
- package/browser-extension/src/lib/types.ts +0 -42
- package/browser-extension/src/manifest.json +0 -47
- package/browser-extension/src/popup/popup.css +0 -510
- package/browser-extension/src/popup/popup.html +0 -128
- package/browser-extension/src/popup/popup.ts +0 -416
- package/browser-extension/tsconfig.json +0 -16
- package/tests/e2e/README.md +0 -25
- package/tests/e2e/navigation.spec.ts +0 -14
- package/tests/e2e/playwright.config.ts +0 -14
- package/tests/integration/README.md +0 -25
- package/tests/integration/mcp-contract.test.ts +0 -57
- package/tests/integration/mcp-transport.test.ts +0 -361
- package/tests/integration/package-lock.json +0 -1463
- package/tests/integration/package.json +0 -8
- package/tests/integration/vitest.config.ts +0 -11
- package/tests/security-hardening.test.ts +0 -456
- package/tests/unit/build-integrity.test.ts +0 -137
- package/tests/unit/cli-build.test.ts +0 -180
- package/tests/unit/cli-config.test.ts +0 -257
- package/tests/unit/cli-mcp-install-toml.test.ts +0 -586
- package/tests/unit/cli-mcp-install.test.ts +0 -123
- package/tests/unit/cli-mcp-stdio-default.test.ts +0 -180
- package/tests/unit/cli-modules-load.test.ts +0 -64
- package/tests/unit/cli-port.test.ts +0 -87
- package/tests/unit/cli-skill-auto-copy.test.ts +0 -260
- package/tests/unit/cli-smoke.test.ts +0 -88
- package/tests/unit/cli-uninstall.test.ts +0 -218
- package/tests/unit/cli-update-root.test.ts +0 -89
- package/tests/unit/cli-user-flow-sim.test.ts +0 -506
- package/tests/unit/cli-wait-hint.test.ts +0 -86
- package/tests/unit/custom-agents.test.ts +0 -478
- package/tests/unit/dep-safety.test.ts +0 -126
- package/tests/unit/detect-system-lang.test.ts +0 -122
- package/tests/unit/mcp-build.test.ts +0 -162
- package/tests/unit/setup-needs-restart.test.ts +0 -139
- package/tests/unit/stop-restart.test.ts +0 -393
- package/tests/unit/vitest.config.ts +0 -8
- /package/_standalone/.next/static/{w5bqzZbd2_vdoPRB0JQ_I → Dn8EHqUedSzanCfrM8WWS}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{w5bqzZbd2_vdoPRB0JQ_I → Dn8EHqUedSzanCfrM8WWS}/_ssgManifest.js +0 -0
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// ── 提取自 scripts/setup.js 的 detectSystemLang 逻辑 ────────────────────────
|
|
4
|
-
// 与源码保持结构一致,方便比对。
|
|
5
|
-
|
|
6
|
-
function detectSystemLang(env: Record<string, string | undefined> = process.env as Record<string, string | undefined>): string {
|
|
7
|
-
// Check env vars by precedence (LC_ALL > LC_MESSAGES > LANG > LANGUAGE)
|
|
8
|
-
// For LANGUAGE, only use the first entry before ':' (it's a priority list)
|
|
9
|
-
const candidates = [
|
|
10
|
-
env.LC_ALL,
|
|
11
|
-
env.LC_MESSAGES,
|
|
12
|
-
env.LANG,
|
|
13
|
-
...(env.LANGUAGE ? [env.LANGUAGE.split(':')[0]] : []),
|
|
14
|
-
];
|
|
15
|
-
const first = candidates.find(Boolean);
|
|
16
|
-
if (first) {
|
|
17
|
-
return first.toLowerCase().startsWith('zh') ? 'zh' : 'en';
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
const locale = Intl.DateTimeFormat().resolvedOptions().locale;
|
|
21
|
-
if (locale.toLowerCase().startsWith('zh')) return 'zh';
|
|
22
|
-
} catch {}
|
|
23
|
-
return 'en';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// ── 通过参数注入 env 的测试(不污染 process.env)─────────────────────────────
|
|
27
|
-
|
|
28
|
-
describe('detectSystemLang — 中文环境检测', () => {
|
|
29
|
-
it('LANG=zh_CN.UTF-8 → zh', () => {
|
|
30
|
-
expect(detectSystemLang({ LANG: 'zh_CN.UTF-8' })).toBe('zh');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('LANG=zh_TW.UTF-8 → zh', () => {
|
|
34
|
-
expect(detectSystemLang({ LANG: 'zh_TW.UTF-8' })).toBe('zh');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('LC_ALL=zh_CN.UTF-8 → zh', () => {
|
|
38
|
-
expect(detectSystemLang({ LANG: undefined, LC_ALL: 'zh_CN.UTF-8' })).toBe('zh');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('LC_MESSAGES=zh_CN.UTF-8 → zh', () => {
|
|
42
|
-
expect(detectSystemLang({ LANG: undefined, LC_ALL: undefined, LC_MESSAGES: 'zh_CN.UTF-8' })).toBe('zh');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('LANGUAGE=zh_CN:en_US → zh(首选项是 zh)', () => {
|
|
46
|
-
expect(detectSystemLang({ LANG: undefined, LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: 'zh_CN:en_US' })).toBe('zh');
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
describe('detectSystemLang — 英文环境检测', () => {
|
|
51
|
-
it('LANG=en_US.UTF-8 → en', () => {
|
|
52
|
-
expect(detectSystemLang({ LANG: 'en_US.UTF-8' })).toBe('en');
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('LANG=en_GB.UTF-8 → en', () => {
|
|
56
|
-
expect(detectSystemLang({ LANG: 'en_GB.UTF-8' })).toBe('en');
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('所有 env 变量为空 → en(由 Intl 或默认)', () => {
|
|
60
|
-
// Intl 返回非 zh 时 fallback 为 en
|
|
61
|
-
const result = detectSystemLang({ LANG: undefined, LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: undefined });
|
|
62
|
-
expect(['en', 'zh']).toContain(result); // 取决于当前系统 Intl locale
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('detectSystemLang — 优先级:env 变量优先于 Intl', () => {
|
|
67
|
-
it('LC_ALL=zh 优先于 LANG=en → zh', () => {
|
|
68
|
-
expect(detectSystemLang({ LANG: 'en_US.UTF-8', LC_ALL: 'zh_CN.UTF-8' })).toBe('zh');
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('LANG=en、其他 env 无 zh → en(不论 Intl 结果)', () => {
|
|
72
|
-
const result = detectSystemLang({ LANG: 'en_US.UTF-8', LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: undefined });
|
|
73
|
-
expect(result).toBe('en');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('detectSystemLang — LANGUAGE 优先级列表', () => {
|
|
78
|
-
it('LANGUAGE=en_US:zh_CN → en(首选项是 en,zh 只是 fallback)', () => {
|
|
79
|
-
expect(detectSystemLang({ LANG: undefined, LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: 'en_US:zh_CN' })).toBe('en');
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it('LANGUAGE=zh_CN:en_US → zh(首选项是 zh)', () => {
|
|
83
|
-
expect(detectSystemLang({ LANG: undefined, LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: 'zh_CN:en_US' })).toBe('zh');
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it('LANG=en + LANGUAGE=zh_CN:en → en(LANG 优先于 LANGUAGE)', () => {
|
|
87
|
-
expect(detectSystemLang({ LANG: 'en_US.UTF-8', LC_ALL: undefined, LC_MESSAGES: undefined, LANGUAGE: 'zh_CN:en_US' })).toBe('en');
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
describe('detectSystemLang — 高优先级英文 + 低优先级中文', () => {
|
|
92
|
-
it('LC_ALL=en + LANG=zh → en(LC_ALL 优先级最高)', () => {
|
|
93
|
-
expect(detectSystemLang({ LANG: 'zh_CN.UTF-8', LC_ALL: 'en_US.UTF-8' })).toBe('en');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('LC_MESSAGES=en + LANG=zh → en(LC_MESSAGES 优先于 LANG)', () => {
|
|
97
|
-
expect(detectSystemLang({ LANG: 'zh_CN.UTF-8', LC_ALL: undefined, LC_MESSAGES: 'en_US.UTF-8' })).toBe('en');
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe('detectSystemLang — 边界条件', () => {
|
|
102
|
-
it('LANG="C" → en', () => {
|
|
103
|
-
expect(detectSystemLang({ LANG: 'C' })).toBe('en');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('LANG="POSIX" → en', () => {
|
|
107
|
-
expect(detectSystemLang({ LANG: 'POSIX' })).toBe('en');
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('env 中含 "ZH"(大写)也能识别', () => {
|
|
111
|
-
// 实现 .toLowerCase() 后比较,所以大写也能匹配
|
|
112
|
-
expect(detectSystemLang({ LANG: 'ZH_CN.UTF-8' })).toBe('zh');
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('LANG=fr_FR.UTF-8 → en(非中文非英文仍返回 en)', () => {
|
|
116
|
-
expect(detectSystemLang({ LANG: 'fr_FR.UTF-8' })).toBe('en');
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('LANG=ja_JP.UTF-8 → en(日文环境返回 en)', () => {
|
|
120
|
-
expect(detectSystemLang({ LANG: 'ja_JP.UTF-8' })).toBe('en');
|
|
121
|
-
});
|
|
122
|
-
});
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
let tempDir: string;
|
|
7
|
-
let mcpDir: string;
|
|
8
|
-
let srcDir: string;
|
|
9
|
-
let distDir: string;
|
|
10
|
-
let bundlePath: string;
|
|
11
|
-
let sdkPkgPath: string;
|
|
12
|
-
let esbuildPkgPath: string;
|
|
13
|
-
let mockRun: ReturnType<typeof vi.fn>;
|
|
14
|
-
let mockInstall: ReturnType<typeof vi.fn>;
|
|
15
|
-
|
|
16
|
-
function setMtime(targetPath: string, timeMs: number) {
|
|
17
|
-
const time = new Date(timeMs);
|
|
18
|
-
fs.utimesSync(targetPath, time, time);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function writeBundle(content = '// bundle') {
|
|
22
|
-
fs.mkdirSync(distDir, { recursive: true });
|
|
23
|
-
fs.writeFileSync(bundlePath, content);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function writeBuildDeps() {
|
|
27
|
-
fs.mkdirSync(path.dirname(sdkPkgPath), { recursive: true });
|
|
28
|
-
fs.writeFileSync(sdkPkgPath, '{}');
|
|
29
|
-
fs.mkdirSync(path.dirname(esbuildPkgPath), { recursive: true });
|
|
30
|
-
fs.writeFileSync(esbuildPkgPath, '{}');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-mcp-build-test-'));
|
|
35
|
-
mcpDir = path.join(tempDir, 'mcp');
|
|
36
|
-
srcDir = path.join(mcpDir, 'src');
|
|
37
|
-
distDir = path.join(mcpDir, 'dist');
|
|
38
|
-
bundlePath = path.join(distDir, 'index.cjs');
|
|
39
|
-
sdkPkgPath = path.join(mcpDir, 'node_modules', '@modelcontextprotocol', 'sdk', 'package.json');
|
|
40
|
-
esbuildPkgPath = path.join(mcpDir, 'node_modules', 'esbuild', 'package.json');
|
|
41
|
-
|
|
42
|
-
fs.mkdirSync(srcDir, { recursive: true });
|
|
43
|
-
fs.writeFileSync(path.join(srcDir, 'index.ts'), 'export const ok = true;');
|
|
44
|
-
fs.writeFileSync(path.join(mcpDir, 'package.json'), JSON.stringify({ name: 'mindos-mcp', version: '1.0.0' }));
|
|
45
|
-
fs.writeFileSync(path.join(mcpDir, 'package-lock.json'), JSON.stringify({ lockfileVersion: 3 }));
|
|
46
|
-
|
|
47
|
-
mockInstall = vi.fn(() => {
|
|
48
|
-
writeBuildDeps();
|
|
49
|
-
});
|
|
50
|
-
mockRun = vi.fn((command: string) => {
|
|
51
|
-
if (command === 'npm run build') {
|
|
52
|
-
writeBundle();
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
vi.resetModules();
|
|
57
|
-
vi.doMock('../../bin/lib/constants.js', () => ({
|
|
58
|
-
ROOT: tempDir,
|
|
59
|
-
BUILD_STAMP: path.join(tempDir, 'app', '.next', '.mindos-build-version'),
|
|
60
|
-
DEPS_STAMP: path.join(tempDir, 'deps-hash'),
|
|
61
|
-
CONFIG_PATH: path.join(tempDir, 'config.json'),
|
|
62
|
-
MINDOS_DIR: tempDir,
|
|
63
|
-
PID_PATH: path.join(tempDir, 'mindos.pid'),
|
|
64
|
-
LOG_PATH: path.join(tempDir, 'mindos.log'),
|
|
65
|
-
CLI_PATH: path.join(tempDir, 'bin', 'cli.js'),
|
|
66
|
-
NODE_BIN: process.execPath,
|
|
67
|
-
UPDATE_CHECK_PATH: path.join(tempDir, 'update-check.json'),
|
|
68
|
-
STANDALONE_SERVER: path.join(tempDir, '_standalone', 'server.js'),
|
|
69
|
-
STANDALONE_STAMP: path.join(tempDir, '_standalone', '.mindos-build-version'),
|
|
70
|
-
}));
|
|
71
|
-
vi.doMock('../../bin/lib/shell.js', () => ({
|
|
72
|
-
execInherited: mockRun,
|
|
73
|
-
npmInstall: mockInstall,
|
|
74
|
-
}));
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
afterEach(() => {
|
|
78
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
79
|
-
vi.restoreAllMocks();
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
async function importMcpBuild() {
|
|
83
|
-
return await import('../../bin/lib/mcp-build.js') as {
|
|
84
|
-
needsMcpBuild: () => boolean;
|
|
85
|
-
ensureMcpBundle: () => void;
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
describe('needsMcpBuild', () => {
|
|
90
|
-
it('returns true when the MCP bundle is missing', async () => {
|
|
91
|
-
const { needsMcpBuild } = await importMcpBuild();
|
|
92
|
-
expect(needsMcpBuild()).toBe(true);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
it('returns false when the bundle is newer than source inputs', async () => {
|
|
96
|
-
writeBundle();
|
|
97
|
-
const now = Date.now();
|
|
98
|
-
setMtime(srcDir, now - 10_000);
|
|
99
|
-
setMtime(path.join(srcDir, 'index.ts'), now - 10_000);
|
|
100
|
-
setMtime(path.join(mcpDir, 'package.json'), now - 10_000);
|
|
101
|
-
setMtime(path.join(mcpDir, 'package-lock.json'), now - 10_000);
|
|
102
|
-
setMtime(bundlePath, now);
|
|
103
|
-
|
|
104
|
-
const { needsMcpBuild } = await importMcpBuild();
|
|
105
|
-
expect(needsMcpBuild()).toBe(false);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('returns true when source changes after the bundle was built', async () => {
|
|
109
|
-
writeBundle();
|
|
110
|
-
const now = Date.now();
|
|
111
|
-
setMtime(bundlePath, now - 20_000);
|
|
112
|
-
setMtime(path.join(srcDir, 'index.ts'), now);
|
|
113
|
-
|
|
114
|
-
const { needsMcpBuild } = await importMcpBuild();
|
|
115
|
-
expect(needsMcpBuild()).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
describe('ensureMcpBundle', () => {
|
|
120
|
-
it('installs build deps and builds when the bundle is missing', async () => {
|
|
121
|
-
const { ensureMcpBundle } = await importMcpBuild();
|
|
122
|
-
|
|
123
|
-
ensureMcpBundle();
|
|
124
|
-
|
|
125
|
-
expect(mockInstall).toHaveBeenCalledWith(mcpDir, '--no-workspaces');
|
|
126
|
-
expect(mockRun).toHaveBeenCalledWith('npm run build', mcpDir);
|
|
127
|
-
expect(fs.existsSync(bundlePath)).toBe(true);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
it('rebuilds stale bundles without reinstalling build deps', async () => {
|
|
131
|
-
writeBuildDeps();
|
|
132
|
-
writeBundle();
|
|
133
|
-
const now = Date.now();
|
|
134
|
-
setMtime(bundlePath, now - 20_000);
|
|
135
|
-
setMtime(path.join(srcDir, 'index.ts'), now);
|
|
136
|
-
|
|
137
|
-
const { ensureMcpBundle } = await importMcpBuild();
|
|
138
|
-
|
|
139
|
-
ensureMcpBundle();
|
|
140
|
-
|
|
141
|
-
expect(mockInstall).not.toHaveBeenCalled();
|
|
142
|
-
expect(mockRun).toHaveBeenCalledWith('npm run build', mcpDir);
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('does nothing when the bundle is already current', async () => {
|
|
146
|
-
writeBuildDeps();
|
|
147
|
-
writeBundle();
|
|
148
|
-
const now = Date.now();
|
|
149
|
-
setMtime(srcDir, now - 10_000);
|
|
150
|
-
setMtime(path.join(srcDir, 'index.ts'), now - 10_000);
|
|
151
|
-
setMtime(path.join(mcpDir, 'package.json'), now - 10_000);
|
|
152
|
-
setMtime(path.join(mcpDir, 'package-lock.json'), now - 10_000);
|
|
153
|
-
setMtime(bundlePath, now);
|
|
154
|
-
|
|
155
|
-
const { ensureMcpBundle } = await importMcpBuild();
|
|
156
|
-
|
|
157
|
-
ensureMcpBundle();
|
|
158
|
-
|
|
159
|
-
expect(mockInstall).not.toHaveBeenCalled();
|
|
160
|
-
expect(mockRun).not.toHaveBeenCalled();
|
|
161
|
-
});
|
|
162
|
-
});
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
|
|
3
|
-
// ── 提取自 app/app/api/setup/route.ts 的 needsRestart 逻辑 ──────────────────
|
|
4
|
-
// 与源码保持结构一致,方便比对。若源码逻辑改变,此处需同步更新。
|
|
5
|
-
|
|
6
|
-
interface CurrentConfig {
|
|
7
|
-
setupPending?: boolean;
|
|
8
|
-
mindRoot?: string;
|
|
9
|
-
port?: number;
|
|
10
|
-
mcpPort?: number;
|
|
11
|
-
authToken?: string;
|
|
12
|
-
webPassword?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface IncomingPayload {
|
|
16
|
-
webPort: number;
|
|
17
|
-
mcpPortNum: number;
|
|
18
|
-
resolvedRoot: string;
|
|
19
|
-
authToken?: string;
|
|
20
|
-
webPassword?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function computeNeedsRestart(current: CurrentConfig, incoming: IncomingPayload): boolean {
|
|
24
|
-
const isFirstTime = current.setupPending === true || !current.mindRoot;
|
|
25
|
-
const resolvedAuthToken = incoming.authToken ?? current.authToken ?? '';
|
|
26
|
-
const resolvedWebPassword = incoming.webPassword ?? '';
|
|
27
|
-
return !isFirstTime && (
|
|
28
|
-
incoming.webPort !== (current.port ?? 3456) ||
|
|
29
|
-
incoming.mcpPortNum !== (current.mcpPort ?? 8781) ||
|
|
30
|
-
incoming.resolvedRoot !== (current.mindRoot || '') ||
|
|
31
|
-
resolvedAuthToken !== (current.authToken ?? '') ||
|
|
32
|
-
resolvedWebPassword !== (current.webPassword ?? '')
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// ── 基础场景 ──────────────────────────────────────────────────────────────────
|
|
37
|
-
|
|
38
|
-
const EXISTING: CurrentConfig = {
|
|
39
|
-
setupPending: false,
|
|
40
|
-
mindRoot: '/home/user/MindOS/mind',
|
|
41
|
-
port: 3456,
|
|
42
|
-
mcpPort: 8781,
|
|
43
|
-
authToken: 'abc-token',
|
|
44
|
-
webPassword: 'secret',
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const UNCHANGED: IncomingPayload = {
|
|
48
|
-
webPort: 3456,
|
|
49
|
-
mcpPortNum: 8781,
|
|
50
|
-
resolvedRoot: '/home/user/MindOS/mind',
|
|
51
|
-
authToken: 'abc-token',
|
|
52
|
-
webPassword: 'secret',
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
describe('needsRestart — 首次 onboard 不触发', () => {
|
|
56
|
-
it('setupPending=true 时不触发', () => {
|
|
57
|
-
const current: CurrentConfig = { ...EXISTING, setupPending: true };
|
|
58
|
-
expect(computeNeedsRestart(current, UNCHANGED)).toBe(false);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('mindRoot 为空字符串时不触发', () => {
|
|
62
|
-
const current: CurrentConfig = { ...EXISTING, setupPending: false, mindRoot: '' };
|
|
63
|
-
expect(computeNeedsRestart(current, UNCHANGED)).toBe(false);
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it('mindRoot 为 undefined 时不触发', () => {
|
|
67
|
-
const current: CurrentConfig = { ...EXISTING, setupPending: false, mindRoot: undefined };
|
|
68
|
-
expect(computeNeedsRestart(current, UNCHANGED)).toBe(false);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
describe('needsRestart — 再次 onboard 无变更不触发', () => {
|
|
73
|
-
it('所有字段相同时不触发', () => {
|
|
74
|
-
expect(computeNeedsRestart(EXISTING, UNCHANGED)).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('只改 AI Key/Model(payload 中无对应字段)不触发', () => {
|
|
78
|
-
// AI 配置不在 needsRestart 的比较字段里
|
|
79
|
-
expect(computeNeedsRestart(EXISTING, UNCHANGED)).toBe(false);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
describe('needsRestart — 各字段变更触发', () => {
|
|
84
|
-
it('改 webPort 触发', () => {
|
|
85
|
-
const incoming = { ...UNCHANGED, webPort: 3001 };
|
|
86
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(true);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('改 mcpPort 触发', () => {
|
|
90
|
-
const incoming = { ...UNCHANGED, mcpPortNum: 8788 };
|
|
91
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(true);
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('改 mindRoot 触发', () => {
|
|
95
|
-
const incoming = { ...UNCHANGED, resolvedRoot: '/home/user/notes' };
|
|
96
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(true);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it('改 authToken 触发', () => {
|
|
100
|
-
const incoming = { ...UNCHANGED, authToken: 'new-token' };
|
|
101
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(true);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('改 webPassword 触发', () => {
|
|
105
|
-
const incoming = { ...UNCHANGED, webPassword: 'new-pass' };
|
|
106
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(true);
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
describe('needsRestart — 边界条件', () => {
|
|
111
|
-
it('authToken=undefined 时使用 current.authToken,不误判', () => {
|
|
112
|
-
// 模拟前端未传 authToken(保留原值),不应触发重启
|
|
113
|
-
const incoming: IncomingPayload = { ...UNCHANGED, authToken: undefined };
|
|
114
|
-
expect(computeNeedsRestart(EXISTING, incoming)).toBe(false);
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it('webPassword=undefined 时视为空字符串', () => {
|
|
118
|
-
// current 无密码,incoming 也未传,不应触发
|
|
119
|
-
const current: CurrentConfig = { ...EXISTING, webPassword: '' };
|
|
120
|
-
const incoming: IncomingPayload = { ...UNCHANGED, webPassword: undefined };
|
|
121
|
-
expect(computeNeedsRestart(current, incoming)).toBe(false);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('current 无 port/mcpPort 时使用默认值 3456/8781', () => {
|
|
125
|
-
const current: CurrentConfig = { ...EXISTING, port: undefined, mcpPort: undefined };
|
|
126
|
-
// incoming 与默认值相同,不触发
|
|
127
|
-
expect(computeNeedsRestart(current, UNCHANGED)).toBe(false);
|
|
128
|
-
// incoming 与默认值不同,触发
|
|
129
|
-
expect(computeNeedsRestart(current, { ...UNCHANGED, webPort: 3001 })).toBe(true);
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('current 无 authToken 时视为空字符串', () => {
|
|
133
|
-
const current: CurrentConfig = { ...EXISTING, authToken: undefined };
|
|
134
|
-
// incoming 传空字符串,与 undefined 等价,不触发
|
|
135
|
-
expect(computeNeedsRestart(current, { ...UNCHANGED, authToken: '' })).toBe(false);
|
|
136
|
-
// incoming 传新 token,触发
|
|
137
|
-
expect(computeNeedsRestart(current, { ...UNCHANGED, authToken: 'new' })).toBe(true);
|
|
138
|
-
});
|
|
139
|
-
});
|