@shawnstack/quickforge 1.5.2 → 1.5.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/README.md +10 -10
- package/dist/assets/{AgentProfilesPage-DKyIh3dE.js → AgentProfilesPage-BToo_R3Y.js} +1 -1
- package/dist/assets/{ChatPanelHost-BUZ6scv9.js → ChatPanelHost-BTqhhkWK.js} +1 -1
- package/dist/assets/{PluginsPage-CN-SFQ_s.js → PluginsPage-DwzV2vQ4.js} +1 -1
- package/dist/assets/{ScheduledTasksPage-C0htXZk2.js → ScheduledTasksPage-Cbm6LVk3.js} +1 -1
- package/dist/assets/{SharedConversationPage-CxbAx1fN.js → SharedConversationPage-CHE9qABz.js} +1 -1
- package/dist/assets/{TerminalDock-_voUf7d-.js → TerminalDock-Loi8A4pJ.js} +1 -1
- package/dist/assets/{WorkspaceInspector-Ci4FuaZH.js → WorkspaceInspector-Nf5xELW7.js} +1 -1
- package/dist/assets/{WorkspaceReaderDialog-D75__GFg.js → WorkspaceReaderDialog-Bai7v3V0.js} +1 -1
- package/dist/assets/{diff-line-counts-DHyWKEXk.js → diff-line-counts-CCPYa_e0.js} +1 -1
- package/dist/assets/{index-BzOV50wA.js → index-Bt_dRvdG.js} +39 -5
- package/dist/assets/{index-BI7xZuj-.css → index-BzaZg9Br.css} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/mcp/config.mjs +20 -20
- package/server/routes/backup.mjs +84 -20
- package/server/storage.mjs +182 -48
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{wt as t}from"./icons-DzxBk7tb.js";import{n}from"./react-vendor-DsAeMFcm.js";import{h as r}from"./index-
|
|
1
|
+
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{wt as t}from"./icons-DzxBk7tb.js";import{n}from"./react-vendor-DsAeMFcm.js";import{h as r}from"./index-Bt_dRvdG.js";import{n as i,t as a}from"./monaco-dMY7_GLO.js";var o=e(t(),1);function s(){let[e,t]=(0,o.useState)(()=>r());return(0,o.useEffect)(()=>{if(typeof document>`u`)return;let e=document.documentElement,n=()=>t(r());n();let i=new MutationObserver(n);return i.observe(e,{attributes:!0,attributeFilter:[`class`]}),()=>i.disconnect()},[]),e}var c=n();function l({path:e,content:t,language:n}){return(0,c.jsx)(a,{value:t,language:n,theme:s()===`dark`?`vs-dark`:`vs`,options:{readOnly:!0,contextmenu:!1,automaticLayout:!0,minimap:{enabled:!1},fontSize:13,lineHeight:20,lineNumbers:`on`,scrollBeyondLastLine:!1,wordWrap:`off`,renderLineHighlight:`line`,folding:!1,glyphMargin:!1,scrollbar:{verticalScrollbarSize:8,horizontalScrollbarSize:8}}},e)}function u(e){let t=e.trim();if(t&&!/^(javascript|data|vbscript):/i.test(t)&&/^(https?:|mailto:|#|\/|\.\.?\/)/i.test(t))return t}function d(e,t){let n=[],r=/`([^`]+)`|\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|\*\*([^*]+)\*\*|__([^_]+)__|\*([^*\n]+)\*|_([^_\n]+)_/g,i=0,a=0,o;for(;o=r.exec(e);){o.index>i&&n.push(e.slice(i,o.index));let s=`${t}-inline-${a++}`;if(o[1])n.push((0,c.jsx)(`code`,{className:`rounded bg-muted/35 px-1 py-0.5 font-mono text-[0.85em] text-foreground/90`,children:o[1]},s));else if(o[2]&&o[3]){let e=u(o[3]);n.push(e?(0,c.jsx)(`a`,{className:`text-primary underline-offset-4 hover:underline`,href:e,target:e.startsWith(`http`)?`_blank`:void 0,rel:`noreferrer`,children:o[2]},s):`[${o[2]}](${o[3]})`)}else o[4]||o[5]?n.push((0,c.jsx)(`strong`,{className:`font-semibold text-foreground/95`,children:o[4]||o[5]},s)):(o[6]||o[7])&&n.push((0,c.jsx)(`em`,{className:`italic`,children:o[6]||o[7]},s));i=r.lastIndex}return i<e.length&&n.push(e.slice(i)),n.length?n:[e]}function f(e,t){return e.split(`
|
|
2
2
|
`).flatMap((e,n)=>{let r=d(e,`${t}-line-${n}`);return n===0?r:[(0,c.jsx)(`br`,{},`${t}-br-${n}`),...r]})}function p(e){return/^\s*(```|~~~)/.test(e)}function m(e){return/^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(e)}function h(e,t){return!!(e[t]?.includes(`|`)&&e[t+1]&&m(e[t+1]))}function g(e,t){let n=e[t]??``;return p(n)||h(e,t)||/^\s{0,3}#{1,6}\s+/.test(n)||/^\s{0,3}([-*_])(?:\s*\1){2,}\s*$/.test(n)||/^\s{0,3}>\s?/.test(n)||/^\s{0,3}[-*+]\s+/.test(n)||/^\s{0,3}\d+[.)]\s+/.test(n)}function _(e){return e.trim().replace(/^\|/,``).replace(/\|$/,``).split(`|`).map(e=>e.trim())}function v(e){let t=e.replace(/\r\n?/g,`
|
|
3
3
|
`).split(`
|
|
4
4
|
`),n=[],r=0,i=0;for(;r<t.length;){let e=t[r],a=`markdown-block-${i++}`;if(!e.trim()){r+=1;continue}if(p(e)){let i=e.match(/^\s*(```|~~~)\s*([^`]*)$/),o=i?.[1]??"```",s=i?.[2]?.trim(),l=[];for(r+=1;r<t.length&&!t[r].trimStart().startsWith(o);)l.push(t[r]),r+=1;r<t.length&&(r+=1),n.push((0,c.jsxs)(`figure`,{className:`my-5 overflow-hidden rounded-xl border border-border bg-muted/20`,children:[s?(0,c.jsx)(`figcaption`,{className:`border-b border-border px-3 py-1.5 font-mono text-[11px] text-muted-foreground/65`,children:s}):null,(0,c.jsx)(`pre`,{className:`overflow-auto p-4 text-[12px] leading-5`,children:(0,c.jsx)(`code`,{children:l.join(`
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ChatPanelHost-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ChatPanelHost-BTqhhkWK.js","assets/rolldown-runtime-DWdDZTNf.js","assets/pi-web-ui-CBet4bMl.js","assets/pi-ai-Cx633yhb.js","assets/lit-vendor-Dr3cpBGF.js","assets/icons-DzxBk7tb.js","assets/react-vendor-DsAeMFcm.js","assets/plugin-api-YfYj_Bd7.js","assets/logger-B65Akg8A.js","assets/TerminalDock-Loi8A4pJ.js","assets/xterm-5XDrJ343.js","assets/xterm-BrP-ENHg.css","assets/ScheduledTasksPage-Cbm6LVk3.js","assets/AgentProfilesPage-BToo_R3Y.js","assets/PluginsPage-DwzV2vQ4.js","assets/SharedConversationPage-CHE9qABz.js","assets/WorkspaceInspector-Nf5xELW7.js","assets/diff-line-counts-CCPYa_e0.js","assets/monaco-dMY7_GLO.js","assets/WorkspaceReaderDialog-Bai7v3V0.js"])))=>i.map(i=>d[i]);
|
|
2
2
|
import{i as e}from"./rolldown-runtime-DWdDZTNf.js";import{B as t,C as n,Ct as r,D as i,E as a,F as o,H as s,M as c,N as l,O as u,R as d,S as f,St as p,T as m,V as h,Z as g,_,a as v,b as y,c as b,d as x,dt as S,f as C,ft as w,gt as T,h as E,ht as D,i as ee,it as O,j as k,lt as A,m as j,mt as M,n as N,p as te,rt as P,s as F,st as ne,tt as I,u as L,v as re,vt as R,w as ie,wt as z,x as ae,xt as oe,y as se,yt as ce,z as le}from"./icons-DzxBk7tb.js";import{i as ue,n as de,r as fe}from"./react-vendor-DsAeMFcm.js";import{f as pe,p as B,u as me}from"./lit-vendor-Dr3cpBGF.js";import{n as he,r as ge,t as _e}from"./css-utils-rkE68RDy.js";import{_ as ve,a as ye,d as V,f as be,g as xe,h as Se,i as Ce,m as we,n as Te,o as Ee,p as De,r as Oe,t as ke,u as Ae}from"./pi-web-ui-CBet4bMl.js";import{_ as je,p as Me,y as Ne}from"./pi-ai-Cx633yhb.js";import{t as H}from"./logger-B65Akg8A.js";(function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var U=e(z(),1),Pe=fe(),Fe=`language`,Ie=[`en`,`zh`],Le={en:{language:`Language`,displayLanguage:`Display language`,languageDescription:`Choose the display language for 速构 QuickForge. The page will reload to apply the change.`,simplifiedChinese:`Simplified Chinese`,english:`English`,apply:`Apply`,noLanguageChange:`The selected language is already active.`,newChat:`New chat`,loadingChatWorkspace:`Loading chat workspace...`,localServiceUnavailableTitle:`Local QuickForge service unavailable`,localServiceUnavailableDescription:`QuickForge requires the local service for storage. Start QuickForge with npm run dev or the quickforge command, then reload this page.`,project:`Project`,projects:`Projects`,loadingProject:`Loading project...`,addProject:`Add project`,noProjects:`No projects yet.`,expandProject:`Expand project`,collapseProject:`Collapse project`,expandAllProjects:`Expand all projects`,collapseAllProjects:`Collapse all projects`,dragToReorder:`Drag to reorder`,newProjectChat:`New project chat`,projectChat:`Project chat`,normalChat:`Chat`,conversations:`Conversations`,noConversations:`No conversations`,filter:`Filter`,selecting:`Selecting...`,chooseFolder:`Choose folder`,selectProjectDirectory:`Select project directory`,selectProjectDirectoryDescription:`Browse local folders or paste a path, then choose the folder to add it as a project.`,quickAccess:`Quick access`,path:`Path`,go:`Go`,parentDirectory:`Parent directory`,noFolders:`No folders in this directory.`,selectThisFolder:`Select this folder`,folderPickerPathPlaceholder:`Enter or paste a folder path`,filesystemRootsFailed:`Failed to load filesystem roots.`,directoryLoadFailed:`Failed to load directory.`,noSavedConversations:`No saved conversations yet.`,rename:`Rename`,renameSession:`Rename conversation`,sessionName:`Conversation name`,deleteProject:`Delete project`,deleteProjectConfirm:`Are you sure you want to delete project "{name}"? Its conversations will be kept.`,deleteSession:`Delete session`,deleteSessionConfirm:`Are you sure you want to delete this conversation? This cannot be undone.`,deleteSessionFailed:`Failed to delete conversation.`,archiveSession:`Archive conversation`,confirmArchive:`Archive`,archivedConversations:`Archived conversations`,archivedConversationsDescription:`Archived conversations are hidden from the sidebar. Restore them here or delete them permanently.`,searchArchivedConversations:`Search archived conversations`,noArchivedConversations:`No archived conversations yet.`,archivedAt:`Archived at`,lastModified:`Last modified`,restoreSession:`Restore`,restoreSessionFailed:`Failed to restore conversation.`,sessionRestored:`Conversation restored.`,sessionNotFound:`Conversation not found.`,deletePermanently:`Delete`,deleteAll:`Delete all`,deleteArchivedSessionConfirm:`Permanently delete "{title}"? This cannot be undone.`,deleteAllArchivedSessionsConfirm:`Permanently delete all archived conversations? This cannot be undone.`,archivedSessionDeleted:`Archived conversation deleted.`,archivedSessionsDeleted:`Archived conversations deleted.`,allProjects:`All projects`,unknownProject:`Unknown project`,conversationCount:`{count} conversations`,confirm:`Confirm`,confirmDelete:`Delete`,settings:`Settings`,toggleSidebar:`Toggle sidebar`,failedToSelectProjectDirectory:`Failed to select project directory.`,projectSwitchFailed:`Failed to switch to the project for this conversation. Workspace tools were not started.`,copy:`Copy`,copied:`Copied`,svgDisplayMode:`SVG display mode`,svgPreviewMode:`Preview`,svgSourceMode:`Source`,svgEnlargePreview:`Click to enlarge SVG preview`,copySvgSource:`Copy SVG source`,downloadSvg:`Download SVG`,rollback:`Rollback`,retry:`Retry`,reloadPage:`Reload page`,fork:`Fork`,forkConversation:`Fork conversation from here`,yoloEnabledTitle:`Workspace access enabled: local tools can use this project`,yoloDisabledTitle:`Workspace access locked: local tools are blocked`,agentAccessMenuLabel:`Agent access mode`,agentAccessDefaultLabel:`Default permissions`,agentAccessFullLabel:`Full access`,agentAccessDefaultTitle:`Default permissions: work inside the current repository; ask before actions that may affect the system.`,agentAccessFullTitle:`Full access: developer-level authorization; tools can run automatically within the configured workspace boundaries.`,agentAccessModeSyncFailed:`Failed to sync Agent access mode.`,planModeLabel:`Plan`,planModeEnabledTitle:`Plan mode enabled: send the next message as /plan. Click to remove. Shortcut: Shift+Tab`,planModeDisabledTitle:`Plan mode: send the next message as /plan. Shortcut: Shift+Tab`,composerPlaceholder:`Describe what you want to build, change, or debug...`,assistantWaitingThinking:`Thinking`,assistantWaitingOrganizing:`Organizing the answer`,assistantWaitingContinuing:`This may take a little longer`,assistantWaitingAriaLabel:`Assistant is preparing a response`,customCommandsHint:`Custom commands`,customCommandsEmptyHint:`No project commands yet.`,customCommandsListDescription:`List project custom commands`,customCommandsNewDescription:`Create a project custom command`,planCommandDescription:`Create a plan first; this turn cannot edit files or run commands.`,reviewCommandDescription:`Review pending code changes before commit; this turn cannot edit files.`,summaryCommandDescription:`Create a new chat with this conversation summarized to reduce context usage.`,compactCommandDescription:`Compact this conversation context in place using the same rolling summary as auto-compaction.`,clearCommandDescription:`Clear the current chat history and context without calling the model.`,helpCommandDescription:`Show all available commands and their usage.`,yoloBlockedReason:`Local tool {name} was blocked by the current Agent permission mode. Switch to Full access or approve the tool call when prompted.`,globalToolBlockedReason:`Local tool {name} was blocked because this is a normal chat with no project attached. Start or open a project chat to use workspace tools.`,noActiveProjectToolBlockedReason:`Local tool {name} was blocked because there is no active project. Add or select a project to use workspace tools.`,generationStillRunning:`Generation is still running. Stop it or wait until it finishes before rolling back.`,noConversationTurnToRollback:`There is no conversation turn to roll back.`,rollbackConfirmTitle:`Confirm rollback?`,rollbackConfirm:`Roll back to before this message? This message and all following conversation history will be removed, and the message content will be restored to the composer.`,sharedRollbackConfirmTitle:`Confirm shared conversation rollback?`,sharedRollbackConfirm:`This will directly modify the sharer's original conversation. This message and all following conversation history will be removed, and the message content will be restored to the composer.`,confirmRollback:`Confirm rollback`,rollingBack:`Rolling back...`,rollbackFailed:`Rollback failed.`,retryFailed:`Retry failed.`,copyFailed:`Copy failed. Please check clipboard permissions.`,errorBoundaryTitle:`Something went wrong`,errorBoundaryUnexpected:`An unexpected error occurred.`,errorBoundaryTryAgain:`Try again`,execute:`Run`,addCustomModelFirst:`Please add a custom model in Settings and make sure the model ID is filled in before saving.`,modelSetupRequired:`Please add a model before starting a new chat.`,modelSetupTitle:`No model configured yet`,modelSetupDescription:`Add an OpenAI-Compatible or Anthropic-compatible model to start chatting. QuickForge will only use models that you configure.`,modelSetupSupports:`Supports LiteLLM, OpenRouter, DeepSeek, Qwen, Zhipu, Ollama, and most /v1/chat/completions services.`,modelSetupLocalStorage:`Providers, model IDs, and API keys are stored locally by the QuickForge service on this machine.`,modelSetupAddModel:`Add model`,modelSetupUseLiteLlmExample:`Use LiteLLM example`,firstUseGuideTitle:`Start with a safe workflow`,firstUseGuideDescription:`Add a project, ask QuickForge to understand it, and use /plan before granting local tool access for code changes.`,firstUseGuideStepModel:`Confirm the model you want to use.`,firstUseGuideStepProject:`Add a local project so AI can use workspace context.`,firstUseGuideStepPlan:`Use /plan first; that turn cannot edit files or run commands.`,firstUseGuideConfigureModel:`Configure model`,firstUseGuideAddProject:`Add project`,firstUseGuideUsePrompt:`Try example prompt`,firstUseGuideCopyPrompt:`Copy /plan example`,firstUseGuideDismiss:`Got it`,firstUseGuideProjectPrompt:`/plan Read this project and explain its structure, run commands, and main risks. Do not modify files yet.`,firstUseGuideGeneralPrompt:`/plan Break this request into implementation steps and risks first. Do not modify files yet.`,defaultOptions:`Default Options`,defaultOptionsDescription:`Configure the default model, thinking level, tool display, and context management for new chats and scheduled tasks.`,defaultModel:`Default model`,defaultThinkingLevel:`Default thinking level`,toolDisplay:`Tool Display`,showToolDetails:`Show detailed tool JSON`,expandToolsByDefault:`Expand tool calls by default`,showToolDetailsDescription:`When disabled, tool input and details JSON are hidden. Console output, status, summaries, and diffs remain visible.`,fontSize:`Font size`,fontSizeDescription:`Adjust the global base font size and common body text size.`,baseFontSize:`Base font size (px)`,bodyFontSize:`Body text size (px)`,bodyFontSizeNote:`Applies to the Tailwind text-sm utility used by common interface text.`,appearance:`Appearance`,appearanceDescription:`Customize the interface theme and font size.`,theme:`Theme`,themeDescription:`Switch between light and dark. Changes apply instantly.`,lightTheme:`Light`,darkTheme:`Dark`,appearanceSaved:`Appearance saved`,interfaceFontSize:`Interface font size`,messageFontSize:`Conversation font size`,messageFontSizeNote:`Applies to the main text in chat messages.`,customFontSize:`Custom`,fontSizeSmall:`Small`,fontSizeDefault:`Default`,fontSizeLarge:`Large`,fontSizeExtraLarge:`Extra Large`,advancedFontSizeSettings:`Advanced font size settings`,restoreDefault:`Restore default`,fontSizeSaved:`Font size saved`,toolDetailsHidden:`Tool details are hidden. Enable detailed tool JSON in Settings to view full parameters.`,toolArgsSummary:`Arguments summary`,saveDefaultOptions:`Save defaults`,saving:`Saving...`,defaultOptionsSaved:`Default options saved`,contextManagement:`Context Management`,autoCompactEnabled:`Automatically compact context`,autoCompactRequireConfirmation:`Ask before compacting automatically`,autoCompactTriggerNote:`Checks run before each model request. Lower the threshold or reduce the model Context Window to test triggering.`,autoCompactThresholdPercent:`Compact when context reaches (%)`,autoCompactKeepRecentTurns:`Keep recent user turns`,autoCompactDescription:`When the estimated next request reaches the configured share of the model context window, QuickForge summarizes older history and continues the current task. This uses one extra model call.`,autoCompactHistoryPreserved:`The full chat history remains visible; only the context sent to the model is compacted.`,thinkingLevel:`Thinking level`,thinkingOff:`Off`,thinkingLow:`Low`,thinkingMedium:`Medium`,thinkingHigh:`High`,thinkingXHigh:`XHigh`,currentConfiguration:`Current configuration`,thinkingSupported:`Thinking`,thinkingNotSupported:`This model does not support thinking levels.`,thinkingRequiresReasoningModel:`Thinking levels require a reasoning / thinking model.`,customModels:`Custom Models`,customModelsTitle:`Custom models`,customModelsDescription:`Only use custom OpenAI-Compatible models that you configure.`,addModel:`Add model`,editModel:`Edit model`,delete:`Delete`,editCustomModel:`Edit custom model`,addCustomModel:`Add custom model`,providerName:`Provider name`,providerNamePlaceholder:`e.g., LiteLLM`,protocolType:`Protocol type`,protocolHelp:`Use OpenAI Compatible for LiteLLM, OpenRouter, and most /v1/chat/completions services. Use Anthropic Messages only for the direct Anthropic API.`,apiKey:`API Key`,apiKeyPlaceholder:`Leave empty if not required`,showApiKey:`Show API Key`,hideApiKey:`Hide API Key`,customHeaders:`Custom Headers JSON`,customHeadersPlaceholder:`{
|
|
3
3
|
"X-Custom-Header": "value"
|
|
4
4
|
}`,customHeadersHelp:`Optional provider-level HTTP headers. Must be a JSON object with string values. Headers are saved locally with this model configuration.`,invalidHeadersJson:`Custom headers must be a valid JSON object with string key-value pairs.`,modelId:`Model ID`,modelIdPlaceholder:`e.g., anthropic/claude-sonnet-4`,contextWindow:`Context Window`,maxTokens:`Max Tokens`,reasoningModel:`Reasoning / Thinking model (DeepSeek V4, Qwen, etc.)`,providerProtocol:`Protocol`,model:`Model`,reasoning:`Reasoning`,noModelAdded:`No model added`,modelsCount:`{count} model(s)`,modelIndex:`Model #{index}`,modelsList:`Models`,atLeastOneModel:`At least one model is required.`,duplicateModelId:`Duplicate model IDs are not allowed.`,cancel:`Cancel`,save:`Save`,yes:`Yes`,no:`No`,loading:`Loading...`,noCustomModels:`No custom models yet. Click "Add model".`,fillProviderBaseUrlModel:`Please fill in provider name and Base URL.`,saveCustomModelFailed:`Failed to save custom model.`,confirmDeleteProvider:`Delete {name}?`,deleteFailed:`Delete failed.`,selectCustomModel:`Select custom model`,close:`Close`,back:`Back`,searchModels:`Search models...`,noMatchingCustomModels:`No matching custom models`,presets:`Quick templates`,presetOpenai:`OpenAI`,presetDeepseek:`DeepSeek`,presetGlm:`Zhipu GLM`,presetOllama:`Local Ollama`,presetLitellm:`LiteLLM Proxy`,presetCustom:`Custom`,providerAdvanced:`Advanced options`,expandModel:`Adjust context window, max tokens, reasoning`,addHeader:`Add header`,headerName:`Header name`,headerValue:`Value`,removeHeader:`Remove header`,testConnection:`Test connection`,testingConnection:`Testing...`,connectionOk:`Connection OK`,connectionFailed:`Connection failed`,testRequiresFields:`Fill in Base URL and at least one model ID.`,readFile:`Read File`,searchFiles:`Search Files`,writeFile:`Write File`,editFile:`Edit File`,runCommand:`Run Command`,presentFiles:`Present Files`,executeInTerminal:`Run in terminal`,confirmExecuteCommandTitle:`Run command in terminal?`,confirmExecuteMultipleCommands:`This will run multiple lines in your local terminal. Continue?`,confirmExecuteDangerousCommand:`This command may modify your system, publish packages, push code, or run a remote script. Continue?`,terminalCommandExecuteFailed:`Failed to run command in terminal.`,runSubagent:`Run subagent`,subagentGeneral:`General`,subagentExplore:`Explore`,subagentRunning:`{name} running`,subagentCompleted:`{name} completed`,subagentFailed:`{name} failed`,subagentTask:`Task`,subagentContext:`Context`,subagentExpectedOutput:`Expected output`,subagentResult:`Result`,subagentToolCalls:`Tool calls`,subagentToolApprovalWaiting:`{source} requests approval: {toolName}`,toolApprovalSourceSubagent:`Source: {source} subagent`,activateSkill:`Activate Skill`,readSkillResource:`Read Skill Resource`,yoloModeSyncFailed:`Failed to sync Agent access mode. The previous state has been restored.`,toolApprovalFailed:`Failed to submit tool approval. Please try again.`,toolApprovalSubmitting:`Submitting...`,terminateCommand:`Terminate`,terminateCommandTitle:`Terminate this running command`,commandTerminateRequested:`Terminating...`,running:`Running`,done:`Done`,error:`Error`,taskCompleted:`Task completed`,taskError:`Task error`,called:`Called`,input:`Input`,output:`Output`,details:`Details`,scheduledTasks:`Scheduled Tasks`,scheduledTasksDescription:`Tasks are saved in the local backend service and run by the cron expression parsed by AI.`,createTask:`Create task`,editTask:`Edit`,cancelEditTask:`Cancel edit`,saveTask:`Save task`,taskScheduleDescriptionLabel:`Schedule description`,taskScheduleDescriptionPlaceholder:`e.g., Every day at 9 AM, send this to AI: generate my daily sales report.`,quickAiParseTask:`AI parses this description into a cron expression. The system stores and runs by cron.`,taskTitleLabel:`Task name`,taskTitlePlaceholder:`e.g., Daily work summary`,promptContentLabel:`AI will send this content`,promptContentPlaceholder:`Write the exact content that should be sent to AI when this task runs.`,taskEnabledSwitch:`Enable this task`,taskInstructionPlaceholder:`e.g., Generate a daily sales report at 9 AM every day`,aiParseTask:`AI Parse`,confirmCreate:`Confirm create`,taskList:`Task list`,noScheduledTasks:`No scheduled tasks yet. Enter a natural language instruction above to create one.`,taskEnabled:`Enabled`,taskRunning:`Running`,taskPaused:`Paused`,taskFinished:`Completed`,taskFailed:`Failed`,executeNow:`Run now`,enable:`Enable`,pauseTask:`Pause`,deleteTask:`Delete`,recentExecutions:`Recent executions`,executionSuccess:`Success`,executionRunning:`Running`,nextExecution:`Next`,lastExecution:`Last`,noModelAvailable:`No models available`,noProjectBound:`No project`,aiParsed:`AI parsed, please confirm`,taskName:`Task name`,executionRule:`Execution rule`,nextExecutionTime:`Next execution`,taskProject:`Project`,taskThinkingLevel:`Thinking`,aiInstruction:`AI instruction`,taskModel:`Model`,taskThinking:`Thinking`,taskProjectLabel:`Project`,taskExecutionMode:`Execution mode`,taskExecutionModeSerial:`Serial`,taskExecutionModeParallel:`Parallel`,taskExecutionModeHelp:`This only controls whether the same task may overlap. Different scheduled tasks still run in parallel.`,tasksCount:`{total} tasks, {enabled} enabled`,confirmDeleteTask:`Are you sure you want to delete this scheduled task? This cannot be undone.`,waitingForResult:`Waiting for result`,autoRun:`Auto`,manualRun:`Manual test`,runInputContent:`Sent to AI`,runAiResult:`AI result`,runDuration:`Duration: `,taskListTab:`Task list`,executionHistoryTab:`Execution history`,agentsTab:`Agents`,agentsDescription:`Create reusable Agent Profiles for scheduled tasks and run_subagent delegation.`,createAgent:`Create agent`,editAgent:`Edit agent`,builtinAgent:`Built-in`,builtinAgentReadonly:`Built-in agents are read-only in this version.`,enabledAsSubagent:`Enabled as subagent`,enableAsSubagent:`Enable as subagent`,disableAsSubagent:`Disable as subagent`,noDescription:`No description.`,maxRuntimeMs:`Max runtime: `,maxToolCalls:`Max tool calls: `,defaultAgent:`Default Agent`,executionAgent:`Execution Agent: `,agentName:`Agent name`,agentLabel:`Display name`,agentLabelPlaceholder:`e.g., Code Review Agent`,agentDescription:`Description`,agentSystemPrompt:`System prompt`,allowedTools:`Allowed tools`,highRiskTool:`High risk`,confirmDeleteAgent:`Are you sure you want to delete this custom agent? Scheduled tasks using it will fall back to the default agent.`,aiFillAgent:`AI fill`,aiFillAgentDescription:`Describe the agent you want. AI will only fill agent name, display name, description, and system prompt.`,aiFillAgentPlaceholder:`e.g., Create a read-only code review agent focused on architecture, bugs, and test coverage.`,aiFillAgentLoading:`Generating...`,aiFillAgentNoModel:`Please configure a default model first.`,aiFillAgentFailed:`AI fill failed. Please check model configuration and API key, then try again.`,aiFillAgentInputRequired:`Please describe the agent you want to create.`,taskContent:`Task content`,viewDetails:`View details`,moreActions:`More actions`,historyFilters:`Filters`,allTasks:`All tasks`,allStatuses:`All statuses`,allTriggers:`All triggers`,triggerType:`Trigger`,keyword:`Keyword`,keywordPlaceholder:`Search input, result, or error`,startTime:`Start time`,endTime:`End time`,query:`Search`,reset:`Reset`,previousPage:`Previous`,nextPage:`Next`,pageSize:`{size} / page`,paginationSummary:`Page {page} / {pages}, {total} total`,noExecutionHistory:`No execution history yet.`,viewConversation:`View conversation`,createdAt:`Created at`,status:`Status`,search:`Search`,searchDialog:`Search conversations...`,noSearchResults:`No matching conversations found`,searchHint:`Enter keywords to search loaded conversations`,scheduledTasksLabel:`Scheduled Tasks`,skills:`Skills`,mcp:`MCP`,mcpServers:`MCP Servers`,plugins:`Plugins`,pluginMentionHeader:`Plugins`,composerAddMenu:`Add`,composerAddAttachment:`Attachment`,composerAddPlugins:`Plugins`,composerAddBack:`Back`,pluginOpenaiDocumentsName:`Documents`,pluginOpenaiDocumentsDescription:`Create and edit document artifacts`,pluginOpenaiSpreadsheetsName:`Spreadsheets`,pluginOpenaiSpreadsheetsDescription:`Create, analyze, and structure spreadsheet files`,pluginOpenaiPresentationsName:`Presentations`,pluginOpenaiPresentationsDescription:`Create and edit presentations`,pluginsDescription:`Manage local QuickForge plugins. This first version supports manifest-based plugins that contribute Agent tools.`,pluginsReload:`Reload plugins`,loadingPlugins:`Loading plugins...`,noPlugins:`No plugins found`,noPluginsDescription:`Place a plugin folder with plugin.json under one of these search paths, then reload.`,pluginsCount:`{total} plugins, {enabled} enabled`,pluginToolsCount:`{count} tools`,pluginPermissionsCount:`{count} permissions`,pluginDetails:`Plugin details`,pluginVersion:`Version`,pluginStatusLoaded:`Loaded`,pluginStatusDisabled:`Disabled`,pluginStatusError:`Error`,pluginTools:`Tools`,pluginPermissions:`Declared permissions`,pluginNoTools:`No tools declared.`,pluginNoPermissions:`No permissions declared.`,pluginTrustedNotice:`Plugins are local trusted Node.js code in this MVP; permissions are displayed for review and future enforcement.`,pluginDiscoveryErrors:`Plugin discovery errors`,enablePlugin:`Enable`,disablePlugin:`Disable`,pluginsLoadFailed:`Failed to load plugins.`,pluginsSaveFailed:`Failed to update plugin.`,manageMcpServers:`Manage MCP servers`,mcpNoServersDescription:`No MCP servers configured yet. Click "Add server" or paste an mcpServers JSON on the right.`,mcpConfiguredServers:`Configured servers`,mcpReconnect:`Reconnect`,mcpAddServer:`Add server`,mcpEditServer:`Edit server`,mcpServerName:`Server name`,mcpCommand:`Command`,mcpTransport:`Transport`,mcpUrl:`URL`,mcpArgs:`Arguments, one per line`,mcpCwd:`Working directory`,mcpEnv:`Environment variables, KEY=value per line`,mcpToolsCount:`{count} tools`,mcpLoadFailed:`Failed to load MCP servers.`,mcpSaveFailed:`Failed to save MCP server.`,mcpDeleteFailed:`Failed to delete MCP server.`,mcpReconnectFailed:`Failed to reconnect MCP servers.`,mcpDeleteConfirm:`Delete MCP server "{name}"?`,mcpImportConfig:`Import MCP JSON`,mcpImportConfigDescription:"Paste an MCP JSON configuration in mcpServers format. QuickForge supports stdio, HTTP, and SSE transports. For remote servers, headers are accepted and resolved from backend environment variables when using ${...}.",mcpUseExample:`Use example`,mcpImportUpdate:`Import / update`,mcpReplaceAll:`Replace all`,mcpReplaceConfirm:`This will remove MCP servers that are not included in the JSON. Continue?`,mcpInvalidJson:`MCP configuration must be valid JSON.`,mcpInvalidConfigJson:`MCP configuration must contain a mcpServers object.`,mcpEmptyConfigJson:`mcpServers cannot be empty.`,mcpInvalidServerName:`Invalid MCP server name: {name}. Use lowercase letters, numbers, and hyphens only.`,mcpInvalidServerConfig:`MCP server "{name}" must be an object.`,mcpInvalidTransport:`MCP server "{name}" transport must be stdio, http, or sse.`,mcpMissingCommand:`MCP server "{name}" requires command for stdio transport.`,mcpMissingUrl:`MCP server "{name}" requires url for HTTP/SSE transport.`,mcpArgsMustBeArray:`MCP server "{name}" args must be an array.`,mcpEnvMustBeObject:`MCP server "{name}" env must be an object.`,mcpHeadersMustBeObject:`MCP server "{name}" headers must be an object.`,mcpHeaders:`Headers, KEY=value per line`,mcpReconnectServer:`Reconnect`,mcpMoreTools:`+{count}`,mcpNamePlaceholder:`e.g. my-server`,mcpUrlPlaceholder:`https://example.com/mcp`,mcpCommandPlaceholder:`e.g. npx`,mcpTabServer:`Server`,mcpTabJson:`JSON`,optional:`Optional`,globalSkills:`Global Skills`,projectSkills:`Project Skills`,help:`Help`,projectCommands:`Project Commands`,projectCommandsDescription:`Configure extra Markdown slash-command directories for the current project. QuickForge also reads user-level commands from ~/.quickforge/commands/ (shared across all projects), then project directories .claude/commands, .opencode/commands, .ai/commands, and these configured directories in order. Later duplicate command names override earlier ones.`,selectProjectForCommands:`Please select or add a project before configuring project commands.`,commandDirectory:`Command directory`,commandDirectories:`Command directories`,commandDirectoryPlaceholder:`.claude/commands
|
|
5
5
|
.opencode/commands
|
|
6
|
-
D:\\shared\\ai-commands`,commandDirectoryHelp:`One directory per line. Supports relative paths and absolute paths. Relative paths are resolved from the current project root. Leave empty to use the built-in compatible command directories only.`,commandDirectoryExamples:`Examples`,projectCommandsSaved:`Project command settings saved.`,loadedCommands:`Loaded commands ({count})`,noCommandsLoaded:`No commands loaded yet. Add a directory above or create a command to get started.`,openCommandDir:`Open command directory`,createCommand:`New command`,newCommandPrompt:`Enter a command name (lowercase letters, numbers, hyphens):`,commandCreated:`Command created: {name}`,commandAlreadyExists:`Command already exists: {name}`,invalidCommandName:`Invalid command name. Use lowercase letters, numbers, and hyphens.`,manageSkills:`Manage skills`,manageGlobalSkills:`Manage global skills`,manageProjectSkills:`Manage project skills`,openFolder:`Open folder`,openInExplorer:`Open in Explorer`,openInExplorerFailed:`Failed to open the project folder.`,moreOptions:`More options`,pinSession:`Pin conversation`,unpinSession:`Unpin conversation`,shareSession:`Share conversation`,selectProjectForSkills:`Please select or add a project before managing skills.`,skillsDescription:`Select reusable Agent Skills enabled for project "{project}". QuickForge discloses only name/description in the prompt; full SKILL.md instructions are loaded on demand with activate_skill.`,globalSkillsDescription:`Select reusable Agent Skills enabled globally for QuickForge. Skills are discovered from ~/.claude/skills, ~/.opencode/skills, ~/.agents/skills, and ~/.quickforge/skills. Only the catalog is injected into new chats; instructions load on demand.`,projectSkillsDescription:`Select project Agent Skills for "{project}". Project skills are discovered from .claude/skills, .opencode/skills, .agents/skills, and .quickforge/skills; they override global skills with the same name and load on demand in new project chats.`,searchSkills:`Search skills...`,availableSkills:`Available skills`,selectedSkillsCount:`{count} selected`,noMatchingSkills:`No matching skills found`,skillSearchPaths:`Search paths`,failedToLoadSkills:`Failed to load skills.`,failedToSaveSkills:`Failed to save skills.`,readSkill:`Read skill`,readSkillContent:`Read skill content`,backToSkillList:`Back to skill list`,failedToReadSkill:`Failed to read skill content.`,noSkillContent:`This skill has no readable content.`,requestFailed:`Request failed`,backupRestore:`Backup & Restore`,backupRestoreDescription:`Export or restore QuickForge settings, providers, projects, scheduled tasks, and conversations. Imports create a safety backup on the local service before writing data. Backups may contain sensitive conversations, local paths, code snippets, and optionally API keys.`,exportData:`Export data`,exportDataDescription:`Download a JSON backup that you can keep or move to another QuickForge installation. API keys are excluded unless you explicitly include them.`,exportScope:`Export scope`,exportScopeAll:`Everything`,exportScopeConfig:`Configuration only`,exportScopeSessions:`Conversations only`,includeApiKeys:`Include API keys`,includeApiKeysDescription:`API keys are sensitive. Only enable this for private encrypted storage or trusted migration.`,backupExportSecretsConfirm:`This backup will contain API keys. Do not commit it to Git or share it with untrusted people. Continue?`,exportBackup:`Export backup`,backupExported:`Backup exported.`,backupExportFailed:`Backup export failed.`,importData:`Import data`,importDataDescription:`Restore a previously exported JSON backup. The file will be inspected first, then matching sections in the current local data will be replaced.`,importBackup:`Import backup`,backupInspectTitle:`Backup preview`,backupInspectExportedAt:`Exported at`,backupInspectVersion:`Version`,backupInspectScope:`Scope`,backupInspectSecrets:`Contains API keys`,backupInspectSections:`Sections`,backupInspectFailed:`Backup inspection failed.`,backupInspected:`Backup inspected. Choose what to restore below.`,selectRestoreSections:`Select data to restore`,confirmImportSelected:`Import selected data`,selectAtLeastOneRestoreSection:`Select at least one data section to restore.`,restoreSettings:`Settings`,restoreSettingsDescription:`App preferences such as language and default options.`,restoreProviderKeys:`API keys`,restoreProviderKeysDescription:`Sensitive provider API keys. Restoring replaces current saved keys.`,restoreCustomProviders:`Custom providers and models`,restoreCustomProvidersDescription:`Custom model providers, endpoints, model IDs, and related configuration.`,restoreProjects:`Projects`,restoreProjectsDescription:`Project list, active project, and selected skills.`,restoreScheduledTasks:`Scheduled tasks`,restoreScheduledTasksDescription:`Saved scheduled AI tasks.`,restoreConversations:`Conversations`,restoreConversationsDescription:`Conversation history and metadata. This is restored as one consistent unit.`,backupImportConfirm:`Importing will replace matching local QuickForge data. A safety backup will be created first. Continue?`,backupImported:`Backup imported. The app will reload.`,backupImportFailed:`Backup import failed.`,backupSafetyBackupPath:`Safety backup saved at`,about:`About`,aboutQuickForge:`About QuickForge`,aboutQuickForgeDescription:`View project information, GitHub repository, and install updates from npm.`,projectInfo:`Project information`,packageName:`Package`,currentVersion:`Current version`,latestVersion:`Latest version`,github:`GitHub`,checkUpdate:`Check for updates`,checkingUpdate:`Checking...`,checkUpdateDescription:`Check npm for the latest QuickForge release. Updating runs a global npm install on this computer.`,updateAvailableMessage:`A new version is available: {current} → {latest}.`,localVersionNewerMessage:`Local version {current} is newer than npm latest {latest}.`,alreadyLatestVersion:`QuickForge is up to date ({version}).`,updateNow:`Update now`,updatingQuickForge:`Updating QuickForge...`,updateCompleted:`Update completed. Please restart QuickForge and refresh this page.`,updateFailed:`Update failed.`,updateCheckFailed:`Failed to check for updates.`,updateCommand:`Command`,updateConfirm:`QuickForge will run this command on your computer:
|
|
6
|
+
D:\\shared\\ai-commands`,commandDirectoryHelp:`One directory per line. Supports relative paths and absolute paths. Relative paths are resolved from the current project root. Leave empty to use the built-in compatible command directories only.`,commandDirectoryExamples:`Examples`,projectCommandsSaved:`Project command settings saved.`,loadedCommands:`Loaded commands ({count})`,noCommandsLoaded:`No commands loaded yet. Add a directory above or create a command to get started.`,openCommandDir:`Open command directory`,createCommand:`New command`,newCommandPrompt:`Enter a command name (lowercase letters, numbers, hyphens):`,commandCreated:`Command created: {name}`,commandAlreadyExists:`Command already exists: {name}`,invalidCommandName:`Invalid command name. Use lowercase letters, numbers, and hyphens.`,manageSkills:`Manage skills`,manageGlobalSkills:`Manage global skills`,manageProjectSkills:`Manage project skills`,openFolder:`Open folder`,openInExplorer:`Open in Explorer`,openInExplorerFailed:`Failed to open the project folder.`,moreOptions:`More options`,pinSession:`Pin conversation`,unpinSession:`Unpin conversation`,shareSession:`Share conversation`,selectProjectForSkills:`Please select or add a project before managing skills.`,skillsDescription:`Select reusable Agent Skills enabled for project "{project}". QuickForge discloses only name/description in the prompt; full SKILL.md instructions are loaded on demand with activate_skill.`,globalSkillsDescription:`Select reusable Agent Skills enabled globally for QuickForge. Skills are discovered from ~/.claude/skills, ~/.opencode/skills, ~/.agents/skills, and ~/.quickforge/skills. Only the catalog is injected into new chats; instructions load on demand.`,projectSkillsDescription:`Select project Agent Skills for "{project}". Project skills are discovered from .claude/skills, .opencode/skills, .agents/skills, and .quickforge/skills; they override global skills with the same name and load on demand in new project chats.`,searchSkills:`Search skills...`,availableSkills:`Available skills`,selectedSkillsCount:`{count} selected`,noMatchingSkills:`No matching skills found`,skillSearchPaths:`Search paths`,failedToLoadSkills:`Failed to load skills.`,failedToSaveSkills:`Failed to save skills.`,readSkill:`Read skill`,readSkillContent:`Read skill content`,backToSkillList:`Back to skill list`,failedToReadSkill:`Failed to read skill content.`,noSkillContent:`This skill has no readable content.`,requestFailed:`Request failed`,backupRestore:`Backup & Restore`,backupRestoreDescription:`Export or restore QuickForge settings, providers, projects, scheduled tasks, and conversations. Imports create a safety backup on the local service before writing data. Backups may contain sensitive conversations, local paths, code snippets, and optionally API keys.`,exportData:`Export data`,exportDataDescription:`Download a JSON backup that you can keep or move to another QuickForge installation. API keys are excluded unless you explicitly include them.`,exportScope:`Export scope`,exportScopeAll:`Everything`,exportScopeConfig:`Configuration only`,exportScopeSessions:`Conversations only`,includeApiKeys:`Include API keys`,includeApiKeysDescription:`API keys are sensitive. Only enable this for private encrypted storage or trusted migration.`,backupExportSecretsConfirm:`This backup will contain API keys. Do not commit it to Git or share it with untrusted people. Continue?`,exportBackup:`Export backup`,backupExported:`Backup exported.`,backupExportFailed:`Backup export failed.`,importData:`Import data`,importDataDescription:`Restore a previously exported JSON backup. The file will be inspected first, then matching sections in the current local data will be replaced.`,importBackup:`Import backup`,backupInspectTitle:`Backup preview`,backupInspectExportedAt:`Exported at`,backupInspectVersion:`Version`,backupInspectScope:`Scope`,backupInspectSecrets:`Contains API keys`,backupInspectSections:`Sections`,backupInspectFailed:`Backup inspection failed.`,backupInspected:`Backup inspected. Choose what to restore below.`,selectRestoreSections:`Select data to restore`,restoreMode:`Restore mode`,restoreModeReplace:`Replace`,restoreModeReplaceDescription:`Replace local data in the selected sections entirely with the backup. Existing local data will be overwritten.`,restoreModeMerge:`Merge`,restoreModeMergeDescription:`Merge backup data into local. On conflict the backup wins; local-only entries are preserved.`,confirmImportSelected:`Import selected data`,selectAtLeastOneRestoreSection:`Select at least one data section to restore.`,restoreSettings:`Settings`,restoreSettingsDescription:`App preferences such as language and default options.`,restoreMcp:`MCP servers`,restoreMcpDescription:`Global MCP server definitions and their enable/disable state.`,restoreProviderKeys:`API keys`,restoreProviderKeysDescription:`Sensitive provider API keys. Restoring replaces current saved keys.`,restoreCustomProviders:`Custom providers and models`,restoreCustomProvidersDescription:`Custom model providers, endpoints, model IDs, and related configuration.`,restoreProjects:`Projects`,restoreProjectsDescription:`Project list, active project, and selected skills.`,restoreScheduledTasks:`Scheduled tasks`,restoreScheduledTasksDescription:`Saved scheduled AI tasks.`,restoreConversations:`Conversations`,restoreConversationsDescription:`Conversation history and metadata. This is restored as one consistent unit.`,backupImportConfirm:`Importing will replace matching local QuickForge data. A safety backup will be created first. Continue?`,backupImported:`Backup imported. The app will reload.`,backupImportFailed:`Backup import failed.`,backupSafetyBackupPath:`Safety backup saved at`,about:`About`,aboutQuickForge:`About QuickForge`,aboutQuickForgeDescription:`View project information, GitHub repository, and install updates from npm.`,projectInfo:`Project information`,packageName:`Package`,currentVersion:`Current version`,latestVersion:`Latest version`,github:`GitHub`,checkUpdate:`Check for updates`,checkingUpdate:`Checking...`,checkUpdateDescription:`Check npm for the latest QuickForge release. Updating runs a global npm install on this computer.`,updateAvailableMessage:`A new version is available: {current} → {latest}.`,localVersionNewerMessage:`Local version {current} is newer than npm latest {latest}.`,alreadyLatestVersion:`QuickForge is up to date ({version}).`,updateNow:`Update now`,updatingQuickForge:`Updating QuickForge...`,updateCompleted:`Update completed. Please restart QuickForge and refresh this page.`,updateFailed:`Update failed.`,updateCheckFailed:`Failed to check for updates.`,updateCommand:`Command`,updateConfirm:`QuickForge will run this command on your computer:
|
|
7
7
|
{command}
|
|
8
8
|
|
|
9
9
|
The update may require network access and npm permissions. Continue?`,updateFrequencySection:`Auto-check for updates`,updateFrequencyDescription:`Check for new releases in the background on startup. When a newer version is found, a gentle reminder appears in the bottom-left corner.`,frequencyStartup:`On every startup`,frequencyDaily:`Once a day`,frequencyWeekly:`Once a week`,frequencyOff:`Off`,lastCheckedAt:`Last checked: {time}`,lastCheckedNever:`Not checked yet`,newVersionAvailable:`New version {version} available`,newVersionAvailableSub:`Current {current} · click to view`,updateLater:`Later`,backendService:`Backend Service`,backendServiceDescription:`Restart the local QuickForge backend service. Running generations will be interrupted and the page will reconnect automatically.`,backendServiceStatus:`Service status`,restartBackendService:`Restart backend service`,restartBackendServiceDescription:`Use this when the local backend is stuck or after changing environment-level service settings.`,restartBackendConfirm:`Restart the backend service now? Running generations will be interrupted and the page will reconnect automatically.`,backendRestarting:`Backend is restarting...`,backendRestarted:`Backend restarted. Reloading...`,backendRestartFailed:`Backend restart failed.`,backendRestartTimeout:`Backend restart timed out. Please restart QuickForge manually.`,backendRestartUnsupported:`This launch mode does not support restarting from the UI. Please restart QuickForge manually.`,serviceMode:`Mode`,servicePid:`PID`,serviceStartedAt:`Started at`,serviceDataDir:`Data directory`,serviceWorkspace:`Workspace`,terminalShell:`Terminal shell`,terminalShellDescription:`QuickForge auto-detects common macOS, Windows, and Linux shells. Pick the checked default, or add a custom command/path only when it is missing. QUICKFORGE_TERMINAL_SHELL still takes priority.`,terminalShellAutoDetectedHint:`Detected entries are shown automatically for this computer.`,terminalShellDefault:`Default shell`,terminalShellSaved:`Terminal shell setting saved. New terminal sessions will use it.`,terminalShellProfilesSaved:`Terminal shell profiles saved.`,terminalShellCommand:`Custom shell command or path`,terminalShellCommandPlaceholder:`C:\\Program Files\\Git\\bin\\bash.exe`,terminalShellAdd:`Add`,terminalShellSetDefault:`Set as default`,terminalShellDefaultBadge:`Default`,terminalShellDetected:`Detected`,terminalShellNoDetected:`No shell was detected. Add a custom shell command or path below.`,terminalShellProfileRequired:`Enter a shell command or executable path before saving.`,terminalShellDeleteConfirm:`Delete terminal shell profile "{name}"?`,channels:`Channels`,channelsDescription:`Manage local communication channels that bridge external apps to QuickForge agents.`,channelsSecurityWarning:`Channel operations can start local processes on this computer. They are available only from the local machine.`,channelsEmpty:`No channels are available yet.`,start:`Start`,stop:`Stop`,restart:`Restart`,channelProvider:`Provider`,channelCommand:`Command`,channelPid:`PID`,channelStartedAt:`Started at`,channelWorkspace:`Launch workspace`,channelWorkspaceDescription:`WeChat ACP sessions start in the selected workspace. Use the default workspace for global, non-project chats.`,channelDefaultWorkspace:`Default workspace`,channelCurrentWorkspace:`Current workspace`,channelNoWorkspaces:`No workspace is available. Configure the default workspace before starting this channel.`,channelRequirements:`Requirements`,channelRecentLogs:`Recent logs`,channelNoLogs:`No logs yet.`,channelQrTitle:`Scan with WeChat`,channelQrDescription:`Use WeChat to scan the QR code shown below. If the terminal QR code is hard to scan, open the link instead.`,channelQrLink:`Login link`,channelStatusStopped:`Stopped`,channelStatusStarting:`Starting`,channelStatusWaitingScan:`Waiting for scan`,channelStatusRunning:`Running`,channelStatusStopping:`Stopping`,channelStatusError:`Error`,channelRestartConfirm:`Restart channel "{name}"?`,channelLogoutConfirm:`Log out channel "{name}"? You will need to scan again before using it.`,channelReloginConfirm:`Re-login channel "{name}"? The current process will stop and a new QR code will be generated.`,terminalNew:`New terminal`,terminalNewWith:`New terminal with`,terminalNewWithProfile:`New terminal: {name}`,terminalSelectShell:`Choose shell for new terminal`,terminalCollapse:`Collapse terminal`,terminalFullscreen:`Fullscreen terminal`,terminalExitFullscreen:`Exit fullscreen`,terminalStarting:`Starting terminal...`,terminalUnavailable:`Terminal unavailable`,terminalNoSessions:`No terminal sessions`,terminalCreateFailed:`Failed to create terminal`,terminalCloseFailed:`Failed to close terminal`,terminalConnectionFailed:`Failed to connect to terminal.`,terminalConnectionClosedUnexpectedly:`Terminal connection closed unexpectedly.`,terminalCloseSession:`Close {name}`,workspaceNoFilesToDisplay:`No files to display.`,workspaceNoWorkingTreeChanges:`No working tree changes.`,noProjectSelected:`No project selected`,workspacePanel:`Workspace`,workspaceExpandRightPanel:`Expand right panel`,workspaceCollapseRightPanel:`Collapse right panel`,workspaceOverview:`Overview`,workspaceFiles:`Workspace Files`,workspaceBrowser:`Browser`,workspaceChanges:`Changes`,workspaceCurrentArtifacts:`Current session changes`,workspaceNoArtifacts:`No AI-produced files detected in this session yet.`,workspacePresentedArtifact:`Presented artifact`,workspaceInferredArtifact:`Inferred artifact`,workspaceCommands:`Commands`,workspaceCommandOutput:`Output`,workspaceCurrentBranch:`Current branch`,workspaceChangeCount:`changes`,workspaceNotGitRepository:`This project is not a Git repository.`,workspaceSelectProject:`Select a project to inspect its workspace.`,workspaceLoading:`Loading workspace...`,workspaceLoadFailed:`Failed to load workspace.`,workspaceFilterFiles:`Filter files by name or path`,workspaceOpenFileFailed:`Failed to open file.`,workspaceOpenDiffFailed:`Failed to open diff.`,workspaceViewDiff:`View diff`,refreshWorkspace:`Refresh workspace`,closeWorkspace:`Close workspace`,workspaceFullscreen:`Fullscreen workspace`,workspaceExitFullscreen:`Exit fullscreen`,workspaceStaged:`Staged`,workspaceUntracked:`Untracked`,workspaceConflicts:`Conflicts`,workspaceStagedChanges:`Staged Changes`,workspaceReview:`Review`,workspaceCommitMessage:`Commit msg`,workspaceReviewPrompt:`Please review the current workspace changes and generate a concise summary, risk assessment, verification plan, and a suggested commit message.
|
|
@@ -16,7 +16,7 @@ Changed files:
|
|
|
16
16
|
"X-Custom-Header": "value"
|
|
17
17
|
}`,customHeadersHelp:`可选的提供商级 HTTP Headers。必须是值为字符串的 JSON 对象,会随模型配置保存在本地。`,invalidHeadersJson:`自定义 Headers 必须是有效 JSON 对象,并且键和值都必须是字符串。`,modelId:`模型 ID`,modelIdPlaceholder:`例如:anthropic/claude-sonnet-4`,contextWindow:`Context Window`,maxTokens:`Max Tokens`,reasoningModel:`推理/思考模型(DeepSeek V4、Qwen 等)`,providerProtocol:`协议`,model:`模型`,reasoning:`推理`,noModelAdded:`未添加模型`,modelsCount:`{count} 个模型`,modelIndex:`模型 #{index}`,modelsList:`模型列表`,atLeastOneModel:`至少需要一个模型。`,duplicateModelId:`模型 ID 不能重复。`,cancel:`取消`,save:`保存`,yes:`是`,no:`否`,loading:`加载中...`,noCustomModels:`还没有自定义模型,请点击"添加模型"。`,fillProviderBaseUrlModel:`请填写提供商名称和 Base URL。`,saveCustomModelFailed:`保存自定义模型失败。`,confirmDeleteProvider:`确定删除 {name} 吗?`,deleteFailed:`删除失败。`,selectCustomModel:`选择自定义模型`,close:`关闭`,back:`返回`,searchModels:`搜索模型...`,noMatchingCustomModels:`没有匹配的自定义模型`,presets:`快速模板`,presetOpenai:`OpenAI`,presetDeepseek:`DeepSeek`,presetGlm:`智谱 GLM`,presetOllama:`本地 Ollama`,presetLitellm:`LiteLLM 代理`,presetCustom:`自定义`,providerAdvanced:`高级选项`,expandModel:`调整上下文窗口、最大输出、推理`,addHeader:`添加请求头`,headerName:`请求头名称`,headerValue:`值`,removeHeader:`移除请求头`,testConnection:`测试连接`,testingConnection:`测试中…`,connectionOk:`连接成功`,connectionFailed:`连接失败`,testRequiresFields:`请填写 Base URL 和至少一个模型 ID。`,readFile:`读取文件`,searchFiles:`搜索文件`,writeFile:`写入文件`,editFile:`编辑文件`,runCommand:`运行命令`,presentFiles:`展示文件`,executeInTerminal:`在终端中执行`,confirmExecuteCommandTitle:`在终端中执行命令?`,confirmExecuteMultipleCommands:`即将在本地终端中执行多行命令,是否继续?`,confirmExecuteDangerousCommand:`该命令可能修改系统、发布包、推送代码或执行远程脚本,是否继续?`,terminalCommandExecuteFailed:`在终端中执行命令失败。`,runSubagent:`运行 subagent`,subagentGeneral:`General`,subagentExplore:`Explore`,subagentRunning:`{name} 运行中`,subagentCompleted:`{name} 已完成`,subagentFailed:`{name} 失败`,subagentTask:`任务`,subagentContext:`上下文`,subagentExpectedOutput:`期望输出`,subagentResult:`结果`,subagentToolCalls:`工具调用`,subagentToolApprovalWaiting:`{source} 请求审批:{toolName}`,toolApprovalSourceSubagent:`来源:{source} subagent`,activateSkill:`激活技能`,readSkillResource:`读取技能资源`,yoloModeSyncFailed:`同步 Agent 权限模式失败,已恢复为之前的状态。`,toolApprovalFailed:`提交工具审批失败,请重试。`,toolApprovalSubmitting:`提交中...`,terminateCommand:`终止`,terminateCommandTitle:`终止这个正在运行的命令`,commandTerminateRequested:`正在终止...`,running:`运行中`,done:`完成`,error:`错误`,taskCompleted:`对话任务完成`,taskError:`对话任务出错`,called:`已调用`,input:`输入`,output:`输出`,details:`详情`,scheduledTasks:`定时任务`,scheduledTasksDescription:`任务保存在本地后台服务中,并按 AI 解析出的 cron 表达式执行。`,createTask:`创建任务`,editTask:`编辑`,cancelEditTask:`取消编辑`,saveTask:`保存任务`,taskScheduleDescriptionLabel:`定时描述`,taskScheduleDescriptionPlaceholder:`例如:每天早上 9 点,把这段内容发给 AI:帮我生成销售日报。`,quickAiParseTask:`AI 会把这段描述解析为 cron 表达式,系统只保存并按 cron 执行。`,taskTitleLabel:`任务名称`,taskTitlePlaceholder:`例如:每日工作总结`,promptContentLabel:`AI 将发送的内容`,promptContentPlaceholder:`填写到点后原样发送给 AI 的内容。`,taskEnabledSwitch:`启用这个任务`,taskInstructionPlaceholder:`例如:每天早上 9 点帮我生成销售日报`,aiParseTask:`AI 解析任务`,confirmCreate:`确认创建`,taskList:`任务列表`,noScheduledTasks:`还没有定时任务。先输入一句自然语言指令创建一个。`,taskEnabled:`启用中`,taskRunning:`执行中`,taskPaused:`已暂停`,taskFinished:`已完成`,taskFailed:`执行失败`,executeNow:`立即执行`,enable:`启用`,pauseTask:`暂停`,deleteTask:`删除`,recentExecutions:`最近执行记录`,executionSuccess:`成功`,executionRunning:`执行中`,nextExecution:`下一次:`,lastExecution:`上次:`,noModelAvailable:`暂无可用模型`,noProjectBound:`不绑定项目`,aiParsed:`AI 已解析,请确认`,taskName:`任务名称:`,executionRule:`执行规则:`,nextExecutionTime:`下一次执行:`,taskProject:`项目:`,taskThinkingLevel:`思考:`,aiInstruction:`AI 指令:`,taskModel:`模型`,taskThinking:`思考`,taskProjectLabel:`项目`,taskExecutionMode:`执行模式`,taskExecutionModeSerial:`串行`,taskExecutionModeParallel:`并行`,taskExecutionModeHelp:`该设置只控制同一个任务是否允许重叠执行;不同定时任务之间仍可并行执行。`,tasksCount:`共 {total} 个任务,{enabled} 个启用中`,confirmDeleteTask:`确定要删除这个定时任务吗?删除后不可恢复。`,waitingForResult:`等待结果`,autoRun:`自动执行`,manualRun:`手动测试`,runInputContent:`发送给 AI 的内容`,runAiResult:`AI 结果`,runDuration:`耗时:`,taskListTab:`任务列表`,executionHistoryTab:`执行历史`,agentsTab:`Agents`,agentsDescription:`创建可复用的 Agent Profile,用于定时任务和 run_subagent 委派。`,createAgent:`创建 Agent`,editAgent:`编辑 Agent`,builtinAgent:`内置`,builtinAgentReadonly:`内置 Agent 在当前版本中只读。`,enabledAsSubagent:`允许作为 sub agent`,enableAsSubagent:`启用作为 sub agent`,disableAsSubagent:`禁用作为 sub agent`,noDescription:`暂无描述。`,maxRuntimeMs:`最大运行时间:`,maxToolCalls:`最大工具调用:`,defaultAgent:`默认 Agent`,executionAgent:`执行 Agent:`,agentName:`Agent 名称`,agentLabel:`显示名称`,agentLabelPlaceholder:`例如:代码审查 Agent`,agentDescription:`描述`,agentSystemPrompt:`系统提示词`,allowedTools:`可用工具`,highRiskTool:`高风险`,confirmDeleteAgent:`确定删除这个自定义 Agent 吗?使用它的定时任务将回退到默认 Agent。`,aiFillAgent:`AI 填充`,aiFillAgentDescription:`描述你想创建的 Agent,AI 只会填充 Agent 名称、显示名称、描述和系统提示词。`,aiFillAgentPlaceholder:`例如:生成一个只读代码审查 Agent,重点检查架构、潜在 bug 和测试覆盖。`,aiFillAgentLoading:`生成中...`,aiFillAgentNoModel:`请先配置默认模型。`,aiFillAgentFailed:`AI 填充失败,请检查模型配置和 API Key 后重试。`,aiFillAgentInputRequired:`请描述你想创建的 Agent。`,taskContent:`任务内容`,viewDetails:`查看详情`,moreActions:`更多操作`,historyFilters:`筛选条件`,allTasks:`全部任务`,allStatuses:`全部状态`,allTriggers:`全部触发方式`,triggerType:`触发方式`,keyword:`关键词`,keywordPlaceholder:`搜索输入、结果或错误`,startTime:`开始时间`,endTime:`结束时间`,query:`查询`,reset:`重置`,previousPage:`上一页`,nextPage:`下一页`,pageSize:`每页 {size} 条`,paginationSummary:`第 {page} / {pages} 页,共 {total} 条`,noExecutionHistory:`暂无执行历史。`,viewConversation:`查看对话`,createdAt:`创建时间`,status:`状态`,search:`搜索`,searchDialog:`搜索对话记录...`,noSearchResults:`没有找到相关对话`,searchHint:`输入关键词搜索已加载的对话记录`,scheduledTasksLabel:`定时任务`,skills:`技能`,mcp:`MCP`,mcpServers:`MCP 服务`,plugins:`插件`,pluginMentionHeader:`插件`,composerAddMenu:`添加`,composerAddAttachment:`附件`,composerAddPlugins:`插件`,composerAddBack:`返回`,pluginOpenaiDocumentsName:`文档`,pluginOpenaiDocumentsDescription:`创建和编辑文档产物`,pluginOpenaiSpreadsheetsName:`表格`,pluginOpenaiSpreadsheetsDescription:`创建、分析和整理表格文件`,pluginOpenaiPresentationsName:`演示文稿`,pluginOpenaiPresentationsDescription:`创建和编辑演示文稿`,pluginsDescription:`管理本地 QuickForge 插件。当前首版支持通过 manifest 声明并贡献 Agent 工具的插件。`,pluginsReload:`重新加载插件`,loadingPlugins:`正在加载插件...`,noPlugins:`未发现插件`,noPluginsDescription:`将包含 plugin.json 的插件目录放到以下任一搜索路径,然后重新加载。`,pluginsCount:`共 {total} 个插件,{enabled} 个已启用`,pluginToolsCount:`{count} 个工具`,pluginPermissionsCount:`{count} 个权限`,pluginDetails:`插件详情`,pluginVersion:`版本`,pluginStatusLoaded:`已加载`,pluginStatusDisabled:`已停用`,pluginStatusError:`错误`,pluginTools:`工具`,pluginPermissions:`声明权限`,pluginNoTools:`未声明工具。`,pluginNoPermissions:`未声明权限。`,pluginTrustedNotice:`首版插件属于本地可信 Node.js 代码;权限目前用于展示和后续强校验。`,pluginDiscoveryErrors:`插件发现错误`,enablePlugin:`启用`,disablePlugin:`禁用`,pluginsLoadFailed:`加载插件失败。`,pluginsSaveFailed:`更新插件失败。`,manageMcpServers:`管理 MCP 服务`,mcpNoServersDescription:`还没有配置 MCP 服务。点击「添加服务」,或在右侧粘贴 mcpServers JSON 配置。`,mcpConfiguredServers:`已配置服务`,mcpReconnect:`重新连接`,mcpAddServer:`添加服务`,mcpEditServer:`编辑服务`,mcpServerName:`服务名称`,mcpCommand:`命令`,mcpTransport:`传输方式`,mcpUrl:`URL`,mcpArgs:`参数,每行一个`,mcpCwd:`工作目录`,mcpEnv:`环境变量,每行 KEY=value`,mcpToolsCount:`{count} 个工具`,mcpLoadFailed:`加载 MCP 服务失败。`,mcpSaveFailed:`保存 MCP 服务失败。`,mcpDeleteFailed:`删除 MCP 服务失败。`,mcpReconnectFailed:`重新连接 MCP 服务失败。`,mcpDeleteConfirm:`确定删除 MCP 服务「{name}」吗?`,mcpImportConfig:`导入 MCP JSON`,mcpImportConfigDescription:"直接粘贴 mcpServers 格式的 MCP JSON 配置。QuickForge 支持 stdio、HTTP 和 SSE 传输;远程服务可使用 headers,并支持通过 ${...} 从后端进程环境变量读取。",mcpUseExample:`使用示例`,mcpImportUpdate:`导入 / 更新`,mcpReplaceAll:`替换全部`,mcpReplaceConfirm:`这会删除当前未包含在 JSON 中的 MCP 服务,确定继续吗?`,mcpInvalidJson:`MCP 配置必须是合法 JSON。`,mcpInvalidConfigJson:`MCP 配置必须包含 mcpServers 对象。`,mcpEmptyConfigJson:`mcpServers 不能为空。`,mcpInvalidServerName:`MCP 服务名称无效:{name}。请只使用小写字母、数字和连字符。`,mcpInvalidServerConfig:`MCP 服务「{name}」必须是对象。`,mcpInvalidTransport:`MCP 服务「{name}」的传输方式必须是 stdio、http 或 sse。`,mcpMissingCommand:`MCP 服务「{name}」使用 stdio 传输时必须提供 command。`,mcpMissingUrl:`MCP 服务「{name}」使用 HTTP/SSE 传输时必须提供 url。`,mcpArgsMustBeArray:`MCP 服务「{name}」的 args 必须是数组。`,mcpEnvMustBeObject:`MCP 服务「{name}」的 env 必须是对象。`,mcpHeadersMustBeObject:`MCP 服务「{name}」的 headers 必须是对象。`,mcpHeaders:`Headers,每行 KEY=value`,mcpReconnectServer:`重连`,mcpMoreTools:`+{count}`,mcpNamePlaceholder:`例如 my-server`,mcpUrlPlaceholder:`https://example.com/mcp`,mcpCommandPlaceholder:`例如 npx`,mcpTabServer:`服务`,mcpTabJson:`JSON`,optional:`可选`,globalSkills:`全局技能`,projectSkills:`项目技能`,help:`帮助`,projectCommands:`项目命令`,projectCommandsDescription:`为当前项目配置额外的 Markdown slash command 目录。QuickForge 还会读取用户级目录 ~/.quickforge/commands/(所有项目共享),然后依次读取项目目录 .claude/commands、.opencode/commands、.ai/commands 及此处的配置目录;同名 command 以后面的目录覆盖前面的目录。`,selectProjectForCommands:`请先选择或添加一个项目,再配置项目命令。`,commandDirectory:`命令目录`,commandDirectories:`命令目录`,commandDirectoryPlaceholder:`.claude/commands
|
|
18
18
|
.opencode/commands
|
|
19
|
-
D:\\shared\\ai-commands`,commandDirectoryHelp:`一行一个目录。支持相对路径和绝对路径。相对路径会基于当前项目根目录解析。留空则只使用内置兼容命令目录。`,commandDirectoryExamples:`示例`,projectCommandsSaved:`项目命令设置已保存。`,loadedCommands:`已加载命令({count})`,noCommandsLoaded:`暂未加载到任何命令。请在上方添加目录或新建命令后重试。`,openCommandDir:`打开命令目录`,createCommand:`新建命令`,newCommandPrompt:`请输入命令名(小写字母、数字、连字符):`,commandCreated:`命令已创建:{name}`,commandAlreadyExists:`命令已存在:{name}`,invalidCommandName:`命令名无效,请使用小写字母、数字和连字符。`,manageSkills:`管理技能`,manageGlobalSkills:`管理全局技能`,manageProjectSkills:`管理项目技能`,openFolder:`打开文件夹`,openInExplorer:`在资源管理器打开`,openInExplorerFailed:`打开项目目录失败。`,moreOptions:`更多选项`,pinSession:`置顶对话`,unpinSession:`取消置顶`,shareSession:`分享对话`,selectProjectForSkills:`请先选择或添加一个项目,再管理技能。`,skillsDescription:`选择项目「{project}」启用的 Agent Skills。QuickForge 只在提示词中披露名称/描述;完整 SKILL.md 指令会在需要时通过 activate_skill 按需加载。`,globalSkillsDescription:`选择 QuickForge 全局启用的 Agent Skills。技能会从 ~/.claude/skills、~/.opencode/skills、~/.agents/skills 和 ~/.quickforge/skills 发现。新对话只注入目录,完整指令按需加载。`,projectSkillsDescription:`选择项目「{project}」启用的 Agent Skills。项目技能从 .claude/skills、.opencode/skills、.agents/skills 和 .quickforge/skills 发现;同名项目技能会覆盖全局技能,并只在新项目对话中按需加载。`,searchSkills:`搜索技能...`,availableSkills:`可用技能`,selectedSkillsCount:`已选择 {count} 个`,noMatchingSkills:`没有匹配的技能`,skillSearchPaths:`搜索路径`,failedToLoadSkills:`加载技能失败。`,failedToSaveSkills:`保存技能失败。`,readSkill:`阅读技能`,readSkillContent:`阅读技能内容`,backToSkillList:`返回技能列表`,failedToReadSkill:`读取技能内容失败。`,noSkillContent:`该技能没有可阅读的内容。`,requestFailed:`请求失败`,backupRestore:`备份与恢复`,backupRestoreDescription:`导出或恢复 QuickForge 的设置、模型提供商、项目、定时任务和对话。导入前本地服务会先创建一份安全备份。备份可能包含敏感对话、本机路径、代码片段,并可选包含 API Key。`,exportData:`导出数据`,exportDataDescription:`下载 JSON 备份文件,可自行保存或迁移到其他 QuickForge 安装。默认不包含 API Key,除非你明确勾选。`,exportScope:`导出范围`,exportScopeAll:`全部数据`,exportScopeConfig:`仅配置`,exportScopeSessions:`仅对话`,includeApiKeys:`包含 API Key`,includeApiKeysDescription:`API Key 属于敏感信息。仅在私密加密保存或可信迁移时启用。`,backupExportSecretsConfirm:`此备份将包含 API Key。请不要提交到 Git 或分享给不可信人员。是否继续?`,exportBackup:`导出备份`,backupExported:`备份已导出。`,backupExportFailed:`导出备份失败。`,importData:`导入数据`,importDataDescription:`恢复之前导出的 JSON 备份。系统会先检查文件内容,然后替换当前本地数据中对应的部分。`,importBackup:`导入备份`,backupInspectTitle:`备份预览`,backupInspectExportedAt:`导出时间`,backupInspectVersion:`版本`,backupInspectScope:`范围`,backupInspectSecrets:`包含 API Key`,backupInspectSections:`数据项`,backupInspectFailed:`检查备份失败。`,backupInspected:`备份已检查,请在下方选择要恢复的数据。`,selectRestoreSections:`选择要恢复的数据`,confirmImportSelected:`导入所选数据`,selectAtLeastOneRestoreSection:`请至少选择一个要恢复的数据项。`,restoreSettings:`设置`,restoreSettingsDescription:`语言、默认选项等应用偏好设置。`,restoreProviderKeys:`API Key`,restoreProviderKeysDescription:`敏感的模型提供商 API Key。恢复后会替换当前保存的密钥。`,restoreCustomProviders:`自定义提供商和模型`,restoreCustomProvidersDescription:`自定义模型提供商、端点、模型 ID 及相关配置。`,restoreProjects:`项目`,restoreProjectsDescription:`项目列表、当前项目和已选择的技能。`,restoreScheduledTasks:`定时任务`,restoreScheduledTasksDescription:`已保存的 AI 定时任务。`,restoreConversations:`对话`,restoreConversationsDescription:`对话历史和元数据。会作为一个一致的整体恢复。`,backupImportConfirm:`导入会替换当前 QuickForge 本地数据中对应的部分。系统会先创建安全备份。是否继续?`,backupImported:`备份已导入,应用即将刷新。`,backupImportFailed:`导入备份失败。`,backupSafetyBackupPath:`安全备份保存位置`,about:`关于`,aboutQuickForge:`关于 QuickForge`,aboutQuickForgeDescription:`查看项目信息、GitHub 仓库,并从 npm 安装更新。`,projectInfo:`项目信息`,packageName:`包名`,currentVersion:`当前版本`,latestVersion:`最新版本`,github:`GitHub`,checkUpdate:`检查更新`,checkingUpdate:`检查中...`,checkUpdateDescription:`从 npm 检查 QuickForge 最新版本。点击更新会在这台电脑上执行全局 npm 安装。`,updateAvailableMessage:`发现新版本:{current} → {latest}。`,localVersionNewerMessage:`本地版本 {current} 高于 npm 最新版本 {latest}。`,alreadyLatestVersion:`QuickForge 已是最新版本({version})。`,updateNow:`立即更新`,updatingQuickForge:`正在更新 QuickForge...`,updateCompleted:`更新完成。请重启 QuickForge 并刷新页面。`,updateFailed:`更新失败。`,updateCheckFailed:`检查更新失败。`,updateCommand:`命令`,updateConfirm:`QuickForge 将在这台电脑上执行以下命令:
|
|
19
|
+
D:\\shared\\ai-commands`,commandDirectoryHelp:`一行一个目录。支持相对路径和绝对路径。相对路径会基于当前项目根目录解析。留空则只使用内置兼容命令目录。`,commandDirectoryExamples:`示例`,projectCommandsSaved:`项目命令设置已保存。`,loadedCommands:`已加载命令({count})`,noCommandsLoaded:`暂未加载到任何命令。请在上方添加目录或新建命令后重试。`,openCommandDir:`打开命令目录`,createCommand:`新建命令`,newCommandPrompt:`请输入命令名(小写字母、数字、连字符):`,commandCreated:`命令已创建:{name}`,commandAlreadyExists:`命令已存在:{name}`,invalidCommandName:`命令名无效,请使用小写字母、数字和连字符。`,manageSkills:`管理技能`,manageGlobalSkills:`管理全局技能`,manageProjectSkills:`管理项目技能`,openFolder:`打开文件夹`,openInExplorer:`在资源管理器打开`,openInExplorerFailed:`打开项目目录失败。`,moreOptions:`更多选项`,pinSession:`置顶对话`,unpinSession:`取消置顶`,shareSession:`分享对话`,selectProjectForSkills:`请先选择或添加一个项目,再管理技能。`,skillsDescription:`选择项目「{project}」启用的 Agent Skills。QuickForge 只在提示词中披露名称/描述;完整 SKILL.md 指令会在需要时通过 activate_skill 按需加载。`,globalSkillsDescription:`选择 QuickForge 全局启用的 Agent Skills。技能会从 ~/.claude/skills、~/.opencode/skills、~/.agents/skills 和 ~/.quickforge/skills 发现。新对话只注入目录,完整指令按需加载。`,projectSkillsDescription:`选择项目「{project}」启用的 Agent Skills。项目技能从 .claude/skills、.opencode/skills、.agents/skills 和 .quickforge/skills 发现;同名项目技能会覆盖全局技能,并只在新项目对话中按需加载。`,searchSkills:`搜索技能...`,availableSkills:`可用技能`,selectedSkillsCount:`已选择 {count} 个`,noMatchingSkills:`没有匹配的技能`,skillSearchPaths:`搜索路径`,failedToLoadSkills:`加载技能失败。`,failedToSaveSkills:`保存技能失败。`,readSkill:`阅读技能`,readSkillContent:`阅读技能内容`,backToSkillList:`返回技能列表`,failedToReadSkill:`读取技能内容失败。`,noSkillContent:`该技能没有可阅读的内容。`,requestFailed:`请求失败`,backupRestore:`备份与恢复`,backupRestoreDescription:`导出或恢复 QuickForge 的设置、模型提供商、项目、定时任务和对话。导入前本地服务会先创建一份安全备份。备份可能包含敏感对话、本机路径、代码片段,并可选包含 API Key。`,exportData:`导出数据`,exportDataDescription:`下载 JSON 备份文件,可自行保存或迁移到其他 QuickForge 安装。默认不包含 API Key,除非你明确勾选。`,exportScope:`导出范围`,exportScopeAll:`全部数据`,exportScopeConfig:`仅配置`,exportScopeSessions:`仅对话`,includeApiKeys:`包含 API Key`,includeApiKeysDescription:`API Key 属于敏感信息。仅在私密加密保存或可信迁移时启用。`,backupExportSecretsConfirm:`此备份将包含 API Key。请不要提交到 Git 或分享给不可信人员。是否继续?`,exportBackup:`导出备份`,backupExported:`备份已导出。`,backupExportFailed:`导出备份失败。`,importData:`导入数据`,importDataDescription:`恢复之前导出的 JSON 备份。系统会先检查文件内容,然后替换当前本地数据中对应的部分。`,importBackup:`导入备份`,backupInspectTitle:`备份预览`,backupInspectExportedAt:`导出时间`,backupInspectVersion:`版本`,backupInspectScope:`范围`,backupInspectSecrets:`包含 API Key`,backupInspectSections:`数据项`,backupInspectFailed:`检查备份失败。`,backupInspected:`备份已检查,请在下方选择要恢复的数据。`,selectRestoreSections:`选择要恢复的数据`,restoreMode:`恢复模式`,restoreModeReplace:`替换`,restoreModeReplaceDescription:`用备份内容完全替换所选分区的本地数据,现有本地数据将被覆盖。`,restoreModeMerge:`合并`,restoreModeMergeDescription:`将备份内容合并到本地,冲突时以备份为准,本地独有的条目将被保留。`,confirmImportSelected:`导入所选数据`,selectAtLeastOneRestoreSection:`请至少选择一个要恢复的数据项。`,restoreSettings:`设置`,restoreSettingsDescription:`语言、默认选项等应用偏好设置。`,restoreMcp:`MCP 服务`,restoreMcpDescription:`全局 MCP 服务定义及其启用/停用状态。`,restoreProviderKeys:`API Key`,restoreProviderKeysDescription:`敏感的模型提供商 API Key。恢复后会替换当前保存的密钥。`,restoreCustomProviders:`自定义提供商和模型`,restoreCustomProvidersDescription:`自定义模型提供商、端点、模型 ID 及相关配置。`,restoreProjects:`项目`,restoreProjectsDescription:`项目列表、当前项目和已选择的技能。`,restoreScheduledTasks:`定时任务`,restoreScheduledTasksDescription:`已保存的 AI 定时任务。`,restoreConversations:`对话`,restoreConversationsDescription:`对话历史和元数据。会作为一个一致的整体恢复。`,backupImportConfirm:`导入会替换当前 QuickForge 本地数据中对应的部分。系统会先创建安全备份。是否继续?`,backupImported:`备份已导入,应用即将刷新。`,backupImportFailed:`导入备份失败。`,backupSafetyBackupPath:`安全备份保存位置`,about:`关于`,aboutQuickForge:`关于 QuickForge`,aboutQuickForgeDescription:`查看项目信息、GitHub 仓库,并从 npm 安装更新。`,projectInfo:`项目信息`,packageName:`包名`,currentVersion:`当前版本`,latestVersion:`最新版本`,github:`GitHub`,checkUpdate:`检查更新`,checkingUpdate:`检查中...`,checkUpdateDescription:`从 npm 检查 QuickForge 最新版本。点击更新会在这台电脑上执行全局 npm 安装。`,updateAvailableMessage:`发现新版本:{current} → {latest}。`,localVersionNewerMessage:`本地版本 {current} 高于 npm 最新版本 {latest}。`,alreadyLatestVersion:`QuickForge 已是最新版本({version})。`,updateNow:`立即更新`,updatingQuickForge:`正在更新 QuickForge...`,updateCompleted:`更新完成。请重启 QuickForge 并刷新页面。`,updateFailed:`更新失败。`,updateCheckFailed:`检查更新失败。`,updateCommand:`命令`,updateConfirm:`QuickForge 将在这台电脑上执行以下命令:
|
|
20
20
|
{command}
|
|
21
21
|
|
|
22
22
|
更新可能需要网络访问和 npm 权限。是否继续?`,updateFrequencySection:`自动检查更新`,updateFrequencyDescription:`启动时在后台检测新版本。发现新版本时,会在左下角轻轻提醒。`,frequencyStartup:`每次启动检查`,frequencyDaily:`每天一次`,frequencyWeekly:`每周一次`,frequencyOff:`关闭`,lastCheckedAt:`上次检查:{time}`,lastCheckedNever:`尚未检查`,newVersionAvailable:`发现新版本 {version}`,newVersionAvailableSub:`当前 {current} · 点击查看`,updateLater:`稍后`,backendService:`后端服务`,backendServiceDescription:`重启 QuickForge 本地后端服务。正在运行的生成会被中断,页面会自动重新连接。`,backendServiceStatus:`服务状态`,restartBackendService:`重启后端服务`,restartBackendServiceDescription:`当本地后端卡住,或调整了服务级环境配置后,可以在这里重启。`,restartBackendConfirm:`确定现在重启后端服务吗?正在运行的生成会被中断,页面会自动重新连接。`,backendRestarting:`后端正在重启...`,backendRestarted:`后端已重启,正在刷新页面...`,backendRestartFailed:`后端重启失败。`,backendRestartTimeout:`后端重启超时,请手动重启 QuickForge。`,backendRestartUnsupported:`当前启动方式不支持从界面重启,请手动重启 QuickForge。`,serviceMode:`模式`,servicePid:`PID`,serviceStartedAt:`启动时间`,serviceDataDir:`数据目录`,serviceWorkspace:`工作区`,terminalShell:`终端 Shell`,terminalShellDescription:`QuickForge 会自动识别这台电脑上常见的 macOS、Windows 和 Linux Shell。勾选默认项即可;只有缺少时才需要添加自定义命令或路径。QUICKFORGE_TERMINAL_SHELL 仍会优先生效。`,terminalShellAutoDetectedHint:`已识别的条目会自动显示在列表中。`,terminalShellDefault:`默认 Shell`,terminalShellSaved:`终端 Shell 设置已保存,新建终端会话会使用该设置。`,terminalShellProfilesSaved:`终端 Shell 配置已保存。`,terminalShellCommand:`自定义 Shell 命令或路径`,terminalShellCommandPlaceholder:`C:\\Program Files\\Git\\bin\\bash.exe`,terminalShellAdd:`添加`,terminalShellSetDefault:`设为默认`,terminalShellDefaultBadge:`默认`,terminalShellDetected:`已识别`,terminalShellNoDetected:`未识别到可用 Shell,请在下方添加自定义 Shell 命令或路径。`,terminalShellProfileRequired:`保存前请输入 Shell 命令或可执行文件路径。`,terminalShellDeleteConfirm:`确定删除终端 Shell 配置“{name}”吗?`,channels:`渠道`,channelsDescription:`管理把外部应用接入 QuickForge Agent 的本地通信渠道。`,channelsSecurityWarning:`渠道操作会在本机启动本地进程。出于安全考虑,仅允许从本机访问。`,channelsEmpty:`暂无可用渠道。`,start:`启动`,stop:`停止`,restart:`重启`,channelProvider:`提供方`,channelCommand:`命令`,channelPid:`PID`,channelStartedAt:`启动时间`,channelWorkspace:`启动工作区`,channelWorkspaceDescription:`微信 ACP 会话会在所选工作区启动。使用默认工作区时,对应非项目的全局对话。`,channelDefaultWorkspace:`默认工作区`,channelCurrentWorkspace:`当前工作区`,channelNoWorkspaces:`当前没有可用工作区。请先配置默认工作区再启动此渠道。`,channelRequirements:`要求`,channelRecentLogs:`最近日志`,channelNoLogs:`暂无日志。`,channelQrTitle:`使用微信扫码`,channelQrDescription:`请用微信扫描下方二维码。如果终端二维码不易扫描,也可以打开登录链接。`,channelQrLink:`登录链接`,channelStatusStopped:`已停止`,channelStatusStarting:`启动中`,channelStatusWaitingScan:`等待扫码`,channelStatusRunning:`运行中`,channelStatusStopping:`停止中`,channelStatusError:`出错`,channelRestartConfirm:`确定重启渠道“{name}”吗?`,channelLogoutConfirm:`确定退出渠道“{name}”的登录吗?再次使用前需要重新扫码。`,channelReloginConfirm:`确定重新登录渠道“{name}”吗?当前进程会停止,并生成新的二维码。`,terminalNew:`新建终端`,terminalNewWith:`新建终端使用`,terminalNewWithProfile:`新建终端:{name}`,terminalSelectShell:`选择 Shell 新建终端`,terminalCollapse:`收起终端`,terminalFullscreen:`全屏终端`,terminalExitFullscreen:`退出全屏`,terminalStarting:`正在启动终端...`,terminalUnavailable:`终端不可用`,terminalNoSessions:`没有终端会话`,terminalCreateFailed:`创建终端失败`,terminalCloseFailed:`关闭终端失败`,terminalConnectionFailed:`连接终端失败。`,terminalConnectionClosedUnexpectedly:`终端连接异常断开。`,terminalCloseSession:`关闭 {name}`,workspaceNoFilesToDisplay:`没有可显示的文件。`,workspaceNoWorkingTreeChanges:`工作区没有变更。`,noProjectSelected:`未选择项目`,workspacePanel:`工作空间`,workspaceExpandRightPanel:`展开右侧边栏`,workspaceCollapseRightPanel:`关闭右侧边栏`,workspaceOverview:`概览`,workspaceFiles:`工作空间文件`,workspaceBrowser:`浏览器`,workspaceChanges:`变更`,workspaceCurrentArtifacts:`当前 Session 修改`,workspaceNoArtifacts:`当前 Session 尚未检测到 AI 产生的文件。`,workspacePresentedArtifact:`展示产物`,workspaceInferredArtifact:`推断产物`,workspaceCommands:`命令`,workspaceCommandOutput:`输出`,workspaceCurrentBranch:`当前分支`,workspaceChangeCount:`项变更`,workspaceNotGitRepository:`此项目不是 Git 仓库。`,workspaceSelectProject:`请选择一个项目来查看工作空间。`,workspaceLoading:`正在加载工作空间...`,workspaceLoadFailed:`加载工作空间失败。`,workspaceFilterFiles:`按名称或路径筛选文件`,workspaceOpenFileFailed:`打开文件失败。`,workspaceOpenDiffFailed:`打开 diff 失败。`,workspaceViewDiff:`查看 diff`,refreshWorkspace:`刷新工作空间`,closeWorkspace:`关闭工作空间`,workspaceFullscreen:`全屏工作空间`,workspaceExitFullscreen:`退出全屏`,workspaceStaged:`已暂存`,workspaceUntracked:`未跟踪`,workspaceConflicts:`冲突`,workspaceStagedChanges:`已暂存变更`,workspaceReview:`审查`,workspaceCommitMessage:`提交信息`,workspaceReviewPrompt:`请审查当前工作空间的变更,并生成一份简要的总结、风险评估、验证计划以及建议的提交信息。
|
|
@@ -728,7 +728,7 @@ D:\\shared\\ai-commands`,commandDirectoryHelp:`一行一个目录。支持相对
|
|
|
728
728
|
${this.error?B`<span class="text-sm text-destructive">${this.error}</span>`:null}
|
|
729
729
|
</div>
|
|
730
730
|
</div>
|
|
731
|
-
`}},Gs=`quickforge-default-options-settings-tab`;customElements.get(Gs)||customElements.define(Gs,Ws);function Ks(){return document.createElement(Gs)}var qs=`quickforge-backup`,Js=[{id:`settings`,countKey:`settings`,label:()=>G(`restoreSettings`),description:()=>G(`restoreSettingsDescription`)},{id:`providerKeys`,countKey:`providerKeys`,label:()=>G(`restoreProviderKeys`),description:()=>G(`restoreProviderKeysDescription`)},{id:`customProviders`,countKey:`customProviders`,label:()=>G(`restoreCustomProviders`),description:()=>G(`restoreCustomProvidersDescription`)},{id:`projects`,countKey:`projects`,label:()=>G(`restoreProjects`),description:()=>G(`restoreProjectsDescription`)},{id:`scheduledTasks`,countKey:`scheduledTasks`,label:()=>G(`restoreScheduledTasks`),description:()=>G(`restoreScheduledTasksDescription`)},{id:`conversations`,countKey:`sessions`,label:()=>G(`restoreConversations`),description:()=>G(`restoreConversationsDescription`)}];function Ys(e,t){let n=new Blob([`${JSON.stringify(t,null,2)}\n`],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=e,document.body.appendChild(i),i.click(),i.remove(),URL.revokeObjectURL(r)}function Xs(){return new Date().toISOString().replace(/[:.]/g,`-`)}function Zs(e){return e?Object.entries(e).map(([e,t])=>`${e}: ${t}`).join(`, `):``}function Qs(e){return Js.filter(t=>(e.sections?.[t.countKey]??0)>0)}var $s=class extends Ee{exportScope=`all`;includeSecrets=!1;busy=!1;message=``;error=``;safetyBackupPath=``;pendingImport=null;getTabName(){return G(`backupRestore`)}setScope(e){this.exportScope=e===`config`||e===`sessions`?e:`all`,this.exportScope===`sessions`&&(this.includeSecrets=!1),this.clearStatus(),this.requestUpdate()}clearStatus(){this.message=``,this.error=``,this.safetyBackupPath=``}setIncludeSecrets(e){this.includeSecrets=e&&this.exportScope!==`sessions`,this.message=``,this.error=``,this.requestUpdate()}async exportBackup(){if(!(this.includeSecrets&&!await Y({description:G(`backupExportSecretsConfirm`),confirmLabel:G(`exportBackup`),cancelLabel:G(`cancel`)}))){this.busy=!0,this.clearStatus(),this.requestUpdate();try{let e=new URLSearchParams({scope:this.exportScope,includeSecrets:this.includeSecrets?`1`:`0`}),t=await fetch(`/api/backup/export?${e.toString()}`,{cache:`no-store`}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||G(`backupExportFailed`));let r=this.includeSecrets?`with-secrets`:`no-secrets`;Ys(`${qs}-${this.exportScope}-${r}-${Xs()}.json`,n),this.message=G(`backupExported`)}catch(e){this.error=e instanceof Error?e.message:G(`backupExportFailed`)}finally{this.busy=!1,this.requestUpdate()}}}async inspectBackup(e){let t=await fetch(`/api/backup/inspect`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||G(`backupInspectFailed`));if(!n)throw Error(G(`backupInspectFailed`));return n}async importBackupFromFile(e){this.busy=!0,this.clearStatus(),this.pendingImport=null,this.requestUpdate();try{let t=await e.text(),n=JSON.parse(t),r=await this.inspectBackup(n),i=new Set(Qs(r).map(e=>e.id));this.pendingImport={backup:n,inspect:r,selectedSections:i},this.message=G(`backupInspected`)}catch(e){this.error=e instanceof Error?e.message:G(`backupImportFailed`)}finally{this.busy=!1,this.requestUpdate()}}togglePendingSection(e,t){this.pendingImport&&(t?this.pendingImport.selectedSections.add(e):this.pendingImport.selectedSections.delete(e),this.message=``,this.error=``,this.requestUpdate())}cancelPendingImport(){this.pendingImport=null,this.message=``,this.error=``,this.requestUpdate()}async confirmPendingImport(){if(this.pendingImport){if(this.pendingImport.selectedSections.size===0){this.error=G(`selectAtLeastOneRestoreSection`),this.requestUpdate();return}this.busy=!0,this.clearStatus(),this.requestUpdate();try{let e=await fetch(`/api/backup/import`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({backup:this.pendingImport.backup,sections:[...this.pendingImport.selectedSections]})}),t=await e.json().catch(()=>null);if(!e.ok)throw Error(t?.error||G(`backupImportFailed`));let n=Zs(t?.summary);this.safetyBackupPath=t?.safetyBackupPath||``,this.pendingImport=null,this.message=n?`${G(`backupImported`)} ${n}`:G(`backupImported`),window.setTimeout(()=>window.location.reload(),1500)}catch(e){this.error=e instanceof Error?e.message:G(`backupImportFailed`)}finally{this.busy=!1,this.requestUpdate()}}}handleFileChange(e){let t=e.target,n=t.files?.[0];t.value=``,n&&this.importBackupFromFile(n)}renderPendingImport(){if(!this.pendingImport)return null;let{inspect:e,selectedSections:t}=this.pendingImport,n=Qs(e);return B`
|
|
731
|
+
`}},Gs=`quickforge-default-options-settings-tab`;customElements.get(Gs)||customElements.define(Gs,Ws);function Ks(){return document.createElement(Gs)}var qs=`quickforge-backup`,Js=[{id:`settings`,countKey:`settings`,label:()=>G(`restoreSettings`),description:()=>G(`restoreSettingsDescription`)},{id:`mcp`,countKey:`mcp`,label:()=>G(`restoreMcp`),description:()=>G(`restoreMcpDescription`)},{id:`providerKeys`,countKey:`providerKeys`,label:()=>G(`restoreProviderKeys`),description:()=>G(`restoreProviderKeysDescription`)},{id:`customProviders`,countKey:`customProviders`,label:()=>G(`restoreCustomProviders`),description:()=>G(`restoreCustomProvidersDescription`)},{id:`projects`,countKey:`projects`,label:()=>G(`restoreProjects`),description:()=>G(`restoreProjectsDescription`)},{id:`scheduledTasks`,countKey:`scheduledTasks`,label:()=>G(`restoreScheduledTasks`),description:()=>G(`restoreScheduledTasksDescription`)},{id:`conversations`,countKey:`sessions`,label:()=>G(`restoreConversations`),description:()=>G(`restoreConversationsDescription`)}];function Ys(e,t){let n=new Blob([`${JSON.stringify(t,null,2)}\n`],{type:`application/json`}),r=URL.createObjectURL(n),i=document.createElement(`a`);i.href=r,i.download=e,document.body.appendChild(i),i.click(),i.remove(),URL.revokeObjectURL(r)}function Xs(){return new Date().toISOString().replace(/[:.]/g,`-`)}function Zs(e){return e?Object.entries(e).map(([e,t])=>`${e}: ${t}`).join(`, `):``}function Qs(e){return Js.filter(t=>(e.sections?.[t.countKey]??0)>0)}var $s=class extends Ee{exportScope=`all`;includeSecrets=!1;busy=!1;message=``;error=``;safetyBackupPath=``;pendingImport=null;getTabName(){return G(`backupRestore`)}setScope(e){this.exportScope=e===`config`||e===`sessions`?e:`all`,this.exportScope===`sessions`&&(this.includeSecrets=!1),this.clearStatus(),this.requestUpdate()}clearStatus(){this.message=``,this.error=``,this.safetyBackupPath=``}setIncludeSecrets(e){this.includeSecrets=e&&this.exportScope!==`sessions`,this.message=``,this.error=``,this.requestUpdate()}async exportBackup(){if(!(this.includeSecrets&&!await Y({description:G(`backupExportSecretsConfirm`),confirmLabel:G(`exportBackup`),cancelLabel:G(`cancel`)}))){this.busy=!0,this.clearStatus(),this.requestUpdate();try{let e=new URLSearchParams({scope:this.exportScope,includeSecrets:this.includeSecrets?`1`:`0`}),t=await fetch(`/api/backup/export?${e.toString()}`,{cache:`no-store`}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||G(`backupExportFailed`));let r=this.includeSecrets?`with-secrets`:`no-secrets`;Ys(`${qs}-${this.exportScope}-${r}-${Xs()}.json`,n),this.message=G(`backupExported`)}catch(e){this.error=e instanceof Error?e.message:G(`backupExportFailed`)}finally{this.busy=!1,this.requestUpdate()}}}async inspectBackup(e){let t=await fetch(`/api/backup/inspect`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(e)}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||G(`backupInspectFailed`));if(!n)throw Error(G(`backupInspectFailed`));return n}async importBackupFromFile(e){this.busy=!0,this.clearStatus(),this.pendingImport=null,this.requestUpdate();try{let t=await e.text(),n=JSON.parse(t),r=await this.inspectBackup(n),i=new Set(Qs(r).map(e=>e.id));this.pendingImport={backup:n,inspect:r,selectedSections:i,mode:`replace`},this.message=G(`backupInspected`)}catch(e){this.error=e instanceof Error?e.message:G(`backupImportFailed`)}finally{this.busy=!1,this.requestUpdate()}}togglePendingSection(e,t){this.pendingImport&&(t?this.pendingImport.selectedSections.add(e):this.pendingImport.selectedSections.delete(e),this.message=``,this.error=``,this.requestUpdate())}setRestoreMode(e){this.pendingImport&&(this.pendingImport.mode=e,this.message=``,this.error=``,this.requestUpdate())}cancelPendingImport(){this.pendingImport=null,this.message=``,this.error=``,this.requestUpdate()}async confirmPendingImport(){if(this.pendingImport){if(this.pendingImport.selectedSections.size===0){this.error=G(`selectAtLeastOneRestoreSection`),this.requestUpdate();return}this.busy=!0,this.clearStatus(),this.requestUpdate();try{let e=await fetch(`/api/backup/import`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({backup:this.pendingImport.backup,sections:[...this.pendingImport.selectedSections],mode:this.pendingImport.mode})}),t=await e.json().catch(()=>null);if(!e.ok)throw Error(t?.error||G(`backupImportFailed`));let n=Zs(t?.summary);this.safetyBackupPath=t?.safetyBackupPath||``,this.pendingImport=null,this.message=n?`${G(`backupImported`)} ${n}`:G(`backupImported`),window.setTimeout(()=>window.location.reload(),1500)}catch(e){this.error=e instanceof Error?e.message:G(`backupImportFailed`)}finally{this.busy=!1,this.requestUpdate()}}}handleFileChange(e){let t=e.target,n=t.files?.[0];t.value=``,n&&this.importBackupFromFile(n)}renderPendingImport(){if(!this.pendingImport)return null;let{inspect:e,selectedSections:t}=this.pendingImport,n=Qs(e);return B`
|
|
732
732
|
<section class="rounded-lg border border-amber-500/30 bg-amber-500/5 p-4">
|
|
733
733
|
<h4 class="text-sm font-semibold text-foreground">${G(`backupInspectTitle`)}</h4>
|
|
734
734
|
<dl class="mt-3 grid gap-1 text-sm text-muted-foreground">
|
|
@@ -744,6 +744,40 @@ D:\\shared\\ai-commands`,commandDirectoryHelp:`一行一个目录。支持相对
|
|
|
744
744
|
</div>
|
|
745
745
|
`:null}
|
|
746
746
|
|
|
747
|
+
<div class="mt-4">
|
|
748
|
+
<div class="text-sm font-medium text-foreground">${G(`restoreMode`)}</div>
|
|
749
|
+
<div class="mt-2 grid gap-2">
|
|
750
|
+
<label class="flex items-start gap-2 rounded-md border border-border bg-background/60 p-3 text-sm ${this.pendingImport.mode===`replace`?`border-primary`:``}">
|
|
751
|
+
<input
|
|
752
|
+
class="mt-1"
|
|
753
|
+
type="radio"
|
|
754
|
+
name="restore-mode"
|
|
755
|
+
.checked=${this.pendingImport.mode===`replace`}
|
|
756
|
+
?disabled=${this.busy}
|
|
757
|
+
@change=${()=>this.setRestoreMode(`replace`)}
|
|
758
|
+
/>
|
|
759
|
+
<span>
|
|
760
|
+
<span class="block text-foreground">${G(`restoreModeReplace`)}</span>
|
|
761
|
+
<span class="block text-xs text-muted-foreground">${G(`restoreModeReplaceDescription`)}</span>
|
|
762
|
+
</span>
|
|
763
|
+
</label>
|
|
764
|
+
<label class="flex items-start gap-2 rounded-md border border-border bg-background/60 p-3 text-sm ${this.pendingImport.mode===`merge`?`border-primary`:``}">
|
|
765
|
+
<input
|
|
766
|
+
class="mt-1"
|
|
767
|
+
type="radio"
|
|
768
|
+
name="restore-mode"
|
|
769
|
+
.checked=${this.pendingImport.mode===`merge`}
|
|
770
|
+
?disabled=${this.busy}
|
|
771
|
+
@change=${()=>this.setRestoreMode(`merge`)}
|
|
772
|
+
/>
|
|
773
|
+
<span>
|
|
774
|
+
<span class="block text-foreground">${G(`restoreModeMerge`)}</span>
|
|
775
|
+
<span class="block text-xs text-muted-foreground">${G(`restoreModeMergeDescription`)}</span>
|
|
776
|
+
</span>
|
|
777
|
+
</label>
|
|
778
|
+
</div>
|
|
779
|
+
</div>
|
|
780
|
+
|
|
747
781
|
<div class="mt-4">
|
|
748
782
|
<div class="text-sm font-medium text-foreground">${G(`selectRestoreSections`)}</div>
|
|
749
783
|
<div class="mt-2 grid gap-2">
|
|
@@ -1439,4 +1473,4 @@ D:\\shared\\ai-commands`,commandDirectoryHelp:`一行一个目录。支持相对
|
|
|
1439
1473
|
${this.error?B`<div class="rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive">${this.error}</div>`:null}
|
|
1440
1474
|
</div>
|
|
1441
1475
|
`}},Ic=`quickforge-channels-settings-tab`;customElements.get(Ic)||customElements.define(Ic,Fc);function Lc(){return document.createElement(Ic)}var Rc=[`low`,`medium`,`high`,`xhigh`];function zc(e){switch(e){case`low`:return G(`thinkingLow`);case`medium`:return G(`thinkingMedium`);case`high`:return G(`thinkingHigh`);case`xhigh`:return G(`thinkingXHigh`);default:return G(`thinkingOff`)}}function Bc(e){return e.id}function Vc(e,t=``){let n=document.createElement(`button`);return n.type=`button`,n.className=e,n.textContent=t,n}function Hc(e){document.querySelectorAll(`.quickforge-model-menu, .quickforge-model-submenu`).forEach(e=>{e.__quickforgeCleanup?.(),e.remove()}),e?.setAttribute(`aria-expanded`,`false`)}function Uc(e){return e??document.querySelector(`.quickforge-model-trigger`)}function Wc(e,t){let n=Uc(t),r=Math.min(260,window.innerWidth-24);e.style.width=`${r}px`;let i=e.offsetHeight||360;if(!n){e.style.left=`${Math.max(12,Math.round((window.innerWidth-r)/2))}px`,e.style.top=`${Math.max(12,Math.round((window.innerHeight-i)/2))}px`;return}let a=n.getBoundingClientRect(),o=Math.max(12,Math.min(a.right-r,window.innerWidth-r-12)),s=a.top-i-8,c=a.bottom+8,l=s>=12?s:Math.min(c,window.innerHeight-i-12);e.style.left=`${o}px`,e.style.top=`${Math.max(12,l)}px`}function Gc(e,t){let n=Math.min(252,window.innerWidth-24);e.style.width=`${n}px`;let r=t.getBoundingClientRect(),i=e.offsetHeight||320,a=r.left-n-0>=12?r.left-n-0:Math.min(r.right+0,window.innerWidth-n-12),o=Math.max(12,Math.min(r.top,window.innerHeight-i-12));e.style.left=`${a}px`,e.style.top=`${o}px`}function Kc(e){let t=Vc(`quickforge-model-menu-item`);t.setAttribute(`role`,`menuitemradio`),t.setAttribute(`aria-checked`,String(!!e.selected)),e.disabled&&(t.disabled=!0);let n=document.createElement(`span`);n.className=`quickforge-model-menu-item-label`,n.textContent=e.label;let r=document.createElement(`span`);return r.className=`quickforge-model-menu-item-suffix`,r.textContent=e.chevron?`›`:e.selected?`✓`:``,t.append(n,r),e.onPointerDown&&(t.onpointerdown=e.onPointerDown),e.onPointerEnter&&(t.onpointerenter=e.onPointerEnter),t}function qc(e,t,n,r,i={}){let a=Uc(i.anchor);if(document.querySelector(`.quickforge-model-menu`)){Hc(a);return}let o=i.thinkingLevel??`off`,s=e,c=null,l=document.createElement(`div`);l.className=`quickforge-model-menu`,l.setAttribute(`role`,`menu`),l.setAttribute(`aria-label`,G(`selectCustomModel`));let u=()=>{c?.remove(),c=document.createElement(`div`),c.className=`quickforge-model-submenu`,c.setAttribute(`role`,`menu`),c.setAttribute(`aria-label`,G(`model`));let e=document.createElement(`div`);e.className=`quickforge-model-menu-header`,e.textContent=G(`model`),c.append(e);let r=[...t].sort((e,t)=>Bc(e).localeCompare(Bc(t)));for(let e of r)c.append(Kc({label:Bc(e),selected:je(s,e),onPointerDown:t=>{t.preventDefault(),t.stopPropagation(),!e.reasoning&&o!==`off`&&(o=`off`,i.onThinkingLevelSelect?.(`off`)),s=e,n(e),Hc(a)}}));c.addEventListener(`pointerdown`,e=>e.stopPropagation()),document.body.append(c),Gc(c,l)},d=()=>{l.replaceChildren();let e=document.createElement(`div`);if(e.className=`quickforge-model-menu-header`,e.textContent=G(`reasoning`),l.append(e),s?.reasoning===!0)for(let e of Rc)l.append(Kc({label:zc(e),selected:o===e,onPointerDown:t=>{t.preventDefault(),t.stopPropagation(),o=e,i.onThinkingLevelSelect?.(e),d(),Wc(l,a)}}));else{let e=document.createElement(`div`);e.className=`quickforge-model-menu-note`,e.textContent=G(`thinkingNotSupported`),l.append(e)}let t=document.createElement(`div`);t.className=`quickforge-model-menu-separator`,l.append(t),l.append(Kc({label:s?Bc(s):G(`noModelAdded`),chevron:!0,onPointerEnter:u,onPointerDown:e=>{e.preventDefault(),e.stopPropagation(),u()}}))},f=()=>Hc(a),p=e=>{if(e.type===`resize`||e.type===`scroll`){Wc(l,a),c&&Gc(c,l);return}if(e instanceof KeyboardEvent){if(e.key!==`Escape`)return;e.preventDefault()}else{let t=e.target;if(l.contains(t)||c?.contains(t)||a?.contains(t))return}f()};l.__quickforgeCleanup=()=>{document.removeEventListener(`pointerdown`,p,!0),document.removeEventListener(`keydown`,p,!0),window.removeEventListener(`resize`,p,!0),window.removeEventListener(`scroll`,p,!0)},l.addEventListener(`pointerdown`,e=>e.stopPropagation()),d(),document.body.append(l),Wc(l,a),a?.setAttribute(`aria-expanded`,`true`),document.addEventListener(`pointerdown`,p,!0),document.addEventListener(`keydown`,p,!0),window.addEventListener(`resize`,p,!0),window.addEventListener(`scroll`,p,!0)}function Jc({storageRef:e,activeModelRef:t,agentRef:n,createAgent:r,updateCurrentAgentModel:i,setChatPanelRevision:a,needsModelSetup:o,setNeedsModelSetup:s,setRestoredDraft:c,notifySettingsChanged:l,setSettingsDialogOpen:u}){let d=(0,U.useCallback)(async()=>{let o=e.current;if(!o)return!1;let c=await Sn(o);return c?(t.current=c,s(!1),await dn(o,c),n.current?(i(c),a(e=>e+1)):await r({model:c,tools:[]},Ht(),{scope:`global`,attachToView:!0}),l(),!0):(s(!0),!1)},[e,t,n,r,i,a,s,l]),f=(0,U.useCallback)(e=>{u(!0),ye.open([Ds(),Ns(),Ks(),ws(),Ac(),tc(),sc(),yc(),Lc(),Cc(),Dc()],()=>{u(!1),(o||!n.current)&&d().catch(e=>H.error(`Failed to activate configured model:`,e))}),window.setTimeout(()=>{let t=document.querySelector(`settings-dialog`);t&&(t.activeTabIndex=e===`defaults`?2:e===`customModels`?3:10,t.requestUpdate?.())},0)},[d,o,n,u]),p=(0,U.useCallback)(()=>{f(`customModels`)},[f]);return{activateConfiguredModel:d,openModelSettings:p,openDefaultOptionsSettings:(0,U.useCallback)(()=>{f(`defaults`)},[f]),openAboutSettings:(0,U.useCallback)(()=>{f(`about`)},[f]),activateLiteLlmExampleModel:(0,U.useCallback)(async()=>{let o=e.current;if(!o)return;let c=on($t);await Dn(o,$t,c),await dn(o,c),t.current=c,s(!1),n.current?(i(c),a(e=>e+1)):await r({model:c,tools:[]},Ht(),{scope:`global`,attachToView:!0}),l()},[e,t,n,r,i,a,s,l]),openCustomModelSelector:(0,U.useCallback)(async r=>{let o=e.current,s=n.current;if(!o||!s)return;let l=r instanceof HTMLElement?r:r?.currentTarget instanceof HTMLElement?r.currentTarget:document.querySelector(`.quickforge-model-trigger`),d=document.querySelector(`agent-interface message-editor textarea`)?.value??``,f=bn(await o.customProviders.getAll());if(f.length===0){await Y({description:G(`addCustomModelFirst`),confirmLabel:G(`modelSetupAddModel`),cancelLabel:G(`cancel`)})&&p();return}qc(s.state.model??t.current,f,e=>{let n=e,r=n.reasoning?s.state.thinkingLevel:`off`;s.state.thinkingLevel!==r&&(s.state.thinkingLevel=r,s.updateThinkingLevel(r).catch(e=>{H.error(`Failed to sync thinking level to server:`,e)})),t.current=n,i(n),d&&c({id:Date.now(),sessionId:s.sessionId,text:d}),a(e=>e+1),dn(o,n).catch(e=>{H.error(`Failed to save active model:`,e)})},async e=>{u(!0),await ye.open([Ds(),Ns(),Ks(),ws(e.provider),Ac(),tc(),sc(),yc(),Lc(),Cc(),Dc()],()=>u(!1));let t=document.querySelector(`settings-dialog`);t&&(t.activeTabIndex=3,t.requestUpdate?.())},{thinkingLevel:s.state.thinkingLevel,anchor:l,onThinkingLevelSelect:e=>{s.state.thinkingLevel=e,s.updateThinkingLevel(e).catch(e=>{H.error(`Failed to sync thinking level to server:`,e)}),a(e=>e+1)}})},[e,t,n,i,a,c,p,u])}}function Yc(){let e=new URL(window.location.href);e.searchParams.delete(`session`),window.history.replaceState({},``,e)}function Xc(e){return!!(e&&!e.state.isStreaming&&e.state.messages.length===0)}function Zc({storageRef:e,activeModelRef:t,activeProjectRef:n,currentChatScopeRef:r,currentSessionIdRef:i,taskMapRef:a,agentRef:o,startDeferredSession:s,createAgent:c,syncSessionUI:l,setCurrentAgentMessages:u,setChatPanelRevision:d,refreshSessions:f,needsModelSetup:p,switchActiveProject:m,closeWorkspacePage:h,setRestoredDraft:g}){let _=(0,U.useCallback)(async()=>{if(p){X(G(`modelSetupRequired`));return}h(),!(Xc(o.current)&&r.current===`global`)&&(g(void 0),Yc(),await s({scope:`global`}))},[o,r,p,g,h,s]),v=(0,U.useCallback)(async e=>{if(p){X(G(`modelSetupRequired`));return}h();let t=e??n.current;t&&(Xc(o.current)&&r.current===`project`&&n.current?.id===t.id||(n.current?.id!==t.id&&await m(t.id),g(void 0),Yc(),await s({scope:`project`,project:t})))},[n,o,r,p,g,h,s,m]),y=(0,U.useCallback)(async s=>{let p=o.current;if(!p)return;if(p.state.isStreaming){X(G(`generationStillRunning`));return}let m=wo(p.state.messages,s),h=m>=0?p.state.messages[m]:void 0;if(m<0||!h){X(G(`noConversationTurnToRollback`));return}let _={id:Date.now(),sessionId:p.sessionId,text:To(h),attachments:h.role===`user-with-attachments`?h.attachments:void 0},v=p.state.messages.slice(0,m);try{v=(await p.rollback(s)).session.messages??v}catch(e){H.error(`Failed to rollback conversation:`,e),X(e instanceof Error?e.message:G(`rollbackFailed`));return}u(v);let y=i.current?a.current.get(i.current):void 0;if(Ao(v)&&y){_&&g(_),d(e=>e+1),l(y).catch(e=>H.error(`Failed to sync session UI:`,e));return}let b=e.current,x=i.current,S=r.current,C=S===`project`?n.current:void 0,w=p.state.model??t.current,T=p.state.thinkingLevel;if(x){let e=a.current.get(x);e?.unsubscribe(),e?.agent.dispose(),a.current.delete(x)}if(b&&x)try{await b.sessions.delete(x),await f({broadcast:!0})}catch(e){H.error(`Failed to delete rolled back empty session:`,e)}let E=Ht();await c({model:w,thinkingLevel:T,messages:[],tools:[]},E,{scope:S,project:C,attachToView:!0,title:`New chat`}),g({..._,sessionId:E}),d(e=>e+1)},[t,n,o,c,r,i,f,d,u,g,e,l,a]),b=(0,U.useCallback)(async e=>{try{await Eo(e)}catch(e){throw H.error(`Failed to copy answer:`,e),X(G(`copyFailed`)),e}},[]),x=(0,U.useCallback)(async i=>{let a=o.current;if(!a)return;if(a.state.isStreaming){X(G(`generationStillRunning`));return}let s=a.state.messages.slice(0,i+1);if(!ko(s))return;let l=r.current,u=l===`project`?n.current:void 0,d=Ht(),p=Do(s),m=e.current;await c({model:a.state.model??t.current,thinkingLevel:a.state.thinkingLevel,messages:s,tools:[]},d,{scope:l,project:u,attachToView:!0,title:p}),m&&f({broadcast:!0}).catch(e=>H.error(`Failed to refresh sessions:`,e))},[t,n,o,c,r,f,e]);return{startNewGlobalChat:_,startNewProjectChat:v,rollbackFromMessage:y,retryFromMessage:(0,U.useCallback)(async e=>{let t=o.current;if(!t)return;if(t.state.isStreaming){X(G(`generationStillRunning`));return}let n=t.state.messages;if(e<0||e>=n.length)return;let r=n[e];if(r.role!==`user`&&r.role!==`user-with-attachments`)return;u(n.slice(0,e+1)),d(e=>e+1);try{await t.continue()}catch(e){H.error(`Failed to retry:`,e),X(e instanceof Error?e.message:G(`retryFailed`));return}let s=i.current?a.current.get(i.current):void 0;s&&(l(s).catch(e=>H.error(`Failed to sync session UI after retry:`,e)),d(e=>e+1))},[o,i,d,u,l,a]),copyAnswer:b,forkFromMessage:x}}function Qc({activeProjectRef:e,refreshSessions:t,notifyProjectsChanged:n,setActiveProject:r,setProjects:i,setExpandedProjectIds:a,setChatPanelRevision:o}){return{deleteProjectInline:(0,U.useCallback)(async s=>{let c=await fetch(`/api/project/${encodeURIComponent(s)}`,{method:`DELETE`}),l=await c.json().catch(()=>null);if(!c.ok)throw Error(l?.error||`Failed to delete project`);r(l.project),i(l.projects),a(e=>{let t=new Set(e);return t.delete(s),t}),await t({broadcast:!0}),n(),e.current?.id===s&&(e.current=l.project,o(e=>e+1))},[e,t,n,r,i,a,o])}}function $c({options:e,onResolve:t}){let n=(0,U.useRef)(null),[r,i]=(0,U.useState)(e.defaultValue??``),a=(0,U.useRef)(r);return(0,U.useEffect)(()=>{a.current=r},[r]),(0,U.useEffect)(()=>{n.current?.focus(),n.current?.select()},[]),(0,U.useEffect)(()=>{let e=e=>{e.key===`Escape`&&t(null),e.key===`Enter`&&a.current.trim()&&t(a.current.trim())};return document.addEventListener(`keydown`,e),()=>document.removeEventListener(`keydown`,e)},[t]),(0,pt.createPortal)((0,q.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50`,onClick:e=>{e.target===e.currentTarget&&t(null)},children:(0,q.jsxs)(`div`,{className:K(`w-full max-w-sm rounded-lg border border-border bg-background p-6 shadow-quickforge`,`mx-4`),children:[(0,q.jsx)(`h2`,{className:`text-base font-semibold text-foreground`,children:e.title}),e.description?(0,q.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:e.description}):null,(0,q.jsx)(`div`,{className:`mt-4`,children:(0,q.jsx)(yt,{ref:n,value:r,onChange:e=>i(e.target.value),placeholder:e.placeholder,className:`w-full`})}),(0,q.jsxs)(`div`,{className:`mt-5 flex justify-end gap-2`,children:[(0,q.jsx)(J,{variant:`outline`,size:`sm`,onClick:()=>t(null),children:e.cancelLabel??`Cancel`}),(0,q.jsx)(J,{size:`sm`,onClick:()=>r.trim()?t(r.trim()):void 0,disabled:!r.trim(),children:e.confirmLabel??`Save`})]})]})}),document.body)}function el(e){return new Promise(t=>{let n=document.createElement(`div`);document.body.appendChild(n);let r=(0,Pe.createRoot)(n);function i(){r.unmount(),setTimeout(()=>n.remove(),0)}function a(e){i(),t(e)}r.render((0,q.jsx)($c,{options:e,onResolve:a}))})}function tl({storageRef:e,taskMapRef:t,currentSessionIdRef:n,loadAgentSession:r,setCurrentTitleRef:i,refreshSessions:a,closeWorkspacePage:o,startNewGlobalChat:s}){return{loadSession:(0,U.useCallback)(e=>{o(),r(e)},[r,o]),renameSession:(0,U.useCallback)(async(t,r)=>{let o=e.current;if(!o)return;let s=await el({title:G(`renameSession`),description:G(`sessionName`),defaultValue:r,confirmLabel:G(`save`),cancelLabel:G(`cancel`)});if(!s||s===r)return;let c=await o.sessions.get(t);if(!c)return;let l=await o.sessions.getMetadata(t);l&&(await o.sessions.save(c,{...l,title:s}),await a({broadcast:!0}),n.current===t&&i(s))},[n,a,i,e]),togglePinSession:(0,U.useCallback)(async t=>{let n=e.current;if(!n)return;let r=await n.sessions.get(t);if(!r)return;let i=await n.sessions.getMetadata(t);if(!i)return;let o=i.pinnedAt?void 0:new Date().toISOString(),s={...r,pinnedAt:o},c={...i,pinnedAt:o};await n.sessions.save(s,c),await a({broadcast:!0})},[a,e]),archiveSession:(0,U.useCallback)(async r=>{let i=e.current;if(!i)return;let c=t.current.get(r);c?.unsubscribe(),c?.agent.dispose(),t.current.delete(r);let l=await i.sessions.get(r);if(!l)return;let u=await i.sessions.getMetadata(r);if(!u)return;let d=new Date().toISOString(),f={...l,archivedAt:d},p={...u,archivedAt:d};await i.sessions.save(f,p),await a({broadcast:!0}),n.current===r&&(o(),await s())},[n,a,o,s,e,t]),startNewGlobalSession:(0,U.useCallback)(()=>{o(),s()},[o,s])}}var nl=e=>e===`full-access`;function rl({storageRef:e,agentAccessModeRef:t,setAgentAccessMode:n,agentRef:r,setChatPanelRevision:i,notifySettingsChanged:a}){let o=(0,U.useCallback)(o=>{let s=e.current,c=r.current,l=t.current;if(l===o)return;n(o),t.current=o;let u=()=>{t.current=l,n(l),i(e=>e+1)};(async()=>{try{c&&await c.updateAccessMode(o),s&&await Tn(s,o),i(e=>e+1),a()}catch(e){H.error(`Failed to sync agent access mode:`,e),u(),X(e instanceof Error?e.message:G(`agentAccessModeSyncFailed`))}})()},[t,r,a,n,i,e]);return{setAccessMode:o,toggleYoloMode:(0,U.useCallback)(()=>{o(nl(t.current)?`default`:`full-access`)},[t,o])}}function il(){let[e,t]=(0,U.useState)(!0),[n,r]=(0,U.useState)(!1),[i,a]=(0,U.useState)(!1),[o,s]=(0,U.useState)(!1),[c,l]=(0,U.useState)(!1),[u,d]=(0,U.useState)(),[f,p]=(0,U.useState)(!1),[m,h]=(0,U.useState)(!1),[g,_]=(0,U.useState)(!1),[v,y]=(0,U.useState)(`overview`),[b,x]=(0,U.useState)(),[S,C]=(0,U.useState)(``),[w,T]=(0,U.useState)(!1),[E,D]=(0,U.useState)(),[ee,O]=(0,U.useState)(!1),[k,A]=(0,U.useState)(),[j,M]=(0,U.useState)(!1),[N,te]=(0,U.useState)(),[P,F]=(0,U.useState)(!1),[ne,I]=(0,U.useState)(!1);return{sidebarOpen:e,setSidebarOpen:t,mobileSidebarOpen:n,setMobileSidebarOpen:r,projectsCollapsed:i,setProjectsCollapsed:a,conversationsCollapsed:o,setConversationsCollapsed:s,mcpServersDialogOpen:c,setMcpServersDialogOpen:l,skillsDialog:u,setSkillsDialog:d,shareDialogOpen:f,setShareDialogOpen:p,conversationMenuOpen:m,setConversationMenuOpen:h,workspaceInspectorOpen:g,setWorkspaceInspectorOpen:_,workspacePanelView:v,setWorkspacePanelView:y,workspaceInspectorFocusTarget:b,setWorkspaceInspectorFocusTarget:x,webPreviewUrl:S,setWebPreviewUrl:C,artifactPreviewOpen:w,setArtifactPreviewOpen:T,activeArtifactPath:E,setActiveArtifactPath:D,inlineReaderOpen:ee,setInlineReaderOpen:O,inlineReaderFile:k,setInlineReaderFile:A,inlineReaderLoading:j,setInlineReaderLoading:M,inlineReaderError:N,setInlineReaderError:te,firstUseGuideDismissed:P,setFirstUseGuideDismissed:F,settingsDialogOpen:ne,setSettingsDialogOpen:I,toggleProjectsCollapsed:(0,U.useCallback)(()=>a(e=>!e),[]),toggleConversationsCollapsed:(0,U.useCallback)(()=>s(e=>!e),[])}}function al(e){return e===`running`||e===`idle`||e===`error`||e===`aborted`?e:void 0}function ol(e){let[t,n]=(0,U.useState)({}),r=(0,U.useMemo)(()=>new Set(e.map(e=>e.id)),[e]),i=(0,U.useMemo)(()=>e.map(e=>e.id).sort().join(`
|
|
1442
|
-
`),[e]),a=(0,U.useCallback)(async()=>{if(r.size===0){n({});return}try{let e=await vo(),t=new Map(e.map(e=>[e.sessionId,al(e.status)]).filter(e=>!!e[1]));n(e=>{let n={};for(let i of r){let r=t.get(i),a=e[i];r?n[i]=r:a===`running`?n[i]=`idle`:a&&a!==`idle`&&(n[i]=a)}return n})}catch(e){H.error(`Failed to refresh visible agent statuses:`,e)}},[r]);return(0,U.useEffect)(()=>{let e=window.setTimeout(()=>{a()},0);return()=>window.clearTimeout(e)},[a,i]),(0,U.useEffect)(()=>yo(e=>{let t=e.sessionId;if(!(!t||!r.has(t))){if(e.type===`agent_start`){n(e=>({...e,[t]:`running`}));return}if(e.type===`agent_end`){let r=al(e.status)===`aborted`?`aborted`:e.errorMessage?`error`:`idle`;n(e=>({...e,[t]:r}))}}}),[r]),(0,U.useEffect)(()=>{let e=()=>{document.visibilityState===`visible`&&a()};return document.addEventListener(`visibilitychange`,e),()=>document.removeEventListener(`visibilitychange`,e)},[a]),t}function sl(e){return e===`idle`?{tone:`success`,message:G(`taskCompleted`)}:e===`error`?{tone:`error`,message:G(`taskError`)}:e===`aborted`?{tone:`aborted`,message:G(`processAborted`)}:e===`running`?{tone:`running`,message:G(`taskRunning`)}:{tone:`neutral`,message:G(`taskRunning`)}}function cl({toast:e,onDismiss:t,onClick:n}){let[r,i]=(0,U.useState)(!1),[a,o]=(0,U.useState)(!1),s=(0,U.useRef)(null);(0,U.useEffect)(()=>{let n=window.setTimeout(()=>i(!0),10);return s.current=window.setTimeout(()=>{o(!0),s.current=window.setTimeout(()=>t(e.id),200)},5e3),()=>{window.clearTimeout(n),s.current!==null&&window.clearTimeout(s.current)}},[e.id,t]);let c=()=>{o(!0),s.current!==null&&window.clearTimeout(s.current),s.current=window.setTimeout(()=>t(e.id),200)},l=sl(e.status),u=l.tone===`error`,d=l.tone===`success`,f=K(`size-5`,u&&`text-destructive`,d&&`text-emerald-500`,l.tone===`aborted`&&`text-amber-600`,l.tone===`running`&&`text-blue-600`,l.tone===`neutral`&&`text-muted-foreground`);return(0,q.jsxs)(`div`,{role:`alert`,onClick:()=>n(e.sessionId),className:K(`pointer-events-auto flex w-80 cursor-pointer items-start gap-3 rounded-xl border border-border bg-background p-3 shadow-quickforge transition-all duration-200 ease-out`,r&&!a?`translate-x-0 opacity-100`:`translate-x-4 opacity-0`),children:[(0,q.jsx)(`div`,{className:`mt-0.5 shrink-0`,children:d?(0,q.jsx)(S,{className:f}):(0,q.jsx)(A,{className:f})}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`p`,{className:`truncate text-sm font-medium text-foreground/90`,children:e.title}),(0,q.jsx)(`p`,{className:`mt-0.5 line-clamp-3 text-xs text-muted-foreground`,children:e.message||l.message})]}),(0,q.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},className:`shrink-0 rounded-md p-0.5 text-muted-foreground/60 transition-colors hover:text-foreground`,"aria-label":G(`close`),children:(0,q.jsx)(N,{className:`size-4`})})]})}function ll({toasts:e,onDismiss:t,onClick:n}){return e.length===0?null:(0,q.jsx)(`div`,{className:`pointer-events-none fixed right-4 top-16 z-50 flex flex-col gap-2`,children:e.map(e=>(0,q.jsx)(cl,{toast:e,onDismiss:t,onClick:n},e.id))})}async function ul(e,t){let n=await fetch(e,{...t,cache:`no-store`,headers:{...t?.body?{"content-type":`application/json`}:void 0,...t?.headers}}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`Request failed: ${n.status}`);return r}function dl(e){if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let t=new Uint8Array(1);return crypto.getRandomValues(t),e[t[0]%e.length]}return e[Math.floor(Math.random()*e.length)]}function fl(){let e=()=>Array.from({length:6},()=>dl(`ABCDEFGHJKLMNPQRSTUVWXYZ23456789`)).join(``);return`${e()}-${e()}`}function pl(e=24){return new Date(Date.now()+e*60*60*1e3).toISOString()}async function ml(e){return ul(`/api/shares`,{method:`POST`,body:JSON.stringify(e)})}async function hl(e){return ul(`/api/shares${e?`?sessionId=${encodeURIComponent(e)}`:``}`)}async function gl(e){return ul(`/api/shares/${encodeURIComponent(e)}`,{method:`DELETE`})}async function _l(e){return ul(`/api/shared/${encodeURIComponent(e)}/meta`)}async function vl(e,t=``){return ul(`/api/shared/${encodeURIComponent(e)}/unlock`,{method:`POST`,body:JSON.stringify({password:t})})}async function yl(e){return ul(`/api/shared/${encodeURIComponent(e)}/models`)}function bl({open:e,sessionId:t,title:n,onOpenChange:r}){let i=(0,U.useId)(),[a,o]=(0,U.useState)(`read`),[s,c]=(0,U.useState)(``),[l,u]=(0,U.useState)(`24h`),[d,f]=(0,U.useState)(!1),[p,m]=(0,U.useState)(``),[h,g]=(0,U.useState)([]),[_,y]=(0,U.useState)(!1),[b,x]=(0,U.useState)(),S=(0,U.useMemo)(()=>{if(l!==`never`)return pl(l===`1h`?1:l===`7d`?168:24)},[l]);if((0,U.useEffect)(()=>{!e||!t||hl(t).then(e=>g(e.shares)).catch(e=>x(e instanceof Error?e.message:`Failed to load shares`))},[e,t]),!e)return null;let C=a===`operate`,w=!!t&&(a!==`operate`||d&&s.trim()),T=async()=>{if(!(!t||!w)){if(C&&!s.trim()){x(`可操作分享必须设置密码。`);return}y(!0),x(void 0);try{let e=await ml({sessionId:t,permission:a,password:s.trim(),expiresAt:S});m(e.url),await Eo(e.url),f(!1),g((await hl(t)).shares)}catch(e){x(e instanceof Error?e.message:`Failed to create share`)}finally{y(!1)}}},E=async e=>{let t=e.url||`${window.location.origin}/share/${encodeURIComponent(e.id)}`;m(t),await Eo(t)},D=async e=>{try{await gl(e),g(t=>t.map(t=>t.id===e?{...t,revokedAt:new Date().toISOString()}:t))}catch(e){x(e instanceof Error?e.message:`Failed to revoke share`)}};return(0,q.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4`,onMouseDown:e=>{e.target===e.currentTarget&&r(!1)},children:(0,q.jsxs)(`div`,{className:`flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-quickforge`,onMouseDown:e=>e.stopPropagation(),children:[(0,q.jsxs)(`div`,{className:`shrink-0 border-b border-border px-5 py-4`,children:[(0,q.jsx)(`h2`,{className:`text-base font-semibold`,children:`分享到局域网`}),(0,q.jsxs)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:[`当前对话:`,n,`。同一个对话只会有一个固定分享链接;只读分享密码可选,可操作分享必须设置密码。`]})]}),(0,q.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-4`,children:(0,q.jsxs)(`div`,{className:`space-y-4`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-2 text-sm font-medium`,children:`权限`}),(0,q.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-2`,children:[(0,q.jsxs)(`button`,{type:`button`,className:`rounded-xl border p-3 text-left text-sm ${a===`read`?`border-primary bg-primary/10`:`border-border`}`,onClick:()=>o(`read`),children:[(0,q.jsx)(`div`,{className:`font-medium`,children:`仅阅读`}),(0,q.jsx)(`div`,{className:`mt-1 text-xs text-muted-foreground`,children:`只能查看这一个对话。`})]}),(0,q.jsxs)(`button`,{type:`button`,className:`rounded-xl border p-3 text-left text-sm ${a===`operate`?`border-red-400 bg-red-50 text-red-950`:`border-border`}`,onClick:()=>o(`operate`),children:[(0,q.jsx)(`div`,{className:`font-medium text-red-700`,children:`可操作(高危)`}),(0,q.jsx)(`div`,{className:`mt-1 text-xs text-red-700`,children:`允许对方操作这个原对话,禁止 Fork。`})]})]})]}),a===`operate`?(0,q.jsxs)(`div`,{className:`rounded-xl border border-red-300 bg-red-50 p-3 text-sm text-red-900`,children:[(0,q.jsxs)(`div`,{className:`flex gap-2 font-semibold`,children:[(0,q.jsx)(ee,{className:`mt-0.5 size-4`}),`高危可操作权限`]}),(0,q.jsx)(`p`,{className:`mt-2 text-xs leading-5`,children:`拥有链接和密码的人只能操作这一个原对话,但对方的消息、停止生成、回滚、模型/思考等级选择、YOLO 状态下可用工具等操作会按正常对话权限直接影响你的本机原对话。可操作分享必须设置密码。`}),(0,q.jsxs)(`label`,{className:`mt-3 flex items-center gap-2 text-xs font-medium`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:d,onChange:e=>f(e.target.checked)}),`我已了解风险,仍然允许可操作权限。`]})]}):null,(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`label`,{htmlFor:i,className:`block text-sm font-medium`,children:C?`密码(可操作必填)`:`密码(可选)`}),(0,q.jsxs)(`div`,{className:`flex flex-col gap-3 sm:flex-row sm:items-center`,children:[(0,q.jsx)(`input`,{id:i,value:s,onChange:e=>c(e.target.value),className:`h-10 w-full min-w-0 rounded-md border border-input bg-background px-3 text-sm`,placeholder:C?`可操作分享必须设置密码`:`留空则打开链接无需密码`}),(0,q.jsxs)(J,{variant:`outline`,className:`h-10 sm:shrink-0`,onClick:()=>c(fl()),children:[(0,q.jsx)(re,{className:`mr-2 size-4`}),`生成密码`]})]}),(0,q.jsx)(`span`,{className:`block text-xs text-muted-foreground`,children:C?`可操作分享必须设置非空密码;修改密码后旧密码和已解锁状态会失效。`:`留空保存会取消密码保护;填写新密码保存后旧密码和已解锁状态会失效。`})]}),(0,q.jsxs)(`label`,{className:`block text-sm font-medium`,children:[`有效期`,(0,q.jsxs)(`select`,{value:l,onChange:e=>u(e.target.value),className:`mt-2 h-10 w-full rounded-md border border-input bg-background px-3 text-sm`,children:[(0,q.jsx)(`option`,{value:`1h`,children:`1 小时`}),(0,q.jsx)(`option`,{value:`24h`,children:`24 小时`}),(0,q.jsx)(`option`,{value:`7d`,children:`7 天`}),(0,q.jsx)(`option`,{value:`never`,children:`永久,需手动撤销`})]})]}),p?(0,q.jsxs)(`div`,{className:`rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-sm text-emerald-900`,children:[`已复制到剪切板。`,(0,q.jsx)(`pre`,{className:`mt-2 max-h-36 overflow-auto whitespace-pre-wrap text-xs`,children:p})]}):null,b?(0,q.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:b}):null,h.length?(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-2 text-sm font-medium`,children:`已有分享`}),(0,q.jsx)(`div`,{className:`space-y-2`,children:h.map(e=>(0,q.jsxs)(`div`,{className:`flex items-center gap-2 rounded-lg border border-border p-2 text-xs`,children:[(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`truncate font-mono`,children:e.id}),(0,q.jsxs)(`div`,{className:`text-muted-foreground`,children:[e.permission===`operate`?`可操作`:`只读`,` · `,e.hasPassword?`有密码`:`无密码`,` · `,e.revokedAt?`已撤销`:e.expiresAt?`到期 ${new Date(e.expiresAt).toLocaleString()}`:`永久`]})]}),e.revokedAt?null:(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>void E(e),"aria-label":`复制分享链接`,title:`复制分享链接`,children:(0,q.jsx)(O,{className:`size-4`})}),(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`text-destructive`,onClick:()=>void D(e.id),"aria-label":`撤销分享`,title:`撤销分享`,children:(0,q.jsx)(v,{className:`size-4`})})]})]},e.id))})]}):null]})}),(0,q.jsx)(`div`,{className:`shrink-0 border-t border-border px-5 py-4`,children:(0,q.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,q.jsx)(J,{variant:`outline`,onClick:()=>r(!1),children:G(`cancel`)}),(0,q.jsxs)(J,{variant:a===`operate`?`destructive`:`default`,disabled:!w||_,onClick:()=>void T(),title:a===`operate`&&!s.trim()?`可操作分享必须设置密码`:void 0,children:[(0,q.jsx)(O,{className:`mr-2 size-4`}),a===`operate`?`保存配置并复制高危可操作链接`:`保存配置并复制链接`]})]})})]})})}async function xl(e){let t=await fetch(e,{cache:`no-store`}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||`Request failed: ${t.status}`);return n}async function Sl(e,t){let n=await fetch(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`Request failed: ${n.status}`);return r}function Cl(e){return`projectId=${encodeURIComponent(e)}`}function wl(e){return xl(`/api/workspace/tree?${Cl(e)}`)}function Tl(e,t){return xl(`/api/workspace/file?${Cl(e)}&path=${encodeURIComponent(t)}`)}function El(e,t){return Sl(`/api/workspace/resolve-path`,{projectId:e,path:t})}function Dl(e){return xl(`/api/git/status?${Cl(e)}`)}function Ol(e,t){return xl(`/api/git/file-diff?${Cl(e)}&path=${encodeURIComponent(t)}`)}function kl(e){let t=e.replace(/\\/g,`/`);return t.split(`/`).filter(Boolean).pop()||t||`artifact`}function Al(e){let t=e.toLowerCase();return t.endsWith(`.html`)||t.endsWith(`.htm`)?`html`:/\.(svg|png|jpe?g|webp|gif|bmp|ico)$/i.test(t)?`image`:t.endsWith(`.md`)||t.endsWith(`.mdx`)?`markdown`:/\.(ts|tsx|js|jsx|mjs|cjs|css|scss|less|json|jsonc|txt|xml|yml|yaml|toml|ini|py|rb|go|rs|java|c|h|cpp|hpp|cs|php|sh|bash|zsh|ps1)$/i.test(t)?`code`:`unknown`}function jl(e){return Al(e)!==`unknown`}var Ml=/\.(svg|png|jpe?g|webp|gif|ico)$/i;function Nl(e){return Al(e)===`html`||Ml.test(e)}function Pl(e,t){let n=t.replace(/\\/g,`/`);return!e?.trim()||n.startsWith(`/`)||/^[a-zA-Z]:\//.test(n)?t:`${e.trim().replace(/\\/g,`/`).replace(/\/+$/,``)}/${n.replace(/^\/+/,``)}`}function Fl(e,t,n){let r=t.replace(/\\/g,`/`),i=r.match(/^\/+/)?.[0]??``,a=i+r.slice(i.length).split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`),o=`/api/workspace/preview/${encodeURIComponent(e)}/${a}`;return n?`${o}?r=${n}`:o}function Il(e){return e.replace(/\\/g,`/`).toLowerCase()}function Ll(e){let t=kl(e.path).toLowerCase();return e.defaultPreview?0:e.explicit&&e.preview?1:e.explicit?2:t===`index.html`?3:e.kind===`html`?4:e.kind===`image`?5:e.kind===`markdown`?6:e.kind===`code`?7:20}function Rl(e){let t=new Map;for(let n of e){if(!n.path)continue;let e=Il(n.path),r=n.kind??Al(n.path),i=t.get(e),a=n.preview??jl(n.path),o=n.source===`present_files`||n.presentation===`explicit`;if(!i){t.set(e,{id:e,path:n.path,title:n.title,description:n.description,kind:r,preview:a,defaultPreview:!!n.defaultPreview,explicit:o,addedLines:n.addedLines,removedLines:n.removedLines,sources:[n.source],toolCallIds:n.toolCallId?[n.toolCallId]:[]});continue}i.preview=i.preview||a,i.defaultPreview=i.defaultPreview||!!n.defaultPreview,i.explicit=i.explicit||o,i.title=n.title||i.title,i.description=n.description||i.description,typeof n.addedLines==`number`&&(i.addedLines=(i.addedLines??0)+n.addedLines),typeof n.removedLines==`number`&&(i.removedLines=(i.removedLines??0)+n.removedLines),i.kind=i.kind===`unknown`?r:i.kind,i.sources.includes(n.source)||i.sources.push(n.source),n.toolCallId&&!i.toolCallIds.includes(n.toolCallId)&&i.toolCallIds.push(n.toolCallId)}return[...t.values()].sort((e,t)=>Ll(e)-Ll(t))}function zl(e){let t=Rl(e).filter(e=>e.preview&&e.explicit);if(t.length<=1)return t[0];let n=new Map;for(let t=0;t<e.length;t++){let r=e[t]?.toolCallId;r&&n.set(r,t)}let r=e=>{let t=e.toolCallIds,r=-1;for(let e of t){let t=n.get(e);typeof t==`number`&&t>r&&(r=t)}return r};return[...t].sort((e,t)=>r(t)-r(e))[0]}var Bl=(0,U.lazy)(()=>Ne(()=>import(`./ChatPanelHost-BUZ6scv9.js`).then(e=>({default:e.ChatPanelHost})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),Vl=(0,U.lazy)(()=>Ne(()=>import(`./TerminalDock-_voUf7d-.js`).then(e=>({default:e.TerminalDock})),__vite__mapDeps([9,1,10,11,5,6]))),Hl=(0,U.lazy)(()=>Ne(()=>import(`./ScheduledTasksPage-C0htXZk2.js`).then(e=>({default:e.ScheduledTasksPage})),__vite__mapDeps([12,1,5,6]))),Ul=(0,U.lazy)(()=>Ne(()=>import(`./AgentProfilesPage-DKyIh3dE.js`).then(e=>({default:e.AgentProfilesPage})),__vite__mapDeps([13,1,5,6]))),Wl=(0,U.lazy)(()=>Ne(()=>import(`./PluginsPage-CN-SFQ_s.js`).then(e=>({default:e.PluginsPage})),__vite__mapDeps([14,1,5,6,7]))),Gl=(0,U.lazy)(()=>Ne(()=>import(`./SharedConversationPage-CxbAx1fN.js`).then(e=>({default:e.SharedConversationPage})),__vite__mapDeps([15,1,3,2,4,5,6,0,7,8]))),Kl=(0,U.lazy)(()=>Ne(()=>import(`./WorkspaceInspector-Ci4FuaZH.js`).then(e=>({default:e.WorkspaceInspector})),__vite__mapDeps([16,1,5,6,17,18]))),ql=(0,U.lazy)(()=>Ne(()=>import(`./WorkspaceReaderDialog-D75__GFg.js`).then(e=>({default:e.WorkspaceReaderDialog})),__vite__mapDeps([19,1,5,6,17,18]))),Jl=`quickforge:auto-preview-seen-signatures`,Yl=200;function Xl(){if(typeof window>`u`)return new Set;try{let e=window.sessionStorage.getItem(Jl),t=e?JSON.parse(e):void 0;return Array.isArray(t)?new Set(t.filter(e=>typeof e==`string`&&e.length>0)):new Set}catch{return new Set}}function Zl(e){return Xl().has(e)}function Ql(e){if(!(typeof window>`u`))try{let t=[...Xl(),e].slice(-Yl);window.sessionStorage.setItem(Jl,JSON.stringify(t))}catch{}}function $l(){return(0,q.jsx)(`div`,{className:`flex min-h-0 flex-1 items-center justify-center text-sm text-muted-foreground`,children:G(`loading`)})}function eu(){return null}function tu(e){return e===`idle`||e===`running`||e===`error`||e===`aborted`}function nu(e){return e.type===`scheduled_task_notification`}function ru(e){return e.type===`scheduled_task_started`}function iu(e){return e===`starting`||e===`waiting_scan`||e===`running`||e===`stopping`}function au(e){return Array.isArray(e.channels)?e.channels.some(e=>iu(e.status)):iu(e.snapshot?.status)||iu(e.status)}function ou(e){return[...Array.isArray(e.channels)?e.channels:[],...e.snapshot?[e.snapshot]:[]].filter(e=>iu(e.status)).map(e=>e.launchWorkspace).filter(e=>e?.kind===`project`&&typeof e.id==`string`&&e.id.length>0).map(e=>e.id)}function su(){let e=(0,U.useRef)(null),t=(0,U.useRef)(on($t)),r=(0,U.useRef)(`default`),i=(0,U.useRef)(void 0),o=(0,U.useRef)(void 0),{activeProject:s,projects:c,defaultWorkspace:u,expandedProjectIds:d,selectingProject:p,projectPickerOpen:m,loadProject:h,switchActiveProject:g,handleSelectProjectPath:_,selectProjectDirectory:v,setProjectPickerOpen:y,toggleProjectExpanded:b,toggleAllProjectsExpanded:S,reorderProjects:C,setActiveProject:w,setProjects:T,setExpandedProjectIds:E}=ro(),{agentAccessMode:D,setAgentAccessMode:ee,initialize:O}=io(),k=il(),{setArtifactPreviewOpen:A,setWorkspaceInspectorOpen:j}=k,[M,N]=(0,U.useState)(!1),[te,P]=(0,U.useState)(),[ne,L]=(0,U.useState)(`chat`),[re,R]=(0,U.useState)(!1),[z,ae]=(0,U.useState)(null),[oe,se]=(0,U.useState)([]),ce=(0,U.useRef)(``),[le,ue]=(0,U.useState)(),[de,fe]=(0,U.useState)(()=>new Set),pe=(0,U.useRef)(0),[B,me]=(0,U.useState)(null),{toasts:he,handleTaskComplete:ge,addToast:_e,dismissToast:ve}=Ro(),ye=ne===`scheduledTasks`,V=ne===`agentProfiles`,be=ne===`plugins`,xe=ne!==`chat`,Se=(0,U.useCallback)(()=>L(`chat`),[]),Ce=(0,U.useRef)(null),we=(0,U.useRef)(null),{allLoadedSessions:Te,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,projectHasMore:ke,globalLoading:Ae,projectLoading:je,projectLoaded:Me,loadGlobalSessions:Ne,loadProjectSessions:Pe,refreshSessions:Fe,loadMoreGlobal:Ie,loadMoreProject:Le}=Lo({backendRef:we,expandedProjectIds:d,externalProjectIds:de,onBroadcastSessionsChanged:(0,U.useCallback)(()=>Ce.current?.notifySessionsChanged(),[])}),Re=oo({onSessionsChanged:()=>{Fe()},onProjectsChanged:()=>{h()},onSettingsChanged:()=>{Fe()}});(0,U.useEffect)(()=>{r.current=D},[D]),(0,U.useEffect)(()=>{i.current=s},[s]),(0,U.useEffect)(()=>{o.current=u},[u]),(0,U.useEffect)(()=>{Ce.current=Re},[Re]);let ze=(0,U.useCallback)((e,t)=>{ue({sessionId:e,...t})},[]),W=No({storageRef:e,activeModelRef:t,agentAccessModeRef:r,activeProjectRef:i,defaultWorkspaceRef:o,setAgentAccessMode:ee,switchActiveProject:g,sessions:Te,refreshSessions:Fe,onTaskComplete:ge}),{createAgent:Be,startDeferredSession:Ve,loadSession:He,syncSessionUI:Ue,setCurrentAgentMessages:We,updateCurrentAgentModel:Ge,setChatPanelRevision:Ke,setCurrentTitleRef:qe,agentRef:Je,taskMapRef:Ye,currentSessionIdRef:Xe,currentChatScopeRef:Ze}=W,Qe=(0,U.useCallback)(e=>{e&&(Se(),He(e))},[Se,He]),$e=(0,U.useCallback)(e=>{e.trim()&&(Se(),P({id:Date.now(),sessionId:Je.current?.sessionId,text:e}))},[Je,Se]),et=(0,U.useCallback)(()=>{W.currentToolProject?.id&&(Se(),A(!1),k.setWorkspacePanelView(`changes`),k.setWorkspaceInspectorFocusTarget({tab:`git`,nonce:Date.now()}),k.setWorkspaceInspectorOpen(!0))},[W.currentToolProject?.id,Se,A,k]),tt=(0,U.useCallback)(async e=>{let t=W.currentToolProject?.id;if(!t){_e({sessionId:W.currentSessionId??``,title:`无法打开文件`,status:`error`,message:`当前对话没有关联项目。`});return}k.setInlineReaderOpen(!0),k.setInlineReaderLoading(!0),k.setInlineReaderError(void 0),k.setInlineReaderFile(void 0);try{let n=await Tl(t,(await El(t,e)).relativePath);k.setInlineReaderFile(n)}catch(e){let t=e instanceof Error?e.message:`打开文件失败`;k.setInlineReaderError(t),_e({sessionId:W.currentSessionId??``,title:`无法打开文件`,status:`error`,message:t})}finally{k.setInlineReaderLoading(!1)}},[_e,W.currentSessionId,W.currentToolProject?.id,k]),nt=(0,U.useCallback)(e=>{let t=W.currentToolProject;!t?.id||!Nl(e)||(Se(),A(!1),k.setWebPreviewUrl(Pl(t.path,e)),k.setWorkspacePanelView(`browser`),j(!0))},[W.currentToolProject,Se,A,j,k]);(0,U.useEffect)(()=>{let e=W.currentToolProject,t=e?.id;if(!t)return;let n=zl(oe);if(!n?.path)return;let r=n.toolCallIds[n.toolCallIds.length-1],i=`${t}:${n.path}:${n.defaultPreview?`default`:n.explicit?`explicit`:`inferred`}:${r??``}`;if(i!==ce.current){if(Zl(i)){ce.current=i;return}ce.current=i,Ql(i),queueMicrotask(()=>{Se(),A(!1),n.kind===`markdown`||n.kind===`code`?(k.setWorkspacePanelView(`files`),k.setWorkspaceInspectorFocusTarget({tab:`files`,filePath:n.path,nonce:Date.now()})):(k.setWebPreviewUrl(Pl(e.path,n.path)),k.setWorkspacePanelView(`browser`)),j(!0)})}},[W.currentToolProject,Se,oe,A,j,k]),(0,U.useEffect)(()=>{ce.current=``,A(!1)},[W.currentToolProject?.id,A]),(0,U.useEffect)(()=>{if(!nt)return;let e=e=>{let t=e.detail;t&&typeof t.path==`string`&&nt(t.path)};return window.addEventListener(`quickforge:preview-artifact`,e),()=>window.removeEventListener(`quickforge:preview-artifact`,e)},[nt]),(0,U.useEffect)(()=>yo(e=>{if(ru(e)){let t=typeof e.projectId==`string`?e.projectId:void 0;t&&(E(e=>{let n=new Set(e);return n.add(t),n}),Pe(t,0)),Fe({broadcast:!0});return}if((e.type===`agent_end`||e.type===`title_updated`||e.type===`session_forked`)&&Fe({broadcast:!0}),!nu(e))return;let t=typeof e.sessionId==`string`?e.sessionId:void 0,n=typeof e.title==`string`?e.title:G(`scheduledTasks`),r=tu(e.status)?e.status:`idle`,i=typeof e.message==`string`?e.message:void 0;_e({sessionId:t??``,title:n,status:r,message:i})}),[_e,Pe,Fe,E]);let{ready:rt,startupError:it,retryBootstrap:ot}=cs({storageRef:e,backendRef:we,activeModelRef:t,agentAccessModeRef:r,activeProjectRef:i,setAgentAccessMode:ee,taskMapRef:Ye,loadGlobalSessions:Ne,loadProject:h,initAgentAccessMode:O,switchActiveProject:g,createAgent:Be,setNeedsModelSetup:N,onStorageReady:me}),ct=_s(e,rt);(0,U.useEffect)(()=>{if(!rt)return;let e=0,t,n=(t=[])=>{let n=Date.now();if(t.length>0&&fe(e=>{let n=new Set(e);for(let e of t)n.add(e);return n}),!(n-e<5e3)){e=n,h(),Fe();for(let e of t)Pe(e,0)}},r=e=>{if(!e){t&&window.clearInterval(t),t=void 0;return}t||=window.setInterval(n,15e3)},i=new EventSource(`/api/channels/events`),a=e=>{try{let t=JSON.parse(e.data),i=ou(t);au(t)?(r(!0),n(i)):(t.type===`snapshot`||t.type===`status`)&&r(!1)}catch{}};return i.addEventListener(`snapshot`,a),i.addEventListener(`status`,a),i.addEventListener(`log`,a),()=>{i.close(),t&&window.clearInterval(t)}},[h,Pe,rt,Fe]),(0,U.useEffect)(()=>{if(rt)for(let e of d)!Me(e)&&!je(e)&&Pe(e,0)},[rt,d,Me,je,Pe]);let{startNewGlobalChat:lt,startNewProjectChat:ut,rollbackFromMessage:dt,retryFromMessage:pt,copyAnswer:mt,forkFromMessage:ht}=Zc({storageRef:e,activeModelRef:t,activeProjectRef:i,currentChatScopeRef:Ze,currentSessionIdRef:Xe,taskMapRef:Ye,agentRef:Je,createAgent:Be,startDeferredSession:Ve,syncSessionUI:Ue,setCurrentAgentMessages:We,setChatPanelRevision:Ke,refreshSessions:Fe,needsModelSetup:M,switchActiveProject:g,closeWorkspacePage:Se,setRestoredDraft:P}),{deleteProjectInline:gt}=Qc({activeProjectRef:i,refreshSessions:Fe,notifyProjectsChanged:Re.notifyProjectsChanged,setActiveProject:w,setProjects:T,setExpandedProjectIds:E,setChatPanelRevision:Ke}),{setAccessMode:_t}=rl({storageRef:e,agentAccessModeRef:r,setAgentAccessMode:ee,agentRef:Je,setChatPanelRevision:Ke,notifySettingsChanged:Re.notifySettingsChanged}),vt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t)throw Error(G(`toolApprovalFailed`));try{await t.approveToolCall(e)}catch(e){throw H.error(`Failed to approve tool call:`,e),e instanceof Error?e:Error(G(`toolApprovalFailed`))}},[Je]),yt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t)throw Error(G(`toolApprovalFailed`));try{await t.rejectToolCall(e)}catch(e){throw H.error(`Failed to reject tool call:`,e),e instanceof Error?e:Error(G(`toolApprovalFailed`))}},[Je]),bt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t?.approveAutoCompact)throw Error(G(`toolApprovalFailed`));await t.approveAutoCompact(e)},[Je]),xt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t?.rejectAutoCompact)throw Error(G(`toolApprovalFailed`));await t.rejectAutoCompact(e)},[Je]),{loadSession:St,renameSession:Ct,togglePinSession:wt,archiveSession:Tt,startNewGlobalSession:Et}=tl({storageRef:e,taskMapRef:Ye,currentSessionIdRef:Xe,loadAgentSession:He,setCurrentTitleRef:qe,refreshSessions:Fe,closeWorkspacePage:Se,startNewGlobalChat:lt}),{openModelSettings:Dt,openDefaultOptionsSettings:Ot,openAboutSettings:kt,activateLiteLlmExampleModel:At,openCustomModelSelector:jt}=Jc({storageRef:e,activeModelRef:t,agentRef:Je,createAgent:Be,updateCurrentAgentModel:Ge,setChatPanelRevision:Ke,needsModelSetup:M,setNeedsModelSetup:N,setRestoredDraft:P,notifySettingsChanged:Re.notifySettingsChanged,setSettingsDialogOpen:k.setSettingsDialogOpen}),Mt=(0,U.useMemo)(()=>[...Ee,...c.flatMap(e=>De(e.id))],[Ee,c,De]),Nt=!!(0,U.useMemo)(()=>{if(W.currentSessionId)return Mt.find(e=>e.id===W.currentSessionId)},[W.currentSessionId,Mt])?.pinnedAt,Pt=ol(Mt),Ft=(0,U.useCallback)(e=>W.taskStatuses[e.id]??Pt[e.id]??e.taskStatus??`idle`,[W.taskStatuses,Pt]);(0,U.useEffect)(()=>{if(!k.conversationMenuOpen)return;let e=()=>k.setConversationMenuOpen(!1);return window.addEventListener(`click`,e),window.addEventListener(`blur`,e),()=>{window.removeEventListener(`click`,e),window.removeEventListener(`blur`,e)}},[k,k.conversationMenuOpen]),(0,U.useEffect)(()=>{let e=e=>{let t=e.detail,n=typeof t?.command==`string`?t.command.trim():``;n&&(async()=>{(t?.confirm||t?.dangerous)&&!await Y({title:G(`confirmExecuteCommandTitle`),description:t?.dangerous?G(`confirmExecuteDangerousCommand`):G(`confirmExecuteMultipleCommands`),confirmLabel:G(`executeInTerminal`),cancelLabel:G(`cancel`),variant:t?.dangerous?`destructive`:`default`})||(R(!0),ae({id:++pe.current,command:n,execute:!0}))})().catch(e=>{H.error(`Failed to execute markdown command:`,e),X(e instanceof Error?e.message:G(`terminalCommandExecuteFailed`))})};return window.addEventListener(`quickforge:execute-markdown-command`,e),()=>window.removeEventListener(`quickforge:execute-markdown-command`,e)},[]);let It=(0,U.useCallback)(e=>{ae(t=>t?.id===e?null:t)},[]),Lt=(0,U.useCallback)(()=>{k.setFirstUseGuideDismissed(!0)},[k]),zt=(0,U.useCallback)(()=>{let e=W.currentToolProject?.id?G(`firstUseGuideProjectPrompt`):G(`firstUseGuideGeneralPrompt`);navigator.clipboard.writeText(e).then(()=>_e({sessionId:W.currentSessionId??``,title:G(`copied`),status:`idle`,message:e})).catch(e=>{H.error(`Failed to copy first-use guide prompt:`,e),X(G(`copyFailed`))})},[_e,W.currentSessionId,W.currentToolProject?.id]),Bt=!!B&&!k.firstUseGuideDismissed&&!re&&c.length===0&&Ee.length===0,Vt=(0,U.useCallback)(()=>{let e=W.currentSessionId;e&&(k.setConversationMenuOpen(!1),wt(e))},[W.currentSessionId,wt,k]),Ht=(0,U.useCallback)(()=>{let e=W.currentSessionId;e&&(k.setConversationMenuOpen(!1),Ct(e,W.currentTitle))},[W.currentSessionId,W.currentTitle,Ct,k]),Ut=(0,U.useCallback)(()=>{k.setConversationMenuOpen(!1),k.setShareDialogOpen(!0)},[k]),{setSkillsDialog:Z,setMcpServersDialogOpen:Wt,setSidebarOpen:Gt}=k,qt=(0,U.useCallback)(()=>{Z({scope:`global`})},[Z]),Jt=(0,U.useCallback)(e=>{Z({scope:`project`,project:e})},[Z]),Yt=(0,U.useCallback)(async e=>{let t=await fetch(`/api/project/${encodeURIComponent(e.id)}/open-in-explorer`,{method:`POST`});if(t.ok)return;let n=await t.json().catch(()=>null);throw Error(n?.error||G(`openInExplorerFailed`))},[]),Xt=(0,U.useCallback)(()=>{Wt(!0)},[Wt]),Zt=(0,U.useCallback)(e=>{Yt(e).catch(e=>{H.error(`Failed to open project in explorer:`,e),X(e instanceof Error?e.message:G(`openInExplorerFailed`))})},[Yt]),Qt=(0,U.useCallback)(()=>L(`scheduledTasks`),[L]),en=(0,U.useCallback)(()=>L(`agentProfiles`),[L]),tn=(0,U.useCallback)(()=>L(`plugins`),[L]),nn=(0,U.useCallback)(()=>Gt(e=>!e),[Gt]),Q=(0,U.useCallback)(()=>{k.setMobileSidebarOpen(!1)},[k]),rn=(0,U.useCallback)(e=>{Q(),St(e)},[Q,St]),an=(0,U.useCallback)(()=>{Q(),Et()},[Q,Et]),sn=(0,U.useCallback)(e=>{Q(),ut(e)},[Q,ut]),cn=(0,U.useCallback)(()=>{Q(),L(`scheduledTasks`)},[Q]),ln=(0,U.useCallback)(()=>{Q(),L(`agentProfiles`)},[Q]),un=(0,U.useCallback)(()=>{Q(),qt()},[Q,qt]),dn=(0,U.useCallback)(()=>{Q(),k.setMcpServersDialogOpen(!0)},[Q,k]),fn=(0,U.useCallback)(e=>{Q(),Jt(e)},[Q,Jt]),pn=(0,U.useCallback)(e=>{if(e.scope===`project`&&e.project&&e.projects){T(e.projects),k.setSkillsDialog({scope:`project`,project:e.project}),i.current?.id===e.project.id&&(w(e.project),i.current=e.project),Re.notifyProjectsChanged();return}Re.notifyProjectsChanged()},[Re,w,T,k]),mn=(0,q.jsx)(`div`,{className:`flex h-full w-full items-center justify-center text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)});return it?(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background p-6 text-foreground`,children:(0,q.jsxs)(`div`,{className:`max-w-md rounded-lg border border-border bg-background p-5 text-center`,children:[(0,q.jsx)(`h1`,{className:`text-base font-semibold`,children:G(`localServiceUnavailableTitle`)}),(0,q.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:it}),(0,q.jsxs)(`div`,{className:`mt-4 flex justify-center gap-2`,children:[(0,q.jsx)(J,{variant:`outline`,size:`sm`,onClick:ot,children:G(`retry`)}),(0,q.jsx)(J,{variant:`default`,size:`sm`,onClick:()=>window.location.reload(),children:G(`reloadPage`)})]})]})}):!rt||!W.agent&&!M?(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background text-foreground`,children:(0,q.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)})}):(0,q.jsxs)(q.Fragment,{children:[!k.settingsDialogOpen&&(0,q.jsxs)(`div`,{className:`fixed right-2 top-2 z-[60] flex items-center gap-1`,"aria-label":G(`workspacePanel`),children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>R(e=>!e),disabled:xe||M,"aria-label":`终端`,title:`终端`,className:re?`bg-accent text-accent-foreground`:void 0,children:(0,q.jsx)(F,{className:`size-4`})}),(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>{A(!1),k.setWorkspaceInspectorOpen(e=>!e)},disabled:!W.currentToolProject?.id||xe||M,"aria-label":k.workspaceInspectorOpen?G(`workspaceCollapseRightPanel`):G(`workspaceExpandRightPanel`),title:k.workspaceInspectorOpen?G(`workspaceCollapseRightPanel`):G(`workspaceExpandRightPanel`),className:K(`hidden lg:inline-flex`,k.workspaceInspectorOpen?`bg-accent text-accent-foreground`:void 0),children:(0,q.jsx)(a,{className:`size-4`})})]}),(0,q.jsxs)(`div`,{className:`flex h-screen min-h-0 bg-background text-foreground`,children:[(0,q.jsx)(no,{sidebarOpen:k.sidebarOpen,scheduledTasksActive:ye,agentProfilesActive:V,pluginsActive:be,projectsCollapsed:k.projectsCollapsed,conversationsCollapsed:k.conversationsCollapsed,projects:c,expandedProjectIds:d,activeProject:s,currentSessionId:W.currentSessionId,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,globalLoading:Ae,onLoadMoreGlobal:Ie,projectHasMore:ke,projectLoading:je,projectLoaded:Me,onLoadMoreProject:Le,sessionTaskStatus:Ft,selectingProject:p,onToggleProjectsCollapsed:k.toggleProjectsCollapsed,onToggleConversationsCollapsed:k.toggleConversationsCollapsed,onToggleProjectExpanded:b,onToggleAllProjectsExpanded:S,onReorderProjects:C,onSelectProjectDirectory:v,onStartNewProjectChat:ut,onOpenGlobalSkills:qt,onOpenMcpServers:Xt,onOpenProjectSkills:Jt,onOpenProjectInExplorer:Zt,onDeleteProject:gt,onLoadSession:St,onTogglePinSession:wt,onRenameSession:Ct,onDeleteSession:Tt,onStartNewGlobalChat:Et,onOpenScheduledTasks:Qt,onOpenAgentProfiles:en,onOpenPlugins:tn,onOpenSettings:Ot,updateAvailable:ct.result.updateAvailable,latestVersion:ct.result.latestVersion,currentVersion:ct.result.currentVersion,onOpenUpdate:kt,onDismissUpdate:ct.dismissUpdate,onToggleSidebar:nn,currentSessionHoverInfo:le}),k.mobileSidebarOpen?(0,q.jsxs)(`div`,{className:`fixed inset-0 z-50 md:hidden`,role:`dialog`,"aria-modal":`true`,children:[(0,q.jsx)(`button`,{type:`button`,className:`absolute inset-0 bg-background/65 backdrop-blur-sm`,onClick:Q,"aria-label":G(`toggleSidebar`)}),(0,q.jsx)(`div`,{className:`absolute inset-y-0 left-0 max-w-[85vw] shadow-quickforge`,children:(0,q.jsx)(no,{variant:`mobile`,sidebarOpen:!0,scheduledTasksActive:ye,agentProfilesActive:V,pluginsActive:be,projectsCollapsed:k.projectsCollapsed,conversationsCollapsed:k.conversationsCollapsed,projects:c,expandedProjectIds:d,activeProject:s,currentSessionId:W.currentSessionId,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,globalLoading:Ae,onLoadMoreGlobal:Ie,projectHasMore:ke,projectLoading:je,projectLoaded:Me,onLoadMoreProject:Le,sessionTaskStatus:Ft,selectingProject:p,onToggleProjectsCollapsed:k.toggleProjectsCollapsed,onToggleConversationsCollapsed:k.toggleConversationsCollapsed,onToggleProjectExpanded:b,onToggleAllProjectsExpanded:S,onReorderProjects:C,onSelectProjectDirectory:()=>{Q(),v()},onStartNewProjectChat:sn,onOpenGlobalSkills:un,onOpenMcpServers:dn,onOpenProjectSkills:fn,onOpenProjectInExplorer:e=>{Q(),Yt(e).catch(e=>{H.error(`Failed to open project in explorer:`,e),X(e instanceof Error?e.message:G(`openInExplorerFailed`))})},onDeleteProject:gt,onLoadSession:rn,onTogglePinSession:wt,onRenameSession:Ct,onDeleteSession:Tt,onStartNewGlobalChat:an,onOpenScheduledTasks:cn,onOpenAgentProfiles:ln,onOpenPlugins:()=>{Q(),L(`plugins`)},onOpenSettings:()=>{Q(),Ot()},updateAvailable:ct.result.updateAvailable,latestVersion:ct.result.latestVersion,currentVersion:ct.result.currentVersion,onOpenUpdate:()=>{Q(),kt()},onDismissUpdate:ct.dismissUpdate,onToggleSidebar:Q,currentSessionHoverInfo:le})})]}):null,(0,q.jsxs)(`main`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,q.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-2 border-b border-border px-3 pr-20`,children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`md:hidden`,onClick:()=>k.setMobileSidebarOpen(!0),"aria-label":G(`toggleSidebar`),children:(0,q.jsx)(l,{className:`size-4`})}),(0,q.jsx)(`div`,{className:`min-w-0 flex-1`,children:ye?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`scheduledTasks`)})]}):V?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`agentsTab`)})]}):be?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`plugins`)})]}):(0,q.jsxs)(`div`,{className:`flex max-w-full min-w-0 items-center`,children:[W.currentToolProject?.name?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`min-w-0 truncate text-sm text-muted-foreground/60`,children:W.currentToolProject.name}),(0,q.jsx)(`div`,{className:`mx-1 shrink-0 text-sm text-muted-foreground/45`,children:`/`})]}):null,(0,q.jsx)(`div`,{className:`min-w-0 truncate text-sm font-medium text-foreground/90`,children:Kt(W.currentTitle)}),(0,q.jsxs)(`div`,{className:`relative ml-0.5 shrink-0`,onClick:e=>e.stopPropagation(),children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`size-6`,onClick:()=>k.setConversationMenuOpen(e=>!e),disabled:!W.currentSessionId||M,"aria-label":G(`moreOptions`),"aria-expanded":k.conversationMenuOpen,children:(0,q.jsx)(I,{className:`size-4`})}),k.conversationMenuOpen?(0,q.jsxs)(`div`,{className:`absolute left-0 top-8 z-30 min-w-44 rounded-lg border border-border bg-popover p-1 shadow-quickforge`,children:[(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Vt,children:[Nt?(0,q.jsx)(n,{className:`size-4`}):(0,q.jsx)(f,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(Nt?`unpinSession`:`pinSession`)})]}),(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Ht,children:[(0,q.jsx)(ie,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(`renameSession`)})]}),(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Ut,children:[(0,q.jsx)(x,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(`shareSession`)})]})]}):null]})]})})]}),(0,q.jsx)(`section`,{className:`relative flex min-h-0 flex-1 flex-col`,children:ye?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Hl,{onOpenSession:Qe})}):V?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Ul,{})}):be?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Wl,{})}):M?(0,q.jsx)(kn,{onAddModel:Dt,onUseExample:()=>{At().catch(e=>H.error(`Failed to use LiteLLM example:`,e))}}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col`,children:(0,q.jsx)(at,{children:(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)($l,{}),children:(0,q.jsx)(Bl,{agent:W.agent,onModelSelect:jt,revision:W.chatPanelRevision,agentAccessMode:D,workspaceToolsEnabled:!!W.currentToolProject?.id,project:W.currentToolProject,projectId:W.currentToolProject?.id,chatScope:W.chatScope,onAccessModeChange:_t,onRollbackFromMessage:dt,onRetryFromMessage:pt,onCopyAnswer:mt,onForkFromMessage:ht,onApproveToolCall:vt,onRejectToolCall:yt,onApproveAutoCompact:bt,onRejectAutoCompact:xt,onOpenWorkspaceGitChanges:et,onOpenLocalFilePath:tt,onArtifactsChange:se,onContextUsageDisplayChange:ze,disableFork:!1,restoredDraft:te})})})}),Bt?(0,q.jsx)(On,{hasProject:!!W.currentToolProject?.id,onConfigureModel:Dt,onAddProject:v,onCopyExamplePrompt:zt,onDismiss:Lt}):null,re?(0,q.jsx)(U.Suspense,{fallback:null,children:(0,q.jsx)(Vl,{project:W.currentToolProject,pendingCommand:z,onPendingCommandHandled:It,onCollapse:()=>R(!1)})}):null]})})]}),k.workspaceInspectorOpen&&W.currentToolProject?.id?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(eu,{}),children:(0,q.jsx)(Kl,{project:W.currentToolProject,open:!0,view:k.workspacePanelView,onViewChange:k.setWorkspacePanelView,onPreviewArtifact:nt,onDraftRequest:$e,focusTarget:k.workspaceInspectorFocusTarget,previewUrl:k.webPreviewUrl,onPreviewUrlChange:k.setWebPreviewUrl,artifacts:oe})}):null,k.inlineReaderOpen?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(eu,{}),children:(0,q.jsx)(ql,{open:!0,mode:`file`,file:k.inlineReaderFile,loading:k.inlineReaderLoading,error:k.inlineReaderError,onOpenChange:k.setInlineReaderOpen,onDraftRequest:$e})}):null]}),(0,q.jsx)(st,{open:m,initialPath:s?.path,disabled:p,onOpenChange:y,onSelect:_}),(0,q.jsx)(ft,{open:!!k.skillsDialog,scope:k.skillsDialog?.scope??`global`,project:k.skillsDialog?.project,onOpenChange:e=>{e||k.setSkillsDialog(void 0)},onSaved:pn}),(0,q.jsx)(Rt,{open:k.mcpServersDialogOpen,onOpenChange:k.setMcpServersDialogOpen}),(0,q.jsx)(bl,{open:k.shareDialogOpen,sessionId:W.currentSessionId,title:Kt(W.currentTitle),onOpenChange:k.setShareDialogOpen}),(0,q.jsx)(ll,{toasts:he,onDismiss:ve,onClick:Qe})]})}function cu(){let e=window.location.pathname.match(/^\/share\/([^/]+)\/?$/)?.[1];return e?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)}),children:(0,q.jsx)(Gl,{shareId:decodeURIComponent(e)})}):(0,q.jsx)(su,{})}tt({hideSelector:!0}),rt(),window.addEventListener(`error`,e=>{H.error(`Uncaught error:`,e.error??e.message)}),window.addEventListener(`unhandledrejection`,e=>{H.error(`Unhandled promise rejection:`,e.reason)}),`serviceWorker`in navigator&&window.addEventListener(`load`,()=>{navigator.serviceWorker.register(`/sw.js`).catch(()=>{})}),(0,Pe.createRoot)(document.getElementById(`root`)).render((0,q.jsx)(U.StrictMode,{children:(0,q.jsx)(at,{children:(0,q.jsx)(cu,{})})}));export{Vt as A,so as C,un as D,xn as E,K as F,G as I,Y as M,ut as N,hn as O,J as P,fo as S,fn as T,Co as _,Rl as a,wo as b,Dl as c,_l as d,yl as f,Uo as g,is as h,jl as i,X as j,Sn as k,Tl as l,qc as m,Al as n,Fl as o,vl as p,Nl as r,Ol as s,kl as t,wl as u,Eo as v,po as w,lo as x,To as y};
|
|
1476
|
+
`),[e]),a=(0,U.useCallback)(async()=>{if(r.size===0){n({});return}try{let e=await vo(),t=new Map(e.map(e=>[e.sessionId,al(e.status)]).filter(e=>!!e[1]));n(e=>{let n={};for(let i of r){let r=t.get(i),a=e[i];r?n[i]=r:a===`running`?n[i]=`idle`:a&&a!==`idle`&&(n[i]=a)}return n})}catch(e){H.error(`Failed to refresh visible agent statuses:`,e)}},[r]);return(0,U.useEffect)(()=>{let e=window.setTimeout(()=>{a()},0);return()=>window.clearTimeout(e)},[a,i]),(0,U.useEffect)(()=>yo(e=>{let t=e.sessionId;if(!(!t||!r.has(t))){if(e.type===`agent_start`){n(e=>({...e,[t]:`running`}));return}if(e.type===`agent_end`){let r=al(e.status)===`aborted`?`aborted`:e.errorMessage?`error`:`idle`;n(e=>({...e,[t]:r}))}}}),[r]),(0,U.useEffect)(()=>{let e=()=>{document.visibilityState===`visible`&&a()};return document.addEventListener(`visibilitychange`,e),()=>document.removeEventListener(`visibilitychange`,e)},[a]),t}function sl(e){return e===`idle`?{tone:`success`,message:G(`taskCompleted`)}:e===`error`?{tone:`error`,message:G(`taskError`)}:e===`aborted`?{tone:`aborted`,message:G(`processAborted`)}:e===`running`?{tone:`running`,message:G(`taskRunning`)}:{tone:`neutral`,message:G(`taskRunning`)}}function cl({toast:e,onDismiss:t,onClick:n}){let[r,i]=(0,U.useState)(!1),[a,o]=(0,U.useState)(!1),s=(0,U.useRef)(null);(0,U.useEffect)(()=>{let n=window.setTimeout(()=>i(!0),10);return s.current=window.setTimeout(()=>{o(!0),s.current=window.setTimeout(()=>t(e.id),200)},5e3),()=>{window.clearTimeout(n),s.current!==null&&window.clearTimeout(s.current)}},[e.id,t]);let c=()=>{o(!0),s.current!==null&&window.clearTimeout(s.current),s.current=window.setTimeout(()=>t(e.id),200)},l=sl(e.status),u=l.tone===`error`,d=l.tone===`success`,f=K(`size-5`,u&&`text-destructive`,d&&`text-emerald-500`,l.tone===`aborted`&&`text-amber-600`,l.tone===`running`&&`text-blue-600`,l.tone===`neutral`&&`text-muted-foreground`);return(0,q.jsxs)(`div`,{role:`alert`,onClick:()=>n(e.sessionId),className:K(`pointer-events-auto flex w-80 cursor-pointer items-start gap-3 rounded-xl border border-border bg-background p-3 shadow-quickforge transition-all duration-200 ease-out`,r&&!a?`translate-x-0 opacity-100`:`translate-x-4 opacity-0`),children:[(0,q.jsx)(`div`,{className:`mt-0.5 shrink-0`,children:d?(0,q.jsx)(S,{className:f}):(0,q.jsx)(A,{className:f})}),(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`p`,{className:`truncate text-sm font-medium text-foreground/90`,children:e.title}),(0,q.jsx)(`p`,{className:`mt-0.5 line-clamp-3 text-xs text-muted-foreground`,children:e.message||l.message})]}),(0,q.jsx)(`button`,{type:`button`,onClick:e=>{e.stopPropagation(),c()},className:`shrink-0 rounded-md p-0.5 text-muted-foreground/60 transition-colors hover:text-foreground`,"aria-label":G(`close`),children:(0,q.jsx)(N,{className:`size-4`})})]})}function ll({toasts:e,onDismiss:t,onClick:n}){return e.length===0?null:(0,q.jsx)(`div`,{className:`pointer-events-none fixed right-4 top-16 z-50 flex flex-col gap-2`,children:e.map(e=>(0,q.jsx)(cl,{toast:e,onDismiss:t,onClick:n},e.id))})}async function ul(e,t){let n=await fetch(e,{...t,cache:`no-store`,headers:{...t?.body?{"content-type":`application/json`}:void 0,...t?.headers}}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`Request failed: ${n.status}`);return r}function dl(e){if(typeof crypto<`u`&&typeof crypto.getRandomValues==`function`){let t=new Uint8Array(1);return crypto.getRandomValues(t),e[t[0]%e.length]}return e[Math.floor(Math.random()*e.length)]}function fl(){let e=()=>Array.from({length:6},()=>dl(`ABCDEFGHJKLMNPQRSTUVWXYZ23456789`)).join(``);return`${e()}-${e()}`}function pl(e=24){return new Date(Date.now()+e*60*60*1e3).toISOString()}async function ml(e){return ul(`/api/shares`,{method:`POST`,body:JSON.stringify(e)})}async function hl(e){return ul(`/api/shares${e?`?sessionId=${encodeURIComponent(e)}`:``}`)}async function gl(e){return ul(`/api/shares/${encodeURIComponent(e)}`,{method:`DELETE`})}async function _l(e){return ul(`/api/shared/${encodeURIComponent(e)}/meta`)}async function vl(e,t=``){return ul(`/api/shared/${encodeURIComponent(e)}/unlock`,{method:`POST`,body:JSON.stringify({password:t})})}async function yl(e){return ul(`/api/shared/${encodeURIComponent(e)}/models`)}function bl({open:e,sessionId:t,title:n,onOpenChange:r}){let i=(0,U.useId)(),[a,o]=(0,U.useState)(`read`),[s,c]=(0,U.useState)(``),[l,u]=(0,U.useState)(`24h`),[d,f]=(0,U.useState)(!1),[p,m]=(0,U.useState)(``),[h,g]=(0,U.useState)([]),[_,y]=(0,U.useState)(!1),[b,x]=(0,U.useState)(),S=(0,U.useMemo)(()=>{if(l!==`never`)return pl(l===`1h`?1:l===`7d`?168:24)},[l]);if((0,U.useEffect)(()=>{!e||!t||hl(t).then(e=>g(e.shares)).catch(e=>x(e instanceof Error?e.message:`Failed to load shares`))},[e,t]),!e)return null;let C=a===`operate`,w=!!t&&(a!==`operate`||d&&s.trim()),T=async()=>{if(!(!t||!w)){if(C&&!s.trim()){x(`可操作分享必须设置密码。`);return}y(!0),x(void 0);try{let e=await ml({sessionId:t,permission:a,password:s.trim(),expiresAt:S});m(e.url),await Eo(e.url),f(!1),g((await hl(t)).shares)}catch(e){x(e instanceof Error?e.message:`Failed to create share`)}finally{y(!1)}}},E=async e=>{let t=e.url||`${window.location.origin}/share/${encodeURIComponent(e.id)}`;m(t),await Eo(t)},D=async e=>{try{await gl(e),g(t=>t.map(t=>t.id===e?{...t,revokedAt:new Date().toISOString()}:t))}catch(e){x(e instanceof Error?e.message:`Failed to revoke share`)}};return(0,q.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4`,onMouseDown:e=>{e.target===e.currentTarget&&r(!1)},children:(0,q.jsxs)(`div`,{className:`flex max-h-[90vh] w-full max-w-2xl flex-col overflow-hidden rounded-2xl border border-border bg-background shadow-quickforge`,onMouseDown:e=>e.stopPropagation(),children:[(0,q.jsxs)(`div`,{className:`shrink-0 border-b border-border px-5 py-4`,children:[(0,q.jsx)(`h2`,{className:`text-base font-semibold`,children:`分享到局域网`}),(0,q.jsxs)(`p`,{className:`mt-1 text-sm text-muted-foreground`,children:[`当前对话:`,n,`。同一个对话只会有一个固定分享链接;只读分享密码可选,可操作分享必须设置密码。`]})]}),(0,q.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto px-5 py-4`,children:(0,q.jsxs)(`div`,{className:`space-y-4`,children:[(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-2 text-sm font-medium`,children:`权限`}),(0,q.jsxs)(`div`,{className:`grid gap-2 sm:grid-cols-2`,children:[(0,q.jsxs)(`button`,{type:`button`,className:`rounded-xl border p-3 text-left text-sm ${a===`read`?`border-primary bg-primary/10`:`border-border`}`,onClick:()=>o(`read`),children:[(0,q.jsx)(`div`,{className:`font-medium`,children:`仅阅读`}),(0,q.jsx)(`div`,{className:`mt-1 text-xs text-muted-foreground`,children:`只能查看这一个对话。`})]}),(0,q.jsxs)(`button`,{type:`button`,className:`rounded-xl border p-3 text-left text-sm ${a===`operate`?`border-red-400 bg-red-50 text-red-950`:`border-border`}`,onClick:()=>o(`operate`),children:[(0,q.jsx)(`div`,{className:`font-medium text-red-700`,children:`可操作(高危)`}),(0,q.jsx)(`div`,{className:`mt-1 text-xs text-red-700`,children:`允许对方操作这个原对话,禁止 Fork。`})]})]})]}),a===`operate`?(0,q.jsxs)(`div`,{className:`rounded-xl border border-red-300 bg-red-50 p-3 text-sm text-red-900`,children:[(0,q.jsxs)(`div`,{className:`flex gap-2 font-semibold`,children:[(0,q.jsx)(ee,{className:`mt-0.5 size-4`}),`高危可操作权限`]}),(0,q.jsx)(`p`,{className:`mt-2 text-xs leading-5`,children:`拥有链接和密码的人只能操作这一个原对话,但对方的消息、停止生成、回滚、模型/思考等级选择、YOLO 状态下可用工具等操作会按正常对话权限直接影响你的本机原对话。可操作分享必须设置密码。`}),(0,q.jsxs)(`label`,{className:`mt-3 flex items-center gap-2 text-xs font-medium`,children:[(0,q.jsx)(`input`,{type:`checkbox`,checked:d,onChange:e=>f(e.target.checked)}),`我已了解风险,仍然允许可操作权限。`]})]}):null,(0,q.jsxs)(`div`,{className:`space-y-2`,children:[(0,q.jsx)(`label`,{htmlFor:i,className:`block text-sm font-medium`,children:C?`密码(可操作必填)`:`密码(可选)`}),(0,q.jsxs)(`div`,{className:`flex flex-col gap-3 sm:flex-row sm:items-center`,children:[(0,q.jsx)(`input`,{id:i,value:s,onChange:e=>c(e.target.value),className:`h-10 w-full min-w-0 rounded-md border border-input bg-background px-3 text-sm`,placeholder:C?`可操作分享必须设置密码`:`留空则打开链接无需密码`}),(0,q.jsxs)(J,{variant:`outline`,className:`h-10 sm:shrink-0`,onClick:()=>c(fl()),children:[(0,q.jsx)(re,{className:`mr-2 size-4`}),`生成密码`]})]}),(0,q.jsx)(`span`,{className:`block text-xs text-muted-foreground`,children:C?`可操作分享必须设置非空密码;修改密码后旧密码和已解锁状态会失效。`:`留空保存会取消密码保护;填写新密码保存后旧密码和已解锁状态会失效。`})]}),(0,q.jsxs)(`label`,{className:`block text-sm font-medium`,children:[`有效期`,(0,q.jsxs)(`select`,{value:l,onChange:e=>u(e.target.value),className:`mt-2 h-10 w-full rounded-md border border-input bg-background px-3 text-sm`,children:[(0,q.jsx)(`option`,{value:`1h`,children:`1 小时`}),(0,q.jsx)(`option`,{value:`24h`,children:`24 小时`}),(0,q.jsx)(`option`,{value:`7d`,children:`7 天`}),(0,q.jsx)(`option`,{value:`never`,children:`永久,需手动撤销`})]})]}),p?(0,q.jsxs)(`div`,{className:`rounded-xl border border-emerald-300 bg-emerald-50 p-3 text-sm text-emerald-900`,children:[`已复制到剪切板。`,(0,q.jsx)(`pre`,{className:`mt-2 max-h-36 overflow-auto whitespace-pre-wrap text-xs`,children:p})]}):null,b?(0,q.jsx)(`div`,{className:`rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive`,children:b}):null,h.length?(0,q.jsxs)(`div`,{children:[(0,q.jsx)(`div`,{className:`mb-2 text-sm font-medium`,children:`已有分享`}),(0,q.jsx)(`div`,{className:`space-y-2`,children:h.map(e=>(0,q.jsxs)(`div`,{className:`flex items-center gap-2 rounded-lg border border-border p-2 text-xs`,children:[(0,q.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,q.jsx)(`div`,{className:`truncate font-mono`,children:e.id}),(0,q.jsxs)(`div`,{className:`text-muted-foreground`,children:[e.permission===`operate`?`可操作`:`只读`,` · `,e.hasPassword?`有密码`:`无密码`,` · `,e.revokedAt?`已撤销`:e.expiresAt?`到期 ${new Date(e.expiresAt).toLocaleString()}`:`永久`]})]}),e.revokedAt?null:(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>void E(e),"aria-label":`复制分享链接`,title:`复制分享链接`,children:(0,q.jsx)(O,{className:`size-4`})}),(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`text-destructive`,onClick:()=>void D(e.id),"aria-label":`撤销分享`,title:`撤销分享`,children:(0,q.jsx)(v,{className:`size-4`})})]})]},e.id))})]}):null]})}),(0,q.jsx)(`div`,{className:`shrink-0 border-t border-border px-5 py-4`,children:(0,q.jsxs)(`div`,{className:`flex justify-end gap-2`,children:[(0,q.jsx)(J,{variant:`outline`,onClick:()=>r(!1),children:G(`cancel`)}),(0,q.jsxs)(J,{variant:a===`operate`?`destructive`:`default`,disabled:!w||_,onClick:()=>void T(),title:a===`operate`&&!s.trim()?`可操作分享必须设置密码`:void 0,children:[(0,q.jsx)(O,{className:`mr-2 size-4`}),a===`operate`?`保存配置并复制高危可操作链接`:`保存配置并复制链接`]})]})})]})})}async function xl(e){let t=await fetch(e,{cache:`no-store`}),n=await t.json().catch(()=>null);if(!t.ok)throw Error(n?.error||`Request failed: ${t.status}`);return n}async function Sl(e,t){let n=await fetch(e,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(t)}),r=await n.json().catch(()=>null);if(!n.ok)throw Error(r?.error||`Request failed: ${n.status}`);return r}function Cl(e){return`projectId=${encodeURIComponent(e)}`}function wl(e){return xl(`/api/workspace/tree?${Cl(e)}`)}function Tl(e,t){return xl(`/api/workspace/file?${Cl(e)}&path=${encodeURIComponent(t)}`)}function El(e,t){return Sl(`/api/workspace/resolve-path`,{projectId:e,path:t})}function Dl(e){return xl(`/api/git/status?${Cl(e)}`)}function Ol(e,t){return xl(`/api/git/file-diff?${Cl(e)}&path=${encodeURIComponent(t)}`)}function kl(e){let t=e.replace(/\\/g,`/`);return t.split(`/`).filter(Boolean).pop()||t||`artifact`}function Al(e){let t=e.toLowerCase();return t.endsWith(`.html`)||t.endsWith(`.htm`)?`html`:/\.(svg|png|jpe?g|webp|gif|bmp|ico)$/i.test(t)?`image`:t.endsWith(`.md`)||t.endsWith(`.mdx`)?`markdown`:/\.(ts|tsx|js|jsx|mjs|cjs|css|scss|less|json|jsonc|txt|xml|yml|yaml|toml|ini|py|rb|go|rs|java|c|h|cpp|hpp|cs|php|sh|bash|zsh|ps1)$/i.test(t)?`code`:`unknown`}function jl(e){return Al(e)!==`unknown`}var Ml=/\.(svg|png|jpe?g|webp|gif|ico)$/i;function Nl(e){return Al(e)===`html`||Ml.test(e)}function Pl(e,t){let n=t.replace(/\\/g,`/`);return!e?.trim()||n.startsWith(`/`)||/^[a-zA-Z]:\//.test(n)?t:`${e.trim().replace(/\\/g,`/`).replace(/\/+$/,``)}/${n.replace(/^\/+/,``)}`}function Fl(e,t,n){let r=t.replace(/\\/g,`/`),i=r.match(/^\/+/)?.[0]??``,a=i+r.slice(i.length).split(`/`).filter(Boolean).map(e=>encodeURIComponent(e)).join(`/`),o=`/api/workspace/preview/${encodeURIComponent(e)}/${a}`;return n?`${o}?r=${n}`:o}function Il(e){return e.replace(/\\/g,`/`).toLowerCase()}function Ll(e){let t=kl(e.path).toLowerCase();return e.defaultPreview?0:e.explicit&&e.preview?1:e.explicit?2:t===`index.html`?3:e.kind===`html`?4:e.kind===`image`?5:e.kind===`markdown`?6:e.kind===`code`?7:20}function Rl(e){let t=new Map;for(let n of e){if(!n.path)continue;let e=Il(n.path),r=n.kind??Al(n.path),i=t.get(e),a=n.preview??jl(n.path),o=n.source===`present_files`||n.presentation===`explicit`;if(!i){t.set(e,{id:e,path:n.path,title:n.title,description:n.description,kind:r,preview:a,defaultPreview:!!n.defaultPreview,explicit:o,addedLines:n.addedLines,removedLines:n.removedLines,sources:[n.source],toolCallIds:n.toolCallId?[n.toolCallId]:[]});continue}i.preview=i.preview||a,i.defaultPreview=i.defaultPreview||!!n.defaultPreview,i.explicit=i.explicit||o,i.title=n.title||i.title,i.description=n.description||i.description,typeof n.addedLines==`number`&&(i.addedLines=(i.addedLines??0)+n.addedLines),typeof n.removedLines==`number`&&(i.removedLines=(i.removedLines??0)+n.removedLines),i.kind=i.kind===`unknown`?r:i.kind,i.sources.includes(n.source)||i.sources.push(n.source),n.toolCallId&&!i.toolCallIds.includes(n.toolCallId)&&i.toolCallIds.push(n.toolCallId)}return[...t.values()].sort((e,t)=>Ll(e)-Ll(t))}function zl(e){let t=Rl(e).filter(e=>e.preview&&e.explicit);if(t.length<=1)return t[0];let n=new Map;for(let t=0;t<e.length;t++){let r=e[t]?.toolCallId;r&&n.set(r,t)}let r=e=>{let t=e.toolCallIds,r=-1;for(let e of t){let t=n.get(e);typeof t==`number`&&t>r&&(r=t)}return r};return[...t].sort((e,t)=>r(t)-r(e))[0]}var Bl=(0,U.lazy)(()=>Ne(()=>import(`./ChatPanelHost-BTqhhkWK.js`).then(e=>({default:e.ChatPanelHost})),__vite__mapDeps([0,1,2,3,4,5,6,7,8]))),Vl=(0,U.lazy)(()=>Ne(()=>import(`./TerminalDock-Loi8A4pJ.js`).then(e=>({default:e.TerminalDock})),__vite__mapDeps([9,1,10,11,5,6]))),Hl=(0,U.lazy)(()=>Ne(()=>import(`./ScheduledTasksPage-Cbm6LVk3.js`).then(e=>({default:e.ScheduledTasksPage})),__vite__mapDeps([12,1,5,6]))),Ul=(0,U.lazy)(()=>Ne(()=>import(`./AgentProfilesPage-BToo_R3Y.js`).then(e=>({default:e.AgentProfilesPage})),__vite__mapDeps([13,1,5,6]))),Wl=(0,U.lazy)(()=>Ne(()=>import(`./PluginsPage-DwzV2vQ4.js`).then(e=>({default:e.PluginsPage})),__vite__mapDeps([14,1,5,6,7]))),Gl=(0,U.lazy)(()=>Ne(()=>import(`./SharedConversationPage-CHE9qABz.js`).then(e=>({default:e.SharedConversationPage})),__vite__mapDeps([15,1,3,2,4,5,6,0,7,8]))),Kl=(0,U.lazy)(()=>Ne(()=>import(`./WorkspaceInspector-Nf5xELW7.js`).then(e=>({default:e.WorkspaceInspector})),__vite__mapDeps([16,1,5,6,17,18]))),ql=(0,U.lazy)(()=>Ne(()=>import(`./WorkspaceReaderDialog-Bai7v3V0.js`).then(e=>({default:e.WorkspaceReaderDialog})),__vite__mapDeps([19,1,5,6,17,18]))),Jl=`quickforge:auto-preview-seen-signatures`,Yl=200;function Xl(){if(typeof window>`u`)return new Set;try{let e=window.sessionStorage.getItem(Jl),t=e?JSON.parse(e):void 0;return Array.isArray(t)?new Set(t.filter(e=>typeof e==`string`&&e.length>0)):new Set}catch{return new Set}}function Zl(e){return Xl().has(e)}function Ql(e){if(!(typeof window>`u`))try{let t=[...Xl(),e].slice(-Yl);window.sessionStorage.setItem(Jl,JSON.stringify(t))}catch{}}function $l(){return(0,q.jsx)(`div`,{className:`flex min-h-0 flex-1 items-center justify-center text-sm text-muted-foreground`,children:G(`loading`)})}function eu(){return null}function tu(e){return e===`idle`||e===`running`||e===`error`||e===`aborted`}function nu(e){return e.type===`scheduled_task_notification`}function ru(e){return e.type===`scheduled_task_started`}function iu(e){return e===`starting`||e===`waiting_scan`||e===`running`||e===`stopping`}function au(e){return Array.isArray(e.channels)?e.channels.some(e=>iu(e.status)):iu(e.snapshot?.status)||iu(e.status)}function ou(e){return[...Array.isArray(e.channels)?e.channels:[],...e.snapshot?[e.snapshot]:[]].filter(e=>iu(e.status)).map(e=>e.launchWorkspace).filter(e=>e?.kind===`project`&&typeof e.id==`string`&&e.id.length>0).map(e=>e.id)}function su(){let e=(0,U.useRef)(null),t=(0,U.useRef)(on($t)),r=(0,U.useRef)(`default`),i=(0,U.useRef)(void 0),o=(0,U.useRef)(void 0),{activeProject:s,projects:c,defaultWorkspace:u,expandedProjectIds:d,selectingProject:p,projectPickerOpen:m,loadProject:h,switchActiveProject:g,handleSelectProjectPath:_,selectProjectDirectory:v,setProjectPickerOpen:y,toggleProjectExpanded:b,toggleAllProjectsExpanded:S,reorderProjects:C,setActiveProject:w,setProjects:T,setExpandedProjectIds:E}=ro(),{agentAccessMode:D,setAgentAccessMode:ee,initialize:O}=io(),k=il(),{setArtifactPreviewOpen:A,setWorkspaceInspectorOpen:j}=k,[M,N]=(0,U.useState)(!1),[te,P]=(0,U.useState)(),[ne,L]=(0,U.useState)(`chat`),[re,R]=(0,U.useState)(!1),[z,ae]=(0,U.useState)(null),[oe,se]=(0,U.useState)([]),ce=(0,U.useRef)(``),[le,ue]=(0,U.useState)(),[de,fe]=(0,U.useState)(()=>new Set),pe=(0,U.useRef)(0),[B,me]=(0,U.useState)(null),{toasts:he,handleTaskComplete:ge,addToast:_e,dismissToast:ve}=Ro(),ye=ne===`scheduledTasks`,V=ne===`agentProfiles`,be=ne===`plugins`,xe=ne!==`chat`,Se=(0,U.useCallback)(()=>L(`chat`),[]),Ce=(0,U.useRef)(null),we=(0,U.useRef)(null),{allLoadedSessions:Te,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,projectHasMore:ke,globalLoading:Ae,projectLoading:je,projectLoaded:Me,loadGlobalSessions:Ne,loadProjectSessions:Pe,refreshSessions:Fe,loadMoreGlobal:Ie,loadMoreProject:Le}=Lo({backendRef:we,expandedProjectIds:d,externalProjectIds:de,onBroadcastSessionsChanged:(0,U.useCallback)(()=>Ce.current?.notifySessionsChanged(),[])}),Re=oo({onSessionsChanged:()=>{Fe()},onProjectsChanged:()=>{h()},onSettingsChanged:()=>{Fe()}});(0,U.useEffect)(()=>{r.current=D},[D]),(0,U.useEffect)(()=>{i.current=s},[s]),(0,U.useEffect)(()=>{o.current=u},[u]),(0,U.useEffect)(()=>{Ce.current=Re},[Re]);let ze=(0,U.useCallback)((e,t)=>{ue({sessionId:e,...t})},[]),W=No({storageRef:e,activeModelRef:t,agentAccessModeRef:r,activeProjectRef:i,defaultWorkspaceRef:o,setAgentAccessMode:ee,switchActiveProject:g,sessions:Te,refreshSessions:Fe,onTaskComplete:ge}),{createAgent:Be,startDeferredSession:Ve,loadSession:He,syncSessionUI:Ue,setCurrentAgentMessages:We,updateCurrentAgentModel:Ge,setChatPanelRevision:Ke,setCurrentTitleRef:qe,agentRef:Je,taskMapRef:Ye,currentSessionIdRef:Xe,currentChatScopeRef:Ze}=W,Qe=(0,U.useCallback)(e=>{e&&(Se(),He(e))},[Se,He]),$e=(0,U.useCallback)(e=>{e.trim()&&(Se(),P({id:Date.now(),sessionId:Je.current?.sessionId,text:e}))},[Je,Se]),et=(0,U.useCallback)(()=>{W.currentToolProject?.id&&(Se(),A(!1),k.setWorkspacePanelView(`changes`),k.setWorkspaceInspectorFocusTarget({tab:`git`,nonce:Date.now()}),k.setWorkspaceInspectorOpen(!0))},[W.currentToolProject?.id,Se,A,k]),tt=(0,U.useCallback)(async e=>{let t=W.currentToolProject?.id;if(!t){_e({sessionId:W.currentSessionId??``,title:`无法打开文件`,status:`error`,message:`当前对话没有关联项目。`});return}k.setInlineReaderOpen(!0),k.setInlineReaderLoading(!0),k.setInlineReaderError(void 0),k.setInlineReaderFile(void 0);try{let n=await Tl(t,(await El(t,e)).relativePath);k.setInlineReaderFile(n)}catch(e){let t=e instanceof Error?e.message:`打开文件失败`;k.setInlineReaderError(t),_e({sessionId:W.currentSessionId??``,title:`无法打开文件`,status:`error`,message:t})}finally{k.setInlineReaderLoading(!1)}},[_e,W.currentSessionId,W.currentToolProject?.id,k]),nt=(0,U.useCallback)(e=>{let t=W.currentToolProject;!t?.id||!Nl(e)||(Se(),A(!1),k.setWebPreviewUrl(Pl(t.path,e)),k.setWorkspacePanelView(`browser`),j(!0))},[W.currentToolProject,Se,A,j,k]);(0,U.useEffect)(()=>{let e=W.currentToolProject,t=e?.id;if(!t)return;let n=zl(oe);if(!n?.path)return;let r=n.toolCallIds[n.toolCallIds.length-1],i=`${t}:${n.path}:${n.defaultPreview?`default`:n.explicit?`explicit`:`inferred`}:${r??``}`;if(i!==ce.current){if(Zl(i)){ce.current=i;return}ce.current=i,Ql(i),queueMicrotask(()=>{Se(),A(!1),n.kind===`markdown`||n.kind===`code`?(k.setWorkspacePanelView(`files`),k.setWorkspaceInspectorFocusTarget({tab:`files`,filePath:n.path,nonce:Date.now()})):(k.setWebPreviewUrl(Pl(e.path,n.path)),k.setWorkspacePanelView(`browser`)),j(!0)})}},[W.currentToolProject,Se,oe,A,j,k]),(0,U.useEffect)(()=>{ce.current=``,A(!1)},[W.currentToolProject?.id,A]),(0,U.useEffect)(()=>{if(!nt)return;let e=e=>{let t=e.detail;t&&typeof t.path==`string`&&nt(t.path)};return window.addEventListener(`quickforge:preview-artifact`,e),()=>window.removeEventListener(`quickforge:preview-artifact`,e)},[nt]),(0,U.useEffect)(()=>yo(e=>{if(ru(e)){let t=typeof e.projectId==`string`?e.projectId:void 0;t&&(E(e=>{let n=new Set(e);return n.add(t),n}),Pe(t,0)),Fe({broadcast:!0});return}if((e.type===`agent_end`||e.type===`title_updated`||e.type===`session_forked`)&&Fe({broadcast:!0}),!nu(e))return;let t=typeof e.sessionId==`string`?e.sessionId:void 0,n=typeof e.title==`string`?e.title:G(`scheduledTasks`),r=tu(e.status)?e.status:`idle`,i=typeof e.message==`string`?e.message:void 0;_e({sessionId:t??``,title:n,status:r,message:i})}),[_e,Pe,Fe,E]);let{ready:rt,startupError:it,retryBootstrap:ot}=cs({storageRef:e,backendRef:we,activeModelRef:t,agentAccessModeRef:r,activeProjectRef:i,setAgentAccessMode:ee,taskMapRef:Ye,loadGlobalSessions:Ne,loadProject:h,initAgentAccessMode:O,switchActiveProject:g,createAgent:Be,setNeedsModelSetup:N,onStorageReady:me}),ct=_s(e,rt);(0,U.useEffect)(()=>{if(!rt)return;let e=0,t,n=(t=[])=>{let n=Date.now();if(t.length>0&&fe(e=>{let n=new Set(e);for(let e of t)n.add(e);return n}),!(n-e<5e3)){e=n,h(),Fe();for(let e of t)Pe(e,0)}},r=e=>{if(!e){t&&window.clearInterval(t),t=void 0;return}t||=window.setInterval(n,15e3)},i=new EventSource(`/api/channels/events`),a=e=>{try{let t=JSON.parse(e.data),i=ou(t);au(t)?(r(!0),n(i)):(t.type===`snapshot`||t.type===`status`)&&r(!1)}catch{}};return i.addEventListener(`snapshot`,a),i.addEventListener(`status`,a),i.addEventListener(`log`,a),()=>{i.close(),t&&window.clearInterval(t)}},[h,Pe,rt,Fe]),(0,U.useEffect)(()=>{if(rt)for(let e of d)!Me(e)&&!je(e)&&Pe(e,0)},[rt,d,Me,je,Pe]);let{startNewGlobalChat:lt,startNewProjectChat:ut,rollbackFromMessage:dt,retryFromMessage:pt,copyAnswer:mt,forkFromMessage:ht}=Zc({storageRef:e,activeModelRef:t,activeProjectRef:i,currentChatScopeRef:Ze,currentSessionIdRef:Xe,taskMapRef:Ye,agentRef:Je,createAgent:Be,startDeferredSession:Ve,syncSessionUI:Ue,setCurrentAgentMessages:We,setChatPanelRevision:Ke,refreshSessions:Fe,needsModelSetup:M,switchActiveProject:g,closeWorkspacePage:Se,setRestoredDraft:P}),{deleteProjectInline:gt}=Qc({activeProjectRef:i,refreshSessions:Fe,notifyProjectsChanged:Re.notifyProjectsChanged,setActiveProject:w,setProjects:T,setExpandedProjectIds:E,setChatPanelRevision:Ke}),{setAccessMode:_t}=rl({storageRef:e,agentAccessModeRef:r,setAgentAccessMode:ee,agentRef:Je,setChatPanelRevision:Ke,notifySettingsChanged:Re.notifySettingsChanged}),vt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t)throw Error(G(`toolApprovalFailed`));try{await t.approveToolCall(e)}catch(e){throw H.error(`Failed to approve tool call:`,e),e instanceof Error?e:Error(G(`toolApprovalFailed`))}},[Je]),yt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t)throw Error(G(`toolApprovalFailed`));try{await t.rejectToolCall(e)}catch(e){throw H.error(`Failed to reject tool call:`,e),e instanceof Error?e:Error(G(`toolApprovalFailed`))}},[Je]),bt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t?.approveAutoCompact)throw Error(G(`toolApprovalFailed`));await t.approveAutoCompact(e)},[Je]),xt=(0,U.useCallback)(async e=>{let t=Je.current;if(!t?.rejectAutoCompact)throw Error(G(`toolApprovalFailed`));await t.rejectAutoCompact(e)},[Je]),{loadSession:St,renameSession:Ct,togglePinSession:wt,archiveSession:Tt,startNewGlobalSession:Et}=tl({storageRef:e,taskMapRef:Ye,currentSessionIdRef:Xe,loadAgentSession:He,setCurrentTitleRef:qe,refreshSessions:Fe,closeWorkspacePage:Se,startNewGlobalChat:lt}),{openModelSettings:Dt,openDefaultOptionsSettings:Ot,openAboutSettings:kt,activateLiteLlmExampleModel:At,openCustomModelSelector:jt}=Jc({storageRef:e,activeModelRef:t,agentRef:Je,createAgent:Be,updateCurrentAgentModel:Ge,setChatPanelRevision:Ke,needsModelSetup:M,setNeedsModelSetup:N,setRestoredDraft:P,notifySettingsChanged:Re.notifySettingsChanged,setSettingsDialogOpen:k.setSettingsDialogOpen}),Mt=(0,U.useMemo)(()=>[...Ee,...c.flatMap(e=>De(e.id))],[Ee,c,De]),Nt=!!(0,U.useMemo)(()=>{if(W.currentSessionId)return Mt.find(e=>e.id===W.currentSessionId)},[W.currentSessionId,Mt])?.pinnedAt,Pt=ol(Mt),Ft=(0,U.useCallback)(e=>W.taskStatuses[e.id]??Pt[e.id]??e.taskStatus??`idle`,[W.taskStatuses,Pt]);(0,U.useEffect)(()=>{if(!k.conversationMenuOpen)return;let e=()=>k.setConversationMenuOpen(!1);return window.addEventListener(`click`,e),window.addEventListener(`blur`,e),()=>{window.removeEventListener(`click`,e),window.removeEventListener(`blur`,e)}},[k,k.conversationMenuOpen]),(0,U.useEffect)(()=>{let e=e=>{let t=e.detail,n=typeof t?.command==`string`?t.command.trim():``;n&&(async()=>{(t?.confirm||t?.dangerous)&&!await Y({title:G(`confirmExecuteCommandTitle`),description:t?.dangerous?G(`confirmExecuteDangerousCommand`):G(`confirmExecuteMultipleCommands`),confirmLabel:G(`executeInTerminal`),cancelLabel:G(`cancel`),variant:t?.dangerous?`destructive`:`default`})||(R(!0),ae({id:++pe.current,command:n,execute:!0}))})().catch(e=>{H.error(`Failed to execute markdown command:`,e),X(e instanceof Error?e.message:G(`terminalCommandExecuteFailed`))})};return window.addEventListener(`quickforge:execute-markdown-command`,e),()=>window.removeEventListener(`quickforge:execute-markdown-command`,e)},[]);let It=(0,U.useCallback)(e=>{ae(t=>t?.id===e?null:t)},[]),Lt=(0,U.useCallback)(()=>{k.setFirstUseGuideDismissed(!0)},[k]),zt=(0,U.useCallback)(()=>{let e=W.currentToolProject?.id?G(`firstUseGuideProjectPrompt`):G(`firstUseGuideGeneralPrompt`);navigator.clipboard.writeText(e).then(()=>_e({sessionId:W.currentSessionId??``,title:G(`copied`),status:`idle`,message:e})).catch(e=>{H.error(`Failed to copy first-use guide prompt:`,e),X(G(`copyFailed`))})},[_e,W.currentSessionId,W.currentToolProject?.id]),Bt=!!B&&!k.firstUseGuideDismissed&&!re&&c.length===0&&Ee.length===0,Vt=(0,U.useCallback)(()=>{let e=W.currentSessionId;e&&(k.setConversationMenuOpen(!1),wt(e))},[W.currentSessionId,wt,k]),Ht=(0,U.useCallback)(()=>{let e=W.currentSessionId;e&&(k.setConversationMenuOpen(!1),Ct(e,W.currentTitle))},[W.currentSessionId,W.currentTitle,Ct,k]),Ut=(0,U.useCallback)(()=>{k.setConversationMenuOpen(!1),k.setShareDialogOpen(!0)},[k]),{setSkillsDialog:Z,setMcpServersDialogOpen:Wt,setSidebarOpen:Gt}=k,qt=(0,U.useCallback)(()=>{Z({scope:`global`})},[Z]),Jt=(0,U.useCallback)(e=>{Z({scope:`project`,project:e})},[Z]),Yt=(0,U.useCallback)(async e=>{let t=await fetch(`/api/project/${encodeURIComponent(e.id)}/open-in-explorer`,{method:`POST`});if(t.ok)return;let n=await t.json().catch(()=>null);throw Error(n?.error||G(`openInExplorerFailed`))},[]),Xt=(0,U.useCallback)(()=>{Wt(!0)},[Wt]),Zt=(0,U.useCallback)(e=>{Yt(e).catch(e=>{H.error(`Failed to open project in explorer:`,e),X(e instanceof Error?e.message:G(`openInExplorerFailed`))})},[Yt]),Qt=(0,U.useCallback)(()=>L(`scheduledTasks`),[L]),en=(0,U.useCallback)(()=>L(`agentProfiles`),[L]),tn=(0,U.useCallback)(()=>L(`plugins`),[L]),nn=(0,U.useCallback)(()=>Gt(e=>!e),[Gt]),Q=(0,U.useCallback)(()=>{k.setMobileSidebarOpen(!1)},[k]),rn=(0,U.useCallback)(e=>{Q(),St(e)},[Q,St]),an=(0,U.useCallback)(()=>{Q(),Et()},[Q,Et]),sn=(0,U.useCallback)(e=>{Q(),ut(e)},[Q,ut]),cn=(0,U.useCallback)(()=>{Q(),L(`scheduledTasks`)},[Q]),ln=(0,U.useCallback)(()=>{Q(),L(`agentProfiles`)},[Q]),un=(0,U.useCallback)(()=>{Q(),qt()},[Q,qt]),dn=(0,U.useCallback)(()=>{Q(),k.setMcpServersDialogOpen(!0)},[Q,k]),fn=(0,U.useCallback)(e=>{Q(),Jt(e)},[Q,Jt]),pn=(0,U.useCallback)(e=>{if(e.scope===`project`&&e.project&&e.projects){T(e.projects),k.setSkillsDialog({scope:`project`,project:e.project}),i.current?.id===e.project.id&&(w(e.project),i.current=e.project),Re.notifyProjectsChanged();return}Re.notifyProjectsChanged()},[Re,w,T,k]),mn=(0,q.jsx)(`div`,{className:`flex h-full w-full items-center justify-center text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)});return it?(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background p-6 text-foreground`,children:(0,q.jsxs)(`div`,{className:`max-w-md rounded-lg border border-border bg-background p-5 text-center`,children:[(0,q.jsx)(`h1`,{className:`text-base font-semibold`,children:G(`localServiceUnavailableTitle`)}),(0,q.jsx)(`p`,{className:`mt-2 text-sm text-muted-foreground`,children:it}),(0,q.jsxs)(`div`,{className:`mt-4 flex justify-center gap-2`,children:[(0,q.jsx)(J,{variant:`outline`,size:`sm`,onClick:ot,children:G(`retry`)}),(0,q.jsx)(J,{variant:`default`,size:`sm`,onClick:()=>window.location.reload(),children:G(`reloadPage`)})]})]})}):!rt||!W.agent&&!M?(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background text-foreground`,children:(0,q.jsx)(`div`,{className:`text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)})}):(0,q.jsxs)(q.Fragment,{children:[!k.settingsDialogOpen&&(0,q.jsxs)(`div`,{className:`fixed right-2 top-2 z-[60] flex items-center gap-1`,"aria-label":G(`workspacePanel`),children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>R(e=>!e),disabled:xe||M,"aria-label":`终端`,title:`终端`,className:re?`bg-accent text-accent-foreground`:void 0,children:(0,q.jsx)(F,{className:`size-4`})}),(0,q.jsx)(J,{variant:`ghost`,size:`icon`,onClick:()=>{A(!1),k.setWorkspaceInspectorOpen(e=>!e)},disabled:!W.currentToolProject?.id||xe||M,"aria-label":k.workspaceInspectorOpen?G(`workspaceCollapseRightPanel`):G(`workspaceExpandRightPanel`),title:k.workspaceInspectorOpen?G(`workspaceCollapseRightPanel`):G(`workspaceExpandRightPanel`),className:K(`hidden lg:inline-flex`,k.workspaceInspectorOpen?`bg-accent text-accent-foreground`:void 0),children:(0,q.jsx)(a,{className:`size-4`})})]}),(0,q.jsxs)(`div`,{className:`flex h-screen min-h-0 bg-background text-foreground`,children:[(0,q.jsx)(no,{sidebarOpen:k.sidebarOpen,scheduledTasksActive:ye,agentProfilesActive:V,pluginsActive:be,projectsCollapsed:k.projectsCollapsed,conversationsCollapsed:k.conversationsCollapsed,projects:c,expandedProjectIds:d,activeProject:s,currentSessionId:W.currentSessionId,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,globalLoading:Ae,onLoadMoreGlobal:Ie,projectHasMore:ke,projectLoading:je,projectLoaded:Me,onLoadMoreProject:Le,sessionTaskStatus:Ft,selectingProject:p,onToggleProjectsCollapsed:k.toggleProjectsCollapsed,onToggleConversationsCollapsed:k.toggleConversationsCollapsed,onToggleProjectExpanded:b,onToggleAllProjectsExpanded:S,onReorderProjects:C,onSelectProjectDirectory:v,onStartNewProjectChat:ut,onOpenGlobalSkills:qt,onOpenMcpServers:Xt,onOpenProjectSkills:Jt,onOpenProjectInExplorer:Zt,onDeleteProject:gt,onLoadSession:St,onTogglePinSession:wt,onRenameSession:Ct,onDeleteSession:Tt,onStartNewGlobalChat:Et,onOpenScheduledTasks:Qt,onOpenAgentProfiles:en,onOpenPlugins:tn,onOpenSettings:Ot,updateAvailable:ct.result.updateAvailable,latestVersion:ct.result.latestVersion,currentVersion:ct.result.currentVersion,onOpenUpdate:kt,onDismissUpdate:ct.dismissUpdate,onToggleSidebar:nn,currentSessionHoverInfo:le}),k.mobileSidebarOpen?(0,q.jsxs)(`div`,{className:`fixed inset-0 z-50 md:hidden`,role:`dialog`,"aria-modal":`true`,children:[(0,q.jsx)(`button`,{type:`button`,className:`absolute inset-0 bg-background/65 backdrop-blur-sm`,onClick:Q,"aria-label":G(`toggleSidebar`)}),(0,q.jsx)(`div`,{className:`absolute inset-y-0 left-0 max-w-[85vw] shadow-quickforge`,children:(0,q.jsx)(no,{variant:`mobile`,sidebarOpen:!0,scheduledTasksActive:ye,agentProfilesActive:V,pluginsActive:be,projectsCollapsed:k.projectsCollapsed,conversationsCollapsed:k.conversationsCollapsed,projects:c,expandedProjectIds:d,activeProject:s,currentSessionId:W.currentSessionId,globalSessions:Ee,sessionsForProject:De,globalHasMore:Oe,globalLoading:Ae,onLoadMoreGlobal:Ie,projectHasMore:ke,projectLoading:je,projectLoaded:Me,onLoadMoreProject:Le,sessionTaskStatus:Ft,selectingProject:p,onToggleProjectsCollapsed:k.toggleProjectsCollapsed,onToggleConversationsCollapsed:k.toggleConversationsCollapsed,onToggleProjectExpanded:b,onToggleAllProjectsExpanded:S,onReorderProjects:C,onSelectProjectDirectory:()=>{Q(),v()},onStartNewProjectChat:sn,onOpenGlobalSkills:un,onOpenMcpServers:dn,onOpenProjectSkills:fn,onOpenProjectInExplorer:e=>{Q(),Yt(e).catch(e=>{H.error(`Failed to open project in explorer:`,e),X(e instanceof Error?e.message:G(`openInExplorerFailed`))})},onDeleteProject:gt,onLoadSession:rn,onTogglePinSession:wt,onRenameSession:Ct,onDeleteSession:Tt,onStartNewGlobalChat:an,onOpenScheduledTasks:cn,onOpenAgentProfiles:ln,onOpenPlugins:()=>{Q(),L(`plugins`)},onOpenSettings:()=>{Q(),Ot()},updateAvailable:ct.result.updateAvailable,latestVersion:ct.result.latestVersion,currentVersion:ct.result.currentVersion,onOpenUpdate:()=>{Q(),kt()},onDismissUpdate:ct.dismissUpdate,onToggleSidebar:Q,currentSessionHoverInfo:le})})]}):null,(0,q.jsxs)(`main`,{className:`flex min-w-0 flex-1 flex-col`,children:[(0,q.jsxs)(`header`,{className:`flex h-14 shrink-0 items-center gap-2 border-b border-border px-3 pr-20`,children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`md:hidden`,onClick:()=>k.setMobileSidebarOpen(!0),"aria-label":G(`toggleSidebar`),children:(0,q.jsx)(l,{className:`size-4`})}),(0,q.jsx)(`div`,{className:`min-w-0 flex-1`,children:ye?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`scheduledTasks`)})]}):V?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`agentsTab`)})]}):be?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`truncate text-xs text-muted-foreground`,children:`AI Workspace`}),(0,q.jsx)(`div`,{className:`truncate text-sm font-medium`,children:G(`plugins`)})]}):(0,q.jsxs)(`div`,{className:`flex max-w-full min-w-0 items-center`,children:[W.currentToolProject?.name?(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`min-w-0 truncate text-sm text-muted-foreground/60`,children:W.currentToolProject.name}),(0,q.jsx)(`div`,{className:`mx-1 shrink-0 text-sm text-muted-foreground/45`,children:`/`})]}):null,(0,q.jsx)(`div`,{className:`min-w-0 truncate text-sm font-medium text-foreground/90`,children:Kt(W.currentTitle)}),(0,q.jsxs)(`div`,{className:`relative ml-0.5 shrink-0`,onClick:e=>e.stopPropagation(),children:[(0,q.jsx)(J,{variant:`ghost`,size:`icon`,className:`size-6`,onClick:()=>k.setConversationMenuOpen(e=>!e),disabled:!W.currentSessionId||M,"aria-label":G(`moreOptions`),"aria-expanded":k.conversationMenuOpen,children:(0,q.jsx)(I,{className:`size-4`})}),k.conversationMenuOpen?(0,q.jsxs)(`div`,{className:`absolute left-0 top-8 z-30 min-w-44 rounded-lg border border-border bg-popover p-1 shadow-quickforge`,children:[(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Vt,children:[Nt?(0,q.jsx)(n,{className:`size-4`}):(0,q.jsx)(f,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(Nt?`unpinSession`:`pinSession`)})]}),(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Ht,children:[(0,q.jsx)(ie,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(`renameSession`)})]}),(0,q.jsxs)(`button`,{type:`button`,className:`flex w-full items-center gap-2 whitespace-nowrap rounded-md px-2 py-1.5 text-left text-sm text-foreground/86 transition-colors hover:bg-muted`,onClick:Ut,children:[(0,q.jsx)(x,{className:`size-4`}),(0,q.jsx)(`span`,{children:G(`shareSession`)})]})]}):null]})]})})]}),(0,q.jsx)(`section`,{className:`relative flex min-h-0 flex-1 flex-col`,children:ye?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Hl,{onOpenSession:Qe})}):V?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Ul,{})}):be?(0,q.jsx)(U.Suspense,{fallback:mn,children:(0,q.jsx)(Wl,{})}):M?(0,q.jsx)(kn,{onAddModel:Dt,onUseExample:()=>{At().catch(e=>H.error(`Failed to use LiteLLM example:`,e))}}):(0,q.jsxs)(q.Fragment,{children:[(0,q.jsx)(`div`,{className:`flex min-h-0 flex-1 flex-col`,children:(0,q.jsx)(at,{children:(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)($l,{}),children:(0,q.jsx)(Bl,{agent:W.agent,onModelSelect:jt,revision:W.chatPanelRevision,agentAccessMode:D,workspaceToolsEnabled:!!W.currentToolProject?.id,project:W.currentToolProject,projectId:W.currentToolProject?.id,chatScope:W.chatScope,onAccessModeChange:_t,onRollbackFromMessage:dt,onRetryFromMessage:pt,onCopyAnswer:mt,onForkFromMessage:ht,onApproveToolCall:vt,onRejectToolCall:yt,onApproveAutoCompact:bt,onRejectAutoCompact:xt,onOpenWorkspaceGitChanges:et,onOpenLocalFilePath:tt,onArtifactsChange:se,onContextUsageDisplayChange:ze,disableFork:!1,restoredDraft:te})})})}),Bt?(0,q.jsx)(On,{hasProject:!!W.currentToolProject?.id,onConfigureModel:Dt,onAddProject:v,onCopyExamplePrompt:zt,onDismiss:Lt}):null,re?(0,q.jsx)(U.Suspense,{fallback:null,children:(0,q.jsx)(Vl,{project:W.currentToolProject,pendingCommand:z,onPendingCommandHandled:It,onCollapse:()=>R(!1)})}):null]})})]}),k.workspaceInspectorOpen&&W.currentToolProject?.id?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(eu,{}),children:(0,q.jsx)(Kl,{project:W.currentToolProject,open:!0,view:k.workspacePanelView,onViewChange:k.setWorkspacePanelView,onPreviewArtifact:nt,onDraftRequest:$e,focusTarget:k.workspaceInspectorFocusTarget,previewUrl:k.webPreviewUrl,onPreviewUrlChange:k.setWebPreviewUrl,artifacts:oe})}):null,k.inlineReaderOpen?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(eu,{}),children:(0,q.jsx)(ql,{open:!0,mode:`file`,file:k.inlineReaderFile,loading:k.inlineReaderLoading,error:k.inlineReaderError,onOpenChange:k.setInlineReaderOpen,onDraftRequest:$e})}):null]}),(0,q.jsx)(st,{open:m,initialPath:s?.path,disabled:p,onOpenChange:y,onSelect:_}),(0,q.jsx)(ft,{open:!!k.skillsDialog,scope:k.skillsDialog?.scope??`global`,project:k.skillsDialog?.project,onOpenChange:e=>{e||k.setSkillsDialog(void 0)},onSaved:pn}),(0,q.jsx)(Rt,{open:k.mcpServersDialogOpen,onOpenChange:k.setMcpServersDialogOpen}),(0,q.jsx)(bl,{open:k.shareDialogOpen,sessionId:W.currentSessionId,title:Kt(W.currentTitle),onOpenChange:k.setShareDialogOpen}),(0,q.jsx)(ll,{toasts:he,onDismiss:ve,onClick:Qe})]})}function cu(){let e=window.location.pathname.match(/^\/share\/([^/]+)\/?$/)?.[1];return e?(0,q.jsx)(U.Suspense,{fallback:(0,q.jsx)(`div`,{className:`flex h-screen items-center justify-center bg-background text-sm text-muted-foreground`,children:G(`loadingChatWorkspace`)}),children:(0,q.jsx)(Gl,{shareId:decodeURIComponent(e)})}):(0,q.jsx)(su,{})}tt({hideSelector:!0}),rt(),window.addEventListener(`error`,e=>{H.error(`Uncaught error:`,e.error??e.message)}),window.addEventListener(`unhandledrejection`,e=>{H.error(`Unhandled promise rejection:`,e.reason)}),`serviceWorker`in navigator&&window.addEventListener(`load`,()=>{navigator.serviceWorker.register(`/sw.js`).catch(()=>{})}),(0,Pe.createRoot)(document.getElementById(`root`)).render((0,q.jsx)(U.StrictMode,{children:(0,q.jsx)(at,{children:(0,q.jsx)(cu,{})})}));export{Vt as A,so as C,un as D,xn as E,K as F,G as I,Y as M,ut as N,hn as O,J as P,fo as S,fn as T,Co as _,Rl as a,wo as b,Dl as c,_l as d,yl as f,Uo as g,is as h,jl as i,X as j,Sn as k,Tl as l,qc as m,Al as n,Fl as o,vl as p,Nl as r,Ol as s,kl as t,wl as u,Eo as v,po as w,lo as x,To as y};
|