@geminilight/mindos 0.7.2 → 0.7.4

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 (254) 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 +19 -19
  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.js +4 -4
  43. package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
  44. package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
  45. package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
  46. package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
  47. package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
  48. package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
  49. package/_standalone/.next/server/app/api/channels/verify/route_client-reference-manifest.js +1 -1
  50. package/_standalone/.next/server/app/api/connect/route_client-reference-manifest.js +1 -1
  51. package/_standalone/.next/server/app/api/embedding/route_client-reference-manifest.js +1 -1
  52. package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
  53. package/_standalone/.next/server/app/api/extract-docx/route_client-reference-manifest.js +1 -1
  54. package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
  55. package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
  56. package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
  57. package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
  58. package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  59. package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  60. package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
  61. package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  62. package/_standalone/.next/server/app/api/im/activity/route_client-reference-manifest.js +1 -1
  63. package/_standalone/.next/server/app/api/im/config/route_client-reference-manifest.js +1 -1
  64. package/_standalone/.next/server/app/api/im/feishu/long-connection/event/route_client-reference-manifest.js +1 -1
  65. package/_standalone/.next/server/app/api/im/feishu/long-connection/route_client-reference-manifest.js +1 -1
  66. package/_standalone/.next/server/app/api/im/status/route_client-reference-manifest.js +1 -1
  67. package/_standalone/.next/server/app/api/im/test/route_client-reference-manifest.js +1 -1
  68. package/_standalone/.next/server/app/api/im/webhook/feishu/route_client-reference-manifest.js +1 -1
  69. package/_standalone/.next/server/app/api/im/webhook-status/route_client-reference-manifest.js +1 -1
  70. package/_standalone/.next/server/app/api/inbox/clip/route_client-reference-manifest.js +1 -1
  71. package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
  72. package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
  73. package/_standalone/.next/server/app/api/lint/route_client-reference-manifest.js +1 -1
  74. package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
  75. package/_standalone/.next/server/app/api/mcp/direct-tools/route_client-reference-manifest.js +1 -1
  76. package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
  77. package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
  78. package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
  79. package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
  80. package/_standalone/.next/server/app/api/mcp/tools/route_client-reference-manifest.js +1 -1
  81. package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
  82. package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
  83. package/_standalone/.next/server/app/api/obsidian/compat-report/route_client-reference-manifest.js +1 -1
  84. package/_standalone/.next/server/app/api/obsidian/import/route_client-reference-manifest.js +1 -1
  85. package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
  86. package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  87. package/_standalone/.next/server/app/api/search/prewarm/route_client-reference-manifest.js +1 -1
  88. package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  89. package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
  90. package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
  91. package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
  92. package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
  93. package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
  94. package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
  95. package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
  96. package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
  97. package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
  98. package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  99. package/_standalone/.next/server/app/api/space-overview/route_client-reference-manifest.js +1 -1
  100. package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
  101. package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
  102. package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
  103. package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  104. package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
  105. package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
  106. package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
  107. package/_standalone/.next/server/app/capture/history/page.js +1 -1
  108. package/_standalone/.next/server/app/capture/history/page.js.nft.json +1 -1
  109. package/_standalone/.next/server/app/capture/history/page_client-reference-manifest.js +1 -1
  110. package/_standalone/.next/server/app/capture/page.js +1 -1
  111. package/_standalone/.next/server/app/capture/page.js.nft.json +1 -1
  112. package/_standalone/.next/server/app/capture/page_client-reference-manifest.js +1 -1
  113. package/_standalone/.next/server/app/changelog/page.js +1 -1
  114. package/_standalone/.next/server/app/changelog/page.js.nft.json +1 -1
  115. package/_standalone/.next/server/app/changelog/page_client-reference-manifest.js +1 -1
  116. package/_standalone/.next/server/app/changes/page.js +1 -1
  117. package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
  118. package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
  119. package/_standalone/.next/server/app/echo/[segment]/page.js +1 -1
  120. package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
  121. package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
  122. package/_standalone/.next/server/app/echo/page.js +1 -1
  123. package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
  124. package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
  125. package/_standalone/.next/server/app/explore/page.js +1 -1
  126. package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
  127. package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
  128. package/_standalone/.next/server/app/help/page.js +1 -1
  129. package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
  130. package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
  131. package/_standalone/.next/server/app/inbox/history/page.js +1 -1
  132. package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
  133. package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
  134. package/_standalone/.next/server/app/login/page.js +1 -1
  135. package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
  136. package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
  137. package/_standalone/.next/server/app/page.js +1 -1
  138. package/_standalone/.next/server/app/page.js.nft.json +1 -1
  139. package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  140. package/_standalone/.next/server/app/setup/page.js +1 -1
  141. package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
  142. package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  143. package/_standalone/.next/server/app/todo/page.js +1 -1
  144. package/_standalone/.next/server/app/todo/page.js.nft.json +1 -1
  145. package/_standalone/.next/server/app/todo/page_client-reference-manifest.js +1 -1
  146. package/_standalone/.next/server/app/trash/page.js +2 -2
  147. package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
  148. package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
  149. package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
  150. package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
  151. package/_standalone/.next/server/app/wiki/page.js +2 -0
  152. package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -0
  153. package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -0
  154. package/_standalone/.next/server/app-paths-manifest.json +19 -19
  155. package/_standalone/.next/server/chunks/2250.js +1 -1
  156. package/_standalone/.next/server/chunks/{1057.js → 3861.js} +2 -2
  157. package/_standalone/.next/server/chunks/4802.js +30 -30
  158. package/_standalone/.next/server/chunks/8388.js +1 -1
  159. package/_standalone/.next/server/middleware-build-manifest.js +1 -1
  160. package/_standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  161. package/_standalone/.next/server/pages/500.html +2 -2
  162. package/_standalone/.next/server/server-reference-manifest.js +1 -1
  163. package/_standalone/.next/server/server-reference-manifest.json +1 -1
  164. package/_standalone/.next/static/chunks/{5581-bae715e40d227b5f.js → 5581-beecbc4ca5625aa9.js} +2 -2
  165. package/_standalone/.next/static/chunks/6762.c871d0bf3f45ba87.js +1 -0
  166. package/_standalone/.next/static/chunks/{8064-e65acd2762132099.js → 8064-acac37daf946082b.js} +1 -1
  167. package/_standalone/.next/static/chunks/{3985.695651f6b5cd768c.js → 8984.91fb8cde1983c564.js} +2 -2
  168. package/_standalone/.next/static/chunks/app/{layout-0cf6f2a65f605a0d.js → layout-20faba3bc0af7cd2.js} +19 -19
  169. package/_standalone/.next/static/chunks/app/trash/page-0c2c67929b71ef71.js +1 -0
  170. package/_standalone/.next/static/chunks/app/view/[...path]/not-found-fd06cc989103ebe7.js +1 -0
  171. package/_standalone/.next/static/chunks/app/view/[...path]/page-dba70888697ba910.js +12 -0
  172. package/_standalone/.next/static/chunks/app/wiki/page-9bc1fec84d343290.js +14 -0
  173. package/_standalone/.next/static/chunks/webpack-3c1d0331f1da64b8.js +1 -0
  174. package/_standalone/.next/trace +97 -97
  175. package/_standalone/MINDOS_ARCHITECTURE_DIAGRAM.md +488 -0
  176. package/_standalone/MINDOS_EXPLORATION_SUMMARY.md +229 -0
  177. package/_standalone/MINDOS_INFRASTRUCTURE_ANALYSIS.md +732 -0
  178. package/_standalone/__tests__/api/mcp-install.test.ts +8 -2
  179. package/_standalone/__tests__/core/embedding-provider.test.ts +78 -0
  180. package/_standalone/__tests__/skills/mindos-skill-copy-alignment.test.ts +10 -4
  181. package/_standalone/components/ask/AskHeader.tsx +25 -18
  182. package/_standalone/components/ask/SessionHistoryPanel.tsx +21 -12
  183. package/_standalone/components/settings/AiTab.tsx +3 -0
  184. package/_standalone/data/skills/mindos/SKILL.md +269 -0
  185. package/_standalone/data/skills/mindos/references/write-supplement.md +119 -0
  186. package/_standalone/data/skills/mindos-zh/SKILL.md +227 -0
  187. package/_standalone/data/skills/mindos-zh/references/write-supplement.md +119 -0
  188. package/app/__tests__/api/mcp-install.test.ts +8 -2
  189. package/app/__tests__/core/embedding-provider.test.ts +78 -0
  190. package/app/__tests__/skills/mindos-skill-copy-alignment.test.ts +10 -4
  191. package/app/app/api/ask/route.ts +14 -9
  192. package/app/app/view/[...path]/ViewPageClient.tsx +15 -12
  193. package/app/app/view/[...path]/not-found.tsx +9 -5
  194. package/app/components/ask/AskHeader.tsx +25 -18
  195. package/app/components/ask/SessionHistoryPanel.tsx +21 -12
  196. package/app/components/settings/AiTab.tsx +3 -0
  197. package/app/eslint.config.mjs +18 -0
  198. package/app/lib/core/embedding-provider.ts +12 -4
  199. package/app/lib/i18n/modules/settings.ts +2 -0
  200. package/app/package-lock.json +20214 -0
  201. package/app/tsconfig.tsbuildinfo +1 -0
  202. package/app/vitest.config.ts +14 -0
  203. package/assets/demo-flow-zh.html +622 -0
  204. package/assets/images/demo-flow-dark.png +0 -0
  205. package/assets/images/demo-flow-dark.webp +0 -0
  206. package/assets/images/demo-flow-light.png +0 -0
  207. package/assets/images/demo-flow-light.webp +0 -0
  208. package/assets/images/demo-flow-zh-dark.png +0 -0
  209. package/assets/images/demo-flow-zh-dark.webp +0 -0
  210. package/assets/images/demo-flow-zh-light.png +0 -0
  211. package/assets/images/demo-flow-zh-light.webp +0 -0
  212. package/assets/images/gui-sync-cv.png +0 -0
  213. package/assets/images/gui-sync-cv.webp +0 -0
  214. package/assets/images/mindos-chat.png +0 -0
  215. package/assets/images/mindos-chat.webp +0 -0
  216. package/assets/images/mindos-dashboard.png +0 -0
  217. package/assets/images/mindos-dashboard.webp +0 -0
  218. package/assets/images/mindos-echo.png +0 -0
  219. package/assets/images/mindos-echo.webp +0 -0
  220. package/assets/images/mindos-home.png +0 -0
  221. package/assets/images/mindos-home.webp +0 -0
  222. package/assets/images/wechat-qr.png +0 -0
  223. package/bin/lib/mcp-build.js +8 -0
  224. package/mcp/package-lock.json +2202 -0
  225. package/mcp/src/index.ts +783 -0
  226. package/package.json +13 -1
  227. package/.env.local.example +0 -38
  228. package/.playwright-cli/page-2026-04-12T12-26-53-393Z.yml +0 -6
  229. package/.playwright-cli/page-2026-04-12T12-27-20-256Z.yml +0 -120
  230. package/.syncinclude +0 -105
  231. package/MINDOS_SEARCH_DIAGRAM.txt +0 -243
  232. package/_standalone/.next/static/chunks/576.3cae31209383ddbd.js +0 -1
  233. package/_standalone/.next/static/chunks/app/trash/page-085f121c0815d542.js +0 -1
  234. package/_standalone/.next/static/chunks/app/view/[...path]/not-found-2a6eec67e91eaaf9.js +0 -1
  235. package/_standalone/.next/static/chunks/app/view/[...path]/page-faeaf8c09c1c6d7c.js +0 -12
  236. package/_standalone/.next/static/chunks/webpack-a1bb35f2d540e463.js +0 -1
  237. package/scripts/build-runtime-archive.sh +0 -151
  238. package/scripts/fix-postcss-deps.cjs +0 -75
  239. package/scripts/gen-renderer-index.js +0 -64
  240. package/scripts/hooks/block-public-merge.sh +0 -42
  241. package/scripts/hooks/pre-merge-commit +0 -4
  242. package/scripts/hooks/pre-push +0 -37
  243. package/scripts/hooks/prepare-commit-msg +0 -12
  244. package/scripts/migrate-agent-audit-log.js +0 -170
  245. package/scripts/migrate-agent-diff.js +0 -146
  246. package/scripts/parse-syncinclude.sh +0 -92
  247. package/scripts/prepare-standalone.mjs +0 -83
  248. package/scripts/release.sh +0 -145
  249. package/scripts/setup.js +0 -1427
  250. package/scripts/test-oss-upload.sh +0 -100
  251. package/scripts/verify-standalone.mjs +0 -129
  252. package/scripts/write-build-stamp.js +0 -40
  253. /package/_standalone/.next/static/{q5RP_Mx8BrCfvVDnLpRRc → 0UlbV2rA2i4B-8YYg41wQ}/_buildManifest.js +0 -0
  254. /package/_standalone/.next/static/{q5RP_Mx8BrCfvVDnLpRRc → 0UlbV2rA2i4B-8YYg41wQ}/_ssgManifest.js +0 -0
@@ -179,7 +179,9 @@ describe('POST /api/mcp/install', () => {
179
179
  it('handles empty config file gracefully (e.g. fresh VS Code mcp.json)', async () => {
180
180
  const { POST } = await importInstallRoute();
181
181
  // Pre-create an empty config file (common with VS Code)
182
- const copilotDir = path.join(tempHome, '.config', 'Code', 'User');
182
+ const copilotDir = process.platform === 'darwin'
183
+ ? path.join(tempHome, 'Library', 'Application Support', 'Code', 'User')
184
+ : path.join(tempHome, '.config', 'Code', 'User');
183
185
  fs.mkdirSync(copilotDir, { recursive: true });
184
186
  fs.writeFileSync(path.join(copilotDir, 'mcp.json'), '', 'utf-8');
185
187
 
@@ -195,7 +197,11 @@ describe('POST /api/mcp/install', () => {
195
197
  const body = await res.json();
196
198
  expect(body.results[0].status).toBe('ok');
197
199
 
198
- const config = JSON.parse(fs.readFileSync(path.join(copilotDir, 'mcp.json'), 'utf-8'));
200
+ const configPath = path.join(copilotDir, 'mcp.json');
201
+ expect(fs.existsSync(configPath)).toBe(true);
202
+ const content = fs.readFileSync(configPath, 'utf-8');
203
+ expect(content.trim()).not.toBe(''); // Should have written valid JSON
204
+ const config = JSON.parse(content);
199
205
  expect(config.servers.mindos.type).toBe('stdio');
200
206
  });
201
207
 
@@ -8,6 +8,10 @@ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
8
8
  // Mock @huggingface/transformers to avoid real downloads
9
9
  vi.mock('@huggingface/transformers', () => ({
10
10
  pipeline: vi.fn(),
11
+ env: {
12
+ remoteHost: '',
13
+ remotePathTemplate: '',
14
+ },
11
15
  }));
12
16
 
13
17
  describe('embedding-provider retry logic', () => {
@@ -21,6 +25,80 @@ describe('embedding-provider retry logic', () => {
21
25
  vi.clearAllMocks();
22
26
  });
23
27
 
28
+ describe('mirror configuration', () => {
29
+ it('should configure hf-mirror.com when HF_ENDPOINT is not set', async () => {
30
+ const originalEnv = process.env.HF_ENDPOINT;
31
+ delete process.env.HF_ENDPOINT;
32
+
33
+ const { pipeline, env } = await import('@huggingface/transformers');
34
+ // Reset env to simulate fresh state
35
+ env.remoteHost = '';
36
+ env.remotePathTemplate = '';
37
+
38
+ const mockPipeline = { mock: true };
39
+ vi.mocked(pipeline).mockResolvedValueOnce(mockPipeline);
40
+
41
+ const { downloadLocalModel } = await import('@/lib/core/embedding-provider');
42
+ await downloadLocalModel('test-model');
43
+
44
+ // Verify mirror was configured
45
+ expect(env.remoteHost).toBe('https://hf-mirror.com');
46
+ expect(env.remotePathTemplate).toBe('{model}/resolve/{revision}/{fileName}');
47
+
48
+ // Restore
49
+ if (originalEnv) process.env.HF_ENDPOINT = originalEnv;
50
+ });
51
+
52
+ it('should respect HF_ENDPOINT environment variable', async () => {
53
+ const originalEnv = process.env.HF_ENDPOINT;
54
+ process.env.HF_ENDPOINT = 'https://custom-mirror.com';
55
+
56
+ const { pipeline, env } = await import('@huggingface/transformers');
57
+ // Reset env to simulate fresh state
58
+ env.remoteHost = '';
59
+ env.remotePathTemplate = '';
60
+
61
+ const mockPipeline = { mock: true };
62
+ vi.mocked(pipeline).mockResolvedValueOnce(mockPipeline);
63
+
64
+ const { downloadLocalModel } = await import('@/lib/core/embedding-provider');
65
+ await downloadLocalModel('test-model');
66
+
67
+ // Verify custom mirror was NOT overridden (env.remoteHost should remain empty)
68
+ expect(env.remoteHost).toBe('');
69
+
70
+ // Restore
71
+ if (originalEnv) {
72
+ process.env.HF_ENDPOINT = originalEnv;
73
+ } else {
74
+ delete process.env.HF_ENDPOINT;
75
+ }
76
+ });
77
+
78
+ it('should not override if env.remoteHost is already set', async () => {
79
+ const originalEnv = process.env.HF_ENDPOINT;
80
+ delete process.env.HF_ENDPOINT;
81
+
82
+ const { pipeline, env } = await import('@huggingface/transformers');
83
+ // Simulate user has already configured a custom mirror
84
+ env.remoteHost = 'https://user-custom-mirror.com';
85
+ env.remotePathTemplate = 'custom/{model}/{fileName}';
86
+
87
+ const mockPipeline = { mock: true };
88
+ vi.mocked(pipeline).mockResolvedValueOnce(mockPipeline);
89
+
90
+ const { downloadLocalModel } = await import('@/lib/core/embedding-provider');
91
+ await downloadLocalModel('test-model');
92
+
93
+ // Verify user's custom mirror was NOT overridden
94
+ expect(env.remoteHost).toBe('https://user-custom-mirror.com');
95
+ expect(env.remotePathTemplate).toBe('custom/{model}/{fileName}');
96
+
97
+ // Restore
98
+ if (originalEnv) process.env.HF_ENDPOINT = originalEnv;
99
+ });
100
+ });
101
+
24
102
  describe('isRetryableError classification', () => {
25
103
  // These would be internal to the module, tested indirectly through loadLocalPipeline behavior
26
104
 
@@ -1,9 +1,10 @@
1
1
  import { describe, it, expect } from 'vitest';
2
- import { readFileSync } from 'node:fs';
2
+ import { readFileSync, existsSync } from 'node:fs';
3
3
  import path from 'node:path';
4
4
 
5
- const root = '/data/home/geminitwang/code/sop_note';
5
+ const root = path.resolve(__dirname, '../../..');
6
6
  const read = (relativePath: string) => readFileSync(path.join(root, relativePath), 'utf8');
7
+ const exists = (relativePath: string) => existsSync(path.join(root, relativePath));
7
8
 
8
9
  describe('MindOS skill copy alignment', () => {
9
10
  it('keeps source and app skill copies aligned for default skill', () => {
@@ -12,8 +13,13 @@ describe('MindOS skill copy alignment', () => {
12
13
  });
13
14
 
14
15
  it('keeps source and app skill copies aligned for max skill', () => {
15
- expect(read('skills/mindos-max/SKILL.md')).toBe(read('app/data/skills/mindos-max/SKILL.md'));
16
- expect(read('skills/mindos-max-zh/SKILL.md')).toBe(read('app/data/skills/mindos-max-zh/SKILL.md'));
16
+ // Only check if both source and app copies exist
17
+ if (exists('app/data/skills/mindos-max/SKILL.md')) {
18
+ expect(read('skills/mindos-max/SKILL.md')).toBe(read('app/data/skills/mindos-max/SKILL.md'));
19
+ }
20
+ if (exists('app/data/skills/mindos-max-zh/SKILL.md')) {
21
+ expect(read('skills/mindos-max-zh/SKILL.md')).toBe(read('app/data/skills/mindos-max-zh/SKILL.md'));
22
+ }
17
23
  });
18
24
 
19
25
  it('removes second-brain wording from aligned skill descriptions', () => {
@@ -1,4 +1,4 @@
1
- import { memo, useState, useRef, useEffect, useCallback } from 'react';
1
+ import { memo, useState, useRef, useEffect, useCallback, useTransition } from 'react';
2
2
  import { createPortal } from 'react-dom';
3
3
  import { Sparkles, SquarePen, History, X, Maximize2, Minimize2, PanelRight, AppWindow, ChevronDown, Check, Trash2, Pencil, Pin, PinOff } from 'lucide-react';
4
4
  import { SaveSessionButton } from './SaveSessionInline';
@@ -38,6 +38,7 @@ export default memo(function AskHeader({
38
38
  messages,
39
39
  }: AskHeaderProps) {
40
40
  const { t } = useLocale();
41
+ const [isPending, startTransition] = useTransition();
41
42
  const iconSize = 14;
42
43
  const hasMultipleSessions = sessions && sessions.length >= 2;
43
44
  const headerButtonClass = isPanel
@@ -93,8 +94,10 @@ export default memo(function AskHeader({
93
94
  }, [renamingId]);
94
95
 
95
96
  const handleSelectSession = useCallback((id: string) => {
96
- onLoadSession?.(id);
97
- setSwitcherOpen(false);
97
+ startTransition(() => {
98
+ onLoadSession?.(id);
99
+ setSwitcherOpen(false);
100
+ });
98
101
  }, [onLoadSession]);
99
102
 
100
103
  const handleStartRename = useCallback((id: string, currentTitle: string) => {
@@ -103,10 +106,12 @@ export default memo(function AskHeader({
103
106
  }, []);
104
107
 
105
108
  const handleCommitRename = useCallback(() => {
106
- if (renamingId && onRenameSession && renameValue.trim()) {
107
- onRenameSession(renamingId, renameValue.trim());
108
- }
109
- setRenamingId(null);
109
+ startTransition(() => {
110
+ if (renamingId && onRenameSession && renameValue.trim()) {
111
+ onRenameSession(renamingId, renameValue.trim());
112
+ }
113
+ setRenamingId(null);
114
+ });
110
115
  }, [renamingId, renameValue, onRenameSession]);
111
116
 
112
117
  // Position dropdown below trigger
@@ -222,11 +227,13 @@ export default memo(function AskHeader({
222
227
  ref={switcherRef}
223
228
  type="button"
224
229
  onClick={() => {
225
- if (sessions && sessions.length >= 2) {
226
- setSwitcherOpen(v => !v);
227
- } else {
228
- onToggleHistory();
229
- }
230
+ startTransition(() => {
231
+ if (sessions && sessions.length >= 2) {
232
+ setSwitcherOpen(v => !v);
233
+ } else {
234
+ onToggleHistory();
235
+ }
236
+ });
230
237
  }}
231
238
  className={`flex items-center gap-1 min-w-0 text-sm font-medium text-[var(--amber)] hover:text-[var(--amber)]/80 hover:bg-muted/40 transition-colors ${titleTriggerClass}`}
232
239
  aria-expanded={switcherOpen}
@@ -249,32 +256,32 @@ export default memo(function AskHeader({
249
256
  )}
250
257
  {hideTitle && <div />}
251
258
  <div className="flex items-center gap-1 shrink-0">
252
- <button type="button" onClick={(e) => { e.stopPropagation(); onToggleHistory(); }} aria-pressed={showHistory} className={`${headerButtonClass} inline-flex items-center justify-center transition-colors ${showHistory ? 'bg-[var(--amber)]/10 text-[var(--amber)]' : 'text-muted-foreground hover:text-foreground hover:bg-muted'}`} title={t.hints.sessionHistory}>
259
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onToggleHistory()); }} aria-pressed={showHistory} className={`${headerButtonClass} inline-flex items-center justify-center transition-colors ${showHistory ? 'bg-[var(--amber)]/10 text-[var(--amber)]' : 'text-muted-foreground hover:text-foreground hover:bg-muted'}`} title={t.hints.sessionHistory}>
253
260
  <History size={iconSize} />
254
261
  </button>
255
262
  {messages && messages.length > 0 && (
256
263
  <SaveSessionButton messages={messages} disabled={isLoading} />
257
264
  )}
258
- <button type="button" onClick={(e) => { e.stopPropagation(); onReset(); }} disabled={isLoading} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-40`} title={t.hints.newSession}>
265
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onReset()); }} disabled={isLoading} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors disabled:opacity-40`} title={t.hints.newSession}>
259
266
  <SquarePen size={iconSize} />
260
267
  </button>
261
268
  {onMaximize && (
262
- <button type="button" onClick={(e) => { e.stopPropagation(); onMaximize(); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={maximized ? t.hints.restorePanel : t.hints.maximizePanel}>
269
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onMaximize()); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={maximized ? t.hints.restorePanel : t.hints.maximizePanel}>
263
270
  {maximized ? <Minimize2 size={iconSize} /> : <Maximize2 size={iconSize} />}
264
271
  </button>
265
272
  )}
266
273
  {onDockToPanel && (
267
- <button type="button" onClick={(e) => { e.stopPropagation(); onDockToPanel(); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={t.hints.dockToSide ?? 'Dock to side panel'}>
274
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onDockToPanel()); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={t.hints.dockToSide ?? 'Dock to side panel'}>
268
275
  <PanelRight size={iconSize} />
269
276
  </button>
270
277
  )}
271
278
  {onModeSwitch && (
272
- <button type="button" onClick={(e) => { e.stopPropagation(); onModeSwitch(); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={askMode === 'popup' ? t.hints.dockToSide : t.hints.openAsPopup}>
279
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onModeSwitch()); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={askMode === 'popup' ? t.hints.dockToSide : t.hints.openAsPopup}>
273
280
  {askMode === 'popup' ? <PanelRight size={iconSize} /> : <AppWindow size={iconSize} />}
274
281
  </button>
275
282
  )}
276
283
  {onClose && (
277
- <button type="button" onClick={(e) => { e.stopPropagation(); onClose(); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={t.hints.closePanel} aria-label="Close">
284
+ <button type="button" onClick={(e) => { e.stopPropagation(); startTransition(() => onClose()); }} className={`${headerButtonClass} inline-flex items-center justify-center hover:bg-muted text-muted-foreground hover:text-foreground transition-colors`} title={t.hints.closePanel} aria-label="Close">
278
285
  <X size={iconSize} />
279
286
  </button>
280
287
  )}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
3
+ import { useState, useRef, useEffect, useCallback, useMemo, useTransition } from 'react';
4
4
  import { Search, Trash2, Pencil, Pin, PinOff, FolderInput, MessageSquare, SquarePen, X } from 'lucide-react';
5
5
  import type { ChatSession } from '@/lib/types';
6
6
  import { sessionTitle } from '@/hooks/useAskSession';
@@ -60,6 +60,7 @@ export default function SessionHistoryPanel({
60
60
  onClose, onNewChat,
61
61
  }: SessionHistoryPanelProps) {
62
62
  const { t } = useLocale();
63
+ const [isPending, startTransition] = useTransition();
63
64
  const ask = t.ask;
64
65
  const [query, setQuery] = useState('');
65
66
  const [editingId, setEditingId] = useState<string | null>(null);
@@ -113,13 +114,17 @@ export default function SessionHistoryPanel({
113
114
  const totalCount = sessions.filter(s => s.messages.length > 0).length;
114
115
 
115
116
  const handleLoad = useCallback((id: string) => {
116
- onLoad(id);
117
- onClose();
117
+ startTransition(() => {
118
+ onLoad(id);
119
+ onClose();
120
+ });
118
121
  }, [onLoad, onClose]);
119
122
 
120
123
  const handleNewChat = useCallback(() => {
121
- onNewChat();
122
- onClose();
124
+ startTransition(() => {
125
+ onNewChat();
126
+ onClose();
127
+ });
123
128
  }, [onNewChat, onClose]);
124
129
 
125
130
  const startRename = useCallback((s: ChatSession) => {
@@ -128,10 +133,12 @@ export default function SessionHistoryPanel({
128
133
  }, []);
129
134
 
130
135
  const commitRename = useCallback(() => {
131
- if (editingId && editValue.trim()) {
132
- onRename(editingId, editValue.trim());
133
- }
134
- setEditingId(null);
136
+ startTransition(() => {
137
+ if (editingId && editValue.trim()) {
138
+ onRename(editingId, editValue.trim());
139
+ }
140
+ setEditingId(null);
141
+ });
135
142
  }, [editingId, editValue, onRename]);
136
143
 
137
144
  const handleClearAll = useCallback(() => {
@@ -141,9 +148,11 @@ export default function SessionHistoryPanel({
141
148
  clearTimer.current = setTimeout(() => setConfirmClearAll(false), 3000);
142
149
  return;
143
150
  }
144
- if (clearTimer.current) clearTimeout(clearTimer.current);
145
- onClearAll();
146
- setConfirmClearAll(false);
151
+ startTransition(() => {
152
+ if (clearTimer.current) clearTimeout(clearTimer.current);
153
+ onClearAll();
154
+ setConfirmClearAll(false);
155
+ });
147
156
  }, [confirmClearAll, onClearAll]);
148
157
 
149
158
  // Keyboard: Esc to close
@@ -804,6 +804,9 @@ function EmbeddingSearchCard({ data, setData, t }: {
804
804
  <X size={14} />
805
805
  <span>{downloadError ?? 'Download failed'}</span>
806
806
  </div>
807
+ <p className="text-xs text-muted-foreground">
808
+ {e.downloadFailedHint as string ?? 'If download keeps failing, try API mode or set HF_ENDPOINT=https://hf-mirror.com'}
809
+ </p>
807
810
  <button
808
811
  type="button"
809
812
  onClick={handleRetry}
@@ -0,0 +1,269 @@
1
+ ---
2
+ name: mindos
3
+ disable-model-invocation: true
4
+ description: >
5
+ MindOS is the user's local knowledge assistant and shared knowledge base. It keeps decisions,
6
+ meeting notes, SOPs, debugging lessons, architecture choices, research findings, and preferences
7
+ available across sessions and agents.
8
+ 更新笔记, 搜索知识库, 整理文件, 执行SOP/工作流, 复盘, 追加CSV, 跨Agent交接,
9
+ 路由非结构化输入到对应文件, 提炼经验, 同步关联文档.
10
+ NOT for editing app source, project docs, or paths outside the KB.
11
+ Core concepts: Space, Instruction (INSTRUCTION.md), Skill (SKILL.md); notes can embody both.
12
+
13
+ Trigger on: save or record anything, search for prior notes or context, update or edit a file,
14
+ organize notes, run a workflow or SOP, capture decisions, append rows to a table or CSV,
15
+ hand off context to another agent, check if something was discussed before, look up a past
16
+ decision, distill lessons learned, prepare context for a meeting, quick-capture to staging area,
17
+ organize inbox, check knowledge health, detect conflicts or contradictions, find stale content.
18
+ Chinese triggers: 帮我记下来, 搜一下笔记, 更新知识库, 整理文件, 复盘, 提炼经验,
19
+ 保存, 记录, 交接, 查一下之前的, 有没有相关笔记, 把这个存起来, 放到暂存台,
20
+ 整理暂存台, 知识健康检查, 检测知识冲突.
21
+
22
+ Proactive behavior — do not wait for the user to mention MindOS:
23
+ (1) When user's question implies stored context may exist (past decisions, previous discussions,
24
+ meeting records) → search MindOS first, even if they don't explicitly mention it.
25
+ (2) After completing valuable work (bug fixed, decision made, lesson learned, architecture chosen,
26
+ meeting summarized) → offer to save it to MindOS for future reference.
27
+ (3) After a long or multi-topic conversation → suggest persisting key decisions and context.
28
+ ---
29
+
30
+ # MindOS Skill
31
+
32
+ <!-- version: 3.2.0 — CLI-first, MCP optional -->
33
+
34
+ ## CLI commands
35
+
36
+ Use `mindos file <subcommand>` for all knowledge base operations. Add `--json` for structured output.
37
+
38
+ | Operation | Command |
39
+ |-----------|---------|
40
+ | List files | `mindos file list` |
41
+ | Read file | `mindos file read <path>` |
42
+ | Write/overwrite | `mindos file write <path> --content "..."` |
43
+ | Create new file | `mindos file create <path> --content "..."` |
44
+ | Append to file | `mindos file append <path> --content "..."` |
45
+ | Edit section | `mindos file edit-section <path> -H "## Heading" --content "..."` |
46
+ | Insert after heading | `mindos file insert-heading <path> -H "## Heading" --content "..."` |
47
+ | Append CSV row | `mindos file append-csv <path> --row "col1,col2,col3"` |
48
+ | Delete file | `mindos file delete <path>` |
49
+ | Rename/move | `mindos file rename <old> <new>` |
50
+ | Search | `mindos search "query"` |
51
+ | Backlinks | `mindos file backlinks <path>` |
52
+ | Recent files | `mindos file recent --limit 10` |
53
+ | Git history | `mindos file history <path>` |
54
+ | List spaces | `mindos space list` |
55
+ | Create space | `mindos space create "name"` |
56
+
57
+ > **MCP users:** If you only have MCP tools (`mindos_*`), use them directly — they are self-describing via their schemas. Prefer CLI when available (lower token cost).
58
+
59
+ ### CLI setup
60
+
61
+ ```bash
62
+ npm install -g @geminilight/mindos
63
+ # Remote mode: mindos config set url http://<IP>:<PORT> && mindos config set authToken <token>
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Rules
69
+
70
+ 1. **Bootstrap first** — list the KB tree to understand structure before searching or writing.
71
+ 2. **Default to read-only.** Only write when the user explicitly asks to save, record, organize, or edit. Lookup / summarize / quote = no writes.
72
+ 3. **Rule precedence** (highest wins): user's current-turn instruction → `.mindos/user-preferences.md` → nearest directory `INSTRUCTION.md` → root `INSTRUCTION.md` → this SKILL's defaults.
73
+ 4. **Multi-file edits require a plan first.** Present the full change list; execute only after approval.
74
+ 5. After create/delete/move/rename → **sync affected READMEs** automatically.
75
+ 6. **Read before write.** Always read a file before overwriting it. Never write based on assumptions.
76
+
77
+ ---
78
+
79
+ ## Retrieval strategy
80
+
81
+ When retrieving knowledge, use **two paths in parallel**, then filter before deep-reading:
82
+
83
+ ### Path 1: Directory scan (by name/structure)
84
+
85
+ Browse the KB tree and **look at file names and directory names**. Titles often reveal content without reading. If a user asks about "authentication", and you see `Decisions/auth-jwt-vs-session.md`, that's a strong candidate — read it directly, no search needed.
86
+
87
+ - After bootstrap, scan the tree for paths whose names relate to the query topic.
88
+ - Pay attention to directory semantics: `Decisions/`, `Projects/`, `Workflows/`, `Resources/` etc. each imply what kind of content lives there.
89
+ - If the KB is small (<50 files), a quick tree scan may be faster and more reliable than search.
90
+
91
+ ### Path 2: Full-text search (by content)
92
+
93
+ Use `search` for content that can't be guessed from file names alone.
94
+
95
+ - Craft queries from the user's actual words. If the user says "那个很慢的接口", search for "慢 接口" or "性能 API".
96
+ - One well-targeted search is better than 4 vague ones. Only add a second search if the first returned <3 results or if the topic has obvious alternate terms (e.g., Chinese + English).
97
+ - **Do NOT** mechanically fire 2-4 searches every time. Think first, search precisely.
98
+
99
+ ### Filter: snippet triage before full read
100
+
101
+ Search results include a **snippet** and a **BM25 score**. Use them to decide what to read:
102
+
103
+ - **High score + snippet clearly on-topic** → read full file.
104
+ - **Medium score + snippet partially relevant** → read full file only if no better candidates exist.
105
+ - **Low score or snippet off-topic** → skip. Do not read every search result.
106
+ - Aim to read **1-3 files** deeply, not 10 files superficially.
107
+
108
+ ### Combined example
109
+
110
+ ```
111
+ User: "之前关于数据库选型的讨论"
112
+
113
+ Step 1 (tree scan): See "Decisions/database-postgres-vs-mongo.md" → strong match by name.
114
+ Step 2 (search): search("数据库选型") → returns 5 results.
115
+ Step 3 (triage): Result #1 snippet mentions "PostgreSQL vs MongoDB 对比" (score 18.3) → read.
116
+ Result #2 snippet mentions "数据库连接池配置" (score 4.1) → skip, off-topic.
117
+ Result #3 snippet mentions "选型会议纪要" (score 12.7) → read.
118
+ Step 4 (answer): Cite from the 2-3 files actually read.
119
+ ```
120
+
121
+ ---
122
+
123
+ ## NEVER do (hard-won pitfalls)
124
+
125
+ - **NEVER write to the KB root** unless explicitly told. Root is for governance files only. New content goes under the most fitting subdirectory.
126
+ - **NEVER assume directory names.** Infer from the actual bootstrap tree — the KB may use Chinese names or flat layout.
127
+ - **NEVER use full-file overwrite for a small edit.** Use `mindos file edit-section` or `mindos file insert-heading` for targeted changes. Full rewrites destroy git diffs.
128
+ - **NEVER modify `INSTRUCTION.md` or `README.md` without confirmation.** Governance docs — treat as high-sensitivity.
129
+ - **NEVER create a file without checking siblings.** Read 1-2 files in the target directory to learn local style.
130
+ - **NEVER leave orphan references.** After rename/move, check backlinks and update every referring file.
131
+ - **NEVER skip routing confirmation for multi-file writes.** The user's mental model may differ from yours.
132
+ - **NEVER read every search result.** Use snippet + score to triage. Only deep-read files that are clearly relevant.
133
+
134
+ ---
135
+
136
+ ## MindOS concepts
137
+
138
+ - **Space** — Knowledge partitions organized the way you think. Agents follow the same structure.
139
+ - **Instruction** — A rules file (`INSTRUCTION.md`) all connected agents obey.
140
+ - **Skill** — Teaches agents how to read, write, and organize the KB.
141
+ - **Inbox** — The `Inbox/` directory is a staging area for quick capture. Files land here when there's no obvious home yet. They get organized later — by the user manually or via AI-assisted batch organization.
142
+
143
+ Notes can embody both Instruction and Skill — they're just Markdown files in the tree.
144
+
145
+ ---
146
+
147
+ ## Decision tree
148
+
149
+ ```
150
+ User request
151
+
152
+ ├─ Lookup / summarize / quote?
153
+ │ └─ [Read-only]: search → read → answer with citations. No writes.
154
+
155
+ ├─ Save / record / update / organize specific content?
156
+ │ ├─ Know where it goes → [Single-file edit]
157
+ │ ├─ Don't know where it goes → [Inbox path] — save to Inbox/, classify later
158
+ │ └─ Multiple files or unclear → [Multi-file routing] — plan first
159
+
160
+ ├─ Organize inbox / classify staged files?
161
+ │ └─ [Inbox organize] — read Inbox/ files, propose destinations, move after approval
162
+
163
+ ├─ Structural change (rename / move / delete / reorganize)?
164
+ │ └─ [Structural path] — check backlinks before and after
165
+
166
+ ├─ Procedural / repeatable task?
167
+ │ └─ [SOP path] — find and follow existing SOP, or create one
168
+
169
+ ├─ Retrospective / distill / handoff?
170
+ │ └─ [Retrospective path]
171
+
172
+ ├─ Knowledge health check / detect conflicts?
173
+ │ └─ [Health check path] — read references/knowledge-health.md
174
+
175
+ └─ Ambiguous?
176
+ └─ ASK. Propose 2-3 specific options based on KB state.
177
+ ```
178
+
179
+ ---
180
+
181
+ ## Judgment heuristics
182
+
183
+ **Save intent boundary:**
184
+ - "save this" / "record" / "write down" = write
185
+ - "search" / "summarize" / "look up" = read-only
186
+ - "organize" → ask: display only, or write back?
187
+
188
+ **File location uncertainty:**
189
+ - Can't decide in 5 seconds → save to `Inbox/`, inform user, propose classification later
190
+ - "Just put it somewhere" / "先放着" → save to `Inbox/`
191
+ - User drags files or pastes unstructured content without specifying location → `Inbox/`
192
+
193
+ **Scope creep:**
194
+ - Input routes to >5 files → pause, confirm scope
195
+ - "Update all of these" spanning multiple topics → split into batches
196
+
197
+ **Citation:** KB-cited facts must include the file path.
198
+
199
+ ---
200
+
201
+ ## Post-task hooks
202
+
203
+ After write tasks (not simple reads), scan this table. At most 1 proposal; highest priority wins. Check `.mindos/user-preferences.md` suppression first.
204
+
205
+ | Hook | Priority | Condition |
206
+ |------|----------|-----------|
207
+ | Experience capture | high | Debugging, troubleshooting, or multi-round work |
208
+ | Consistency sync | high | Edited file with backlinks |
209
+ | SOP drift | medium | Followed SOP but diverged |
210
+ | Linked update | medium | Changed CSV/TODO status with related docs |
211
+ | Structure classification | medium | Created file in inbox/temp location |
212
+ | Pattern extraction | low | 3+ similar operations this session |
213
+
214
+ If a hook triggers → read [references/post-task-hooks.md](./references/post-task-hooks.md).
215
+
216
+ ## Preference capture
217
+
218
+ When user expresses a standing preference → read [references/preference-capture.md](./references/preference-capture.md) and follow confirm-then-write flow.
219
+
220
+ ## SOP authoring
221
+
222
+ When creating/rewriting an SOP → read [references/sop-template.md](./references/sop-template.md).
223
+
224
+ ## Inbox (staging area)
225
+
226
+ The `Inbox/` directory is the KB's quick-capture zone. It has its own `INSTRUCTION.md` that governs behavior.
227
+
228
+ **When to use Inbox:**
229
+ - User says "just save it" / "先放着" / "放到暂存台" without specifying a location
230
+ - Content doesn't clearly fit any existing Space or directory
231
+ - Batch import of multiple files that need individual classification
232
+
233
+ **How to save to Inbox:**
234
+ ```bash
235
+ mindos file create "Inbox/<filename>.md" --content "..."
236
+ ```
237
+
238
+ **How to organize Inbox:**
239
+ 1. List Inbox files: `mindos file list Inbox/`
240
+ 2. Read each file to understand its content
241
+ 3. For each file, propose the best destination directory based on KB structure
242
+ 4. Present the full routing plan to user for approval
243
+ 5. Move files: `mindos file rename "Inbox/<file>" "<target-dir>/<file>"`
244
+ 6. After moving, check if the target directory's README needs updating
245
+
246
+ **Aging reminder:** Files in Inbox older than 7 days are considered "aging". If you notice aging files during bootstrap, mention it: "You have N files in Inbox that have been sitting there for over a week. Want me to help organize them?"
247
+
248
+ ## Knowledge health check
249
+
250
+ When user asks to check knowledge health, detect conflicts, audit quality, or says "知识健康检查" / "检测冲突" → read [references/knowledge-health.md](./references/knowledge-health.md) for the full procedure.
251
+
252
+ Quick summary of what gets checked:
253
+ - **Contradictions**: conflicting facts across files on the same topic
254
+ - **Broken links**: references to files that no longer exist
255
+ - **Stale content**: files with outdated date markers or untouched for >6 months
256
+ - **Duplicates**: two files covering the same ground without cross-referencing
257
+ - **Orphan files**: files with zero backlinks, hard to discover
258
+ - **Structural issues**: wrong directory, missing READMEs, aging Inbox files
259
+
260
+ ---
261
+
262
+ ## Error handling (CLI)
263
+
264
+ ```bash
265
+ "command not found: mindos" → npm install -g @geminilight/mindos
266
+ "Mind root not configured" → mindos onboard
267
+ "401 Unauthorized" → Check AUTH_TOKEN: mindos token (on server)
268
+ "ECONNREFUSED" → Start server: mindos start
269
+ ```