@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.
Files changed (227) hide show
  1. package/_standalone/.mindos-build-version +1 -1
  2. package/_standalone/.next/BUILD_ID +1 -1
  3. package/_standalone/.next/app-path-routes-manifest.json +27 -27
  4. package/_standalone/.next/build-manifest.json +3 -3
  5. package/_standalone/.next/cache/.previewinfo +1 -1
  6. package/_standalone/.next/cache/.rscinfo +1 -1
  7. package/_standalone/.next/cache/config.json +3 -3
  8. package/_standalone/.next/prerender-manifest.json +3 -3
  9. package/_standalone/.next/react-loadable-manifest.json +4 -4
  10. package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
  11. package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  12. package/_standalone/.next/server/app/_global-error.html +2 -2
  13. package/_standalone/.next/server/app/_global-error.rsc +1 -1
  14. package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  15. package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  16. package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  17. package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  18. package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  19. package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  20. package/_standalone/.next/server/app/_not-found/page.js +1 -1
  21. package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  22. package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  23. package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
  24. package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
  25. package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
  26. package/_standalone/.next/server/app/agents/page.js +1 -1
  27. package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
  28. package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
  29. package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
  30. package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
  31. package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
  32. package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
  33. package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
  34. package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
  35. package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
  36. package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
  37. package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
  38. package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
  39. package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
  40. package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
  41. package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
  42. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  43. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/channels/verify/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/connect/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/embedding/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/im/activity/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/im/config/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/im/status/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/im/test/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/im/webhook/feishu/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/im/webhook-status/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/inbox/clip/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/lint/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/mcp/direct-tools/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/space-overview/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  94. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  97. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/changelog/page.js +1 -1
  101. package/_standalone/.next/server/app/changelog/page.js.nft.json +1 -1
  102. package/_standalone/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/changes/page.js +1 -1
  104. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  105. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  107. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  108. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  109. package/_standalone/.next/server/app/echo/page.js +1 -1
  110. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  111. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  112. package/_standalone/.next/server/app/explore/page.js +1 -1
  113. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  114. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  115. package/_standalone/.next/server/app/help/page.js +1 -1
  116. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  117. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  118. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  119. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  120. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  121. package/_standalone/.next/server/app/login/page.js +1 -1
  122. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  123. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  124. package/_standalone/.next/server/app/page.js +1 -1
  125. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  126. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  127. package/_standalone/.next/server/app/setup/page.js +1 -1
  128. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  129. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  130. package/_standalone/.next/server/app/trash/page.js +2 -2
  131. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  132. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  133. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  134. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  135. package/_standalone/.next/server/app-paths-manifest.json +27 -27
  136. package/_standalone/.next/server/chunks/{3311.js → 2449.js} +2 -2
  137. package/_standalone/.next/server/chunks/5299.js +1 -1
  138. package/_standalone/.next/server/chunks/6022.js +34 -34
  139. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  140. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  141. package/_standalone/.next/server/pages/500.html +2 -2
  142. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  143. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  144. package/_standalone/.next/static/chunks/{7143.879daa87569c5b02.js → 4094.09364c01df411380.js} +1 -1
  145. package/_standalone/.next/static/chunks/{5795.d9099a1afecd6047.js → 5331.c89084fd7f67887d.js} +2 -2
  146. package/_standalone/.next/static/chunks/app/{layout-a344709b8447be75.js → layout-fcbde5bee626d21a.js} +63 -63
  147. package/_standalone/.next/static/chunks/app/trash/page-e623ff0ab35de002.js +1 -0
  148. package/_standalone/.next/static/chunks/app/view/[...path]/page-49c4eff6ffdb5168.js +12 -0
  149. package/_standalone/.next/static/chunks/{webpack-2f2787d3469d3df1.js → webpack-dc486b68118d1328.js} +1 -1
  150. package/_standalone/.next/trace +72 -72
  151. package/_standalone/package-lock.json +2 -2
  152. package/_standalone/package.json +1 -1
  153. package/app/package.json +1 -1
  154. package/package.json +1 -1
  155. package/_standalone/.next/static/chunks/app/trash/page-0907fdd06a4467de.js +0 -1
  156. package/_standalone/.next/static/chunks/app/view/[...path]/page-f53ce199b4a4bbb5.js +0 -12
  157. package/browser-extension/README.md +0 -160
  158. package/browser-extension/build.mjs +0 -63
  159. package/browser-extension/extension/background/service-worker.js +0 -1
  160. package/browser-extension/extension/content/extractor.js +0 -2
  161. package/browser-extension/extension/icons/icon-128.png +0 -0
  162. package/browser-extension/extension/icons/icon-128.svg +0 -4
  163. package/browser-extension/extension/icons/icon-16.png +0 -0
  164. package/browser-extension/extension/icons/icon-16.svg +0 -4
  165. package/browser-extension/extension/icons/icon-32.png +0 -0
  166. package/browser-extension/extension/icons/icon-32.svg +0 -4
  167. package/browser-extension/extension/icons/icon-48.png +0 -0
  168. package/browser-extension/extension/icons/icon-48.svg +0 -4
  169. package/browser-extension/extension/manifest.json +0 -47
  170. package/browser-extension/extension/popup/popup.css +0 -510
  171. package/browser-extension/extension/popup/popup.html +0 -128
  172. package/browser-extension/extension/popup/popup.js +0 -73
  173. package/browser-extension/package-lock.json +0 -617
  174. package/browser-extension/package.json +0 -21
  175. package/browser-extension/scripts/gen-icons.sh +0 -38
  176. package/browser-extension/src/background/service-worker.ts +0 -27
  177. package/browser-extension/src/content/extractor.ts +0 -44
  178. package/browser-extension/src/icons/icon-128.png +0 -0
  179. package/browser-extension/src/icons/icon-128.svg +0 -4
  180. package/browser-extension/src/icons/icon-16.png +0 -0
  181. package/browser-extension/src/icons/icon-16.svg +0 -4
  182. package/browser-extension/src/icons/icon-32.png +0 -0
  183. package/browser-extension/src/icons/icon-32.svg +0 -4
  184. package/browser-extension/src/icons/icon-48.png +0 -0
  185. package/browser-extension/src/icons/icon-48.svg +0 -4
  186. package/browser-extension/src/lib/api.ts +0 -146
  187. package/browser-extension/src/lib/markdown.ts +0 -68
  188. package/browser-extension/src/lib/storage.ts +0 -37
  189. package/browser-extension/src/lib/types.ts +0 -42
  190. package/browser-extension/src/manifest.json +0 -47
  191. package/browser-extension/src/popup/popup.css +0 -510
  192. package/browser-extension/src/popup/popup.html +0 -128
  193. package/browser-extension/src/popup/popup.ts +0 -416
  194. package/browser-extension/tsconfig.json +0 -16
  195. package/tests/e2e/README.md +0 -25
  196. package/tests/e2e/navigation.spec.ts +0 -14
  197. package/tests/e2e/playwright.config.ts +0 -14
  198. package/tests/integration/README.md +0 -25
  199. package/tests/integration/mcp-contract.test.ts +0 -57
  200. package/tests/integration/mcp-transport.test.ts +0 -361
  201. package/tests/integration/package-lock.json +0 -1463
  202. package/tests/integration/package.json +0 -8
  203. package/tests/integration/vitest.config.ts +0 -11
  204. package/tests/security-hardening.test.ts +0 -456
  205. package/tests/unit/build-integrity.test.ts +0 -137
  206. package/tests/unit/cli-build.test.ts +0 -180
  207. package/tests/unit/cli-config.test.ts +0 -257
  208. package/tests/unit/cli-mcp-install-toml.test.ts +0 -586
  209. package/tests/unit/cli-mcp-install.test.ts +0 -123
  210. package/tests/unit/cli-mcp-stdio-default.test.ts +0 -180
  211. package/tests/unit/cli-modules-load.test.ts +0 -64
  212. package/tests/unit/cli-port.test.ts +0 -87
  213. package/tests/unit/cli-skill-auto-copy.test.ts +0 -260
  214. package/tests/unit/cli-smoke.test.ts +0 -88
  215. package/tests/unit/cli-uninstall.test.ts +0 -218
  216. package/tests/unit/cli-update-root.test.ts +0 -89
  217. package/tests/unit/cli-user-flow-sim.test.ts +0 -506
  218. package/tests/unit/cli-wait-hint.test.ts +0 -86
  219. package/tests/unit/custom-agents.test.ts +0 -478
  220. package/tests/unit/dep-safety.test.ts +0 -126
  221. package/tests/unit/detect-system-lang.test.ts +0 -122
  222. package/tests/unit/mcp-build.test.ts +0 -162
  223. package/tests/unit/setup-needs-restart.test.ts +0 -139
  224. package/tests/unit/stop-restart.test.ts +0 -393
  225. package/tests/unit/vitest.config.ts +0 -8
  226. /package/_standalone/.next/static/{w5bqzZbd2_vdoPRB0JQ_I → Dn8EHqUedSzanCfrM8WWS}/_buildManifest.js +0 -0
  227. /package/_standalone/.next/static/{w5bqzZbd2_vdoPRB0JQ_I → Dn8EHqUedSzanCfrM8WWS}/_ssgManifest.js +0 -0
@@ -1,586 +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 TOML support in MCP install — entry format and config file merging.
8
- *
9
- * Mirrors the TypeScript tests in app/__tests__/api/mcp-install.test.ts
10
- * for the Codex TOML path (lines 133-177).
11
- *
12
- * Tests two modules:
13
- * 1. bin/lib/toml.js — buildTomlEntry(), mergeTomlEntry()
14
- * 2. bin/lib/mcp-install.js — TOML-aware install flow
15
- */
16
-
17
- // Dynamic import because bin/lib uses ESM
18
- async function importToml() {
19
- return await import('../../bin/lib/toml.js');
20
- }
21
-
22
- let tempDir: string;
23
-
24
- beforeEach(() => {
25
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-mcp-toml-test-'));
26
- });
27
-
28
- afterEach(() => {
29
- fs.rmSync(tempDir, { recursive: true, force: true });
30
- });
31
-
32
- // ── buildTomlEntry ──────────────────────────────────────────────────────────
33
-
34
- describe('buildTomlEntry', () => {
35
- it('generates stdio entry with env sub-table', async () => {
36
- const { buildTomlEntry } = await importToml();
37
- const result = buildTomlEntry('mcp_servers', 'mindos', {
38
- type: 'stdio',
39
- command: 'mindos',
40
- args: ['mcp'],
41
- env: { MCP_TRANSPORT: 'stdio' },
42
- });
43
-
44
- expect(result).toContain('[mcp_servers.mindos]');
45
- expect(result).toContain('type = "stdio"');
46
- expect(result).toContain('command = "mindos"');
47
- expect(result).toContain('args = ["mcp"]');
48
- expect(result).toContain('[mcp_servers.mindos.env]');
49
- expect(result).toContain('MCP_TRANSPORT = "stdio"');
50
- });
51
-
52
- it('generates http entry with URL only', async () => {
53
- const { buildTomlEntry } = await importToml();
54
- const result = buildTomlEntry('mcp_servers', 'mindos', {
55
- url: 'http://localhost:8781/mcp',
56
- });
57
-
58
- expect(result).toContain('[mcp_servers.mindos]');
59
- expect(result).toContain('url = "http://localhost:8781/mcp"');
60
- expect(result).not.toContain('[mcp_servers.mindos.env]');
61
- expect(result).not.toContain('[mcp_servers.mindos.headers]');
62
- });
63
-
64
- it('generates http entry with Authorization header', async () => {
65
- const { buildTomlEntry } = await importToml();
66
- const result = buildTomlEntry('mcp_servers', 'mindos', {
67
- url: 'http://localhost:8781/mcp',
68
- headers: { Authorization: 'Bearer tok-abc' },
69
- });
70
-
71
- expect(result).toContain('[mcp_servers.mindos]');
72
- expect(result).toContain('url = "http://localhost:8781/mcp"');
73
- expect(result).toContain('[mcp_servers.mindos.headers]');
74
- expect(result).toContain('Authorization = "Bearer tok-abc"');
75
- });
76
-
77
- it('generates entry with both env and headers', async () => {
78
- const { buildTomlEntry } = await importToml();
79
- const result = buildTomlEntry('mcp_servers', 'mindos', {
80
- type: 'stdio',
81
- command: 'mindos',
82
- args: ['mcp', '--verbose'],
83
- env: { MCP_TRANSPORT: 'stdio', DEBUG: '1' },
84
- headers: { 'X-Custom': 'value' },
85
- });
86
-
87
- expect(result).toContain('[mcp_servers.mindos]');
88
- expect(result).toContain('args = ["mcp", "--verbose"]');
89
- expect(result).toContain('[mcp_servers.mindos.env]');
90
- expect(result).toContain('MCP_TRANSPORT = "stdio"');
91
- expect(result).toContain('DEBUG = "1"');
92
- expect(result).toContain('[mcp_servers.mindos.headers]');
93
- expect(result).toContain('X-Custom = "value"');
94
-
95
- // Verify section order: main → env → headers
96
- const mainIdx = result.indexOf('[mcp_servers.mindos]');
97
- const envIdx = result.indexOf('[mcp_servers.mindos.env]');
98
- const headersIdx = result.indexOf('[mcp_servers.mindos.headers]');
99
- expect(mainIdx).toBeLessThan(envIdx);
100
- expect(envIdx).toBeLessThan(headersIdx);
101
- });
102
-
103
- it('omits null/undefined fields gracefully', async () => {
104
- const { buildTomlEntry } = await importToml();
105
- const result = buildTomlEntry('mcp_servers', 'mindos', {
106
- type: 'stdio',
107
- command: null,
108
- url: undefined,
109
- args: null,
110
- });
111
-
112
- expect(result).toContain('[mcp_servers.mindos]');
113
- expect(result).toContain('type = "stdio"');
114
- expect(result).not.toContain('command');
115
- expect(result).not.toContain('url');
116
- expect(result).not.toContain('args');
117
- });
118
-
119
- it('supports custom section and server names', async () => {
120
- const { buildTomlEntry } = await importToml();
121
- const result = buildTomlEntry('custom_servers', 'my-server', {
122
- type: 'http',
123
- url: 'http://example.com/api',
124
- });
125
-
126
- expect(result).toContain('[custom_servers.my-server]');
127
- expect(result).toContain('type = "http"');
128
- expect(result).toContain('url = "http://example.com/api"');
129
- });
130
-
131
- it('handles empty entry object', async () => {
132
- const { buildTomlEntry } = await importToml();
133
- const result = buildTomlEntry('mcp_servers', 'mindos', {});
134
-
135
- expect(result).toBe('[mcp_servers.mindos]');
136
- });
137
- });
138
-
139
- // ── mergeTomlEntry ──────────────────────────────────────────────────────────
140
-
141
- describe('mergeTomlEntry', () => {
142
- it('creates new block when file is empty', async () => {
143
- const { mergeTomlEntry } = await importToml();
144
- const result = mergeTomlEntry('', 'mcp_servers', 'mindos', {
145
- type: 'stdio',
146
- command: 'mindos',
147
- args: ['mcp'],
148
- env: { MCP_TRANSPORT: 'stdio' },
149
- });
150
-
151
- expect(result).toContain('[mcp_servers.mindos]');
152
- expect(result).toContain('type = "stdio"');
153
- expect(result).toContain('[mcp_servers.mindos.env]');
154
- expect(result).toContain('MCP_TRANSPORT = "stdio"');
155
- });
156
-
157
- it('preserves unrelated sections', async () => {
158
- const { mergeTomlEntry } = await importToml();
159
- const existing = [
160
- '[other_section]',
161
- 'key = "value"',
162
- '',
163
- '[another.nested]',
164
- 'foo = "bar"',
165
- '',
166
- ].join('\n');
167
-
168
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
169
- type: 'stdio',
170
- command: 'mindos',
171
- });
172
-
173
- expect(result).toContain('[other_section]');
174
- expect(result).toContain('key = "value"');
175
- expect(result).toContain('[another.nested]');
176
- expect(result).toContain('foo = "bar"');
177
- expect(result).toContain('[mcp_servers.mindos]');
178
- });
179
-
180
- it('replaces existing mindos section', async () => {
181
- const { mergeTomlEntry } = await importToml();
182
- const existing = [
183
- '[mcp_servers.mindos]',
184
- 'type = "http"',
185
- 'url = "http://old:8000/mcp"',
186
- '',
187
- ].join('\n');
188
-
189
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
190
- type: 'stdio',
191
- command: 'mindos',
192
- args: ['mcp'],
193
- env: { MCP_TRANSPORT: 'stdio' },
194
- });
195
-
196
- // Old values gone
197
- expect(result).not.toContain('http://old:8000/mcp');
198
- expect(result).not.toContain('type = "http"');
199
-
200
- // New values present
201
- expect(result).toContain('[mcp_servers.mindos]');
202
- expect(result).toContain('type = "stdio"');
203
- expect(result).toContain('command = "mindos"');
204
- expect(result).toContain('[mcp_servers.mindos.env]');
205
- expect(result).toContain('MCP_TRANSPORT = "stdio"');
206
- });
207
-
208
- it('replaces existing section including env sub-table', async () => {
209
- const { mergeTomlEntry } = await importToml();
210
- const existing = [
211
- '[mcp_servers.mindos]',
212
- 'type = "stdio"',
213
- 'command = "old-cmd"',
214
- '',
215
- '[mcp_servers.mindos.env]',
216
- 'OLD_VAR = "old-value"',
217
- '',
218
- '[other_section]',
219
- 'key = "keep"',
220
- '',
221
- ].join('\n');
222
-
223
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
224
- type: 'stdio',
225
- command: 'mindos',
226
- args: ['mcp'],
227
- env: { MCP_TRANSPORT: 'stdio' },
228
- });
229
-
230
- // Old env gone
231
- expect(result).not.toContain('OLD_VAR');
232
- expect(result).not.toContain('old-cmd');
233
-
234
- // Other section preserved
235
- expect(result).toContain('[other_section]');
236
- expect(result).toContain('key = "keep"');
237
-
238
- // New values present
239
- expect(result).toContain('[mcp_servers.mindos]');
240
- expect(result).toContain('command = "mindos"');
241
- expect(result).toContain('MCP_TRANSPORT = "stdio"');
242
- });
243
-
244
- it('preserves other servers in same section namespace', async () => {
245
- const { mergeTomlEntry } = await importToml();
246
- const existing = [
247
- '[mcp_servers.other-server]',
248
- 'type = "http"',
249
- 'url = "http://other:9000"',
250
- '',
251
- '[mcp_servers.mindos]',
252
- 'type = "http"',
253
- 'url = "http://old:8000"',
254
- '',
255
- ].join('\n');
256
-
257
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
258
- type: 'stdio',
259
- command: 'mindos',
260
- });
261
-
262
- // Other server preserved
263
- expect(result).toContain('[mcp_servers.other-server]');
264
- expect(result).toContain('url = "http://other:9000"');
265
-
266
- // mindos updated
267
- expect(result).toContain('[mcp_servers.mindos]');
268
- expect(result).toContain('type = "stdio"');
269
- expect(result).not.toContain('http://old:8000');
270
- });
271
-
272
- it('handles file with leading content before any section', async () => {
273
- const { mergeTomlEntry } = await importToml();
274
- const existing = [
275
- '# Codex configuration',
276
- 'model = "gpt-4"',
277
- '',
278
- '[mcp_servers.existing]',
279
- 'type = "stdio"',
280
- '',
281
- ].join('\n');
282
-
283
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
284
- type: 'stdio',
285
- command: 'mindos',
286
- });
287
-
288
- // Leading content preserved
289
- expect(result).toContain('# Codex configuration');
290
- expect(result).toContain('model = "gpt-4"');
291
- expect(result).toContain('[mcp_servers.existing]');
292
- expect(result).toContain('[mcp_servers.mindos]');
293
- });
294
-
295
- it('strips trailing blank lines before appending', async () => {
296
- const { mergeTomlEntry } = await importToml();
297
- const existing = '[other]\nkey = "val"\n\n\n\n';
298
-
299
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
300
- type: 'stdio',
301
- });
302
-
303
- // Should not have excessive blank lines between sections
304
- const lines = result.split('\n');
305
- let maxConsecutiveBlanks = 0;
306
- let consecutiveBlanks = 0;
307
- for (const line of lines) {
308
- if (line.trim() === '') {
309
- consecutiveBlanks++;
310
- maxConsecutiveBlanks = Math.max(maxConsecutiveBlanks, consecutiveBlanks);
311
- } else {
312
- consecutiveBlanks = 0;
313
- }
314
- }
315
- // At most 1 blank line between sections (the separator)
316
- expect(maxConsecutiveBlanks).toBeLessThanOrEqual(1);
317
- });
318
-
319
- it('replaces section with headers sub-table', async () => {
320
- const { mergeTomlEntry } = await importToml();
321
- const existing = [
322
- '[mcp_servers.mindos]',
323
- 'url = "http://old:8000"',
324
- '',
325
- '[mcp_servers.mindos.headers]',
326
- 'Authorization = "Bearer old-token"',
327
- '',
328
- ].join('\n');
329
-
330
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
331
- url: 'http://new:9000',
332
- headers: { Authorization: 'Bearer new-token' },
333
- });
334
-
335
- expect(result).not.toContain('old-token');
336
- expect(result).not.toContain('http://old:8000');
337
- expect(result).toContain('url = "http://new:9000"');
338
- expect(result).toContain('Authorization = "Bearer new-token"');
339
- });
340
- });
341
-
342
- // ── File I/O integration ────────────────────────────────────────────────────
343
-
344
- describe('TOML file I/O integration', () => {
345
- it('creates new TOML config file when none exists', async () => {
346
- const { mergeTomlEntry } = await importToml();
347
- const configPath = path.join(tempDir, 'config.toml');
348
- const entry = {
349
- type: 'stdio',
350
- command: 'mindos',
351
- args: ['mcp'],
352
- env: { MCP_TRANSPORT: 'stdio' },
353
- };
354
-
355
- const merged = mergeTomlEntry('', 'mcp_servers', 'mindos', entry);
356
- fs.writeFileSync(configPath, merged, 'utf-8');
357
-
358
- const content = fs.readFileSync(configPath, 'utf-8');
359
- expect(content).toContain('[mcp_servers.mindos]');
360
- expect(content).toContain('type = "stdio"');
361
- expect(content).toContain('command = "mindos"');
362
- expect(content).toContain('args = ["mcp"]');
363
- expect(content).toContain('[mcp_servers.mindos.env]');
364
- expect(content).toContain('MCP_TRANSPORT = "stdio"');
365
- });
366
-
367
- it('preserves existing TOML content when merging', async () => {
368
- const { mergeTomlEntry } = await importToml();
369
- const configPath = path.join(tempDir, 'config.toml');
370
-
371
- // Write initial config (simulates existing Codex config)
372
- const initial = [
373
- '# Codex global config',
374
- 'model = "o3"',
375
- 'approval_mode = "suggest"',
376
- '',
377
- '[mcp_servers.filesystem]',
378
- 'type = "stdio"',
379
- 'command = "npx"',
380
- 'args = ["-y", "@anthropic/filesystem-server"]',
381
- '',
382
- ].join('\n');
383
- fs.writeFileSync(configPath, initial, 'utf-8');
384
-
385
- // Merge mindos entry
386
- const existing = fs.readFileSync(configPath, 'utf-8');
387
- const merged = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
388
- type: 'stdio',
389
- command: 'mindos',
390
- args: ['mcp'],
391
- env: { MCP_TRANSPORT: 'stdio' },
392
- });
393
- fs.writeFileSync(configPath, merged, 'utf-8');
394
-
395
- const content = fs.readFileSync(configPath, 'utf-8');
396
-
397
- // Original content preserved
398
- expect(content).toContain('# Codex global config');
399
- expect(content).toContain('model = "o3"');
400
- expect(content).toContain('approval_mode = "suggest"');
401
- expect(content).toContain('[mcp_servers.filesystem]');
402
- expect(content).toContain('command = "npx"');
403
-
404
- // New mindos entry added
405
- expect(content).toContain('[mcp_servers.mindos]');
406
- expect(content).toContain('type = "stdio"');
407
- expect(content).toContain('command = "mindos"');
408
- });
409
-
410
- it('updates existing mindos entry without losing other content', async () => {
411
- const { mergeTomlEntry } = await importToml();
412
- const configPath = path.join(tempDir, 'config.toml');
413
-
414
- // Write config with old mindos + other server
415
- const initial = [
416
- '[mcp_servers.other]',
417
- 'type = "stdio"',
418
- 'command = "other-cmd"',
419
- '',
420
- '[mcp_servers.mindos]',
421
- 'type = "http"',
422
- 'url = "http://old:8000/mcp"',
423
- '',
424
- '[mcp_servers.mindos.headers]',
425
- 'Authorization = "Bearer old-token"',
426
- '',
427
- ].join('\n');
428
- fs.writeFileSync(configPath, initial, 'utf-8');
429
-
430
- // Update mindos to stdio
431
- const existing = fs.readFileSync(configPath, 'utf-8');
432
- const merged = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
433
- type: 'stdio',
434
- command: 'mindos',
435
- args: ['mcp'],
436
- env: { MCP_TRANSPORT: 'stdio' },
437
- });
438
- fs.writeFileSync(configPath, merged, 'utf-8');
439
-
440
- const content = fs.readFileSync(configPath, 'utf-8');
441
-
442
- // Other server preserved
443
- expect(content).toContain('[mcp_servers.other]');
444
- expect(content).toContain('command = "other-cmd"');
445
-
446
- // Old mindos values gone
447
- expect(content).not.toContain('http://old:8000/mcp');
448
- expect(content).not.toContain('old-token');
449
-
450
- // New mindos values present
451
- expect(content).toContain('[mcp_servers.mindos]');
452
- expect(content).toContain('type = "stdio"');
453
- expect(content).toContain('command = "mindos"');
454
- expect(content).toContain('[mcp_servers.mindos.env]');
455
- });
456
-
457
- it('roundtrip: TS parseToml can read CLI-generated TOML', async () => {
458
- const { mergeTomlEntry } = await importToml();
459
- const configPath = path.join(tempDir, 'config.toml');
460
-
461
- const merged = mergeTomlEntry('', 'mcp_servers', 'mindos', {
462
- type: 'stdio',
463
- command: 'mindos',
464
- args: ['mcp'],
465
- env: { MCP_TRANSPORT: 'stdio' },
466
- });
467
- fs.writeFileSync(configPath, merged, 'utf-8');
468
-
469
- // Simulate the TS parseTomlServerNames function (from app/lib/mcp-agents.ts:376-400)
470
- const content = fs.readFileSync(configPath, 'utf-8');
471
- const lines = content.split('\n');
472
- const names = new Set<string>();
473
- const sectionPrefix = 'mcp_servers.';
474
- for (const line of lines) {
475
- const trimmed = line.trim();
476
- if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
477
- const section = trimmed.slice(1, -1).trim();
478
- if (section.startsWith(sectionPrefix)) {
479
- const name = section.slice(sectionPrefix.length).split('.')[0]?.trim();
480
- if (name) names.add(name);
481
- }
482
- }
483
- }
484
-
485
- expect(names.has('mindos')).toBe(true);
486
- });
487
-
488
- it('roundtrip: TS parseTomlMcpEntry can read CLI-generated TOML', async () => {
489
- const { mergeTomlEntry } = await importToml();
490
- const configPath = path.join(tempDir, 'config.toml');
491
-
492
- const merged = mergeTomlEntry('', 'mcp_servers', 'mindos', {
493
- type: 'stdio',
494
- command: 'mindos',
495
- args: ['mcp'],
496
- env: { MCP_TRANSPORT: 'stdio' },
497
- });
498
- fs.writeFileSync(configPath, merged, 'utf-8');
499
-
500
- // Simulate parseTomlMcpEntry (from app/lib/mcp-agents.ts:562-626)
501
- const content = fs.readFileSync(configPath, 'utf-8');
502
- const lines = content.split('\n');
503
- const targetSection = '[mcp_servers.mindos]';
504
- let inTargetSection = false;
505
- const entry: Record<string, string> = {};
506
-
507
- for (const line of lines) {
508
- const trimmed = line.trim();
509
- if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
510
- if (inTargetSection) break; // exit when next section starts
511
- inTargetSection = trimmed === targetSection;
512
- continue;
513
- }
514
- if (!inTargetSection) continue;
515
- const match = trimmed.match(/^([a-zA-Z0-9_-]+)\s*=\s*(.+)$/);
516
- if (match) {
517
- const [, key, rawValue] = match;
518
- entry[key] = rawValue.replace(/^["'](.+)["']$/, '$1');
519
- }
520
- }
521
-
522
- expect(entry.type).toBe('stdio');
523
- expect(entry.command).toBe('mindos');
524
- });
525
- });
526
-
527
- // ── Edge cases ──────────────────────────────────────────────────────────────
528
-
529
- describe('TOML edge cases', () => {
530
- it('handles file with only comments', async () => {
531
- const { mergeTomlEntry } = await importToml();
532
- const existing = '# This is a comment\n# Another comment\n';
533
-
534
- const result = mergeTomlEntry(existing, 'mcp_servers', 'mindos', {
535
- type: 'stdio',
536
- });
537
-
538
- expect(result).toContain('# This is a comment');
539
- expect(result).toContain('# Another comment');
540
- expect(result).toContain('[mcp_servers.mindos]');
541
- });
542
-
543
- it('handles consecutive merge operations (idempotent)', async () => {
544
- const { mergeTomlEntry } = await importToml();
545
-
546
- // First merge
547
- const first = mergeTomlEntry('', 'mcp_servers', 'mindos', {
548
- type: 'stdio', command: 'mindos',
549
- });
550
-
551
- // Second merge (should replace, not duplicate)
552
- const second = mergeTomlEntry(first, 'mcp_servers', 'mindos', {
553
- type: 'http', url: 'http://localhost:8781/mcp',
554
- });
555
-
556
- // Count occurrences of section header
557
- const matches = second.match(/\[mcp_servers\.mindos\]/g);
558
- expect(matches).toHaveLength(1);
559
-
560
- // New values present, old gone
561
- expect(second).toContain('type = "http"');
562
- expect(second).not.toContain('type = "stdio"');
563
- });
564
-
565
- it('handles multiple different servers in sequence', async () => {
566
- const { mergeTomlEntry } = await importToml();
567
-
568
- let content = '';
569
- content = mergeTomlEntry(content, 'mcp_servers', 'server-a', {
570
- type: 'stdio', command: 'a',
571
- });
572
- content = mergeTomlEntry(content, 'mcp_servers', 'server-b', {
573
- type: 'stdio', command: 'b',
574
- });
575
- content = mergeTomlEntry(content, 'mcp_servers', 'mindos', {
576
- type: 'stdio', command: 'mindos',
577
- });
578
-
579
- expect(content).toContain('[mcp_servers.server-a]');
580
- expect(content).toContain('[mcp_servers.server-b]');
581
- expect(content).toContain('[mcp_servers.mindos]');
582
- expect(content).toContain('command = "a"');
583
- expect(content).toContain('command = "b"');
584
- expect(content).toContain('command = "mindos"');
585
- });
586
- });