@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,506 +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
- * End-to-end user flow simulation for all agent types.
8
- *
9
- * Simulates the real code paths that run when a user does:
10
- * 1. `mindos mcp install <agent>` (CLI)
11
- * 2. Frontend "Install Selected" button (API)
12
- * 3. `mindos setup` wizard (setup.js)
13
- * 4. Frontend snippet display (mcp-snippets)
14
- *
15
- * Each test creates real temp directories and files, calls the same logic
16
- * the production code uses, and verifies the output files.
17
- */
18
-
19
- let tempDir: string;
20
-
21
- beforeEach(() => {
22
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-userflow-'));
23
- });
24
-
25
- afterEach(() => {
26
- fs.rmSync(tempDir, { recursive: true, force: true });
27
- });
28
-
29
- // ── Helpers (mirrors production code exactly) ────────────────────────────
30
-
31
- /** Pure-Node.js recursive copy (from bin/lib/mcp-install.js) */
32
- function copyDirSync(src: string, dst: string) {
33
- fs.mkdirSync(dst, { recursive: true });
34
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
35
- const s = path.join(src, entry.name);
36
- const d = path.join(dst, entry.name);
37
- if (entry.isDirectory()) {
38
- copyDirSync(s, d);
39
- } else {
40
- fs.copyFileSync(s, d);
41
- }
42
- }
43
- }
44
-
45
- /** Build MCP entry (from bin/lib/mcp-install.js:340-344) */
46
- function buildEntry(transport: string, url?: string, token?: string) {
47
- return transport === 'stdio'
48
- ? { type: 'stdio', command: 'mindos', args: ['mcp'], env: { MCP_TRANSPORT: 'stdio' } }
49
- : token
50
- ? { url, headers: { Authorization: `Bearer ${token}` } }
51
- : { url };
52
- }
53
-
54
- /** TOML builder (from bin/lib/toml.js) */
55
- function buildTomlEntry(sectionKey: string, serverName: string, entry: Record<string, unknown>): string {
56
- const lines: string[] = [];
57
- lines.push(`[${sectionKey}.${serverName}]`);
58
- if (entry.type != null) lines.push(`type = "${entry.type}"`);
59
- if (entry.command != null) lines.push(`command = "${entry.command}"`);
60
- if (entry.url != null) lines.push(`url = "${entry.url}"`);
61
- if (Array.isArray(entry.args)) {
62
- lines.push(`args = [${entry.args.map((a: string) => `"${a}"`).join(', ')}]`);
63
- }
64
- if (entry.env && typeof entry.env === 'object') {
65
- lines.push('');
66
- lines.push(`[${sectionKey}.${serverName}.env]`);
67
- for (const [k, v] of Object.entries(entry.env)) {
68
- lines.push(`${k} = "${v}"`);
69
- }
70
- }
71
- if (entry.headers && typeof entry.headers === 'object') {
72
- lines.push('');
73
- lines.push(`[${sectionKey}.${serverName}.headers]`);
74
- for (const [k, v] of Object.entries(entry.headers)) {
75
- lines.push(`${k} = "${v}"`);
76
- }
77
- }
78
- return lines.join('\n');
79
- }
80
-
81
- function mergeTomlEntry(existing: string, sectionKey: string, serverName: string, entry: Record<string, unknown>): string {
82
- const sectionHeader = `[${sectionKey}.${serverName}]`;
83
- const envHeader = `[${sectionKey}.${serverName}.env]`;
84
- const headersHeader = `[${sectionKey}.${serverName}.headers]`;
85
- const newBlock = buildTomlEntry(sectionKey, serverName, entry);
86
- const lines = existing.split('\n');
87
- const result: string[] = [];
88
- let skipping = false;
89
- for (const line of lines) {
90
- const trimmed = line.trim();
91
- if (trimmed === sectionHeader || trimmed === envHeader || trimmed === headersHeader) {
92
- skipping = true; continue;
93
- }
94
- if (skipping && trimmed.startsWith('[')) skipping = false;
95
- if (!skipping) result.push(line);
96
- }
97
- while (result.length > 0 && result[result.length - 1].trim() === '') result.pop();
98
- result.push('');
99
- result.push(newBlock);
100
- result.push('');
101
- return result.join('\n');
102
- }
103
-
104
- /** Create a realistic skill source directory */
105
- function createSkillSource(skillName: string): string {
106
- const dir = path.join(tempDir, 'project', 'skills', skillName);
107
- fs.mkdirSync(dir, { recursive: true });
108
- fs.writeFileSync(path.join(dir, 'SKILL.md'), `---\nname: ${skillName}\n---\n# ${skillName} Skill`);
109
- fs.writeFileSync(path.join(dir, 'README.md'), `# ${skillName}`);
110
- return dir;
111
- }
112
-
113
- // ── Agent configs (mirrors MCP_AGENTS) ───────────────────────────────────
114
-
115
- const AGENTS = {
116
- 'workbuddy': { name: 'WorkBuddy', global: '.workbuddy/mcp.json', key: 'mcpServers', format: 'json' as const, skillMode: 'unsupported' },
117
- 'qclaw': { name: 'QClaw', global: '.qclaw/mcp.json', key: 'mcpServers', format: 'json' as const, skillMode: 'unsupported' },
118
- 'lingma': { name: 'Lingma', global: '.lingma/mcp.json', key: 'mcpServers', format: 'json' as const, skillMode: 'unsupported' },
119
- 'codex': { name: 'Codex', global: '.codex/config.toml', key: 'mcp_servers', format: 'toml' as const, skillMode: 'universal' },
120
- 'claude-code': { name: 'Claude Code', global: '.claude.json', key: 'mcpServers', format: 'json' as const, skillMode: 'additional' },
121
- };
122
-
123
- // ═══════════════════════════════════════════════════════════════════════════
124
- // Flow 1: `mindos mcp install workbuddy` (CLI, unsupported agent)
125
- // ═══════════════════════════════════════════════════════════════════════════
126
-
127
- describe('Flow 1: CLI — mindos mcp install workbuddy', () => {
128
- it('Step 1: writes MCP config to ~/.workbuddy/mcp.json', () => {
129
- const agent = AGENTS['workbuddy'];
130
- const configPath = path.join(tempDir, agent.global);
131
- const entry = buildEntry('stdio');
132
-
133
- // Simulate CLI write (mcp-install.js:387-399)
134
- const dir = path.dirname(configPath);
135
- fs.mkdirSync(dir, { recursive: true });
136
- const config: Record<string, Record<string, unknown>> = {};
137
- config[agent.key] = { mindos: entry };
138
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
139
-
140
- // Verify
141
- const written = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
142
- expect(written.mcpServers.mindos.type).toBe('stdio');
143
- expect(written.mcpServers.mindos.command).toBe('mindos');
144
- expect(written.mcpServers.mindos.args).toEqual(['mcp']);
145
- expect(written.mcpServers.mindos.env.MCP_TRANSPORT).toBe('stdio');
146
- });
147
-
148
- it('Step 2: auto-copies skill to ~/.workbuddy/skills/mindos/', () => {
149
- const skillSrc = createSkillSource('mindos');
150
- const agentDir = path.join(tempDir, '.workbuddy');
151
- fs.mkdirSync(agentDir, { recursive: true });
152
-
153
- // Simulate autoInstallSkillForAgent (mcp-install.js:31-59)
154
- const targetDir = path.join(agentDir, 'skills', 'mindos');
155
- expect(fs.existsSync(targetDir)).toBe(false);
156
- copyDirSync(skillSrc, targetDir);
157
-
158
- // Verify
159
- expect(fs.existsSync(path.join(targetDir, 'SKILL.md'))).toBe(true);
160
- expect(fs.readFileSync(path.join(targetDir, 'SKILL.md'), 'utf-8')).toContain('mindos Skill');
161
- expect(fs.existsSync(path.join(targetDir, 'README.md'))).toBe(true);
162
- });
163
-
164
- it('Step 3: skips copy if skill already exists', () => {
165
- const skillSrc = createSkillSource('mindos');
166
- const targetDir = path.join(tempDir, '.workbuddy', 'skills', 'mindos');
167
- fs.mkdirSync(targetDir, { recursive: true });
168
- fs.writeFileSync(path.join(targetDir, 'SKILL.md'), 'user-customized');
169
-
170
- // Guard check (mcp-install.js:51)
171
- if (!fs.existsSync(targetDir)) {
172
- copyDirSync(skillSrc, targetDir);
173
- }
174
-
175
- expect(fs.readFileSync(path.join(targetDir, 'SKILL.md'), 'utf-8')).toBe('user-customized');
176
- });
177
-
178
- it('End-to-end: MCP config + skill copy in one flow', () => {
179
- const skillSrc = createSkillSource('mindos');
180
- const agentDir = path.join(tempDir, '.workbuddy');
181
- fs.mkdirSync(agentDir, { recursive: true });
182
-
183
- // Step A: write MCP config
184
- const configPath = path.join(agentDir, 'mcp.json');
185
- const entry = buildEntry('stdio');
186
- fs.writeFileSync(configPath, JSON.stringify({ mcpServers: { mindos: entry } }, null, 2) + '\n');
187
-
188
- // Step B: auto-copy skill
189
- const targetSkill = path.join(agentDir, 'skills', 'mindos');
190
- copyDirSync(skillSrc, targetSkill);
191
-
192
- // Verify both exist
193
- expect(fs.existsSync(configPath)).toBe(true);
194
- expect(fs.existsSync(path.join(targetSkill, 'SKILL.md'))).toBe(true);
195
-
196
- // Verify MCP config is valid JSON
197
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
198
- expect(config.mcpServers.mindos.type).toBe('stdio');
199
- });
200
- });
201
-
202
- // ═══════════════════════════════════════════════════════════════════════════
203
- // Flow 2: `mindos mcp install codex` (CLI, TOML agent)
204
- // ═══════════════════════════════════════════════════════════════════════════
205
-
206
- describe('Flow 2: CLI — mindos mcp install codex (TOML)', () => {
207
- it('writes valid TOML to ~/.codex/config.toml', () => {
208
- const configPath = path.join(tempDir, '.codex', 'config.toml');
209
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
210
-
211
- const entry = buildEntry('stdio');
212
- const merged = mergeTomlEntry('', 'mcp_servers', 'mindos', entry);
213
- fs.writeFileSync(configPath, merged, 'utf-8');
214
-
215
- const content = fs.readFileSync(configPath, 'utf-8');
216
- expect(content).toContain('[mcp_servers.mindos]');
217
- expect(content).toContain('type = "stdio"');
218
- expect(content).toContain('command = "mindos"');
219
- expect(content).toContain('[mcp_servers.mindos.env]');
220
- expect(content).toContain('MCP_TRANSPORT = "stdio"');
221
- });
222
-
223
- it('preserves existing codex config when adding MindOS', () => {
224
- const configPath = path.join(tempDir, '.codex', 'config.toml');
225
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
226
-
227
- const existing = 'model = "o3"\napproval_mode = "suggest"\n\n[mcp_servers.filesystem]\ntype = "stdio"\ncommand = "npx"\n';
228
- fs.writeFileSync(configPath, existing);
229
-
230
- const content = fs.readFileSync(configPath, 'utf-8');
231
- const entry = buildEntry('stdio');
232
- const merged = mergeTomlEntry(content, 'mcp_servers', 'mindos', entry);
233
- fs.writeFileSync(configPath, merged, 'utf-8');
234
-
235
- const final = fs.readFileSync(configPath, 'utf-8');
236
- expect(final).toContain('model = "o3"');
237
- expect(final).toContain('[mcp_servers.filesystem]');
238
- expect(final).toContain('[mcp_servers.mindos]');
239
- });
240
-
241
- it('does NOT auto-copy skill (codex is universal, not unsupported)', () => {
242
- // codex has mode: 'universal', so autoInstallSkillForAgent should return null
243
- const agent = AGENTS['codex'];
244
- expect(agent.skillMode).toBe('universal');
245
- // The check: reg.mode !== 'unsupported' → return null
246
- });
247
- });
248
-
249
- // ═══════════════════════════════════════════════════════════════════════════
250
- // Flow 3: Frontend "Install Selected" (API route, unsupported agent)
251
- // ═══════════════════════════════════════════════════════════════════════════
252
-
253
- describe('Flow 3: Frontend API — install unsupported agent', () => {
254
- it('writes MCP config + copies skill in one API call', () => {
255
- const skillSrc = createSkillSource('mindos');
256
-
257
- for (const agentKey of ['workbuddy', 'qclaw', 'lingma'] as const) {
258
- const agent = AGENTS[agentKey];
259
- const agentHome = path.join(tempDir, path.dirname(agent.global));
260
- fs.mkdirSync(agentHome, { recursive: true });
261
-
262
- // Step A: write MCP config (API route.ts:187-203)
263
- const configPath = path.join(tempDir, agent.global);
264
- const entry = buildEntry('stdio');
265
- const config: Record<string, Record<string, unknown>> = {};
266
- config[agent.key] = { mindos: entry };
267
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
268
-
269
- // Step B: auto-copy skill (API route.ts:218-231)
270
- const skillTarget = path.join(agentHome, 'skills', 'mindos');
271
- if (!fs.existsSync(skillTarget)) {
272
- copyDirSync(skillSrc, skillTarget);
273
- }
274
-
275
- // Verify MCP config
276
- const written = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
277
- expect(written.mcpServers.mindos.type).toBe('stdio');
278
-
279
- // Verify skill
280
- expect(fs.existsSync(path.join(skillTarget, 'SKILL.md'))).toBe(true);
281
- }
282
- });
283
-
284
- it('MCP config for workbuddy is valid and complete', () => {
285
- const configPath = path.join(tempDir, '.workbuddy', 'mcp.json');
286
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
287
-
288
- const entry = buildEntry('stdio');
289
- fs.writeFileSync(configPath, JSON.stringify({ mcpServers: { mindos: entry } }, null, 2) + '\n');
290
-
291
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
292
-
293
- // Full struct validation
294
- expect(Object.keys(config)).toEqual(['mcpServers']);
295
- expect(Object.keys(config.mcpServers)).toEqual(['mindos']);
296
- expect(config.mcpServers.mindos).toEqual({
297
- type: 'stdio',
298
- command: 'mindos',
299
- args: ['mcp'],
300
- env: { MCP_TRANSPORT: 'stdio' },
301
- });
302
- });
303
-
304
- it('HTTP transport with token works for unsupported agents', () => {
305
- const configPath = path.join(tempDir, '.qclaw', 'mcp.json');
306
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
307
-
308
- const entry = buildEntry('http', 'http://192.168.1.100:8781/mcp', 'secret-token');
309
- fs.writeFileSync(configPath, JSON.stringify({ mcpServers: { mindos: entry } }, null, 2) + '\n');
310
-
311
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
312
- expect(config.mcpServers.mindos.url).toBe('http://192.168.1.100:8781/mcp');
313
- expect(config.mcpServers.mindos.headers.Authorization).toBe('Bearer secret-token');
314
- });
315
- });
316
-
317
- // ═══════════════════════════════════════════════════════════════════════════
318
- // Flow 4: Frontend snippet display
319
- // ═══════════════════════════════════════════════════════════════════════════
320
-
321
- describe('Flow 4: Frontend — config snippet generation', () => {
322
- it('WorkBuddy stdio snippet is valid JSON', () => {
323
- // Simulate generateStdioSnippet for WorkBuddy (format: json, key: mcpServers)
324
- const stdioEntry = { type: 'stdio', command: 'mindos', args: ['mcp'] };
325
- const snippet = JSON.stringify({ mcpServers: { mindos: stdioEntry } }, null, 2);
326
-
327
- // Verify it's parseable and correct
328
- const parsed = JSON.parse(snippet);
329
- expect(parsed.mcpServers.mindos.type).toBe('stdio');
330
- expect(parsed.mcpServers.mindos.command).toBe('mindos');
331
- expect(snippet).toContain('"mcpServers"');
332
- });
333
-
334
- it('Codex stdio snippet is valid TOML', () => {
335
- // Simulate generateStdioSnippet for Codex (format: toml, key: mcp_servers)
336
- const lines = [
337
- '[mcp_servers.mindos]',
338
- 'command = "mindos"',
339
- 'args = ["mcp"]',
340
- '',
341
- '[mcp_servers.mindos.env]',
342
- 'MCP_TRANSPORT = "stdio"',
343
- ];
344
- const snippet = lines.join('\n');
345
-
346
- expect(snippet).toContain('[mcp_servers.mindos]');
347
- expect(snippet).toContain('command = "mindos"');
348
- expect(snippet).toContain('MCP_TRANSPORT = "stdio"');
349
- });
350
-
351
- it('WorkBuddy HTTP snippet includes auth header', () => {
352
- const httpEntry = { url: 'http://192.168.1.100:8781/mcp', headers: { Authorization: 'Bearer tok-123' } };
353
- const snippet = JSON.stringify({ mcpServers: { mindos: httpEntry } }, null, 2);
354
-
355
- expect(snippet).toContain('"url"');
356
- expect(snippet).toContain('192.168.1.100');
357
- expect(snippet).toContain('Bearer tok-123');
358
- });
359
- });
360
-
361
- // ═══════════════════════════════════════════════════════════════════════════
362
- // Flow 5: setup.js wizard — cpSync skill copy
363
- // ═══════════════════════════════════════════════════════════════════════════
364
-
365
- describe('Flow 5: Setup wizard — cpSync skill install', () => {
366
- it('copies skill via cpSync for unsupported agents', () => {
367
- const skillSrc = createSkillSource('mindos');
368
-
369
- for (const agent of ['.workbuddy', '.qclaw', '.lingma']) {
370
- const agentDir = path.join(tempDir, agent);
371
- fs.mkdirSync(agentDir, { recursive: true });
372
- const targetSkillDir = path.join(agentDir, 'skills', 'mindos');
373
-
374
- // Simulate setup.js: cpSync(skillSourceDir, targetSkillDir, { recursive: true })
375
- fs.cpSync(skillSrc, targetSkillDir, { recursive: true });
376
-
377
- expect(fs.existsSync(path.join(targetSkillDir, 'SKILL.md'))).toBe(true);
378
- expect(fs.readFileSync(path.join(targetSkillDir, 'SKILL.md'), 'utf-8')).toContain('mindos Skill');
379
- }
380
- });
381
-
382
- it('skips if target already exists', () => {
383
- const skillSrc = createSkillSource('mindos');
384
- const targetSkillDir = path.join(tempDir, '.workbuddy', 'skills', 'mindos');
385
- fs.mkdirSync(targetSkillDir, { recursive: true });
386
- fs.writeFileSync(path.join(targetSkillDir, 'SKILL.md'), 'custom');
387
-
388
- // Guard check (setup.js): if (!existsSync(targetSkillDir))
389
- if (!fs.existsSync(targetSkillDir)) {
390
- fs.cpSync(skillSrc, targetSkillDir, { recursive: true });
391
- }
392
-
393
- expect(fs.readFileSync(path.join(targetSkillDir, 'SKILL.md'), 'utf-8')).toBe('custom');
394
- });
395
- });
396
-
397
- // ═══════════════════════════════════════════════════════════════════════════
398
- // Flow 6: Update existing config (re-install scenario)
399
- // ═══════════════════════════════════════════════════════════════════════════
400
-
401
- describe('Flow 6: Re-install — update existing config', () => {
402
- it('WorkBuddy: updates MCP config without losing other servers', () => {
403
- const configPath = path.join(tempDir, '.workbuddy', 'mcp.json');
404
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
405
-
406
- // Pre-existing config with another MCP server
407
- fs.writeFileSync(configPath, JSON.stringify({
408
- mcpServers: {
409
- 'other-server': { url: 'http://other:9000' },
410
- mindos: { url: 'http://old:8000' },
411
- },
412
- }, null, 2));
413
-
414
- // Re-install with stdio
415
- const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
416
- config.mcpServers.mindos = buildEntry('stdio');
417
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
418
-
419
- const final = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
420
- expect(final.mcpServers.mindos.type).toBe('stdio');
421
- expect(final.mcpServers['other-server'].url).toBe('http://other:9000');
422
- });
423
-
424
- it('Codex: updates TOML config without losing other sections', () => {
425
- const configPath = path.join(tempDir, '.codex', 'config.toml');
426
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
427
-
428
- const existing = [
429
- 'model = "o3"',
430
- '',
431
- '[mcp_servers.mindos]',
432
- 'type = "http"',
433
- 'url = "http://old:8000"',
434
- '',
435
- '[mcp_servers.other]',
436
- 'type = "stdio"',
437
- '',
438
- ].join('\n');
439
- fs.writeFileSync(configPath, existing);
440
-
441
- const content = fs.readFileSync(configPath, 'utf-8');
442
- const merged = mergeTomlEntry(content, 'mcp_servers', 'mindos', buildEntry('stdio'));
443
- fs.writeFileSync(configPath, merged);
444
-
445
- const final = fs.readFileSync(configPath, 'utf-8');
446
- expect(final).toContain('model = "o3"');
447
- expect(final).toContain('[mcp_servers.other]');
448
- expect(final).toContain('[mcp_servers.mindos]');
449
- expect(final).toContain('type = "stdio"');
450
- expect(final).not.toContain('http://old:8000');
451
- });
452
-
453
- it('WorkBuddy: skill not overwritten on re-install', () => {
454
- const skillSrc = createSkillSource('mindos');
455
- const targetSkill = path.join(tempDir, '.workbuddy', 'skills', 'mindos');
456
-
457
- // First install
458
- copyDirSync(skillSrc, targetSkill);
459
- // User customizes
460
- fs.writeFileSync(path.join(targetSkill, 'SKILL.md'), 'user-patched');
461
-
462
- // Re-install: guard prevents overwrite
463
- if (!fs.existsSync(targetSkill)) {
464
- copyDirSync(skillSrc, targetSkill);
465
- }
466
-
467
- expect(fs.readFileSync(path.join(targetSkill, 'SKILL.md'), 'utf-8')).toBe('user-patched');
468
- });
469
- });
470
-
471
- // ═══════════════════════════════════════════════════════════════════════════
472
- // Flow 7: Cross-agent consistency check
473
- // ═══════════════════════════════════════════════════════════════════════════
474
-
475
- describe('Flow 7: Cross-agent consistency — all agents produce valid configs', () => {
476
- it('all JSON agents produce identical MCP entry structure', () => {
477
- const entry = buildEntry('stdio');
478
-
479
- for (const [key, agent] of Object.entries(AGENTS)) {
480
- if (agent.format === 'toml') continue;
481
-
482
- const configPath = path.join(tempDir, `test-${key}.json`);
483
- const config: Record<string, Record<string, unknown>> = {};
484
- config[agent.key] = { mindos: entry };
485
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
486
-
487
- const parsed = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
488
- expect(parsed[agent.key].mindos.type).toBe('stdio');
489
- expect(parsed[agent.key].mindos.command).toBe('mindos');
490
- expect(parsed[agent.key].mindos.args).toEqual(['mcp']);
491
- }
492
- });
493
-
494
- it('TOML agents produce valid TOML entry', () => {
495
- const entry = buildEntry('stdio');
496
-
497
- for (const [key, agent] of Object.entries(AGENTS)) {
498
- if (agent.format !== 'toml') continue;
499
-
500
- const merged = mergeTomlEntry('', agent.key, 'mindos', entry);
501
- expect(merged).toContain(`[${agent.key}.mindos]`);
502
- expect(merged).toContain('type = "stdio"');
503
- expect(merged).toContain('command = "mindos"');
504
- }
505
- });
506
- });
@@ -1,86 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { parseLogHint } from '../../bin/lib/gateway.js';
3
-
4
- describe('parseLogHint', () => {
5
- // ── npm install lines ──
6
- it('detects "Installing app dependencies"', () => {
7
- expect(parseLogHint('Installing app dependencies (first run)...\n')).toBe('installing dependencies…');
8
- });
9
-
10
- it('detects "Updating app dependencies"', () => {
11
- expect(parseLogHint('Updating app dependencies (package-lock.json changed)...\n')).toBe('updating dependencies…');
12
- });
13
-
14
- it('detects "added N packages"', () => {
15
- expect(parseLogHint('added 387 packages in 12s')).toBe('dependencies installed');
16
- });
17
-
18
- it('detects "Installing MCP dependencies"', () => {
19
- expect(parseLogHint('Installing MCP dependencies (first run)...\n')).toBe('installing MCP…');
20
- });
21
-
22
- // ── next build lines ──
23
- it('detects "Building MindOS"', () => {
24
- expect(parseLogHint('Building MindOS (first run or new version detected)...\n')).toBe('building app…');
25
- });
26
-
27
- it('detects "Creating an optimized production build"', () => {
28
- expect(parseLogHint(' Creating an optimized production build ...')).toBe('building app…');
29
- });
30
-
31
- it('detects "Compiling"', () => {
32
- expect(parseLogHint(' ✓ Compiled /api/health in 320ms')).toBe('compiling…');
33
- });
34
-
35
- it('detects "Collecting page data"', () => {
36
- expect(parseLogHint(' Collecting page data ...')).toBe('collecting page data…');
37
- });
38
-
39
- it('detects "Generating static pages"', () => {
40
- expect(parseLogHint(' Generating static pages (0/8) ...')).toBe('generating pages…');
41
- });
42
-
43
- it('detects "Finalizing page optimization"', () => {
44
- expect(parseLogHint(' Finalizing page optimization ...')).toBe('optimizing…');
45
- });
46
-
47
- it('detects route bundle lines', () => {
48
- expect(parseLogHint('├ ○ /api/health 0.3 kB')).toBe('bundling routes…');
49
- });
50
-
51
- // ── next start lines ──
52
- it('detects Next.js banner', () => {
53
- expect(parseLogHint('▲ Next.js 15.2.4')).toBe('starting server…');
54
- });
55
-
56
- it('detects "Ready in"', () => {
57
- expect(parseLogHint(' Ready in 1.8s')).toBe('starting server…');
58
- });
59
-
60
- // ── should NOT match ──
61
- it('returns null for empty lines', () => {
62
- expect(parseLogHint('')).toBeNull();
63
- expect(parseLogHint(' ')).toBeNull();
64
- });
65
-
66
- it('returns null for npm warn/error lines', () => {
67
- // These don't match any pattern since we removed the error catch-all
68
- expect(parseLogHint('npm warn deprecated inflight@1.0.6')).toBeNull();
69
- });
70
-
71
- it('returns null for stack trace lines', () => {
72
- expect(parseLogHint(' at Function._resolveFilename (node:internal/modules/cjs/loader:1383:15)')).toBeNull();
73
- });
74
-
75
- it('returns null for random log lines', () => {
76
- expect(parseLogHint('Server listening on port 3456')).toBeNull();
77
- expect(parseLogHint('[MCP] Request: tools/list')).toBeNull();
78
- });
79
-
80
- // "Installing MCP dependencies" should match MCP, not generic dependencies
81
- it('prioritizes MCP match for MCP dependencies line', () => {
82
- // The line contains both "Installing" and "MCP dependencies"
83
- // "Installing MCP dependencies" should match the MCP-specific rule
84
- expect(parseLogHint('Installing MCP dependencies (first run)...')).toBe('installing MCP…');
85
- });
86
- });