fss-link 1.0.40 → 1.0.45

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 (428) hide show
  1. package/dist/commands/mcp/add.test.ts +122 -0
  2. package/dist/commands/mcp/add.ts +222 -0
  3. package/dist/commands/mcp/list.test.ts +154 -0
  4. package/dist/commands/mcp/list.ts +139 -0
  5. package/dist/commands/mcp/remove.test.ts +69 -0
  6. package/dist/commands/mcp/remove.ts +60 -0
  7. package/dist/commands/mcp.test.ts +55 -0
  8. package/dist/commands/mcp.ts +27 -0
  9. package/dist/config/apiValidation.test.ts +118 -0
  10. package/dist/config/auth.test.ts +79 -0
  11. package/dist/config/auth.ts +100 -0
  12. package/dist/config/config.integration.test.ts +407 -0
  13. package/dist/config/config.test.ts +1952 -0
  14. package/dist/config/config.ts +690 -0
  15. package/dist/config/database.test.ts +96 -0
  16. package/dist/config/database.ts +752 -0
  17. package/dist/config/extension.test.ts +236 -0
  18. package/dist/config/extension.ts +180 -0
  19. package/dist/config/keyBindings.test.ts +62 -0
  20. package/dist/config/keyBindings.ts +184 -0
  21. package/dist/config/modelManager.ts +275 -0
  22. package/dist/config/providerManager.ts +244 -0
  23. package/dist/config/providerPersistence.test.ts +377 -0
  24. package/dist/config/providerPersistence.ts +105 -0
  25. package/dist/config/sandboxConfig.ts +107 -0
  26. package/dist/config/settings.test.ts +1424 -0
  27. package/dist/config/settings.ts +517 -0
  28. package/dist/config/settingsSchema.test.ts +252 -0
  29. package/dist/config/settingsSchema.ts +728 -0
  30. package/dist/config/trustedFolders.test.ts +208 -0
  31. package/dist/config/trustedFolders.ts +167 -0
  32. package/dist/gemini.test.tsx +252 -0
  33. package/dist/gemini.tsx +357 -0
  34. package/dist/generated/git-commit.ts +10 -0
  35. package/dist/index.ts +21 -0
  36. package/dist/nonInteractiveCli.test.ts +276 -0
  37. package/dist/nonInteractiveCli.ts +143 -0
  38. package/dist/package.json +87 -87
  39. package/dist/patches/is-in-ci.ts +17 -0
  40. package/dist/services/BuiltinCommandLoader.test.ts +127 -0
  41. package/dist/services/BuiltinCommandLoader.ts +95 -0
  42. package/dist/services/CommandService.test.ts +352 -0
  43. package/dist/services/CommandService.ts +103 -0
  44. package/dist/services/FileCommandLoader.test.ts +1002 -0
  45. package/dist/services/FileCommandLoader.ts +289 -0
  46. package/dist/services/McpPromptLoader.ts +231 -0
  47. package/dist/services/SearchEngineConfigProvider.ts +100 -0
  48. package/dist/services/prompt-processors/argumentProcessor.test.ts +41 -0
  49. package/dist/services/prompt-processors/argumentProcessor.ts +23 -0
  50. package/dist/services/prompt-processors/shellProcessor.test.ts +709 -0
  51. package/dist/services/prompt-processors/shellProcessor.ts +248 -0
  52. package/dist/services/prompt-processors/types.ts +44 -0
  53. package/dist/services/types.ts +24 -0
  54. package/dist/src/config/apiValidation.test.d.ts +6 -0
  55. package/dist/src/config/apiValidation.test.js +99 -0
  56. package/dist/src/config/apiValidation.test.js.map +1 -0
  57. package/dist/src/config/database.d.ts +32 -0
  58. package/dist/src/config/database.js +281 -2
  59. package/dist/src/config/database.js.map +1 -1
  60. package/dist/src/config/database.test.d.ts +6 -0
  61. package/dist/src/config/database.test.js +80 -0
  62. package/dist/src/config/database.test.js.map +1 -0
  63. package/dist/src/config/providerManager.d.ts +74 -0
  64. package/dist/src/config/providerManager.js +203 -0
  65. package/dist/src/config/providerManager.js.map +1 -0
  66. package/dist/src/config/providerPersistence.d.ts +75 -0
  67. package/dist/src/config/providerPersistence.js +55 -0
  68. package/dist/src/config/providerPersistence.js.map +1 -0
  69. package/dist/src/config/providerPersistence.test.d.ts +6 -0
  70. package/dist/src/config/providerPersistence.test.js +283 -0
  71. package/dist/src/config/providerPersistence.test.js.map +1 -0
  72. package/dist/src/config/settingsSchema.d.ts +9 -0
  73. package/dist/src/config/settingsSchema.js +9 -0
  74. package/dist/src/config/settingsSchema.js.map +1 -1
  75. package/dist/src/generated/git-commit.d.ts +1 -1
  76. package/dist/src/generated/git-commit.js +1 -1
  77. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  78. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  79. package/dist/src/ui/App.js +14 -2
  80. package/dist/src/ui/App.js.map +1 -1
  81. package/dist/src/ui/commands/contextCommand.d.ts +7 -0
  82. package/dist/src/ui/commands/contextCommand.js +115 -0
  83. package/dist/src/ui/commands/contextCommand.js.map +1 -0
  84. package/dist/src/ui/components/ContextUsageDisplay.d.ts +3 -1
  85. package/dist/src/ui/components/ContextUsageDisplay.js +43 -3
  86. package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -1
  87. package/dist/src/ui/components/Footer.d.ts +1 -0
  88. package/dist/src/ui/components/Footer.js +2 -2
  89. package/dist/src/ui/components/Footer.js.map +1 -1
  90. package/dist/src/ui/components/GeminiKeyDialog.d.ts +11 -0
  91. package/dist/src/ui/components/GeminiKeyDialog.js +156 -0
  92. package/dist/src/ui/components/GeminiKeyDialog.js.map +1 -0
  93. package/dist/src/ui/components/OpenAIEndpointDialog.d.ts +19 -0
  94. package/dist/src/ui/components/OpenAIEndpointDialog.js +163 -0
  95. package/dist/src/ui/components/OpenAIEndpointDialog.js.map +1 -0
  96. package/dist/src/ui/components/WelcomeBackDialog.d.ts +36 -0
  97. package/dist/src/ui/components/WelcomeBackDialog.js +109 -0
  98. package/dist/src/ui/components/WelcomeBackDialog.js.map +1 -0
  99. package/dist/src/ui/hooks/useWelcomeBack.d.ts +52 -0
  100. package/dist/src/ui/hooks/useWelcomeBack.js +214 -0
  101. package/dist/src/ui/hooks/useWelcomeBack.js.map +1 -0
  102. package/dist/src/zed-integration/schema.d.ts +1516 -1516
  103. package/dist/test-setup.ts +12 -0
  104. package/dist/test-utils/customMatchers.ts +65 -0
  105. package/dist/test-utils/mockCommandContext.test.ts +62 -0
  106. package/dist/test-utils/mockCommandContext.ts +105 -0
  107. package/dist/test-utils/render.tsx +18 -0
  108. package/dist/tsconfig.tsbuildinfo +1 -1
  109. package/dist/ui/App.test.tsx +2181 -0
  110. package/dist/ui/App.tsx +1344 -0
  111. package/dist/ui/IdeIntegrationNudge.tsx +98 -0
  112. package/dist/ui/__snapshots__/App.test.tsx.snap +124 -0
  113. package/dist/ui/colors.ts +56 -0
  114. package/dist/ui/commands/aboutCommand.test.ts +153 -0
  115. package/dist/ui/commands/aboutCommand.ts +49 -0
  116. package/dist/ui/commands/authCommand.test.ts +36 -0
  117. package/dist/ui/commands/authCommand.ts +17 -0
  118. package/dist/ui/commands/bugCommand.test.ts +114 -0
  119. package/dist/ui/commands/bugCommand.ts +92 -0
  120. package/dist/ui/commands/chatCommand.test.ts +414 -0
  121. package/dist/ui/commands/chatCommand.ts +280 -0
  122. package/dist/ui/commands/clearCommand.test.ts +100 -0
  123. package/dist/ui/commands/clearCommand.ts +29 -0
  124. package/dist/ui/commands/compressCommand.test.ts +129 -0
  125. package/dist/ui/commands/compressCommand.ts +78 -0
  126. package/dist/ui/commands/contextCommand.ts +132 -0
  127. package/dist/ui/commands/copyCommand.test.ts +296 -0
  128. package/dist/ui/commands/copyCommand.ts +67 -0
  129. package/dist/ui/commands/corgiCommand.test.ts +34 -0
  130. package/dist/ui/commands/corgiCommand.ts +16 -0
  131. package/dist/ui/commands/directoryCommand.test.tsx +185 -0
  132. package/dist/ui/commands/directoryCommand.tsx +179 -0
  133. package/dist/ui/commands/docsCommand.test.ts +99 -0
  134. package/dist/ui/commands/docsCommand.ts +42 -0
  135. package/dist/ui/commands/editorCommand.test.ts +30 -0
  136. package/dist/ui/commands/editorCommand.ts +21 -0
  137. package/dist/ui/commands/extensionsCommand.test.ts +67 -0
  138. package/dist/ui/commands/extensionsCommand.ts +46 -0
  139. package/dist/ui/commands/helpCommand.test.ts +52 -0
  140. package/dist/ui/commands/helpCommand.ts +23 -0
  141. package/dist/ui/commands/ideCommand.test.ts +255 -0
  142. package/dist/ui/commands/ideCommand.ts +283 -0
  143. package/dist/ui/commands/initCommand.test.ts +127 -0
  144. package/dist/ui/commands/initCommand.ts +117 -0
  145. package/dist/ui/commands/mcpCommand.test.ts +1057 -0
  146. package/dist/ui/commands/mcpCommand.ts +531 -0
  147. package/dist/ui/commands/memoryCommand.test.ts +344 -0
  148. package/dist/ui/commands/memoryCommand.ts +305 -0
  149. package/dist/ui/commands/privacyCommand.test.ts +38 -0
  150. package/dist/ui/commands/privacyCommand.ts +17 -0
  151. package/dist/ui/commands/quitCommand.test.ts +55 -0
  152. package/dist/ui/commands/quitCommand.ts +36 -0
  153. package/dist/ui/commands/restoreCommand.test.ts +250 -0
  154. package/dist/ui/commands/restoreCommand.ts +157 -0
  155. package/dist/ui/commands/searchEngineSetupCommand.ts +18 -0
  156. package/dist/ui/commands/settingsCommand.test.ts +36 -0
  157. package/dist/ui/commands/settingsCommand.ts +17 -0
  158. package/dist/ui/commands/setupGithubCommand.test.ts +238 -0
  159. package/dist/ui/commands/setupGithubCommand.ts +212 -0
  160. package/dist/ui/commands/speakCommand.ts +175 -0
  161. package/dist/ui/commands/statsCommand.test.ts +78 -0
  162. package/dist/ui/commands/statsCommand.ts +70 -0
  163. package/dist/ui/commands/terminalSetupCommand.test.ts +85 -0
  164. package/dist/ui/commands/terminalSetupCommand.ts +45 -0
  165. package/dist/ui/commands/themeCommand.test.ts +38 -0
  166. package/dist/ui/commands/themeCommand.ts +17 -0
  167. package/dist/ui/commands/toolsCommand.test.ts +105 -0
  168. package/dist/ui/commands/toolsCommand.ts +71 -0
  169. package/dist/ui/commands/ttsCommand.ts +143 -0
  170. package/dist/ui/commands/types.ts +204 -0
  171. package/dist/ui/commands/vimCommand.ts +25 -0
  172. package/dist/ui/commands/voiceCommand.ts +125 -0
  173. package/dist/ui/components/AboutBox.tsx +133 -0
  174. package/dist/ui/components/AsciiArt.ts +54 -0
  175. package/dist/ui/components/AuthDialog.test.tsx +334 -0
  176. package/dist/ui/components/AuthDialog.tsx +289 -0
  177. package/dist/ui/components/AuthInProgress.tsx +62 -0
  178. package/dist/ui/components/AutoAcceptIndicator.tsx +47 -0
  179. package/dist/ui/components/ConsoleSummaryDisplay.tsx +35 -0
  180. package/dist/ui/components/ContextSummaryDisplay.test.tsx +85 -0
  181. package/dist/ui/components/ContextSummaryDisplay.tsx +120 -0
  182. package/dist/ui/components/ContextUsageDisplay.tsx +77 -0
  183. package/dist/ui/components/DebugProfiler.tsx +36 -0
  184. package/dist/ui/components/DetailedMessagesDisplay.tsx +82 -0
  185. package/dist/ui/components/EditorSettingsDialog.tsx +172 -0
  186. package/dist/ui/components/FolderTrustDialog.test.tsx +36 -0
  187. package/dist/ui/components/FolderTrustDialog.tsx +74 -0
  188. package/dist/ui/components/Footer.test.tsx +159 -0
  189. package/dist/ui/components/Footer.tsx +158 -0
  190. package/dist/ui/components/GeminiKeyDialog.tsx +252 -0
  191. package/dist/ui/components/GeminiRespondingSpinner.tsx +34 -0
  192. package/dist/ui/components/Header.test.tsx +44 -0
  193. package/dist/ui/components/Header.tsx +70 -0
  194. package/dist/ui/components/Help.tsx +174 -0
  195. package/dist/ui/components/HistoryItemDisplay.test.tsx +125 -0
  196. package/dist/ui/components/HistoryItemDisplay.tsx +98 -0
  197. package/dist/ui/components/InputPrompt.test.tsx +1467 -0
  198. package/dist/ui/components/InputPrompt.tsx +641 -0
  199. package/dist/ui/components/LMStudioModelPrompt.tsx +215 -0
  200. package/dist/ui/components/LoadingIndicator.test.tsx +296 -0
  201. package/dist/ui/components/LoadingIndicator.tsx +82 -0
  202. package/dist/ui/components/MemoryUsageDisplay.tsx +36 -0
  203. package/dist/ui/components/ModelStatsDisplay.test.tsx +252 -0
  204. package/dist/ui/components/ModelStatsDisplay.tsx +197 -0
  205. package/dist/ui/components/OllamaModelPrompt.tsx +206 -0
  206. package/dist/ui/components/OpenAIEndpointDialog.tsx +261 -0
  207. package/dist/ui/components/OpenAIKeyPrompt.test.tsx +64 -0
  208. package/dist/ui/components/OpenAIKeyPrompt.tsx +197 -0
  209. package/dist/ui/components/PrepareLabel.tsx +48 -0
  210. package/dist/ui/components/SearchEngineConfigDialog.tsx +280 -0
  211. package/dist/ui/components/SessionSummaryDisplay.test.tsx +75 -0
  212. package/dist/ui/components/SessionSummaryDisplay.tsx +18 -0
  213. package/dist/ui/components/SettingsDialog.test.tsx +865 -0
  214. package/dist/ui/components/SettingsDialog.tsx +753 -0
  215. package/dist/ui/components/ShellConfirmationDialog.test.tsx +53 -0
  216. package/dist/ui/components/ShellConfirmationDialog.tsx +103 -0
  217. package/dist/ui/components/ShellModeIndicator.tsx +18 -0
  218. package/dist/ui/components/ShowMoreLines.tsx +40 -0
  219. package/dist/ui/components/StatsDisplay.test.tsx +401 -0
  220. package/dist/ui/components/StatsDisplay.tsx +273 -0
  221. package/dist/ui/components/SuggestionsDisplay.tsx +102 -0
  222. package/dist/ui/components/ThemeDialog.tsx +310 -0
  223. package/dist/ui/components/Tips.tsx +45 -0
  224. package/dist/ui/components/TodoDisplay.test.tsx +97 -0
  225. package/dist/ui/components/TodoDisplay.tsx +72 -0
  226. package/dist/ui/components/ToolStatsDisplay.test.tsx +180 -0
  227. package/dist/ui/components/ToolStatsDisplay.tsx +208 -0
  228. package/dist/ui/components/UpdateNotification.tsx +23 -0
  229. package/dist/ui/components/WelcomeBackDialog.tsx +290 -0
  230. package/dist/ui/components/__snapshots__/IDEContextDetailDisplay.test.tsx.snap +24 -0
  231. package/dist/ui/components/__snapshots__/ModelStatsDisplay.test.tsx.snap +121 -0
  232. package/dist/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap +30 -0
  233. package/dist/ui/components/__snapshots__/ShellConfirmationDialog.test.tsx.snap +21 -0
  234. package/dist/ui/components/__snapshots__/StatsDisplay.test.tsx.snap +264 -0
  235. package/dist/ui/components/__snapshots__/ToolStatsDisplay.test.tsx.snap +91 -0
  236. package/dist/ui/components/messages/CompressionMessage.tsx +49 -0
  237. package/dist/ui/components/messages/DiffRenderer.test.tsx +365 -0
  238. package/dist/ui/components/messages/DiffRenderer.tsx +358 -0
  239. package/dist/ui/components/messages/ErrorMessage.tsx +31 -0
  240. package/dist/ui/components/messages/GeminiMessage.tsx +43 -0
  241. package/dist/ui/components/messages/GeminiMessageContent.tsx +43 -0
  242. package/dist/ui/components/messages/InfoMessage.tsx +32 -0
  243. package/dist/ui/components/messages/ToolConfirmationMessage.test.tsx +58 -0
  244. package/dist/ui/components/messages/ToolConfirmationMessage.tsx +297 -0
  245. package/dist/ui/components/messages/ToolGroupMessage.tsx +126 -0
  246. package/dist/ui/components/messages/ToolMessage.test.tsx +183 -0
  247. package/dist/ui/components/messages/ToolMessage.tsx +296 -0
  248. package/dist/ui/components/messages/UserMessage.tsx +43 -0
  249. package/dist/ui/components/messages/UserShellMessage.tsx +25 -0
  250. package/dist/ui/components/shared/MaxSizedBox.test.tsx +425 -0
  251. package/dist/ui/components/shared/MaxSizedBox.tsx +624 -0
  252. package/dist/ui/components/shared/RadioButtonSelect.test.tsx +181 -0
  253. package/dist/ui/components/shared/RadioButtonSelect.tsx +234 -0
  254. package/dist/ui/components/shared/__snapshots__/RadioButtonSelect.test.tsx.snap +47 -0
  255. package/dist/ui/components/shared/text-buffer.test.ts +1728 -0
  256. package/dist/ui/components/shared/text-buffer.ts +2227 -0
  257. package/dist/ui/components/shared/vim-buffer-actions.test.ts +1119 -0
  258. package/dist/ui/components/shared/vim-buffer-actions.ts +814 -0
  259. package/dist/ui/constants.ts +17 -0
  260. package/dist/ui/contexts/KeypressContext.test.tsx +391 -0
  261. package/dist/ui/contexts/KeypressContext.tsx +440 -0
  262. package/dist/ui/contexts/OverflowContext.tsx +87 -0
  263. package/dist/ui/contexts/SessionContext.test.tsx +132 -0
  264. package/dist/ui/contexts/SessionContext.tsx +143 -0
  265. package/dist/ui/contexts/SettingsContext.tsx +20 -0
  266. package/dist/ui/contexts/StreamingContext.tsx +22 -0
  267. package/dist/ui/contexts/VimModeContext.tsx +79 -0
  268. package/dist/ui/editors/editorSettingsManager.ts +66 -0
  269. package/dist/ui/hooks/atCommandProcessor.test.ts +1102 -0
  270. package/dist/ui/hooks/atCommandProcessor.ts +485 -0
  271. package/dist/ui/hooks/shellCommandProcessor.test.ts +481 -0
  272. package/dist/ui/hooks/shellCommandProcessor.ts +314 -0
  273. package/dist/ui/hooks/slashCommandProcessor.test.ts +1044 -0
  274. package/dist/ui/hooks/slashCommandProcessor.ts +595 -0
  275. package/dist/ui/hooks/useAtCompletion.test.ts +497 -0
  276. package/dist/ui/hooks/useAtCompletion.ts +244 -0
  277. package/dist/ui/hooks/useAuthCommand.ts +129 -0
  278. package/dist/ui/hooks/useAutoAcceptIndicator.test.ts +300 -0
  279. package/dist/ui/hooks/useAutoAcceptIndicator.ts +52 -0
  280. package/dist/ui/hooks/useBracketedPaste.ts +37 -0
  281. package/dist/ui/hooks/useCommandCompletion.test.ts +518 -0
  282. package/dist/ui/hooks/useCommandCompletion.tsx +238 -0
  283. package/dist/ui/hooks/useCompletion.ts +128 -0
  284. package/dist/ui/hooks/useConsoleMessages.test.ts +147 -0
  285. package/dist/ui/hooks/useConsoleMessages.ts +110 -0
  286. package/dist/ui/hooks/useEditorSettings.test.ts +283 -0
  287. package/dist/ui/hooks/useEditorSettings.ts +75 -0
  288. package/dist/ui/hooks/useFocus.test.ts +119 -0
  289. package/dist/ui/hooks/useFocus.ts +48 -0
  290. package/dist/ui/hooks/useFolderTrust.test.ts +159 -0
  291. package/dist/ui/hooks/useFolderTrust.ts +72 -0
  292. package/dist/ui/hooks/useGeminiStream.test.tsx +1998 -0
  293. package/dist/ui/hooks/useGeminiStream.ts +1017 -0
  294. package/dist/ui/hooks/useGitBranchName.test.ts +280 -0
  295. package/dist/ui/hooks/useGitBranchName.ts +79 -0
  296. package/dist/ui/hooks/useHistoryManager.test.ts +202 -0
  297. package/dist/ui/hooks/useHistoryManager.ts +111 -0
  298. package/dist/ui/hooks/useInputHistory.test.ts +261 -0
  299. package/dist/ui/hooks/useInputHistory.ts +111 -0
  300. package/dist/ui/hooks/useKeypress.test.ts +280 -0
  301. package/dist/ui/hooks/useKeypress.ts +39 -0
  302. package/dist/ui/hooks/useKittyKeyboardProtocol.ts +31 -0
  303. package/dist/ui/hooks/useLoadingIndicator.test.ts +139 -0
  304. package/dist/ui/hooks/useLoadingIndicator.ts +57 -0
  305. package/dist/ui/hooks/useLogger.ts +32 -0
  306. package/dist/ui/hooks/useMessageQueue.test.ts +226 -0
  307. package/dist/ui/hooks/useMessageQueue.ts +69 -0
  308. package/dist/ui/hooks/usePhraseCycler.test.ts +145 -0
  309. package/dist/ui/hooks/usePhraseCycler.ts +198 -0
  310. package/dist/ui/hooks/usePrivacySettings.test.ts +242 -0
  311. package/dist/ui/hooks/usePrivacySettings.ts +150 -0
  312. package/dist/ui/hooks/useReactToolScheduler.ts +309 -0
  313. package/dist/ui/hooks/useRefreshMemoryCommand.ts +7 -0
  314. package/dist/ui/hooks/useReverseSearchCompletion.test.tsx +260 -0
  315. package/dist/ui/hooks/useReverseSearchCompletion.tsx +95 -0
  316. package/dist/ui/hooks/useSettingsCommand.ts +25 -0
  317. package/dist/ui/hooks/useShellHistory.test.ts +219 -0
  318. package/dist/ui/hooks/useShellHistory.ts +133 -0
  319. package/dist/ui/hooks/useShowMemoryCommand.ts +75 -0
  320. package/dist/ui/hooks/useSlashCompletion.test.ts +434 -0
  321. package/dist/ui/hooks/useSlashCompletion.ts +187 -0
  322. package/dist/ui/hooks/useStateAndRef.ts +36 -0
  323. package/dist/ui/hooks/useTerminalSize.ts +32 -0
  324. package/dist/ui/hooks/useThemeCommand.ts +110 -0
  325. package/dist/ui/hooks/useTimer.test.ts +120 -0
  326. package/dist/ui/hooks/useTimer.ts +65 -0
  327. package/dist/ui/hooks/useToolScheduler.test.ts +1123 -0
  328. package/dist/ui/hooks/useWelcomeBack.ts +253 -0
  329. package/dist/ui/hooks/vim.test.ts +1691 -0
  330. package/dist/ui/hooks/vim.ts +784 -0
  331. package/dist/ui/keyMatchers.test.ts +337 -0
  332. package/dist/ui/keyMatchers.ts +105 -0
  333. package/dist/ui/privacy/CloudFreePrivacyNotice.tsx +117 -0
  334. package/dist/ui/privacy/CloudPaidPrivacyNotice.tsx +59 -0
  335. package/dist/ui/privacy/GeminiPrivacyNotice.tsx +62 -0
  336. package/dist/ui/privacy/PrivacyNotice.tsx +42 -0
  337. package/dist/ui/semantic-colors.ts +26 -0
  338. package/dist/ui/themes/ansi-light.ts +150 -0
  339. package/dist/ui/themes/ansi.ts +159 -0
  340. package/dist/ui/themes/atom-one-dark.ts +147 -0
  341. package/dist/ui/themes/ayu-light.ts +139 -0
  342. package/dist/ui/themes/ayu.ts +113 -0
  343. package/dist/ui/themes/color-utils.test.ts +221 -0
  344. package/dist/ui/themes/color-utils.ts +231 -0
  345. package/dist/ui/themes/default-light.ts +108 -0
  346. package/dist/ui/themes/default.ts +151 -0
  347. package/dist/ui/themes/dracula.ts +124 -0
  348. package/dist/ui/themes/fss-code-dark.ts +156 -0
  349. package/dist/ui/themes/fss-dark.ts +113 -0
  350. package/dist/ui/themes/fss-light.ts +139 -0
  351. package/dist/ui/themes/github-dark.ts +147 -0
  352. package/dist/ui/themes/github-light.ts +149 -0
  353. package/dist/ui/themes/googlecode.ts +146 -0
  354. package/dist/ui/themes/no-color.ts +125 -0
  355. package/dist/ui/themes/qwen-dark.ts +118 -0
  356. package/dist/ui/themes/qwen-light.ts +144 -0
  357. package/dist/ui/themes/semantic-tokens.ts +127 -0
  358. package/dist/ui/themes/shades-of-purple.ts +352 -0
  359. package/dist/ui/themes/theme-manager.test.ts +99 -0
  360. package/dist/ui/themes/theme-manager.ts +257 -0
  361. package/dist/ui/themes/theme.test.ts +97 -0
  362. package/dist/ui/themes/theme.ts +451 -0
  363. package/dist/ui/themes/xcode.ts +154 -0
  364. package/dist/ui/types.ts +255 -0
  365. package/dist/ui/utils/CodeColorizer.tsx +217 -0
  366. package/dist/ui/utils/ConsolePatcher.ts +71 -0
  367. package/dist/ui/utils/InlineMarkdownRenderer.tsx +173 -0
  368. package/dist/ui/utils/MarkdownDisplay.test.tsx +244 -0
  369. package/dist/ui/utils/MarkdownDisplay.tsx +415 -0
  370. package/dist/ui/utils/TableRenderer.tsx +159 -0
  371. package/dist/ui/utils/__snapshots__/MarkdownDisplay.test.tsx.snap +93 -0
  372. package/dist/ui/utils/clipboardUtils.test.ts +76 -0
  373. package/dist/ui/utils/clipboardUtils.ts +149 -0
  374. package/dist/ui/utils/commandUtils.test.ts +384 -0
  375. package/dist/ui/utils/commandUtils.ts +106 -0
  376. package/dist/ui/utils/computeStats.test.ts +292 -0
  377. package/dist/ui/utils/computeStats.ts +86 -0
  378. package/dist/ui/utils/displayUtils.test.ts +58 -0
  379. package/dist/ui/utils/displayUtils.ts +32 -0
  380. package/dist/ui/utils/formatters.test.ts +72 -0
  381. package/dist/ui/utils/formatters.ts +63 -0
  382. package/dist/ui/utils/isNarrowWidth.ts +9 -0
  383. package/dist/ui/utils/kittyProtocolDetector.ts +105 -0
  384. package/dist/ui/utils/markdownUtilities.test.ts +50 -0
  385. package/dist/ui/utils/markdownUtilities.ts +125 -0
  386. package/dist/ui/utils/platformConstants.ts +52 -0
  387. package/dist/ui/utils/terminalSetup.ts +342 -0
  388. package/dist/ui/utils/textUtils.ts +40 -0
  389. package/dist/ui/utils/updateCheck.test.ts +163 -0
  390. package/dist/ui/utils/updateCheck.ts +100 -0
  391. package/dist/utils/checks.ts +28 -0
  392. package/dist/utils/cleanup.test.ts +68 -0
  393. package/dist/utils/cleanup.ts +36 -0
  394. package/dist/utils/dialogScopeUtils.ts +64 -0
  395. package/dist/utils/events.ts +14 -0
  396. package/dist/utils/gitUtils.test.ts +149 -0
  397. package/dist/utils/gitUtils.ts +116 -0
  398. package/dist/utils/handleAutoUpdate.test.ts +272 -0
  399. package/dist/utils/handleAutoUpdate.ts +145 -0
  400. package/dist/utils/installationInfo.test.ts +315 -0
  401. package/dist/utils/installationInfo.ts +176 -0
  402. package/dist/utils/package.ts +38 -0
  403. package/dist/utils/readStdin.ts +51 -0
  404. package/dist/utils/resolvePath.ts +21 -0
  405. package/dist/utils/sandbox-macos-permissive-closed.sb +32 -0
  406. package/dist/utils/sandbox-macos-permissive-open.sb +25 -0
  407. package/dist/utils/sandbox-macos-permissive-proxied.sb +37 -0
  408. package/dist/utils/sandbox-macos-restrictive-closed.sb +93 -0
  409. package/dist/utils/sandbox-macos-restrictive-open.sb +96 -0
  410. package/dist/utils/sandbox-macos-restrictive-proxied.sb +98 -0
  411. package/dist/utils/sandbox.ts +962 -0
  412. package/dist/utils/settingsUtils.test.ts +797 -0
  413. package/dist/utils/settingsUtils.ts +489 -0
  414. package/dist/utils/spawnWrapper.ts +9 -0
  415. package/dist/utils/startupWarnings.test.ts +83 -0
  416. package/dist/utils/startupWarnings.ts +40 -0
  417. package/dist/utils/updateEventEmitter.ts +13 -0
  418. package/dist/utils/userStartupWarnings.test.ts +87 -0
  419. package/dist/utils/userStartupWarnings.ts +69 -0
  420. package/dist/utils/version.ts +12 -0
  421. package/dist/validateNonInterActiveAuth.test.ts +260 -0
  422. package/dist/validateNonInterActiveAuth.ts +51 -0
  423. package/dist/vitest.config.ts +37 -0
  424. package/dist/zed-integration/acp.ts +366 -0
  425. package/dist/zed-integration/fileSystemService.ts +47 -0
  426. package/dist/zed-integration/schema.ts +466 -0
  427. package/dist/zed-integration/zedIntegration.ts +944 -0
  428. package/package.json +2 -2
@@ -0,0 +1,315 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
8
+ import { getInstallationInfo, PackageManager } from './installationInfo.js';
9
+ import * as fs from 'fs';
10
+ import * as path from 'path';
11
+ import * as childProcess from 'child_process';
12
+ import { isGitRepository } from 'fss-link-core';
13
+
14
+ vi.mock('fss-link-core', () => ({
15
+ isGitRepository: vi.fn(),
16
+ }));
17
+
18
+ vi.mock('fs', async (importOriginal) => {
19
+ const actualFs = await importOriginal<typeof fs>();
20
+ return {
21
+ ...actualFs,
22
+ realpathSync: vi.fn(),
23
+ existsSync: vi.fn(),
24
+ };
25
+ });
26
+
27
+ vi.mock('child_process', async (importOriginal) => {
28
+ const actual = await importOriginal<typeof import('child_process')>();
29
+ return {
30
+ ...actual,
31
+ execSync: vi.fn(),
32
+ };
33
+ });
34
+
35
+ const mockedIsGitRepository = vi.mocked(isGitRepository);
36
+ const mockedRealPathSync = vi.mocked(fs.realpathSync);
37
+ const mockedExistsSync = vi.mocked(fs.existsSync);
38
+ const mockedExecSync = vi.mocked(childProcess.execSync);
39
+
40
+ describe('getInstallationInfo', () => {
41
+ const projectRoot = '/path/to/project';
42
+ let originalArgv: string[];
43
+
44
+ beforeEach(() => {
45
+ vi.resetAllMocks();
46
+ originalArgv = [...process.argv];
47
+ // Mock process.cwd() for isGitRepository
48
+ vi.spyOn(process, 'cwd').mockReturnValue(projectRoot);
49
+ });
50
+
51
+ afterEach(() => {
52
+ process.argv = originalArgv;
53
+ });
54
+
55
+ it('should return UNKNOWN when cliPath is not available', () => {
56
+ process.argv[1] = '';
57
+ const info = getInstallationInfo(projectRoot, false);
58
+ expect(info.packageManager).toBe(PackageManager.UNKNOWN);
59
+ });
60
+
61
+ it('should return UNKNOWN and log error if realpathSync fails', () => {
62
+ const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
63
+ process.argv[1] = '/path/to/cli';
64
+ const error = new Error('realpath failed');
65
+ mockedRealPathSync.mockImplementation(() => {
66
+ throw error;
67
+ });
68
+
69
+ const info = getInstallationInfo(projectRoot, false);
70
+
71
+ expect(info.packageManager).toBe(PackageManager.UNKNOWN);
72
+ expect(consoleSpy).toHaveBeenCalledWith(error);
73
+ consoleSpy.mockRestore();
74
+ });
75
+
76
+ it('should detect running from a local git clone', () => {
77
+ process.argv[1] = `${projectRoot}/packages/cli/dist/index.js`;
78
+ mockedRealPathSync.mockReturnValue(
79
+ `${projectRoot}/packages/cli/dist/index.js`,
80
+ );
81
+ mockedIsGitRepository.mockReturnValue(true);
82
+
83
+ const info = getInstallationInfo(projectRoot, false);
84
+
85
+ expect(info.packageManager).toBe(PackageManager.UNKNOWN);
86
+ expect(info.isGlobal).toBe(false);
87
+ expect(info.updateMessage).toBe(
88
+ 'Running from a local git clone. Please update with "git pull".',
89
+ );
90
+ });
91
+
92
+ it('should detect running via npx', () => {
93
+ const npxPath = `/Users/test/.npm/_npx/12345/bin/gemini`;
94
+ process.argv[1] = npxPath;
95
+ mockedRealPathSync.mockReturnValue(npxPath);
96
+
97
+ const info = getInstallationInfo(projectRoot, false);
98
+
99
+ expect(info.packageManager).toBe(PackageManager.NPX);
100
+ expect(info.isGlobal).toBe(false);
101
+ expect(info.updateMessage).toBe('Running via npx, update not applicable.');
102
+ });
103
+
104
+ it('should detect running via pnpx', () => {
105
+ const pnpxPath = `/Users/test/.pnpm/_pnpx/12345/bin/gemini`;
106
+ process.argv[1] = pnpxPath;
107
+ mockedRealPathSync.mockReturnValue(pnpxPath);
108
+
109
+ const info = getInstallationInfo(projectRoot, false);
110
+
111
+ expect(info.packageManager).toBe(PackageManager.PNPX);
112
+ expect(info.isGlobal).toBe(false);
113
+ expect(info.updateMessage).toBe('Running via pnpx, update not applicable.');
114
+ });
115
+
116
+ it('should detect running via bunx', () => {
117
+ const bunxPath = `/Users/test/.bun/install/cache/12345/bin/gemini`;
118
+ process.argv[1] = bunxPath;
119
+ mockedRealPathSync.mockReturnValue(bunxPath);
120
+ mockedExecSync.mockImplementation(() => {
121
+ throw new Error('Command failed');
122
+ });
123
+
124
+ const info = getInstallationInfo(projectRoot, false);
125
+
126
+ expect(info.packageManager).toBe(PackageManager.BUNX);
127
+ expect(info.isGlobal).toBe(false);
128
+ expect(info.updateMessage).toBe('Running via bunx, update not applicable.');
129
+ });
130
+
131
+ it('should detect Homebrew installation via execSync', () => {
132
+ Object.defineProperty(process, 'platform', {
133
+ value: 'darwin',
134
+ });
135
+ const cliPath = '/usr/local/bin/gemini';
136
+ process.argv[1] = cliPath;
137
+ mockedRealPathSync.mockReturnValue(cliPath);
138
+ mockedExecSync.mockReturnValue(Buffer.from('gemini-cli')); // Simulate successful command
139
+
140
+ const info = getInstallationInfo(projectRoot, false);
141
+
142
+ expect(mockedExecSync).toHaveBeenCalledWith(
143
+ 'brew list -1 | grep -q "^fss-link$"',
144
+ { stdio: 'ignore' },
145
+ );
146
+ expect(info.packageManager).toBe(PackageManager.HOMEBREW);
147
+ expect(info.isGlobal).toBe(true);
148
+ expect(info.updateMessage).toContain('brew upgrade');
149
+ });
150
+
151
+ it('should fall through if brew command fails', () => {
152
+ Object.defineProperty(process, 'platform', {
153
+ value: 'darwin',
154
+ });
155
+ const cliPath = '/usr/local/bin/gemini';
156
+ process.argv[1] = cliPath;
157
+ mockedRealPathSync.mockReturnValue(cliPath);
158
+ mockedExecSync.mockImplementation(() => {
159
+ throw new Error('Command failed');
160
+ });
161
+
162
+ const info = getInstallationInfo(projectRoot, false);
163
+
164
+ expect(mockedExecSync).toHaveBeenCalledWith(
165
+ 'brew list -1 | grep -q "^fss-link$"',
166
+ { stdio: 'ignore' },
167
+ );
168
+ // Should fall back to default global npm
169
+ expect(info.packageManager).toBe(PackageManager.NPM);
170
+ expect(info.isGlobal).toBe(true);
171
+ });
172
+
173
+ it('should detect global pnpm installation', () => {
174
+ const pnpmPath = `/Users/test/.pnpm/global/5/node_modules/.pnpm/some-hash/node_modules/fss-link-core/dist/index.js`;
175
+ process.argv[1] = pnpmPath;
176
+ mockedRealPathSync.mockReturnValue(pnpmPath);
177
+ mockedExecSync.mockImplementation(() => {
178
+ throw new Error('Command failed');
179
+ });
180
+
181
+ const info = getInstallationInfo(projectRoot, false);
182
+ expect(info.packageManager).toBe(PackageManager.PNPM);
183
+ expect(info.isGlobal).toBe(true);
184
+ expect(info.updateCommand).toBe('pnpm add -g fss-link-core@latest');
185
+ expect(info.updateMessage).toContain('Attempting to automatically update');
186
+
187
+ const infoDisabled = getInstallationInfo(projectRoot, true);
188
+ expect(infoDisabled.updateMessage).toContain('Please run pnpm add');
189
+ });
190
+
191
+ it('should detect global yarn installation', () => {
192
+ const yarnPath = `/Users/test/.yarn/global/node_modules/fss-link-core/dist/index.js`;
193
+ process.argv[1] = yarnPath;
194
+ mockedRealPathSync.mockReturnValue(yarnPath);
195
+ mockedExecSync.mockImplementation(() => {
196
+ throw new Error('Command failed');
197
+ });
198
+
199
+ const info = getInstallationInfo(projectRoot, false);
200
+ expect(info.packageManager).toBe(PackageManager.YARN);
201
+ expect(info.isGlobal).toBe(true);
202
+ expect(info.updateCommand).toBe(
203
+ 'yarn global add fss-link-core@latest',
204
+ );
205
+ expect(info.updateMessage).toContain('Attempting to automatically update');
206
+
207
+ const infoDisabled = getInstallationInfo(projectRoot, true);
208
+ expect(infoDisabled.updateMessage).toContain('Please run yarn global add');
209
+ });
210
+
211
+ it('should detect global bun installation', () => {
212
+ const bunPath = `/Users/test/.bun/bin/gemini`;
213
+ process.argv[1] = bunPath;
214
+ mockedRealPathSync.mockReturnValue(bunPath);
215
+ mockedExecSync.mockImplementation(() => {
216
+ throw new Error('Command failed');
217
+ });
218
+
219
+ const info = getInstallationInfo(projectRoot, false);
220
+ expect(info.packageManager).toBe(PackageManager.BUN);
221
+ expect(info.isGlobal).toBe(true);
222
+ expect(info.updateCommand).toBe('bun add -g fss-link-core@latest');
223
+ expect(info.updateMessage).toContain('Attempting to automatically update');
224
+
225
+ const infoDisabled = getInstallationInfo(projectRoot, true);
226
+ expect(infoDisabled.updateMessage).toContain('Please run bun add');
227
+ });
228
+
229
+ it('should detect local installation and identify yarn from lockfile', () => {
230
+ const localPath = `${projectRoot}/node_modules/.bin/gemini`;
231
+ process.argv[1] = localPath;
232
+ mockedRealPathSync.mockReturnValue(localPath);
233
+ mockedExecSync.mockImplementation(() => {
234
+ throw new Error('Command failed');
235
+ });
236
+ mockedExistsSync.mockImplementation(
237
+ (p) => p === path.join(projectRoot, 'yarn.lock'),
238
+ );
239
+
240
+ const info = getInstallationInfo(projectRoot, false);
241
+
242
+ expect(info.packageManager).toBe(PackageManager.YARN);
243
+ expect(info.isGlobal).toBe(false);
244
+ expect(info.updateMessage).toContain('Locally installed');
245
+ });
246
+
247
+ it('should detect local installation and identify pnpm from lockfile', () => {
248
+ const localPath = `${projectRoot}/node_modules/.bin/gemini`;
249
+ process.argv[1] = localPath;
250
+ mockedRealPathSync.mockReturnValue(localPath);
251
+ mockedExecSync.mockImplementation(() => {
252
+ throw new Error('Command failed');
253
+ });
254
+ mockedExistsSync.mockImplementation(
255
+ (p) => p === path.join(projectRoot, 'pnpm-lock.yaml'),
256
+ );
257
+
258
+ const info = getInstallationInfo(projectRoot, false);
259
+
260
+ expect(info.packageManager).toBe(PackageManager.PNPM);
261
+ expect(info.isGlobal).toBe(false);
262
+ });
263
+
264
+ it('should detect local installation and identify bun from lockfile', () => {
265
+ const localPath = `${projectRoot}/node_modules/.bin/gemini`;
266
+ process.argv[1] = localPath;
267
+ mockedRealPathSync.mockReturnValue(localPath);
268
+ mockedExecSync.mockImplementation(() => {
269
+ throw new Error('Command failed');
270
+ });
271
+ mockedExistsSync.mockImplementation(
272
+ (p) => p === path.join(projectRoot, 'bun.lockb'),
273
+ );
274
+
275
+ const info = getInstallationInfo(projectRoot, false);
276
+
277
+ expect(info.packageManager).toBe(PackageManager.BUN);
278
+ expect(info.isGlobal).toBe(false);
279
+ });
280
+
281
+ it('should default to local npm installation if no lockfile is found', () => {
282
+ const localPath = `${projectRoot}/node_modules/.bin/gemini`;
283
+ process.argv[1] = localPath;
284
+ mockedRealPathSync.mockReturnValue(localPath);
285
+ mockedExecSync.mockImplementation(() => {
286
+ throw new Error('Command failed');
287
+ });
288
+ mockedExistsSync.mockReturnValue(false); // No lockfiles
289
+
290
+ const info = getInstallationInfo(projectRoot, false);
291
+
292
+ expect(info.packageManager).toBe(PackageManager.NPM);
293
+ expect(info.isGlobal).toBe(false);
294
+ });
295
+
296
+ it('should default to global npm installation for unrecognized paths', () => {
297
+ const globalPath = `/usr/local/bin/gemini`;
298
+ process.argv[1] = globalPath;
299
+ mockedRealPathSync.mockReturnValue(globalPath);
300
+ mockedExecSync.mockImplementation(() => {
301
+ throw new Error('Command failed');
302
+ });
303
+
304
+ const info = getInstallationInfo(projectRoot, false);
305
+ expect(info.packageManager).toBe(PackageManager.NPM);
306
+ expect(info.isGlobal).toBe(true);
307
+ expect(info.updateCommand).toBe(
308
+ 'npm install -g fss-link-core@latest',
309
+ );
310
+ expect(info.updateMessage).toContain('Attempting to automatically update');
311
+
312
+ const infoDisabled = getInstallationInfo(projectRoot, true);
313
+ expect(infoDisabled.updateMessage).toContain('Please run npm install');
314
+ });
315
+ });
@@ -0,0 +1,176 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { isGitRepository } from 'fss-link-core';
8
+ import * as fs from 'fs';
9
+ import * as path from 'path';
10
+ import * as childProcess from 'child_process';
11
+
12
+ export enum PackageManager {
13
+ NPM = 'npm',
14
+ YARN = 'yarn',
15
+ PNPM = 'pnpm',
16
+ PNPX = 'pnpx',
17
+ BUN = 'bun',
18
+ BUNX = 'bunx',
19
+ HOMEBREW = 'homebrew',
20
+ NPX = 'npx',
21
+ UNKNOWN = 'unknown',
22
+ }
23
+
24
+ export interface InstallationInfo {
25
+ packageManager: PackageManager;
26
+ isGlobal: boolean;
27
+ updateCommand?: string;
28
+ updateMessage?: string;
29
+ }
30
+
31
+ export function getInstallationInfo(
32
+ projectRoot: string,
33
+ isAutoUpdateDisabled: boolean,
34
+ ): InstallationInfo {
35
+ const cliPath = process.argv[1];
36
+ if (!cliPath) {
37
+ return { packageManager: PackageManager.UNKNOWN, isGlobal: false };
38
+ }
39
+
40
+ try {
41
+ // Normalize path separators to forward slashes for consistent matching.
42
+ const realPath = fs.realpathSync(cliPath).replace(/\\/g, '/');
43
+ const normalizedProjectRoot = projectRoot?.replace(/\\/g, '/');
44
+ const isGit = isGitRepository(process.cwd());
45
+
46
+ // Check for local git clone first
47
+ if (
48
+ isGit &&
49
+ normalizedProjectRoot &&
50
+ realPath.startsWith(normalizedProjectRoot) &&
51
+ !realPath.includes('/node_modules/')
52
+ ) {
53
+ return {
54
+ packageManager: PackageManager.UNKNOWN, // Not managed by a package manager in this sense
55
+ isGlobal: false,
56
+ updateMessage:
57
+ 'Running from a local git clone. Please update with "git pull".',
58
+ };
59
+ }
60
+
61
+ // Check for npx/pnpx
62
+ if (realPath.includes('/.npm/_npx') || realPath.includes('/npm/_npx')) {
63
+ return {
64
+ packageManager: PackageManager.NPX,
65
+ isGlobal: false,
66
+ updateMessage: 'Running via npx, update not applicable.',
67
+ };
68
+ }
69
+ if (realPath.includes('/.pnpm/_pnpx')) {
70
+ return {
71
+ packageManager: PackageManager.PNPX,
72
+ isGlobal: false,
73
+ updateMessage: 'Running via pnpx, update not applicable.',
74
+ };
75
+ }
76
+
77
+ // Check for Homebrew
78
+ if (process.platform === 'darwin') {
79
+ try {
80
+ // We do not support homebrew for now, keep forward compatibility for future use
81
+ childProcess.execSync('brew list -1 | grep -q "^fss-link$"', {
82
+ stdio: 'ignore',
83
+ });
84
+ return {
85
+ packageManager: PackageManager.HOMEBREW,
86
+ isGlobal: true,
87
+ updateMessage:
88
+ 'Installed via Homebrew. Please update with "brew upgrade".',
89
+ };
90
+ } catch (_error) {
91
+ // continue to the next check
92
+ }
93
+ }
94
+
95
+ // Check for pnpm
96
+ if (realPath.includes('/.pnpm/global')) {
97
+ const updateCommand = 'pnpm add -g fss-link-core@latest';
98
+ return {
99
+ packageManager: PackageManager.PNPM,
100
+ isGlobal: true,
101
+ updateCommand,
102
+ updateMessage: isAutoUpdateDisabled
103
+ ? `Please run ${updateCommand} to update`
104
+ : 'Installed with pnpm. Attempting to automatically update now...',
105
+ };
106
+ }
107
+
108
+ // Check for yarn
109
+ if (realPath.includes('/.yarn/global')) {
110
+ const updateCommand = 'yarn global add fss-link-core@latest';
111
+ return {
112
+ packageManager: PackageManager.YARN,
113
+ isGlobal: true,
114
+ updateCommand,
115
+ updateMessage: isAutoUpdateDisabled
116
+ ? `Please run ${updateCommand} to update`
117
+ : 'Installed with yarn. Attempting to automatically update now...',
118
+ };
119
+ }
120
+
121
+ // Check for bun
122
+ if (realPath.includes('/.bun/install/cache')) {
123
+ return {
124
+ packageManager: PackageManager.BUNX,
125
+ isGlobal: false,
126
+ updateMessage: 'Running via bunx, update not applicable.',
127
+ };
128
+ }
129
+ if (realPath.includes('/.bun/bin')) {
130
+ const updateCommand = 'bun add -g fss-link-core@latest';
131
+ return {
132
+ packageManager: PackageManager.BUN,
133
+ isGlobal: true,
134
+ updateCommand,
135
+ updateMessage: isAutoUpdateDisabled
136
+ ? `Please run ${updateCommand} to update`
137
+ : 'Installed with bun. Attempting to automatically update now...',
138
+ };
139
+ }
140
+
141
+ // Check for local install
142
+ if (
143
+ normalizedProjectRoot &&
144
+ realPath.startsWith(`${normalizedProjectRoot}/node_modules`)
145
+ ) {
146
+ let pm = PackageManager.NPM;
147
+ if (fs.existsSync(path.join(projectRoot, 'yarn.lock'))) {
148
+ pm = PackageManager.YARN;
149
+ } else if (fs.existsSync(path.join(projectRoot, 'pnpm-lock.yaml'))) {
150
+ pm = PackageManager.PNPM;
151
+ } else if (fs.existsSync(path.join(projectRoot, 'bun.lockb'))) {
152
+ pm = PackageManager.BUN;
153
+ }
154
+ return {
155
+ packageManager: pm,
156
+ isGlobal: false,
157
+ updateMessage:
158
+ "Locally installed. Please update via your project's package.json.",
159
+ };
160
+ }
161
+
162
+ // Assume global npm
163
+ const updateCommand = 'npm install -g fss-link-core@latest';
164
+ return {
165
+ packageManager: PackageManager.NPM,
166
+ isGlobal: true,
167
+ updateCommand,
168
+ updateMessage: isAutoUpdateDisabled
169
+ ? `Please run ${updateCommand} to update`
170
+ : 'Installed with npm. Attempting to automatically update now...',
171
+ };
172
+ } catch (error) {
173
+ console.log(error);
174
+ return { packageManager: PackageManager.UNKNOWN, isGlobal: false };
175
+ }
176
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import {
8
+ readPackageUp,
9
+ type PackageJson as BasePackageJson,
10
+ } from 'read-package-up';
11
+ import { fileURLToPath } from 'url';
12
+ import path from 'path';
13
+
14
+ export type PackageJson = BasePackageJson & {
15
+ config?: {
16
+ sandboxImageUri?: string;
17
+ };
18
+ };
19
+
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = path.dirname(__filename);
22
+
23
+ let packageJson: PackageJson | undefined;
24
+
25
+ export async function getPackageJson(): Promise<PackageJson | undefined> {
26
+ if (packageJson) {
27
+ return packageJson;
28
+ }
29
+
30
+ const result = await readPackageUp({ cwd: __dirname });
31
+ if (!result) {
32
+ // TODO: Maybe bubble this up as an error.
33
+ return;
34
+ }
35
+
36
+ packageJson = result.packageJson;
37
+ return packageJson;
38
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ export async function readStdin(): Promise<string> {
8
+ const MAX_STDIN_SIZE = 8 * 1024 * 1024; // 8MB
9
+ return new Promise((resolve, reject) => {
10
+ let data = '';
11
+ let totalSize = 0;
12
+ process.stdin.setEncoding('utf8');
13
+
14
+ const onReadable = () => {
15
+ let chunk;
16
+ while ((chunk = process.stdin.read()) !== null) {
17
+ if (totalSize + chunk.length > MAX_STDIN_SIZE) {
18
+ const remainingSize = MAX_STDIN_SIZE - totalSize;
19
+ data += chunk.slice(0, remainingSize);
20
+ console.warn(
21
+ `Warning: stdin input truncated to ${MAX_STDIN_SIZE} bytes.`,
22
+ );
23
+ process.stdin.destroy(); // Stop reading further
24
+ break;
25
+ }
26
+ data += chunk;
27
+ totalSize += chunk.length;
28
+ }
29
+ };
30
+
31
+ const onEnd = () => {
32
+ cleanup();
33
+ resolve(data);
34
+ };
35
+
36
+ const onError = (err: Error) => {
37
+ cleanup();
38
+ reject(err);
39
+ };
40
+
41
+ const cleanup = () => {
42
+ process.stdin.removeListener('readable', onReadable);
43
+ process.stdin.removeListener('end', onEnd);
44
+ process.stdin.removeListener('error', onError);
45
+ };
46
+
47
+ process.stdin.on('readable', onReadable);
48
+ process.stdin.on('end', onEnd);
49
+ process.stdin.on('error', onError);
50
+ });
51
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Google LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import * as os from 'os';
8
+ import * as path from 'path';
9
+
10
+ export function resolvePath(p: string): string {
11
+ if (!p) {
12
+ return '';
13
+ }
14
+ let expandedPath = p;
15
+ if (p.toLowerCase().startsWith('%userprofile%')) {
16
+ expandedPath = os.homedir() + p.substring('%userprofile%'.length);
17
+ } else if (p === '~' || p.startsWith('~/')) {
18
+ expandedPath = os.homedir() + p.substring(1);
19
+ }
20
+ return path.normalize(expandedPath);
21
+ }
@@ -0,0 +1,32 @@
1
+ (version 1)
2
+
3
+ ;; allow everything by default
4
+ (allow default)
5
+
6
+ ;; deny all writes EXCEPT under specific paths
7
+ (deny file-write*)
8
+ (allow file-write*
9
+ (subpath (param "TARGET_DIR"))
10
+ (subpath (param "TMP_DIR"))
11
+ (subpath (param "CACHE_DIR"))
12
+ (subpath (string-append (param "HOME_DIR") "/.qwen"))
13
+ (subpath (string-append (param "HOME_DIR") "/.npm"))
14
+ (subpath (string-append (param "HOME_DIR") "/.cache"))
15
+ (subpath (string-append (param "HOME_DIR") "/.gitconfig"))
16
+ ;; Allow writes to included directories from --include-directories
17
+ (subpath (param "INCLUDE_DIR_0"))
18
+ (subpath (param "INCLUDE_DIR_1"))
19
+ (subpath (param "INCLUDE_DIR_2"))
20
+ (subpath (param "INCLUDE_DIR_3"))
21
+ (subpath (param "INCLUDE_DIR_4"))
22
+ (literal "/dev/stdout")
23
+ (literal "/dev/stderr")
24
+ (literal "/dev/null")
25
+ )
26
+
27
+ ;; deny all inbound network traffic EXCEPT on debugger port
28
+ (deny network-inbound)
29
+ (allow network-inbound (local ip "localhost:9229"))
30
+
31
+ ;; deny all outbound network traffic
32
+ (deny network-outbound)
@@ -0,0 +1,25 @@
1
+ (version 1)
2
+
3
+ ;; allow everything by default
4
+ (allow default)
5
+
6
+ ;; deny all writes EXCEPT under specific paths
7
+ (deny file-write*)
8
+ (allow file-write*
9
+ (subpath (param "TARGET_DIR"))
10
+ (subpath (param "TMP_DIR"))
11
+ (subpath (param "CACHE_DIR"))
12
+ (subpath (string-append (param "HOME_DIR") "/.qwen"))
13
+ (subpath (string-append (param "HOME_DIR") "/.npm"))
14
+ (subpath (string-append (param "HOME_DIR") "/.cache"))
15
+ (subpath (string-append (param "HOME_DIR") "/.gitconfig"))
16
+ ;; Allow writes to included directories from --include-directories
17
+ (subpath (param "INCLUDE_DIR_0"))
18
+ (subpath (param "INCLUDE_DIR_1"))
19
+ (subpath (param "INCLUDE_DIR_2"))
20
+ (subpath (param "INCLUDE_DIR_3"))
21
+ (subpath (param "INCLUDE_DIR_4"))
22
+ (literal "/dev/stdout")
23
+ (literal "/dev/stderr")
24
+ (literal "/dev/null")
25
+ )
@@ -0,0 +1,37 @@
1
+ (version 1)
2
+
3
+ ;; allow everything by default
4
+ (allow default)
5
+
6
+ ;; deny all writes EXCEPT under specific paths
7
+ (deny file-write*)
8
+ (allow file-write*
9
+ (subpath (param "TARGET_DIR"))
10
+ (subpath (param "TMP_DIR"))
11
+ (subpath (param "CACHE_DIR"))
12
+ (subpath (string-append (param "HOME_DIR") "/.qwen"))
13
+ (subpath (string-append (param "HOME_DIR") "/.npm"))
14
+ (subpath (string-append (param "HOME_DIR") "/.cache"))
15
+ (subpath (string-append (param "HOME_DIR") "/.gitconfig"))
16
+ ;; Allow writes to included directories from --include-directories
17
+ (subpath (param "INCLUDE_DIR_0"))
18
+ (subpath (param "INCLUDE_DIR_1"))
19
+ (subpath (param "INCLUDE_DIR_2"))
20
+ (subpath (param "INCLUDE_DIR_3"))
21
+ (subpath (param "INCLUDE_DIR_4"))
22
+ (literal "/dev/stdout")
23
+ (literal "/dev/stderr")
24
+ (literal "/dev/null")
25
+ )
26
+
27
+ ;; deny all inbound network traffic EXCEPT on debugger port
28
+ (deny network-inbound)
29
+ (allow network-inbound (local ip "localhost:9229"))
30
+
31
+ ;; deny all outbound network traffic EXCEPT through proxy on localhost:8877
32
+ ;; set `GEMINI_SANDBOX_PROXY_COMMAND=<command>` to run proxy alongside sandbox
33
+ ;; proxy must listen on :::8877 (see docs/examples/proxy-script.md)
34
+ (deny network-outbound)
35
+ (allow network-outbound (remote tcp "localhost:8877"))
36
+
37
+ (allow network-bind (local ip "*:*"))