@mindstudio-ai/local-model-tunnel 0.3.1 → 0.3.3
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.
- package/dist/{chunk-PTK4SJQK.js → chunk-V3RKCMCQ.js} +571 -706
- package/dist/chunk-V3RKCMCQ.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{tui-QOSKXZWU.js → tui-KQ4LWB4E.js} +259 -102
- package/dist/tui-KQ4LWB4E.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-PTK4SJQK.js.map +0 -1
- package/dist/tui-QOSKXZWU.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tui/index.tsx","../src/tui/App.tsx","../src/tui/components/Header.tsx","../src/tui/components/NavigationMenu.tsx","../src/tui/hooks/useConnection.ts","../src/tui/hooks/useProviders.ts","../src/tui/hooks/useModels.ts","../src/tui/hooks/useRequests.ts","../src/tui/hooks/useRegisteredModels.ts","../src/tui/pages/DashboardPage.tsx","../src/tui/components/RequestLog.tsx","../src/tui/hooks/useSetupProviders.ts","../src/tui/pages/RegisterPage.tsx","../src/tui/hooks/useRegister.ts","../src/tui/pages/SetupPage.tsx","../src/tui/components/MarkdownText.tsx","../src/tui/pages/OnboardingPage.tsx","../src/tui/hooks/useAuth.ts","../src/update.ts","../src/tui/components/UpdatePrompt.tsx"],"sourcesContent":["import React from 'react';\nimport { render } from 'ink';\nimport { execFileSync, execSync } from 'node:child_process';\nimport { App } from './App';\nimport { TunnelRunner } from '../runner';\nimport { checkForUpdate } from '../update';\nimport { UpdatePrompt } from './components/UpdatePrompt';\n\nasync function promptForUpdate(\n currentVersion: string,\n latestVersion: string,\n): Promise<boolean> {\n return new Promise((resolve) => {\n const { unmount } = render(\n <UpdatePrompt\n currentVersion={currentVersion}\n latestVersion={latestVersion}\n onChoice={(shouldUpdate) => {\n unmount();\n resolve(shouldUpdate);\n }}\n />,\n { exitOnCtrlC: true },\n );\n });\n}\n\nexport async function startTUI(): Promise<void> {\n // Clear the screen\n console.clear();\n\n // Check for updates before launching the main app\n const update = await checkForUpdate();\n if (update) {\n const shouldUpdate = await promptForUpdate(\n update.currentVersion,\n update.latestVersion,\n );\n if (shouldUpdate) {\n console.log('\\nUpdating to v' + update.latestVersion + '...\\n');\n try {\n execSync('npm install -g @mindstudio-ai/local-model-tunnel@latest', {\n stdio: 'inherit',\n });\n console.log('\\nRestarting...\\n');\n execFileSync(process.execPath, process.argv.slice(1), {\n stdio: 'inherit',\n });\n } catch {\n console.error('\\nUpdate failed. Continuing with current version.\\n');\n }\n return;\n }\n console.clear();\n }\n\n // Create the runner instance\n const runner = new TunnelRunner();\n\n // Render the TUI with stdin configured for keyboard input\n const { waitUntilExit } = render(\n <App runner={runner} />,\n {\n exitOnCtrlC: true,\n },\n );\n\n // Wait for the app to exit\n await waitUntilExit();\n\n // Ensure clean shutdown\n runner.stop();\n}\n","import React, { useEffect, useCallback, useState } from 'react';\nimport { Box, useApp, useStdout } from 'ink';\nimport { Header } from './components/Header';\nimport { NavigationMenu } from './components/NavigationMenu';\nimport type { MenuItem } from './components/NavigationMenu';\nimport { useConnection } from './hooks/useConnection';\nimport { useProviders } from './hooks/useProviders';\nimport { useModels } from './hooks/useModels';\nimport { useRequests } from './hooks/useRequests';\nimport { useSyncedModels } from './hooks/useRegisteredModels';\nimport { DashboardPage } from './pages/DashboardPage';\nimport { SyncPage } from './pages/RegisterPage';\nimport { SetupPage } from './pages/SetupPage';\nimport { OnboardingPage } from './pages/OnboardingPage';\nimport { TunnelRunner } from '../runner';\nimport { getApiKey, getConfigPath } from '../config';\nimport type { Page } from './types';\n\ninterface AppProps {\n runner: TunnelRunner;\n}\n\nexport function App({ runner }: AppProps) {\n const { exit } = useApp();\n const { stdout } = useStdout();\n const {\n status: connectionStatus,\n environment,\n error: connectionError,\n retry: retryConnection,\n } = useConnection();\n const { refresh: refreshProviders } = useProviders();\n const {\n models,\n warnings: modelWarnings,\n loading: modelsLoading,\n refresh: refreshModels,\n } = useModels();\n const { requests } = useRequests();\n const { syncedNames, refresh: refreshSynced } =\n useSyncedModels(connectionStatus);\n const shouldOnboard = getApiKey() === undefined;\n const [page, setPage] = useState<Page>(\n shouldOnboard ? 'onboarding' : 'dashboard',\n );\n\n // Refresh everything when returning to dashboard\n useEffect(() => {\n if (page === 'dashboard') {\n refreshAll();\n }\n }, [page]);\n\n // Start runner when connected with models\n useEffect(() => {\n if (connectionStatus === 'connected' && models.length > 0) {\n runner.start(models.map((m) => m.name));\n }\n }, [connectionStatus, models, runner]);\n\n // Stop only on unmount\n useEffect(() => () => runner.stop(), [runner]);\n\n // Refresh everything\n const refreshAll = useCallback(async () => {\n await Promise.all([\n refreshProviders(),\n refreshModels(),\n refreshSynced(),\n ]);\n }, [refreshProviders, refreshModels, refreshSynced]);\n\n const handleQuit = useCallback(() => {\n runner.stop();\n exit();\n }, [runner, exit]);\n\n const handleOnboardingComplete = useCallback(() => {\n retryConnection();\n refreshAll();\n setPage('dashboard');\n }, [retryConnection, refreshAll]);\n\n const handleNavigate = useCallback(\n (id: string) => {\n switch (id) {\n case 'auth':\n setPage('onboarding');\n break;\n case 'register':\n setPage('sync');\n break;\n case 'setup':\n setPage('setup');\n break;\n case 'refresh':\n refreshAll();\n break;\n case 'quit':\n handleQuit();\n break;\n }\n },\n [refreshModels, refreshSynced, refreshAll, handleQuit],\n );\n\n const subpageMenuItems: MenuItem[] = [\n { id: 'back', label: 'Back', description: 'Return to dashboard' },\n ];\n\n const handleSubpageNavigate = useCallback(\n (id: string) => {\n if (id === 'back') {\n setPage('dashboard');\n } else {\n handleNavigate(id);\n }\n },\n [handleNavigate],\n );\n\n const termHeight = (stdout?.rows ?? 24) - 4;\n\n return (\n <Box flexDirection=\"column\" height={termHeight} overflow=\"hidden\">\n {page === 'onboarding' ? (\n <OnboardingPage onComplete={handleOnboardingComplete} />\n ) : (\n <>\n <Header\n connection={connectionStatus}\n environment={environment}\n configPath={getConfigPath()}\n connectionError={connectionError}\n />\n\n {page === 'dashboard' && (\n <DashboardPage\n requests={requests}\n models={models}\n modelWarnings={modelWarnings}\n syncedNames={syncedNames}\n modelsLoading={modelsLoading}\n onNavigate={handleNavigate}\n />\n )}\n {page === 'setup' && (\n <SetupPage onBack={() => setPage('dashboard')} />\n )}\n {page === 'sync' && <SyncPage />}\n\n {page !== 'dashboard' && page !== 'setup' && <Box flexGrow={1} />}\n\n {page !== 'dashboard' && page !== 'setup' && (\n <NavigationMenu\n items={subpageMenuItems}\n onSelect={handleSubpageNavigate}\n />\n )}\n </>\n )}\n </Box>\n );\n}\n","import React from 'react';\nimport os from 'node:os';\nimport { Box, Text } from 'ink';\nimport type { ConnectionStatus } from '../types';\nimport { createRequire } from 'node:module';\n\ninterface HeaderProps {\n connection: ConnectionStatus;\n environment: 'prod' | 'local';\n configPath: string;\n connectionError?: string | null;\n}\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../package.json') as { version: string };\n\nexport const LogoString = ` .=+-. :++.\n *@@@@@+ :%@@@@%:\n .%@@@@@@#..@@@@@@@=\n .*@@@@@@@--@@@@@@@#.**.\n *@@@@@@@.-@@@@@@@@.#@@*\n.#@@@@@@@-.@@@@@@@* #@@@@%.\n=@@@@@@@-.@@@@@@@#.-@@@@@@+\n:@@@@@@: +@@@@@#. .@@@@@@:\n .++: .-*-. .++:`;\n\nconst getConnectionDisplay = (status: ConnectionStatus) => {\n switch (status) {\n case 'connected':\n return { color: 'green', text: 'Connected to Cloud' };\n case 'connecting':\n return { color: 'yellow', text: 'Connecting...' };\n case 'not_authenticated':\n return { color: 'yellow', text: 'Not Authenticated' };\n case 'disconnected':\n return { color: 'red', text: 'Disconnected' };\n default:\n return { color: 'red', text: 'Error' };\n }\n};\n\nexport function Header({\n connection,\n environment,\n configPath,\n connectionError,\n}: HeaderProps) {\n const { color: connectionColor, text: connectionText } =\n getConnectionDisplay(connection);\n\n return (\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n borderStyle=\"round\"\n borderColor=\"cyan\"\n paddingX={1}\n paddingY={1}\n width=\"100%\"\n >\n <Box paddingLeft={3}>\n <Text color=\"cyan\">{LogoString}</Text>\n </Box>\n <Box flexDirection=\"column\" marginLeft={4}>\n <Box>\n <Text bold color=\"white\">\n MindStudio Local Tunnel\n </Text>\n {environment !== 'prod' && (\n <>\n <Text> </Text>\n <Text color=\"yellow\" bold>\n [LOCAL]\n </Text>\n </>\n )}\n </Box>\n <Text color=\"gray\">v{pkg.version}</Text>\n <Text color={connectionColor}>● {connectionText}</Text>\n {connectionError && <Text color=\"red\">{connectionError}</Text>}\n <Text color=\"gray\">\n Config: {configPath.replace(os.homedir(), '~')}\n </Text>\n </Box>\n </Box>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { Box, Text, useInput } from 'ink';\n\nexport interface MenuItem {\n id: string;\n label: string;\n description: string;\n disabled?: boolean;\n disabledReason?: string;\n isSeparator?: boolean;\n color?: string;\n}\n\ninterface NavigationMenuProps {\n items: MenuItem[];\n onSelect: (id: string) => void;\n title?: string;\n}\n\nexport function NavigationMenu({ items, onSelect, title }: NavigationMenuProps) {\n const getDefaultIndex = () => {\n const backIdx = items.findIndex((i) => i.id === 'back');\n if (backIdx >= 0) return backIdx;\n const firstIdx = items.findIndex((i) => !i.disabled && !i.isSeparator);\n return firstIdx >= 0 ? firstIdx : 0;\n };\n const [selectedIndex, setSelectedIndex] = useState(getDefaultIndex);\n\n useEffect(() => {\n setSelectedIndex(getDefaultIndex());\n }, [items]);\n\n const findNextEnabled = (from: number, direction: 1 | -1): number => {\n let idx = from;\n for (let i = 0; i < items.length; i++) {\n idx = (idx + direction + items.length) % items.length;\n if (!items[idx]!.disabled && !items[idx]!.isSeparator) return idx;\n }\n return from;\n };\n\n useInput((input, key) => {\n if (input === 'q' || key.escape) {\n const backItem = items.find((i) => i.id === 'back');\n if (backItem) {\n onSelect('back');\n } else if (input === 'q') {\n onSelect('quit');\n }\n return;\n }\n if (key.upArrow) {\n setSelectedIndex((prev) => findNextEnabled(prev, -1));\n } else if (key.downArrow) {\n setSelectedIndex((prev) => findNextEnabled(prev, 1));\n } else if (key.return) {\n const item = items[selectedIndex];\n if (item && !item.disabled) {\n onSelect(item.id);\n }\n }\n });\n\n // Fixed height: header + items + hint + margins\n const separatorExtraLines = items.filter((item, idx) => item.isSeparator && idx > 0).length;\n const menuHeight = items.length + 4 + separatorExtraLines;\n\n return (\n <Box flexDirection=\"column\" paddingX={1} marginBottom={1} borderStyle=\"single\" borderTop borderBottom={false} borderLeft={false} borderRight={false} borderColor=\"gray\">\n <Box marginTop={1}>\n <Text color=\"gray\">{title ?? 'Actions'}</Text>\n </Box>\n <Box flexDirection=\"column\">\n {items.map((item, index) => {\n if (item.isSeparator) {\n return (\n <Box key={item.id} marginTop={index > 0 ? 1 : 0}>\n {item.label ? (\n <Text bold color={item.color ?? 'gray'} wrap=\"truncate-end\">\n {item.label}\n </Text>\n ) : null}\n </Box>\n );\n }\n\n const isSelected = index === selectedIndex;\n const prefix = isSelected ? '❯' : ' ';\n\n if (item.disabled) {\n return (\n <Box key={item.id}>\n <Text color=\"gray\" wrap=\"truncate-end\">\n {prefix} {item.label}\n {item.disabledReason ? ` (${item.disabledReason})` : ''}\n </Text>\n </Box>\n );\n }\n\n return (\n <Box key={item.id}>\n <Text color={isSelected ? 'cyan' : 'white'} bold={isSelected} wrap=\"truncate-end\">\n {prefix} {item.label}\n </Text>\n {isSelected && (\n <Text color=\"gray\" wrap=\"truncate-end\"> - {item.description}</Text>\n )}\n </Box>\n );\n })}\n </Box>\n\n <Box marginTop={1} height={1}>\n <Text color=\"gray\" wrap=\"truncate-end\">\n {items.some((i) => i.id === 'back')\n ? 'Up/Down Navigate \\u2022 Enter Select \\u2022 q/Esc Back'\n : 'Up/Down Navigate \\u2022 Enter Select \\u2022 q Quit'}\n </Text>\n </Box>\n </Box>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { verifyApiKey } from '../../api';\nimport { getApiKey, getEnvironment } from '../../config';\nimport type { ConnectionStatus } from '../types';\n\ninterface UseConnectionResult {\n status: ConnectionStatus;\n environment: 'prod' | 'local';\n error: string | null;\n retry: () => void;\n}\n\nexport function useConnection(): UseConnectionResult {\n const [status, setStatus] = useState<ConnectionStatus>('connecting');\n const [error, setError] = useState<string | null>(null);\n const environment = getEnvironment();\n\n const connect = useCallback(async () => {\n setStatus('connecting');\n setError(null);\n\n const apiKey = getApiKey();\n if (!apiKey) {\n setStatus('not_authenticated');\n return;\n }\n\n try {\n const isValid = await verifyApiKey();\n if (isValid) {\n setStatus('connected');\n } else {\n setStatus('not_authenticated');\n }\n } catch (err) {\n setStatus('error');\n setError(err instanceof Error ? err.message : 'Connection failed');\n }\n }, []);\n\n useEffect(() => {\n connect();\n }, [connect]);\n\n return {\n status,\n environment,\n error,\n retry: connect,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { getProviderStatuses } from '../../providers';\nimport type { ProviderStatus } from '../types';\n\ninterface UseProvidersResult {\n providers: ProviderStatus[];\n loading: boolean;\n refresh: () => Promise<void>;\n}\n\nexport function useProviders(pollInterval: number = 10000): UseProvidersResult {\n const [providers, setProviders] = useState<ProviderStatus[]>([]);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n try {\n const statuses = await getProviderStatuses();\n setProviders(statuses);\n } catch {\n // Keep existing state on error\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n refresh();\n\n // Poll for provider status changes\n const interval = setInterval(refresh, pollInterval);\n return () => clearInterval(interval);\n }, [refresh, pollInterval]);\n\n return {\n providers,\n loading,\n refresh,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { discoverAllModels } from '../../providers';\nimport type { LocalModel } from '../../providers/types';\n\ninterface UseModelsResult {\n models: LocalModel[];\n warnings: LocalModel[];\n loading: boolean;\n refresh: () => Promise<void>;\n}\n\nexport function useModels(): UseModelsResult {\n const [models, setModels] = useState<LocalModel[]>([]);\n const [warnings, setWarnings] = useState<LocalModel[]>([]);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n try {\n const discoveredModels = await discoverAllModels();\n setModels(discoveredModels.filter((m) => !m.statusHint));\n setWarnings(discoveredModels.filter((m) => !!m.statusHint));\n } catch {\n // Keep existing state on error\n } finally {\n setLoading(false);\n }\n }, []);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return {\n models,\n warnings,\n loading,\n refresh,\n };\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\nimport { requestEvents } from '../../events';\nimport type { RequestLogEntry } from '../types';\n\ninterface UseRequestsResult {\n requests: RequestLogEntry[];\n activeCount: number;\n clear: () => void;\n}\n\nexport function useRequests(maxHistory: number = 50): UseRequestsResult {\n const [requests, setRequests] = useState<RequestLogEntry[]>([]);\n const requestsRef = useRef<Map<string, RequestLogEntry>>(new Map());\n\n // Update timer for active request durations\n useEffect(() => {\n const interval = setInterval(() => {\n // Force re-render for active requests to update elapsed time\n setRequests((prev) => {\n const hasActive = prev.some((r) => r.status === 'processing');\n return hasActive ? [...prev] : prev;\n });\n }, 1000);\n\n return () => clearInterval(interval);\n }, []);\n\n useEffect(() => {\n const unsubStart = requestEvents.onStart((event) => {\n const entry: RequestLogEntry = {\n id: event.id,\n modelId: event.modelId,\n requestType: event.requestType,\n status: 'processing',\n startTime: event.timestamp,\n };\n\n requestsRef.current.set(event.id, entry);\n setRequests((prev) => [...prev, entry].slice(-maxHistory));\n });\n\n const unsubProgress = requestEvents.onProgress((event) => {\n const existing = requestsRef.current.get(event.id);\n if (existing && existing.status === 'processing') {\n const updated: RequestLogEntry = {\n ...existing,\n ...(event.content !== undefined && { content: event.content }),\n ...(event.step !== undefined && { step: event.step }),\n ...(event.totalSteps !== undefined && { totalSteps: event.totalSteps }),\n };\n requestsRef.current.set(event.id, updated);\n setRequests((prev) =>\n prev.map((r) => (r.id === event.id ? updated : r)),\n );\n }\n });\n\n const unsubComplete = requestEvents.onComplete((event) => {\n const existing = requestsRef.current.get(event.id);\n if (existing) {\n const updated: RequestLogEntry = {\n ...existing,\n status: event.success ? 'completed' : 'failed',\n endTime: Date.now(),\n duration: event.duration,\n result: event.result,\n error: event.error,\n };\n\n requestsRef.current.set(event.id, updated);\n setRequests((prev) =>\n prev.map((r) => (r.id === event.id ? updated : r)),\n );\n }\n });\n\n return () => {\n unsubStart();\n unsubProgress();\n unsubComplete();\n };\n }, [maxHistory]);\n\n const activeCount = requests.filter((r) => r.status === 'processing').length;\n\n const clear = useCallback(() => {\n requestsRef.current.clear();\n setRequests([]);\n }, []);\n\n return {\n requests,\n activeCount,\n clear,\n };\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport { getSyncedModels } from '../../api';\nimport type { ConnectionStatus } from '../types';\n\ninterface UseSyncedModelsResult {\n syncedNames: Set<string>;\n refresh: () => Promise<void>;\n}\n\nexport function useSyncedModels(\n connectionStatus: ConnectionStatus,\n): UseSyncedModelsResult {\n const [syncedNames, setSyncedNames] = useState<Set<string>>(\n new Set(),\n );\n\n const refresh = useCallback(async () => {\n if (connectionStatus !== 'connected') {\n setSyncedNames(new Set());\n return;\n }\n\n try {\n const models = await getSyncedModels();\n setSyncedNames(new Set(models.map((m) => m.name)));\n } catch {\n // Keep existing state on error\n }\n }, [connectionStatus]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return {\n syncedNames,\n refresh,\n };\n}\n","import React, { useMemo } from 'react';\nimport { Box, Text, useStdout } from 'ink';\nimport Spinner from 'ink-spinner';\nimport { RequestLog } from '../components/RequestLog';\nimport { NavigationMenu } from '../components/NavigationMenu';\nimport type { MenuItem } from '../components/NavigationMenu';\nimport type { LocalModel, ComfyWorkflowParameterSchema } from '../../providers/types';\nimport type { ProviderStatus, RequestLogEntry } from '../types';\nimport { useSetupProviders } from '../hooks/useSetupProviders';\n\nfunction getWorkflowCount(model: LocalModel): number | null {\n const param = model.parameters?.find((p) => p.type === 'comfyWorkflow');\n if (!param) return null;\n return (param as ComfyWorkflowParameterSchema).comfyWorkflowOptions.availableWorkflows.length;\n}\n\nfunction getCapabilityLabel(capability: string): {\n label: string;\n color: string;\n} {\n switch (capability) {\n case 'text':\n return { label: 'Text Generation', color: 'gray' };\n case 'image':\n return { label: 'Image Generation', color: 'gray' };\n case 'video':\n return { label: 'Video Generation', color: 'gray' };\n default:\n return { label: capability, color: 'gray' };\n }\n}\n\ninterface DashboardPageProps {\n requests: RequestLogEntry[];\n models: LocalModel[];\n modelWarnings?: LocalModel[];\n syncedNames: Set<string>;\n modelsLoading?: boolean;\n onNavigate: (id: string) => void;\n}\n\nexport function DashboardPage({\n requests,\n models,\n modelWarnings = [],\n syncedNames,\n modelsLoading,\n onNavigate,\n}: DashboardPageProps) {\n const { stdout } = useStdout();\n const { providers, loading: setupLoading } = useSetupProviders();\n\n const installedProviders = providers.filter(({ status }) => status.installed);\n\n const provNameWidth = Math.max(\n ...installedProviders.map((p) => p.provider.displayName.length),\n 8,\n );\n const provStatusWidth = 'Local Server Running'.length;\n\n const allModelNames = new Set(models.map((m) => m.name));\n const unavailableSynced = [...syncedNames].filter(\n (name) => !allModelNames.has(name),\n );\n\n const menuItems = useMemo((): MenuItem[] => {\n return [\n {\n id: 'register',\n label: 'Sync Models',\n description: 'Sync models with MindStudio Cloud',\n },\n {\n id: 'refresh',\n label: 'Refresh Providers',\n description: 'Re-detect local AI providers and models',\n },\n {\n id: 'setup',\n label: 'Manage Providers',\n description: 'Manage local AI providers',\n },\n {\n id: 'auth',\n label: 'Re-authenticate',\n description: 'Re-authenticate with MindStudio',\n },\n {\n id: 'quit',\n label: 'Exit',\n description: 'Quit the application',\n },\n ];\n }, []);\n\n // Compute maxVisible for request log based on terminal height\n const termHeight = (stdout?.rows ?? 24) - 4; // matches App's height calculation\n\n // Header: border(2) + padding(2) + logo(~10 lines) = 14\n const headerLines = 14;\n\n // Providers section: marginTop(1) + title(1) + content gap(1) + content\n const providerContentLines = setupLoading\n ? 1\n : installedProviders.length === 0\n ? 2\n : installedProviders.length;\n const providersLines = 3 + providerContentLines;\n\n // Models section: marginTop(1) + title(1) + content gap(1) + content\n const modelContentLines = modelsLoading\n ? 1\n : models.length === 0 && unavailableSynced.length === 0 && modelWarnings.length === 0\n ? 2\n : models.length +\n modelWarnings.length +\n (unavailableSynced.length > 0\n ? 1 + unavailableSynced.length\n : 0);\n const modelsLines = 3 + modelContentLines;\n\n // Request log overhead: marginTop(1) + title(1) + content gap(1)\n const requestLogOverhead = 3;\n\n // Menu: border-top(1) + marginTop(1) + title(1) + items + hint(1) + marginTop(1) + marginBottom(1)\n const menuLines = menuItems.length + 6;\n\n const usedLines =\n headerLines + providersLines + modelsLines + requestLogOverhead + menuLines;\n const maxVisible = Math.max(3, termHeight - usedLines);\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n {/* Providers */}\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text bold color=\"white\" underline>\n Providers\n </Text>\n\n {setupLoading ? (\n <Box marginTop={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Detecting providers...</Text>\n </Box>\n ) : installedProviders.length === 0 ? (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"yellow\">No providers installed.</Text>\n <Text color=\"gray\">\n Use \"Manage Providers\" below to install one.\n </Text>\n </Box>\n ) : (\n <Box flexDirection=\"column\" marginTop={1}>\n {installedProviders.map(({ provider, status }) => {\n const url = provider.baseUrl;\n const statusColor = status.running ? 'green' : 'yellow';\n const statusText = status.running\n ? 'Local Server Running'\n : 'Installed (not running)';\n\n return (\n <Box key={provider.name}>\n <Text color=\"white\">\n {provider.displayName.padEnd(provNameWidth + 2)}\n </Text>\n <Text color={statusColor}>\n {statusText.padEnd(provStatusWidth + 2)}\n </Text>\n {status.running && <Text color=\"gray\">{url}</Text>}\n </Box>\n );\n })}\n </Box>\n )}\n </Box>\n\n {/* Models */}\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text bold color=\"white\" underline>\n Models\n </Text>\n\n {modelsLoading ? (\n <Box marginTop={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Discovering models...</Text>\n </Box>\n ) : models.length === 0 && unavailableSynced.length === 0 && modelWarnings.length === 0 ? (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"yellow\">No models found.</Text>\n <Text color=\"gray\">\n Download models using your provider (e.g., ollama pull llama3.2)\n </Text>\n </Box>\n ) : (\n <Box flexDirection=\"column\" marginTop={1}>\n {models.map((model) => {\n const cap = getCapabilityLabel(model.capability);\n const isSynced = syncedNames.has(model.name);\n const displayProvider =\n providers.find((p) => p.provider.name === model.provider)\n ?.provider.displayName ?? model.provider;\n const workflowCount = getWorkflowCount(model);\n const workflowSuffix = workflowCount !== null\n ? ` (${workflowCount} workflow${workflowCount !== 1 ? 's' : ''}, ${isSynced ? workflowCount : 0} synced)`\n : '';\n return (\n <Box key={`${model.provider}:${model.name}`}>\n <Text color={isSynced ? 'green' : 'gray'}>\n {isSynced ? '\\u25CF' : '\\u25CB'}\n </Text>\n <Text color=\"white\">{` ${model.name}`}</Text>\n {workflowSuffix && <Text color=\"gray\">{workflowSuffix}</Text>}\n <Text color=\"gray\">{' - '}</Text>\n <Text color=\"gray\">{displayProvider}</Text>\n <Text color=\"gray\">{' - '}</Text>\n <Text color={cap.color}>{cap.label}</Text>\n </Box>\n );\n })}\n {modelWarnings.map((warning) => {\n const displayProvider =\n providers.find((p) => p.provider.name === warning.provider)\n ?.provider.displayName ?? warning.provider;\n return (\n <Box key={`${warning.provider}:${warning.name}`}>\n <Text color=\"gray\">{'\\u25CB'}</Text>\n <Text color=\"white\">{` ${warning.name}`}</Text>\n <Text color=\"gray\">{' - '}</Text>\n <Text color=\"gray\">{displayProvider}</Text>\n <Text color=\"gray\">{' - '}</Text>\n <Text color=\"yellow\">{warning.statusHint}</Text>\n </Box>\n );\n })}\n\n {unavailableSynced.length > 0 && (\n <Box flexDirection=\"column\" marginTop={models.length > 0 ? 1 : 0}>\n <Text color=\"gray\">\n Synced but not currently available:\n </Text>\n {unavailableSynced.map((name) => (\n <Box key={name}>\n <Text color=\"gray\">{'\\u25CB'}</Text>\n <Text color=\"gray\">{` ${name}`}</Text>\n </Box>\n ))}\n </Box>\n )}\n </Box>\n )}\n </Box>\n\n {/* Request log */}\n <RequestLog\n requests={requests}\n maxVisible={maxVisible}\n hasModels={models.length > 0}\n />\n\n {/* Bottom: Navigation menu pane */}\n <NavigationMenu items={menuItems} onSelect={onNavigate} />\n </Box>\n );\n}\n","import React from 'react';\nimport { Box, Text, useStdout } from 'ink';\nimport Spinner from 'ink-spinner';\nimport type { RequestLogEntry } from '../types';\n\ninterface RequestLogProps {\n requests: RequestLogEntry[];\n maxVisible?: number;\n hasModels?: boolean;\n}\n\nfunction formatTime(timestamp: number): string {\n const date = new Date(timestamp);\n return date.toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n });\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nfunction getRequestTypeLabel(type: string): { label: string; color: string } {\n switch (type) {\n case 'llm_chat':\n return { label: 'text', color: 'gray' };\n case 'image_generation':\n return { label: 'image', color: 'gray' };\n case 'video_generation':\n return { label: 'video', color: 'gray' };\n default:\n return { label: type, color: 'gray' };\n }\n}\n\nfunction snippetLine(content: string, maxWidth: number): string {\n // Collapse whitespace/newlines into single spaces\n const flat = content.replace(/\\s+/g, ' ').trim();\n if (flat.length <= maxWidth) return flat;\n return '\\u2026' + flat.slice(-(maxWidth - 1));\n}\n\nfunction RequestItem({ request, width }: { request: RequestLogEntry; width: number }) {\n const time = formatTime(request.startTime);\n const typeLabel = getRequestTypeLabel(request.requestType);\n // indent for snippet: status(1) + space(1) + padding for alignment\n const snippetIndent = ' ';\n const snippetWidth = width - snippetIndent.length - 2; // 2 for paddingX\n\n if (request.status === 'processing') {\n const elapsed = Date.now() - request.startTime;\n const snippet = request.content && request.requestType === 'llm_chat'\n ? snippetLine(request.content, snippetWidth)\n : null;\n const stepProgress = request.step !== undefined && request.totalSteps\n ? `Step ${request.step}/${request.totalSteps}`\n : null;\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text color=\"gray\">{' '}{time} </Text>\n <Text color=\"white\">{request.modelId}</Text>\n <Text color=\"gray\"> </Text>\n <Text color={typeLabel.color}>{typeLabel.label}</Text>\n <Text color=\"gray\"> {formatDuration(elapsed)}...</Text>\n </Box>\n {snippet && (\n <Text color=\"gray\" wrap=\"truncate-end\">\n {snippetIndent}{snippet}\n </Text>\n )}\n {stepProgress && (\n <Text color=\"gray\">\n {snippetIndent}{stepProgress}\n </Text>\n )}\n </Box>\n );\n }\n\n if (request.status === 'completed') {\n const duration = request.duration ? formatDuration(request.duration) : '';\n let resultInfo = '';\n if (request.result?.chars) {\n resultInfo = ` \\u00B7 ${request.result.chars} chars`;\n } else if (request.result?.imageSize) {\n resultInfo = ` \\u00B7 ${Math.round(request.result.imageSize / 1024)}KB`;\n } else if (request.result?.videoSize) {\n resultInfo = ` \\u00B7 ${Math.round(request.result.videoSize / 1024 / 1024)}MB`;\n }\n\n const snippet = request.content && request.requestType === 'llm_chat'\n ? snippetLine(request.content, snippetWidth)\n : null;\n\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color=\"green\">{'\\u2713'}</Text>\n <Text color=\"gray\">{' '}{time} </Text>\n <Text color=\"white\">{request.modelId}</Text>\n <Text color=\"gray\"> </Text>\n <Text color={typeLabel.color}>{typeLabel.label}</Text>\n <Text color=\"gray\"> {duration}{resultInfo}</Text>\n </Box>\n {snippet && (\n <Text color=\"gray\" wrap=\"truncate-end\">\n {snippetIndent}{snippet}\n </Text>\n )}\n </Box>\n );\n }\n\n // Failed\n return (\n <Box flexDirection=\"column\">\n <Box>\n <Text color=\"red\">{'\\u25CF'}</Text>\n <Text color=\"gray\">{' '}{time} </Text>\n <Text color=\"white\">{request.modelId}</Text>\n <Text color=\"gray\"> </Text>\n <Text color={typeLabel.color}>{typeLabel.label}</Text>\n <Text color=\"red\"> {request.error || 'Failed'}</Text>\n </Box>\n </Box>\n );\n}\n\nexport function RequestLog({ requests, maxVisible = 8, hasModels = true }: RequestLogProps) {\n const { stdout } = useStdout();\n const width = stdout?.columns ?? 80;\n\n // Get the most recent requests, with active ones always shown\n const activeRequests = requests.filter((r) => r.status === 'processing');\n const completedRequests = requests.filter((r) => r.status !== 'processing');\n\n // Requests with a snippet or step progress take 2 lines, others take 1\n const itemLines = (r: RequestLogEntry) => {\n if (r.requestType === 'llm_chat' && r.content) return 2;\n if (r.status === 'processing' && r.step !== undefined) return 2;\n return 1;\n };\n\n let completedToShow: RequestLogEntry[] = [];\n let linesUsed = activeRequests.reduce((sum, r) => sum + itemLines(r), 0);\n for (let i = completedRequests.length - 1; i >= 0 && linesUsed < maxVisible; i--) {\n const r = completedRequests[i]!;\n const lines = itemLines(r);\n if (linesUsed + lines <= maxVisible) {\n completedToShow.unshift(r);\n linesUsed += lines;\n } else {\n break;\n }\n }\n\n const visibleRequests = [...completedToShow, ...activeRequests];\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n width=\"100%\"\n paddingX={1}\n marginTop={1}\n >\n <Box>\n <Text bold underline color=\"white\">\n Generation Requests\n </Text>\n {activeRequests.length > 0 && (\n <Text color=\"cyan\"> ({activeRequests.length} active)</Text>\n )}\n </Box>\n\n {requests.length === 0 ? (\n <Box marginTop={1} flexDirection=\"column\">\n <Text color=\"gray\">{hasModels\n ? 'Tunnel is live — requests will appear here when models are used in MindStudio'\n : 'Start a model to begin receiving generation requests.'\n }</Text>\n </Box>\n ) : (\n <Box flexDirection=\"column\" marginTop={1}>\n {visibleRequests.map((request) => (\n <RequestItem key={request.id} request={request} width={width} />\n ))}\n </Box>\n )}\n </Box>\n );\n}\n","import { useState, useEffect, useCallback } from 'react';\nimport {\n detectAllProviderStatuses,\n type Provider,\n type ProviderSetupStatus,\n} from '../../providers';\n\ninterface ProviderWithStatus {\n provider: Provider;\n status: ProviderSetupStatus;\n}\n\ninterface UseSetupProvidersResult {\n providers: ProviderWithStatus[];\n loading: boolean;\n refresh: () => Promise<void>;\n}\n\nexport function useSetupProviders(): UseSetupProvidersResult {\n const [providers, setProviders] = useState<ProviderWithStatus[]>([]);\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n setLoading(true);\n const statuses = await detectAllProviderStatuses();\n setProviders(statuses);\n setLoading(false);\n }, []);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n return { providers, loading, refresh };\n}\n","import React, { useEffect } from 'react';\nimport { Box, Text } from 'ink';\nimport Spinner from 'ink-spinner';\nimport { useSync } from '../hooks/useRegister';\n\nexport function SyncPage() {\n const { status, progress, syncedModels, error, startSync, cancel } =\n useSync();\n\n // Start sync on mount\n useEffect(() => {\n startSync();\n return () => cancel();\n }, []);\n\n if (status === 'idle') {\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n <Box marginTop={1}>\n <Text color=\"gray\">Starting model sync...</Text>\n </Box>\n </Box>\n );\n }\n\n if (status === 'error') {\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n <Box marginTop={1}>\n <Text color=\"red\">Sync failed: {error}</Text>\n </Box>\n </Box>\n );\n }\n\n if (status === 'discovering') {\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n <Box marginTop={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Discovering local models...</Text>\n </Box>\n </Box>\n );\n }\n\n if (status === 'syncing') {\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n <Box marginTop={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text>\n {' '}\n Syncing {progress.current}/{progress.total} models...\n </Text>\n </Box>\n </Box>\n );\n }\n\n // Done\n const newModels = syncedModels.filter((m) => m.isNew);\n const resyncedModels = syncedModels.filter((m) => !m.isNew);\n\n return (\n <Box flexDirection=\"column\" marginTop={1} paddingX={1}>\n {newModels.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"green\">\n Synced {newModels.length} new model\n {newModels.length !== 1 ? 's' : ''}:\n </Text>\n {newModels.map((m) => (\n <Box key={m.name}>\n <Text color=\"green\">{' ✓ '}</Text>\n <Text>{m.name} </Text>\n <Text color=\"gray\">[{m.provider}]</Text>\n </Box>\n ))}\n </Box>\n )}\n\n {resyncedModels.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <Text color=\"green\">\n Resynced {resyncedModels.length} existing model\n {resyncedModels.length !== 1 ? 's' : ''}:\n </Text>\n {resyncedModels.map((m) => (\n <Box key={m.name}>\n <Text color=\"green\">{' ✓ '}</Text>\n <Text>{m.name} </Text>\n <Text color=\"gray\">[{m.provider}]</Text>\n </Box>\n ))}\n </Box>\n )}\n </Box>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport { getSyncedModels, syncLocalModel, updateLocalModel } from '../../api';\nimport { discoverAllModelsWithParameters } from '../../providers';\n\ntype SyncStatus = 'idle' | 'discovering' | 'syncing' | 'done' | 'error';\n\ninterface SyncProgress {\n current: number;\n total: number;\n}\n\ninterface SyncedModel {\n name: string;\n provider: string;\n capability: string;\n isNew: boolean;\n}\n\ninterface UseSyncResult {\n status: SyncStatus;\n progress: SyncProgress;\n syncedModels: SyncedModel[];\n error: string | null;\n startSync: () => void;\n cancel: () => void;\n}\n\nconst MODEL_TYPE_MAP = {\n text: 'llm_chat',\n image: 'image_generation',\n video: 'video_generation',\n} as const;\n\nexport function useSync(): UseSyncResult {\n const [status, setStatus] = useState<SyncStatus>('idle');\n const [progress, setProgress] = useState<SyncProgress>({\n current: 0,\n total: 0,\n });\n const [syncedModels, setSyncedModels] = useState<SyncedModel[]>(\n [],\n );\n const [error, setError] = useState<string | null>(null);\n const cancelledRef = useRef(false);\n\n useEffect(() => {\n return () => {\n cancelledRef.current = true;\n };\n }, []);\n\n const cancel = useCallback(() => {\n cancelledRef.current = true;\n setStatus('idle');\n }, []);\n\n const startSync = useCallback(() => {\n cancelledRef.current = false;\n setError(null);\n setSyncedModels([]);\n\n const run = async () => {\n try {\n setStatus('discovering');\n\n const localModels = await discoverAllModelsWithParameters();\n if (cancelledRef.current) return;\n\n if (localModels.length === 0) {\n setError('No local models found.');\n setStatus('error');\n return;\n }\n\n const existingSynced = await getSyncedModels();\n if (cancelledRef.current) return;\n\n // Map remote model names to their IDs for updates\n const remoteByName = new Map(\n existingSynced.map((m) => [m.name, m.id]),\n );\n\n setStatus('syncing');\n setProgress({ current: 0, total: localModels.length });\n\n for (let i = 0; i < localModels.length; i++) {\n if (cancelledRef.current) return;\n\n const model = localModels[i]!;\n const modelType =\n MODEL_TYPE_MAP[model.capability as keyof typeof MODEL_TYPE_MAP];\n const existingId = remoteByName.get(model.name);\n\n if (existingId) {\n await updateLocalModel({\n modelId: existingId,\n modelName: model.name,\n provider: model.provider,\n modelType,\n parameters: model.parameters,\n });\n } else {\n await syncLocalModel({\n modelName: model.name,\n provider: model.provider,\n modelType,\n parameters: model.parameters,\n });\n }\n\n setProgress({ current: i + 1, total: localModels.length });\n }\n\n if (cancelledRef.current) return;\n\n const finalModels: SyncedModel[] = localModels.map((m) => ({\n name: m.name,\n provider: m.provider,\n capability: m.capability,\n isNew: !remoteByName.has(m.name),\n }));\n\n setSyncedModels(finalModels);\n setStatus('done');\n } catch (err) {\n if (!cancelledRef.current) {\n setError(err instanceof Error ? err.message : 'Sync failed');\n setStatus('error');\n }\n }\n };\n\n run();\n }, []);\n\n return {\n status,\n progress,\n syncedModels,\n error,\n startSync,\n cancel,\n };\n}\n","import React, { useState, useMemo, useEffect } from 'react';\nimport { Box, Text, useInput, useStdout } from 'ink';\nimport Spinner from 'ink-spinner';\nimport { renderMarkdown } from '../components/MarkdownText';\nimport { useSetupProviders } from '../hooks/useSetupProviders';\nimport type { Provider } from '../../providers/types';\n\ninterface SetupPageProps {\n onBack: () => void;\n}\n\nfunction ProviderDetailView({\n provider,\n onBack,\n}: {\n provider: Provider;\n onBack: () => void;\n}) {\n const [scrollOffset, setScrollOffset] = useState(0);\n const { stdout } = useStdout();\n const termHeight = (stdout?.rows ?? 24) - 4; // matches App's height calc\n const headerHeight = 14; // border(2) + padding(2) + logo(9) + 1\n const footerLines = 6; // border-top(1) + margin(1) + \"Actions\"(1) + \"Back\"(1) + margin(1) + hint(1)\n const contentPadding = 2; // paddingY={1}\n const viewHeight = termHeight - headerHeight - footerLines - contentPadding;\n const contentWidth = (stdout?.columns ?? 80) - 4; // 2 padding + 1 scrollbar + 1 margin\n\n const renderedLines = useMemo(() => {\n const rendered = renderMarkdown(provider.readme, contentWidth);\n return rendered.split('\\n');\n }, [provider.readme, contentWidth]);\n\n const maxScroll = Math.max(0, renderedLines.length - viewHeight);\n\n useInput((input, key) => {\n if (input === 'q' || key.escape || key.return) {\n onBack();\n return;\n }\n if (key.upArrow) {\n setScrollOffset((prev) => Math.max(0, prev - 1));\n } else if (key.downArrow) {\n setScrollOffset((prev) => Math.min(maxScroll, prev + 1));\n }\n });\n\n const visibleContent = renderedLines\n .slice(scrollOffset, scrollOffset + viewHeight)\n .join('\\n');\n\n const scrollbar = useMemo(() => {\n if (maxScroll === 0) return null;\n const thumbSize = Math.max(\n 1,\n Math.round((viewHeight / renderedLines.length) * viewHeight),\n );\n const thumbPos = Math.round(\n (scrollOffset / maxScroll) * (viewHeight - thumbSize),\n );\n\n return Array.from(\n { length: viewHeight },\n (_, i) => i >= thumbPos && i < thumbPos + thumbSize,\n );\n }, [scrollOffset, maxScroll, viewHeight, renderedLines.length]);\n\n return (\n <Box flexDirection=\"column\">\n <Box height={viewHeight}>\n <Box\n flexDirection=\"column\"\n paddingX={1}\n paddingY={1}\n flexGrow={1}\n overflow=\"hidden\"\n >\n <Text>{visibleContent}</Text>\n </Box>\n {scrollbar && (\n <Box flexDirection=\"column\">\n {scrollbar.map((isThumb, i) => (\n <Text\n key={i}\n color={isThumb ? 'cyan' : 'gray'}\n dimColor={!isThumb}\n >\n {isThumb ? '\\u2503' : '\\u2502'}\n </Text>\n ))}\n </Box>\n )}\n </Box>\n\n <Box\n flexDirection=\"column\"\n paddingX={1}\n borderStyle=\"single\"\n borderTop\n borderBottom={false}\n borderLeft={false}\n borderRight={false}\n borderColor=\"gray\"\n >\n <Box marginTop={1}>\n <Text color=\"gray\">\n Actions\n </Text>\n </Box>\n <Box>\n <Text color=\"cyan\" bold>\n {'\\u276F'} Back\n </Text>\n <Text color=\"gray\"> - Return to providers</Text>\n </Box>\n <Box marginTop={1} height={1}>\n <Text color=\"gray\" wrap=\"truncate-end\">\n Up/Down Scroll {'\\u2022'} Enter/q/Esc Back\n {maxScroll > 0 &&\n ` \\u2022 ${Math.round((scrollOffset / maxScroll) * 100)}%`}\n </Text>\n </Box>\n </Box>\n </Box>\n );\n}\n\nexport function SetupPage({ onBack }: SetupPageProps) {\n const { providers, loading } = useSetupProviders();\n const [selectedProvider, setSelectedProvider] = useState<string | null>(null);\n const running = useMemo(\n () => providers.filter((p) => p.status.running),\n [providers],\n );\n const installed = useMemo(\n () => providers.filter((p) => p.status.installed && !p.status.running),\n [providers],\n );\n const notInstalled = useMemo(\n () => providers.filter((p) => !p.status.installed),\n [providers],\n );\n const allProviders = useMemo(\n () => [...running, ...installed, ...notInstalled],\n [running, installed, notInstalled],\n );\n\n const totalItems = allProviders.length + 1; // +1 for Back\n const backIndex = allProviders.length;\n const [cursorIndex, setCursorIndex] = useState(backIndex);\n\n useEffect(() => {\n setCursorIndex(backIndex);\n }, [backIndex]);\n\n useInput((input, key) => {\n if (selectedProvider) return;\n if (input === 'q' || key.escape) {\n onBack();\n return;\n }\n if (key.upArrow) {\n setCursorIndex((prev) => Math.max(0, prev - 1));\n } else if (key.downArrow) {\n setCursorIndex((prev) => Math.min(totalItems - 1, prev + 1));\n } else if (key.return) {\n if (cursorIndex === backIndex) {\n onBack();\n } else if (allProviders[cursorIndex]) {\n setSelectedProvider(allProviders[cursorIndex]!.provider.name);\n }\n }\n });\n\n if (selectedProvider) {\n const found = providers.find((p) => p.provider.name === selectedProvider);\n if (found) {\n return (\n <ProviderDetailView\n provider={found.provider}\n onBack={() => setSelectedProvider(null)}\n />\n );\n }\n }\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text bold color=\"white\" underline>\n Manage Providers\n </Text>\n <Text color=\"gray\">Select a provider to view its setup guide.</Text>\n\n {loading ? (\n <Box marginTop={1}>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text> Detecting providers...</Text>\n </Box>\n ) : (\n <Box flexDirection=\"column\" marginTop={1}>\n {running.length > 0 && (\n <>\n <Text bold color=\"green\">\n Running\n </Text>\n {running.map(({ provider }, i) => {\n const index = i;\n const isSelected = index === cursorIndex;\n return (\n <Box\n key={provider.name}\n flexDirection=\"column\"\n marginTop={i > 0 ? 1 : 0}\n >\n <Box>\n <Text\n color={isSelected ? 'cyan' : 'white'}\n bold={isSelected}\n >\n {isSelected ? '\\u276F' : ' '} {'\\u25CF'}{' '}\n {provider.displayName}\n </Text>\n </Box>\n <Text color=\"gray\" wrap=\"wrap\">\n {' '}\n {provider.description}\n </Text>\n </Box>\n );\n })}\n </>\n )}\n {installed.length > 0 && (\n <Box\n flexDirection=\"column\"\n marginTop={running.length > 0 ? 1 : 0}\n >\n <Text bold color=\"yellow\">\n Installed\n </Text>\n {installed.map(({ provider, status }, i) => {\n const index = running.length + i;\n const isSelected = index === cursorIndex;\n return (\n <Box\n key={provider.name}\n flexDirection=\"column\"\n marginTop={i > 0 ? 1 : 0}\n >\n <Box>\n <Text\n color={isSelected ? 'cyan' : 'white'}\n bold={isSelected}\n >\n {isSelected ? '\\u276F' : ' '} {'\\u25CB'}{' '}\n {provider.displayName}\n </Text>\n </Box>\n <Text color=\"gray\" wrap=\"wrap\">\n {' '}\n {provider.description}\n </Text>\n </Box>\n );\n })}\n </Box>\n )}\n {notInstalled.length > 0 && (\n <Box\n flexDirection=\"column\"\n marginTop={running.length > 0 || installed.length > 0 ? 1 : 0}\n >\n <Text bold color=\"gray\">\n Not Installed\n </Text>\n {notInstalled.map(({ provider }, i) => {\n const index = running.length + installed.length + i;\n const isSelected = index === cursorIndex;\n return (\n <Box\n key={provider.name}\n flexDirection=\"column\"\n marginTop={i > 0 ? 1 : 0}\n >\n <Box>\n <Text\n color={isSelected ? 'cyan' : 'white'}\n bold={isSelected}\n >\n {isSelected ? '\\u276F' : ' '} {provider.displayName}\n </Text>\n </Box>\n <Text color=\"gray\" wrap=\"wrap\">\n {' '}\n {provider.description}\n </Text>\n </Box>\n );\n })}\n </Box>\n )}\n\n {/* Back option */}\n <Box marginTop={1}>\n <Text\n color={cursorIndex === backIndex ? 'cyan' : 'white'}\n bold={cursorIndex === backIndex}\n >\n {cursorIndex === backIndex ? '\\u276F' : ' '} Back\n </Text>\n </Box>\n </Box>\n )}\n\n <Box marginTop={1}>\n <Text color=\"gray\">\n Up/Down Navigate {'\\u2022'} Enter Select {'\\u2022'} q/Esc Back\n </Text>\n </Box>\n </Box>\n </Box>\n );\n}\n","import React, { useMemo } from 'react';\nimport { Text, useStdout } from 'ink';\nimport chalk from 'chalk';\nimport { marked } from 'marked';\nimport { markedTerminal } from 'marked-terminal';\n\nconst codeStyle = chalk.cyan;\nconst identity = (s: string) => s;\n\ninterface MarkdownTextProps {\n content: string;\n width?: number;\n}\n\n/**\n * Render markdown to an ANSI string.\n * Each line is self-contained (no cross-line ANSI escapes).\n */\nexport function renderMarkdown(content: string, width: number): string {\n marked.use(\n markedTerminal({\n width,\n codespan: codeStyle,\n link: identity,\n href: identity,\n }) as any,\n );\n marked.use({\n renderer: {\n code({ text }: { text: string }) {\n const lines = text\n .trim()\n .split('\\n')\n .map((l) => ' ' + codeStyle(l))\n .join('\\n');\n return lines + '\\n\\n';\n },\n link({ href, text }: { href: string; text: string }) {\n if (text && text !== href) {\n return `${text} (${href})`;\n }\n return href;\n },\n },\n });\n return (marked.parse(content) as string).trimEnd();\n}\n\nexport function MarkdownText({ content, width: widthProp }: MarkdownTextProps) {\n const { stdout } = useStdout();\n const width = widthProp ?? (stdout?.columns ?? 80) - 4;\n\n const rendered = useMemo(\n () => renderMarkdown(content, width),\n [content, width],\n );\n\n return <Text wrap=\"wrap\">{rendered}</Text>;\n}\n","import React, { useEffect, useCallback, useState, useMemo } from 'react';\nimport { Box, Text, useInput } from 'ink';\nimport Spinner from 'ink-spinner';\nimport chalk from 'chalk';\nimport { useAuth } from '../hooks/useAuth';\nimport { LogoString } from '../components/Header';\n\ninterface OnboardingPageProps {\n onComplete: () => void;\n}\n\nconst SHIMMER_SPEED = 35;\n\nfunction useShimmerLogo(): string {\n const [frame, setFrame] = useState(0);\n\n const lines = useMemo(() => LogoString.split('\\n'), []);\n const totalChars = useMemo(() => {\n let count = 0;\n for (const line of lines) {\n for (const ch of line) {\n if (ch !== ' ' && ch !== '\\t') count++;\n }\n }\n return count;\n }, [lines]);\n\n // Full cycle: fade in + hold + fade out + pause\n const cycleLength = totalChars + 40;\n\n useEffect(() => {\n const interval = setInterval(() => {\n setFrame((f) => (f + 1) % cycleLength);\n }, SHIMMER_SPEED);\n return () => clearInterval(interval);\n }, [cycleLength]);\n\n return useMemo(() => {\n // Map frame to a wave that fades the whole logo in and out\n // Phase 0..totalChars: characters light up one by one (sweep in)\n // Phase totalChars..totalChars+20: hold bright\n // Phase totalChars+20..cycleLength: all fade out together\n const sweepPos = frame;\n const holdEnd = totalChars + 20;\n\n let charIdx = 0;\n return lines\n .map((line) => {\n let result = '';\n for (let i = 0; i < line.length; i++) {\n const ch = line[i]!;\n if (ch === ' ' || ch === '\\t') {\n result += ch;\n continue;\n }\n\n let brightness: number;\n if (sweepPos <= totalChars) {\n // Sweep phase: characters light up as the wave passes\n const lag = charIdx;\n const t = sweepPos - lag;\n brightness = t <= 0 ? 0.1 : Math.min(1, t / 8);\n } else if (sweepPos <= holdEnd) {\n // Hold phase: everything bright\n brightness = 1;\n } else {\n // Fade out phase\n const fadeProgress = (sweepPos - holdEnd) / (cycleLength - holdEnd);\n brightness = Math.max(0.1, 1 - fadeProgress);\n }\n\n if (brightness >= 0.9) {\n result += chalk.cyanBright.bold(ch);\n } else if (brightness >= 0.6) {\n result += chalk.cyan(ch);\n } else if (brightness >= 0.3) {\n result += chalk.rgb(0, 100, 120)(ch);\n } else {\n result += chalk.rgb(0, 50, 60)(ch);\n }\n\n charIdx++;\n }\n return result;\n })\n .join('\\n');\n }, [frame, lines, totalChars, cycleLength]);\n}\n\nexport function OnboardingPage({ onComplete }: OnboardingPageProps) {\n const {\n status: authStatus,\n authUrl,\n timeRemaining,\n startAuth,\n cancel: cancelAuth,\n } = useAuth();\n const shimmerLogo = useShimmerLogo();\n\n // Auto-navigate to dashboard on success\n useEffect(() => {\n if (authStatus === 'success') {\n const timer = setTimeout(() => onComplete(), 1500);\n return () => clearTimeout(timer);\n }\n }, [authStatus, onComplete]);\n\n // Clean up auth on unmount\n useEffect(() => {\n return () => cancelAuth();\n }, []);\n\n const handleAction = useCallback(() => {\n cancelAuth();\n startAuth();\n }, [cancelAuth, startAuth]);\n\n const canAct =\n authStatus === 'idle' ||\n authStatus === 'expired' ||\n authStatus === 'timeout';\n\n useInput((_input, key) => {\n if (canAct && !key.ctrl) {\n handleAction();\n }\n });\n\n return (\n <Box flexDirection=\"column\" flexGrow={1}>\n <Box flexGrow={1} />\n\n <Box flexDirection=\"column\" alignItems=\"center\">\n <Text>{shimmerLogo}</Text>\n\n <Box flexDirection=\"column\" alignItems=\"center\" marginTop={2}>\n <Text bold color=\"white\">\n MindStudio Local Tunnel\n </Text>\n </Box>\n\n <Box flexDirection=\"column\" alignItems=\"center\">\n {authStatus === 'idle' && (\n <>\n <Text color=\"gray\">\n Connect your MindStudio account to get started.\n </Text>\n <Box marginTop={1}>\n <Text color=\"cyan\" bold>\n Press any key to Connect Account\n </Text>\n </Box>\n </>\n )}\n\n {(authStatus === 'expired' || authStatus === 'timeout') && (\n <>\n <Text color=\"red\">\n {authStatus === 'expired'\n ? 'Authorization expired.'\n : 'Authorization timed out.'}\n </Text>\n <Box marginTop={1}>\n <Text color=\"cyan\" bold>\n Press any key to Try Again\n </Text>\n </Box>\n </>\n )}\n\n {authStatus === 'waiting' && (\n <>\n <Box>\n <Text color=\"cyan\">\n <Spinner type=\"dots\" />\n </Text>\n <Text>\n {' '}\n Waiting for browser authorization... ({timeRemaining}s\n remaining)\n </Text>\n </Box>\n {authUrl && (\n <Box flexDirection=\"column\" alignItems=\"center\" marginTop={1}>\n <Text color=\"gray\">If browser didn't open, visit:</Text>\n <Text color=\"cyan\">{authUrl}</Text>\n </Box>\n )}\n </>\n )}\n\n {authStatus === 'success' && (\n <Text color=\"green\">{'\\u2713'} Authenticated!</Text>\n )}\n </Box>\n </Box>\n\n <Box flexGrow={1} />\n </Box>\n );\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport open from 'open';\nimport { requestDeviceAuth, pollDeviceAuth } from '../../api';\nimport { setApiKey } from '../../config';\n\ntype AuthStatus = 'idle' | 'waiting' | 'success' | 'expired' | 'timeout';\n\ninterface UseAuthResult {\n status: AuthStatus;\n authUrl: string | null;\n timeRemaining: number;\n startAuth: () => void;\n cancel: () => void;\n}\n\nconst POLL_INTERVAL = 2000;\nconst MAX_ATTEMPTS = 30;\n\nexport function useAuth(): UseAuthResult {\n const [status, setStatus] = useState<AuthStatus>('idle');\n const [authUrl, setAuthUrl] = useState<string | null>(null);\n const [timeRemaining, setTimeRemaining] = useState(0);\n const cancelledRef = useRef(false);\n const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n // Clean up timer on unmount\n useEffect(() => {\n return () => {\n cancelledRef.current = true;\n if (timerRef.current) clearInterval(timerRef.current);\n };\n }, []);\n\n const cancel = useCallback(() => {\n cancelledRef.current = true;\n if (timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n setStatus('idle');\n setAuthUrl(null);\n setTimeRemaining(0);\n }, []);\n\n const startAuth = useCallback(() => {\n cancelledRef.current = false;\n\n const run = async () => {\n try {\n const { url, token } = await requestDeviceAuth();\n if (cancelledRef.current) return;\n\n setAuthUrl(url);\n setStatus('waiting');\n\n const totalTime = (MAX_ATTEMPTS * POLL_INTERVAL) / 1000;\n setTimeRemaining(totalTime);\n\n // Countdown timer\n timerRef.current = setInterval(() => {\n setTimeRemaining((prev) => {\n const next = prev - 1;\n if (next <= 0 && timerRef.current) {\n clearInterval(timerRef.current);\n timerRef.current = null;\n }\n return Math.max(0, next);\n });\n }, 1000);\n\n await open(url);\n\n // Poll loop\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n if (cancelledRef.current) return;\n\n const result = await pollDeviceAuth(token);\n\n if (result.status === 'completed' && result.apiKey) {\n if (timerRef.current) clearInterval(timerRef.current);\n setApiKey(result.apiKey);\n setStatus('success');\n return;\n }\n\n if (result.status === 'expired') {\n if (timerRef.current) clearInterval(timerRef.current);\n setStatus('expired');\n return;\n }\n }\n\n if (!cancelledRef.current) {\n setStatus('timeout');\n }\n } catch {\n if (!cancelledRef.current) {\n setStatus('expired');\n }\n }\n };\n\n run();\n }, []);\n\n return {\n status,\n authUrl,\n timeRemaining,\n startAuth,\n cancel,\n };\n}\n","import { createRequire } from 'node:module';\n\nconst require = createRequire(import.meta.url);\nconst pkg = require('../package.json') as { version: string };\n\nexport function getCurrentVersion(): string {\n return pkg.version;\n}\n\nexport async function fetchLatestVersion(): Promise<string | null> {\n try {\n const res = await fetch(\n 'https://registry.npmjs.org/@mindstudio-ai/local-model-tunnel/latest',\n { signal: AbortSignal.timeout(5000) },\n );\n if (!res.ok) return null;\n const data = (await res.json()) as { version?: string };\n return data.version ?? null;\n } catch {\n return null;\n }\n}\n\nexport function isNewerVersion(current: string, latest: string): boolean {\n const currentParts = current.split('.').map(Number);\n const latestParts = latest.split('.').map(Number);\n for (let i = 0; i < Math.max(currentParts.length, latestParts.length); i++) {\n const c = currentParts[i] ?? 0;\n const l = latestParts[i] ?? 0;\n if (l > c) return true;\n if (l < c) return false;\n }\n return false;\n}\n\nexport async function checkForUpdate(): Promise<{\n currentVersion: string;\n latestVersion: string;\n} | null> {\n const currentVersion = getCurrentVersion();\n const latestVersion = await fetchLatestVersion();\n if (!latestVersion) return null;\n if (!isNewerVersion(currentVersion, latestVersion)) return null;\n return { currentVersion, latestVersion };\n}\n","import React from 'react';\nimport { Box, Text, useInput } from 'ink';\n\ninterface UpdatePromptProps {\n currentVersion: string;\n latestVersion: string;\n onChoice: (shouldUpdate: boolean) => void;\n}\n\nexport function UpdatePrompt({\n currentVersion,\n latestVersion,\n onChoice,\n}: UpdatePromptProps) {\n useInput((input) => {\n if (input.toLowerCase() === 'y') {\n onChoice(true);\n } else {\n onChoice(false);\n }\n });\n\n return (\n <Box flexDirection=\"column\" paddingY={1} paddingX={2}>\n <Text>\n <Text color=\"yellow\" bold>\n Update available:\n </Text>\n <Text>\n {' '}\n v{currentVersion} {'\\u2192'} v{latestVersion}\n </Text>\n </Text>\n <Box marginTop={1}>\n <Text>\n Press <Text bold color=\"cyan\">y</Text> to update, any other key to\n skip\n </Text>\n </Box>\n </Box>\n );\n}\n"],"mappings":"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","names":["useEffect","useCallback","useState","Box","useStdout","require","Box","Text","jsx","jsxs","useState","useEffect","useState","useEffect","useState","useEffect","useCallback","useState","useCallback","useEffect","useState","useEffect","useCallback","useState","useCallback","useEffect","useState","useEffect","useCallback","useState","useEffect","useCallback","useState","useEffect","useCallback","useState","useCallback","useEffect","Box","Text","useStdout","Spinner","Box","Text","jsx","jsxs","useState","useEffect","useCallback","useState","useCallback","useEffect","jsx","jsxs","useStdout","Box","Text","Spinner","useEffect","Box","Text","Spinner","useState","useCallback","useRef","useEffect","useState","useRef","useEffect","useCallback","jsx","jsxs","useEffect","Box","Text","Spinner","useState","useMemo","useEffect","Box","Text","useInput","useStdout","Spinner","useMemo","Text","useStdout","jsx","Fragment","jsx","jsxs","useState","useStdout","useMemo","useInput","Box","Text","useEffect","Spinner","useEffect","useCallback","useState","useMemo","Box","Text","useInput","Spinner","chalk","useState","useCallback","useRef","useEffect","useState","useRef","useEffect","useCallback","Fragment","jsx","jsxs","useState","useMemo","useEffect","chalk","useCallback","useInput","Box","Text","Spinner","Fragment","jsx","jsxs","useStdout","useState","useEffect","useCallback","Box","createRequire","require","pkg","Box","Text","useInput","jsx","jsxs","jsx"]}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/config.ts","../src/api.ts","../src/providers/ollama/index.ts","../src/providers/utils.ts","../src/providers/ollama/readme.md","../src/providers/lmstudio/index.ts","../src/providers/lmstudio/readme.md","../src/providers/stable-diffusion/index.ts","../src/providers/stable-diffusion/readme.md","../src/providers/comfyui/index.ts","../src/providers/comfyui/workflows/ltx-video.ts","../src/providers/comfyui/workflows/wan2.1.ts","../src/providers/comfyui/workflows/index.ts","../src/providers/comfyui/readme.md","../src/providers/index.ts","../src/events.ts","../src/runner.ts"],"sourcesContent":["import Conf from 'conf';\nimport os from 'node:os';\nimport path from 'node:path';\n\nexport type Environment = 'prod' | 'local';\n\ninterface EnvironmentConfig {\n apiKey?: string;\n apiBaseUrl: string;\n}\n\ninterface ConfigSchema {\n environment: Environment;\n providerBaseUrls: Record<string, string>;\n providerInstallPaths: Record<string, string>;\n environments: {\n prod: EnvironmentConfig;\n local: EnvironmentConfig;\n };\n}\n\nexport const config = new Conf<ConfigSchema>({\n projectName: 'mindstudio-local',\n cwd: path.join(os.homedir(), '.mindstudio-local-tunnel'),\n configName: 'config',\n defaults: {\n environment: 'prod',\n providerBaseUrls: {},\n providerInstallPaths: {},\n environments: {\n prod: {\n apiBaseUrl: 'https://api.mindstudio.ai',\n },\n local: {\n apiBaseUrl: 'http://localhost:3129',\n },\n },\n },\n});\n\n// Environment management\nexport function getEnvironment(): Environment {\n return config.get('environment');\n}\n\nexport function setEnvironment(env: Environment): void {\n config.set('environment', env);\n}\n\n// Get config for current environment\nfunction getEnvConfig(): EnvironmentConfig {\n const env = getEnvironment();\n return config.get(`environments.${env}`) as EnvironmentConfig;\n}\n\nfunction setEnvConfig(key: keyof EnvironmentConfig, value: string): void {\n const env = getEnvironment();\n config.set(`environments.${env}.${key}`, value);\n}\n\n// API Key (per environment)\nexport function getApiKey(): string | undefined {\n return getEnvConfig().apiKey;\n}\n\nexport function setApiKey(key: string): void {\n setEnvConfig('apiKey', key);\n}\n\nexport function clearApiKey(): void {\n const env = getEnvironment();\n config.delete(`environments.${env}.apiKey` as keyof ConfigSchema);\n}\n\n// API Base URL (per environment)\nexport function getApiBaseUrl(): string {\n return getEnvConfig().apiBaseUrl;\n}\n\nexport function setApiBaseUrl(url: string): void {\n setEnvConfig('apiBaseUrl', url);\n}\n\nexport function getConfigPath(): string {\n return config.path;\n}\n\n// Provider helpers\nexport function getProviderBaseUrl(name: string, defaultUrl: string): string {\n const urls = config.get('providerBaseUrls');\n return urls[name] ?? defaultUrl;\n}\n\nexport function getProviderInstallPath(name: string): string | undefined {\n const paths = config.get('providerInstallPaths');\n return paths[name];\n}\n\n// Get all environment info for display\nexport function getEnvironmentInfo(): {\n current: Environment;\n apiBaseUrl: string;\n hasApiKey: boolean;\n} {\n const env = getEnvironment();\n const envConfig = getEnvConfig();\n return {\n current: env,\n apiBaseUrl: envConfig.apiBaseUrl,\n hasApiKey: !!envConfig.apiKey,\n };\n}\n","import { getApiKey, getApiBaseUrl } from './config';\n\nexport interface LocalModelRequest {\n id: string;\n organizationId: string;\n modelId: string;\n requestType: 'llm_chat' | 'image_generation' | 'video_generation';\n payload: {\n messages?: Array<{ role: string; content: string }>;\n prompt?: string;\n temperature?: number;\n maxTokens?: number;\n config?: Record<string, unknown>;\n };\n createdAt: number;\n}\n\nfunction getHeaders(): Record<string, string> {\n const apiKey = getApiKey();\n if (!apiKey) {\n throw new Error('Not authenticated. Run: mindstudio-local auth');\n }\n\n return {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n };\n}\n\nexport async function pollForRequest(\n models: string[],\n): Promise<LocalModelRequest | null> {\n const baseUrl = getApiBaseUrl();\n const modelsParam = models.join(',');\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/poll?models=${encodeURIComponent(modelsParam)}`,\n {\n method: 'GET',\n headers: getHeaders(),\n },\n );\n\n if (response.status === 204) {\n return null;\n }\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Poll failed: ${response.status} ${error}`);\n }\n const data = (await response.json()) as { request: LocalModelRequest };\n return data.request;\n}\n\n/**\n * Progress update for text generation (streaming content)\n */\nexport async function submitProgress(\n requestId: string,\n content: string,\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/progress`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ content }),\n },\n );\n\n if (!response.ok) {\n console.warn(`Progress update failed: ${response.status}`);\n }\n}\n\n/**\n * Progress update for image/video generation (step-based)\n */\nexport async function submitGenerationProgress(\n requestId: string,\n step: number,\n totalSteps: number,\n preview?: string,\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/progress`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({\n type: 'generation',\n step,\n totalSteps,\n preview,\n }),\n },\n );\n\n if (!response.ok) {\n console.warn(`Generation progress update failed: ${response.status}`);\n }\n}\n\n/**\n * Result for text/chat completions\n */\nexport interface TextResult {\n content?: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/**\n * Result for image generation\n */\nexport interface ImageResult {\n /** Base64-encoded image data */\n imageBase64: string;\n /** MIME type (e.g., \"image/png\") */\n mimeType: string;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Result for video generation\n */\nexport interface VideoResult {\n /** Base64-encoded video data */\n videoBase64: string;\n /** MIME type (e.g., \"video/webp\", \"video/mp4\") */\n mimeType: string;\n /** Duration in seconds */\n duration?: number;\n /** Frames per second */\n fps?: number;\n /** Seed used for generation */\n seed?: number;\n}\n\n/**\n * Combined result type\n */\nexport type RequestResult = TextResult | ImageResult | VideoResult;\n\nexport async function submitResult(\n requestId: string,\n success: boolean,\n result?: RequestResult,\n error?: string,\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(\n `${baseUrl}/v1/local-models/requests/${requestId}/result`,\n {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify({ success, result, error }),\n },\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Result submission failed: ${response.status} ${errorText}`,\n );\n }\n}\n\nexport async function verifyApiKey(): Promise<boolean> {\n const baseUrl = getApiBaseUrl();\n\n try {\n const response = await fetch(`${baseUrl}/v1/local-models/verify-api-key`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n return response.status === 204 || response.ok;\n } catch {\n return false;\n }\n}\n\nexport type ModelTypeMindStudio =\n | 'llm_chat'\n | 'image_generation'\n | 'video_generation';\n\nexport interface RegisterModelOptions {\n modelName: string;\n provider: string;\n modelType?: ModelTypeMindStudio;\n /** Parameter schemas for configurable options */\n parameters?: unknown[];\n}\n\nexport async function registerLocalModel(\n modelNameOrOptions: string | RegisterModelOptions,\n provider: string = 'ollama',\n modelType: ModelTypeMindStudio = 'llm_chat',\n): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n let payload: {\n modelName: string;\n provider: string;\n modelType: ModelTypeMindStudio;\n parameters?: unknown[];\n };\n\n if (typeof modelNameOrOptions === 'string') {\n // Legacy signature\n payload = {\n modelName: modelNameOrOptions,\n provider,\n modelType,\n };\n } else {\n // New options object signature\n payload = {\n modelName: modelNameOrOptions.modelName,\n provider: modelNameOrOptions.provider,\n modelType: modelNameOrOptions.modelType || 'llm_chat',\n parameters: modelNameOrOptions.parameters,\n };\n }\n\n const response = await fetch(`${baseUrl}/v1/local-models/models/create`, {\n method: 'POST',\n headers: getHeaders(),\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Register failed: ${response.status} ${errorText}`);\n }\n}\n\nexport async function getRegisteredModels(): Promise<string[]> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/models`, {\n method: 'GET',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(\n `Failed to fetch registered models: ${response.status} ${errorText}`,\n );\n }\n\n const data = (await response.json()) as { models: string[] };\n return data.models;\n}\n\nexport async function requestDeviceAuth(): Promise<{\n url: string;\n token: string;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/request-auth-url`, {\n method: 'GET',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth request failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n url: string;\n token: string;\n };\n\n return data;\n}\n\nexport async function pollDeviceAuth(token: string): Promise<{\n status: 'pending' | 'completed' | 'expired';\n apiKey?: string;\n}> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/developer/v2/poll-auth-url`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ token }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Device auth poll failed: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n status: 'pending' | 'completed' | 'expired';\n apiKey?: string;\n };\n\n return data;\n}\n\nexport async function disconnectHeartbeat(): Promise<void> {\n const baseUrl = getApiBaseUrl();\n\n const response = await fetch(`${baseUrl}/v1/local-models/disconnect`, {\n method: 'POST',\n headers: getHeaders(),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Heartbeat disconnect failed: ${response.status} ${error}`);\n }\n}\n","import { Ollama } from 'ollama';\nimport { getProviderBaseUrl } from '../../config';\nimport { commandExists } from '../utils';\nimport readme from './readme.md';\nimport type {\n Provider,\n LocalModel,\n ChatMessage,\n ChatOptions,\n ChatResponse,\n ProviderSetupStatus,\n} from '../types';\n\nclass OllamaProvider implements Provider {\n readonly name = 'ollama';\n readonly displayName = 'Ollama';\n readonly description = 'Run open-source LLMs locally via CLI. Supports Llama, Mistral, Gemma, and more.';\n readonly capabilities = ['text'] as const;\n readonly readme = readme;\n readonly defaultBaseUrl = 'http://localhost:11434';\n\n get baseUrl(): string {\n return getProviderBaseUrl(this.name, this.defaultBaseUrl);\n }\n\n private createClient(): Ollama {\n return new Ollama({ host: this.baseUrl });\n }\n\n async isRunning(): Promise<boolean> {\n try {\n const client = this.createClient();\n await client.list();\n return true;\n } catch {\n return false;\n }\n }\n\n async discoverModels(): Promise<LocalModel[]> {\n try {\n const client = this.createClient();\n const response = await client.list();\n\n return response.models.map((m) => ({\n name: m.name,\n provider: this.name,\n capability: 'text' as const,\n size: m.size,\n parameterSize: m.details?.parameter_size,\n quantization: m.details?.quantization_level,\n }));\n } catch {\n return [];\n }\n }\n\n async detect(): Promise<ProviderSetupStatus> {\n const installed = await commandExists('ollama');\n let running = false;\n\n if (installed) {\n running = await this.isRunning();\n }\n\n return { installed, running };\n }\n\n async *chat(\n model: string,\n messages: ChatMessage[],\n options?: ChatOptions,\n ): AsyncGenerator<ChatResponse> {\n const client = this.createClient();\n\n const stream = await client.chat({\n model,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n stream: true,\n options: {\n temperature: options?.temperature,\n num_predict: options?.maxTokens,\n },\n });\n\n for await (const chunk of stream) {\n yield {\n content: chunk.message.content,\n done: chunk.done,\n };\n }\n }\n}\n\nexport default new OllamaProvider();\n","import { exec } from 'child_process';\nimport { promisify } from 'util';\n\nconst execAsync = promisify(exec);\n\n/**\n * Check if a command exists in PATH\n */\nexport async function commandExists(command: string): Promise<boolean> {\n try {\n const checkCmd = process.platform === 'win32' ? 'where' : 'which';\n await execAsync(`${checkCmd} ${command}`);\n return true;\n } catch {\n return false;\n }\n}\n","# Ollama\n\nOllama lets you run text generation models (Llama, Mistral, Gemma, etc.) locally. Once it's running with at least one model downloaded, MindStudio will detect it automatically.\n\n**Default port:** 11434\n**Website:** https://ollama.com\n**GitHub:** https://github.com/ollama/ollama\n\n## Step 1: Install Ollama\n\n### macOS / Linux\n\nOpen a terminal and paste this command:\n\n```\ncurl -fsSL https://ollama.com/install.sh | sh\n```\n\n### macOS (alternative)\n\nDownload the app from https://ollama.com/download, open the file, and drag it into your Applications folder.\n\n### Windows\n\nDownload the installer from https://ollama.com/download and run it. Follow the on-screen instructions.\n\n## Step 2: Start the Server\n\nOpen a terminal and run:\n\n```\nollama serve\n```\n\nLeave this terminal window open -- the server needs to keep running for MindStudio to connect to it.\n\n**macOS tip:** If you installed Ollama as a desktop app, the server starts automatically when you open it. Look for the Ollama icon in your menu bar -- if it's there, you can skip this step.\n\n## Step 3: Download a Model\n\nOpen a **new** terminal window (keep the server running in the other one) and download a model:\n\n```\nollama pull llama3.2\n```\n\nSome good models to start with:\n\n- **llama3.2** -- fast, great all-around model (2 GB download)\n- **mistral** -- efficient for most tasks (4 GB)\n- **gemma2** -- Google's open model (5 GB)\n\nBrowse more models at https://ollama.com/library\n\nOnce the download finishes, go back to the MindStudio tunnel and select **Refresh Providers**. Your models should appear.\n\n## Troubleshooting\n\n- **MindStudio says Ollama is \"not running\"** -- Make sure `ollama serve` is running in a terminal window. You should see \"Listening on 127.0.0.1:11434\" in the output.\n\n- **Ollama is running but no models show up** -- You need to download at least one model first. Run `ollama pull llama3.2` in a separate terminal window.\n\n- **\"address already in use\"** -- Ollama is probably already running. On macOS, check for the Ollama icon in your menu bar. On Linux, run `pkill ollama` and try `ollama serve` again.\n\n- **\"out of memory\" errors** -- Your machine doesn't have enough RAM for that model. Try a smaller one like `llama3.2` (2 GB).\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { getProviderBaseUrl } from '../../config';\nimport readme from './readme.md';\nimport type {\n Provider,\n LocalModel,\n ChatMessage,\n ChatOptions,\n ChatResponse,\n ProviderSetupStatus,\n} from '../types';\n\ninterface LMStudioModel {\n id: string;\n object: string;\n owned_by: string;\n}\n\ninterface LMStudioModelsResponse {\n data: LMStudioModel[];\n}\n\nclass LMStudioProvider implements Provider {\n readonly name = 'lmstudio';\n readonly displayName = 'LM Studio';\n readonly description = 'Desktop app for running LLMs locally with a visual interface. No terminal required.';\n readonly capabilities = ['text'] as const;\n readonly readme = readme;\n readonly defaultBaseUrl = 'http://localhost:1234/v1';\n\n get baseUrl(): string {\n return getProviderBaseUrl(this.name, this.defaultBaseUrl);\n }\n\n private getBaseUrl(): string {\n return this.baseUrl;\n }\n\n async isRunning(): Promise<boolean> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/models`, {\n method: 'GET',\n signal: AbortSignal.timeout(3000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n async discoverModels(): Promise<LocalModel[]> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/models`);\n\n if (!response.ok) {\n return [];\n }\n\n const data = (await response.json()) as LMStudioModelsResponse;\n\n return data.data.map((m) => ({\n name: m.id,\n provider: this.name,\n capability: 'text' as const,\n }));\n } catch {\n return [];\n }\n }\n\n async detect(): Promise<ProviderSetupStatus> {\n let installed = false;\n\n const possiblePaths = {\n darwin: ['/Applications/LM Studio.app'],\n linux: [\n path.join(os.homedir(), '.local/share/LM Studio'),\n '/opt/lm-studio',\n ],\n win32: [\n path.join(process.env.LOCALAPPDATA || '', 'LM Studio'),\n path.join(process.env.PROGRAMFILES || '', 'LM Studio'),\n ],\n };\n\n const paths =\n possiblePaths[process.platform as keyof typeof possiblePaths] || [];\n for (const p of paths) {\n if (fs.existsSync(p)) {\n installed = true;\n break;\n }\n }\n\n let running = false;\n try {\n const response = await fetch('http://localhost:1234/v1/models', {\n signal: AbortSignal.timeout(1000),\n });\n running = response.ok;\n if (running) installed = true;\n } catch {\n running = false;\n }\n\n return { installed, running };\n }\n\n async *chat(\n model: string,\n messages: ChatMessage[],\n options?: ChatOptions,\n ): AsyncGenerator<ChatResponse> {\n const response = await fetch(`${this.getBaseUrl()}/chat/completions`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model,\n messages: messages.map((m) => ({\n role: m.role,\n content: m.content,\n })),\n stream: true,\n temperature: options?.temperature,\n max_tokens: options?.maxTokens,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`LM Studio request failed: ${response.status} ${error}`);\n }\n\n if (!response.body) {\n throw new Error('No response body from LM Studio');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n yield { content: '', done: true };\n break;\n }\n\n buffer += decoder.decode(value, { stream: true });\n\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n\n if (!trimmed || !trimmed.startsWith('data: ')) {\n continue;\n }\n\n const data = trimmed.slice(6);\n\n if (data === '[DONE]') {\n yield { content: '', done: true };\n return;\n }\n\n try {\n const parsed = JSON.parse(data) as {\n choices: Array<{\n delta?: { content?: string };\n finish_reason?: string | null;\n }>;\n };\n\n const choice = parsed.choices[0];\n const content = choice?.delta?.content || '';\n const isDone = choice?.finish_reason !== null;\n\n if (content) {\n yield { content, done: isDone };\n }\n } catch {\n // Skip malformed JSON chunks\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n}\n\nexport default new LMStudioProvider();\n","# LM Studio\n\nLM Studio is a desktop app for running text generation models locally. No terminal needed -- everything is done through the app. Once its server is running, MindStudio will detect it automatically.\n\n**Default port:** 1234\n**Website:** https://lmstudio.ai\n**GitHub:** https://github.com/lmstudio-ai\n\n## Step 1: Install LM Studio\n\n1. Go to https://lmstudio.ai\n2. Click the download button for your operating system\n3. Open the downloaded file and install it like any other app\n\n## Step 2: Download a Model\n\n1. Open LM Studio\n2. Click the **Discover** tab on the left sidebar\n3. Search for a model (see suggestions below)\n4. Click the download button next to the model you want\n5. Wait for the download to finish\n\nGood starter models:\n\n- **Llama 3.2** -- great all-around model, fast\n- **Mistral** -- efficient and capable\n- **Phi-3** -- compact, runs well on most machines\n\n## Step 3: Start the Server\n\nThis is the key step -- LM Studio needs to be running its local server for MindStudio to connect.\n\n1. In LM Studio, click the **Developer** tab on the left sidebar\n2. Select a model from the dropdown at the top if one isn't already loaded\n3. Click **Start Server**\n\nYou should see a green indicator showing the server is running on `http://localhost:1234`.\n\n**Important:** Just opening LM Studio is not enough. You must start the server from the Developer tab.\n\nLeave LM Studio open with the server running while you use MindStudio. Go back to the tunnel and select **Refresh Providers** -- your models should appear.\n\n## Troubleshooting\n\n- **MindStudio says LM Studio is \"not running\"** -- Make sure you started the server in the Developer tab. The green indicator should be visible.\n\n- **Server is running but no models show up** -- You need to load a model in the Developer tab. Select one from the dropdown at the top of the Developer tab before starting the server.\n\n- **Port conflict** -- If something else is using port 1234, you can change the port in the Developer tab settings.\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { getProviderBaseUrl, getProviderInstallPath } from '../../config';\nimport readme from './readme.md';\nimport type {\n Provider,\n LocalModel,\n ImageGenerationOptions,\n ImageGenerationResult,\n ImageGenerationProgress,\n ParameterSchema,\n ProviderSetupStatus,\n} from '../types';\n\n/**\n * Response from AUTOMATIC1111's /sdapi/v1/sd-models endpoint\n */\ninterface SDModel {\n title: string;\n model_name: string;\n hash?: string;\n sha256?: string;\n filename: string;\n}\n\n/**\n * Response from AUTOMATIC1111's /sdapi/v1/txt2img endpoint\n */\ninterface Txt2ImgResponse {\n images: string[];\n parameters: Record<string, unknown>;\n info: string;\n}\n\n/**\n * Response from AUTOMATIC1111's /sdapi/v1/progress endpoint\n */\ninterface ProgressResponse {\n progress: number;\n eta_relative: number;\n state: {\n skipped: boolean;\n interrupted: boolean;\n job: string;\n job_count: number;\n job_timestamp: string;\n job_no: number;\n sampling_step: number;\n sampling_steps: number;\n };\n current_image?: string;\n textinfo?: string;\n}\n\n/**\n * Response from AUTOMATIC1111's /sdapi/v1/samplers endpoint\n */\ninterface SDSampler {\n name: string;\n aliases: string[];\n options: Record<string, unknown>;\n}\n\n/**\n * Stable Diffusion provider for AUTOMATIC1111 WebUI\n * Default URL: http://127.0.0.1:7860\n */\nclass StableDiffusionProvider implements Provider {\n readonly name = 'stable-diffusion';\n readonly displayName = 'Stable Diffusion WebUI';\n readonly description = 'Generate images locally using Stable Diffusion checkpoints. Runs as a local web UI.';\n readonly capabilities = ['image'] as const;\n readonly readme = readme;\n readonly defaultBaseUrl = 'http://127.0.0.1:7860';\n\n get baseUrl(): string {\n return getProviderBaseUrl(this.name, this.defaultBaseUrl);\n }\n\n private getBaseUrl(): string {\n return this.baseUrl;\n }\n\n async isRunning(): Promise<boolean> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/sd-models`, {\n method: 'GET',\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n async discoverModels(): Promise<LocalModel[]> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/sd-models`);\n\n if (!response.ok) {\n return [];\n }\n\n const models = (await response.json()) as SDModel[];\n\n return models.map((m) => ({\n name: m.model_name,\n provider: this.name,\n capability: 'image' as const,\n }));\n } catch {\n return [];\n }\n }\n\n async detect(): Promise<ProviderSetupStatus> {\n const savedPath = getProviderInstallPath(this.name);\n\n const possiblePaths = [\n ...(savedPath ? [savedPath] : []),\n path.join(os.homedir(), 'stable-diffusion-webui'),\n path.join(os.homedir(), 'Projects', 'stable-diffusion-webui'),\n path.join(os.homedir(), 'Code', 'stable-diffusion-webui'),\n ];\n\n let installed = false;\n for (const p of possiblePaths) {\n if (\n fs.existsSync(path.join(p, 'launch.py')) ||\n fs.existsSync(path.join(p, 'webui.sh')) ||\n fs.existsSync(path.join(p, 'webui.bat'))\n ) {\n installed = true;\n break;\n }\n }\n\n let running = false;\n try {\n const response = await fetch('http://127.0.0.1:7860/sdapi/v1/sd-models', {\n signal: AbortSignal.timeout(1000),\n });\n running = response.ok;\n if (running) installed = true;\n } catch {\n running = false;\n }\n\n return { installed, running };\n }\n\n /**\n * Get the currently loaded model\n */\n async getCurrentModel(): Promise<string | null> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/options`);\n if (!response.ok) return null;\n\n const options = (await response.json()) as {\n sd_model_checkpoint?: string;\n };\n return options.sd_model_checkpoint || null;\n } catch {\n return null;\n }\n }\n\n /**\n * Switch to a different model\n */\n async setModel(modelName: string): Promise<void> {\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/options`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sd_model_checkpoint: modelName }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Failed to switch model: ${error}`);\n }\n }\n\n async generateImage(\n model: string,\n prompt: string,\n options?: ImageGenerationOptions,\n ): Promise<ImageGenerationResult> {\n const currentModel = await this.getCurrentModel();\n if (currentModel && !currentModel.includes(model)) {\n await this.setModel(model);\n }\n\n const payload = {\n prompt,\n negative_prompt: options?.negativePrompt || '',\n steps: options?.steps || 20,\n width: options?.width || 512,\n height: options?.height || 512,\n cfg_scale: options?.cfgScale || 7,\n seed: options?.seed ?? -1,\n sampler_name: options?.sampler || 'Euler a',\n };\n\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/txt2img`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Image generation failed: ${response.status} ${error}`);\n }\n\n const result = (await response.json()) as Txt2ImgResponse;\n\n if (!result.images || result.images.length === 0) {\n throw new Error('No images returned from Stable Diffusion');\n }\n\n let info: Record<string, unknown> = {};\n let seed: number | undefined;\n try {\n info = JSON.parse(result.info);\n seed = typeof info.seed === 'number' ? info.seed : undefined;\n } catch {\n // Ignore parse errors\n }\n\n return {\n imageBase64: result.images[0],\n mimeType: 'image/png',\n seed,\n info,\n };\n }\n\n async generateImageWithProgress(\n model: string,\n prompt: string,\n options?: ImageGenerationOptions,\n onProgress?: (progress: ImageGenerationProgress) => void,\n ): Promise<ImageGenerationResult> {\n const generatePromise = this.generateImage(model, prompt, options);\n\n if (onProgress) {\n const pollProgress = async () => {\n while (true) {\n try {\n const response = await fetch(\n `${this.getBaseUrl()}/sdapi/v1/progress`,\n );\n if (!response.ok) break;\n\n const progress = (await response.json()) as ProgressResponse;\n\n onProgress({\n step: progress.state.sampling_step,\n totalSteps: progress.state.sampling_steps,\n preview: progress.current_image,\n });\n\n if (progress.progress >= 1.0) break;\n\n await new Promise((resolve) => setTimeout(resolve, 500));\n } catch {\n break;\n }\n }\n };\n\n pollProgress().catch(() => {});\n }\n\n return generatePromise;\n }\n\n /**\n * Fetch available samplers from the backend\n */\n private async getSamplers(): Promise<string[]> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/sdapi/v1/samplers`);\n if (!response.ok) return this.getDefaultSamplers();\n\n const samplers = (await response.json()) as SDSampler[];\n return samplers.map((s) => s.name);\n } catch {\n return this.getDefaultSamplers();\n }\n }\n\n private getDefaultSamplers(): string[] {\n return [\n 'Euler a',\n 'Euler',\n 'LMS',\n 'Heun',\n 'DPM2',\n 'DPM2 a',\n 'DPM++ 2S a',\n 'DPM++ 2M',\n 'DPM++ SDE',\n 'DPM fast',\n 'DPM adaptive',\n 'LMS Karras',\n 'DPM2 Karras',\n 'DPM2 a Karras',\n 'DPM++ 2S a Karras',\n 'DPM++ 2M Karras',\n 'DPM++ SDE Karras',\n 'DDIM',\n 'PLMS',\n 'UniPC',\n ];\n }\n\n private generateDimensionOptions(): Array<{ label: string; value: string }> {\n const options: Array<{ label: string; value: string }> = [];\n for (let size = 256; size <= 2048; size += 64) {\n options.push({\n label: `${size}px`,\n value: String(size),\n });\n }\n return options;\n }\n\n async getParameterSchemas(): Promise<ParameterSchema[]> {\n const samplers = await this.getSamplers();\n const dimensionOptions = this.generateDimensionOptions();\n\n return [\n {\n type: 'select',\n label: 'Sampler',\n variable: 'sampler',\n helpText: 'The sampling method used for image generation',\n defaultValue: 'Euler a',\n selectOptions: samplers.map((name) => ({\n label: name,\n value: name,\n })),\n },\n {\n type: 'select',\n label: 'Width',\n variable: 'width',\n defaultValue: '512',\n selectOptions: dimensionOptions,\n },\n {\n type: 'select',\n label: 'Height',\n variable: 'height',\n defaultValue: '512',\n selectOptions: dimensionOptions,\n },\n {\n type: 'number',\n label: 'Steps',\n variable: 'steps',\n helpText:\n 'Number of denoising steps. More steps = higher quality but slower.',\n defaultValue: 20,\n numberOptions: {\n min: 1,\n max: 150,\n step: 1,\n },\n },\n {\n type: 'number',\n label: 'CFG Scale',\n variable: 'cfgScale',\n helpText:\n 'How strongly the image should follow the prompt. Higher = more literal.',\n defaultValue: 7,\n numberOptions: {\n min: 1,\n max: 30,\n step: 0.5,\n },\n },\n {\n type: 'number',\n label: 'Seed',\n variable: 'seed',\n helpText:\n \"A specific value used to guide the 'randomness' of generation. Use -1 for random.\",\n defaultValue: -1,\n numberOptions: {\n min: -1,\n max: 2147483647,\n },\n },\n {\n type: 'text',\n label: 'Negative Prompt',\n variable: 'negativePrompt',\n helpText: \"Things you don't want in the image\",\n placeholder: 'blurry, low quality, distorted',\n },\n ];\n }\n}\n\nexport default new StableDiffusionProvider();\n","# Stable Diffusion WebUI\n\nAUTOMATIC1111's Stable Diffusion WebUI runs image generation models locally. Once the server is running with at least one model, MindStudio will detect it automatically.\n\n**Default port:** 7860\n**GitHub:** https://github.com/AUTOMATIC1111/stable-diffusion-webui\n\n## What You'll Need\n\n- **Python 3.10 or newer** -- Check by opening a terminal and typing `python3 --version`. If you don't have it, download from https://www.python.org/downloads/\n\n- **Git** -- Check by typing `git --version`. If you don't have it, download from https://git-scm.com/downloads\n\n## Step 1: Install the WebUI\n\nOpen a terminal and paste this command:\n\n```\ngit clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git ~/stable-diffusion-webui\n```\n\n**Windows users**, use this instead:\n\n```\ngit clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git %USERPROFILE%\\stable-diffusion-webui\n```\n\n## Step 2: Download a Model\n\nYou need at least one model file for MindStudio to use. Model files have the `.safetensors` extension (typically 2-7 GB).\n\n1. Browse models at https://civitai.com or https://huggingface.co\n2. Download a `.safetensors` checkpoint file\n3. Move the file into this folder:\n\n```\n~/stable-diffusion-webui/models/Stable-diffusion/\n```\n\nGood starter models:\n\n- **Stable Diffusion XL (SDXL)** -- high quality, 1024x1024\n- **Stable Diffusion 1.5** -- fast, widely supported\n\n## Step 3: Start the Server\n\nOpen a terminal and run:\n\n```\ncd ~/stable-diffusion-webui && ./webui.sh --api\n```\n\n**Windows users:**\n\n```\ncd %USERPROFILE%\\stable-diffusion-webui && webui-user.bat --api\n```\n\nThe first time you run this it will take several minutes to install dependencies. This is normal -- let it finish.\n\n**Important:** The `--api` flag is required. Without it, MindStudio cannot send requests to the server.\n\nLeave this terminal window open while using MindStudio. Once the server is ready, go back to the tunnel and select **Refresh Providers** -- your models should appear.\n\n## Troubleshooting\n\n- **MindStudio says WebUI is \"not running\"** -- Make sure you included `--api` when launching. The terminal should show the server at `http://127.0.0.1:7860`.\n\n- **Server is running but no models show up** -- Make sure your `.safetensors` file is directly in the `models/Stable-diffusion/` folder, not inside a subfolder. Restart the server after adding new model files.\n\n- **\"Python not found\"** -- Python 3.10+ is required. Download from https://www.python.org/downloads/. On Windows, check \"Add Python to PATH\" during installation.\n\n- **Errors during first launch** -- Delete the `venv` folder inside `stable-diffusion-webui` and run the launch command again to reinstall dependencies from scratch.\n\n- **\"CUDA out of memory\"** -- Your GPU doesn't have enough memory. Add `--medvram` or `--lowvram` to the launch command: `./webui.sh --api --medvram`\n","import * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { getProviderBaseUrl, getProviderInstallPath } from '../../config';\nimport { getWorkflowForModel, isKnownVideoModel } from './workflows';\nimport readme from './readme.md';\nimport type {\n Provider,\n LocalModel,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationProgress,\n ParameterSchema,\n ProviderSetupStatus,\n} from '../types';\n\n/**\n * ComfyUI provider for video generation.\n * Default URL: http://127.0.0.1:8188\n */\nclass ComfyUIProvider implements Provider {\n readonly name = 'comfyui';\n readonly displayName = 'ComfyUI';\n readonly description = 'Generate videos locally using node-based workflows. Supports LTX-Video and Wan2.1.';\n readonly capabilities = ['video'] as const;\n readonly readme = readme;\n readonly defaultBaseUrl = 'http://127.0.0.1:8188';\n\n get baseUrl(): string {\n return getProviderBaseUrl(this.name, this.defaultBaseUrl);\n }\n\n private getBaseUrl(): string {\n return this.baseUrl;\n }\n\n async isRunning(): Promise<boolean> {\n try {\n const response = await fetch(`${this.getBaseUrl()}/system_stats`, {\n method: 'GET',\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n async detect(): Promise<ProviderSetupStatus> {\n const savedPath = getProviderInstallPath(this.name);\n\n const possiblePaths = [\n ...(savedPath ? [savedPath] : []),\n path.join(os.homedir(), 'ComfyUI'),\n path.join(os.homedir(), 'comfyui'),\n path.join(os.homedir(), 'Projects', 'ComfyUI'),\n path.join(os.homedir(), 'Code', 'ComfyUI'),\n ];\n\n let installed = false;\n for (const p of possiblePaths) {\n if (\n fs.existsSync(path.join(p, 'main.py')) &&\n fs.existsSync(path.join(p, 'requirements.txt'))\n ) {\n installed = true;\n break;\n }\n }\n\n let running = false;\n try {\n const response = await fetch('http://127.0.0.1:8188/system_stats', {\n signal: AbortSignal.timeout(1000),\n });\n running = response.ok;\n if (running) installed = true;\n } catch {\n running = false;\n }\n\n return { installed, running };\n }\n\n /**\n * Discover video models by scanning ComfyUI's model directories.\n */\n async discoverModels(): Promise<LocalModel[]> {\n const models: LocalModel[] = [];\n\n try {\n const response = await fetch(\n `${this.getBaseUrl()}/object_info/CheckpointLoaderSimple`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n const nodeInfo = data.CheckpointLoaderSimple as {\n input?: { required?: { ckpt_name?: [string[]] } };\n };\n const checkpoints = nodeInfo?.input?.required?.ckpt_name?.[0] || [];\n for (const name of checkpoints) {\n if (isKnownVideoModel(name)) {\n const workflow = getWorkflowForModel(name);\n models.push({\n name: name,\n provider: this.name,\n capability: 'video',\n parameterSize: workflow?.displayName,\n });\n }\n }\n }\n } catch {\n // API not available\n }\n\n try {\n const response = await fetch(\n `${this.getBaseUrl()}/object_info/UNETLoader`,\n { signal: AbortSignal.timeout(5000) },\n );\n if (response.ok) {\n const data = (await response.json()) as Record<string, unknown>;\n const nodeInfo = data.UNETLoader as {\n input?: { required?: { unet_name?: [string[]] } };\n };\n const unetModels = nodeInfo?.input?.required?.unet_name?.[0] || [];\n for (const name of unetModels) {\n if (isKnownVideoModel(name) && !models.some((m) => m.name === name)) {\n const workflow = getWorkflowForModel(name);\n models.push({\n name: name,\n provider: this.name,\n capability: 'video',\n parameterSize: workflow?.displayName,\n });\n }\n }\n }\n } catch {\n // Ignore\n }\n\n if (models.length === 0) {\n const installPath = getProviderInstallPath(this.name);\n if (installPath) {\n const dirs = [\n path.join(installPath, 'models', 'checkpoints'),\n path.join(installPath, 'models', 'diffusion_models'),\n ];\n for (const dir of dirs) {\n if (fs.existsSync(dir)) {\n try {\n const files = fs.readdirSync(dir);\n for (const file of files) {\n if (\n isKnownVideoModel(file) &&\n !models.some((m) => m.name === file)\n ) {\n const workflow = getWorkflowForModel(file);\n models.push({\n name: file,\n provider: this.name,\n capability: 'video',\n parameterSize: workflow?.displayName,\n });\n }\n }\n } catch {\n // Ignore read errors\n }\n }\n }\n }\n }\n\n return models;\n }\n\n /**\n * Generate a video using ComfyUI.\n */\n async generateVideo(\n model: string,\n prompt: string,\n options?: VideoGenerationOptions,\n onProgress?: (progress: VideoGenerationProgress) => void,\n ): Promise<VideoGenerationResult> {\n const baseUrl = this.getBaseUrl();\n const workflowConfig = getWorkflowForModel(model);\n\n if (!workflowConfig) {\n throw new Error(\n `No workflow template found for model: ${model}. Supported families: LTX-Video, Wan2.1`,\n );\n }\n\n const defaults = workflowConfig.defaults;\n const seed =\n options?.seed !== undefined && options.seed !== -1\n ? options.seed\n : Math.floor(Math.random() * 2 ** 32);\n\n const workflow = workflowConfig.buildWorkflow({\n model,\n prompt,\n negativePrompt:\n options?.negativePrompt || 'worst quality, blurry, distorted',\n width: options?.width || defaults.width,\n height: options?.height || defaults.height,\n numFrames: options?.numFrames || defaults.numFrames,\n fps: options?.fps || defaults.fps,\n steps: options?.steps || defaults.steps,\n cfgScale: options?.cfgScale || defaults.cfgScale,\n seed,\n });\n\n const clientId = `mindstudio_${Date.now()}_${Math.random().toString(36).slice(2)}`;\n\n const wsUrl = baseUrl.replace(/^http/, 'ws') + `/ws?clientId=${clientId}`;\n\n const submitResponse = await fetch(`${baseUrl}/prompt`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n prompt: workflow,\n client_id: clientId,\n }),\n });\n\n if (!submitResponse.ok) {\n const errorText = await submitResponse.text();\n throw new Error(\n `ComfyUI prompt submission failed: ${submitResponse.status} ${errorText}`,\n );\n }\n\n const submitResult = (await submitResponse.json()) as {\n prompt_id: string;\n number: number;\n node_errors?: Record<string, unknown>;\n };\n\n if (\n submitResult.node_errors &&\n Object.keys(submitResult.node_errors).length > 0\n ) {\n throw new Error(\n `ComfyUI workflow validation failed: ${JSON.stringify(submitResult.node_errors)}`,\n );\n }\n\n const promptId = submitResult.prompt_id;\n\n await this.waitForCompletion(wsUrl, promptId, onProgress);\n\n const historyResponse = await fetch(`${baseUrl}/history/${promptId}`, {\n signal: AbortSignal.timeout(30000),\n });\n\n if (!historyResponse.ok) {\n throw new Error(\n `Failed to fetch result history: ${historyResponse.status}`,\n );\n }\n\n const history = (await historyResponse.json()) as Record<\n string,\n {\n outputs: Record<\n string,\n {\n images?: Array<{\n filename: string;\n subfolder: string;\n type: string;\n }>;\n gifs?: Array<{ filename: string; subfolder: string; type: string }>;\n }\n >;\n }\n >;\n\n const promptHistory = history[promptId];\n if (!promptHistory) {\n throw new Error('No result found in ComfyUI history');\n }\n\n const outputNodeId = workflowConfig.outputNodeId;\n const outputData = promptHistory.outputs[outputNodeId];\n const outputFiles = outputData?.gifs || outputData?.images;\n\n if (!outputFiles || outputFiles.length === 0) {\n throw new Error('No output files found in ComfyUI result');\n }\n\n const outputFile = outputFiles[0];\n\n const fileUrl = new URL(`${baseUrl}/view`);\n fileUrl.searchParams.set('filename', outputFile.filename);\n fileUrl.searchParams.set('subfolder', outputFile.subfolder || '');\n fileUrl.searchParams.set('type', outputFile.type || 'output');\n\n const fileResponse = await fetch(fileUrl.toString(), {\n signal: AbortSignal.timeout(60000),\n });\n\n if (!fileResponse.ok) {\n throw new Error(`Failed to download output file: ${fileResponse.status}`);\n }\n\n const fileBuffer = await fileResponse.arrayBuffer();\n const videoBase64 = Buffer.from(fileBuffer).toString('base64');\n\n const ext = path.extname(outputFile.filename).toLowerCase();\n const mimeType =\n ext === '.mp4'\n ? 'video/mp4'\n : ext === '.webm'\n ? 'video/webm'\n : ext === '.webp'\n ? 'image/webp'\n : ext === '.gif'\n ? 'image/gif'\n : 'video/mp4';\n\n const fps = options?.fps || defaults.fps;\n const numFrames = options?.numFrames || defaults.numFrames;\n\n return {\n videoBase64,\n mimeType,\n duration: numFrames / fps,\n fps,\n seed,\n };\n }\n\n /**\n * Wait for a ComfyUI prompt to finish execution via WebSocket.\n */\n private waitForCompletion(\n wsUrl: string,\n promptId: string,\n onProgress?: (progress: VideoGenerationProgress) => void,\n ): Promise<void> {\n return new Promise((resolve, reject) => {\n const timeoutMs = 30 * 60 * 1000;\n let ws: WebSocket;\n\n const timeout = setTimeout(() => {\n try {\n ws?.close();\n } catch {\n // Ignore\n }\n reject(new Error('Video generation timed out after 30 minutes'));\n }, timeoutMs);\n\n try {\n ws = new WebSocket(wsUrl);\n } catch (err) {\n clearTimeout(timeout);\n reject(\n new Error(\n `Failed to connect to ComfyUI WebSocket: ${err instanceof Error ? err.message : err}`,\n ),\n );\n return;\n }\n\n ws.onmessage = (event) => {\n try {\n const message = JSON.parse(\n typeof event.data === 'string' ? event.data : '',\n ) as {\n type: string;\n data: Record<string, unknown>;\n };\n\n if (message.type === 'progress') {\n const data = message.data as {\n value: number;\n max: number;\n prompt_id?: string;\n node?: string;\n };\n if (!data.prompt_id || data.prompt_id === promptId) {\n onProgress?.({\n step: data.value,\n totalSteps: data.max,\n currentNode: data.node as string | undefined,\n });\n }\n }\n\n if (message.type === 'execution_success') {\n const data = message.data as { prompt_id: string };\n if (data.prompt_id === promptId) {\n clearTimeout(timeout);\n ws.close();\n resolve();\n }\n }\n\n if (message.type === 'execution_error') {\n const data = message.data as {\n prompt_id: string;\n exception_message?: string;\n node_type?: string;\n };\n if (data.prompt_id === promptId) {\n clearTimeout(timeout);\n ws.close();\n reject(\n new Error(\n `ComfyUI execution error${data.node_type ? ` in ${data.node_type}` : ''}: ${data.exception_message || 'Unknown error'}`,\n ),\n );\n }\n }\n } catch {\n // Ignore non-JSON messages\n }\n };\n\n ws.onerror = () => {\n clearTimeout(timeout);\n reject(new Error('ComfyUI WebSocket error: connection failed'));\n };\n\n ws.onclose = (event) => {\n if (!event.wasClean) {\n clearTimeout(timeout);\n reject(new Error('ComfyUI WebSocket connection closed unexpectedly'));\n }\n };\n });\n }\n\n /**\n * Get parameter schemas for video generation UI configuration.\n */\n async getParameterSchemas(): Promise<ParameterSchema[]> {\n return [\n {\n type: 'number',\n label: 'Width',\n variable: 'width',\n helpText:\n 'Video width in pixels. Larger = better quality but bigger file.',\n defaultValue: 512,\n numberOptions: { min: 256, max: 1280, step: 64 },\n },\n {\n type: 'number',\n label: 'Height',\n variable: 'height',\n helpText:\n 'Video height in pixels. Larger = better quality but bigger file.',\n defaultValue: 320,\n numberOptions: { min: 256, max: 1280, step: 64 },\n },\n {\n type: 'number',\n label: 'Frames',\n variable: 'numFrames',\n helpText:\n 'Number of frames to generate. More frames = longer video but bigger file. Keep low to avoid upload limits.',\n defaultValue: 41,\n numberOptions: { min: 9, max: 97, step: 8 },\n },\n {\n type: 'number',\n label: 'FPS',\n variable: 'fps',\n helpText: 'Frames per second for the output video.',\n defaultValue: 8,\n numberOptions: { min: 4, max: 30, step: 1 },\n },\n {\n type: 'number',\n label: 'Steps',\n variable: 'steps',\n helpText:\n 'Number of denoising steps. More steps = higher quality but slower.',\n defaultValue: 20,\n numberOptions: { min: 10, max: 100, step: 1 },\n },\n {\n type: 'number',\n label: 'CFG Scale',\n variable: 'cfgScale',\n helpText:\n 'How strongly the video should follow the prompt. Higher = more literal.',\n defaultValue: 7,\n numberOptions: { min: 1, max: 20, step: 0.5 },\n },\n {\n type: 'number',\n label: 'Seed',\n variable: 'seed',\n helpText:\n 'A specific value used to guide randomness. Use -1 for random.',\n defaultValue: -1,\n numberOptions: { min: -1, max: 2147483647 },\n },\n {\n type: 'text',\n label: 'Negative Prompt',\n variable: 'negativePrompt',\n helpText: \"Things you don't want in the video\",\n placeholder: 'worst quality, blurry, distorted',\n },\n ];\n }\n}\n\nexport default new ComfyUIProvider();\n","/**\n * LTX-Video text-to-video workflow template for ComfyUI.\n *\n * Based on the official ComfyUI LTX-Video example workflow.\n * The checkpoint contains the MODEL + VAE but NOT the text encoder.\n * A separate CLIPLoader with type \"ltxv\" loads the T5-XXL text encoder.\n *\n * Model: ltx-video-2b-v0.9.5.safetensors in models/checkpoints/\n * Text encoder: t5xxl_fp16.safetensors in models/text_encoders/\n */\n\nexport interface LtxVideoParams {\n /** Model checkpoint filename (in models/checkpoints/) */\n model: string;\n /** Text encoder filename (in models/text_encoders/) */\n textEncoder: string;\n /** Positive prompt */\n prompt: string;\n /** Negative prompt */\n negativePrompt: string;\n /** Video width */\n width: number;\n /** Video height */\n height: number;\n /** Number of frames to generate */\n numFrames: number;\n /** Frames per second for output */\n fps: number;\n /** Number of sampling steps */\n steps: number;\n /** CFG scale */\n cfgScale: number;\n /** Random seed (-1 for random) */\n seed: number;\n}\n\nexport const LTX_VIDEO_DEFAULTS: LtxVideoParams = {\n model: 'ltx-video-2b-v0.9.5.safetensors',\n textEncoder: 't5xxl_fp16.safetensors',\n prompt: '',\n negativePrompt:\n 'worst quality, blurry, distorted, disfigured, motion smear, motion artifacts',\n width: 512,\n height: 320,\n numFrames: 41,\n fps: 8,\n steps: 20,\n cfgScale: 3.0,\n seed: -1,\n};\n\n/**\n * Build an LTX-Video text-to-video workflow in ComfyUI API format.\n * Follows the official ComfyUI example workflow structure.\n */\nexport function buildLtxVideoWorkflow(\n params: Partial<LtxVideoParams> & { prompt: string },\n): Record<string, unknown> {\n const p = { ...LTX_VIDEO_DEFAULTS, ...params };\n const seed = p.seed === -1 ? Math.floor(Math.random() * 2 ** 32) : p.seed;\n\n return {\n // Node 1: Load checkpoint (MODEL + VAE, CLIP output unused)\n '1': {\n class_type: 'CheckpointLoaderSimple',\n inputs: {\n ckpt_name: p.model,\n },\n },\n // Node 2: Load text encoder (T5-XXL) separately\n '2': {\n class_type: 'CLIPLoader',\n inputs: {\n clip_name: p.textEncoder,\n type: 'ltxv',\n },\n },\n // Node 3: Positive prompt encoding (CLIP from CLIPLoader, NOT from checkpoint)\n '3': {\n class_type: 'CLIPTextEncode',\n inputs: {\n text: p.prompt,\n clip: ['2', 0],\n },\n },\n // Node 4: Negative prompt encoding\n '4': {\n class_type: 'CLIPTextEncode',\n inputs: {\n text: p.negativePrompt,\n clip: ['2', 0],\n },\n },\n // Node 5: Empty latent video\n '5': {\n class_type: 'EmptyLTXVLatentVideo',\n inputs: {\n width: p.width,\n height: p.height,\n length: p.numFrames,\n batch_size: 1,\n },\n },\n // Node 6: KSampler\n '6': {\n class_type: 'KSampler',\n inputs: {\n model: ['1', 0],\n positive: ['3', 0],\n negative: ['4', 0],\n latent_image: ['5', 0],\n seed: seed,\n steps: p.steps,\n cfg: p.cfgScale,\n sampler_name: 'euler',\n scheduler: 'normal',\n denoise: 1.0,\n },\n },\n // Node 7: VAE Decode (VAE from checkpoint, slot 2)\n '7': {\n class_type: 'VAEDecode',\n inputs: {\n samples: ['6', 0],\n vae: ['1', 2],\n },\n },\n // Node 8: Save as MP4 via VideoHelperSuite\n '8': {\n class_type: 'VHS_VideoCombine',\n inputs: {\n images: ['7', 0],\n frame_rate: p.fps,\n loop_count: 0,\n filename_prefix: 'ltxv_output',\n format: 'video/h264-mp4',\n pingpong: false,\n save_output: true,\n },\n },\n };\n}\n\n/** Output node ID for fetching results */\nexport const LTX_VIDEO_OUTPUT_NODE = '8';\n","/**\n * Wan2.1 text-to-video workflow template for ComfyUI.\n *\n * Uses ComfyUI's native Wan 2.1 support (no custom nodes required).\n * Diffusion model: wan2.1_t2v_1.3B_fp16.safetensors in models/diffusion_models/\n * Text encoder: umt5_xxl_fp8_e4m3fn_scaled.safetensors in models/text_encoders/\n * VAE: wan_2.1_vae.safetensors in models/vae/\n */\n\nexport interface Wan21Params {\n /** Diffusion model filename */\n model: string;\n /** Text encoder filename */\n textEncoder: string;\n /** VAE filename */\n vae: string;\n /** Positive prompt */\n prompt: string;\n /** Negative prompt */\n negativePrompt: string;\n /** Video width */\n width: number;\n /** Video height */\n height: number;\n /** Number of frames to generate */\n numFrames: number;\n /** Frames per second for output */\n fps: number;\n /** Number of sampling steps */\n steps: number;\n /** CFG scale */\n cfgScale: number;\n /** Random seed (-1 for random) */\n seed: number;\n}\n\nexport const WAN21_DEFAULTS: Wan21Params = {\n model: 'wan2.1_t2v_1.3B_fp16.safetensors',\n textEncoder: 'umt5_xxl_fp8_e4m3fn_scaled.safetensors',\n vae: 'wan_2.1_vae.safetensors',\n prompt: '',\n negativePrompt: 'worst quality, blurry, distorted',\n width: 480,\n height: 320,\n numFrames: 25,\n fps: 8,\n steps: 20,\n cfgScale: 5.0,\n seed: -1,\n};\n\n/**\n * Build a Wan2.1 text-to-video workflow in ComfyUI API format.\n */\nexport function buildWan21Workflow(\n params: Partial<Wan21Params> & { prompt: string },\n): Record<string, unknown> {\n const p = { ...WAN21_DEFAULTS, ...params };\n const seed = p.seed === -1 ? Math.floor(Math.random() * 2 ** 32) : p.seed;\n\n return {\n // Node 1: Load diffusion model (UNET)\n '1': {\n class_type: 'UNETLoader',\n inputs: {\n unet_name: p.model,\n weight_dtype: 'default',\n },\n },\n // Node 2: Load text encoder (UMT5-XXL)\n '2': {\n class_type: 'CLIPLoader',\n inputs: {\n clip_name: p.textEncoder,\n type: 'wan',\n },\n },\n // Node 3: Load VAE\n '3': {\n class_type: 'VAELoader',\n inputs: {\n vae_name: p.vae,\n },\n },\n // Node 4: Positive prompt encoding\n '4': {\n class_type: 'CLIPTextEncode',\n inputs: {\n text: p.prompt,\n clip: ['2', 0],\n },\n },\n // Node 5: Negative prompt encoding\n '5': {\n class_type: 'CLIPTextEncode',\n inputs: {\n text: p.negativePrompt,\n clip: ['2', 0],\n },\n },\n // Node 6: Empty latent image (for video frames)\n '6': {\n class_type: 'EmptySD3LatentImage',\n inputs: {\n width: p.width,\n height: p.height,\n batch_size: p.numFrames,\n },\n },\n // Node 7: KSampler\n '7': {\n class_type: 'KSampler',\n inputs: {\n model: ['1', 0],\n positive: ['4', 0],\n negative: ['5', 0],\n latent_image: ['6', 0],\n seed: seed,\n steps: p.steps,\n cfg: p.cfgScale,\n sampler_name: 'euler',\n scheduler: 'normal',\n denoise: 1.0,\n },\n },\n // Node 8: VAE Decode\n '8': {\n class_type: 'VAEDecode',\n inputs: {\n samples: ['7', 0],\n vae: ['3', 0],\n },\n },\n // Node 9: Save as MP4 via VideoHelperSuite\n '9': {\n class_type: 'VHS_VideoCombine',\n inputs: {\n images: ['8', 0],\n frame_rate: p.fps,\n loop_count: 0,\n filename_prefix: 'wan21_output',\n format: 'video/h264-mp4',\n pingpong: false,\n save_output: true,\n },\n },\n };\n}\n\n/** Output node ID for fetching results */\nexport const WAN21_OUTPUT_NODE = '9';\n","/**\n * Workflow registry - maps model filenames to workflow builders.\n */\n\nimport {\n buildLtxVideoWorkflow,\n LTX_VIDEO_OUTPUT_NODE,\n LTX_VIDEO_DEFAULTS,\n} from './ltx-video';\nimport {\n buildWan21Workflow,\n WAN21_OUTPUT_NODE,\n WAN21_DEFAULTS,\n} from './wan2.1';\n\nexport type ModelFamily = 'ltx-video' | 'wan2.1';\n\nexport interface WorkflowConfig {\n family: ModelFamily;\n displayName: string;\n /** Build the workflow JSON for ComfyUI's /prompt endpoint */\n buildWorkflow: (params: {\n model: string;\n prompt: string;\n negativePrompt: string;\n width: number;\n height: number;\n numFrames: number;\n fps: number;\n steps: number;\n cfgScale: number;\n seed: number;\n }) => Record<string, unknown>;\n /** Node ID that produces the output (for fetching results from /history) */\n outputNodeId: string;\n /** Default parameters */\n defaults: {\n width: number;\n height: number;\n numFrames: number;\n fps: number;\n steps: number;\n cfgScale: number;\n };\n}\n\n/**\n * Known model files and their workflow configurations.\n * Keys are filename patterns (matched case-insensitively).\n */\nconst MODEL_REGISTRY: Array<{\n /** Pattern to match against model filenames */\n pattern: RegExp;\n config: WorkflowConfig;\n}> = [\n // LTX-Video models\n {\n pattern: /ltx[_-]?video/i,\n config: {\n family: 'ltx-video',\n displayName: 'LTX-Video',\n buildWorkflow: (params) =>\n buildLtxVideoWorkflow({\n model: params.model,\n prompt: params.prompt,\n negativePrompt: params.negativePrompt,\n width: params.width,\n height: params.height,\n numFrames: params.numFrames,\n fps: params.fps,\n steps: params.steps,\n cfgScale: params.cfgScale,\n seed: params.seed,\n }),\n outputNodeId: LTX_VIDEO_OUTPUT_NODE,\n defaults: {\n width: LTX_VIDEO_DEFAULTS.width,\n height: LTX_VIDEO_DEFAULTS.height,\n numFrames: LTX_VIDEO_DEFAULTS.numFrames,\n fps: LTX_VIDEO_DEFAULTS.fps,\n steps: LTX_VIDEO_DEFAULTS.steps,\n cfgScale: LTX_VIDEO_DEFAULTS.cfgScale,\n },\n },\n },\n // Wan 2.1 models\n {\n pattern: /wan2[\\._]?1/i,\n config: {\n family: 'wan2.1',\n displayName: 'Wan 2.1',\n buildWorkflow: (params) =>\n buildWan21Workflow({\n model: params.model,\n prompt: params.prompt,\n negativePrompt: params.negativePrompt,\n width: params.width,\n height: params.height,\n numFrames: params.numFrames,\n fps: params.fps,\n steps: params.steps,\n cfgScale: params.cfgScale,\n seed: params.seed,\n }),\n outputNodeId: WAN21_OUTPUT_NODE,\n defaults: {\n width: WAN21_DEFAULTS.width,\n height: WAN21_DEFAULTS.height,\n numFrames: WAN21_DEFAULTS.numFrames,\n fps: WAN21_DEFAULTS.fps,\n steps: WAN21_DEFAULTS.steps,\n cfgScale: WAN21_DEFAULTS.cfgScale,\n },\n },\n },\n];\n\n/**\n * Find the workflow configuration for a given model filename.\n */\nexport function getWorkflowForModel(\n modelFilename: string,\n): WorkflowConfig | null {\n for (const entry of MODEL_REGISTRY) {\n if (entry.pattern.test(modelFilename)) {\n return entry.config;\n }\n }\n return null;\n}\n\n/**\n * Check if a model filename is recognized as a video model.\n */\nexport function isKnownVideoModel(modelFilename: string): boolean {\n return getWorkflowForModel(modelFilename) !== null;\n}\n\n/**\n * Get all supported model families.\n */\nexport function getSupportedFamilies(): WorkflowConfig[] {\n return MODEL_REGISTRY.map((entry) => entry.config);\n}\n\nexport { buildLtxVideoWorkflow } from './ltx-video';\nexport { buildWan21Workflow } from './wan2.1';\n","# ComfyUI\n\nComfyUI runs video generation models (LTX-Video, Wan2.1) locally. MindStudio handles all the workflow complexity for you -- you just need to install ComfyUI and download a model.\n\n**Default port:** 8188\n**Website:** https://www.comfy.org\n**GitHub:** https://github.com/comfyanonymous/ComfyUI\n\n## What You'll Need\n\n- **Python 3.10 or newer** -- Check by opening a terminal and typing `python3 --version`. If you don't have it, download from https://www.python.org/downloads/\n\n- **Git** -- Check by typing `git --version`. If you don't have it, download from https://git-scm.com/downloads\n\n- **A GPU with 8+ GB of VRAM** -- Video generation is demanding. Without enough GPU memory, generation will fail or be extremely slow.\n\n## Step 1: Install ComfyUI\n\nOpen a terminal and run these commands one at a time, waiting for each to finish before running the next.\n\nDownload ComfyUI:\n\n```\ngit clone https://github.com/comfyanonymous/ComfyUI.git ~/ComfyUI\n```\n\nGo into the folder:\n\n```\ncd ~/ComfyUI\n```\n\nCreate an isolated Python environment:\n\n```\npython3 -m venv venv\n```\n\nActivate the environment:\n\n```\nsource venv/bin/activate\n```\n\n**Windows users:** use `venv\\Scripts\\activate` instead.\n\nInstall dependencies (may take a few minutes):\n\n```\npip install -r requirements.txt\n```\n\n## Step 2: Download a Video Model\n\nYou need at least one video model for MindStudio to use.\n\n### LTX-Video (recommended to start)\n\nFastest option, good for getting up and running quickly.\n\n1. Go to https://huggingface.co/Lightricks/LTX-Video\n2. Download `ltx-video-2b-v0.9.5.safetensors`\n3. Move the file into:\n\n```\n~/ComfyUI/models/checkpoints/\n```\n\n### Wan2.1\n\nHigher quality but slower and needs more VRAM. Requires multiple files -- make sure you download all of them or it won't work.\n\n1. Go to https://huggingface.co/Comfy-Org/Wan2.1_ComfyUI_repackaged\n2. Place UNET files in `~/ComfyUI/models/diffusion_models/`\n3. Place text encoder files in `~/ComfyUI/models/text_encoders/`\n4. Place VAE files in `~/ComfyUI/models/vae/`\n\n## Step 3: Start the Server\n\nEvery time you want to use ComfyUI with MindStudio, open a terminal and run:\n\n```\ncd ~/ComfyUI && source venv/bin/activate && python main.py --listen\n```\n\n**Windows users:**\n\n```\ncd %USERPROFILE%\\ComfyUI && venv\\Scripts\\activate && python main.py --listen\n```\n\n**Important:** The `--listen` flag is required. Without it, MindStudio cannot connect to the server.\n\nLeave this terminal window open. When you see \"To see the GUI go to: http://0.0.0.0:8188\", the server is ready. Go back to the tunnel and select **Refresh Providers** -- your models should appear.\n\n## Troubleshooting\n\n- **MindStudio says ComfyUI is \"not running\"** -- Make sure you started with the `--listen` flag. Without it, the server won't accept connections from MindStudio.\n\n- **Server is running but no models show up** -- Check that your model files are in the right folders under `~/ComfyUI/models/`. Checkpoint files go in `checkpoints/`, UNET files go in `diffusion_models/`.\n\n- **Generation fails with workflow errors** -- For Wan2.1, you need all three files (UNET, text encoder, VAE). If any are missing, generation will fail.\n\n- **\"CUDA out of memory\"** -- Video generation needs a lot of GPU memory. Try reducing the resolution or number of frames in your generation settings, or use LTX-Video which is lighter.\n\n- **Server crashes mid-generation** -- Press Ctrl+C in the terminal and run the start command again.\n","import ollama from './ollama';\nimport lmstudio from './lmstudio';\nimport stableDiffusion from './stable-diffusion';\nimport comfyui from './comfyui';\nimport type {\n Provider,\n LocalModel,\n ProviderSetupStatus,\n ModelCapability,\n} from './types';\n\nexport * from './types';\n\n// Registry of all available providers\nexport const allProviders: Provider[] = [\n ollama,\n lmstudio,\n stableDiffusion,\n comfyui,\n];\n\n/**\n * Get a provider instance by name\n */\nexport function getProvider(name: string): Provider | undefined {\n return allProviders.find((p) => p.name === name);\n}\n\n/**\n * Get all providers that support a given capability\n */\nexport function getProvidersByCapability(cap: ModelCapability): Provider[] {\n return allProviders.filter((p) => p.capabilities.includes(cap));\n}\n\n/**\n * Discover which providers are currently running\n */\nexport async function discoverRunningProviders(): Promise<Provider[]> {\n const results = await Promise.all(\n allProviders.map(async (provider) => ({\n provider,\n running: await provider.isRunning(),\n })),\n );\n\n return results.filter((r) => r.running).map((r) => r.provider);\n}\n\n/**\n * Discover all models from all running providers\n */\nexport async function discoverAllModels(): Promise<LocalModel[]> {\n const runningProviders = await discoverRunningProviders();\n\n const modelArrays = await Promise.all(\n runningProviders.map((p) => p.discoverModels()),\n );\n\n return modelArrays.flat();\n}\n\n/**\n * Check if any provider is running\n */\nexport async function isAnyProviderRunning(): Promise<boolean> {\n const results = await Promise.all(allProviders.map((p) => p.isRunning()));\n return results.some((r) => r);\n}\n\n/**\n * Get provider status for all providers\n */\nexport async function getProviderStatuses(): Promise<\n Array<{ provider: Provider; running: boolean }>\n> {\n return Promise.all(\n allProviders.map(async (provider) => ({\n provider,\n running: await provider.isRunning(),\n })),\n );\n}\n\n/**\n * Discover models filtered by capability\n */\nexport async function discoverModelsByCapability(\n capability: ModelCapability,\n): Promise<LocalModel[]> {\n const runningProviders = await discoverRunningProviders();\n const filteredProviders = runningProviders.filter((p) =>\n p.capabilities.includes(capability),\n );\n\n const modelArrays = await Promise.all(\n filteredProviders.map((p) => p.discoverModels()),\n );\n\n return modelArrays.flat();\n}\n\n/**\n * Detect installation/running status for all providers\n */\nexport async function detectAllProviderStatuses(): Promise<\n Array<{ provider: Provider; status: ProviderSetupStatus }>\n> {\n return Promise.all(\n allProviders.map(async (provider) => ({\n provider,\n status: await provider.detect(),\n })),\n );\n}\n\n/**\n * Discover all models with their parameter schemas\n * For providers with getParameterSchemas, fetches available parameters dynamically\n */\nexport async function discoverAllModelsWithParameters(): Promise<LocalModel[]> {\n const runningProviders = await discoverRunningProviders();\n\n const modelsWithParams = await Promise.all(\n runningProviders.map(async (provider) => {\n const models = await provider.discoverModels();\n\n if (typeof provider.getParameterSchemas === 'function') {\n const parameters = await provider.getParameterSchemas();\n return models.map((model) => ({\n ...model,\n parameters,\n }));\n }\n\n return models;\n }),\n );\n\n return modelsWithParams.flat();\n}\n","import { EventEmitter } from 'events';\n\nexport interface RequestStartEvent {\n id: string;\n modelId: string;\n requestType: 'llm_chat' | 'image_generation' | 'video_generation';\n timestamp: number;\n}\n\nexport interface RequestProgressEvent {\n id: string;\n content?: string;\n step?: number;\n totalSteps?: number;\n}\n\nexport interface RequestCompleteEvent {\n id: string;\n success: boolean;\n duration: number;\n result?: {\n chars?: number;\n imageSize?: number;\n videoSize?: number;\n };\n error?: string;\n}\n\nclass RequestEventEmitter extends EventEmitter {\n emitStart(event: RequestStartEvent) {\n this.emit('request:start', event);\n }\n\n emitProgress(event: RequestProgressEvent) {\n this.emit('request:progress', event);\n }\n\n emitComplete(event: RequestCompleteEvent) {\n this.emit('request:complete', event);\n }\n\n onStart(handler: (event: RequestStartEvent) => void) {\n this.on('request:start', handler);\n return () => this.off('request:start', handler);\n }\n\n onProgress(handler: (event: RequestProgressEvent) => void) {\n this.on('request:progress', handler);\n return () => this.off('request:progress', handler);\n }\n\n onComplete(handler: (event: RequestCompleteEvent) => void) {\n this.on('request:complete', handler);\n return () => this.off('request:complete', handler);\n }\n}\n\nexport const requestEvents = new RequestEventEmitter();\n","import {\n pollForRequest,\n submitProgress,\n submitGenerationProgress,\n submitResult,\n disconnectHeartbeat,\n type LocalModelRequest,\n} from './api';\nimport {\n getProvider,\n discoverAllModels,\n type Provider,\n type LocalModel,\n} from './providers';\nimport { requestEvents } from './events';\n\n/**\n * TunnelRunner handles the polling and request processing loop.\n * It emits events that listeners (TUI or simple chalk output) can subscribe to.\n */\nexport class TunnelRunner {\n private isRunning = false;\n private modelProviderMap: Map<string, Provider> = new Map();\n private models: string[] = [];\n\n /**\n * Start with a pre-discovered list of model names.\n * Used by the TUI, which discovers models itself.\n */\n async start(models: string[]): Promise<void> {\n if (this.isRunning) return;\n\n this.models = models;\n this.isRunning = true;\n\n // Build model -> provider mapping\n const allModels = await discoverAllModels();\n this.buildModelProviderMap(allModels);\n\n // Start polling loop\n this.pollLoop();\n }\n\n stop(): void {\n this.isRunning = false;\n disconnectHeartbeat().catch(() => {});\n }\n\n private buildModelProviderMap(models: LocalModel[]): void {\n this.modelProviderMap.clear();\n for (const model of models) {\n const provider = getProvider(model.provider);\n if (provider) {\n this.modelProviderMap.set(model.name, provider);\n }\n }\n }\n\n private async pollLoop(): Promise<void> {\n while (this.isRunning) {\n try {\n const request = await pollForRequest(this.models);\n if (request) {\n // Process request in background\n this.processRequest(request);\n }\n } catch (error) {\n // Wait before retrying on error\n await this.sleep(5000);\n }\n }\n }\n\n private async processRequest(request: LocalModelRequest): Promise<void> {\n const startTime = Date.now();\n\n // Emit start event\n requestEvents.emitStart({\n id: request.id,\n modelId: request.modelId,\n requestType: request.requestType,\n timestamp: startTime,\n });\n\n const provider = this.modelProviderMap.get(request.modelId);\n\n if (!provider) {\n const error = `Model ${request.modelId} not found`;\n await submitResult(request.id, false, undefined, error);\n requestEvents.emitComplete({\n id: request.id,\n success: false,\n duration: Date.now() - startTime,\n error,\n });\n return;\n }\n\n try {\n switch (request.requestType) {\n case 'llm_chat':\n await this.handleTextRequest(request, provider, startTime);\n break;\n case 'image_generation':\n await this.handleImageRequest(request, provider, startTime);\n break;\n case 'video_generation':\n await this.handleVideoRequest(request, provider, startTime);\n break;\n default:\n throw new Error(`Unsupported request type: ${request.requestType}`);\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n await submitResult(request.id, false, undefined, message);\n requestEvents.emitComplete({\n id: request.id,\n success: false,\n duration: Date.now() - startTime,\n error: message,\n });\n }\n }\n\n private async handleTextRequest(\n request: LocalModelRequest,\n provider: Provider,\n startTime: number,\n ): Promise<void> {\n if (!provider.chat) {\n throw new Error(`Provider does not support text generation`);\n }\n\n const messages = (request.payload.messages || []).map((m) => ({\n role: m.role as 'user' | 'assistant' | 'system',\n content: m.content,\n }));\n\n const stream = provider.chat(request.modelId, messages, {\n temperature: request.payload.temperature,\n maxTokens: request.payload.maxTokens,\n });\n\n let fullContent = '';\n let lastProgressUpdate = 0;\n const progressInterval = 100;\n\n for await (const chunk of stream) {\n fullContent += chunk.content;\n\n const now = Date.now();\n if (now - lastProgressUpdate > progressInterval) {\n await submitProgress(request.id, fullContent);\n requestEvents.emitProgress({\n id: request.id,\n content: fullContent,\n });\n lastProgressUpdate = now;\n }\n }\n\n await submitProgress(request.id, fullContent);\n await submitResult(request.id, true, {\n content: fullContent,\n usage: { promptTokens: 0, completionTokens: 0 },\n });\n\n requestEvents.emitComplete({\n id: request.id,\n success: true,\n duration: Date.now() - startTime,\n result: { chars: fullContent.length },\n });\n }\n\n private async handleImageRequest(\n request: LocalModelRequest,\n provider: Provider,\n startTime: number,\n ): Promise<void> {\n if (!provider.generateImage) {\n throw new Error(`Provider does not support image generation`);\n }\n\n const prompt = request.payload.prompt || '';\n const config = request.payload.config || {};\n\n let result;\n if (provider.generateImageWithProgress) {\n result = await provider.generateImageWithProgress(\n request.modelId,\n prompt,\n {\n negativePrompt: config.negativePrompt as string | undefined,\n width: config.width as number | undefined,\n height: config.height as number | undefined,\n steps: config.steps as number | undefined,\n cfgScale: config.cfgScale as number | undefined,\n seed: config.seed as number | undefined,\n sampler: config.sampler as string | undefined,\n },\n async (progress) => {\n await submitGenerationProgress(\n request.id,\n progress.step,\n progress.totalSteps,\n progress.preview,\n );\n requestEvents.emitProgress({\n id: request.id,\n step: progress.step,\n totalSteps: progress.totalSteps,\n });\n },\n );\n } else {\n result = await provider.generateImage(request.modelId, prompt, {\n negativePrompt: config.negativePrompt as string | undefined,\n width: config.width as number | undefined,\n height: config.height as number | undefined,\n steps: config.steps as number | undefined,\n cfgScale: config.cfgScale as number | undefined,\n seed: config.seed as number | undefined,\n sampler: config.sampler as string | undefined,\n });\n }\n\n await submitResult(request.id, true, {\n imageBase64: result.imageBase64,\n mimeType: result.mimeType,\n seed: result.seed,\n });\n\n const imageSize = Math.round((result.imageBase64.length * 3) / 4);\n\n requestEvents.emitComplete({\n id: request.id,\n success: true,\n duration: Date.now() - startTime,\n result: { imageSize },\n });\n }\n\n private async handleVideoRequest(\n request: LocalModelRequest,\n provider: Provider,\n startTime: number,\n ): Promise<void> {\n if (!provider.generateVideo) {\n throw new Error(`Provider does not support video generation`);\n }\n\n const prompt = request.payload.prompt || '';\n const config = request.payload.config || {};\n\n const result = await provider.generateVideo(\n request.modelId,\n prompt,\n {\n negativePrompt: config.negativePrompt as string | undefined,\n width: config.width as number | undefined,\n height: config.height as number | undefined,\n numFrames: config.numFrames as number | undefined,\n fps: config.fps as number | undefined,\n steps: config.steps as number | undefined,\n cfgScale: config.cfgScale as number | undefined,\n seed: config.seed as number | undefined,\n },\n async (progress) => {\n await submitGenerationProgress(\n request.id,\n progress.step,\n progress.totalSteps,\n );\n requestEvents.emitProgress({\n id: request.id,\n step: progress.step,\n totalSteps: progress.totalSteps,\n });\n },\n );\n\n await submitResult(request.id, true, {\n videoBase64: result.videoBase64,\n mimeType: result.mimeType,\n duration: result.duration,\n fps: result.fps,\n seed: result.seed,\n });\n\n const videoSize = Math.round((result.videoBase64.length * 3) / 4);\n\n requestEvents.emitComplete({\n id: request.id,\n success: true,\n duration: Date.now() - startTime,\n result: { videoSize },\n });\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"],"mappings":"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","names":["path","os","readme_default","readme_default","fs","path","os","readme_default","readme_default","fs","path","os","readme_default","readme_default","submitResult","config"]}
|