@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,123 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import os from 'os';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Tests for MCP install config — entry format and config file merging.
|
|
8
|
-
*
|
|
9
|
-
* mcpInstall() is an interactive TUI function that can't be directly imported
|
|
10
|
-
* without triggering readline. We test the two critical contracts:
|
|
11
|
-
*
|
|
12
|
-
* 1. Entry format (contract test — logic extracted from source)
|
|
13
|
-
* 2. Config file merge (e2e — real file I/O)
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
let tempDir: string;
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-mcp-test-'));
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// ── Entry format contract ───────────────────────────────────────────────────
|
|
27
|
-
// Extracted from mcp-install.js lines 278-282
|
|
28
|
-
|
|
29
|
-
function buildEntry(transport: string, url?: string, token?: string) {
|
|
30
|
-
return transport === 'stdio'
|
|
31
|
-
? { type: 'stdio', command: 'mindos', args: ['mcp'], env: { MCP_TRANSPORT: 'stdio' } }
|
|
32
|
-
: token
|
|
33
|
-
? { url, headers: { Authorization: `Bearer ${token}` } }
|
|
34
|
-
: { url };
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('MCP entry format', () => {
|
|
38
|
-
it('stdio entry has correct structure', () => {
|
|
39
|
-
const entry = buildEntry('stdio');
|
|
40
|
-
expect(entry).toEqual({
|
|
41
|
-
type: 'stdio',
|
|
42
|
-
command: 'mindos',
|
|
43
|
-
args: ['mcp'],
|
|
44
|
-
env: { MCP_TRANSPORT: 'stdio' },
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('http entry with token includes Authorization header', () => {
|
|
49
|
-
const entry = buildEntry('http', 'http://localhost:8781/mcp', 'tok-abc');
|
|
50
|
-
expect(entry).toEqual({
|
|
51
|
-
url: 'http://localhost:8781/mcp',
|
|
52
|
-
headers: { Authorization: 'Bearer tok-abc' },
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('http entry without token has no headers', () => {
|
|
57
|
-
const entry = buildEntry('http', 'http://localhost:8781/mcp');
|
|
58
|
-
expect(entry).toEqual({ url: 'http://localhost:8781/mcp' });
|
|
59
|
-
expect(entry).not.toHaveProperty('headers');
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
// ── Config file merge ───────────────────────────────────────────────────────
|
|
64
|
-
// Simulates the read→merge→write logic from mcp-install.js lines 312-329
|
|
65
|
-
|
|
66
|
-
function mergeAndWrite(configPath: string, agentKey: string, entry: unknown) {
|
|
67
|
-
let config: Record<string, Record<string, unknown>> = {};
|
|
68
|
-
if (fs.existsSync(configPath)) {
|
|
69
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
70
|
-
}
|
|
71
|
-
if (!config[agentKey]) config[agentKey] = {};
|
|
72
|
-
config[agentKey].mindos = entry;
|
|
73
|
-
|
|
74
|
-
const dir = path.dirname(configPath);
|
|
75
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
76
|
-
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
describe('MCP config file merge', () => {
|
|
80
|
-
it('creates new config file when none exists', () => {
|
|
81
|
-
const configPath = path.join(tempDir, 'mcp.json');
|
|
82
|
-
const entry = buildEntry('stdio');
|
|
83
|
-
mergeAndWrite(configPath, 'mcpServers', entry);
|
|
84
|
-
|
|
85
|
-
const result = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
86
|
-
expect(result.mcpServers.mindos).toEqual(entry);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('preserves other mcpServers when adding mindos', () => {
|
|
90
|
-
const configPath = path.join(tempDir, 'mcp.json');
|
|
91
|
-
// Pre-existing config with another server
|
|
92
|
-
fs.writeFileSync(configPath, JSON.stringify({
|
|
93
|
-
mcpServers: {
|
|
94
|
-
'other-server': { url: 'http://other:9000/mcp' },
|
|
95
|
-
},
|
|
96
|
-
}, null, 2));
|
|
97
|
-
|
|
98
|
-
const entry = buildEntry('http', 'http://localhost:8781/mcp', 'tok-123');
|
|
99
|
-
mergeAndWrite(configPath, 'mcpServers', entry);
|
|
100
|
-
|
|
101
|
-
const result = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
102
|
-
expect(result.mcpServers.mindos).toEqual(entry);
|
|
103
|
-
expect(result.mcpServers['other-server']).toEqual({ url: 'http://other:9000/mcp' });
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('updates existing mindos entry without losing other servers', () => {
|
|
107
|
-
const configPath = path.join(tempDir, 'mcp.json');
|
|
108
|
-
// Pre-existing config with old mindos + another server
|
|
109
|
-
fs.writeFileSync(configPath, JSON.stringify({
|
|
110
|
-
mcpServers: {
|
|
111
|
-
mindos: { url: 'http://old:8000/mcp' },
|
|
112
|
-
'other-server': { command: 'other-cmd' },
|
|
113
|
-
},
|
|
114
|
-
}, null, 2));
|
|
115
|
-
|
|
116
|
-
const newEntry = buildEntry('stdio');
|
|
117
|
-
mergeAndWrite(configPath, 'mcpServers', newEntry);
|
|
118
|
-
|
|
119
|
-
const result = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
120
|
-
expect(result.mcpServers.mindos).toEqual(newEntry);
|
|
121
|
-
expect(result.mcpServers['other-server']).toEqual({ command: 'other-cmd' });
|
|
122
|
-
});
|
|
123
|
-
});
|
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
-
import { createServer, Server } from 'net';
|
|
3
|
-
import { spawn, ChildProcess } from 'child_process';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Regression test: `mindos mcp` (standalone) must default to stdio transport.
|
|
8
|
-
*
|
|
9
|
-
* Bug: When MindOS is already running (ports 3456 + 8781 bound), invoking
|
|
10
|
-
* `mindos mcp` via an MCP client would start the MCP server in HTTP mode
|
|
11
|
-
* (the default) and crash with EADDRINUSE on port 8781.
|
|
12
|
-
*
|
|
13
|
-
* Root cause: bin/cli.js `mcp` handler did not set MCP_TRANSPORT, so
|
|
14
|
-
* mcp/src/index.ts fell through to the default "http" transport.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const CLI = join(__dirname, '../../bin/cli.js');
|
|
18
|
-
|
|
19
|
-
const children: ChildProcess[] = [];
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
for (const child of children) {
|
|
23
|
-
try { child.kill('SIGTERM'); } catch {}
|
|
24
|
-
}
|
|
25
|
-
children.length = 0;
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
function getFreePort(): Promise<number> {
|
|
29
|
-
return new Promise((resolve, reject) => {
|
|
30
|
-
const srv = createServer();
|
|
31
|
-
srv.listen(0, '127.0.0.1', () => {
|
|
32
|
-
const addr = srv.address();
|
|
33
|
-
if (addr && typeof addr === 'object') {
|
|
34
|
-
srv.close(() => resolve(addr.port));
|
|
35
|
-
} else {
|
|
36
|
-
reject(new Error('no addr'));
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
srv.on('error', reject);
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ── Core regression test ──────────────────────────────────────────────────
|
|
44
|
-
|
|
45
|
-
describe('mindos mcp stdio transport (regression)', () => {
|
|
46
|
-
let blocker: Server | null = null;
|
|
47
|
-
|
|
48
|
-
afterEach(async () => {
|
|
49
|
-
if (blocker) {
|
|
50
|
-
await new Promise<void>((resolve) => blocker!.close(() => resolve()));
|
|
51
|
-
blocker = null;
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('starts in stdio mode even when MCP_PORT is already in use', async () => {
|
|
56
|
-
const port = await getFreePort();
|
|
57
|
-
|
|
58
|
-
blocker = createServer();
|
|
59
|
-
await new Promise<void>((resolve, reject) => {
|
|
60
|
-
blocker!.listen(port, '127.0.0.1', () => resolve());
|
|
61
|
-
blocker!.on('error', reject);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
const proc = spawn(process.execPath, [CLI, 'mcp'], {
|
|
65
|
-
env: {
|
|
66
|
-
...process.env,
|
|
67
|
-
MCP_TRANSPORT: 'stdio',
|
|
68
|
-
MCP_PORT: String(port),
|
|
69
|
-
MINDOS_URL: 'http://localhost:3456',
|
|
70
|
-
},
|
|
71
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
72
|
-
});
|
|
73
|
-
children.push(proc);
|
|
74
|
-
|
|
75
|
-
let stderr = '';
|
|
76
|
-
proc.stderr?.on('data', (d: Buffer) => { stderr += d.toString(); });
|
|
77
|
-
|
|
78
|
-
const response = await new Promise<string>((resolve, reject) => {
|
|
79
|
-
const timeout = setTimeout(
|
|
80
|
-
() => reject(new Error(`No response within 10s. stderr: ${stderr}`)),
|
|
81
|
-
10_000,
|
|
82
|
-
);
|
|
83
|
-
let buf = '';
|
|
84
|
-
proc.stdout?.on('data', (chunk: Buffer) => {
|
|
85
|
-
buf += chunk.toString();
|
|
86
|
-
for (const line of buf.split('\n')) {
|
|
87
|
-
if (!line.trim()) continue;
|
|
88
|
-
try {
|
|
89
|
-
const parsed = JSON.parse(line);
|
|
90
|
-
if (parsed.id === 1) {
|
|
91
|
-
clearTimeout(timeout);
|
|
92
|
-
resolve(line);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
} catch { /* incomplete */ }
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
proc.stdin?.write(JSON.stringify({
|
|
100
|
-
jsonrpc: '2.0', method: 'initialize', id: 1,
|
|
101
|
-
params: {
|
|
102
|
-
protocolVersion: '2025-03-26',
|
|
103
|
-
capabilities: {},
|
|
104
|
-
clientInfo: { name: 'test', version: '0.0.1' },
|
|
105
|
-
},
|
|
106
|
-
}) + '\n');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
const parsed = JSON.parse(response);
|
|
110
|
-
expect(parsed).toHaveProperty('result');
|
|
111
|
-
expect(parsed.result.serverInfo.name).toBe('mindos-mcp-server');
|
|
112
|
-
|
|
113
|
-
// Port is STILL occupied by blocker — stdio never tried to bind
|
|
114
|
-
expect(blocker!.listening).toBe(true);
|
|
115
|
-
proc.kill('SIGTERM');
|
|
116
|
-
}, 15_000);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// ── CLI handler env construction (pure logic, no spawning) ────────────────
|
|
120
|
-
|
|
121
|
-
describe('CLI mcp handler environment construction', () => {
|
|
122
|
-
/**
|
|
123
|
-
* Mirrors the logic in bin/cli.js `mcp` handler after the fix.
|
|
124
|
-
* This is the contract we're verifying.
|
|
125
|
-
*/
|
|
126
|
-
function buildMcpEnv(incoming: Record<string, string | undefined>) {
|
|
127
|
-
const env = { ...incoming };
|
|
128
|
-
if (!env.MCP_TRANSPORT) {
|
|
129
|
-
env.MCP_TRANSPORT = 'stdio';
|
|
130
|
-
}
|
|
131
|
-
const webPort = env.MINDOS_WEB_PORT || '3456';
|
|
132
|
-
env.MINDOS_URL = env.MINDOS_URL || `http://localhost:${webPort}`;
|
|
133
|
-
if (env.MCP_TRANSPORT === 'http') {
|
|
134
|
-
env.MCP_PORT = env.MINDOS_MCP_PORT || '8781';
|
|
135
|
-
}
|
|
136
|
-
return env;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
it('defaults MCP_TRANSPORT to stdio when not set', () => {
|
|
140
|
-
const env = buildMcpEnv({});
|
|
141
|
-
expect(env.MCP_TRANSPORT).toBe('stdio');
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
it('preserves MCP_TRANSPORT when caller provides it', () => {
|
|
145
|
-
const env = buildMcpEnv({ MCP_TRANSPORT: 'http' });
|
|
146
|
-
expect(env.MCP_TRANSPORT).toBe('http');
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('does not set MCP_PORT for stdio transport', () => {
|
|
150
|
-
const env = buildMcpEnv({});
|
|
151
|
-
expect(env.MCP_PORT).toBeUndefined();
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
it('sets MCP_PORT for explicit http transport', () => {
|
|
155
|
-
const env = buildMcpEnv({ MCP_TRANSPORT: 'http' });
|
|
156
|
-
expect(env.MCP_PORT).toBe('8781');
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('respects custom MCP port from config for http', () => {
|
|
160
|
-
const env = buildMcpEnv({ MCP_TRANSPORT: 'http', MINDOS_MCP_PORT: '9999' });
|
|
161
|
-
expect(env.MCP_PORT).toBe('9999');
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('sets MINDOS_URL from web port when not provided', () => {
|
|
165
|
-
const env = buildMcpEnv({ MINDOS_WEB_PORT: '4000' });
|
|
166
|
-
expect(env.MINDOS_URL).toBe('http://localhost:4000');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('preserves MINDOS_URL when already set', () => {
|
|
170
|
-
const env = buildMcpEnv({ MINDOS_URL: 'http://remote:5000' });
|
|
171
|
-
expect(env.MINDOS_URL).toBe('http://remote:5000');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('uses default ports when nothing is configured', () => {
|
|
175
|
-
const env = buildMcpEnv({});
|
|
176
|
-
expect(env.MCP_TRANSPORT).toBe('stdio');
|
|
177
|
-
expect(env.MINDOS_URL).toBe('http://localhost:3456');
|
|
178
|
-
expect(env.MCP_PORT).toBeUndefined();
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { execFileSync } from 'child_process';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Module-load smoke tests — verify every bin/ JS module can be parsed by
|
|
8
|
-
* the Node.js ESM loader without SyntaxError.
|
|
9
|
-
*
|
|
10
|
-
* Catches issues like premature comment termination (e.g. `MINDOS_*/` inside
|
|
11
|
-
* a block comment being treated as the closing `*/`).
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
const ROOT = path.resolve(__dirname, '..', '..');
|
|
15
|
-
const BIN = path.join(ROOT, 'bin');
|
|
16
|
-
|
|
17
|
-
/** Collect all .js files under a directory (non-recursive, single level). */
|
|
18
|
-
function listJs(dir: string): string[] {
|
|
19
|
-
if (!fs.existsSync(dir)) return [];
|
|
20
|
-
return fs
|
|
21
|
-
.readdirSync(dir)
|
|
22
|
-
.filter((f) => f.endsWith('.js'))
|
|
23
|
-
.sort()
|
|
24
|
-
.map((f) => path.join(dir, f));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Gather every module under bin/
|
|
28
|
-
const modules = [
|
|
29
|
-
...listJs(BIN),
|
|
30
|
-
...listJs(path.join(BIN, 'commands')),
|
|
31
|
-
...listJs(path.join(BIN, 'lib')),
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
describe('bin/ modules can be parsed by Node.js ESM loader', () => {
|
|
35
|
-
it.each(modules.map((m) => [path.relative(ROOT, m), m]))(
|
|
36
|
-
'%s loads without SyntaxError',
|
|
37
|
-
(_label, modulePath) => {
|
|
38
|
-
// Use a subprocess so a SyntaxError in one module doesn't kill the
|
|
39
|
-
// test runner. The script simply imports the module and exits.
|
|
40
|
-
const script = `import(${JSON.stringify('file://' + modulePath)}).then(() => process.exit(0)).catch(e => { process.stderr.write(e.message); process.exit(1); })`;
|
|
41
|
-
|
|
42
|
-
try {
|
|
43
|
-
execFileSync(process.execPath, ['--input-type=module', '-e', script], {
|
|
44
|
-
encoding: 'utf-8',
|
|
45
|
-
timeout: 10_000,
|
|
46
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
47
|
-
});
|
|
48
|
-
} catch (err: unknown) {
|
|
49
|
-
const e = err as { stderr?: string };
|
|
50
|
-
const msg = (e.stderr || '').trim();
|
|
51
|
-
expect.fail(
|
|
52
|
-
`Module failed to load: ${path.relative(ROOT, modulePath as string)}\n` +
|
|
53
|
-
` Error: ${msg}`,
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
);
|
|
58
|
-
|
|
59
|
-
it('discovered at least 40 modules (sanity check)', () => {
|
|
60
|
-
// We currently have ~50 modules; fail if the glob suddenly finds very few,
|
|
61
|
-
// which would mean the test isn't actually covering anything.
|
|
62
|
-
expect(modules.length).toBeGreaterThanOrEqual(40);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, afterEach } from 'vitest';
|
|
2
|
-
import { createServer, Server } from 'net';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Tests for bin/lib/port.js — isPortInUse.
|
|
6
|
-
* Uses real TCP servers to verify port detection accuracy.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
// Dynamic import to match ESM module
|
|
10
|
-
async function importPort() {
|
|
11
|
-
return await import('../../bin/lib/port.js') as {
|
|
12
|
-
isPortInUse: (port: number) => Promise<boolean>;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let server: Server | null = null;
|
|
17
|
-
|
|
18
|
-
afterEach(async () => {
|
|
19
|
-
if (server) {
|
|
20
|
-
await new Promise<void>((resolve) => {
|
|
21
|
-
server!.close(() => resolve());
|
|
22
|
-
});
|
|
23
|
-
server = null;
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
function startServer(): Promise<number> {
|
|
28
|
-
return new Promise((resolve, reject) => {
|
|
29
|
-
server = createServer();
|
|
30
|
-
server.listen(0, '127.0.0.1', () => {
|
|
31
|
-
const addr = server!.address();
|
|
32
|
-
if (addr && typeof addr === 'object') {
|
|
33
|
-
resolve(addr.port);
|
|
34
|
-
} else {
|
|
35
|
-
reject(new Error('Could not get server port'));
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
server.on('error', reject);
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
describe('isPortInUse', () => {
|
|
43
|
-
it('returns false for an unused port', async () => {
|
|
44
|
-
const { isPortInUse } = await importPort();
|
|
45
|
-
// Use a random high port that's very unlikely to be in use
|
|
46
|
-
// First find one by binding and immediately releasing
|
|
47
|
-
const tmpServer = createServer();
|
|
48
|
-
const port = await new Promise<number>((resolve, reject) => {
|
|
49
|
-
tmpServer.listen(0, '127.0.0.1', () => {
|
|
50
|
-
const addr = tmpServer.address();
|
|
51
|
-
if (addr && typeof addr === 'object') {
|
|
52
|
-
const p = addr.port;
|
|
53
|
-
tmpServer.close(() => resolve(p));
|
|
54
|
-
} else {
|
|
55
|
-
reject(new Error('no addr'));
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
const result = await isPortInUse(port);
|
|
60
|
-
expect(result).toBe(false);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('returns true when a server is listening on the port', async () => {
|
|
64
|
-
const port = await startServer();
|
|
65
|
-
const { isPortInUse } = await importPort();
|
|
66
|
-
const result = await isPortInUse(port);
|
|
67
|
-
expect(result).toBe(true);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('returns false after server is closed', async () => {
|
|
71
|
-
const port = await startServer();
|
|
72
|
-
const { isPortInUse } = await importPort();
|
|
73
|
-
|
|
74
|
-
// Verify it's in use first
|
|
75
|
-
expect(await isPortInUse(port)).toBe(true);
|
|
76
|
-
|
|
77
|
-
// Close the server
|
|
78
|
-
await new Promise<void>((resolve) => {
|
|
79
|
-
server!.close(() => resolve());
|
|
80
|
-
});
|
|
81
|
-
server = null;
|
|
82
|
-
|
|
83
|
-
// Now should be free
|
|
84
|
-
const result = await isPortInUse(port);
|
|
85
|
-
expect(result).toBe(false);
|
|
86
|
-
});
|
|
87
|
-
});
|