@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,260 +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 auto-copy skill logic used by unsupported agents.
8
- *
9
- * Validates:
10
- * 1. copyDirSync — recursive pure-Node.js directory copy (cross-platform)
11
- * 2. autoInstallSkillForAgent — end-to-end skill copy for unsupported agents
12
- * 3. Edge cases: existing target, missing source, symlinks, nested dirs
13
- */
14
-
15
- let tempDir: string;
16
-
17
- beforeEach(() => {
18
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-skill-copy-test-'));
19
- });
20
-
21
- afterEach(() => {
22
- fs.rmSync(tempDir, { recursive: true, force: true });
23
- });
24
-
25
- // ── copyDirSync (extracted from bin/lib/mcp-install.js for testing) ──────
26
-
27
- /** Pure-Node.js recursive directory copy — mirrors the CLI implementation. */
28
- function copyDirSync(src: string, dst: string) {
29
- fs.mkdirSync(dst, { recursive: true });
30
- for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
31
- const s = path.join(src, entry.name);
32
- const d = path.join(dst, entry.name);
33
- if (entry.isDirectory()) {
34
- copyDirSync(s, d);
35
- } else {
36
- fs.copyFileSync(s, d);
37
- }
38
- }
39
- }
40
-
41
- describe('copyDirSync (cross-platform recursive copy)', () => {
42
- it('copies a flat directory with files', () => {
43
- const src = path.join(tempDir, 'src');
44
- const dst = path.join(tempDir, 'dst');
45
- fs.mkdirSync(src);
46
- fs.writeFileSync(path.join(src, 'SKILL.md'), '# Test Skill\n');
47
- fs.writeFileSync(path.join(src, 'config.json'), '{"key":"val"}');
48
-
49
- copyDirSync(src, dst);
50
-
51
- expect(fs.existsSync(path.join(dst, 'SKILL.md'))).toBe(true);
52
- expect(fs.existsSync(path.join(dst, 'config.json'))).toBe(true);
53
- expect(fs.readFileSync(path.join(dst, 'SKILL.md'), 'utf-8')).toBe('# Test Skill\n');
54
- expect(fs.readFileSync(path.join(dst, 'config.json'), 'utf-8')).toBe('{"key":"val"}');
55
- });
56
-
57
- it('copies nested directories recursively', () => {
58
- const src = path.join(tempDir, 'src');
59
- fs.mkdirSync(path.join(src, 'sub', 'deep'), { recursive: true });
60
- fs.writeFileSync(path.join(src, 'top.txt'), 'top');
61
- fs.writeFileSync(path.join(src, 'sub', 'mid.txt'), 'mid');
62
- fs.writeFileSync(path.join(src, 'sub', 'deep', 'bottom.txt'), 'bottom');
63
-
64
- const dst = path.join(tempDir, 'dst');
65
- copyDirSync(src, dst);
66
-
67
- expect(fs.readFileSync(path.join(dst, 'top.txt'), 'utf-8')).toBe('top');
68
- expect(fs.readFileSync(path.join(dst, 'sub', 'mid.txt'), 'utf-8')).toBe('mid');
69
- expect(fs.readFileSync(path.join(dst, 'sub', 'deep', 'bottom.txt'), 'utf-8')).toBe('bottom');
70
- });
71
-
72
- it('creates destination directory if it does not exist', () => {
73
- const src = path.join(tempDir, 'src');
74
- fs.mkdirSync(src);
75
- fs.writeFileSync(path.join(src, 'file.txt'), 'content');
76
-
77
- const dst = path.join(tempDir, 'non', 'existent', 'dst');
78
- copyDirSync(src, dst);
79
-
80
- expect(fs.existsSync(path.join(dst, 'file.txt'))).toBe(true);
81
- });
82
-
83
- it('copies empty directories', () => {
84
- const src = path.join(tempDir, 'src');
85
- fs.mkdirSync(path.join(src, 'empty-sub'), { recursive: true });
86
-
87
- const dst = path.join(tempDir, 'dst');
88
- copyDirSync(src, dst);
89
-
90
- expect(fs.statSync(path.join(dst, 'empty-sub')).isDirectory()).toBe(true);
91
- });
92
-
93
- it('preserves file content for binary-like files', () => {
94
- const src = path.join(tempDir, 'src');
95
- fs.mkdirSync(src);
96
- // Write a buffer with non-UTF8 bytes
97
- const buf = Buffer.from([0x00, 0x01, 0x02, 0xFF, 0xFE]);
98
- fs.writeFileSync(path.join(src, 'binary.bin'), buf);
99
-
100
- const dst = path.join(tempDir, 'dst');
101
- copyDirSync(src, dst);
102
-
103
- const copied = fs.readFileSync(path.join(dst, 'binary.bin'));
104
- expect(Buffer.compare(copied, buf)).toBe(0);
105
- });
106
-
107
- it('handles files with special characters in names', () => {
108
- const src = path.join(tempDir, 'src');
109
- fs.mkdirSync(src);
110
- // Spaces, dashes, dots are common in skill files
111
- fs.writeFileSync(path.join(src, 'my-skill file.v2.md'), 'content');
112
-
113
- const dst = path.join(tempDir, 'dst');
114
- copyDirSync(src, dst);
115
-
116
- expect(fs.readFileSync(path.join(dst, 'my-skill file.v2.md'), 'utf-8')).toBe('content');
117
- });
118
- });
119
-
120
- // ── Realistic skill directory copy ───────────────────────────────────────
121
-
122
- describe('Skill directory copy (realistic structure)', () => {
123
- it('copies a typical MindOS skill directory', () => {
124
- // Create a realistic skill directory
125
- const skillSrc = path.join(tempDir, 'skills', 'mindos');
126
- fs.mkdirSync(skillSrc, { recursive: true });
127
- fs.writeFileSync(path.join(skillSrc, 'SKILL.md'), '---\nname: mindos\n---\n# MindOS Skill');
128
- fs.writeFileSync(path.join(skillSrc, 'README.md'), '# README');
129
-
130
- // Simulate copying to a WorkBuddy-like agent dir
131
- const agentDir = path.join(tempDir, '.workbuddy');
132
- fs.mkdirSync(agentDir);
133
- const targetSkillDir = path.join(agentDir, 'skills', 'mindos');
134
-
135
- copyDirSync(skillSrc, targetSkillDir);
136
-
137
- expect(fs.existsSync(path.join(targetSkillDir, 'SKILL.md'))).toBe(true);
138
- expect(fs.readFileSync(path.join(targetSkillDir, 'SKILL.md'), 'utf-8')).toContain('MindOS Skill');
139
- expect(fs.existsSync(path.join(targetSkillDir, 'README.md'))).toBe(true);
140
- });
141
-
142
- it('does not overwrite if target already exists (guard check)', () => {
143
- const skillSrc = path.join(tempDir, 'skills', 'mindos');
144
- fs.mkdirSync(skillSrc, { recursive: true });
145
- fs.writeFileSync(path.join(skillSrc, 'SKILL.md'), 'new content');
146
-
147
- const targetSkillDir = path.join(tempDir, '.agent', 'skills', 'mindos');
148
- fs.mkdirSync(targetSkillDir, { recursive: true });
149
- fs.writeFileSync(path.join(targetSkillDir, 'SKILL.md'), 'existing content');
150
-
151
- // Simulate the guard from autoInstallSkillForAgent: skip if exists
152
- if (!fs.existsSync(targetSkillDir)) {
153
- copyDirSync(skillSrc, targetSkillDir);
154
- }
155
-
156
- // Existing content should NOT be overwritten
157
- expect(fs.readFileSync(path.join(targetSkillDir, 'SKILL.md'), 'utf-8')).toBe('existing content');
158
- });
159
-
160
- it('copies to multiple agent directories independently', () => {
161
- const skillSrc = path.join(tempDir, 'skills', 'mindos');
162
- fs.mkdirSync(skillSrc, { recursive: true });
163
- fs.writeFileSync(path.join(skillSrc, 'SKILL.md'), 'shared skill');
164
-
165
- // Copy to 3 different unsupported agent dirs
166
- for (const agent of ['workbuddy', 'qclaw', 'lingma']) {
167
- const target = path.join(tempDir, `.${agent}`, 'skills', 'mindos');
168
- fs.mkdirSync(path.join(tempDir, `.${agent}`), { recursive: true });
169
- copyDirSync(skillSrc, target);
170
- expect(fs.readFileSync(path.join(target, 'SKILL.md'), 'utf-8')).toBe('shared skill');
171
- }
172
- });
173
-
174
- it('copies Chinese skill variant (mindos-zh) when available', () => {
175
- // Create both English and Chinese skill variants
176
- const skillSrcEn = path.join(tempDir, 'skills', 'mindos');
177
- fs.mkdirSync(skillSrcEn, { recursive: true });
178
- fs.writeFileSync(path.join(skillSrcEn, 'SKILL.md'), '---\nname: mindos\n---\n# MindOS (English)');
179
-
180
- const skillSrcZh = path.join(tempDir, 'skills', 'mindos-zh');
181
- fs.mkdirSync(skillSrcZh, { recursive: true });
182
- fs.writeFileSync(path.join(skillSrcZh, 'SKILL.md'), '---\nname: mindos-zh\n---\n# MindOS (中文)');
183
-
184
- // Simulate copying Chinese variant to agent
185
- const agentDir = path.join(tempDir, '.copaw');
186
- fs.mkdirSync(agentDir);
187
- const targetSkillZh = path.join(agentDir, 'skills', 'mindos-zh');
188
-
189
- copyDirSync(skillSrcZh, targetSkillZh);
190
-
191
- expect(fs.existsSync(path.join(targetSkillZh, 'SKILL.md'))).toBe(true);
192
- expect(fs.readFileSync(path.join(targetSkillZh, 'SKILL.md'), 'utf-8')).toContain('中文');
193
- });
194
-
195
- it('supports both English and Chinese skill variants for all unsupported agents', () => {
196
- // Create both skill variants
197
- const skillSrcEn = path.join(tempDir, 'skills', 'mindos');
198
- fs.mkdirSync(skillSrcEn, { recursive: true });
199
- fs.writeFileSync(path.join(skillSrcEn, 'SKILL.md'), 'English version');
200
-
201
- const skillSrcZh = path.join(tempDir, 'skills', 'mindos-zh');
202
- fs.mkdirSync(skillSrcZh, { recursive: true });
203
- fs.writeFileSync(path.join(skillSrcZh, 'SKILL.md'), '中文版本');
204
-
205
- // Test all unsupported agents
206
- const agents = ['workbuddy', 'qclaw', 'lingma', 'copaw'];
207
- for (const agent of agents) {
208
- const agentDir = path.join(tempDir, `.${agent}`);
209
- fs.mkdirSync(agentDir, { recursive: true });
210
-
211
- // English variant
212
- const targetEn = path.join(agentDir, 'skills', 'mindos');
213
- copyDirSync(skillSrcEn, targetEn);
214
- expect(fs.readFileSync(path.join(targetEn, 'SKILL.md'), 'utf-8')).toBe('English version');
215
-
216
- // Chinese variant (reset for next agent)
217
- fs.rmSync(agentDir, { recursive: true });
218
- fs.mkdirSync(agentDir, { recursive: true });
219
- const targetZh = path.join(agentDir, 'skills', 'mindos-zh');
220
- copyDirSync(skillSrcZh, targetZh);
221
- expect(fs.readFileSync(path.join(targetZh, 'SKILL.md'), 'utf-8')).toBe('中文版本');
222
- }
223
- });
224
- });
225
-
226
- // ── cpSync cross-platform equivalence ────────────────────────────────────
227
-
228
- describe('Node.js cpSync vs copyDirSync equivalence', () => {
229
- it('produces identical output to cpSync recursive', () => {
230
- const src = path.join(tempDir, 'src');
231
- fs.mkdirSync(path.join(src, 'sub'), { recursive: true });
232
- fs.writeFileSync(path.join(src, 'a.txt'), 'aaa');
233
- fs.writeFileSync(path.join(src, 'sub', 'b.txt'), 'bbb');
234
-
235
- const dst1 = path.join(tempDir, 'dst-cpsync');
236
- const dst2 = path.join(tempDir, 'dst-manual');
237
-
238
- // cpSync (used in setup.js)
239
- fs.cpSync(src, dst1, { recursive: true });
240
- // copyDirSync (used in mcp-install.js)
241
- copyDirSync(src, dst2);
242
-
243
- // Both should produce identical file trees
244
- const walk = (dir: string): Record<string, string> => {
245
- const result: Record<string, string> = {};
246
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
247
- const rel = entry.name;
248
- const abs = path.join(dir, rel);
249
- if (entry.isDirectory()) {
250
- Object.entries(walk(abs)).forEach(([k, v]) => { result[`${rel}/${k}`] = v; });
251
- } else {
252
- result[rel] = fs.readFileSync(abs, 'utf-8');
253
- }
254
- }
255
- return result;
256
- };
257
-
258
- expect(walk(dst1)).toEqual(walk(dst2));
259
- });
260
- });
@@ -1,88 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { execFileSync } from 'child_process';
3
- import fs from 'fs';
4
- import os from 'os';
5
- import path from 'path';
6
-
7
- /**
8
- * CLI smoke tests — verify core commands don't crash on invocation.
9
- * Runs `node bin/cli.js` in a subprocess with HOME set to an empty temp dir
10
- * so no real config interferes.
11
- */
12
-
13
- const ROOT = path.resolve(__dirname, '..', '..');
14
- const CLI = path.join(ROOT, 'bin', 'cli.js');
15
-
16
- let tempHome: string;
17
- let savedHome: string | undefined;
18
-
19
- beforeEach(() => {
20
- tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-smoke-'));
21
- savedHome = process.env.HOME;
22
- });
23
-
24
- afterEach(() => {
25
- process.env.HOME = savedHome;
26
- fs.rmSync(tempHome, { recursive: true, force: true });
27
- });
28
-
29
- function run(args: string[]): { stdout: string; stderr: string; exitCode: number } {
30
- try {
31
- const stdout = execFileSync(process.execPath, [CLI, ...args], {
32
- encoding: 'utf-8',
33
- env: { ...process.env, HOME: tempHome, NODE_ENV: 'test' },
34
- timeout: 15000,
35
- stdio: ['pipe', 'pipe', 'pipe'],
36
- });
37
- return { stdout, stderr: '', exitCode: 0 };
38
- } catch (err: unknown) {
39
- const e = err as { stdout?: string; stderr?: string; status?: number };
40
- return {
41
- stdout: e.stdout || '',
42
- stderr: e.stderr || '',
43
- exitCode: e.status ?? 1,
44
- };
45
- }
46
- }
47
-
48
- describe('CLI smoke tests', () => {
49
- it('mindos --version exits 0 and outputs version', () => {
50
- const { stdout, exitCode } = run(['--version']);
51
- expect(exitCode).toBe(0);
52
- expect(stdout).toMatch(/mindos\/\d+\.\d+\.\d+/);
53
- });
54
-
55
- it('mindos --help exits 0 and outputs help text', () => {
56
- const { stdout, exitCode } = run(['--help']);
57
- expect(exitCode).toBe(0);
58
- expect(stdout).toContain('MindOS CLI');
59
- });
60
-
61
- it('mindos doctor without config exits 1 and suggests onboard', () => {
62
- const { stdout, stderr, exitCode } = run(['doctor']);
63
- expect(exitCode).toBe(1);
64
- const output = stdout + stderr;
65
- expect(output).toMatch(/onboard/i);
66
- });
67
-
68
- it('mindos config show without config exits 1', () => {
69
- const { exitCode } = run(['config', 'show']);
70
- expect(exitCode).toBe(1);
71
- });
72
-
73
- it('mindos config validate without config exits 1', () => {
74
- const { exitCode } = run(['config', 'validate']);
75
- expect(exitCode).toBe(1);
76
- });
77
-
78
- it('mindos sync without config exits 0 and shows not configured', () => {
79
- const { stdout, exitCode } = run(['sync']);
80
- expect(exitCode).toBe(0);
81
- expect(stdout).toMatch(/not configured/i);
82
- });
83
-
84
- it('mindos nonexistent exits 1', () => {
85
- const { exitCode } = run(['nonexistent']);
86
- expect(exitCode).toBe(1);
87
- });
88
- });
@@ -1,218 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { execFileSync } from 'child_process';
3
- import fs from 'fs';
4
- import os from 'os';
5
- import path from 'path';
6
-
7
- /**
8
- * Tests for `mindos uninstall` command.
9
- *
10
- * Key invariants:
11
- * 1. Default answer is N — empty/piped stdin must abort without deleting anything
12
- * 2. Config is read BEFORE ~/.mindos/ is deleted (ordering bug regression)
13
- * 3. Knowledge base deletion requires triple protection (confirm → YES → password)
14
- * 4. Help text lists the uninstall command
15
- */
16
-
17
- const ROOT = path.resolve(__dirname, '..', '..');
18
- const CLI = path.join(ROOT, 'bin', 'cli.js');
19
-
20
- let tempHome: string;
21
- let savedHome: string | undefined;
22
-
23
- beforeEach(() => {
24
- tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-uninstall-'));
25
- savedHome = process.env.HOME;
26
- });
27
-
28
- afterEach(() => {
29
- process.env.HOME = savedHome;
30
- fs.rmSync(tempHome, { recursive: true, force: true });
31
- });
32
-
33
- function run(
34
- args: string[],
35
- opts: { input?: string; home?: string } = {},
36
- ): { stdout: string; stderr: string; exitCode: number } {
37
- const home = opts.home ?? tempHome;
38
- try {
39
- const stdout = execFileSync(process.execPath, [CLI, ...args], {
40
- encoding: 'utf-8',
41
- env: { ...process.env, HOME: home, NODE_ENV: 'test' },
42
- input: opts.input ?? '',
43
- timeout: 15000,
44
- stdio: ['pipe', 'pipe', 'pipe'],
45
- });
46
- return { stdout, stderr: '', exitCode: 0 };
47
- } catch (err: unknown) {
48
- const e = err as { stdout?: string; stderr?: string; status?: number };
49
- return {
50
- stdout: e.stdout || '',
51
- stderr: e.stderr || '',
52
- exitCode: e.status ?? 1,
53
- };
54
- }
55
- }
56
-
57
- /** Write a minimal config.json in the temp home's .mindos/ */
58
- function writeConfig(
59
- config: Record<string, unknown>,
60
- home: string = tempHome,
61
- ): void {
62
- const dir = path.join(home, '.mindos');
63
- fs.mkdirSync(dir, { recursive: true });
64
- fs.writeFileSync(path.join(dir, 'config.json'), JSON.stringify(config));
65
- }
66
-
67
- describe('mindos uninstall — smoke', () => {
68
- it('aborts on empty enter (default N) and exits 0', () => {
69
- const { stdout, exitCode } = run(['uninstall'], { input: '\n' });
70
- expect(exitCode).toBe(0);
71
- expect(stdout).toContain('Aborted');
72
- });
73
-
74
- it('aborts when user types n', () => {
75
- const { stdout, exitCode } = run(['uninstall'], { input: 'n\n' });
76
- expect(exitCode).toBe(0);
77
- expect(stdout).toContain('Aborted');
78
- });
79
-
80
- it('shows operation list before asking for confirmation', () => {
81
- const { stdout } = run(['uninstall'], { input: '\n' });
82
- expect(stdout).toContain('Stop running MindOS processes');
83
- expect(stdout).toContain('Remove background service');
84
- expect(stdout).toContain('Uninstall npm package');
85
- });
86
- });
87
-
88
- describe('mindos uninstall — help text', () => {
89
- it('--all lists the uninstall command', () => {
90
- const { stdout, exitCode } = run(['--all']);
91
- expect(exitCode).toBe(0);
92
- expect(stdout).toContain('uninstall');
93
- });
94
- });
95
-
96
- describe('mindos uninstall — does not delete on N answers', () => {
97
- it('keeps ~/.mindos/ when user says Y to proceed but N to remove config', () => {
98
- const mindRoot = path.join(tempHome, 'MindOS');
99
- fs.mkdirSync(mindRoot, { recursive: true });
100
- fs.writeFileSync(path.join(mindRoot, 'test.md'), 'hello');
101
- writeConfig({ mindRoot });
102
-
103
- // Y to proceed, N to remove config, N to remove knowledge base
104
- const { stdout } = run(['uninstall'], { input: 'y\nn\nn\n' });
105
- expect(stdout).toContain('Kept');
106
- expect(fs.existsSync(path.join(tempHome, '.mindos'))).toBe(true);
107
- expect(fs.existsSync(mindRoot)).toBe(true);
108
- });
109
-
110
- it('keeps knowledge base when user says Y to proceed, Y to config, N to kb', () => {
111
- const mindRoot = path.join(tempHome, 'MindOS');
112
- fs.mkdirSync(mindRoot, { recursive: true });
113
- fs.writeFileSync(path.join(mindRoot, 'test.md'), 'hello');
114
- writeConfig({ mindRoot });
115
-
116
- // Y proceed, Y remove config, N remove kb
117
- const { stdout } = run(['uninstall'], { input: 'y\ny\nn\n' });
118
- expect(fs.existsSync(path.join(tempHome, '.mindos'))).toBe(false);
119
- expect(fs.existsSync(mindRoot)).toBe(true);
120
- });
121
- });
122
-
123
- describe('mindos uninstall — knowledge base triple protection', () => {
124
- it('keeps knowledge base when user types wrong confirmation (not YES)', () => {
125
- const mindRoot = path.join(tempHome, 'MindOS');
126
- fs.mkdirSync(mindRoot, { recursive: true });
127
- writeConfig({ mindRoot });
128
-
129
- // Y proceed, N config, Y kb, type "yes" (wrong — must be uppercase YES)
130
- const { stdout } = run(['uninstall'], { input: 'y\nn\ny\nyes\n' });
131
- expect(stdout).toContain('Knowledge base kept');
132
- expect(fs.existsSync(mindRoot)).toBe(true);
133
- });
134
-
135
- it('keeps knowledge base when password is wrong', () => {
136
- const mindRoot = path.join(tempHome, 'MindOS');
137
- fs.mkdirSync(mindRoot, { recursive: true });
138
- writeConfig({ mindRoot, webPassword: 'secret123' });
139
-
140
- // Y proceed, N config, Y kb, YES confirm, wrong password
141
- const { stdout } = run(['uninstall'], { input: 'y\nn\ny\nYES\nwrongpw\n' });
142
- expect(stdout).toContain('Wrong password');
143
- expect(fs.existsSync(mindRoot)).toBe(true);
144
- });
145
-
146
- it('deletes knowledge base when all protections pass (no password)', () => {
147
- const mindRoot = path.join(tempHome, 'MindOS');
148
- fs.mkdirSync(mindRoot, { recursive: true });
149
- fs.writeFileSync(path.join(mindRoot, 'note.md'), 'data');
150
- writeConfig({ mindRoot });
151
-
152
- // Y proceed, N config, Y kb, YES confirm
153
- const { stdout } = run(['uninstall'], { input: 'y\nn\ny\nYES\n' });
154
- expect(stdout).toContain('Removed');
155
- expect(fs.existsSync(mindRoot)).toBe(false);
156
- });
157
-
158
- it('deletes knowledge base when all protections pass (correct password)', () => {
159
- const mindRoot = path.join(tempHome, 'MindOS');
160
- fs.mkdirSync(mindRoot, { recursive: true });
161
- writeConfig({ mindRoot, webPassword: 'mypass' });
162
-
163
- // Y proceed, N config, Y kb, YES confirm, correct password
164
- const { stdout } = run(['uninstall'], { input: 'y\nn\ny\nYES\nmypass\n' });
165
- expect(fs.existsSync(mindRoot)).toBe(false);
166
- });
167
- });
168
-
169
- describe('mindos uninstall — config read ordering (regression)', () => {
170
- /**
171
- * Regression: config must be read BEFORE ~/.mindos/ is deleted.
172
- * Otherwise mindRoot and webPassword are lost, and the knowledge base
173
- * question is silently skipped.
174
- *
175
- * Test: user says Y to proceed, Y to delete config, then expects the
176
- * knowledge base question to still appear (config was read beforehand).
177
- */
178
- it('still asks about knowledge base even after deleting ~/.mindos/', () => {
179
- const mindRoot = path.join(tempHome, 'MindOS');
180
- fs.mkdirSync(mindRoot, { recursive: true });
181
- fs.writeFileSync(path.join(mindRoot, 'note.md'), 'data');
182
- writeConfig({ mindRoot });
183
-
184
- // Y proceed, Y remove config (deletes ~/.mindos/), Y remove kb, YES confirm
185
- const { stdout } = run(['uninstall'], { input: 'y\ny\ny\nYES\n' });
186
- // Config dir should be gone
187
- expect(fs.existsSync(path.join(tempHome, '.mindos'))).toBe(false);
188
- // Knowledge base should also be gone — proves config was read before deletion
189
- expect(fs.existsSync(mindRoot)).toBe(false);
190
- });
191
-
192
- it('password check works even after config dir is deleted', () => {
193
- const mindRoot = path.join(tempHome, 'MindOS');
194
- fs.mkdirSync(mindRoot, { recursive: true });
195
- writeConfig({ mindRoot, webPassword: 'pw123' });
196
-
197
- // Y proceed, Y remove config, Y remove kb, YES, wrong password
198
- const { stdout } = run(['uninstall'], { input: 'y\ny\ny\nYES\nwrong\n' });
199
- expect(fs.existsSync(path.join(tempHome, '.mindos'))).toBe(false);
200
- expect(stdout).toContain('Wrong password');
201
- // Knowledge base must survive — password was read from config before deletion
202
- expect(fs.existsSync(mindRoot)).toBe(true);
203
- });
204
- });
205
-
206
- describe('mindos uninstall — tilde expansion in mindRoot', () => {
207
- it('expands ~ in mindRoot to HOME', () => {
208
- const mindRoot = path.join(tempHome, 'MyNotes');
209
- fs.mkdirSync(mindRoot, { recursive: true });
210
- fs.writeFileSync(path.join(mindRoot, 'test.md'), 'data');
211
- // Store with ~ prefix — the code should expand it
212
- writeConfig({ mindRoot: '~/MyNotes' });
213
-
214
- // Y proceed, N config, Y kb, YES
215
- const { stdout } = run(['uninstall'], { input: 'y\nn\ny\nYES\n' });
216
- expect(fs.existsSync(mindRoot)).toBe(false);
217
- });
218
- });
@@ -1,89 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
- import { execFileSync } from 'node:child_process';
3
- import fs from 'node:fs';
4
- import os from 'node:os';
5
- import path from 'node:path';
6
-
7
- const ROOT = path.resolve(__dirname, '..', '..');
8
- const CLI = path.join(ROOT, 'bin', 'cli.js');
9
- const CURRENT_VERSION = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf-8')).version;
10
-
11
- let tempDir: string;
12
- let fakeBinDir: string;
13
- let fakeInstallRoot: string;
14
-
15
- beforeEach(() => {
16
- tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mindos-update-root-'));
17
- fakeBinDir = path.join(tempDir, 'fake-bin');
18
- fakeInstallRoot = path.join(tempDir, 'new-root');
19
-
20
- fs.mkdirSync(fakeBinDir, { recursive: true });
21
- fs.mkdirSync(path.join(fakeInstallRoot, 'bin'), { recursive: true });
22
- fs.mkdirSync(path.join(fakeInstallRoot, 'app', '.next'), { recursive: true });
23
-
24
- fs.writeFileSync(path.join(fakeBinDir, 'npm'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
25
- fs.writeFileSync(path.join(fakeInstallRoot, 'bin', 'cli.js'), '#!/bin/sh\nexit 0\n', { mode: 0o755 });
26
- fs.symlinkSync(path.join(fakeInstallRoot, 'bin', 'cli.js'), path.join(fakeBinDir, 'mindos'));
27
- fs.writeFileSync(
28
- path.join(fakeInstallRoot, 'package.json'),
29
- JSON.stringify({ name: '@geminilight/mindos', version: '9.9.9' }),
30
- );
31
- fs.writeFileSync(
32
- path.join(fakeInstallRoot, 'app', '.next', '.mindos-build-version'),
33
- '9.9.9',
34
- );
35
- fs.writeFileSync(
36
- path.join(fakeInstallRoot, 'app', 'package.json'),
37
- JSON.stringify({ name: 'wiki-app', version: '0.1.0' }),
38
- );
39
- });
40
-
41
- afterEach(() => {
42
- fs.rmSync(tempDir, { recursive: true, force: true });
43
- });
44
-
45
- describe('mindos update root resolution', () => {
46
- it('uses the resolved installed CLI path instead of falling back to the current repo root', () => {
47
- const stdout = execFileSync(process.execPath, [CLI, 'update'], {
48
- cwd: ROOT,
49
- encoding: 'utf-8',
50
- env: {
51
- ...process.env,
52
- PATH: `${fakeBinDir}:${process.env.PATH}`,
53
- },
54
- timeout: 30_000,
55
- stdio: ['pipe', 'pipe', 'pipe'],
56
- });
57
-
58
- expect(stdout).toContain(`Updated: ${CURRENT_VERSION} → 9.9.9`);
59
- expect(stdout).not.toContain('Already on the latest version');
60
- });
61
-
62
- it('skips the shell shim under ~/.mindos/bin/ and falls back to current ROOT', () => {
63
- const fakeHome = path.join(tempDir, 'home');
64
- const shimDir = path.join(fakeHome, '.mindos', 'bin');
65
- fs.mkdirSync(shimDir, { recursive: true });
66
- fs.writeFileSync(
67
- path.join(shimDir, 'mindos'),
68
- '#!/bin/sh\nexec node "$(dirname "$0")/../cli.js" "$@"\n',
69
- { mode: 0o755 },
70
- );
71
-
72
- const stdout = execFileSync(process.execPath, [CLI, 'update'], {
73
- cwd: ROOT,
74
- encoding: 'utf-8',
75
- env: {
76
- ...process.env,
77
- HOME: fakeHome,
78
- PATH: `${shimDir}:${fakeBinDir}:${process.env.PATH}`,
79
- },
80
- timeout: 30_000,
81
- stdio: ['pipe', 'pipe', 'pipe'],
82
- });
83
-
84
- // `which mindos` finds shimDir/mindos first, but getUpdatedRoot() skips it
85
- // (dirname matches $HOME/.mindos/bin). Falls back to ROOT where
86
- // package.json has CURRENT_VERSION → reports "already on the latest".
87
- expect(stdout).toContain('Already on the latest version');
88
- });
89
- });